From a146e5689f9dc371043ca28cfade0d7eb3611c21 Mon Sep 17 00:00:00 2001 From: Quentin Boileau Date: Wed, 19 Aug 2026 10:38:53 +0200 Subject: [PATCH 1/4] Fix setup-chainguard-tool composit action to support arm64 runners --- .../actions/setup-chainguard-tool/README.md | 14 +++++----- .../actions/setup-chainguard-tool/action.yml | 11 +++++--- .../scripts/resolve-release.sh | 26 ++++++++++++++----- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/.github/actions/setup-chainguard-tool/README.md b/.github/actions/setup-chainguard-tool/README.md index ef4ed1a..6e6636a 100644 --- a/.github/actions/setup-chainguard-tool/README.md +++ b/.github/actions/setup-chainguard-tool/README.md @@ -1,8 +1,9 @@ # setup-chainguard-tool Local composite action that installs a Chainguard Go CLI — [apko](https://github.com/chainguard-dev/apko) -or [melange](https://github.com/chainguard-dev/melange) — on a `linux/amd64` -GitHub-hosted runner. +or [melange](https://github.com/chainguard-dev/melange) — on a `linux/amd64` or +`linux/arm64` GitHub-hosted runner. Both are needed: the `apks` jobs run +natively on a runner of the arch they build. There is no first-party `chainguard-dev/actions/setup-apko` upstream, and `curl | sh` is not a supply-chain story we want to tell. So we ship our own @@ -10,8 +11,8 @@ installer that: 1. Resolves the requested version (or `latest`) to an immutable release tag and dereferences it to the commit SHA the tag points at. -2. Downloads `__linux_amd64.tar.gz` + `checksums.txt` from the - release. +2. Downloads `__linux_.tar.gz` + `checksums.txt` + from the release. 3. Verifies `checksums.txt` was signed by that project's release workflow using Sigstore keyless (cosign `verify-blob` against Fulcio + Rekor). 4. Verifies the SHA-256 of the archive matches the entry in `checksums.txt`. @@ -23,7 +24,7 @@ installer that: ## Why one action for both Chainguard's CLIs are goreleaser-built to the same shape — the archive is -`__linux_amd64.tar.gz`, it sits beside a cosign-signed +`__linux_.tar.gz`, it sits beside a cosign-signed `checksums.txt`, and ` version` prints `GitVersion:` / `GitCommit:`. Only the name varies, so the tool is an input rather than a second copy of the scripts. @@ -61,7 +62,7 @@ This downloads one verified binary instead. | `verify-signature` | `"true"` | Verify the Sigstore signature of `checksums.txt`. | | `cosign-certificate-identity-regexp` | the tool's own release workflows | Cosign identity regex for the release signer. | | `cosign-oidc-issuer` | `https://token.actions.githubusercontent.com` | Cosign OIDC issuer. | -| `install-dir` | `///amd64` | Where to install the binary. | +| `install-dir` | `///` | Where to install the binary. | ## Outputs @@ -70,6 +71,7 @@ This downloads one verified binary instead. | `version` | Installed version without the leading `v` (e.g. `1.2.30`). | | `tag` | Release tag installed (e.g. `v1.2.30`). | | `commit-sha` | Commit SHA the release tag dereferences to (also verified against the binary). | +| `arch` | Release architecture installed for this runner (`amd64` or `arm64`). | | `sha256` | SHA-256 of the downloaded archive. | | `path` | Full path to the installed binary. | | `install-dir` | Directory added to `PATH`. | diff --git a/.github/actions/setup-chainguard-tool/action.yml b/.github/actions/setup-chainguard-tool/action.yml index dfb1ad2..de22b6e 100644 --- a/.github/actions/setup-chainguard-tool/action.yml +++ b/.github/actions/setup-chainguard-tool/action.yml @@ -1,9 +1,9 @@ name: "Setup Chainguard tool" description: > - Install a Chainguard Go CLI (apko, melange, ...) on a linux/amd64 runner. - Resolves the requested version (or the latest release) to an immutable - release tag + commit sha1, verifies the downloaded archive against the - release SHA-256 checksums and their Sigstore (cosign keyless) signature, + Install a Chainguard Go CLI (apko, melange, ...) on a linux/amd64 or + linux/arm64 runner. Resolves the requested version (or the latest release) to + an immutable release tag + commit sha1, verifies the downloaded archive against + the release SHA-256 checksums and their Sigstore (cosign keyless) signature, then verifies the installed binary reports the expected tag and commit. # One action for every Chainguard CLI: their releases are goreleaser-built to @@ -68,6 +68,9 @@ outputs: commit-sha: description: Commit sha1 the release tag points at, also verified against the installed binary. value: ${{ steps.resolve.outputs.commit-sha }} + arch: + description: Release architecture installed for this runner, amd64 or arm64. + value: ${{ steps.resolve.outputs.arch }} sha256: description: SHA-256 checksum of the downloaded release archive. value: ${{ steps.install.outputs.sha256 }} diff --git a/.github/actions/setup-chainguard-tool/scripts/resolve-release.sh b/.github/actions/setup-chainguard-tool/scripts/resolve-release.sh index a920ab1..be78b95 100755 --- a/.github/actions/setup-chainguard-tool/scripts/resolve-release.sh +++ b/.github/actions/setup-chainguard-tool/scripts/resolve-release.sh @@ -4,14 +4,25 @@ # installed. # # Inputs (env): TOOL, REPOSITORY, VERSION, EXPECTED_COMMIT_SHA, INSTALL_DIR_INPUT, GH_TOKEN -# Outputs (GITHUB_OUTPUT): tag, version, commit-sha, archive, install-dir +# Outputs (GITHUB_OUTPUT): tag, version, commit-sha, arch, archive, install-dir set -euo pipefail -# This action only ships the linux/amd64 release archive. -if [ "$(uname -s)" != "Linux" ] || [ "$(uname -m)" != "x86_64" ]; then - echo "::error::setup-chainguard-tool only supports linux/amd64 runners (got $(uname -s)/$(uname -m))" +# The runner's own architecture, not the image's: this picks which release +# archive to download. `apks` jobs run natively on an arm64 runner, so hardcoding +# amd64 here fails half the matrix. RUNNER_ARCH is what GitHub sets; uname is the +# fallback for local runs, and both spellings of each arch are accepted. +if [ "$(uname -s)" != "Linux" ]; then + echo "::error::setup-chainguard-tool only supports Linux runners (got $(uname -s))" exit 1 fi +case "${RUNNER_ARCH:-$(uname -m)}" in + X64 | x86_64 | amd64) ARCH="amd64" ;; + ARM64 | aarch64 | arm64) ARCH="arm64" ;; + *) + echo "::error::setup-chainguard-tool has no release archive for ${RUNNER_ARCH:-$(uname -m)}" + exit 1 + ;; +esac # Resolve the requested version to an immutable release tag. if [ -z "${VERSION}" ] || [ "${VERSION}" = "latest" ]; then @@ -51,15 +62,16 @@ fi INSTALL_DIR="${INSTALL_DIR_INPUT}" if [ -z "${INSTALL_DIR}" ]; then - INSTALL_DIR="${RUNNER_TOOL_CACHE:-${HOME}/.cache}/${TOOL}/${TAG}/amd64" + INSTALL_DIR="${RUNNER_TOOL_CACHE:-${HOME}/.cache}/${TOOL}/${TAG}/${ARCH}" fi -echo "${TOOL} ${TAG} (${COMMIT_SHA}) for linux/amd64 -> ${INSTALL_DIR}" +echo "${TOOL} ${TAG} (${COMMIT_SHA}) for linux/${ARCH} -> ${INSTALL_DIR}" { echo "tag=${TAG}" echo "version=${VERSION_NUMBER}" echo "commit-sha=${COMMIT_SHA}" - echo "archive=${TOOL}_${VERSION_NUMBER}_linux_amd64.tar.gz" + echo "arch=${ARCH}" + echo "archive=${TOOL}_${VERSION_NUMBER}_linux_${ARCH}.tar.gz" echo "install-dir=${INSTALL_DIR}" } >> "${GITHUB_OUTPUT}" From 4494cd7e3f102cf5ba687162a7cf125cb8992606 Mon Sep 17 00:00:00 2001 From: Quentin Boileau Date: Wed, 19 Aug 2026 12:43:01 +0200 Subject: [PATCH 2/4] ci: port setup-bubblewrap in a small composit action --- .github/actions/setup-bubblewrap/README.md | 48 +++++++++++++++++++ .github/actions/setup-bubblewrap/action.yml | 13 +++++ .../scripts/setup-bubblewrap.sh | 37 ++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 .github/actions/setup-bubblewrap/README.md create mode 100644 .github/actions/setup-bubblewrap/action.yml create mode 100755 .github/actions/setup-bubblewrap/scripts/setup-bubblewrap.sh diff --git a/.github/actions/setup-bubblewrap/README.md b/.github/actions/setup-bubblewrap/README.md new file mode 100644 index 0000000..011ca3d --- /dev/null +++ b/.github/actions/setup-bubblewrap/README.md @@ -0,0 +1,48 @@ +# setup-bubblewrap + +Installs [bubblewrap](https://github.com/containers/bubblewrap) so melange can +use its default Linux runner, and nothing else. + +## Why this exists separately + +melange resolves an empty `--runner` to bubblewrap on Linux, and then requires +`bwrap` on `PATH` plus a working `bwrap --unshare-user` before it will build. +Neither holds on a stock `ubuntu-24.04` runner: bubblewrap is not in the image, +and 24.04 blocks unprivileged user namespaces through apparmor +([melange#1508](https://github.com/chainguard-dev/melange/issues/1508)). + +`chainguard-dev/actions/setup-melange` fixes both, but also installs a Go +toolchain, `build-essential` and `qemu-user-static`, and finishes by +`curl`-installing an unverified melange tarball into `/usr/local/bin`. In this +repo melange is installed by [`setup-chainguard-tool`](../setup-chainguard-tool), +which verifies the release checksums against their Sigstore signature and asserts +the binary reports the pinned commit — so the only piece worth keeping is the +sandbox setup. The Go toolchain only matters for `version: tip` (building melange +from source) and qemu only for emulating a foreign arch, which the `apks` jobs +never do: each runs natively on a runner of its own arch. + +## Usage + +```yaml +- name: Install melange + uses: ./.github/actions/setup-chainguard-tool + with: + tool: melange + version: v0.41.1 + # sudo's secure_path is what `sudo melange` searches. + install-dir: /usr/local/bin + +- name: Setup bubblewrap + uses: ./.github/actions/setup-bubblewrap +``` + +No inputs, no outputs. The two steps are lifted from `setup-melange`, with one +change: `apt-get install` runs against the image's existing apt lists and only +falls back to `apt-get update` if they are too stale. Upstream needs no fallback +because its qemu step already ran `apt update` — the step that stalled this job +for 20+ minutes when the runner's Azure mirror was degraded. + +Verification is upstream's `bwrap --unshare-user --bind / / true`, unprivileged. +That is stricter than our builds need — `melange-build-pkg` runs +`sudo melange build`, and as root melange never asks for a uid map, so apparmor's +userns restriction does not apply — but it fails at setup rather than mid-build. diff --git a/.github/actions/setup-bubblewrap/action.yml b/.github/actions/setup-bubblewrap/action.yml new file mode 100644 index 0000000..5ce8a6a --- /dev/null +++ b/.github/actions/setup-bubblewrap/action.yml @@ -0,0 +1,13 @@ +name: "Setup bubblewrap" +description: > + Install bubblewrap and the apparmor profile melange's default Linux runner + needs on a GitHub-hosted Ubuntu runner, without the Go toolchain, qemu and + unverified melange download that chainguard-dev/actions/setup-melange also + brings. Pair it with setup-chainguard-tool, which installs melange itself. + +runs: + using: composite + steps: + - name: Install bubblewrap + shell: bash + run: "${{ github.action_path }}/scripts/setup-bubblewrap.sh" diff --git a/.github/actions/setup-bubblewrap/scripts/setup-bubblewrap.sh b/.github/actions/setup-bubblewrap/scripts/setup-bubblewrap.sh new file mode 100755 index 0000000..50ef82b --- /dev/null +++ b/.github/actions/setup-bubblewrap/scripts/setup-bubblewrap.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# Install bubblewrap, melange's default Linux runner, which the runner image does +# not ship. Adapted from chainguard-dev/actions/setup-melange, minus the Go +# toolchain, qemu and the unverified melange download — see the README. +set -euo pipefail + +# Only refresh the index if the image's apt lists turn out to be too stale: that +# update is the mirror round trip that has stalled this job for 20+ minutes. +sudo apt-get install --assume-yes bubblewrap \ + || { sudo apt-get update && sudo apt-get install --assume-yes bubblewrap; } + +# https://github.com/chainguard-dev/melange/issues/1508 +sudo tee /etc/apparmor.d/local-bwrap >/dev/null <<"EOF" +abi , +include + +profile local-bwrap /usr/bin/bwrap flags=(unconfined) { + userns, + # Site-specific additions and overrides. See local/README for details. + include if exists +} +EOF + +sudo systemctl reload apparmor + +if ! bwrap --unshare-user --bind / / true; then + echo "::error::failed to verify 'bwrap --unshare-user'" + command -v bwrap || : + ls /proc/self/ns || echo "no /proc/self/ns" + kver="$(uname -r)" || echo "uname -r failed" + if [ -f "/boot/config-${kver}" ]; then + grep CONFIG_USER_NS "/boot/config-${kver}" || echo "no CONFIG_USER_NS in /boot/config-${kver}" + fi + exit 1 +fi + +echo "bubblewrap (bwrap) installed successfully." From 34ef0909420736f2117958671e362acf51a1f6dd Mon Sep 17 00:00:00 2001 From: Quentin Boileau Date: Wed, 19 Aug 2026 12:43:50 +0200 Subject: [PATCH 3/4] ci: allow download in specific directory --- .../scripts/download-and-verify.sh | 11 +- .../tests/test-resolve-release.sh | 127 ++++++++++++++++++ 2 files changed, 136 insertions(+), 2 deletions(-) create mode 100755 .github/actions/setup-chainguard-tool/tests/test-resolve-release.sh diff --git a/.github/actions/setup-chainguard-tool/scripts/download-and-verify.sh b/.github/actions/setup-chainguard-tool/scripts/download-and-verify.sh index 1c948e8..6ba8322 100755 --- a/.github/actions/setup-chainguard-tool/scripts/download-and-verify.sh +++ b/.github/actions/setup-chainguard-tool/scripts/download-and-verify.sh @@ -58,8 +58,15 @@ if [ -z "${BINARY}" ]; then exit 1 fi -mkdir -p "${INSTALL_DIR}" -install -m 0755 "${BINARY}" "${INSTALL_DIR}/${TOOL}" +# A root-owned install-dir is deliberate: `sudo melange` (what melange-build-pkg +# runs) searches sudo's secure_path, which the tool cache is not in. +SUDO=() +mkdir -p "${INSTALL_DIR}" 2>/dev/null || true +if [ ! -w "${INSTALL_DIR}" ]; then + SUDO=(sudo) + "${SUDO[@]}" mkdir -p "${INSTALL_DIR}" +fi +"${SUDO[@]}" install -m 0755 "${BINARY}" "${INSTALL_DIR}/${TOOL}" echo "${INSTALL_DIR}" >> "${GITHUB_PATH}" { diff --git a/.github/actions/setup-chainguard-tool/tests/test-resolve-release.sh b/.github/actions/setup-chainguard-tool/tests/test-resolve-release.sh new file mode 100755 index 0000000..c316e62 --- /dev/null +++ b/.github/actions/setup-chainguard-tool/tests/test-resolve-release.sh @@ -0,0 +1,127 @@ +#!/usr/bin/env bash +# +# Tests for setup-chainguard-tool's resolve-release.sh. +# No network: `gh` is stubbed on PATH. +# +# The arch mapping is the point: it only runs on the runner it resolves for, so an +# amd64-only assumption passes every local check and every x86_64 job, and fails +# exactly one thing — the aarch64 `apks` job in the nightly. +# Silent on success; prints only failures. +set -euo pipefail + +SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/scripts/resolve-release.sh" +TMP="$(mktemp -d)" +trap 'rm -rf "${TMP}"' EXIT + +checks=0 +fails=0 +fail() { fails=$((fails + 1)); echo " FAIL $1" >&2; } +assert_eq() { + checks=$((checks + 1)) + if [ "$2" != "$3" ]; then + echo " FAIL $1: want '$2', got '$3'" >&2 + fails=$((fails + 1)) + fi +} + +mkdir -p "${TMP}/bin" +cat > "${TMP}/bin/gh" <<'STUB' +#!/usr/bin/env bash +case "$*" in + *"git/ref/tags/"*) echo "${STUB_OBJECT_TYPE:-commit} ${STUB_SHA:-c0ffee1111111111111111111111111111111111}" ;; + *"git/tags/"*) echo "${STUB_DEREF_SHA:-deadbeef2222222222222222222222222222222}" ;; + *"release view"*) echo "${STUB_LATEST_TAG:-v9.9.9}" ;; + *) echo "unexpected gh call: $*" >&2; exit 1 ;; +esac +STUB +chmod +x "${TMP}/bin/gh" +export PATH="${TMP}/bin:${PATH}" + +# Echoes the script's `key=value` outputs. The status is returned explicitly: +# errexit is suppressed inside an `if` condition, so the trailing `cat` would +# otherwise report success for a failed script. +resolve() { + local out="${TMP}/out" rc=0 + : > "${out}" + env GITHUB_OUTPUT="${out}" \ + RUNNER_TOOL_CACHE="${TMP}/tool-cache" \ + TOOL="${TOOL:-melange}" \ + REPOSITORY="${REPOSITORY:-chainguard-dev/melange}" \ + VERSION="${VERSION:-v0.41.1}" \ + EXPECTED_COMMIT_SHA="${EXPECTED_COMMIT_SHA:-}" \ + INSTALL_DIR_INPUT="${INSTALL_DIR_INPUT:-}" \ + "$@" "${SCRIPT}" >/dev/null || rc=$? + cat "${out}" + return "${rc}" +} +value() { sed -n "s/^$2=//p" <<<"$1"; } + +# --- arch mapping ----------------------------------------------------------- +# Both spellings reach the script: GitHub sets RUNNER_ARCH=X64/ARM64, a local run +# falls back to uname's x86_64/aarch64. +for arch in X64 x86_64 amd64; do + out="$(resolve RUNNER_ARCH="${arch}")" + assert_eq "${arch} resolves to amd64" "amd64" "$(value "${out}" arch)" + assert_eq "${arch} picks the amd64 archive" \ + "melange_0.41.1_linux_amd64.tar.gz" "$(value "${out}" archive)" +done + +for arch in ARM64 aarch64 arm64; do + out="$(resolve RUNNER_ARCH="${arch}")" + assert_eq "${arch} resolves to arm64" "arm64" "$(value "${out}" arch)" + assert_eq "${arch} picks the arm64 archive" \ + "melange_0.41.1_linux_arm64.tar.gz" "$(value "${out}" archive)" +done + +# Per-arch, so a cached amd64 binary can never be served to an arm64 job. +out="$(resolve RUNNER_ARCH=ARM64)" +assert_eq "install dir is arch-scoped" \ + "${TMP}/tool-cache/melange/v0.41.1/arm64" "$(value "${out}" install-dir)" + +checks=$((checks + 1)) +if resolve RUNNER_ARCH=ARMV7 >/dev/null 2>&1; then + fail "an arch with no release archive should exit non-zero" +fi + +# --- version + tag resolution ----------------------------------------------- +out="$(TOOL=apko REPOSITORY=chainguard-dev/apko VERSION=1.2.30 resolve RUNNER_ARCH=X64)" +assert_eq "a version without the v still tags" "v1.2.30" "$(value "${out}" tag)" +assert_eq "version output drops the v" "1.2.30" "$(value "${out}" version)" +assert_eq "tool name drives the archive prefix" \ + "apko_1.2.30_linux_amd64.tar.gz" "$(value "${out}" archive)" + +out="$(VERSION=latest resolve RUNNER_ARCH=X64 STUB_LATEST_TAG=v1.2.31)" +assert_eq "latest resolves through gh release view" "v1.2.31" "$(value "${out}" tag)" + +out="$(resolve RUNNER_ARCH=X64 STUB_OBJECT_TYPE=commit STUB_SHA=abc1234567890def1234567890abcdef12345678)" +assert_eq "a lightweight tag is used as-is" \ + "abc1234567890def1234567890abcdef12345678" "$(value "${out}" commit-sha)" + +# An annotated tag's ref points at the tag object, not the commit, so the pin +# would otherwise be compared against a sha `uses:` never sees. +out="$(resolve RUNNER_ARCH=X64 STUB_OBJECT_TYPE=tag \ + STUB_DEREF_SHA=99991234567890def1234567890abcdef1234567)" +assert_eq "an annotated tag is dereferenced" \ + "99991234567890def1234567890abcdef1234567" "$(value "${out}" commit-sha)" + +# --- pins ------------------------------------------------------------------- +checks=$((checks + 1)) +if ! EXPECTED_COMMIT_SHA=abc1234 resolve RUNNER_ARCH=X64 \ + STUB_SHA=abc1234567890def1234567890abcdef12345678 >/dev/null 2>&1; then + fail "an abbreviated expected-commit-sha should match its full sha" +fi + +checks=$((checks + 1)) +if EXPECTED_COMMIT_SHA=0000000 resolve RUNNER_ARCH=X64 >/dev/null 2>&1; then + fail "a mismatched expected-commit-sha should exit non-zero" +fi + +# --- explicit install dir --------------------------------------------------- +out="$(INSTALL_DIR_INPUT=/usr/local/bin resolve RUNNER_ARCH=X64)" +assert_eq "an explicit install-dir wins" "/usr/local/bin" "$(value "${out}" install-dir)" + +if [ "${fails}" -ne 0 ]; then + echo "resolve-release: ${fails}/${checks} failed" >&2 + exit 1 +fi +echo "resolve-release: ${checks} checks passed" From 7ad12638833d6e2ba07caedd25e3e0a74b70ec38 Mon Sep 17 00:00:00 2001 From: Quentin Boileau Date: Wed, 19 Aug 2026 12:44:35 +0200 Subject: [PATCH 4/4] ci: refactore melange build to not use melange-build action that re-setup melange --- .github/workflows/build.yml | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da72083..d01c388 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -130,6 +130,11 @@ jobs: with: tool: melange version: ${{ env.MELANGE_VERSION }} + # melange-build-pkg runs `sudo melange`, which searches secure_path. + install-dir: /usr/local/bin + + - name: Setup bubblewrap + uses: ./.github/actions/setup-bubblewrap # melange never writes to its own cache, so a miss must be filled here. - name: Prefetch melange sources @@ -137,25 +142,33 @@ jobs: DIR: ${{ matrix.apk.dir }} run: ./scripts/melange-sources.sh "${DIR}" --prefetch "${{ runner.temp }}/melange-cache" + # These two rather than the melange-build wrapper around them: that wrapper + # starts with setup-melange, which apt-installs a Go toolchain and qemu on + # every job, then curls an unverified melange over the one installed above. + # # The temporary signing key is per-job and thrown away with the runner: # the build job re-indexes every arch under one key of its own - # (scripts/melange-index.sh). It cannot be skipped here — melange-build + # (scripts/melange-index.sh). It cannot be skipped here — melange-build-pkg # adds `--keyring-append .pub` for every config after the first. + - name: Generate a temporary melange signing key + uses: chainguard-dev/actions/melange-keygen@bed8050123fff65538e2db1902ff9404030c0221 # v1.6.31 + with: + # Absolute paths so the key and the packages land where apko.yaml's + # `@local ./packages` and `./melange.rsa.pub` resolve from the image dir. + signing-key-path: ${{ github.workspace }}/images/${{ matrix.apk.dir }}/melange.rsa + - name: Build local APKs with melange - uses: chainguard-dev/actions/melange-build@bed8050123fff65538e2db1902ff9404030c0221 # v1.6.31 + uses: chainguard-dev/actions/melange-build-pkg@bed8050123fff65538e2db1902ff9404030c0221 # v1.6.31 with: - version: ${{ env.MELANGE_VERSION }} multi-config: ${{ matrix.apk.configs }} workdir: images/${{ matrix.apk.dir }} archs: ${{ matrix.apk.arch }} - sign-with-temporary-key: true + sign-with-key: true # Trivy skips packages whose PURL namespace doesn't match the image's # distro, so without this our own packages' CVEs go unreported. namespace: wolfi # Absolute: melange runs under sudo, where ~ is root's home. cache-dir: ${{ runner.temp }}/melange-cache - # Absolute paths so they land where apko.yaml's `@local ./packages` - # and `./melange.rsa.pub` resolve from the image directory. signing-key-path: ${{ github.workspace }}/images/${{ matrix.apk.dir }}/melange.rsa repository-path: ${{ github.workspace }}/images/${{ matrix.apk.dir }}/packages