From ee3d482090a23af22b72d3350c985e1ecaa8c8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99ska?= <372403+keskad@users.noreply.github.com> Date: Thu, 6 Aug 2026 15:38:23 +0200 Subject: [PATCH 1/3] Stop publishing hub and Android binaries via ORAS. GitHub Releases (with minisign) remain the pin channel; tip builds are available as Actions artifacts. Co-authored-by: Cursor --- .github/workflows/ci.yml | 34 ----------- .github/workflows/release.yml | 21 ------- scripts/publish-oci-bigfred-hub.sh | 61 ------------------- scripts/publish-oci-loco-android.sh | 33 ---------- scripts/retag-oci-bigfred-hub.sh | 93 ----------------------------- scripts/retag-oci-loco-android.sh | 66 -------------------- 6 files changed, 308 deletions(-) delete mode 100755 scripts/publish-oci-bigfred-hub.sh delete mode 100755 scripts/publish-oci-loco-android.sh delete mode 100755 scripts/retag-oci-bigfred-hub.sh delete mode 100755 scripts/retag-oci-loco-android.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0130679..0c898c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -131,37 +131,3 @@ jobs: if-no-files-found: error retention-days: 90 - publish-oci: - name: Publish OCI artifacts to GHCR (ORAS) - needs: build - if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main') - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Download binaries - uses: actions/download-artifact@v4 - with: - name: binaries - path: dist/ - - - name: Set up ORAS - uses: oras-project/setup-oras@v1 - - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Publish loco-server-android-arm64 - run: ./scripts/publish-oci-loco-android.sh dist/loco-server-android-arm64 - - - name: Publish bigfred-hub-linux-arm64 - if: github.ref == 'refs/heads/master' - run: ./scripts/publish-oci-bigfred-hub.sh dist/loco-server-linux-arm64 dist/bigfred-remote-icmp-linux-arm64 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7a79e6c..727b16f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -130,24 +130,3 @@ jobs: fi gh release upload "$TAG" "${FILES[@]}" --clobber - - name: Set up ORAS - uses: oras-project/setup-oras@v1 - - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Retag loco-server Android OCI artifact from main - env: - MINISIGN_SECRET_KEY: ${{ secrets.MINISIGN_SECRET_KEY }} - MINISIGN_PASSWORD: ${{ secrets.MINISIGN_PASSWORD }} - run: ./scripts/retag-oci-loco-android.sh "${GITHUB_REF_NAME}" - - - name: Retag hub linux/arm64 OCI artifact from master - env: - MINISIGN_SECRET_KEY: ${{ secrets.MINISIGN_SECRET_KEY }} - MINISIGN_PASSWORD: ${{ secrets.MINISIGN_PASSWORD }} - run: ./scripts/retag-oci-bigfred-hub.sh "${GITHUB_REF_NAME}" diff --git a/scripts/publish-oci-bigfred-hub.sh b/scripts/publish-oci-bigfred-hub.sh deleted file mode 100755 index 83e38a8..0000000 --- a/scripts/publish-oci-bigfred-hub.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env bash -# Publish hub linux/arm64 binaries to GHCR as one OCI artifact (ORAS). -# Intended for CI on push to master only. -# Usage: publish-oci-bigfred-hub.sh -# -# Tags: master, sha-<7> -# -# ORAS rejects absolute file paths unless --disable-path-validation is set; -# we push from a staging dir with relative basenames. -set -euo pipefail - -SERVER_BIN="${1:?usage: $0 }" -ICMP_BIN="${2:?usage: $0 }" -IMAGE="${BIGFRED_HUB_OCI_IMAGE:-ghcr.io/dcc-bigfred/bigfred-hub-linux-arm64}" -SERVER_MEDIA_TYPE="application/vnd.dcc-bigfred.loco-server.linux.arm64.v1" -ICMP_MEDIA_TYPE="application/vnd.dcc-bigfred.remote-icmp.linux.arm64.v1" - -if [[ ! -f "${SERVER_BIN}" ]]; then - echo "error: binary not found: ${SERVER_BIN}" >&2 - exit 1 -fi -if [[ ! -f "${ICMP_BIN}" ]]; then - echo "error: binary not found: ${ICMP_BIN}" >&2 - exit 1 -fi - -BRANCH="${GITHUB_REF_NAME:?GITHUB_REF_NAME required}" -if [[ "${BRANCH}" != "master" ]]; then - echo "error: hub OCI publish is only allowed from master (got ${BRANCH})" >&2 - exit 1 -fi - -SHA_TAG="sha-${GITHUB_SHA::7}" - -# ORAS layer file names come from basename; stage fixed names for consumers. -tmpdir="$(mktemp -d)" -cleanup() { rm -rf "${tmpdir}"; } -trap cleanup EXIT - -cp -f "${SERVER_BIN}" "${tmpdir}/loco-server-linux-arm64" -cp -f "${ICMP_BIN}" "${tmpdir}/bigfred-remote-icmp-linux-arm64" -chmod 755 "${tmpdir}/loco-server-linux-arm64" "${tmpdir}/bigfred-remote-icmp-linux-arm64" - -annotate=( - --annotation "org.opencontainers.image.source=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" - --annotation "org.opencontainers.image.revision=${GITHUB_SHA}" -) - -layers=( - "loco-server-linux-arm64:${SERVER_MEDIA_TYPE}" - "bigfred-remote-icmp-linux-arm64:${ICMP_MEDIA_TYPE}" -) - -echo "Publishing ${IMAGE}:master and :${SHA_TAG}" -echo " loco-server: $(wc -c < "${tmpdir}/loco-server-linux-arm64") bytes" -echo " remote-icmp: $(wc -c < "${tmpdir}/bigfred-remote-icmp-linux-arm64") bytes" -( - cd "${tmpdir}" - oras push "${IMAGE}:master" "${layers[@]}" "${annotate[@]}" - oras push "${IMAGE}:${SHA_TAG}" "${layers[@]}" "${annotate[@]}" -) diff --git a/scripts/publish-oci-loco-android.sh b/scripts/publish-oci-loco-android.sh deleted file mode 100755 index af07589..0000000 --- a/scripts/publish-oci-loco-android.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash -# Publish loco-server-android-arm64 to GHCR as an OCI artifact (ORAS). -# Intended for CI on push to master/main only. -# Usage: publish-oci-loco-android.sh -# -# Tags: main, sha-<7> -set -euo pipefail - -BINARY="${1:?usage: $0 }" -IMAGE="${BIGFRED_OCI_IMAGE:-ghcr.io/dcc-bigfred/loco-server-android-arm64}" -MEDIA_TYPE="application/vnd.dcc-bigfred.loco-server.android.arm64.v1" - -if [[ ! -f "${BINARY}" ]]; then - echo "error: binary not found: ${BINARY}" >&2 - exit 1 -fi - -BRANCH="${GITHUB_REF_NAME:?GITHUB_REF_NAME required}" -if [[ "${BRANCH}" != "master" && "${BRANCH}" != "main" ]]; then - echo "error: OCI publish is only allowed from master/main (got ${BRANCH})" >&2 - exit 1 -fi - -SHA_TAG="sha-${GITHUB_SHA::7}" - -annotate=( - --annotation "org.opencontainers.image.source=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" - --annotation "org.opencontainers.image.revision=${GITHUB_SHA}" -) - -echo "Publishing ${IMAGE}:main and :${SHA_TAG} ($(wc -c < "${BINARY}") bytes)" -oras push "${IMAGE}:main" "${BINARY}:${MEDIA_TYPE}" "${annotate[@]}" -oras push "${IMAGE}:${SHA_TAG}" "${BINARY}:${MEDIA_TYPE}" "${annotate[@]}" diff --git a/scripts/retag-oci-bigfred-hub.sh b/scripts/retag-oci-bigfred-hub.sh deleted file mode 100755 index af86d74..0000000 --- a/scripts/retag-oci-bigfred-hub.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env bash -# Retag the hub linux/arm64 OCI artifact from :master to a release tag and -# latest-release. Injects .bigfred.version into both binaries and signs them -# with minisign (fail-closed). -# Usage: retag-oci-bigfred-hub.sh e.g. v1.2.3 -# -# Requires: GITHUB_SHA (tag commit), oras, objcopy (binutils), minisign, -# MINISIGN_SECRET_KEY (and optional MINISIGN_PASSWORD). -# -# ORAS rejects absolute file paths; we push from the pull dir with relative names. -set -euo pipefail - -RELEASE_TAG="${1:?usage: $0 }" -IMAGE="${BIGFRED_HUB_OCI_IMAGE:-ghcr.io/dcc-bigfred/bigfred-hub-linux-arm64}" -SERVER_MEDIA_TYPE="application/vnd.dcc-bigfred.loco-server.linux.arm64.v1" -ICMP_MEDIA_TYPE="application/vnd.dcc-bigfred.remote-icmp.linux.arm64.v1" -MINISIG_MEDIA_TYPE="application/vnd.dcc-bigfred.minisig.v1" -TAG_COMMIT="${GITHUB_SHA:?GITHUB_SHA required (tag commit)}" -TAG_COMMIT_SHORT="${TAG_COMMIT::7}" - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -tmpdir="$(mktemp -d)" -cleanup() { rm -rf "${tmpdir}"; } -trap cleanup EXIT - -echo "Pulling ${IMAGE}:master…" -oras pull "${IMAGE}:master" -o "${tmpdir}" - -# Prefer canonical layer names; fall back to unique basename matches. -# Resolves to basenames under $tmpdir (relative for oras push). -find_layer() { - local want="$1" - if [[ -f "${tmpdir}/${want}" ]]; then - echo "${want}" - return 0 - fi - mapfile -t files < <(find "${tmpdir}" -type f \ - ! -name 'manifest.json' ! -name 'config.json' ! -name '*.minisig' \ - -name "${want}" -printf '%f\n') - if [[ ${#files[@]} -eq 1 ]]; then - echo "${files[0]}" - return 0 - fi - return 1 -} - -SERVER_NAME="$(find_layer loco-server-linux-arm64)" || true -ICMP_NAME="$(find_layer bigfred-remote-icmp-linux-arm64)" || true -if [[ -z "${SERVER_NAME}" || -z "${ICMP_NAME}" ]]; then - echo "error: expected loco-server-linux-arm64 and bigfred-remote-icmp-linux-arm64 in OCI artifact, found:" >&2 - find "${tmpdir}" -type f >&2 - exit 1 -fi - -SERVER_BIN="${tmpdir}/${SERVER_NAME}" -ICMP_BIN="${tmpdir}/${ICMP_NAME}" - -"${SCRIPT_DIR}/inject-elf-version.sh" "${SERVER_BIN}" "${RELEASE_TAG}" "${TAG_COMMIT_SHORT}" -"${SCRIPT_DIR}/inject-elf-version.sh" "${ICMP_BIN}" "${RELEASE_TAG}" "${TAG_COMMIT_SHORT}" - -if [[ -z "${MINISIGN_SECRET_KEY:-}" ]]; then - echo "error: MINISIGN_SECRET_KEY is required to publish a signed OCI release (fail-closed)" >&2 - exit 1 -fi -if ! command -v minisign >/dev/null 2>&1; then - echo "error: minisign not on PATH" >&2 - exit 1 -fi - -"${SCRIPT_DIR}/minisign-sign.sh" "${SERVER_BIN}" "${ICMP_BIN}" - -push_args=( - "${SERVER_NAME}:${SERVER_MEDIA_TYPE}" - "${ICMP_NAME}:${ICMP_MEDIA_TYPE}" - "${SERVER_NAME}.minisig:${MINISIG_MEDIA_TYPE}" - "${ICMP_NAME}.minisig:${MINISIG_MEDIA_TYPE}" -) - -annotate=( - --annotation "org.opencontainers.image.source=${GITHUB_SERVER_URL:-https://github.com}/${GITHUB_REPOSITORY:-dcc-bigfred/bigfred}" - --annotation "org.opencontainers.image.revision=${TAG_COMMIT}" - --annotation "org.opencontainers.image.version=${RELEASE_TAG}" -) - -echo "Publishing ${IMAGE}:${RELEASE_TAG} and :latest-release" -echo " loco-server: $(wc -c < "${SERVER_BIN}") bytes" -echo " remote-icmp: $(wc -c < "${ICMP_BIN}") bytes" -( - cd "${tmpdir}" - oras push "${IMAGE}:${RELEASE_TAG}" "${push_args[@]}" "${annotate[@]}" - oras push "${IMAGE}:latest-release" "${push_args[@]}" "${annotate[@]}" -) diff --git a/scripts/retag-oci-loco-android.sh b/scripts/retag-oci-loco-android.sh deleted file mode 100755 index 8f93663..0000000 --- a/scripts/retag-oci-loco-android.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash -# Retag the loco-server-android-arm64 OCI artifact from :main to a release tag, -# injecting .bigfred.version (ELF section) with the release tag + tag commit. -# Optionally signs the binary with minisign and pushes .minisig as a second layer. -# Signing is fail-closed: MINISIGN_SECRET_KEY is required and must verify against -# the committed minisign.pub. -# Usage: retag-oci-loco-android.sh e.g. v1.2.3 -# -# Requires: GITHUB_SHA (tag commit), oras, objcopy (binutils), minisign, -# MINISIGN_SECRET_KEY (and optional MINISIGN_PASSWORD). -set -euo pipefail - -RELEASE_TAG="${1:?usage: $0 }" -IMAGE="${BIGFRED_OCI_IMAGE:-ghcr.io/dcc-bigfred/loco-server-android-arm64}" -MEDIA_TYPE="application/vnd.dcc-bigfred.loco-server.android.arm64.v1" -MINISIG_MEDIA_TYPE="application/vnd.dcc-bigfred.minisig.v1" -TAG_COMMIT="${GITHUB_SHA:?GITHUB_SHA required (tag commit)}" -TAG_COMMIT_SHORT="${TAG_COMMIT::7}" - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -tmpdir="$(mktemp -d)" -cleanup() { rm -rf "${tmpdir}"; } -trap cleanup EXIT - -echo "Pulling ${IMAGE}:main…" -oras pull "${IMAGE}:main" -o "${tmpdir}" - -BINARY="${tmpdir}/loco-server-android-arm64" -if [[ ! -f "${BINARY}" ]]; then - mapfile -t files < <(find "${tmpdir}" -type f ! -name 'manifest.json' ! -name 'config.json') - if [[ ${#files[@]} -eq 1 ]]; then - BINARY="${files[0]}" - else - echo "error: expected loco-server-android-arm64 in OCI artifact, found:" >&2 - find "${tmpdir}" -type f >&2 - exit 1 - fi -fi - -"${SCRIPT_DIR}/inject-elf-version.sh" "${BINARY}" "${RELEASE_TAG}" "${TAG_COMMIT_SHORT}" - -push_args=( - "${BINARY}:${MEDIA_TYPE}" -) - -if [[ -z "${MINISIGN_SECRET_KEY:-}" ]]; then - echo "error: MINISIGN_SECRET_KEY is required to publish a signed OCI release (fail-closed)" >&2 - exit 1 -fi -if ! command -v minisign >/dev/null 2>&1; then - echo "error: minisign not on PATH" >&2 - exit 1 -fi -# Signs and verifies against committed minisign.pub (key mismatch fails the job). -"${SCRIPT_DIR}/minisign-sign.sh" "${BINARY}" -push_args+=("${BINARY}.minisig:${MINISIG_MEDIA_TYPE}") - -annotate=( - --annotation "org.opencontainers.image.source=${GITHUB_SERVER_URL:-https://github.com}/${GITHUB_REPOSITORY:-dcc-bigfred/bigfred}" - --annotation "org.opencontainers.image.revision=${TAG_COMMIT}" - --annotation "org.opencontainers.image.version=${RELEASE_TAG}" -) - -echo "Publishing ${IMAGE}:${RELEASE_TAG} ($(wc -c < "${BINARY}") bytes)" -oras push "${IMAGE}:${RELEASE_TAG}" "${push_args[@]}" "${annotate[@]}" From 9482239d20496472c959f529fd6a5241ec409c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99ska?= <372403+keskad@users.noreply.github.com> Date: Thu, 6 Aug 2026 19:59:58 +0200 Subject: [PATCH 2/3] Inject ELF version via go run common/cmd/inject-elf-version. Drop local inject-elf-version.sh; install cross objcopy for arm64 assets on amd64 runners. Co-authored-by: Cursor --- .github/workflows/release.yml | 16 +++++++++++++++- scripts/inject-elf-version.sh | 32 -------------------------------- 2 files changed, 15 insertions(+), 33 deletions(-) delete mode 100755 scripts/inject-elf-version.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 727b16f..b3603b0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,15 +65,29 @@ jobs: --name binaries \ --dir release-assets + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.22" + + - name: Install cross objcopy for arm64 ELF rewrite + run: | + set -euo pipefail + sudo apt-get update + sudo apt-get install -y --no-install-recommends binutils-aarch64-linux-gnu + - name: Inject release version into ELF binaries + env: + GOPROXY: direct run: | set -euo pipefail TAG="${GITHUB_REF_NAME}" COMMIT="${GITHUB_SHA::7}" + INJECT="github.com/dcc-bigfred/common/cmd/inject-elf-version@latest" find release-assets -type f -print0 | while IFS= read -r -d '' f; do # Only ELF binaries carry the section (skip .exe if present). if file -b "$f" | grep -qi 'ELF'; then - ./scripts/inject-elf-version.sh "$f" "$TAG" "$COMMIT" + go run "${INJECT}" "$f" "$TAG" "$COMMIT" .bigfred.version else echo "skip (not ELF): $f" fi diff --git a/scripts/inject-elf-version.sh b/scripts/inject-elf-version.sh deleted file mode 100755 index 4dbf9d1..0000000 --- a/scripts/inject-elf-version.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash -# Inject release version metadata into an ELF binary as section -# .bigfred.version (JSON {"version":"v1.2.3","commit":"abc1234"}). -# Usage: inject-elf-version.sh -set -euo pipefail - -BINARY="${1:?usage: $0 }" -VERSION="${2:?}" -TAG_COMMIT="${3:?}" - -if [[ ! -f "${BINARY}" ]]; then - echo "error: binary not found: ${BINARY}" >&2 - exit 1 -fi - -if ! command -v objcopy >/dev/null 2>&1; then - echo "error: objcopy not found (install binutils)" >&2 - exit 1 -fi - -tmpdir="$(mktemp -d)" -cleanup() { rm -rf "${tmpdir}"; } -trap cleanup EXIT - -section_file="${tmpdir}/bigfred.version.json" -printf '{"version":"%s","commit":"%s"}' "${VERSION}" "${TAG_COMMIT}" > "${section_file}" - -# remove is a no-op when the section is absent -objcopy --remove-section .bigfred.version "${BINARY}" 2>/dev/null || true -objcopy --add-section ".bigfred.version=${section_file}" "${BINARY}" - -echo "Injected .bigfred.version into ${BINARY}: version=${VERSION} commit=${TAG_COMMIT}" From c3c1fc91d01dca8e6afe802eea8399ba6201a35a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99ska?= <372403+keskad@users.noreply.github.com> Date: Thu, 6 Aug 2026 20:09:58 +0200 Subject: [PATCH 3/3] Sign releases via go run common/cmd/minisign-sign. Drop local minisign bash helpers; CI smoke-tests the shared package. Co-authored-by: Cursor --- .github/workflows/ci.yml | 6 ++- .github/workflows/release.yml | 3 +- Makefile | 3 +- scripts/minisign-sign.sh | 71 ----------------------------------- scripts/test-minisign-sign.sh | 44 ---------------------- 5 files changed, 8 insertions(+), 119 deletions(-) delete mode 100755 scripts/minisign-sign.sh delete mode 100755 scripts/test-minisign-sign.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c898c9..e08a913 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,8 +32,10 @@ jobs: - name: Install minisign run: sudo apt-get update && sudo apt-get install -y minisign - - name: Smoke-test minisign-sign.sh - run: ./scripts/test-minisign-sign.sh + - name: Smoke-test minisign-sign + env: + GOPROXY: direct + run: go test -count=1 github.com/dcc-bigfred/common/internal/minisignsign@latest - name: Set up Node uses: actions/setup-node@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b3603b0..b28b0de 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -115,7 +115,8 @@ jobs: exit 1 fi # Signs and verifies each artifact against committed minisign.pub. - ./scripts/minisign-sign.sh "${FILES[@]}" + export GOPROXY="${GOPROXY:-direct}" + go run github.com/dcc-bigfred/common/cmd/minisign-sign@latest "${FILES[@]}" - name: Create release if missing env: diff --git a/Makefile b/Makefile index 9992233..17a0be9 100644 --- a/Makefile +++ b/Makefile @@ -113,7 +113,8 @@ test: ensure-go-junit-report .PHONY: test-minisign test-minisign: - ./scripts/test-minisign-sign.sh + @command -v minisign >/dev/null 2>&1 || { echo "error: minisign required"; exit 1; } + GOPROXY=$${GOPROXY:-direct} go test -count=1 github.com/dcc-bigfred/common/internal/minisignsign@latest .PHONY: fmt fmt: ## Run go fmt against code. diff --git a/scripts/minisign-sign.sh b/scripts/minisign-sign.sh deleted file mode 100755 index e77a770..0000000 --- a/scripts/minisign-sign.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash -# Sign one or more files with minisign (writes .minisig next to each), -# then verify each signature against the committed public key. -# Usage: minisign-sign.sh [file...] -# -# Env: -# MINISIGN_SECRET_KEY — full contents of the minisign secret key file (required) -# MINISIGN_PASSWORD — password if the secret key is encrypted (optional) -# MINISIGN_PUBLIC_KEY — path to public key (default: minisign.pub next to repo root / -# or $SCRIPT_DIR/../minisign.pub) -# GITHUB_REF_NAME / GITHUB_SHA — included in the trusted comment when set -set -euo pipefail - -if [[ $# -lt 1 ]]; then - echo "usage: $0 [file...]" >&2 - exit 1 -fi - -: "${MINISIGN_SECRET_KEY:?MINISIGN_SECRET_KEY required}" - -if ! command -v minisign >/dev/null 2>&1; then - echo "error: minisign not found on PATH" >&2 - exit 1 -fi - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PUBKEY="${MINISIGN_PUBLIC_KEY:-${SCRIPT_DIR}/../minisign.pub}" -if [[ ! -f "${PUBKEY}" ]]; then - echo "error: public key not found: ${PUBKEY}" >&2 - exit 1 -fi - -tmpdir="$(mktemp -d)" -cleanup() { rm -rf "${tmpdir}"; } -trap cleanup EXIT - -keyfile="${tmpdir}/minisign.key" -# Preserve exact file contents (including trailing newline). -printf '%s' "${MINISIGN_SECRET_KEY}" > "${keyfile}" -# minisign keys end with a newline; ensure one if the secret was pasted without it. -[[ "$(tail -c1 "${keyfile}" | wc -l)" -eq 0 ]] && printf '\n' >> "${keyfile}" -chmod 600 "${keyfile}" - -trusted="BigFred ${GITHUB_REF_NAME:-unknown} ${GITHUB_SHA:-}" - -for f in "$@"; do - if [[ ! -f "${f}" ]]; then - echo "error: file not found: ${f}" >&2 - exit 1 - fi - if [[ "${f}" == *.minisig ]]; then - echo "skip (already a signature): ${f}" - continue - fi - - if [[ -n "${MINISIGN_PASSWORD:-}" ]]; then - minisign -Sm "${f}" -s "${keyfile}" -t "${trusted}" <<< "${MINISIGN_PASSWORD}" - else - # Unencrypted key (-W at generation time): no password prompt. - minisign -Sm "${f}" -s "${keyfile}" -t "${trusted}" < /dev/null - fi - echo "signed: ${f} -> ${f}.minisig" - - # Fail closed if the secret key does not match the committed public key. - if ! minisign -Vm "${f}" -x "${f}.minisig" -p "${PUBKEY}" >/dev/null; then - echo "error: signature verification failed for ${f} against ${PUBKEY}" >&2 - echo "error: MINISIGN_SECRET_KEY does not match the committed public key" >&2 - exit 1 - fi - echo "verified: ${f} (pubkey=$(basename "${PUBKEY}"))" -done diff --git a/scripts/test-minisign-sign.sh b/scripts/test-minisign-sign.sh deleted file mode 100755 index 9a126cd..0000000 --- a/scripts/test-minisign-sign.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash -# Smoke-test minisign-sign.sh: sign + verify against matching pubkey must pass; -# verify against a mismatched pubkey must fail the script. -set -euo pipefail - -ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -MINISIGN_BIN="${MINISIGN_BIN:-minisign}" -if ! command -v "${MINISIGN_BIN}" >/dev/null 2>&1; then - # Prefer local tooling from monorepo .secrets if present. - if [[ -x "${ROOT}/../.secrets/minisign" ]]; then - MINISIGN_BIN="${ROOT}/../.secrets/minisign" - else - echo "skip: minisign not on PATH" >&2 - exit 0 - fi -fi -export PATH="$(dirname "${MINISIGN_BIN}"):${PATH}" - -tmpdir="$(mktemp -d)" -cleanup() { rm -rf "${tmpdir}"; } -trap cleanup EXIT - -# Fresh keypair for the test (unencrypted). -"${MINISIGN_BIN}" -G -p "${tmpdir}/test.pub" -s "${tmpdir}/test.key" -W -payload="${tmpdir}/artifact.bin" -printf 'hello-bigfred-release\n' > "${payload}" - -export MINISIGN_SECRET_KEY -MINISIGN_SECRET_KEY="$(cat "${tmpdir}/test.key")" -export MINISIGN_PUBLIC_KEY="${tmpdir}/test.pub" - -"${ROOT}/scripts/minisign-sign.sh" "${payload}" -[[ -f "${payload}.minisig" ]] - -# Mismatch: point public key at a different key — signing must fail verification. -"${MINISIGN_BIN}" -G -p "${tmpdir}/other.pub" -s "${tmpdir}/other.key" -W -export MINISIGN_PUBLIC_KEY="${tmpdir}/other.pub" -rm -f "${payload}.minisig" -if "${ROOT}/scripts/minisign-sign.sh" "${payload}"; then - echo "error: expected minisign-sign.sh to fail on pubkey mismatch" >&2 - exit 1 -fi - -echo "ok: minisign-sign.sh smoke test passed"