@expressots/studio-agent 4.0.0-preview.1

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.
Files changed (86) hide show
  1. package/README.md +143 -0
  2. package/dist/agent.d.ts +127 -0
  3. package/dist/agent.d.ts.map +1 -0
  4. package/dist/agent.js +1031 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/discovery/index.d.ts +2 -0
  7. package/dist/discovery/index.d.ts.map +1 -0
  8. package/dist/discovery/index.js +2 -0
  9. package/dist/discovery/index.js.map +1 -0
  10. package/dist/discovery/route-scanner.d.ts +35 -0
  11. package/dist/discovery/route-scanner.d.ts.map +1 -0
  12. package/dist/discovery/route-scanner.js +385 -0
  13. package/dist/discovery/route-scanner.js.map +1 -0
  14. package/dist/index.d.ts +15 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +15 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/instrumentation/index.d.ts +2 -0
  19. package/dist/instrumentation/index.d.ts.map +1 -0
  20. package/dist/instrumentation/index.js +2 -0
  21. package/dist/instrumentation/index.js.map +1 -0
  22. package/dist/instrumentation/tracer.d.ts +40 -0
  23. package/dist/instrumentation/tracer.d.ts.map +1 -0
  24. package/dist/instrumentation/tracer.js +190 -0
  25. package/dist/instrumentation/tracer.js.map +1 -0
  26. package/dist/introspection/container-introspector.d.ts +81 -0
  27. package/dist/introspection/container-introspector.d.ts.map +1 -0
  28. package/dist/introspection/container-introspector.js +251 -0
  29. package/dist/introspection/container-introspector.js.map +1 -0
  30. package/dist/logging/log-capture.d.ts +58 -0
  31. package/dist/logging/log-capture.d.ts.map +1 -0
  32. package/dist/logging/log-capture.js +184 -0
  33. package/dist/logging/log-capture.js.map +1 -0
  34. package/dist/recording/index.d.ts +2 -0
  35. package/dist/recording/index.d.ts.map +1 -0
  36. package/dist/recording/index.js +2 -0
  37. package/dist/recording/index.js.map +1 -0
  38. package/dist/recording/request-recorder.d.ts +43 -0
  39. package/dist/recording/request-recorder.d.ts.map +1 -0
  40. package/dist/recording/request-recorder.js +373 -0
  41. package/dist/recording/request-recorder.js.map +1 -0
  42. package/dist/security/fix-resolver.d.ts +40 -0
  43. package/dist/security/fix-resolver.d.ts.map +1 -0
  44. package/dist/security/fix-resolver.js +283 -0
  45. package/dist/security/fix-resolver.js.map +1 -0
  46. package/dist/security/fix-runner.d.ts +60 -0
  47. package/dist/security/fix-runner.d.ts.map +1 -0
  48. package/dist/security/fix-runner.js +188 -0
  49. package/dist/security/fix-runner.js.map +1 -0
  50. package/dist/security/index.d.ts +140 -0
  51. package/dist/security/index.d.ts.map +1 -0
  52. package/dist/security/index.js +460 -0
  53. package/dist/security/index.js.map +1 -0
  54. package/dist/security/lockfile-graph.d.ts +69 -0
  55. package/dist/security/lockfile-graph.d.ts.map +1 -0
  56. package/dist/security/lockfile-graph.js +245 -0
  57. package/dist/security/lockfile-graph.js.map +1 -0
  58. package/dist/security/npm-audit.d.ts +67 -0
  59. package/dist/security/npm-audit.d.ts.map +1 -0
  60. package/dist/security/npm-audit.js +320 -0
  61. package/dist/security/npm-audit.js.map +1 -0
  62. package/dist/security/osv-cache.d.ts +51 -0
  63. package/dist/security/osv-cache.d.ts.map +1 -0
  64. package/dist/security/osv-cache.js +99 -0
  65. package/dist/security/osv-cache.js.map +1 -0
  66. package/dist/security/osv-client.d.ts +47 -0
  67. package/dist/security/osv-client.d.ts.map +1 -0
  68. package/dist/security/osv-client.js +247 -0
  69. package/dist/security/osv-client.js.map +1 -0
  70. package/dist/security/posture-analyzer.d.ts +44 -0
  71. package/dist/security/posture-analyzer.d.ts.map +1 -0
  72. package/dist/security/posture-analyzer.js +397 -0
  73. package/dist/security/posture-analyzer.js.map +1 -0
  74. package/dist/security/reachability.d.ts +59 -0
  75. package/dist/security/reachability.d.ts.map +1 -0
  76. package/dist/security/reachability.js +302 -0
  77. package/dist/security/reachability.js.map +1 -0
  78. package/dist/security/score.d.ts +36 -0
  79. package/dist/security/score.d.ts.map +1 -0
  80. package/dist/security/score.js +94 -0
  81. package/dist/security/score.js.map +1 -0
  82. package/dist/types/index.d.ts +587 -0
  83. package/dist/types/index.d.ts.map +1 -0
  84. package/dist/types/index.js +14 -0
  85. package/dist/types/index.js.map +1 -0
  86. package/package.json +75 -0
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Security engine — orchestrates supply-chain scanning (npm audit +
3
+ * OSV) and runtime posture analysis, packages the result into a single
4
+ * `SecurityReport`, and offers a debounced re-run hook the agent can
5
+ * call on each new exchange/log without breaking the host event loop.
6
+ *
7
+ * The engine is intentionally framework-free: it takes plain snapshot
8
+ * functions from the agent and emits reports to a listener. That makes
9
+ * it trivially testable and keeps the security policy (debounce,
10
+ * change detection, gating on connected clients) firmly in the agent
11
+ * itself — the engine just provides the data.
12
+ */
13
+ import type { AppStructure, FixProgressMessage, FixResultMessage, RecordedExchange, RouteInfo, SecurityReport } from '../types/index.js';
14
+ import type { LogEntry } from '../logging/log-capture.js';
15
+ /**
16
+ * Snapshot accessors the engine reads on each pass. Functions, not
17
+ * snapshot objects, so we always see the freshest state without the
18
+ * agent having to thread updates through.
19
+ */
20
+ export interface SecurityEngineDeps {
21
+ cwd: string;
22
+ dbPath: string;
23
+ getRoutes: () => RouteInfo[];
24
+ getStructure: () => AppStructure | null;
25
+ getExchanges: () => RecordedExchange[];
26
+ getLogs: () => LogEntry[];
27
+ }
28
+ export type SecurityReportListener = (report: SecurityReport) => void;
29
+ /**
30
+ * Hook the engine calls during an "Apply fix" run so the agent can
31
+ * stream output back to the UI. Kept as a callback (not a listener
32
+ * registered via `onReport`) because progress is per-call, not a
33
+ * global subscription.
34
+ */
35
+ export type FixProgressListener = (msg: FixProgressMessage) => void;
36
+ /**
37
+ * Input to `applyFix` — references either a single finding (`findingId`)
38
+ * or a fix group (`fixGroupId`). When the request can't be resolved
39
+ * (stale id, no matching fix), the engine resolves with `success: false`
40
+ * and an explanatory `summary` rather than throwing.
41
+ */
42
+ export interface ApplyFixInput {
43
+ targetKind: 'finding' | 'fix-group';
44
+ /** ID of the target — either `FixGroup.id` or `DependencyFinding.id`. */
45
+ targetId: string;
46
+ /** Set to true to allow semver-major upgrades (`--force`). */
47
+ allowMajor?: boolean;
48
+ }
49
+ export declare class SecurityEngine {
50
+ private readonly deps;
51
+ private readonly osvClient;
52
+ private readonly osvCache;
53
+ private lastDependencies;
54
+ private lastFixGroups;
55
+ private lastFixAvailability;
56
+ private lastLockfile;
57
+ private lastReachability;
58
+ private lastReport;
59
+ private lastHash;
60
+ private listener;
61
+ private postureTimer;
62
+ /**
63
+ * Start in `running` so a freshly-connected UI doesn't briefly show
64
+ * "no vulnerabilities" before the first scan completes. The engine
65
+ * flips this to `idle` / `error` when `runFullScan` finishes.
66
+ */
67
+ private auditState;
68
+ private auditError;
69
+ private missingLockfile;
70
+ private auditInFlight;
71
+ /** State of an in-flight Apply-fix job (one at a time). */
72
+ private fixState;
73
+ private fixInFlight;
74
+ constructor(deps: SecurityEngineDeps);
75
+ /** Subscribe to security report transitions. Only one listener supported. */
76
+ onReport(listener: SecurityReportListener): void;
77
+ /** Latest known report (always safe — initialised to an empty one). */
78
+ getReport(): SecurityReport;
79
+ /**
80
+ * Run a full scan: `npm audit` + OSV.dev + posture analysis. Safe to
81
+ * call repeatedly — concurrent calls coalesce onto the in-flight
82
+ * promise so we never spawn two `npm audit` children at once.
83
+ */
84
+ runFullScan(): Promise<void>;
85
+ /**
86
+ * Apply an enrichment pipeline against the latest snapshots. Split
87
+ * out so `scheduleRefresh` can re-run reachability against fresh
88
+ * exchanges without re-fetching OSV / re-running npm audit.
89
+ */
90
+ private enrichDependencies;
91
+ /**
92
+ * Notify the engine that some upstream state likely changed (a new
93
+ * exchange, log line, etc.). Debounced — multiple calls inside the
94
+ * debounce window collapse to a single posture pass.
95
+ */
96
+ scheduleRefresh(): void;
97
+ /** Cancel any pending refresh — called from `StudioAgent.stop()`. */
98
+ stop(): void;
99
+ /**
100
+ * Rebuild the report from current state and emit if its finding-id
101
+ * hash changed (or if the scan state changed). This is the single
102
+ * point where we decide whether to disturb the WS stream.
103
+ *
104
+ * On a posture-only refresh we also re-run reachability against the
105
+ * latest exchange buffer so the chips ("confirmed: 5 hits") update
106
+ * without a full audit.
107
+ */
108
+ private rebuildAndEmit;
109
+ /** Emit a transient "scan running / error" frame even when findings haven't changed. */
110
+ private emitProgress;
111
+ /**
112
+ * Apply a remediation. The caller (agent) wires the per-line progress
113
+ * callback into a `fix_progress` WS broadcast. Returns the final
114
+ * `FixResultMessage` once the spawned command exits.
115
+ *
116
+ * The method enforces two invariants:
117
+ * 1. Only one fix runs at a time (`fixInFlight` is awaited).
118
+ * 2. After every fix attempt — success or failure — we trigger a
119
+ * full rescan. The post-scan `security` frame is what tells the
120
+ * UI whether the change actually cleared the advisory.
121
+ */
122
+ applyFix(input: ApplyFixInput, onProgress: FixProgressListener): Promise<FixResultMessage>;
123
+ /**
124
+ * Look up the FixSpec corresponding to the user's request and convert
125
+ * it into the argv tuple `runFix` expects. Returns `null` for unknown
126
+ * ids / nothing-to-do specs.
127
+ */
128
+ private resolveFixTarget;
129
+ private snapshotScanState;
130
+ }
131
+ export { OsvCache } from './osv-cache.js';
132
+ export { OsvClient } from './osv-client.js';
133
+ export { runNpmAudit } from './npm-audit.js';
134
+ export { analyzePosture } from './posture-analyzer.js';
135
+ export { buildSecurityReport, hashFindingIds, emptyReport } from './score.js';
136
+ export { LockfileGraph } from './lockfile-graph.js';
137
+ export { enrichFindings as enrichFindingsWithFixes, buildFixGroups, } from './fix-resolver.js';
138
+ export { buildReachabilitySnapshot, enrichWithReachability, } from './reachability.js';
139
+ export { runFix, buildFixArgs } from './fix-runner.js';
140
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,460 @@
1
+ /**
2
+ * Security engine — orchestrates supply-chain scanning (npm audit +
3
+ * OSV) and runtime posture analysis, packages the result into a single
4
+ * `SecurityReport`, and offers a debounced re-run hook the agent can
5
+ * call on each new exchange/log without breaking the host event loop.
6
+ *
7
+ * The engine is intentionally framework-free: it takes plain snapshot
8
+ * functions from the agent and emits reports to a listener. That makes
9
+ * it trivially testable and keeps the security policy (debounce,
10
+ * change detection, gating on connected clients) firmly in the agent
11
+ * itself — the engine just provides the data.
12
+ */
13
+ import * as fs from 'node:fs';
14
+ import * as path from 'node:path';
15
+ import { runNpmAudit, } from './npm-audit.js';
16
+ import { OsvClient } from './osv-client.js';
17
+ import { OsvCache } from './osv-cache.js';
18
+ import { analyzePosture } from './posture-analyzer.js';
19
+ import { buildSecurityReport, emptyReport, hashFindingIds, } from './score.js';
20
+ import { LockfileGraph } from './lockfile-graph.js';
21
+ import { buildFixGroups, enrichFindings, } from './fix-resolver.js';
22
+ import { buildReachabilitySnapshot, enrichWithReachability, } from './reachability.js';
23
+ import { buildFixArgs, runFix, } from './fix-runner.js';
24
+ /** How often the engine will re-run posture analysis on event-driven triggers. */
25
+ const POSTURE_DEBOUNCE_MS = 2000;
26
+ export class SecurityEngine {
27
+ deps;
28
+ osvClient;
29
+ osvCache;
30
+ lastDependencies = [];
31
+ lastFixGroups = [];
32
+ lastFixAvailability = new Map();
33
+ lastLockfile = null;
34
+ lastReachability = null;
35
+ lastReport;
36
+ lastHash = '';
37
+ listener = null;
38
+ postureTimer = null;
39
+ /**
40
+ * Start in `running` so a freshly-connected UI doesn't briefly show
41
+ * "no vulnerabilities" before the first scan completes. The engine
42
+ * flips this to `idle` / `error` when `runFullScan` finishes.
43
+ */
44
+ auditState = 'running';
45
+ auditError;
46
+ missingLockfile = false;
47
+ auditInFlight = null;
48
+ /** State of an in-flight Apply-fix job (one at a time). */
49
+ fixState = undefined;
50
+ fixInFlight = null;
51
+ constructor(deps) {
52
+ this.deps = deps;
53
+ this.osvCache = new OsvCache(deps.dbPath);
54
+ this.osvClient = new OsvClient(this.osvCache);
55
+ this.lastReport = emptyReport(this.snapshotScanState(0));
56
+ }
57
+ /** Subscribe to security report transitions. Only one listener supported. */
58
+ onReport(listener) {
59
+ this.listener = listener;
60
+ }
61
+ /** Latest known report (always safe — initialised to an empty one). */
62
+ getReport() {
63
+ return this.lastReport;
64
+ }
65
+ /**
66
+ * Run a full scan: `npm audit` + OSV.dev + posture analysis. Safe to
67
+ * call repeatedly — concurrent calls coalesce onto the in-flight
68
+ * promise so we never spawn two `npm audit` children at once.
69
+ */
70
+ async runFullScan() {
71
+ if (this.auditInFlight)
72
+ return this.auditInFlight;
73
+ this.auditInFlight = (async () => {
74
+ this.auditState = 'running';
75
+ this.auditError = undefined;
76
+ this.emitProgress();
77
+ const audit = await runNpmAudit(this.deps.cwd);
78
+ this.missingLockfile = audit.state === 'missing-lockfile';
79
+ this.lastFixAvailability = audit.fixAvailability;
80
+ if (audit.state === 'error') {
81
+ this.auditState = 'error';
82
+ this.auditError = audit.error;
83
+ }
84
+ else {
85
+ this.auditState = 'idle';
86
+ }
87
+ let osvFindings = [];
88
+ if (audit.state === 'ok') {
89
+ try {
90
+ const packages = readInstalledPackages(this.deps.cwd);
91
+ osvFindings = await this.osvClient.lookup(packages);
92
+ }
93
+ catch {
94
+ // OSV failures degrade gracefully — we still ship npm audit findings.
95
+ }
96
+ }
97
+ // Reconcile npm + OSV first; then enrich with lockfile root-cause
98
+ // analysis; then with reachability. The enrichment passes are pure
99
+ // functions of (findings, snapshot) so order is deterministic.
100
+ const reconciled = reconcileDependencyFindings(audit.findings, osvFindings);
101
+ this.lastLockfile = LockfileGraph.load(this.deps.cwd);
102
+ this.lastReachability = await buildReachabilitySnapshot(this.deps.cwd, this.deps.getStructure());
103
+ this.lastDependencies = this.enrichDependencies(reconciled);
104
+ this.lastFixGroups = buildFixGroups(this.lastDependencies);
105
+ this.rebuildAndEmit();
106
+ })();
107
+ try {
108
+ await this.auditInFlight;
109
+ }
110
+ finally {
111
+ this.auditInFlight = null;
112
+ }
113
+ }
114
+ /**
115
+ * Apply an enrichment pipeline against the latest snapshots. Split
116
+ * out so `scheduleRefresh` can re-run reachability against fresh
117
+ * exchanges without re-fetching OSV / re-running npm audit.
118
+ */
119
+ enrichDependencies(findings) {
120
+ const withFix = enrichFindings(findings, this.lastFixAvailability, this.lastLockfile);
121
+ if (!this.lastReachability)
122
+ return withFix;
123
+ return enrichWithReachability(withFix, this.lastReachability, this.deps.getExchanges());
124
+ }
125
+ /**
126
+ * Notify the engine that some upstream state likely changed (a new
127
+ * exchange, log line, etc.). Debounced — multiple calls inside the
128
+ * debounce window collapse to a single posture pass.
129
+ */
130
+ scheduleRefresh() {
131
+ if (this.postureTimer)
132
+ return;
133
+ this.postureTimer = setTimeout(() => {
134
+ this.postureTimer = null;
135
+ this.rebuildAndEmit();
136
+ }, POSTURE_DEBOUNCE_MS);
137
+ }
138
+ /** Cancel any pending refresh — called from `StudioAgent.stop()`. */
139
+ stop() {
140
+ if (this.postureTimer) {
141
+ clearTimeout(this.postureTimer);
142
+ this.postureTimer = null;
143
+ }
144
+ this.osvCache.flush();
145
+ }
146
+ /**
147
+ * Rebuild the report from current state and emit if its finding-id
148
+ * hash changed (or if the scan state changed). This is the single
149
+ * point where we decide whether to disturb the WS stream.
150
+ *
151
+ * On a posture-only refresh we also re-run reachability against the
152
+ * latest exchange buffer so the chips ("confirmed: 5 hits") update
153
+ * without a full audit.
154
+ */
155
+ rebuildAndEmit() {
156
+ const posture = analyzePosture({
157
+ routes: this.deps.getRoutes(),
158
+ structure: this.deps.getStructure(),
159
+ exchanges: this.deps.getExchanges(),
160
+ logs: this.deps.getLogs(),
161
+ });
162
+ // Light-touch refresh: reachability snapshot only depends on src/
163
+ // (rarely changes during a session) so we reuse the cached one,
164
+ // but we re-run `enrichWithReachability` to fold in the latest
165
+ // exchange counts.
166
+ if (this.lastReachability && this.lastDependencies.length > 0) {
167
+ this.lastDependencies = enrichWithReachability(this.lastDependencies, this.lastReachability, this.deps.getExchanges());
168
+ // Reachability changes can move findings between groups (severity
169
+ // tie-break uses reachability), so we rebuild groups too.
170
+ this.lastFixGroups = buildFixGroups(this.lastDependencies);
171
+ }
172
+ const report = buildSecurityReport({
173
+ dependencies: this.lastDependencies,
174
+ posture,
175
+ fixGroups: this.lastFixGroups,
176
+ scanState: this.snapshotScanState(Date.now()),
177
+ });
178
+ const nextHash = hashFindingIds(report) +
179
+ '|' +
180
+ scanStateHash(report.scanState) +
181
+ '|' +
182
+ hashReachability(report.dependencies);
183
+ this.lastReport = report;
184
+ if (nextHash !== this.lastHash) {
185
+ this.lastHash = nextHash;
186
+ this.listener?.(report);
187
+ }
188
+ }
189
+ /** Emit a transient "scan running / error" frame even when findings haven't changed. */
190
+ emitProgress() {
191
+ const report = buildSecurityReport({
192
+ dependencies: this.lastDependencies,
193
+ posture: this.lastReport.posture,
194
+ fixGroups: this.lastFixGroups,
195
+ scanState: this.snapshotScanState(this.lastReport.scanState.postureLastRunAt),
196
+ });
197
+ this.lastReport = report;
198
+ // Force-emit: scan state transitions are user-visible.
199
+ this.lastHash =
200
+ hashFindingIds(report) +
201
+ '|' +
202
+ scanStateHash(report.scanState) +
203
+ '|' +
204
+ hashReachability(report.dependencies);
205
+ this.listener?.(report);
206
+ }
207
+ /**
208
+ * Apply a remediation. The caller (agent) wires the per-line progress
209
+ * callback into a `fix_progress` WS broadcast. Returns the final
210
+ * `FixResultMessage` once the spawned command exits.
211
+ *
212
+ * The method enforces two invariants:
213
+ * 1. Only one fix runs at a time (`fixInFlight` is awaited).
214
+ * 2. After every fix attempt — success or failure — we trigger a
215
+ * full rescan. The post-scan `security` frame is what tells the
216
+ * UI whether the change actually cleared the advisory.
217
+ */
218
+ async applyFix(input, onProgress) {
219
+ if (this.fixInFlight) {
220
+ return {
221
+ targetId: input.targetId,
222
+ success: false,
223
+ exitCode: null,
224
+ durationMs: 0,
225
+ command: '',
226
+ summary: 'Another fix is already running. Please wait.',
227
+ };
228
+ }
229
+ const target = this.resolveFixTarget(input);
230
+ if (!target) {
231
+ return {
232
+ targetId: input.targetId,
233
+ success: false,
234
+ exitCode: null,
235
+ durationMs: 0,
236
+ command: '',
237
+ summary: 'Fix target not found. Rescan and try again.',
238
+ };
239
+ }
240
+ const job = (async () => {
241
+ this.fixState = {
242
+ state: 'running',
243
+ targetId: input.targetId,
244
+ command: target.pretty,
245
+ };
246
+ this.emitProgress();
247
+ const result = await runFix({
248
+ cwd: this.deps.cwd,
249
+ kind: target.kind,
250
+ package: target.package,
251
+ version: target.version,
252
+ targetId: input.targetId,
253
+ }, (line, stream) => onProgress({
254
+ targetId: input.targetId,
255
+ stream,
256
+ line,
257
+ timestamp: Date.now(),
258
+ }));
259
+ const summary = result.state === 'success'
260
+ ? `${target.pretty} completed in ${(result.durationMs / 1000).toFixed(1)}s`
261
+ : `${target.pretty} failed (${result.exitCode ?? 'no exit code'})`;
262
+ const finalMsg = {
263
+ targetId: input.targetId,
264
+ success: result.state === 'success',
265
+ exitCode: result.exitCode,
266
+ durationMs: result.durationMs,
267
+ command: result.command || target.pretty,
268
+ summary,
269
+ errorTail: result.state === 'success'
270
+ ? undefined
271
+ : result.stderrTail.slice(-4096) || result.stdoutTail.slice(-4096),
272
+ };
273
+ this.fixState = {
274
+ state: result.state === 'success' ? 'success' : 'error',
275
+ targetId: input.targetId,
276
+ command: result.command || target.pretty,
277
+ error: result.state === 'success' ? undefined : summary,
278
+ };
279
+ // Always rescan — even on failure — so the UI agrees with the
280
+ // lockfile's actual current state, not what we *hoped* would change.
281
+ await this.runFullScan();
282
+ // Clear the fix banner once the rescan has updated everything else.
283
+ this.fixState = undefined;
284
+ this.emitProgress();
285
+ return finalMsg;
286
+ })();
287
+ this.fixInFlight = job;
288
+ try {
289
+ return await job;
290
+ }
291
+ finally {
292
+ this.fixInFlight = null;
293
+ }
294
+ }
295
+ /**
296
+ * Look up the FixSpec corresponding to the user's request and convert
297
+ * it into the argv tuple `runFix` expects. Returns `null` for unknown
298
+ * ids / nothing-to-do specs.
299
+ */
300
+ resolveFixTarget(input) {
301
+ const spec = input.targetKind === 'fix-group'
302
+ ? this.lastFixGroups.find((g) => g.id === input.targetId)?.fix
303
+ : this.lastDependencies.find((f) => f.id === input.targetId)?.fix;
304
+ if (!spec)
305
+ return null;
306
+ let kind;
307
+ switch (spec.kind) {
308
+ case 'install':
309
+ kind = 'install';
310
+ break;
311
+ case 'audit-fix':
312
+ kind = 'audit-fix';
313
+ break;
314
+ case 'audit-fix-force':
315
+ kind = input.allowMajor ? 'audit-fix-force' : 'audit-fix-force';
316
+ break;
317
+ case 'override':
318
+ case 'none':
319
+ return null;
320
+ }
321
+ // For `install` we need to break the version out of the command.
322
+ let pkg;
323
+ let ver;
324
+ if (kind === 'install') {
325
+ const m = spec.command.match(/^npm install\s+(.+?)@([^@]+)$/);
326
+ if (!m)
327
+ return null;
328
+ pkg = m[1].trim();
329
+ ver = m[2].trim().replace(/^['"]|['"]$/g, '');
330
+ }
331
+ const argv = buildFixArgs({
332
+ cwd: this.deps.cwd,
333
+ kind,
334
+ package: pkg,
335
+ version: ver,
336
+ targetId: input.targetId,
337
+ });
338
+ if (!argv)
339
+ return null;
340
+ return { kind, pretty: argv.pretty, package: pkg, version: ver };
341
+ }
342
+ snapshotScanState(postureLastRunAt) {
343
+ return {
344
+ audit: this.auditState,
345
+ postureLastRunAt,
346
+ auditError: this.auditError,
347
+ missingLockfile: this.missingLockfile || undefined,
348
+ fix: this.fixState,
349
+ };
350
+ }
351
+ }
352
+ /**
353
+ * Reachability counts are part of the report payload — when a recorded
354
+ * exchange flips a finding from `likely` → `confirmed` we want the UI
355
+ * to update even if the finding-id set hasn't changed.
356
+ */
357
+ function hashReachability(deps) {
358
+ const parts = [];
359
+ for (const f of deps) {
360
+ const r = f.reachability;
361
+ if (!r)
362
+ continue;
363
+ parts.push(`${f.id}:${r.level}:${r.runtimeHits}`);
364
+ }
365
+ parts.sort();
366
+ return parts.join('|');
367
+ }
368
+ function scanStateHash(s) {
369
+ return [
370
+ s.audit,
371
+ s.missingLockfile ? '1' : '0',
372
+ s.auditError ?? '',
373
+ s.fix?.state ?? '',
374
+ s.fix?.targetId ?? '',
375
+ ].join('|');
376
+ }
377
+ /**
378
+ * Combine findings from `npm audit` and OSV, deduping by id. We trust
379
+ * npm audit's transitive `path` (it knows the lockfile) and OSV's
380
+ * severity/refs (richer than what npm reports). When both sources
381
+ * produce a finding for the same id, we merge.
382
+ */
383
+ function reconcileDependencyFindings(fromNpm, fromOsv) {
384
+ const byId = new Map();
385
+ for (const f of fromNpm)
386
+ byId.set(f.id, { ...f });
387
+ for (const f of fromOsv) {
388
+ const existing = byId.get(f.id);
389
+ if (!existing) {
390
+ byId.set(f.id, f);
391
+ continue;
392
+ }
393
+ // Merge: keep npm's path (it knows the resolution graph), prefer
394
+ // OSV's references/summary/cvss (they're richer), and pick the
395
+ // higher severity to avoid silently downgrading anything.
396
+ byId.set(f.id, {
397
+ ...existing,
398
+ summary: f.summary || existing.summary,
399
+ references: dedupe([...existing.references, ...f.references]),
400
+ severity: pickHigherSeverity(existing.severity, f.severity),
401
+ cvss: f.cvss ?? existing.cvss,
402
+ fixedVersion: f.fixedVersion ?? existing.fixedVersion,
403
+ });
404
+ }
405
+ return [...byId.values()];
406
+ }
407
+ function pickHigherSeverity(a, b) {
408
+ const order = [
409
+ 'INFO',
410
+ 'LOW',
411
+ 'MEDIUM',
412
+ 'HIGH',
413
+ 'CRITICAL',
414
+ ];
415
+ return order.indexOf(a) >= order.indexOf(b) ? a : b;
416
+ }
417
+ function dedupe(arr) {
418
+ return [...new Set(arr)];
419
+ }
420
+ /**
421
+ * Read the host's `package.json` and return a flat list of direct
422
+ * dependencies to query OSV for. We don't traverse `node_modules` here
423
+ * — npm audit already covers transitive vulns; querying OSV for every
424
+ * transitive dep would blow up the batch size and add latency for
425
+ * diminishing returns.
426
+ */
427
+ function readInstalledPackages(cwd) {
428
+ const file = path.join(cwd, 'package.json');
429
+ if (!fs.existsSync(file))
430
+ return [];
431
+ try {
432
+ const raw = fs.readFileSync(file, 'utf-8');
433
+ const parsed = JSON.parse(raw);
434
+ const out = [];
435
+ for (const map of [parsed.dependencies, parsed.devDependencies]) {
436
+ if (!map)
437
+ continue;
438
+ for (const [name, version] of Object.entries(map)) {
439
+ out.push({ name, version: stripSemverPrefix(version) });
440
+ }
441
+ }
442
+ return out;
443
+ }
444
+ catch {
445
+ return [];
446
+ }
447
+ }
448
+ function stripSemverPrefix(version) {
449
+ return version.replace(/^[\^~>=<]+/, '').trim();
450
+ }
451
+ export { OsvCache } from './osv-cache.js';
452
+ export { OsvClient } from './osv-client.js';
453
+ export { runNpmAudit } from './npm-audit.js';
454
+ export { analyzePosture } from './posture-analyzer.js';
455
+ export { buildSecurityReport, hashFindingIds, emptyReport } from './score.js';
456
+ export { LockfileGraph } from './lockfile-graph.js';
457
+ export { enrichFindings as enrichFindingsWithFixes, buildFixGroups, } from './fix-resolver.js';
458
+ export { buildReachabilitySnapshot, enrichWithReachability, } from './reachability.js';
459
+ export { runFix, buildFixArgs } from './fix-runner.js';
460
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"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"}