From 17ac718e18b2e6fc1aa6e3e974ec383af9f1a015 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Wed, 4 Oct 2023 11:00:11 -0700 Subject: [PATCH] fix: supply mtree file for determinism --- oci/private/tarball.bzl | 21 +++++++++++++++------ oci/private/tarball.sh.tpl | 8 ++++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/oci/private/tarball.bzl b/oci/private/tarball.bzl index 93041106..456e81d9 100644 --- a/oci/private/tarball.bzl +++ b/oci/private/tarball.bzl @@ -51,13 +51,14 @@ def _tarball_impl(ctx): yq_bin = ctx.toolchains["@aspect_bazel_lib//lib:yq_toolchain_type"].yqinfo.bin bsdtar = ctx.toolchains["@aspect_bazel_lib//lib:tar_toolchain_type"] executable = ctx.actions.declare_file("{}/tarball.sh".format(ctx.label.name)) + mtree = ctx.actions.declare_file("_{}.mtree".format(ctx.label.name)) repo_tags = ctx.file.repo_tags substitutions = { "{{yq}}": yq_bin.path, "{{tar}}": bsdtar.tarinfo.binary.path, "{{image_dir}}": image.path, - "{{tarball_path}}": tarball.path, + "{{mtree_out}}": mtree.path, } if ctx.attr.repo_tags: @@ -72,16 +73,24 @@ def _tarball_impl(ctx): ctx.actions.run( executable = util.maybe_wrap_launcher_for_windows(ctx, executable), - inputs = depset( - direct = [image, repo_tags, executable], - transitive = [bsdtar.default.files], - ), - outputs = [tarball], + inputs = [image, repo_tags, executable], + outputs = [mtree], tools = [yq_bin], mnemonic = "OCITarball", progress_message = "OCI Tarball %{label}", ) + # TODO(2.0): this oci_tarball rule should just produce an mtree manifest instead, + # and then the tar rule can be composed in the oci_tarball macro in defs.bzl. + # To make it a non-breaking change, call the tar action ourselves instead. + ctx.actions.run( + executable = bsdtar.tarinfo.binary, + inputs = depset(direct = [mtree], transitive = [bsdtar.default.files]), + outputs = [tarball], + arguments = ["--create", "-C", "STAGING_DIR", "--file", "TARBALL_PATH", "@" + mtree.path], + mnemonic = "Tar", + ) + exe = ctx.actions.declare_file(ctx.label.name + ".sh") ctx.actions.expand_template( diff --git a/oci/private/tarball.sh.tpl b/oci/private/tarball.sh.tpl index ca42f691..b9bb326c 100644 --- a/oci/private/tarball.sh.tpl +++ b/oci/private/tarball.sh.tpl @@ -6,7 +6,7 @@ readonly YQ="{{yq}}" readonly TAR="{{tar}}" readonly IMAGE_DIR="{{image_dir}}" readonly BLOBS_DIR="${STAGING_DIR}/blobs" -readonly TARBALL_PATH="{{tarball_path}}" +readonly OUT="{{mtree_out}}" readonly TAGS_FILE="{{tags}}" MANIFEST_DIGEST=$(${YQ} eval '.manifests[0].digest | sub(":"; "/")' "${IMAGE_DIR}/index.json" | tr -d '"') @@ -35,4 +35,8 @@ layers="${LAYERS}" \ --null-input '.[0] = {"Config": env(config), "RepoTags": "${repo_tags}" | envsubst | split("%") | map(select(. != "")) , "Layers": env(layers) | map( "blobs/" + . + ".tar.gz") }' \ --output-format json > "${STAGING_DIR}/manifest.json" -${TAR} -C "${STAGING_DIR}" -cf "${TARBALL_PATH}" manifest.json blobs +# Write output in mtree format +# https://man.freebsd.org/cgi/man.cgi?mtree(8) +# so that tar produces a deterministic output. +echo "${STAGING_DIR}/manifest.json uid=0 gid=0 mode=0755 type=file">>${OUT} +echo "blobs uid=0 gid=0 mode=0755 type=dir">>${OUT}