@muretai/agent-entry 1.3.0 → 1.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.
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * conformance/run.mjs — check an Agent Entry implementation against the golden vectors.
4
+ *
5
+ * WHY THIS SHIPS IN THE PACKAGE. A conformance suite that lives on a website is a suite
6
+ * with an uptime requirement, and until now this one was worse than that: the vectors sat
7
+ * in a git checkout that `npm install` never delivers, so "run the suite" meant "send us
8
+ * your implementation and we will run it". Everything needed to hold this code to its own
9
+ * contract is now in the tarball: `npm test`, no network, no dependencies, no account.
10
+ *
11
+ * WHAT IT CHECKS, AND WHY BOTH HALVES ARE HERE. The positive half proves this build
12
+ * produces the same BYTES as every other implementation — canonical JSON, did:key, the six
13
+ * signed fields. The negative half proves it REFUSES what it must, and it is the half that
14
+ * catches the failure nobody notices: an implementation that verifies nothing passes every
15
+ * positive vector in the file. A drift in either direction is silent on the wire — nothing
16
+ * throws, signatures simply stop verifying for everyone else.
17
+ *
18
+ * Run: node conformance/run.mjs (from the package root)
19
+ * npm test
20
+ */
21
+
22
+ import { readFileSync } from 'node:fs';
23
+ import { fileURLToPath } from 'node:url';
24
+ import { dirname, join } from 'node:path';
25
+
26
+ import {
27
+ canonicalJSON, didFromPublicKeyHex, publicKeyFromSeedHex, signingPayload,
28
+ signEnvelope, verifyEnvelope,
29
+ } from '../muretai-agent-entry.mjs';
30
+
31
+ const HERE = dirname(fileURLToPath(import.meta.url));
32
+ const vectors = JSON.parse(readFileSync(join(HERE, 'vectors.json'), 'utf8'));
33
+
34
+ let pass = 0;
35
+ const failures = [];
36
+
37
+ function check(ok, label, detail) {
38
+ if (ok) { pass += 1; return true; }
39
+ failures.push(detail ? `${label}\n ${detail}` : label);
40
+ return false;
41
+ }
42
+
43
+ // ---------------------------------------------------------------- canonical JSON
44
+ for (const v of vectors.canonical) {
45
+ let got;
46
+ try { got = canonicalJSON(v.payload); } catch (e) { got = `THREW: ${e.message}`; }
47
+ check(got === v.canonical, `canonical/${v.name}`,
48
+ got === v.canonical ? '' : `want ${JSON.stringify(v.canonical)}\n got ${JSON.stringify(got)}`);
49
+ }
50
+
51
+ // `numberHazards` is DELIBERATELY NOT EXECUTED, and reading it is the point. Every case
52
+ // there is a value whose canonical bytes differ between languages, so asserting either
53
+ // spelling would be asserting one runtime's float formatting — the opposite of the
54
+ // contract. The rule it carries is a SIGNER discipline (`signMustNotEmit`), not a
55
+ // canonicaliser output: never sign a payload containing one, because the bytes you produce
56
+ // will only verify where they were produced. An agent entry meets it for free — the only
57
+ // number among the six signed fields is `timestamp`, and integer epoch seconds is the
58
+ // contract.
59
+ const hazards = vectors.numberHazards?.length ?? 0;
60
+
61
+ // ---------------------------------------------------------------- did:key
62
+ for (const v of vectors.did) {
63
+ if (v.curve !== 'ed25519') continue; // p256 did:key is not an envelope signer
64
+ let got;
65
+ try { got = didFromPublicKeyHex(v.publicHex); } catch (e) { got = `THREW: ${e.message}`; }
66
+ check(got === v.did, `did/${v.publicHex.slice(0, 12)}…`,
67
+ got === v.did ? '' : `want ${v.did}\n got ${got}`);
68
+ }
69
+
70
+ // ---------------------------------------------------------------- the six signed fields
71
+ for (const v of vectors.envelope) {
72
+ const fields = { from: v.from, to: v.to, messageId: v.messageId,
73
+ contextId: v.contextId ?? null, timestamp: v.timestamp, text: v.text };
74
+ let got;
75
+ try { got = signingPayload(fields); } catch (e) { got = `THREW: ${e.message}`; }
76
+ check(got === v.signingPayload, `envelope/${v.name}`,
77
+ got === v.signingPayload ? '' : `want ${JSON.stringify(v.signingPayload)}\n got ${JSON.stringify(got)}`);
78
+ }
79
+
80
+ // A signature this build makes must verify in this build. Round-tripping is the weakest
81
+ // possible claim on its own — it only says the code agrees with itself — which is exactly
82
+ // why the byte checks above and the refusals below are not optional.
83
+ {
84
+ const seed = '11'.repeat(32);
85
+ const from = didFromPublicKeyHex(publicKeyFromSeedHex(seed));
86
+ const fields = { from, to: from, messageId: 'm1', contextId: null,
87
+ timestamp: 1752451200, text: 'round trip' };
88
+ const sig = signEnvelope(seed, fields);
89
+ check(verifyEnvelope({ ...fields, sig }, { recipientDid: from }), 'envelope/round-trip');
90
+ }
91
+
92
+ // ---------------------------------------------------------------- the refusals
93
+ // The half that catches an implementation which verifies nothing.
94
+ for (const v of vectors.reject.message) {
95
+ const fields = { from: v.from, to: v.to, messageId: v.messageId,
96
+ contextId: v.contextId ?? null, timestamp: v.timestamp,
97
+ text: v.text, sig: v.sig };
98
+ let accepted;
99
+ try {
100
+ accepted = verifyEnvelope(fields, { recipientDid: v.recipientDid ?? v.to });
101
+ } catch {
102
+ accepted = false; // refusing by throwing is still refusing
103
+ }
104
+ check(accepted === false, `reject/${v.name}`,
105
+ accepted === false ? '' : `ACCEPTED a message it must refuse — ${v.why || ''}`);
106
+ }
107
+
108
+ // ---------------------------------------------------------------- verdict
109
+ console.log(`\n${vectors.note}\n`);
110
+ if (failures.length) {
111
+ console.log(`FAILED — ${failures.length} of ${pass + failures.length} checks:\n`);
112
+ for (const f of failures) console.log(` ✗ ${f}`);
113
+ console.log('\nA mismatch here is not cosmetic: these bytes are what every other');
114
+ console.log('implementation signs and verifies.\n');
115
+ process.exit(1);
116
+ }
117
+ console.log(`OK — ${pass} checks: the bytes match, and every case that must be refused was.`);
118
+ console.log(` (${hazards} numberHazards read, not executed — see the comment in this file:`);
119
+ console.log(` they are a SIGNER rule, not bytes any single runtime can be held to.)\n`);