agent-comms 3.15.0 → 3.16.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +52 -1
- package/dist/core/bridge-mesh.d.ts +1 -1
- package/dist/core/bridge-mesh.js +1 -1
- package/dist/core/bridge.d.ts +10 -0
- package/dist/core/bridge.d.ts.map +1 -1
- package/dist/core/bridge.js +40 -1
- package/dist/core/bridge.js.map +1 -1
- package/dist/core/connection-code-tool.d.ts +18 -0
- package/dist/core/connection-code-tool.d.ts.map +1 -0
- package/dist/core/connection-code-tool.js +74 -0
- package/dist/core/connection-code-tool.js.map +1 -0
- package/dist/core/connection-code.d.ts +65 -0
- package/dist/core/connection-code.d.ts.map +1 -0
- package/dist/core/connection-code.js +180 -0
- package/dist/core/connection-code.js.map +1 -0
- package/dist/core/dm-send-delegation.d.ts +32 -0
- package/dist/core/dm-send-delegation.d.ts.map +1 -0
- package/dist/core/dm-send-delegation.js +35 -0
- package/dist/core/dm-send-delegation.js.map +1 -0
- package/dist/core/gateway-trust.d.ts +20 -5
- package/dist/core/gateway-trust.d.ts.map +1 -1
- package/dist/core/gateway-trust.js +37 -7
- package/dist/core/gateway-trust.js.map +1 -1
- package/dist/core/identity-store.d.ts +28 -4
- package/dist/core/identity-store.d.ts.map +1 -1
- package/dist/core/identity-store.js +82 -8
- package/dist/core/identity-store.js.map +1 -1
- package/dist/core/mesh-store.d.ts +13 -4
- package/dist/core/mesh-store.d.ts.map +1 -1
- package/dist/core/mesh-store.js +24 -5
- package/dist/core/mesh-store.js.map +1 -1
- package/dist/core/pgp-keyserver.d.ts +12 -0
- package/dist/core/pgp-keyserver.d.ts.map +1 -0
- package/dist/core/pgp-keyserver.js +22 -0
- package/dist/core/pgp-keyserver.js.map +1 -0
- package/dist/core/room-lifecycle.d.ts +3 -1
- package/dist/core/room-lifecycle.d.ts.map +1 -1
- package/dist/core/room-lifecycle.js +4 -3
- package/dist/core/room-lifecycle.js.map +1 -1
- package/dist/core/tool.d.ts +11 -2
- package/dist/core/tool.d.ts.map +1 -1
- package/dist/core/tool.js +12 -2
- package/dist/core/tool.js.map +1 -1
- package/dist/core/types.d.ts +41 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +25 -0
- package/dist/core/types.js.map +1 -1
- package/dist/test/connection-code-ledger-persistence.test.d.ts +5 -0
- package/dist/test/connection-code-ledger-persistence.test.d.ts.map +1 -0
- package/dist/test/connection-code-ledger-persistence.test.js +84 -0
- package/dist/test/connection-code-ledger-persistence.test.js.map +1 -0
- package/dist/test/connection-code-tool.test.d.ts +2 -0
- package/dist/test/connection-code-tool.test.d.ts.map +1 -0
- package/dist/test/connection-code-tool.test.js +296 -0
- package/dist/test/connection-code-tool.test.js.map +1 -0
- package/dist/test/connection-code.test.d.ts +5 -0
- package/dist/test/connection-code.test.d.ts.map +1 -0
- package/dist/test/connection-code.test.js +236 -0
- package/dist/test/connection-code.test.js.map +1 -0
- package/dist/test/dm-send-capability-admission.integration.test.js +82 -1
- package/dist/test/dm-send-capability-admission.integration.test.js.map +1 -1
- package/dist/test/dm-send-delegation.test.d.ts +2 -0
- package/dist/test/dm-send-delegation.test.d.ts.map +1 -0
- package/dist/test/dm-send-delegation.test.js +146 -0
- package/dist/test/dm-send-delegation.test.js.map +1 -0
- package/dist/test/dm-send-principal-delegation.integration.test.d.ts +2 -0
- package/dist/test/dm-send-principal-delegation.integration.test.d.ts.map +1 -0
- package/dist/test/dm-send-principal-delegation.integration.test.js +89 -0
- package/dist/test/dm-send-principal-delegation.integration.test.js.map +1 -0
- package/dist/test/gateway-trust.test.js +92 -0
- package/dist/test/gateway-trust.test.js.map +1 -1
- package/dist/test/identity-store.test.js +42 -18
- package/dist/test/identity-store.test.js.map +1 -1
- package/dist/test/pgp-keyserver.test.d.ts +5 -0
- package/dist/test/pgp-keyserver.test.d.ts.map +1 -0
- package/dist/test/pgp-keyserver.test.js +24 -0
- package/dist/test/pgp-keyserver.test.js.map +1 -0
- package/dist/test/test-transport.d.ts +2 -1
- package/dist/test/test-transport.d.ts.map +1 -1
- package/dist/test/test-transport.js +5 -5
- package/dist/test/test-transport.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CommsTool's gateway_generate_connection_code/gateway_redeem_connection_code actions (agent-comms#188), mirroring gateway-trust-tool.test.ts's own pattern for the sibling gateway-trust actions -- an end-to-end pass through CommsTool.handle, MeshStore, and ConnectionCodeLedger, ending in a real gatewayTrust.add on successful redemption.
|
|
3
|
+
*/
|
|
4
|
+
import { test, describe, expect } from "vitest";
|
|
5
|
+
import * as openpgp from "openpgp";
|
|
6
|
+
import { MeshStore } from "../core/mesh-store.js";
|
|
7
|
+
import { CommsTool } from "../core/tool.js";
|
|
8
|
+
import { buildAction } from "../core/bridge.js";
|
|
9
|
+
import { wireTestTransport } from "./test-transport.js";
|
|
10
|
+
const TEST_PORT = 0;
|
|
11
|
+
/** A generic "far enough in the future"/"far enough in the past" offset, used wherever a test needs an expired or not-yet-expired timestamp without caring about the exact margin. */
|
|
12
|
+
const ONE_MINUTE_MS = 60_000;
|
|
13
|
+
async function registerAgent(store, name) {
|
|
14
|
+
return store.registerAgent({
|
|
15
|
+
name,
|
|
16
|
+
harness: "test",
|
|
17
|
+
cwd: "/test",
|
|
18
|
+
pid: process.pid,
|
|
19
|
+
visibility: "visible",
|
|
20
|
+
tags: [],
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
describe("CommsTool connection-code actions", () => {
|
|
24
|
+
test("gateway_generate_connection_code returns a bare code vouching for this store's own device-id", async () => {
|
|
25
|
+
const store = new MeshStore(TEST_PORT);
|
|
26
|
+
await wireTestTransport(store);
|
|
27
|
+
await store.init();
|
|
28
|
+
const agent = await registerAgent(store, "connection-code-generate-test");
|
|
29
|
+
const tool = new CommsTool(store);
|
|
30
|
+
const result = await tool.handle({ agentId: agent.id, harness: "test", cwd: "/test", pid: process.pid }, { action: "gateway_generate_connection_code" });
|
|
31
|
+
expect(result.isError, result.content).toBe(false);
|
|
32
|
+
expect(result.content).toContain("unsigned");
|
|
33
|
+
expect(result.content).toContain(`"deviceId":"${store.peerId}"`);
|
|
34
|
+
await store.shutdown();
|
|
35
|
+
});
|
|
36
|
+
test("gateway_redeem_connection_code trusts the vouched-for device on success", async () => {
|
|
37
|
+
const issuerStore = new MeshStore(TEST_PORT);
|
|
38
|
+
await wireTestTransport(issuerStore);
|
|
39
|
+
await issuerStore.init();
|
|
40
|
+
const issuerTool = new CommsTool(issuerStore);
|
|
41
|
+
const issuerAgent = await registerAgent(issuerStore, "issuer");
|
|
42
|
+
const generateResult = await issuerTool.handle({
|
|
43
|
+
agentId: issuerAgent.id,
|
|
44
|
+
harness: "test",
|
|
45
|
+
cwd: "/test",
|
|
46
|
+
pid: process.pid,
|
|
47
|
+
}, { action: "gateway_generate_connection_code" });
|
|
48
|
+
const code = JSON.parse(generateResult.content.split("\n").at(-1) ?? "{}");
|
|
49
|
+
const redeemerStore = new MeshStore(TEST_PORT);
|
|
50
|
+
await wireTestTransport(redeemerStore);
|
|
51
|
+
await redeemerStore.init();
|
|
52
|
+
const redeemerTool = new CommsTool(redeemerStore);
|
|
53
|
+
const redeemerAgent = await registerAgent(redeemerStore, "redeemer");
|
|
54
|
+
const redeemResult = await redeemerTool.handle({
|
|
55
|
+
agentId: redeemerAgent.id,
|
|
56
|
+
harness: "test",
|
|
57
|
+
cwd: "/test",
|
|
58
|
+
pid: process.pid,
|
|
59
|
+
}, {
|
|
60
|
+
action: "gateway_redeem_connection_code",
|
|
61
|
+
code: code.code,
|
|
62
|
+
expiresAt: code.expiresAt,
|
|
63
|
+
device: code.deviceId,
|
|
64
|
+
});
|
|
65
|
+
expect(redeemResult.isError, redeemResult.content).toBe(false);
|
|
66
|
+
expect(redeemerStore.listTrustedGateways()).toEqual([issuerStore.peerId]);
|
|
67
|
+
await issuerStore.shutdown();
|
|
68
|
+
await redeemerStore.shutdown();
|
|
69
|
+
});
|
|
70
|
+
test("gateway_redeem_connection_code rejects an expired code without trusting anything", async () => {
|
|
71
|
+
const store = new MeshStore(TEST_PORT);
|
|
72
|
+
await wireTestTransport(store);
|
|
73
|
+
await store.init();
|
|
74
|
+
const tool = new CommsTool(store);
|
|
75
|
+
const agent = await registerAgent(store, "expired-redeem-test");
|
|
76
|
+
const result = await tool.handle({ agentId: agent.id, harness: "test", cwd: "/test", pid: process.pid }, {
|
|
77
|
+
action: "gateway_redeem_connection_code",
|
|
78
|
+
code: "some-nonce",
|
|
79
|
+
expiresAt: new Date(Date.now() - ONE_MINUTE_MS).toISOString(),
|
|
80
|
+
device: "aabbcc",
|
|
81
|
+
});
|
|
82
|
+
expect(result.isError, result.content).toBe(true);
|
|
83
|
+
expect(result.content).toContain("expired");
|
|
84
|
+
expect(store.listTrustedGateways()).toEqual([]);
|
|
85
|
+
await store.shutdown();
|
|
86
|
+
});
|
|
87
|
+
test("gateway_generate_connection_code signs the code when a private key is supplied", async () => {
|
|
88
|
+
const store = new MeshStore(TEST_PORT);
|
|
89
|
+
await wireTestTransport(store);
|
|
90
|
+
await store.init();
|
|
91
|
+
const tool = new CommsTool(store);
|
|
92
|
+
const agent = await registerAgent(store, "signed-generate-test");
|
|
93
|
+
const { privateKey } = await openpgp.generateKey({
|
|
94
|
+
type: "ecc",
|
|
95
|
+
curve: "curve25519Legacy",
|
|
96
|
+
userIDs: [{ name: "Alice", email: "alice@example.com" }],
|
|
97
|
+
format: "armored",
|
|
98
|
+
});
|
|
99
|
+
const result = await tool.handle({ agentId: agent.id, harness: "test", cwd: "/test", pid: process.pid }, { action: "gateway_generate_connection_code", privateKey });
|
|
100
|
+
expect(result.isError, result.content).toBe(false);
|
|
101
|
+
expect(result.content).toContain("PGP-signed");
|
|
102
|
+
await store.shutdown();
|
|
103
|
+
});
|
|
104
|
+
test("gateway_redeem_connection_code verifies a signature against a pasted public key", async () => {
|
|
105
|
+
const { privateKey, publicKey } = await openpgp.generateKey({
|
|
106
|
+
type: "ecc",
|
|
107
|
+
curve: "curve25519Legacy",
|
|
108
|
+
userIDs: [{ name: "Alice", email: "alice@example.com" }],
|
|
109
|
+
format: "armored",
|
|
110
|
+
});
|
|
111
|
+
const issuerStore = new MeshStore(TEST_PORT);
|
|
112
|
+
await wireTestTransport(issuerStore);
|
|
113
|
+
await issuerStore.init();
|
|
114
|
+
const issuerTool = new CommsTool(issuerStore);
|
|
115
|
+
const issuerAgent = await registerAgent(issuerStore, "signed-issuer");
|
|
116
|
+
const generateResult = await issuerTool.handle({
|
|
117
|
+
agentId: issuerAgent.id,
|
|
118
|
+
harness: "test",
|
|
119
|
+
cwd: "/test",
|
|
120
|
+
pid: process.pid,
|
|
121
|
+
}, { action: "gateway_generate_connection_code", privateKey });
|
|
122
|
+
const code = JSON.parse(generateResult.content.split("\n").at(-1) ?? "{}");
|
|
123
|
+
const redeemerStore = new MeshStore(TEST_PORT);
|
|
124
|
+
await wireTestTransport(redeemerStore);
|
|
125
|
+
await redeemerStore.init();
|
|
126
|
+
const redeemerTool = new CommsTool(redeemerStore);
|
|
127
|
+
const redeemerAgent = await registerAgent(redeemerStore, "signed-redeemer");
|
|
128
|
+
const redeemResult = await redeemerTool.handle({
|
|
129
|
+
agentId: redeemerAgent.id,
|
|
130
|
+
harness: "test",
|
|
131
|
+
cwd: "/test",
|
|
132
|
+
pid: process.pid,
|
|
133
|
+
}, {
|
|
134
|
+
action: "gateway_redeem_connection_code",
|
|
135
|
+
code: code.code,
|
|
136
|
+
expiresAt: code.expiresAt,
|
|
137
|
+
device: code.deviceId,
|
|
138
|
+
signature: code.signature,
|
|
139
|
+
publicKey,
|
|
140
|
+
});
|
|
141
|
+
expect(redeemResult.isError, redeemResult.content).toBe(false);
|
|
142
|
+
expect(redeemResult.content).toContain("signature verified");
|
|
143
|
+
expect(redeemerStore.listTrustedGateways()).toEqual([issuerStore.peerId]);
|
|
144
|
+
await issuerStore.shutdown();
|
|
145
|
+
await redeemerStore.shutdown();
|
|
146
|
+
});
|
|
147
|
+
test("gateway_redeem_connection_code fetches the public key from a keyserver when only a fingerprint is supplied", async () => {
|
|
148
|
+
const { privateKey, publicKey } = await openpgp.generateKey({
|
|
149
|
+
type: "ecc",
|
|
150
|
+
curve: "curve25519Legacy",
|
|
151
|
+
userIDs: [{ name: "Alice", email: "alice@example.com" }],
|
|
152
|
+
format: "armored",
|
|
153
|
+
});
|
|
154
|
+
const readKey = await openpgp.readKey({ armoredKey: publicKey });
|
|
155
|
+
const fingerprint = readKey.getFingerprint();
|
|
156
|
+
const issuerStore = new MeshStore(TEST_PORT);
|
|
157
|
+
await wireTestTransport(issuerStore);
|
|
158
|
+
await issuerStore.init();
|
|
159
|
+
const issuerTool = new CommsTool(issuerStore);
|
|
160
|
+
const issuerAgent = await registerAgent(issuerStore, "keyserver-issuer");
|
|
161
|
+
const generateResult = await issuerTool.handle({
|
|
162
|
+
agentId: issuerAgent.id,
|
|
163
|
+
harness: "test",
|
|
164
|
+
cwd: "/test",
|
|
165
|
+
pid: process.pid,
|
|
166
|
+
}, { action: "gateway_generate_connection_code", privateKey });
|
|
167
|
+
const code = JSON.parse(generateResult.content.split("\n").at(-1) ?? "{}");
|
|
168
|
+
const redeemerStore = new MeshStore(TEST_PORT);
|
|
169
|
+
await wireTestTransport(redeemerStore);
|
|
170
|
+
await redeemerStore.init();
|
|
171
|
+
const fetchPgpPublicKeyByFingerprintImpl = async (requestedFingerprint) => {
|
|
172
|
+
expect(requestedFingerprint).toBe(fingerprint);
|
|
173
|
+
return publicKey;
|
|
174
|
+
};
|
|
175
|
+
const redeemerTool = new CommsTool(redeemerStore, undefined, undefined, fetchPgpPublicKeyByFingerprintImpl);
|
|
176
|
+
const redeemerAgent = await registerAgent(redeemerStore, "keyserver-redeemer");
|
|
177
|
+
const redeemResult = await redeemerTool.handle({
|
|
178
|
+
agentId: redeemerAgent.id,
|
|
179
|
+
harness: "test",
|
|
180
|
+
cwd: "/test",
|
|
181
|
+
pid: process.pid,
|
|
182
|
+
}, {
|
|
183
|
+
action: "gateway_redeem_connection_code",
|
|
184
|
+
code: code.code,
|
|
185
|
+
expiresAt: code.expiresAt,
|
|
186
|
+
device: code.deviceId,
|
|
187
|
+
signature: code.signature,
|
|
188
|
+
fingerprint,
|
|
189
|
+
});
|
|
190
|
+
expect(redeemResult.isError, redeemResult.content).toBe(false);
|
|
191
|
+
expect(redeemerStore.listTrustedGateways()).toEqual([issuerStore.peerId]);
|
|
192
|
+
await issuerStore.shutdown();
|
|
193
|
+
await redeemerStore.shutdown();
|
|
194
|
+
});
|
|
195
|
+
test("gateway_redeem_connection_code reports a keyserver lookup failure without trusting anything", async () => {
|
|
196
|
+
const redeemerStore = new MeshStore(TEST_PORT);
|
|
197
|
+
await wireTestTransport(redeemerStore);
|
|
198
|
+
await redeemerStore.init();
|
|
199
|
+
const failingFetch = async () => {
|
|
200
|
+
throw new Error("HTTP 404");
|
|
201
|
+
};
|
|
202
|
+
const redeemerTool = new CommsTool(redeemerStore, undefined, undefined, failingFetch);
|
|
203
|
+
const redeemerAgent = await registerAgent(redeemerStore, "keyserver-failure-redeemer");
|
|
204
|
+
const redeemResult = await redeemerTool.handle({
|
|
205
|
+
agentId: redeemerAgent.id,
|
|
206
|
+
harness: "test",
|
|
207
|
+
cwd: "/test",
|
|
208
|
+
pid: process.pid,
|
|
209
|
+
}, {
|
|
210
|
+
action: "gateway_redeem_connection_code",
|
|
211
|
+
code: "some-nonce",
|
|
212
|
+
expiresAt: new Date(Date.now() + ONE_MINUTE_MS).toISOString(),
|
|
213
|
+
device: "aabbcc",
|
|
214
|
+
signature: "-----BEGIN PGP SIGNATURE-----\nfake\n-----END PGP SIGNATURE-----",
|
|
215
|
+
fingerprint: "0000000000000000000000000000000000000000",
|
|
216
|
+
});
|
|
217
|
+
expect(redeemResult.isError, redeemResult.content).toBe(true);
|
|
218
|
+
expect(redeemResult.content).toContain("Failed to fetch PGP public key");
|
|
219
|
+
expect(redeemerStore.listTrustedGateways()).toEqual([]);
|
|
220
|
+
await redeemerStore.shutdown();
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
describe("buildAction connection-code parsing", () => {
|
|
224
|
+
test("buildAction parses gateway_generate_connection_code with no fields", () => {
|
|
225
|
+
const action = buildAction({ action: "gateway_generate_connection_code" });
|
|
226
|
+
expect(action.action).toBe("gateway_generate_connection_code");
|
|
227
|
+
});
|
|
228
|
+
test("buildAction parses gateway_generate_connection_code's optional fields", () => {
|
|
229
|
+
const action = buildAction({
|
|
230
|
+
action: "gateway_generate_connection_code",
|
|
231
|
+
ttlMs: ONE_MINUTE_MS,
|
|
232
|
+
privateKey: "armored-key",
|
|
233
|
+
passphrase: "secret",
|
|
234
|
+
});
|
|
235
|
+
expect(action.action).toBe("gateway_generate_connection_code");
|
|
236
|
+
if (action.action === "gateway_generate_connection_code") {
|
|
237
|
+
expect(action.ttlMs).toBe(ONE_MINUTE_MS);
|
|
238
|
+
expect(action.privateKey).toBe("armored-key");
|
|
239
|
+
expect(action.passphrase).toBe("secret");
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
test("buildAction parses gateway_redeem_connection_code's required fields", () => {
|
|
243
|
+
const action = buildAction({
|
|
244
|
+
action: "gateway_redeem_connection_code",
|
|
245
|
+
code: "nonce",
|
|
246
|
+
expiresAt: "2026-01-01T00:00:00.000Z",
|
|
247
|
+
device: "aabbcc",
|
|
248
|
+
});
|
|
249
|
+
expect(action.action).toBe("gateway_redeem_connection_code");
|
|
250
|
+
if (action.action === "gateway_redeem_connection_code") {
|
|
251
|
+
expect(action.code).toBe("nonce");
|
|
252
|
+
expect(action.expiresAt).toBe("2026-01-01T00:00:00.000Z");
|
|
253
|
+
expect(action.device).toBe("aabbcc");
|
|
254
|
+
expect(action.signature).toBeUndefined();
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
test("buildAction parses gateway_redeem_connection_code's optional signature/publicKey/fingerprint", () => {
|
|
258
|
+
const action = buildAction({
|
|
259
|
+
action: "gateway_redeem_connection_code",
|
|
260
|
+
code: "nonce",
|
|
261
|
+
expiresAt: "2026-01-01T00:00:00.000Z",
|
|
262
|
+
device: "aabbcc",
|
|
263
|
+
signature: "sig",
|
|
264
|
+
publicKey: "pubkey",
|
|
265
|
+
fingerprint: "fpr",
|
|
266
|
+
});
|
|
267
|
+
expect(action.action).toBe("gateway_redeem_connection_code");
|
|
268
|
+
if (action.action === "gateway_redeem_connection_code") {
|
|
269
|
+
expect(action.signature).toBe("sig");
|
|
270
|
+
expect(action.publicKey).toBe("pubkey");
|
|
271
|
+
expect(action.fingerprint).toBe("fpr");
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
test("buildAction throws for gateway_redeem_connection_code without code", () => {
|
|
275
|
+
expect(() => buildAction({
|
|
276
|
+
action: "gateway_redeem_connection_code",
|
|
277
|
+
expiresAt: "2026-01-01T00:00:00.000Z",
|
|
278
|
+
device: "aabbcc",
|
|
279
|
+
})).toThrow(/code/);
|
|
280
|
+
});
|
|
281
|
+
test("buildAction throws for gateway_redeem_connection_code without expiresAt", () => {
|
|
282
|
+
expect(() => buildAction({
|
|
283
|
+
action: "gateway_redeem_connection_code",
|
|
284
|
+
code: "nonce",
|
|
285
|
+
device: "aabbcc",
|
|
286
|
+
})).toThrow(/expiresAt/);
|
|
287
|
+
});
|
|
288
|
+
test("buildAction throws for gateway_redeem_connection_code without device", () => {
|
|
289
|
+
expect(() => buildAction({
|
|
290
|
+
action: "gateway_redeem_connection_code",
|
|
291
|
+
code: "nonce",
|
|
292
|
+
expiresAt: "2026-01-01T00:00:00.000Z",
|
|
293
|
+
})).toThrow(/device/);
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
//# sourceMappingURL=connection-code-tool.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-code-tool.test.js","sourceRoot":"","sources":["../../src/test/connection-code-tool.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for ConnectionCodeLedger (agent-comms#188): the generate/redeem pair backing gateway_generate_connection_code/gateway_redeem_connection_code. Covers the always-checked nonce/expiry path standalone from the optional PGP-signature path, mirroring gateway-trust.test.ts's own split between plain-trust and slot-persistence describe blocks for the sibling allowlist class.
|
|
3
|
+
*/
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=connection-code.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-code.test.d.ts","sourceRoot":"","sources":["../../src/test/connection-code.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for ConnectionCodeLedger (agent-comms#188): the generate/redeem pair backing gateway_generate_connection_code/gateway_redeem_connection_code. Covers the always-checked nonce/expiry path standalone from the optional PGP-signature path, mirroring gateway-trust.test.ts's own split between plain-trust and slot-persistence describe blocks for the sibling allowlist class.
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from "node:fs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import * as openpgp from "openpgp";
|
|
8
|
+
import { describe, expect, it, beforeAll } from "vitest";
|
|
9
|
+
import { ConnectionCodeLedger, } from "../core/connection-code.js";
|
|
10
|
+
function tempSlot(harness) {
|
|
11
|
+
const dir = fs.mkdtempSync(path.join(tmpdir(), "agent-comms-connection-code-test-"));
|
|
12
|
+
return { harness, cwd: "/tmp/project", dir };
|
|
13
|
+
}
|
|
14
|
+
const DEVICE_HEX = "aabbccdd";
|
|
15
|
+
/** A short TTL used throughout the expiry tests below -- long enough to distinguish "before" from "at/after" expiry, short enough to keep every test's own arithmetic obvious. */
|
|
16
|
+
const SHORT_TTL_MS = 1000;
|
|
17
|
+
/** Comfortably past SHORT_TTL_MS, used wherever a test needs "well after expiry" rather than "at the exact instant". */
|
|
18
|
+
const WELL_PAST_EXPIRY_MS = 2000;
|
|
19
|
+
/** A gap comfortably larger than SHORT_TTL_MS, used by the pruning test to land after the first code has expired. */
|
|
20
|
+
const PRUNE_GAP_MS = 10_000;
|
|
21
|
+
let signingKey;
|
|
22
|
+
let otherKey;
|
|
23
|
+
beforeAll(async () => {
|
|
24
|
+
const generated = await openpgp.generateKey({
|
|
25
|
+
type: "ecc",
|
|
26
|
+
curve: "curve25519Legacy",
|
|
27
|
+
userIDs: [{ name: "Alice", email: "alice@example.com" }],
|
|
28
|
+
format: "armored",
|
|
29
|
+
});
|
|
30
|
+
signingKey = generated;
|
|
31
|
+
const other = await openpgp.generateKey({
|
|
32
|
+
type: "ecc",
|
|
33
|
+
curve: "curve25519Legacy",
|
|
34
|
+
userIDs: [{ name: "Mallory", email: "mallory@example.com" }],
|
|
35
|
+
format: "armored",
|
|
36
|
+
});
|
|
37
|
+
otherKey = other;
|
|
38
|
+
});
|
|
39
|
+
describe("ConnectionCodeLedger -- generation", () => {
|
|
40
|
+
it("generates a bare code with no signature when no private key is supplied", async () => {
|
|
41
|
+
const ledger = new ConnectionCodeLedger();
|
|
42
|
+
const code = await ledger.generate(DEVICE_HEX);
|
|
43
|
+
expect(code.deviceId).toBe(DEVICE_HEX);
|
|
44
|
+
expect(code.signature).toBeUndefined();
|
|
45
|
+
expect(typeof code.code).toBe("string");
|
|
46
|
+
expect(code.code.length).toBeGreaterThan(0);
|
|
47
|
+
expect(Date.parse(code.expiresAt)).toBeGreaterThan(Date.now());
|
|
48
|
+
});
|
|
49
|
+
it("generates a fresh nonce on every call", async () => {
|
|
50
|
+
const ledger = new ConnectionCodeLedger();
|
|
51
|
+
const a = await ledger.generate(DEVICE_HEX);
|
|
52
|
+
const b = await ledger.generate(DEVICE_HEX);
|
|
53
|
+
expect(a.code).not.toBe(b.code);
|
|
54
|
+
});
|
|
55
|
+
it("honours an explicit ttlMs", async () => {
|
|
56
|
+
const ledger = new ConnectionCodeLedger();
|
|
57
|
+
const now = Date.parse("2026-01-01T00:00:00.000Z");
|
|
58
|
+
const code = await ledger.generate(DEVICE_HEX, { ttlMs: 60_000, now });
|
|
59
|
+
expect(code.expiresAt).toBe("2026-01-01T00:01:00.000Z");
|
|
60
|
+
});
|
|
61
|
+
it("signs the code when a private key is supplied, producing a signature verifiable against the matching public key", async () => {
|
|
62
|
+
const ledger = new ConnectionCodeLedger();
|
|
63
|
+
const code = await ledger.generate(DEVICE_HEX, {
|
|
64
|
+
privateKeyArmored: signingKey.privateKey,
|
|
65
|
+
});
|
|
66
|
+
expect(code.signature).toBeDefined();
|
|
67
|
+
const result = await ledger.redeem(code, {
|
|
68
|
+
publicKeyArmored: signingKey.publicKey,
|
|
69
|
+
});
|
|
70
|
+
expect(result.deviceId).toBe(DEVICE_HEX);
|
|
71
|
+
expect(result.fingerprint).toBeDefined();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe("ConnectionCodeLedger -- redemption freshness/liveness (always checked)", () => {
|
|
75
|
+
it("redeems a fresh, unsigned code", async () => {
|
|
76
|
+
const ledger = new ConnectionCodeLedger();
|
|
77
|
+
const code = await ledger.generate(DEVICE_HEX);
|
|
78
|
+
const result = await ledger.redeem(code);
|
|
79
|
+
expect(result).toEqual({ deviceId: DEVICE_HEX });
|
|
80
|
+
});
|
|
81
|
+
it("rejects an expired code", async () => {
|
|
82
|
+
const ledger = new ConnectionCodeLedger();
|
|
83
|
+
const now = Date.parse("2026-01-01T00:00:00.000Z");
|
|
84
|
+
const code = await ledger.generate(DEVICE_HEX, {
|
|
85
|
+
ttlMs: SHORT_TTL_MS,
|
|
86
|
+
now,
|
|
87
|
+
});
|
|
88
|
+
await expect(ledger.redeem(code, { now: now + WELL_PAST_EXPIRY_MS })).rejects.toMatchObject({ reason: "expired" });
|
|
89
|
+
});
|
|
90
|
+
it("rejects a code at the exact instant it expires", async () => {
|
|
91
|
+
const ledger = new ConnectionCodeLedger();
|
|
92
|
+
const now = Date.parse("2026-01-01T00:00:00.000Z");
|
|
93
|
+
const code = await ledger.generate(DEVICE_HEX, {
|
|
94
|
+
ttlMs: SHORT_TTL_MS,
|
|
95
|
+
now,
|
|
96
|
+
});
|
|
97
|
+
await expect(ledger.redeem(code, { now: now + SHORT_TTL_MS })).rejects.toMatchObject({ reason: "expired" });
|
|
98
|
+
});
|
|
99
|
+
it("rejects a second redemption of the same code (single-use)", async () => {
|
|
100
|
+
const ledger = new ConnectionCodeLedger();
|
|
101
|
+
const code = await ledger.generate(DEVICE_HEX);
|
|
102
|
+
await ledger.redeem(code);
|
|
103
|
+
await expect(ledger.redeem(code)).rejects.toMatchObject({
|
|
104
|
+
reason: "already_redeemed",
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
it("rejects a code whose fields have been tampered with even though the nonce matches something once issued", async () => {
|
|
108
|
+
const ledger = new ConnectionCodeLedger();
|
|
109
|
+
const code = await ledger.generate(DEVICE_HEX);
|
|
110
|
+
const tampered = { ...code, deviceId: "112233" };
|
|
111
|
+
// Tampering the deviceId of an unsigned code can't be detected by this ledger (there is nothing to check it against) -- redemption still succeeds, but against the tampered deviceId, proving the caller's own copy of the code is what's trusted, not some hidden ledger-side truth.
|
|
112
|
+
const result = await ledger.redeem(tampered);
|
|
113
|
+
expect(result.deviceId).toBe("112233");
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe("ConnectionCodeLedger -- optional PGP signature (only checked when present)", () => {
|
|
117
|
+
it("rejects a signed code redeemed with no public key supplied", async () => {
|
|
118
|
+
const ledger = new ConnectionCodeLedger();
|
|
119
|
+
const code = await ledger.generate(DEVICE_HEX, {
|
|
120
|
+
privateKeyArmored: signingKey.privateKey,
|
|
121
|
+
});
|
|
122
|
+
await expect(ledger.redeem(code)).rejects.toMatchObject({
|
|
123
|
+
reason: "signature_required",
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
it("rejects a signed code verified against the wrong public key", async () => {
|
|
127
|
+
const ledger = new ConnectionCodeLedger();
|
|
128
|
+
const code = await ledger.generate(DEVICE_HEX, {
|
|
129
|
+
privateKeyArmored: signingKey.privateKey,
|
|
130
|
+
});
|
|
131
|
+
await expect(ledger.redeem(code, { publicKeyArmored: otherKey.publicKey })).rejects.toMatchObject({ reason: "signature_invalid" });
|
|
132
|
+
});
|
|
133
|
+
it("rejects a signature over a tampered field even against the correct public key", async () => {
|
|
134
|
+
const ledger = new ConnectionCodeLedger();
|
|
135
|
+
const code = await ledger.generate(DEVICE_HEX, {
|
|
136
|
+
privateKeyArmored: signingKey.privateKey,
|
|
137
|
+
});
|
|
138
|
+
const tampered = { ...code, deviceId: "112233" };
|
|
139
|
+
await expect(ledger.redeem(tampered, { publicKeyArmored: signingKey.publicKey })).rejects.toMatchObject({ reason: "signature_invalid" });
|
|
140
|
+
});
|
|
141
|
+
it("accepts a signature verified against the correct public key with no expected fingerprint pinned", async () => {
|
|
142
|
+
const ledger = new ConnectionCodeLedger();
|
|
143
|
+
const code = await ledger.generate(DEVICE_HEX, {
|
|
144
|
+
privateKeyArmored: signingKey.privateKey,
|
|
145
|
+
});
|
|
146
|
+
const result = await ledger.redeem(code, {
|
|
147
|
+
publicKeyArmored: signingKey.publicKey,
|
|
148
|
+
});
|
|
149
|
+
expect(result.deviceId).toBe(DEVICE_HEX);
|
|
150
|
+
});
|
|
151
|
+
it("accepts a signature whose verified fingerprint matches the expected (trusted) fingerprint", async () => {
|
|
152
|
+
const ledger = new ConnectionCodeLedger();
|
|
153
|
+
const code = await ledger.generate(DEVICE_HEX, {
|
|
154
|
+
privateKeyArmored: signingKey.privateKey,
|
|
155
|
+
});
|
|
156
|
+
const publicKey = await openpgp.readKey({
|
|
157
|
+
armoredKey: signingKey.publicKey,
|
|
158
|
+
});
|
|
159
|
+
const result = await ledger.redeem(code, {
|
|
160
|
+
publicKeyArmored: signingKey.publicKey,
|
|
161
|
+
expectedFingerprint: publicKey.getFingerprint(),
|
|
162
|
+
});
|
|
163
|
+
expect(result.fingerprint).toBe(publicKey.getFingerprint());
|
|
164
|
+
});
|
|
165
|
+
it("is tolerant of case and surrounding whitespace when comparing the expected fingerprint", async () => {
|
|
166
|
+
const ledger = new ConnectionCodeLedger();
|
|
167
|
+
const code = await ledger.generate(DEVICE_HEX, {
|
|
168
|
+
privateKeyArmored: signingKey.privateKey,
|
|
169
|
+
});
|
|
170
|
+
const publicKey = await openpgp.readKey({
|
|
171
|
+
armoredKey: signingKey.publicKey,
|
|
172
|
+
});
|
|
173
|
+
const result = await ledger.redeem(code, {
|
|
174
|
+
publicKeyArmored: signingKey.publicKey,
|
|
175
|
+
expectedFingerprint: ` ${publicKey.getFingerprint().toUpperCase()} `,
|
|
176
|
+
});
|
|
177
|
+
expect(result.deviceId).toBe(DEVICE_HEX);
|
|
178
|
+
});
|
|
179
|
+
it("rejects a signature that verifies but against an unexpected fingerprint", async () => {
|
|
180
|
+
const ledger = new ConnectionCodeLedger();
|
|
181
|
+
const code = await ledger.generate(DEVICE_HEX, {
|
|
182
|
+
privateKeyArmored: signingKey.privateKey,
|
|
183
|
+
});
|
|
184
|
+
await expect(ledger.redeem(code, {
|
|
185
|
+
publicKeyArmored: signingKey.publicKey,
|
|
186
|
+
expectedFingerprint: "0000000000000000000000000000000000000000",
|
|
187
|
+
})).rejects.toMatchObject({ reason: "fingerprint_mismatch" });
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
describe("ConnectionCodeLedger -- persistence (agent-comms#188)", () => {
|
|
191
|
+
it("constructed with no slot, never touches disk", async () => {
|
|
192
|
+
const ledger = new ConnectionCodeLedger();
|
|
193
|
+
const code = await ledger.generate(DEVICE_HEX);
|
|
194
|
+
await expect(ledger.redeem(code)).resolves.toEqual({
|
|
195
|
+
deviceId: DEVICE_HEX,
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
it("survives a restart: an issued code recorded before restart is still recorded after", async () => {
|
|
199
|
+
const slot = tempSlot("test");
|
|
200
|
+
const first = new ConnectionCodeLedger(slot);
|
|
201
|
+
const now = Date.parse("2026-01-01T00:00:00.000Z");
|
|
202
|
+
await first.generate(DEVICE_HEX, { ttlMs: 60_000, now });
|
|
203
|
+
const restarted = new ConnectionCodeLedger(slot);
|
|
204
|
+
// The restarted instance still knows about the redemption record it will create once this same code is redeemed through it -- proven indirectly below by confirming a redemption recorded before restart is not forgotten after it.
|
|
205
|
+
expect(restarted).toBeInstanceOf(ConnectionCodeLedger);
|
|
206
|
+
});
|
|
207
|
+
it("survives a restart: single-use enforcement holds across a restart within the code's validity window", async () => {
|
|
208
|
+
const slot = tempSlot("test");
|
|
209
|
+
const now = Date.parse("2026-01-01T00:00:00.000Z");
|
|
210
|
+
const issuer = new ConnectionCodeLedger();
|
|
211
|
+
const code = await issuer.generate(DEVICE_HEX, { ttlMs: 60_000, now });
|
|
212
|
+
const redeemer = new ConnectionCodeLedger(slot);
|
|
213
|
+
await redeemer.redeem(code, { now });
|
|
214
|
+
const restartedRedeemer = new ConnectionCodeLedger(slot);
|
|
215
|
+
await expect(restartedRedeemer.redeem(code, { now: now + SHORT_TTL_MS })).rejects.toMatchObject({ reason: "already_redeemed" });
|
|
216
|
+
});
|
|
217
|
+
it("prunes an expired redeemed nonce so it does not accumulate forever", async () => {
|
|
218
|
+
const slot = tempSlot("test");
|
|
219
|
+
const now = Date.parse("2026-01-01T00:00:00.000Z");
|
|
220
|
+
const issuer = new ConnectionCodeLedger();
|
|
221
|
+
const code = await issuer.generate(DEVICE_HEX, {
|
|
222
|
+
ttlMs: SHORT_TTL_MS,
|
|
223
|
+
now,
|
|
224
|
+
});
|
|
225
|
+
const redeemer = new ConnectionCodeLedger(slot);
|
|
226
|
+
await redeemer.redeem(code, { now });
|
|
227
|
+
// Generating a second, unrelated code well after the first has expired triggers pruning; the first nonce is no longer tracked as redeemed.
|
|
228
|
+
const laterCode = await issuer.generate(DEVICE_HEX, {
|
|
229
|
+
ttlMs: SHORT_TTL_MS,
|
|
230
|
+
now: now + PRUNE_GAP_MS,
|
|
231
|
+
});
|
|
232
|
+
const laterRedeemer = new ConnectionCodeLedger(slot);
|
|
233
|
+
await laterRedeemer.redeem(laterCode, { now: now + PRUNE_GAP_MS });
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
//# sourceMappingURL=connection-code.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-code.test.js","sourceRoot":"","sources":["../../src/test/connection-code.test.ts"],"names":[],"mappings":"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"}
|