Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions dist/mesh/engine.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { isBroadAllow, isSensitiveDeny } from '../parsers/claude.js';
import { codexSandboxRank } from '../parsers/codex.js';
export function runMeshRules(policies) {
Expand Down Expand Up @@ -33,7 +33,7 @@
continue;
}
findings.push({
kind: 'claude_mcp_grant_missing_server',
kind: 'policy_mesh.claude_mcp_grant_missing_server',
severity: 'medium',
file: claude.file,
line,
Expand Down Expand Up @@ -69,7 +69,7 @@
.join(' vs ');
const primary = servers[0];
findings.push({
kind: 'mcp_command_mismatch',
kind: 'policy_mesh.mcp_command_mismatch',
severity: 'high',
file: primary.file,
line: primary.line,
Expand Down Expand Up @@ -102,7 +102,7 @@
}
const primary = servers[0];
findings.push({
kind: 'mcp_server_missing',
kind: 'policy_mesh.mcp_server_missing',
severity: 'low',
file: primary.file,
line: primary.line,
Expand Down Expand Up @@ -138,7 +138,7 @@
}
const primary = servers[0];
findings.push({
kind: 'mcp_enabled_mismatch',
kind: 'policy_mesh.mcp_enabled_mismatch',
severity: 'medium',
file: primary.file,
line: primary.line,
Expand Down Expand Up @@ -171,7 +171,7 @@
const primary = servers[0];
const differingKeys = differingEnvKeys(servers);
findings.push({
kind: 'mcp_env_mismatch',
kind: 'policy_mesh.mcp_env_mismatch',
severity: 'medium',
file: primary.file,
line: primary.line,
Expand Down Expand Up @@ -206,7 +206,7 @@
const primary = servers[0];
const differingKeys = differingHeaderKeys(servers);
findings.push({
kind: 'mcp_header_mismatch',
kind: 'policy_mesh.mcp_header_mismatch',
severity: 'medium',
file: primary.file,
line: primary.line,
Expand All @@ -233,7 +233,7 @@
continue;
}
findings.push({
kind: 'mcp_unpinned',
kind: 'policy_mesh.mcp_unpinned',
severity: 'medium',
file: server.file,
line: server.line,
Expand All @@ -260,7 +260,7 @@
for (const deny of sensitiveDenies) {
const line = claude.deny.get(deny);
findings.push({
kind: 'claude_deny_allow_overlap',
kind: 'policy_mesh.claude_deny_allow_overlap',
severity: 'medium',
file: claude.file,
line,
Expand Down Expand Up @@ -288,7 +288,7 @@
}
const [primaryAllow, line] = broadAllows[0];
findings.push({
kind: 'claude_broad_allow_no_guard',
kind: 'policy_mesh.claude_broad_allow_no_guard',
severity: 'medium',
file: claude.file,
line,
Expand All @@ -309,7 +309,7 @@
return findingsEmpty();
}
return [{
kind: 'codex_network_without_review',
kind: 'policy_mesh.codex_network_without_review',
severity: 'medium',
file: codex.file,
line: codex.networkLine,
Expand All @@ -330,7 +330,7 @@
if (unpinned.length > 0 || hasMismatch) {
const risky = unpinned[0];
findings.push({
kind: 'codex_trusted_with_risky_mcp',
kind: 'policy_mesh.codex_trusted_with_risky_mcp',
severity: 'high',
file: risky?.file ?? codex.file,
line: risky?.line ?? codex.trustLine,
Expand Down Expand Up @@ -364,7 +364,7 @@
return findingsEmpty();
}
return [{
kind: 'codex_claude_posture_gap',
kind: 'policy_mesh.codex_claude_posture_gap',
severity: 'medium',
file: codex.file,
line: codex.sandboxLine,
Expand Down
2 changes: 1 addition & 1 deletion dist/parsers/errors.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
const SURFACE_NAMES = {
root_mcp: 'Root MCP',
cursor_mcp: 'Cursor MCP',
Expand All @@ -10,7 +10,7 @@
export function configParseFinding(file, surface, parseError) {
const syntax = surface === 'codex' ? 'TOML' : 'JSON';
return {
kind: 'config_parse_error',
kind: 'policy_mesh.config_parse_error',
severity: 'high',
file,
line: parseError.line,
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"name": "policymesh",
"version": "0.1.18",
Expand Down Expand Up @@ -31,7 +31,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"

Check warning on line 34 in package.json

View workflow job for this annotation

GitHub Actions / scope-review

TaskBound low scope creep

Changed dependency agent-gov-core from github:Conalh/agent-gov-core#v0.1.2 to github:Conalh/agent-gov-core#v0.2.0. Recommendation: Review whether the version change is in scope for the task.
},
"devDependencies": {
"@types/node": "^24.0.0",
Expand Down
24 changes: 12 additions & 12 deletions src/mesh/engine.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { isBroadAllow, isSensitiveDeny } from '../parsers/claude.js';
import { codexSandboxRank } from '../parsers/codex.js';
import type { Finding, MatrixRow, McpServer, RepoPolicies, SurfaceId } from '../types.js';
Expand Down Expand Up @@ -42,7 +42,7 @@
}

findings.push({
kind: 'claude_mcp_grant_missing_server',
kind: 'policy_mesh.claude_mcp_grant_missing_server',
severity: 'medium',
file: claude.file,
line,
Expand Down Expand Up @@ -83,7 +83,7 @@
.join(' vs ');
const primary = servers[0];
findings.push({
kind: 'mcp_command_mismatch',
kind: 'policy_mesh.mcp_command_mismatch',
severity: 'high',
file: primary.file,
line: primary.line,
Expand Down Expand Up @@ -121,7 +121,7 @@

const primary = servers[0];
findings.push({
kind: 'mcp_server_missing',
kind: 'policy_mesh.mcp_server_missing',
severity: 'low',
file: primary.file,
line: primary.line,
Expand Down Expand Up @@ -162,7 +162,7 @@

const primary = servers[0];
findings.push({
kind: 'mcp_enabled_mismatch',
kind: 'policy_mesh.mcp_enabled_mismatch',
severity: 'medium',
file: primary.file,
line: primary.line,
Expand Down Expand Up @@ -200,7 +200,7 @@
const primary = servers[0];
const differingKeys = differingEnvKeys(servers);
findings.push({
kind: 'mcp_env_mismatch',
kind: 'policy_mesh.mcp_env_mismatch',
severity: 'medium',
file: primary.file,
line: primary.line,
Expand Down Expand Up @@ -240,7 +240,7 @@
const primary = servers[0];
const differingKeys = differingHeaderKeys(servers);
findings.push({
kind: 'mcp_header_mismatch',
kind: 'policy_mesh.mcp_header_mismatch',
severity: 'medium',
file: primary.file,
line: primary.line,
Expand Down Expand Up @@ -271,7 +271,7 @@
}

findings.push({
kind: 'mcp_unpinned',
kind: 'policy_mesh.mcp_unpinned',
severity: 'medium',
file: server.file,
line: server.line,
Expand Down Expand Up @@ -303,7 +303,7 @@
for (const deny of sensitiveDenies) {
const line = claude.deny.get(deny);
findings.push({
kind: 'claude_deny_allow_overlap',
kind: 'policy_mesh.claude_deny_allow_overlap',
severity: 'medium',
file: claude.file,
line,
Expand Down Expand Up @@ -336,7 +336,7 @@

const [primaryAllow, line] = broadAllows[0];
findings.push({
kind: 'claude_broad_allow_no_guard',
kind: 'policy_mesh.claude_broad_allow_no_guard',
severity: 'medium',
file: claude.file,
line,
Expand All @@ -361,7 +361,7 @@
}

return [{
kind: 'codex_network_without_review',
kind: 'policy_mesh.codex_network_without_review',
severity: 'medium',
file: codex.file,
line: codex.networkLine,
Expand All @@ -385,7 +385,7 @@
if (unpinned.length > 0 || hasMismatch) {
const risky = unpinned[0];
findings.push({
kind: 'codex_trusted_with_risky_mcp',
kind: 'policy_mesh.codex_trusted_with_risky_mcp',
severity: 'high',
file: risky?.file ?? codex.file,
line: risky?.line ?? codex.trustLine,
Expand Down Expand Up @@ -424,7 +424,7 @@
}

return [{
kind: 'codex_claude_posture_gap',
kind: 'policy_mesh.codex_claude_posture_gap',
severity: 'medium',
file: codex.file,
line: codex.sandboxLine,
Expand Down
2 changes: 1 addition & 1 deletion src/parsers/errors.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import type { Finding, SurfaceId } from '../types.js';
import type { JsonParseError } from '../discovery.js';

Expand All @@ -15,7 +15,7 @@
const syntax = surface === 'codex' ? 'TOML' : 'JSON';

return {
kind: 'config_parse_error',
kind: 'policy_mesh.config_parse_error',
severity: 'high',
file,
line: parseError.line,
Expand Down
44 changes: 22 additions & 22 deletions test/cli-output.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,16 @@ test('CLI conflicted fixture returns high rating with expected kinds', async ()
assert.ok(report.findingCount >= 5);

const kinds = report.findings.map((finding) => finding.kind);
assert.ok(kinds.includes('mcp_command_mismatch'));
assert.ok(kinds.includes('mcp_unpinned'));
assert.ok(kinds.includes('claude_deny_allow_overlap'));
assert.ok(kinds.includes('claude_broad_allow_no_guard'));
assert.ok(kinds.includes('codex_network_without_review'));
assert.ok(kinds.includes('codex_trusted_with_risky_mcp'));
assert.ok(kinds.includes('codex_claude_posture_gap'));
assert.ok(kinds.includes('policy_mesh.mcp_command_mismatch'));
assert.ok(kinds.includes('policy_mesh.mcp_unpinned'));
assert.ok(kinds.includes('policy_mesh.claude_deny_allow_overlap'));
assert.ok(kinds.includes('policy_mesh.claude_broad_allow_no_guard'));
assert.ok(kinds.includes('policy_mesh.codex_network_without_review'));
assert.ok(kinds.includes('policy_mesh.codex_trusted_with_risky_mcp'));
assert.ok(kinds.includes('policy_mesh.codex_claude_posture_gap'));

const githubMismatch = report.findings.find(
(finding) => finding.kind === 'mcp_command_mismatch' && finding.subject === 'github'
(finding) => finding.kind === 'policy_mesh.mcp_command_mismatch' && finding.subject === 'github'
);
assert.ok(githubMismatch);
assert.ok(githubMismatch.surfaces.includes('codex'));
Expand All @@ -153,7 +153,7 @@ test('CLI reports malformed agent config instead of crashing', async () => {
assert.equal(report.findingCount, 1);
assert.equal(report.surfaceCount, 1);
assert.ok(report.effectiveUnion.includes('1 unreadable agent config'));
assert.equal(report.findings[0].kind, 'config_parse_error');
assert.equal(report.findings[0].kind, 'policy_mesh.config_parse_error');
assert.equal(report.findings[0].file, '.cursor/mcp.json');
assert.match(report.findings[0].message, /Could not parse Cursor MCP config/);
});
Expand All @@ -172,7 +172,7 @@ test('CLI reports malformed Codex config instead of hiding the surface', async (
assert.equal(report.findingCount, 1);
assert.equal(report.surfaceCount, 1);
assert.ok(report.effectiveUnion.includes('1 unreadable agent config'));
assert.equal(report.findings[0].kind, 'config_parse_error');
assert.equal(report.findings[0].kind, 'policy_mesh.config_parse_error');
assert.equal(report.findings[0].file, '.codex/config.toml');
assert.equal(report.findings[0].line, 1);
assert.match(report.findings[0].message, /Could not parse Codex config/);
Expand All @@ -192,7 +192,7 @@ test('CLI reports Claude MCP grants whose server is not defined in MCP configs',
assert.equal(report.rating, 'medium');
assert.equal(report.findingCount, 1);
assert.equal(report.surfaceCount, 2);
assert.equal(report.findings[0].kind, 'claude_mcp_grant_missing_server');
assert.equal(report.findings[0].kind, 'policy_mesh.claude_mcp_grant_missing_server');
assert.equal(report.findings[0].severity, 'medium');
assert.equal(report.findings[0].file, '.claude/settings.json');
assert.equal(report.findings[0].line, 4);
Expand All @@ -215,7 +215,7 @@ test('CLI reports servers missing from configured but empty MCP surfaces', async
assert.equal(report.rating, 'low');
assert.equal(report.findingCount, 1);
assert.equal(report.surfaceCount, 2);
assert.equal(report.findings[0].kind, 'mcp_server_missing');
assert.equal(report.findings[0].kind, 'policy_mesh.mcp_server_missing');
assert.equal(report.findings[0].severity, 'low');
assert.equal(report.findings[0].subject, 'github');
assert.deepEqual(report.findings[0].surfaces, ['root_mcp', 'cursor_mcp']);
Expand All @@ -237,7 +237,7 @@ test('CLI reports MCP server enabled-state drift across surfaces', async () => {
assert.equal(report.rating, 'medium');
assert.equal(report.findingCount, 1);
assert.equal(report.surfaceCount, 2);
assert.equal(report.findings[0].kind, 'mcp_enabled_mismatch');
assert.equal(report.findings[0].kind, 'policy_mesh.mcp_enabled_mismatch');
assert.equal(report.findings[0].severity, 'medium');
assert.equal(report.findings[0].subject, 'github');
assert.deepEqual(report.findings[0].surfaces, ['root_mcp', 'cursor_mcp']);
Expand All @@ -259,7 +259,7 @@ test('CLI reports MCP server environment drift without leaking values', async ()
assert.equal(report.rating, 'medium');
assert.equal(report.findingCount, 1);
assert.equal(report.surfaceCount, 2);
assert.equal(report.findings[0].kind, 'mcp_env_mismatch');
assert.equal(report.findings[0].kind, 'policy_mesh.mcp_env_mismatch');
assert.equal(report.findings[0].severity, 'medium');
assert.equal(report.findings[0].subject, 'github');
assert.deepEqual(report.findings[0].surfaces, ['root_mcp', 'vscode_mcp']);
Expand All @@ -284,7 +284,7 @@ test('CLI reports only differing MCP environment value keys without leaking valu
assert.equal(report.rating, 'medium');
assert.equal(report.findingCount, 1);
assert.equal(report.surfaceCount, 2);
assert.equal(report.findings[0].kind, 'mcp_env_mismatch');
assert.equal(report.findings[0].kind, 'policy_mesh.mcp_env_mismatch');
assert.match(report.findings[0].message, /environment values differ/);
assert.match(report.findings[0].message, /GITHUB_TOKEN/);
assert.doesNotMatch(report.findings[0].message, /SHARED_TIMEOUT/);
Expand All @@ -305,7 +305,7 @@ test('CLI reports MCP server header drift without leaking values', async () => {
assert.equal(report.rating, 'medium');
assert.equal(report.findingCount, 1);
assert.equal(report.surfaceCount, 2);
assert.equal(report.findings[0].kind, 'mcp_header_mismatch');
assert.equal(report.findings[0].kind, 'policy_mesh.mcp_header_mismatch');
assert.equal(report.findings[0].severity, 'medium');
assert.equal(report.findings[0].subject, 'analytics');
assert.deepEqual(report.findings[0].surfaces, ['root_mcp', 'vscode_mcp']);
Expand All @@ -330,7 +330,7 @@ test('CLI reports Codex MCP server command drift against root MCP config', async
assert.equal(report.rating, 'high');
assert.equal(report.findingCount, 1);
assert.equal(report.surfaceCount, 2);
assert.equal(report.findings[0].kind, 'mcp_command_mismatch');
assert.equal(report.findings[0].kind, 'policy_mesh.mcp_command_mismatch');
assert.equal(report.findings[0].subject, 'github');
assert.deepEqual(report.findings[0].surfaces, ['root_mcp', 'codex']);
assert.ok(report.findings[0].locations.some((location) => location.file === '.codex/config.toml' && location.surface === 'codex'));
Expand All @@ -355,7 +355,7 @@ test('CLI does not flag mcp_command_mismatch on neutral -y flag drift between su
const report = JSON.parse(stdout);

const mismatchFindings = report.findings.filter(
(finding) => finding.kind === 'mcp_command_mismatch'
(finding) => finding.kind === 'policy_mesh.mcp_command_mismatch'
);
assert.deepEqual(mismatchFindings, [], 'expected no mcp_command_mismatch findings');
assert.equal(report.surfaceCount, 2);
Expand All @@ -374,7 +374,7 @@ test('CLI reports Codeium plugin MCP command drift against root MCP config', asy
assert.equal(report.rating, 'high');
assert.equal(report.findingCount, 1);
assert.equal(report.surfaceCount, 2);
assert.equal(report.findings[0].kind, 'mcp_command_mismatch');
assert.equal(report.findings[0].kind, 'policy_mesh.mcp_command_mismatch');
assert.equal(report.findings[0].subject, 'github');
assert.deepEqual(report.findings[0].surfaces, ['root_mcp', 'codeium_mcp']);
assert.ok(report.findings[0].locations.some((location) => location.file === '.codeium/mcp_config.json' && location.surface === 'codeium_mcp'));
Expand All @@ -394,7 +394,7 @@ test('CLI reports only differing MCP header value keys without leaking values',
assert.equal(report.rating, 'medium');
assert.equal(report.findingCount, 1);
assert.equal(report.surfaceCount, 2);
assert.equal(report.findings[0].kind, 'mcp_header_mismatch');
assert.equal(report.findings[0].kind, 'policy_mesh.mcp_header_mismatch');
assert.match(report.findings[0].message, /header values differ/);
assert.match(report.findings[0].message, /Authorization/);
assert.doesNotMatch(report.findings[0].message, /X-Org/);
Expand All @@ -415,9 +415,9 @@ test('CLI reports Codex network access alongside unreadable agent surfaces', asy
assert.equal(report.rating, 'high');
assert.equal(report.findingCount, 2);
assert.equal(report.surfaceCount, 2);
assert.equal(report.findings[0].kind, 'config_parse_error');
assert.equal(report.findings[0].kind, 'policy_mesh.config_parse_error');
assert.equal(report.findings[0].file, '.cursor/mcp.json');
assert.equal(report.findings[1].kind, 'codex_network_without_review');
assert.equal(report.findings[1].kind, 'policy_mesh.codex_network_without_review');
assert.equal(report.findings[1].severity, 'medium');
assert.equal(report.findings[1].file, '.codex/config.toml');
assert.equal(report.findings[1].line, 1);
Expand Down