projscan 2.0.0 → 2.2.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 +38 -29
- package/dist/analyzers/supplyChainCheck.d.ts +2 -0
- package/dist/analyzers/supplyChainCheck.js +400 -0
- package/dist/analyzers/supplyChainCheck.js.map +1 -0
- package/dist/cli/_shared.d.ts +1 -0
- package/dist/cli/_shared.js +19 -3
- package/dist/cli/_shared.js.map +1 -1
- package/dist/cli/commands/analyze.js +7 -3
- package/dist/cli/commands/analyze.js.map +1 -1
- package/dist/cli/commands/applyFix.js +2 -2
- package/dist/cli/commands/applyFix.js.map +1 -1
- package/dist/cli/commands/audit.js +2 -2
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/badge.js +2 -1
- package/dist/cli/commands/badge.js.map +1 -1
- package/dist/cli/commands/ci.js +3 -3
- package/dist/cli/commands/ci.js.map +1 -1
- package/dist/cli/commands/coupling.js +2 -2
- package/dist/cli/commands/coupling.js.map +1 -1
- package/dist/cli/commands/coverage.js +2 -2
- package/dist/cli/commands/coverage.js.map +1 -1
- package/dist/cli/commands/dependencies.js +2 -2
- package/dist/cli/commands/dependencies.js.map +1 -1
- package/dist/cli/commands/diagram.js +2 -2
- package/dist/cli/commands/diagram.js.map +1 -1
- package/dist/cli/commands/diff.js +2 -2
- package/dist/cli/commands/diff.js.map +1 -1
- package/dist/cli/commands/doctor.js +3 -3
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/explain.js +2 -2
- package/dist/cli/commands/explain.js.map +1 -1
- package/dist/cli/commands/explainIssue.js +2 -2
- package/dist/cli/commands/explainIssue.js.map +1 -1
- package/dist/cli/commands/file.js +2 -2
- package/dist/cli/commands/file.js.map +1 -1
- package/dist/cli/commands/fix.js +2 -1
- package/dist/cli/commands/fix.js.map +1 -1
- package/dist/cli/commands/fixSuggest.js +2 -2
- package/dist/cli/commands/fixSuggest.js.map +1 -1
- package/dist/cli/commands/help.js +2 -1
- package/dist/cli/commands/help.js.map +1 -1
- package/dist/cli/commands/hotspots.js +2 -2
- package/dist/cli/commands/hotspots.js.map +1 -1
- package/dist/cli/commands/impact.js +2 -2
- package/dist/cli/commands/impact.js.map +1 -1
- package/dist/cli/commands/init.js +2 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/installHook.js +2 -1
- package/dist/cli/commands/installHook.js.map +1 -1
- package/dist/cli/commands/mcp.js +2 -1
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/memory.js +5 -4
- package/dist/cli/commands/memory.js.map +1 -1
- package/dist/cli/commands/outdated.js +2 -2
- package/dist/cli/commands/outdated.js.map +1 -1
- package/dist/cli/commands/plugin.js +83 -3
- package/dist/cli/commands/plugin.js.map +1 -1
- package/dist/cli/commands/prDiff.js +2 -2
- package/dist/cli/commands/prDiff.js.map +1 -1
- package/dist/cli/commands/preflight.d.ts +1 -0
- package/dist/cli/commands/preflight.js +80 -0
- package/dist/cli/commands/preflight.js.map +1 -0
- package/dist/cli/commands/review.js +2 -2
- package/dist/cli/commands/review.js.map +1 -1
- package/dist/cli/commands/search.js +2 -2
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/session.js +5 -5
- package/dist/cli/commands/session.js.map +1 -1
- package/dist/cli/commands/structure.js +2 -2
- package/dist/cli/commands/structure.js.map +1 -1
- package/dist/cli/commands/taint.js +2 -2
- package/dist/cli/commands/taint.js.map +1 -1
- package/dist/cli/commands/upgrade.js +2 -2
- package/dist/cli/commands/upgrade.js.map +1 -1
- package/dist/cli/commands/watch.js +2 -1
- package/dist/cli/commands/watch.js.map +1 -1
- package/dist/cli/commands/workspace.js +4 -2
- package/dist/cli/commands/workspace.js.map +1 -1
- package/dist/cli/commands/workspaces.js +2 -2
- package/dist/cli/commands/workspaces.js.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/core/issueEngine.js +2 -0
- package/dist/core/issueEngine.js.map +1 -1
- package/dist/core/pluginDx.d.ts +14 -0
- package/dist/core/pluginDx.js +298 -0
- package/dist/core/pluginDx.js.map +1 -0
- package/dist/core/plugins.d.ts +5 -6
- package/dist/core/plugins.js +99 -13
- package/dist/core/plugins.js.map +1 -1
- package/dist/core/preflight.d.ts +11 -0
- package/dist/core/preflight.js +450 -0
- package/dist/core/preflight.js.map +1 -0
- package/dist/core/review.js +132 -3
- package/dist/core/review.js.map +1 -1
- package/dist/core/sessionResources.d.ts +6 -0
- package/dist/core/sessionResources.js +216 -0
- package/dist/core/sessionResources.js.map +1 -0
- package/dist/mcp/resources.js +25 -0
- package/dist/mcp/resources.js.map +1 -1
- package/dist/mcp/tools/preflight.d.ts +2 -0
- package/dist/mcp/tools/preflight.js +51 -0
- package/dist/mcp/tools/preflight.js.map +1 -0
- package/dist/mcp/tools.js +2 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/projscan-sbom.cdx.json +4589 -0
- package/dist/reporters/htmlReporter.d.ts +2 -1
- package/dist/reporters/htmlReporter.js +70 -0
- package/dist/reporters/htmlReporter.js.map +1 -1
- package/dist/tool-manifest.json +33 -3
- package/dist/types.d.ts +141 -0
- package/dist/utils/banner.js +14 -4
- package/dist/utils/banner.js.map +1 -1
- package/dist/utils/fileWalker.js +4 -0
- package/dist/utils/fileWalker.js.map +1 -1
- package/dist/utils/formatSupport.d.ts +58 -0
- package/dist/utils/formatSupport.js +63 -0
- package/dist/utils/formatSupport.js.map +1 -0
- package/docs/PLUGIN-AUTHORING.md +30 -0
- package/package.json +12 -7
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { scanRepository } from './repositoryScanner.js';
|
|
2
|
+
import { collectIssues } from './issueEngine.js';
|
|
3
|
+
import { analyzeHotspots } from './hotspotAnalyzer.js';
|
|
4
|
+
import { computeReview } from './review.js';
|
|
5
|
+
import { loadSession } from './session.js';
|
|
6
|
+
import { PLUGIN_PREVIEW_FLAG, pluginsEnabled } from './plugins.js';
|
|
7
|
+
import { getChangedFiles } from '../utils/changedFiles.js';
|
|
8
|
+
import { loadConfig, applyConfigToIssues } from '../utils/config.js';
|
|
9
|
+
import { calculateScore } from '../utils/scoreCalculator.js';
|
|
10
|
+
const DEFAULT_MAX_CHANGED_FILES = 50;
|
|
11
|
+
const MAX_EVIDENCE_FILES = 40;
|
|
12
|
+
export async function computePreflight(rootPath, options = {}) {
|
|
13
|
+
const mode = options.mode ?? 'before_edit';
|
|
14
|
+
const configResult = await loadConfig(rootPath).catch(() => ({ config: { ignore: [] } }));
|
|
15
|
+
const scan = await scanRepository(rootPath, { ignore: configResult.config.ignore });
|
|
16
|
+
const issues = applyConfigToIssues(await collectIssuesWithPluginOption(rootPath, scan.files, options.enablePlugins), configResult.config);
|
|
17
|
+
const health = calculateScore(issues);
|
|
18
|
+
const changedFiles = await safeChangedFiles(rootPath, mode, options.baseRef);
|
|
19
|
+
const session = await safeSession(rootPath);
|
|
20
|
+
const hotspots = await safeHotspots(rootPath, scan.files, issues);
|
|
21
|
+
const review = await safeReview(rootPath, mode, options);
|
|
22
|
+
const reasons = buildPreflightReasons({
|
|
23
|
+
mode,
|
|
24
|
+
issues,
|
|
25
|
+
changedFiles,
|
|
26
|
+
health,
|
|
27
|
+
session,
|
|
28
|
+
hotspots,
|
|
29
|
+
review,
|
|
30
|
+
maxChangedFiles: options.maxChangedFiles ?? DEFAULT_MAX_CHANGED_FILES,
|
|
31
|
+
});
|
|
32
|
+
const verdict = decidePreflightVerdict(reasons);
|
|
33
|
+
const supplyChain = countSupplyChainIssues(issues);
|
|
34
|
+
const evidence = buildEvidence({
|
|
35
|
+
health,
|
|
36
|
+
changedFiles,
|
|
37
|
+
session,
|
|
38
|
+
hotspots,
|
|
39
|
+
issues,
|
|
40
|
+
pluginsEnabledForRun: options.enablePlugins === true || pluginsEnabled(),
|
|
41
|
+
review,
|
|
42
|
+
});
|
|
43
|
+
const truncated = evidence.session?.truncated === true ||
|
|
44
|
+
changedFiles.files.length > MAX_EVIDENCE_FILES ||
|
|
45
|
+
(evidence.hotspots?.touched.length ?? 0) > MAX_EVIDENCE_FILES;
|
|
46
|
+
const report = {
|
|
47
|
+
schemaVersion: 1,
|
|
48
|
+
mode,
|
|
49
|
+
verdict,
|
|
50
|
+
summary: '',
|
|
51
|
+
reasons,
|
|
52
|
+
evidence,
|
|
53
|
+
requiredChecks: buildRequiredChecks(mode, health, changedFiles, review, supplyChain),
|
|
54
|
+
suggestedNextActions: buildSuggestedActions(reasons, mode, changedFiles),
|
|
55
|
+
toolCalls: buildToolCalls(reasons, mode, changedFiles),
|
|
56
|
+
...(truncated ? { truncated: true } : {}),
|
|
57
|
+
};
|
|
58
|
+
return { ...report, summary: summarizePreflight(report) };
|
|
59
|
+
}
|
|
60
|
+
function countSupplyChainIssues(issues) {
|
|
61
|
+
const supplyChainIssues = issues.filter((issue) => issue.category === 'supply-chain');
|
|
62
|
+
return {
|
|
63
|
+
errorIssues: supplyChainIssues.filter((issue) => issue.severity === 'error').length,
|
|
64
|
+
warningIssues: supplyChainIssues.filter((issue) => issue.severity === 'warning').length,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function decidePreflightVerdict(reasons) {
|
|
68
|
+
if (reasons.some((reason) => reason.severity === 'error'))
|
|
69
|
+
return 'block';
|
|
70
|
+
if (reasons.some((reason) => reason.severity === 'warning'))
|
|
71
|
+
return 'caution';
|
|
72
|
+
return 'proceed';
|
|
73
|
+
}
|
|
74
|
+
export function summarizePreflight(report) {
|
|
75
|
+
if (report.reasons.length === 0) {
|
|
76
|
+
return `${report.verdict}: no blocking or cautionary signals found`;
|
|
77
|
+
}
|
|
78
|
+
return `${report.verdict}: ${report.reasons[0].message}`;
|
|
79
|
+
}
|
|
80
|
+
async function collectIssuesWithPluginOption(rootPath, files, enablePlugins) {
|
|
81
|
+
if (enablePlugins !== true)
|
|
82
|
+
return collectIssues(rootPath, files);
|
|
83
|
+
const previous = process.env[PLUGIN_PREVIEW_FLAG];
|
|
84
|
+
process.env[PLUGIN_PREVIEW_FLAG] = '1';
|
|
85
|
+
try {
|
|
86
|
+
return await collectIssues(rootPath, files);
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
if (previous === undefined)
|
|
90
|
+
delete process.env[PLUGIN_PREVIEW_FLAG];
|
|
91
|
+
else
|
|
92
|
+
process.env[PLUGIN_PREVIEW_FLAG] = previous;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function safeChangedFiles(rootPath, mode, baseRef) {
|
|
96
|
+
if (mode === 'before_edit') {
|
|
97
|
+
return {
|
|
98
|
+
available: false,
|
|
99
|
+
count: 0,
|
|
100
|
+
files: [],
|
|
101
|
+
baseRef: null,
|
|
102
|
+
reason: 'changed-file detection is not required before edits',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const result = await getChangedFiles(rootPath, baseRef);
|
|
107
|
+
return {
|
|
108
|
+
available: result.available,
|
|
109
|
+
count: result.files.length,
|
|
110
|
+
files: result.files,
|
|
111
|
+
baseRef: result.baseRef,
|
|
112
|
+
...(result.reason ? { reason: result.reason } : {}),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
return {
|
|
117
|
+
available: false,
|
|
118
|
+
count: 0,
|
|
119
|
+
files: [],
|
|
120
|
+
baseRef: null,
|
|
121
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async function safeSession(rootPath) {
|
|
126
|
+
const { session } = await loadSession(rootPath);
|
|
127
|
+
const touchedFiles = Object.values(session.touchedFiles)
|
|
128
|
+
.sort((a, b) => {
|
|
129
|
+
const byTime = Date.parse(b.lastTouchedAt) - Date.parse(a.lastTouchedAt);
|
|
130
|
+
return byTime !== 0 ? byTime : a.file.localeCompare(b.file);
|
|
131
|
+
})
|
|
132
|
+
.map((touch) => touch.file);
|
|
133
|
+
return {
|
|
134
|
+
id: session.id,
|
|
135
|
+
touchedFiles,
|
|
136
|
+
eventCount: session.events.length,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
async function safeHotspots(rootPath, files, issues) {
|
|
140
|
+
try {
|
|
141
|
+
return await analyzeHotspots(rootPath, files, issues, { limit: 20 });
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async function safeReview(rootPath, mode, options) {
|
|
148
|
+
if (mode === 'before_edit') {
|
|
149
|
+
return { available: false, reason: 'review is not required before edits' };
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
const report = await computeReview(rootPath, {
|
|
153
|
+
base: options.baseRef,
|
|
154
|
+
head: options.headRef,
|
|
155
|
+
});
|
|
156
|
+
return {
|
|
157
|
+
available: report.available,
|
|
158
|
+
verdict: report.available ? report.verdict : undefined,
|
|
159
|
+
summary: report.available ? report.summary.join('; ') : undefined,
|
|
160
|
+
reason: report.available ? undefined : report.reason,
|
|
161
|
+
newTaintFlows: report.available ? report.newTaintFlows.length : undefined,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
return {
|
|
166
|
+
available: false,
|
|
167
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function buildPreflightReasons(input) {
|
|
172
|
+
const reasons = [];
|
|
173
|
+
const changedSet = new Set(input.changedFiles.files);
|
|
174
|
+
const changedOnly = input.mode !== 'before_edit' && input.changedFiles.available;
|
|
175
|
+
for (const issue of input.issues) {
|
|
176
|
+
if (issue.category !== 'supply-chain')
|
|
177
|
+
continue;
|
|
178
|
+
reasons.push({
|
|
179
|
+
severity: issue.severity,
|
|
180
|
+
source: 'supply-chain',
|
|
181
|
+
issueId: issue.id,
|
|
182
|
+
file: firstIssueFile(issue),
|
|
183
|
+
message: `${issue.severity === 'error' ? 'Supply-chain gate blocks' : 'Supply-chain gate flags'} ${issue.id}: ${issue.title}`,
|
|
184
|
+
tool: 'projscan_doctor',
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
for (const issue of input.issues) {
|
|
188
|
+
if (!issue.id.startsWith('plugin:'))
|
|
189
|
+
continue;
|
|
190
|
+
reasons.push({
|
|
191
|
+
severity: issue.severity,
|
|
192
|
+
source: 'plugin',
|
|
193
|
+
issueId: issue.id,
|
|
194
|
+
file: firstIssueFile(issue),
|
|
195
|
+
message: `${issue.severity === 'error' ? 'Plugin policy blocks' : 'Plugin policy flags'} ${issue.id}: ${issue.title}`,
|
|
196
|
+
tool: 'projscan_plugin',
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (changedOnly) {
|
|
200
|
+
const changedIssues = input.issues.filter((issue) => issueTouchesChangedFile(issue, changedSet));
|
|
201
|
+
const error = changedIssues.find((issue) => issue.severity === 'error');
|
|
202
|
+
const warning = changedIssues.find((issue) => issue.severity === 'warning');
|
|
203
|
+
if (error) {
|
|
204
|
+
reasons.push({
|
|
205
|
+
severity: 'error',
|
|
206
|
+
source: 'doctor',
|
|
207
|
+
issueId: error.id,
|
|
208
|
+
file: firstIssueFile(error),
|
|
209
|
+
message: `Health error on changed file: ${error.title}`,
|
|
210
|
+
tool: 'projscan_doctor',
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
else if (warning) {
|
|
214
|
+
reasons.push({
|
|
215
|
+
severity: 'warning',
|
|
216
|
+
source: 'doctor',
|
|
217
|
+
issueId: warning.id,
|
|
218
|
+
file: firstIssueFile(warning),
|
|
219
|
+
message: `Health warning on changed file: ${warning.title}`,
|
|
220
|
+
tool: 'projscan_doctor',
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
else if (input.mode !== 'before_edit' && !input.changedFiles.available) {
|
|
225
|
+
reasons.push({
|
|
226
|
+
severity: 'warning',
|
|
227
|
+
source: 'changed-files',
|
|
228
|
+
message: `Changed files unavailable: ${input.changedFiles.reason ?? 'unknown reason'}`,
|
|
229
|
+
tool: 'projscan_review',
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
if (input.mode !== 'before_edit' &&
|
|
233
|
+
input.changedFiles.available &&
|
|
234
|
+
input.changedFiles.count > input.maxChangedFiles) {
|
|
235
|
+
reasons.push({
|
|
236
|
+
severity: 'warning',
|
|
237
|
+
source: 'changed-files',
|
|
238
|
+
message: `${input.changedFiles.count} changed files exceeds the preflight threshold of ${input.maxChangedFiles}`,
|
|
239
|
+
tool: 'projscan_review',
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
if (input.review.available) {
|
|
243
|
+
if ((input.review.newTaintFlows ?? 0) > 0) {
|
|
244
|
+
reasons.push({
|
|
245
|
+
severity: 'error',
|
|
246
|
+
source: 'taint',
|
|
247
|
+
message: `${input.review.newTaintFlows} new taint flow(s) found in review`,
|
|
248
|
+
tool: 'projscan_review',
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
if (input.review.verdict === 'block') {
|
|
252
|
+
reasons.push({
|
|
253
|
+
severity: 'error',
|
|
254
|
+
source: 'review',
|
|
255
|
+
message: 'Review verdict is block',
|
|
256
|
+
tool: 'projscan_review',
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
else if (input.review.verdict === 'review') {
|
|
260
|
+
reasons.push({
|
|
261
|
+
severity: 'warning',
|
|
262
|
+
source: 'review',
|
|
263
|
+
message: 'Review verdict requires careful review',
|
|
264
|
+
tool: 'projscan_review',
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
else if (input.mode !== 'before_edit') {
|
|
269
|
+
reasons.push({
|
|
270
|
+
severity: 'warning',
|
|
271
|
+
source: 'review',
|
|
272
|
+
message: `Review unavailable: ${input.review.reason ?? 'unknown reason'}`,
|
|
273
|
+
tool: 'projscan_review',
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
const touched = new Set(input.session.touchedFiles);
|
|
277
|
+
const hotspotTouches = input.hotspots?.available === true
|
|
278
|
+
? input.hotspots.hotspots.filter((hotspot) => touched.has(hotspot.relativePath) && hotspot.riskScore >= 40)
|
|
279
|
+
: [];
|
|
280
|
+
for (const hotspot of hotspotTouches.slice(0, 3)) {
|
|
281
|
+
reasons.push({
|
|
282
|
+
severity: 'warning',
|
|
283
|
+
source: 'hotspots',
|
|
284
|
+
file: hotspot.relativePath,
|
|
285
|
+
message: `Touched file overlaps high-risk hotspot ${hotspot.relativePath} (risk ${hotspot.riskScore})`,
|
|
286
|
+
tool: 'projscan_hotspots',
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
if (input.health.errors > 0 && input.mode === 'before_merge' && !changedOnly) {
|
|
290
|
+
reasons.push({
|
|
291
|
+
severity: 'warning',
|
|
292
|
+
source: 'doctor',
|
|
293
|
+
message: `${input.health.errors} project health error(s) exist; changed-file scoping was unavailable`,
|
|
294
|
+
tool: 'projscan_doctor',
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
return reasons;
|
|
298
|
+
}
|
|
299
|
+
function buildEvidence(input) {
|
|
300
|
+
const pluginIssues = input.issues.filter((issue) => issue.id.startsWith('plugin:'));
|
|
301
|
+
const supplyChainIssues = input.issues.filter((issue) => issue.category === 'supply-chain');
|
|
302
|
+
const touched = input.hotspots?.available === true
|
|
303
|
+
? input.hotspots.hotspots
|
|
304
|
+
.filter((hotspot) => input.session.touchedFiles.includes(hotspot.relativePath))
|
|
305
|
+
.slice(0, MAX_EVIDENCE_FILES)
|
|
306
|
+
.map((hotspot) => ({ file: hotspot.relativePath, riskScore: hotspot.riskScore }))
|
|
307
|
+
: [];
|
|
308
|
+
const sessionTouchedFiles = input.session.touchedFiles.slice(0, MAX_EVIDENCE_FILES);
|
|
309
|
+
const changedEvidenceFiles = input.changedFiles.files.slice(0, MAX_EVIDENCE_FILES);
|
|
310
|
+
return {
|
|
311
|
+
health: {
|
|
312
|
+
score: input.health.score,
|
|
313
|
+
grade: input.health.grade,
|
|
314
|
+
errors: input.health.errors,
|
|
315
|
+
warnings: input.health.warnings,
|
|
316
|
+
infos: input.health.infos,
|
|
317
|
+
},
|
|
318
|
+
changedFiles: {
|
|
319
|
+
available: input.changedFiles.available,
|
|
320
|
+
count: input.changedFiles.count,
|
|
321
|
+
files: changedEvidenceFiles,
|
|
322
|
+
...(input.changedFiles.reason ? { reason: input.changedFiles.reason } : {}),
|
|
323
|
+
},
|
|
324
|
+
review: {
|
|
325
|
+
available: input.review.available,
|
|
326
|
+
...(input.review.verdict ? { verdict: input.review.verdict } : {}),
|
|
327
|
+
...(input.review.summary ? { summary: input.review.summary } : {}),
|
|
328
|
+
...(input.review.reason ? { reason: input.review.reason } : {}),
|
|
329
|
+
},
|
|
330
|
+
session: {
|
|
331
|
+
id: input.session.id,
|
|
332
|
+
touchedFiles: sessionTouchedFiles,
|
|
333
|
+
totalTouchedFiles: input.session.touchedFiles.length,
|
|
334
|
+
eventCount: input.session.eventCount,
|
|
335
|
+
...(input.session.touchedFiles.length > MAX_EVIDENCE_FILES ? { truncated: true } : {}),
|
|
336
|
+
},
|
|
337
|
+
hotspots: { touched },
|
|
338
|
+
plugins: {
|
|
339
|
+
enabled: input.pluginsEnabledForRun,
|
|
340
|
+
errorIssues: pluginIssues.filter((issue) => issue.severity === 'error').length,
|
|
341
|
+
warningIssues: pluginIssues.filter((issue) => issue.severity === 'warning').length,
|
|
342
|
+
},
|
|
343
|
+
supplyChain: {
|
|
344
|
+
errorIssues: supplyChainIssues.filter((issue) => issue.severity === 'error').length,
|
|
345
|
+
warningIssues: supplyChainIssues.filter((issue) => issue.severity === 'warning').length,
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
function buildRequiredChecks(mode, health, changedFiles, review, supplyChain) {
|
|
350
|
+
const checks = [
|
|
351
|
+
{
|
|
352
|
+
name: 'health',
|
|
353
|
+
status: health.errors > 0 ? 'fail' : health.warnings > 0 ? 'warn' : 'pass',
|
|
354
|
+
reason: `${health.errors} error(s), ${health.warnings} warning(s), ${health.infos} info`,
|
|
355
|
+
},
|
|
356
|
+
];
|
|
357
|
+
checks.push({
|
|
358
|
+
name: 'supply-chain',
|
|
359
|
+
status: (supplyChain?.errorIssues ?? 0) > 0
|
|
360
|
+
? 'fail'
|
|
361
|
+
: (supplyChain?.warningIssues ?? 0) > 0
|
|
362
|
+
? 'warn'
|
|
363
|
+
: 'pass',
|
|
364
|
+
reason: `${supplyChain?.errorIssues ?? 0} error(s), ${supplyChain?.warningIssues ?? 0} warning(s)`,
|
|
365
|
+
});
|
|
366
|
+
checks.push({
|
|
367
|
+
name: 'changed-files',
|
|
368
|
+
status: changedFiles.available ? 'pass' : 'unavailable',
|
|
369
|
+
reason: changedFiles.available
|
|
370
|
+
? `${changedFiles.count} changed file(s)`
|
|
371
|
+
: changedFiles.reason ?? 'changed-file detection unavailable',
|
|
372
|
+
});
|
|
373
|
+
checks.push({
|
|
374
|
+
name: 'review',
|
|
375
|
+
status: mode === 'before_edit'
|
|
376
|
+
? 'unavailable'
|
|
377
|
+
: !review.available
|
|
378
|
+
? 'unavailable'
|
|
379
|
+
: review.verdict === 'block'
|
|
380
|
+
? 'fail'
|
|
381
|
+
: review.verdict === 'review'
|
|
382
|
+
? 'warn'
|
|
383
|
+
: 'pass',
|
|
384
|
+
reason: mode === 'before_edit'
|
|
385
|
+
? 'review is not required before edits'
|
|
386
|
+
: review.available
|
|
387
|
+
? review.summary ?? review.verdict
|
|
388
|
+
: review.reason ?? 'review unavailable',
|
|
389
|
+
});
|
|
390
|
+
return checks;
|
|
391
|
+
}
|
|
392
|
+
function buildSuggestedActions(reasons, mode, changedFiles) {
|
|
393
|
+
if (reasons.length === 0)
|
|
394
|
+
return [];
|
|
395
|
+
const actions = [];
|
|
396
|
+
if (reasons.some((reason) => reason.source === 'review' || reason.source === 'taint')) {
|
|
397
|
+
actions.push({
|
|
398
|
+
label: 'Inspect the full review before continuing',
|
|
399
|
+
command: 'projscan review --format json',
|
|
400
|
+
tool: 'projscan_review',
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
if (reasons.some((reason) => reason.source === 'doctor' || reason.source === 'plugin' || reason.source === 'supply-chain')) {
|
|
404
|
+
actions.push({
|
|
405
|
+
label: 'Inspect health, plugin policy, and supply-chain findings',
|
|
406
|
+
command: 'projscan doctor --format json',
|
|
407
|
+
tool: 'projscan_doctor',
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
if (reasons.some((reason) => reason.source === 'hotspots')) {
|
|
411
|
+
actions.push({
|
|
412
|
+
label: 'Inspect touched hotspots',
|
|
413
|
+
command: 'projscan hotspots --format json',
|
|
414
|
+
tool: 'projscan_hotspots',
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
if (mode !== 'before_edit' && !changedFiles.available) {
|
|
418
|
+
actions.push({
|
|
419
|
+
label: 'Run preflight with an explicit base ref',
|
|
420
|
+
command: 'projscan preflight --base-ref main --format json',
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
return dedupeActions(actions);
|
|
424
|
+
}
|
|
425
|
+
function buildToolCalls(reasons, mode, changedFiles) {
|
|
426
|
+
return buildSuggestedActions(reasons, mode, changedFiles).map((action) => ({
|
|
427
|
+
label: action.label,
|
|
428
|
+
...(action.tool ? { tool: action.tool } : {}),
|
|
429
|
+
...(action.args ? { args: action.args } : {}),
|
|
430
|
+
}));
|
|
431
|
+
}
|
|
432
|
+
function dedupeActions(actions) {
|
|
433
|
+
const seen = new Set();
|
|
434
|
+
const out = [];
|
|
435
|
+
for (const action of actions) {
|
|
436
|
+
const key = `${action.label}:${action.command ?? action.tool ?? ''}`;
|
|
437
|
+
if (seen.has(key))
|
|
438
|
+
continue;
|
|
439
|
+
seen.add(key);
|
|
440
|
+
out.push(action);
|
|
441
|
+
}
|
|
442
|
+
return out;
|
|
443
|
+
}
|
|
444
|
+
function issueTouchesChangedFile(issue, changedFiles) {
|
|
445
|
+
return (issue.locations ?? []).some((location) => location.file && changedFiles.has(location.file));
|
|
446
|
+
}
|
|
447
|
+
function firstIssueFile(issue) {
|
|
448
|
+
return issue.locations?.find((location) => location.file)?.file;
|
|
449
|
+
}
|
|
450
|
+
//# sourceMappingURL=preflight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../../src/core/preflight.ts"],"names":[],"mappings":"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"}
|
package/dist/core/review.js
CHANGED
|
@@ -40,6 +40,32 @@ export async function computeReview(rootPath, options = {}) {
|
|
|
40
40
|
if (!baseSha) {
|
|
41
41
|
return unavailable(`Could not resolve base ref "${baseRef}".`, options, baseRef, headRef, headSha);
|
|
42
42
|
}
|
|
43
|
+
if (headSha && headSha === baseSha) {
|
|
44
|
+
const report = {
|
|
45
|
+
available: true,
|
|
46
|
+
base: { ref: baseRef, resolvedSha: baseSha },
|
|
47
|
+
head: { ref: headRef, resolvedSha: headSha },
|
|
48
|
+
prDiff: {
|
|
49
|
+
available: true,
|
|
50
|
+
base: { ref: baseRef, resolvedSha: baseSha },
|
|
51
|
+
head: { ref: headRef, resolvedSha: headSha },
|
|
52
|
+
filesAdded: [],
|
|
53
|
+
filesRemoved: [],
|
|
54
|
+
filesModified: [],
|
|
55
|
+
totalFilesChanged: 0,
|
|
56
|
+
},
|
|
57
|
+
changedFiles: [],
|
|
58
|
+
newCycles: [],
|
|
59
|
+
riskyFunctions: [],
|
|
60
|
+
dependencyChanges: [],
|
|
61
|
+
contractChanges: [],
|
|
62
|
+
newTaintFlows: [],
|
|
63
|
+
verdict: 'ok',
|
|
64
|
+
summary: ['No structural changes detected between base and head.'],
|
|
65
|
+
};
|
|
66
|
+
applyIntent(report, options.intent);
|
|
67
|
+
return report;
|
|
68
|
+
}
|
|
43
69
|
// Head-side data: scan + graph + issues + hotspots.
|
|
44
70
|
const headScan = await scanRepository(rootPath);
|
|
45
71
|
const headGraph = await buildCodeGraph(rootPath, headScan.files);
|
|
@@ -126,6 +152,7 @@ export async function computeReview(rootPath, options = {}) {
|
|
|
126
152
|
const riskyFunctions = findRiskyFunctions(baseGraph, headGraph, prDiff);
|
|
127
153
|
// Dependency changes across root + workspaces.
|
|
128
154
|
const dependencyChanges = diffManifests(basePackageManifests, headPackageManifests);
|
|
155
|
+
const contractChanges = buildContractChanges(prDiff, baseGraph, headGraph, basePackageManifests, headPackageManifests);
|
|
129
156
|
// 1.6+ — taint flows newly introduced at head. A flow is "new" iff
|
|
130
157
|
// (a) the (sourceFn, sinkFn) pair didn't exist at base, AND
|
|
131
158
|
// (b) at least one file along the flow's path is in the PR diff.
|
|
@@ -149,6 +176,7 @@ export async function computeReview(rootPath, options = {}) {
|
|
|
149
176
|
newCycles,
|
|
150
177
|
riskyFunctions,
|
|
151
178
|
dependencyChanges,
|
|
179
|
+
contractChanges,
|
|
152
180
|
newTaintFlows,
|
|
153
181
|
verdict,
|
|
154
182
|
summary,
|
|
@@ -157,7 +185,11 @@ export async function computeReview(rootPath, options = {}) {
|
|
|
157
185
|
// annotate each finding with an alignment label, and append a
|
|
158
186
|
// small intent summary to the verdict bullets. Does NOT change the
|
|
159
187
|
// verdict — verdict stays structural.
|
|
160
|
-
|
|
188
|
+
applyIntent(report, options.intent);
|
|
189
|
+
return report;
|
|
190
|
+
}
|
|
191
|
+
function applyIntent(report, rawIntent) {
|
|
192
|
+
const intent = parseIntent(rawIntent);
|
|
161
193
|
if (intent) {
|
|
162
194
|
const analysis = annotateReviewWithIntent(report, intent);
|
|
163
195
|
report.intent = {
|
|
@@ -171,7 +203,6 @@ export async function computeReview(rootPath, options = {}) {
|
|
|
171
203
|
};
|
|
172
204
|
appendIntentToSummary(report.summary, analysis);
|
|
173
205
|
}
|
|
174
|
-
return report;
|
|
175
206
|
}
|
|
176
207
|
async function computeNewTaintFlows(rootPath, baseGraph, headGraph, touchedFiles) {
|
|
177
208
|
const { config } = await loadConfig(rootPath);
|
|
@@ -399,8 +430,22 @@ async function readOneManifest(dir, manifestFile, workspaceName) {
|
|
|
399
430
|
manifestFile,
|
|
400
431
|
dependencies: parsed.dependencies ?? {},
|
|
401
432
|
devDependencies: parsed.devDependencies ?? {},
|
|
433
|
+
entrypoints: readEntrypoints(parsed),
|
|
402
434
|
};
|
|
403
435
|
}
|
|
436
|
+
function readEntrypoints(parsed) {
|
|
437
|
+
const out = {};
|
|
438
|
+
for (const field of ['main', 'module', 'types', 'exports', 'bin']) {
|
|
439
|
+
const value = parsed[field];
|
|
440
|
+
if (value === undefined)
|
|
441
|
+
continue;
|
|
442
|
+
out[field] = entrypointValue(value);
|
|
443
|
+
}
|
|
444
|
+
return out;
|
|
445
|
+
}
|
|
446
|
+
function entrypointValue(value) {
|
|
447
|
+
return typeof value === 'string' ? value : JSON.stringify(value);
|
|
448
|
+
}
|
|
404
449
|
function diffManifests(base, head) {
|
|
405
450
|
const out = [];
|
|
406
451
|
const allManifests = new Set([...base.keys(), ...head.keys()]);
|
|
@@ -417,6 +462,81 @@ function diffManifests(base, head) {
|
|
|
417
462
|
out.sort((a, b) => a.manifestFile.localeCompare(b.manifestFile));
|
|
418
463
|
return out;
|
|
419
464
|
}
|
|
465
|
+
function buildContractChanges(prDiff, baseGraph, headGraph, baseManifests, headManifests) {
|
|
466
|
+
const changes = [];
|
|
467
|
+
for (const file of prDiff.filesAdded) {
|
|
468
|
+
const entry = headGraph.files.get(file);
|
|
469
|
+
for (const exp of entry?.exports ?? []) {
|
|
470
|
+
changes.push(exportContractChange('export-added', file, exp.name));
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
for (const file of prDiff.filesRemoved) {
|
|
474
|
+
const entry = baseGraph.files.get(file);
|
|
475
|
+
for (const exp of entry?.exports ?? []) {
|
|
476
|
+
changes.push(exportContractChange('export-removed', file, exp.name));
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
for (const file of prDiff.filesModified) {
|
|
480
|
+
for (const symbol of file.exportsAdded) {
|
|
481
|
+
changes.push(exportContractChange('export-added', file.relativePath, symbol));
|
|
482
|
+
}
|
|
483
|
+
for (const symbol of file.exportsRemoved) {
|
|
484
|
+
changes.push(exportContractChange('export-removed', file.relativePath, symbol));
|
|
485
|
+
}
|
|
486
|
+
for (const rename of file.exportsRenamed) {
|
|
487
|
+
changes.push({
|
|
488
|
+
kind: 'export-renamed',
|
|
489
|
+
file: file.relativePath,
|
|
490
|
+
symbol: rename.to,
|
|
491
|
+
before: rename.from,
|
|
492
|
+
after: rename.to,
|
|
493
|
+
confidence: 'high',
|
|
494
|
+
why: `Export "${rename.from}" was renamed to "${rename.to}" in ${file.relativePath}; downstream imports of the old name can fail at compile time or runtime.`,
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
changes.push(...entrypointContractChanges(baseManifests, headManifests));
|
|
499
|
+
return changes;
|
|
500
|
+
}
|
|
501
|
+
function exportContractChange(kind, file, symbol) {
|
|
502
|
+
return {
|
|
503
|
+
kind,
|
|
504
|
+
file,
|
|
505
|
+
symbol,
|
|
506
|
+
confidence: 'high',
|
|
507
|
+
why: kind === 'export-added'
|
|
508
|
+
? `Export "${symbol}" was added in ${file}; downstream code may start depending on a new public API.`
|
|
509
|
+
: `Export "${symbol}" was removed from ${file}; downstream imports can fail at compile time or runtime.`,
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
function entrypointContractChanges(base, head) {
|
|
513
|
+
const out = [];
|
|
514
|
+
const allManifests = new Set([...base.keys(), ...head.keys()]);
|
|
515
|
+
for (const manifestFile of allManifests) {
|
|
516
|
+
const baseEntrypoints = base.get(manifestFile)?.entrypoints ?? {};
|
|
517
|
+
const headEntrypoints = head.get(manifestFile)?.entrypoints ?? {};
|
|
518
|
+
const fields = new Set([...Object.keys(baseEntrypoints), ...Object.keys(headEntrypoints)]);
|
|
519
|
+
for (const field of fields) {
|
|
520
|
+
const before = baseEntrypoints[field];
|
|
521
|
+
const after = headEntrypoints[field];
|
|
522
|
+
if (before === after)
|
|
523
|
+
continue;
|
|
524
|
+
const kind = field === 'exports' ? 'public-export-changed' : 'entrypoint-changed';
|
|
525
|
+
out.push({
|
|
526
|
+
kind,
|
|
527
|
+
file: manifestFile,
|
|
528
|
+
symbol: field,
|
|
529
|
+
...(before !== undefined ? { before } : {}),
|
|
530
|
+
...(after !== undefined ? { after } : {}),
|
|
531
|
+
confidence: 'high',
|
|
532
|
+
why: kind === 'public-export-changed'
|
|
533
|
+
? `${manifestFile} package "exports" changed; consumers may resolve different public modules.`
|
|
534
|
+
: `${manifestFile} package "${field}" changed from ${before ?? '<unset>'} to ${after ?? '<unset>'}; package consumers may load a different entrypoint.`,
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return out.sort((a, b) => `${a.file}:${a.symbol ?? ''}`.localeCompare(`${b.file}:${b.symbol ?? ''}`));
|
|
539
|
+
}
|
|
420
540
|
function diffOneManifest(base, head, manifestFile) {
|
|
421
541
|
const workspace = head?.workspace ?? base?.workspace ?? '';
|
|
422
542
|
const baseDeps = base?.dependencies ?? {};
|
|
@@ -645,7 +765,15 @@ export function shapeReviewForTier(report, tier) {
|
|
|
645
765
|
const riskyFunctionsAdded = report.riskyFunctions.length;
|
|
646
766
|
const depsChanged = report.dependencyChanges.length;
|
|
647
767
|
const taintFlowsAdded = report.newTaintFlows?.length ?? 0;
|
|
648
|
-
const
|
|
768
|
+
const contractChanges = report.contractChanges?.length ?? 0;
|
|
769
|
+
const totals = {
|
|
770
|
+
filesChanged,
|
|
771
|
+
cyclesAdded,
|
|
772
|
+
riskyFunctionsAdded,
|
|
773
|
+
depsChanged,
|
|
774
|
+
taintFlowsAdded,
|
|
775
|
+
contractChanges,
|
|
776
|
+
};
|
|
649
777
|
if (tier === 'verdict-only') {
|
|
650
778
|
return {
|
|
651
779
|
available: report.available,
|
|
@@ -683,6 +811,7 @@ export function shapeReviewForTier(report, tier) {
|
|
|
683
811
|
newCycles: report.newCycles.slice(0, 3),
|
|
684
812
|
riskyFunctions: report.riskyFunctions.slice(0, 3),
|
|
685
813
|
dependencyChanges: report.dependencyChanges.slice(0, 3),
|
|
814
|
+
contractChanges: report.contractChanges?.slice(0, TOP) ?? [],
|
|
686
815
|
newTaintFlows: report.newTaintFlows?.slice(0, 5) ?? [],
|
|
687
816
|
verdict: report.verdict,
|
|
688
817
|
summary: report.summary,
|