prae-cli 0.4.0 → 0.5.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/lib/bin.js +2 -2
- package/lib/{cli-BvAYSK5w.js → cli-ZfwhJKRw.js} +39 -9
- package/lib/index.js +2 -2
- package/lib/receipt-check-Dql0uqxw.js +39 -0
- package/lib/{src-CAUNqZJ1.js → src-CXU0_W1P.js} +18 -1
- package/lib/src-Kubj3MTX.js +3 -0
- package/package.json +1 -1
- package/lib/src-CBK_quVO.js +0 -3
- /package/lib/{src-aU5WW02C.js → src-BfYsUDW9.js} +0 -0
- /package/lib/{src-CCeafjdm.js → src-C4fnUm9V.js} +0 -0
package/lib/bin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "./evaluate-BilZez15.js";
|
|
3
|
-
import { t as main } from "./cli-
|
|
4
|
-
import "./src-
|
|
3
|
+
import { t as main } from "./cli-ZfwhJKRw.js";
|
|
4
|
+
import "./src-CXU0_W1P.js";
|
|
5
5
|
import "./views-DalPkBZZ.js";
|
|
6
6
|
|
|
7
7
|
//#region src/bin.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as evaluate } from "./evaluate-BilZez15.js";
|
|
2
|
-
import {
|
|
2
|
+
import { m as seal, t as Ledger } from "./src-CXU0_W1P.js";
|
|
3
3
|
import { a as renderPacks, c as renderShell, i as renderOverview, l as VERDICT_LABEL$1, n as renderApprovals, o as esc, r as renderCompliance, s as renderNav, t as navFor } from "./views-DalPkBZZ.js";
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
@@ -864,6 +864,10 @@ const USAGE = `prae — operator policy for agent harnesses
|
|
|
864
864
|
prae receipt <ledger.jsonl> <seq> --key <private.pem> [--out <file>]
|
|
865
865
|
Export one decision as a self-contained signed receipt.
|
|
866
866
|
|
|
867
|
+
prae verify-receipt <receipt.json>
|
|
868
|
+
Check one receipt with nothing but the file: recompute its hash, verify
|
|
869
|
+
its signature, and print the key fingerprint to compare against your own.
|
|
870
|
+
|
|
867
871
|
prae report <ledger.jsonl> [--out <file.html>]
|
|
868
872
|
Render the decision record as a printable evidence report.
|
|
869
873
|
|
|
@@ -972,7 +976,7 @@ async function mcp(root, packPath, ledgerPath) {
|
|
|
972
976
|
const chosen = packPath ?? bundled;
|
|
973
977
|
if (chosen === void 0) return fail("mcp needs --pack <file>; no bundled secret-catcher found");
|
|
974
978
|
const pack = await loadPack(chosen);
|
|
975
|
-
const { Ledger: Ledger$1 } = await import("./src-
|
|
979
|
+
const { Ledger: Ledger$1 } = await import("./src-Kubj3MTX.js");
|
|
976
980
|
const ledger = ledgerPath === void 0 ? void 0 : Ledger$1.open(ledgerPath);
|
|
977
981
|
console.error(`prae mcp: serving ${resolve$1(root)} under ${pack.pack} ${pack.version}` + (ledgerPath === void 0 ? " (no ledger)" : ` · ledger ${ledgerPath}`));
|
|
978
982
|
await serveMcp({
|
|
@@ -1024,7 +1028,7 @@ async function explain(path, tool, pairs) {
|
|
|
1024
1028
|
* a key that arrived beside it is checked against nothing.
|
|
1025
1029
|
*/
|
|
1026
1030
|
async function keygen(dir) {
|
|
1027
|
-
const { generateKeypair, fingerprint } = await import("./src-
|
|
1031
|
+
const { generateKeypair, fingerprint } = await import("./src-Kubj3MTX.js");
|
|
1028
1032
|
const { writeFileSync: writeFileSync$1 } = await import("node:fs");
|
|
1029
1033
|
const keys = generateKeypair();
|
|
1030
1034
|
const priv = join(dir, "prae-signing.pem");
|
|
@@ -1040,7 +1044,7 @@ async function keygen(dir) {
|
|
|
1040
1044
|
console.log("private key with `signingKey` to sign every row.");
|
|
1041
1045
|
}
|
|
1042
1046
|
async function receipt(path, seq, keyPath, out) {
|
|
1043
|
-
const { Ledger: Ledger$1, makeReceipt, fingerprint } = await import("./src-
|
|
1047
|
+
const { Ledger: Ledger$1, makeReceipt, fingerprint } = await import("./src-Kubj3MTX.js");
|
|
1044
1048
|
const { readFileSync: readFileSync$1 } = await import("node:fs");
|
|
1045
1049
|
const { createPublicKey } = await import("node:crypto");
|
|
1046
1050
|
const privateKey = readFileSync$1(keyPath, "utf8");
|
|
@@ -1061,6 +1065,27 @@ async function receipt(path, seq, keyPath, out) {
|
|
|
1061
1065
|
console.log("The verifier compares that fingerprint against the one they");
|
|
1062
1066
|
console.log("pinned — a receipt is only as good as the key they trust.");
|
|
1063
1067
|
}
|
|
1068
|
+
/**
|
|
1069
|
+
* `prae verify-receipt`: check a single self-contained receipt.
|
|
1070
|
+
*
|
|
1071
|
+
* The counterparty's command. It needs nothing but the receipt file — no
|
|
1072
|
+
* ledger, no PRAE account, no trust in the machine that issued it. The verdict
|
|
1073
|
+
* and its wording live in `receipt-check.ts` as a pure function; this reads the
|
|
1074
|
+
* file and sets the exit code, so scripts can branch on it.
|
|
1075
|
+
*/
|
|
1076
|
+
async function verifyReceiptCmd(path) {
|
|
1077
|
+
const { checkReceipt } = await import("./receipt-check-Dql0uqxw.js");
|
|
1078
|
+
let parsed;
|
|
1079
|
+
try {
|
|
1080
|
+
parsed = JSON.parse(await readFile(path, "utf8"));
|
|
1081
|
+
} catch {
|
|
1082
|
+
return fail(`cannot read a receipt from ${path}`);
|
|
1083
|
+
}
|
|
1084
|
+
const result = checkReceipt(parsed);
|
|
1085
|
+
for (const line of result.lines) if (result.ok) console.log(line);
|
|
1086
|
+
else console.error(line);
|
|
1087
|
+
if (!result.ok) process.exit(1);
|
|
1088
|
+
}
|
|
1064
1089
|
async function verify(path, keyPath) {
|
|
1065
1090
|
let ledger;
|
|
1066
1091
|
try {
|
|
@@ -1074,7 +1099,7 @@ async function verify(path, keyPath) {
|
|
|
1074
1099
|
const last = entries.at(-1);
|
|
1075
1100
|
console.log(`${result.entries} entries · chain intact${last === void 0 ? "" : ` · seal ${seal(last)}`}`);
|
|
1076
1101
|
if (keyPath !== void 0) {
|
|
1077
|
-
const { verifySignature, fingerprint } = await import("./src-
|
|
1102
|
+
const { verifySignature, fingerprint } = await import("./src-Kubj3MTX.js");
|
|
1078
1103
|
const { readFileSync: readFileSync$1 } = await import("node:fs");
|
|
1079
1104
|
const publicKey = readFileSync$1(keyPath, "utf8");
|
|
1080
1105
|
let signed = 0;
|
|
@@ -1150,7 +1175,7 @@ async function report(path, out) {
|
|
|
1150
1175
|
* that step is a proposal a human approves, and it starts from this list.
|
|
1151
1176
|
*/
|
|
1152
1177
|
async function instructions(from, asJson) {
|
|
1153
|
-
const { ingest } = await import("./src-
|
|
1178
|
+
const { ingest } = await import("./src-C4fnUm9V.js");
|
|
1154
1179
|
const result = ingest(from);
|
|
1155
1180
|
if (asJson) {
|
|
1156
1181
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -1186,7 +1211,7 @@ async function instructions(from, asJson) {
|
|
|
1186
1211
|
* on purpose rather than something that happened to their policy.
|
|
1187
1212
|
*/
|
|
1188
1213
|
async function propose(from, options) {
|
|
1189
|
-
const [{ ingest }, { extract }] = await Promise.all([import("./src-
|
|
1214
|
+
const [{ ingest }, { extract }] = await Promise.all([import("./src-C4fnUm9V.js"), import("./src-BfYsUDW9.js")]);
|
|
1190
1215
|
const read = ingest(from);
|
|
1191
1216
|
if (read.files.length === 0) {
|
|
1192
1217
|
console.log(`No instruction files found at or above ${from}.`);
|
|
@@ -1246,8 +1271,8 @@ async function consoleOut(path, argv) {
|
|
|
1246
1271
|
const instructionsDir = flag(argv, "instructions");
|
|
1247
1272
|
if (instructionsDir !== void 0) {
|
|
1248
1273
|
const [{ ingest }, { extract }, { renderInstructions }] = await Promise.all([
|
|
1249
|
-
import("./src-
|
|
1250
|
-
import("./src-
|
|
1274
|
+
import("./src-C4fnUm9V.js"),
|
|
1275
|
+
import("./src-BfYsUDW9.js"),
|
|
1251
1276
|
import("./instructions-D4VOn2lk.js")
|
|
1252
1277
|
]);
|
|
1253
1278
|
const read = ingest(instructionsDir);
|
|
@@ -1369,6 +1394,11 @@ async function main(argv) {
|
|
|
1369
1394
|
if (path === void 0) fail("verify needs a ledger file");
|
|
1370
1395
|
return verify(path, flag(rest, "key"));
|
|
1371
1396
|
}
|
|
1397
|
+
case "verify-receipt": {
|
|
1398
|
+
const path = rest[0];
|
|
1399
|
+
if (path === void 0) fail("verify-receipt needs a receipt file");
|
|
1400
|
+
return verifyReceiptCmd(path);
|
|
1401
|
+
}
|
|
1372
1402
|
case "report": {
|
|
1373
1403
|
const path = rest[0];
|
|
1374
1404
|
if (path === void 0) fail("report needs a ledger file");
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./evaluate-BilZez15.js";
|
|
2
|
-
import { a as planWrite, i as dshHome, n as applyWrite, o as praeRow, r as defaultProfile, s as profileAt, t as main } from "./cli-
|
|
3
|
-
import "./src-
|
|
2
|
+
import { a as planWrite, i as dshHome, n as applyWrite, o as praeRow, r as defaultProfile, s as profileAt, t as main } from "./cli-ZfwhJKRw.js";
|
|
3
|
+
import "./src-CXU0_W1P.js";
|
|
4
4
|
import "./views-DalPkBZZ.js";
|
|
5
5
|
|
|
6
6
|
export { applyWrite, defaultProfile, dshHome, main, planWrite, praeRow, profileAt };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { c as verifyReceipt, i as fingerprint } from "./src-CXU0_W1P.js";
|
|
2
|
+
|
|
3
|
+
//#region src/receipt-check.ts
|
|
4
|
+
/** Shape we require before we will call it a receipt at all. */
|
|
5
|
+
function looksLikeReceipt(value) {
|
|
6
|
+
if (typeof value !== "object" || value === null) return false;
|
|
7
|
+
const r = value;
|
|
8
|
+
return typeof r.signature === "string" && typeof r.publicKey === "string" && typeof r.entry === "object" && r.entry !== null;
|
|
9
|
+
}
|
|
10
|
+
function checkReceipt(parsed) {
|
|
11
|
+
if (!looksLikeReceipt(parsed)) return {
|
|
12
|
+
ok: false,
|
|
13
|
+
lines: ["✗ not a receipt: expected `entry`, `signature` and `publicKey` fields"]
|
|
14
|
+
};
|
|
15
|
+
const result = verifyReceipt(parsed);
|
|
16
|
+
if (!result.ok) return {
|
|
17
|
+
ok: false,
|
|
18
|
+
lines: [`✗ receipt does NOT verify: ${result.reason}`]
|
|
19
|
+
};
|
|
20
|
+
const { verdict, tool, rule, subject } = parsed.entry;
|
|
21
|
+
return {
|
|
22
|
+
ok: true,
|
|
23
|
+
lines: [
|
|
24
|
+
"✓ receipt verifies — authentic and unaltered",
|
|
25
|
+
` ${[
|
|
26
|
+
verdict,
|
|
27
|
+
tool,
|
|
28
|
+
rule === void 0 ? void 0 : `· ${rule}`,
|
|
29
|
+
subject === void 0 ? void 0 : `· ${subject}`
|
|
30
|
+
].filter((part) => part !== void 0).join(" ")}`,
|
|
31
|
+
` sealed by key ${fingerprint(parsed.publicKey)}`,
|
|
32
|
+
" Compare that fingerprint to the one you pinned out of band.",
|
|
33
|
+
" It matches → this is a decision that key’s holder sealed, unchanged."
|
|
34
|
+
]
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
export { checkReceipt };
|
|
@@ -76,6 +76,23 @@ function makeReceipt(entry, privateKeyPem, publicKeyPem) {
|
|
|
76
76
|
publicKey: publicKeyPem
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
|
+
/** Verify a receipt from nothing but the receipt. */
|
|
80
|
+
function verifyReceipt(receipt) {
|
|
81
|
+
if (receipt.receipt !== "prae/1") return {
|
|
82
|
+
ok: false,
|
|
83
|
+
reason: `unknown receipt format ${String(receipt.receipt)}`
|
|
84
|
+
};
|
|
85
|
+
const { seq, prev, hash, sig,...record } = receipt.entry;
|
|
86
|
+
if (hashEntry(record, seq, prev) !== hash) return {
|
|
87
|
+
ok: false,
|
|
88
|
+
reason: "entry contents do not match their seal; the row was altered"
|
|
89
|
+
};
|
|
90
|
+
if (!verifySignature(receipt.entry, receipt.signature, receipt.publicKey)) return {
|
|
91
|
+
ok: false,
|
|
92
|
+
reason: "signature does not verify; not sealed by this key"
|
|
93
|
+
};
|
|
94
|
+
return { ok: true };
|
|
95
|
+
}
|
|
79
96
|
/**
|
|
80
97
|
* A short identifier for a public key, for pinning by eye.
|
|
81
98
|
*
|
|
@@ -222,4 +239,4 @@ var Ledger = class Ledger {
|
|
|
222
239
|
};
|
|
223
240
|
|
|
224
241
|
//#endregion
|
|
225
|
-
export { generateKeypair as a,
|
|
242
|
+
export { generateKeypair as a, verifyReceipt as c, canonical as d, chain as f, fingerprint as i, verifySignature as l, seal as m, readEntries as n, makeReceipt as o, hashEntry as p, verifyEntries as r, signEntry as s, Ledger as t, GENESIS as u };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { a as generateKeypair, c as verifyReceipt, d as canonical, f as chain, i as fingerprint, l as verifySignature, m as seal, n as readEntries, o as makeReceipt, p as hashEntry, r as verifyEntries, s as signEntry, t as Ledger, u as GENESIS } from "./src-CXU0_W1P.js";
|
|
2
|
+
|
|
3
|
+
export { GENESIS, Ledger, canonical, chain, fingerprint, generateKeypair, hashEntry, makeReceipt, readEntries, seal, signEntry, verifyEntries, verifyReceipt, verifySignature };
|
package/package.json
CHANGED
package/lib/src-CBK_quVO.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { a as generateKeypair, c as verifySignature, d as chain, f as hashEntry, i as fingerprint, l as GENESIS, n as readEntries, o as makeReceipt, p as seal, r as verifyEntries, s as signEntry, t as Ledger, u as canonical } from "./src-CAUNqZJ1.js";
|
|
2
|
-
|
|
3
|
-
export { GENESIS, Ledger, canonical, chain, fingerprint, generateKeypair, hashEntry, makeReceipt, readEntries, seal, signEntry, verifyEntries, verifySignature };
|
|
File without changes
|
|
File without changes
|