@kevinrabun/judges 3.98.0 → 3.99.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/CHANGELOG.md +13 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +63 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/finding-auto-suppress.d.ts +5 -0
- package/dist/commands/finding-auto-suppress.d.ts.map +1 -0
- package/dist/commands/finding-auto-suppress.js +127 -0
- package/dist/commands/finding-auto-suppress.js.map +1 -0
- package/dist/commands/finding-dismiss-workflow.d.ts +5 -0
- package/dist/commands/finding-dismiss-workflow.d.ts.map +1 -0
- package/dist/commands/finding-dismiss-workflow.js +120 -0
- package/dist/commands/finding-dismiss-workflow.js.map +1 -0
- package/dist/commands/finding-reachability-check.d.ts +5 -0
- package/dist/commands/finding-reachability-check.d.ts.map +1 -0
- package/dist/commands/finding-reachability-check.js +103 -0
- package/dist/commands/finding-reachability-check.js.map +1 -0
- package/dist/commands/review-audit-export.d.ts +5 -0
- package/dist/commands/review-audit-export.d.ts.map +1 -0
- package/dist/commands/review-audit-export.js +94 -0
- package/dist/commands/review-audit-export.js.map +1 -0
- package/dist/commands/review-data-retention.d.ts +5 -0
- package/dist/commands/review-data-retention.d.ts.map +1 -0
- package/dist/commands/review-data-retention.js +120 -0
- package/dist/commands/review-data-retention.js.map +1 -0
- package/dist/commands/review-permission-model.d.ts +5 -0
- package/dist/commands/review-permission-model.d.ts.map +1 -0
- package/dist/commands/review-permission-model.js +150 -0
- package/dist/commands/review-permission-model.js.map +1 -0
- package/dist/commands/review-pipeline-status.d.ts +5 -0
- package/dist/commands/review-pipeline-status.d.ts.map +1 -0
- package/dist/commands/review-pipeline-status.js +55 -0
- package/dist/commands/review-pipeline-status.js.map +1 -0
- package/dist/commands/review-repo-onboard.d.ts +5 -0
- package/dist/commands/review-repo-onboard.d.ts.map +1 -0
- package/dist/commands/review-repo-onboard.js +115 -0
- package/dist/commands/review-repo-onboard.js.map +1 -0
- package/dist/commands/review-review-comments.d.ts +5 -0
- package/dist/commands/review-review-comments.d.ts.map +1 -0
- package/dist/commands/review-review-comments.js +85 -0
- package/dist/commands/review-review-comments.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-auto-suppress.d.ts","sourceRoot":"","sources":["../../src/commands/finding-auto-suppress.ts"],"names":[],"mappings":"AAAA;;GAEG;AAsBH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAqI3D"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding-auto-suppress — Automatically suppress findings matching criteria.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
5
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
6
|
+
export function runFindingAutoSuppress(argv) {
|
|
7
|
+
const storeIdx = argv.indexOf("--store");
|
|
8
|
+
const storePath = storeIdx >= 0 ? argv[storeIdx + 1] : ".judges-suppressions.json";
|
|
9
|
+
const formatIdx = argv.indexOf("--format");
|
|
10
|
+
const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
|
|
11
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
12
|
+
console.log(`
|
|
13
|
+
judges finding-auto-suppress — Automatically suppress findings
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
judges finding-auto-suppress [--store <path>]
|
|
17
|
+
[--add-rule <id> --field <f> --pattern <p> --reason <reason>]
|
|
18
|
+
[--remove-rule <id>] [--apply <report> --out <path>]
|
|
19
|
+
[--format table|json]
|
|
20
|
+
|
|
21
|
+
Options:
|
|
22
|
+
--store <path> Suppression store (default: .judges-suppressions.json)
|
|
23
|
+
--add-rule <id> Add suppression rule
|
|
24
|
+
--field <f> Match field: ruleId, severity, title
|
|
25
|
+
--pattern <p> Match pattern (substring)
|
|
26
|
+
--reason <reason> Suppression reason
|
|
27
|
+
--remove-rule <id> Remove rule by id
|
|
28
|
+
--apply <report> Apply suppressions to report, output filtered findings
|
|
29
|
+
--out <path> Write filtered report to file
|
|
30
|
+
--format <fmt> Output format: table (default), json
|
|
31
|
+
--help, -h Show this help
|
|
32
|
+
`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
let store;
|
|
36
|
+
if (existsSync(storePath)) {
|
|
37
|
+
store = JSON.parse(readFileSync(storePath, "utf-8"));
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
store = { rules: [], lastUpdated: new Date().toISOString().split("T")[0] };
|
|
41
|
+
}
|
|
42
|
+
// Add rule
|
|
43
|
+
const addIdx = argv.indexOf("--add-rule");
|
|
44
|
+
if (addIdx >= 0) {
|
|
45
|
+
const id = argv[addIdx + 1];
|
|
46
|
+
const fieldIdx = argv.indexOf("--field");
|
|
47
|
+
const patternIdx = argv.indexOf("--pattern");
|
|
48
|
+
const reasonIdx = argv.indexOf("--reason");
|
|
49
|
+
const rule = {
|
|
50
|
+
id,
|
|
51
|
+
field: (fieldIdx >= 0 ? argv[fieldIdx + 1] : "ruleId"),
|
|
52
|
+
pattern: patternIdx >= 0 ? argv[patternIdx + 1] : "",
|
|
53
|
+
reason: reasonIdx >= 0 ? argv[reasonIdx + 1] : "",
|
|
54
|
+
createdAt: new Date().toISOString().split("T")[0],
|
|
55
|
+
};
|
|
56
|
+
const existingIdx = store.rules.findIndex((r) => r.id === id);
|
|
57
|
+
if (existingIdx >= 0) {
|
|
58
|
+
store.rules[existingIdx] = rule;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
store.rules.push(rule);
|
|
62
|
+
}
|
|
63
|
+
store.lastUpdated = new Date().toISOString().split("T")[0];
|
|
64
|
+
writeFileSync(storePath, JSON.stringify(store, null, 2));
|
|
65
|
+
console.log(`Suppression rule "${id}" saved.`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Remove rule
|
|
69
|
+
const removeIdx = argv.indexOf("--remove-rule");
|
|
70
|
+
if (removeIdx >= 0) {
|
|
71
|
+
const id = argv[removeIdx + 1];
|
|
72
|
+
store.rules = store.rules.filter((r) => r.id !== id);
|
|
73
|
+
store.lastUpdated = new Date().toISOString().split("T")[0];
|
|
74
|
+
writeFileSync(storePath, JSON.stringify(store, null, 2));
|
|
75
|
+
console.log(`Rule "${id}" removed.`);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// Apply suppressions to report
|
|
79
|
+
const applyIdx = argv.indexOf("--apply");
|
|
80
|
+
if (applyIdx >= 0) {
|
|
81
|
+
const reportPath = argv[applyIdx + 1];
|
|
82
|
+
if (!existsSync(reportPath)) {
|
|
83
|
+
console.error(`Report not found: ${reportPath}`);
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const report = JSON.parse(readFileSync(reportPath, "utf-8"));
|
|
88
|
+
const findings = report.findings ?? [];
|
|
89
|
+
let suppressed = 0;
|
|
90
|
+
const filtered = findings.filter((f) => {
|
|
91
|
+
for (const rule of store.rules) {
|
|
92
|
+
const fieldValue = String(f[rule.field] ?? "");
|
|
93
|
+
if (fieldValue.includes(rule.pattern)) {
|
|
94
|
+
suppressed++;
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return true;
|
|
99
|
+
});
|
|
100
|
+
const outIdx = argv.indexOf("--out");
|
|
101
|
+
if (outIdx >= 0) {
|
|
102
|
+
const outPath = argv[outIdx + 1];
|
|
103
|
+
writeFileSync(outPath, JSON.stringify({ ...report, findings: filtered }, null, 2));
|
|
104
|
+
console.log(`Filtered report written to: ${outPath}`);
|
|
105
|
+
}
|
|
106
|
+
console.log(`Suppressed: ${suppressed} | Remaining: ${filtered.length} | Total: ${findings.length}`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// List rules
|
|
110
|
+
if (format === "json") {
|
|
111
|
+
console.log(JSON.stringify(store, null, 2));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
console.log(`\nSuppression Rules`);
|
|
115
|
+
console.log("═".repeat(65));
|
|
116
|
+
if (store.rules.length === 0) {
|
|
117
|
+
console.log(" No suppression rules. Use --add-rule to create one.");
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
for (const r of store.rules) {
|
|
121
|
+
console.log(` ${r.id.padEnd(20)} ${r.field}:${r.pattern}`);
|
|
122
|
+
console.log(` Reason: ${r.reason} (${r.createdAt})`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
console.log("═".repeat(65));
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=finding-auto-suppress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-auto-suppress.js","sourceRoot":"","sources":["../../src/commands/finding-auto-suppress.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-dismiss-workflow.d.ts","sourceRoot":"","sources":["../../src/commands/finding-dismiss-workflow.ts"],"names":[],"mappings":"AAAA;;GAEG;AAsBH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA8H9D"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding-dismiss-workflow — Manage finding dismissal workflows.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
5
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
6
|
+
export function runFindingDismissWorkflow(argv) {
|
|
7
|
+
const storeIdx = argv.indexOf("--store");
|
|
8
|
+
const storePath = storeIdx >= 0 ? argv[storeIdx + 1] : ".judges-dismissals.json";
|
|
9
|
+
const formatIdx = argv.indexOf("--format");
|
|
10
|
+
const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
|
|
11
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
12
|
+
console.log(`
|
|
13
|
+
judges finding-dismiss-workflow — Manage finding dismissals
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
judges finding-dismiss-workflow [--store <path>]
|
|
17
|
+
[--dismiss <ruleId> --reason <r> --by <name> --note <text> --expires <date>]
|
|
18
|
+
[--revoke <ruleId>] [--audit] [--format table|json]
|
|
19
|
+
|
|
20
|
+
Options:
|
|
21
|
+
--store <path> Dismissal store (default: .judges-dismissals.json)
|
|
22
|
+
--dismiss <ruleId> Dismiss a finding
|
|
23
|
+
--reason <r> Reason: false-positive, accepted-risk, wont-fix, duplicate
|
|
24
|
+
--by <name> Who dismissed it
|
|
25
|
+
--note <text> Additional note
|
|
26
|
+
--expires <date> Expiry date (YYYY-MM-DD)
|
|
27
|
+
--revoke <ruleId> Revoke a dismissal
|
|
28
|
+
--audit Show audit log of all dismissals
|
|
29
|
+
--format <fmt> Output format: table (default), json
|
|
30
|
+
--help, -h Show this help
|
|
31
|
+
`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
let store;
|
|
35
|
+
if (existsSync(storePath)) {
|
|
36
|
+
store = JSON.parse(readFileSync(storePath, "utf-8"));
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
store = { dismissals: [], lastUpdated: new Date().toISOString().split("T")[0] };
|
|
40
|
+
}
|
|
41
|
+
// Dismiss
|
|
42
|
+
const dismissIdx = argv.indexOf("--dismiss");
|
|
43
|
+
if (dismissIdx >= 0) {
|
|
44
|
+
const ruleId = argv[dismissIdx + 1];
|
|
45
|
+
const reasonIdx = argv.indexOf("--reason");
|
|
46
|
+
const byIdx = argv.indexOf("--by");
|
|
47
|
+
const noteIdx = argv.indexOf("--note");
|
|
48
|
+
const expiresIdx = argv.indexOf("--expires");
|
|
49
|
+
const dismissal = {
|
|
50
|
+
ruleId,
|
|
51
|
+
reason: (reasonIdx >= 0 ? argv[reasonIdx + 1] : "accepted-risk"),
|
|
52
|
+
dismissedBy: byIdx >= 0 ? argv[byIdx + 1] : "unknown",
|
|
53
|
+
dismissedAt: new Date().toISOString().split("T")[0],
|
|
54
|
+
expiresAt: expiresIdx >= 0 ? argv[expiresIdx + 1] : "9999-12-31",
|
|
55
|
+
note: noteIdx >= 0 ? argv[noteIdx + 1] : "",
|
|
56
|
+
};
|
|
57
|
+
store.dismissals.push(dismissal);
|
|
58
|
+
store.lastUpdated = new Date().toISOString().split("T")[0];
|
|
59
|
+
writeFileSync(storePath, JSON.stringify(store, null, 2));
|
|
60
|
+
console.log(`Dismissed: ${ruleId} (${dismissal.reason})`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Revoke
|
|
64
|
+
const revokeIdx = argv.indexOf("--revoke");
|
|
65
|
+
if (revokeIdx >= 0) {
|
|
66
|
+
const ruleId = argv[revokeIdx + 1];
|
|
67
|
+
const before = store.dismissals.length;
|
|
68
|
+
store.dismissals = store.dismissals.filter((d) => d.ruleId !== ruleId);
|
|
69
|
+
store.lastUpdated = new Date().toISOString().split("T")[0];
|
|
70
|
+
writeFileSync(storePath, JSON.stringify(store, null, 2));
|
|
71
|
+
console.log(`Revoked ${before - store.dismissals.length} dismissal(s) for: ${ruleId}`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// Audit log
|
|
75
|
+
if (argv.includes("--audit")) {
|
|
76
|
+
const today = new Date().toISOString().split("T")[0];
|
|
77
|
+
const active = store.dismissals.filter((d) => d.expiresAt >= today);
|
|
78
|
+
const expired = store.dismissals.filter((d) => d.expiresAt < today);
|
|
79
|
+
if (format === "json") {
|
|
80
|
+
console.log(JSON.stringify({ active, expired }, null, 2));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
console.log(`\nDismissal Audit`);
|
|
84
|
+
console.log("═".repeat(70));
|
|
85
|
+
if (active.length > 0) {
|
|
86
|
+
console.log(" Active:");
|
|
87
|
+
for (const d of active) {
|
|
88
|
+
console.log(` ${d.ruleId.padEnd(25)} [${d.reason}] by ${d.dismissedBy} (${d.dismissedAt})`);
|
|
89
|
+
if (d.note.length > 0)
|
|
90
|
+
console.log(` Note: ${d.note}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (expired.length > 0) {
|
|
94
|
+
console.log(" Expired:");
|
|
95
|
+
for (const d of expired) {
|
|
96
|
+
console.log(` ${d.ruleId.padEnd(25)} [${d.reason}] expired ${d.expiresAt}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
console.log(`\n Active: ${active.length} | Expired: ${expired.length}`);
|
|
100
|
+
console.log("═".repeat(70));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// List
|
|
104
|
+
if (format === "json") {
|
|
105
|
+
console.log(JSON.stringify(store, null, 2));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
console.log(`\nDismissals`);
|
|
109
|
+
console.log("═".repeat(65));
|
|
110
|
+
if (store.dismissals.length === 0) {
|
|
111
|
+
console.log(" No dismissals. Use --dismiss <ruleId> to add one.");
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
for (const d of store.dismissals) {
|
|
115
|
+
console.log(` ${d.ruleId.padEnd(25)} [${d.reason}] by ${d.dismissedBy}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
console.log("═".repeat(65));
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=finding-dismiss-workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-dismiss-workflow.js","sourceRoot":"","sources":["../../src/commands/finding-dismiss-workflow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-reachability-check.d.ts","sourceRoot":"","sources":["../../src/commands/finding-reachability-check.ts"],"names":[],"mappings":"AAAA;;GAEG;AAkBH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAyGhE"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding-reachability-check — Check if findings affect reachable code paths.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, existsSync } from "fs";
|
|
5
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
6
|
+
export function runFindingReachabilityCheck(argv) {
|
|
7
|
+
const reportIdx = argv.indexOf("--report");
|
|
8
|
+
const sourceIdx = argv.indexOf("--source");
|
|
9
|
+
const formatIdx = argv.indexOf("--format");
|
|
10
|
+
const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
|
|
11
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
12
|
+
console.log(`
|
|
13
|
+
judges finding-reachability-check — Check finding reachability
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
judges finding-reachability-check --report <path> [--source <path>]
|
|
17
|
+
[--format table|json]
|
|
18
|
+
|
|
19
|
+
Options:
|
|
20
|
+
--report <path> Report file with findings
|
|
21
|
+
--source <path> Source file to check reachability against
|
|
22
|
+
--format <fmt> Output format: table (default), json
|
|
23
|
+
--help, -h Show this help
|
|
24
|
+
|
|
25
|
+
Checks if findings reference code that is reachable in the source.
|
|
26
|
+
`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (reportIdx < 0) {
|
|
30
|
+
console.error("Missing --report <path>");
|
|
31
|
+
process.exitCode = 1;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const reportPath = argv[reportIdx + 1];
|
|
35
|
+
if (!existsSync(reportPath)) {
|
|
36
|
+
console.error(`Report not found: ${reportPath}`);
|
|
37
|
+
process.exitCode = 1;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const report = JSON.parse(readFileSync(reportPath, "utf-8"));
|
|
41
|
+
const findings = report.findings ?? [];
|
|
42
|
+
let sourceLines = [];
|
|
43
|
+
if (sourceIdx >= 0) {
|
|
44
|
+
const sourcePath = argv[sourceIdx + 1];
|
|
45
|
+
if (existsSync(sourcePath)) {
|
|
46
|
+
sourceLines = readFileSync(sourcePath, "utf-8").split("\n");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const results = findings.map((f) => {
|
|
50
|
+
const lines = f.lineNumbers ?? [];
|
|
51
|
+
let reachable = true;
|
|
52
|
+
let reason = "assumed reachable";
|
|
53
|
+
if (sourceLines.length > 0 && lines.length > 0) {
|
|
54
|
+
// Check if the referenced lines exist and are not commented out
|
|
55
|
+
const referencedLine = lines[0] - 1;
|
|
56
|
+
if (referencedLine >= 0 && referencedLine < sourceLines.length) {
|
|
57
|
+
const line = sourceLines[referencedLine].trim();
|
|
58
|
+
if (line.startsWith("//") || line.startsWith("/*") || line.startsWith("#") || line.startsWith("*")) {
|
|
59
|
+
reachable = false;
|
|
60
|
+
reason = "line is commented out";
|
|
61
|
+
}
|
|
62
|
+
else if (line.length === 0) {
|
|
63
|
+
reachable = false;
|
|
64
|
+
reason = "line is empty";
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
reason = "line exists and is active code";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
reachable = false;
|
|
72
|
+
reason = "line number out of range";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else if (lines.length === 0) {
|
|
76
|
+
reason = "no line reference — assumed reachable";
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
ruleId: f.ruleId,
|
|
80
|
+
title: f.title,
|
|
81
|
+
severity: f.severity,
|
|
82
|
+
reachable,
|
|
83
|
+
reason,
|
|
84
|
+
lineNumbers: lines,
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
if (format === "json") {
|
|
88
|
+
console.log(JSON.stringify(results, null, 2));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
console.log(`\nReachability Check`);
|
|
92
|
+
console.log("═".repeat(70));
|
|
93
|
+
const reachableCount = results.filter((r) => r.reachable).length;
|
|
94
|
+
const unreachableCount = results.filter((r) => !r.reachable).length;
|
|
95
|
+
for (const r of results) {
|
|
96
|
+
const status = r.reachable ? "REACHABLE" : "UNREACHABLE";
|
|
97
|
+
const lineRef = r.lineNumbers.length > 0 ? `L${r.lineNumbers[0]}` : "N/A";
|
|
98
|
+
console.log(` [${status.padEnd(11)}] ${r.ruleId.padEnd(25)} ${lineRef.padEnd(8)} ${r.reason}`);
|
|
99
|
+
}
|
|
100
|
+
console.log(`\n Reachable: ${reachableCount} | Unreachable: ${unreachableCount} | Total: ${results.length}`);
|
|
101
|
+
console.log("═".repeat(70));
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=finding-reachability-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-reachability-check.js","sourceRoot":"","sources":["../../src/commands/finding-reachability-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-audit-export.d.ts","sourceRoot":"","sources":["../../src/commands/review-audit-export.ts"],"names":[],"mappings":"AAAA;;GAEG;AAuBH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAiGzD"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review-audit-export — Export audit data for external compliance tools.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync, readdirSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
7
|
+
export function runReviewAuditExport(argv) {
|
|
8
|
+
const dirIdx = argv.indexOf("--dir");
|
|
9
|
+
const dir = dirIdx >= 0 ? argv[dirIdx + 1] : ".judges/audit";
|
|
10
|
+
const outIdx = argv.indexOf("--out");
|
|
11
|
+
const exportFormat = argv.indexOf("--export-format");
|
|
12
|
+
const expFmt = exportFormat >= 0 ? argv[exportFormat + 1] : "json";
|
|
13
|
+
const formatIdx = argv.indexOf("--format");
|
|
14
|
+
const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
|
|
15
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
16
|
+
console.log(`
|
|
17
|
+
judges review-audit-export — Export audit data
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
judges review-audit-export [--dir <path>] [--out <path>]
|
|
21
|
+
[--export-format json|csv]
|
|
22
|
+
[--format table|json]
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
--dir <path> Audit data directory (default: .judges/audit)
|
|
26
|
+
--out <path> Write export to file
|
|
27
|
+
--export-format <fmt> Export format: json (default), csv
|
|
28
|
+
--format <fmt> Display format: table (default), json
|
|
29
|
+
--help, -h Show this help
|
|
30
|
+
`);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (!existsSync(dir)) {
|
|
34
|
+
console.log(`Audit directory not found: ${dir}`);
|
|
35
|
+
console.log("No audit data to export.");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const files = readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
39
|
+
const records = [];
|
|
40
|
+
for (const file of files) {
|
|
41
|
+
const content = JSON.parse(readFileSync(join(dir, file), "utf-8"));
|
|
42
|
+
if (Array.isArray(content)) {
|
|
43
|
+
records.push(...content);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
records.push(content);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
records.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
50
|
+
const byAction = {};
|
|
51
|
+
for (const r of records) {
|
|
52
|
+
byAction[r.action] = (byAction[r.action] ?? 0) + 1;
|
|
53
|
+
}
|
|
54
|
+
const auditExport = {
|
|
55
|
+
exportedAt: new Date().toISOString(),
|
|
56
|
+
records,
|
|
57
|
+
summary: { total: records.length, byAction },
|
|
58
|
+
};
|
|
59
|
+
// Write to file
|
|
60
|
+
if (outIdx >= 0) {
|
|
61
|
+
const outPath = argv[outIdx + 1];
|
|
62
|
+
if (expFmt === "csv") {
|
|
63
|
+
const header = "timestamp,action,actor,detail,source";
|
|
64
|
+
const rows = records.map((r) => `"${r.timestamp}","${r.action}","${r.actor}","${r.detail}","${r.source}"`);
|
|
65
|
+
writeFileSync(outPath, [header, ...rows].join("\n"));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
writeFileSync(outPath, JSON.stringify(auditExport, null, 2));
|
|
69
|
+
}
|
|
70
|
+
console.log(`Audit exported to: ${outPath} (${expFmt}, ${records.length} records)`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (format === "json") {
|
|
74
|
+
console.log(JSON.stringify(auditExport, null, 2));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
console.log(`\nAudit Export`);
|
|
78
|
+
console.log("═".repeat(70));
|
|
79
|
+
console.log(` Records: ${records.length}`);
|
|
80
|
+
if (Object.keys(byAction).length > 0) {
|
|
81
|
+
console.log(" By action:");
|
|
82
|
+
for (const [action, count] of Object.entries(byAction)) {
|
|
83
|
+
console.log(` ${action.padEnd(20)} ${count}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (records.length > 0) {
|
|
87
|
+
console.log(`\n Latest records:`);
|
|
88
|
+
for (const r of records.slice(-5)) {
|
|
89
|
+
console.log(` ${r.timestamp.padEnd(22)} ${r.action.padEnd(15)} ${r.actor}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
console.log("═".repeat(70));
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=review-audit-export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-audit-export.js","sourceRoot":"","sources":["../../src/commands/review-audit-export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-data-retention.d.ts","sourceRoot":"","sources":["../../src/commands/review-data-retention.ts"],"names":[],"mappings":"AAAA;;GAEG;AA2BH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAmH3D"}
|