test(api): DC-087 hermetic caddy-admin health mirrors + file-level raw-fetch guard [glm-grade=B]
Two mirrored health-handler test suites (health-endpoints, health-probe-aliases) probed the Caddy admin API with raw Origin-less native fetch. On the prod host the adversarial cron runs the full jest suite every 30 min against a live Caddy admin with enforce_origin: 12 journal 403 lines per run (~700/day of 'client is not allowed to access from origin' spam) while tests stayed green. - Mirrors now call fetchT (byte-identical to src/app.js:930 probe) with fetchT jest.spyOn-mocked at buildApp scope; caddyOk-configurable in both suites - New guard test in utils-http-caddy-admin-origin.test.js: any __tests__ file pairing a raw await-fetch with a Caddy-admin token (:2019|adminUrl| CADDY_ADMIN) fails the suite — file-level pairing catches the historical cross-line drift shape a call-window regex missed - DC-087-ALLOW-RAW-FETCH comment escape hatch (raw-text marker, guard file never self-exempts, skips logged to jest output) Judge: GLM-5.3 cold read via delegate_task deleg_4d384dea (round 1 C -> round 2 B, zero blockers, polish folded). Verdict URN: urn:ump:azrv2xp72koiwi5r4yb6ureu4aqqloqq64sgmftsajh6ci2mzj2q Mutation probes: historical drift reintroduction -> guard red; hatch marker -> skipped+logged; restore -> 33/33. Full suite 2603/2603.
This commit is contained in:
@@ -118,6 +118,67 @@ describe('Caddyfile + utils/http.js — Origin header construction (DC-051)', ()
|
||||
expect(offenders).toEqual([]);
|
||||
});
|
||||
|
||||
test('all :2019 call sites in TESTS use fetchT or a mocked fetchT (not raw fetch)', () => {
|
||||
// DC-087 — the same rule, extended into __tests__. The api-code walk above
|
||||
// skips __tests__, which let two mirrored health-handler test files keep a
|
||||
// raw await-fetch caddy probe long after src/app.js moved to fetchT. On a
|
||||
// host where the suite runs alongside a live Caddy admin (the prod box
|
||||
// runs the full jest suite every 30 min via a cron adversarial check),
|
||||
// that Origin-less raw fetch 403-spammed the Caddy journal (~700
|
||||
// client-not-allowed error lines per day) while the tests still passed —
|
||||
// checks.caddy.ok=false was silently accepted as sandbox noise. Mirrors
|
||||
// MUST call fetchT (mocked at buildApp scope for hermeticity). A raw
|
||||
// await-fetch at a Caddy-admin-URL call site in a test is an offender.
|
||||
// NOTE: keep this comment free of backticks — stripComments pairs
|
||||
// backtick spans across lines, and a stray pair shields real code from
|
||||
// the comment stripper (this test self-flagged its first draft).
|
||||
//
|
||||
// Detection is deliberately FILE-LEVEL, not call-window: the historical
|
||||
// drift kept the fetch call itself token-free (the URL came from a
|
||||
// caddyUrl variable defined on a PREVIOUS line from CADDY_ADMIN_URL),
|
||||
// so a call-window regex never fired. Any raw await-fetch in a file
|
||||
// that also references the Caddy admin anywhere is an offender.
|
||||
// Escape hatch for future tests that intentionally assert Origin-less
|
||||
// 403 behavior against their own local listener: put the marker
|
||||
// DC-087-ALLOW-RAW-FETCH in the file and it is skipped.
|
||||
const testsRoot = path.join(__dirname);
|
||||
const offenders = [];
|
||||
const skipped = [];
|
||||
function walk(dir) {
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
if (entry.name === 'node_modules') continue;
|
||||
const p = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) walk(p);
|
||||
else if (entry.name.endsWith('.js')) {
|
||||
const rawText = fs.readFileSync(p, 'utf8');
|
||||
// Escape hatch (checked on RAW text so a comment marker works —
|
||||
// comments are stripped below): a file carrying the
|
||||
// DC-087-ALLOW-RAW-FETCH marker declares it intentionally
|
||||
// raw-fetches the Caddy admin (e.g. asserting Origin-less 403
|
||||
// against its own local listener). The guard file itself is
|
||||
// always scanned (never skipped) so the hatch can't be used to
|
||||
// blind this very test.
|
||||
if (p !== __filename && /DC-087-ALLOW-RAW-FETCH/.test(rawText)) {
|
||||
skipped.push(p);
|
||||
continue;
|
||||
}
|
||||
const text = stripComments(rawText);
|
||||
const hasAdminToken = /:2019|adminUrl|admin_api_url|CADDY_ADMIN/.test(text);
|
||||
const hasRawAwaitFetch = /await\s+fetch\(/.test(text);
|
||||
if (hasAdminToken && hasRawAwaitFetch) {
|
||||
offenders.push(`${p}: raw await-fetch in a file referencing the Caddy admin (mock fetchT instead; documented escape-hatch marker available for intentional 403 tests)`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
walk(testsRoot);
|
||||
if (skipped.length) {
|
||||
// Visibility for hatch use — shows up in jest output for reviewers.
|
||||
console.info('[DC-087 guard] escape-hatch skipped:', skipped.join(', '));
|
||||
}
|
||||
expect(offenders).toEqual([]);
|
||||
});
|
||||
|
||||
test('readiness handler in src/app.js probes the exact URL the watcher needs', () => {
|
||||
const raw = fs.readFileSync(
|
||||
path.join(__dirname, '../src/app.js'),
|
||||
@@ -127,9 +188,9 @@ describe('Caddyfile + utils/http.js — Origin header construction (DC-051)', ()
|
||||
expect(raw).toMatch(/\/config\/apps\/http\/servers\/srv0\/listen/);
|
||||
// Goes through fetchT, NOT bare fetch — that's how the Origin injection
|
||||
// takes effect. Look at the 800 chars BEFORE the probe URL on the same
|
||||
// line / call site — the call must be `fetchT(...)`, not `await fetch(...)`.
|
||||
// (We look backward because the URL sits inside the call's argument list,
|
||||
// so the call site comes before the URL token.)
|
||||
// line / call site — the call must be fetchT(...), never a raw await of
|
||||
// the global fetch. (We look backward because the URL sits inside the
|
||||
// call's argument list, so the call site comes before the URL token.)
|
||||
const idx = raw.indexOf('srv0/listen');
|
||||
const around = raw.substr(Math.max(0, idx - 400), 800);
|
||||
expect(around).toMatch(/fetchT\(/);
|
||||
|
||||
Reference in New Issue
Block a user