mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-02 23:14:33 +01:00
shared-libs-plan-callers, plan-ceo-section-loading, auto-decide-preserved, plan-design-review-plan-mode and ship-docsync-late-result each get an inventory of every wave census in scope (all artifacts still available) and minimal, redacted detector or actor inputs replayed through the real detector in the free suite: census passes, every distinct census red, and derived negative controls labelled as derived. Fixed false reds stay as expected passes with their history; the two genuine auto-decide product failures (37176837432, 37179171083) stay refused. A contract test bounds each entry at 64 KB, scans it for HIGH credentials, requires a pass and a refusal per case, and reports entries whose series identity is stale. Building the auto-decide corpus exposed a latent native detector misread: a bold 'Mode application and rationale.' heading was parsed as a withdrawn Mode field (37186854666). A field status now ends at its sentence.
78 lines
4.4 KiB
TypeScript
78 lines
4.4 KiB
TypeScript
/**
|
|
* B1 replay corpora contract. Each case directory under
|
|
* test/fixtures/detector-corpora/ holds minimal, redacted detector or actor
|
|
* inputs from named census captures, an inventory of every census in scope
|
|
* (expired artifacts listed as unavailable), and a replay test
|
|
* (test/detector-corpus-<case>.test.ts) that runs the real detector.
|
|
* Stale entries (series identity no longer current) are reported for refresh,
|
|
* never deleted: a fixed false red stays an expected pass with its history.
|
|
*/
|
|
import { describe, expect, test } from 'bun:test';
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import { scan } from '../lib/redact-engine';
|
|
import { caseSeriesIdentities } from '../scripts/eval-flake-rank';
|
|
|
|
const ROOT = path.resolve(import.meta.dir, '..');
|
|
const DIR = path.join(import.meta.dir, 'fixtures', 'detector-corpora');
|
|
const REQUIRED = ['shared-libs-plan-callers', 'plan-ceo-section-loading', 'auto-decide-preserved',
|
|
'plan-design-review-plan-mode', 'ship-docsync-late-result'];
|
|
const MAX_BYTES = 64 * 1024;
|
|
const cases = fs.readdirSync(DIR).filter(name => fs.statSync(path.join(DIR, name)).isDirectory()).sort();
|
|
const entries = (c: string) => fs.readdirSync(path.join(DIR, c)).filter(f => f.endsWith('.json') && f !== 'inventory.json').sort()
|
|
.map(file => ({ file, bytes: fs.statSync(path.join(DIR, c, file)).size, raw: fs.readFileSync(path.join(DIR, c, file), 'utf8') }))
|
|
.map(entry => ({ ...entry, json: JSON.parse(entry.raw) }));
|
|
|
|
test('every required repeat-offender case has a corpus', () => {
|
|
expect(cases).toEqual(expect.arrayContaining(REQUIRED));
|
|
});
|
|
|
|
describe.each(cases)('%s corpus', (c) => {
|
|
const all = entries(c);
|
|
test('has a replay test, at least one expected pass and one expected refusal', () => {
|
|
expect(fs.existsSync(path.join(import.meta.dir, `detector-corpus-${c}.test.ts`))).toBe(true);
|
|
expect(all.some(entry => entry.json.expected === 'pass')).toBe(true);
|
|
expect(all.some(entry => entry.json.expected === 'refuse')).toBe(true);
|
|
});
|
|
test.each(all.map(entry => [entry.file, entry] as const))('%s is a bounded, attributed, credential-free entry', (_file, entry) => {
|
|
const e = entry.json;
|
|
expect(entry.bytes).toBeLessThanOrEqual(MAX_BYTES);
|
|
expect(e).toMatchObject({ schema: 'gstack-detector-corpus/v1', case: c });
|
|
expect(e.detector).toMatch(/^test\/[\w./-]+\.ts#\S+/);
|
|
expect(e.series_identity).toMatch(/^[0-9a-f]{16}$/);
|
|
expect(e.source.run).toMatch(/^\d{8,}$/);
|
|
expect(e.source.sha).toMatch(/^[0-9a-f]{40}$/);
|
|
expect(['periodic', 'gate', 'pr']).toContain(e.source.lane);
|
|
expect(['passed', 'failed']).toContain(e.census_outcome);
|
|
expect(['pass', 'refuse']).toContain(e.expected);
|
|
expect(e.justification.trim().length).toBeGreaterThan(10);
|
|
expect(e.input).toBeDefined();
|
|
// A refusal that no census produced must say how it was derived.
|
|
if (e.expected === 'refuse' && e.census_outcome === 'passed') expect(typeof e.derived).toBe('string');
|
|
const scanned = scan(entry.raw, { repoVisibility: 'private' });
|
|
expect(scanned.oversize).toBe(false);
|
|
expect(scanned.findings.filter(f => f.severity === 'HIGH').map(f => f.id)).toEqual([]);
|
|
});
|
|
test('the inventory lists every census in scope and only existing entries', () => {
|
|
const inventory = JSON.parse(fs.readFileSync(path.join(DIR, c, 'inventory.json'), 'utf8')) as Array<Record<string, unknown>>;
|
|
expect(inventory.length).toBeGreaterThan(0);
|
|
const files = new Set(all.map(entry => entry.file));
|
|
for (const row of inventory) {
|
|
expect(String(row.run)).toMatch(/^\d{8,}$/);
|
|
expect(typeof row.available).toBe('boolean');
|
|
if (row.entry !== null && row.entry !== undefined) expect(files.has(String(row.entry))).toBe(true);
|
|
}
|
|
for (const entry of all.filter(entry => !entry.json.derived)) {
|
|
expect(inventory.some(row => String(row.run) === entry.json.source.run)).toBe(true);
|
|
}
|
|
});
|
|
});
|
|
|
|
test('stale corpus entries are reported for refresh', () => {
|
|
const current = caseSeriesIdentities(cases, ROOT);
|
|
const stale = cases.flatMap(c => entries(c).filter(entry => entry.json.series_identity !== current[c])
|
|
.map(entry => `${c}/${entry.file} (series ${entry.json.series_identity}, current ${current[c]})`));
|
|
if (stale.length) console.log(`[detector-corpora] ${stale.length} stale entr${stale.length === 1 ? 'y' : 'ies'} (refresh from a current census when one fails):\n ${stale.join('\n ')}`);
|
|
expect(Object.keys(current).sort()).toEqual(cases);
|
|
});
|