Files
0pt/.gitea/workflows/release.yml
T
admin ea40a67940
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (push) Successful in 5s
masterplan-lock / check (pull_request) Successful in 4s
CI (SIAX Cloud) / security (pull_request) Successful in 16s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 17s
CI (SIAX Cloud) / integration (pull_request) Successful in 9m49s
CI (SIAX Cloud) / quality (pull_request) Successful in 10m1s
docs(deploy): runbook and workflow headers match the live pipeline
The runbook still described Vercel and an unprovisioned Coolify app. It now
documents the verified chain (ci -> release attestation -> cd -> Coolify),
the proven manual dispatch, the verification endpoints and the rollback.
2026-11-02 18:57:45 +01:00

185 lines
9.5 KiB
YAML

name: Release chain (G17, ADR-W16-003)
# Builds + pushes the 0pt image, then hands off to the shared
# sax3l/siax-templates G17 reference hook for every ADR-W16-003 bar item
# 1-7 (pinned-tool install, SBOM, blocking vuln scan, in-toto attestation,
# scoped-key signing, pubkey verification, AUD0/ST0RE evidence storage).
#
# REPLACES this repo's own ad hoc "P007 pattern" release chain (added
# 2026-09-14). An audit (2026-09-15) found that chain failed most of the
# real promotion bar it claimed to meet: syft/cosign installed via a `curl`
# + freshly-refetched checksums file (not a pinned, out-of-band-verified
# digest -- see siax-templates' `lib/pinned-tools.sh` header for exactly
# why that is not a verified digest), NO vulnerability scan of the built
# digest at all, `cosign sign` on the bare digest only (no in-toto/SLSA
# statement, no source-SHA/build-identity/environment/SBOM-hash bound
# together, no scoped key identity), and evidence committed straight back
# into this same mutable repo (`siax/production-evidence/*.json`,
# `siax/source-bundles/*.json` -- nine such commits already existed in this
# repo's history before this change; deleted in this same PR, superseded by
# the real AUD0 write below). This file keeps ONLY what is genuinely
# 0pt-specific (image name, tag scheme, registry push, Dockerfile) and
# delegates everything else to `.siax/hooks/G17.sh` -> the shared reference
# implementation. See `.siax/hooks/README.md` for the pin status and
# required secrets (none of which were provisioned for the old gate either
# -- see that file's own note).
#
# DELIBERATELY ONE JOB. Gitea 1.26 on this fleet resolves org-level
# secrets (SIAX_CI_TOKEN below is org-level) only for the FIRST job of a
# workflow file -- learned the hard way on sax3l/h0st's and sax3l/aud0's
# own G17 migrations. 0pt does not wire a G20 post-deploy step in this
# pass at all (see `.siax/hooks/README.md` "G20 -- deliberately not wired
# yet": the app is now provisioned and `/api/version` exists, but G20 is still
# not wired in this pass), so the single-job constraint that forces G20 into its own
# workflow file elsewhere does not yet bite here -- documented anyway so a
# future PR adding G20 does not repeat the mistake.
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
env:
IMAGE_REPO: git.cloud.siax.io/sax3l/0pt
DOCKERFILE: Dockerfile
SIAX_TEMPLATES_REPO: sax3l/siax-templates
# PIN STATUS 2026-09-15: sax3l/siax-templates PR #51
# (feat/g17-signed-deploy-gate-adr-w16-003) MERGED to main, plus three
# real follow-up fixes on top -- #56/#57 (SPDX compound-license-
# expression evaluation, exercised live by this repo's own
# G17_LICENSE_ALLOW policy in .siax/hooks/G17.sh) and #59 (G20 retry
# logic -- not used by 0pt yet, but the pin picks up main's current tip
# rather than an older commit, matching what a fresh migration reviews).
#
# Re-pin 2026-09-25 (medveten, granskad): 9a3a0aa -> 09504e3a. Deltaet ar
# EN merge, siax-templates #138 "Upload complete release evidence and
# validate artifact receipt". Enda berorda filer under ci/v2 ar
# reference-hooks/{G17.sh, G17-ADR-W16-003.md, lib/emit-release-evidence.py,
# lib/test_emit_release_evidence.py}. Andringen ar bakatkompatibel by
# design: ST0RE-uppladdningen ar OPT-IN via G17_REQUIRE_ST0RE (default 0),
# sa en AUD0-only-konsument som 0pt kor exakt samma vag som forut.
#
# Deliberately NO branch name here: the pinned commit is checked out
# DIRECTLY (see the step below). The previous shape -- clone `main`, then
# require its HEAD to equal this pin -- turned every unrelated merge in
# siax-templates into a red release chain here (CD-03 / CI-RED-02) while
# nothing was actually unsafe. Checking the pin out directly keeps the pin
# a real supply-chain control (the gate runs exactly this reviewed commit,
# or it fails) without coupling it to someone else's branch tip.
SIAX_TEMPLATES_PINNED_SHA: 09504e3a593ee8ce0eaba606df31c349a3d52277
SIAX_TEMPLATES_DIR: /tmp/siax-templates-g17-ref
jobs:
release:
name: Build, push, G17 (SBOM/scan/attest/verify/evidence)
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: https://git.siax.io/actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4, mirrored + SHA-pinned (SUP-06, same pin n0d/cl0ud/st0re/h0st already use)
with:
fetch-depth: 0
# --- fetch the shared G17 reference implementation -----------------
# Same authenticated-fetch-at-runtime mechanism this repo's OLD
# release.yml already used SIAX_CI_TOKEN for (the evidence-commit
# push a prior PR deleted) -- see .siax/hooks/G17.sh's header for why
# NOT a `uses:` reusable workflow / submodule / vendored copy. Fails
# closed if the exact commit this adapter was reviewed against cannot
# be checked out (removed or rewritten upstream); an unrelated merge
# on siax-templates' own main is NOT a failure and never was a real
# signal.
- name: Fetch siax-templates G17 reference (pinned commit)
env:
SIAX_CI_TOKEN: ${{ secrets.SIAX_CI_TOKEN }}
run: |
set -euo pipefail
rm -rf "$SIAX_TEMPLATES_DIR"
mkdir -p "$SIAX_TEMPLATES_DIR"
git -C "$SIAX_TEMPLATES_DIR" init --quiet
git -C "$SIAX_TEMPLATES_DIR" remote add origin \
"https://oauth2:${SIAX_CI_TOKEN}@git.siax.io/${SIAX_TEMPLATES_REPO}.git"
# Ask for the pinned commit by SHA -- one shallow commit, no branch
# involved. A server with uploadpack.allowReachableSHA1InWant off
# refuses that, so fall back to fetching the branches and taking the
# same commit out of them. Either way the work tree ends up at
# exactly $SIAX_TEMPLATES_PINNED_SHA, never at a branch tip.
if ! git -C "$SIAX_TEMPLATES_DIR" fetch --quiet --depth 1 origin "$SIAX_TEMPLATES_PINNED_SHA"; then
echo "note: server refused a by-SHA fetch; falling back to fetching all branches"
git -C "$SIAX_TEMPLATES_DIR" fetch --quiet origin
fi
if ! git -C "$SIAX_TEMPLATES_DIR" -c advice.detachedHead=false \
checkout --quiet --detach "$SIAX_TEMPLATES_PINNED_SHA"; then
echo "::error::siax-templates commit $SIAX_TEMPLATES_PINNED_SHA not found in $SIAX_TEMPLATES_REPO -- the reviewed commit was removed or rewritten upstream. Re-review siax-templates and update SIAX_TEMPLATES_PINNED_SHA deliberately."
exit 1
fi
actual_sha="$(git -C "$SIAX_TEMPLATES_DIR" rev-parse HEAD)"
if [ "$actual_sha" != "$SIAX_TEMPLATES_PINNED_SHA" ]; then
echo "::error::checked-out siax-templates HEAD is $actual_sha, expected the pinned $SIAX_TEMPLATES_PINNED_SHA -- refusing to run an unreviewed version of the gate."
exit 1
fi
chmod +x "$SIAX_TEMPLATES_DIR/ci/v2/reference-hooks/"*.sh "$SIAX_TEMPLATES_DIR/ci/v2/reference-hooks/lib/"*.sh
echo "siax-templates G17 reference @ $actual_sha (pinned commit, checked out directly)"
- name: Resolve SHA + tag (never :latest)
id: sha
run: |
set -euo pipefail
full="$(git rev-parse HEAD)"
short="$(git rev-parse --short=12 HEAD)"
echo "full=$full" >> "$GITHUB_OUTPUT"
echo "short=$short" >> "$GITHUB_OUTPUT"
echo "image_tag=sha-$short" >> "$GITHUB_OUTPUT"
- name: Docker login (git.cloud.siax.io)
env:
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
run: |
set -euo pipefail
registry_host="$(echo "$IMAGE_REPO" | cut -d/ -f1)"
echo "$REGISTRY_TOKEN" | docker login "$registry_host" -u "$REGISTRY_USER" --password-stdin
- name: Build
env:
IMAGE_TAG: ${{ steps.sha.outputs.image_tag }}
run: |
set -euo pipefail
docker build -f "$DOCKERFILE" -t "${IMAGE_REPO}:${IMAGE_TAG}" .
- name: Push (immutable sha-<12> tag, never :latest)
env:
IMAGE_TAG: ${{ steps.sha.outputs.image_tag }}
run: docker push "${IMAGE_REPO}:${IMAGE_TAG}"
# --- G17: everything else, delegated -------------------------------
- name: G17 (bar items 1-7, delegated to siax-templates)
env:
ARTIFACT_COMMIT_SHA: ${{ steps.sha.outputs.full }}
ARTIFACT_IMAGE_TAG: ${{ steps.sha.outputs.image_tag }}
CI_RUN_ID: ${{ github.run_id }}
CI_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
G17_COSIGN_KEY: /tmp/0pt-g17-cosign.key
G17_COSIGN_KEY_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
AUD0_INGEST_TOKEN: ${{ secrets.AUD0_INGEST_TOKEN }}
AUD0_TENANT_ID: ${{ secrets.AUD0_TENANT_ID }}
run: |
set -euo pipefail
echo "${{ secrets.COSIGN_PRIVATE_KEY }}" > "$G17_COSIGN_KEY"
trap 'rm -f "$G17_COSIGN_KEY"' EXIT
bash .siax/hooks/G17.sh
# NOTE: deliberately NO `actions/upload-artifact@v4` step here.
# sax3l/cl0ud's release.yml (run 23340, 2026-09-14) documents that
# this Gitea instance's act_runner does not reliably support
# upload-artifact@v4 even with continue-on-error: true, and that it
# can abort the whole job before later steps run. G17.sh's own AUD0
# submission (bar item 7, step above) is already the durable evidence
# record; a convenience local copy is not worth re-triggering that
# known breakage.