Skip to content

Merge PR #26: final RC status and ref-integrity closure #114

Merge PR #26: final RC status and ref-integrity closure

Merge PR #26: final RC status and ref-integrity closure #114

name: Consumer Pin Verification
# Verify independent consumers pin OVK to an exact 40-hex candidate SHA (WP-14).
# Historical tags like v1.2.1 cannot evidence this candidate. uses: ./ is forbidden.
on:
workflow_dispatch:
inputs:
ovk_candidate_sha:
description: Exact 40-hex OVK candidate SHA consumers must pin
required: true
type: string
fastapi_ref:
description: Ref for ovk-consumer-fastapi-terraform
required: true
default: main
express_ref:
description: Ref for ovk-consumer-express-actions
required: true
default: main
permissions:
contents: read
jobs:
verify-consumer-pins:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- repo: fraware/ovk-consumer-fastapi-terraform
ref: ${{ inputs.fastapi_ref }}
- repo: fraware/ovk-consumer-express-actions
ref: ${{ inputs.express_ref }}
steps:
- name: Validate candidate SHA shape
env:
OVK_SHA: ${{ inputs.ovk_candidate_sha }}
run: |
python - <<'PY'
import os, re, sys
sha = os.environ["OVK_SHA"].strip().lower()
if not re.fullmatch(r"[0-9a-f]{40}", sha):
sys.exit(f"ovk_candidate_sha must be exact 40-hex, got {sha!r}")
print(f"candidate sha ok: {sha}")
PY
- name: Checkout consumer
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
repository: ${{ matrix.repo }}
ref: ${{ matrix.ref }}
path: consumer
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.12"
- name: Assert immutable Action SHA pin (no uses: ./)

Check failure on line 60 in .github/workflows/consumer-pin-verification.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/consumer-pin-verification.yml

Invalid workflow file

You have an error in your yaml syntax on line 60
env:
OVK_SHA: ${{ inputs.ovk_candidate_sha }}
working-directory: consumer
run: |
set -euo pipefail
echo "Checking ${{ matrix.repo }}@${{ matrix.ref }} for OVK pin ${OVK_SHA}"
python - <<'PY'
import os, re, sys
from pathlib import Path
sha = os.environ["OVK_SHA"].strip().lower()
workflows = list(Path(".github/workflows").glob("*.yml")) + list(Path(".github/workflows").glob("*.yaml"))
if not workflows:
sys.exit("no workflow files")
failures = []
pin = f"fraware/open-verification-kernel@{sha}"
texts = []
for path in workflows:
text = path.read_text(encoding="utf-8")
texts.append(text)
for line in text.splitlines():
m = re.match(r"\s*uses:\s*(\S+)", line)
if not m:
continue
ref = m.group(1).strip().strip("'\"")
if re.match(r"^\./", ref):
failures.append(f"{path.name}: forbidden uses: ./")
if "open-verification-kernel@" in ref:
if ref.endswith(("@main", "@master", "@HEAD")):
failures.append(f"{path.name}: mutable pin {ref}")
if re.search(r"@v?\d+\.\d+", ref) and sha not in ref:
failures.append(f"{path.name}: tag pin cannot evidence candidate SHA: {ref}")
if not ref.lower().endswith("@" + sha):
failures.append(f"{path.name}: expected exact SHA pin {pin}, got {ref}")
joined = "\n".join(texts)
if pin not in joined.lower() and f"open-verification-kernel@{sha}" not in joined.lower():
if f"@{sha}" not in joined.lower() or "open-verification-kernel@" not in joined.lower():
failures.append(f"missing required exact pin .../open-verification-kernel@{sha}")
if failures:
print("FAIL")
for item in failures:
print(item)
raise SystemExit(1)
print(f"Pin verification OK for candidate SHA {sha}")
PY
if [ -f scripts/assert_ovk_pin.py ]; then
python scripts/assert_ovk_pin.py --candidate-sha "$OVK_SHA"
fi
- name: Capture ledger-ready consumer evidence
env:
OVK_SHA: ${{ inputs.ovk_candidate_sha }}
CONSUMER_REPO: ${{ matrix.repo }}
CONSUMER_REF: ${{ matrix.ref }}
working-directory: consumer
run: |
set -euo pipefail
CONSUMER_SOURCE_SHA="$(git rev-parse HEAD)"
export CONSUMER_SOURCE_SHA
mkdir -p ../.verification
python - <<'PY'
import hashlib, json, os, pathlib, re
sha = os.environ["OVK_SHA"].strip().lower()
repo = os.environ["CONSUMER_REPO"]
ref = os.environ["CONSUMER_REF"]
consumer_source_sha = os.environ["CONSUMER_SOURCE_SHA"].strip().lower()
if not re.fullmatch(r"[0-9a-f]{40}", consumer_source_sha):
raise SystemExit(f"consumer_source_sha must be 40-hex, got {consumer_source_sha!r}")
workflows = list(pathlib.Path(".github/workflows").glob("*.yml")) + list(
pathlib.Path(".github/workflows").glob("*.yaml")
)
scenario_digests = []
for path in workflows:
scenario_digests.append(
{"path": path.as_posix(), "sha256": hashlib.sha256(path.read_bytes()).hexdigest()}
)
payload = {
"schema_version": "ovk.consumer_pin_evidence.v1",
"consumer_repository": repo,
"consumer_ref": ref,
"consumer_source_sha": consumer_source_sha,
"ovk_candidate_sha": sha,
"pin": f"fraware/open-verification-kernel@{sha}",
"workflow_digests": scenario_digests,
"note": "Candidate-bound consumer pin evidence; consumer_source_sha records the exact checkout.",
}
out = pathlib.Path("../.verification") / f"consumer-pin-{repo.replace('/', '_')}.json"
out.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
print(out)
PY
- name: Upload consumer pin evidence
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: consumer-pin-${{ strategy.job-index }}
path: .verification/consumer-pin-*.json
if-no-files-found: error