Merge pull request #119 from b7n0de/dependabot/github_actions/actions… #396
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |