Commit Graph

45 Commits

Author SHA1 Message Date
Miloslav Trmač 04deef6fe6 Call .Validate() before digest.Hex() / digest.Encoded()
... to prevent panics if the value does not contain a :, or other unexpected
values (e.g. a path traversal).

Don't bother on paths where we computed the digest ourselves, or it is already trusted
for other reasons.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2024-05-09 15:59:32 +02:00
Miloslav Trmač fbf83e451f Add an internal/signature package
We need something to wrap (format ID, actual data).

And a shared helper for a file/blob representation for things like
dir or c/storage.

This looks quite immature.

Tests of the non-simple signing will only be added with support for that format.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-07-07 13:44:19 +02:00
Miloslav Trmač 592371c8be Implement private.ImageSource in non-forwarding transports
This sets up the precedent that all transports should primarily implement
the private interface; that will allow us to make future changes to the
private interface easier, because we can just change the public interface
wrappers in a single place instead of modifying transports - especially
as more stubs are added soonish.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-07-05 17:02:23 +02:00
Miloslav Trmač 5e75f679a6 Implement private.ImageDestination in non-forwarding transports
This sets up the precedent that all transports should primarily implement
the private interface; that will allow us to make future changes to the
private interface easier, because we can just change the public interface
wrappers in a single place instead of modifying transports - especially
as more stubs are added soonish.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-07-02 01:29:14 +02:00
Miloslav Trmač 6accca5e04 Remove uses of errors.Errorf
This means we won't save the stack, which is cheaper
(and possibly might break callers' format strings that
want to print the stack, but we never promised the stack
to be available).

Use either fmt.Errorf, or errors.New (usually as a local
edit, not carring about errors.new vs. pkg/errors.New;
that's going to be cleaned up later).

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-06-30 21:45:07 +02:00
Miloslav Trmač 7152f888b9 Update users of deprecated io/ioutil
Mostly just name changes that should not change behavior,
apart from ioutil.ReadDir -> os.ReadDir avoiding per-item
lstat(2) in some cases.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-04-13 20:46:48 +02:00
Miloslav Trmač 9a9904944d Use testing.T.TempDir()
... to simplify tests.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-03-17 20:35:00 +01:00
Miloslav Trmač 34d7a624d8 Use assert.ErrorContains
...added in github.com/stretchr/testify 1.7.1.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-03-16 15:29:36 +01:00
Miloslav Trmač bc2f150462 Don't unnecessarily compute the blob digest in PutBlob
Introduce internal/putblobdigest.Digester to encapsulate
the two alternatives, so that the PutBlob implementations only
need to plug it in.

Then use it throughout: let PutBlob use caller-provided digest
values, if any (and they use the right algorithm).

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2021-08-23 14:58:56 +02:00
Miloslav Trmač d05298862a Improve directory.TestGetPutSignatures
- Use a different manifest and manifest list
- Write per-arch manifest before the top-level one
- Same for signatures
- Don't write the top-level manifest twice

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2021-06-22 21:45:51 +02:00
Miloslav Trmač e3aa82e5c9 Document the unparsedToplevel parameter to Commit
... and acknowledge that various tests are strictly speaking
invalid, to reinforce that real callers must not pass nil.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2021-06-22 21:45:50 +02:00
Ivan Voronchihin 4d6079501f Fix this value is never used
Signed-off-by: Ivan Voronchihin <bege13mot@gmail.com>
2019-11-26 18:47:55 +04:00
Miloslav Trmač 7d9cde7252 Update to major version v5
> gomove github.com/containers/image/v4 github.com/containers/image/v5
+ a manual edit of go.mod

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2019-10-25 22:27:45 +02:00
Nalin Dahyabhai ca5fe04cb3 Add manifest list support
Add the manifest.List interface, and implementations for OCIv1 Index and
Docker Schema2List documents.

Add an instanceDigest parameter to PutManifest(), PutSignatures(), and
LayerInfosForCopy, for symmetry with GetManifest() and GetSignatures().
Return an error if the instanceDigest is supplied to destinations which
don't support them, and add stubs that do so even to the transports
which would support it, so that we don't break compilation here.

Add a MultipleImages flag to copy.Options, and if the source for a copy
operation contains multiple images, copy all of the images if we can.
If we can't copy them all, but we were told to, return an error.

Use the generic manifest list API to select a single image to copy from
a list, so that we aren't just limited to the Docker manifest list
format for those cases.

When guessing at the type of a manifest, if the manifest contains a list
of manifests, use its declared MIME type if it included one, else assume
it's an OCI index, because an OCI index doesn't include its MIME type.

When copying, switch from using an encode-then-compare of the original
and updated versions of the list to checking if the instance list was
changed (one of the things we might have changed) or if its type has
changed due to conversion (the other change we might have made).  If
neither has changed, then we don't need to change the encoded value of
the manifest.

When copying, when checking for a digest mismatch in a target image
reference, ignore a mismatch between the digest in the reference and the
digest of the main manifest if we're copying one element from a list,
and the digest in the reference matches the digest of the manifest list.

When copying, if conversion of manifests for single images is being
forced, convert manifest lists to the corresponding list types.

When copying, supply the unparsed top level to Commit() by attaching the
value to the context.Context.

Support manifest lists in the directory transport by using the instance
digest as a prefix of the filename used to store a manifest or a piece
of signature data.

Support manifest lists in the oci-layout transport by accepting indexes
as we do images, and stop guessing about Platform values to add to the
top-level index.

Support storing manifest lists to registries in the docker: transport by
using the manifest digest when we're writing one image as part of
pushing a list of them, and by using the instance digest when reading or
writing signature data, when one is specified, or the cached digest of
the non-instanced digest when one is not specified.

Add partial support for manifest lists to the storage transport: when
committing one image from a list into storage, also add a copy of the
manifest list by extracting it from the context.Context.  The logic is
already in place to enable locating an image using any of multiple
manifest digests.

When writing an image that has an instanceDigest value (meaning it's a
secondary image), don't try to generate a canonical reference to add to
the image's list of names if the reference for the primary image doesn't
contain a name.  That should only happen if we're writing using just an
image ID, which is unlikely, but we still need to handle it.

Avoid computing the digest of the manifest, or retrieving the
either-a-tag-or-a-digest value from the target reference, if we're given
an instanceDigest, which would override them anyway.

Move the check for non-nil instanceDigest values up into the main
PutSignatures() method instead of duplicating it in the per-strategy
helpers.

Add mention of the instanceDigest parameter and its use to various
PutManifest, PutSignatures, and LayerInfosForCopy implementations and
their declarations in interfaces.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2019-10-18 15:15:13 -04:00
Miloslav Trmač e568c94ef3 Correctly use a c/image/v4 module namespace
... so that major-version-aware Go module import
(as opposed to vX.Y.Z+incompatible, which does not allow different
packages to use different versions) works right.

Also requires adding some more GO111MODULE=on options to Makefile.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2019-10-03 22:54:27 +02:00
W. Trevor King d545a196c9 pkg/blobinfocache: Split implementations into subpackages
This allows consumers who don't need the defaulting logic to pick
their desired implementation without pulling in unrelated
dependencies.  For example, it allows you to consume the memory or
NoCache implementations without pulling in github.com/boltdb.

I'd initially included blobinfocache wrappers to preserve backwards
compatibility with the old API while consumers updated to the new
APIs, but Miloslav said we don't have any backwards-compatibility
commitments at the moment [1].

Having single-implementation subpackages also allows for more generic
names (e.g. NewMemoryCache is now just New), because memory.New is
clear enough while memory.NewMemoryCache stutters.

[1]: https://github.com/containers/image/pull/602#issuecomment-471570789

Signed-off-by: W. Trevor King <wking@tremily.us>
2019-03-12 13:24:14 -07:00
Miloslav Trmač 7ad78ecdfd Add a BlobInfoCache parameter to GetBlob, PutBlob and TryReusingBlob.
For now, none of the transports actually use it, so should not change behavior.

copy.Image uses its existing cache object; config parses in image/* usually
use NoCache because they wouldn't appreciably benefit anyway.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2018-12-06 18:59:24 +01:00
Mike Lundy 369c44212b Put context.Context arguments on almost everything
- Network IO paths should react to cancels now.
- File IO paths generally still won't.
- `SystemContext` objects have been renamed to `sys` to leave `ctx`
  available for the stdlib context objects.

Signed-off-by: Mike Lundy <mike@fluffypenguin.org>
2018-04-07 04:34:51 -07:00
Antoine Eiche 69b3fccb5c docker-archive generates docker legacy compatible images
docker save generates image compatible with the legacy format, ie,
layers are tar, they have a configuration file and a repositories file
is created.

There are some external tools that still relie on this old format such
as mesos [1] and nixos [2].

[1] 7ca46e24b3/src/slave/containerizer/mesos/provisioner/docker/local_puller.cpp (L168)
[2] 5c6dc717a6/pkgs/build-support/docker/default.nix (L143)

Signed-off-by: Antoine Eiche <lewo@abesis.fr>
2018-03-27 17:34:45 +02:00
Miloslav Trmač 36f8bf7821 Add a instanceDigest parameter to GetSignatures
This mirrors GetManifest, and allows / requires signatures to be per-instance.

Also add implementations in docker: and atomic:, the only transports which
support both manifest lists and signatures.

Does not change behavior yet, the only user always specifies nil
instanceDigest.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2017-11-15 20:06:05 +01:00
Miloslav Trmač 74a1d256e0 Replace GetTargetManifest by GetManifest(instanceDigest)
This will make the code paths more uniform for consumers of the
primary manifest and the manifest instances.

(Having an explicit support for manifest instances is necessary
for transports like docker-daemon: / oci-archive:, which
contain several images but setting up an ImageSource is very
expensive, or which don't even allow referencing images by digest.)

This is a direct replacement of GetTargetManifest, and should
not change behavior; notably the OCI implementation is still
blindly guessing the manifest type although it is probably
available in the index.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2017-11-15 20:06:05 +01:00
Owen W. Taylor 56b61acbe8 ImageReference.NewImageSource: remove requestedManifestMIMETypes parameter
The requestedManifestMIMETypes parameter was added because a destination
might not support all manifest MIME types that the the source supports,
but the original use case now passes all manifest types and lets
containers/image convert internally. In generally, internal conversion
may be more comprehensive, is more predictable, and avoids bypassing
internal checks.

Fixes: #331
Signed-off-by: Owen W. Taylor <otaylor@fishsoup.net>
2017-09-05 07:56:42 -04:00
Michal Fojtik 1ef1350679
pass context.Context to signature retrieval http calls
Signed-off-by: Michal Fojtik <mfojtik@redhat.com>
2017-08-02 21:16:23 +02:00
Antonio Murdaca f4c6ac26a2
*: move to opencontainers/go-digest
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
2017-01-09 15:55:13 +01:00
George Lestaris bda6e4b37f Replace fmt.Errorf with pkg/errors.Wrap
Signed-off-by: George Lestaris <glestaris@pivotal.io>
2016-12-19 14:13:16 +00:00
Antonio Murdaca d54f1156b2
*: support layers federation
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
2016-11-30 18:54:56 +01:00
Crazykev c979dad117 refactor: use docker/distribution/digest instead of string
Signed-off-by: Crazykev <crazykev@zju.edu.cn>
2016-11-28 19:10:12 +08:00
Miloslav Trmač 0eef2b3a3e Add types.ImageDestination.ShouldCompressLayers
This allows generic code to differentiate between transports where
bandwidth and storage costs are at premium (usually remote
repositories), and where memory/mmap and CPU time are more important
(usually local, especially temporary, storage) [or the dir: case
where we don’t want to modify the input at all if possible].

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-09-19 20:46:27 +02:00
Miloslav Trmač 021a796b8d Add types.BlobInfo, use it in ImageDestination.PutBlob
This does not change behavior. Having a single struct for carrying
the (digest, size) pair around will make manipulating layers much
easier in the future.

... except that dockerImageDestination now logs the uploaded layer using
the realized digest, instead of the input digest = an empty string if the digest is
unknown.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-09-16 21:49:07 +02:00
Miloslav Trmač 5a0d038a03 Add ImageDestination.SupportsSignatures
This allows copy.go to bail early, without transferring any large blobs.

(This is an attribute of an ImageDestination and not an ImageTransport
because supporting signatures may depend on the individual destination,
e.g. depending on server version or whether a sigstore lookaside has
been configured for that destination.)

Also reorders the ImageDestination methods in some cases, to separate
basic management / capability query / upload groups.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-09-06 20:10:10 +02:00
Antonio Murdaca 888ad76c1f
API: ImageDestination.PutBlob returns digest and size
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
2016-09-06 19:29:59 +02:00
Miloslav Trmač 4eec058916 Add ImageDestination.Commit
This marks the image saving as "done".  This is a separate concept from
ImageDestination.Close, which is called whenever the destination
should no longer be used, even if the caller has given up on the upload
process.

The separation between Close and Commit alllows a natural, simple flow:
> dest := ref.NewDestination()
> defer dest.Close()
> ... // do anything, simply return on error
> dest.Commit()

whereas a single Close would be more difficult to use:
> dest := ref.NewDestination()
> succeeded := false
> defer func() {
>    dest.Close(succeeded)
> }()
> ... // do anything, simply return on error
> succeeded = true

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-09-05 22:57:02 +02:00
Miloslav Trmač 287c1321f6 Add ImageDestination.Close
This is necessary to close the socket to the daemon in
daemonImageDestination.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-09-05 22:57:02 +02:00
Miloslav Trmač 557dc5d86d Add an expectedSize parameter to PutBlob
Submit this size in docker: destinations, validate it in dir: and oci:.

Preserve the size, if provided by ImageSource, when copying blobs.

Also document that PutBlob must be called before PutManifest and
PutSignatures; this is clearly the necessary ordering if the layer
tarballs are being generated on the fly, or if the manifest destination
wants to reject manifests referring to nonexistent blobs.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-09-05 22:47:03 +02:00
Miloslav Trmač 45037ddc47 Add ImageSource.Close and Image.Close
These methods are necessary to clean up the temporary tar file copy in
daemonImageSource.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-09-05 22:46:45 +02:00
Miloslav Trmač be7e92f900 Move deleting images from ImageSource to ImageReference
For lookaside signature store, and separating the read and write URLs,
we need to set up read-only and read-write states differently; having
read-write “delete” in dockerImageSource is incovenient.

In tue future, ImageSource.Delete will be a really poor fit for
docker-daemon:, where initializing the ImageSource causes the tarball
to be copied from the daemon.  We could instead implement the
docker-daemon source so that it only copies the tarball on demand, but
not sharing the object is much simpler.

This leaves the Docker implementation in docker_image_src.go to make
reviewing easier.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-08-31 21:13:31 +02:00
Miloslav Trmač dff447c638 Move manifest MIME type selection from GetManifest to ImageSource creation
This allows the selection to be consistent across GetManifest and
GetSignatures (which will be needed by Docker lookaside).

The API change causes lots of churn, but ultimately it just moves the
real origin of the value from image.FromSource() to transport.NewImageSource(),
both of which are static for the life of the ImageSource.

Does not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-08-31 21:13:31 +02:00
Miloslav Trmač 8ad0cad4ea Use types.SystemContext in NewImage*
... instead of Docker-specific certPath and tlsVerify.

Also invert the sense of tlsVerify to make the default secure.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-08-31 21:13:31 +02:00
Miloslav Trmač 3821c913e8 Require ImageDestination.PutBlob to fail and delete data on error in source stream
This is necessary to prevent using layers which have been tampered with.

To implement this, dir: and oci: now store data into temporary files,
and Rename() when all data is successfully copied and validated.

We do not do anything extra for docker:, hoping that the mandatory
digest= parameter in the API call is sufficient.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-08-04 19:30:17 +02:00
Miloslav Trmač b462e18ca7 Replace IntendedDockerReference by Reference().DockerReference
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-07-16 05:08:38 +02:00
Miloslav Trmač d7b3b26b81 Replace CanonicalDockerReference by Reference().DockerReference
This also removes the error return value, only supporting nil
to indicate "Docker references not supported"; other kinds of
errors should have been handled when initially parsing or
creating the reference.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-07-16 05:08:38 +02:00
Miloslav Trmač 0a1111ca30 Add types.ImageTransport and types.ImageReference
This minimizes transport-specific knowledge in image name parsing
(as in cmd/skopeo/utils.go) and allows separation of reference parsing
and their use.

Existing public NewImage... API has been removed; callers are expected
to use any of
* types.ImageTransport.ParseReference().NewImage...
  (if they have a general string)
* transportpackage.ParseReference().NewImage...
  (if they have a transport-specific string)
* transportpackage.NewReference().NewImage...
  (if they have transport-specific raw values)

This usually adds an extra error checking step for the
ParseReference/NewReference call compared to the previous code; this is
considered not a big loss, especially because reporting “the reference
is invalid” and “the reference looks valid but connecting/using it
failed” as distinct failure modes seems quite useful for users.

The references are currently one-way (you can get a types.Image* from an
ImageReference, but not the other way around); that will be fixed soon.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-07-16 05:08:38 +02:00
Miloslav Trmač ca400b95a2 Return a reference.Named instead of a string for Docker references
This is somewhat better typed, and avoids unnecessary roundtrips using
strings when both the producer and consumer want a reference.Named value
(like in PolicyContext.requirementsForImage).

This also forces us to explicitly handle IntendedDockerReference()
returning nil, when before we could rely on it returning "", which would
then be rejected by reference.ParseNamed as invalid input; anyway,
handling that case specially just allows for better error messages.

This adds two FIXMEs about error messages which do not tell the user
which image is being rejected; that will be fixed in the future
generalized reference work.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2016-07-11 21:25:07 +02:00
Antonio Murdaca b89242619d directory: cleanup API
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
2016-07-04 11:32:26 +02:00
Antonio Murdaca ee3863dfd3 directory: add unit tests
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
2016-06-28 17:53:54 +02:00