Files
siftlode/frontend/src/lib/gates.contract.test.ts
T
peter 4aaaaa7860 chore(comments): drop epic, sprint and review-round ids from the code
The code cited its plan instead of saying why: `E28 review J4`, `(R6 S3b)`, `S1 justified…`,
`deep-review round 5`. That plan lives in the private ops repo, so for every reader of this one the
citation was noise, and a sentence whose subject was the plan step ("round 2 showed…") hid its
lesson behind an id. Each one is gone and the "why" kept: a bare citation is deleted, a sentence
carrying a lesson is reworded around it ("a later attempt showed…").

Measured (`scripts/audit_metrics.py`, product code): 652 lines in 270 files carried an epic code by
the definition the next commit holds (507 / 241 by the old, two-digit-only one) -> 0. Across all
code, tests, scripts and configs: ~1100 epic-code lines plus ~320 sprint/round ids.

Behaviour unchanged, checked mechanically: every changed .py file has the same AST once docstrings
are blanked; css/sh/toml/yml/json files are identical once comments are stripped; the only
non-comment changes in TS/JS are test titles, one description string in a contract table, and five
ESLint messages, whose text is all the gates snapshot diff holds. Not touched: Markdown (docs and
the changelog keep their history), Alembic migrations, TV episode notation (`S2 · E5`), DESIGN.md
ids (`C1`, `B4`, `S3h`), tracker ids (`SEC-16`, `DX-17`).

One stale claim fixed on the way: test_hls_reaper's docstring said the player checkpoints "every
10 s whether or not it is playing", which plex/stream.py calls wrong; it now says what the code does.
2026-10-05 00:19:39 +02:00

604 lines
27 KiB
TypeScript

import { createHash } from "node:crypto";
import { readdirSync, readFileSync, writeFileSync } from "node:fs";
import { relative } from "node:path";
import { fileURLToPath } from "node:url";
import { ESLint, type Linter } from "eslint";
import prettierConfig from "eslint-config-prettier";
import { format, resolveConfig } from "prettier";
import { parse as parseToml } from "smol-toml";
import ts from "typescript";
import tseslint from "typescript-eslint";
import { describe, expect, it } from "vitest";
// The gate register (docs/gates.md) is held to the EFFECTIVE configuration. A narrowing that
// is not on the register fails here — a rule switched off for a scope, a weak compiler flag, a ruff
// ignore, a knip exclusion, an accepted CVE. So "the gate checks X" is a claim this test verifies,
// not one a comment makes. (The comment that claimed the React Compiler's rules "are also linted"
// stood for months while the rule that would have said so was off.)
//
// Each narrowing is a (scope, id) pair; the register must hold a table row whose first cell is the
// scope and which names the id in backticks.
const REPO = fileURLToPath(new URL("../../../", import.meta.url));
const FRONTEND = `${REPO}frontend/`;
const read = (path: string) => readFileSync(REPO + path, "utf8");
/** register scope → every backticked id on its rows. */
function register(): Map<string, Set<string>> {
const rows = new Map<string, Set<string>>();
for (const line of read("docs/gates.md").split("\n")) {
if (!line.startsWith("|") || /^\|(\s*-+\s*\|)+\s*$/.test(line)) continue; // not the |---| rule
// a row may cover several scopes the same way: `src tests · ui tests · lib tests`
for (const scope of line
.split("|")[1]!
.split(" · ")
.map((s) => s.trim())) {
const ids = rows.get(scope) ?? new Set<string>();
for (const m of line.matchAll(/`([^`]+)`/g)) ids.add(m[1]!);
rows.set(scope, ids);
}
}
return rows;
}
function missingFrom(found: [scope: string, id: string][]): string[] {
const reg = register();
return found.filter(([scope, id]) => !reg.get(scope)?.has(id)).map(([s, id]) => `${s}: ${id}`);
}
const jsonc = (path: string) => {
const { config, error } = ts.parseConfigFileTextToJson(path, read(path));
if (error)
throw new Error(`${path}: ${ts.flattenDiagnosticMessageText(error.messageText, "\n")}`);
return config as Record<string, unknown>;
};
// --- ESLint ---------------------------------------------------------------------------------------
const severity = (v: Linter.RuleEntry | undefined): number => {
if (v === undefined) return -1; // not applied at all
const s = Array.isArray(v) ? v[0] : v;
return s === 2 || s === "error" ? 2 : s === 1 || s === "warn" ? 1 : 0;
};
// Formatting is Prettier's (its own lane): the rules eslint-config-prettier switches off are not a
// narrowing of anything.
const PRETTIER_OFF = new Set(
Object.entries(prettierConfig.rules ?? {})
.filter(([, v]) => severity(v as Linter.RuleEntry) === 0)
.map(([r]) => r),
);
// …and the core rules typescript-eslint's compatibility layer switches off for TS files because the
// type checker reports them itself (no-undef, no-redeclare, no-dupe-keys, …).
const TSC_OWNED = new Set(
Object.entries(tseslint.configs.eslintRecommended.rules ?? {})
.filter(([, v]) => severity(v as Linter.RuleEntry) === 0)
.map(([r]) => r),
);
const family = (rule: string) => (rule.includes("/") ? `${rule.split("/")[0]}/*` : rule);
// A rule option whose key says it lets something through (`allowShortCircuit`,
// `allowForKnownSafeCalls`, `ignoreRestSiblings`, `exceptAfterSingleLine`) narrows the rule, and a
// `no-restricted-*` list re-declared for a scope narrows it by every entry it leaves out.
const RELAXING_KEY = /^(allow|ignore|except)/;
const relaxes = (options: unknown[]): boolean =>
options.some(
(o) =>
o !== null &&
typeof o === "object" &&
Object.entries(o).some(
([k, v]) => RELAXING_KEY.test(k) && v !== false && !(Array.isArray(v) && v.length === 0),
),
);
function restrictedEntries(entry: Linter.RuleEntry | undefined): Set<string> {
const opts: unknown[] = Array.isArray(entry) ? entry.slice(1) : [];
const flat = opts.flatMap((o) => {
if (o === null || typeof o !== "object" || Array.isArray(o)) return [o];
const { paths = [], patterns = [] } = o as { paths?: unknown[]; patterns?: unknown[] };
return "paths" in o || "patterns" in o ? [...paths, ...patterns] : [o];
});
return new Set(flat.map((e) => JSON.stringify(e)));
}
// --- the snapshot ---------------------------------------------------------------------------------
// The configs that can narrow a gate in more shapes than a check can enumerate are held to a
// COMMITTED SNAPSHOT: ESLint's effective config per scope, and the lines that run the
// lanes. Any change fails until the snapshot is regenerated, so a narrowing arrives as a diff of
// `gates.snapshot.json` in review instead of slipping past a detector. (Three review rounds kept
// finding shapes the detector this replaced did not model — a `basePath` global ignore, a widened glob
// filed under a narrow row, a substring check on a gate line. A comparison against everything has no
// shape to miss.)
//
// A scope is named by PATH (`scopeOf`), and every file of a scope must get the same effective config.
// So a new file in a known place changes nothing (the snapshot once listed every file, and 31% of
// commits regenerated it), while a glob that moves a file into another config splits its scope and
// fails below, and a scope whose rules change is a snapshot diff.
//
// Regenerate: GATE_SNAPSHOT=update npx vitest run src/lib/gates.contract.test.ts
// then read the diff like any gate change. A new kind of file (a new config or a new place) needs a
// line in `scopeOf` and, when it narrows anything, its register rows.
const SNAPSHOT = "frontend/src/lib/gates.snapshot.json";
type EslintConfig = {
rules: Record<string, unknown[]>;
linterOptions: Record<string, unknown>;
languageOptions: Record<string, unknown>;
plugins: string[];
settings: unknown;
};
type Snapshot = {
eslint: Record<string, EslintConfig>;
lanes: Record<string, unknown>;
};
/** The register scope a code file belongs to, by its path (relative to frontend/). */
function scopeOf(file: string): string {
if (!file.includes("/")) return /[.][mc]?js$/.test(file) ? "js configs" : "ts configs";
if (file.startsWith("e2e/")) return "e2e";
if (file.startsWith("src/design-lab/")) return "design-lab";
// the network owners (NETWORK_OWNERS in eslint.config.js)
if (file === "src/lib/http.ts") return "lib/http.ts";
if (file === "src/lib/api/core.ts") return "lib/api/core.ts";
const test = /[.]test[.]tsx?$/.test(file);
if (file.startsWith("src/components/ui/")) return test ? "ui tests" : "ui";
if (file.startsWith("src/lib/")) return test ? "lib tests" : "src/lib";
return test ? "src tests" : "src";
}
const sortKeys = (v: unknown): unknown =>
Array.isArray(v)
? v.map(sortKeys)
: v !== null && typeof v === "object"
? Object.fromEntries(
Object.keys(v)
.sort()
.map((k) => [k, sortKeys((v as Record<string, unknown>)[k])]),
)
: v;
// through JSON, so a value compares as what the file can hold (a RegExp option is `{}` on both sides)
const canonical = <T>(v: T): T => JSON.parse(JSON.stringify(sortKeys(v) ?? null)) as T;
function normalize(cfg: Linter.Config): EslintConfig {
const lang = { ...(cfg.languageOptions ?? {}) } as Record<string, unknown>;
const parser = lang.parser as { meta?: { name?: string } } | undefined;
const parserOptions = { ...(lang.parserOptions as Record<string, unknown> | undefined) };
if (typeof parserOptions.tsconfigRootDir === "string")
// absolute: differs per machine
parserOptions.tsconfigRootDir = relative(FRONTEND, parserOptions.tsconfigRootDir) || ".";
// ~1200 browser globals per config: held by count and digest, not listed
const globals = Object.entries((lang.globals ?? {}) as Record<string, unknown>)
.map(([name, v]) => `${name}:${String(v)}`)
.sort();
const digest = createHash("sha1").update(globals.join("\n")).digest("hex").slice(0, 12);
return canonical({
languageOptions: {
...lang,
parser: parser ? (parser.meta?.name ?? "(unnamed parser)") : null,
parserOptions,
globals: `${globals.length} names, sha1 ${digest}`,
},
linterOptions: (cfg.linterOptions ?? {}) as Record<string, unknown>,
plugins: Object.keys(cfg.plugins ?? {}).sort(),
settings: cfg.settings ?? null,
rules: Object.fromEntries(
Object.entries(cfg.rules ?? {}).map(([rule, v]) => [
rule,
Array.isArray(v) ? [severity(v), ...v.slice(1)] : [severity(v)],
]),
),
});
}
// Every code file `eslint .` walks into. The skipped directories are the global ignores' generated
// output (the register's `everywhere` row) — untracked, and present on one machine but not another.
// Every other file is asked for its config, so a file a new ignore drops is reported as not linted.
const WALK_SKIP = new Set([
"node_modules",
"dist",
"playwright-report",
"test-results",
"e2e/.auth",
]);
const CODE = /[.](?:[mc]?[jt]s|[jt]sx)$/;
function codeFiles(dir = ""): string[] {
return readdirSync(FRONTEND + dir, { withFileTypes: true }).flatMap((d) => {
const path = dir + d.name;
if (d.isDirectory()) return WALK_SKIP.has(path) ? [] : codeFiles(`${path}/`);
return CODE.test(d.name) ? [path] : [];
});
}
// On disk every config but src is written as its difference from src — the rules it sets otherwise
// and the src rules it does not apply — so a scope reads like its register rows, and one rule set
// is not repeated a dozen times. In memory it is always whole.
type Stored = Omit<EslintConfig, "rules"> & {
rules: Record<string, unknown[]>;
notApplied?: string[];
};
function toStored(configs: Record<string, EslintConfig>): Record<string, Stored> {
const src = configs.src?.rules;
if (!src) return configs;
return Object.fromEntries(
Object.entries(configs).map(([name, cfg]) => {
if (name === "src") return [name, cfg];
const rules = Object.fromEntries(
Object.entries(cfg.rules).filter(([r, v]) => JSON.stringify(v) !== JSON.stringify(src[r])),
);
return [
name,
{ ...cfg, rules, notApplied: Object.keys(src).filter((r) => !(r in cfg.rules)) },
];
}),
);
}
function fromStored(stored: Record<string, Stored>): Record<string, EslintConfig> {
const src = stored.src?.rules ?? {};
return Object.fromEntries(
Object.entries(stored).map(([name, { notApplied, ...cfg }]) => {
if (!notApplied) return [name, cfg];
const rules = { ...src, ...cfg.rules };
for (const r of notApplied) delete rules[r];
return [name, canonical({ ...cfg, rules })];
}),
);
}
const committed = (): Snapshot => {
const s = JSON.parse(read(SNAPSHOT)) as Omit<Snapshot, "eslint"> & {
eslint: Record<string, Stored>;
};
return canonical({ ...s, eslint: fromStored(s.eslint) });
};
type EslintActual = {
configs: Record<string, EslintConfig>;
/** the files no config lints */
notLinted: string[];
/** `scope: file` for each file whose config is not its scope's (the scope's majority) */
strays: string[];
};
async function eslintActual(): Promise<EslintActual> {
const eslint = new ESLint({ cwd: FRONTEND });
const byScope = new Map<string, Map<string, { config: EslintConfig; files: string[] }>>();
const notLinted: string[] = [];
for (const file of codeFiles().sort()) {
const raw = (await eslint.calculateConfigForFile(file)) as Linter.Config | undefined;
if (!raw) {
notLinted.push(file);
continue;
}
const config = normalize(raw);
const key = JSON.stringify(config);
const scope = scopeOf(file);
const groups =
byScope.get(scope) ?? new Map<string, { config: EslintConfig; files: string[] }>();
const group = groups.get(key) ?? { config, files: [] };
group.files.push(file);
groups.set(key, group);
byScope.set(scope, groups);
}
const configs: Record<string, EslintConfig> = {};
const strays: string[] = [];
for (const [scope, groups] of byScope) {
const [first, ...rest] = [...groups.values()].sort((a, b) => b.files.length - a.files.length);
configs[scope] = first!.config;
for (const g of rest) strays.push(...g.files.map((f) => `${scope}: ${f}`));
}
return { configs: canonical(configs), notLinted, strays };
}
// the lines that run each lane, comments and blank lines aside
function meaningful(path: string): string[] {
return read(path)
.split("\n")
.map((l) => l.trimEnd())
.filter((l) => {
const t = l.trim();
return t !== "" && !/^(#|\/\/|\/\*|\*)/.test(t);
});
}
const lanes = () => ({
"scripts/check.sh": meaningful("scripts/check.sh"),
"backend/docker-compose.test.yml": meaningful("backend/docker-compose.test.yml"),
"backend/Dockerfile.test": meaningful("backend/Dockerfile.test"),
"frontend/package.json scripts": (
JSON.parse(read("frontend/package.json")) as { scripts: Record<string, string> }
).scripts,
"frontend/vitest.config.ts": meaningful("frontend/vitest.config.ts"),
"frontend/.prettierignore": meaningful("frontend/.prettierignore"),
});
let actual: Promise<EslintActual> | undefined;
const linted = () => (actual ??= eslintActual());
const current = async (): Promise<Snapshot> =>
canonical({ eslint: (await linted()).configs, lanes: lanes() });
// --- the register, read off the snapshot ------------------------------------------------------------
const ignorable = (rule: string, all: Record<string, unknown>) =>
PRETTIER_OFF.has(rule) ||
TSC_OWNED.has(rule) ||
// a core rule off because its typescript-eslint twin replaces it is reported as the twin
(!rule.includes("/") && `@typescript-eslint/${rule}` in all);
const entry = (v: unknown[] | undefined) => v as Linter.RuleEntry | undefined;
/** Every narrowing in the effective ESLint configs, as (scope, id). */
function eslintNarrowings({ configs, notLinted }: EslintActual): [string, string][] {
const found: [string, string][] = notLinted.map((f) => ["everywhere", `${f} — not linted`]);
const src = configs.src?.rules;
if (!src) return [...found, ["src", "(no config named src)"]];
for (const [scope, { rules, linterOptions }] of Object.entries(configs)) {
// an unused `eslint-disable` is an error on every file, or a stale suppression stays armed
if (severity(linterOptions.reportUnusedDisableDirectives as Linter.RuleEntry) !== 2)
found.push([scope, "reportUnusedDisableDirectives"]);
const ids = new Set<string>();
for (const [rule, v] of Object.entries(rules)) {
if (ignorable(rule, rules)) continue;
const mine = entry(v)!;
const theirs = scope === "src" ? undefined : entry(src[rule]);
const relaxed = relaxes(v.slice(1)) && JSON.stringify(v) !== JSON.stringify(src[rule]);
if (theirs === undefined) {
// src, or a rule src does not have (the test and e2e plugins): at off or warn, or relaxed
if (severity(mine) < 2 || (scope === "src" ? relaxes(v.slice(1)) : relaxed)) ids.add(rule);
} else if (severity(mine) < severity(theirs)) ids.add(rule);
else if (rule.includes("no-restricted-")) {
const own = restrictedEntries(mine);
if ([...restrictedEntries(theirs)].some((e) => !own.has(e))) ids.add(rule);
} else if (relaxed) ids.add(rule);
}
// a src rule not applied at all here: one id for its whole family
if (scope !== "src")
for (const [rule, v] of Object.entries(src))
if (!(rule in rules) && !ignorable(rule, src) && severity(entry(v)) > 0)
ids.add(family(rule));
for (const id of ids) found.push([scope, id]);
}
return found;
}
describe("the gate snapshot (gates.snapshot.json)", () => {
it("holds the effective ESLint config of every scope and the lines that run each lane", async () => {
const now = await current();
if (process.env.GATE_SNAPSHOT === "update") {
const path = REPO + SNAPSHOT;
const options = { ...(await resolveConfig(path)), filepath: path };
const stored = { ...now, eslint: toStored(now.eslint) };
writeFileSync(path, await format(JSON.stringify(sortKeys(stored)), options));
return;
}
expect(now).toEqual(committed());
}, 120_000);
// A glob that moves one file into another config (a product file into the test config) leaves its
// scope's config as it was, so the snapshot alone would not see it: the file now differs from the
// rest of its scope, and that is what fails here.
it("gives every file of a scope the same config", async () => {
expect((await linted()).strays).toEqual([]);
}, 120_000);
});
describe("the gate register (docs/gates.md)", () => {
it("lists every ESLint rule narrowed, by scope", async () => {
expect(missingFrom(eslintNarrowings(await linted()))).toEqual([]);
}, 120_000);
it("keeps --max-warnings 0, which is what makes a warn-level rule fail", () => {
const pkg = JSON.parse(read("frontend/package.json")) as { scripts: Record<string, string> };
expect(pkg.scripts.lint).toBe("eslint . --max-warnings 0");
});
// --- TypeScript ---------------------------------------------------------------------------------
const PROJECTS = [
"frontend/tsconfig.json",
"frontend/tsconfig.node.json",
"frontend/e2e/tsconfig.json",
];
const REQUIRED_ON = [
"strict",
"noUncheckedIndexedAccess",
"noUnusedLocals",
"noUnusedParameters",
"noFallthroughCasesInSwitch",
];
it.each(PROJECTS)("%s keeps the strict flags on", (path) => {
const opts = jsonc(path).compilerOptions as Record<string, unknown>;
expect(REQUIRED_ON.filter((flag) => opts[flag] !== true)).toEqual([]);
});
// `strict: true` is a bundle: a sub-flag set false beside it, an `extends` this test cannot see
// through, or a narrowed `include` / an `exclude` weakens the project while the five flags above
// still read true.
const STRICT_FAMILY = [
"noImplicitAny",
"strictNullChecks",
"strictFunctionTypes",
"strictBindCallApply",
"strictPropertyInitialization",
"noImplicitThis",
"alwaysStrict",
"useUnknownInCatchVariables",
"strictBuiltinIteratorReturn",
];
const INCLUDE: Record<string, string[]> = {
"frontend/tsconfig.json": ["src"],
"frontend/tsconfig.node.json": [
"vite.config.ts",
"vitest.config.ts",
"reactPlugin.ts",
"devOnlyGuard.ts",
"playwright.config.ts",
"postcss.config.js",
],
"frontend/e2e/tsconfig.json": [".", "../playwright.config.ts"],
};
it("lists every weakening compiler flag", () => {
const found: [string, string][] = [];
for (const path of PROJECTS) {
const cfg = jsonc(path);
const opts = cfg.compilerOptions as Record<string, unknown>;
if (opts.skipLibCheck === true) found.push(["all three projects", "skipLibCheck"]);
for (const flag of STRICT_FAMILY) if (opts[flag] === false) found.push([path, flag]);
for (const key of ["extends", "exclude", "files"]) if (key in cfg) found.push([path, key]);
expect(cfg.include, path).toEqual(INCLUDE[path]);
}
expect(missingFrom(found)).toEqual([]);
});
it("type-checks every config file at the frontend root, or lists it", () => {
const checked = new Set(INCLUDE["frontend/tsconfig.node.json"]);
const roots = readdirSync(FRONTEND).filter((f) => /[.](ts|js|mjs|cjs)$/.test(f));
const found = roots
.filter((f) => !checked.has(f))
.map((f): [string, string] => ["config files", `${f} — not type-checked`]);
expect(missingFrom(found)).toEqual([]);
// a `.js` in `include` is dropped without a word unless allowJs, and read unchecked without
// checkJs
const opts = jsonc("frontend/tsconfig.node.json").compilerOptions as Record<string, unknown>;
if ([...checked].some((f) => /[.][mc]?js$/.test(f)))
expect([opts.allowJs, opts.checkJs]).toEqual([true, true]);
});
// --- Ruff -----------------------------------------------------------------------------------------
// Ruff, pyright, pytest and knip are read as whitelists: a key this test does not know (an
// `extend-exclude`, a `lint.extend-ignore`, a narrowing `select`, a pyright `exclude`, a pytest
// `-m "not slow"`, a knip `rules`) fails until someone decides whether it narrows (only
// `ignore` and the immutable calls used to be read). The TOML is PARSED, not scanned line by
// line: a `[lint.per-file-ignores]` table or a quoted key is a key path like any other (a line
// regex saw neither).
const keyPaths = (o: Record<string, unknown>, prefix = ""): string[] =>
Object.entries(o).flatMap(([k, v]) =>
v !== null && typeof v === "object" && !Array.isArray(v)
? keyPaths(v as Record<string, unknown>, `${prefix}${k}.`)
: [`${prefix}${k}`],
);
it("lists every ruff ignore and immutable call, and knows every key", () => {
const cfg = parseToml(read("backend/ruff.toml"));
expect(keyPaths(cfg).sort()).toEqual(
[
"lint.extend-select",
"lint.flake8-bugbear.extend-immutable-calls",
"line-length",
"target-version",
].sort(),
);
const lint = cfg.lint as Record<string, unknown>;
// the selection on top of ruff's defaults (E, F) — dropping one narrows the lane
expect(lint["extend-select"]).toEqual([
"LOG",
"G",
"T20",
"TRY400",
"TRY401",
"S110",
"S112",
"BLE001",
"RUF100",
"PLW1510",
"B",
]);
const immutable = (lint["flake8-bugbear"] as Record<string, string[]>)[
"extend-immutable-calls"
]!;
const found = immutable.map((c): [string, string] => ["backend + scripts", c]);
expect(missingFrom(found)).toEqual([]);
});
// Every ruff lane passes `--config backend/ruff.toml`, which makes ruff ignore any other config
// file it would discover (measured: a nested `ruff.toml` selecting the `D` rules changed nothing).
// So that flag is what makes this file the whole configuration. The snapshot holds every line of
// the gate script; these two are spelled out because the reason is (a substring check once let
// an extra `--config "lint.extend-ignore=…"` override through).
it("runs both ruff lanes on backend/ruff.toml and nothing else", () => {
const lanes = read("scripts/check.sh")
.split("\n")
.filter((l) => /python -m ruff (check|format)/.test(l))
.map((l) => l.trim());
expect(lanes).toEqual([
"ruff_check() { ruff_pinned && python -m ruff check --config backend/ruff.toml backend scripts; }",
"ruff_format() { ruff_pinned && python -m ruff format --check --config backend/ruff.toml backend scripts; }",
]);
});
// --- basedpyright ---------------------------------------------------------------------------------
const PYRIGHT_KEYS = [
"include",
"extraPaths",
"typeCheckingMode",
"pythonVersion",
"pythonPlatform",
];
it("lists the type-check mode, the baseline and every rule override, and knows every key", () => {
const cfg = jsonc("backend/pyrightconfig.json");
const found: [string, string][] = [];
if (cfg.typeCheckingMode !== "all" && cfg.typeCheckingMode !== "strict")
found.push(["backend/app + alembic", "typeCheckingMode"]);
found.push(["backend/app + alembic", "baseline.json"]);
const weak = [false, "none", "warning", "information", "hint"];
for (const [key, value] of Object.entries(cfg))
if (key.startsWith("report") && weak.includes(value as string | boolean))
found.push(["backend/app + alembic", key]);
expect(
Object.keys(cfg).filter((k) => !k.startsWith("report") && !PYRIGHT_KEYS.includes(k)),
).toEqual([]);
expect(cfg.include).toEqual(["app", "alembic"]); // tests/ out — its row says why
expect(missingFrom(found)).toEqual([]);
});
// --- pytest ---------------------------------------------------------------------------------------
// Held line by line, not key by key: pytest's ini reader also takes `key: value` and indented
// continuation lines (`addopts = -q` + ` -m "not slow"`), and a key regex saw neither.
// Every line that is not blank or a comment must be one of these, and all must be there.
it("keeps pytest strict: the whole tests/ tree, no selection, no warning filters, --strict-markers", () => {
const lines = read("backend/pytest.ini")
.split("\n")
.map((l) => l.trimEnd())
.filter((l) => l.trim() !== "" && !/^[#;]/.test(l.trim()));
expect(lines).toEqual([
"[pytest]",
"testpaths = tests",
"pythonpath = .",
"addopts = -q -rs --strict-markers",
]);
});
// --- knip -----------------------------------------------------------------------------------------
it("lists every knip exclusion and every other key", () => {
const cfg = jsonc("frontend/knip.jsonc") as { project?: string[] } & Record<string, unknown>;
const found: [string, string][] = (cfg.project ?? [])
.filter((p) => p.startsWith("!"))
.map((p): [string, string] => ["knip", p]);
for (const key of Object.keys(cfg).filter(
(k) => !["$schema", "project", "playwright"].includes(k),
))
found.push(["knip", key]);
expect(missingFrom(found)).toEqual([]);
const pkg = JSON.parse(read("frontend/package.json")) as { scripts: Record<string, string> };
expect(pkg.scripts.knip).toBe("knip");
// the positive pattern is the project itself: narrowing it drops files from the lane
expect((cfg.project ?? []).filter((p) => !p.startsWith("!"))).toEqual(["**/*.{ts,tsx,js}"]);
// and knip.jsonc is the config knip reads: a knip.json (read first) or a package.json `knip` key
// (merged in) would narrow it unseen
const KNIP_FILES = /^\.?knip(\.config)?\.(json|jsonc|js|ts|mjs|cjs|mts|cts|toml|ya?ml)$/;
expect(readdirSync(FRONTEND).filter((f) => KNIP_FILES.test(f))).toEqual(["knip.jsonc"]);
expect("knip" in pkg).toBe(false);
});
// --- accepted findings ----------------------------------------------------------------------------
it("accepts a CVE only with a statement, an expiry, and a row", () => {
const yaml = read(".trivyignore.yaml");
const entries = yaml
.split(/\n\s*- id:\s*/)
.slice(1)
.map((chunk) => ({
id: chunk.split("\n")[0]!.trim(),
statement: /\n\s*statement:\s*\S/.test(chunk),
expires: /\n\s*expired_at:\s*\d{4}-\d{2}-\d{2}/.test(chunk),
}));
expect(entries.filter((e) => !e.statement || !e.expires).map((e) => e.id)).toEqual([]);
const pipIgnores = read("scripts/check.sh")
.split("\n")
.filter((l) => !l.trim().startsWith("#")) // the lane's comment explains the flag; it is not one
.flatMap((l) => [...l.matchAll(/--ignore-vuln[ =](\S+)/g)].map((m) => m[1]!));
const found = [...entries.map((e) => e.id), ...pipIgnores].map((id): [string, string] => [
"accepted",
id,
]);
expect(missingFrom(found)).toEqual([]);
});
});