// Tests for the public-link gate. Unit tests use synthetic content; the last test is the // FERDIG criterion and reads this repository's own README and manifest. import { test } from 'node:test'; import assert from 'node:assert/strict'; import { spawnSync } from 'node:child_process'; import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { PUBLIC_REPOS, extractRepoLinks, scanFiles, runCheck } from './check-public-links.mjs'; const HERE = dirname(fileURLToPath(import.meta.url)); const REPO = join(HERE, '..'); const CLI = join(HERE, 'check-public-links.mjs'); test('extractRepoLinks finds every org-repo link with its line, dropping .git', () => { const content = [ '# title', '[a](https://git.fromaitochitta.com/open/voyage) and [b](https://git.fromaitochitta.com/open/okr/src/branch/main)', '"url": "https://git.fromaitochitta.com/open/repo-mailbox.git"', 'https://example.com/open/not-ours', ].join('\n'); assert.deepEqual(extractRepoLinks(content), [ { line: 2, repo: 'voyage' }, { line: 2, repo: 'okr' }, { line: 3, repo: 'repo-mailbox' }, ]); }); test('scanFiles flags only links to repositories off the public list', () => { const { links, findings } = scanFiles( [ { path: 'README.md', content: 'https://git.fromaitochitta.com/open/voyage\nhttps://git.fromaitochitta.com/open/gone-private' }, { path: 'm.json', content: '"https://git.fromaitochitta.com/open/gone-private.git"' }, ], ['voyage'], ); assert.equal(links.length, 3); assert.deepEqual(findings.map((f) => `${f.path}:${f.line}:${f.repo}`), ['README.md:2:gone-private', 'm.json:1:gone-private']); }); test('the public list is sorted and has no duplicates', () => { assert.deepEqual([...PUBLIC_REPOS].sort(), PUBLIC_REPOS); assert.equal(new Set(PUBLIC_REPOS).size, PUBLIC_REPOS.length); }); function tmpRoot(files) { const root = mkdtempSync(join(tmpdir(), 'public-links-')); for (const [path, body] of Object.entries(files)) { mkdirSync(dirname(join(root, path)), { recursive: true }); writeFileSync(join(root, path), body); } return root; } test('CLI exits 1 on a hit and 0 on a clean surface, always printing the denominator', () => { const run = (root) => spawnSync(process.execPath, [CLI, root], { encoding: 'utf8' }); const dirty = run(tmpRoot({ 'README.md': 'https://git.fromaitochitta.com/open/voyage\nhttps://git.fromaitochitta.com/open/gone-private\n' })); assert.equal(dirty.status, 1); assert.match(dirty.stdout, /\[ERROR\] link to a repository not listed as public — README\.md:2: open\/gone-private/); assert.match(dirty.stdout, /2 org-repo links in 1\/2 files/); const clean = run(tmpRoot({ '.claude-plugin/marketplace.json': '"https://git.fromaitochitta.com/open/voyage.git"' })); assert.equal(clean.status, 0); assert.match(clean.stdout, /1 org-repo links in 1\/2 files, \d+ public repos listed — 0 hit/); }); test('CLI fails when it finds no links at all: verified nothing', () => { const r = spawnSync(process.execPath, [CLI, tmpRoot({ 'README.md': 'no links\n' })], { encoding: 'utf8' }); assert.equal(r.status, 1); assert.match(r.stdout, /verified nothing/); }); // The FERDIG criterion: the catalog links only to repositories listed as public, and every // plugin in the manifest is one of them. test('this repository: README and manifest link only to public repositories', () => { const { files, links, findings } = runCheck(REPO); assert.equal(files, 2, 'both surface files present'); assert.ok(links.length > 0, '0 links found — verified nothing'); assert.deepEqual(findings.map((f) => `${f.path}:${f.line}: open/${f.repo}`), []); });