dsh-research-report 0.2.0 → 0.3.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/lib/cli.js ADDED
@@ -0,0 +1,103 @@
1
+ import { _ as sha256Of, a as renderSarif, o as renderVerificationJson, r as buildVerificationReport, s as verifySealedReport } from "./verify-sealed-Bv1Z5cFD.js";
2
+ import path from "node:path";
3
+ import { readFile } from "node:fs/promises";
4
+ //#region src/cli.ts
5
+ /**
6
+ * Standalone sealed-report verifier CLI. One command recomputes the seal hash
7
+ * (SHA-256 of manifest.json), the report hash, and the audit-journal hashes,
8
+ * re-runs the byte-level + integrity claim check against the evidence ledger,
9
+ * and prints a SARIF 2.1.0 or JSON report. Zero network, zero model, zero
10
+ * @deepseek-ai imports — this entry bundles to a self-contained binary.
11
+ *
12
+ * Usage:
13
+ * dsh-research-verify --report <dir> [--seal <sha256>] [--ledger <dir>] [--format json|sarif]
14
+ *
15
+ * @module dsh-research-report/cli
16
+ */
17
+ /** Print usage and exit non-zero. */
18
+ function usage(message) {
19
+ if (message !== void 0) console.error(`dsh-research-verify: ${message}`);
20
+ console.error("Usage: dsh-research-verify --report <dir> [--seal <sha256>] [--ledger <dir>] [--format json|sarif]");
21
+ console.error(" --report <dir> Sealed report directory (holds manifest.json + report.md).");
22
+ console.error(" --seal <sha256> Expected seal hash to compare the recomputed manifest hash against.");
23
+ console.error(" --ledger <dir> Evidence ledger root (objects/<sha256> + index.jsonl) for claim re-checks.");
24
+ console.error(" --format <fmt> Output format: json (default) or sarif.");
25
+ process.exit(message === void 0 ? 0 : 2);
26
+ }
27
+ /** Parse argv into {@link CliArgs}. */
28
+ function parseArgs(argv) {
29
+ const args = {
30
+ reportDir: "",
31
+ seal: null,
32
+ ledger: null,
33
+ format: "json"
34
+ };
35
+ for (let index = 0; index < argv.length; index++) {
36
+ const token = argv[index];
37
+ switch (token) {
38
+ case "--help":
39
+ case "-h":
40
+ usage();
41
+ break;
42
+ case "--report":
43
+ args.reportDir = argv[++index] ?? "";
44
+ break;
45
+ case "--seal":
46
+ args.seal = argv[++index] ?? null;
47
+ break;
48
+ case "--ledger":
49
+ args.ledger = argv[++index] ?? null;
50
+ break;
51
+ case "--format":
52
+ args.format = argv[++index] === "sarif" ? "sarif" : "json";
53
+ break;
54
+ default: usage(`unknown argument ${token}`);
55
+ }
56
+ }
57
+ if (args.reportDir === "") usage("--report is required");
58
+ return args;
59
+ }
60
+ /** Read one evidence snapshot from a ledger root by its manifest evidence record. */
61
+ async function readLedgerEvidence(ledgerRoot, record) {
62
+ let content;
63
+ try {
64
+ content = await readFile(path.join(ledgerRoot, "objects", record.sha256), "utf8");
65
+ } catch (error) {
66
+ if (error.code === "ENOENT") return {
67
+ content: "",
68
+ integrity: "missing"
69
+ };
70
+ throw error;
71
+ }
72
+ return {
73
+ content,
74
+ integrity: sha256Of(content) === record.sha256 ? "ok" : "tampered"
75
+ };
76
+ }
77
+ /** The standalone verifier entry point. */
78
+ async function main(argv) {
79
+ const args = parseArgs(argv);
80
+ const manifestText = await readFile(path.join(args.reportDir, "manifest.json"), "utf8");
81
+ const manifest = JSON.parse(manifestText);
82
+ const sealHash = sha256Of(manifestText);
83
+ const evidenceById = new Map((Array.isArray(manifest.evidence) ? manifest.evidence : []).map((record) => [record.id, record]));
84
+ const claimRecheck = args.ledger === null ? "skipped-no-ledger" : "rechecked";
85
+ const result = await verifySealedReport(args.reportDir, args.seal ?? sealHash, {
86
+ readFile: (file) => readFile(file, "utf8"),
87
+ readEvidenceContent: async (id) => {
88
+ if (args.ledger === null) return void 0;
89
+ const record = evidenceById.get(id);
90
+ if (record === void 0) return void 0;
91
+ return readLedgerEvidence(args.ledger, record);
92
+ }
93
+ });
94
+ const report = buildVerificationReport(result, args.reportDir, args.seal, claimRecheck);
95
+ process.stdout.write(args.format === "sarif" ? renderSarif(report) : renderVerificationJson(report));
96
+ if (!report.ok) process.exitCode = 1;
97
+ }
98
+ main(process.argv.slice(2)).catch((error) => {
99
+ console.error(`dsh-research-verify: ${error instanceof Error ? error.message : String(error)}`);
100
+ process.exitCode = 1;
101
+ });
102
+ //#endregion
103
+ export {};