Merge pull request #691 from MBombeck/fix/gate-blind-spots

Let the structural guards see the directories they were skipping
This commit is contained in:
Marc-André Bombeck authored and GitHub committed 2026-08-02 17:05:49 +02:00
commit 526041770d
32 files changed
+432 -165

No files matched your search

+5 -1
View File
@@ -30,7 +30,11 @@ jobs:
- run: pnpm db:generate
# v1.4.42 — exports + types tiers promoted to enforcing. The
# `knip.json` ignore-block carries the shadcn UI surface and the
# `knip.jsonc` ignore-block carries the shadcn UI surface and the
# `src/lib/validations/**` contract types; everything else has
# to clear or get justified there.
#
# This pass cannot see a module whose only importer is its own test —
# vitest is a knip plugin, so test files are entries. The header of
# `knip.jsonc` demonstrates that and names the pass that does see it.
- run: pnpm knip --reporter compact
+10 -3
View File
@@ -100,9 +100,16 @@ not immediately. A weekly `geoipupdate` followed by
The databases are downloaded under your own MaxMind account, so their
terms are between you and MaxMind — read what your account agrees to at
<https://www.maxmind.com/en/geolite2/eula>. HealthLog's own attribution
("this product includes GeoLite2 data created by MaxMind") is already on
the `/about` page and covers an instance that uses them.
<https://www.maxmind.com/en/geolite/eula>. That agreement, the GeoLite
End User License Agreement, incorporates CC BY-SA 4.0 by reference and
controls wherever the two disagree; both require you to attribute the
data to MaxMind if you make it available to anyone else.
HealthLog's own attribution ("This product includes GeoLite2 data
created by MaxMind, available from https://www.maxmind.com") is already
on the `/about` page and covers an instance that uses them. Keep that
page reachable — it is what carries the attribution for your deployment,
and it is served without a session for exactly that reason.
## Troubleshooting
+6
View File
@@ -41,6 +41,12 @@ test.describe("v1.4.27 — public pages", () => {
// GeoLite2 attribution is the load-bearing reason this page exists.
await expect(page.getByText(/GeoLite2/).first()).toBeVisible();
await expect(page.getByText(/MaxMind/).first()).toBeVisible();
// Both licences, because naming only the Creative Commons one understates
// the terms: the GeoLite EULA is what governs and CC BY-SA 4.0 rides
// inside it.
await expect(
page.getByText(/GeoLite End User License Agreement/i),
).toBeVisible();
await expect(page.getByText(/Attribution-ShareAlike 4\.0/i)).toBeVisible();
});
-77
View File
@@ -1,77 +0,0 @@
{
"$schema": "https://unpkg.com/knip@6/schema.json",
"entry": [
"src/app/**/page.tsx",
"src/app/**/layout.tsx",
"src/app/**/route.ts",
"src/app/**/loading.tsx",
"src/app/**/not-found.tsx",
"src/app/**/error.tsx",
"src/app/**/global-error.tsx",
"src/app/**/template.tsx",
"src/app/**/opengraph-image.tsx",
"src/app/**/twitter-image.tsx",
"src/app/**/icon.tsx",
"src/app/**/apple-icon.tsx",
"src/app/**/manifest.ts",
"src/app/**/robots.ts",
"src/app/**/sitemap.ts",
"src/app/**/default.tsx",
"src/proxy.ts",
"src/instrumentation.ts",
"src/lib/jobs/**/*.ts",
"src/lib/ai/coach/eval/judge.ts",
"scripts/**/*.ts",
"scripts/**/*.mjs",
"e2e/**/*.spec.ts",
"e2e/**/*.test.ts",
"tests/**/*.test.ts",
"tests/**/setup.ts",
"vitest.config.ts",
"vitest.config.integration.ts",
"playwright.config.ts",
"next.config.ts",
"eslint.config.*",
"knip.json"
],
"project": [
"src/**/*.{ts,tsx}",
"scripts/**/*.{ts,mjs}",
"tests/**/*.ts",
"e2e/**/*.ts"
],
"ignore": [
"src/generated/**",
"prisma/**",
"public/**",
".next/**",
"**/__mocks__/**",
"e2e/setup/test-helpers.ts",
"src/lib/logging/index.ts"
],
"ignoreDependencies": [
"@types/node",
"@types/react",
"@types/react-dom",
"@hookform/resolvers",
"react-hook-form",
"@prisma/client",
"next-themes",
"@vitejs/plugin-react",
"shadcn",
"tailwindcss",
"testcontainers",
"tw-animate-css",
"@napi-rs/canvas",
"@openai/codex-security",
"postcss"
],
"ignoreBinaries": ["docker", "docker-compose", "pg_isready", "tsx", "cosign"],
"ignoreExportsUsedInFile": true,
"ignoreIssues": {
"src/components/ui/**": ["exports", "types"],
"src/lib/validations/**": ["types"],
"src/hooks/_internal/use-query-client-safe.ts": ["exports"],
"src/lib/google-health/sync.ts": ["exports"]
}
}
+131
View File
@@ -0,0 +1,131 @@
// Dead-code configuration. JSONC rather than JSON so this can say what the
// gate proves — the previous JSON file could not, and the difference matters
// more here than anywhere else in the repo.
//
// ## What `pnpm knip` (the CI gate in .github/workflows/knip.yml) proves
//
// A module, export or dependency that nothing in the repository reaches is a
// build failure. That is a real property and it catches the ordinary case: a
// helper left behind after its last caller was rewritten.
//
// ## What it does NOT prove, demonstrated
//
// It does not prove a module is still reachable from production. Vitest is a
// knip plugin here, so `src/**/__tests__/**` are entry files, and a module
// whose ONLY importer is its own test counts as used — forever. Planting
// `src/lib/dead-probe.ts` with a single test importing it left `pnpm knip` at
// exit 0. Nothing in the default pass can see that class of dead code, so do
// not read a green Dead-code gate as "every module is still wired to
// something that ships".
//
// ## The pass that does see it
//
// pnpm knip --production --include files
//
// Production mode drops the plugin-supplied test entries and keeps only the
// entry and project patterns suffixed with `!` below — the app router tree,
// the proxy, instrumentation, the pg-boss workers, and `scripts/` (maintainer
// tooling is not production, but it is a legitimate non-test consumer, so a
// module reached only from a script is not the thing we are hunting). The `!`
// suffix is inert in the default pass, so both modes read one config.
//
// This is a review tool, not a second gate, for two reasons written down so
// the next reader does not have to rediscover them:
//
// 1. It reports 29 files today. Some are test-only by construction (the
// guard helpers under `src/__tests__/helpers/`, the settings section
// harness) and some are deliberately unreachable from production
// (`src/lib/ai/mock-client.ts` is excluded structurally by the
// `PROVIDER_CHAIN_TYPES` allowlist). Baselining the rest without
// triaging each one would encode noise as an invariant.
// 2. It has false positives. `src/lib/mood/note-backfill.ts` is imported by
// `scripts/backfill-mood-note-column.ts` through the `@/` alias and is
// still reported, because `scripts/` sits outside the tsconfig that
// defines the alias. The default pass hides that resolution failure
// behind the module's test importer.
//
// Run it in the deep-audit step, the same way
// `scripts/audit-column-readers.ts` is run: read the list, judge each entry,
// do not treat the exit code as a verdict.
{
"$schema": "https://unpkg.com/knip@6/schema.json",
// `!` marks an entry as production. Read the block above before adding or
// removing one — the suffix is what separates the two passes.
"entry": [
"src/app/**/page.tsx!",
"src/app/**/layout.tsx!",
"src/app/**/route.ts!",
"src/app/**/loading.tsx!",
"src/app/**/not-found.tsx!",
"src/app/**/error.tsx!",
"src/app/**/global-error.tsx!",
"src/app/**/template.tsx!",
"src/app/**/opengraph-image.tsx!",
"src/app/**/twitter-image.tsx!",
"src/app/**/icon.tsx!",
"src/app/**/apple-icon.tsx!",
"src/app/**/manifest.ts!",
"src/app/**/robots.ts!",
"src/app/**/sitemap.ts!",
"src/app/**/default.tsx!",
"src/proxy.ts!",
"src/instrumentation.ts!",
"src/lib/jobs/**/*.ts!",
"src/lib/ai/coach/eval/judge.ts!",
"scripts/**/*.ts!",
"scripts/**/*.mjs!",
"e2e/**/*.spec.ts",
"e2e/**/*.test.ts",
"tests/**/*.test.ts",
"tests/**/setup.ts",
"vitest.config.ts",
"vitest.config.integration.ts",
"playwright.config.ts",
"next.config.ts!",
"eslint.config.*",
"knip.jsonc",
],
"project": [
"src/**/*.{ts,tsx}!",
"scripts/**/*.{ts,mjs}!",
"tests/**/*.ts",
"e2e/**/*.ts",
],
"ignore": [
"src/generated/**",
"prisma/**",
"public/**",
".next/**",
"**/__mocks__/**",
"e2e/setup/test-helpers.ts",
"src/lib/logging/index.ts",
],
"ignoreDependencies": [
"@types/node",
"@types/react",
"@types/react-dom",
"@hookform/resolvers",
"react-hook-form",
"@prisma/client",
"next-themes",
"@vitejs/plugin-react",
"shadcn",
"tailwindcss",
"testcontainers",
"tw-animate-css",
"@napi-rs/canvas",
"@openai/codex-security",
"postcss",
],
"ignoreBinaries": ["docker", "docker-compose", "pg_isready", "tsx", "cosign"],
// Scoped to a single file: an export used only inside its own module is not
// a finding. It is also why the default pass cannot answer the question the
// production pass answers — this setting is about exports, not reachability.
"ignoreExportsUsedInFile": true,
"ignoreIssues": {
"src/components/ui/**": ["exports", "types"],
"src/lib/validations/**": ["types"],
"src/hooks/_internal/use-query-client-safe.ts": ["exports"],
"src/lib/google-health/sync.ts": ["exports"],
},
}
@@ -55,6 +55,12 @@ const CONSUMER_ROOTS = [
join(SRC, "app"),
];
/**
* Pruned on purpose: the generated Prisma client, build output, vendored
* dependencies, and the suites themselves are not the tree under audit. Note
* what is NOT pruned — this walk descends into dot-prefixed directories, so
* `src/app/.well-known` is inside the sweep. `fs.globSync` would drop it.
*/
const SKIP_DIRS = new Set([
"__tests__",
"__mocks__",
@@ -15,19 +15,17 @@
*/
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { globSync } from "node:fs";
import { join, sep } from "node:path";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
function sourceFiles(): string[] {
return globSync("**/*.{ts,tsx}", { cwd: SRC })
.filter(
(p) => !p.startsWith(`generated${sep}`) && !p.startsWith("generated/"),
)
return walkSourceFiles(SRC, { floor: 3000 })
.filter((p) => !p.startsWith("generated/"))
.filter((p) => !p.includes("__tests__"))
.filter((p) => !p.endsWith(".test.ts") && !p.endsWith(".test.tsx"))
.map((p) => p.split(sep).join("/"))
.sort();
}
@@ -33,20 +33,18 @@
*/
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { join, sep } from "node:path";
import { globSync } from "node:fs";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
/** Every non-test `.ts` / `.tsx` under `src/`, minus the generated client. */
function sourceFiles(): string[] {
return globSync("**/*.{ts,tsx}", { cwd: SRC })
.filter(
(p) => !p.startsWith(`generated${sep}`) && !p.startsWith("generated/"),
)
return walkSourceFiles(SRC, { floor: 3000 })
.filter((p) => !p.startsWith("generated/"))
.filter((p) => !p.includes("__tests__"))
.filter((p) => !p.endsWith(".test.ts") && !p.endsWith(".test.tsx"))
.map((p) => p.split(sep).join("/"))
.sort();
}
@@ -14,8 +14,9 @@
*/
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { join, sep } from "node:path";
import { globSync } from "node:fs";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
@@ -24,13 +25,10 @@ const SRC = join(process.cwd(), "src");
* client (9 MB; never read it) and test files themselves.
*/
function sourceFiles(): string[] {
return globSync("**/*.{ts,tsx}", { cwd: SRC })
.filter(
(p) => !p.startsWith(`generated${sep}`) && !p.startsWith("generated/"),
)
return walkSourceFiles(SRC, { floor: 3000 })
.filter((p) => !p.startsWith("generated/"))
.filter((p) => !p.includes("__tests__"))
.filter((p) => !p.endsWith(".test.ts") && !p.endsWith(".test.tsx"))
.map((p) => p.split(sep).join("/"))
.sort();
}
@@ -28,6 +28,12 @@ const ROOT = process.cwd();
/** Client-side code: the component tree, the hooks, and the app's pages. */
const CLIENT_ROOTS = ["src/components", "src/hooks", "src/app"];
/**
* Pruned on purpose: the generated Prisma client, build output, vendored
* dependencies, and the suites themselves are not the tree under audit. Note
* what is NOT pruned — this walk descends into dot-prefixed directories, so
* `src/app/.well-known` is inside the sweep. `fs.globSync` would drop it.
*/
const SKIP_DIRS = new Set(["__tests__", "node_modules", ".next", "generated"]);
function walk(dir: string, out: string[] = []): string[] {
@@ -25,8 +25,9 @@
*/
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { join, sep } from "node:path";
import { globSync } from "node:fs";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
@@ -49,13 +50,10 @@ const INVALIDATION =
const REFETCH = /refetchInactiveDailyReads\(/g;
function sourceFiles(): string[] {
return globSync("**/*.{ts,tsx}", { cwd: SRC })
.filter(
(p) => !p.startsWith(`generated${sep}`) && !p.startsWith("generated/"),
)
return walkSourceFiles(SRC, { floor: 3000 })
.filter((p) => !p.startsWith("generated/"))
.filter((p) => !p.includes("__tests__"))
.filter((p) => !p.endsWith(".test.ts") && !p.endsWith(".test.tsx"))
.map((p) => p.split(sep).join("/"))
.sort();
}
@@ -108,6 +106,13 @@ const NO_REFETCH_ALLOWLIST = [
].sort();
describe("daily-reads refetch guard", () => {
// A sweep that finds nothing agrees with every allowlist, so the size of
// the tree being read is asserted before anything is concluded from it.
// Pinned below the real source-file count with headroom, not at one.
it("reads the tree it claims to sweep", () => {
expect(sourceFiles().length).toBeGreaterThan(1500);
});
it("the blessed helper pairs the bundle invalidation with the inactive refetch", () => {
const src = read(FACTORY);
// The one canonical entry point every intake surface routes through.
@@ -49,8 +49,10 @@
* red at the call site.
*/
import { describe, it, expect } from "vitest";
import { readFileSync, globSync } from "node:fs";
import { join, sep } from "node:path";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
@@ -558,8 +560,7 @@ const CONTROL_ROOTS = ["app/", "components/", "hooks/"];
const EXCLUDED_PREFIXES = ["app/api/", "generated/", "lib/"];
function sourceFiles(): string[] {
return globSync("**/*.{ts,tsx}", { cwd: SRC })
.map((p) => p.split(sep).join("/"))
return walkSourceFiles(SRC, { floor: 3000 })
.filter((p) => !p.includes("__tests__"))
.filter((p) => !p.endsWith(".test.ts") && !p.endsWith(".test.tsx"))
.sort();
@@ -23,9 +23,11 @@
* are pinned to a named allowlist, so a new converted-value surface
* cannot quietly join them.
*/
import { readFileSync, globSync } from "node:fs";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
import { describe, it, expect } from "vitest";
import {
@@ -69,7 +71,7 @@ const RAW_SCALE_READ =
/\b\w*[Tt]ransform(?:For\([^)]*\))?\??\.(factor|offset)\b/;
function sourceFiles(): string[] {
return globSync("**/*.{ts,tsx}", { cwd: SRC }).filter(
return walkSourceFiles(SRC, { floor: 3000 }).filter(
(rel) =>
// Never walk the Prisma client, and skip the suites that legitimately
// exercise the raw arithmetic they are asserting about.
@@ -132,6 +132,12 @@ const REGISTRY: readonly KeySpace[] = [
];
describe("dynamic-key exhaustiveness (enum-derived)", () => {
// Six shipped locales. An empty read of `messages/` would register zero
// per-locale cases and the suite would report green over nothing.
it("reads every shipped locale bundle", () => {
expect(LOCALES.length).toBeGreaterThanOrEqual(6);
});
it("discovers all six shipped locales", () => {
expect(LOCALES.map((l) => l.locale).sort()).toEqual([
"de",
@@ -14,8 +14,10 @@
* a runtime property, proven by the suite itself.
*/
import { describe, it, expect } from "vitest";
import { readFileSync, globSync } from "node:fs";
import { join, sep } from "node:path";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
const E2E = join(process.cwd(), "e2e");
@@ -33,9 +35,7 @@ const DIRECT_IMPORT_ALLOWLIST: Record<string, string> = {
};
function e2eFiles(): string[] {
return globSync("**/*.ts", { cwd: E2E })
.map((p) => p.split(sep).join("/"))
.sort();
return walkSourceFiles(E2E, { floor: 40, extensions: [".ts"] }).sort();
}
function read(rel: string): string {
@@ -23,20 +23,18 @@
*/
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { join, sep } from "node:path";
import { globSync } from "node:fs";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
const VALIDATOR_MODULE = "@/lib/validations/external-id";
function sourceFiles(): string[] {
return globSync("**/*.{ts,tsx}", { cwd: SRC })
.filter(
(p) => !p.startsWith(`generated${sep}`) && !p.startsWith("generated/"),
)
return walkSourceFiles(SRC, { floor: 3000 })
.filter((p) => !p.startsWith("generated/"))
.filter((p) => !p.includes("__tests__"))
.filter((p) => !p.endsWith(".test.ts") && !p.endsWith(".test.tsx"))
.map((p) => p.split(sep).join("/"))
.sort();
}
+75
View File
@@ -0,0 +1,75 @@
/**
* The one file walker the structural guards share.
*
* ## Why this exists rather than `fs.globSync`
*
* A guard that freezes a discovered set against an allowlist is only as
* honest as its idea of "every source file". `fs.globSync` has a rule that
* silently narrows that idea: a glob's `*` never matches a leading dot, so
* `**\/*.{ts,tsx}` skips every dot-prefixed directory without saying so.
*
* `src/app/.well-known/` holds three live route modules — the two OAuth
* discovery documents the MCP server publishes and the
* apple-app-site-association handler. Every guard built on `globSync` walked
* straight past all three and reported a clean sweep over a tree with a hole
* in it. Demonstrated, not assumed: an unlisted `getSession()` call planted
* in `app/.well-known/oauth-authorization-server/route.ts` left
* `session-surface-guard` at 9 passed, and fails it once the walk goes
* through here.
*
* `readdirSync(root, { recursive: true })` has no dot rule. It is the reason
* `delegable-surface-guard.test.ts` already walks by hand; this helper makes
* that the shared behaviour instead of one guard's private correction.
*
* ## Why `floor` is required and not optional
*
* The other way a sweep goes quiet is by finding nothing at all: an empty
* match set agrees with an empty allowlist, and the guard passes on a tree it
* never read. A wrong root, a renamed directory, or a walk that throws away
* every entry all look exactly like compliance. So every caller states the
* size it expects to walk, pinned below the real count with headroom, and a
* walk that comes back smaller throws instead of reporting a clean sweep.
* The floor covers the walk; a guard that filters further is still on the
* hook for a floor over its own narrowed set.
*
* ## What it returns
*
* Posix-separated paths relative to `root`, sorted, so a guard's output and
* its failure message read the same on every platform. Directory entries are
* dropped by the extension filter.
*
* ## What it does not do
*
* It applies no exclusions of its own — not `generated/`, not `__tests__`,
* not `.test.ts`. Each guard states its own, because what counts as out of
* scope is the guard's claim to make, not the walker's.
*
* And it must not be rooted at the repository root. Descending into
* dot-prefixed directories is the whole point, but at the root that means
* `.git` and — on a maintainer's machine mid-release — the `.wt-*` sibling
* worktrees, each a full second copy of the tree that would double every
* match. Every caller roots at `src/`, `e2e/` or a subtree of one.
*/
import { readdirSync } from "node:fs";
import { sep } from "node:path";
export function walkSourceFiles(
root: string,
options: { floor: number; extensions?: readonly string[] },
): string[] {
const extensions = options.extensions ?? [".ts", ".tsx"];
const files = readdirSync(root, { recursive: true })
.map((entry) => String(entry).split(sep).join("/"))
.filter((rel) => extensions.some((ext) => rel.endsWith(ext)))
.sort();
if (files.length < options.floor) {
throw new Error(
`walkSourceFiles(${root}) found ${files.length} file(s) matching ` +
`${extensions.join(", ")}, below the stated floor of ${options.floor}. ` +
`A sweep this small is a broken walk, not a clean tree — check the ` +
`root before lowering the floor.`,
);
}
return files;
}
@@ -27,6 +27,12 @@ const ROOT = join(__dirname, "../..");
const SRC = join(ROOT, "src");
const EN_BUNDLE_PATH = join(ROOT, "messages/en.json");
/**
* Pruned on purpose: the generated Prisma client, build output, vendored
* dependencies, and the suites themselves are not the tree under audit. Note
* what is NOT pruned — this walk descends into dot-prefixed directories, so
* `src/app/.well-known` is inside the sweep. `fs.globSync` would drop it.
*/
const SKIP_DIRS = new Set(["__tests__", "node_modules", ".next", "generated"]);
function walk(dir: string, out: string[] = []): string[] {
+6
View File
@@ -115,6 +115,12 @@ const REQUIRED_KEY_SETS: Array<{
];
describe("v1.4.27 B6 i18n drift-guard — required keys present in every locale", () => {
// Six shipped locales. An empty read of `messages/` would register zero
// per-locale cases and the suite would report green over nothing.
it("reads every shipped locale bundle", () => {
expect(LOCALES.length).toBeGreaterThanOrEqual(6);
});
for (const { label, required } of REQUIRED_KEY_SETS) {
describe(label, () => {
it.each(LOCALES)(
@@ -35,6 +35,12 @@ const ROOT = join(__dirname, "../..");
const SRC = join(ROOT, "src");
const EN_BUNDLE_PATH = join(ROOT, "messages/en.json");
/**
* Pruned on purpose: the generated Prisma client, build output, vendored
* dependencies, and the suites themselves are not the tree under audit. Note
* what is NOT pruned — this walk descends into dot-prefixed directories, so
* `src/app/.well-known` is inside the sweep. `fs.globSync` would drop it.
*/
const SKIP_DIRS = new Set(["__tests__", "node_modules", ".next", "generated"]);
/**
@@ -22,6 +22,12 @@ import { join, relative, sep } from "node:path";
const ROOT = join(__dirname, "../..");
const SRC = join(ROOT, "src");
/**
* Pruned on purpose: the generated Prisma client, build output, vendored
* dependencies, and the suites themselves are not the tree under audit. Note
* what is NOT pruned — this walk descends into dot-prefixed directories, so
* `src/app/.well-known` is inside the sweep. `fs.globSync` would drop it.
*/
const SKIP_DIRS = new Set(["__tests__", "node_modules", ".next", "generated"]);
/**
@@ -61,6 +67,13 @@ function walk(dir: string, out: string[] = []): string[] {
}
describe("medicationInventoryItem write isolation", () => {
// A sweep that finds nothing agrees with every allowlist, so the size of
// the tree being read is asserted before anything is concluded from it.
// Pinned below the real source-file count with headroom, not at one.
it("reads the tree it claims to sweep", () => {
expect(walk(SRC).length).toBeGreaterThan(1500);
});
it("no file outside the consumption module + inventory surfaces writes inventory items", () => {
const offenders: string[] = [];
for (const file of walk(SRC)) {
@@ -80,6 +80,12 @@ function flatten(obj: unknown, prefix: string, out: [string, string][]): void {
}
describe("medications.efficacy — banned verdict/advice verbs", () => {
// Six shipped locales. An empty read of `messages/` would register zero
// per-locale cases and the suite would report green over nothing.
it("reads every shipped locale bundle", () => {
expect(LOCALES.length).toBeGreaterThanOrEqual(6);
});
it.each(LOCALES)("%s carries no forbidden verb", (file) => {
const bundle = JSON.parse(readFileSync(join(MESSAGES, file), "utf8")) as {
medications?: { efficacy?: unknown };
@@ -64,6 +64,9 @@ describe("prisma migrations — numeric prefixes are unique", () => {
const numbered = readdirSync(MIGRATIONS_DIR, {
withFileTypes: true,
}).filter((e) => e.isDirectory() && NUMBERED_MIGRATION.test(e.name));
expect(numbered.length).toBeGreaterThan(0);
// Not `> 0`: a walk that returns a single directory is as broken as one
// that returns none, and both would pass a zero floor. Pinned below the
// real migration count with headroom.
expect(numbered.length).toBeGreaterThan(200);
});
});
@@ -19,6 +19,12 @@ import { readFileSync, readdirSync, statSync } from "node:fs";
import { join } from "node:path";
const SRC = join(__dirname, "..");
/**
* Pruned on purpose: the generated Prisma client, build output, vendored
* dependencies, and the suites themselves are not the tree under audit. Note
* what is NOT pruned — this walk descends into dot-prefixed directories, so
* `src/app/.well-known` is inside the sweep. `fs.globSync` would drop it.
*/
const SKIP_DIRS = new Set(["__tests__", "node_modules", ".next", "generated"]);
/**
@@ -52,6 +58,13 @@ function stripComments(source: string): string {
}
describe("doctor-report aggregator egress", () => {
// A sweep that finds nothing agrees with every allowlist, so the size of
// the tree being read is asserted before anything is concluded from it.
// Pinned below the real source-file count with headroom, not at one.
it("reads the tree it claims to sweep", () => {
expect(walk(SRC).length).toBeGreaterThan(1500);
});
it("keeps the set of aggregator callers frozen", () => {
const found: string[] = [];
for (const file of walk(SRC)) {
+5 -4
View File
@@ -34,8 +34,9 @@
*/
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { join, sep } from "node:path";
import { globSync } from "node:fs";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
@@ -46,8 +47,8 @@ const SRC = join(process.cwd(), "src");
* `app/`) and never read — see CLAUDE.md.
*/
function appFiles(): string[] {
return globSync("app/**/*.{ts,tsx}", { cwd: SRC })
.map((p) => p.split(sep).join("/"))
return walkSourceFiles(SRC, { floor: 3000 })
.filter((p) => p.startsWith("app/"))
.filter((p) => !p.includes("__tests__"))
.filter((p) => !p.endsWith(".test.ts") && !p.endsWith(".test.tsx"))
.sort();
+12 -7
View File
@@ -24,19 +24,17 @@
*/
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { join, sep } from "node:path";
import { globSync } from "node:fs";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
function sourceFiles(): string[] {
return globSync("**/*.{ts,tsx}", { cwd: SRC })
.filter(
(p) => !p.startsWith(`generated${sep}`) && !p.startsWith("generated/"),
)
return walkSourceFiles(SRC, { floor: 3000 })
.filter((p) => !p.startsWith("generated/"))
.filter((p) => !p.includes("__tests__"))
.filter((p) => !p.endsWith(".test.ts") && !p.endsWith(".test.tsx"))
.map((p) => p.split(sep).join("/"))
.sort();
}
@@ -120,6 +118,13 @@ const ELEVATION_ROUTES = [
].sort();
describe("S1 — the elevation-accepting route set is frozen", () => {
// A sweep that finds nothing agrees with every allowlist, so the size of
// the tree being read is asserted before anything is concluded from it.
// Pinned below the real source-file count with headroom, not at one.
it("reads the tree it claims to sweep", () => {
expect(sourceFiles().length).toBeGreaterThan(1500);
});
it("only the known MFA-management mutations call the gate", () => {
const found = callers("requireMfaManagementAuth", API_HANDLER).filter(
(rel) => rel !== "lib/api-handler.ts",
@@ -493,6 +493,13 @@ function markerCounts(
}
describe("success affordance — owned by the outcome module, pinned everywhere else", () => {
// A sweep that finds nothing agrees with every allowlist, so the size of
// the tree being read is asserted before anything is concluded from it.
// Pinned below the real component-file count with headroom, not at one.
it("reads the tree it claims to sweep", () => {
expect(componentSourceFiles().length).toBeGreaterThan(400);
});
it("lets no unlisted component reach for the success affordance", () => {
const unlisted = componentSourceFiles()
.filter((path) => !path.startsWith(PRESENTATION_DIR))
@@ -11,9 +11,10 @@
* Mutation check: add `unit="kg"` back to any swept page and this goes red.
*/
import { readFileSync } from "node:fs";
import { globSync } from "node:fs";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
import { describe, it, expect } from "vitest";
import {
@@ -74,9 +75,11 @@ const HEIGHT_CONTROL = join(
function sweptFiles(): string[] {
return [
join(SRC, "app", "page-client.tsx"),
...globSync("app/insights/**/page.tsx", { cwd: SRC }).map((rel) =>
join(SRC, rel),
),
...walkSourceFiles(SRC, { floor: 700, extensions: [".tsx"] })
.filter(
(rel) => rel.startsWith("app/insights/") && rel.endsWith("/page.tsx"),
)
.map((rel) => join(SRC, rel)),
...TARGET_SURFACES,
];
}
@@ -18,8 +18,10 @@
* settles is that there is only one of it.
*/
import { describe, it, expect } from "vitest";
import { readFileSync, globSync } from "node:fs";
import { join, sep } from "node:path";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
@@ -71,8 +73,7 @@ const FIX_THE_ZONE = [
].join(" ");
function sourceFiles(): string[] {
return globSync("**/*.{ts,tsx}", { cwd: SRC })
.map((p) => p.split(sep).join("/"))
return walkSourceFiles(SRC, { floor: 3000 })
.filter((p) => !p.startsWith("generated/"))
.filter((p) => !p.includes("__tests__/"))
.sort();
@@ -94,6 +95,13 @@ function declaresTheBucket(source: string): boolean {
}
describe("the checkup due-day bucket has one home", () => {
// A sweep that finds nothing agrees with every allowlist, so the size of
// the tree being read is asserted before anything is concluded from it.
// Pinned below the real source-file count with headroom, not at one.
it("reads the tree it claims to sweep", () => {
expect(sourceFiles().length).toBeGreaterThan(1500);
});
it("is declared in exactly one file", () => {
const declaring = sourceFiles().filter((rel) =>
declaresTheBucket(read(rel)),
@@ -21,8 +21,9 @@
*/
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { globSync } from "node:fs";
import { join, sep } from "node:path";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
@@ -52,8 +53,7 @@ const IDENTITY_OWNER: Record<string, string> = {
const EXPECTED_CALL_SITES = Object.keys(IDENTITY_OWNER).sort();
function sourceFiles(): string[] {
return globSync("**/*.{ts,tsx}", { cwd: SRC })
.map((p) => p.split(sep).join("/"))
return walkSourceFiles(SRC, { floor: 3000 })
.filter((p) => !p.startsWith("generated/"))
.filter((p) => !p.includes("__tests__"))
.filter((p) => !p.endsWith(".test.ts") && !p.endsWith(".test.tsx"))
@@ -81,6 +81,13 @@ function invokesPicker(source: string): boolean {
}
describe("the picker's call-site set is frozen", () => {
// A sweep that finds nothing agrees with every allowlist, so the size of
// the tree being read is asserted before anything is concluded from it.
// Pinned below the real source-file count with headroom, not at one.
it("reads the tree it claims to sweep", () => {
expect(sourceFiles().length).toBeGreaterThan(1500);
});
it("has exactly the call sites this file acknowledges", () => {
const found = sourceFiles()
.filter((rel) => rel !== PICKER)
@@ -20,20 +20,18 @@
*/
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { join, sep } from "node:path";
import { globSync } from "node:fs";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
/** Every non-test `.ts` / `.tsx` under `src/`, minus the generated client. */
function sourceFiles(): string[] {
return globSync("**/*.{ts,tsx}", { cwd: SRC })
.filter(
(p) => !p.startsWith(`generated${sep}`) && !p.startsWith("generated/"),
)
return walkSourceFiles(SRC, { floor: 3000 })
.filter((p) => !p.startsWith("generated/"))
.filter((p) => !p.includes("__tests__"))
.filter((p) => !p.endsWith(".test.ts") && !p.endsWith(".test.tsx"))
.map((p) => p.split(sep).join("/"))
.sort();
}
@@ -131,6 +129,13 @@ const READ_TIME_NARROWERS = [
];
describe("T1 — the set of sport-label mappers is frozen", () => {
// A sweep that finds nothing agrees with every allowlist, so the size of
// the tree being read is asserted before anything is concluded from it.
// Pinned below the real source-file count with headroom, not at one.
it("reads the tree it claims to sweep", () => {
expect(sourceFiles().length).toBeGreaterThan(1500);
});
it("every exported sport-type resolver is registered", () => {
const found = new Set<string>();
for (const rel of sourceFiles()) {
+21 -7
View File
@@ -8,9 +8,11 @@ import Link from "next/link";
*
* 1. The runtime image bundles MaxMind GeoLite2-City and
* GeoLite2-ASN databases for offline IP-to-location and
* IP-to-ASN lookups. The CC BY-SA 4.0 licence requires the
* attribution to be reachable from the running application,
* not just the source repository.
* IP-to-ASN lookups. They ship under the GeoLite End User
* License Agreement, which incorporates CC BY-SA 4.0 by
* reference and controls over it; both want the attribution
* reachable from the running application, not just from the
* source repository.
* 2. A general home for open-source credits as the project
* accumulates more third-party data sources (already true for
* the upcoming ICD-10 reference table in the iOS Health import
@@ -35,7 +37,7 @@ import Link from "next/link";
// weakening the CSP with `unsafe-inline`.
export const dynamic = "force-dynamic";
const LAST_UPDATED = "2026-05-15";
const LAST_UPDATED = "2026-08-02";
export const metadata: Metadata = {
title: "About — HealthLog",
@@ -119,7 +121,9 @@ export default function AboutPage() {
>
github.com/MBombeck/HealthLog
</a>{" "}
and is licensed under the GNU Affero General Public License v3.0.
and is licensed under the PolyForm Noncommercial License 1.0.0.
Releases up to and including v1.15.18 were published under AGPL-3.0
and stay available under it.
</p>
</Section>
@@ -156,6 +160,15 @@ export default function AboutPage() {
) power the offline IP-to-location and IP-to-carrier lookups that
decorate the admin login-overview audit table. They are distributed
under the{" "}
<a
href="https://www.maxmind.com/en/geolite/eula"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
GeoLite End User License Agreement
</a>
, which incorporates the{" "}
<a
href="https://creativecommons.org/licenses/by-sa/4.0/"
target="_blank"
@@ -163,8 +176,9 @@ export default function AboutPage() {
className="text-primary hover:underline"
>
Creative Commons Attribution-ShareAlike 4.0 International License
</a>
.
</a>{" "}
by reference and controls wherever the two disagree. The attribution
above is what that licence asks for.
</p>
</Section>