Skip to content

Commit 8e042e6

Browse files
chore(rules-audit): 9 quick-win cleanups from 2026-05-28 catalogue audit (#382)
## Summary Smallest mechanical cleanups from the 2026-05-28 Hypatia rules audit. 7 files, 40 insertions, 21 deletions. | # | Change | Audit ref | |---|---|---| | 1 | Add `affinescript`/`affine` to `@allowed_languages` (was missing — active bug) | Part 5.6 | | 2 | Remove `rescript` from `@allowed_languages` (banned 2026-04-30) | Part 4.1 | | 3 | `@banned_languages` "typescript" => "affinescript" (was "rescript") | Part 4.1 | | 4 | `root_hygiene` tsconfig.json reason corrected → "use AffineScript" | Part 4.1 | | 5 | DELETE `:mu_plugin_no_guard` — WordPress/PHP both banned, dead rule | Part 4.7 | | 6 | DELETE `:ncl_missing_spdx` — duplicate of `security_errors/missing_spdx` | Part 3.3 | | 7 | DELETE `hex-ex-doc-xss` — targets ex_doc < 0.31.0 (2023), no live signal | Part 4.8 | | 8 | SD012 tombstone comment | Part 4.5 | | 9 | HYP-DOG-002 tombstone comment | Part 4.4 | | 10 | Fix `missing_permissions` suggestion: "read-all" → granular (was contradicting `scorecard_compliance/token_permissions`) | Part 3.2 | ## Test plan - [x] 26/26 lang-policy + security_errors tests pass via standalone elixir - [x] All 7 modules compile clean - [ ] CI green 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9b0875f commit 8e042e6

7 files changed

Lines changed: 40 additions & 21 deletions

File tree

lib/rules/cicd_rules.ex

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,10 +291,11 @@ defmodule Hypatia.Rules.CicdRules do
291291
reason: "Unfilled RSR template placeholder",
292292
exception: "rsr-template-repo"},
293293
%{id: :deno_all_perms, pattern: ~r/deno\s+run\s+-A\b/,
294-
reason: "Deno -A (all permissions) banned -- use specific --allow-* flags"},
295-
%{id: :mu_plugin_no_guard, pattern: ~r/define\(\s*['"]WP_DEBUG['"]/,
296-
reason: "WordPress mu-plugins must guard constants with defined() check",
297-
applies_to: ["*/mu-plugins/*.php"]}
294+
reason: "Deno -A (all permissions) banned -- use specific --allow-* flags"}
295+
# REMOVED 2026-05-28: :mu_plugin_no_guard targeted WordPress mu-plugins
296+
# (PHP). PHP is fully banned estate-wide; no estate repo can have a
297+
# mu-plugins/*.php path. The rule could never fire. See Hypatia audit
298+
# 2026-05-28, Part 4.7.
298299
]
299300

300301
def blocked_patterns, do: @blocked_patterns

lib/rules/code_safety.ex

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,9 +369,10 @@ defmodule Hypatia.Rules.CodeSafety do
369369
%{id: :ncl_banned_language_ref, severity: :high,
370370
pattern: ~r/language\s*=\s*"(typescript|go|python|java|kotlin|swift|dart)"/, cwe: "CWE-1104",
371371
description: "Banned language referenced in Nickel build target"},
372-
%{id: :ncl_missing_spdx, severity: :medium,
373-
pattern: ~r/\A(?!.*SPDX-License-Identifier).{0,500}\z/s, cwe: "CWE-1104",
374-
description: "Nickel file missing SPDX-License-Identifier header"},
372+
# REMOVED 2026-05-28: :ncl_missing_spdx — exact duplicate of
373+
# security_errors/missing_spdx which already covers any file type.
374+
# Nickel files have no scope distinction worth a separate rule. See
375+
# Hypatia audit 2026-05-28, Part 3.3.
375376
%{id: :ncl_k9_missing_pedigree, severity: :high,
376377
pattern: ~r/\AK9!(?!.*pedigree\s*=).+\z/s, cwe: "CWE-1104",
377378
description: "K9 contractile missing pedigree section"},

lib/rules/dogfooding.ex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ defmodule Hypatia.Rules.Dogfooding do
9696
end
9797
end
9898

99+
# ─── HYP-DOG-002: TOMBSTONE ──────────────────────────────────────────
100+
# HYP-DOG-002 was never implemented; gap left between DOG-001 and
101+
# DOG-003 during a prior renumbering. Documented as a tombstone (not
102+
# filled) per Hypatia audit 2026-05-28, Part 4.4: reusing this slot
103+
# for a fresh rule could collide with an operator's mental model
104+
# from logs. New rules should take HYP-DOG-011+.
105+
99106
# ─── HYP-DOG-003: Renamed tool references ────────────────────────────
100107

101108
defp check_stale_names(findings, repo_path) do

lib/rules/root_hygiene.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ defmodule Hypatia.Rules.RootHygiene do
103103
action: :delete},
104104
%{pattern: ".npmrc", reason: "npm banned -- use Deno", severity: :medium,
105105
action: :delete},
106-
%{pattern: "tsconfig.json", reason: "TypeScript banned -- use ReScript", severity: :high,
106+
%{pattern: "tsconfig.json", reason: "TypeScript banned -- use AffineScript", severity: :high,
107107
action: :flag},
108108
%{pattern: "go.mod", reason: "Go banned -- use Rust", severity: :high,
109109
action: :flag},

lib/rules/rules.ex

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -334,14 +334,11 @@ defmodule Hypatia.Rules do
334334
findings
335335
end
336336

337-
# ex_doc -- older versions have XSS in generated docs
338-
findings =
339-
if Regex.match?(~r/"ex_doc":\s*\{[^}]*"version":\s*"0\.(2[0-9]\.|30\.[0-5])"/, content) do
340-
[%{rule: "hex-ex-doc-xss", severity: :low,
341-
description: "ex_doc < 0.31.0 may generate docs with XSS -- update to >= 0.31.0"} | findings]
342-
else
343-
findings
344-
end
337+
# REMOVED 2026-05-28: hex-ex-doc-xss — targeted ex_doc < 0.31.0,
338+
# which was released 2023-12. Any actively-maintained Elixir
339+
# repo in the estate has long since updated; very-low-signal
340+
# rule that produces noise without value. See Hypatia audit
341+
# 2026-05-28, Part 4.8.
345342

346343
# nimble_parsec -- stack overflow on deeply nested input
347344
findings =

lib/rules/security_errors.ex

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ defmodule Hypatia.Rules.SecurityErrors do
174174
# ---------------------------------------------------------------------------
175175

176176
@fix_suggestions %{
177-
"TokenPermissionsID" => "Add \"permissions: read-all\" at workflow level",
177+
"TokenPermissionsID" => "Add granular workflow-level permissions (e.g. contents: read; scope each job's permissions to the minimum needed). NOTE: do NOT use \"read-all\" -- scorecard_compliance/token_permissions flags read-all as HIGH severity per current OSSF guidance.",
178178
"PinnedDependenciesID" => "Replace @vN with @SHA # vN format",
179179
"SecurityPolicyID" => "Create SECURITY.md with vulnerability reporting instructions",
180180
"BranchProtectionID" => "Enable branch protection via Settings > Branches",
@@ -206,9 +206,9 @@ defmodule Hypatia.Rules.SecurityErrors do
206206
"rust-toolchain-sha-missing-input" => "Add \"with: toolchain: stable\" to dtolnay step",
207207
"workflow-linter-self-detection" => "Add grep -v filters for grep/echo/comments",
208208
"unpinned_action" => "Replace @vN with @SHA # vN format",
209-
"missing_permissions" => "Add \"permissions: read-all\" at workflow level",
209+
"missing_permissions" => "Add granular workflow-level permissions (e.g. contents: read; scope each job's permissions to the minimum needed). NOTE: do NOT use \"read-all\" -- scorecard_compliance/token_permissions flags read-all as HIGH severity per current OSSF guidance.",
210210
"missing_spdx" => "Add SPDX-License-Identifier header to file",
211-
"missing-workflow-permissions" => "Add \"permissions: read-all\" at workflow level",
211+
"missing-workflow-permissions" => "Add granular workflow-level permissions (e.g. contents: read; scope each job's permissions to the minimum needed). NOTE: do NOT use \"read-all\" -- scorecard_compliance/token_permissions flags read-all as HIGH severity per current OSSF guidance.",
212212
"missing-spdx-header" => "Add SPDX-License-Identifier header to file",
213213
"stub-crypto-function" => "Replace stub with real cryptographic implementation or add compile_error! guard",
214214
"stub-hash-return" => "Replace format!(\"stub:...\") with real hash computation",
@@ -458,13 +458,19 @@ defmodule Hypatia.Rules.SecurityErrors do
458458
# RSR Language Policy
459459
# ---------------------------------------------------------------------------
460460

461+
# Policy refresh 2026-05-28: rescript REMOVED (banned 2026-04-30 per
462+
# estate policy refresh — migration target is AffineScript directly,
463+
# not through ReScript). affinescript ADDED. typescript replacement
464+
# corrected from "rescript" → "affinescript".
461465
@allowed_languages MapSet.new([
462-
"rescript", "rust", "gleam", "julia", "logtalk", "haskell",
466+
"affinescript", "affine",
467+
"rust", "gleam", "julia", "logtalk", "haskell",
463468
"bash", "nickel", "guile", "ocaml", "ada", "elixir", "zig", "idris2"
464469
])
465470

466471
@banned_languages %{
467-
"typescript" => "rescript",
472+
"typescript" => "affinescript",
473+
"rescript" => "affinescript",
468474
"nodejs" => "deno",
469475
"golang" => "rust",
470476
"python" => "julia",

lib/rules/structural_drift.ex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,13 @@ defmodule Hypatia.Rules.StructuralDrift do
515515
end)
516516
end
517517

518+
# ─── SD012: TOMBSTONE ────────────────────────────────────────────────
519+
# SD012 was never implemented; gap left between SD011 and SD013
520+
# during a prior renumbering. Documented as a tombstone (rather than
521+
# deleted from the sequence) per Hypatia audit 2026-05-28, Part 4.5:
522+
# reusing the SD012 slot for a fresh rule could collide with an
523+
# operator's mental model from logs. New rules should take SD014+.
524+
518525
# ─── SD013: Path-specific gitignore patterns ───────────────────────────
519526

520527
@path_specific_artifacts [

0 commit comments

Comments
 (0)