Skip to content

Merge pull request #119 from b7n0de/dependabot/github_actions/actions… #396

Merge pull request #119 from b7n0de/dependabot/github_actions/actions…

Merge pull request #119 from b7n0de/dependabot/github_actions/actions… #396

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
branch-base:
# ADVISORY only (FEHLER D, 2026-07-05): warns if a PR branch forks from a release tag instead of
# main — a tag-based branch re-conflicts on CHANGELOG.md every PR. Never blocks the build
# (branch_base_check.py always exits 0); continue-on-error is belt-and-suspenders.
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: Fetch tags and base branch
run: git fetch --tags --force origin "${{ github.event.pull_request.base.ref }}"
- name: Branch-base advisory
env:
BRANCH_BASE_REF: ${{ github.event.pull_request.base.ref }}
BRANCH_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: python scripts/branch_base_check.py
rust-parity:
# ADVISORY only (Finding 11, 2026-07-15), same project-style precedent as branch-base above.
# tools/pb_verify_rs is a SECOND, independent implementation of a small slice of the verifier —
# scripts/rust_parity_gate.py reports which Python `verify_*` surfaces it does/does not yet cover
# and, in --strict mode, catches a STALE claim (a registry entry saying COVERED when the Rust
# source/binary/crosscheck.py no longer back it up). It never blocks a merge: PENDING is the
# expected, honestly-declared majority state (see CROSS_IMPLEMENTATION_REPORT.md) — the point of
# this gate is HONESTY about the gap, not closing it. continue-on-error is belt-and-suspenders on
# top of the script's own default exit-0 contract; --strict is used here (registry-integrity is a
# real regression worth a red annotation) but the job itself never fails the build.
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.12"
- name: Install
run: python -m pip install -e ".[dev,eval]"
- name: Build the independent Rust second-verifier (ubuntu-latest ships cargo/rustup preinstalled)
run: cd tools/pb_verify_rs && cargo build --release
# PB-2026-0718-15: fmt/clippy are now a DETERMINISTIC gate. tools/pb_verify_rs/rust-toolchain.toml
# pins the exact toolchain (1.95.0 + rustfmt + clippy), so rustup installs the SAME rustfmt/clippy the
# code was formatted with — no more version drift disagreeing on line breaks at main.rs:1132/1496. The
# job stays continue-on-error (advisory, like rust-parity), but with the pin these should be green.
- name: Rust format check (pinned toolchain)
run: cd tools/pb_verify_rs && cargo fmt --check
- name: Rust clippy (deny warnings, pinned toolchain)
run: cd tools/pb_verify_rs && cargo clippy --all-targets -- -D warnings
- name: Cross-implementation agreement (crosscheck.py)
run: PYTHONPATH=src python tools/pb_verify_rs/crosscheck.py
- name: Rust parity report (advisory — PENDING is the expected, honest majority state)
run: python scripts/rust_parity_gate.py --strict --json
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: ${{ matrix.python-version }}
- name: Install
run: python -m pip install -e ".[dev]"
- name: Lint
run: ruff check .
- name: Type check
run: mypy src
- name: Claims hygiene (no un-negated overclaims in docs)
run: python scripts/claims_hygiene_check.py
- name: Doc links (no broken internal Markdown links)
run: python scripts/doc_link_check.py
- name: Test
run: python -m unittest discover -s tests -v
- name: Conformance corpus (offline; anchor sub-checks skip without the [anchors] extra)
run: python conformance/run_conformance.py
- name: F1 corpus integrity (schema + cross-format one-vocabulary consistency)
run: python conformance/cross_format.py
- name: F4 type-confusion matrix (public verifiers never raw-crash on JSON confusion)
run: python scripts/type_confusion_gate.py --strict
- name: F3 formal lineage-ladder model (bounded enumeration; z3-extended with the [formal] extra)
run: python formal/model.py
- name: F5 readiness-pack integrity (evidence grounded in real artifacts)
run: python scripts/readiness_pack_gate.py
- name: WP-B locked test manifest (no silent test shrink; pytest is the normative runner)
run: python scripts/test_manifest_gate.py
- name: WP-D fuzz-soak smoke (never-raise + never-false-accept over every parser class)
run: python scripts/fuzz_soak.py --duration-seconds 20 --no-write
- name: WP-G readiness-pack manifest + self-receipt integrity
run: python scripts/readiness_pack_manifest.py --check
- name: Verify the example bundle end to end
run: |
python examples/make_example.py
proofbundle verify examples/example_bundle.json
audit-candidate-matrix:
# 3.6.0 audit-candidate acceptance matrix (advisory): one machine-checkable check per §9 obligation.
# ADVISORY like rust-parity/branch-base — it prints an honest verdict per check (PASS/PENDING/
# DATA_BLOCKED/EXTERNAL/FAIL). It is NOT --strict here: a full run needs a soak box (24h) and the
# build backend, so DATA_BLOCKED is expected in CI and must not fail the build (No-Fake). The
# underlying obligations are each ALSO enforced by their own blocking gate/test elsewhere in CI.
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.12"
- name: Install
run: python -m pip install -e ".[dev,eval]"
- name: Build the independent Rust second-verifier (for the differential leg)
run: cd tools/pb_verify_rs && cargo build --release
- name: Regenerate the Python<->Rust differential matrix artifact
run: PYTHONPATH=src python tools/pb_verify_rs/crosscheck.py --matrix audit_artifacts/360/rust_differential_matrix.json
- name: Audit-candidate matrix (advisory; DATA_BLOCKED expected for the 24h soak in CI)
run: PYTHONPATH=src python scripts/audit_candidate_matrix.py
coverage:
# Coverage ratchet (comparable to python-tuf's --fail-under in tox / sigstore-python's Makefile):
# a floor that prevents a silent coverage regression. Conservative (below the current ~84%) to avoid
# flakiness from extras-dependent line counts; raise it over time. Runs the FULL pytest suite (the
# unittest-discover CI job runs only TestCase classes, so this counts the pytest-function tests too).
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.12"
- name: Install with all test extras
run: python -m pip install -e ".[dev,pq,anchors,eval]" coverage pytest
- name: Coverage with a --fail-under ratchet floor
run: |
python -m coverage run --source=src/proofbundle -m pytest -q
python -m coverage report -m --fail-under=83
crypto-floor:
# v1.7: prove the declared dependency FLOOR actually works, not just the latest. `cryptography`
# has an unbounded upper (stable API) — this pins the LOWER bound the project claims to support
# so a future floor bump can't silently break the trusted core.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.10"
- name: Install with the cryptography floor
run: |
python -m pip install -e ".[dev,eval]"
python -m pip install "cryptography==42.*"
- name: Core test suite on the floor
run: python -m unittest discover -s tests
- name: Dependency-free verify must hold on the floor (trusted-core verify path)
run: python -m proofbundle.cli verify examples/example_bundle.json
- name: Offline tamper demo must hold on the floor (needs the [eval] JCS canonicalizer)
run: python -m proofbundle.cli demo
mutation:
# Anti-Goodhart gate (v1.3): the suite must KILL broken implementations, not just be green.
# Differential vs the baseline; documented-equivalent mutants must keep surviving.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.12"
- name: Install
# [anchors] is required so the WP-A1 mutation operators (needs_rp_trust self-trust) are actually
# KILLED — without the rfc3161-client/opentimestamps libs the anchor code short-circuits at no_lib
# and the A-1 defenses would go untested by the mutation gate (release-audit F13).
run: python -m pip install -e ".[dev,pq,anchors]"
- name: Mutation check
run: python scripts/mutation_check.py
anchors:
# EXPERIMENTAL [anchors] extra (v2.0 preview): exercises the RFC 3161 TSA verifier against a real
# captured FreeTSA token + the frozen-chain rotation test — these SKIP in the base job (no
# rfc3161-client), so this job installs the extra and actually runs them. Offline: the fixture is
# committed, no live TSA call in CI.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.12"
- name: Install with the anchors extra
run: python -m pip install -e ".[dev,anchors]"
- name: Anchor tests (generic + rfc3161-tsa + opentimestamps, run not skipped)
run: python -m unittest tests.test_anchors_generic tests.test_anchors_rfc3161 tests.test_anchors_ots tests.test_conformance -v
- name: Conformance corpus with anchors required (confirmed anchor verified offline against its frozen block header)
run: python conformance/run_conformance.py --require-anchors
dependency-audit:
# pip-audit (audit hygiene, 2026-07-12): scan installed dependencies against the PyPA/OSV advisory DB.
# The ambient build tools are upgraded first so their own advisories cannot mask real project-dependency
# findings. Blocking: a known-vulnerable dependency should stop a merge. An accepted or currently-unfixable
# advisory can be pinned here with `--ignore-vuln <ID>` plus a justification comment.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.12"
- name: Install project + audit tooling
run: |
python -m pip install --upgrade pip setuptools wheel pip-audit
python -m pip install -e ".[dev,eval,anchors]"
- name: Audit dependencies for known vulnerabilities
# PYSEC-2026-2132 (click 8.2.1 command injection in click.edit()) is accepted, not fixable here:
# click is NOT a proofbundle runtime dependency (`dependencies = ["cryptography>=42"]`, zero
# `import click` in src/) — it arrives only transitively via the dev/eval/inspect extras'
# inspect_ai, whose own pin caps it at click<8.2.2 (so a local bump is impossible without an
# inspect_ai release), and click.edit() is never reached from the offline verify path. The scoped
# ignore keeps the job blocking for a REAL finding in `cryptography` (the one dependency that
# matters for this project's trust model). Re-evaluate when inspect_ai relaxes its click cap.
run: pip-audit --desc --ignore-vuln PYSEC-2026-2132