@securecode-ai/mcp 0.5.5 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/types.d.ts +7 -0
- package/dist/approval/auditLog.d.ts +1 -1
- package/dist/approval/auditLog.js +11 -3
- package/dist/approval/auditLog.js.map +1 -1
- package/dist/approval/broker.d.ts +7 -2
- package/dist/approval/broker.js +239 -110
- package/dist/approval/broker.js.map +1 -1
- package/dist/approval/policy.d.ts +10 -0
- package/dist/approval/policy.js +104 -0
- package/dist/approval/policy.js.map +1 -0
- package/dist/approval/types.d.ts +11 -2
- package/dist/approval/types.js +10 -1
- package/dist/approval/types.js.map +1 -1
- package/dist/attack/agentScanExecutor.d.ts +35 -1
- package/dist/attack/agentScanExecutor.js +405 -76
- package/dist/attack/agentScanExecutor.js.map +1 -1
- package/dist/attack/agentScanLoop.d.ts +20 -0
- package/dist/attack/agentScanLoop.js +1264 -60
- package/dist/attack/agentScanLoop.js.map +1 -1
- package/dist/attack/agentScanProtocol.d.ts +382 -6
- package/dist/attack/agentScanProtocol.js +110 -4
- package/dist/attack/agentScanProtocol.js.map +1 -1
- package/dist/attack/agentTrace.d.ts +73 -0
- package/dist/attack/agentTrace.js +228 -0
- package/dist/attack/agentTrace.js.map +1 -0
- package/dist/attack/architectureScoutExecutor.d.ts +18 -0
- package/dist/attack/architectureScoutExecutor.js +211 -0
- package/dist/attack/architectureScoutExecutor.js.map +1 -0
- package/dist/attack/architectureScoutLoop.d.ts +36 -0
- package/dist/attack/architectureScoutLoop.js +403 -0
- package/dist/attack/architectureScoutLoop.js.map +1 -0
- package/dist/attack/architectureScoutProtocol.d.ts +209 -0
- package/dist/attack/architectureScoutProtocol.js +47 -0
- package/dist/attack/architectureScoutProtocol.js.map +1 -0
- package/dist/attack/candidateStore.d.ts +95 -0
- package/dist/attack/candidateStore.js +231 -0
- package/dist/attack/candidateStore.js.map +1 -0
- package/dist/attack/evidenceLedger.d.ts +67 -0
- package/dist/attack/evidenceLedger.js +192 -0
- package/dist/attack/evidenceLedger.js.map +1 -0
- package/dist/attack/finishGate.d.ts +62 -0
- package/dist/attack/finishGate.js +209 -0
- package/dist/attack/finishGate.js.map +1 -0
- package/dist/attack/fixCodeMerge.d.ts +27 -0
- package/dist/attack/fixCodeMerge.js +42 -0
- package/dist/attack/fixCodeMerge.js.map +1 -0
- package/dist/attack/fixVerifyLoop.d.ts +55 -0
- package/dist/attack/fixVerifyLoop.js +187 -0
- package/dist/attack/fixVerifyLoop.js.map +1 -0
- package/dist/attack/investigationProfiles.d.ts +36 -0
- package/dist/attack/investigationProfiles.js +144 -0
- package/dist/attack/investigationProfiles.js.map +1 -0
- package/dist/attack/investigationState.d.ts +227 -0
- package/dist/attack/investigationState.js +666 -0
- package/dist/attack/investigationState.js.map +1 -0
- package/dist/attack/mutationOperators.d.ts +22 -0
- package/dist/attack/mutationOperators.js +170 -0
- package/dist/attack/mutationOperators.js.map +1 -0
- package/dist/attack/mutationTest.d.ts +33 -0
- package/dist/attack/mutationTest.js +110 -0
- package/dist/attack/mutationTest.js.map +1 -0
- package/dist/attack/proofGate.d.ts +20 -0
- package/dist/attack/proofGate.js +104 -0
- package/dist/attack/proofGate.js.map +1 -0
- package/dist/attack/proofTypes.d.ts +57 -0
- package/dist/attack/proofTypes.js +32 -0
- package/dist/attack/proofTypes.js.map +1 -0
- package/dist/attack/protocolValidator.d.ts +50 -0
- package/dist/attack/protocolValidator.js +427 -0
- package/dist/attack/protocolValidator.js.map +1 -0
- package/dist/attack/qualityMetrics.d.ts +133 -0
- package/dist/attack/qualityMetrics.js +226 -0
- package/dist/attack/qualityMetrics.js.map +1 -0
- package/dist/attack/scanScheduler.d.ts +52 -0
- package/dist/attack/scanScheduler.js +265 -0
- package/dist/attack/scanScheduler.js.map +1 -0
- package/dist/attack/scanState.d.ts +58 -0
- package/dist/attack/scanState.js +102 -0
- package/dist/attack/scanState.js.map +1 -0
- package/dist/attack/searchIntent.d.ts +16 -0
- package/dist/attack/searchIntent.js +57 -0
- package/dist/attack/searchIntent.js.map +1 -0
- package/dist/attack/verifyLoop.d.ts +43 -0
- package/dist/attack/verifyLoop.js +314 -14
- package/dist/attack/verifyLoop.js.map +1 -1
- package/dist/attack/workItem.d.ts +57 -0
- package/dist/attack/workItem.js +225 -0
- package/dist/attack/workItem.js.map +1 -0
- package/dist/audit/findingReviewQueue.d.ts +109 -0
- package/dist/audit/findingReviewQueue.js +335 -0
- package/dist/audit/findingReviewQueue.js.map +1 -0
- package/dist/audit/scanAuditLog.d.ts +160 -0
- package/dist/audit/scanAuditLog.js +404 -0
- package/dist/audit/scanAuditLog.js.map +1 -0
- package/dist/dependency/dependencyChecker.js +35 -9
- package/dist/dependency/dependencyChecker.js.map +1 -1
- package/dist/dependency/exploitPriority.d.ts +33 -0
- package/dist/dependency/exploitPriority.js +78 -0
- package/dist/dependency/exploitPriority.js.map +1 -0
- package/dist/dependency/finding.d.ts +16 -0
- package/dist/dependency/osvClient.js +2 -0
- package/dist/dependency/osvClient.js.map +1 -1
- package/dist/dependency/types.d.ts +12 -1
- package/dist/mcp/server.js +13 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +1 -0
- package/dist/mcp/tools.js +127 -6
- package/dist/mcp/tools.js.map +1 -1
- package/dist/project-map/agentMemory.d.ts +83 -1
- package/dist/project-map/agentMemory.js +197 -7
- package/dist/project-map/agentMemory.js.map +1 -1
- package/dist/project-map/architectureContext.d.ts +202 -0
- package/dist/project-map/architectureContext.js +421 -0
- package/dist/project-map/architectureContext.js.map +1 -0
- package/dist/project-map/blastRadius.d.ts +54 -0
- package/dist/project-map/blastRadius.js +196 -0
- package/dist/project-map/blastRadius.js.map +1 -0
- package/dist/project-map/callGraphExtractor.d.ts +13 -0
- package/dist/project-map/callGraphExtractor.js +222 -0
- package/dist/project-map/callGraphExtractor.js.map +1 -0
- package/dist/project-map/capabilityRegistry.d.ts +46 -0
- package/dist/project-map/capabilityRegistry.js +91 -0
- package/dist/project-map/capabilityRegistry.js.map +1 -0
- package/dist/project-map/findTests.d.ts +29 -0
- package/dist/project-map/findTests.js +236 -0
- package/dist/project-map/findTests.js.map +1 -0
- package/dist/project-map/handlerInventory.d.ts +112 -0
- package/dist/project-map/handlerInventory.js +184 -0
- package/dist/project-map/handlerInventory.js.map +1 -0
- package/dist/project-map/implementationResolver.d.ts +43 -0
- package/dist/project-map/implementationResolver.js +217 -0
- package/dist/project-map/implementationResolver.js.map +1 -0
- package/dist/project-map/mapContext.d.ts +6 -1
- package/dist/project-map/mapContext.js +1 -0
- package/dist/project-map/mapContext.js.map +1 -1
- package/dist/project-map/scanCache.d.ts +57 -3
- package/dist/project-map/scanCache.js +61 -2
- package/dist/project-map/scanCache.js.map +1 -1
- package/dist/project-map/symbolIndex.d.ts +39 -0
- package/dist/project-map/symbolIndex.js +385 -0
- package/dist/project-map/symbolIndex.js.map +1 -0
- package/dist/tooling/agentEvalScoring.d.ts +77 -0
- package/dist/tooling/agentEvalScoring.js +140 -0
- package/dist/tooling/agentEvalScoring.js.map +1 -0
- package/dist/tooling/agentRegression.d.ts +53 -0
- package/dist/tooling/agentRegression.js +99 -0
- package/dist/tooling/agentRegression.js.map +1 -0
- package/dist/tools/agentScan.d.ts +69 -0
- package/dist/tools/agentScan.js +702 -43
- package/dist/tools/agentScan.js.map +1 -1
- package/dist/tools/findingReviewTools.d.ts +22 -0
- package/dist/tools/findingReviewTools.js +121 -0
- package/dist/tools/findingReviewTools.js.map +1 -0
- package/dist/tools/fix.js +1 -1
- package/dist/tools/fix.js.map +1 -1
- package/dist/tools/map.js +191 -1
- package/dist/tools/map.js.map +1 -1
- package/dist/tools/runTests.d.ts +2 -0
- package/dist/tools/runTests.js +29 -0
- package/dist/tools/runTests.js.map +1 -0
- package/dist/utils/effectMock.d.ts +1 -0
- package/dist/utils/effectMock.js +162 -0
- package/dist/utils/effectMock.js.map +1 -0
- package/dist/utils/gitContext.d.ts +26 -0
- package/dist/utils/gitContext.js +317 -0
- package/dist/utils/gitContext.js.map +1 -0
- package/dist/utils/localTestRunner.d.ts +57 -2
- package/dist/utils/localTestRunner.js +122 -115
- package/dist/utils/localTestRunner.js.map +1 -1
- package/dist/utils/securityConfig.d.ts +17 -0
- package/dist/utils/securityConfig.js +192 -0
- package/dist/utils/securityConfig.js.map +1 -0
- package/dist/utils/testCommandPolicy.d.ts +36 -0
- package/dist/utils/testCommandPolicy.js +252 -0
- package/dist/utils/testCommandPolicy.js.map +1 -0
- package/dist/utils/testRunner.d.ts +56 -0
- package/dist/utils/testRunner.js +246 -0
- package/dist/utils/testRunner.js.map +1 -0
- package/dist/utils/testSafety.d.ts +40 -2
- package/dist/utils/testSafety.js +205 -26
- package/dist/utils/testSafety.js.map +1 -1
- package/dist/utils/verificationSandbox.d.ts +113 -0
- package/dist/utils/verificationSandbox.js +656 -0
- package/dist/utils/verificationSandbox.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Architecture context — the structured output of the architecture scout
|
|
4
|
+
* subagent and the cached input to later agent-scan runs.
|
|
5
|
+
*
|
|
6
|
+
* The architecture scout is triggered by `securecode.map action:architecture`.
|
|
7
|
+
* It consumes the deterministic project map (endpoints, imports, call graph,
|
|
8
|
+
* config, deps) plus a bounded set of file reads, and produces this context:
|
|
9
|
+
* - project type / frameworks / runtimes / package manager
|
|
10
|
+
* - ranked important files (entrypoints, auth, data, config, security controls)
|
|
11
|
+
* - trust boundaries (where untrusted input enters)
|
|
12
|
+
* - data-flow summaries (source → sink across the architecture)
|
|
13
|
+
* - security controls in place (and what's missing)
|
|
14
|
+
* - architecture-level risks
|
|
15
|
+
* - recommended scan order (which files to scan first)
|
|
16
|
+
*
|
|
17
|
+
* Cache lives at `.securecode/architecture-context.json`. Invalidates when:
|
|
18
|
+
* - the project map is rebuilt (builtAt changes)
|
|
19
|
+
* - the project map schema version changes
|
|
20
|
+
* - the requested depth differs (quick/standard/deep produce different ctx)
|
|
21
|
+
* - ARCHITECTURE_CONTEXT_VERSION bumps (prompt/logic change)
|
|
22
|
+
* - 7-day TTL
|
|
23
|
+
*
|
|
24
|
+
* agent-scan auto-loads a cached architecture context (if present and valid)
|
|
25
|
+
* and passes it into the agent target so the vulnerability investigator starts
|
|
26
|
+
* with project-wide context instead of having to discover it from scratch.
|
|
27
|
+
*/
|
|
28
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
29
|
+
if (k2 === undefined) k2 = k;
|
|
30
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
31
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
32
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
33
|
+
}
|
|
34
|
+
Object.defineProperty(o, k2, desc);
|
|
35
|
+
}) : (function(o, m, k, k2) {
|
|
36
|
+
if (k2 === undefined) k2 = k;
|
|
37
|
+
o[k2] = m[k];
|
|
38
|
+
}));
|
|
39
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
40
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
41
|
+
}) : function(o, v) {
|
|
42
|
+
o["default"] = v;
|
|
43
|
+
});
|
|
44
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
45
|
+
var ownKeys = function(o) {
|
|
46
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
47
|
+
var ar = [];
|
|
48
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
49
|
+
return ar;
|
|
50
|
+
};
|
|
51
|
+
return ownKeys(o);
|
|
52
|
+
};
|
|
53
|
+
return function (mod) {
|
|
54
|
+
if (mod && mod.__esModule) return mod;
|
|
55
|
+
var result = {};
|
|
56
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
57
|
+
__setModuleDefault(result, mod);
|
|
58
|
+
return result;
|
|
59
|
+
};
|
|
60
|
+
})();
|
|
61
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
62
|
+
exports.ARCHITECTURE_CONTEXT_VERSION = void 0;
|
|
63
|
+
exports.readArchitectureCache = readArchitectureCache;
|
|
64
|
+
exports.getCachedArchitectureContext = getCachedArchitectureContext;
|
|
65
|
+
exports.writeCachedArchitectureContext = writeCachedArchitectureContext;
|
|
66
|
+
exports.clearArchitectureCache = clearArchitectureCache;
|
|
67
|
+
exports.formatArchitectureContextForPrompt = formatArchitectureContextForPrompt;
|
|
68
|
+
exports.formatArchitectureRiskTasksForTarget = formatArchitectureRiskTasksForTarget;
|
|
69
|
+
exports.createInvestigationTasksFromRisks = createInvestigationTasksFromRisks;
|
|
70
|
+
const fs = __importStar(require("fs"));
|
|
71
|
+
const path = __importStar(require("path"));
|
|
72
|
+
const CACHE_DIR = '.securecode';
|
|
73
|
+
const CACHE_FILE = 'architecture-context.json';
|
|
74
|
+
/**
|
|
75
|
+
* Bump when the architecture scout prompt or logic changes in a way that
|
|
76
|
+
* would produce a different context for the same project. All cached
|
|
77
|
+
* entries with an older version are invalidated.
|
|
78
|
+
*/
|
|
79
|
+
exports.ARCHITECTURE_CONTEXT_VERSION = 1;
|
|
80
|
+
/** Cache TTL: 7 days. Older entries are re-derived. */
|
|
81
|
+
const CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
82
|
+
// ── Path helpers ────────────────────────────────────────────────────────────
|
|
83
|
+
function cachePath(workspaceRoot) {
|
|
84
|
+
return path.join(workspaceRoot, CACHE_DIR, CACHE_FILE);
|
|
85
|
+
}
|
|
86
|
+
// ── Read / Write ────────────────────────────────────────────────────────────
|
|
87
|
+
/**
|
|
88
|
+
* Read the architecture cache. Returns null if the file doesn't exist,
|
|
89
|
+
* is corrupt, or is a forward-incompatible version.
|
|
90
|
+
*/
|
|
91
|
+
function readArchitectureCache(workspaceRoot) {
|
|
92
|
+
const p = cachePath(workspaceRoot);
|
|
93
|
+
try {
|
|
94
|
+
if (!fs.existsSync(p))
|
|
95
|
+
return null;
|
|
96
|
+
const raw = fs.readFileSync(p, 'utf8');
|
|
97
|
+
const data = JSON.parse(raw);
|
|
98
|
+
if (!data.version || data.version > exports.ARCHITECTURE_CONTEXT_VERSION) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
return data;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Look up a cached architecture context by depth.
|
|
109
|
+
* Returns null if not found, expired, or stale (project map changed).
|
|
110
|
+
*
|
|
111
|
+
* Stale check: the caller passes the CURRENT project map's builtAt + version.
|
|
112
|
+
* If the cached entry was derived against a different map, it's invalid —
|
|
113
|
+
* the architecture may have changed.
|
|
114
|
+
*/
|
|
115
|
+
function getCachedArchitectureContext(workspaceRoot, depth, currentMapBuiltAt, currentMapVersion) {
|
|
116
|
+
const cache = readArchitectureCache(workspaceRoot);
|
|
117
|
+
if (!cache)
|
|
118
|
+
return null;
|
|
119
|
+
const entry = cache.entries[depth];
|
|
120
|
+
if (!entry)
|
|
121
|
+
return null;
|
|
122
|
+
// Version check
|
|
123
|
+
if (entry.context.version !== exports.ARCHITECTURE_CONTEXT_VERSION)
|
|
124
|
+
return null;
|
|
125
|
+
// TTL check
|
|
126
|
+
if (Date.now() - entry.storedAt > CACHE_TTL_MS)
|
|
127
|
+
return null;
|
|
128
|
+
// Project map staleness check — if the map was rebuilt after the context
|
|
129
|
+
// was derived, the context is stale.
|
|
130
|
+
if (entry.context.projectMapBuiltAt !== currentMapBuiltAt)
|
|
131
|
+
return null;
|
|
132
|
+
if (entry.context.projectMapVersion !== currentMapVersion)
|
|
133
|
+
return null;
|
|
134
|
+
return entry.context;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Write an architecture context to the cache, keyed by depth.
|
|
138
|
+
*/
|
|
139
|
+
function writeCachedArchitectureContext(workspaceRoot, context) {
|
|
140
|
+
const dir = path.join(workspaceRoot, CACHE_DIR);
|
|
141
|
+
if (!fs.existsSync(dir)) {
|
|
142
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
143
|
+
}
|
|
144
|
+
let cache;
|
|
145
|
+
const existing = readArchitectureCache(workspaceRoot);
|
|
146
|
+
if (existing && existing.version === exports.ARCHITECTURE_CONTEXT_VERSION) {
|
|
147
|
+
cache = existing;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
cache = { version: exports.ARCHITECTURE_CONTEXT_VERSION, entries: {} };
|
|
151
|
+
}
|
|
152
|
+
// Prune expired entries
|
|
153
|
+
const now = Date.now();
|
|
154
|
+
for (const [k, e] of Object.entries(cache.entries)) {
|
|
155
|
+
if (e && now - e.storedAt > CACHE_TTL_MS) {
|
|
156
|
+
delete cache.entries[k];
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
cache.entries[context.depth] = { context, storedAt: now };
|
|
160
|
+
// Atomic write
|
|
161
|
+
const p = cachePath(workspaceRoot);
|
|
162
|
+
const tmp = p + '.tmp';
|
|
163
|
+
fs.writeFileSync(tmp, JSON.stringify(cache, null, 2), 'utf8');
|
|
164
|
+
fs.renameSync(tmp, p);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Clear the architecture cache for a workspace (e.g., when the user requests
|
|
168
|
+
* a fresh derivation with --no-cache).
|
|
169
|
+
*/
|
|
170
|
+
function clearArchitectureCache(workspaceRoot) {
|
|
171
|
+
const p = cachePath(workspaceRoot);
|
|
172
|
+
try {
|
|
173
|
+
if (fs.existsSync(p))
|
|
174
|
+
fs.unlinkSync(p);
|
|
175
|
+
}
|
|
176
|
+
catch { /* best effort */ }
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Format an architecture context into a compact string for injection into
|
|
180
|
+
* the agent-scan target prompt. Returns empty string if context is empty.
|
|
181
|
+
*
|
|
182
|
+
* This is what the vulnerability investigator sees at the start of a scan —
|
|
183
|
+
* a distilled view of the project's architecture so it doesn't have to
|
|
184
|
+
* re-discover "where is auth?", "what's the data layer?", "what are the
|
|
185
|
+
* entrypoints?" from scratch.
|
|
186
|
+
*/
|
|
187
|
+
function formatArchitectureContextForPrompt(ctx) {
|
|
188
|
+
if (!ctx || !ctx.importantFiles || ctx.importantFiles.length === 0)
|
|
189
|
+
return '';
|
|
190
|
+
const lines = ['Project architecture (from a prior architecture-scout run — use this as context, verify with tools when relevant):'];
|
|
191
|
+
lines.push('');
|
|
192
|
+
lines.push(`Project: ${ctx.project.type}`);
|
|
193
|
+
if (ctx.project.frameworks.length)
|
|
194
|
+
lines.push(`Frameworks: ${ctx.project.frameworks.join(', ')}`);
|
|
195
|
+
if (ctx.project.runtimes.length)
|
|
196
|
+
lines.push(`Runtimes: ${ctx.project.runtimes.join(', ')}`);
|
|
197
|
+
if (ctx.project.packageManager)
|
|
198
|
+
lines.push(`Package manager: ${ctx.project.packageManager}`);
|
|
199
|
+
if (ctx.summary) {
|
|
200
|
+
lines.push('');
|
|
201
|
+
lines.push(`Summary: ${ctx.summary}`);
|
|
202
|
+
}
|
|
203
|
+
lines.push('');
|
|
204
|
+
lines.push(`Important files (${ctx.importantFiles.length}, ranked by security importance):`);
|
|
205
|
+
for (const f of ctx.importantFiles.slice(0, 30)) {
|
|
206
|
+
lines.push(` [${f.importance}] ${f.file} (${f.role}) — ${f.reasons.join('; ')}`);
|
|
207
|
+
}
|
|
208
|
+
if (ctx.importantFiles.length > 30) {
|
|
209
|
+
lines.push(` ... and ${ctx.importantFiles.length - 30} more (see architecture context)`);
|
|
210
|
+
}
|
|
211
|
+
if (ctx.trustBoundaries.length > 0) {
|
|
212
|
+
lines.push('');
|
|
213
|
+
lines.push(`Trust boundaries (${ctx.trustBoundaries.length}):`);
|
|
214
|
+
for (const tb of ctx.trustBoundaries.slice(0, 15)) {
|
|
215
|
+
lines.push(` ${tb.entry} — input: ${tb.inputType} — guard: ${tb.guard || 'NONE'}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (ctx.securityControls.length > 0) {
|
|
219
|
+
lines.push('');
|
|
220
|
+
lines.push(`Security controls (${ctx.securityControls.length}):`);
|
|
221
|
+
for (const sc of ctx.securityControls.slice(0, 15)) {
|
|
222
|
+
lines.push(` [${sc.coverage}] ${sc.kind} at ${sc.location}${sc.notes ? ` — ${sc.notes}` : ''}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (ctx.architectureRisks.length > 0) {
|
|
226
|
+
lines.push('');
|
|
227
|
+
lines.push(`Architecture-level risks (${ctx.architectureRisks.length}) — these are NOT vulnerability findings, they are structural concerns to investigate:`);
|
|
228
|
+
for (const r of ctx.architectureRisks.slice(0, 10)) {
|
|
229
|
+
lines.push(` [${r.severity}] ${r.title}: ${r.description} (${r.files.join(', ')})`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (ctx.recommendedScanOrder.length > 0) {
|
|
233
|
+
lines.push('');
|
|
234
|
+
lines.push(`Recommended scan order (first ${Math.min(10, ctx.recommendedScanOrder.length)}):`);
|
|
235
|
+
for (const f of ctx.recommendedScanOrder.slice(0, 10)) {
|
|
236
|
+
lines.push(` ${f}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return lines.join('\n');
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Extract architecture risks that are relevant to a specific target file and
|
|
243
|
+
* format them as explicit investigation tasks the agent must address.
|
|
244
|
+
*
|
|
245
|
+
* A risk is relevant if:
|
|
246
|
+
* - The target file is listed in the risk's files[]
|
|
247
|
+
* - The target file's path is a substring of any file in the risk's files[]
|
|
248
|
+
* - The risk has no specific files (project-wide)
|
|
249
|
+
*
|
|
250
|
+
* Each task tells the agent:
|
|
251
|
+
* - What the risk is
|
|
252
|
+
* - Which evidence is needed to resolve it
|
|
253
|
+
* - What tool to use
|
|
254
|
+
* - That unresolved risks must go in coverageGaps[]
|
|
255
|
+
*/
|
|
256
|
+
function formatArchitectureRiskTasksForTarget(ctx, targetFilePath) {
|
|
257
|
+
if (!ctx || !ctx.architectureRisks || ctx.architectureRisks.length === 0)
|
|
258
|
+
return '';
|
|
259
|
+
const normalizedTarget = targetFilePath.replace(/\\/g, '/').toLowerCase();
|
|
260
|
+
const relevant = ctx.architectureRisks.filter(r => {
|
|
261
|
+
if (!r.files || r.files.length === 0)
|
|
262
|
+
return true;
|
|
263
|
+
return r.files.some(f => {
|
|
264
|
+
const nf = f.replace(/\\/g, '/').toLowerCase();
|
|
265
|
+
return nf === normalizedTarget ||
|
|
266
|
+
nf.includes(normalizedTarget) ||
|
|
267
|
+
normalizedTarget.includes(nf);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
if (relevant.length === 0)
|
|
271
|
+
return '';
|
|
272
|
+
const lines = [
|
|
273
|
+
`[Architecture risk investigation tasks — you MUST address these before finishing:`,
|
|
274
|
+
` These are structural concerns from the architecture scout that apply to this file.`,
|
|
275
|
+
` For each: investigate, collect evidence, and either resolve (prove safe) or`,
|
|
276
|
+
` report as a finding (if proven) or coverage gap (if unresolved).]`,
|
|
277
|
+
'',
|
|
278
|
+
];
|
|
279
|
+
relevant.forEach((r, i) => {
|
|
280
|
+
lines.push(` Task ${i + 1}: [${r.severity}] ${r.title}`);
|
|
281
|
+
lines.push(` Risk: ${r.description}`);
|
|
282
|
+
if (r.files.length > 0) {
|
|
283
|
+
lines.push(` Files: ${r.files.join(', ')}`);
|
|
284
|
+
}
|
|
285
|
+
lines.push(` Required evidence:`);
|
|
286
|
+
lines.push(` - Trace the code path from input to the sensitive operation`);
|
|
287
|
+
lines.push(` - Determine whether the control is present, bypassed, or missing`);
|
|
288
|
+
lines.push(` - Establish the threat model (is the attacker in scope?)`);
|
|
289
|
+
lines.push(` - If you cannot resolve this risk, put it in coverageGaps[]`);
|
|
290
|
+
lines.push('');
|
|
291
|
+
});
|
|
292
|
+
return lines.join('\n');
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Convert architecture risks relevant to a target file into structured
|
|
296
|
+
* InvestigationTask objects. Each task tracks its own status and must be
|
|
297
|
+
* resolved before the scan finishes.
|
|
298
|
+
*
|
|
299
|
+
* A risk is relevant if:
|
|
300
|
+
* - The target file is listed in the risk's files[]
|
|
301
|
+
* - The target file's path is a substring of any file in the risk's files[]
|
|
302
|
+
* - The risk has no specific files (project-wide)
|
|
303
|
+
*/
|
|
304
|
+
function createInvestigationTasksFromRisks(ctx, targetFilePath) {
|
|
305
|
+
if (!ctx || !ctx.architectureRisks || ctx.architectureRisks.length === 0)
|
|
306
|
+
return [];
|
|
307
|
+
const normalizedTarget = targetFilePath.replace(/\\/g, '/').toLowerCase();
|
|
308
|
+
const allImportantFiles = (ctx.importantFiles || []).map(f => f.file);
|
|
309
|
+
const relevant = ctx.architectureRisks.filter(r => {
|
|
310
|
+
if (!r.files || r.files.length === 0)
|
|
311
|
+
return true;
|
|
312
|
+
return r.files.some(f => {
|
|
313
|
+
const nf = f.replace(/\\/g, '/').toLowerCase();
|
|
314
|
+
if (nf === normalizedTarget || nf.includes(normalizedTarget) || normalizedTarget.includes(nf)) {
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
if (allImportantFiles.some(imp => {
|
|
318
|
+
const impN = imp.replace(/\\/g, '/').toLowerCase();
|
|
319
|
+
return impN === nf && (impN === normalizedTarget || impN.includes(normalizedTarget) || normalizedTarget.includes(impN));
|
|
320
|
+
})) {
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
return false;
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
return relevant.map((r, i) => {
|
|
327
|
+
const id = `arch-risk-${i + 1}-${r.title.toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 40)}`;
|
|
328
|
+
const riskFiles = r.files.length > 0 ? r.files : [targetFilePath];
|
|
329
|
+
const relatedFiles = riskFiles.filter(f => f !== targetFilePath);
|
|
330
|
+
const sourceSymbols = inferSourceSymbols(r);
|
|
331
|
+
const sinkSymbols = inferSinkSymbols(r);
|
|
332
|
+
const proofDimensions = inferProofDimensions(r);
|
|
333
|
+
return {
|
|
334
|
+
id,
|
|
335
|
+
targetFiles: riskFiles,
|
|
336
|
+
claim: r.title,
|
|
337
|
+
requiredTools: inferRequiredTools(r),
|
|
338
|
+
requiredEvidence: [
|
|
339
|
+
'Trace the code path from input to the sensitive operation',
|
|
340
|
+
'Determine whether the control is present, bypassed, or missing',
|
|
341
|
+
'Establish the threat model (is the attacker in scope?)',
|
|
342
|
+
],
|
|
343
|
+
status: 'pending',
|
|
344
|
+
entryFiles: [targetFilePath],
|
|
345
|
+
relatedFiles,
|
|
346
|
+
sourceSymbols,
|
|
347
|
+
sinkSymbols,
|
|
348
|
+
requiredProofDimensions: proofDimensions,
|
|
349
|
+
};
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
function inferSourceSymbols(risk) {
|
|
353
|
+
const text = (risk.title + ' ' + risk.description).toLowerCase();
|
|
354
|
+
const symbols = [];
|
|
355
|
+
if (/shell|exec|spawn|child_process|command/i.test(text)) {
|
|
356
|
+
symbols.push('execFile', 'spawn', 'exec', 'child_process');
|
|
357
|
+
}
|
|
358
|
+
if (/auth|token|session|login|credential/i.test(text)) {
|
|
359
|
+
symbols.push('authenticate', 'authorize', 'verifyToken', 'createSession');
|
|
360
|
+
}
|
|
361
|
+
if (/origin|csrf|cors/i.test(text)) {
|
|
362
|
+
symbols.push('isTrustedAppOrigin', 'shouldRejectUntrustedRequestOrigin');
|
|
363
|
+
}
|
|
364
|
+
if (/mcp|gateway|external/i.test(text)) {
|
|
365
|
+
symbols.push('ExternalMcpGateway', 'connectExternal');
|
|
366
|
+
}
|
|
367
|
+
return symbols;
|
|
368
|
+
}
|
|
369
|
+
function inferSinkSymbols(risk) {
|
|
370
|
+
const text = (risk.title + ' ' + risk.description).toLowerCase();
|
|
371
|
+
const symbols = [];
|
|
372
|
+
if (/shell|exec|spawn|child_process|command/i.test(text)) {
|
|
373
|
+
symbols.push('execFile', 'spawn', 'exec', 'child_process');
|
|
374
|
+
}
|
|
375
|
+
if (/file|write|read|unlink|path/i.test(text)) {
|
|
376
|
+
symbols.push('writeFile', 'readFile', 'unlink', 'mkdir');
|
|
377
|
+
}
|
|
378
|
+
if (/sql|query|database/i.test(text)) {
|
|
379
|
+
symbols.push('query', 'queryRaw', 'execute');
|
|
380
|
+
}
|
|
381
|
+
return symbols;
|
|
382
|
+
}
|
|
383
|
+
function inferProofDimensions(risk) {
|
|
384
|
+
const text = (risk.title + ' ' + risk.description).toLowerCase();
|
|
385
|
+
const dims = ['source', 'reachability', 'control', 'threat-model'];
|
|
386
|
+
if (/shell|exec|spawn|child_process|command/i.test(text)) {
|
|
387
|
+
dims.push('impact');
|
|
388
|
+
dims.push('verification');
|
|
389
|
+
}
|
|
390
|
+
if (/auth|token|session|login|credential|bypass/i.test(text)) {
|
|
391
|
+
dims.push('impact');
|
|
392
|
+
}
|
|
393
|
+
if (/external|mcp|gateway|ssrf/i.test(text)) {
|
|
394
|
+
dims.push('impact');
|
|
395
|
+
}
|
|
396
|
+
return [...new Set(dims)];
|
|
397
|
+
}
|
|
398
|
+
function inferRequiredTools(risk) {
|
|
399
|
+
const tools = [];
|
|
400
|
+
const text = (risk.title + ' ' + risk.description).toLowerCase();
|
|
401
|
+
if (/auth|token|session|login|credential|password|jwt/i.test(text)) {
|
|
402
|
+
tools.push('search_code', 'check_policy', 'read_config');
|
|
403
|
+
}
|
|
404
|
+
if (/flow|taint|cross-file|propagat|input|sink/i.test(text)) {
|
|
405
|
+
tools.push('trace_flow_cross_file', 'trace_flow');
|
|
406
|
+
}
|
|
407
|
+
if (/config|env|secret|key/i.test(text)) {
|
|
408
|
+
tools.push('read_config');
|
|
409
|
+
}
|
|
410
|
+
if (/route|endpoint|handler/i.test(text)) {
|
|
411
|
+
tools.push('get_endpoints', 'check_policy');
|
|
412
|
+
}
|
|
413
|
+
if (/owner|permission|access|rbac|role/i.test(text)) {
|
|
414
|
+
tools.push('search_code', 'check_policy', 'trace_flow_cross_file');
|
|
415
|
+
}
|
|
416
|
+
if (tools.length === 0) {
|
|
417
|
+
tools.push('read_file', 'search_code', 'trace_flow_cross_file');
|
|
418
|
+
}
|
|
419
|
+
return [...new Set(tools)];
|
|
420
|
+
}
|
|
421
|
+
//# sourceMappingURL=architectureContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"architectureContext.js","sourceRoot":"","sources":["../../src/project-map/architectureContext.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blast radius computation — given a set of changed files, compute which
|
|
3
|
+
* other files in the workspace are affected by those changes.
|
|
4
|
+
*
|
|
5
|
+
* Uses the Project Map's import graph (forward: what this file imports;
|
|
6
|
+
* reverse: who imports this file) to traverse the dependency graph to a
|
|
7
|
+
* depth cap. The result is a set of files that the agent scan should focus
|
|
8
|
+
* on, plus the changed files themselves.
|
|
9
|
+
*
|
|
10
|
+
* Algorithm:
|
|
11
|
+
* 1. Invert the Project Map's `imports` records once into a reverse map:
|
|
12
|
+
* for each file F that imports module M, record F as an importer of M.
|
|
13
|
+
* 2. BFS from each changed file:
|
|
14
|
+
* - Forward edges: files that THIS file imports (if F changes, the
|
|
15
|
+
* files F depends on might behave differently — but they're
|
|
16
|
+
* dependencies, not dependents. We skip forward edges for blast
|
|
17
|
+
* radius because changing a file doesn't affect its dependencies.)
|
|
18
|
+
* - Reverse edges: files that import THIS file (if F changes, files
|
|
19
|
+
* that depend on F are affected — these are the blast radius.)
|
|
20
|
+
* 3. Cap depth at `maxDepth` (default 3) to avoid traversing the entire
|
|
21
|
+
* workspace for a large change.
|
|
22
|
+
* 4. Cap total files at `maxFiles` (default 100) to keep the scope
|
|
23
|
+
* manageable.
|
|
24
|
+
*
|
|
25
|
+
* Security:
|
|
26
|
+
* - All file paths come from the Project Map (already workspace-confined)
|
|
27
|
+
* - No filesystem access — pure graph computation
|
|
28
|
+
* - Output is a list of workspace-relative paths
|
|
29
|
+
*/
|
|
30
|
+
import type { ProjectMap } from './types';
|
|
31
|
+
export interface BlastRadiusOptions {
|
|
32
|
+
/** Changed files (workspace-relative paths). */
|
|
33
|
+
changedFiles: string[];
|
|
34
|
+
/** The project map (from cache or freshly built). */
|
|
35
|
+
map: ProjectMap;
|
|
36
|
+
/** Max BFS depth (default 3). */
|
|
37
|
+
maxDepth?: number;
|
|
38
|
+
/** Max total files in the result (default 100). */
|
|
39
|
+
maxFiles?: number;
|
|
40
|
+
}
|
|
41
|
+
export interface BlastRadiusResult {
|
|
42
|
+
/** All files in the blast radius (changed + affected), workspace-relative. */
|
|
43
|
+
files: string[];
|
|
44
|
+
/** Only the changed files that exist in the project map. */
|
|
45
|
+
changedFiles: string[];
|
|
46
|
+
/** Files affected by the changes (not the changed files themselves). */
|
|
47
|
+
affectedFiles: string[];
|
|
48
|
+
/** BFS depth reached (0 = only changed files, 1 = direct importers, etc.). */
|
|
49
|
+
depthReached: number;
|
|
50
|
+
/** Whether the result was truncated by maxFiles. */
|
|
51
|
+
truncated: boolean;
|
|
52
|
+
}
|
|
53
|
+
export declare function computeBlastRadius(options: BlastRadiusOptions): BlastRadiusResult;
|
|
54
|
+
export declare function formatBlastRadius(result: BlastRadiusResult): string;
|