mirror of
https://github.com/CharlesWiltgen/Axiom.git
synced 2026-09-20 19:58:20 +08:00
fix(gate): scan the repo configuration too, and assert nothing tracked goes unread
The leak scan reads an enumeration — SURFACES plus ROOT_FILES — so any tracked file outside it is invisible, and an unread file reads as a clean one. Nine were: .gitignore, .gitattributes, .mise.toml, and .github/** (dependabot plus the three workflows). All clean today, which is the point: nothing would have caught it if they were not. This is the second time the enumeration has drifted — Axiom-77q9 fixed the first, 38 files under axiom-mcp — and both were found by hand rather than by the gate. .github is now a surface and the three dotfiles are root files, so the scan reads 1985 files instead of 1978. The workflow's paths filter gained the same four entries, since a change to a file the scan reads must still start the job — the CI-paths test enforces that pairing and failed until it did. The durable fix is the assertion rather than the four additions: a new test derives the tracked file list from git and fails if any file is in neither the scanned set nor SELF_EXEMPT, naming the file and where to declare it. Verified by deleting the .github surface and watching it fail with all four paths listed, then restoring. The third omission now fails in CI instead of waiting to be noticed. Verified: 518/518 unit tests, 15/15 leak-scan tests, pre-deploy --static clean.
This commit is contained in:
@@ -33,7 +33,10 @@ on:
|
||||
- 'MARKETPLACE-SUBMISSION.md'
|
||||
- 'CURSOR-MARKETPLACE-SUBMISSION.md'
|
||||
- 'SUBMISSION-STATUS.md'
|
||||
- '.github/workflows/test-suite.yml'
|
||||
- '.github/**'
|
||||
- '.gitattributes'
|
||||
- '.gitignore'
|
||||
- '.mise.toml'
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
@@ -56,7 +59,10 @@ on:
|
||||
- 'MARKETPLACE-SUBMISSION.md'
|
||||
- 'CURSOR-MARKETPLACE-SUBMISSION.md'
|
||||
- 'SUBMISSION-STATUS.md'
|
||||
- '.github/workflows/test-suite.yml'
|
||||
- '.github/**'
|
||||
- '.gitattributes'
|
||||
- '.gitignore'
|
||||
- '.mise.toml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -3,7 +3,8 @@ import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import test from "node:test";
|
||||
import { type LeakRule, ROOT_FILES, RULES, SURFACES, isObviousPlaceholderUuid, scanRepo, shippedFiles } from "./leak-scan.ts";
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { type LeakRule, ROOT_FILES, RULES, SELF_EXEMPT, SURFACES, isObviousPlaceholderUuid, scanRepo, shippedFiles } from "./leak-scan.ts";
|
||||
|
||||
/**
|
||||
* The engine is tested with its own rules, not the shipped list. Two reasons: a
|
||||
@@ -322,3 +323,28 @@ test("the CI paths filter covers every surface the scan reads", () => {
|
||||
assert.ok(entries.includes(file), `root file "${file}" is not in the CI paths filter`);
|
||||
}
|
||||
});
|
||||
|
||||
test("every tracked file is scanned, or exempt with a reason", () => {
|
||||
// The surface model enumerates what to read, so anything outside the enumeration is
|
||||
// invisible — and an unread file reads as a clean one. That has shipped twice: 38
|
||||
// axiom-mcp files (Axiom-77q9) and later .gitignore, .gitattributes, .mise.toml and
|
||||
// .github/**. Both were found by hand. This asserts the property instead, so the
|
||||
// third omission fails here rather than waiting for someone to notice a gap.
|
||||
const root = path.resolve(import.meta.dirname, "..");
|
||||
const tracked = execFileSync("git", ["-c", "core.quotepath=false", "ls-files"], {
|
||||
cwd: root,
|
||||
encoding: "utf8",
|
||||
})
|
||||
.split("\n")
|
||||
.filter(Boolean);
|
||||
const scanned = new Set(shippedFiles(root));
|
||||
|
||||
const unread = tracked.filter((rel) => !scanned.has(rel) && !SELF_EXEMPT.has(rel));
|
||||
assert.deepEqual(
|
||||
unread,
|
||||
[],
|
||||
`tracked file(s) in no scanned surface: ${unread.join(", ")}. Add the directory to ` +
|
||||
`SURFACES or the file to ROOT_FILES in scripts/leak-scan.ts, and add it to the ` +
|
||||
`workflow's paths filter — an unscanned file reads as a clean one.`,
|
||||
);
|
||||
});
|
||||
|
||||
+14
-1
@@ -83,12 +83,22 @@ export const SURFACES: Surface[] = [
|
||||
{ path: "docs", trackedOnly: true },
|
||||
{ path: "tools", trackedOnly: true },
|
||||
{ path: "scripts", trackedOnly: true },
|
||||
// Repo configuration ships publicly and can carry a local path (a tool config, a
|
||||
// runner path in a workflow) as easily as source can. It was in no surface until a
|
||||
// tracked-but-unscanned check found it; scripts/leak-scan.test.ts now fails when any
|
||||
// tracked file is in neither a surface nor ROOT_FILES nor SELF_EXEMPT, so the next
|
||||
// omission is caught rather than discovered.
|
||||
{ path: ".github", trackedOnly: true },
|
||||
];
|
||||
|
||||
/**
|
||||
* Root files are read from disk, not from the index: CHANGELOG.md is gitignored
|
||||
* here yet is rendered into the published site, so "tracked" is the wrong test
|
||||
* for them.
|
||||
*
|
||||
* The three dotfiles were added by the tracked-but-unscanned check. `.mise.toml`
|
||||
* and `.gitignore` both name local paths in normal use, which is exactly what the
|
||||
* absolute-home-path rule exists to catch.
|
||||
*/
|
||||
export const ROOT_FILES = [
|
||||
"README.md",
|
||||
@@ -100,6 +110,9 @@ export const ROOT_FILES = [
|
||||
"MARKETPLACE-SUBMISSION.md",
|
||||
"CURSOR-MARKETPLACE-SUBMISSION.md",
|
||||
"SUBMISSION-STATUS.md",
|
||||
".gitattributes",
|
||||
".gitignore",
|
||||
".mise.toml",
|
||||
];
|
||||
|
||||
const SKIP_DIRS = new Set([
|
||||
@@ -120,7 +133,7 @@ const SKIP_DIRS = new Set([
|
||||
* legitimate place for the strings to appear. Exempting them by name is narrower
|
||||
* than weakening a pattern to avoid matching its own source.
|
||||
*/
|
||||
const SELF_EXEMPT = new Set(["scripts/leak-scan.ts", "scripts/leak-scan.test.ts"]);
|
||||
export const SELF_EXEMPT = new Set(["scripts/leak-scan.ts", "scripts/leak-scan.test.ts"]);
|
||||
|
||||
export const RULES: LeakRule[] = [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user