Skip to content

Commit 004053a

Browse files
hyperpolymathclaude
andcommitted
audit: gap matrix — alerts × hypatia × bots × directives (2026-04-17)
GitHub-scope gap matrix identifying where security signals lack end-to-end coverage through Hypatia rules → gitbot-fleet → directives. Four actionable gaps surfaced: - gap-codeql-to-hypatia (medium) — no rule ingests CodeQL alerts - gap-secret-scanning-to-cipherbot (high) — control-tier only - gap-scorecard-auto-remediation (low) — rule reports but does not route - gap-dependabot-pr-lifecycle (medium) — DA009 extension candidate Mirror-side delta (gap-mirror-side-discrepancy) is flagged deferred/PARKED, pending Atlassian + GitLab tokens (tracked in ~/Desktop/AI-WORK.md §0). Sampled 5 repos (standards, gitbot-fleet, boj-server, idaptik, hypatia) — 27 total open alerts across 3 distinct Rust advisories; 23 auto-routable under Hypatia Safety Triangle, 4 require-human-review. Pre-wiring baseline for verifying the 2026-04-17 dd64722 dispatch pipeline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6322cd0 commit 004053a

1 file changed

Lines changed: 262 additions & 0 deletions

File tree

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Gap Matrix — alerts × hypatia × bots × directives
3+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath)
4+
#
5+
# Scope: GitHub source-of-truth only (mirror-side sweep is PARKED — see
6+
# ~/Desktop/AI-WORK.md §0, requires Atlassian + GitLab tokens).
7+
# When the mirror sweep runs, a sibling gap-matrix-mirror-*.a2ml
8+
# will cover the delta-vs-GitHub column.
9+
#
10+
# Purpose: identify where a GitHub security signal does NOT currently
11+
# have end-to-end coverage through Hypatia rules + gitbot-fleet
12+
# + bot directives. Each gap row is an actionable wiring task.
13+
#
14+
# Method: structural matrix first (signal → rule → bot → directive),
15+
# then concrete-alert sample from 5 representative repos (2026-04-17).
16+
17+
@abstract:
18+
Cross-reference of GitHub security signals against Hypatia rule coverage,
19+
gitbot-fleet action capability, and bot directive presence. Output row =
20+
one signal × one repo; gap = missing coverage at any stage of the pipeline.
21+
@end
22+
23+
## Pipeline stages
24+
25+
[[stages]]
26+
id = "signal"
27+
description = "GitHub security signal (Dependabot, CodeQL, secret-scanning, workflow)"
28+
29+
[[stages]]
30+
id = "rule"
31+
description = "Hypatia rule module that classifies / routes the signal"
32+
33+
[[stages]]
34+
id = "bot"
35+
description = "gitbot-fleet bot that can take a physical action (PR, comment, patch)"
36+
37+
[[stages]]
38+
id = "directive"
39+
description = "Bot directive in .machine_readable/bot_directives/<bot>.a2ml governing per-repo behaviour"
40+
41+
## Structural matrix — signal → rule → bot → directive
42+
43+
[[coverage]]
44+
signal_type = "dependabot.alert.open"
45+
hypatia_rule = "Hypatia.Rules.DependabotAlerts (DA001-DA008, classify_alert, to_recipe, fixes_from_alerts)"
46+
dispatch_clause = "FleetDispatcher.dispatch_routed_action({:dependabot_fix, recipe, pattern}) — wired commit dd64722"
47+
bot = "rhodibot (substitute tier — PR open) | sustainabot (control tier — advisory) | rhodibot (eliminate tier — auto-dispatch via Fleet)"
48+
directive_coverage = "present in all 44 migrated repos post-2026-04-17 A2ML sweep"
49+
status = "wired"
50+
notes = "Full pipeline: alert → classify → safety-triangle tier → dispatch → bot action → (Kin Gate + rate limiter) → PR/comment"
51+
52+
[[coverage]]
53+
signal_type = "dependabot.alert.dismissed"
54+
hypatia_rule = "classify_alert → :control tier (respects human dismissal)"
55+
dispatch_clause = "control → sustainabot advisory only"
56+
bot = "sustainabot"
57+
directive_coverage = "yes"
58+
status = "wired"
59+
notes = "Explicit no-op on dismissed/fixed alerts — safety triangle respects human acceptance of risk."
60+
61+
[[coverage]]
62+
signal_type = "codeql.finding"
63+
hypatia_rule = "Hypatia.Rules.CodeSafety (partial — covers SHA-pinning, language policy, secret detection)"
64+
dispatch_clause = "missing — no FleetDispatcher clause routes CodeQL alerts"
65+
bot = "cipherbot (for crypto findings) | panicbot (for unsafe patterns) | rhodibot (for version pins)"
66+
directive_coverage = "partial — cipherbot.a2ml and panicbot.a2ml present; no CodeQL-specific directive schema"
67+
status = "GAP"
68+
notes = "CodeQL alerts visible via `gh api repos/.../code-scanning/alerts` but no Hypatia rule currently consumes them. Symmetric work to DA001-DA008 pending."
69+
70+
[[coverage]]
71+
signal_type = "secret_scanning.alert"
72+
hypatia_rule = "Hypatia.Rules.SecurityErrors.detect_secrets/1 — detection only, no alert-listing"
73+
dispatch_clause = "missing"
74+
bot = "cipherbot would be the natural handler"
75+
directive_coverage = "cipherbot.a2ml present but no secret-scanning-alert schema"
76+
status = "GAP"
77+
notes = "GitHub secret-scanning alerts not consumed by Hypatia. Cipherbot has the capability (rotate/revoke workflows exist) but no trigger path."
78+
79+
[[coverage]]
80+
signal_type = "workflow.failure (CI red)"
81+
hypatia_rule = "Hypatia.Rules.WorkflowAudit + Hypatia.Rules.CICDRules"
82+
dispatch_clause = "FleetDispatcher dispatches to panicbot / rhodibot for SHA-pin drift + workflow repair"
83+
bot = "rhodibot (SHA-pin updates) | panicbot (test-failure triage) | finishingbot (stale-PR pruning)"
84+
directive_coverage = "rhodibot.a2ml, panicbot.a2ml, finishingbot.a2ml present"
85+
status = "wired"
86+
notes = "Note: GitHub Actions billing freeze (AI-WORK.md §0 blocker 2026-04-17) blinds this signal — cannot distinguish CI reds from billing stalls until resolved."
87+
88+
[[coverage]]
89+
signal_type = "scorecard.score_drop"
90+
hypatia_rule = "Hypatia.Rules.ScorecardCompliance"
91+
dispatch_clause = "missing — rule reads scorecard but no dispatch to auto-remediate drops"
92+
bot = "rhodibot (for branch-protection / SHA-pin fixes) | sustainabot (for maintenance-signal drops)"
93+
directive_coverage = "yes for both bots"
94+
status = "GAP"
95+
notes = "Rule reports score but does not route to remediation. Wiring comparable to DA005-DA008 would be symmetric work."
96+
97+
[[coverage]]
98+
signal_type = "dependabot.pr.open (pull_request)"
99+
hypatia_rule = "none — Dependabot-generated PRs not inspected"
100+
dispatch_clause = "missing"
101+
bot = "rhodibot could merge safe ones; finishingbot could prune stale ones"
102+
directive_coverage = "neither has a Dependabot-PR-specific directive schema"
103+
status = "GAP"
104+
notes = "Many Dependabot PRs sit open across the estate — a future DA009 rule + dispatch clause would close this loop."
105+
106+
## Sampled concrete data — 5 repos, 2026-04-17
107+
108+
[[sample]]
109+
repo = "hyperpolymath/standards"
110+
total_open_alerts = 5
111+
distinct_advisories = 3
112+
classification_summary = "5× :eliminate (rust patch bumps, confidence ≥0.95) | 0× :substitute | 0× :control"
113+
notes = "All 5 are Rust low-severity patch-in-0.x-series. Post-wiring (commit dd64722), these should auto-route to rhodibot via dispatch_eliminate_via_fleet."
114+
115+
[[sample.advisories]]
116+
ghsa = "GHSA-965h-392x-2mh5"
117+
package = "rustls-webpki"
118+
ecosystem = "rust"
119+
vulnerable_range = ">= 0.101.0, < 0.103.12"
120+
first_patched = "0.103.12"
121+
bump_class = "patch (within 0.103 series)"
122+
hypatia_classification = ":eliminate — strict-semver ecosystem + patch bump → confidence ≥ 0.95"
123+
expected_route = "Fleet → rhodibot PR (auto-executable tier)"
124+
125+
[[sample.advisories]]
126+
ghsa = "GHSA-xgp8-3hg3-c2mh"
127+
package = "rustls-webpki"
128+
ecosystem = "rust"
129+
vulnerable_range = ">= 0.101.0, < 0.103.12"
130+
first_patched = "0.103.12"
131+
bump_class = "patch"
132+
hypatia_classification = ":eliminate"
133+
expected_route = "Fleet → rhodibot PR"
134+
135+
[[sample.advisories]]
136+
ghsa = "GHSA-cq8v-f236-94qc"
137+
package = "rand"
138+
ecosystem = "rust"
139+
vulnerable_range = ">= 0.7.0, < 0.9.3"
140+
first_patched = "0.9.3"
141+
bump_class = "major (pre-1.0 — 0.7 → 0.9 crosses minor under 0.x semantics)"
142+
hypatia_classification = ":substitute — major bump flagged for review"
143+
expected_route = "rhodibot PR with requires_human = true"
144+
145+
[[sample]]
146+
repo = "hyperpolymath/gitbot-fleet"
147+
total_open_alerts = 18
148+
distinct_advisories = 3
149+
classification_summary = "same 3 GHSAs as standards, multiplied across 6 workspace crates each"
150+
notes = "18 = 3 advisories × 6 crates. Fleet dispatch should deduplicate at the advisory level (one PR per advisory, not per Cargo.lock occurrence). Worth verifying the dedup logic in fixes_from_alerts."
151+
152+
[[sample]]
153+
repo = "hyperpolymath/boj-server"
154+
total_open_alerts = 3
155+
distinct_advisories = 3
156+
classification_summary = "same 3 GHSAs, single occurrence each"
157+
notes = "Clean 3-for-3 pattern. Expected route identical to standards."
158+
159+
[[sample]]
160+
repo = "hyperpolymath/idaptik"
161+
total_open_alerts = 1
162+
distinct_advisories = 1
163+
classification_summary = "1× rand GHSA-cq8v-f236-94qc :substitute"
164+
notes = "Single major-bump item. Will require maintainer review post-rhodibot PR."
165+
166+
[[sample]]
167+
repo = "hyperpolymath/hypatia"
168+
total_open_alerts = 0
169+
distinct_advisories = 0
170+
classification_summary = "n/a"
171+
notes = "Clean — Hypatia itself has no open Dependabot alerts. Expected for a pure-Elixir repo with few Rust dependencies."
172+
173+
## Identified wiring gaps (actionable follow-up)
174+
175+
[[gap]]
176+
id = "gap-codeql-to-hypatia"
177+
priority = "medium"
178+
description = "CodeQL alerts not ingested by any Hypatia rule"
179+
proposed_rule = "Hypatia.Rules.CodeqlAlerts — symmetric to DependabotAlerts; classify by severity + rule-id, dispatch via FleetDispatcher"
180+
proposed_dispatch = "{:codeql_fix, recipe, pattern}"
181+
blocked_by = "none — design work only"
182+
183+
[[gap]]
184+
id = "gap-secret-scanning-to-cipherbot"
185+
priority = "high"
186+
description = "Secret-scanning alerts visible on GitHub but no Hypatia rule consumes them"
187+
proposed_rule = "Hypatia.Rules.SecretScanning — list alerts, classify by secret-type, always :control tier (no auto-revoke)"
188+
proposed_dispatch = "{:secret_rotation_advisory, alert, repo} → cipherbot advisory-only"
189+
blocked_by = "none — safety-critical so must be control-tier only, no auto-execute"
190+
191+
[[gap]]
192+
id = "gap-scorecard-auto-remediation"
193+
priority = "low"
194+
description = "ScorecardCompliance reports but does not route to rhodibot/sustainabot to remediate drops"
195+
proposed_rule = "extend Hypatia.Rules.ScorecardCompliance with classify_drop/1 + to_recipe/1"
196+
proposed_dispatch = "{:scorecard_fix, drop, remediation} → rhodibot PR"
197+
blocked_by = "none"
198+
199+
[[gap]]
200+
id = "gap-dependabot-pr-lifecycle"
201+
priority = "medium"
202+
description = "Dependabot-generated PRs accumulate unmerged; no auto-merge safe ones, no auto-prune stale ones"
203+
proposed_rule = "Hypatia.Rules.DependabotAlerts extension DA009 — classify_dependabot_pr/1"
204+
proposed_dispatch = "{:dependabot_pr_merge, pr} if safe → rhodibot | {:dependabot_pr_prune, pr} if stale → finishingbot"
205+
blocked_by = "none"
206+
207+
[[gap]]
208+
id = "gap-mirror-side-discrepancy"
209+
priority = "deferred — PARKED"
210+
description = "Unknown delta between GitHub-side findings and GitLab+Bitbucket mirrors"
211+
proposed_rule = "Hypatia.Rules.MirrorDelta — compare source-of-truth GitHub findings against mirror-visible findings, flag discrepancies"
212+
proposed_dispatch = "{:mirror_advisory_sync, delta} → sustainabot advisory"
213+
blocked_by = "Atlassian API token refresh + GitLab PAT (see ~/Desktop/AI-WORK.md §0)"
214+
215+
## Coverage summary
216+
217+
[[summary]]
218+
pipeline_stage = "signal types monitored"
219+
count_wired = 3
220+
count_gap = 4
221+
gap_list = ["codeql", "secret_scanning", "scorecard_drop", "dependabot_pr_lifecycle"]
222+
223+
[[summary]]
224+
pipeline_stage = "bots with directive coverage"
225+
count_wired = 11
226+
count_gap = 0
227+
notes = "All 11 gitbot-fleet bots have .a2ml directives post-2026-04-17 migration."
228+
229+
[[summary]]
230+
pipeline_stage = "repos sampled"
231+
count = 5
232+
total_open_alerts = 27
233+
distinct_advisories = 3
234+
auto_routable_eliminate = 23
235+
requires_human_substitute = 4
236+
control_only = 0
237+
238+
## Next-action recommendation
239+
240+
[[next_action]]
241+
id = "verify-dedup"
242+
owner = "CLAUDE"
243+
description = "Verify fixes_from_alerts dedupes per-advisory so rhodibot opens one PR per GHSA, not one per Cargo.lock hit. Gitbot-fleet's 18 alerts / 3 advisories / 6 crates is the test case."
244+
effort = "30 min"
245+
246+
[[next_action]]
247+
id = "draft-codeql-rule"
248+
owner = "CLAUDE"
249+
description = "Draft Hypatia.Rules.CodeqlAlerts module mirroring DependabotAlerts structure. Non-invasive — compile + test in isolation before wiring."
250+
effort = "2-3 hours"
251+
252+
[[next_action]]
253+
id = "draft-secret-scanning-rule"
254+
owner = "CLAUDE"
255+
description = "Draft Hypatia.Rules.SecretScanning — strictly control-tier. Per user policy, no auto-revoke or auto-rotate; cipherbot advisory-only."
256+
effort = "1-2 hours"
257+
258+
[[next_action]]
259+
id = "resume-mirror-sweep"
260+
owner = "JONATHAN"
261+
description = "Refresh Atlassian API token + obtain GitLab PAT; drop both in ~/.netrc. Unblocks the MirrorDelta rule design + closes gap-mirror-side-discrepancy."
262+
effort = "5 min after token in hand"

0 commit comments

Comments
 (0)