diff --git a/.github/workflows/release-verification-chain-policy.yml b/.github/workflows/release-verification-chain-policy.yml new file mode 100644 index 0000000..e8ab866 --- /dev/null +++ b/.github/workflows/release-verification-chain-policy.yml @@ -0,0 +1,57 @@ +name: release-verification-chain-policy + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: release-verification-chain-policy-${{ github.ref }} + cancel-in-progress: true + +jobs: + qualify: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5, Node 24 + + - name: Qualify M1.29 automatic post-release chain + shell: bash + run: | + set -euo pipefail + file=.github/workflows/release-verification.yml + + grep -Fq 'workflow_run:' "$file" + grep -Fq 'workflows: [release]' "$file" + grep -Fq 'types: [completed]' "$file" + grep -Fq "github.event.workflow_run.conclusion == 'success'" "$file" + grep -Fq "github.event.workflow_run.head_sha" "$file" + grep -Fq 'release-evidence.json' "$file" + grep -Fq '.release_commit == $commit' "$file" + grep -Fq 'No published release evidence is bound to release workflow commit' "$file" + + # Existing independent fallbacks remain available. + grep -Fq 'release:' "$file" + grep -Fq 'types: [published]' "$file" + grep -Fq 'workflow_dispatch:' "$file" + grep -Fq "cron: '17 6 * * 1'" "$file" + + # The release producer remains container-tag driven. + grep -Fq 'workflows: [container]' .github/workflows/release.yml + grep -Fq "startsWith(github.event.workflow_run.head_branch, 'v')" .github/workflows/release.yml + grep -Fq 'Create GitHub release if missing' .github/workflows/release.yml + + - name: Record M1.29 policy + run: | + { + echo '### M1.29 automatic release-verification chain' + echo + echo '- successful release workflow runs automatically trigger release-verification' + echo '- release-verification binds the selected GitHub Release to the producer head SHA through release-evidence.json' + echo '- workflow-run selection fails closed if no published evidence matches the producer commit' + echo '- release, manual dispatch and weekly schedule triggers remain as independent fallbacks' + } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/release-verification.yml b/.github/workflows/release-verification.yml index a08e65d..c232039 100644 --- a/.github/workflows/release-verification.yml +++ b/.github/workflows/release-verification.yml @@ -1,6 +1,9 @@ name: release-verification on: + workflow_run: + workflows: [release] + types: [completed] release: types: [published] workflow_dispatch: @@ -19,6 +22,9 @@ permissions: jobs: verify: + if: >- + github.event_name != 'workflow_run' || + github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-24.04 steps: - name: Select release to audit @@ -27,6 +33,7 @@ jobs: GH_TOKEN: ${{ github.token }} EVENT_TAG: ${{ github.event_name == 'release' && github.event.release.tag_name || '' }} INPUT_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || '' }} + WORKFLOW_COMMIT: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || '' }} shell: bash run: | set -euo pipefail @@ -35,6 +42,29 @@ jobs: tag="$INPUT_TAG" fi + if [[ -z "$tag" && -n "$WORKFLOW_COMMIT" ]]; then + while IFS= read -r candidate; do + [[ -n "$candidate" ]] || continue + metadata="$(gh release view "$candidate" --repo "$GITHUB_REPOSITORY" --json isDraft,assets)" + if ! jq -e '.isDraft == false and any(.assets[]?; .name == "release-evidence.json")' <<<"$metadata" >/dev/null; then + continue + fi + tmp="$(mktemp -d)" + if gh release download "$candidate" --repo "$GITHUB_REPOSITORY" --dir "$tmp" --pattern release-evidence.json >/dev/null 2>&1 && + jq -e --arg commit "$WORKFLOW_COMMIT" '.release_commit == $commit' "$tmp/release-evidence.json" >/dev/null 2>&1; then + tag="$candidate" + rm -rf "$tmp" + break + fi + rm -rf "$tmp" + done < <(gh release list --repo "$GITHUB_REPOSITORY" --limit 100 --json tagName --jq '.[].tagName') + + if [[ -z "$tag" ]]; then + echo "No published release evidence is bound to release workflow commit $WORKFLOW_COMMIT" >&2 + exit 1 + fi + fi + if [[ -z "$tag" ]]; then while IFS= read -r candidate; do [[ -n "$candidate" ]] || continue