Skip to content

ci: enforce provenance-bound parity receipts #13

ci: enforce provenance-bound parity receipts

ci: enforce provenance-bound parity receipts #13

Workflow file for this run

name: Quality ratchet
# pull_request_target loads this workflow from protected main. The job never
# imports or executes PR code; it runs a protected-base judge over static files.
on:
pull_request_target:
types: [opened, synchronize, reopened, ready_for_review]
push:
branches: [main]
permissions:
actions: read
contents: read
pull-requests: read
statuses: write
jobs:
quality-ratchet:
name: ruff + mypy (no new debt)
runs-on: ubuntu-latest
timeout-minutes: 20
env:
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }}
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
PR_NUMBER: ${{ github.event.pull_request.number || 0 }}
steps:
- name: Check out the protected comparison graph
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
- name: Install pinned quality tools
run: python -m pip install "ruff==0.15.10" "mypy==1.20.1"
- name: Resolve commits and protected judge
id: commits
shell: bash
run: |
set -euo pipefail
if [[ ! "$HEAD_SHA" =~ ^[0-9a-f]{40}$ ]]; then
echo "Invalid head SHA: $HEAD_SHA" >&2
exit 2
fi
if [[ "$BASE_SHA" =~ ^0{40}$ ]]; then
BASE_SHA=$(git rev-parse "${HEAD_SHA}^" 2>/dev/null || printf '%s' "$HEAD_SHA")
fi
if [[ ! "$BASE_SHA" =~ ^[0-9a-f]{40}$ ]]; then
echo "Invalid base SHA: $BASE_SHA" >&2
exit 2
fi
if ! git cat-file -e "${BASE_SHA}^{commit}" 2>/dev/null; then
git fetch --no-tags --depth=1 origin "$BASE_SHA"
fi
if ! git cat-file -e "${HEAD_SHA}^{commit}" 2>/dev/null; then
if [[ "$GITHUB_EVENT_NAME" == "pull_request_target" ]]; then
git fetch --no-tags origin \
"+refs/pull/${PR_NUMBER}/head:refs/remotes/pull/quality-head"
else
git fetch --no-tags --depth=1 origin "$HEAD_SHA"
fi
fi
git cat-file -e "${BASE_SHA}^{commit}"
git cat-file -e "${HEAD_SHA}^{commit}"
JUDGE="$RUNNER_TEMP/protected-ci-quality-ratchet.py"
if git cat-file -e "${BASE_SHA}:scripts/ci_quality_ratchet.py" 2>/dev/null; then
git show "${BASE_SHA}:scripts/ci_quality_ratchet.py" > "$JUDGE"
JUDGE_SOURCE="protected-base"
elif [[ "$GITHUB_EVENT_NAME" == "push" ]]; then
# One-time bootstrap for the merge that first introduces the gate.
git show "${HEAD_SHA}:scripts/ci_quality_ratchet.py" > "$JUDGE"
JUDGE_SOURCE="bootstrap-head"
else
echo "Protected base does not contain the quality judge" >&2
exit 2
fi
python -m py_compile "$JUDGE"
echo "base_sha=$BASE_SHA" >> "$GITHUB_OUTPUT"
echo "head_sha=$HEAD_SHA" >> "$GITHUB_OUTPUT"
echo "judge=$JUDGE" >> "$GITHUB_OUTPUT"
echo "judge_source=$JUDGE_SOURCE" >> "$GITHUB_OUTPUT"
- name: Bind the event to the current protected-main tip
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
MAIN_REF="$RUNNER_TEMP/current-main-ref.json"
gh api "repos/${GITHUB_REPOSITORY}/git/ref/heads/main" > "$MAIN_REF"
ARGS=(--verify-main-ref-response "$MAIN_REF")
if [[ "$GITHUB_EVENT_NAME" == "pull_request_target" ]]; then
PULL_REQUEST="$RUNNER_TEMP/current-pull-request.json"
gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}" > "$PULL_REQUEST"
ARGS+=(
--verify-pull-request-response "$PULL_REQUEST"
--expected-current-main-sha "${{ steps.commits.outputs.base_sha }}"
--expected-current-head-sha "${{ steps.commits.outputs.head_sha }}"
)
else
ARGS+=(--expected-current-main-sha "${{ steps.commits.outputs.head_sha }}")
fi
python -I "${{ steps.commits.outputs.judge }}" "${ARGS[@]}"
- name: Verify protected policy authorization
id: authorization
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [[ "$GITHUB_EVENT_NAME" == "push" ]]; then
echo "push_approved=true" >> "$GITHUB_OUTPUT"
echo "candidate=false" >> "$GITHUB_OUTPUT"
exit 0
fi
STATUS_JSON=$(gh api \
"repos/${GITHUB_REPOSITORY}/commits/${HEAD_SHA}/status")
STATUS_ENTRY=$(jq -c '
[.statuses[]
| select(.context == "quality-ratchet/policy-approved")
| select(.state == "success")
| select(.creator.login == "github-actions[bot]")]
| first // {}
' <<< "$STATUS_JSON")
TARGET_URL=$(jq -r '
.target_url // ""
' <<< "$STATUS_ENTRY")
if [[ ! "$TARGET_URL" =~ /actions/runs/([0-9]+)$ ]]; then
echo "push_approved=false" >> "$GITHUB_OUTPUT"
echo "candidate=false" >> "$GITHUB_OUTPUT"
exit 0
fi
RUN_ID="${BASH_REMATCH[1]}"
EXPECTED_DESCRIPTION="sha:${HEAD_SHA:0:12} run:${RUN_ID}"
[[ "$(jq -r '.description // ""' <<< "$STATUS_ENTRY")" == "$EXPECTED_DESCRIPTION" ]] || {
echo "push_approved=false" >> "$GITHUB_OUTPUT"
echo "candidate=false" >> "$GITHUB_OUTPUT"
exit 0
}
RUN_JSON=$(gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}")
if ! jq -e --arg base_sha "$BASE_SHA" '
.event == "workflow_dispatch"
and .head_branch == "main"
and .head_sha == $base_sha
and .conclusion == "success"
and .path == ".github/workflows/quality-baseline-update.yml"
' <<< "$RUN_JSON" >/dev/null; then
echo "push_approved=false" >> "$GITHUB_OUTPUT"
echo "candidate=false" >> "$GITHUB_OUTPUT"
exit 0
fi
APPROVAL_NAME="quality-policy-approval-${HEAD_SHA}-${RUN_ID}"
ARTIFACTS=$(gh api \
"repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}/artifacts")
MATCH_COUNT=$(jq --arg name "$APPROVAL_NAME" \
'[.artifacts[] | select(.name == $name and .expired == false)] | length' \
<<< "$ARTIFACTS")
[[ "$MATCH_COUNT" == "1" ]] || {
echo "push_approved=false" >> "$GITHUB_OUTPUT"
echo "candidate=false" >> "$GITHUB_OUTPUT"
exit 0
}
ARTIFACT_ID=$(jq -r --arg name "$APPROVAL_NAME" \
'.artifacts[] | select(.name == $name and .expired == false) | .id' \
<<< "$ARTIFACTS")
ARTIFACT_DIGEST=$(jq -r --arg name "$APPROVAL_NAME" \
'.artifacts[] | select(.name == $name and .expired == false) | .digest' \
<<< "$ARTIFACTS")
[[ "$ARTIFACT_ID" =~ ^[1-9][0-9]*$ ]]
[[ "$ARTIFACT_DIGEST" =~ ^sha256:[0-9a-f]{64}$ ]]
echo "push_approved=false" >> "$GITHUB_OUTPUT"
echo "candidate=true" >> "$GITHUB_OUTPUT"
echo "run_id=$RUN_ID" >> "$GITHUB_OUTPUT"
echo "artifact_id=$ARTIFACT_ID" >> "$GITHUB_OUTPUT"
- name: Download exact approval evidence
if: steps.authorization.outputs.candidate == 'true'
uses: actions/download-artifact@v4
with:
artifact-ids: ${{ steps.authorization.outputs.artifact_id }}
path: ${{ runner.temp }}/approval-evidence
github-token: ${{ github.token }}
repository: ${{ github.repository }}
run-id: ${{ steps.authorization.outputs.run_id }}
- name: Verify immutable approval evidence binding
if: steps.authorization.outputs.candidate == 'true'
id: evidence
shell: bash
run: |
set -euo pipefail
python -I "${{ steps.commits.outputs.judge }}" \
--verify-approval-evidence \
"$RUNNER_TEMP/approval-evidence/quality-policy-approval.json" \
--expected-candidate-sha "$HEAD_SHA" \
--expected-base-sha "$BASE_SHA" \
--expected-run-id "${{ steps.authorization.outputs.run_id }}" \
--expected-repository "$GITHUB_REPOSITORY"
echo "approved=true" >> "$GITHUB_OUTPUT"
- name: Compare protected base and head findings
shell: bash
run: |
set -euo pipefail
ARGS=(
--repo .
--base-sha "${{ steps.commits.outputs.base_sha }}"
--head-sha "${{ steps.commits.outputs.head_sha }}"
--report "$RUNNER_TEMP/quality-ratchet.json"
)
if [[ "${{ steps.authorization.outputs.push_approved }}" == "true" \
|| "${{ steps.evidence.outputs.approved }}" == "true" ]]; then
ARGS+=(--authorization-approved)
fi
python -I "${{ steps.commits.outputs.judge }}" "${ARGS[@]}"
- name: Reconfirm current protected-main tip before publishing
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
MAIN_REF="$RUNNER_TEMP/final-main-ref.json"
gh api "repos/${GITHUB_REPOSITORY}/git/ref/heads/main" > "$MAIN_REF"
ARGS=(--verify-main-ref-response "$MAIN_REF")
if [[ "$GITHUB_EVENT_NAME" == "pull_request_target" ]]; then
PULL_REQUEST="$RUNNER_TEMP/final-pull-request.json"
gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}" > "$PULL_REQUEST"
ARGS+=(
--verify-pull-request-response "$PULL_REQUEST"
--expected-current-main-sha "${{ steps.commits.outputs.base_sha }}"
--expected-current-head-sha "${{ steps.commits.outputs.head_sha }}"
)
else
ARGS+=(--expected-current-main-sha "${{ steps.commits.outputs.head_sha }}")
fi
python -I "${{ steps.commits.outputs.judge }}" "${ARGS[@]}"
- name: Publish protected result on the exact head SHA
if: always()
env:
GH_TOKEN: ${{ github.token }}
JOB_STATUS: ${{ job.status }}
run: |
STATE=failure
DESCRIPTION='Protected base quality ratchet failed'
if [[ "$JOB_STATUS" == "success" ]]; then
STATE=success
DESCRIPTION='Protected base quality ratchet passed'
fi
gh api --method POST \
"repos/${GITHUB_REPOSITORY}/statuses/${HEAD_SHA}" \
-f state="$STATE" \
-f context='quality-ratchet/protected' \
-f description="$DESCRIPTION" \
-f target_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
- name: Upload ratchet evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: quality-ratchet-${{ steps.commits.outputs.head_sha }}
path: ${{ runner.temp }}/quality-ratchet.json
if-no-files-found: warn
retention-days: 14