Skip to content

fix(ci): enforce the dormant pre-commit hook; clear fmt + lopdf-advisory rot#2

Open
evnchn wants to merge 1 commit into
SecurityRonin:mainfrom
evnchn:fix/ci-hooks-fmt-advisory
Open

fix(ci): enforce the dormant pre-commit hook; clear fmt + lopdf-advisory rot#2
evnchn wants to merge 1 commit into
SecurityRonin:mainfrom
evnchn:fix/ci-hooks-fmt-advisory

Conversation

@evnchn

@evnchn evnchn commented Jun 29, 2026

Copy link
Copy Markdown

Drafted by Claude Code on evnchn's behalf; every claim below was verified as described.

TL;DR

Greens 3 of main's currently-red CI jobs — Rustfmt, Cargo Deny, Cargo Audit — by fixing causes, not symptoms.

The load-bearing finding: .githooks/pre-commit was doubly dormant — nothing sets core.hooksPath, and the file is committed non-executable (100644), which git silently skips even when hooks are enabled. So formatting drifted into main unguarded.

Deliberately not touched: the Test job (36 failures are committed TDD-red tests for unbuilt subcommands — yours by design) and the Docs job (separate workflow). This PR doesn't pretend to fix those.

Ask: review/merge. The advisory call (ignore vs upgrade) is the one judgement worth a second look — reasoning folded below.

Root cause — why fmt drifted into main

.githooks/pre-commit already exists and runs the right checks, but:

  1. No core.hooksPath is ever set (no setup recipe, no CONTRIBUTING step) — so git never looks in .githooks/.
  2. The hook is tracked 100644 — even with core.hooksPath set, git skips a non-executable hook on POSIX.

The 6 fmt-drift lines all trace to two mechanical rename commits (RapidTriage → Issen, unit → parse job) — find-and-replace sweeps that reformat nothing — committed directly to main. CI flagged them only post-merge. The rest of the tree is clean.

The hook also can't simply be enabled as-is: it ran cargo test --workspace, which is intentionally red (the 36 TDD tests), so it would block every commit. Hence scoping the enforced hook to fmt + clippy.

What changed (4 parts)
Change Effect
Justfile: just setupgit config core.hooksPath .githooks; CONTRIBUTING.md documents it the hook is actually enforced going forward
.githooks/pre-commit: mode 100644 → 100755, drop cargo test --workspace, keep fmt + clippy (-D warnings) hook is invoked by git and can pass (CI still runs the full test job)
cargo fmt on the 3 drifted files clears the Rustfmt failure
RUSTSEC-2026-0187 (lopdf) → deny.toml + .cargo/audit.toml greens Cargo Deny + Cargo Audit

Note: just setup overwrites a contributor's existing local core.hooksPath (per-clone-local, not global). Happy to add a guard if you'd prefer.

The advisory: why ignore, not upgrade (the non-rug-sweep check)

cargo audit suggests lopdf >= 0.42.0. I checked whether that's reachable before ignoring:

$ cargo update -p lopdf --precise 0.42.0
error: failed to select a version for the requirement `lopdf = "^0.39.0"`
  required by package `printpdf v0.9.1`

printpdf 0.9 (pinned in crates/issen-report/Cargo.toml) requires lopdf ^0.39, so it can't be bumped independently — the real fix is a future printpdf bump. lopdf is reached only via printpdf for report generation; the advisory is a stack overflow when parsing deeply-nested input PDFs, a path this code never takes. So a documented ignore matching the existing "transitive; awaiting upstream" policy in deny.toml is proportionate.

Verification (pinned 1.96.0 toolchain, matching CI)
cargo fmt --all -- --check    → PASS
cargo deny check              → advisories ok, bans ok, licenses ok, sources ok   (rc 0)
cargo audit                   → 13 allowed warnings, 0 vulnerabilities            (rc 0)

Hook executable-bit fix proven behaviorally (with core.hooksPath=.githooks):

  • mode 100644: an empty test commit succeeded → hook skipped (the latent bug).
  • mode 100755: the same commit was blocked, printing ==> pre-commit: cargo fmt --check → git now invokes it.

cargo fmt changes are mechanical line-wrapping only (no semantic drift). Reviewed independently by a second model (Codex, different lineage): no blocking findings.

Out of scope (left red on purpose)

  • 36 Test failures — committed TDD-red for Ingest/Analyse/Pivot/Supertimeline subcommands not yet built.
  • Docs job — separate workflow; not diagnosed here. Happy to follow up.

… new lopdf advisory

Three of main's red CI jobs are accidental rot, not feature work:

- Rustfmt: .githooks/pre-commit exists (fmt+clippy+test) but is never enforced
  — nothing sets core.hooksPath, so two mechanical rename commits drifted
  formatting into main. Add a 'just setup' recipe + a CONTRIBUTING step that
  sets core.hooksPath=.githooks; scope the enforced hook to fmt + clippy (the
  test suite is intentionally red under the TDD workflow, so it cannot gate
  every commit — CI still runs it); and run cargo fmt to clear the existing
  drift (issen-report, issen-signatures, an issen-mem scratch test).
- Cargo Deny / Cargo Audit: add RUSTSEC-2026-0187 (lopdf stack overflow, high)
  to deny.toml and .cargo/audit.toml. lopdf is transitive via printpdf 0.9
  (pins lopdf ^0.39) and used only for report generation, never to parse
  untrusted PDFs, so it cannot be bumped independently — matching the existing
  'transitive; awaiting upstream' ignore policy.

Verified on the pinned 1.96.0 toolchain: cargo fmt --all --check, cargo deny
check, and cargo audit all pass. The Test job's 36 failures are left untouched
(committed TDD red tests for subcommands not yet built).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DRGyJcRwSwtMcirxKZr7p4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant