Skip to content

Add support for manifest list signature removal and sparse manifest list stripping#2892

Open
aguidirh wants to merge 11 commits into
podman-container-tools:mainfrom
aguidirh:RUN-4764
Open

Add support for manifest list signature removal and sparse manifest list stripping#2892
aguidirh wants to merge 11 commits into
podman-container-tools:mainfrom
aguidirh:RUN-4764

Conversation

@aguidirh

@aguidirh aguidirh commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR introduces two new flags for the skopeo copy command to provide more granular control over multi-architecture image copying:

  • --remove-list-signatures: Removes only the manifest list signature while preserving per-instance signatures
  • --strip-sparse-manifest-list: Strips missing instances from manifest lists when copying specific platforms

Relates to #2882

Motivation

When copying multi-architecture images with platform-specific selections, users currently face two challenges:

  1. The --remove-signatures flag removes ALL signatures (both manifest list and per-instance), but sometimes users only want to remove the manifest list signature
  2. Some registries don't support sparse manifest lists (manifest lists with missing instances), requiring users to strip the non-copied instances

Changes

New Flags

--remove-list-signatures

  • Removes only the manifest list signature while preserving per-instance signatures
  • Provides finer control than --remove-signatures
  • If both flags are specified, --remove-signatures takes precedence

--strip-sparse-manifest-list

  • Strips missing instances from manifest lists when copying only a subset of platforms
  • Useful for registries that don't support sparse manifest lists
  • Requires explicit signature removal using either --remove-signatures or --remove-list-signatures
  • The operation will fail if signatures are present and not explicitly removed

Documentation

  • Updated docs/skopeo-copy.1.md with flag descriptions and usage examples
  • Added example showing how to copy specific platforms with sparse list stripping

Tests

  • Added TestCopyPlatformListWithStripSparse integration test
  • Updated TestSharedCopyOptionsCopyOptions unit tests to cover new flags

Test Plan

  • Unit tests pass: make test-unit-local
  • Integration tests pass: make test-integration-local
  • Validation passes: make validate-local
  • Documentation validation passes: make validate-docs

Example Usage

Copy specific platforms and strip the sparse manifest list:

skopeo copy --multi-arch=linux/amd64,linux/arm64 \
  --strip-sparse-manifest-list \
  --remove-list-signatures \
  docker://quay.io/skopeo/stable:latest \
  docker://registry.example.com/skopeo:latest

Remove only manifest list signatures:

skopeo copy --multi-arch=linux/amd64,linux/arm64 \
  --remove-list-signatures \
  docker://quay.io/skopeo/stable:latest \
  docker://registry.example.com/skopeo:latest

@aguidirh aguidirh changed the title Add support for selective signature removal and sparse manifest list stripping Add support for manifest list signature removal and sparse manifest list stripping Jun 8, 2026
@aguidirh

aguidirh commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Hi @mtrmac,

I added the --remove-list-signatures to the sync command because I see a scenario where people would like to sync the repos where the signature of the manifest list is not present in source.

I did not add the --strip-sparse-manifest-list to the sync because I saw the sync command always pull and push everything, so I did not see a reason to add this flag.

Please let me know what you think about it.

@mtrmac

mtrmac commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

I added the --remove-list-signatures to the sync command because I see a scenario where people would like to sync the repos where the signature of the manifest list is not present in source.

*shrug* I don’t see a strong reason to think users want that feature individually, but it’s easier / more consistent to implement that way, so, why not.

I did not add the --strip-sparse-manifest-list to the sync because I saw the sync command always pull and push everything, so I did not see a reason to add this flag.

Yeah, we’d have to move all of the --multi-arch option to be shared between copy and sync. That would also be fine, but more work, and really if users are motivated to use oc-mirror instead of skopeo sync, I think that’s the better outcome for everyone.

(ACK to the general structure from a very brief skim, I’ll try to do a more careful review soonish.)

Comment thread integration/copy_test.go
require.NoError(t, err)
assert.Equal(t, 3, len(manifestFiles), "Expected manifest list + 2 platform manifests after stripping")
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have a test that calls both --remove-list-signatures and --remove-signatures to make sure all get wiped.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might also be good to have a test to make sure --strip-sparse-manifest-list fails without a --remove*signatures option

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have a test that calls both --remove-list-signatures and --remove-signatures to make sure all get wiped.

Do you mean testing each flag isolated? Or testing both of them together?

According to @mtrmac comment both flags shouldn't be used together.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have a test that calls both --remove-list-signatures and --remove-signatures to make sure all get wiped.

Skipped — went with mtrmac's suggestion to reject both flags together instead. Implemented on d5d3ab84.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might also be good to have a test to make sure --strip-sparse-manifest-list fails without a --remove*signatures option

Implemented on 4646b190.

@TomSweeneyRedHat

Copy link
Copy Markdown
Contributor

@aguidirh looks like you need to update the branch.

@TomSweeneyRedHat

Copy link
Copy Markdown
Contributor

Changes LGTM overall.

@mtrmac mtrmac left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

As usual, naming things tends to be the hardest part :)

Comment thread docs/skopeo-copy.1.md Outdated
Comment thread docs/skopeo-copy.1.md Outdated
Comment thread cmd/skopeo/copy.go Outdated
Comment thread cmd/skopeo/utils.go
Comment thread cmd/skopeo/utils.go Outdated
Comment thread docs/skopeo-copy.1.md Outdated
Comment thread integration/copy_test.go
Comment thread docs/skopeo-copy.1.md Outdated
aguidirh added 10 commits June 12, 2026 15:47
…stripping

This commit introduces two new flags for the skopeo copy command to provide
more granular control over multi-architecture image copying:

--remove-list-signatures: Removes only the manifest list signature while
preserving per-instance signatures. This provides finer control than the
existing --remove-signatures flag which removes all signatures.

--strip-sparse-manifest-list: Strips missing instances from manifest lists
when copying only a subset of platforms (using --multi-arch with a platform
list). This is useful for registries that don't support sparse manifest lists.

The --strip-sparse-manifest-list flag requires explicit signature removal
using either --remove-signatures or --remove-list-signatures, as stripping
instances invalidates the manifest list signature.

These flags address scenarios where users need to copy multi-architecture
images to registries with different signature requirements or those that
don't support sparse manifest lists, while still maintaining control over
which signatures are preserved.

Documentation has been updated with usage examples, and integration tests
have been added to verify the new functionality.

Signed-off-by: Alex Guidi <aguidi@redhat.com>
…t list stripping

Signed-off-by: Alex Guidi <aguidi@redhat.com>
…t list stripping

Signed-off-by: Alex Guidi <aguidi@redhat.com>
…t list stripping

Signed-off-by: Alex Guidi <aguidi@redhat.com>
…t list stripping

Signed-off-by: Alex Guidi <aguidi@redhat.com>
…t list stripping

Signed-off-by: Alex Guidi <aguidi@redhat.com>
…t list stripping

Signed-off-by: Alex Guidi <aguidi@redhat.com>
…t list stripping

Signed-off-by: Alex Guidi <aguidi@redhat.com>
…t list stripping

Signed-off-by: Alex Guidi <aguidi@redhat.com>
…t list stripping

Signed-off-by: Alex Guidi <aguidi@redhat.com>
…t list stripping

Signed-off-by: Alex Guidi <aguidi@redhat.com>
@aguidirh

Copy link
Copy Markdown
Contributor Author

@mtrmac are these tests flakies?

Because make test-integration-local is passing on my localhost.

@mtrmac

mtrmac commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

@mtrmac are these tests flakies?

The same, newly added, test is failing in all three runs, I think this very likely to be legitimate.

I guess, but did not verify, that the image is not signed, so that error path does not engage. I’m not very sure what TestCopyPlatformListStripRemovedPlatformsFailsWithoutSignatureRemoval is supposed to verify — but maybe using --preserve-digests instead of relying on a signature would trigger the same “we can’t modify the manifest list” error path.

Because make test-integration-local is passing on my localhost.

I think most tests there are skipped without SKOPEO_CONTAINER_TESTS (and enabling that outside of a non-confined VM might be a bad idea).

@mtrmac mtrmac left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! LGTM apart from the failing TestCopyPlatformListStripRemovedPlatformsFailsWithoutSignatureRemoval

Comment thread cmd/skopeo/utils.go
}

if opts.removeSignatures && opts.removeListSignatures {
return nil, nil, fmt.Errorf("Only one of --remove-signatures and --remove-list-signatures can be specified")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking: covering this in unit tests wouldn’t hurt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skopeo copy --multi-arch with specific platforms fails with "blob unknown to registry" when manifest list contains other platforms

3 participants