diff --git a/pkg/builds/cosa_v1.go b/pkg/builds/cosa_v1.go index 03ce3a2e21..a77967e37e 100644 --- a/pkg/builds/cosa_v1.go +++ b/pkg/builds/cosa_v1.go @@ -1,7 +1,7 @@ package builds // generated by 'make schema' -// source hash: 4289a52f5ee4665caa5432d9caa653b74605117632ac045955912e624d149524 +// source hash: 11704f512a9b6e0c5ac178a9917e03a05ea10a7878ef9b5c0a6695d52c9cd7f5 type AdvisoryDiff []AdvisoryDiffItems @@ -182,11 +182,12 @@ type PackageSetDifferences []PackageSetDifferencesItems type PackageSetDifferencesItems interface{} type PrimaryImage struct { - AdditionalImages []interface{} `json:"additional-images,omitempty"` - Comment string `json:"comment,omitempty"` - Digest string `json:"digest,omitempty"` - Image string `json:"image"` - Tags []PrimaryImageTag `json:"tags,omitempty"` + AdditionalImages []interface{} `json:"additional-images,omitempty"` + Comment string `json:"comment,omitempty"` + Digest string `json:"digest,omitempty"` + Image string `json:"image"` + ManifestListDigest string `json:"manifest-list-digest,omitempty"` + Tags []PrimaryImageTag `json:"tags,omitempty"` } type PrimaryImageTag string diff --git a/pkg/builds/schema_doc.go b/pkg/builds/schema_doc.go index 1648c60d33..73c4c1489d 100644 --- a/pkg/builds/schema_doc.go +++ b/pkg/builds/schema_doc.go @@ -1,5 +1,5 @@ // Generated by ./generate-schema.sh -// Source hash: 4289a52f5ee4665caa5432d9caa653b74605117632ac045955912e624d149524 +// Source hash: 11704f512a9b6e0c5ac178a9917e03a05ea10a7878ef9b5c0a6695d52c9cd7f5 // DO NOT EDIT package builds @@ -98,6 +98,7 @@ var generatedSchemaJSON = `{ ], "optional": [ "digest", + "manifest-list-digest", "tags", "comment", "additional-images" @@ -108,6 +109,11 @@ var generatedSchemaJSON = `{ "type": "string", "title": "Digest" }, + "manifest-list-digest": { + "$id": "#/image/manifest-list-digest", + "type": "string", + "title": "Manifest List Digest" + }, "comment": { "$id": "#/image/comment", "type": "string", diff --git a/src/cmd-coreos-prune b/src/cmd-coreos-prune index 767eaa1df0..7c5690f56e 100755 --- a/src/cmd-coreos-prune +++ b/src/cmd-coreos-prune @@ -55,7 +55,7 @@ Build = collections.namedtuple("Build", ["id", "images", "arch", "meta_json"]) # set metadata caching to 5m CACHE_MAX_AGE_METADATA = 60 * 5 # These lists are up to date as of schema hash -# 4289a52f5ee4665caa5432d9caa653b74605117632ac045955912e624d149524. If changing +# 11704f512a9b6e0c5ac178a9917e03a05ea10a7878ef9b5c0a6695d52c9cd7f5. If changing # this hash, ensure that the list of SUPPORTED and UNSUPPORTED artifacts below # is up to date. SUPPORTED = ["amis", "aws-winli", "gcp"] diff --git a/src/cmd-push-container-manifest b/src/cmd-push-container-manifest index 1f313ba199..2256195bf0 100755 --- a/src/cmd-push-container-manifest +++ b/src/cmd-push-container-manifest @@ -103,7 +103,7 @@ def main(): return # Create/Upload the manifest list to the container registry - manifest_info = create_and_push_container_manifest( + manifest_digest, manifest_info = create_and_push_container_manifest( args.repo, args.tags, images, args.write_digest_to_file, args.v2s2) # if we pushed in v2s2 mode, we need to reload from the repo the actual # final digests: https://github.com/containers/podman/issues/16603 @@ -125,6 +125,7 @@ def main(): image = { 'image': args.repo, 'digest': manifest['digest'], + 'manifest-list-digest': manifest_digest, 'tags': args.tags } if buildmetas[arch].get(args.metajsonname): diff --git a/src/cmd-sign b/src/cmd-sign index 3b06845875..80cf584be0 100755 --- a/src/cmd-sign +++ b/src/cmd-sign @@ -75,8 +75,6 @@ def parse_args(): "public keys to use for signature verification", default="/etc/pki/rpm-gpg") robosig.add_argument("--s3-sigstore", help="bucket and prefix to S3 sigstore") - robosig.add_argument("--manifest-list-digest", metavar="ALGO:DIGEST", - help="digest to manifest list to also sign") robosig.add_argument("--verify-only", action='store_true', help="verify only that the sigs are valid and make public") robosig.set_defaults(func=cmd_robosignatory) @@ -313,6 +311,7 @@ def robosign_oci(args, s3, build, gpgkey): # in containers-signature(5) to refer to how users will actually be pulling # the image (which is usually by tag). identities = {} + manifest_list_digest = None for arch in builds.get_build_arches(args.build): build = builds.get_build_meta(args.build, arch) image = build.get('base-oscontainer') @@ -325,15 +324,19 @@ def robosign_oci(args, s3, build, gpgkey): for tag in image['tags']: identity = f"{image['image']}:{tag}" identities.setdefault(identity, []).append(image['digest']) + print(f"Signing for {identity} with digest {image['digest']} ({arch})") + if manifest_list_digest is None: + manifest_list_digest = image.get('manifest-list-digest') # For the manifest list digest, reuse the tags from the x86_64 build. As # mentioned above, it's the same tags on all arches. - if args.manifest_list_digest: + if manifest_list_digest: build = builds.get_build_meta(args.build, 'x86_64') image = build.get('base-oscontainer') for tag in image['tags']: identity = f"{image['image']}:{tag}" - identities[identity].append(args.manifest_list_digest) + identities[identity].append(manifest_list_digest) + print(f"Signing for {identity} with digest {manifest_list_digest} (manifest list)") # add the git commit of ourselves in the signatures for bookkeeping creator = 'coreos-assembler' diff --git a/src/cosalib/container_manifest.py b/src/cosalib/container_manifest.py index a7d8dac367..4fdaee9fec 100644 --- a/src/cosalib/container_manifest.py +++ b/src/cosalib/container_manifest.py @@ -1,4 +1,5 @@ import json +import tempfile from cosalib.cmdlib import runcmd @@ -53,7 +54,7 @@ def delete_local_container_imgref(repo, tag): runcmd(cmd) -def push_container_manifest(repo, tags, write_digest_to_file, v2s2=False): +def push_container_manifest(repo, tags, write_digest_to_file, v2s2=False) -> str: ''' Push manifest to registry @param repo str registry repository @@ -66,14 +67,21 @@ def push_container_manifest(repo, tags, write_digest_to_file, v2s2=False): # to create a manifest with 2 different mediaType. It seems to be # a Quay issue. base_cmd.extend(["--remove-signatures", "-f", "v2s2"]) - if write_digest_to_file: - base_cmd.extend(["--digestfile", write_digest_to_file]) - runcmd(base_cmd + [f"{repo}:{tags[0]}"]) + + with tempfile.NamedTemporaryFile(mode='r+', encoding='utf-8') as f: + runcmd(base_cmd + [f"{repo}:{tags[0]}", "--digestfile", f.name]) + digest = f.read() + if write_digest_to_file: + with open(write_digest_to_file, mode='w', encoding='utf-8') as g: + g.write(digest) + for tag in tags[1:]: runcmd(base_cmd + [f"{repo}:{tag}"]) + return digest + -def create_and_push_container_manifest(repo, tags, images, write_digest_to_file, v2s2) -> dict: +def create_and_push_container_manifest(repo, tags, images, write_digest_to_file, v2s2) -> tuple[str, dict]: ''' Do it all! Create, push, cleanup, and return the final manifest JSON. @param repo str registry repository @@ -85,6 +93,6 @@ def create_and_push_container_manifest(repo, tags, images, write_digest_to_file, # perhaps left over from a previous failed run -> delete delete_local_container_imgref(repo, tags[0]) manifest_info = create_local_container_manifest(repo, tags[0], images) - push_container_manifest(repo, tags, write_digest_to_file, v2s2) + manifest_digest = push_container_manifest(repo, tags, write_digest_to_file, v2s2) delete_local_container_imgref(repo, tags[0]) - return manifest_info + return (manifest_digest, manifest_info) diff --git a/src/v1.json b/src/v1.json index a17b2f07f4..5337efc046 100644 --- a/src/v1.json +++ b/src/v1.json @@ -92,6 +92,7 @@ ], "optional": [ "digest", + "manifest-list-digest", "tags", "comment", "additional-images" @@ -102,6 +103,11 @@ "type": "string", "title": "Digest" }, + "manifest-list-digest": { + "$id": "#/image/manifest-list-digest", + "type": "string", + "title": "Manifest List Digest" + }, "comment": { "$id": "#/image/comment", "type": "string",