Skip to content

Commit 5a50e43

Browse files
authored
Merge pull request #22 from fraware/hardening/full-vision-2026-08-24
Trust closure: monotonic decisions, sealed routing, honest provenance
2 parents e709735 + 8c2039c commit 5a50e43

659 files changed

Lines changed: 33439 additions & 1835 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/bench-badge.yml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ jobs:
1212
update-badge:
1313
runs-on: ubuntu-latest
1414
steps:
15-
- uses: actions/checkout@v4
16-
- uses: actions/setup-python@v5
15+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
16+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
1717
with:
1818
python-version: '3.11'
1919
- name: Install package
@@ -23,7 +23,12 @@ jobs:
2323
- name: Run expanded benchmark
2424
run: ovk bench --expanded --leaderboard .verification/formal-pr-bench-leaderboard.json
2525
- name: Render shields.io badge JSON
26-
run: python scripts/render_bench_badge.py --verified-source-sha "${GITHUB_SHA}"
26+
# A benchmark run proves only which source revision was measured. It must
27+
# never mint verified_source_sha; that designation belongs exclusively to
28+
# the complete release-evidence ledger after all required workflows,
29+
# package/Action checks, consumers, and holdout gates have been observed
30+
# for one exact source revision.
31+
run: python scripts/render_bench_badge.py --benchmark-source-sha "${GITHUB_SHA}"
2732
- name: Commit badge artifacts
2833
run: |
2934
git config user.name "github-actions[bot]"
@@ -32,13 +37,14 @@ jobs:
3237
if git diff --staged --quiet; then
3338
echo "No badge changes to commit"
3439
else
35-
# Badge commits skip CI by design. Health claims must cite verified_source_sha
36-
# inside the JSON (the commit that ran the bench), not this commit.
40+
# Badge commits skip CI by design. benchmark_source_sha identifies
41+
# the commit measured by this benchmark job; it is not a release
42+
# verification claim.
3743
git commit -m "chore: update FormalPR-Bench badge [skip ci]"
3844
git push
3945
fi
4046
- name: Upload full leaderboard artifact
41-
uses: actions/upload-artifact@v4
47+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
4248
with:
4349
name: formal-pr-bench-leaderboard
4450
path: |

.github/workflows/ci.yml

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ on:
44
push:
55
branches: [main]
66
pull_request:
7-
branches: [main]
7+
workflow_dispatch:
88

99
jobs:
1010
unit:
1111
runs-on: ubuntu-latest
1212
steps:
13-
- uses: actions/checkout@v4
14-
- uses: actions/setup-python@v5
13+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
14+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
1515
with:
1616
python-version: '3.11'
1717
- name: Install package
@@ -20,12 +20,21 @@ jobs:
2020
python scripts/sync_package_data.py
2121
pip install --no-cache-dir -e '.[dev]'
2222
- name: Lint
23-
run: ruff check ovk tests benchmarks/formal_pr_bench
23+
run: |
24+
set -o pipefail
25+
ruff check ovk tests benchmarks/formal_pr_bench 2>&1 | tee ruff-report.txt
26+
- name: Upload lint report on failure
27+
if: failure()
28+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
29+
with:
30+
name: ruff-report
31+
path: ruff-report.txt
32+
if-no-files-found: error
2433
- name: Unit and integration pytest
2534
run: pytest -x -vv --tb=long --junitxml=pytest-results.xml
2635
- name: Upload pytest results on failure
2736
if: failure()
28-
uses: actions/upload-artifact@v4
37+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
2938
with:
3039
name: pytest-results
3140
path: |
@@ -36,8 +45,8 @@ jobs:
3645
needs: unit
3746
runs-on: ubuntu-latest
3847
steps:
39-
- uses: actions/checkout@v4
40-
- uses: actions/setup-python@v5
48+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
49+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
4150
with:
4251
python-version: '3.11'
4352
- name: Install package
@@ -49,12 +58,26 @@ jobs:
4958
run: python scripts/validate_templates.py
5059
- name: Validate adapter capabilities
5160
run: python scripts/validate_capabilities.py
61+
- name: Validate adapter conformance
62+
run: python scripts/validate_adapter_conformance.py
63+
- name: Check capability tables are fresh
64+
run: python scripts/render_capability_tables.py --check
65+
- name: Check TCB document is fresh
66+
run: python scripts/render_tcb_doc.py --check
67+
- name: Verify RC DoD (in-repo)
68+
run: python scripts/verify_rc_dod.py
69+
- name: Verify RC install surface (Action SHA pins + metadata)
70+
run: python scripts/verify_rc_install.py
71+
- name: Check template claim registry is fresh
72+
run: python scripts/build_template_registry.py --check
73+
- name: Require SHA-pinned third-party actions in Action/release paths
74+
run: python scripts/pin_action_shas.py
5275
- name: Score all benchmark cases
5376
run: python benchmarks/formal_pr_bench/score_all_lanes.py
5477
- name: Score expanded benchmark and publish leaderboard
5578
run: |
5679
ovk bench --expanded --leaderboard .verification/formal-pr-bench-leaderboard.json
57-
python scripts/render_bench_badge.py --verified-source-sha "${GITHUB_SHA}" --dry-run
80+
python scripts/render_bench_badge.py --benchmark-source-sha "${GITHUB_SHA}" --dry-run
5881
- name: Pilot program
5982
run: ovk pilot
6083
- name: Exercise ovk check on multi-surface PR
@@ -137,7 +160,7 @@ jobs:
137160
- name: Validate dogfood release bundle
138161
run: ovk validate-outputs ovk-action-dogfood-bundle
139162
- name: Upload OVK artifacts
140-
uses: actions/upload-artifact@v4
163+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
141164
with:
142165
name: ovk-ci-artifacts
143166
path: |
@@ -159,7 +182,7 @@ jobs:
159182
contents: read
160183
checks: write
161184
steps:
162-
- uses: actions/checkout@v4
185+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
163186
- name: Strict emit-check on known-bad diff
164187
id: ovk
165188
continue-on-error: true
@@ -181,7 +204,7 @@ jobs:
181204
permissions:
182205
contents: read
183206
steps:
184-
- uses: actions/checkout@v4
207+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
185208
with:
186209
fetch-depth: 2
187210
- name: Exercise automatic diff collection
@@ -201,8 +224,8 @@ jobs:
201224
needs: unit
202225
runs-on: ubuntu-latest
203226
steps:
204-
- uses: actions/checkout@v4
205-
- uses: actions/setup-python@v5
227+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
228+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
206229
with:
207230
python-version: '3.12'
208231
- name: Build sdist and wheel
@@ -248,8 +271,8 @@ jobs:
248271
needs: unit
249272
runs-on: ubuntu-latest
250273
steps:
251-
- uses: actions/checkout@v4
252-
- uses: actions/setup-python@v5
274+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
275+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
253276
with:
254277
python-version: '3.11'
255278
- name: Install package
@@ -262,7 +285,7 @@ jobs:
262285
python scripts/build_template_conformance.py --check --print-domain-counts
263286
test -f docs/benchmarks/template-conformance.json
264287
- name: Upload template conformance matrix
265-
uses: actions/upload-artifact@v4
288+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
266289
with:
267290
name: template-conformance
268-
path: docs/benchmarks/template-conformance.json
291+
path: docs/benchmarks/template-conformance.json
Lines changed: 85 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
name: Consumer Pin Verification
22

3-
# Optional gate: verify independent consumers still pin immutable OVK v1.2.1
4-
# (or a configured tag) and never uses: ./
3+
# Verify independent consumers pin OVK to an exact 40-hex candidate SHA (WP-14).
4+
# Historical tags like v1.2.1 cannot evidence this candidate. uses: ./ is forbidden.
55

66
on:
77
workflow_dispatch:
88
inputs:
9-
ovk_tag:
10-
description: Immutable OVK tag consumers must pin
9+
ovk_candidate_sha:
10+
description: Exact 40-hex OVK candidate SHA consumers must pin
1111
required: true
12-
default: v1.2.1
12+
type: string
1313
fastapi_ref:
1414
description: Ref for ovk-consumer-fastapi-terraform
1515
required: true
@@ -34,54 +34,118 @@ jobs:
3434
- repo: fraware/ovk-consumer-express-actions
3535
ref: ${{ inputs.express_ref }}
3636
steps:
37+
- name: Validate candidate SHA shape
38+
env:
39+
OVK_SHA: ${{ inputs.ovk_candidate_sha }}
40+
run: |
41+
python - <<'PY'
42+
import os, re, sys
43+
sha = os.environ["OVK_SHA"].strip().lower()
44+
if not re.fullmatch(r"[0-9a-f]{40}", sha):
45+
sys.exit(f"ovk_candidate_sha must be exact 40-hex, got {sha!r}")
46+
print(f"candidate sha ok: {sha}")
47+
PY
48+
3749
- name: Checkout consumer
38-
uses: actions/checkout@v4
50+
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
3951
with:
4052
repository: ${{ matrix.repo }}
4153
ref: ${{ matrix.ref }}
4254
path: consumer
43-
- uses: actions/setup-python@v5
55+
56+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
4457
with:
4558
python-version: "3.12"
46-
- name: Assert immutable Action pin
59+
60+
- name: Assert immutable Action SHA pin (no uses: ./)
4761
env:
48-
OVK_TAG: ${{ inputs.ovk_tag }}
62+
OVK_SHA: ${{ inputs.ovk_candidate_sha }}
4963
working-directory: consumer
5064
run: |
5165
set -euo pipefail
52-
echo "Checking ${{ matrix.repo }}@${{ matrix.ref }} for OVK pin ${OVK_TAG}"
66+
echo "Checking ${{ matrix.repo }}@${{ matrix.ref }} for OVK pin ${OVK_SHA}"
5367
python - <<'PY'
5468
import os, re, sys
5569
from pathlib import Path
56-
tag = os.environ["OVK_TAG"]
70+
sha = os.environ["OVK_SHA"].strip().lower()
5771
workflows = list(Path(".github/workflows").glob("*.yml")) + list(Path(".github/workflows").glob("*.yaml"))
5872
if not workflows:
5973
sys.exit("no workflow files")
6074
failures = []
75+
pin = f"fraware/open-verification-kernel@{sha}"
76+
texts = []
6177
for path in workflows:
6278
text = path.read_text(encoding="utf-8")
79+
texts.append(text)
6380
for line in text.splitlines():
6481
m = re.match(r"\s*uses:\s*(\S+)", line)
6582
if not m:
6683
continue
6784
ref = m.group(1).strip().strip("'\"")
6885
if re.match(r"^\./", ref):
6986
failures.append(f"{path.name}: forbidden uses: ./")
70-
if "open-verification-kernel@" in ref and ref.endswith(("@main", "@master", "@HEAD")):
71-
failures.append(f"{path.name}: mutable pin {ref}")
72-
if f"fraware/open-verification-kernel@{tag}" not in text and "open-verification-kernel@" in text:
73-
# Allow workflows that do not reference OVK; require pin when present.
74-
pass
75-
texts = "\n".join(p.read_text(encoding="utf-8") for p in workflows)
76-
if f"fraware/open-verification-kernel@{tag}" not in texts:
77-
failures.append(f"missing required pin fraware/open-verification-kernel@{tag}")
87+
if "open-verification-kernel@" in ref:
88+
if ref.endswith(("@main", "@master", "@HEAD")):
89+
failures.append(f"{path.name}: mutable pin {ref}")
90+
# Tags like @v1.2.1 are insufficient for candidate evidence.
91+
if re.search(r"@v?\d+\.\d+", ref) and sha not in ref:
92+
failures.append(f"{path.name}: tag pin cannot evidence candidate SHA: {ref}")
93+
if not ref.lower().endswith("@" + sha):
94+
failures.append(f"{path.name}: expected exact SHA pin {pin}, got {ref}")
95+
joined = "\n".join(texts)
96+
if pin not in joined.lower() and f"open-verification-kernel@{sha}" not in joined.lower():
97+
# Also allow ownerless path forms that still end with @sha
98+
if f"@{sha}" not in joined.lower() or "open-verification-kernel@" not in joined.lower():
99+
failures.append(f"missing required exact pin .../open-verification-kernel@{sha}")
78100
if failures:
79101
print("FAIL")
80102
for item in failures:
81103
print(item)
82104
raise SystemExit(1)
83-
print(f"Pin verification OK for tag {tag}")
105+
print(f"Pin verification OK for candidate SHA {sha}")
84106
PY
85107
if [ -f scripts/assert_ovk_pin.py ]; then
86-
python scripts/assert_ovk_pin.py
108+
python scripts/assert_ovk_pin.py --candidate-sha "$OVK_SHA"
87109
fi
110+
111+
- name: Capture ledger-ready consumer evidence
112+
env:
113+
OVK_SHA: ${{ inputs.ovk_candidate_sha }}
114+
CONSUMER_REPO: ${{ matrix.repo }}
115+
CONSUMER_REF: ${{ matrix.ref }}
116+
working-directory: consumer
117+
run: |
118+
mkdir -p ../.verification
119+
python - <<'PY'
120+
import hashlib, json, os, pathlib, re
121+
sha = os.environ["OVK_SHA"].strip().lower()
122+
repo = os.environ["CONSUMER_REPO"]
123+
ref = os.environ["CONSUMER_REF"]
124+
workflows = list(pathlib.Path(".github/workflows").glob("*.yml")) + list(
125+
pathlib.Path(".github/workflows").glob("*.yaml")
126+
)
127+
scenario_digests = []
128+
for path in workflows:
129+
scenario_digests.append(
130+
{"path": path.as_posix(), "sha256": hashlib.sha256(path.read_bytes()).hexdigest()}
131+
)
132+
payload = {
133+
"schema_version": "ovk.consumer_pin_evidence.v1",
134+
"consumer_repository": repo,
135+
"consumer_ref": ref,
136+
"ovk_candidate_sha": sha,
137+
"pin": f"fraware/open-verification-kernel@{sha}",
138+
"workflow_digests": scenario_digests,
139+
"note": "Ledger-ready shape for release_ledger.consumers[]; requires live consumer checkout.",
140+
}
141+
out = pathlib.Path("../.verification") / f"consumer-pin-{repo.replace('/', '_')}.json"
142+
out.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
143+
print(out)
144+
PY
145+
146+
- name: Upload consumer pin evidence
147+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
148+
with:
149+
name: consumer-pin-${{ strategy.job-index }}
150+
path: .verification/consumer-pin-*.json
151+
if-no-files-found: warn

0 commit comments

Comments
 (0)