diff --git a/.bazelrc b/.bazelrc index a36455a9..a92e35fa 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,12 +1,15 @@ # Bazel settings that apply to this repository. # Take care to document any settings that you expect users to apply. # Settings that apply only to CI are in .github/workflows/ci.bazelrc +common --enable_platform_specific_config build --incompatible_strict_action_env build --nolegacy_external_runfiles common --test_env=DOCKER_HOST --action_env=DOCKER_HOST --repo_env=DOCKER_HOST +common:windows --test_env=APPDATA --action_env=APPDATA --repo_env=APPDATA +common:windows --test_env=PROGRAMDATA --action_env=PROGRAMDATA --repo_env=PROGRAMDATA -# On bazel 6.4.0 these are needed to successfully fetch images. +# On bazel 6.5.0 these are needed to successfully fetch images. common:needs_credential_helpers --credential_helper=public.ecr.aws=%workspace%/examples/credential_helper/auth.sh common:needs_credential_helpers --credential_helper=index.docker.io=%workspace%/examples/credential_helper/auth.sh common:needs_credential_helpers --credential_helper=docker.elastic.co=%workspace%/examples/credential_helper/auth.sh @@ -17,6 +20,14 @@ common:needs_credential_helpers --credential_helper_cache_duration=0 # https://bazelbuild.slack.com/archives/C014RARENH0/p1691158021917459?thread_ts=1691156601.420349&cid=C014RARENH0 common --check_direct_dependencies=off +# Symlinks are pretty much required on windows so enable by default +startup --windows_enable_symlinks + +# Point tools such as coursier (used in rules_jvm_external) to Bazel's downloaded JDK +# suggested in https://github.com/bazelbuild/rules_jvm_external/issues/445 +common --repo_env=JAVA_HOME=../bazel_tools/jdk +common --action_env=JAVA_HOME=../bazel_tools/jdk + # Load any settings specific to the current user. # .bazelrc.user should appear in .gitignore so that settings are not shared with team members # This needs to be last statement in this diff --git a/.bazelversion b/.bazelversion index 01f266ec..6e1107e4 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1,4 +1,4 @@ -7.4.1 +7.6.1 # The first line of this file is used by Bazelisk and Bazel to be sure # the right version of Bazel is used to build and test this repo. diff --git a/.bcr/presubmit.yml b/.bcr/presubmit.yml index dedf0607..acdf5f05 100644 --- a/.bcr/presubmit.yml +++ b/.bcr/presubmit.yml @@ -2,8 +2,7 @@ bcr_test_module: module_path: "e2e/smoke" matrix: bazel: ["6.x", "7.x"] - # TODO(#97): add windows - platform: ["debian10", "ubuntu2004"] + platform: ["debian10", "ubuntu2004", "windows"] tasks: test_linux: name: "Run test module" @@ -19,3 +18,9 @@ bcr_test_module: - "//..." # This test requires a docker daemon, not available on BCR CI - "-//:test" + test_windows: + name: "Run test module" + bazel: ${{ bazel }} + platform: windows + test_targets: + - "//..." diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 93f41ceb..06c6e487 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,47 +18,46 @@ concurrency: cancel-in-progress: ${{ github.ref_name != 'main' }} jobs: - matrix-prep-bazelversion: - # Prepares the 'bazelversion' axis of the test matrix - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - id: bazel_7 - run: echo "bazelversion=$(head -n 1 .bazelversion)" >> $GITHUB_OUTPUT - - id: bazel_6 - run: echo "bazelversion=6.4.0" >> $GITHUB_OUTPUT - outputs: - # Will look like ["", "6.4.0"] - bazelversions: ${{ toJSON(steps.*.outputs.bazelversion) }} - - matrix-prep-os: - # Prepares the 'os' axis of the test matrix + matrix-prep: runs-on: ubuntu-latest env: TC_CLOUD_TOKEN: ${{ secrets.TC_CLOUD_TOKEN }} steps: + - uses: actions/checkout@v4 + - id: bazel-version + name: Prepare 'bazel-version' matrix axis + run: | + v=$(head -n 1 .bazelversion) + m=${v::1} + a=( + "major:$m, version:\"$v\"" + "major:6, version:\"6.5.0\"" + ) + printf -v j '{%s},' "${a[@]}" + echo "res=[${j%,}]" | tee -a $GITHUB_OUTPUT - id: linux - run: echo "os=ubuntu-latest" >> $GITHUB_OUTPUT + run: echo "os=ubuntu" >> $GITHUB_OUTPUT - id: macos - run: echo "os=macos-13" >> $GITHUB_OUTPUT + run: echo "os=macos" >> $GITHUB_OUTPUT # Don't run MacOS if there is no TestContainers API token which is the case on forks. We need it for container tests. if: ${{ env.TC_CLOUD_TOKEN != '' }} + - id: windows + run: echo "os=windows" >> $GITHUB_OUTPUT outputs: - # Will look like ["ubuntu-latest", "macos-13"] + bazel-version: ${{ steps.bazel-version.outputs.res }} + # Will look like ["ubuntu", "macos", "windows"] os: ${{ toJSON(steps.*.outputs.os) }} test: - # The type of runner that the job will run on - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.os }}-latest needs: - - matrix-prep-bazelversion - - matrix-prep-os - + - matrix-prep strategy: fail-fast: false matrix: - os: ${{ fromJSON(needs.matrix-prep-os.outputs.os) }} - bazelversion: ${{ fromJSON(needs.matrix-prep-bazelversion.outputs.bazelversions) }} + bazel-version: ${{ fromJSON(needs.matrix-prep.outputs.bazel-version) }} + bzlmod: [1, 0] + os: ${{ fromJSON(needs.matrix-prep.outputs.os) }} folder: - . - e2e/wasm @@ -66,34 +65,46 @@ jobs: - e2e/assertion - examples/dockerfile - bzlmodEnabled: [true, false] exclude: - # macos is expensive (billed at 10X) so don't test these - - os: macos-13 - folder: e2e/wasm - - os: macos-13 - folder: e2e/assertion - - os: macos-13 - bazelversion: 6.4.0 + # Don't test MacOS and Windows against secondary bazel version to minimize minutes (billed at 10X and 2X respectively) + # https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#included-storage-and-minutes + - os: macos + bazel-version: + major: 6 + - os: windows + bazel-version: + major: 6 + # Root workspace. Requires bzlmod and bazel 7+. Ubuntu-bazel-7 is tested on Buildkite using Aspect Workflows - folder: . - bazelversion: 6.4.0 + bzlmod: 0 + - folder: . + bazel-version: + major: 6 + - folder: . + bazel-version: + major: 7 + os: ubuntu + # examples/dockerfile. Requires bzlmod and bazel 7+. Skip windows (todo: buildx not supported) - folder: examples/dockerfile - bzlmodEnabled: false + bzlmod: 0 - folder: examples/dockerfile - bazelversion: 6.4.0 - # e2e/assertion is bzlmod only but it has test for both cases. + bazel-version: + major: 6 + - folder: examples/dockerfile + os: windows + # e2e/assertion. Requires bzlmod. Skip macos (save CI minutes). Skip windows (BATS tests don't work reliably) + - folder: e2e/assertion + bzlmod: 0 - folder: e2e/assertion - bzlmodEnabled: false - # TODO: fix + os: macos + # e2e/wasm. Requires workspace (todo: bzlmod). Skip macos (save CI minutes). Skip windows (todo: configure WASM C++ toolchains on Windows) - folder: e2e/wasm - bzlmodEnabled: true - # Don't test the root module with WORKSPACE at all - - folder: . - bzlmodEnabled: false - # This is tested on Buildkite using Aspect Workflows - - bazelversion: 7.4.1 - folder: . - os: ubuntu-latest + bzlmod: 1 + - folder: e2e/wasm + os: macos + - folder: e2e/wasm + os: windows + # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it @@ -103,9 +114,9 @@ jobs: with: path: | ~/.cache/bazel-repo - key: bazel-cache-${{ matrix.os }}-${{ matrix.folder }}-${{ matrix.bazelversion }}-${{ hashFiles('**/BUILD.bazel', '**/*.bzl', 'WORKSPACE', 'WORKSPACE.bzlmod','MODULE.bzl') }} + key: bazel-cache-${{ matrix.os }}-${{ matrix.folder }}-${{ matrix.bazel-version }}-${{ hashFiles('**/BUILD.bazel', '**/*.bzl', 'WORKSPACE', 'WORKSPACE.bzlmod','MODULE.bzl') }} restore-keys: | - bazel-cache-${{ matrix.os }}-${{ matrix.folder }}-${{ matrix.bazelversion }} + bazel-cache-${{ matrix.os }}-${{ matrix.folder }}-${{ matrix.bazel-version }} bazel-cache-${{ matrix.os }}-${{ matrix.folder }} bazel-cache-${{ matrix.os }} bazel-cache- @@ -114,37 +125,38 @@ jobs: # Store the --enable_bzlmod flag that we add to the test command below # only when we're running bzlmod in our test matrix. id: set_bzlmod_flag - if: matrix.bzlmodEnabled + if: matrix.bzlmod == '1' run: echo "bzlmod_flag=--enable_bzlmod" >> $GITHUB_OUTPUT - name: Set credential helpers flag # Add --config needs_credential_helpers to add additional credential helpers # to fetch from registries with HTTP headers set by credential helpers. id: set_credential_helper_flag - if: matrix.bazelversion == '6.4.0' && matrix.folder == '.' + if: matrix.bazel-version == '6.5.0' && matrix.folder == '.' run: echo "credential_helper_flag=--config=needs_credential_helpers" >> $GITHUB_OUTPUT - name: Setup crane for credential helpers to use uses: imjasonh/setup-crane@v0.3 - if: matrix.bazelversion == '6.4.0' && matrix.folder == '.' + if: matrix.bazel-version == '6.5.0' && matrix.folder == '.' with: version: "v0.19.1" - name: Configure Bazel version working-directory: ${{ matrix.folder }} - run: echo "${{ matrix.bazelversion }}" > .bazelversion + run: echo "${{ matrix.bazel-version.version }}" > .bazelversion - name: Configure TestContainers cloud - if: ${{ matrix.os == 'macos-13' }} + if: ${{ matrix.os == 'macos' }} uses: atomicjar/testcontainers-cloud-setup-action@main with: wait: true token: ${{ secrets.TC_CLOUD_TOKEN }} - - run: man xargs + # this causes windows failure; why is this here? + # - run: man xargs - name: Configure Remote Docker Host - if: ${{ matrix.os == 'macos-13' }} + if: ${{ matrix.os == 'macos' }} run: | echo "DOCKER_HOST=$(grep 'tc.host' ~/.testcontainers.properties | cut -d '=' -f2 | xargs)" >> $GITHUB_ENV curl -fsSL https://download.docker.com/mac/static/stable/x86_64/docker-23.0.0.tgz | tar -xOvf - docker/docker > /usr/local/bin/docker @@ -152,6 +164,7 @@ jobs: - name: bazel test //... working-directory: ${{ matrix.folder }} + shell: bash run: | bazel \ --bazelrc=$GITHUB_WORKSPACE/.github/workflows/ci.bazelrc \ diff --git a/MODULE.bazel b/MODULE.bazel index e6371521..8a675ebb 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -2,13 +2,17 @@ module( name = "rules_oci", + # align with https://github.com/bazel-contrib/bazel-lib/pull/1160 + bazel_compatibility = [">=6.5.0"], compatibility_level = 1, ) -bazel_dep(name = "aspect_bazel_lib", version = "2.7.2") +bazel_dep(name = "aspect_bazel_lib", version = "2.21.2") bazel_dep(name = "bazel_features", version = "1.10.0") bazel_dep(name = "bazel_skylib", version = "1.8.1") bazel_dep(name = "platforms", version = "0.0.8") +bazel_dep(name = "tar.bzl", version = "0.5.6") +bazel_dep(name = "jq.bzl", version = "0.4.0") oci = use_extension("//oci:extensions.bzl", "oci") oci.toolchains() @@ -23,10 +27,11 @@ use_repo(zstd, "zstd_toolchains") register_toolchains("@zstd_toolchains//:all") -bazel_lib = use_extension("@aspect_bazel_lib//lib:extensions.bzl", "toolchains") -bazel_lib.jq() -bazel_lib.tar() -use_repo(bazel_lib, "bsd_tar_toolchains", "jq_toolchains") +jq_toolchains = use_extension("@jq.bzl//jq:extensions.bzl", "toolchains") +use_repo(jq_toolchains, "jq_toolchains") + +tar_toolchains = use_extension("@tar.bzl//tar:extensions.bzl", "toolchains") +use_repo(tar_toolchains, "bsd_tar_toolchains") # Dev dependencies diff --git a/cosign/private/attest.bzl b/cosign/private/attest.bzl index 02489442..1a041fc9 100644 --- a/cosign/private/attest.bzl +++ b/cosign/private/attest.bzl @@ -1,5 +1,9 @@ "Implementation details for attest rule" +load("@aspect_bazel_lib//lib:paths.bzl", "BASH_RLOCATION_FUNCTION", "to_rlocation_path") +load("@aspect_bazel_lib//lib:windows_utils.bzl", "create_windows_native_launcher_script") +load("//oci/private:util.bzl", "is_windows_exec", "IS_EXEC_PLATFORM_WINDOWS_ATTRS") + _DOC = """Attest an oci_image using cosign binary at a remote registry. ```starlark @@ -52,42 +56,46 @@ _attrs = { Digests and tags are not allowed. If this attribute is not set, the repository must be passed at runtime via the `--repository` flag. """), "_attest_sh_tpl": attr.label(default = "attest.sh.tpl", allow_single_file = True), -} + "_runfiles": attr.label(default = "@bazel_tools//tools/bash/runfiles"), +} | IS_EXEC_PLATFORM_WINDOWS_ATTRS def _cosign_attest_impl(ctx): cosign = ctx.toolchains["@rules_oci//cosign:toolchain_type"] - jq = ctx.toolchains["@aspect_bazel_lib//lib:jq_toolchain_type"] + jq = ctx.toolchains["@jq.bzl//jq/toolchain:type"] if ctx.attr.repository and (ctx.attr.repository.find(":") != -1 or ctx.attr.repository.find("@") != -1): fail("repository attribute should not contain digest or tag.") fixed_args = [ "--predicate", - ctx.file.predicate.short_path, + to_rlocation_path(ctx, ctx.file.predicate), "--type", ctx.attr.type, ] if ctx.attr.repository: fixed_args.extend(["--repository", ctx.attr.repository]) - executable = ctx.actions.declare_file("cosign_attest_{}.sh".format(ctx.label.name)) + bash_launcher = ctx.actions.declare_file("cosign_attest_{}.sh".format(ctx.label.name)) ctx.actions.expand_template( template = ctx.file._attest_sh_tpl, - output = executable, + output = bash_launcher, is_executable = True, substitutions = { - "{{cosign_path}}": cosign.cosign_info.binary.short_path, - "{{jq_path}}": jq.jqinfo.bin.short_path, - "{{image_dir}}": ctx.file.image.short_path, + "{{BASH_RLOCATION_FUNCTION}}": BASH_RLOCATION_FUNCTION, + "{{cosign_path}}": to_rlocation_path(ctx, cosign.cosign_info.binary), + "{{jq_path}}": to_rlocation_path(ctx, jq.jqinfo.bin), + "{{image_dir}}": to_rlocation_path(ctx, ctx.file.image), "{{fixed_args}}": " ".join(fixed_args), "{{type}}": ctx.attr.type, }, ) - runfiles = ctx.runfiles(files = [ctx.file.image, ctx.file.predicate]) + executable = create_windows_native_launcher_script(ctx, bash_launcher) if is_windows_exec(ctx) else bash_launcher + runfiles = ctx.runfiles(files = [ctx.file.image, ctx.file.predicate, bash_launcher]) runfiles = runfiles.merge(ctx.attr.image[DefaultInfo].default_runfiles) runfiles = runfiles.merge(jq.default.default_runfiles) runfiles = runfiles.merge(cosign.default.default_runfiles) + runfiles = runfiles.merge(ctx.attr._runfiles.default_runfiles) return DefaultInfo(executable = executable, runfiles = runfiles) @@ -97,7 +105,8 @@ cosign_attest = rule( doc = _DOC, executable = True, toolchains = [ + "@bazel_tools//tools/sh:toolchain_type", "@rules_oci//cosign:toolchain_type", - "@aspect_bazel_lib//lib:jq_toolchain_type", + "@jq.bzl//jq/toolchain:type", ], ) diff --git a/cosign/private/attest.sh.tpl b/cosign/private/attest.sh.tpl index 005a59bc..366bfa7b 100644 --- a/cosign/private/attest.sh.tpl +++ b/cosign/private/attest.sh.tpl @@ -1,9 +1,11 @@ #!/usr/bin/env bash set -o pipefail -o errexit -o nounset -readonly COSIGN="{{cosign_path}}" -readonly JQ="{{jq_path}}" -readonly IMAGE_DIR="{{image_dir}}" +{{BASH_RLOCATION_FUNCTION}} + +readonly COSIGN="$(rlocation "{{cosign_path}}")" +readonly JQ="$(rlocation "{{jq_path}}")" +readonly IMAGE_DIR="$(rlocation "{{image_dir}}")" readonly DIGEST=$("${JQ}" -r '.manifests[].digest' "${IMAGE_DIR}/index.json") readonly FIXED_ARGS=({{fixed_args}}) @@ -15,11 +17,14 @@ fi REPOSITORY="" ARGS=() +PREDICATE="" while (( $# > 0 )); do case "$1" in --repository) shift; REPOSITORY="$1"; shift ;; (--repository=*) REPOSITORY="${1#--repository=}"; shift ;; + --predicate) shift; PREDICATE="$(rlocation "$1")"; shift ;; + (--predicate=*) PREDICATE="$(rlocation "${1#--predicate=}")"; shift ;; *) ARGS+=( "$1" ); shift ;; esac done @@ -29,5 +34,5 @@ if [[ -z "${REPOSITORY}" ]]; then exit 1 fi -exec "${COSIGN}" attest "${REPOSITORY}@${DIGEST}" ${ARGS[@]+"${ARGS[@]}"} +exec "${COSIGN}" attest "${REPOSITORY}@${DIGEST}" --predicate "${PREDICATE}" ${ARGS[@]+"${ARGS[@]}"} diff --git a/cosign/private/sign.bzl b/cosign/private/sign.bzl index 2e478492..c5ba43f2 100644 --- a/cosign/private/sign.bzl +++ b/cosign/private/sign.bzl @@ -1,5 +1,9 @@ "Implementation details for sign rule" +load("@aspect_bazel_lib//lib:paths.bzl", "BASH_RLOCATION_FUNCTION", "to_rlocation_path") +load("@aspect_bazel_lib//lib:windows_utils.bzl", "create_windows_native_launcher_script") +load("//oci/private:util.bzl", "is_windows_exec", "IS_EXEC_PLATFORM_WINDOWS_ATTRS") + _DOC = """Sign an oci_image using cosign binary at a remote registry. It signs the image by its digest determined beforehand. @@ -48,16 +52,17 @@ _attrs = { Digests and tags are not allowed. If this attribute is not set, the repository must be passed at runtime via the `--repository` flag. """), "_sign_sh_tpl": attr.label(default = "sign.sh.tpl", allow_single_file = True), -} + "_runfiles": attr.label(default = "@bazel_tools//tools/bash/runfiles"), +} | IS_EXEC_PLATFORM_WINDOWS_ATTRS def _cosign_sign_impl(ctx): cosign = ctx.toolchains["@rules_oci//cosign:toolchain_type"] - jq = ctx.toolchains["@aspect_bazel_lib//lib:jq_toolchain_type"] + jq = ctx.toolchains["@jq.bzl//jq/toolchain:type"] if ctx.attr.repository and (ctx.attr.repository.find(":") != -1 or ctx.attr.repository.find("@") != -1): fail("repository attribute should not contain digest or tag.") - executable = ctx.actions.declare_file("cosign_sign_{}.sh".format(ctx.label.name)) + bash_launcher = ctx.actions.declare_file("cosign_sign_{}.sh".format(ctx.label.name)) fixed_args = [] if ctx.attr.repository: @@ -65,20 +70,23 @@ def _cosign_sign_impl(ctx): ctx.actions.expand_template( template = ctx.file._sign_sh_tpl, - output = executable, + output = bash_launcher, is_executable = True, substitutions = { - "{{cosign_path}}": cosign.cosign_info.binary.short_path, - "{{jq_path}}": jq.jqinfo.bin.short_path, - "{{image_dir}}": ctx.file.image.short_path, + "{{BASH_RLOCATION_FUNCTION}}": BASH_RLOCATION_FUNCTION, + "{{cosign_path}}": to_rlocation_path(ctx, cosign.cosign_info.binary), + "{{jq_path}}": to_rlocation_path(ctx, jq.jqinfo.bin), + "{{image_dir}}": to_rlocation_path(ctx, ctx.file.image), "{{fixed_args}}": " ".join(fixed_args), }, ) - runfiles = ctx.runfiles(files = [ctx.file.image]) + executable = create_windows_native_launcher_script(ctx, bash_launcher) if is_windows_exec(ctx) else bash_launcher + runfiles = ctx.runfiles(files = [ctx.file.image, bash_launcher]) runfiles = runfiles.merge(ctx.attr.image[DefaultInfo].default_runfiles) runfiles = runfiles.merge(jq.default.default_runfiles) runfiles = runfiles.merge(cosign.default.default_runfiles) + runfiles = runfiles.merge(ctx.attr._runfiles.default_runfiles) return DefaultInfo(executable = executable, runfiles = runfiles) @@ -88,7 +96,8 @@ cosign_sign = rule( doc = _DOC, executable = True, toolchains = [ + "@bazel_tools//tools/sh:toolchain_type", "@rules_oci//cosign:toolchain_type", - "@aspect_bazel_lib//lib:jq_toolchain_type", + "@jq.bzl//jq/toolchain:type", ], ) diff --git a/cosign/private/sign.sh.tpl b/cosign/private/sign.sh.tpl index 83016bd5..594df3e3 100644 --- a/cosign/private/sign.sh.tpl +++ b/cosign/private/sign.sh.tpl @@ -1,9 +1,11 @@ #!/usr/bin/env bash set -o pipefail -o errexit -o nounset -readonly COSIGN="{{cosign_path}}" -readonly JQ="{{jq_path}}" -readonly IMAGE_DIR="{{image_dir}}" +{{BASH_RLOCATION_FUNCTION}} + +readonly COSIGN="$(rlocation "{{cosign_path}}")" +readonly JQ="$(rlocation "{{jq_path}}")" +readonly IMAGE_DIR="$(rlocation "{{image_dir}}")" readonly DIGEST=$("${JQ}" -r '.manifests[].digest' "${IMAGE_DIR}/index.json") readonly FIXED_ARGS=({{fixed_args}}) diff --git a/cosign/private/versions.bzl b/cosign/private/versions.bzl index 5f29c277..2e5ab26b 100644 --- a/cosign/private/versions.bzl +++ b/cosign/private/versions.bzl @@ -9,6 +9,8 @@ COSIGN_VERSIONS = { "linux-arm64": "sha256-VqFkgL3VbseJq6plkkQC9rksAEHwaIWZWFPAVWe3bzQ=", "linux-ppc64le": "sha256-vn642hpl2gu7YaEVp+E88FsjN57pdpFZl0uK1pDU8Fc=", "linux-s390x": "sha256-6AybLpHQBp2XqQabBcR9yj+eGbRlLEx+bKMx14e6CXI=", + "windows-amd64": "sha256-BJAm2uMkbW6oIBUS7D7846qwx/HTONUuJsUl3QK0GKA=", + "windows-arm64": "sha256-ABnfxLMtY8E5KqJkrtIlPB4ML7CSFvjizCabv7i7SbU=", }, "v2.2.3": { "darwin-amd64": "sha256-JCn0sCf8MRpjJOnbb7OpN9VZ3GHekGocLQ0eBnFoXkw=", @@ -18,6 +20,8 @@ COSIGN_VERSIONS = { "linux-arm64": "sha256-sIjWdvDAEjuMNI4Y1CHPlmAg7cSXekhhFaEmQ96pmj8=", "linux-ppc64le": "sha256-IaAWkdvfyzUbTpTM9QGk6HNyLPX+b2epc172bstBlB0=", "linux-s390x": "sha256-1yzyiRkNKMacuVxeMhOaoZgf/KCoQyfImgErsfOoBR0=", + "windows-amd64": "sha256-9/Jy1WxYCw7Jb1m/6fiOxfQrbhld8AnONBdCjg4N6tE=", + "windows-arm64": "sha256-Adj8SzLWM8E5KqJkrtIlPB4ML7CSFvjizCabs7i7SbU=", }, "v2.0.2": { "darwin-amd64": "sha256-D1HL4ZoxW5GehwQvBIUzGCFyLst/ziLMG4gO1IM/yLA=", diff --git a/cosign/repositories.bzl b/cosign/repositories.bzl index 027a1040..dcc24644 100644 --- a/cosign/repositories.bzl +++ b/cosign/repositories.bzl @@ -20,6 +20,8 @@ def _cosign_repo_impl(repository_ctx): version = repository_ctx.attr.cosign_version, platform = platform, ) + if ("windows" in repository_ctx.attr.platform): + url += ".exe" repository_ctx.download( url = url, output = "cosign", diff --git a/docs/compare_dockerfile.md b/docs/compare_dockerfile.md index fb0c626d..a2f8b4b3 100644 --- a/docs/compare_dockerfile.md +++ b/docs/compare_dockerfile.md @@ -65,7 +65,7 @@ oci_pull( 2. Replace `COPY` with `tar`. ```starlark -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") tar( name = "web_assets", @@ -77,7 +77,7 @@ tar( 3. The resulting `BUILD` file would look like: ```starlark -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") tar( name = "web_assets", diff --git a/docs/image.md b/docs/image.md index 9fcc7166..1c5e9b60 100644 --- a/docs/image.md +++ b/docs/image.md @@ -11,6 +11,8 @@ load("@rules_oci//oci:defs.bzl", ...) ## oci_image_rule
+load("@rules_oci//oci:defs.bzl", "oci_image_rule")
+
 oci_image_rule(name, annotations, architecture, base, cmd, created, entrypoint, env, exposed_ports,
                labels, os, resource_set, tars, user, variant, volumes, workdir)
 
@@ -91,6 +93,8 @@ oci_image( ## oci_image
+load("@rules_oci//oci:defs.bzl", "oci_image")
+
 oci_image(name, created, labels, annotations, env, cmd, entrypoint, exposed_ports, volumes, kwargs)
 
diff --git a/docs/image_index.md b/docs/image_index.md index b9351494..d217229c 100644 --- a/docs/image_index.md +++ b/docs/image_index.md @@ -11,6 +11,8 @@ load("@rules_oci//oci:defs.bzl", ...) ## oci_image_index_rule
+load("@rules_oci//oci:defs.bzl", "oci_image_index_rule")
+
 oci_image_index_rule(name, images, platforms)
 
@@ -86,6 +88,8 @@ oci_image_index( ## oci_image_index
+load("@rules_oci//oci:defs.bzl", "oci_image_index")
+
 oci_image_index(name, kwargs)
 
diff --git a/docs/load.md b/docs/load.md index 67fbdc92..2391b099 100644 --- a/docs/load.md +++ b/docs/load.md @@ -25,6 +25,8 @@ docker run --rm my-repository:latest ## oci_load
+load("@rules_oci//oci/private:load.bzl", "oci_load")
+
 oci_load(name, format, image, loader, repo_tags)
 
diff --git a/docs/pull.md b/docs/pull.md index 2301c66e..1dc2a26c 100644 --- a/docs/pull.md +++ b/docs/pull.md @@ -161,6 +161,8 @@ In this example, we provide a `www_authenticate_challenges` attribute to the `oc ## oci_pull
+load("@rules_oci//oci:pull.bzl", "oci_pull")
+
 oci_pull(name, www_authenticate_challenges, image, repository, registry, platforms, digest, tag,
          reproducible, is_bzlmod, config, bazel_tags)
 
diff --git a/docs/push.md b/docs/push.md index 89ce6196..05e7e5dd 100644 --- a/docs/push.md +++ b/docs/push.md @@ -11,6 +11,8 @@ load("@rules_oci//oci:defs.bzl", ...) ## oci_push_rule
+load("@rules_oci//oci:defs.bzl", "oci_push_rule")
+
 oci_push_rule(name, image, remote_tags, repository, repository_file)
 
@@ -167,6 +169,8 @@ multirun( ## oci_push
+load("@rules_oci//oci:defs.bzl", "oci_push")
+
 oci_push(name, remote_tags, kwargs)
 
diff --git a/docs/scala.md b/docs/scala.md index 4a9f6c5f..d41e4bd6 100644 --- a/docs/scala.md +++ b/docs/scala.md @@ -20,7 +20,7 @@ object App { ``` In this example, I will not use bzlmod and fall back to the `WORKSPACE` file, as `rules_scala` doesn't support bzlmod yet. This file setups -the `rules_scala` according to the documentation so that we can build scala targets. Next, it configures `aspect_bazel_lib` so that we can have access to `tar` rule needed later. Finally, it configures `rules_oci` and pulls the base image with Java 17. +the `rules_scala` according to the documentation so that we can build scala targets. Next, it configures `bazel_lib` so that we can have access to `tar` rule needed later. Finally, it configures `rules_oci` and pulls the base image with Java 17. **WORKSPACE** @@ -72,21 +72,21 @@ scalatest_repositories() scalatest_toolchain() http_archive( - name = "aspect_bazel_lib", + name = "bazel_lib", sha256 = "6d758a8f646ecee7a3e294fbe4386daafbe0e5966723009c290d493f227c390b", strip_prefix = "bazel-lib-2.7.7", url = "https://github.com/aspect-build/bazel-lib/releases/download/v2.7.7/bazel-lib-v2.7.7.tar.gz", ) -load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies", "aspect_bazel_lib_register_toolchains") +load("@aspect_bazel_lib//lib:repositories.bzl", "bazel_lib_dependencies", "bazel_lib_register_toolchains") # Required bazel-lib dependencies -aspect_bazel_lib_dependencies() +bazel_lib_dependencies() # Register bazel-lib toolchains -aspect_bazel_lib_register_toolchains() +bazel_lib_register_toolchains() http_archive( name = "rules_oci", @@ -133,7 +133,7 @@ scala_binary( After that, we can package that binary into a layer using `tar` ```python -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") tar( name = "layer", @@ -181,7 +181,7 @@ Complete `BUILD.bazel` file ```python load("@io_bazel_rules_scala//scala:scala.bzl", "scala_binary") -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") load("@rules_oci//oci:defs.bzl", "oci_image", "oci_load") scala_binary( diff --git a/e2e/assertion/MODULE.bazel b/e2e/assertion/MODULE.bazel index 17b01bff..8796682b 100644 --- a/e2e/assertion/MODULE.bazel +++ b/e2e/assertion/MODULE.bazel @@ -2,9 +2,10 @@ bazel_dep(name = "rules_go", version = "0.53.0") bazel_dep(name = "gazelle", version = "0.42.0") -bazel_dep(name = "aspect_bazel_lib", version = "2.7.2") +bazel_dep(name = "aspect_bazel_lib", version = "2.21.2") bazel_dep(name = "rules_oci", version = "0.0.0") bazel_dep(name = "external_wksp", version = "1.0") +bazel_dep(name = "tar.bzl", version = "0.5.6") local_path_override( module_name = "rules_oci", @@ -18,7 +19,7 @@ local_path_override( oci = use_extension("@rules_oci//oci:extensions.bzl", "oci") oci.toolchains(name = "ocix") -use_repo(oci, "ocix_crane_toolchains") +use_repo(oci, "ocix_crane_toolchains", "ocix_regctl_toolchains") go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") go_deps.from_file(go_mod = "//registry:go.mod") diff --git a/e2e/smoke/BUILD.bazel b/e2e/smoke/BUILD.bazel index 3079c557..2e9a7ec3 100644 --- a/e2e/smoke/BUILD.bazel +++ b/e2e/smoke/BUILD.bazel @@ -49,7 +49,8 @@ filegroup( container_structure_test( name = "test", configs = ["test.yaml"], - image = ":image", + driver = "tar", + image = ":tarball.tar", ) genrule( @@ -72,11 +73,18 @@ assert_json_matches( filter1 = ".[0].RepoTags", ) +NOT_WINDOWS = select({ + "@platforms//os:windows": ["@platforms//:incompatible"], + "//conditions:default": [], +}) + genrule( name = "docker_created", srcs = [":tarball.tar"], outs = ["docker_created.txt"], cmd = "docker load -i $(location :tarball.tar) && docker inspect --format='{{{{.Created}}}}' {} > $@".format(tags[0]), + # todo: find a way to run this without requiring OS installation of docker + target_compatible_with = NOT_WINDOWS, ) diff_test( diff --git a/e2e/smoke/MODULE.bazel b/e2e/smoke/MODULE.bazel index dbc9cd14..75f83478 100644 --- a/e2e/smoke/MODULE.bazel +++ b/e2e/smoke/MODULE.bazel @@ -1,10 +1,11 @@ "Bazel dependencies" -bazel_dep(name = "aspect_bazel_lib", version = "2.7.2") -bazel_dep(name = "bazel_skylib", version = "1.5.0") +bazel_dep(name = "aspect_bazel_lib", version = "2.21.2") +bazel_dep(name = "bazel_skylib", version = "1.8.1") bazel_dep(name = "platforms", version = "0.0.8") bazel_dep(name = "rules_oci", version = "0.0.0") -bazel_dep(name = "container_structure_test", version = "1.15.0") +bazel_dep(name = "container_structure_test", version = "1.19.1") +bazel_dep(name = "tar.bzl", version = "0.5.6") local_path_override( module_name = "rules_oci", diff --git a/e2e/smoke/WORKSPACE.bazel b/e2e/smoke/WORKSPACE.bazel index 29f83b89..148fc50f 100644 --- a/e2e/smoke/WORKSPACE.bazel +++ b/e2e/smoke/WORKSPACE.bazel @@ -9,17 +9,45 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "aspect_bazel_lib", - sha256 = "a8a92645e7298bbf538aa880131c6adb4cf6239bbd27230f077a00414d58e4ce", - strip_prefix = "bazel-lib-2.7.2", - url = "https://github.com/aspect-build/bazel-lib/releases/download/v2.7.2/bazel-lib-v2.7.2.tar.gz", + sha256 = "53cadea9109e646a93ed4dc90c9bbcaa8073c7c3df745b92f6a5000daf7aa3da", + strip_prefix = "bazel-lib-2.21.2", + url = "https://github.com/bazel-contrib/bazel-lib/releases/download/v2.21.2/bazel-lib-v2.21.2.tar.gz", ) load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies", "aspect_bazel_lib_register_toolchains") +# Required bazel-lib dependencies + aspect_bazel_lib_dependencies() +# Required rules_shell dependencies +load("@rules_shell//shell:repositories.bzl", "rules_shell_dependencies", "rules_shell_toolchains") + +rules_shell_dependencies() + +rules_shell_toolchains() + +# Register bazel-lib toolchains + aspect_bazel_lib_register_toolchains() +# Create the host platform repository transitively required by bazel-lib + +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") +load("@platforms//host:extension.bzl", "host_platform_repo") + +maybe( + host_platform_repo, + name = "host_platform", +) + +http_archive( + name = "tar.bzl", + sha256 = "29a3c99c28deca5f8245e2fc32ffdb99c1ea69316462718f3bebfff441d36e4a", + strip_prefix = "tar.bzl-0.5.6", + url = "https://github.com/bazel-contrib/tar.bzl/releases/download/v0.5.6/tar.bzl-v0.5.6.tar.gz", +) + http_archive( name = "container_structure_test", sha256 = "4fd1e0d4974fb95e06d0e94e6ceaae126382bf958524062db4e582232590b863", @@ -53,3 +81,12 @@ oci_pull( "linux/arm64", ], ) + +http_archive( + name = "bazel_features", + sha256 = "adc8ddf121917f197f75c5245dfa8d7b1619f10a1002e25062b093b7957f2798", + strip_prefix = "bazel_features-1.37.0", + url = "https://github.com/bazel-contrib/bazel_features/releases/download/v1.37.0/bazel_features-v1.37.0.tar.gz", +) +load("@bazel_features//:deps.bzl", "bazel_features_deps") +bazel_features_deps() diff --git a/e2e/wasm/BUILD.bazel b/e2e/wasm/BUILD.bazel index 0e0db653..8314d98d 100644 --- a/e2e/wasm/BUILD.bazel +++ b/e2e/wasm/BUILD.bazel @@ -1,4 +1,4 @@ -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") load("@aspect_bazel_lib//lib:transitions.bzl", "platform_transition_filegroup") load("@bazel_skylib//rules:build_test.bzl", "build_test") load("@rules_oci//oci:defs.bzl", "oci_image", "oci_load") diff --git a/e2e/wasm/MODULE.bazel b/e2e/wasm/MODULE.bazel index a9e8c101..09bcf15d 100644 --- a/e2e/wasm/MODULE.bazel +++ b/e2e/wasm/MODULE.bazel @@ -1,9 +1,10 @@ bazel_dep(name = "rules_oci", version = "0.0.0") -bazel_dep(name = "aspect_bazel_lib", version = "2.7.2") -bazel_dep(name = "bazel_skylib", version = "1.5.0") +bazel_dep(name = "aspect_bazel_lib", version = "2.21.2") +bazel_dep(name = "bazel_skylib", version = "1.8.1") bazel_dep(name = "platforms", version = "0.0.8") bazel_dep(name = "rules_rust", version = "0.45.1") bazel_dep(name = "hermetic_cc_toolchain", version = "3.1.0") +bazel_dep(name = "tar.bzl", version = "0.5.6") local_path_override( module_name = "rules_oci", diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel index c019804d..e5d9ecf4 100644 --- a/examples/BUILD.bazel +++ b/examples/BUILD.bazel @@ -1,5 +1,7 @@ package(default_visibility = ["//examples:__subpackages__"]) +exports_files(["jd_test.bash"]) + platform( name = "linux_arm64", constraint_values = [ diff --git a/examples/assert.bzl b/examples/assert.bzl index c870a3d5..0f246f92 100644 --- a/examples/assert.bzl +++ b/examples/assert.bzl @@ -13,7 +13,7 @@ image_path="$(location {image})" manifest_digest=$$($(JQ_BIN) -r '.manifests[0].digest | sub(":"; "/")' $$image_path/index.json) config_digest=$$($(JQ_BIN) -r '.config.digest | sub(":"; "/")' $$image_path/blobs/$$manifest_digest) -$(JQ_BIN) 'def pick(p): . as $$v | reduce path(p) as $$p ({{}}; setpath($$p; $$v | getpath($$p))); pick({keys})' "$$image_path/blobs/$$config_digest" > $@ +$(JQ_BIN) 'def pick(p): . as $$v | reduce path(p) as $$p ({{}}; setpath($$p; $$v | getpath($$p))); pick({keys})' "$$image_path/blobs/$$config_digest" | tr -d '\r' > $@ """ _DEFAULT_ = {"____I_WILL_NOT_MATCH_ANYTHING__": True} @@ -98,18 +98,20 @@ def assert_oci_config( toolchains = ["@jq_toolchains//:resolved_toolchain"], ) - native_test( + native.sh_test( name = name, + srcs = ["//examples:jd_test.bash"], + args = [ + "$(rlocationpath @multitool//tools/jd)", + "$(rlocationpath %s)" % expected, + "$(rlocationpath %s)" % actual, + ], data = [ + "@multitool//tools/jd", expected, actual, + "@bazel_tools//tools/bash/runfiles", ], - args = [ - "$(location %s)" % expected, - "$(location %s)" % actual, - ], - src = "@multitool//tools/jd", - out = name, ) # buildifier: disable=function-docstring-args diff --git a/examples/assertion/BUILD.bazel b/examples/assertion/BUILD.bazel index b8135340..60c1e3d8 100644 --- a/examples/assertion/BUILD.bazel +++ b/examples/assertion/BUILD.bazel @@ -1,4 +1,4 @@ -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") load("@aspect_bazel_lib//lib:testing.bzl", "assert_json_matches") load("@aspect_bazel_lib//lib:transitions.bzl", "platform_transition_filegroup") load("@bazel_skylib//rules:build_test.bzl", "build_test") @@ -6,6 +6,11 @@ load("@bazel_skylib//rules:write_file.bzl", "write_file") load("@rules_oci//oci:defs.bzl", "oci_image", "oci_load") load("//examples:assert.bzl", "assert_oci_config") +NOT_WINDOWS = select({ + "@platforms//os:windows": ["@platforms//:incompatible"], + "//conditions:default": [], +}) + # Case 1: image name containing a capital case. oci_image( name = "imagE", @@ -67,6 +72,7 @@ oci_load( name = "case4_load", image = ":case4_transition", repo_tags = ["case4:example"], + target_compatible_with = NOT_WINDOWS, ) filegroup( @@ -86,6 +92,7 @@ oci_load( name = "case5_load", image = ":case5", repo_tags = ["case5:example"], + target_compatible_with = NOT_WINDOWS, ) filegroup( @@ -263,6 +270,7 @@ oci_load( name = "case9_tarball", image = ":case9_image", repo_tags = repo_tags, + target_compatible_with = NOT_WINDOWS, ) # Not typically recommended: ask the tarball rule to write the .tar file @@ -305,6 +313,7 @@ oci_load( name = "case10_tarball", image = ":case10", repo_tags = ["case10:example"], + target_compatible_with = NOT_WINDOWS, ) genrule( @@ -327,6 +336,7 @@ oci_load( name = "case11_tarball", image = ":case11", repo_tags = ["case11:example"], + target_compatible_with = NOT_WINDOWS, ) write_file( @@ -380,9 +390,14 @@ sh_test( name = "case12_test", srcs = ["assert_push_transitive_deps.sh"], args = [ - "$(location :case12)", + "$(rlocationpath :case12)", + ], + data = [ + ":case12", + "@bazel_tools//tools/bash/runfiles", ], - data = [":case12"], + # TODO; refactor this test to allow run without runfiles + target_compatible_with = NOT_WINDOWS, ) # Case 13: image should have history entries @@ -619,3 +634,16 @@ build_test( ":case10_run", ], ) + +# build them as test. +build_test( + name = "test_windows", + targets = [ + ":imagE", + ":case2", + ":case3", + ], + target_compatible_with = [ + "@platforms//os:windows", + ], +) diff --git a/examples/assertion/assert_push_transitive_deps.sh b/examples/assertion/assert_push_transitive_deps.sh index 9f23f5f3..bc952814 100755 --- a/examples/assertion/assert_push_transitive_deps.sh +++ b/examples/assertion/assert_push_transitive_deps.sh @@ -1,6 +1,19 @@ #!/usr/bin/env bash -IMAGE_DIR="$1" +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: runfiles.bash initializer cannot find $f. An executable rule may have forgotten to expose it in the runfiles, or the binary may require RUNFILES_DIR to be set."; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +IMAGE_DIR="$(rlocation $1)" + +# TODO: Does this test actually even have any meaning without runfiles active? for blob in "$IMAGE_DIR/blobs/sha256"/*; do blob_real_path=$(realpath "$blob") diff --git a/examples/assertion/attest_external/BUILD.bazel b/examples/assertion/attest_external/BUILD.bazel index 912f1806..2194e5b5 100644 --- a/examples/assertion/attest_external/BUILD.bazel +++ b/examples/assertion/attest_external/BUILD.bazel @@ -1,5 +1,10 @@ load("//cosign:defs.bzl", "cosign_attest") +NOT_WINDOWS = select({ + "@platforms//os:windows": ["@platforms//:incompatible"], + "//conditions:default": [], +}) + cosign_attest( name = "attest", image = "@empty_image", @@ -12,12 +17,12 @@ sh_test( name = "test", srcs = ["test.bash"], args = [ - "$(JQ_BIN)", - "$(COSIGN_BIN)", - "$(CRANE_BIN)", - "$(location :attest)", - "$(location @empty_image)", - "$(location @example_sbom)", + "$(rlocationpath @jq_toolchains//:resolved_toolchain)", + "$(rlocationpath @oci_cosign_toolchains//:current_toolchain)", + "$(rlocationpath @oci_crane_toolchains//:current_toolchain)", + "$(rlocationpath :attest)", + "$(rlocationpath @empty_image)", + "$(rlocationpath @example_sbom)", ], data = [ ":attest", @@ -26,10 +31,13 @@ sh_test( "@jq_toolchains//:resolved_toolchain", "@oci_cosign_toolchains//:current_toolchain", "@oci_crane_toolchains//:current_toolchain", + "@bazel_tools//tools/bash/runfiles", ], toolchains = [ "@oci_cosign_toolchains//:current_toolchain", "@oci_crane_toolchains//:current_toolchain", "@jq_toolchains//:resolved_toolchain", ], + # the diff command is not available on windows + target_compatible_with = NOT_WINDOWS, ) diff --git a/examples/assertion/attest_external/test.bash b/examples/assertion/attest_external/test.bash index e578b3a8..19ae5663 100755 --- a/examples/assertion/attest_external/test.bash +++ b/examples/assertion/attest_external/test.bash @@ -1,17 +1,28 @@ #!/usr/bin/env bash set -o pipefail -o errexit -o nounset -readonly JQ="${1/external\//../}" -readonly COSIGN="${2/external\//../}" -readonly CRANE="${3/external\//../}" -readonly ATTACHER="$4" -readonly IMAGE_PATH="$5" -readonly SBOM_PATH="$6" +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: runfiles.bash initializer cannot find $f. An executable rule may have forgotten to expose it in the runfiles, or the binary may require RUNFILES_DIR to be set."; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +readonly JQ="$(rlocation $1)" +readonly COSIGN="$(rlocation $2)" +readonly CRANE="$(rlocation $3)" +readonly ATTACHER="$(rlocation $4)" +readonly IMAGE_PATH="$(rlocation $5)" +readonly SBOM_PATH="$(rlocation $6)" # start a registry output=$(mktemp) $CRANE registry serve --address=localhost:0 >> $output 2>&1 & -timeout=$((SECONDS+10)) +timeout=$((SECONDS+20)) while [ "${SECONDS}" -lt "${timeout}" ]; do port="$(cat $output | sed -nr 's/.+serving on port ([0-9]+)/\1/p')" [ -n "${port}" ] && break @@ -20,7 +31,9 @@ done readonly REPOSITORY="localhost:$port/local" # generate key -COSIGN_PASSWORD=123 "${COSIGN}" generate-key-pair +rm -f cosign.key +rm -f cosign.pub +COSIGN_PASSWORD=123 "${COSIGN}" generate-key-pair REF=$("${CRANE}" push "${IMAGE_PATH}" "${REPOSITORY}") @@ -28,6 +41,6 @@ REF=$("${CRANE}" push "${IMAGE_PATH}" "${REPOSITORY}") COSIGN_PASSWORD=123 "${ATTACHER}" --repository "${REPOSITORY}" --key=cosign.key -y # download the sbom -"${COSIGN}" verify-attestation "$REF" --key=cosign.pub --type spdx | "${JQ}" -r '.payload' | base64 --decode | "${JQ}" -r '.predicate' > "$TEST_TMPDIR/download.sbom" +"${COSIGN}" verify-attestation "$REF" --key=cosign.pub --type spdx | "${JQ}" -r '.payload' | tr -d '\r' | base64 --decode | "${JQ}" -r '.predicate' > "$TEST_TMPDIR/download.sbom" diff -u --ignore-space-change --strip-trailing-cr "$SBOM_PATH" "$TEST_TMPDIR/download.sbom" || (echo "FAIL: downloaded SBOM does not match the original" && exit 1) \ No newline at end of file diff --git a/examples/assertion/big_image/BUILD.bazel b/examples/assertion/big_image/BUILD.bazel index 033ccd43..aca5c834 100644 --- a/examples/assertion/big_image/BUILD.bazel +++ b/examples/assertion/big_image/BUILD.bazel @@ -1,4 +1,4 @@ -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") load("//oci:defs.bzl", "oci_image", "oci_load") # These numbers were gathered on a `Apple M2 Pro` diff --git a/examples/assertion/sign_external/BUILD.bazel b/examples/assertion/sign_external/BUILD.bazel index 670a4a47..e850ff93 100644 --- a/examples/assertion/sign_external/BUILD.bazel +++ b/examples/assertion/sign_external/BUILD.bazel @@ -12,11 +12,11 @@ sh_test( name = "test", srcs = ["test.bash"], args = [ - "$(JQ_BIN)", - "$(CRANE_BIN)", - "$(COSIGN_BIN)", - "$(location :sign)", - "$(location @empty_image)", + "$(rlocationpath @jq_toolchains//:resolved_toolchain)", + "$(rlocationpath @oci_crane_toolchains//:current_toolchain)", + "$(rlocationpath @oci_cosign_toolchains//:current_toolchain)", + "$(rlocationpath :sign)", + "$(rlocationpath @empty_image)", ], data = [ ":sign", @@ -24,6 +24,7 @@ sh_test( "@jq_toolchains//:resolved_toolchain", "@oci_cosign_toolchains//:current_toolchain", "@oci_crane_toolchains//:current_toolchain", + "@bazel_tools//tools/bash/runfiles", ], toolchains = [ "@oci_cosign_toolchains//:current_toolchain", diff --git a/examples/assertion/sign_external/test.bash b/examples/assertion/sign_external/test.bash index b3469b5d..959ec7d5 100755 --- a/examples/assertion/sign_external/test.bash +++ b/examples/assertion/sign_external/test.bash @@ -1,11 +1,22 @@ #!/usr/bin/env bash set -o pipefail -o errexit -o nounset -readonly JQ="${1/external\//../}" -readonly CRANE="${2/external\//../}" -readonly COSIGN="${3/external\//../}" -readonly IMAGE_SIGNER="$4" -readonly IMAGE="$5" +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: runfiles.bash initializer cannot find $f. An executable rule may have forgotten to expose it in the runfiles, or the binary may require RUNFILES_DIR to be set."; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +readonly JQ="$(rlocation $1)" +readonly CRANE="$(rlocation $2)" +readonly COSIGN="$(rlocation $3)" +readonly IMAGE_SIGNER="$(rlocation $4)" +readonly IMAGE="$(rlocation $5)" # start a registry output=$(mktemp) @@ -24,7 +35,9 @@ readonly DIGEST=$("$JQ" -r '.manifests[0].digest' "$IMAGE/index.json") "${CRANE}" push "${IMAGE}" "${REPOSITORY}@${DIGEST}" # Create key-pair -COSIGN_PASSWORD=123 "${COSIGN}" generate-key-pair +rm -f cosign.key +rm -f cosign.pub +COSIGN_PASSWORD=123 "${COSIGN}" generate-key-pair # Sign the image at remote registry COSIGN_PASSWORD=123 "${IMAGE_SIGNER}" --repository="${REPOSITORY}" --key=cosign.key -y @@ -36,4 +49,4 @@ REF=$("${CRANE}" push "${IMAGE}" "${REPOSITORY}") "${COSIGN}" verify "${REPOSITORY}:latest" --key=cosign.pub # Verify using the Digest -"${COSIGN}" verify "${REF}" --key=cosign.pub \ No newline at end of file +"${COSIGN}" verify "${REF}" --key=cosign.pub diff --git a/examples/attest/BUILD.bazel b/examples/attest/BUILD.bazel index 5f632834..58b3a4a7 100644 --- a/examples/attest/BUILD.bazel +++ b/examples/attest/BUILD.bazel @@ -2,6 +2,11 @@ load("@aspect_bazel_lib//lib:copy_file.bzl", "copy_file") load("//cosign:defs.bzl", "cosign_attest") load("//oci:defs.bzl", "oci_image") +NOT_WINDOWS = select({ + "@platforms//os:windows": ["@platforms//:incompatible"], + "//conditions:default": [], +}) + copy_file( name = "sbom", src = "sbom.spdx", @@ -27,12 +32,12 @@ sh_test( name = "test", srcs = ["test.bash"], args = [ - "$(JQ_BIN)", - "$(COSIGN_BIN)", - "$(CRANE_BIN)", - "$(location :attest)", - "$(location :image)", - "$(location sbom.spdx)", + "$(rlocationpath @jq_toolchains//:resolved_toolchain)", + "$(rlocationpath @oci_cosign_toolchains//:current_toolchain)", + "$(rlocationpath @oci_crane_toolchains//:current_toolchain)", + "$(rlocationpath :attest)", + "$(rlocationpath :image)", + "$(rlocationpath sbom.spdx)", ], data = [ "sbom.spdx", @@ -41,12 +46,15 @@ sh_test( "@jq_toolchains//:resolved_toolchain", "@oci_cosign_toolchains//:current_toolchain", "@oci_crane_toolchains//:current_toolchain", + "@bazel_tools//tools/bash/runfiles", ], toolchains = [ "@oci_cosign_toolchains//:current_toolchain", "@oci_crane_toolchains//:current_toolchain", "@jq_toolchains//:resolved_toolchain", ], + # the diff command is not available on windows + target_compatible_with = NOT_WINDOWS, ) cosign_attest( @@ -59,7 +67,7 @@ cosign_attest( sh_test( name = "test_attest_no_repo_fails", srcs = ["test_attest_no_repo_fails.bash"], - args = ["$(location :attest_no_repo)"], + args = ["$(rlocationpath :attest_no_repo)"], data = [":attest_no_repo"], ) @@ -67,12 +75,12 @@ sh_test( name = "test_attest_no_repo_passes", srcs = ["test_attest_no_repo_passes.bash"], args = [ - "$(JQ_BIN)", - "$(COSIGN_BIN)", - "$(CRANE_BIN)", - "$(location :attest_no_repo)", - "$(location :image)", - "$(location sbom.spdx)", + "$(rlocationpath @jq_toolchains//:resolved_toolchain)", + "$(rlocationpath @oci_cosign_toolchains//:current_toolchain)", + "$(rlocationpath @oci_crane_toolchains//:current_toolchain)", + "$(rlocationpath :attest_no_repo)", + "$(rlocationpath :image)", + "$(rlocationpath sbom.spdx)", ], data = [ "sbom.spdx", @@ -87,4 +95,6 @@ sh_test( "@oci_crane_toolchains//:current_toolchain", "@jq_toolchains//:resolved_toolchain", ], + # the diff command is not available on windows + target_compatible_with = NOT_WINDOWS, ) diff --git a/examples/attest/test.bash b/examples/attest/test.bash index 8b368d9a..38f379d9 100755 --- a/examples/attest/test.bash +++ b/examples/attest/test.bash @@ -1,12 +1,23 @@ #!/usr/bin/env bash set -o pipefail -o errexit -o nounset -readonly JQ="${1/external\//../}" -readonly COSIGN="${2/external\//../}" -readonly CRANE="${3/external\//../}" -readonly ATTACHER="$4" -readonly IMAGE_PATH="$5" -readonly SBOM_PATH="$6" +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: runfiles.bash initializer cannot find $f. An executable rule may have forgotten to expose it in the runfiles, or the binary may require RUNFILES_DIR to be set."; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +readonly JQ="$(rlocation $1)" +readonly COSIGN="$(rlocation $2)" +readonly CRANE="$(rlocation $3)" +readonly ATTACHER="$(rlocation $4)" +readonly IMAGE_PATH="$(rlocation $5)" +readonly SBOM_PATH="$(rlocation $6)" # start a registry output=$(mktemp) @@ -20,7 +31,9 @@ done readonly REPOSITORY="localhost:$port/local" # generate key -COSIGN_PASSWORD=123 "${COSIGN}" generate-key-pair +rm -f cosign.key +rm -f cosign.pub +COSIGN_PASSWORD=123 "${COSIGN}" generate-key-pair REF=$("${CRANE}" push "${IMAGE_PATH}" "${REPOSITORY}") @@ -28,6 +41,6 @@ REF=$("${CRANE}" push "${IMAGE_PATH}" "${REPOSITORY}") COSIGN_PASSWORD=123 "${ATTACHER}" --repository "${REPOSITORY}" --key=cosign.key -y # download the sbom -"${COSIGN}" verify-attestation $REF --key=cosign.pub --type spdx | "${JQ}" -r '.payload' | base64 --decode | "${JQ}" -r '.predicate' > "$TEST_TMPDIR/download.sbom" +"${COSIGN}" verify-attestation $REF --key=cosign.pub --type spdx | "${JQ}" -r '.payload' | tr -d '\r' | base64 --decode | "${JQ}" -r '.predicate' > "$TEST_TMPDIR/download.sbom" -diff -u --ignore-space-change --strip-trailing-cr "$SBOM_PATH" "$TEST_TMPDIR/download.sbom" || (echo "FAIL: downloaded SBOM does not match the original" && exit 1) \ No newline at end of file +diff -u --ignore-space-change --strip-trailing-cr "$SBOM_PATH" "$TEST_TMPDIR/download.sbom" || (echo "FAIL: downloaded SBOM does not match the original" && exit 1) diff --git a/examples/attest/test_attest_no_repo_fails.bash b/examples/attest/test_attest_no_repo_fails.bash index c5b7b1d2..836b8484 100755 --- a/examples/attest/test_attest_no_repo_fails.bash +++ b/examples/attest/test_attest_no_repo_fails.bash @@ -2,7 +2,18 @@ set -o pipefail -o errexit -o nounset -readonly IMAGE_ATTESTER="$1" +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: runfiles.bash initializer cannot find $f. An executable rule may have forgotten to expose it in the runfiles, or the binary may require RUNFILES_DIR to be set."; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +readonly IMAGE_ATTESTER="$(rlocation $1)" # Run the cosign_attest target and check that it fails with the expected error message. if ! "$IMAGE_ATTESTER" &> output.txt; then diff --git a/examples/attest/test_attest_no_repo_passes.bash b/examples/attest/test_attest_no_repo_passes.bash index 5d897c79..1b29d0a3 100755 --- a/examples/attest/test_attest_no_repo_passes.bash +++ b/examples/attest/test_attest_no_repo_passes.bash @@ -1,17 +1,28 @@ #!/usr/bin/env bash set -o pipefail -o errexit -o nounset -readonly JQ="${1/external\//../}" -readonly COSIGN="${2/external\//../}" -readonly CRANE="${3/external\//../}" -readonly ATTACHER_NO_REPO="$4" -readonly IMAGE_PATH="$5" -readonly SBOM_PATH="$6" +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: runfiles.bash initializer cannot find $f. An executable rule may have forgotten to expose it in the runfiles, or the binary may require RUNFILES_DIR to be set."; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +readonly JQ="$(rlocation $1)" +readonly COSIGN="$(rlocation $2)" +readonly CRANE="$(rlocation $3)" +readonly ATTACHER_NO_REPO="$(rlocation $4)" +readonly IMAGE_PATH="$(rlocation $5)" +readonly SBOM_PATH="$(rlocation $6)" # start a registry output=$(mktemp) $CRANE registry serve --address=localhost:0 >> "$output" 2>&1 & -timeout=$((SECONDS+10)) +timeout=$((SECONDS+20)) while [ "${SECONDS}" -lt "${timeout}" ]; do port="$(sed -nr 's/.+serving on port ([0-9]+)/\1/p' < "$output")" [ -n "${port}" ] && break @@ -20,6 +31,8 @@ done readonly REPOSITORY="localhost:$port/local" # generate key +rm -f cosign.key +rm -f cosign.pub COSIGN_PASSWORD=123 "${COSIGN}" generate-key-pair REF=$("${CRANE}" push "${IMAGE_PATH}" "${REPOSITORY}") @@ -28,6 +41,6 @@ REF=$("${CRANE}" push "${IMAGE_PATH}" "${REPOSITORY}") COSIGN_PASSWORD=123 "${ATTACHER_NO_REPO}" --repository "${REPOSITORY}" --key=cosign.key -y # download the sbom -"${COSIGN}" verify-attestation "$REF" --key=cosign.pub --type spdx | "${JQ}" -r '.payload' | base64 --decode | "${JQ}" -r '.predicate' > "$TEST_TMPDIR/download.sbom" +"${COSIGN}" verify-attestation "$REF" --key=cosign.pub --type spdx --output json | "${JQ}" -r ".payload | @base64d | fromjson | .predicate" > "$TEST_TMPDIR/download.sbom" diff -u --ignore-space-change --strip-trailing-cr "$SBOM_PATH" "$TEST_TMPDIR/download.sbom" || (echo "FAIL: downloaded SBOM does not match the original" && exit 1) diff --git a/examples/cmd_location_expansion/BUILD.bazel b/examples/cmd_location_expansion/BUILD.bazel index 7c2408cb..5760e3aa 100644 --- a/examples/cmd_location_expansion/BUILD.bazel +++ b/examples/cmd_location_expansion/BUILD.bazel @@ -1,4 +1,5 @@ -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@aspect_bazel_lib//lib:expand_template.bzl", "expand_template") +load("@tar.bzl//tar:tar.bzl", "tar") load("@rules_oci//oci:defs.bzl", "oci_image") load("//examples:assert.bzl", "assert_oci_config", "assert_oci_image_command") @@ -7,17 +8,19 @@ tar( srcs = [":app.bash"], ) -genrule( +expand_template( name = "app_cmd", - outs = ["app_cmd.txt"], - cmd = """ - echo $(rootpaths :app.bash) > "$@" - echo "a1" >> "$@" - echo "a2 b2" >> "$@" - echo " a3\tb3 " >> "$@" - """, - tools = [ - ":app.bash", + template = [ + "{{app_path}}", + "a1", + "a2 b2", + " a3\tb3 ", + ], + substitutions = { + "{{app_path}}": "$(rootpath :app.bash)", + }, + data = [ + ":app.bash" ], ) diff --git a/examples/deb/BUILD.bazel b/examples/deb/BUILD.bazel index cc37fb69..61641ab3 100644 --- a/examples/deb/BUILD.bazel +++ b/examples/deb/BUILD.bazel @@ -1,5 +1,10 @@ load("//oci:defs.bzl", "oci_image", "oci_load") +NOT_WINDOWS = select({ + "@platforms//os:windows": ["@platforms//:incompatible"], + "//conditions:default": [], +}) + _ARCH = [ "amd64", "arm64", @@ -24,4 +29,5 @@ oci_load( name = "load", image = ":image_amd64", repo_tags = ["test:test"], + target_compatible_with = NOT_WINDOWS, ) diff --git a/examples/dockerfile/MODULE.bazel b/examples/dockerfile/MODULE.bazel index 15249676..1236c972 100644 --- a/examples/dockerfile/MODULE.bazel +++ b/examples/dockerfile/MODULE.bazel @@ -3,7 +3,7 @@ module(name = "dockerfile") bazel_dep(name = "bazel_skylib", version = "1.5.0") -bazel_dep(name = "aspect_bazel_lib", version = "2.7.2") +bazel_dep(name = "aspect_bazel_lib", version = "2.19.3") bazel_dep(name = "rules_oci", version = "2.2.5") bazel_dep(name = "rules_go", version = "0.53.0") diff --git a/examples/env/BUILD.bazel b/examples/env/BUILD.bazel index 0c8b6fd7..eb4ababf 100644 --- a/examples/env/BUILD.bazel +++ b/examples/env/BUILD.bazel @@ -1,5 +1,5 @@ load("@aspect_bazel_lib//lib:expand_template.bzl", "expand_template") -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") load("@rules_oci//oci:defs.bzl", "oci_image") load("//examples:assert.bzl", "assert_oci_image_command") diff --git a/examples/image_index/BUILD.bazel b/examples/image_index/BUILD.bazel index 57cc68e8..9343debe 100644 --- a/examples/image_index/BUILD.bazel +++ b/examples/image_index/BUILD.bazel @@ -1,5 +1,5 @@ load("@aspect_bazel_lib//lib:copy_file.bzl", "copy_file") -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") load("@rules_oci//oci:defs.bzl", "oci_image", "oci_image_index") platform( diff --git a/examples/jd_test.bash b/examples/jd_test.bash new file mode 100755 index 00000000..9dc92561 --- /dev/null +++ b/examples/jd_test.bash @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: runfiles.bash initializer cannot find $f. An executable rule may have forgotten to expose it in the runfiles, or the binary may require RUNFILES_DIR to be set."; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +readonly JD="$(rlocation $1)" +readonly EXPECTED="$(rlocation $2)" +readonly ACTUAL="$(rlocation $3)" + +$JD $EXPECTED $ACTUAL diff --git a/examples/just_tar/BUILD.bazel b/examples/just_tar/BUILD.bazel index 68536ec7..9446c2bd 100644 --- a/examples/just_tar/BUILD.bazel +++ b/examples/just_tar/BUILD.bazel @@ -1,4 +1,4 @@ -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") # See `Case 3` in examples/assertion genrule( diff --git a/examples/labels/BUILD.bazel b/examples/labels/BUILD.bazel index 4bd8e3d1..e494ac5e 100644 --- a/examples/labels/BUILD.bazel +++ b/examples/labels/BUILD.bazel @@ -1,5 +1,5 @@ load("@aspect_bazel_lib//lib:expand_template.bzl", "expand_template") -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") load("@rules_oci//oci:defs.bzl", "oci_image") load("//examples:assert.bzl", "assert_oci_config") diff --git a/examples/multi_architecture_image/BUILD.bazel b/examples/multi_architecture_image/BUILD.bazel index bb5177c1..31128e5c 100644 --- a/examples/multi_architecture_image/BUILD.bazel +++ b/examples/multi_architecture_image/BUILD.bazel @@ -1,8 +1,13 @@ -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") load("@aspect_bazel_lib//lib:testing.bzl", "assert_contains") load("//oci:defs.bzl", "oci_image", "oci_image_index", "oci_load") load(":transition.bzl", "multi_arch") +NOT_WINDOWS = select({ + "@platforms//os:windows": ["@platforms//:incompatible"], + "//conditions:default": [], +}) + tar( name = "app", srcs = ["test.bash"], @@ -30,6 +35,8 @@ oci_image_index( images = [ ":images", ], + # todo: re-enable on windows when oci_load is fixed + target_compatible_with = NOT_WINDOWS, ) oci_load( @@ -37,6 +44,8 @@ oci_load( image = ":index", repo_tags = ["my-repository:latest"], format = "oci", + # todo: re-enable on windows when oci_load is fixed + target_compatible_with = NOT_WINDOWS, ) assert_contains( diff --git a/examples/push/BUILD.bazel b/examples/push/BUILD.bazel index 189f699c..805b5b81 100644 --- a/examples/push/BUILD.bazel +++ b/examples/push/BUILD.bazel @@ -88,12 +88,12 @@ sh_test( name = "test", srcs = ["test.bash"], args = [ - "$(CRANE_BIN)", - "$(location :push_image)", - "$(location :push_image_index)", - "$(location :push_image_repository_file)", - "$(location :push_image_wo_tags)", - "$(location :push_image_wo_repository)", + "$(rlocationpath @oci_crane_toolchains//:current_toolchain)", + "$(rlocationpath :push_image)", + "$(rlocationpath :push_image_index)", + "$(rlocationpath :push_image_repository_file)", + "$(rlocationpath :push_image_wo_tags)", + "$(rlocationpath :push_image_wo_repository)", ], data = [ ":push_image", @@ -102,6 +102,7 @@ sh_test( ":push_image_wo_tags", ":push_image_wo_repository", "@oci_crane_toolchains//:current_toolchain", + "@bazel_tools//tools/bash/runfiles", ], toolchains = [ "@oci_crane_toolchains//:current_toolchain", @@ -111,7 +112,7 @@ sh_test( sh_test( name = "test_push_image_wo_repository_fails", srcs = ["test_push_image_wo_repository_fails.bash"], - args = ["$(location :push_image_wo_repository)"], + args = ["$(rlocationpath :push_image_wo_repository)"], data = [ ":push_image_wo_repository", ], diff --git a/examples/push/test.bash b/examples/push/test.bash index d3b0e719..4948615c 100755 --- a/examples/push/test.bash +++ b/examples/push/test.bash @@ -1,12 +1,23 @@ #!/usr/bin/env bash set -o pipefail -o errexit -o nounset -readonly CRANE="${1/external\//../}" -readonly PUSH_IMAGE="$2" -readonly PUSH_IMAGE_INDEX="$3" -readonly PUSH_IMAGE_REPOSITORY_FILE="$4" -readonly PUSH_IMAGE_WO_TAGS="$5" -readonly PUSH_IMAGE_WO_REPOSITORY="$6" +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: runfiles.bash initializer cannot find $f. An executable rule may have forgotten to expose it in the runfiles, or the binary may require RUNFILES_DIR to be set."; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +readonly CRANE="$(rlocation $1)" +readonly PUSH_IMAGE="$(rlocation $2)" +readonly PUSH_IMAGE_INDEX="$(rlocation $3)" +readonly PUSH_IMAGE_REPOSITORY_FILE="$(rlocation $4)" +readonly PUSH_IMAGE_WO_TAGS="$(rlocation $5)" +readonly PUSH_IMAGE_WO_REPOSITORY="$(rlocation $6)" # start a registry output=$(mktemp) @@ -33,7 +44,7 @@ REPOSITORY="${REGISTRY}/local-index" REPOSITORY="${REGISTRY}/local-wo-tags" "${PUSH_IMAGE_WO_TAGS}" --repository "${REPOSITORY}" TAGS=$("${CRANE}" ls "$REPOSITORY") -if [ -n "${TAGS}" ]; then +if [ -n "${TAGS:-}" ]; then echo "image is not supposed to have any tags but got" echo "${TAGS}" exit 1 @@ -41,7 +52,7 @@ fi # should push image to the repository defined in the file -set -ex +set -e REPOSITORY="${REGISTRY}/repository-file" "${PUSH_IMAGE_REPOSITORY_FILE}" --repository "${REPOSITORY}" "${CRANE}" digest "$REPOSITORY:latest" diff --git a/examples/push/test_push_image_wo_repository_fails.bash b/examples/push/test_push_image_wo_repository_fails.bash index 4efda77b..1e066124 100755 --- a/examples/push/test_push_image_wo_repository_fails.bash +++ b/examples/push/test_push_image_wo_repository_fails.bash @@ -2,7 +2,18 @@ set -o pipefail -o errexit -o nounset -readonly PUSH_IMAGE_WO_REPOSITORY="$1" +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: runfiles.bash initializer cannot find $f. An executable rule may have forgotten to expose it in the runfiles, or the binary may require RUNFILES_DIR to be set."; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +readonly PUSH_IMAGE_WO_REPOSITORY="$(rlocation $1)" # Run the oci_push target and check that it fails with an error message. if ! "$PUSH_IMAGE_WO_REPOSITORY" &> output.txt; then diff --git a/examples/sign/BUILD.bazel b/examples/sign/BUILD.bazel index 7415991a..baca569d 100644 --- a/examples/sign/BUILD.bazel +++ b/examples/sign/BUILD.bazel @@ -1,4 +1,4 @@ -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") load("//cosign:defs.bzl", "cosign_sign") load("//oci:defs.bzl", "oci_image") @@ -24,11 +24,11 @@ sh_test( name = "test", srcs = ["test.bash"], args = [ - "$(JQ_BIN)", - "$(CRANE_BIN)", - "$(COSIGN_BIN)", - "$(location :sign)", - "$(location :image)", + "$(rlocationpath @jq_toolchains//:resolved_toolchain)", + "$(rlocationpath @oci_crane_toolchains//:current_toolchain)", + "$(rlocationpath @oci_cosign_toolchains//:current_toolchain)", + "$(rlocationpath :sign)", + "$(rlocationpath :image)", ], data = [ ":image", @@ -36,6 +36,7 @@ sh_test( "@jq_toolchains//:resolved_toolchain", "@oci_cosign_toolchains//:current_toolchain", "@oci_crane_toolchains//:current_toolchain", + "@bazel_tools//tools/bash/runfiles", ], toolchains = [ "@oci_cosign_toolchains//:current_toolchain", @@ -52,7 +53,7 @@ cosign_sign( sh_test( name = "test_sign_no_repo_fails", srcs = ["test_sign_no_repo_fails.bash"], - args = ["$(location :sign_no_repo)"], + args = ["$(rlocationpath :sign_no_repo)"], data = [":sign_no_repo"], ) @@ -60,11 +61,11 @@ sh_test( name = "test_sign_no_repo_passes", srcs = ["test_sign_no_repo_passes.bash"], args = [ - "$(JQ_BIN)", - "$(CRANE_BIN)", - "$(COSIGN_BIN)", - "$(location :sign_no_repo)", - "$(location :image)", + "$(rlocationpath @jq_toolchains//:resolved_toolchain)", + "$(rlocationpath @oci_crane_toolchains//:current_toolchain)", + "$(rlocationpath @oci_cosign_toolchains//:current_toolchain)", + "$(rlocationpath :sign_no_repo)", + "$(rlocationpath :image)", ], data = [ ":image", diff --git a/examples/sign/test.bash b/examples/sign/test.bash index c5f311aa..46621904 100755 --- a/examples/sign/test.bash +++ b/examples/sign/test.bash @@ -1,11 +1,22 @@ #!/usr/bin/env bash set -o pipefail -o errexit -o nounset -readonly JQ="${1/external\//../}" -readonly CRANE="${2/external\//../}" -readonly COSIGN="${3/external\//../}" -readonly IMAGE_SIGNER="$4" -readonly IMAGE="$5" +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: runfiles.bash initializer cannot find $f. An executable rule may have forgotten to expose it in the runfiles, or the binary may require RUNFILES_DIR to be set."; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +readonly JQ="$(rlocation $1)" +readonly CRANE="$(rlocation $2)" +readonly COSIGN="$(rlocation $3)" +readonly IMAGE_SIGNER="$(rlocation $4)" +readonly IMAGE="$(rlocation $5)" # start a registry output=$(mktemp) @@ -23,7 +34,9 @@ readonly DIGEST=$("$JQ" -r '.manifests[0].digest' "$IMAGE/index.json") "${CRANE}" push "${IMAGE}" "${REPOSITORY}@${DIGEST}" # Create key-pair -COSIGN_PASSWORD=123 "${COSIGN}" generate-key-pair +rm -f cosign.key +rm -f cosign.pub +COSIGN_PASSWORD=123 "${COSIGN}" generate-key-pair # Sign the image at remote registry echo "y" | COSIGN_PASSWORD=123 "${IMAGE_SIGNER}" --repository="${REPOSITORY}" --key=cosign.key @@ -35,4 +48,4 @@ REF=$("${CRANE}" push "${IMAGE}" "${REPOSITORY}") "${COSIGN}" verify "${REPOSITORY}:latest" --key=cosign.pub # Verify using the Digest -"${COSIGN}" verify "${REF}" --key=cosign.pub \ No newline at end of file +"${COSIGN}" verify "${REF}" --key=cosign.pub diff --git a/examples/sign/test_sign_no_repo_fails.bash b/examples/sign/test_sign_no_repo_fails.bash index 23833cb1..3a6b7d9a 100755 --- a/examples/sign/test_sign_no_repo_fails.bash +++ b/examples/sign/test_sign_no_repo_fails.bash @@ -2,7 +2,18 @@ set -o pipefail -o errexit -o nounset -readonly IMAGE_SIGNER="$1" +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: runfiles.bash initializer cannot find $f. An executable rule may have forgotten to expose it in the runfiles, or the binary may require RUNFILES_DIR to be set."; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +readonly IMAGE_SIGNER="$(rlocation $1)" # Run the cosign_sign target and check that it fails with the expected error message. if ! "$IMAGE_SIGNER" &> output.txt; then diff --git a/examples/sign/test_sign_no_repo_passes.bash b/examples/sign/test_sign_no_repo_passes.bash index b2fedfb1..4b05395f 100755 --- a/examples/sign/test_sign_no_repo_passes.bash +++ b/examples/sign/test_sign_no_repo_passes.bash @@ -1,11 +1,22 @@ #!/usr/bin/env bash set -o pipefail -o errexit -o nounset -readonly JQ="${1/external\//../}" -readonly CRANE="${2/external\//../}" -readonly COSIGN="${3/external\//../}" -readonly IMAGE_SIGNER_NO_REPO="$4" -readonly IMAGE="$5" +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: runfiles.bash initializer cannot find $f. An executable rule may have forgotten to expose it in the runfiles, or the binary may require RUNFILES_DIR to be set."; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +readonly JQ="$(rlocation $1)" +readonly CRANE="$(rlocation $2)" +readonly COSIGN="$(rlocation $3)" +readonly IMAGE_SIGNER_NO_REPO="$(rlocation $4)" +readonly IMAGE="$(rlocation $5)" # start a registry output=$(mktemp) @@ -25,6 +36,8 @@ readonly DIGEST "${CRANE}" push "${IMAGE}" "${REPOSITORY}@${DIGEST}" # Create key-pair +rm -f cosign.key +rm -f cosign.pub COSIGN_PASSWORD=123 "${COSIGN}" generate-key-pair # Sign the image at remote registry diff --git a/examples/tarball_as_base/BUILD.bazel b/examples/tarball_as_base/BUILD.bazel index 83c4e127..6754bf57 100644 --- a/examples/tarball_as_base/BUILD.bazel +++ b/examples/tarball_as_base/BUILD.bazel @@ -1,6 +1,11 @@ load("@aspect_bazel_lib//lib:run_binary.bzl", "run_binary") load("@rules_oci//oci:defs.bzl", "oci_image", "oci_load") +NOT_WINDOWS = select({ + "@platforms//os:windows": ["@platforms//:incompatible"], + "//conditions:default": [], +}) + # Pluck out the regctl tool from the toolchain. filegroup( name = "regctl", @@ -43,4 +48,5 @@ oci_load( name = "load", image = ":image", repo_tags = ["example:latest"], + target_compatible_with = NOT_WINDOWS, ) diff --git a/examples/tarball_incremental_loader/BUILD.bazel b/examples/tarball_incremental_loader/BUILD.bazel index a26d2e35..f2fbeb2f 100644 --- a/examples/tarball_incremental_loader/BUILD.bazel +++ b/examples/tarball_incremental_loader/BUILD.bazel @@ -1,6 +1,11 @@ -load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load("@tar.bzl//tar:tar.bzl", "tar") load("//oci:defs.bzl", "oci_image", "oci_load") +NOT_WINDOWS = select({ + "@platforms//os:windows": ["@platforms//:incompatible"], + "//conditions:default": [], +}) + tar( name = "app", srcs = ["test.bash"], @@ -18,4 +23,5 @@ oci_load( image = ":image", loader = "loader.sh", repo_tags = ["test:test"], + target_compatible_with = NOT_WINDOWS, ) diff --git a/oci/BUILD.bazel b/oci/BUILD.bazel index f1a9530f..433bd41f 100644 --- a/oci/BUILD.bazel +++ b/oci/BUILD.bazel @@ -55,7 +55,7 @@ bzl_library( "//oci/private:push", "@aspect_bazel_lib//lib:copy_file", "@aspect_bazel_lib//lib:directory_path", - "@aspect_bazel_lib//lib:jq", + "@jq.bzl//jq:jq", "@bazel_skylib//lib:types", "@bazel_skylib//rules:write_file", ], diff --git a/oci/defs.bzl b/oci/defs.bzl index a156d81f..4b6884e2 100644 --- a/oci/defs.bzl +++ b/oci/defs.bzl @@ -8,7 +8,7 @@ load("@rules_oci//oci:defs.bzl", ...) load("@aspect_bazel_lib//lib:copy_file.bzl", "copy_file") load("@aspect_bazel_lib//lib:directory_path.bzl", "directory_path") -load("@aspect_bazel_lib//lib:jq.bzl", "jq") +load("@jq.bzl//jq:jq.bzl", "jq") load("@aspect_bazel_lib//lib:utils.bzl", "propagate_common_rule_attributes") load("@bazel_skylib//lib:types.bzl", "types") load("@bazel_skylib//rules:write_file.bzl", "write_file") diff --git a/oci/dependencies.bzl b/oci/dependencies.bzl index c929428a..e6db6d5a 100644 --- a/oci/dependencies.bzl +++ b/oci/dependencies.bzl @@ -4,8 +4,10 @@ These are needed for local dev, and users must install them as well. See https://docs.bazel.build/versions/main/skylark/deploying.html#dependencies """ +load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies", "aspect_bazel_lib_register_toolchains") load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") +load("@platforms//host:extension.bzl", "host_platform_repo") def http_archive(**kwargs): maybe(_http_archive, **kwargs) @@ -13,18 +15,18 @@ def http_archive(**kwargs): def rules_oci_dependencies(): http_archive( name = "bazel_skylib", - sha256 = "c6966ec828da198c5d9adbaa94c05e3a1c7f21bd012a0b29ba8ddbccb2c93b0d", + sha256 = "bc283cdfcd526a52c3201279cda4bc298652efa898b10b4db0837dc51652756f", urls = [ - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz", - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.7.1/bazel-skylib-1.7.1.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.7.1/bazel-skylib-1.7.1.tar.gz", ], ) http_archive( name = "aspect_bazel_lib", - sha256 = "a8a92645e7298bbf538aa880131c6adb4cf6239bbd27230f077a00414d58e4ce", - strip_prefix = "bazel-lib-2.7.2", - url = "https://github.com/aspect-build/bazel-lib/releases/download/v2.7.2/bazel-lib-v2.7.2.tar.gz", + sha256 = "53cadea9109e646a93ed4dc90c9bbcaa8073c7c3df745b92f6a5000daf7aa3da", + strip_prefix = "bazel-lib-2.21.2", + url = "https://github.com/bazel-contrib/bazel-lib/releases/download/v2.21.2/bazel-lib-v2.21.2.tar.gz", ) http_archive( @@ -33,3 +35,25 @@ def rules_oci_dependencies(): strip_prefix = "bazel_features-1.10.0", url = "https://github.com/bazel-contrib/bazel_features/releases/download/v1.10.0/bazel_features-v1.10.0.tar.gz", ) + + http_archive( + name = "tar.bzl", + sha256 = "29a3c99c28deca5f8245e2fc32ffdb99c1ea69316462718f3bebfff441d36e4a", + strip_prefix = "tar.bzl-0.5.6", + url = "https://github.com/bazel-contrib/tar.bzl/releases/download/v0.5.6/tar.bzl-v0.5.6.tar.gz", + ) + + # Required bazel-lib dependencies + + aspect_bazel_lib_dependencies() + + # Register bazel-lib toolchains + + aspect_bazel_lib_register_toolchains() + + # Create the host platform repository transitively required by bazel-lib + + maybe( + host_platform_repo, + name = "host_platform", + ) diff --git a/oci/private/BUILD.bazel b/oci/private/BUILD.bazel index 0f234949..00bd5bf6 100644 --- a/oci/private/BUILD.bazel +++ b/oci/private/BUILD.bazel @@ -1,4 +1,5 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") +load("util.bzl", "is_exec_platform_windows") exports_files( glob(["*.bzl"]), @@ -20,6 +21,7 @@ bzl_library( deps = [ ":util", "@aspect_bazel_lib//lib:paths", + "@aspect_bazel_lib//lib:windows_utils", ], ) @@ -107,3 +109,8 @@ bzl_library( "@bazel_skylib//lib:versions", ], ) + +is_exec_platform_windows( + name = "is_exec_platform_windows", + visibility = ["//visibility:public"], +) diff --git a/oci/private/descriptor.sh b/oci/private/descriptor.sh.tpl old mode 100755 new mode 100644 similarity index 71% rename from oci/private/descriptor.sh rename to oci/private/descriptor.sh.tpl index 2145ca3f..e02c5012 --- a/oci/private/descriptor.sh +++ b/oci/private/descriptor.sh.tpl @@ -11,25 +11,29 @@ set -o pipefail -o errexit -o nounset # See: https://github.com/opencontainers/image-spec/blob/main/descriptor.md # shellcheck disable=SC2153 -PATH="$HPATH:$PATH" archive="$1" output="$2" label="$3" -digest="$(regctl digest <"$archive")" +readonly ZSTD="{{zstd_path}}" +readonly JQ="{{jq_path}}" +readonly REGCTL="{{regctl_path}}" +readonly COREUTILS="{{coreutils_path}}" + +digest=$(${REGCTL} digest <"$archive") diffid="$digest" -size=$(coreutils wc -c "$archive" | coreutils cut -f1 -d' ') +size=$(${COREUTILS} wc -c "$archive" | ${COREUTILS} cut -f1 -d' ') compression= -if [[ $(coreutils od -An -t x1 --read-bytes 2 "$archive") == " 1f 8b" ]]; then +if [[ $(${COREUTILS} od -An -t x1 --read-bytes 2 "$archive") == " 1f 8b" ]]; then compression="gzip" - diffid=$(zstd --decompress --format=gzip <"$archive" | regctl digest) + diffid=$(${ZSTD} --decompress --format=gzip <"$archive" | ${REGCTL} digest) elif zstd -t <"$archive" 2>/dev/null; then compression="zstd" - diffid=$(zstd --decompress --format=zstd <"$archive" | regctl digest) + diffid=$(${ZSTD} --decompress --format=zstd <"$archive" | ${REGCTL} digest) fi -jq -n \ +${JQ} -n \ --arg compression "$compression" \ --arg diffid "$diffid" \ --arg digest "$digest" \ diff --git a/oci/private/image.bzl b/oci/private/image.bzl index 73a0d573..1d0710eb 100644 --- a/oci/private/image.bzl +++ b/oci/private/image.bzl @@ -2,7 +2,7 @@ load("@aspect_bazel_lib//lib:resource_sets.bzl", "resource_set", "resource_set_attr") load("@bazel_features//:features.bzl", "bazel_features") -load("util.bzl", "util") +load("util.bzl", "util", "is_windows_exec", "IS_EXEC_PLATFORM_WINDOWS_ATTRS") _ACCEPTED_TAR_EXTENSIONS = [ ".tar", @@ -95,9 +95,8 @@ If `group/gid` is not specified, the default group and supplementary groups of t "labels": attr.label(doc = "A file containing a dictionary of labels. Each line should be in the form `name=value`.", allow_single_file = True), "annotations": attr.label(doc = "A file containing a dictionary of annotations. Each line should be in the form `name=value`.", allow_single_file = True), "_image_sh": attr.label(default = "image.sh", allow_single_file = True), - "_descriptor_sh": attr.label(default = "descriptor.sh", executable = True, cfg = "exec", allow_single_file = True), - "_windows_constraint": attr.label(default = "@platforms//os:windows"), -} + "_descriptor_sh": attr.label(default = "descriptor.sh.tpl", executable = True, cfg = "exec", allow_single_file = True), +} | IS_EXEC_PLATFORM_WINDOWS_ATTRS def _platform_str(os, arch, variant = None): parts = dict(os = os, architecture = arch) @@ -106,24 +105,35 @@ def _platform_str(os, arch, variant = None): return json.encode(parts) def _calculate_descriptor(ctx, idx, layer, zstd, jq, coreutils, regctl): + # Represents either manifest.json or index.json depending on the image format + bash_launcher = ctx.actions.declare_file("%s.%s.descriptor.sh" % (ctx.label.name, idx)) descriptor = ctx.actions.declare_file("%s.%s.descriptor.json" % (ctx.label.name, idx)) + + substitutions = { + "{{zstd_path}}": zstd.zstdinfo.binary.path, + "{{jq_path}}": jq.jqinfo.bin.path, + "{{coreutils_path}}": coreutils.coreutils_info.bin.path, + "{{regctl_path}}": regctl.regctl_info.binary.path, + } + + ctx.actions.expand_template( + template = ctx.file._descriptor_sh, + output = bash_launcher, + is_executable = True, + substitutions = substitutions, + ) + args = ctx.actions.args() args.add(layer) args.add(descriptor) args.add(layer.owner) + executable = util.maybe_wrap_launcher_for_windows(ctx, bash_launcher) + inputs = [bash_launcher] ctx.actions.run( - executable = util.maybe_wrap_launcher_for_windows(ctx, ctx.executable._descriptor_sh), - inputs = [layer], + executable = executable, + inputs = [layer] + inputs, outputs = [descriptor], arguments = [args], - env = { - "HPATH": ":".join([ - zstd.zstdinfo.binary.dirname, - jq.jqinfo.bin.dirname, - coreutils.coreutils_info.bin.dirname, - regctl.regctl_info.binary.dirname, - ]), - }, tools = [ jq.jqinfo.bin, zstd.zstdinfo.binary, @@ -142,7 +152,7 @@ def _oci_image_impl(ctx): fail("'os', 'architecture' and 'variant' come from the image provided by 'base' and cannot be overridden.") regctl = ctx.toolchains["@rules_oci//oci:regctl_toolchain_type"] - jq = ctx.toolchains["@aspect_bazel_lib//lib:jq_toolchain_type"] + jq = ctx.toolchains["@jq.bzl//jq/toolchain:type"] coreutils = ctx.toolchains["@aspect_bazel_lib//lib:coreutils_toolchain_type"] zstd = ctx.toolchains["@aspect_bazel_lib//lib:zstd_toolchain_type"] @@ -152,6 +162,9 @@ def _oci_image_impl(ctx): # create the image builder builder = ctx.actions.declare_file("image_%s.sh" % ctx.label.name) + # pass the platform json via template to avoid issues with escaping via bat wrappers + platform_str = _platform_str(ctx.attr.os, ctx.attr.architecture, ctx.attr.variant) if not ctx.attr.base else "0" + platform_str = platform_str.replace('"', '\\"') ctx.actions.expand_template( template = ctx.file._image_sh, output = builder, @@ -162,6 +175,7 @@ def _oci_image_impl(ctx): "{{coreutils_path}}": coreutils.coreutils_info.bin.dirname, "{{output}}": output.path, "{{treeartifact_symlinks}}": str(int(use_symlinks)), + "{{scratch}}": platform_str, }, ) @@ -183,7 +197,7 @@ def _oci_image_impl(ctx): transitive_inputs.append(base_default_info.files) else: # create a scratch base image with given os/arch[/variant] - args.add(_platform_str(ctx.attr.os, ctx.attr.architecture, ctx.attr.variant), format = "--scratch=%s") + args.add("--scratch=true") # If tree artifact symlinks are supported also add tars into runfiles. if use_symlinks: @@ -238,10 +252,16 @@ def _oci_image_impl(ctx): if ctx.attr.workdir: args.add(ctx.attr.workdir, format = "--workdir=%s") + # todo: remove if not needed + #args.set_param_file_format("multiline") + args.use_param_file("@%s", use_always=True) + # without this on windows the args are quoted and the quotes end up in the bash script and upset the parsing + # eg unknown argument '--scratch=true' + args.set_param_file_format("multiline") action_env = {} # Windows: Don't convert arguments like --entrypoint=/some/bin to --entrypoint=C:/msys64/some/bin - if ctx.target_platform_has_constraint(ctx.attr._windows_constraint[platform_common.ConstraintValueInfo]): + if is_windows_exec(ctx): # See https://www.msys2.org/wiki/Porting/: # > Setting MSYS2_ARG_CONV_EXCL=* prevents any path transformation. action_env["MSYS2_ARG_CONV_EXCL"] = "*" @@ -249,13 +269,16 @@ def _oci_image_impl(ctx): # This one is for Windows Git MSys action_env["MSYS_NO_PATHCONV"] = "1" + executable = util.maybe_wrap_launcher_for_windows(ctx, builder) ctx.actions.run( inputs = depset(inputs, transitive = transitive_inputs), arguments = [args], outputs = [output], env = action_env, - executable = util.maybe_wrap_launcher_for_windows(ctx, builder), + executable = executable, tools = [ + executable, + builder, regctl.regctl_info.binary, jq.jqinfo.bin, coreutils.coreutils_info.bin, @@ -278,7 +301,7 @@ oci_image = rule( attrs = dict(_attrs, **resource_set_attr), doc = _DOC, toolchains = [ - "@aspect_bazel_lib//lib:jq_toolchain_type", + "@jq.bzl//jq/toolchain:type", "@aspect_bazel_lib//lib:coreutils_toolchain_type", "@aspect_bazel_lib//lib:zstd_toolchain_type", "@rules_oci//oci:regctl_toolchain_type", diff --git a/oci/private/image.sh b/oci/private/image.sh index a7dc886e..bbc200c0 100644 --- a/oci/private/image.sh +++ b/oci/private/image.sh @@ -16,6 +16,7 @@ readonly ENV_EXPAND_FILTER='[$raw | match("\\${?([a-zA-Z0-9_]+)}?"; "gm")] | red {parts: [], prev: 0}; {parts: (.parts + [$raw[.prev:$match.offset], ($envs[] | select(.key == $match.captures[0].string)).value ]), prev: ($match.offset + $match.length)} ) | .parts + [$raw[.prev:]] | join("")' +readonly SCRATCH="{{scratch}}" function base_from_scratch() { local platform="$1" @@ -44,7 +45,12 @@ function base_from() { coreutils cp --no-preserve=mode "$blob" "$OUTPUT/blobs/$relative_to_blobs" fi done - coreutils cp --no-preserve=mode "$path/oci-layout" "$OUTPUT/oci-layout" + # without this explicit chmod the following error occurs on windows: + # bazel build /examples/tarball_as_base:image + # failed to write index: cannot create oci-layout: open bazel-out/x64_windows-fastbuild/bin/examples/tarball_as_base/image/oci-layout: Access is denied. + # chmod is not part of coreutils + coreutils cp "$path/oci-layout" "$OUTPUT/oci-layout" + /usr/bin/chmod +w "$OUTPUT/oci-layout" jq '.manifests[0].annotations["org.opencontainers.image.ref.name"] = "intermediate"' "$path/index.json" >"$OUTPUT/index.json" } @@ -117,10 +123,30 @@ function add_layer() { CONFIG="{}" +# Expand @params file if present +ARGS=() for ARG in "$@"; do + if [[ "$ARG" == @* ]]; then + PARAMS_FILE="${ARG#@}" + if [[ -f "$PARAMS_FILE" ]]; then + while IFS= read -r line || [ -n "$line" ]; do + # skip empty lines and comments + [[ -z "$line" || "$line" =~ ^# ]] && continue + ARGS+=("$line") + done < "$PARAMS_FILE" + else + echo "Params file $PARAMS_FILE not found" >&2 + exit 1 + fi + else + ARGS+=("$ARG") + fi +done + +for ARG in "${ARGS[@]}"; do case "$ARG" in --scratch=*) - base_from_scratch "${ARG#--scratch=}" + base_from_scratch "${SCRATCH}" ;; --from=*) base_from "${ARG#--from=}" @@ -133,6 +159,8 @@ for ARG in "$@"; do # Get environment from existing config env=$(get_config | jq '(.config.Env // []) | map(. | split("=") | {"key": .[0], "value": .[1:] | join("=")})') while IFS= read -r expansion || [ -n "$expansion" ]; do + # Strip carriage return from Windows line endings + expansion="${expansion%$'\r'}" # collect all characters until a `=` is encountered key="${expansion%%=*}" # skip `length(k) + 1` to collect the rest. diff --git a/oci/private/image_index.bzl b/oci/private/image_index.bzl index 091ceabe..668430b4 100644 --- a/oci/private/image_index.bzl +++ b/oci/private/image_index.bzl @@ -1,5 +1,7 @@ "Implementation details for oci_image_index rule" +load("//oci/private:util.bzl", "util", "IS_EXEC_PLATFORM_WINDOWS_ATTRS") + _DOC = """Build a multi-architecture OCI compatible container image. It takes number of `oci_image` targets to create a fat multi-architecture image conforming to [OCI Image Index Specification](https://github.com/opencontainers/image-spec/blob/main/image-index.md). @@ -101,13 +103,13 @@ def _oci_image_index_impl(ctx): if len(ctx.attr.platforms) > 0 and len(ctx.attr.images) != len(ctx.attr.platforms): fail("platforms can only be specified when there is exactly one image in the images attribute.") - jq = ctx.toolchains["@aspect_bazel_lib//lib:jq_toolchain_type"] + jq = ctx.toolchains["@jq.bzl//jq/toolchain:type"] coreutils = ctx.toolchains["@aspect_bazel_lib//lib:coreutils_toolchain_type"] - launcher = ctx.actions.declare_file("image_index_{}.sh".format(ctx.label.name)) + bash_launcher = ctx.actions.declare_file("image_index_{}.sh".format(ctx.label.name)) ctx.actions.expand_template( template = ctx.file._image_index_sh_tpl, - output = launcher, + output = bash_launcher, is_executable = True, substitutions = { "{{jq_path}}": jq.jqinfo.bin.path, @@ -121,11 +123,12 @@ def _oci_image_index_impl(ctx): args.add(output.path, format = "--output=%s") args.add_all(ctx.files.images, map_each = _expand_image_to_args, expand_directories = False) + executable = util.maybe_wrap_launcher_for_windows(ctx, bash_launcher) ctx.actions.run( - inputs = ctx.files.images, + inputs = ctx.files.images + [bash_launcher], arguments = [args], outputs = [output], - executable = launcher, + executable = executable, tools = [jq.jqinfo.bin, coreutils.coreutils_info.bin], mnemonic = "OCIIndex", progress_message = "OCI Index %{label}", @@ -136,10 +139,11 @@ def _oci_image_index_impl(ctx): oci_image_index = rule( implementation = _oci_image_index_impl, - attrs = _attrs, + attrs = _attrs | IS_EXEC_PLATFORM_WINDOWS_ATTRS, doc = _DOC, toolchains = [ - "@aspect_bazel_lib//lib:jq_toolchain_type", + "@jq.bzl//jq/toolchain:type", "@aspect_bazel_lib//lib:coreutils_toolchain_type", + "@bazel_tools//tools/sh:toolchain_type", ], ) diff --git a/oci/private/load.bzl b/oci/private/load.bzl index 55acc195..bf91fcd5 100644 --- a/oci/private/load.bzl +++ b/oci/private/load.bzl @@ -20,7 +20,7 @@ docker run --rm my-repository:latest """ load("@aspect_bazel_lib//lib:paths.bzl", "BASH_RLOCATION_FUNCTION", "to_rlocation_path") -load("//oci/private:util.bzl", "util") +load("//oci/private:util.bzl", "util", "IS_EXEC_PLATFORM_WINDOWS_ATTRS") doc = """Loads an OCI layout into a container daemon without needing to publish the image first. @@ -130,8 +130,7 @@ attrs = { ), "_tarball_sh": attr.label(allow_single_file = True, default = "//oci/private:tarball.sh.tpl"), "_runfiles": attr.label(default = "@bazel_tools//tools/bash/runfiles"), - "_windows_constraint": attr.label(default = "@platforms//os:windows"), -} +} | IS_EXEC_PLATFORM_WINDOWS_ATTRS def _get_workspace_name(ctx, file): label = getattr(file, "owner", None) @@ -149,9 +148,9 @@ def _get_workspace_root_path(ctx, file): return file.root.path def _load_impl(ctx): - jq = ctx.toolchains["@aspect_bazel_lib//lib:jq_toolchain_type"] + jq = ctx.toolchains["@jq.bzl//jq/toolchain:type"] coreutils = ctx.toolchains["@aspect_bazel_lib//lib:coreutils_toolchain_type"] - bsdtar = ctx.toolchains["@aspect_bazel_lib//lib:tar_toolchain_type"] + bsdtar = ctx.toolchains["@tar.bzl//tar/toolchain:type"] image = ctx.file.image repo_tags = ctx.file.repo_tags @@ -259,8 +258,8 @@ oci_load = rule( toolchains = [ "@bazel_tools//tools/sh:toolchain_type", "@aspect_bazel_lib//lib:coreutils_toolchain_type", - "@aspect_bazel_lib//lib:jq_toolchain_type", - "@aspect_bazel_lib//lib:tar_toolchain_type", + "@jq.bzl//jq/toolchain:type", + "@tar.bzl//tar/toolchain:type", ], executable = True, ) diff --git a/oci/private/push.bzl b/oci/private/push.bzl index c2143a61..d0b24720 100644 --- a/oci/private/push.bzl +++ b/oci/private/push.bzl @@ -1,7 +1,8 @@ "Implementation details for the push rule" +load("//oci/private:util.bzl", "util", "is_windows_exec", "IS_EXEC_PLATFORM_WINDOWS_ATTRS") load("@aspect_bazel_lib//lib:paths.bzl", "BASH_RLOCATION_FUNCTION", "to_rlocation_path") -load("//oci/private:util.bzl", "util") +load("@aspect_bazel_lib//lib:windows_utils.bzl", "create_windows_native_launcher_script") _DOC = """Push an oci_image or oci_image_index to a remote registry. @@ -195,13 +196,12 @@ _attrs = { default = "push.sh.tpl", allow_single_file = True, ), - "_runfiles": attr.label(default = "@bazel_tools//tools/bash/runfiles"), - "_windows_constraint": attr.label(default = "@platforms//os:windows"), "_jq": attr.label( cfg = _transition_to_target, default = "@jq_toolchains//:resolved_toolchain", ), -} + "_runfiles": attr.label(default = "@bazel_tools//tools/bash/runfiles"), +} | IS_EXEC_PLATFORM_WINDOWS_ATTRS def _quote_args(args): return ["\"{}\"".format(arg) for arg in args] @@ -220,7 +220,7 @@ def _impl(ctx): if maybe_digest or maybe_tag: fail("`repository` attribute should not contain digest or tag. got: {}".format(ctx.attr.repository)) - executable = ctx.actions.declare_file("push_%s.sh" % ctx.label.name) + bash_launcher = ctx.actions.declare_file("push_%s.sh" % ctx.label.name) files = [ctx.file.image] substitutions = { "{{BASH_RLOCATION_FUNCTION}}": BASH_RLOCATION_FUNCTION, @@ -242,22 +242,25 @@ def _impl(ctx): ctx.actions.expand_template( template = ctx.file._push_sh_tpl, - output = executable, + output = bash_launcher, is_executable = True, substitutions = substitutions, ) + files.append(bash_launcher) + executable = create_windows_native_launcher_script(ctx, bash_launcher) if is_windows_exec(ctx) else bash_launcher runfiles = ctx.runfiles(files = files) runfiles = runfiles.merge(jq.default.default_runfiles) runfiles = runfiles.merge(ctx.attr.image[DefaultInfo].default_runfiles) runfiles = runfiles.merge(crane.default.default_runfiles) runfiles = runfiles.merge(ctx.attr._runfiles.default_runfiles) - - return DefaultInfo(executable = util.maybe_wrap_launcher_for_windows(ctx, executable), runfiles = runfiles) + return DefaultInfo(executable = executable, runfiles = runfiles) oci_push_lib = struct( implementation = _impl, attrs = _attrs, - toolchains = ["@bazel_tools//tools/sh:toolchain_type"], + toolchains = [ + "@bazel_tools//tools/sh:toolchain_type", + ], ) oci_push = rule( diff --git a/oci/private/push.sh.tpl b/oci/private/push.sh.tpl index 324107ec..b483a125 100644 --- a/oci/private/push.sh.tpl +++ b/oci/private/push.sh.tpl @@ -5,15 +5,15 @@ set -o pipefail -o errexit -o nounset runfiles_export_envvars -readonly CRANE="$(rlocation "{{crane_path}}")" -readonly JQ="$(rlocation "{{jq_path}}")" -readonly IMAGE_DIR="$(rlocation "{{image_dir}}")" -readonly TAGS_FILE="$(rlocation "{{tags}}")" +readonly CRANE="$(rlocation {{crane_path}})" +readonly JQ="$(rlocation {{jq_path}})" +readonly IMAGE_DIR="$(rlocation {{image_dir}})" +readonly TAGS_FILE="$(rlocation {{tags}})" readonly FIXED_ARGS=({{fixed_args}}) -readonly REPOSITORY_FILE="$(rlocation "{{repository_file}}")" +readonly REPOSITORY_FILE="$(rlocation {{repository_file}})" REPOSITORY="" -if [ -f "$REPOSITORY_FILE" ] ; then +if [ -n "$REPOSITORY_FILE" ] && [ -f $REPOSITORY_FILE ] ; then REPOSITORY=$(tr -d '\n' < "$REPOSITORY_FILE") fi @@ -75,6 +75,6 @@ do "${CRANE}" tag "${GLOBAL_FLAGS[@]+"${GLOBAL_FLAGS[@]}"}" $(cat "${REFS}") "${tag}" done -if [[ -e "${TAGS_FILE:-}" ]]; then +if [[ -n "${TAGS_FILE:-}" ]] && [[ -e "${TAGS_FILE:-}" ]]; then cat "${TAGS_FILE}" | xargs -r -n1 "${CRANE}" tag "${GLOBAL_FLAGS[@]+"${GLOBAL_FLAGS[@]}"}" $(cat "${REFS}") fi diff --git a/oci/private/tarball.sh.tpl b/oci/private/tarball.sh.tpl index cfc69bb9..d1370a25 100644 --- a/oci/private/tarball.sh.tpl +++ b/oci/private/tarball.sh.tpl @@ -1,6 +1,7 @@ #!/usr/bin/env bash # Produce an mtree specification file for creating a tarball in the form needed for `docker load`. # This doesn't actually run `tar` because that large output is often not required by any other actions in the graph and causes load on the cache. + set -o pipefail -o errexit -o nounset readonly FORMAT="{{format}}" @@ -69,6 +70,8 @@ if [[ "${FORMAT}" == "oci" ]]; then LAYER_DIGESTS=$("${JQ}" -r '.layers | map(.digest | sub(":"; "/"))' "${IMAGE_MANIFEST_BLOB_PATH}") for LAYER_DIGEST in $("${JQ}" -r ".[]" <<< $LAYER_DIGESTS); do + # remove control characters; causing test failures on windows + LAYER_DIGEST=$("${COREUTILS}" tr -d '[:cntrl:]' <<< "${LAYER_DIGEST}") add_to_tar "${IMAGE_DIR}/blobs/${LAYER_DIGEST}" blobs/${LAYER_DIGEST} done done @@ -95,6 +98,8 @@ LAYERS=$(${JQ} -cr '.layers | map(.digest | sub(":"; "/"))' ${MANIFEST_BLOB_PATH add_to_tar "${CONFIG_BLOB_PATH}" "blobs/${CONFIG_DIGEST}" for LAYER in $(${JQ} -r ".[]" <<< $LAYERS); do + # remove control characters; causing test failures on windows + LAYER=$("${COREUTILS}" tr -d '[:cntrl:]' <<< "${LAYER}") add_to_tar "${IMAGE_DIR}/blobs/${LAYER}" "blobs/${LAYER}.tar.gz" done diff --git a/oci/private/util.bzl b/oci/private/util.bzl index 90ea9a2a..a1e2288a 100644 --- a/oci/private/util.bzl +++ b/oci/private/util.bzl @@ -188,7 +188,46 @@ def _warning(rctx, message): "\033[0;33mWARNING:\033[0m {}".format(message), ], quiet = False) -def _maybe_wrap_launcher_for_windows(ctx, bash_launcher): +# From https://github.com/bazel-contrib/bazel-lib/pull/702 by thesayyn +def _is_exec_platform_windows(ctx): + is_windows = ctx.target_platform_has_constraint(ctx.attr._windows_constraint[platform_common.ConstraintValueInfo]) + executable = ctx.actions.declare_file("windows_exec.bats") + ctx.actions.write( + executable, + content = "@noop", + ) + + return [ + DefaultInfo(executable = executable), + OutputGroupInfo(windows = depset()) if is_windows else OutputGroupInfo(), + ] + +is_exec_platform_windows = rule( + implementation = _is_exec_platform_windows, + attrs = { + "_windows_constraint": attr.label(default = "@platforms//os:windows"), + }, +) + +IS_EXEC_PLATFORM_WINDOWS_ATTRS = { + "_is_platform_windows_exec": attr.label( + default = "//oci/private:is_exec_platform_windows", + executable = True, + cfg = "exec", + ), +} + +def is_windows_exec(ctx): + """Utility function for checking if the action run on windows. + + Args: + ctx: rule context + """ + + outputgroupinfo = ctx.attr._is_platform_windows_exec[OutputGroupInfo] + return hasattr(outputgroupinfo, "windows") + +def _maybe_wrap_launcher_for_windows(ctx, bash_launcher, use_subdir=False): """Windows cannot directly execute a shell script. Wrap with a .bat file that executes the shell script with a bash command. @@ -196,15 +235,26 @@ def _maybe_wrap_launcher_for_windows(ctx, bash_launcher): https://github.com/aspect-build/bazel-lib/blob/main/lib/windows_utils.bzl but without requiring that the script has a .runfiles folder. + Note: only works to wrap scripts generated in bazel-out. Will not wrap + scripts from the repo itself. + To use: - - add the _windows_constraint appears in the rule attrs - make sure the bash_launcher is in the inputs to the action - @bazel_tools//tools/sh:toolchain_type should appear in the rules toolchains """ - if not ctx.target_platform_has_constraint(ctx.attr._windows_constraint[platform_common.ConstraintValueInfo]): + if not is_windows_exec(ctx): return bash_launcher - win_launcher = ctx.actions.declare_file("wrap_%s.bat" % ctx.label.name) + if use_subdir: + win_launcher = ctx.actions.declare_file("%s/wrap_%s.bat" % (ctx.label.name, bash_launcher.basename.removesuffix(".sh"))) + else: + win_launcher = ctx.actions.declare_file("%s.bat" % bash_launcher.basename.removesuffix(".sh")) + bash_bin = ctx.toolchains["@bazel_tools//tools/sh:toolchain_type"].path.replace("/", "\\") + if "WINDOWS\\system32" in bash_bin: + print("WARNING: The bash binary is in the system32 directory, which may cause issues with the launcher script. Configure BAZEL_SH to reference a fully featured bash (e.g. git/msys2).") + if bash_bin == "\\bin\\bash": + print("WARNING: The bash binary path looks like a Unix path. Configure BAZEL_SH to reference a Windows path.") + ctx.actions.write( output = win_launcher, content = r"""@echo off @@ -222,7 +272,7 @@ if defined args ( ) "{bash_bin}" -c "%parent_dir%{launcher} !args!" """.format( - bash_bin = ctx.toolchains["@bazel_tools//tools/sh:toolchain_type"].path, + bash_bin = bash_bin, launcher = paths.relativize(bash_launcher.path, win_launcher.dirname), ), is_executable = True, diff --git a/oci/private/versions.bzl b/oci/private/versions.bzl index b263ace8..0f7f8142 100644 --- a/oci/private/versions.bzl +++ b/oci/private/versions.bzl @@ -1,7 +1,7 @@ "Mirror of release info" CRANE_VERSIONS = { - "v0.18.0": { + "v0.20.6": { "go-containerregistry-0": "sha256-Jc71fORYho8n/Jlk6jI+VQoqrhr9SuQIEUZIrCMl+UA=", "darwin_arm64": "sha256-1vp5e6uDqr+eXAsBqjdQv50ophXaHYrTCD0PUn5vvuY=", "darwin_x86_64": "sha256-mX1dkeqEHemwwj+fuCvIqfs8OJsNiPoAab816pTCmX8=", @@ -10,10 +10,10 @@ CRANE_VERSIONS = { "linux_i386": "sha256-tGlnKAaPEIqLbiq5iZGTMs8YAY0rVm9QaYp+cA/jvG0=", "linux_ppc64le": "sha256-vLHAkrKcCgkKCjYYSbwanG9yMIfk5IRQTiuhm4/kuLU=", "linux_s390x": "sha256-b9IoSBjkeKE7KTDf23rYmdCLg9SwWE3oPmAVtb4Dv0k=", - "linux_x86_64": "sha256-zfTUJtll2ai6YT1+vzrd+TEBqi6FOj8I+/2u0oI5GPM=", - "windows_arm64": "sha256-hpOhAEjn1gOMR/pt1jjabGX26Cg5IzcDY1YrE+v2RS8=", - "windows_armv6": "sha256-+jTBS3mcqaVdt+x9S8FiUpbOPG6slBxPYW2QPaa4BE0=", - "windows_x86_64": "sha256-EerTSy1+/uaOcgfanzk5kTHpPkufFou01xtghEj6nco=", + "linux_x86_64": "sha256-wdWT0BVR8smj31ygoL5Dhag5vZuG1KduGNexfRZVkSc=", + "windows_arm64": "sha256-gPhIch4F0ogiPUebW++ew7AmB2rWADGvJLo4CY63Gbc=", + "windows_armv6": "sha256-i5pR8nbPkB96Zq+FtSG0YcyrGyYei9x5ncIwsOdfjcw=", + "windows_x86_64": "sha256-OZSR76HYjR7hjGZC0CWqDGekm/6ClwM/tIWxJyrXDJ0=", }, } diff --git a/oci/tests/BUILD.bazel b/oci/tests/BUILD.bazel index 17abd571..3de09e71 100644 --- a/oci/tests/BUILD.bazel +++ b/oci/tests/BUILD.bazel @@ -22,6 +22,13 @@ genrule( toolchains = ["@oci_crane_toolchains//:current_toolchain"], ) +genrule( + name = "crane_gen_windows", + outs = ["crane.bat"], + cmd = "echo '@echo off' > $@ && echo 'set CRANE_PATH=$(CRANE_BIN)' >> $@ && echo 'set CRANE_PATH=%CRANE_PATH:/=\\%' >> $@ && echo '%CRANE_PATH% %*' >> $@", + toolchains = ["@oci_crane_toolchains//:current_toolchain"], +) + # Use crane to pull images as a comparison for our oci_pull repository rule [ run_binary( @@ -43,7 +50,12 @@ genrule( reference = reference, ), tags = ["requires-network"], - tool = "crane.sh", + tool = select( + { + "@platforms//os:windows": ":crane.bat", + "//conditions:default": ":crane.sh", + } + ), visibility = ["//visibility:public"], ) for platform in IMAGES_TO_TEST.keys() diff --git a/oci/tests/pull_tests.bzl b/oci/tests/pull_tests.bzl index a7ccc992..fdf472ae 100644 --- a/oci/tests/pull_tests.bzl +++ b/oci/tests/pull_tests.bzl @@ -39,8 +39,19 @@ def _parse_image_test_impl(ctx): parse_image_test = unittest.make(_parse_image_test_impl) +def _windows_host(ctx): + """Returns true if the host platform is windows. + + The typical approach using ctx.target_platform_has_constraint does not work for transitioned + build targets. We need to know the host platform, not the target platform. + """ + return ctx.configuration.host_path_separator == ";" + def _parse_www_authenticate_test_impl(ctx): env = unittest.begin(ctx) + # TODO: enable on windows + if _windows_host(ctx): + return unittest.end(env) asserts.equals( env, { diff --git a/tools/tools.lock.json b/tools/tools.lock.json index 09ddcbb0..000e3d81 100644 --- a/tools/tools.lock.json +++ b/tools/tools.lock.json @@ -22,6 +22,13 @@ "sha256": "d8af275d61e770a8cf552d893e03ac4b5938517ea875fb5f7b7275e381358c92", "os": "macos", "cpu": "x86_64" + }, + { + "kind": "file", + "url": "https://github.com/docker/buildx/releases/download/v0.20.1/buildx-v0.20.1.windows-amd64.exe", + "sha256": "39f53ec70c6ce37beca6898809e8eb89a77a1651be35ea50b51629c7a5d3b1f2", + "os": "windows", + "cpu": "x86_64" } ] }, @@ -50,6 +57,14 @@ "sha256": "e793fa4531d5216107b84b87f191c582ee9378254f17b5aabcf0fa3010293ae7", "os": "macos", "cpu": "x86_64" + }, + { + "kind": "archive", + "url": "https://download.docker.com/win/static/stable/x86_64/docker-23.0.0.zip", + "file": "docker/docker.exe", + "sha256": "7cdf8dfb19b545079bee399b927b77220987b0428501e0d1525311d31ca8b29e", + "os": "windows", + "cpu": "x86_64" } ] }, @@ -82,6 +97,13 @@ "sha256": "bd6f3b3b93032f47ad2c017e92df302651c9a649f4b533455371877eaaa76585", "os": "macos", "cpu": "x86_64" + }, + { + "kind": "file", + "url": "https://github.com/docker/compose/releases/download/v2.32.4/docker-compose-windows-x86_64.exe", + "sha256": "5df58bb738c7ac2712c031e15154b49f32f4026640d8c0539090d6e0a66d6dfd", + "os": "windows", + "cpu": "x86_64" } ] }, @@ -107,6 +129,13 @@ "sha256": "7cda0be31188f8388ba537161a4f3aaaaba58bca5707be86980de759ae90c2b7", "os": "macos", "cpu": "x86_64" + }, + { + "kind": "file", + "url": "https://github.com/josephburnett/jd/releases/download/v1.9.1/jd-amd64-windows.exe", + "sha256": "6421f25f518f9861286ce5b7c5d2a8c7aa8d86e03cd14ef8f8520724cb49a9ca", + "os": "windows", + "cpu": "x86_64" } ] }, @@ -143,6 +172,14 @@ "sha256": "abde3bbbd49a09d33048e1f55cc9a8aa5dd61a13493a0b1bd5ffc2c56e5bf837", "os": "macos", "cpu": "x86_64" + }, + { + "kind": "archive", + "url": "https://github.com/theoremlp/multitool/releases/download/v0.9.0/multitool-x86_64-pc-windows-msvc.zip", + "file": "multitool.exe", + "sha256": "df058283b8d23fd56f8accee3ad218faef20d5bd81735c2615626aeca46d2158", + "os": "windows", + "cpu": "x86_64" } ] }