/** * Static tripwire for .github/workflows/free-tests.yml — the Linux free-suite * lane. Pins the three properties that made the lane worth having: * * 1. It invokes the CANONICAL runner (bun run test:free), not a raw * `bun test ` glob — the runner owns TEST_ROOTS and strict-output * classification, so a truncated run can't report green. * 2. It is SECRETLESS: free tests make no API calls, and keeping keys out * means fork PRs get real signal here. Any `secrets.` reference is a * regression. * 3. It triggers on `pull_request` (never `pull_request_target`, which * would hand a fork PR the base repo's context). * * Same wiring-tripwire class as test/hermetic-wiring.test.ts. */ import { describe, test, expect } from 'bun:test'; import * as fs from 'fs'; import * as path from 'path'; const WORKFLOW = path.resolve(import.meta.dir, '..', '.github', 'workflows', 'free-tests.yml'); describe('free-tests workflow wiring', () => { const source = fs.readFileSync(WORKFLOW, 'utf-8'); test('workflow exists and invokes the canonical runner', () => { expect(source).toContain('bun run test:free'); expect(source).not.toMatch(/run:\s*bun test\s/); }); test('secretless: no secrets reach the free lane', () => { expect(source).not.toContain('secrets.'); expect(source).not.toContain('ANTHROPIC_API_KEY'); expect(source).not.toContain('OPENAI_API_KEY'); }); test('pull_request trigger, never pull_request_target', () => { expect(source).toContain('pull_request:'); expect(source).not.toContain('pull_request_target'); }); test('if sharded (matrix), the matrix count matches --shards N', () => { // Single-job --parallel mode has no matrix — vacuously fine. If someone // switches to the shard matrix (the V3 fallback), the two encodings of // the shard count must agree or CI silently drops files. const shardsFlag = source.match(/--shards\s+(\d+)/); const matrix = source.match(/shard:\s*\[([^\]]+)\]/); if (shardsFlag || matrix) { expect(shardsFlag, 'matrix present but no --shards N flag').toBeTruthy(); expect(matrix, '--shards N present but no shard matrix').toBeTruthy(); const count = parseInt(shardsFlag![1], 10); const entries = matrix![1].split(',').map(s => s.trim()).filter(Boolean); expect(entries.length).toBe(count); } }); });