From ed0e835863a0eeed0227534a9f88916785127322 Mon Sep 17 00:00:00 2001 From: compat-seeder Date: Sun, 10 May 2026 16:59:39 +0300 Subject: [PATCH] feat(compat): sign seeded-ci.json with cosign (Phase 4.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds cosign install + sign-blob step before commit. The detached .sig (base64-encoded ASN.1 DER ECDSA over SHA256(file)) is committed alongside seeded-ci.json. Tower's loader verifies it pure-Go before replay; mismatched/missing sig → refuse + log. cosign.pub is also checked in so the workflow can self-verify before push (catches key-rotation mismatch early). The same pubkey is embedded in Tower's binary at compat_bootstrap_pubkey.pem; both copies must match or replay will fail. --- .gitea/workflows/seed-compat.yml | 51 +++++++++++++++++++++++++++----- compat-bootstrap/cosign.pub | 4 +++ 2 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 compat-bootstrap/cosign.pub diff --git a/.gitea/workflows/seed-compat.yml b/.gitea/workflows/seed-compat.yml index 8962c2e..c35efce 100644 --- a/.gitea/workflows/seed-compat.yml +++ b/.gitea/workflows/seed-compat.yml @@ -98,13 +98,51 @@ jobs: print(f'merged {len(rows)} rows; stamp={stamp}') PY + - name: Install cosign + run: | + set -euo pipefail + if ! command -v cosign >/dev/null 2>&1; then + curl -sSL -o /usr/local/bin/cosign \ + https://github.com/sigstore/cosign/releases/download/v2.4.1/cosign-linux-amd64 + chmod +x /usr/local/bin/cosign + fi + cosign version | head -3 + + - name: Sign seeded-ci.json (Phase 4.1) + env: + COSIGN_PRIVATE_KEY: ${{ secrets.COMPAT_SIGNING_KEY }} + COSIGN_PASSWORD: ${{ secrets.COMPAT_SIGNING_PASSWORD }} + run: | + set -euo pipefail + if [ ! -f compat-bootstrap/seeded-ci.json ]; then + echo "ERROR: seeded-ci.json was not produced; nothing to sign" + exit 1 + fi + # cosign sign-blob with --key env://VAR reads the private key + # PEM from the named env var; the file/stdout split keeps the + # raw key out of process args (where it'd show up in `ps`). + cosign sign-blob --yes \ + --key env://COSIGN_PRIVATE_KEY \ + --output-signature compat-bootstrap/seeded-ci.json.sig \ + compat-bootstrap/seeded-ci.json + # Sanity: verify with the public copy on disk before we push. + # Catches a key-rotation mismatch while we still can. + # (skips the Sigstore tlog — we're not relying on Rekor) + if [ -f compat-bootstrap/cosign.pub ]; then + cosign verify-blob --insecure-ignore-tlog \ + --key compat-bootstrap/cosign.pub \ + --signature compat-bootstrap/seeded-ci.json.sig \ + compat-bootstrap/seeded-ci.json + fi + echo "signed: $(wc -c < compat-bootstrap/seeded-ci.json.sig) bytes" + - name: Commit + push if content changed env: GIT_USER_TOKEN: ${{ secrets.COMPAT_PUSH_TOKEN }} run: | set -euo pipefail # Discard the per-major scratch files + addon worktrees; only - # the consolidated snapshot is part of the canonical state. + # the consolidated snapshot + sig are part of the canonical state. for major in 18.0 19.0; do git worktree remove --force "addons-$major" || true; done rm -rf compat-bootstrap/per-major @@ -116,12 +154,11 @@ jobs: exit 1 fi - # Stage first, then diff against index — this catches both - # "tracked file changed" and "new file appeared" cases. The - # bare `git diff --quiet` form silently passes for untracked - # files (no diff = exit 0), which masked the very-first run. - git add compat-bootstrap/seeded-ci.json - if git diff --cached --quiet -- compat-bootstrap/seeded-ci.json; then + # Stage both the JSON and its sig. The .sig changes whenever + # the JSON changes (different SHA256 → different signature), + # so a content-stable run will produce a no-op diff for both. + git add compat-bootstrap/seeded-ci.json compat-bootstrap/seeded-ci.json.sig + if git diff --cached --quiet -- compat-bootstrap/seeded-ci.json compat-bootstrap/seeded-ci.json.sig; then echo "no content change in seeded-ci.json; nothing to commit" exit 0 fi diff --git a/compat-bootstrap/cosign.pub b/compat-bootstrap/cosign.pub new file mode 100644 index 0000000..17293c0 --- /dev/null +++ b/compat-bootstrap/cosign.pub @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgbGcCGMzThWEY5aaVK249Q+ZNm1w +BznDxfRvzL9AGdb1vkUngdcVmGXZBwg/rHXSkYJjt4t9Ky9mZkB9pB02BQ== +-----END PUBLIC KEY-----