@a2a-exposed/encryption 0.0.0-stage → 0.8.56

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,55 @@
1
+ // Bounded native child protocol. Secrets travel only through local pipes, never argv/env.
2
+ import { spawn } from "node:child_process";
3
+ import { fileURLToPath } from "node:url";
4
+ export class NativeStoreError extends Error {
5
+ constructor(code, pid) { super(code); this.code = code; if (pid) this.pid = pid; }
6
+ }
7
+ export async function nativeCredentialOperation(input, { allowOsConsent = false, onSpawn, spawnImpl = spawn, timeoutMs = 5000, graceMs = 500, platform = process.platform } = {}) {
8
+ if (allowOsConsent !== true) throw new NativeStoreError("key_store_consent");
9
+ if (!["get", "set", "delete"].includes(input?.op) || !/^[a-f0-9-]{36}$/.test(input.namespace || "") || !/^[a-f0-9-]{36}\/[A-Za-z0-9_-]{43}$/.test(input.account || "")) throw new NativeStoreError("key_store_inputs");
10
+ const body = JSON.stringify(input); if (Buffer.byteLength(body) > 16384) throw new NativeStoreError("key_store_inputs");
11
+ const write = input.op !== "get";
12
+ return new Promise((resolve, reject) => {
13
+ let child, output = "", done = false, exited = false, stopping, timer, escalation, reap;
14
+ const unavailable = () => new NativeStoreError(write ? "native_outcome_unknown" : "key_store_unavailable", child?.pid);
15
+ function finish(error, value) {
16
+ if (done) return; done = true; clearTimeout(timer); clearTimeout(escalation); clearTimeout(reap);
17
+ child?.stdin?.destroy(); child?.stdout?.destroy();
18
+ if (error?.code === "native_process_unreaped") child?.unref?.();
19
+ error ? reject(error) : resolve(value);
20
+ }
21
+ function stop(error = unavailable()) {
22
+ if (done || stopping) return; stopping = error;
23
+ child?.stdin?.destroy();
24
+ try { child?.kill(platform === "win32" ? "SIGKILL" : "SIGTERM"); } catch {}
25
+ escalation = setTimeout(() => {
26
+ if (done) return;
27
+ try { child?.kill("SIGKILL"); } catch {}
28
+ reap = setTimeout(() => finish(new NativeStoreError("native_process_unreaped", child?.pid)), graceMs);
29
+ }, graceMs);
30
+ }
31
+ try {
32
+ const env = { PATH: process.env.PATH, ...(process.env.HOME ? { HOME: process.env.HOME } : {}), ...(process.env.DBUS_SESSION_BUS_ADDRESS ? { DBUS_SESSION_BUS_ADDRESS: process.env.DBUS_SESSION_BUS_ADDRESS } : {}), ...(process.env.SystemRoot ? { SystemRoot: process.env.SystemRoot } : {}), ...(process.env.USERPROFILE ? { USERPROFILE: process.env.USERPROFILE } : {}) };
33
+ child = spawnImpl(process.execPath, [fileURLToPath(new URL("./keyring-worker.mjs", import.meta.url))], { stdio: ["pipe", "pipe", "ignore"], windowsHide: true, env });
34
+ child.on("error", () => { if (!child.pid) finish(new NativeStoreError("key_store_unavailable")); else stop(); });
35
+ child.on("exit", () => { exited = true; });
36
+ child.stdout.on("data", chunk => { if (done) return; output += chunk; if (Buffer.byteLength(output) > 16384) stop(); });
37
+ child.stdin.on("error", () => stop());
38
+ child.on("close", code => {
39
+ if (done) return;
40
+ if (!exited && child.pid) { stop(); return; }
41
+ if (stopping) { finish(stopping); return; }
42
+ try {
43
+ const value = JSON.parse(output);
44
+ if (code || value.ok !== true || Object.keys(value).some(key => !["ok", "value"].includes(key))) throw Error();
45
+ if (input.op === "get" && value.value !== null && typeof value.value !== "string") throw Error();
46
+ finish(null, value.value);
47
+ } catch { finish(unavailable()); }
48
+ });
49
+ timer = setTimeout(() => stop(), timeoutMs);
50
+ // Durably record the broker PID before giving it private input.
51
+ onSpawn?.(child.pid);
52
+ child.stdin.end(body);
53
+ } catch { if (child?.pid) stop(); else finish(new NativeStoreError("key_store_unavailable")); }
54
+ });
55
+ }
package/package.json CHANGED
@@ -1,6 +1,59 @@
1
1
  {
2
2
  "name": "@a2a-exposed/encryption",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.8.56",
4
+ "description": "Local sealed A2A envelope primitives and key custody for opt-in CLI and stdio MCP encryption.",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./index.mjs",
8
+ "./local-state": "./local-state.mjs",
9
+ "./backup": "./backup.mjs",
10
+ "./content": "./content.mjs",
11
+ "./carriers": "./carriers.mjs",
12
+ "./assignment": "./assignment.mjs",
13
+ "./ledger": "./ledger.mjs",
14
+ "./tasks": "./tasks.mjs",
15
+ "./transport": "./transport.mjs"
16
+ },
17
+ "files": [
18
+ "index.mjs",
19
+ "README.md",
20
+ "LICENSE",
21
+ "local-state.mjs",
22
+ "keyring-worker.mjs",
23
+ "native-store.mjs",
24
+ "backup.mjs",
25
+ "LOCAL-CUSTODY-DRAFT.md",
26
+ "DEPENDENCIES.md",
27
+ "content.mjs",
28
+ "carriers.mjs",
29
+ "schemas/",
30
+ "assignment.mjs",
31
+ "ledger.mjs",
32
+ "tasks.mjs",
33
+ "transport.mjs"
34
+ ],
35
+ "scripts": {
36
+ "test": "node --test test/*.test.mjs",
37
+ "prepack": "node -e \"require('fs').copyFileSync('../LICENSE','LICENSE')\""
38
+ },
39
+ "engines": {
40
+ "node": ">=22.18"
41
+ },
42
+ "dependencies": {
43
+ "@hpke/chacha20poly1305": "1.8.1",
44
+ "@hpke/core": "1.10.1",
45
+ "@hpke/dhkem-x25519": "1.8.1"
46
+ },
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git+https://github.com/telegraphic-dev/a2a-exposed.git",
50
+ "directory": "encryption"
51
+ },
52
+ "license": "MIT",
53
+ "publishConfig": {
54
+ "access": "public"
55
+ },
56
+ "optionalDependencies": {
57
+ "@napi-rs/keyring": "2.1.2"
58
+ }
59
+ }
@@ -0,0 +1,271 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://a2a.exposed/ext/sealed/v1/assigned-carrier.schema.json",
4
+ "description": "Co-carried sealed response and non-null response-bound receipt. Runtime also compares all header bindings and the ciphertext digest before authentication.",
5
+ "oneOf": [
6
+ {
7
+ "type": "object",
8
+ "properties": {
9
+ "kind": {
10
+ "const": "message"
11
+ },
12
+ "messageId": {
13
+ "type": "string",
14
+ "pattern": "^[!-~]{1,200}$"
15
+ },
16
+ "contextId": {
17
+ "type": "string",
18
+ "pattern": "^[!-~]{1,200}$"
19
+ },
20
+ "taskId": {
21
+ "type": "string",
22
+ "pattern": "^[!-~]{1,200}$"
23
+ },
24
+ "role": {
25
+ "enum": [
26
+ "user",
27
+ "agent"
28
+ ]
29
+ },
30
+ "parts": {
31
+ "type": "array",
32
+ "minItems": 1,
33
+ "maxItems": 1,
34
+ "items": {
35
+ "type": "object",
36
+ "properties": {
37
+ "kind": {
38
+ "const": "data"
39
+ },
40
+ "data": {
41
+ "$ref": "https://a2a.exposed/ext/sealed/v1/envelope.schema.json",
42
+ "properties": {
43
+ "header": {
44
+ "properties": {
45
+ "kind": {
46
+ "enum": [
47
+ "message",
48
+ "status"
49
+ ]
50
+ }
51
+ }
52
+ }
53
+ }
54
+ },
55
+ "metadata": {
56
+ "type": "object",
57
+ "properties": {
58
+ "https://a2a.exposed/ext/sealed/v1": {
59
+ "type": "object",
60
+ "properties": {
61
+ "v": {
62
+ "const": 1
63
+ }
64
+ },
65
+ "required": [
66
+ "v"
67
+ ],
68
+ "additionalProperties": false
69
+ }
70
+ },
71
+ "required": [
72
+ "https://a2a.exposed/ext/sealed/v1"
73
+ ],
74
+ "additionalProperties": false
75
+ }
76
+ },
77
+ "required": [
78
+ "kind",
79
+ "data",
80
+ "metadata"
81
+ ],
82
+ "additionalProperties": false
83
+ }
84
+ },
85
+ "extensions": {
86
+ "type": "array",
87
+ "minItems": 1,
88
+ "maxItems": 1,
89
+ "items": {
90
+ "const": "https://a2a.exposed/ext/sealed/v1"
91
+ }
92
+ },
93
+ "metadata": {
94
+ "type": "object",
95
+ "properties": {
96
+ "https://a2a.exposed/ext/sealed/v1": {
97
+ "type": "object",
98
+ "properties": {
99
+ "v": {
100
+ "const": 1
101
+ },
102
+ "assignment": {
103
+ "allOf": [
104
+ {
105
+ "$ref": "https://a2a.exposed/ext/sealed/v1/assignment.schema.json"
106
+ },
107
+ {
108
+ "properties": {
109
+ "responseDigest": {
110
+ "type": "string",
111
+ "pattern": "^[A-Za-z0-9_-]{43}$"
112
+ }
113
+ }
114
+ }
115
+ ]
116
+ }
117
+ },
118
+ "required": [
119
+ "v",
120
+ "assignment"
121
+ ],
122
+ "additionalProperties": false
123
+ }
124
+ },
125
+ "required": [
126
+ "https://a2a.exposed/ext/sealed/v1"
127
+ ],
128
+ "additionalProperties": false
129
+ }
130
+ },
131
+ "required": [
132
+ "kind",
133
+ "messageId",
134
+ "contextId",
135
+ "role",
136
+ "parts",
137
+ "extensions",
138
+ "metadata"
139
+ ],
140
+ "additionalProperties": false
141
+ },
142
+ {
143
+ "type": "object",
144
+ "properties": {
145
+ "messageId": {
146
+ "type": "string",
147
+ "pattern": "^[!-~]{1,200}$"
148
+ },
149
+ "contextId": {
150
+ "type": "string",
151
+ "pattern": "^[!-~]{1,200}$"
152
+ },
153
+ "taskId": {
154
+ "type": "string",
155
+ "pattern": "^[!-~]{1,200}$"
156
+ },
157
+ "role": {
158
+ "enum": [
159
+ "ROLE_USER",
160
+ "ROLE_AGENT"
161
+ ]
162
+ },
163
+ "parts": {
164
+ "type": "array",
165
+ "minItems": 1,
166
+ "maxItems": 1,
167
+ "items": {
168
+ "type": "object",
169
+ "properties": {
170
+ "data": {
171
+ "$ref": "https://a2a.exposed/ext/sealed/v1/envelope.schema.json",
172
+ "properties": {
173
+ "header": {
174
+ "properties": {
175
+ "kind": {
176
+ "enum": [
177
+ "message",
178
+ "status"
179
+ ]
180
+ }
181
+ }
182
+ }
183
+ }
184
+ },
185
+ "metadata": {
186
+ "type": "object",
187
+ "properties": {
188
+ "https://a2a.exposed/ext/sealed/v1": {
189
+ "type": "object",
190
+ "properties": {
191
+ "v": {
192
+ "const": 1
193
+ }
194
+ },
195
+ "required": [
196
+ "v"
197
+ ],
198
+ "additionalProperties": false
199
+ }
200
+ },
201
+ "required": [
202
+ "https://a2a.exposed/ext/sealed/v1"
203
+ ],
204
+ "additionalProperties": false
205
+ }
206
+ },
207
+ "required": [
208
+ "data",
209
+ "metadata"
210
+ ],
211
+ "additionalProperties": false
212
+ }
213
+ },
214
+ "extensions": {
215
+ "type": "array",
216
+ "minItems": 1,
217
+ "maxItems": 1,
218
+ "items": {
219
+ "const": "https://a2a.exposed/ext/sealed/v1"
220
+ }
221
+ },
222
+ "metadata": {
223
+ "type": "object",
224
+ "properties": {
225
+ "https://a2a.exposed/ext/sealed/v1": {
226
+ "type": "object",
227
+ "properties": {
228
+ "v": {
229
+ "const": 1
230
+ },
231
+ "assignment": {
232
+ "allOf": [
233
+ {
234
+ "$ref": "https://a2a.exposed/ext/sealed/v1/assignment.schema.json"
235
+ },
236
+ {
237
+ "properties": {
238
+ "responseDigest": {
239
+ "type": "string",
240
+ "pattern": "^[A-Za-z0-9_-]{43}$"
241
+ }
242
+ }
243
+ }
244
+ ]
245
+ }
246
+ },
247
+ "required": [
248
+ "v",
249
+ "assignment"
250
+ ],
251
+ "additionalProperties": false
252
+ }
253
+ },
254
+ "required": [
255
+ "https://a2a.exposed/ext/sealed/v1"
256
+ ],
257
+ "additionalProperties": false
258
+ }
259
+ },
260
+ "required": [
261
+ "messageId",
262
+ "contextId",
263
+ "role",
264
+ "parts",
265
+ "extensions",
266
+ "metadata"
267
+ ],
268
+ "additionalProperties": false
269
+ }
270
+ ]
271
+ }
@@ -0,0 +1,73 @@
1
+ {
2
+ "type": "object",
3
+ "properties": {
4
+ "v": {
5
+ "const": 1
6
+ },
7
+ "kind": {
8
+ "const": "assignment"
9
+ },
10
+ "requestDigest": {
11
+ "type": "string",
12
+ "pattern": "^[A-Za-z0-9_-]{43}$"
13
+ },
14
+ "from": {
15
+ "$ref": "https://a2a.exposed/ext/sealed/v1/envelope.schema.json#/properties/header/properties/from"
16
+ },
17
+ "to": {
18
+ "$ref": "https://a2a.exposed/ext/sealed/v1/envelope.schema.json#/properties/header/properties/from"
19
+ },
20
+ "contextId": {
21
+ "type": "string",
22
+ "pattern": "^[!-~]{1,200}$"
23
+ },
24
+ "requestMessageId": {
25
+ "type": "string",
26
+ "pattern": "^[!-~]{1,200}$"
27
+ },
28
+ "taskId": {
29
+ "type": "string",
30
+ "pattern": "^[!-~]{1,200}$"
31
+ },
32
+ "responseKind": {
33
+ "const": "task"
34
+ },
35
+ "responseDigest": {
36
+ "anyOf": [
37
+ {
38
+ "type": "null"
39
+ },
40
+ {
41
+ "type": "string",
42
+ "pattern": "^[A-Za-z0-9_-]{43}$"
43
+ }
44
+ ]
45
+ },
46
+ "ackId": {
47
+ "type": "string",
48
+ "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$"
49
+ },
50
+ "signature": {
51
+ "type": "string",
52
+ "pattern": "^[A-Za-z0-9_-]{86}$"
53
+ }
54
+ },
55
+ "required": [
56
+ "v",
57
+ "kind",
58
+ "requestDigest",
59
+ "from",
60
+ "to",
61
+ "contextId",
62
+ "requestMessageId",
63
+ "taskId",
64
+ "responseKind",
65
+ "responseDigest",
66
+ "ackId",
67
+ "signature"
68
+ ],
69
+ "additionalProperties": false,
70
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
71
+ "$id": "https://a2a.exposed/ext/sealed/v1/assignment.schema.json",
72
+ "description": "Signed assignment receipt structure. Runtime verifies exact request/task/endpoint binding, canonical bytes and Ed25519 signature; durable acceptance requires the local transaction."
73
+ }
@@ -0,0 +1,84 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://a2a.exposed/ext/sealed/v1/capability.schema.json",
4
+ "description": "Discovery shape only. Runtime requires full equality to the current locally approved bundle and a separately approved same-origin RPC endpoint; a card never approves trust. Bundle signatures/key derivation/URLs/dates need runtime checks.",
5
+ "type": "object",
6
+ "properties": {
7
+ "uri": {
8
+ "const": "https://a2a.exposed/ext/sealed/v1"
9
+ },
10
+ "required": {
11
+ "const": false
12
+ },
13
+ "description": {
14
+ "type": "string",
15
+ "maxLength": 4096
16
+ },
17
+ "params": {
18
+ "type": "object",
19
+ "properties": {
20
+ "bundle": {
21
+ "type": "object",
22
+ "properties": {
23
+ "v": {
24
+ "const": 1
25
+ },
26
+ "suite": {
27
+ "const": "HPKE-X25519-SHA256-ChaCha20Poly1305"
28
+ },
29
+ "cardUrl": {
30
+ "type": "string",
31
+ "maxLength": 2048,
32
+ "pattern": "^https://"
33
+ },
34
+ "identityKey": {
35
+ "type": "string",
36
+ "pattern": "^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$"
37
+ },
38
+ "encryptionKey": {
39
+ "type": "string",
40
+ "pattern": "^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$"
41
+ },
42
+ "keyId": {
43
+ "type": "string",
44
+ "pattern": "^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$"
45
+ },
46
+ "notBefore": {
47
+ "type": "string",
48
+ "pattern": "^\\d{4}-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d\\.\\d{3}Z$"
49
+ },
50
+ "signature": {
51
+ "type": "string",
52
+ "pattern": "^[A-Za-z0-9_-]{85}[AQgw]$"
53
+ }
54
+ },
55
+ "required": [
56
+ "v",
57
+ "suite",
58
+ "cardUrl",
59
+ "identityKey",
60
+ "encryptionKey",
61
+ "keyId",
62
+ "notBefore",
63
+ "signature"
64
+ ],
65
+ "additionalProperties": false
66
+ },
67
+ "responseKind": {
68
+ "const": "task"
69
+ }
70
+ },
71
+ "required": [
72
+ "bundle",
73
+ "responseKind"
74
+ ],
75
+ "additionalProperties": false
76
+ }
77
+ },
78
+ "required": [
79
+ "uri",
80
+ "required",
81
+ "params"
82
+ ],
83
+ "additionalProperties": false
84
+ }