proofseal 0.0.1 → 0.1.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/LICENSE +21 -0
- package/NOTICE +13 -0
- package/README.md +210 -2
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +440 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.js +58 -0
- package/dist/config.js.map +1 -0
- package/dist/core/canonical.d.ts +16 -0
- package/dist/core/canonical.js +29 -0
- package/dist/core/canonical.js.map +1 -0
- package/dist/core/hash.d.ts +32 -0
- package/dist/core/hash.js +81 -0
- package/dist/core/hash.js.map +1 -0
- package/dist/core/marker-lint.d.ts +5 -0
- package/dist/core/marker-lint.js +55 -0
- package/dist/core/marker-lint.js.map +1 -0
- package/dist/core/paths.d.ts +10 -0
- package/dist/core/paths.js +13 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/harness/quantize.d.ts +38 -0
- package/dist/harness/quantize.js +76 -0
- package/dist/harness/quantize.js.map +1 -0
- package/dist/harness/run.d.ts +61 -0
- package/dist/harness/run.js +137 -0
- package/dist/harness/run.js.map +1 -0
- package/dist/history/gitinfo.d.ts +16 -0
- package/dist/history/gitinfo.js +69 -0
- package/dist/history/gitinfo.js.map +1 -0
- package/dist/history/jsonl.d.ts +28 -0
- package/dist/history/jsonl.js +71 -0
- package/dist/history/jsonl.js.map +1 -0
- package/dist/history/queries.d.ts +43 -0
- package/dist/history/queries.js +86 -0
- package/dist/history/queries.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/keys/derive.d.ts +28 -0
- package/dist/keys/derive.js +59 -0
- package/dist/keys/derive.js.map +1 -0
- package/dist/manifest/schema.d.ts +1068 -0
- package/dist/manifest/schema.js +102 -0
- package/dist/manifest/schema.js.map +1 -0
- package/dist/manifest/seal.d.ts +41 -0
- package/dist/manifest/seal.js +185 -0
- package/dist/manifest/seal.js.map +1 -0
- package/dist/manifest/verify.d.ts +102 -0
- package/dist/manifest/verify.js +246 -0
- package/dist/manifest/verify.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +138 -0
- package/dist/mcp/server.js.map +1 -0
- package/package.json +50 -3
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ProofSeal CLI — thin wrapper over the library API (ADR-0001 §4.1).
|
|
4
|
+
* Exit-code contract: 0 ok/drift · 1 regressed/missing/seal-mismatch · 2 precondition.
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
8
|
+
import { join, resolve, dirname } from 'node:path';
|
|
9
|
+
import { seal } from '../manifest/seal.js';
|
|
10
|
+
import { verify, toVerifyJson } from '../manifest/verify.js';
|
|
11
|
+
import { lintMarker } from '../core/marker-lint.js';
|
|
12
|
+
import { ClaimSchema } from '../manifest/schema.js';
|
|
13
|
+
import { loadHistory } from '../history/jsonl.js';
|
|
14
|
+
import { fixTimeline, diffLatest, findRegressionIntroductions } from '../history/queries.js';
|
|
15
|
+
import { enrichRegressionsWithGit, UNREACHABLE_TAG } from '../history/gitinfo.js';
|
|
16
|
+
import { runHarness } from '../harness/run.js';
|
|
17
|
+
import { DEFAULT_TOLERANCE } from '../harness/quantize.js';
|
|
18
|
+
import { loadConfig, saveConfig, defaultConfig, configPathFor } from '../config.js';
|
|
19
|
+
import { startMcpServer } from '../mcp/server.js';
|
|
20
|
+
const program = new Command();
|
|
21
|
+
program.name('proofseal').description('Witness-chained, tamper-evident claim verification').version('0.1.0');
|
|
22
|
+
function emit(json, data, human) {
|
|
23
|
+
if (json)
|
|
24
|
+
console.log(JSON.stringify(data, null, 2));
|
|
25
|
+
else
|
|
26
|
+
human();
|
|
27
|
+
}
|
|
28
|
+
function fail(json, code, message) {
|
|
29
|
+
if (json)
|
|
30
|
+
console.log(JSON.stringify({ ok: false, error: message }, null, 2));
|
|
31
|
+
else
|
|
32
|
+
console.error(`proofseal: ${message}`);
|
|
33
|
+
process.exit(code);
|
|
34
|
+
}
|
|
35
|
+
// ─── init ───────────────────────────────────────────────────────────
|
|
36
|
+
program
|
|
37
|
+
.command('init')
|
|
38
|
+
.description('Scaffold proofseal.json + proofs/ + a working sample claim')
|
|
39
|
+
.option('--root <path>', 'repo root', '.')
|
|
40
|
+
.option('--force', 'overwrite an existing proofseal.json')
|
|
41
|
+
.option('--json', 'machine-readable output')
|
|
42
|
+
.action((opts) => {
|
|
43
|
+
const root = resolve(opts.root);
|
|
44
|
+
const configPath = configPathFor(root);
|
|
45
|
+
if (existsSync(configPath) && !opts.force) {
|
|
46
|
+
fail(!!opts.json, 2, `${configPath} already exists — pass --force to overwrite`);
|
|
47
|
+
}
|
|
48
|
+
const config = defaultConfig(root);
|
|
49
|
+
saveConfig(root, config);
|
|
50
|
+
mkdirSync(join(root, 'proofs'), { recursive: true });
|
|
51
|
+
// Platform honesty (premortem #3): without a .gitattributes, git autocrlf
|
|
52
|
+
// can rewrite line endings per-OS and silently change file hashes. And
|
|
53
|
+
// history-semantics (premortem: concurrent seals): two branches sealing
|
|
54
|
+
// both append to proofs/history.jsonl — `merge=union` keeps both lines on
|
|
55
|
+
// merge, and queries order by issuedAt so interleaving is safe. Print
|
|
56
|
+
// guidance only — never write the file for the user.
|
|
57
|
+
const historyRel = config.history ?? 'proofs/history.jsonl';
|
|
58
|
+
const unionLine = `${historyRel} merge=union`;
|
|
59
|
+
const gitattributesPath = join(root, '.gitattributes');
|
|
60
|
+
let gitattributesHint;
|
|
61
|
+
if (!existsSync(gitattributesPath)) {
|
|
62
|
+
gitattributesHint = `no .gitattributes found — consider adding \`* text=auto eol=lf\` (so git autocrlf cannot rewrite line endings per-OS and change file hashes) and \`${unionLine}\` (so seals from two branches merge without conflict; entries are ordered by issuedAt)`;
|
|
63
|
+
}
|
|
64
|
+
else if (!readFileSync(gitattributesPath, 'utf8').includes('merge=union')) {
|
|
65
|
+
gitattributesHint = `consider adding \`${unionLine}\` to .gitattributes so seals from two branches merge without conflict (entries are ordered by issuedAt, so union-merge interleaving is safe)`;
|
|
66
|
+
}
|
|
67
|
+
emit(!!opts.json, {
|
|
68
|
+
ok: true,
|
|
69
|
+
configPath,
|
|
70
|
+
claims: config.claims.length,
|
|
71
|
+
...(gitattributesHint ? { gitattributesHint } : {}),
|
|
72
|
+
}, () => {
|
|
73
|
+
console.log(`Initialized ${configPath}`);
|
|
74
|
+
if (gitattributesHint)
|
|
75
|
+
console.log(`hint: ${gitattributesHint}`);
|
|
76
|
+
console.log('Next: proofseal seal && proofseal verify');
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
// ─── claim add | list | rm ─────────────────────────────────────────
|
|
80
|
+
const claim = program.command('claim').description('Manage claim entries');
|
|
81
|
+
/** Marker lint (premortem #7): advisory only — warnings, never failures. */
|
|
82
|
+
function lintMarkerClaim(root, entry) {
|
|
83
|
+
if (entry.type !== 'marker')
|
|
84
|
+
return [];
|
|
85
|
+
const abs = join(root, entry.file);
|
|
86
|
+
const text = existsSync(abs) ? readFileSync(abs, 'utf8') : undefined;
|
|
87
|
+
return lintMarker(entry.marker, text);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Map a batch-file entry onto the config claim shape (`name` is accepted as
|
|
91
|
+
* an alias for `harness`; harness defaults to the claim id, like the flags).
|
|
92
|
+
*/
|
|
93
|
+
function normalizeBatchEntry(raw) {
|
|
94
|
+
if (raw === null || typeof raw !== 'object')
|
|
95
|
+
return raw;
|
|
96
|
+
const r = raw;
|
|
97
|
+
if (r.type !== 'harness')
|
|
98
|
+
return raw;
|
|
99
|
+
const { name, ...rest } = r;
|
|
100
|
+
return {
|
|
101
|
+
...rest,
|
|
102
|
+
harness: r.harness ?? name ?? r.id,
|
|
103
|
+
seed: r.seed ?? 42,
|
|
104
|
+
quantizeDecimals: r.quantizeDecimals ?? 6,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/** Batch authoring: validate ALL entries before adding ANY (all-or-nothing). */
|
|
108
|
+
function claimAddFromFile(json, root, config, fromFile) {
|
|
109
|
+
let parsed;
|
|
110
|
+
try {
|
|
111
|
+
parsed = JSON.parse(readFileSync(resolve(root, fromFile), 'utf8'));
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
fail(json, 2, `could not read ${fromFile}: ${e.message}`);
|
|
115
|
+
}
|
|
116
|
+
if (!Array.isArray(parsed))
|
|
117
|
+
fail(json, 2, `${fromFile} must contain a JSON array of claim objects`);
|
|
118
|
+
const errors = [];
|
|
119
|
+
const entries = [];
|
|
120
|
+
const seen = new Set(config.claims.map((c) => c.id));
|
|
121
|
+
parsed.forEach((raw, i) => {
|
|
122
|
+
const res = ClaimSchema.safeParse(normalizeBatchEntry(raw));
|
|
123
|
+
if (!res.success) {
|
|
124
|
+
const reasons = res.error.issues
|
|
125
|
+
.map((iss) => `${iss.path.join('.') || '(root)'}: ${iss.message}`)
|
|
126
|
+
.join('; ');
|
|
127
|
+
errors.push(`[${i}] invalid claim: ${reasons}`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (seen.has(res.data.id)) {
|
|
131
|
+
errors.push(`[${i}] duplicate claim id '${res.data.id}' (already in the file or in proofseal.json)`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
seen.add(res.data.id);
|
|
135
|
+
entries.push(res.data);
|
|
136
|
+
});
|
|
137
|
+
if (errors.length > 0) {
|
|
138
|
+
fail(json, 2, `--from-file rejected (no claims were added):\n ${errors.join('\n ')}`);
|
|
139
|
+
}
|
|
140
|
+
const warnings = [];
|
|
141
|
+
for (const entry of entries) {
|
|
142
|
+
for (const w of lintMarkerClaim(root, entry))
|
|
143
|
+
warnings.push(`[${entry.id}] ${w}`);
|
|
144
|
+
}
|
|
145
|
+
config.claims.push(...entries);
|
|
146
|
+
saveConfig(root, config);
|
|
147
|
+
for (const w of warnings)
|
|
148
|
+
console.warn(`warning: ${w}`);
|
|
149
|
+
emit(json, { ok: true, added: entries.length, ids: entries.map((e) => e.id), warnings }, () => console.log(`Added ${entries.length} claims`));
|
|
150
|
+
}
|
|
151
|
+
claim
|
|
152
|
+
.command('add')
|
|
153
|
+
.option('--id <id>', 'claim id')
|
|
154
|
+
.option('--type <type>', 'file-hash | marker | harness')
|
|
155
|
+
.option('--file <path>', 'file the claim covers (file-hash, marker)')
|
|
156
|
+
.option('--marker <substring>', 'distinctive substring (marker)')
|
|
157
|
+
.option('--name <name>', 'harness name (defaults to the claim id)')
|
|
158
|
+
.option('--cmd <command>', 'harness command (harness)')
|
|
159
|
+
.option('--seed <n>', 'harness seed', '42')
|
|
160
|
+
.option('--quantize-decimals <n>', 'quantize decimals', '6')
|
|
161
|
+
.option('--desc <text>', 'claim description')
|
|
162
|
+
.option('--from-file <path>', 'JSON array of claim objects — all-or-nothing batch add')
|
|
163
|
+
.option('--root <path>', 'repo root', '.')
|
|
164
|
+
.option('--json', 'machine-readable output')
|
|
165
|
+
.action((o) => {
|
|
166
|
+
const json = o.json !== undefined;
|
|
167
|
+
try {
|
|
168
|
+
const { root, config } = loadConfig(o.root ?? '.');
|
|
169
|
+
if (o.fromFile) {
|
|
170
|
+
claimAddFromFile(json, root, config, o.fromFile);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (!o.id || !o.type)
|
|
174
|
+
fail(json, 2, '--id and --type are required (or use --from-file <path>)');
|
|
175
|
+
if (config.claims.some((c) => c.id === o.id))
|
|
176
|
+
fail(json, 2, `claim '${o.id}' already exists`);
|
|
177
|
+
let entry;
|
|
178
|
+
if (o.type === 'file-hash') {
|
|
179
|
+
if (!o.file)
|
|
180
|
+
fail(json, 2, '--file required for file-hash claims');
|
|
181
|
+
entry = { id: o.id, type: 'file-hash', file: o.file, desc: o.desc };
|
|
182
|
+
}
|
|
183
|
+
else if (o.type === 'marker') {
|
|
184
|
+
if (!o.file || !o.marker)
|
|
185
|
+
fail(json, 2, '--file and --marker required for marker claims');
|
|
186
|
+
entry = { id: o.id, type: 'marker', file: o.file, marker: o.marker, desc: o.desc };
|
|
187
|
+
}
|
|
188
|
+
else if (o.type === 'harness') {
|
|
189
|
+
if (!o.cmd)
|
|
190
|
+
fail(json, 2, '--cmd required for harness claims');
|
|
191
|
+
entry = {
|
|
192
|
+
id: o.id,
|
|
193
|
+
type: 'harness',
|
|
194
|
+
harness: o.name ?? o.id,
|
|
195
|
+
cmd: o.cmd,
|
|
196
|
+
seed: Number(o.seed ?? 42),
|
|
197
|
+
quantizeDecimals: Number(o.quantizeDecimals ?? 6),
|
|
198
|
+
desc: o.desc,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
fail(json, 2, `unknown claim type '${o.type}' (expected file-hash | marker | harness)`);
|
|
203
|
+
}
|
|
204
|
+
const warnings = lintMarkerClaim(root, entry);
|
|
205
|
+
config.claims.push(entry);
|
|
206
|
+
saveConfig(root, config);
|
|
207
|
+
for (const w of warnings)
|
|
208
|
+
console.warn(`warning: ${w}`);
|
|
209
|
+
emit(json, { ok: true, claim: entry, warnings }, () => console.log(`Added claim '${o.id}' (${o.type})`));
|
|
210
|
+
}
|
|
211
|
+
catch (e) {
|
|
212
|
+
fail(json, 2, e.message);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
claim
|
|
216
|
+
.command('list')
|
|
217
|
+
.option('--root <path>', 'repo root', '.')
|
|
218
|
+
.option('--json', 'machine-readable output')
|
|
219
|
+
.action((o) => {
|
|
220
|
+
try {
|
|
221
|
+
const { config } = loadConfig(o.root);
|
|
222
|
+
emit(!!o.json, { ok: true, claims: config.claims }, () => {
|
|
223
|
+
for (const c of config.claims) {
|
|
224
|
+
const target = c.type === 'harness' ? c.cmd : c.file;
|
|
225
|
+
console.log(`${c.id}\t${c.type}\t${target}${c.desc ? `\t${c.desc}` : ''}`);
|
|
226
|
+
}
|
|
227
|
+
if (config.claims.length === 0)
|
|
228
|
+
console.log('(no claims)');
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
catch (e) {
|
|
232
|
+
fail(!!o.json, 2, e.message);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
claim
|
|
236
|
+
.command('rm <id>')
|
|
237
|
+
.option('--root <path>', 'repo root', '.')
|
|
238
|
+
.option('--json', 'machine-readable output')
|
|
239
|
+
.action((id, o) => {
|
|
240
|
+
try {
|
|
241
|
+
const { root, config } = loadConfig(o.root);
|
|
242
|
+
const before = config.claims.length;
|
|
243
|
+
config.claims = config.claims.filter((c) => c.id !== id);
|
|
244
|
+
if (config.claims.length === before)
|
|
245
|
+
fail(!!o.json, 2, `claim '${id}' not found`);
|
|
246
|
+
saveConfig(root, config);
|
|
247
|
+
emit(!!o.json, { ok: true, removed: id }, () => console.log(`Removed claim '${id}'`));
|
|
248
|
+
}
|
|
249
|
+
catch (e) {
|
|
250
|
+
fail(!!o.json, 2, e.message);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
// ─── seal ───────────────────────────────────────────────────────────
|
|
254
|
+
program
|
|
255
|
+
.command('seal')
|
|
256
|
+
.description('Refresh claims, derive commit-bound key, seal manifest, append history')
|
|
257
|
+
.option('--root <path>', 'repo root', '.')
|
|
258
|
+
.option('--json', 'machine-readable output')
|
|
259
|
+
.action(async (o) => {
|
|
260
|
+
try {
|
|
261
|
+
const result = await seal({ root: o.root });
|
|
262
|
+
emit(!!o.json, { ok: result.ok, summary: result.summary, manifestPath: result.manifestPath, manifestHash: result.witness.integrity.manifestHash, warnings: result.warnings, filesWritten: result.filesWritten }, () => {
|
|
263
|
+
console.log(`Sealed ${result.manifestPath}`);
|
|
264
|
+
console.log(`claims: ${result.summary.totalClaims} verified: ${result.summary.verified} missing: ${result.summary.missing}`);
|
|
265
|
+
for (const w of result.warnings)
|
|
266
|
+
console.warn(`warning [${w.id}]: ${w.message}`);
|
|
267
|
+
// CI footgun pack (premortem #5): verify on a clean clone only works
|
|
268
|
+
// if every seal output is committed — print the checklist explicitly.
|
|
269
|
+
console.log('');
|
|
270
|
+
console.log('Seal complete. Now commit these files:');
|
|
271
|
+
for (const f of result.filesWritten)
|
|
272
|
+
console.log(` ${f}`);
|
|
273
|
+
});
|
|
274
|
+
process.exit(result.ok ? 0 : 1);
|
|
275
|
+
}
|
|
276
|
+
catch (e) {
|
|
277
|
+
fail(!!o.json, 2, e.message);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
// ─── verify ─────────────────────────────────────────────────────────
|
|
281
|
+
program
|
|
282
|
+
.command('verify')
|
|
283
|
+
.description('Verify the integrity seal + classify every claim (pass/drift/regressed/missing)')
|
|
284
|
+
.option('--manifest <path>', 'manifest path')
|
|
285
|
+
.option('--root <path>', 'repo root', '.')
|
|
286
|
+
.option('--json', 'machine-readable output')
|
|
287
|
+
.action(async (o) => {
|
|
288
|
+
const result = await verify({ root: o.root, manifestPath: o.manifest });
|
|
289
|
+
emit(!!o.json, toVerifyJson(result), () => {
|
|
290
|
+
if (result.precondition) {
|
|
291
|
+
console.error(`precondition: ${result.precondition}`);
|
|
292
|
+
if (result.hint)
|
|
293
|
+
console.error(`hint: ${result.hint}`);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (result.platformWarning) {
|
|
297
|
+
console.log(`PLATFORM WARNING: ${result.platformWarning}`);
|
|
298
|
+
console.log('');
|
|
299
|
+
}
|
|
300
|
+
const s = result.signature;
|
|
301
|
+
console.log('Manifest integrity seal:');
|
|
302
|
+
console.log(` hash matches: ${s.manifestHashOk ? 'yes' : 'SEAL MISMATCH'}`);
|
|
303
|
+
console.log(` public key reproducible: ${s.publicKeyReproducible ? 'yes' : 'SEAL MISMATCH'}`);
|
|
304
|
+
console.log(` seal valid: ${s.signatureValid ? 'yes' : 'SEAL MISMATCH'}`);
|
|
305
|
+
console.log('');
|
|
306
|
+
console.log(`Summary: pass=${result.summary.pass} drift=${result.summary.drift} regressed=${result.summary.regressed} missing=${result.summary.missing}`);
|
|
307
|
+
for (const r of result.results.filter((r) => r.status === 'regressed' || r.status === 'missing')) {
|
|
308
|
+
console.log(` ${r.status.toUpperCase()} ${r.id} ${r.file ?? ''}${r.detail ? ` (${r.detail})` : ''}`);
|
|
309
|
+
}
|
|
310
|
+
console.log(`\nnote: ${result.note}`);
|
|
311
|
+
});
|
|
312
|
+
process.exit(result.exitCode);
|
|
313
|
+
});
|
|
314
|
+
// ─── history ────────────────────────────────────────────────────────
|
|
315
|
+
program
|
|
316
|
+
.command('history')
|
|
317
|
+
.description('Timeline per claim, latest diff, regression bisection')
|
|
318
|
+
.option('--id <claimId>', 'timeline for a single claim')
|
|
319
|
+
.option('--diff', 'latest-vs-previous transitions')
|
|
320
|
+
.option('--bisect', 'find regression-introducing commit ranges')
|
|
321
|
+
.option('--root <path>', 'repo root', '.')
|
|
322
|
+
.option('--json', 'machine-readable output')
|
|
323
|
+
.action((o) => {
|
|
324
|
+
try {
|
|
325
|
+
const { historyPath, root } = loadConfig(o.root);
|
|
326
|
+
const history = loadHistory(historyPath);
|
|
327
|
+
if (o.id) {
|
|
328
|
+
const timeline = fixTimeline(history, o.id);
|
|
329
|
+
emit(!!o.json, { ok: true, id: o.id, timeline }, () => {
|
|
330
|
+
for (const t of timeline)
|
|
331
|
+
console.log(`${t.issuedAt} ${t.commit.slice(0, 12)} ${t.status}`);
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
else if (o.diff) {
|
|
335
|
+
const diff = diffLatest(history);
|
|
336
|
+
emit(!!o.json, { ok: true, diff }, () => console.log(JSON.stringify(diff, null, 2)));
|
|
337
|
+
}
|
|
338
|
+
else if (o.bisect) {
|
|
339
|
+
const regressions = enrichRegressionsWithGit(root, findRegressionIntroductions(history));
|
|
340
|
+
emit(!!o.json, { ok: true, regressions }, () => {
|
|
341
|
+
if (regressions.length === 0)
|
|
342
|
+
console.log('No regressed claims in latest snapshot.');
|
|
343
|
+
const tag = (reachable) => (reachable === false ? ` ${UNREACHABLE_TAG}` : '');
|
|
344
|
+
for (const r of regressions) {
|
|
345
|
+
const lastPass = r.lastPassCommit
|
|
346
|
+
? `${r.lastPassCommit.slice(0, 12)}${tag(r.lastPassReachable)}`
|
|
347
|
+
: '(never)';
|
|
348
|
+
console.log(`${r.id}: last pass ${lastPass} → regressed at ${r.regressedAtCommit.slice(0, 12)}${tag(r.regressedAtReachable)}`);
|
|
349
|
+
if (r.rangeCommitCount != null) {
|
|
350
|
+
const n = r.rangeCommitCount;
|
|
351
|
+
const advice = n > 1 ? ' — seal more often (e.g. in CI on main) for tighter localization' : '';
|
|
352
|
+
console.log(` range spans ${n} commit${n === 1 ? '' : 's'}${advice}`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
emit(!!o.json, { ok: true, entries: history }, () => {
|
|
359
|
+
for (const e of history) {
|
|
360
|
+
console.log(`${e.issuedAt} ${e.commit.slice(0, 12)} claims=${e.summary.totalClaims} verified=${e.summary.verified} missing=${e.summary.missing}`);
|
|
361
|
+
}
|
|
362
|
+
if (history.length === 0)
|
|
363
|
+
console.log('(no history)');
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
catch (e) {
|
|
368
|
+
fail(!!o.json, 2, e.message);
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
// ─── harness run ────────────────────────────────────────────────────
|
|
372
|
+
const harness = program.command('harness').description('Deterministic-output harnesses');
|
|
373
|
+
harness
|
|
374
|
+
.command('run <name>')
|
|
375
|
+
.option('--update', 'regenerate expectedSha256 + reference vector (reviewed bumps only)')
|
|
376
|
+
.option('--root <path>', 'repo root', '.')
|
|
377
|
+
.option('--json', 'machine-readable output')
|
|
378
|
+
.action(async (name, o) => {
|
|
379
|
+
const json = !!o.json;
|
|
380
|
+
try {
|
|
381
|
+
const { root, config } = loadConfig(o.root);
|
|
382
|
+
const claimDef = config.claims.find((c) => c.type === 'harness' && (c.harness === name || c.id === name));
|
|
383
|
+
if (!claimDef)
|
|
384
|
+
fail(json, 2, `no harness claim named '${name}'`);
|
|
385
|
+
const def = claimDef;
|
|
386
|
+
const result = await runHarness({
|
|
387
|
+
name,
|
|
388
|
+
cmd: def.cmd,
|
|
389
|
+
cwd: root,
|
|
390
|
+
seed: def.seed,
|
|
391
|
+
quantizeDecimals: def.quantizeDecimals,
|
|
392
|
+
exclude: def.exclude,
|
|
393
|
+
expectedSha256: o.update ? undefined : def.expectedSha256,
|
|
394
|
+
referenceVector: def.referenceVector,
|
|
395
|
+
tolerance: def.tolerance,
|
|
396
|
+
});
|
|
397
|
+
if (result.status === 'error') {
|
|
398
|
+
fail(json, 2, `harness '${name}' failed: ${result.error}`);
|
|
399
|
+
}
|
|
400
|
+
if (o.update) {
|
|
401
|
+
const refRel = def.referenceVector ?? `proofs/${name}.reference.json`;
|
|
402
|
+
const refAbs = join(root, refRel);
|
|
403
|
+
mkdirSync(dirname(refAbs), { recursive: true });
|
|
404
|
+
writeFileSync(refAbs, JSON.stringify(result.values) + '\n');
|
|
405
|
+
def.expectedSha256 = result.hash;
|
|
406
|
+
def.referenceVector = refRel;
|
|
407
|
+
def.tolerance = def.tolerance ?? { ...DEFAULT_TOLERANCE };
|
|
408
|
+
saveConfig(root, config);
|
|
409
|
+
emit(json, { ok: true, updated: true, hash: result.hash, referenceVector: refRel }, () => {
|
|
410
|
+
console.log(`Updated harness '${name}': expectedSha256=${result.hash}`);
|
|
411
|
+
console.log(`Reference vector written to ${refRel}. Re-run \`proofseal seal\`.`);
|
|
412
|
+
});
|
|
413
|
+
process.exit(0);
|
|
414
|
+
}
|
|
415
|
+
if (!def.expectedSha256) {
|
|
416
|
+
fail(json, 2, `harness '${name}' has no committed expectedSha256 — run with --update first`);
|
|
417
|
+
}
|
|
418
|
+
emit(json, { ok: result.status === 'pass' || result.status === 'drift', result }, () => {
|
|
419
|
+
console.log(`harness '${name}': ${result.status} hash=${result.hash}`);
|
|
420
|
+
if (result.forensics?.worst) {
|
|
421
|
+
const w = result.forensics.worst;
|
|
422
|
+
console.log(` worst divergence: index ${w.index} actual=${w.actual} expected=${w.expected} diff=${w.diff}`);
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
process.exit(result.status === 'pass' || result.status === 'drift' ? 0 : 1);
|
|
426
|
+
}
|
|
427
|
+
catch (e) {
|
|
428
|
+
fail(json, 2, e.message);
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
// ─── mcp start ──────────────────────────────────────────────────────
|
|
432
|
+
const mcp = program.command('mcp').description('MCP server');
|
|
433
|
+
mcp
|
|
434
|
+
.command('start')
|
|
435
|
+
.description('Start the ProofSeal MCP stdio server')
|
|
436
|
+
.action(async () => {
|
|
437
|
+
await startMcpServer();
|
|
438
|
+
});
|
|
439
|
+
program.parseAsync(process.argv);
|
|
440
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ProofSealConfig } from './manifest/schema.js';
|
|
2
|
+
export declare const CONFIG_FILENAME = "proofseal.json";
|
|
3
|
+
export declare const DEFAULT_MANIFEST_PATH = "proofs/manifest.json";
|
|
4
|
+
export declare const DEFAULT_HISTORY_PATH = "proofs/history.jsonl";
|
|
5
|
+
export interface ResolvedConfig {
|
|
6
|
+
config: ProofSealConfig;
|
|
7
|
+
configPath: string;
|
|
8
|
+
root: string;
|
|
9
|
+
salt: string;
|
|
10
|
+
manifestPath: string;
|
|
11
|
+
historyPath: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function configPathFor(root: string): string;
|
|
14
|
+
/** Load and validate proofseal.json; throws with a hint if absent/invalid. */
|
|
15
|
+
export declare function loadConfig(root?: string): ResolvedConfig;
|
|
16
|
+
/** Persist config (pretty-printed, trailing newline). */
|
|
17
|
+
export declare function saveConfig(root: string, config: ProofSealConfig): string;
|
|
18
|
+
/** Default scaffold written by `proofseal init` (ADR R3: green verify in minutes). */
|
|
19
|
+
export declare function defaultConfig(root: string): ProofSealConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* proofseal.json config loading/saving + path resolution.
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
5
|
+
import { join, resolve, basename, dirname } from 'node:path';
|
|
6
|
+
import { ConfigSchema, SCHEMA_ID } from './manifest/schema.js';
|
|
7
|
+
export const CONFIG_FILENAME = 'proofseal.json';
|
|
8
|
+
export const DEFAULT_MANIFEST_PATH = 'proofs/manifest.json';
|
|
9
|
+
export const DEFAULT_HISTORY_PATH = 'proofs/history.jsonl';
|
|
10
|
+
export function configPathFor(root) {
|
|
11
|
+
return join(resolve(root), CONFIG_FILENAME);
|
|
12
|
+
}
|
|
13
|
+
/** Load and validate proofseal.json; throws with a hint if absent/invalid. */
|
|
14
|
+
export function loadConfig(root = process.cwd()) {
|
|
15
|
+
const absRoot = resolve(root);
|
|
16
|
+
const configPath = configPathFor(absRoot);
|
|
17
|
+
if (!existsSync(configPath)) {
|
|
18
|
+
throw new Error(`${CONFIG_FILENAME} not found in ${absRoot} — run \`proofseal init\` first`);
|
|
19
|
+
}
|
|
20
|
+
const config = ConfigSchema.parse(JSON.parse(readFileSync(configPath, 'utf8')));
|
|
21
|
+
return {
|
|
22
|
+
config,
|
|
23
|
+
configPath,
|
|
24
|
+
root: absRoot,
|
|
25
|
+
salt: config.salt ?? basename(absRoot),
|
|
26
|
+
manifestPath: join(absRoot, config.manifest ?? DEFAULT_MANIFEST_PATH),
|
|
27
|
+
historyPath: join(absRoot, config.history ?? DEFAULT_HISTORY_PATH),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** Persist config (pretty-printed, trailing newline). */
|
|
31
|
+
export function saveConfig(root, config) {
|
|
32
|
+
const configPath = configPathFor(root);
|
|
33
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
34
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
35
|
+
return configPath;
|
|
36
|
+
}
|
|
37
|
+
/** Default scaffold written by `proofseal init` (ADR R3: green verify in minutes). */
|
|
38
|
+
export function defaultConfig(root) {
|
|
39
|
+
return {
|
|
40
|
+
schema: SCHEMA_ID,
|
|
41
|
+
salt: basename(resolve(root)),
|
|
42
|
+
manifest: DEFAULT_MANIFEST_PATH,
|
|
43
|
+
history: DEFAULT_HISTORY_PATH,
|
|
44
|
+
releases: {},
|
|
45
|
+
claims: [
|
|
46
|
+
{
|
|
47
|
+
id: 'sample-config-schema',
|
|
48
|
+
type: 'marker',
|
|
49
|
+
desc: 'ProofSeal config declares the v1 schema (sample claim — replace with your own)',
|
|
50
|
+
file: CONFIG_FILENAME,
|
|
51
|
+
// The escaped serialization of this marker field cannot collide with
|
|
52
|
+
// the raw schema line, so the marker matches exactly once (R5).
|
|
53
|
+
marker: `"schema": "${SCHEMA_ID}"`,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAwB,MAAM,sBAAsB,CAAC;AAErF,MAAM,CAAC,MAAM,eAAe,GAAG,gBAAgB,CAAC;AAChD,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AAC5D,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAW3D,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,eAAe,CAAC,CAAC;AAC9C,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,UAAU,CAAC,OAAe,OAAO,CAAC,GAAG,EAAE;IACrD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,GAAG,eAAe,iBAAiB,OAAO,iCAAiC,CAAC,CAAC;IAC/F,CAAC;IACD,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAChF,OAAO;QACL,MAAM;QACN,UAAU;QACV,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,QAAQ,CAAC,OAAO,CAAC;QACtC,YAAY,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,IAAI,qBAAqB,CAAC;QACrE,WAAW,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,oBAAoB,CAAC;KACnE,CAAC;AACJ,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,MAAuB;IAC9D,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACvC,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAClE,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO;QACL,MAAM,EAAE,SAAS;QACjB,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7B,QAAQ,EAAE,qBAAqB;QAC/B,OAAO,EAAE,oBAAoB;QAC7B,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE;YACN;gBACE,EAAE,EAAE,sBAAsB;gBAC1B,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,gFAAgF;gBACtF,IAAI,EAAE,eAAe;gBACrB,qEAAqE;gBACrE,gEAAgE;gBAChE,MAAM,EAAE,cAAc,SAAS,GAAG;aACnC;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical JSON — sorted-key, undefined-dropping, deterministic
|
|
3
|
+
* serialization (ADR-0001 D5: RuView's byte-stable discipline, ported
|
|
4
|
+
* from the ruflo graph-intelligence witness-signer pattern).
|
|
5
|
+
*
|
|
6
|
+
* The bytes produced here are what gets hashed and signed; any change
|
|
7
|
+
* to this function is a schema-breaking change (bump proofseal/v1).
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Serialize any JSON-representable value to canonical JSON:
|
|
11
|
+
* - object keys sorted lexicographically
|
|
12
|
+
* - keys with `undefined` values dropped
|
|
13
|
+
* - `undefined` itself serializes as `null`
|
|
14
|
+
* - no whitespace
|
|
15
|
+
*/
|
|
16
|
+
export declare function canonicalize(value: unknown): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical JSON — sorted-key, undefined-dropping, deterministic
|
|
3
|
+
* serialization (ADR-0001 D5: RuView's byte-stable discipline, ported
|
|
4
|
+
* from the ruflo graph-intelligence witness-signer pattern).
|
|
5
|
+
*
|
|
6
|
+
* The bytes produced here are what gets hashed and signed; any change
|
|
7
|
+
* to this function is a schema-breaking change (bump proofseal/v1).
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Serialize any JSON-representable value to canonical JSON:
|
|
11
|
+
* - object keys sorted lexicographically
|
|
12
|
+
* - keys with `undefined` values dropped
|
|
13
|
+
* - `undefined` itself serializes as `null`
|
|
14
|
+
* - no whitespace
|
|
15
|
+
*/
|
|
16
|
+
export function canonicalize(value) {
|
|
17
|
+
if (value === undefined)
|
|
18
|
+
return 'null';
|
|
19
|
+
if (value === null || typeof value !== 'object')
|
|
20
|
+
return JSON.stringify(value);
|
|
21
|
+
if (Array.isArray(value))
|
|
22
|
+
return '[' + value.map(canonicalize).join(',') + ']';
|
|
23
|
+
const obj = value;
|
|
24
|
+
const keys = Object.keys(obj)
|
|
25
|
+
.filter((k) => obj[k] !== undefined)
|
|
26
|
+
.sort();
|
|
27
|
+
return '{' + keys.map((k) => JSON.stringify(k) + ':' + canonicalize(obj[k])).join(',') + '}';
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=canonical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../src/core/canonical.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACvC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC9E,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IAC/E,MAAM,GAAG,GAAG,KAAgC,CAAC;IAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;SAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;SACnC,IAAI,EAAE,CAAC;IACV,OAAO,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;AAC/F,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** sha256 of a string (utf8) or Buffer, lowercase hex (64 chars). */
|
|
2
|
+
export declare function sha256Hex(input: Buffer | string): string;
|
|
3
|
+
/** sha256 of a string (utf8) or Buffer, raw 32 bytes. */
|
|
4
|
+
export declare function sha256Bytes(input: Buffer | string): Buffer;
|
|
5
|
+
/** sha256 of a file's raw bytes, lowercase hex. */
|
|
6
|
+
export declare function fileSha256(absPath: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* sha256 of a file's bytes with CRLF→LF normalization (premortem #7:
|
|
9
|
+
* Windows insurance). Used ONLY for diagnostics: when a file-hash claim
|
|
10
|
+
* regresses but the CRLF-normalized hash still matches the sealed hash,
|
|
11
|
+
* the cause is almost certainly git autocrlf rewriting line endings —
|
|
12
|
+
* the regressed detail can then name the cause instead of crying tamper.
|
|
13
|
+
*/
|
|
14
|
+
export declare function fileSha256CrlfNormalized(absPath: string): string;
|
|
15
|
+
/** True if the file (decoded as utf8) contains the marker substring. */
|
|
16
|
+
export declare function fileContains(absPath: string, marker: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Whitespace-normalized marker presence (premortem #7: marker robustness).
|
|
19
|
+
*
|
|
20
|
+
* Markers exist to outlive REBUILDS of a file — but a plain substring check
|
|
21
|
+
* also breaks under routine reformatting (Prettier line-wraps, re-indents,
|
|
22
|
+
* tabs→spaces). That reads as a false "regressed" and teaches users that
|
|
23
|
+
* ProofSeal lies. Both the file text and the marker are normalized (see
|
|
24
|
+
* `normalizeForMarker`) before matching, so whitespace-only rewrites of the
|
|
25
|
+
* marker's surroundings still match while any non-whitespace edit to the
|
|
26
|
+
* marker text itself still (correctly) fails.
|
|
27
|
+
*
|
|
28
|
+
* Plain `fileContains` is kept for exact-substring use cases.
|
|
29
|
+
*/
|
|
30
|
+
export declare function markerPresent(text: string, marker: string): boolean;
|
|
31
|
+
/** Whitespace-normalized count of (non-overlapping) marker occurrences. */
|
|
32
|
+
export declare function markerOccurrences(text: string, marker: string): number;
|