Operator decision 2026-11-10: v6.5 is out of date, and Voyage is not shown again until a complete v1.0 on the new architecture. The repository moves to ktg/voyage (private) and is registered in the private marketplace, the same move the other plugins made on 2026-10-06. The open catalog now lists no plugins. Manifest, README and PUBLIC_REPOS change in the same commit, as the public-link gate requires; the CLI test's fixtures now use this catalog's own repository, which stays on the public list. check-public-links, check-versions (0 plugins), check-retired-refs, check-nav-golden, check-okf-parity exit 0; 244 of 244 tests pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
3.7 KiB
JavaScript
80 lines
3.7 KiB
JavaScript
// 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/ktg-plugin-marketplace\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/ktg-plugin-marketplace.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}`), []);
|
|
});
|