import { readFile, readdir } from 'node:fs/promises'; import { dirname, extname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { describe, expect, it } from 'vitest'; import { parseRosterV2, validateRosterV2Semantics } from './roster-v2.js'; const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..'); const repositoryRoot = resolve(packageRoot, '..', '..'); const fleetDocs = join(repositoryRoot, 'docs', 'fleet'); const frameworkFleet = join(packageRoot, 'framework', 'fleet'); const REQUIRED_FLEET_PAGES = [ 'README.md', 'concepts/desired-vs-observed-state.md', 'concepts/identity-class-runtime.md', 'concepts/role-authority-and-leases.md', 'concepts/generated-env-launch-chain.md', 'reference/roster-v2.schema.json', 'reference/roster-v2-fields.md', 'reference/cli.md', 'reference/role-classes.md', 'reference/lifecycle-transitions.md', 'reference/status-and-drift.md', 'how-to/create-update-delete-agent.md', 'how-to/start-stop-restart.md', 'how-to/configure-tess-interaction.md', 'how-to/configure-ultron-validator.md', 'how-to/customize-roles.md', 'operations/reconcile-and-recover.md', 'operations/env-quarantine.md', 'operations/systemd-tmux-troubleshooting.md', 'operations/backup-restore.md', 'operations/upgrade-assets.md', 'migration/v1-to-v2.md', 'migration/example-profile-disposition.md', 'migration/legacy-class-aliases.md', ] as const; async function markdownFiles(root: string): Promise { const entries = await readdir(root, { withFileTypes: true }); const paths = await Promise.all( entries.map(async (entry): Promise => { const path = join(root, entry.name); if (entry.isDirectory()) return markdownFiles(path); return extname(entry.name) === '.md' ? [path] : []; }), ); return paths.flat().sort(); } function localMarkdownTargets(source: string): string[] { const link = /\[[^\]]*\]\(\s*(?:<([^>]+)>|((?:\\.|[^()\s]|\([^()]*\))+))(?:\s+(?:"[^"]*"|'[^']*'|\([^)]*\)))?\s*\)/g; return [...source.matchAll(link)] .map((match): string => match[1] ?? match[2] ?? '') .filter( (target): boolean => target !== '' && !target.startsWith('http://') && !target.startsWith('https://') && !target.startsWith('mailto:'), ); } function markdownHeadingAnchors(source: string): Set { const anchors = new Set(); let fence: { readonly marker: string; readonly length: number } | undefined; for (const line of source.split('\n')) { const fenceMatch = line.match(/^\s{0,3}(`{3,}|~{3,})(.*)$/); if (fence === undefined && fenceMatch !== null) { const run = fenceMatch[1] ?? ''; fence = { marker: run[0] ?? '', length: run.length }; continue; } if (fence !== undefined) { const closingRun = line.match(/^\s{0,3}(`{3,}|~{3,})\s*$/)?.[1]; if ( closingRun !== undefined && closingRun[0] === fence.marker && closingRun.length >= fence.length ) { fence = undefined; } continue; } const heading = line.match(/^\s{0,3}#{1,6}\s+(.+?)\s*#*\s*$/)?.[1]; if (heading === undefined) continue; const base = heading .replace(/!?\[([^\]]*)\]\([^)]*\)/g, '$1') .replace(/<[^>]*>/g, '') .replace(/[`*_~]/g, '') .toLowerCase() .trim() .replace(/[^\p{L}\p{N}\s-]/gu, '') .replace(/\s+/g, '-'); let anchor = base; let duplicate = 0; while (anchors.has(anchor)) { duplicate += 1; anchor = `${base}-${duplicate}`; } anchors.add(anchor); } return anchors; } function markdownLinkViolations( sourcePath: string, source: string, documents: Readonly>, ): string[] { const violations: string[] = []; for (const target of localMarkdownTargets(source)) { const [encodedPath = '', encodedFragment] = target.split('#', 2); const targetPath = decodeURIComponent(encodedPath); const normalizedTarget = resolve('/', dirname(sourcePath), targetPath).slice(1); const targetSource = documents[normalizedTarget]; if (targetSource === undefined) { violations.push(`${sourcePath} -> ${target}: missing file`); continue; } if (encodedFragment !== undefined) { const fragment = decodeURIComponent(encodedFragment); if (fragment === '' || !markdownHeadingAnchors(targetSource).has(fragment)) { violations.push(`${sourcePath} -> ${target}: missing heading`); } } } return violations; } function commandBasename(token: string): string { return token.slice(token.lastIndexOf('/') + 1); } function shellCommandSegments(source: string): string[] { const segments: string[] = []; let segment = ''; let quote = ''; let escaped = false; const flush = (): void => { if (segment.trim() !== '') segments.push(segment); segment = ''; }; for (const character of source) { if (escaped) { segment += character; escaped = false; continue; } if (character === '\\' && quote !== "'") { segment += character; escaped = true; continue; } if (quote !== '') { segment += character; if (character === quote) quote = ''; continue; } if (character === "'" || character === '"') { segment += character; quote = character; continue; } if (character === '\n' || character === ';' || character === '&' || character === '|') { flush(); continue; } segment += character; } flush(); return segments; } function shellCommandTokens(source: string): string[] { const tokens: string[] = []; let token = ''; let quote = ''; let escaped = false; for (const character of source) { if (escaped) { token += character; escaped = false; continue; } if (character === '\\' && quote !== "'") { escaped = true; continue; } if (quote !== '') { if (character === quote) quote = ''; else token += character; continue; } if (character === "'" || character === '"') { quote = character; continue; } if (/\s/.test(character)) { if (token !== '') { tokens.push(token); token = ''; } continue; } token += character; } if (escaped) token += '\\'; if (token !== '') tokens.push(token); return tokens; } function normalizedCommandTokens(segment: string): string[] { const tokens = shellCommandTokens(segment.trim().replace(/^(?:[$#>]\s*)/, '')); let index = 0; while (index < tokens.length) { const wrapper = commandBasename(tokens[index] ?? ''); if (wrapper === 'env') { index += 1; while (index < tokens.length) { const token = tokens[index] ?? ''; if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(token)) { index += 1; continue; } if (token === '--') { index += 1; break; } if (/^(?:--unset|--chdir)$/.test(token)) { index += 2; continue; } if (/^(?:--unset=|--chdir=)/.test(token)) { index += 1; continue; } if (token === '--split-string') { const splitTokens = shellCommandTokens(tokens[index + 1] ?? ''); tokens.splice(index, 2, ...splitTokens); continue; } const longSplitString = token.match(/^--split-string=(.*)$/)?.[1]; if (longSplitString !== undefined) { tokens.splice(index, 1, ...shellCommandTokens(longSplitString)); continue; } if (/^-[^-]/.test(token)) { const options = token.slice(1); let consumed = false; for (let optionIndex = 0; optionIndex < options.length; optionIndex += 1) { const option = options[optionIndex] ?? ''; if (option === 'u' || option === 'C') { index += options.slice(optionIndex + 1) === '' ? 2 : 1; consumed = true; break; } if (option === 'S') { const attached = options.slice(optionIndex + 1); const operand = attached === '' ? (tokens[index + 1] ?? '') : attached; tokens.splice(index, attached === '' ? 2 : 1, ...shellCommandTokens(operand)); consumed = true; break; } } if (!consumed) index += 1; continue; } if (token.startsWith('-')) { index += 1; continue; } break; } continue; } if (wrapper === 'command') { index += 1; let availabilityQuery = false; while ((tokens[index] ?? '').startsWith('-')) { const option = tokens[index] ?? ''; index += 1; if (option === '--') break; if (/^-[^-]*[vV]/.test(option)) availabilityQuery = true; } if (availabilityQuery) return []; continue; } break; } return tokens.slice(index); } function containsPrivilegedCommand(source: string): boolean { const privilegedCommands = new Set([ 'sudo', 'doas', 'pkexec', 'systemctl', 'service', 'mount', 'umount', 'reboot', 'shutdown', 'poweroff', 'halt', 'chown', 'chmod', 'chroot', 'useradd', 'usermod', 'groupadd', 'visudo', 'apt', 'apt-get', 'apt-cache', 'dpkg', 'yum', 'dnf', 'rpm', 'apk', 'pacman', 'zypper', 'emerge', 'snap', 'flatpak', 'brew', 'nix-env', ]); return shellCommandSegments(source).some((segment): boolean => { const tokens = normalizedCommandTokens(segment); const command = commandBasename(tokens[0] ?? ''); if (privilegedCommands.has(command)) return true; if (command !== 'su') return false; let index = 1; while (index < tokens.length) { const token = tokens[index] ?? ''; if (token === '--') { index += 1; break; } if ( /^(?:--command|--session-command|--group|--supp-group|--shell|--whitelist-environment)$/.test( token, ) ) { index += 2; continue; } if ( /^(?:--command=|--session-command=|--group=|--supp-group=|--shell=|--whitelist-environment=)/.test( token, ) ) { index += 1; continue; } if (/^-[^-]/.test(token)) { const options = token.slice(1); let consumed = false; for (let optionIndex = 0; optionIndex < options.length; optionIndex += 1) { const option = options[optionIndex] ?? ''; if ('cgGsw'.includes(option)) { index += options.slice(optionIndex + 1) === '' ? 2 : 1; consumed = true; break; } } if (!consumed) index += 1; continue; } if (token.startsWith('-')) { index += 1; continue; } break; } const user = tokens[index]; return user === undefined || user === 'root'; }); } function exampleSafetyViolationKinds(source: string): string[] { const kinds = new Set(); const sensitiveKey = /(?:secret|token|password|credential|MOSAIC_AGENT_COMMAND)/i; const credentialFormat = /(?:\bAKIA[0-9A-Z]{16}\b|\bAIza[0-9A-Za-z_-]{35}\b|\bgh[pousr]_[A-Za-z0-9]{20,}\b|\bgithub_pat_[A-Za-z0-9_]{20,}\b|\bglpat-[A-Za-z0-9_-]{20,}\b|\bnpm_[A-Za-z0-9]{20,}\b|\bsk-ant-(?:api\d{2}-)?[A-Za-z0-9_-]{20,}\b|\bsk-proj-[A-Za-z0-9_-]{20,}\b|\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b|\bxox[baprs]-[A-Za-z0-9-]{10,}\b|\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b|\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b|-----BEGIN [A-Z ]*PRIVATE KEY-----|\b[A-Za-z][A-Za-z0-9+.-]*:\/\/[^\s/:]+:[^\s/@]+@)/; if (sensitiveKey.test(source)) kinds.add('sensitive-key'); if (credentialFormat.test(source)) kinds.add('credential-format'); if (containsPrivilegedCommand(source)) kinds.add('privileged-command'); if (/\b(?:Tess|Ultron)\b/.test(source)) kinds.add('identity'); return [...kinds].sort(); } function fencedCodeBlocks(source: string): string[] { const blocks: string[] = []; let fence: { readonly marker: string; readonly length: number } | undefined; let lines: string[] = []; for (const line of source.split('\n')) { const openingRun = line.match(/^\s{0,3}(`{3,}|~{3,})[^\n]*$/)?.[1]; if (fence === undefined && openingRun !== undefined) { fence = { marker: openingRun[0] ?? '', length: openingRun.length }; lines = []; continue; } if (fence === undefined) continue; const closingRun = line.match(/^\s{0,3}(`{3,}|~{3,})\s*$/)?.[1]; if ( closingRun !== undefined && closingRun[0] === fence.marker && closingRun.length >= fence.length ) { blocks.push(lines.join('\n')); fence = undefined; lines = []; continue; } lines.push(line); } if (fence !== undefined) blocks.push(lines.join('\n')); return blocks; } const UNSAFE_EXAMPLE_FIXTURES = [ { expected: 'privileged-command', source: ['cd /srv && su', 'do systemctl restart example'].join(''), }, { expected: 'privileged-command', source: '/usr/bin/sudo systemctl restart example' }, { expected: 'privileged-command', source: '/usr/bin/apt-get install example' }, { expected: 'privileged-command', source: '/usr/bin/env -i /usr/bin/command -- /usr/bin/apt-get install example', }, { expected: 'privileged-command', source: '/usr/bin/env -u FOO /usr/bin/apt-get install example', }, { expected: 'privileged-command', source: 'env -iu FOO /usr/bin/apt-get --version', }, { expected: 'privileged-command', source: 'env -ivS/usr/bin/apt-get --version', }, { expected: 'privileged-command', source: 'env --unset FOO /usr/bin/apt-get install example', }, { expected: 'privileged-command', source: 'env -S apt-get install example' }, { expected: 'privileged-command', source: "env -S 'apt-get update'" }, { expected: 'privileged-command', source: "env -S'/usr/bin/apt-get --version'" }, { expected: 'privileged-command', source: "env --split-string='apt-get update'", }, { expected: 'privileged-command', source: "env --split-string='-i /usr/bin/apt-get update'", }, { expected: 'privileged-command', source: "env --split-string='FOO=x /usr/bin/apt-get update'", }, { expected: 'privileged-command', source: "env --split-string='-- /usr/bin/apt-get update'", }, { expected: 'privileged-command', source: 'reboot' }, { expected: 'privileged-command', source: 'su --command=/bin/sh' }, { expected: 'privileged-command', source: 'su -lc /usr/bin/id' }, { expected: 'privileged-command', source: 'su -l root' }, { expected: 'privileged-command', source: 'su -l -s /bin/sh root' }, { expected: 'privileged-command', source: '/usr/bin/su --login root' }, { expected: 'privileged-command', source: 'su root' }, { expected: 'privileged-command', source: '/usr/sbin/chroot /srv/example' }, { expected: 'credential-format', source: ['ghp_', 'a'.repeat(36)].join('') }, { expected: 'credential-format', source: ['sk-ant-api03-', 'a'.repeat(80)].join(''), }, { expected: 'credential-format', source: ['sk-proj-', 'a'.repeat(80)].join(''), }, { expected: 'credential-format', source: ['rk_live_', 'a'.repeat(24)].join(''), }, { expected: 'credential-format', source: ['eyJ', 'a'.repeat(12), '.', 'b'.repeat(12), '.', 'c'.repeat(12)].join(''), }, ] as const; describe('documentation validation regressions', (): void => { it('rejects a local Markdown link whose heading fragment does not exist', (): void => { expect( markdownLinkViolations('docs/fleet/source.md', '[broken](target.md#missing)', { 'docs/fleet/target.md': '# Present', }), ).toEqual(['docs/fleet/source.md -> target.md#missing: missing heading']); }); it('accepts balanced-parenthesis link destinations and visible-text heading anchors', (): void => { expect(localMarkdownTargets('[guide](guide-(legacy).md#setup "Guide")')).toEqual([ 'guide-(legacy).md#setup', ]); expect(markdownHeadingAnchors('# [Fleet API](cli.md) behavior')).toContain( 'fleet-api-behavior', ); }); it('keeps longer fenced blocks closed only by an equal-or-longer fence', (): void => { expect(markdownHeadingAnchors('````markdown\n```\n# Not a heading\n````\n# Present')).toEqual( new Set(['present']), ); }); it('assigns a free suffix when a prior heading already occupies the next duplicate anchor', (): void => { expect(markdownHeadingAnchors('# Foo\n# Foo-1\n# Foo')).toEqual( new Set(['foo', 'foo-1', 'foo-2']), ); }); it('allows command availability queries without classifying the queried command', (): void => { expect(exampleSafetyViolationKinds('command -v apt-get')).not.toContain('privileged-command'); }); it('keeps quoted command separators as inert argument data', (): void => { expect( exampleSafetyViolationKinds("printf '%s\\n' 'safe; /usr/bin/apt-get update'"), ).not.toContain('privileged-command'); }); it('still detects commands after unquoted command separators', (): void => { expect(exampleSafetyViolationKinds('printf safe; /usr/bin/apt-get update')).toContain( 'privileged-command', ); }); it.each([ "env --split-string='-i -- /usr/bin/printf safe'", "env --split-string='FOO=x /usr/bin/printf safe'", 'env -iu FOO /usr/bin/printf safe', 'env -ivS/usr/bin/printf safe', 'su -lc /usr/bin/id operator', 'su -l -s /bin/sh operator', 'su -s /bin/sh -- operator', 'su -c /usr/bin/id operator', 'su --command=/usr/bin/id operator', 'su --session-command=/usr/bin/id operator', ])('keeps valid non-privileged env and su forms safe', (source): void => { expect(exampleSafetyViolationKinds(source)).not.toContain('privileged-command'); }); it.each(UNSAFE_EXAMPLE_FIXTURES)( 'classifies unsafe example fixture as $expected', ({ expected, source }): void => { expect(exampleSafetyViolationKinds(source)).toContain(expected); }, ); it('extracts tilde-fenced and unclosed examples without exposing their contents', (): void => { const sensitiveFixture = ['sk-ant-api03-', 'a'.repeat(80)].join(''); const blocks = fencedCodeBlocks( `~~~sh\n${sensitiveFixture}\n~~~\n\n\`\`\`sh\n${sensitiveFixture}`, ); expect(blocks).toHaveLength(2); for (const block of blocks) { const kinds = exampleSafetyViolationKinds(block); expect(kinds).toContain('credential-format'); expect(JSON.stringify(kinds)).not.toContain(sensitiveFixture); } }); }); describe('fleet operator documentation', (): void => { it('ships every accepted information-architecture page', async (): Promise => { await expect( Promise.all(REQUIRED_FLEET_PAGES.map((path) => readFile(join(fleetDocs, path), 'utf8'))), ).resolves.toHaveLength(REQUIRED_FLEET_PAGES.length); }); it('resolves every local Markdown link and heading fragment in the fleet book and sitemap', async (): Promise => { const files = [...(await markdownFiles(fleetDocs)), join(repositoryRoot, 'docs', 'SITEMAP.md')]; const documents: Record = {}; for (const file of files) { const relative = file.slice(repositoryRoot.length + 1); documents[relative] = await readFile(file, 'utf8'); } const violations: string[] = []; for (const [sourcePath, source] of Object.entries(documents)) { for (const target of localMarkdownTargets(source)) { const encodedPath = target.split('#', 1)[0] ?? ''; const targetPath = resolve( dirname(join(repositoryRoot, sourcePath)), decodeURIComponent(encodedPath), ); const relativeTarget = targetPath.slice(repositoryRoot.length + 1); if (documents[relativeTarget] === undefined) { try { documents[relativeTarget] = await readFile(targetPath, 'utf8'); } catch { // The deterministic validator below records the missing target without exposing content. } } } violations.push(...markdownLinkViolations(sourcePath, source, documents)); } expect(violations).toEqual([]); }); it('validates the canonical documentation example through the production compiler and resolver', async (): Promise => { const source = await readFile(join(fleetDocs, 'examples', 'roster-v2.yaml'), 'utf8'); const roster = parseRosterV2(source, 'yaml'); const validated = await validateRosterV2Semantics(roster, { rolesDir: join(frameworkFleet, 'roles'), overrideDir: join(fleetDocs, 'examples', 'roles.local'), }); expect(validated.generation).toBe(1); expect(validated.agents.map((agent) => agent.canonicalClass)).toEqual([ 'code', 'interaction', 'validator', ]); }); it('keeps every fenced fleet example free of sensitive values, privileged commands, arbitrary command overrides, and product-hardcoded identities', async (): Promise => { const violations: string[] = []; for (const file of await markdownFiles(fleetDocs)) { const source = await readFile(file, 'utf8'); for (const [index, block] of fencedCodeBlocks(source).entries()) { for (const kind of exampleSafetyViolationKinds(block)) { violations.push(`${file.slice(repositoryRoot.length + 1)}#block-${index + 1}: ${kind}`); } } } const rosterSource = await readFile(join(fleetDocs, 'examples', 'roster-v2.yaml'), 'utf8'); for (const kind of exampleSafetyViolationKinds(rosterSource)) { violations.push(`docs/fleet/examples/roster-v2.yaml: ${kind}`); } expect(violations).toEqual([]); }); });