@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,335 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Finding review queue — non-blocking human review for INCONCLUSIVE findings.
|
|
4
|
+
*
|
|
5
|
+
* When the verify subagent cannot prove or disprove a finding (sandbox
|
|
6
|
+
* unavailable, budget exhausted, test couldn't run), the finding is added
|
|
7
|
+
* to this local review queue. The scan completes without blocking — the
|
|
8
|
+
* user can later adjudicate each item as confirmed, rejected, or deferred.
|
|
9
|
+
*
|
|
10
|
+
* Privacy contract (same as scanAuditLog.ts + agentMemory.ts):
|
|
11
|
+
* - Source code NEVER leaves the machine.
|
|
12
|
+
* - Evidence strings, `why` explanations, fix code, full test scripts,
|
|
13
|
+
* and full API responses are NOT recorded. Only hashes, counts,
|
|
14
|
+
* verdicts, file paths, and line numbers are stored.
|
|
15
|
+
* - The review queue is per-workspace, stored at
|
|
16
|
+
* `<workspaceRoot>/.securecode/finding-review-queue.json`.
|
|
17
|
+
*
|
|
18
|
+
* Retention:
|
|
19
|
+
* - 500 review items per workspace.
|
|
20
|
+
* - Resolved items pruned after 90 days.
|
|
21
|
+
* - Unresolved items kept until explicitly resolved.
|
|
22
|
+
*
|
|
23
|
+
* Dedup: identical findings (fileHash + filePath + line + findingType +
|
|
24
|
+
* evidenceHash) are not re-enqueued — the existing item is returned.
|
|
25
|
+
*/
|
|
26
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
27
|
+
if (k2 === undefined) k2 = k;
|
|
28
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
29
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
30
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
31
|
+
}
|
|
32
|
+
Object.defineProperty(o, k2, desc);
|
|
33
|
+
}) : (function(o, m, k, k2) {
|
|
34
|
+
if (k2 === undefined) k2 = k;
|
|
35
|
+
o[k2] = m[k];
|
|
36
|
+
}));
|
|
37
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
38
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
39
|
+
}) : function(o, v) {
|
|
40
|
+
o["default"] = v;
|
|
41
|
+
});
|
|
42
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
43
|
+
var ownKeys = function(o) {
|
|
44
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
45
|
+
var ar = [];
|
|
46
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
47
|
+
return ar;
|
|
48
|
+
};
|
|
49
|
+
return ownKeys(o);
|
|
50
|
+
};
|
|
51
|
+
return function (mod) {
|
|
52
|
+
if (mod && mod.__esModule) return mod;
|
|
53
|
+
var result = {};
|
|
54
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
55
|
+
__setModuleDefault(result, mod);
|
|
56
|
+
return result;
|
|
57
|
+
};
|
|
58
|
+
})();
|
|
59
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
60
|
+
exports.loadReviewQueue = loadReviewQueue;
|
|
61
|
+
exports.enqueueFindingReview = enqueueFindingReview;
|
|
62
|
+
exports.listFindingReviews = listFindingReviews;
|
|
63
|
+
exports.decideFindingReview = decideFindingReview;
|
|
64
|
+
exports.removeFindingReview = removeFindingReview;
|
|
65
|
+
exports.clearFindingReviews = clearFindingReviews;
|
|
66
|
+
exports.formatReviewItem = formatReviewItem;
|
|
67
|
+
exports.formatReviewList = formatReviewList;
|
|
68
|
+
const fs = __importStar(require("fs"));
|
|
69
|
+
const path = __importStar(require("path"));
|
|
70
|
+
const crypto = __importStar(require("crypto"));
|
|
71
|
+
const REVIEW_DIR = '.securecode';
|
|
72
|
+
const REVIEW_FILE = 'finding-review-queue.json';
|
|
73
|
+
const REVIEW_VERSION = 1;
|
|
74
|
+
const MAX_ITEMS = 500;
|
|
75
|
+
const RESOLVED_TTL_MS = 90 * 24 * 60 * 60 * 1000; // 90 days
|
|
76
|
+
// ── Path helpers ────────────────────────────────────────────────────────────
|
|
77
|
+
function reviewQueuePath(workspaceRoot) {
|
|
78
|
+
return path.join(workspaceRoot, REVIEW_DIR, REVIEW_FILE);
|
|
79
|
+
}
|
|
80
|
+
function ensureReviewDir(workspaceRoot) {
|
|
81
|
+
const dir = path.join(workspaceRoot, REVIEW_DIR);
|
|
82
|
+
if (!fs.existsSync(dir))
|
|
83
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
84
|
+
return dir;
|
|
85
|
+
}
|
|
86
|
+
function hashEvidence(evidence) {
|
|
87
|
+
return crypto.createHash('sha256').update(evidence).digest('hex').slice(0, 16);
|
|
88
|
+
}
|
|
89
|
+
function hashFile(content) {
|
|
90
|
+
return crypto.createHash('sha256').update(content).digest('hex').slice(0, 16);
|
|
91
|
+
}
|
|
92
|
+
function genId() {
|
|
93
|
+
return 'review-' + crypto.randomBytes(4).toString('hex');
|
|
94
|
+
}
|
|
95
|
+
const MAX_VERIFICATION_REASON_LEN = 300;
|
|
96
|
+
function truncateReason(reason) {
|
|
97
|
+
if (!reason)
|
|
98
|
+
return undefined;
|
|
99
|
+
if (reason.length <= MAX_VERIFICATION_REASON_LEN)
|
|
100
|
+
return reason;
|
|
101
|
+
return reason.slice(0, MAX_VERIFICATION_REASON_LEN) + '…';
|
|
102
|
+
}
|
|
103
|
+
// ── Read / Write ─────────────────────────────────────────────────────────────
|
|
104
|
+
/**
|
|
105
|
+
* Load the review queue for a workspace. Returns an empty queue
|
|
106
|
+
* (version + empty array) if the file doesn't exist or is corrupt.
|
|
107
|
+
*/
|
|
108
|
+
function loadReviewQueue(workspaceRoot) {
|
|
109
|
+
const p = reviewQueuePath(workspaceRoot);
|
|
110
|
+
try {
|
|
111
|
+
if (!fs.existsSync(p)) {
|
|
112
|
+
return { version: REVIEW_VERSION, items: [] };
|
|
113
|
+
}
|
|
114
|
+
const raw = fs.readFileSync(p, 'utf8');
|
|
115
|
+
const data = JSON.parse(raw);
|
|
116
|
+
if (!data.version || data.version > REVIEW_VERSION) {
|
|
117
|
+
return { version: REVIEW_VERSION, items: [] };
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
version: REVIEW_VERSION,
|
|
121
|
+
items: data.items || [],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return { version: REVIEW_VERSION, items: [] };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** Save the review queue (atomic write — .tmp + rename). */
|
|
129
|
+
function saveReviewQueue(workspaceRoot, queue) {
|
|
130
|
+
ensureReviewDir(workspaceRoot);
|
|
131
|
+
const p = reviewQueuePath(workspaceRoot);
|
|
132
|
+
const tmp = p + '.tmp';
|
|
133
|
+
fs.writeFileSync(tmp, JSON.stringify(queue, null, 2), 'utf8');
|
|
134
|
+
fs.renameSync(tmp, p);
|
|
135
|
+
}
|
|
136
|
+
// ── Dedup key ────────────────────────────────────────────────────────────────
|
|
137
|
+
function dedupKey(item) {
|
|
138
|
+
return `${item.fileHash}:${item.workspaceRelativePath}:${item.line}:${item.findingType}:${item.evidenceHash}`;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Enqueue a finding for human review. Dedupes by
|
|
142
|
+
* (fileHash + filePath + line + findingType + evidenceHash).
|
|
143
|
+
* Returns the item (existing if duplicate, new otherwise).
|
|
144
|
+
*
|
|
145
|
+
* Re-enqueuing a previously-resolved item with the same dedup key
|
|
146
|
+
* reopens it (clears the decision) — the finding reappeared and needs
|
|
147
|
+
* re-review.
|
|
148
|
+
*/
|
|
149
|
+
function enqueueFindingReview(workspaceRoot, input) {
|
|
150
|
+
const queue = loadReviewQueue(workspaceRoot);
|
|
151
|
+
const fh = hashFile(input.fileContent);
|
|
152
|
+
const eh = hashEvidence(input.evidence);
|
|
153
|
+
const key = dedupKey({
|
|
154
|
+
fileHash: fh,
|
|
155
|
+
workspaceRelativePath: input.workspaceRelativePath,
|
|
156
|
+
line: input.line,
|
|
157
|
+
findingType: input.findingType,
|
|
158
|
+
evidenceHash: eh,
|
|
159
|
+
});
|
|
160
|
+
const now = new Date().toISOString();
|
|
161
|
+
const existingIdx = queue.items.findIndex(item => dedupKey(item) === key);
|
|
162
|
+
if (existingIdx >= 0) {
|
|
163
|
+
const existing = queue.items[existingIdx];
|
|
164
|
+
existing.updatedAt = now;
|
|
165
|
+
existing.severity = input.severity;
|
|
166
|
+
existing.confidence = input.confidence;
|
|
167
|
+
existing.proven = input.proven;
|
|
168
|
+
existing.reviewReason = input.reviewReason;
|
|
169
|
+
existing.verificationReason = truncateReason(input.verificationReason);
|
|
170
|
+
// Reopen if previously resolved — the finding reappeared.
|
|
171
|
+
existing.decision = undefined;
|
|
172
|
+
existing.decisionReason = undefined;
|
|
173
|
+
existing.decidedAt = undefined;
|
|
174
|
+
saveReviewQueue(workspaceRoot, queue);
|
|
175
|
+
return existing;
|
|
176
|
+
}
|
|
177
|
+
const item = {
|
|
178
|
+
id: genId(),
|
|
179
|
+
createdAt: now,
|
|
180
|
+
updatedAt: now,
|
|
181
|
+
workspaceRelativePath: input.workspaceRelativePath,
|
|
182
|
+
fileHash: fh,
|
|
183
|
+
line: input.line,
|
|
184
|
+
lineEnd: input.lineEnd,
|
|
185
|
+
findingType: input.findingType,
|
|
186
|
+
severity: input.severity,
|
|
187
|
+
confidence: input.confidence,
|
|
188
|
+
proven: input.proven,
|
|
189
|
+
reviewReason: input.reviewReason,
|
|
190
|
+
verificationReason: truncateReason(input.verificationReason),
|
|
191
|
+
evidenceHash: eh,
|
|
192
|
+
};
|
|
193
|
+
queue.items.push(item);
|
|
194
|
+
pruneItems(queue);
|
|
195
|
+
saveReviewQueue(workspaceRoot, queue);
|
|
196
|
+
return item;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* List review items, optionally filtered by decision status and/or file path.
|
|
200
|
+
*/
|
|
201
|
+
function listFindingReviews(workspaceRoot, options) {
|
|
202
|
+
const queue = loadReviewQueue(workspaceRoot);
|
|
203
|
+
let items = queue.items;
|
|
204
|
+
if (options?.decision) {
|
|
205
|
+
if (options.decision === 'pending') {
|
|
206
|
+
items = items.filter(i => i.decision === undefined);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
items = items.filter(i => i.decision === options.decision);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (options?.filePath) {
|
|
213
|
+
items = items.filter(i => i.workspaceRelativePath === options.filePath);
|
|
214
|
+
}
|
|
215
|
+
return items;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Mark a review item as confirmed, rejected, or deferred.
|
|
219
|
+
* Returns the updated item, or null if the ID was not found.
|
|
220
|
+
*/
|
|
221
|
+
function decideFindingReview(workspaceRoot, id, decision, reason) {
|
|
222
|
+
const queue = loadReviewQueue(workspaceRoot);
|
|
223
|
+
const item = queue.items.find(i => i.id === id);
|
|
224
|
+
if (!item)
|
|
225
|
+
return null;
|
|
226
|
+
const now = new Date().toISOString();
|
|
227
|
+
item.decision = decision;
|
|
228
|
+
item.decisionReason = reason ? reason.slice(0, 500) : undefined;
|
|
229
|
+
item.decidedAt = now;
|
|
230
|
+
item.updatedAt = now;
|
|
231
|
+
saveReviewQueue(workspaceRoot, queue);
|
|
232
|
+
return item;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Remove a single review item by ID. Returns true if removed.
|
|
236
|
+
*/
|
|
237
|
+
function removeFindingReview(workspaceRoot, id) {
|
|
238
|
+
const queue = loadReviewQueue(workspaceRoot);
|
|
239
|
+
const before = queue.items.length;
|
|
240
|
+
queue.items = queue.items.filter(i => i.id !== id);
|
|
241
|
+
if (queue.items.length === before)
|
|
242
|
+
return false;
|
|
243
|
+
saveReviewQueue(workspaceRoot, queue);
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Clear review items. If `id` is given, removes just that item.
|
|
248
|
+
* If `resolvedOnly` is true, removes only items with a decision set.
|
|
249
|
+
* Otherwise removes ALL items.
|
|
250
|
+
* Returns the count of items removed.
|
|
251
|
+
*/
|
|
252
|
+
function clearFindingReviews(workspaceRoot, options) {
|
|
253
|
+
const queue = loadReviewQueue(workspaceRoot);
|
|
254
|
+
if (options?.id) {
|
|
255
|
+
const before = queue.items.length;
|
|
256
|
+
queue.items = queue.items.filter(i => i.id !== options.id);
|
|
257
|
+
const removed = before - queue.items.length;
|
|
258
|
+
if (removed > 0)
|
|
259
|
+
saveReviewQueue(workspaceRoot, queue);
|
|
260
|
+
return removed;
|
|
261
|
+
}
|
|
262
|
+
if (options?.resolvedOnly) {
|
|
263
|
+
const before = queue.items.length;
|
|
264
|
+
queue.items = queue.items.filter(i => i.decision === undefined);
|
|
265
|
+
const removed = before - queue.items.length;
|
|
266
|
+
if (removed > 0)
|
|
267
|
+
saveReviewQueue(workspaceRoot, queue);
|
|
268
|
+
return removed;
|
|
269
|
+
}
|
|
270
|
+
const removed = queue.items.length;
|
|
271
|
+
queue.items = [];
|
|
272
|
+
if (removed > 0)
|
|
273
|
+
saveReviewQueue(workspaceRoot, queue);
|
|
274
|
+
return removed;
|
|
275
|
+
}
|
|
276
|
+
// ── Pruning ──────────────────────────────────────────────────────────────────
|
|
277
|
+
function pruneItems(queue) {
|
|
278
|
+
const cutoff = Date.now() - RESOLVED_TTL_MS;
|
|
279
|
+
// Drop resolved items older than the TTL.
|
|
280
|
+
queue.items = queue.items.filter(i => {
|
|
281
|
+
if (i.decision === undefined)
|
|
282
|
+
return true; // keep pending
|
|
283
|
+
if (!i.decidedAt)
|
|
284
|
+
return true;
|
|
285
|
+
try {
|
|
286
|
+
return new Date(i.decidedAt).getTime() >= cutoff;
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
// Enforce hard cap — drop oldest resolved first, then oldest pending.
|
|
293
|
+
if (queue.items.length <= MAX_ITEMS)
|
|
294
|
+
return;
|
|
295
|
+
const resolved = queue.items
|
|
296
|
+
.filter(i => i.decision !== undefined)
|
|
297
|
+
.sort((a, b) => (a.decidedAt || a.updatedAt).localeCompare(b.decidedAt || b.updatedAt));
|
|
298
|
+
const toRemove = queue.items.length - MAX_ITEMS;
|
|
299
|
+
const removeIds = new Set(resolved.slice(0, toRemove).map(i => i.id));
|
|
300
|
+
queue.items = queue.items.filter(i => !removeIds.has(i.id));
|
|
301
|
+
// If still over cap (not enough resolved to drop), drop oldest pending.
|
|
302
|
+
if (queue.items.length > MAX_ITEMS) {
|
|
303
|
+
queue.items = queue.items
|
|
304
|
+
.sort((a, b) => a.updatedAt.localeCompare(b.updatedAt))
|
|
305
|
+
.slice(-MAX_ITEMS);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
// ── Formatting ───────────────────────────────────────────────────────────────
|
|
309
|
+
function formatReviewItem(item) {
|
|
310
|
+
const lines = [
|
|
311
|
+
`Review ID: ${item.id}`,
|
|
312
|
+
`File: ${item.workspaceRelativePath}:${item.line}${item.lineEnd ? `-${item.lineEnd}` : ''}`,
|
|
313
|
+
`Type: ${item.findingType}`,
|
|
314
|
+
`Severity: ${item.severity}`,
|
|
315
|
+
`Confidence: ${item.confidence}%`,
|
|
316
|
+
`Verification: ${item.proven}`,
|
|
317
|
+
`Reason: ${item.reviewReason}`,
|
|
318
|
+
];
|
|
319
|
+
if (item.verificationReason) {
|
|
320
|
+
lines.push(`Verification detail: ${item.verificationReason}`);
|
|
321
|
+
}
|
|
322
|
+
lines.push(`Decision: ${item.decision || 'pending'}`);
|
|
323
|
+
return lines.join('\n');
|
|
324
|
+
}
|
|
325
|
+
function formatReviewList(items) {
|
|
326
|
+
if (items.length === 0) {
|
|
327
|
+
return 'No review items found.';
|
|
328
|
+
}
|
|
329
|
+
const lines = [`Review queue (${items.length} item${items.length === 1 ? '' : 's'}):`, ''];
|
|
330
|
+
for (const item of items) {
|
|
331
|
+
lines.push(formatReviewItem(item), '');
|
|
332
|
+
}
|
|
333
|
+
return lines.join('\n').trimEnd();
|
|
334
|
+
}
|
|
335
|
+
//# sourceMappingURL=findingReviewQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findingReviewQueue.js","sourceRoot":"","sources":["../../src/audit/findingReviewQueue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata-only scan audit log — samples per-scan metadata (no source code,
|
|
3
|
+
* no evidence strings) for quality auditing and regression tracking.
|
|
4
|
+
*
|
|
5
|
+
* Privacy contract (same as agentTrace.ts):
|
|
6
|
+
* - Source code NEVER leaves the machine.
|
|
7
|
+
* - Evidence strings, `why` explanations, fix code, and file content are
|
|
8
|
+
* NOT recorded. Only hashes, counts, verdicts, cost, steps, and action
|
|
9
|
+
* type histograms are stored.
|
|
10
|
+
* - The audit log is per-workspace, stored at
|
|
11
|
+
* `<workspaceRoot>/.securecode/scan-audit.jsonl`.
|
|
12
|
+
*
|
|
13
|
+
* Sampling:
|
|
14
|
+
* - Not every scan is recorded — a configurable sampling rate (default 1.0
|
|
15
|
+
* = 100% for local audit; the caller can lower it) gates which scans
|
|
16
|
+
* are persisted. Sampling is deterministic per scan (hash of file path
|
|
17
|
+
* + timestamp) so the same scan re-run doesn't double-count.
|
|
18
|
+
*
|
|
19
|
+
* Reuses metric vocabulary from agentEvalScoring.ts for aggregation:
|
|
20
|
+
* - provenRate, inconclusiveRate, meanSteps, meanCostUsd
|
|
21
|
+
*
|
|
22
|
+
* Retention:
|
|
23
|
+
* - 90-day TTL (longer than trace's 7 days — audit is long-term quality).
|
|
24
|
+
* - 1000 entries per workspace (3x the approval audit cap).
|
|
25
|
+
*/
|
|
26
|
+
export interface ScanAuditSample {
|
|
27
|
+
timestamp: string;
|
|
28
|
+
filePath: string;
|
|
29
|
+
fileHash: string;
|
|
30
|
+
language: string;
|
|
31
|
+
scanStatus: string;
|
|
32
|
+
stepsUsed: number;
|
|
33
|
+
costSpentUsd: number;
|
|
34
|
+
findings: {
|
|
35
|
+
type: string;
|
|
36
|
+
severity: string;
|
|
37
|
+
line: number;
|
|
38
|
+
confidence: number;
|
|
39
|
+
proven: string;
|
|
40
|
+
evidenceLevel?: string;
|
|
41
|
+
verificationLevel?: string;
|
|
42
|
+
}[];
|
|
43
|
+
findingCounts: {
|
|
44
|
+
total: number;
|
|
45
|
+
proven: number;
|
|
46
|
+
unproven: number;
|
|
47
|
+
inconclusive: number;
|
|
48
|
+
notReproducible: number;
|
|
49
|
+
skipped: number;
|
|
50
|
+
};
|
|
51
|
+
precisionMetrics?: {
|
|
52
|
+
investigationNotesCount: number;
|
|
53
|
+
coverageGapsCount: number;
|
|
54
|
+
verificationLevelDistribution: Record<string, number>;
|
|
55
|
+
rootCauseCount: number;
|
|
56
|
+
hasArchitectureContext: boolean;
|
|
57
|
+
stepsGranted?: number;
|
|
58
|
+
extensionsGranted?: number;
|
|
59
|
+
terminationReason?: string;
|
|
60
|
+
provenStrictCount?: number;
|
|
61
|
+
provenRejectedByGate?: number;
|
|
62
|
+
proofGateFailures?: Record<string, number>;
|
|
63
|
+
syntheticProofCount?: number;
|
|
64
|
+
extractedLogicProofCount?: number;
|
|
65
|
+
realImportProofCount?: number;
|
|
66
|
+
baselinePassRate?: number;
|
|
67
|
+
exploitPassRate?: number;
|
|
68
|
+
targetReachedRate?: number;
|
|
69
|
+
flakyProofCount?: number;
|
|
70
|
+
mutationDiscriminationRate?: number;
|
|
71
|
+
humanReviewPendingCount?: number;
|
|
72
|
+
};
|
|
73
|
+
verifyUsage?: {
|
|
74
|
+
findingsAttempted: number;
|
|
75
|
+
roundsUsed: number;
|
|
76
|
+
llmCallsUsed: number;
|
|
77
|
+
costSpentUsd: number;
|
|
78
|
+
wallClockMs: number;
|
|
79
|
+
};
|
|
80
|
+
actionHistogram: Record<string, number>;
|
|
81
|
+
cached: boolean;
|
|
82
|
+
scope?: {
|
|
83
|
+
changedFiles: number;
|
|
84
|
+
blastRadius: number;
|
|
85
|
+
baseRef?: string;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export declare function recordScanAuditSample(workspaceRoot: string, scanResult: {
|
|
89
|
+
filePath: string;
|
|
90
|
+
fileHash: string;
|
|
91
|
+
language: string;
|
|
92
|
+
scanStatus: string;
|
|
93
|
+
stepsUsed: number;
|
|
94
|
+
costSpentUsd: number;
|
|
95
|
+
agentFindings: any[];
|
|
96
|
+
transcript?: any[];
|
|
97
|
+
cached: boolean;
|
|
98
|
+
verifyUsage?: any;
|
|
99
|
+
scope?: any;
|
|
100
|
+
investigationNotes?: any[];
|
|
101
|
+
coverageGaps?: any[];
|
|
102
|
+
hasArchitectureContext?: boolean;
|
|
103
|
+
stepsGranted?: number;
|
|
104
|
+
extensionsGranted?: number;
|
|
105
|
+
terminationReason?: string;
|
|
106
|
+
}, options?: {
|
|
107
|
+
samplingRate?: number;
|
|
108
|
+
}): boolean;
|
|
109
|
+
export interface ScanAuditSummary {
|
|
110
|
+
totalScans: number;
|
|
111
|
+
cachedScans: number;
|
|
112
|
+
freshScans: number;
|
|
113
|
+
totalFindings: number;
|
|
114
|
+
byProven: Record<string, number>;
|
|
115
|
+
bySeverity: Record<string, number>;
|
|
116
|
+
byType: Record<string, number>;
|
|
117
|
+
provenRate: number;
|
|
118
|
+
inconclusiveRate: number;
|
|
119
|
+
meanSteps: number;
|
|
120
|
+
meanCostUsd: number;
|
|
121
|
+
meanFindingsPerScan: number;
|
|
122
|
+
actionTypeUsage: Record<string, number>;
|
|
123
|
+
oldestEntry: string | null;
|
|
124
|
+
newestEntry: string | null;
|
|
125
|
+
}
|
|
126
|
+
export declare function readScanAuditLog(workspaceRoot: string, limit?: number): ScanAuditSample[];
|
|
127
|
+
export declare function summarizeScanAuditLog(workspaceRoot: string): ScanAuditSummary;
|
|
128
|
+
export declare function clearScanAuditLog(workspaceRoot: string): void;
|
|
129
|
+
export declare function formatAuditSummary(summary: ScanAuditSummary): string;
|
|
130
|
+
export interface ProofAuditMetrics {
|
|
131
|
+
provenStrictCount: number;
|
|
132
|
+
provenRejectedByGate: number;
|
|
133
|
+
proofGateFailures: Record<string, number>;
|
|
134
|
+
syntheticProofCount: number;
|
|
135
|
+
extractedLogicProofCount: number;
|
|
136
|
+
realImportProofCount: number;
|
|
137
|
+
baselinePassRate: number;
|
|
138
|
+
exploitPassRate: number;
|
|
139
|
+
targetReachedRate: number;
|
|
140
|
+
flakyProofCount: number;
|
|
141
|
+
mutationDiscriminationRate: number;
|
|
142
|
+
humanReviewPendingCount: number;
|
|
143
|
+
}
|
|
144
|
+
export interface ProofInvariantCheck {
|
|
145
|
+
findingIndex: number;
|
|
146
|
+
violations: string[];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Validate the PROVEN invariant: every PROVEN finding must have:
|
|
150
|
+
* - proofEvidence
|
|
151
|
+
* - proofGateResult.eligibleForProven === true
|
|
152
|
+
* - sourceMode = real-import or real-server
|
|
153
|
+
* - repeatedRuns >= 3
|
|
154
|
+
* - repeatPasses === repeatedRuns
|
|
155
|
+
* - mutation discrimination passed
|
|
156
|
+
*
|
|
157
|
+
* Returns an array of violations per finding. An empty array means all
|
|
158
|
+
* PROVEN findings satisfy the invariant.
|
|
159
|
+
*/
|
|
160
|
+
export declare function validateProvenInvariant(findings: any[]): ProofInvariantCheck[];
|