@securecode-ai/mcp 0.6.1 → 0.9.0
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/README.md +32 -3
- package/dist/api/types.d.ts +27 -0
- package/dist/approval/policy.js +7 -2
- package/dist/approval/policy.js.map +1 -1
- package/dist/attack/agentCorroboration.d.ts +14 -0
- package/dist/attack/agentCorroboration.js +98 -0
- package/dist/attack/agentCorroboration.js.map +1 -0
- package/dist/attack/agentLoop.js +9 -6
- package/dist/attack/agentLoop.js.map +1 -1
- package/dist/attack/agentScanBatchProtocol.d.ts +1 -1
- package/dist/attack/agentScanBatchProtocol.js.map +1 -1
- package/dist/attack/agentScanExecutor.d.ts +6 -2
- package/dist/attack/agentScanExecutor.js +62 -21
- package/dist/attack/agentScanExecutor.js.map +1 -1
- package/dist/attack/agentScanLoop.js +265 -151
- package/dist/attack/agentScanLoop.js.map +1 -1
- package/dist/attack/agentScanProtocol.d.ts +14 -5
- package/dist/attack/agentScanProtocol.js.map +1 -1
- package/dist/attack/architectureScoutLoop.js +1 -1
- package/dist/attack/architectureScoutLoop.js.map +1 -1
- package/dist/attack/investigationState.d.ts +32 -4
- package/dist/attack/investigationState.js +98 -10
- package/dist/attack/investigationState.js.map +1 -1
- package/dist/attack/llmHealth.d.ts +53 -0
- package/dist/attack/llmHealth.js +100 -0
- package/dist/attack/llmHealth.js.map +1 -0
- package/dist/attack/observationLimits.d.ts +12 -0
- package/dist/attack/observationLimits.js +16 -0
- package/dist/attack/observationLimits.js.map +1 -0
- package/dist/attack/policy.d.ts +1 -0
- package/dist/attack/policy.js +1 -0
- package/dist/attack/policy.js.map +1 -1
- package/dist/attack/probeRules.d.ts +51 -0
- package/dist/attack/probeRules.js +291 -0
- package/dist/attack/probeRules.js.map +1 -0
- package/dist/attack/protocol.d.ts +16 -0
- package/dist/attack/qualityMetrics.js +3 -0
- package/dist/attack/qualityMetrics.js.map +1 -1
- package/dist/attack/report.d.ts +3 -1
- package/dist/attack/report.js +4 -2
- package/dist/attack/report.js.map +1 -1
- package/dist/attack/runtimeProbe.d.ts +71 -0
- package/dist/attack/runtimeProbe.js +300 -0
- package/dist/attack/runtimeProbe.js.map +1 -0
- package/dist/attack/scanScheduler.d.ts +7 -0
- package/dist/attack/scanScheduler.js +58 -33
- package/dist/attack/scanScheduler.js.map +1 -1
- package/dist/attack/scanState.d.ts +1 -1
- package/dist/attack/scanState.js.map +1 -1
- package/dist/audit/findingReviewQueue.d.ts +1 -1
- package/dist/audit/findingReviewQueue.js.map +1 -1
- package/dist/auth/credentialStore.js +1 -1
- package/dist/auth/credentialStore.js.map +1 -1
- package/dist/auth/keychain.js +80 -80
- package/dist/auth/keychain.js.map +1 -1
- package/dist/mcp/server.js +5 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.js +8 -9
- package/dist/mcp/tools.js.map +1 -1
- package/dist/project-map/architectureContext.d.ts +1 -1
- package/dist/project-map/architectureContext.js +1 -1
- package/dist/project-map/scanCache.d.ts +6 -1
- package/dist/project-map/scanCache.js +6 -1
- package/dist/project-map/scanCache.js.map +1 -1
- package/dist/tools/agentScan.d.ts +9 -1
- package/dist/tools/agentScan.js +160 -7
- package/dist/tools/agentScan.js.map +1 -1
- package/dist/tools/agentScanBatch.js +7 -1
- package/dist/tools/agentScanBatch.js.map +1 -1
- package/dist/tools/attack.js +1 -1
- package/dist/tools/attack.js.map +1 -1
- package/dist/tools/map.js +1 -1
- package/dist/utils/verificationSandbox.js +43 -2
- package/dist/utils/verificationSandbox.js.map +1 -1
- package/package.json +62 -62
package/README.md
CHANGED
|
@@ -117,14 +117,14 @@ claude mcp add securecode -s user -- securecode-mcp serve --workspace /path/to/y
|
|
|
117
117
|
|
|
118
118
|
| Tool | Description | Approval |
|
|
119
119
|
|------|-------------|----------|
|
|
120
|
-
| `securecode.
|
|
120
|
+
| `securecode.architecture` | Run the AI architecture scout: ranked important files, trust boundaries, security controls, recommended scan order (uses AI credits, cached per depth) | No |
|
|
121
121
|
|
|
122
122
|
### Fixes & Testing
|
|
123
123
|
|
|
124
124
|
| Tool | Description | Approval |
|
|
125
125
|
|------|-------------|----------|
|
|
126
126
|
| `securecode.fix` | Generate a patch for a specific finding | Yes |
|
|
127
|
-
| `securecode.attack` | Endpoint red-team testing (beta) | Yes |
|
|
127
|
+
| `securecode.attack` | Endpoint red-team testing (beta) with deterministic corroboration — findings arrive confirmed/refuted with rule citations, not just "suspected" | Yes |
|
|
128
128
|
| `securecode.run-tests` | Run tests in sandbox for verification | Yes |
|
|
129
129
|
|
|
130
130
|
### Agent Memory (FP Learning)
|
|
@@ -167,7 +167,8 @@ The agent scan (`securecode.agent-scan`) is an AI security investigator that:
|
|
|
167
167
|
6. **Self-critiques** before reporting (selfCritique field)
|
|
168
168
|
7. **Gets reviewed** by an independent critique LLM
|
|
169
169
|
8. **Proves** findings in a sandbox (PROVEN/UNPROVEN)
|
|
170
|
-
9. **
|
|
170
|
+
9. **Runtime-verifies** HTTP findings the sandbox can't reach — with your approval, executes baseline + attack requests against your local dev server to confirm real-world impact
|
|
171
|
+
10. **Generates fixes** for proven findings
|
|
171
172
|
|
|
172
173
|
Agent tools (20+): `read_file`, `search_code`, `trace_flow`, `trace_flow_cross_file`, `check_guard`, `check_policy`, `get_endpoints`, `list_imports`, `list_files`, `call_graph`, `git_blame`, `git_history`, `git_diff`, `check_dependencies`, `read_config`, `find_definition`, `find_references`, `find_tests`, `run_tests`, `finish`.
|
|
173
174
|
|
|
@@ -179,6 +180,32 @@ The deterministic control plane enforces proof quality:
|
|
|
179
180
|
|
|
180
181
|
Languages: JavaScript, TypeScript, Python (partial).
|
|
181
182
|
|
|
183
|
+
## Runtime Verification
|
|
184
|
+
|
|
185
|
+
Some findings can't be proven in a sandbox — auth bypasses, runtime-dependent behavior, effects that only manifest in a live server. When an agent scan produces an HTTP-shaped finding that the sandbox couldn't prove, SecureCode can verify it against your **local dev server**:
|
|
186
|
+
|
|
187
|
+
1. The agent generates a minimal probe plan (a baseline request + attack requests) grounded in its attack library
|
|
188
|
+
2. You approve the probe once per scan (60-second approval window — silently skipped if you don't respond)
|
|
189
|
+
3. SecureCode executes the plan against `127.0.0.1:<port>` and maps the outcome to a deterministic verdict
|
|
190
|
+
|
|
191
|
+
Confirmed probes upgrade the finding to **impact-confirmed** with live response evidence.
|
|
192
|
+
|
|
193
|
+
**Safety rails:**
|
|
194
|
+
- Localhost only — no external traffic, ever
|
|
195
|
+
- Unauthenticated endpoints only; auth headers (`Authorization`, cookies, API keys) are stripped from generated plans
|
|
196
|
+
- Relative paths only, whitelisted methods, read-only payloads
|
|
197
|
+
- Max 8 requests per finding, max 3 probed findings per scan (severity-ordered)
|
|
198
|
+
- Plan credits are refunded if no probe can run
|
|
199
|
+
|
|
200
|
+
**Dev server discovery** (first match wins):
|
|
201
|
+
1. `SECURECODE_DEV_SERVER_PORT` environment variable
|
|
202
|
+
2. `.securecode/runtime-probe.json` in the workspace root: `{ "port": 3000 }`
|
|
203
|
+
3. Auto-detect across common dev ports (3000, 3001, 4000, 5173, 5174, 8000, 8080)
|
|
204
|
+
|
|
205
|
+
Disable entirely with `SECURECODE_DISABLE_RUNTIME_PROBE=1`.
|
|
206
|
+
|
|
207
|
+
> Note: probes currently fire for findings on endpoints the project map can detect (Express/Fastify-style routes). Support for other frameworks is on the roadmap.
|
|
208
|
+
|
|
182
209
|
## Environment Variables
|
|
183
210
|
|
|
184
211
|
| Variable | Default | Description |
|
|
@@ -186,6 +213,8 @@ Languages: JavaScript, TypeScript, Python (partial).
|
|
|
186
213
|
| `SECURECODE_API_TOKEN` | — | API token (alternative to login) |
|
|
187
214
|
| `SECURECODE_API_URL` | `https://api.usesecurecode.tech` | API base URL |
|
|
188
215
|
| `SECURECODE_ATTACK_ENABLED` | — | Set to `1` to enable the attack tool |
|
|
216
|
+
| `SECURECODE_DEV_SERVER_PORT` | auto | Local dev server port for runtime verification |
|
|
217
|
+
| `SECURECODE_DISABLE_RUNTIME_PROBE` | — | Set to `1` to disable runtime verification probes |
|
|
189
218
|
|
|
190
219
|
## Security
|
|
191
220
|
|
package/dist/api/types.d.ts
CHANGED
|
@@ -230,3 +230,30 @@ export interface VerifyAnalyzeResponse {
|
|
|
230
230
|
/** Dollar cost the API charged for this analyze call (credits → USD). */
|
|
231
231
|
costUsd?: number;
|
|
232
232
|
}
|
|
233
|
+
export interface VerifyProbePlanRequest {
|
|
234
|
+
finding: {
|
|
235
|
+
type: string;
|
|
236
|
+
line: number;
|
|
237
|
+
lineEnd?: number;
|
|
238
|
+
evidence: string;
|
|
239
|
+
why: string;
|
|
240
|
+
severity: string;
|
|
241
|
+
};
|
|
242
|
+
endpoint: {
|
|
243
|
+
method: string;
|
|
244
|
+
path: string;
|
|
245
|
+
mountedPath?: string;
|
|
246
|
+
params?: unknown[];
|
|
247
|
+
authScheme?: string;
|
|
248
|
+
middleware?: unknown[];
|
|
249
|
+
};
|
|
250
|
+
framework?: string;
|
|
251
|
+
devServerPort?: number;
|
|
252
|
+
}
|
|
253
|
+
export interface VerifyProbePlanResponse {
|
|
254
|
+
canProbe: boolean;
|
|
255
|
+
skipReason?: string;
|
|
256
|
+
plan: import('../attack/runtimeProbe').ProbePlan | null;
|
|
257
|
+
costUsd: number;
|
|
258
|
+
scanCredits: number;
|
|
259
|
+
}
|
package/dist/approval/policy.js
CHANGED
|
@@ -9,8 +9,8 @@ exports.TOOL_POLICIES = {
|
|
|
9
9
|
category: 'read-only',
|
|
10
10
|
requiresApproval: false,
|
|
11
11
|
},
|
|
12
|
-
'securecode.
|
|
13
|
-
name: 'securecode.
|
|
12
|
+
'securecode.architecture': {
|
|
13
|
+
name: 'securecode.architecture',
|
|
14
14
|
category: 'read-only',
|
|
15
15
|
requiresApproval: false,
|
|
16
16
|
},
|
|
@@ -93,6 +93,11 @@ exports.TOOL_POLICIES = {
|
|
|
93
93
|
requiresApproval: true,
|
|
94
94
|
approvalNote: 'Attack sends HTTP probes to a localhost server. Approval required. Currently disabled via SECURECODE_ATTACK_ENABLED.',
|
|
95
95
|
},
|
|
96
|
+
'securecode.runtime-probe': {
|
|
97
|
+
name: 'securecode.runtime-probe',
|
|
98
|
+
category: 'paid-generation',
|
|
99
|
+
requiresApproval: true,
|
|
100
|
+
},
|
|
96
101
|
};
|
|
97
102
|
function getToolPolicy(toolName) {
|
|
98
103
|
return exports.TOOL_POLICIES[toolName];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/approval/policy.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/approval/policy.ts"],"names":[],"mappings":";;;AA0GA,sCAEC;AAED,oEAQC;AA7GY,QAAA,aAAa,GAA+B;IACrD,iBAAiB,EAAE;QACf,IAAI,EAAE,iBAAiB;QACvB,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;KAC1B;IACD,yBAAyB,EAAE;QACvB,IAAI,EAAE,yBAAyB;QAC/B,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;KAC1B;IACD,8BAA8B,EAAE;QAC5B,IAAI,EAAE,8BAA8B;QACpC,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;KAC1B;IACD,uBAAuB,EAAE;QACrB,IAAI,EAAE,uBAAuB;QAC7B,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;KAC1B;IACD,yBAAyB,EAAE;QACvB,IAAI,EAAE,yBAAyB;QAC/B,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;KAC1B;IACD,uBAAuB,EAAE;QACrB,IAAI,EAAE,uBAAuB;QAC7B,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;QACvB,YAAY,EAAE,2GAA2G;KAC5H;IACD,6BAA6B,EAAE;QAC3B,IAAI,EAAE,6BAA6B;QACnC,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;KAC1B;IACD,kCAAkC,EAAE;QAChC,IAAI,EAAE,kCAAkC;QACxC,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;KAC1B;IACD,6BAA6B,EAAE;QAC3B,IAAI,EAAE,6BAA6B;QACnC,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;KAC1B;IACD,+BAA+B,EAAE;QAC7B,IAAI,EAAE,+BAA+B;QACrC,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;KAC1B;IACD,2BAA2B,EAAE;QACzB,IAAI,EAAE,2BAA2B;QACjC,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;KAC1B;IACD,4BAA4B,EAAE;QAC1B,IAAI,EAAE,4BAA4B;QAClC,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;KAC1B;IACD,2BAA2B,EAAE;QACzB,IAAI,EAAE,2BAA2B;QACjC,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;KAC1B;IACD,kCAAkC,EAAE;QAChC,IAAI,EAAE,kCAAkC;QACxC,QAAQ,EAAE,WAAW;QACrB,gBAAgB,EAAE,KAAK;KAC1B;IACD,gBAAgB,EAAE;QACd,IAAI,EAAE,gBAAgB;QACtB,QAAQ,EAAE,iBAAiB;QAC3B,gBAAgB,EAAE,IAAI;QACtB,YAAY,EAAE,0GAA0G;KAC3H;IACD,sBAAsB,EAAE;QACpB,IAAI,EAAE,sBAAsB;QAC5B,QAAQ,EAAE,iBAAiB;QAC3B,gBAAgB,EAAE,IAAI;QACtB,YAAY,EAAE,4EAA4E;KAC7F;IACD,mBAAmB,EAAE;QACjB,IAAI,EAAE,mBAAmB;QACzB,QAAQ,EAAE,iBAAiB;QAC3B,gBAAgB,EAAE,IAAI;QACtB,YAAY,EAAE,sHAAsH;KACvI;IACD,0BAA0B,EAAE;QACxB,IAAI,EAAE,0BAA0B;QAChC,QAAQ,EAAE,iBAAiB;QAC3B,gBAAgB,EAAE,IAAI;KACzB;CACJ,CAAC;AAEF,SAAgB,aAAa,CAAC,QAAgB;IAC1C,OAAO,qBAAa,CAAC,QAAQ,CAAC,CAAC;AACnC,CAAC;AAED,SAAgB,4BAA4B,CAAC,eAAyB;IAClE,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;QACjC,IAAI,CAAC,qBAAa,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;IACL,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic finding corroboration — port of api/src/attacker/agentCorroboration.ts.
|
|
3
|
+
*
|
|
4
|
+
* assembleAgentFindings maps a finish action's findings onto the transcript and
|
|
5
|
+
* stamps each one via the full deterministic probe rules (probeRules.ts): a
|
|
6
|
+
* finding is only 'confirmed' when its cited step's observation satisfies the
|
|
7
|
+
* action's declared expect. corroborateStep keeps the API's per-step seam but
|
|
8
|
+
* is strengthened from the API's minimal rule-0 check to the full rule set.
|
|
9
|
+
*/
|
|
10
|
+
import type { AgentFinding, AgentTranscriptStep } from './protocol';
|
|
11
|
+
import { type ProbeRuleRequest, type ProbeRuleResponse, type ProbeRuleResult } from './probeRules';
|
|
12
|
+
import { type ReportedAgentFinding } from './report';
|
|
13
|
+
export declare function corroborateStep(attackReq: ProbeRuleRequest, attackResp: ProbeRuleResponse | null, baselineReq?: ProbeRuleRequest | null, baselineResp?: ProbeRuleResponse | null): ProbeRuleResult;
|
|
14
|
+
export declare function assembleAgentFindings(findings: AgentFinding[], transcript: AgentTranscriptStep[]): ReportedAgentFinding[];
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic finding corroboration — port of api/src/attacker/agentCorroboration.ts.
|
|
4
|
+
*
|
|
5
|
+
* assembleAgentFindings maps a finish action's findings onto the transcript and
|
|
6
|
+
* stamps each one via the full deterministic probe rules (probeRules.ts): a
|
|
7
|
+
* finding is only 'confirmed' when its cited step's observation satisfies the
|
|
8
|
+
* action's declared expect. corroborateStep keeps the API's per-step seam but
|
|
9
|
+
* is strengthened from the API's minimal rule-0 check to the full rule set.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.corroborateStep = corroborateStep;
|
|
13
|
+
exports.assembleAgentFindings = assembleAgentFindings;
|
|
14
|
+
const probeRules_1 = require("./probeRules");
|
|
15
|
+
const report_1 = require("./report");
|
|
16
|
+
const REFUTED_NOTE = 'Probe rules refuted the cited step — needs review';
|
|
17
|
+
function toRuleRequest(action) {
|
|
18
|
+
return {
|
|
19
|
+
method: action.method,
|
|
20
|
+
path: action.path,
|
|
21
|
+
headers: action.headers,
|
|
22
|
+
body: action.body,
|
|
23
|
+
successStatus: action.expect?.successStatus,
|
|
24
|
+
successBodyPattern: action.expect?.successBodyPattern,
|
|
25
|
+
successHeaders: action.expect?.successHeaders,
|
|
26
|
+
successLatencyMs: action.expect?.successLatencyMs,
|
|
27
|
+
successConfirmedBy: action.expect?.successConfirmedBy,
|
|
28
|
+
successEvidenceNeeded: action.expect?.successEvidenceNeeded,
|
|
29
|
+
expectedStatus: action.expect?.expectedStatus,
|
|
30
|
+
authRequired: action.expect?.authRequired,
|
|
31
|
+
authEnvVars: action.expect?.authEnvVars,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function toRuleResponse(observation) {
|
|
35
|
+
return {
|
|
36
|
+
statusCode: observation.statusCode,
|
|
37
|
+
headers: observation.headers,
|
|
38
|
+
body: observation.body,
|
|
39
|
+
latencyMs: observation.latencyMs,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function corroborateStep(attackReq, attackResp, baselineReq = null, baselineResp = null) {
|
|
43
|
+
return (0, probeRules_1.applyProbeRules)(attackReq, attackResp, baselineReq, baselineResp);
|
|
44
|
+
}
|
|
45
|
+
function baselinePair(evidenceStepIndex, transcript) {
|
|
46
|
+
if (evidenceStepIndex <= 0)
|
|
47
|
+
return null;
|
|
48
|
+
const first = transcript[0];
|
|
49
|
+
if (!first)
|
|
50
|
+
return null;
|
|
51
|
+
return {
|
|
52
|
+
req: toRuleRequest(first.action),
|
|
53
|
+
resp: first.observation.error ? null : toRuleResponse(first.observation),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function assembleAgentFindings(findings, transcript) {
|
|
57
|
+
return findings.map((finding) => {
|
|
58
|
+
const step = transcript[finding.evidenceStepIndex];
|
|
59
|
+
if (!step) {
|
|
60
|
+
return {
|
|
61
|
+
...finding,
|
|
62
|
+
confirmation: 'suspected',
|
|
63
|
+
reason: `Evidence step ${finding.evidenceStepIndex} missing`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (!step.action.expect) {
|
|
67
|
+
return {
|
|
68
|
+
...finding,
|
|
69
|
+
confirmation: 'suspected',
|
|
70
|
+
reason: report_1.SUSPECTED_FINDING_REASON,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const baseline = baselinePair(finding.evidenceStepIndex, transcript);
|
|
74
|
+
const result = corroborateStep(toRuleRequest(step.action), step.observation.error ? null : toRuleResponse(step.observation), baseline?.req ?? null, baseline?.resp ?? null);
|
|
75
|
+
if (result.verdict === 'confirmed-bypass') {
|
|
76
|
+
return {
|
|
77
|
+
...finding,
|
|
78
|
+
confirmation: 'confirmed',
|
|
79
|
+
rule: result.rule,
|
|
80
|
+
reason: result.reason,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
if (result.verdict === 'refuted') {
|
|
84
|
+
return {
|
|
85
|
+
...finding,
|
|
86
|
+
confirmation: 'suspected',
|
|
87
|
+
rule: result.rule,
|
|
88
|
+
reason: REFUTED_NOTE,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
...finding,
|
|
93
|
+
confirmation: 'suspected',
|
|
94
|
+
reason: report_1.SUSPECTED_FINDING_REASON,
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=agentCorroboration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentCorroboration.js","sourceRoot":"","sources":["../../src/attack/agentCorroboration.ts"],"names":[],"mappings":"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"}
|
package/dist/attack/agentLoop.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.runAttack = runAttack;
|
|
4
4
|
const client_1 = require("../api/client");
|
|
5
|
+
const agentCorroboration_1 = require("./agentCorroboration");
|
|
5
6
|
const executor_1 = require("./executor");
|
|
6
7
|
const policy_1 = require("./policy");
|
|
7
8
|
const report_1 = require("./report");
|
|
@@ -72,18 +73,19 @@ async function runAttack(ctx, endpoint, code, language, options) {
|
|
|
72
73
|
runtimeConfirmed: false,
|
|
73
74
|
};
|
|
74
75
|
const transcript = [];
|
|
76
|
+
let costSpentUsd = 0;
|
|
75
77
|
while (true) {
|
|
76
78
|
const budgetCheck = (0, policy_1.checkBudget)(budget, state);
|
|
77
79
|
if (budgetCheck.exhausted) {
|
|
78
80
|
return {
|
|
79
81
|
status: 'capped',
|
|
80
|
-
report: (0, report_1.buildReport)('capped', [], transcript, stepsTaken,
|
|
82
|
+
report: (0, report_1.buildReport)('capped', [], transcript, stepsTaken, costSpentUsd, budgetCheck.reason),
|
|
81
83
|
};
|
|
82
84
|
}
|
|
83
85
|
if (options.signal?.aborted) {
|
|
84
86
|
return {
|
|
85
87
|
status: 'cancelled',
|
|
86
|
-
report: (0, report_1.buildReport)('cancelled', [], transcript, stepsTaken,
|
|
88
|
+
report: (0, report_1.buildReport)('cancelled', [], transcript, stepsTaken, costSpentUsd, 'Cancelled by user'),
|
|
87
89
|
};
|
|
88
90
|
}
|
|
89
91
|
const stepResp = await client.postJson('/attack/agent/step', {
|
|
@@ -94,14 +96,15 @@ async function runAttack(ctx, endpoint, code, language, options) {
|
|
|
94
96
|
transcript,
|
|
95
97
|
budget: {
|
|
96
98
|
stepsRemaining: budget.maxSteps - stepsTaken,
|
|
97
|
-
costSpentUsd
|
|
98
|
-
costCapUsd:
|
|
99
|
+
costSpentUsd,
|
|
100
|
+
costCapUsd: budget.costCapUsd,
|
|
99
101
|
},
|
|
100
102
|
});
|
|
103
|
+
costSpentUsd += stepResp.costUsd || 0;
|
|
101
104
|
if (!stepResp.next) {
|
|
102
105
|
return {
|
|
103
106
|
status: stepResp.costCapped ? 'capped' : (stepResp.degraded ? 'degraded' : 'completed'),
|
|
104
|
-
report: (0, report_1.buildReport)(stepResp.costCapped ? 'capped' : 'completed', [], transcript, stepsTaken,
|
|
107
|
+
report: (0, report_1.buildReport)(stepResp.costCapped ? 'capped' : 'completed', [], transcript, stepsTaken, costSpentUsd),
|
|
105
108
|
};
|
|
106
109
|
}
|
|
107
110
|
const action = stepResp.next;
|
|
@@ -110,7 +113,7 @@ async function runAttack(ctx, endpoint, code, language, options) {
|
|
|
110
113
|
if (action.type === 'finish') {
|
|
111
114
|
return {
|
|
112
115
|
status: 'completed',
|
|
113
|
-
report: (0, report_1.buildReport)('completed', action.findings || [], transcript, stepsTaken, stepResp.costUsd || 0, action.summary),
|
|
116
|
+
report: (0, report_1.buildReport)('completed', (0, agentCorroboration_1.assembleAgentFindings)(action.findings || [], transcript), transcript, stepsTaken, stepResp.costUsd || 0, action.summary),
|
|
114
117
|
};
|
|
115
118
|
}
|
|
116
119
|
if (action.type === 'http_request') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentLoop.js","sourceRoot":"","sources":["../../src/attack/agentLoop.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"agentLoop.js","sourceRoot":"","sources":["../../src/attack/agentLoop.ts"],"names":[],"mappings":"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"}
|
|
@@ -54,7 +54,7 @@ export interface AgentScanBatchFileResult {
|
|
|
54
54
|
costSpentUsd: number;
|
|
55
55
|
error?: AgentScanBatchFileError;
|
|
56
56
|
}
|
|
57
|
-
export type AgentScanBatchStopReason = 'completed' | 'architecture-failed' | 'architecture-incomplete' | 'insufficient-credits' | 'scan-incomplete' | 'scan-failed' | 'cancelled';
|
|
57
|
+
export type AgentScanBatchStopReason = 'completed' | 'architecture-failed' | 'architecture-incomplete' | 'insufficient-credits' | 'scan-incomplete' | 'scan-failed' | 'llm-degraded' | 'cancelled';
|
|
58
58
|
export interface AgentScanBatchResult {
|
|
59
59
|
status: 'completed' | 'incomplete' | 'failed' | 'preflight-failed' | 'cancelled';
|
|
60
60
|
stopReason: AgentScanBatchStopReason;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentScanBatchProtocol.js","sourceRoot":"","sources":["../../src/attack/agentScanBatchProtocol.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;
|
|
1
|
+
{"version":3,"file":"agentScanBatchProtocol.js","sourceRoot":"","sources":["../../src/attack/agentScanBatchProtocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
import { ApiClient } from '../api/client';
|
|
10
10
|
import type { ServerContext } from '../mcp/types';
|
|
11
11
|
import type { AgentScanAction, AgentScanTarget, ReadFileObservation, StructuredFlowResult } from './agentScanProtocol';
|
|
12
|
-
export
|
|
13
|
-
export declare const LARGE_FILE_THRESHOLD = 300;
|
|
12
|
+
export { MAX_OBSERVATION_CHARS, LARGE_FILE_THRESHOLD } from './observationLimits';
|
|
14
13
|
export declare function truncate(text: string): string;
|
|
15
14
|
export declare function redact(text: string): string;
|
|
16
15
|
export declare function extractFunctionMap(content: string, relPath: string): Promise<string | null>;
|
|
@@ -36,6 +35,11 @@ export declare function extractFunctionBoundaries(content: string, relPath: stri
|
|
|
36
35
|
* and actualStart/actualEnd are 0 (no content lines delivered).
|
|
37
36
|
* 3. Small file with no startLine/endLine → full content returned,
|
|
38
37
|
* actualStart=1, actualEnd=totalLines, truncated=false.
|
|
38
|
+
* 4. Range (or small file) whose rendered content exceeds MAX_OBSERVATION_CHARS
|
|
39
|
+
* → the observation is cut at the last complete line that fits.
|
|
40
|
+
* `truncated === true` and actualEnd is the last DELIVERED line, not the
|
|
41
|
+
* requested end; the observation ends with a re-read note naming the
|
|
42
|
+
* undelivered remainder.
|
|
39
43
|
*/
|
|
40
44
|
export declare function executeReadFileAction(action: AgentScanAction, ctx: ServerContext): Promise<ReadFileObservation>;
|
|
41
45
|
export declare function executeAction(action: AgentScanAction, ctx: ServerContext, runId: string, client: ApiClient, target: AgentScanTarget): Promise<string>;
|
|
@@ -69,12 +69,53 @@ const symbolIndex_1 = require("../project-map/symbolIndex");
|
|
|
69
69
|
const findTests_1 = require("../project-map/findTests");
|
|
70
70
|
const testRunner_1 = require("../utils/testRunner");
|
|
71
71
|
const protocolValidator_1 = require("./protocolValidator");
|
|
72
|
-
|
|
73
|
-
exports.
|
|
72
|
+
var observationLimits_1 = require("./observationLimits");
|
|
73
|
+
Object.defineProperty(exports, "MAX_OBSERVATION_CHARS", { enumerable: true, get: function () { return observationLimits_1.MAX_OBSERVATION_CHARS; } });
|
|
74
|
+
Object.defineProperty(exports, "LARGE_FILE_THRESHOLD", { enumerable: true, get: function () { return observationLimits_1.LARGE_FILE_THRESHOLD; } });
|
|
75
|
+
const observationLimits_2 = require("./observationLimits");
|
|
74
76
|
function truncate(text) {
|
|
75
|
-
if (text.length <=
|
|
77
|
+
if (text.length <= observationLimits_2.MAX_OBSERVATION_CHARS)
|
|
76
78
|
return text;
|
|
77
|
-
return text.slice(0,
|
|
79
|
+
return text.slice(0, observationLimits_2.MAX_OBSERVATION_CHARS) + '\n… [truncated]';
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Render a numbered read observation that fits under MAX_OBSERVATION_CHARS,
|
|
83
|
+
* returning the last line actually delivered.
|
|
84
|
+
*
|
|
85
|
+
* When the requested range exceeds the char cap, the observation is cut at
|
|
86
|
+
* the last complete line that fits and ends with an explicit re-read note
|
|
87
|
+
* naming the undelivered remainder. The loop records coverage for the
|
|
88
|
+
* delivered range only (actualStart..deliveredEnd), so the cut-off tail
|
|
89
|
+
* stays re-readable instead of being silently marked as covered.
|
|
90
|
+
*/
|
|
91
|
+
function renderNumberedRead(header, allLines, start, end) {
|
|
92
|
+
// Reserve room for the re-read note appended when the range is cut.
|
|
93
|
+
const budget = observationLimits_2.MAX_OBSERVATION_CHARS - 120;
|
|
94
|
+
const parts = [];
|
|
95
|
+
let used = header.length + 2;
|
|
96
|
+
let deliveredEnd = start - 1;
|
|
97
|
+
let truncated = false;
|
|
98
|
+
for (let line = start; line <= end; line++) {
|
|
99
|
+
const rendered = `${line}: ${(0, report_1.redactText)(allLines[line - 1])}`;
|
|
100
|
+
const cost = rendered.length + (parts.length > 0 ? 1 : 0);
|
|
101
|
+
if (parts.length > 0 && used + cost > budget) {
|
|
102
|
+
truncated = true;
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
parts.push(rendered);
|
|
106
|
+
used += cost;
|
|
107
|
+
deliveredEnd = line;
|
|
108
|
+
}
|
|
109
|
+
let observation = `${header}\n\n${parts.join('\n')}`;
|
|
110
|
+
if (truncated && deliveredEnd < end) {
|
|
111
|
+
observation += `\n\n[truncated at line ${deliveredEnd} — re-read lines ${deliveredEnd + 1}..${end} for the rest]`;
|
|
112
|
+
}
|
|
113
|
+
// Safety net for pathological single lines longer than the whole cap.
|
|
114
|
+
if (observation.length > observationLimits_2.MAX_OBSERVATION_CHARS) {
|
|
115
|
+
observation = truncate(observation);
|
|
116
|
+
truncated = true;
|
|
117
|
+
}
|
|
118
|
+
return { observation, deliveredEnd, truncated };
|
|
78
119
|
}
|
|
79
120
|
function redact(text) {
|
|
80
121
|
return truncate((0, report_1.redactText)(text));
|
|
@@ -202,6 +243,11 @@ async function extractFunctionBoundaries(content, relPath) {
|
|
|
202
243
|
* and actualStart/actualEnd are 0 (no content lines delivered).
|
|
203
244
|
* 3. Small file with no startLine/endLine → full content returned,
|
|
204
245
|
* actualStart=1, actualEnd=totalLines, truncated=false.
|
|
246
|
+
* 4. Range (or small file) whose rendered content exceeds MAX_OBSERVATION_CHARS
|
|
247
|
+
* → the observation is cut at the last complete line that fits.
|
|
248
|
+
* `truncated === true` and actualEnd is the last DELIVERED line, not the
|
|
249
|
+
* requested end; the observation ends with a re-read note naming the
|
|
250
|
+
* undelivered remainder.
|
|
205
251
|
*/
|
|
206
252
|
async function executeReadFileAction(action, ctx) {
|
|
207
253
|
try {
|
|
@@ -216,20 +262,17 @@ async function executeReadFileAction(action, ctx) {
|
|
|
216
262
|
if (startLine || endLine) {
|
|
217
263
|
const start = Math.max(1, startLine || 1);
|
|
218
264
|
const end = Math.min(totalLines, endLine || totalLines);
|
|
219
|
-
const
|
|
220
|
-
.map((line, i) => `${start + i}: ${line}`)
|
|
221
|
-
.join('\n');
|
|
222
|
-
const observation = redact(`File: ${rel} (lines ${start}-${end} of ${totalLines})\n\n${section}`);
|
|
265
|
+
const rendered = renderNumberedRead(`File: ${rel} (lines ${start}-${end} of ${totalLines})`, allLines, start, end);
|
|
223
266
|
return {
|
|
224
|
-
observation,
|
|
267
|
+
observation: rendered.observation,
|
|
225
268
|
actualStart: start,
|
|
226
|
-
actualEnd:
|
|
269
|
+
actualEnd: rendered.deliveredEnd,
|
|
227
270
|
totalLines,
|
|
228
|
-
truncated:
|
|
271
|
+
truncated: rendered.truncated,
|
|
229
272
|
};
|
|
230
273
|
}
|
|
231
274
|
// Case 2: large file, no range → function map (not raw content)
|
|
232
|
-
if (totalLines >
|
|
275
|
+
if (totalLines > observationLimits_2.LARGE_FILE_THRESHOLD) {
|
|
233
276
|
const funcMap = await extractFunctionMap(content, rel);
|
|
234
277
|
if (funcMap) {
|
|
235
278
|
const observation = redact(`File: ${rel} (${totalLines} lines — LARGE FILE)\n\nThis file is too large to show in full. Here is a function map. Use read_file with startLine/endLine to read specific sections.\n\n${funcMap}`);
|
|
@@ -242,17 +285,15 @@ async function executeReadFileAction(action, ctx) {
|
|
|
242
285
|
};
|
|
243
286
|
}
|
|
244
287
|
}
|
|
245
|
-
// Case 3: small file, no range → full content
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
.join('\n');
|
|
249
|
-
const observation = redact(`File: ${rel} (${totalLines} lines)\n\n${numbered}`);
|
|
288
|
+
// Case 3: small file, no range → full content (may still be cut at
|
|
289
|
+
// the char cap on dense files — same delivered-range reporting)
|
|
290
|
+
const rendered = renderNumberedRead(`File: ${rel} (${totalLines} lines)`, allLines, 1, totalLines);
|
|
250
291
|
return {
|
|
251
|
-
observation,
|
|
292
|
+
observation: rendered.observation,
|
|
252
293
|
actualStart: 1,
|
|
253
|
-
actualEnd:
|
|
294
|
+
actualEnd: rendered.deliveredEnd,
|
|
254
295
|
totalLines,
|
|
255
|
-
truncated:
|
|
296
|
+
truncated: rendered.truncated,
|
|
256
297
|
};
|
|
257
298
|
}
|
|
258
299
|
catch (e) {
|
|
@@ -664,7 +705,7 @@ async function executeFlowAction(action, ctx, runId, client, target) {
|
|
|
664
705
|
.join('\n');
|
|
665
706
|
return `${r.source} (${r.sourceFile}:${r.sourceLine}) → ${r.sink} (${r.sinkFile}:${r.sinkLine}) [${r.canonicalType}]\n${path}`;
|
|
666
707
|
}).join('\n\n');
|
|
667
|
-
const truncated = formatted.length >
|
|
708
|
+
const truncated = formatted.length > observationLimits_2.MAX_OBSERVATION_CHARS;
|
|
668
709
|
return {
|
|
669
710
|
observation: redact(formatted),
|
|
670
711
|
flowResult: {
|