Skip to content

Commit 04027a4

Browse files
Merge branch 'main' into dependabot/cargo/bots/echidnabot/cargo-1e6483c412
2 parents 60134b0 + bb10f7f commit 04027a4

3 files changed

Lines changed: 135 additions & 3 deletions

File tree

bots/gsbot/RSR.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ implemented in **Rust** (with a designed-in SPARK verification seam — see
4444
- ✅ Automated testing (`cargo test --all-targets`)
4545
- ✅ Code quality checks (`cargo clippy --all-targets -- -D warnings`,
4646
`cargo fmt --all -- --check`)
47-
- ✅ Banned-language enforcement (Hypatia / ts-blocker / npm-bun-blocker)
47+
- ✅ Banned-language enforcement (Hypatia / runtime-policy)
4848
- ✅ Build verification
4949

5050
### ✅ Testing (Complete)

robot-repo-automaton/ERROR-CATALOG.scm

Lines changed: 127 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
;; SPDX-FileCopyrightText: 2025 Jonathan D.A. Jewell
33
;; ERROR-CATALOG.scm - Machine-readable catalog of common repo security errors
44
;; Format: Guile Scheme (homoiconic, parseable by robot-repo-cleaner)
5-
;; Updated: 2025-12-15
5+
;; Updated: 2026-07-29
66

77
(define error-catalog
88
'((metadata
99
(format-version . "1.0")
10-
(schema-version . "2025-12-15")
10+
(schema-version . "2026-07-29")
1111
(purpose . "Learning rules for propagating fixes across repositories")
1212
(generator . "robot-repo-bot/Claude analysis"))
1313

@@ -309,4 +309,129 @@
309309
(permissions . "~114 workflows")
310310
(spdx-headers . "~114 workflows")))))
311311

312+
;;=========================================================================
313+
;; ERROR CATEGORY: UNSATISFIABLE MERGE GATES
314+
;; Added 2026-07-29. Every entry below was MEASURED across all 418 active
315+
;; estate repos, not inferred. They share one shape: the board reads green
316+
;; or blocked for a reason no workflow edit can address, because the check
317+
;; never ran at all.
318+
;;=========================================================================
319+
(error-type
320+
(id . "ERR-GATE-001")
321+
(name . "phantom-required-context")
322+
(severity . "critical")
323+
(category . "unsatisfiable-gate")
324+
(description . "A required status-check context that no job ever emits. Every PR sits permanently BLOCKED, and because an absent check produces NO check-run, `gh pr checks` shows nothing wrong.")
325+
326+
(detection
327+
(method . "set-difference")
328+
(sources . ("classic branch protection" "ACTIVE branch-target RULESETS"))
329+
(sample . "PR HEAD SHAs, not the default branch")
330+
(condition . "required-context absent from observed check-runs AND commit statuses"))
331+
332+
(measured
333+
(date . "2026-07-29")
334+
(ruleset-context-rows . 236)
335+
(note . "Rulesets hold most estate requirements; classic protection alone sees almost none."))
336+
337+
(variants
338+
("invented name -- hypatia-scan, emitted by nothing"
339+
"case mismatch -- required `codeql`, real job is `CodeQL`"
340+
"filename as context -- required `.github/dependabot.yml`"))
341+
342+
(remediation
343+
(action . "remove-context-or-rename-to-match-a-real-job")
344+
(api . "DELETE /repos/{o}/{r}/branches/{b}/protection/required_status_checks/contexts")
345+
(warning . "Use that surgical sub-resource. A full PUT .../protection REPLACES the object and silently drops required_signatures / enforce_admins.")
346+
(warning-2 . "In a ruleset, emptying required_status_checks returns HTTP 422 -- the whole rule must be dropped. A ruleset PUT also replaces, so rebuild from a live GET and preserve bypass_actors.")))
347+
348+
(error-type
349+
(id . "ERR-GATE-002")
350+
(name . "required-context-never-runs-on-pull-request")
351+
(severity . "critical")
352+
(category . "unsatisfiable-gate")
353+
(description . "The producing job exists and is healthy, but is push-, schedule- or dynamic-triggered and never runs on pull_request. It therefore cannot satisfy a PR gate however green it looks on main.")
354+
355+
(detection
356+
(method . "compare-two-surfaces")
357+
(condition . "context PRESENT on default-branch HEAD but ABSENT from every sampled PR head"))
358+
359+
(measured
360+
(date . "2026-07-29")
361+
(canonical-case . "Dependabot")
362+
(emitter . "GitHub's managed dynamic/dependabot/dependabot-updates runner")
363+
(check-runs-on-main . 10)
364+
(check-runs-on-pr-head . 0)
365+
(repos-affected . 25)
366+
(note . "Sampling main scores this HEALTHY -- a false negative. It is the likely root of the estate's --admin merge drift."))
367+
368+
(remediation
369+
(action . "add-pull_request-trigger-or-stop-requiring-on-prs")))
370+
371+
(error-type
372+
(id . "ERR-GATE-003")
373+
(name . "dead-action-pin")
374+
(severity . "critical")
375+
(category . "unsatisfiable-gate")
376+
(description . "A `uses:` ref pointing at a DELETED action repository. Actions resolves refs at RUN time, and an unresolvable ref produces NO check run -- not a red one. The repo can be fully green with its scanning entirely absent.")
377+
378+
(detection
379+
(method . "resolve-every-uses-ref-against-the-api")
380+
(condition . "repository 404, or SHA not found"))
381+
382+
(measured
383+
(date . "2026-07-29")
384+
(repos . 69)
385+
(references . 135)
386+
(dead . ("hyperpolymath/a2ml-validate-action" "hyperpolymath/k9-validate-action"))
387+
(live . ("hyperpolymath/a2ml-ecosystem/validate-action" "hyperpolymath/k9-ecosystem/validate-action")))
388+
389+
(remediation
390+
(action . "REPOINT-not-vendor")
391+
(rationale . "Vendoring the script into each consumer creates one drifting copy per repo -- this estate's most recurring failure mode. Repointing is one line per file.")
392+
(warning . "Actions does NOT follow repository renames in `uses:`; a rename is a genuine break.")))
393+
394+
(error-type
395+
(id . "ERR-GATE-004")
396+
(name . "actions-policy-refuses-every-reusable")
397+
(severity . "critical")
398+
(category . "unsatisfiable-gate")
399+
(description . "allowed_actions=selected with an EMPTY patterns_allowed permits only GitHub-owned and verified actions. Every org reusable is refused at parse time, so runs die as startup_failure with ZERO jobs and no check run.")
400+
401+
(detection
402+
(method . "repository-settings")
403+
(api . "GET /repos/{o}/{r}/actions/permissions and .../selected-actions")
404+
(condition . "allowed_actions == selected AND patterns_allowed is empty"))
405+
406+
(measured
407+
(date . "2026-07-29")
408+
(scanned . 418)
409+
(broken . 2)
410+
(proof . "governance.yml went startup_failure/0 jobs -> success/10 jobs with NO file change -- settings only."))
411+
412+
(remediation
413+
(action . "populate-patterns_allowed-or-set-allowed_actions-all")
414+
(warning . "This is a SETTINGS fault. No workflow edit can fix it, and a startup_failure run cannot be re-run -- it has no jobs. Verify by dispatching a fresh run and asserting jobs > 0.")))
415+
416+
(error-type
417+
(id . "ERR-GATE-005")
418+
(name . "empty-jobs-map")
419+
(severity . "high")
420+
(category . "unsatisfiable-gate")
421+
(description . "A workflow whose `jobs:` key is present but has no uncommented job. An empty jobs map is invalid, so the run fails with zero jobs, permanently, on every matching event.")
422+
423+
(detection
424+
(method . "parse-workflow")
425+
(condition . "`jobs:` present AND no uncommented ` <name>:` beneath it"))
426+
427+
(measured
428+
(date . "2026-07-29")
429+
(repos . 20)
430+
(file . "e2e.yml -- an un-instantiated scaffold, every job block commented out"))
431+
432+
(remediation
433+
(action . "instantiate-a-real-job-or-delete-the-workflow")
434+
(warning . "Do NOT write a job that passes without testing anything -- that converts a dead gate into a fake one, which is worse because it is read as evidence.")))
435+
436+
312437
;; End of ERROR-CATALOG.scm

shared-context/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ license = "MPL-2.0"
99
repository = "https://github.com/hyperpolymath/gitbot-fleet"
1010
keywords = ["gitbot-fleet", "coordination", "context", "ci-cd"]
1111
categories = ["development-tools"]
12+
include = [
13+
"Cargo.toml",
14+
"Cargo.lock",
15+
"src/**",
16+
"tests/**",
17+
"benches/**",
18+
]
1219

1320
[dependencies]
1421
# Serialization

0 commit comments

Comments
 (0)