proofseal 0.0.2 → 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 +204 -7
- 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 +43 -13
- package/bin.js +0 -19
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* proofseal/v1 manifest schema — types + zod validation (ADR-0001 §5.3).
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
export const SCHEMA_ID = 'proofseal/v1';
|
|
6
|
+
const Hex64 = z.string().regex(/^[0-9a-f]{64}$/, 'expected 64 lowercase hex chars');
|
|
7
|
+
const Hex128 = z.string().regex(/^[0-9a-f]{128}$/, 'expected 128 lowercase hex chars');
|
|
8
|
+
export const ToleranceSchema = z.object({
|
|
9
|
+
rtol: z.number().nonnegative(),
|
|
10
|
+
atol: z.number().nonnegative(),
|
|
11
|
+
});
|
|
12
|
+
const claimBase = {
|
|
13
|
+
id: z.string().min(1),
|
|
14
|
+
desc: z.string().optional(),
|
|
15
|
+
};
|
|
16
|
+
export const FileHashClaimSchema = z.object({
|
|
17
|
+
...claimBase,
|
|
18
|
+
type: z.literal('file-hash'),
|
|
19
|
+
file: z.string().min(1),
|
|
20
|
+
/** Computed at seal time; optional in config. */
|
|
21
|
+
sha256: z.string().optional(),
|
|
22
|
+
});
|
|
23
|
+
export const MarkerClaimSchema = z.object({
|
|
24
|
+
...claimBase,
|
|
25
|
+
type: z.literal('marker'),
|
|
26
|
+
file: z.string().min(1),
|
|
27
|
+
marker: z.string().min(1),
|
|
28
|
+
/** Computed at seal time; optional in config. */
|
|
29
|
+
sha256: z.string().optional(),
|
|
30
|
+
markerVerified: z.boolean().optional(),
|
|
31
|
+
});
|
|
32
|
+
export const HarnessClaimSchema = z.object({
|
|
33
|
+
...claimBase,
|
|
34
|
+
type: z.literal('harness'),
|
|
35
|
+
/** Harness name (defaults to claim id when omitted in config). */
|
|
36
|
+
harness: z.string().min(1),
|
|
37
|
+
/** Command spawned with PROOFSEAL_SEED in env. */
|
|
38
|
+
cmd: z.string().min(1),
|
|
39
|
+
seed: z.number().int().optional(),
|
|
40
|
+
quantizeDecimals: z.number().int().min(0).max(15).optional(),
|
|
41
|
+
/** Named output blocks to exclude from hashing (pitfall 6: un-hashable features). */
|
|
42
|
+
exclude: z.array(z.string()).optional(),
|
|
43
|
+
/** Committed expectation — set by `proofseal harness run --update`. */
|
|
44
|
+
expectedSha256: z.string().optional(),
|
|
45
|
+
/** Path (relative to root) to a committed JSON array of reference numbers. */
|
|
46
|
+
referenceVector: z.string().optional(),
|
|
47
|
+
tolerance: ToleranceSchema.optional(),
|
|
48
|
+
});
|
|
49
|
+
export const ClaimSchema = z.discriminatedUnion('type', [
|
|
50
|
+
FileHashClaimSchema,
|
|
51
|
+
MarkerClaimSchema,
|
|
52
|
+
HarnessClaimSchema,
|
|
53
|
+
]);
|
|
54
|
+
export const SummarySchema = z.object({
|
|
55
|
+
totalClaims: z.number().int().nonnegative(),
|
|
56
|
+
verified: z.number().int().nonnegative(),
|
|
57
|
+
missing: z.number().int().nonnegative(),
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* Sealing environment (premortem #3: platform honesty). Recorded — and
|
|
61
|
+
* therefore signed — at seal time so verify can warn when the verifying OS
|
|
62
|
+
* differs (built/binary artifact hashes legitimately diverge across OSes).
|
|
63
|
+
*/
|
|
64
|
+
export const PlatformSchema = z.object({
|
|
65
|
+
os: z.string(),
|
|
66
|
+
arch: z.string(),
|
|
67
|
+
node: z.string(),
|
|
68
|
+
});
|
|
69
|
+
export const ManifestSchema = z.object({
|
|
70
|
+
schema: z.literal(SCHEMA_ID),
|
|
71
|
+
issuedAt: z.string(),
|
|
72
|
+
gitCommit: z.string().regex(/^[0-9a-f]{40}$/),
|
|
73
|
+
branch: z.string(),
|
|
74
|
+
salt: z.string(),
|
|
75
|
+
releases: z.record(z.string()),
|
|
76
|
+
summary: SummarySchema,
|
|
77
|
+
claims: z.array(ClaimSchema),
|
|
78
|
+
/** Optional for backward compat: pre-platform manifests still validate. */
|
|
79
|
+
platform: PlatformSchema.optional(),
|
|
80
|
+
});
|
|
81
|
+
export const IntegritySchema = z.object({
|
|
82
|
+
manifestHashAlgo: z.literal('sha256'),
|
|
83
|
+
manifestHash: Hex64,
|
|
84
|
+
signatureAlgo: z.literal('ed25519'),
|
|
85
|
+
publicKey: Hex64,
|
|
86
|
+
signature: Hex128,
|
|
87
|
+
seedDerivation: z.string(),
|
|
88
|
+
});
|
|
89
|
+
export const WitnessSchema = z.object({
|
|
90
|
+
manifest: ManifestSchema,
|
|
91
|
+
integrity: IntegritySchema,
|
|
92
|
+
});
|
|
93
|
+
/** proofseal.json config file shape. */
|
|
94
|
+
export const ConfigSchema = z.object({
|
|
95
|
+
schema: z.literal(SCHEMA_ID),
|
|
96
|
+
salt: z.string().optional(),
|
|
97
|
+
manifest: z.string().optional(),
|
|
98
|
+
history: z.string().optional(),
|
|
99
|
+
releases: z.record(z.string()).optional(),
|
|
100
|
+
claims: z.array(ClaimSchema),
|
|
101
|
+
});
|
|
102
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/manifest/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type HistoryEntry } from '../history/jsonl.js';
|
|
2
|
+
import { type Claim, type ClaimState, type Manifest, type Witness } from './schema.js';
|
|
3
|
+
/** Refresh a single claim against the live tree (synchronous, seal-time). */
|
|
4
|
+
export declare function refreshClaim(root: string, claim: Claim): ClaimState;
|
|
5
|
+
/** Warn-worthy issues found while sealing (R5: marker fragility). */
|
|
6
|
+
export interface SealWarning {
|
|
7
|
+
id: string;
|
|
8
|
+
message: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SealOptions {
|
|
11
|
+
root?: string;
|
|
12
|
+
/** Override the git commit (40-hex). Defaults to `git rev-parse HEAD`. */
|
|
13
|
+
gitCommit?: string;
|
|
14
|
+
/** Override the branch. Defaults to `git rev-parse --abbrev-ref HEAD`. */
|
|
15
|
+
branch?: string;
|
|
16
|
+
/** Override issuedAt (ISO 8601). Defaults to now. */
|
|
17
|
+
issuedAt?: string;
|
|
18
|
+
/** Extra releases map merged over the config's. */
|
|
19
|
+
releases?: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
export interface SealResult {
|
|
22
|
+
ok: boolean;
|
|
23
|
+
witness: Witness;
|
|
24
|
+
manifestPath: string;
|
|
25
|
+
historyPath: string;
|
|
26
|
+
historyEntry: HistoryEntry;
|
|
27
|
+
summary: Manifest['summary'];
|
|
28
|
+
warnings: SealWarning[];
|
|
29
|
+
/**
|
|
30
|
+
* Repo-relative (forward-slash) paths of every file `verify` needs
|
|
31
|
+
* committed: whatever this seal wrote (reference vectors, a rewritten
|
|
32
|
+
* proofseal.json, the manifest, the history log) PLUS any pre-existing
|
|
33
|
+
* verify-required file (proofseal.json, reference vectors) that git
|
|
34
|
+
* reports as untracked or dirty. CI footgun pack (premortem #5) +
|
|
35
|
+
* R4 quickstart finding: verify on a clean clone only works if ALL of
|
|
36
|
+
* these are committed — the CLI prints them as a checklist.
|
|
37
|
+
*/
|
|
38
|
+
filesWritten: string[];
|
|
39
|
+
}
|
|
40
|
+
/** Seal the repo: manifest + integrity block + history snapshot. */
|
|
41
|
+
export declare function seal(opts?: SealOptions): Promise<SealResult>;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seal — refresh claims against the live tree, build the proofseal/v1
|
|
3
|
+
* manifest, derive the commit-bound key, seal, write, append history.
|
|
4
|
+
* (Port of ruflo lib.mjs regenerate(), adapted to sorted-key
|
|
5
|
+
* canonicalization and the three-claim-type model.)
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, writeFileSync, mkdirSync, readFileSync } from 'node:fs';
|
|
8
|
+
import { join, dirname, relative } from 'node:path';
|
|
9
|
+
import { execSync, execFileSync } from 'node:child_process';
|
|
10
|
+
import { canonicalize } from '../core/canonical.js';
|
|
11
|
+
import { normalizeClaimPath } from '../core/paths.js';
|
|
12
|
+
import { sha256Hex, fileSha256, markerPresent, markerOccurrences } from '../core/hash.js';
|
|
13
|
+
import { deriveKey, signBytes, SEED_DERIVATION } from '../keys/derive.js';
|
|
14
|
+
import { appendHistory, claimVerified } from '../history/jsonl.js';
|
|
15
|
+
import { runHarness } from '../harness/run.js';
|
|
16
|
+
import { DEFAULT_TOLERANCE } from '../harness/quantize.js';
|
|
17
|
+
import { loadConfig, saveConfig, CONFIG_FILENAME } from '../config.js';
|
|
18
|
+
import { SCHEMA_ID } from './schema.js';
|
|
19
|
+
/** Refresh a single claim against the live tree (synchronous, seal-time). */
|
|
20
|
+
export function refreshClaim(root, claim) {
|
|
21
|
+
if (claim.type === 'harness') {
|
|
22
|
+
// Existing expectations are carried through unchanged (regeneration only
|
|
23
|
+
// via reviewed `proofseal harness run --update`). First-seal minting of a
|
|
24
|
+
// brand-new expectation happens in seal() itself.
|
|
25
|
+
return {
|
|
26
|
+
...claim,
|
|
27
|
+
harness: claim.harness || claim.id,
|
|
28
|
+
seed: claim.seed ?? 42,
|
|
29
|
+
quantizeDecimals: claim.quantizeDecimals ?? 6,
|
|
30
|
+
...(claim.referenceVector
|
|
31
|
+
? { referenceVector: normalizeClaimPath(claim.referenceVector) }
|
|
32
|
+
: {}),
|
|
33
|
+
missing: false,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Windows insurance: claim paths are sealed with forward slashes so a
|
|
37
|
+
// claim authored on Windows matches on POSIX and vice versa.
|
|
38
|
+
const file = normalizeClaimPath(claim.file);
|
|
39
|
+
const abs = join(root, file);
|
|
40
|
+
if (!existsSync(abs)) {
|
|
41
|
+
if (claim.type === 'marker') {
|
|
42
|
+
return { ...claim, file, sha256: claim.sha256 ?? '', markerVerified: false, missing: true };
|
|
43
|
+
}
|
|
44
|
+
return { ...claim, file, sha256: claim.sha256 ?? '', missing: true };
|
|
45
|
+
}
|
|
46
|
+
const sha256 = fileSha256(abs);
|
|
47
|
+
if (claim.type === 'marker') {
|
|
48
|
+
// Whitespace-normalized check (premortem #7): a Prettier line-wrap or
|
|
49
|
+
// re-indent of the marker's surroundings must not break the claim.
|
|
50
|
+
const verified = markerPresent(readFileSync(abs, 'utf8'), claim.marker);
|
|
51
|
+
return { ...claim, file, sha256, markerVerified: verified, missing: false };
|
|
52
|
+
}
|
|
53
|
+
return { ...claim, file, sha256, missing: false };
|
|
54
|
+
}
|
|
55
|
+
function gitMeta(root, opts) {
|
|
56
|
+
const gitCommit = opts.gitCommit ?? execSync('git rev-parse HEAD', { cwd: root }).toString().trim();
|
|
57
|
+
const branch = opts.branch ?? execSync('git rev-parse --abbrev-ref HEAD', { cwd: root }).toString().trim();
|
|
58
|
+
return { gitCommit, branch };
|
|
59
|
+
}
|
|
60
|
+
/** Seal the repo: manifest + integrity block + history snapshot. */
|
|
61
|
+
export async function seal(opts = {}) {
|
|
62
|
+
const { root, salt, manifestPath, historyPath, config } = loadConfig(opts.root ?? process.cwd());
|
|
63
|
+
const { gitCommit, branch } = gitMeta(root, opts);
|
|
64
|
+
const issuedAt = opts.issuedAt ?? new Date().toISOString();
|
|
65
|
+
const filesWritten = [];
|
|
66
|
+
// First-seal mint: a harness claim with no committed expectation gets one
|
|
67
|
+
// now (run once, record hash + full-precision reference vector, persist to
|
|
68
|
+
// proofseal.json). Regenerating an EXISTING expectation stays explicit via
|
|
69
|
+
// `proofseal harness run --update`.
|
|
70
|
+
let configDirty = false;
|
|
71
|
+
for (const c of config.claims) {
|
|
72
|
+
if (c.type !== 'harness' || c.expectedSha256)
|
|
73
|
+
continue;
|
|
74
|
+
const r = await runHarness({
|
|
75
|
+
name: c.harness || c.id,
|
|
76
|
+
cmd: c.cmd,
|
|
77
|
+
cwd: root,
|
|
78
|
+
seed: c.seed,
|
|
79
|
+
quantizeDecimals: c.quantizeDecimals,
|
|
80
|
+
exclude: c.exclude,
|
|
81
|
+
});
|
|
82
|
+
if (r.hash && r.values) {
|
|
83
|
+
const refRel = normalizeClaimPath(c.referenceVector ?? `proofs/${c.harness || c.id}.reference.json`);
|
|
84
|
+
const refAbs = join(root, refRel);
|
|
85
|
+
mkdirSync(dirname(refAbs), { recursive: true });
|
|
86
|
+
writeFileSync(refAbs, JSON.stringify(r.values) + '\n');
|
|
87
|
+
c.expectedSha256 = r.hash;
|
|
88
|
+
c.referenceVector = refRel;
|
|
89
|
+
c.tolerance = c.tolerance ?? { ...DEFAULT_TOLERANCE };
|
|
90
|
+
configDirty = true;
|
|
91
|
+
filesWritten.push(refRel);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (configDirty) {
|
|
95
|
+
saveConfig(root, config);
|
|
96
|
+
filesWritten.push(CONFIG_FILENAME);
|
|
97
|
+
}
|
|
98
|
+
const refreshed = config.claims.map((c) => refreshClaim(root, c));
|
|
99
|
+
const warnings = [];
|
|
100
|
+
for (const c of refreshed) {
|
|
101
|
+
if (c.type === 'marker' && !c.missing) {
|
|
102
|
+
const text = readFileSync(join(root, c.file), 'utf8');
|
|
103
|
+
// Whitespace-normalized count, consistent with markerPresent matching.
|
|
104
|
+
const occurrences = markerOccurrences(text, c.marker);
|
|
105
|
+
if (occurrences > 1) {
|
|
106
|
+
warnings.push({ id: c.id, message: `marker appears ${occurrences} times in ${c.file} — choose a more distinctive substring` });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const claims = refreshed.map((c) => {
|
|
111
|
+
const { missing: _missing, ...clean } = c;
|
|
112
|
+
return clean;
|
|
113
|
+
});
|
|
114
|
+
const verified = claims.filter((c) => claimVerified(c)).length;
|
|
115
|
+
const missing = refreshed.filter((c) => c.missing).length;
|
|
116
|
+
const manifest = {
|
|
117
|
+
schema: SCHEMA_ID,
|
|
118
|
+
issuedAt,
|
|
119
|
+
gitCommit,
|
|
120
|
+
branch,
|
|
121
|
+
salt,
|
|
122
|
+
releases: { ...(config.releases ?? {}), ...(opts.releases ?? {}) },
|
|
123
|
+
summary: { totalClaims: claims.length, verified, missing },
|
|
124
|
+
claims,
|
|
125
|
+
// Sealing environment (premortem #3) — signed with the rest of the
|
|
126
|
+
// manifest so verify can warn about cross-OS hash drift honestly.
|
|
127
|
+
platform: { os: process.platform, arch: process.arch, node: process.versions.node },
|
|
128
|
+
};
|
|
129
|
+
const manifestHash = sha256Hex(canonicalize(manifest));
|
|
130
|
+
const key = deriveKey(gitCommit, salt);
|
|
131
|
+
const signature = signBytes(key.privateKey, Buffer.from(manifestHash, 'hex'));
|
|
132
|
+
const witness = {
|
|
133
|
+
manifest,
|
|
134
|
+
integrity: {
|
|
135
|
+
manifestHashAlgo: 'sha256',
|
|
136
|
+
manifestHash,
|
|
137
|
+
signatureAlgo: 'ed25519',
|
|
138
|
+
publicKey: key.publicKeyHex,
|
|
139
|
+
signature,
|
|
140
|
+
seedDerivation: SEED_DERIVATION,
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
mkdirSync(dirname(manifestPath), { recursive: true });
|
|
144
|
+
writeFileSync(manifestPath, JSON.stringify(witness, null, 2) + '\n');
|
|
145
|
+
filesWritten.push(normalizeClaimPath(relative(root, manifestPath)));
|
|
146
|
+
mkdirSync(dirname(historyPath), { recursive: true });
|
|
147
|
+
const historyEntry = appendHistory(historyPath, manifest, manifestHash);
|
|
148
|
+
filesWritten.push(normalizeClaimPath(relative(root, historyPath)));
|
|
149
|
+
// Premortem R4 (quickstart-verbatim): the checklist must list every file
|
|
150
|
+
// `verify` NEEDS, not just files written THIS run. proofseal.json usually
|
|
151
|
+
// pre-exists (written by init / claim add) yet is often still untracked —
|
|
152
|
+
// following the printed list verbatim then cloning gives verify exit 1
|
|
153
|
+
// MISSING. Check git status for the config + reference vectors; fail-open
|
|
154
|
+
// (no git / odd state → over-list rather than under-list).
|
|
155
|
+
const neededByVerify = new Set([CONFIG_FILENAME]);
|
|
156
|
+
for (const c of config.claims) {
|
|
157
|
+
if (c.type === 'harness' && c.referenceVector)
|
|
158
|
+
neededByVerify.add(normalizeClaimPath(c.referenceVector));
|
|
159
|
+
}
|
|
160
|
+
for (const rel of neededByVerify) {
|
|
161
|
+
if (filesWritten.includes(rel) || !existsSync(join(root, rel)))
|
|
162
|
+
continue;
|
|
163
|
+
try {
|
|
164
|
+
const status = execFileSync('git', ['status', '--porcelain', '--', rel], { cwd: root })
|
|
165
|
+
.toString()
|
|
166
|
+
.trim();
|
|
167
|
+
if (status !== '')
|
|
168
|
+
filesWritten.push(rel);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
filesWritten.push(rel);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
ok: missing === 0 && verified === claims.length,
|
|
176
|
+
witness,
|
|
177
|
+
manifestPath,
|
|
178
|
+
historyPath,
|
|
179
|
+
historyEntry,
|
|
180
|
+
summary: manifest.summary,
|
|
181
|
+
warnings,
|
|
182
|
+
filesWritten,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=seal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seal.js","sourceRoot":"","sources":["../../src/manifest/seal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { Claim, ClaimStatus, Witness } from './schema.js';
|
|
2
|
+
export declare const THREAT_MODEL_NOTE = "commit-bound tamper-evidence, not third-party authentication";
|
|
3
|
+
/** Detail attached to a regressed file-hash claim caused by git autocrlf. */
|
|
4
|
+
export declare const CRLF_DETAIL = "content identical after line-ending normalization \u2014 likely git autocrlf; pin with .gitattributes (* text=auto eol=lf)";
|
|
5
|
+
/** Named precondition hint for an uncommitted reference vector (premortem #5). */
|
|
6
|
+
export declare const REFERENCE_VECTOR_HINT = "reference vector not found \u2014 did you commit the seal outputs? (run `proofseal seal` then commit the listed files)";
|
|
7
|
+
export interface SignatureCheck {
|
|
8
|
+
manifestHashOk: boolean;
|
|
9
|
+
publicKeyReproducible: boolean;
|
|
10
|
+
signatureValid: boolean;
|
|
11
|
+
/** Hex public key from the witness ('' when no manifest is present). */
|
|
12
|
+
publicKey: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ClaimResult {
|
|
15
|
+
id: string;
|
|
16
|
+
type: Claim['type'];
|
|
17
|
+
desc?: string;
|
|
18
|
+
file?: string;
|
|
19
|
+
status: ClaimStatus;
|
|
20
|
+
sha256Match?: boolean;
|
|
21
|
+
markerPresent?: boolean;
|
|
22
|
+
localSha256?: string;
|
|
23
|
+
hashMatch?: boolean;
|
|
24
|
+
toleranceMatch?: boolean;
|
|
25
|
+
detail?: string;
|
|
26
|
+
/**
|
|
27
|
+
* The failure looks like an unmet environment precondition (build output
|
|
28
|
+
* not built, harness command not installed) rather than a regression.
|
|
29
|
+
* When EVERY failing claim is precondition-suspect, verify exits 2.
|
|
30
|
+
*/
|
|
31
|
+
preconditionSuspect?: boolean;
|
|
32
|
+
/** Harness claim whose committed reference vector file is absent. */
|
|
33
|
+
referenceVectorMissing?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface VerifySummary {
|
|
36
|
+
pass: number;
|
|
37
|
+
drift: number;
|
|
38
|
+
regressed: number;
|
|
39
|
+
missing: number;
|
|
40
|
+
}
|
|
41
|
+
export interface VerifyResult {
|
|
42
|
+
ok: boolean;
|
|
43
|
+
/** 0 ok/drift · 1 regressed/missing/seal-mismatch · 2 precondition. API contract (D7). */
|
|
44
|
+
exitCode: 0 | 1 | 2;
|
|
45
|
+
precondition?: string;
|
|
46
|
+
/** Human hint when a precondition fails (e.g. "run npm ci && npm run build"). */
|
|
47
|
+
hint?: string;
|
|
48
|
+
signature: SignatureCheck;
|
|
49
|
+
summary: VerifySummary;
|
|
50
|
+
results: ClaimResult[];
|
|
51
|
+
note: string;
|
|
52
|
+
/**
|
|
53
|
+
* Set when the verifying OS differs from the sealing OS (premortem #3:
|
|
54
|
+
* platform honesty). Advisory only — never changes exit-code semantics.
|
|
55
|
+
*/
|
|
56
|
+
platformWarning?: string;
|
|
57
|
+
}
|
|
58
|
+
/** Pinned `verify --json` schema, v1 (CONTRACT-RESOLUTIONS §4). */
|
|
59
|
+
export interface VerifyJson {
|
|
60
|
+
ok: boolean;
|
|
61
|
+
signature: {
|
|
62
|
+
valid: boolean;
|
|
63
|
+
publicKey: string;
|
|
64
|
+
publicKeyReproducible: boolean;
|
|
65
|
+
};
|
|
66
|
+
summary: {
|
|
67
|
+
totalClaims: number;
|
|
68
|
+
pass: number;
|
|
69
|
+
drift: number;
|
|
70
|
+
regressed: number;
|
|
71
|
+
missing: number;
|
|
72
|
+
};
|
|
73
|
+
results: Array<{
|
|
74
|
+
id: string;
|
|
75
|
+
type: string;
|
|
76
|
+
status: ClaimStatus;
|
|
77
|
+
file: string;
|
|
78
|
+
detail: string;
|
|
79
|
+
}>;
|
|
80
|
+
precondition: {
|
|
81
|
+
reason: string;
|
|
82
|
+
hint: string;
|
|
83
|
+
} | null;
|
|
84
|
+
/** Additive (v1-compatible): present only on a sealing/verifying OS mismatch. */
|
|
85
|
+
platformWarning?: string;
|
|
86
|
+
}
|
|
87
|
+
/** Map a VerifyResult onto the pinned v1 JSON schema. */
|
|
88
|
+
export declare function toVerifyJson(r: VerifyResult): VerifyJson;
|
|
89
|
+
export interface VerifyOptions {
|
|
90
|
+
root?: string;
|
|
91
|
+
manifestPath?: string;
|
|
92
|
+
/** Execute harness claims (default true). */
|
|
93
|
+
runHarnesses?: boolean;
|
|
94
|
+
/** Current OS for platform-mismatch detection; injectable for tests. */
|
|
95
|
+
currentPlatform?: string;
|
|
96
|
+
}
|
|
97
|
+
/** Integrity-seal triple-check (ADR §5.4). */
|
|
98
|
+
export declare function checkSignature(witness: Witness): SignatureCheck;
|
|
99
|
+
/** Classify a file-backed (file-hash | marker) claim against the live tree. */
|
|
100
|
+
export declare function classifyFileClaim(root: string, claim: Claim): ClaimResult;
|
|
101
|
+
/** Verify a sealed manifest against the live tree. Never throws on bad repos. */
|
|
102
|
+
export declare function verify(opts?: VerifyOptions): Promise<VerifyResult>;
|