Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/rules/cicd_rules.ex
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ defmodule Hypatia.Rules.CicdRules do
id: :nodejs_detected,
glob: "package-lock.json",
reason:
"Node.js banned -- use Deno (org policy 2026-05-25; in-flight migration tracked under standards#253)",
"npm lockfile banned -- use Bun (`bun install`, bun.lock; JS runtime order Bun > pnpm > npm, Deno banned 2026-09-22, standards docs/JS-RUNTIME-POLICY.adoc)",
path_allow_prefixes: [
# (1a) VSCode extension host-required (/vscode/ as path segment)
"/vscode/",
Expand Down
23 changes: 17 additions & 6 deletions lib/rules/root_hygiene.ex
Original file line number Diff line number Diff line change
Expand Up @@ -144,21 +144,32 @@ defmodule Hypatia.Rules.RootHygiene do
action: :rename
},
%{pattern: "Makefile", reason: "Use Justfile", severity: :medium, action: :replace},
# JS runtime order is Bun > pnpm > npm; Deno is banned (2026-09-22).
# Source: standards docs/JS-RUNTIME-POLICY.adoc "Hard Rules". Bun
# lockfiles (bun.lock / bun.lockb) are permitted and expected, so they
# are deliberately absent here: this list used to mark bun.lockb (and
# pnpm-lock.yaml) high/delete and say "use Deno", the inverse of policy.
%{
pattern: "package-lock.json",
reason: "npm banned -- use Deno",
reason: "npm lockfile must not be tracked -- use Bun (`bun install`, bun.lock)",
severity: :high,
action: :delete
},
%{pattern: "yarn.lock", reason: "Yarn banned -- use Deno", severity: :high, action: :delete},
%{pattern: "bun.lockb", reason: "Bun banned -- use Deno", severity: :high, action: :delete},
%{pattern: "yarn.lock", reason: "Yarn banned -- use Bun", severity: :high, action: :delete},
%{
pattern: "pnpm-lock.yaml",
reason: "pnpm banned -- use Deno",
severity: :high,
reason:
"pnpm is tier 2 -- permitted only where an upstream toolchain needs a " <>
"node_modules layout; prefer Bun",
severity: :low,
action: :flag
},
%{
pattern: ".npmrc",
reason: "npm config must not be tracked -- use Bun",
severity: :medium,
action: :delete
},
%{pattern: ".npmrc", reason: "npm banned -- use Deno", severity: :medium, action: :delete},
%{
pattern: "tsconfig.json",
reason: "TypeScript banned -- use AffineScript",
Expand Down
13 changes: 12 additions & 1 deletion test/root_hygiene_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,19 @@ defmodule Hypatia.Rules.RootHygieneTest do
end

test "flags banned package managers" do
findings = RootHygiene.scan_banned(["package-lock.json", "yarn.lock", "bun.lockb"])
findings = RootHygiene.scan_banned(["package-lock.json", "yarn.lock", ".npmrc"])
assert length(findings) == 3
refute Enum.any?(findings, &(&1.reason =~ "Deno"))
end

# Bun is the tier-1 JS runtime (standards docs/JS-RUNTIME-POLICY.adoc):
# its lockfiles must never be flagged, let alone deleted.
test "Bun lockfiles are not flagged" do
assert RootHygiene.scan_banned(["bun.lock", "bun.lockb"]) == []
end

test "a pnpm lockfile is a low-severity flag, never a delete" do
assert [%{severity: :low, action: :flag}] = RootHygiene.scan_banned(["pnpm-lock.yaml"])
end

test "ignores allowed files" do
Expand Down
7 changes: 4 additions & 3 deletions test/rules/cicd_rules_rescript_npm_js_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,10 @@ defmodule Hypatia.Rules.CicdRules.RescriptNpmJsTest do

assert nj, "expected :nodejs_detected finding for non-exempt package-lock.json"
assert length(nj.files) == 2
assert nj.reason =~ "Node.js banned"
assert nj.reason =~ "Deno"
assert nj.reason =~ "standards#253"
# Deno is banned (2026-09-22); the remedy is Bun (JS-RUNTIME-POLICY).
assert nj.reason =~ "use Bun"
refute nj.reason =~ "use Deno"
assert nj.reason =~ "JS-RUNTIME-POLICY"
end

test "exempts VSCode extension host-required lockfiles" do
Expand Down
Loading