diff --git a/dist/detectors/claude-settings.js b/dist/detectors/claude-settings.js index faaacb3..b0b5bdd 100644 --- a/dist/detectors/claude-settings.js +++ b/dist/detectors/claude-settings.js @@ -8,7 +8,7 @@ export async function detectClaudeSettingsDrift(oldRoot, newRoot) { for (const [permission, line] of newSettings.allow) { if (!oldSettings.allow.has(permission) && isBroadAllow(permission)) { findings.push({ - kind: 'permission_allow_widened', + kind: 'scope_trail.permission_allow_widened', severity: severityForAllow(permission), file: CLAUDE_SETTINGS_FILE, line, @@ -21,7 +21,7 @@ export async function detectClaudeSettingsDrift(oldRoot, newRoot) { for (const permission of oldSettings.deny.keys()) { if (!newSettings.deny.has(permission)) { findings.push({ - kind: 'permission_deny_removed', + kind: 'scope_trail.permission_deny_removed', severity: severityForRemovedDeny(permission), file: CLAUDE_SETTINGS_FILE, subject: permission, @@ -33,7 +33,7 @@ export async function detectClaudeSettingsDrift(oldRoot, newRoot) { for (const [hookName, oldCommands] of oldSettings.hookCommands) { if (!newSettings.hookCommands.has(hookName)) { findings.push({ - kind: 'hook_removed', + kind: 'scope_trail.hook_removed', severity: isHighImpactHook(hookName) ? 'high' : 'medium', file: CLAUDE_SETTINGS_FILE, subject: hookName, @@ -48,7 +48,7 @@ export async function detectClaudeSettingsDrift(oldRoot, newRoot) { const changed = [...newCommands].filter((command) => !oldCommands.has(command)); if (changed.length > 0 && newCommands.size === oldCommands.size) { findings.push({ - kind: 'hook_command_changed', + kind: 'scope_trail.hook_command_changed', severity: isHighImpactHook(hookName) ? 'high' : 'medium', file: CLAUDE_SETTINGS_FILE, subject: hookName, @@ -63,7 +63,7 @@ export async function detectClaudeSettingsDrift(oldRoot, newRoot) { for (const hookName of newSettings.hookCommands.keys()) { if (!oldSettings.hookCommands.has(hookName)) { findings.push({ - kind: 'hook_added', + kind: 'scope_trail.hook_added', severity: 'low', file: CLAUDE_SETTINGS_FILE, subject: hookName, diff --git a/dist/detectors/codex-config.js b/dist/detectors/codex-config.js index 5c97f94..19bd0b1 100644 --- a/dist/detectors/codex-config.js +++ b/dist/detectors/codex-config.js @@ -11,7 +11,7 @@ export async function detectCodexConfigDrift(oldRoot, newRoot) { const newEntry = newConfig.get(key); if (newEntry && sandboxRank(newEntry.value) > sandboxRank(oldEntry?.value)) { findings.push({ - kind: 'codex_sandbox_widened', + kind: 'scope_trail.codex_sandbox_widened', severity: sandboxRank(newEntry.value) >= 3 ? 'critical' : 'high', file: CODEX_CONFIG_FILE, line: newEntry.line, @@ -25,7 +25,7 @@ export async function detectCodexConfigDrift(oldRoot, newRoot) { const newApproval = newConfig.get('approval_policy'); if (newApproval && approvalRank(newApproval.value) > approvalRank(oldApproval?.value)) { findings.push({ - kind: 'codex_approval_weakened', + kind: 'scope_trail.codex_approval_weakened', severity: newApproval.value === 'never' ? 'high' : 'medium', file: CODEX_CONFIG_FILE, line: newApproval.line, @@ -39,7 +39,7 @@ export async function detectCodexConfigDrift(oldRoot, newRoot) { const newEntry = newConfig.get(key); if (newEntry?.value === 'true' && oldEntry?.value !== 'true') { findings.push({ - kind: 'codex_network_enabled', + kind: 'scope_trail.codex_network_enabled', severity: 'medium', file: CODEX_CONFIG_FILE, line: newEntry.line, @@ -53,7 +53,7 @@ export async function detectCodexConfigDrift(oldRoot, newRoot) { const newTrust = newConfig.get('projects.trust_level'); if (newTrust?.value === 'trusted' && oldTrust?.value !== 'trusted') { findings.push({ - kind: 'codex_project_trusted', + kind: 'scope_trail.codex_project_trusted', severity: 'high', file: CODEX_CONFIG_FILE, line: newTrust.line, diff --git a/dist/detectors/mcp.js b/dist/detectors/mcp.js index 0be9761..e42fc36 100644 --- a/dist/detectors/mcp.js +++ b/dist/detectors/mcp.js @@ -55,7 +55,7 @@ export async function detectMcpDrift(oldRoot, newRoot) { const oldServer = oldServers[name]; if (!oldServer) { findings.push({ - kind: 'mcp_server_added', + kind: 'scope_trail.mcp_server_added', severity: 'high', file: config.path, line: newServer.line, @@ -66,7 +66,7 @@ export async function detectMcpDrift(oldRoot, newRoot) { } else if (serverCommand(newServer) !== serverCommand(oldServer)) { findings.push({ - kind: 'mcp_server_command_changed', + kind: 'scope_trail.mcp_server_command_changed', severity: 'medium', file: config.path, line: lineForServerCommand(newServer) ?? newServer.line, @@ -77,7 +77,7 @@ export async function detectMcpDrift(oldRoot, newRoot) { } if ((!oldServer || serverCommand(newServer) !== serverCommand(oldServer)) && isUnpinnedCommand(newServer)) { findings.push({ - kind: 'unpinned_mcp_command', + kind: 'scope_trail.unpinned_mcp_command', severity: 'high', file: config.path, line: lineForUnpinnedCommand(newServer) ?? newServer.line, @@ -97,7 +97,7 @@ export async function detectMcpDrift(oldRoot, newRoot) { const changed = oldServer && serverCommand(newServer) !== serverCommand(oldServer); if (!oldServer) { findings.push({ - kind: 'mcp_sample_server_added', + kind: 'scope_trail.mcp_sample_server_added', severity: 'low', file: path, line: newServer.line, @@ -108,7 +108,7 @@ export async function detectMcpDrift(oldRoot, newRoot) { } else if (changed) { findings.push({ - kind: 'mcp_sample_server_command_changed', + kind: 'scope_trail.mcp_sample_server_command_changed', severity: 'low', file: path, line: lineForServerCommand(newServer) ?? newServer.line, @@ -119,7 +119,7 @@ export async function detectMcpDrift(oldRoot, newRoot) { } if ((!oldServer || changed) && isUnpinnedCommand(newServer)) { findings.push({ - kind: 'mcp_sample_unpinned_command', + kind: 'scope_trail.mcp_sample_unpinned_command', severity: severityForSampleCommandRisk(newServer), file: path, line: lineForUnpinnedCommand(newServer) ?? newServer.line, @@ -131,7 +131,7 @@ export async function detectMcpDrift(oldRoot, newRoot) { const endpoint = remoteEndpoint(newServer); if ((!oldServer || changed) && endpoint) { findings.push({ - kind: 'mcp_sample_remote_endpoint', + kind: 'scope_trail.mcp_sample_remote_endpoint', severity: 'medium', file: path, line: lineForRemoteEndpoint(newServer) ?? newServer.line, diff --git a/package-lock.json b/package-lock.json index b7bbe73..e54ae55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.11", "license": "MIT", "dependencies": { - "agent-gov-core": "github:Conalh/agent-gov-core#v0.1.2" + "agent-gov-core": "github:Conalh/agent-gov-core#v0.2.0" }, "bin": { "scopetrail": "dist/index.js" diff --git a/package.json b/package.json index b757443..202bb3d 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "test": "node --test" }, "dependencies": { - "agent-gov-core": "github:Conalh/agent-gov-core#v0.1.2" + "agent-gov-core": "github:Conalh/agent-gov-core#v0.2.0" }, "devDependencies": { "@types/node": "^24.0.0", diff --git a/src/detectors/claude-settings.ts b/src/detectors/claude-settings.ts index 573fee6..b679eee 100644 --- a/src/detectors/claude-settings.ts +++ b/src/detectors/claude-settings.ts @@ -12,7 +12,7 @@ export async function detectClaudeSettingsDrift(oldRoot: string, newRoot: string for (const [permission, line] of newSettings.allow) { if (!oldSettings.allow.has(permission) && isBroadAllow(permission)) { findings.push({ - kind: 'permission_allow_widened', + kind: 'scope_trail.permission_allow_widened', severity: severityForAllow(permission), file: CLAUDE_SETTINGS_FILE, line, @@ -26,7 +26,7 @@ export async function detectClaudeSettingsDrift(oldRoot: string, newRoot: string for (const permission of oldSettings.deny.keys()) { if (!newSettings.deny.has(permission)) { findings.push({ - kind: 'permission_deny_removed', + kind: 'scope_trail.permission_deny_removed', severity: severityForRemovedDeny(permission), file: CLAUDE_SETTINGS_FILE, subject: permission, @@ -39,7 +39,7 @@ export async function detectClaudeSettingsDrift(oldRoot: string, newRoot: string for (const [hookName, oldCommands] of oldSettings.hookCommands) { if (!newSettings.hookCommands.has(hookName)) { findings.push({ - kind: 'hook_removed', + kind: 'scope_trail.hook_removed', severity: isHighImpactHook(hookName) ? 'high' : 'medium', file: CLAUDE_SETTINGS_FILE, subject: hookName, @@ -55,7 +55,7 @@ export async function detectClaudeSettingsDrift(oldRoot: string, newRoot: string const changed = [...newCommands].filter((command) => !oldCommands.has(command)); if (changed.length > 0 && newCommands.size === oldCommands.size) { findings.push({ - kind: 'hook_command_changed', + kind: 'scope_trail.hook_command_changed', severity: isHighImpactHook(hookName) ? 'high' : 'medium', file: CLAUDE_SETTINGS_FILE, subject: hookName, @@ -71,7 +71,7 @@ export async function detectClaudeSettingsDrift(oldRoot: string, newRoot: string for (const hookName of newSettings.hookCommands.keys()) { if (!oldSettings.hookCommands.has(hookName)) { findings.push({ - kind: 'hook_added', + kind: 'scope_trail.hook_added', severity: 'low', file: CLAUDE_SETTINGS_FILE, subject: hookName, diff --git a/src/detectors/codex-config.ts b/src/detectors/codex-config.ts index 476256d..f29fc10 100644 --- a/src/detectors/codex-config.ts +++ b/src/detectors/codex-config.ts @@ -20,7 +20,7 @@ export async function detectCodexConfigDrift(oldRoot: string, newRoot: string): const newEntry = newConfig.get(key); if (newEntry && sandboxRank(newEntry.value) > sandboxRank(oldEntry?.value)) { findings.push({ - kind: 'codex_sandbox_widened', + kind: 'scope_trail.codex_sandbox_widened', severity: sandboxRank(newEntry.value) >= 3 ? 'critical' : 'high', file: CODEX_CONFIG_FILE, line: newEntry.line, @@ -35,7 +35,7 @@ export async function detectCodexConfigDrift(oldRoot: string, newRoot: string): const newApproval = newConfig.get('approval_policy'); if (newApproval && approvalRank(newApproval.value) > approvalRank(oldApproval?.value)) { findings.push({ - kind: 'codex_approval_weakened', + kind: 'scope_trail.codex_approval_weakened', severity: newApproval.value === 'never' ? 'high' : 'medium', file: CODEX_CONFIG_FILE, line: newApproval.line, @@ -50,7 +50,7 @@ export async function detectCodexConfigDrift(oldRoot: string, newRoot: string): const newEntry = newConfig.get(key); if (newEntry?.value === 'true' && oldEntry?.value !== 'true') { findings.push({ - kind: 'codex_network_enabled', + kind: 'scope_trail.codex_network_enabled', severity: 'medium', file: CODEX_CONFIG_FILE, line: newEntry.line, @@ -65,7 +65,7 @@ export async function detectCodexConfigDrift(oldRoot: string, newRoot: string): const newTrust = newConfig.get('projects.trust_level'); if (newTrust?.value === 'trusted' && oldTrust?.value !== 'trusted') { findings.push({ - kind: 'codex_project_trusted', + kind: 'scope_trail.codex_project_trusted', severity: 'high', file: CODEX_CONFIG_FILE, line: newTrust.line, diff --git a/src/detectors/mcp.ts b/src/detectors/mcp.ts index 3100c81..eec3831 100644 --- a/src/detectors/mcp.ts +++ b/src/detectors/mcp.ts @@ -74,7 +74,7 @@ export async function detectMcpDrift(oldRoot: string, newRoot: string): Promise< if (!oldServer) { findings.push({ - kind: 'mcp_server_added', + kind: 'scope_trail.mcp_server_added', severity: 'high', file: config.path, line: newServer.line, @@ -84,7 +84,7 @@ export async function detectMcpDrift(oldRoot: string, newRoot: string): Promise< }); } else if (serverCommand(newServer) !== serverCommand(oldServer)) { findings.push({ - kind: 'mcp_server_command_changed', + kind: 'scope_trail.mcp_server_command_changed', severity: 'medium', file: config.path, line: lineForServerCommand(newServer) ?? newServer.line, @@ -96,7 +96,7 @@ export async function detectMcpDrift(oldRoot: string, newRoot: string): Promise< if ((!oldServer || serverCommand(newServer) !== serverCommand(oldServer)) && isUnpinnedCommand(newServer)) { findings.push({ - kind: 'unpinned_mcp_command', + kind: 'scope_trail.unpinned_mcp_command', severity: 'high', file: config.path, line: lineForUnpinnedCommand(newServer) ?? newServer.line, @@ -119,7 +119,7 @@ export async function detectMcpDrift(oldRoot: string, newRoot: string): Promise< if (!oldServer) { findings.push({ - kind: 'mcp_sample_server_added', + kind: 'scope_trail.mcp_sample_server_added', severity: 'low', file: path, line: newServer.line, @@ -129,7 +129,7 @@ export async function detectMcpDrift(oldRoot: string, newRoot: string): Promise< }); } else if (changed) { findings.push({ - kind: 'mcp_sample_server_command_changed', + kind: 'scope_trail.mcp_sample_server_command_changed', severity: 'low', file: path, line: lineForServerCommand(newServer) ?? newServer.line, @@ -141,7 +141,7 @@ export async function detectMcpDrift(oldRoot: string, newRoot: string): Promise< if ((!oldServer || changed) && isUnpinnedCommand(newServer)) { findings.push({ - kind: 'mcp_sample_unpinned_command', + kind: 'scope_trail.mcp_sample_unpinned_command', severity: severityForSampleCommandRisk(newServer), file: path, line: lineForUnpinnedCommand(newServer) ?? newServer.line, @@ -154,7 +154,7 @@ export async function detectMcpDrift(oldRoot: string, newRoot: string): Promise< const endpoint = remoteEndpoint(newServer); if ((!oldServer || changed) && endpoint) { findings.push({ - kind: 'mcp_sample_remote_endpoint', + kind: 'scope_trail.mcp_sample_remote_endpoint', severity: 'medium', file: path, line: lineForRemoteEndpoint(newServer) ?? newServer.line, diff --git a/test/claude-settings-drift.test.mjs b/test/claude-settings-drift.test.mjs index c7d917c..d45427b 100644 --- a/test/claude-settings-drift.test.mjs +++ b/test/claude-settings-drift.test.mjs @@ -15,10 +15,10 @@ test('detects Claude settings permission drift', async () => { assert.deepEqual( findings.map((finding) => finding.kind), [ - 'permission_allow_widened', - 'permission_allow_widened', - 'permission_deny_removed', - 'hook_removed' + 'scope_trail.permission_allow_widened', + 'scope_trail.permission_allow_widened', + 'scope_trail.permission_deny_removed', + 'scope_trail.hook_removed' ] ); assert.equal(findings[0].subject, 'Bash(npm *)'); diff --git a/test/cli-output.test.mjs b/test/cli-output.test.mjs index 7c97f25..8ad53f1 100644 --- a/test/cli-output.test.mjs +++ b/test/cli-output.test.mjs @@ -25,12 +25,12 @@ test('CLI emits JSON permission drift report', async () => { assert.deepEqual( report.findings.map((finding) => finding.kind), [ - 'mcp_server_added', - 'unpinned_mcp_command', - 'permission_allow_widened', - 'permission_allow_widened', - 'permission_deny_removed', - 'hook_removed' + 'scope_trail.mcp_server_added', + 'scope_trail.unpinned_mcp_command', + 'scope_trail.permission_allow_widened', + 'scope_trail.permission_allow_widened', + 'scope_trail.permission_deny_removed', + 'scope_trail.hook_removed' ] ); }); diff --git a/test/codex-config-drift.test.mjs b/test/codex-config-drift.test.mjs index c9faee1..2775cbc 100644 --- a/test/codex-config-drift.test.mjs +++ b/test/codex-config-drift.test.mjs @@ -15,10 +15,10 @@ test('detects Codex config permission drift', async () => { assert.deepEqual( findings.map((finding) => [finding.kind, finding.subject, finding.severity, finding.line]), [ - ['codex_sandbox_widened', 'sandbox_mode', 'critical', 1], - ['codex_approval_weakened', 'approval_policy', 'high', 2], - ['codex_network_enabled', 'sandbox_workspace_write.network_access', 'medium', 5], - ['codex_project_trusted', 'projects.trust_level', 'high', 8] + ['scope_trail.codex_sandbox_widened', 'sandbox_mode', 'critical', 1], + ['scope_trail.codex_approval_weakened', 'approval_policy', 'high', 2], + ['scope_trail.codex_network_enabled', 'sandbox_workspace_write.network_access', 'medium', 5], + ['scope_trail.codex_project_trusted', 'projects.trust_level', 'high', 8] ] ); }); diff --git a/test/git-diff.test.mjs b/test/git-diff.test.mjs index 43602d8..b2ac354 100644 --- a/test/git-diff.test.mjs +++ b/test/git-diff.test.mjs @@ -77,12 +77,12 @@ test('CLI diffs permission drift between git refs', async () => { assert.deepEqual( report.findings.map((finding) => finding.kind), [ - 'mcp_server_added', - 'unpinned_mcp_command', - 'permission_allow_widened', - 'permission_allow_widened', - 'permission_deny_removed', - 'hook_removed' + 'scope_trail.mcp_server_added', + 'scope_trail.unpinned_mcp_command', + 'scope_trail.permission_allow_widened', + 'scope_trail.permission_allow_widened', + 'scope_trail.permission_deny_removed', + 'scope_trail.hook_removed' ] ); } finally { @@ -131,10 +131,10 @@ test('CLI git diff snapshots sample MCP config paths', async () => { assert.deepEqual( report.findings.map((finding) => finding.kind), - ['mcp_sample_server_added', 'mcp_sample_unpinned_command'] + ['scope_trail.mcp_sample_server_added', 'scope_trail.mcp_sample_unpinned_command'] ); assert.equal(report.findings[0].file, 'examples/.mcp.json.sample'); - assert.equal(report.findings.some((finding) => finding.kind === 'mcp_server_added'), false); + assert.equal(report.findings.some((finding) => finding.kind === 'scope_trail.mcp_server_added'), false); } finally { await rm(repo, { recursive: true, force: true }); } @@ -181,10 +181,10 @@ test('CLI git diff snapshots platform-suffixed MCP example paths', async () => { assert.deepEqual( report.findings.map((finding) => finding.kind), - ['mcp_sample_server_added', 'mcp_sample_unpinned_command'] + ['scope_trail.mcp_sample_server_added', 'scope_trail.mcp_sample_unpinned_command'] ); assert.equal(report.findings[0].file, 'examples/.mcp.json.windows.example'); - assert.equal(report.findings.some((finding) => finding.kind === 'mcp_server_added'), false); + assert.equal(report.findings.some((finding) => finding.kind === 'scope_trail.mcp_server_added'), false); } finally { await rm(repo, { recursive: true, force: true }); } @@ -231,10 +231,10 @@ test('CLI git diff snapshots prefixed MCP config example paths', async () => { assert.deepEqual( report.findings.map((finding) => finding.kind), - ['mcp_sample_server_added', 'mcp_sample_unpinned_command'] + ['scope_trail.mcp_sample_server_added', 'scope_trail.mcp_sample_unpinned_command'] ); assert.equal(report.findings[0].file, 'examples/example_mcp_config.json'); - assert.equal(report.findings.some((finding) => finding.kind === 'mcp_server_added'), false); + assert.equal(report.findings.some((finding) => finding.kind === 'scope_trail.mcp_server_added'), false); } finally { await rm(repo, { recursive: true, force: true }); } diff --git a/test/heuristics-and-snapshot.test.mjs b/test/heuristics-and-snapshot.test.mjs index 3d492a8..cfbfd89 100644 --- a/test/heuristics-and-snapshot.test.mjs +++ b/test/heuristics-and-snapshot.test.mjs @@ -67,7 +67,7 @@ test('Claude detector: hook_added fires when a new hook is introduced', async () ); try { const findings = await detectClaudeSettingsDrift(dir.oldRoot, dir.newRoot); - const added = findings.find((f) => f.kind === 'hook_added'); + const added = findings.find((f) => f.kind === 'scope_trail.hook_added'); assert.ok(added); assert.equal(added.subject, 'PreToolUse'); } finally { @@ -88,7 +88,7 @@ test('Claude detector: hook_command_changed fires when an existing hook is weake ); try { const findings = await detectClaudeSettingsDrift(dir.oldRoot, dir.newRoot); - const changed = findings.find((f) => f.kind === 'hook_command_changed'); + const changed = findings.find((f) => f.kind === 'scope_trail.hook_command_changed'); assert.ok(changed); assert.equal(changed.subject, 'PreToolUse'); assert.equal(changed.severity, 'high'); // PreToolUse is high-impact @@ -107,7 +107,7 @@ test('Claude detector: scoped MCP grant does not trip the broad-allow finding', ); try { const findings = await detectClaudeSettingsDrift(dir.oldRoot, dir.newRoot); - assert.equal(findings.find((f) => f.kind === 'permission_allow_widened'), undefined); + assert.equal(findings.find((f) => f.kind === 'scope_trail.permission_allow_widened'), undefined); } finally { await rm(dir.root, { recursive: true, force: true }); } diff --git a/test/mcp-drift.test.mjs b/test/mcp-drift.test.mjs index bc38a8e..09d5367 100644 --- a/test/mcp-drift.test.mjs +++ b/test/mcp-drift.test.mjs @@ -14,7 +14,7 @@ test('detects added MCP server with unpinned command', async () => { assert.deepEqual( findings.map((finding) => finding.kind), - ['mcp_server_added', 'unpinned_mcp_command'] + ['scope_trail.mcp_server_added', 'scope_trail.unpinned_mcp_command'] ); assert.equal(findings[0].subject, 'stripe-admin'); assert.equal(findings[0].line, 7); @@ -32,10 +32,10 @@ test('detects MCP drift in Cursor and VS Code config files', async () => { assert.deepEqual( findings.map((finding) => [finding.file, finding.kind, finding.subject, finding.line]), [ - ['.cursor/mcp.json', 'mcp_server_added', 'browser-tools', 3], - ['.cursor/mcp.json', 'unpinned_mcp_command', 'browser-tools', 5], - ['.vscode/mcp.json', 'mcp_server_added', 'docs-search', 3], - ['.vscode/mcp.json', 'unpinned_mcp_command', 'docs-search', 5] + ['.cursor/mcp.json', 'scope_trail.mcp_server_added', 'browser-tools', 3], + ['.cursor/mcp.json', 'scope_trail.unpinned_mcp_command', 'browser-tools', 5], + ['.vscode/mcp.json', 'scope_trail.mcp_server_added', 'docs-search', 3], + ['.vscode/mcp.json', 'scope_trail.unpinned_mcp_command', 'docs-search', 5] ] ); }); @@ -49,9 +49,9 @@ test('detects MCP drift in Windsurf config files', async () => { assert.deepEqual( findings.map((finding) => [finding.file, finding.kind, finding.subject, finding.line]), [ - ['.codeium/windsurf/mcp_config.json', 'mcp_server_command_changed', 'team-registry', 4], - ['.codeium/windsurf/mcp_config.json', 'mcp_server_added', 'browser-tools', 6], - ['.codeium/windsurf/mcp_config.json', 'unpinned_mcp_command', 'browser-tools', 8] + ['.codeium/windsurf/mcp_config.json', 'scope_trail.mcp_server_command_changed', 'team-registry', 4], + ['.codeium/windsurf/mcp_config.json', 'scope_trail.mcp_server_added', 'browser-tools', 6], + ['.codeium/windsurf/mcp_config.json', 'scope_trail.unpinned_mcp_command', 'browser-tools', 8] ] ); }); @@ -62,16 +62,16 @@ test('detects sample MCP config drift without treating it as active server drift const findings = await detectMcpDrift(oldDir, newDir); - assert.equal(findings.some((finding) => finding.kind === 'mcp_server_added'), false); - assert.equal(findings.some((finding) => finding.kind === 'unpinned_mcp_command'), false); + assert.equal(findings.some((finding) => finding.kind === 'scope_trail.mcp_server_added'), false); + assert.equal(findings.some((finding) => finding.kind === 'scope_trail.unpinned_mcp_command'), false); assert.deepEqual( findings.map((finding) => [finding.file, finding.kind, finding.subject, finding.severity, finding.line]), [ - ['examples/.mcp.json.sample', 'mcp_sample_server_added', 'docs-search', 'low', 3], - ['examples/.mcp.json.sample', 'mcp_sample_server_added', 'copy-risk', 'low', 7], - ['examples/.mcp.json.sample', 'mcp_sample_unpinned_command', 'copy-risk', 'medium', 9], - ['examples/.mcp.json.sample', 'mcp_sample_server_added', 'remote-admin', 'low', 11], - ['examples/.mcp.json.sample', 'mcp_sample_remote_endpoint', 'remote-admin', 'medium', 12] + ['examples/.mcp.json.sample', 'scope_trail.mcp_sample_server_added', 'docs-search', 'low', 3], + ['examples/.mcp.json.sample', 'scope_trail.mcp_sample_server_added', 'copy-risk', 'low', 7], + ['examples/.mcp.json.sample', 'scope_trail.mcp_sample_unpinned_command', 'copy-risk', 'medium', 9], + ['examples/.mcp.json.sample', 'scope_trail.mcp_sample_server_added', 'remote-admin', 'low', 11], + ['examples/.mcp.json.sample', 'scope_trail.mcp_sample_remote_endpoint', 'remote-admin', 'medium', 12] ] ); }); @@ -99,15 +99,15 @@ test('detects platform-suffixed MCP example drift without treating it as active const findings = await detectMcpDrift(oldDir, newDir); - assert.equal(findings.some((finding) => finding.kind === 'mcp_server_added'), false); - assert.equal(findings.some((finding) => finding.kind === 'unpinned_mcp_command'), false); + assert.equal(findings.some((finding) => finding.kind === 'scope_trail.mcp_server_added'), false); + assert.equal(findings.some((finding) => finding.kind === 'scope_trail.unpinned_mcp_command'), false); assert.deepEqual( findings.map((finding) => [finding.file, finding.kind, finding.subject, finding.severity, finding.line]), [ - ['examples/.mcp.json.example.mac', 'mcp_sample_server_added', 'mac-docs', 'low', 3], - ['examples/.mcp.json.example.mac', 'mcp_sample_remote_endpoint', 'mac-docs', 'medium', 4], - ['examples/.mcp.json.windows.example', 'mcp_sample_server_added', 'win-tools', 'low', 3], - ['examples/.mcp.json.windows.example', 'mcp_sample_unpinned_command', 'win-tools', 'medium', 7] + ['examples/.mcp.json.example.mac', 'scope_trail.mcp_sample_server_added', 'mac-docs', 'low', 3], + ['examples/.mcp.json.example.mac', 'scope_trail.mcp_sample_remote_endpoint', 'mac-docs', 'medium', 4], + ['examples/.mcp.json.windows.example', 'scope_trail.mcp_sample_server_added', 'win-tools', 'low', 3], + ['examples/.mcp.json.windows.example', 'scope_trail.mcp_sample_unpinned_command', 'win-tools', 'medium', 7] ] ); }); @@ -118,15 +118,15 @@ test('detects prefixed MCP config example drift without treating it as active se const findings = await detectMcpDrift(oldDir, newDir); - assert.equal(findings.some((finding) => finding.kind === 'mcp_server_added'), false); - assert.equal(findings.some((finding) => finding.kind === 'unpinned_mcp_command'), false); + assert.equal(findings.some((finding) => finding.kind === 'scope_trail.mcp_server_added'), false); + assert.equal(findings.some((finding) => finding.kind === 'scope_trail.unpinned_mcp_command'), false); assert.deepEqual( findings.map((finding) => [finding.file, finding.kind, finding.subject, finding.severity, finding.line]), [ - ['examples/cursor_mcp_config.json', 'mcp_sample_server_added', 'cursor-docs', 'low', 3], - ['examples/cursor_mcp_config.json', 'mcp_sample_remote_endpoint', 'cursor-docs', 'medium', 4], - ['examples/example_mcp_config.json', 'mcp_sample_server_added', 'copy-risk', 'low', 3], - ['examples/example_mcp_config.json', 'mcp_sample_unpinned_command', 'copy-risk', 'medium', 7] + ['examples/cursor_mcp_config.json', 'scope_trail.mcp_sample_server_added', 'cursor-docs', 'low', 3], + ['examples/cursor_mcp_config.json', 'scope_trail.mcp_sample_remote_endpoint', 'cursor-docs', 'medium', 4], + ['examples/example_mcp_config.json', 'scope_trail.mcp_sample_server_added', 'copy-risk', 'low', 3], + ['examples/example_mcp_config.json', 'scope_trail.mcp_sample_unpinned_command', 'copy-risk', 'medium', 7] ] ); });