Commit 79088f0
fix(governance): make validate-hypatia-baseline actually consult .hypatia-baseline.json (#455)
## Summary
The estate-wide `validate-hypatia-baseline` job in
`governance-reusable.yml` **never read `.hypatia-baseline.json`** — it
ran `hypatia-cli.sh scan .`, counted raw findings with `jq length`, and
failed if >0. Its error message ("findings not in baseline") was
misleading; the baseline had **zero** functional effect beyond flipping
the `has_baseline` trigger. This is the estate-wide fix that
**standards#449 explicitly deferred** ("does not touch
`governance-reusable.yml` itself … has the same bug for every repo that
carries a real baseline").
This wires the **already-present but unused**
`scripts/apply-baseline.sh` into the job.
## What changed (one job, `validate-hypatia-baseline`)
1. **Sparse-checkout `standards/scripts`** to get `apply-baseline.sh`
(mirrors the existing `language-policy` job's `.standards-checkout`
pattern, `ref: main`).
2. **Relativize finding paths** before matching. hypatia's
`honest_completion`/`code_safety` modules emit **absolute** `.file`
paths (`Path.expand(repo)`), while baselines use repo-relative paths
(per the schema + `docs/HYPATIA-BASELINE-FORMAT.adoc`) — so a naive
wire-in would never match (the hypatia#566 gap). Repo root maps to `"."`
so root-scoped findings (`no_tests`) match.
3. **Run `apply-baseline.sh … blocking`** with `BLOCKING_THRESHOLD:
info`, preserving the historical strictness: any finding **not**
acknowledged by an active (non-expired) baseline entry still fails the
gate — **no silent-green** — and only exact matches are suppressed.
## Why it's safe to land
- **Opt-in per repo.** Caller repos SHA-pin the reusable, so **nothing
changes for any repo** (incl. neurophone) until it bumps its
`governance.yml` pin.
- **No silent-green by construction.** `apply-baseline.sh` keeps every
non-baselined finding for the gate; new findings still fail.
- **Touches no licence/SPDX logic.**
## Validation (done locally — standards' own CI can't exercise this)
standards carries **no** `.hypatia-baseline.json`, so
`has_baseline=false` and this job **skips** on standards' own CI. I
therefore ground-truthed the wiring against synthetic fixtures shaped
like real hypatia output (absolute paths) + a neurophone-shaped
baseline:
```
=== relativized paths ===
crates/lsm/benches/bench.rs
.
android/app/src/main/java/ai/neurophone/NativeLib.java
TEST 1: all findings baselined -> exit 0 (pass; all suppressed) ✓
TEST 2: add one NEW non-baselined finding -> exit 1 (fail; no silent-green) ✓
TEST 3: kept=1 (crates/esn/src/lib.rs), suppressed=3 ✓
```
Relativization handles the two hypatia path shapes (`<abs>/crates/...`
and the bare repo root → `"."`); `apply-baseline.sh`'s
`file`/`file_pattern` glob matching and `expires_at` expiry do the rest.
## Decisions for you
1. **Strictness.** I chose `BLOCKING_THRESHOLD: info` to preserve
today's "fail on any finding" behaviour. If you'd prefer the gate only
block on `>= high` (letting new low/medium through), flip that env
value.
2. **Uppercase-`type` residual (pre-existing, not fixed here).** hypatia
emits `SD022`/`GS007` for `structural_drift`/`git_state`, which violate
the baseline **schema**'s lowercase `type` pattern. The filter matches
them fine (it doesn't schema-validate), but such baseline entries are
schema-invalid. Recommend a separate follow-up (relax the schema
pattern, or lowercase hypatia's output) — I can file it.
3. **Rollout.** Recommend: merge here, then repin **one** caller (e.g.
neurophone) and confirm its `validate-hypatia-baseline` goes
green-on-baseline / red-on-new-finding before wider repins.
Left as a **draft** for your review since it edits a security-scan gate
shared estate-wide.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_0172RBMz3qYjb1ttzD2i7RNh
---
_Generated by [Claude
Code](https://claude.ai/code/session_0172RBMz3qYjb1ttzD2i7RNh)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 2bad986 commit 79088f0
1 file changed
Lines changed: 43 additions & 9 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
109 | 123 | | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
110 | 129 | | |
111 | 130 | | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
121 | 155 | | |
122 | 156 | | |
123 | 157 | | |
| |||
0 commit comments