From ca579be998c0e30a71c325b89ba13a362a7f397b Mon Sep 17 00:00:00 2001 From: Sahin Yort Date: Mon, 25 Sep 2023 17:13:50 -0700 Subject: [PATCH] fix: add variant to manifest entry (#368) --- oci/private/pull.bzl | 62 ++++++------------------------------------- oci/private/util.bzl | 41 +++++++++++++++++++++++++++- oci/tests/BUILD.bazel | 25 ++++++++++------- 3 files changed, 63 insertions(+), 65 deletions(-) diff --git a/oci/private/pull.bzl b/oci/private/pull.bzl index a45c5841..347008dd 100644 --- a/oci/private/pull.bzl +++ b/oci/private/pull.bzl @@ -329,23 +329,6 @@ load("@bazel_skylib//rules:write_file.bzl", "write_file") package(default_visibility = ["//visibility:public"]) -# Mimic the output of crane pull [image] layout --format=oci -write_file( - name = "write_layout", - out = "oci-layout", - content = [ - "{{", - " \\"imageLayoutVersion\\": \\"1.0.0\\"", - "}}", - ], -) - -write_file( - name = "write_index", - out = "index.json", - content = [\"\"\"{index_content}\"\"\"], -) - copy_file( name = "manifest", src = "manifest.json", @@ -373,7 +356,6 @@ copy_to_directory( "index.json", ], ) - """ def _find_platform_manifest(image_mf, platform_wanted): @@ -427,45 +409,17 @@ def _oci_pull_impl(rctx): if hash not in tars: tars.append(hash) - # To make testing against `crane pull` simple, we take care to produce a byte-for-byte-identical - # index.json file, which means we can't use jq (it produces a trailing newline) or starlark - # json.encode_indent (it re-orders keys in the dictionary). - if rctx.attr.platform: - os, arch = rctx.attr.platform.split("/", 1) - index_mf = """\ -{ - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.index.v1+json", - "manifests": [ - { - "mediaType": "%s", - "size": %s, - "digest": "%s", - "platform": { - "architecture": "%s", - "os": "%s" - } - } - ] -}""" % (image_mf["mediaType"], image_mf_len, image_digest, arch, os) - else: - index_mf = """\ -{ - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.index.v1+json", - "manifests": [ - { - "mediaType": "%s", - "size": %s, - "digest": "%s" - } - ] -}""" % (image_mf["mediaType"], image_mf_len, image_digest) - + rctx.file("index.json", util.build_manifest_json( + media_type = image_mf["mediaType"], + size = image_mf_len, + digest = image_digest, + platform = rctx.attr.platform + )) + rctx.file("oci-layout", json.encode_indent({"imageLayoutVersion": "1.0.0"}, indent = " ")) + rctx.file("BUILD.bazel", content = _build_file.format( target_name = rctx.attr.target_name, tars = tars, - index_content = index_mf, image_digest = _trim_hash_algorithm(image_digest), config_file = image_config_file, )) diff --git a/oci/private/util.bzl b/oci/private/util.bzl index 0662c30f..f3d9f675 100644 --- a/oci/private/util.bzl +++ b/oci/private/util.bzl @@ -118,10 +118,49 @@ def _file_exists(rctx, path): return result.return_code == 0 +_INDEX_JSON_TMPL="""\ +{{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v1+json", + "manifests": [ + {{ + "mediaType": "{}", + "size": {}, + "digest": "{}"{optional_platform} + }} + ] +}}""" + +def _build_manifest_json(media_type, size, digest, platform): + + optional_platform = "" + + if platform: + platform_parts = platform.split("/", 3) + + optional_variant = "" + if len(platform_parts) == 3: + optional_variant = ''', + "variant": "{}"'''.format(platform_parts[2]) + + optional_platform = """, + "platform": {{ + "architecture": "{}", + "os": "{}"{optional_variant} + }}""".format(platform_parts[1], platform_parts[0], optional_variant = optional_variant) + + return _INDEX_JSON_TMPL.format( + media_type, + size, + digest, + optional_platform = optional_platform + ) + util = struct( parse_image = _parse_image, sha256 = _sha256, warning = _warning, maybe_wrap_launcher_for_windows = _maybe_wrap_launcher_for_windows, - file_exists = _file_exists + file_exists = _file_exists, + build_manifest_json = _build_manifest_json ) diff --git a/oci/tests/BUILD.bazel b/oci/tests/BUILD.bazel index 882e6d3a..00e0ba7d 100644 --- a/oci/tests/BUILD.bazel +++ b/oci/tests/BUILD.bazel @@ -2,13 +2,16 @@ load("@aspect_bazel_lib//lib:diff_test.bzl", "diff_test") load("@bazel_skylib//rules:build_test.bzl", "build_test") load(":pull_tests.bzl", "parse_image_test") -_PLATFORM = "linux/amd64" - IMAGES_TO_TEST = { - "distroless_java": "gcr.io/distroless/java17@sha256:161a1d97d592b3f1919801578c3a47c8e932071168a96267698f4b669c24c76d", - "distroless_static_linux_amd64": "gcr.io/distroless/static@sha256:c3c3d0230d487c0ad3a0d87ad03ee02ea2ff0b3dcce91ca06a1019e07de05f12", - "fluxcd_flux_single": "docker.io/fluxcd/flux:1.25.4", - "chainguard_static_linux_amd64": "cgr.dev/chainguard/static:latest", + "linux/amd64": { + "distroless_java": "gcr.io/distroless/java17@sha256:161a1d97d592b3f1919801578c3a47c8e932071168a96267698f4b669c24c76d", + "distroless_static_linux_amd64": "gcr.io/distroless/static@sha256:c3c3d0230d487c0ad3a0d87ad03ee02ea2ff0b3dcce91ca06a1019e07de05f12", + "fluxcd_flux_single": "docker.io/fluxcd/flux:1.25.4", + "chainguard_static_linux_amd64": "cgr.dev/chainguard/static:latest", + }, + "linux/arm64/v8": { + "ubuntu_linux_arm64_v8": "ubuntu@sha256:67211c14fa74f070d27cc59d69a7fa9aeff8e28ea118ef3babc295a0428a6d21" + } } # Use crane to pull images as a comparison for our oci_pull repository rule @@ -17,12 +20,12 @@ IMAGES_TO_TEST = { name = "pull_{}".format(repo_name), outs = [repo_name], cmd = "$(CRANE_BIN) pull {reference} $@ --format=oci --platform={platform}".format( - platform = _PLATFORM, + platform = platform, reference = reference, ), local = True, # needs to run locally to able to use credential helpers message = "Pulling {reference} for {platform}".format( - platform = _PLATFORM, + platform = platform, reference = reference, ), output_to_bindir = True, @@ -32,7 +35,8 @@ IMAGES_TO_TEST = { ], visibility = ["//visibility:public"], ) - for repo_name, reference in IMAGES_TO_TEST.items() + for platform in IMAGES_TO_TEST.keys() + for repo_name, reference in IMAGES_TO_TEST[platform].items() ] [ @@ -43,7 +47,8 @@ IMAGES_TO_TEST = { repo_name, ), ) - for repo_name, reference in IMAGES_TO_TEST.items() + for platform in IMAGES_TO_TEST.keys() + for repo_name, reference in IMAGES_TO_TEST[platform].items() ] # assert than we don't break fetching these