Files
Ekklesia/scripts/lib/module-package-release.sh
T
ekklesiaandClaude Opus 5.5 27d85e0162
CI / verify (pull_request) Successful in 58s
CI / infrastructure-smoke (pull_request) Successful in 36s
CI / migration-smoke (pull_request) Successful in 1m51s
CI / image-build (pull_request) Successful in 22s
CI / deploy-smoke (same-origin) (pull_request) Successful in 42s
CI / deploy-smoke (split) (pull_request) Successful in 1m31s
fix(smoke): hand the verifier the package's archive and digest as one readable release pair
The split deploy smoke failed in CI with "The SHA-256 file could not be read."
BuildKit's local exporter creates its output directory (`--output
type=local,dest=$work/module-package`) with mode 0700, owned by whoever ran the
build. That directory was mounted into the verifier, which runs as the image's
unprivileged `node` user (uid 1000). In CI the build runs as root, so the
directory was root:root 0700 and the verifier could read neither file; the
digest file is simply read first. On a workstation the build runs as uid 1000,
the same uid as `node`, so it was readable by coincidence.

scripts/lib/module-package-release.sh turns one build's output into the release
pair: it requires exactly one archive and its .sha256 and nothing else, checks
that the digest line names that archive, then creates a fresh directory that
must not exist yet (0755) and copies both files into it (0644). The smoke stages
and mounts only that directory; BuildKit's output directory is never mounted.
Archive-digest verification stays mandatory: the verifier still reads the
.sha256 file. Nothing in the verifier changed.

Tests: the helper is driven in bash against a 0700 build output, and refuses a
missing, malformed, or mismatched digest, stray output, a second archive, and
an existing release directory, creating nothing. A static test pins the smoke
to the release pair and the verifier's single mount with --sha256-file.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 13:10:58 -05:00

54 lines
2.3 KiB
Bash

# shellcheck shell=bash
# The deploy smoke test's module package release pair (ADR 0049).
#
# A package archive and its `.sha256` are one logical release: they travel together, and the
# verifier reads both. This turns one build's output into exactly that pair, in a directory any user
# can traverse, because the verifier runs as the image's unprivileged user.
#
# BuildKit's local exporter creates its output directory with mode 0700, owned by whoever ran the
# build. On a workstation that is usually uid 1000, which is also the image's `node` user, so the
# verifier happened to read it; in CI the build runs as root, and the verifier could read neither file.
# Nothing here depends on who built the package.
# module_package_release <build output directory> <new release directory>
#
# Checks the build output holds exactly one archive and its digest and nothing else, and that the
# digest line names that archive. Then creates the release directory, which must not exist yet (so an
# earlier run's files can never be mixed in), mode 0755, and copies both files into it, mode 0644.
# Prints the archive's file name. Fails, creating nothing, on any deviation.
module_package_release() {
local output="$1" release="$2" archives=() archive digest_line digest named entries
shopt -s nullglob
archives=("$output"/*.tar.gz)
shopt -u nullglob
if ((${#archives[@]} != 1)); then
echo "module_package_release: the build output must hold exactly one package archive." >&2
return 1
fi
archive="$(basename -- "${archives[0]}")"
if [[ ! -f "$output/$archive.sha256" ]]; then
echo "module_package_release: the package's .sha256 is missing." >&2
return 1
fi
entries="$(find "$output" -mindepth 1 -maxdepth 1 | wc -l)"
if ((entries != 2)); then
echo "module_package_release: the build output holds more than the archive and its digest." >&2
return 1
fi
digest_line="$(<"$output/$archive.sha256")"
digest="${digest_line%% *}"
named="${digest_line#* }"
if [[ ! "$digest" =~ ^[0-9a-f]{64}$ || "$named" != "$archive" ]]; then
echo "module_package_release: the .sha256 line does not name this archive." >&2
return 1
fi
mkdir -m 755 -- "$release" || return 1
if ! install -m 0644 -- "$output/$archive" "$output/$archive.sha256" "$release/"; then
rm -rf -- "$release"
return 1
fi
printf '%s\n' "$archive"
}