@reneturcios/tracewatch 0.0.0-stage → 0.1.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.
- package/LICENSE +21 -0
- package/README.md +138 -2
- package/dist/adapters.d.ts +31 -0
- package/dist/adapters.js +128 -0
- package/dist/adapters.js.map +1 -0
- package/dist/blame.d.ts +15 -0
- package/dist/blame.js +218 -0
- package/dist/blame.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +236 -0
- package/dist/cli.js.map +1 -0
- package/dist/core.d.ts +18 -0
- package/dist/core.js +19 -0
- package/dist/core.js.map +1 -0
- package/dist/diff.d.ts +21 -0
- package/dist/diff.js +131 -0
- package/dist/diff.js.map +1 -0
- package/dist/git.d.ts +16 -0
- package/dist/git.js +80 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest.d.ts +54 -0
- package/dist/ingest.js +182 -0
- package/dist/ingest.js.map +1 -0
- package/dist/mcp.d.ts +1 -0
- package/dist/mcp.js +80 -0
- package/dist/mcp.js.map +1 -0
- package/dist/render.d.ts +13 -0
- package/dist/render.js +151 -0
- package/dist/render.js.map +1 -0
- package/dist/report.d.ts +3 -0
- package/dist/report.js +61 -0
- package/dist/report.js.map +1 -0
- package/dist/store.d.ts +31 -0
- package/dist/store.js +163 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +215 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +16 -0
- package/dist/util.js +65 -0
- package/dist/util.js.map +1 -0
- package/dist/watch.d.ts +62 -0
- package/dist/watch.js +401 -0
- package/dist/watch.js.map +1 -0
- package/package.json +1 -6
- package/server.json +1 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* tracewatch CLI.
|
|
4
|
+
*
|
|
5
|
+
* tracewatch ingest <path> [--name <repo>] [--github <owner/repo>] [--tools a,b,c] [--json]
|
|
6
|
+
* tracewatch import <repo> --report <tool>=<file> [--report ...] [--path <p>] [--at <ISO>] [--json]
|
|
7
|
+
* tracewatch diff <repo> [--from <scanId>] [--to <scanId>] [--json]
|
|
8
|
+
* tracewatch blame <repo> (--finding <id> | --rule <rule> --file <path>) [--path <clone>] [--offline] [--json]
|
|
9
|
+
* tracewatch report <repo> [--json]
|
|
10
|
+
* tracewatch findings <repo> [--tool <t>] [--severity <s>] [--status open|resolved|all] [--json]
|
|
11
|
+
* tracewatch watch <path-or-owner/repo> [--path <clone>] [--interval <s>] [--once] [--max-minutes <n>] [--alerts <file>]
|
|
12
|
+
* tracewatch mcp
|
|
13
|
+
* tracewatch --version
|
|
14
|
+
*
|
|
15
|
+
* Every command accepts --store <dir> (default ~/.tracewatch or
|
|
16
|
+
* TRACEWATCH_STORE). Exit codes: 0 success / no changes, 1 a diff found
|
|
17
|
+
* changes, 2 usage error or total failure, 141 when the reader closed
|
|
18
|
+
* the output pipe before the report was delivered.
|
|
19
|
+
*
|
|
20
|
+
* Every report goes through emit(), which waits for stdout to flush
|
|
21
|
+
* before the exit code takes effect: the factory emit contract in
|
|
22
|
+
* FACTORY-NOTES.md. Calling process.exit() right after console.log()
|
|
23
|
+
* truncates piped output past one pipe buffer (64 KiB on Linux) while
|
|
24
|
+
* still exiting 0, which is how agents and CI silently lose reports.
|
|
25
|
+
*/
|
|
26
|
+
import { readFileSync } from "node:fs";
|
|
27
|
+
import { VERSION, Store, defaultStoreDir, diffScans, explainFinding, importReports, ingestPath, renderDiff, renderFindings, renderHealth, renderProvenance, renderScanSummary, repoHealth, watch, } from "./core.js";
|
|
28
|
+
function exitBrokenPipe() {
|
|
29
|
+
process.exit(141);
|
|
30
|
+
}
|
|
31
|
+
process.stdout.on("error", (err) => {
|
|
32
|
+
if (err.code === "EPIPE")
|
|
33
|
+
exitBrokenPipe();
|
|
34
|
+
throw err;
|
|
35
|
+
});
|
|
36
|
+
/** Write one full report and resolve only after stdout has flushed it. */
|
|
37
|
+
async function emit(text, code) {
|
|
38
|
+
process.exitCode = code;
|
|
39
|
+
await new Promise((resolve, reject) => {
|
|
40
|
+
process.stdout.write(`${text}\n`, (err) => {
|
|
41
|
+
if (!err) {
|
|
42
|
+
resolve();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (err.code === "EPIPE")
|
|
46
|
+
exitBrokenPipe();
|
|
47
|
+
reject(err);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function usage() {
|
|
52
|
+
console.error(`Usage:
|
|
53
|
+
tracewatch ingest <path> [--name <repo>] [--github <owner/repo>] [--tools a,b,c] [--json]
|
|
54
|
+
tracewatch import <repo> --report <tool>=<file> [--report ...] [--path <p>] [--at <ISO>] [--json]
|
|
55
|
+
tracewatch diff <repo> [--from <scanId>] [--to <scanId>] [--json]
|
|
56
|
+
tracewatch blame <repo> (--finding <id> | --rule <rule> --file <path>) [--path <clone>] [--offline] [--json]
|
|
57
|
+
tracewatch report <repo> [--json]
|
|
58
|
+
tracewatch findings <repo> [--tool <t>] [--severity <s>] [--status open|resolved|all] [--json]
|
|
59
|
+
tracewatch watch <path-or-owner/repo> [--path <clone>] [--interval <s>] [--once] [--max-minutes <n>] [--alerts <file>]
|
|
60
|
+
tracewatch mcp
|
|
61
|
+
tracewatch --version
|
|
62
|
+
(every command accepts --store <dir>)`);
|
|
63
|
+
process.exit(2);
|
|
64
|
+
}
|
|
65
|
+
function flagValue(args, name) {
|
|
66
|
+
const i = args.indexOf(name);
|
|
67
|
+
return i >= 0 && i + 1 < args.length ? args[i + 1] : undefined;
|
|
68
|
+
}
|
|
69
|
+
function flagValues(args, name) {
|
|
70
|
+
const out = [];
|
|
71
|
+
for (let i = 0; i + 1 < args.length; i++)
|
|
72
|
+
if (args[i] === name)
|
|
73
|
+
out.push(args[i + 1]);
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
function has(args, name) {
|
|
77
|
+
return args.includes(name);
|
|
78
|
+
}
|
|
79
|
+
function positional(args, skipFlagsWithValues) {
|
|
80
|
+
const out = [];
|
|
81
|
+
for (let i = 0; i < args.length; i++) {
|
|
82
|
+
const a = args[i];
|
|
83
|
+
if (skipFlagsWithValues.includes(a)) {
|
|
84
|
+
i++;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (a.startsWith("--"))
|
|
88
|
+
continue;
|
|
89
|
+
out.push(a);
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
const VALUE_FLAGS = ["--name", "--github", "--tools", "--store", "--report", "--path", "--at", "--from", "--to", "--finding", "--rule", "--file", "--tool", "--severity", "--status", "--interval", "--max-minutes", "--alerts"];
|
|
94
|
+
async function main() {
|
|
95
|
+
const argv = process.argv.slice(2);
|
|
96
|
+
const [cmd, ...rest] = argv;
|
|
97
|
+
if (cmd === "--version" || cmd === "-v" || cmd === "version") {
|
|
98
|
+
console.log(VERSION);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (cmd === "mcp") {
|
|
102
|
+
await import("./mcp.js");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (!cmd)
|
|
106
|
+
usage();
|
|
107
|
+
const store = new Store(flagValue(argv, "--store") ?? defaultStoreDir());
|
|
108
|
+
const json = has(argv, "--json");
|
|
109
|
+
try {
|
|
110
|
+
if (cmd === "ingest") {
|
|
111
|
+
const [target] = positional(rest, VALUE_FLAGS);
|
|
112
|
+
if (!target)
|
|
113
|
+
usage();
|
|
114
|
+
const toolsArg = flagValue(rest, "--tools");
|
|
115
|
+
const tools = toolsArg
|
|
116
|
+
? toolsArg.split(",").map((s) => s.trim()).filter(Boolean)
|
|
117
|
+
: undefined;
|
|
118
|
+
const result = await ingestPath(store, target, {
|
|
119
|
+
name: flagValue(rest, "--name"),
|
|
120
|
+
github: flagValue(rest, "--github"),
|
|
121
|
+
tools,
|
|
122
|
+
});
|
|
123
|
+
const allFailed = result.runs.length > 0 && result.runs.every((r) => r.info.status === "error");
|
|
124
|
+
const text = json ? JSON.stringify({ scan: result.record, findings: result.observations }, null, 2) : renderScanSummary(result);
|
|
125
|
+
await emit(text, allFailed ? 2 : 0);
|
|
126
|
+
}
|
|
127
|
+
else if (cmd === "import") {
|
|
128
|
+
const [repo] = positional(rest, VALUE_FLAGS);
|
|
129
|
+
const reportArgs = flagValues(rest, "--report");
|
|
130
|
+
if (!repo || reportArgs.length === 0)
|
|
131
|
+
usage();
|
|
132
|
+
const reports = reportArgs.map((spec) => {
|
|
133
|
+
const eq = spec.indexOf("=");
|
|
134
|
+
if (eq <= 0)
|
|
135
|
+
usage();
|
|
136
|
+
const tool = spec.slice(0, eq);
|
|
137
|
+
const file = spec.slice(eq + 1);
|
|
138
|
+
return { tool, report: JSON.parse(readFileSync(file, "utf8")) };
|
|
139
|
+
});
|
|
140
|
+
const result = importReports(store, {
|
|
141
|
+
repo,
|
|
142
|
+
path: flagValue(rest, "--path"),
|
|
143
|
+
github: flagValue(rest, "--github"),
|
|
144
|
+
at: flagValue(rest, "--at"),
|
|
145
|
+
reports,
|
|
146
|
+
});
|
|
147
|
+
const text = json ? JSON.stringify({ scan: result.record, findings: result.observations }, null, 2) : renderScanSummary(result);
|
|
148
|
+
await emit(text, 0);
|
|
149
|
+
}
|
|
150
|
+
else if (cmd === "diff") {
|
|
151
|
+
const [repo] = positional(rest, VALUE_FLAGS);
|
|
152
|
+
if (!repo)
|
|
153
|
+
usage();
|
|
154
|
+
const diff = diffScans(store, repo, flagValue(rest, "--from"), flagValue(rest, "--to"));
|
|
155
|
+
const changed = diff.added.length + diff.resolved.length + diff.changed.length > 0;
|
|
156
|
+
await emit(json ? JSON.stringify(diff, null, 2) : renderDiff(diff), changed ? 1 : 0);
|
|
157
|
+
}
|
|
158
|
+
else if (cmd === "blame") {
|
|
159
|
+
const [repo] = positional(rest, VALUE_FLAGS);
|
|
160
|
+
if (!repo)
|
|
161
|
+
usage();
|
|
162
|
+
let id = flagValue(rest, "--finding");
|
|
163
|
+
if (!id) {
|
|
164
|
+
const rule = flagValue(rest, "--rule");
|
|
165
|
+
const file = flagValue(rest, "--file");
|
|
166
|
+
if (!rule || !file)
|
|
167
|
+
usage();
|
|
168
|
+
const match = store
|
|
169
|
+
.trackedFindings(repo)
|
|
170
|
+
.filter((t) => t.latest.rule === rule && t.latest.file === file)
|
|
171
|
+
.sort((a, b) => b.lastSeenAt.localeCompare(a.lastSeenAt))[0];
|
|
172
|
+
if (!match) {
|
|
173
|
+
console.error(`error: no tracked finding for rule ${rule} in ${file} on repo "${repo}"`);
|
|
174
|
+
process.exitCode = 2;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
id = match.latest.findingId;
|
|
178
|
+
}
|
|
179
|
+
const explained = await explainFinding(store, repo, id, {
|
|
180
|
+
path: flagValue(rest, "--path"),
|
|
181
|
+
offline: has(rest, "--offline"),
|
|
182
|
+
});
|
|
183
|
+
if (!explained) {
|
|
184
|
+
console.error(`error: finding "${id}" not found on repo "${repo}"`);
|
|
185
|
+
process.exitCode = 2;
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
await emit(json ? JSON.stringify(explained.provenance, null, 2) : renderProvenance(explained.provenance), 0);
|
|
189
|
+
}
|
|
190
|
+
else if (cmd === "report") {
|
|
191
|
+
const [repo] = positional(rest, VALUE_FLAGS);
|
|
192
|
+
if (!repo)
|
|
193
|
+
usage();
|
|
194
|
+
const health = repoHealth(store, repo);
|
|
195
|
+
await emit(json ? JSON.stringify(health, null, 2) : renderHealth(health), 0);
|
|
196
|
+
}
|
|
197
|
+
else if (cmd === "findings") {
|
|
198
|
+
const [repo] = positional(rest, VALUE_FLAGS);
|
|
199
|
+
if (!repo)
|
|
200
|
+
usage();
|
|
201
|
+
const tool = flagValue(rest, "--tool");
|
|
202
|
+
const severity = flagValue(rest, "--severity");
|
|
203
|
+
const status = flagValue(rest, "--status") ?? "open";
|
|
204
|
+
const tracked = store
|
|
205
|
+
.trackedFindings(repo)
|
|
206
|
+
.filter((t) => (tool ? t.latest.tool === tool : true))
|
|
207
|
+
.filter((t) => (severity ? t.latest.severity === severity : true))
|
|
208
|
+
.filter((t) => (status === "all" ? true : t.status === status));
|
|
209
|
+
await emit(json ? JSON.stringify(tracked, null, 2) : renderFindings(repo, tracked), 0);
|
|
210
|
+
}
|
|
211
|
+
else if (cmd === "watch") {
|
|
212
|
+
const [target] = positional(rest, VALUE_FLAGS);
|
|
213
|
+
if (!target)
|
|
214
|
+
usage();
|
|
215
|
+
await watch({
|
|
216
|
+
store,
|
|
217
|
+
target,
|
|
218
|
+
name: flagValue(rest, "--name"),
|
|
219
|
+
path: flagValue(rest, "--path"),
|
|
220
|
+
intervalSec: Number(flagValue(rest, "--interval") ?? 60),
|
|
221
|
+
once: has(rest, "--once"),
|
|
222
|
+
maxMinutes: flagValue(rest, "--max-minutes") ? Number(flagValue(rest, "--max-minutes")) : undefined,
|
|
223
|
+
alertsFile: flagValue(rest, "--alerts"),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
usage();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
console.error(`error: ${err instanceof Error ? err.message : String(err)}`);
|
|
232
|
+
process.exitCode = 2;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
void main();
|
|
236
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tracewatch core facade. The domain logic lives in focused modules:
|
|
3
|
+
* adapters (report shapes), ingest (tool runs and imports), store
|
|
4
|
+
* (JSONL persistence and derived status), diff, blame (provenance),
|
|
5
|
+
* report (health), and watch (early detection with time-to-detect).
|
|
6
|
+
*/
|
|
7
|
+
export declare const VERSION = "0.1.1";
|
|
8
|
+
export * from "./types.js";
|
|
9
|
+
export * from "./util.js";
|
|
10
|
+
export * from "./store.js";
|
|
11
|
+
export * from "./adapters.js";
|
|
12
|
+
export * from "./ingest.js";
|
|
13
|
+
export * from "./diff.js";
|
|
14
|
+
export * from "./blame.js";
|
|
15
|
+
export * from "./report.js";
|
|
16
|
+
export * from "./watch.js";
|
|
17
|
+
export * from "./render.js";
|
|
18
|
+
export * from "./git.js";
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tracewatch core facade. The domain logic lives in focused modules:
|
|
3
|
+
* adapters (report shapes), ingest (tool runs and imports), store
|
|
4
|
+
* (JSONL persistence and derived status), diff, blame (provenance),
|
|
5
|
+
* report (health), and watch (early detection with time-to-detect).
|
|
6
|
+
*/
|
|
7
|
+
export const VERSION = "0.1.1";
|
|
8
|
+
export * from "./types.js";
|
|
9
|
+
export * from "./util.js";
|
|
10
|
+
export * from "./store.js";
|
|
11
|
+
export * from "./adapters.js";
|
|
12
|
+
export * from "./ingest.js";
|
|
13
|
+
export * from "./diff.js";
|
|
14
|
+
export * from "./blame.js";
|
|
15
|
+
export * from "./report.js";
|
|
16
|
+
export * from "./watch.js";
|
|
17
|
+
export * from "./render.js";
|
|
18
|
+
export * from "./git.js";
|
|
19
|
+
//# sourceMappingURL=core.js.map
|
package/dist/core.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAE/B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
|
package/dist/diff.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scan diffing. Two scans of one repo are compared by finding identity:
|
|
3
|
+
*
|
|
4
|
+
* - NEW: identity only in the later scan
|
|
5
|
+
* - RESOLVED: identity only in the earlier scan
|
|
6
|
+
* - CHANGED: identity in both, but the findingId or severity moved
|
|
7
|
+
* (content edit, severity regrade, or, for actionpin, a ref move)
|
|
8
|
+
*
|
|
9
|
+
* Action ref moves are first-class: a pin regression (PINNED to MUTABLE
|
|
10
|
+
* or BRANCH), a pin improvement, or a bare ref move (the tj-actions
|
|
11
|
+
* shape, where the ref under a name changed) each produce a RefEvent
|
|
12
|
+
* with both values spelled out. Output ordering is by identity
|
|
13
|
+
* everywhere, so the same store state always renders the same diff.
|
|
14
|
+
*/
|
|
15
|
+
import type { Store } from "./store.js";
|
|
16
|
+
import { type FindingObs, type RefEvent, type ScanDiff, type ScanRecord } from "./types.js";
|
|
17
|
+
export declare function diffObs(repo: string, fromScan: ScanRecord | null, toScan: ScanRecord, fromObs: FindingObs[], toObs: FindingObs[]): ScanDiff;
|
|
18
|
+
/** Diff two scans of a repo by id; defaults to the last two scans. */
|
|
19
|
+
export declare function diffScans(store: Store, repo: string, fromId?: string, toId?: string): ScanDiff;
|
|
20
|
+
/** Every ref event across consecutive scan pairs, oldest first. */
|
|
21
|
+
export declare function allRefEvents(store: Store, repo: string): RefEvent[];
|
package/dist/diff.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { TOOLS } from "./types.js";
|
|
2
|
+
function refEventFor(before, after, scan) {
|
|
3
|
+
if (before.tool !== "actionpin" || after.tool !== "actionpin")
|
|
4
|
+
return undefined;
|
|
5
|
+
const oldRef = String(before.data.ref ?? "");
|
|
6
|
+
const newRef = String(after.data.ref ?? "");
|
|
7
|
+
const oldClass = String(before.data.classification ?? "");
|
|
8
|
+
const newClass = String(after.data.classification ?? "");
|
|
9
|
+
if (oldRef === newRef && oldClass === newClass)
|
|
10
|
+
return undefined;
|
|
11
|
+
let kind = "ref-move";
|
|
12
|
+
if (oldClass === "PINNED" && newClass !== "PINNED")
|
|
13
|
+
kind = "pin-regression";
|
|
14
|
+
else if (newClass === "PINNED" && oldClass !== "PINNED")
|
|
15
|
+
kind = "pin-improvement";
|
|
16
|
+
return {
|
|
17
|
+
identity: after.identity,
|
|
18
|
+
file: after.file,
|
|
19
|
+
action: String(after.data.action ?? after.file),
|
|
20
|
+
oldRef,
|
|
21
|
+
newRef,
|
|
22
|
+
oldClassification: oldClass,
|
|
23
|
+
newClassification: newClass,
|
|
24
|
+
kind,
|
|
25
|
+
scanId: scan.scanId,
|
|
26
|
+
at: scan.at,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function describeChanges(before, after) {
|
|
30
|
+
const changes = [];
|
|
31
|
+
if (before.severity !== after.severity)
|
|
32
|
+
changes.push(`severity: ${before.severity} -> ${after.severity}`);
|
|
33
|
+
if (before.rule !== after.rule)
|
|
34
|
+
changes.push(`rule: ${before.rule} -> ${after.rule}`);
|
|
35
|
+
if (before.tool === "actionpin" && after.tool === "actionpin") {
|
|
36
|
+
if (before.data.ref !== after.data.ref)
|
|
37
|
+
changes.push(`ref: ${String(before.data.ref)} -> ${String(after.data.ref)}`);
|
|
38
|
+
if (before.data.classification !== after.data.classification) {
|
|
39
|
+
changes.push(`classification: ${String(before.data.classification)} -> ${String(after.data.classification)}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (before.tool === "hookcheck" && after.tool === "hookcheck" && before.data.command !== after.data.command) {
|
|
43
|
+
changes.push("command changed");
|
|
44
|
+
}
|
|
45
|
+
if (before.tool === "injectcheck" && after.tool === "injectcheck" && before.excerpt !== after.excerpt) {
|
|
46
|
+
changes.push("matched content changed");
|
|
47
|
+
}
|
|
48
|
+
if (changes.length === 0 && before.findingId !== after.findingId)
|
|
49
|
+
changes.push("content changed");
|
|
50
|
+
return changes;
|
|
51
|
+
}
|
|
52
|
+
export function diffObs(repo, fromScan, toScan, fromObs, toObs) {
|
|
53
|
+
const fromById = new Map(fromObs.map((o) => [o.identity, o]));
|
|
54
|
+
const toById = new Map(toObs.map((o) => [o.identity, o]));
|
|
55
|
+
const added = [];
|
|
56
|
+
const resolved = [];
|
|
57
|
+
const changed = [];
|
|
58
|
+
const refEvents = [];
|
|
59
|
+
let unchangedCount = 0;
|
|
60
|
+
for (const [identity, after] of toById) {
|
|
61
|
+
const before = fromById.get(identity);
|
|
62
|
+
if (!before) {
|
|
63
|
+
added.push(after);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (before.findingId === after.findingId && before.severity === after.severity) {
|
|
67
|
+
unchangedCount++;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const refEvent = refEventFor(before, after, toScan);
|
|
71
|
+
if (refEvent)
|
|
72
|
+
refEvents.push(refEvent);
|
|
73
|
+
changed.push({ identity, before, after, changes: describeChanges(before, after), refEvent });
|
|
74
|
+
}
|
|
75
|
+
for (const [identity, before] of fromById) {
|
|
76
|
+
if (!toById.has(identity))
|
|
77
|
+
resolved.push(before);
|
|
78
|
+
}
|
|
79
|
+
const byIdentity = (a, b) => a.identity.localeCompare(b.identity);
|
|
80
|
+
added.sort(byIdentity);
|
|
81
|
+
resolved.sort(byIdentity);
|
|
82
|
+
changed.sort(byIdentity);
|
|
83
|
+
refEvents.sort(byIdentity);
|
|
84
|
+
const verdictMoves = TOOLS.map((tool) => ({
|
|
85
|
+
tool,
|
|
86
|
+
from: fromScan?.tools[tool]?.verdict ?? null,
|
|
87
|
+
to: toScan.tools[tool]?.verdict ?? null,
|
|
88
|
+
})).filter((m) => m.from !== m.to);
|
|
89
|
+
return {
|
|
90
|
+
repo,
|
|
91
|
+
from: fromScan ? { scanId: fromScan.scanId, at: fromScan.at } : null,
|
|
92
|
+
to: { scanId: toScan.scanId, at: toScan.at },
|
|
93
|
+
added,
|
|
94
|
+
resolved,
|
|
95
|
+
changed,
|
|
96
|
+
unchangedCount,
|
|
97
|
+
refEvents,
|
|
98
|
+
verdictMoves,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Diff two scans of a repo by id; defaults to the last two scans. */
|
|
102
|
+
export function diffScans(store, repo, fromId, toId) {
|
|
103
|
+
const scans = store.scans(repo);
|
|
104
|
+
if (scans.length === 0)
|
|
105
|
+
throw new Error(`no scans recorded for repo "${repo}"`);
|
|
106
|
+
const to = toId ? store.scanById(toId) : scans[scans.length - 1];
|
|
107
|
+
if (!to || to.repo !== repo)
|
|
108
|
+
throw new Error(`scan "${toId}" not found for repo "${repo}"`);
|
|
109
|
+
let from = null;
|
|
110
|
+
if (fromId) {
|
|
111
|
+
from = store.scanById(fromId) ?? null;
|
|
112
|
+
if (!from || from.repo !== repo)
|
|
113
|
+
throw new Error(`scan "${fromId}" not found for repo "${repo}"`);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
const idx = scans.findIndex((s) => s.scanId === to.scanId);
|
|
117
|
+
from = idx > 0 ? scans[idx - 1] : null;
|
|
118
|
+
}
|
|
119
|
+
return diffObs(repo, from, to, from ? store.observations(from.scanId) : [], store.observations(to.scanId));
|
|
120
|
+
}
|
|
121
|
+
/** Every ref event across consecutive scan pairs, oldest first. */
|
|
122
|
+
export function allRefEvents(store, repo) {
|
|
123
|
+
const scans = store.scans(repo);
|
|
124
|
+
const events = [];
|
|
125
|
+
for (let i = 1; i < scans.length; i++) {
|
|
126
|
+
const d = diffObs(repo, scans[i - 1], scans[i], store.observations(scans[i - 1].scanId), store.observations(scans[i].scanId));
|
|
127
|
+
events.push(...d.refEvents);
|
|
128
|
+
}
|
|
129
|
+
return events;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=diff.js.map
|
package/dist/diff.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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"}
|
package/dist/git.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CommitInfo } from "./types.js";
|
|
2
|
+
export declare function git(args: string[], cwd: string, timeoutMs?: number): Promise<string | null>;
|
|
3
|
+
export declare function headSha(cwd: string): Promise<string | null>;
|
|
4
|
+
export declare function commitTime(cwd: string, ref?: string): Promise<string | null>;
|
|
5
|
+
/** Parse "git@github.com:owner/repo.git" and https forms to owner/repo. */
|
|
6
|
+
export declare function parseGithubSlug(remoteUrl: string): string | null;
|
|
7
|
+
export declare function remoteSlug(cwd: string): Promise<string | null>;
|
|
8
|
+
export declare function parseLogLine(line: string): CommitInfo | null;
|
|
9
|
+
/**
|
|
10
|
+
* Commits whose diff introduced (or removed) the needle in the file,
|
|
11
|
+
* newest first, via the pickaxe. -S is a literal string search, so
|
|
12
|
+
* needles with regex characters are safe as single arguments.
|
|
13
|
+
*/
|
|
14
|
+
export declare function logPickaxe(cwd: string, needle: string, file?: string): Promise<CommitInfo[]>;
|
|
15
|
+
/** The commit git blame assigns to one line of a file at HEAD. */
|
|
16
|
+
export declare function blameLine(cwd: string, file: string, line: number): Promise<CommitInfo | null>;
|
package/dist/git.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin git helpers. Every function returns null (never throws) when git
|
|
3
|
+
* is unavailable or the directory is not a repo, so callers can state
|
|
4
|
+
* "not established" instead of crashing on a non-repo target.
|
|
5
|
+
*/
|
|
6
|
+
import { execFile } from "node:child_process";
|
|
7
|
+
export function git(args, cwd, timeoutMs = 30000) {
|
|
8
|
+
return new Promise((resolve) => {
|
|
9
|
+
execFile("git", args, { cwd, timeout: timeoutMs, maxBuffer: 16 * 1024 * 1024 }, (err, stdout) => {
|
|
10
|
+
resolve(err ? null : stdout);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export async function headSha(cwd) {
|
|
15
|
+
const out = await git(["rev-parse", "HEAD"], cwd);
|
|
16
|
+
const sha = out?.trim();
|
|
17
|
+
return sha && /^[0-9a-f]{40}$/.test(sha) ? sha : null;
|
|
18
|
+
}
|
|
19
|
+
export async function commitTime(cwd, ref = "HEAD") {
|
|
20
|
+
const out = await git(["show", "-s", "--format=%cI", ref], cwd);
|
|
21
|
+
return out ? out.trim() : null;
|
|
22
|
+
}
|
|
23
|
+
/** Parse "git@github.com:owner/repo.git" and https forms to owner/repo. */
|
|
24
|
+
export function parseGithubSlug(remoteUrl) {
|
|
25
|
+
const m = remoteUrl.match(/github\.com[:/]([^/]+)\/([^/]+?)(?:\.git)?$/) ??
|
|
26
|
+
remoteUrl.match(/^([^/\s]+)\/([^/\s]+)$/);
|
|
27
|
+
return m ? `${m[1]}/${m[2]}` : null;
|
|
28
|
+
}
|
|
29
|
+
export async function remoteSlug(cwd) {
|
|
30
|
+
const out = await git(["remote", "get-url", "origin"], cwd);
|
|
31
|
+
return out ? parseGithubSlug(out.trim()) : null;
|
|
32
|
+
}
|
|
33
|
+
const LOG_FORMAT = "%H%x1f%an%x1f%aI%x1f%s";
|
|
34
|
+
export function parseLogLine(line) {
|
|
35
|
+
const parts = line.split("\x1f");
|
|
36
|
+
if (parts.length < 4 || !/^[0-9a-f]{40}$/.test(parts[0]))
|
|
37
|
+
return null;
|
|
38
|
+
return { sha: parts[0], author: parts[1], date: parts[2], subject: parts.slice(3).join("\x1f") };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Commits whose diff introduced (or removed) the needle in the file,
|
|
42
|
+
* newest first, via the pickaxe. -S is a literal string search, so
|
|
43
|
+
* needles with regex characters are safe as single arguments.
|
|
44
|
+
*/
|
|
45
|
+
export async function logPickaxe(cwd, needle, file) {
|
|
46
|
+
if (!needle)
|
|
47
|
+
return [];
|
|
48
|
+
const args = ["log", `--format=${LOG_FORMAT}`, "-S", needle, "--"];
|
|
49
|
+
if (file)
|
|
50
|
+
args.push(file);
|
|
51
|
+
const out = await git(args, cwd, 60000);
|
|
52
|
+
if (!out)
|
|
53
|
+
return [];
|
|
54
|
+
return out.split("\n").map(parseLogLine).filter((c) => c !== null);
|
|
55
|
+
}
|
|
56
|
+
/** The commit git blame assigns to one line of a file at HEAD. */
|
|
57
|
+
export async function blameLine(cwd, file, line) {
|
|
58
|
+
const out = await git(["blame", "--porcelain", "-L", `${line},${line}`, "HEAD", "--", file], cwd);
|
|
59
|
+
if (!out)
|
|
60
|
+
return null;
|
|
61
|
+
let sha = "";
|
|
62
|
+
let author = "";
|
|
63
|
+
let time = "";
|
|
64
|
+
let subject = "";
|
|
65
|
+
for (const l of out.split("\n")) {
|
|
66
|
+
if (!sha && /^[0-9a-f]{40} /.test(l))
|
|
67
|
+
sha = l.split(" ")[0];
|
|
68
|
+
else if (l.startsWith("author "))
|
|
69
|
+
author = l.slice("author ".length);
|
|
70
|
+
else if (l.startsWith("author-time ")) {
|
|
71
|
+
const secs = Number(l.slice("author-time ".length));
|
|
72
|
+
if (Number.isFinite(secs))
|
|
73
|
+
time = new Date(secs * 1000).toISOString();
|
|
74
|
+
}
|
|
75
|
+
else if (l.startsWith("summary "))
|
|
76
|
+
subject = l.slice("summary ".length);
|
|
77
|
+
}
|
|
78
|
+
return sha ? { sha, author, date: time, subject } : null;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=git.js.map
|
package/dist/git.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,MAAM,UAAU,GAAG,CAAC,IAAc,EAAE,GAAW,EAAE,SAAS,GAAG,KAAK;IAChE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;YAC9F,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,GAAW;IACvC,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC;IACxB,OAAO,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,GAAG,GAAG,MAAM;IACxD,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;IAChE,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,MAAM,CAAC,GACL,SAAS,CAAC,KAAK,CAAC,6CAA6C,CAAC;QAC9D,SAAS,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5D,OAAO,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,GAAG,wBAAwB,CAAC;AAE5C,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACtE,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AACnG,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,MAAc,EAAE,IAAa;IACzE,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IACvB,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,YAAY,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACnE,IAAI,IAAI;QAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACxC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAmB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;AACtF,CAAC;AAED,kEAAkE;AAClE,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,IAAY,EAAE,IAAY;IACrE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IAClG,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,IAAI,CAAC,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;aACvD,IAAI,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;aAChE,IAAI,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;YACpD,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QACxE,CAAC;aAAM,IAAI,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3D,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC"}
|
package/dist/ingest.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type AdaptedReport } from "./adapters.js";
|
|
2
|
+
import type { Store } from "./store.js";
|
|
3
|
+
import { type FindingObs, type ScanRecord, type ToolName, type ToolScanInfo } from "./types.js";
|
|
4
|
+
export interface ToolCommand {
|
|
5
|
+
cmd: string;
|
|
6
|
+
args: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function resolveToolCommand(tool: ToolName): ToolCommand;
|
|
9
|
+
interface Capture {
|
|
10
|
+
code: number | null;
|
|
11
|
+
stdout: string;
|
|
12
|
+
stderr: string;
|
|
13
|
+
timedOut: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function runCapture(cmd: string, args: string[], timeoutMs?: number): Promise<Capture>;
|
|
16
|
+
export declare function toolVersion(tool: ToolName): Promise<string>;
|
|
17
|
+
export interface ToolRun {
|
|
18
|
+
tool: ToolName;
|
|
19
|
+
info: ToolScanInfo;
|
|
20
|
+
adapted: AdaptedReport | null;
|
|
21
|
+
}
|
|
22
|
+
export declare function runTool(tool: ToolName, target: string): Promise<ToolRun>;
|
|
23
|
+
/** Run injectcheck against a single text file (watch mode issue/file scans). */
|
|
24
|
+
export declare function runInjectcheckFile(file: string): Promise<AdaptedReport | null>;
|
|
25
|
+
export interface IngestResult {
|
|
26
|
+
record: ScanRecord;
|
|
27
|
+
observations: FindingObs[];
|
|
28
|
+
runs: ToolRun[];
|
|
29
|
+
}
|
|
30
|
+
/** Stamp adapted reports into the store as one scan record. Exported for watch mode. */
|
|
31
|
+
export declare function recordScan(store: Store, repo: string, source: ScanRecord["source"], adaptedList: AdaptedReport[], infos: Partial<Record<ToolName, ToolScanInfo>>, extra: {
|
|
32
|
+
path?: string;
|
|
33
|
+
github?: string;
|
|
34
|
+
headSha?: string | null;
|
|
35
|
+
at?: string;
|
|
36
|
+
warnings?: string[];
|
|
37
|
+
}): IngestResult;
|
|
38
|
+
export declare function ingestPath(store: Store, target: string, opts?: {
|
|
39
|
+
name?: string;
|
|
40
|
+
github?: string;
|
|
41
|
+
tools?: ToolName[];
|
|
42
|
+
source?: ScanRecord["source"];
|
|
43
|
+
}): Promise<IngestResult>;
|
|
44
|
+
export declare function importReports(store: Store, opts: {
|
|
45
|
+
repo: string;
|
|
46
|
+
path?: string;
|
|
47
|
+
github?: string;
|
|
48
|
+
at?: string;
|
|
49
|
+
reports: {
|
|
50
|
+
tool: ToolName;
|
|
51
|
+
report: unknown;
|
|
52
|
+
}[];
|
|
53
|
+
}): IngestResult;
|
|
54
|
+
export {};
|