@7h3/protocol 0.4.0 → 0.5.1

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.
Files changed (248) hide show
  1. package/README.md +6 -323
  2. package/agentAdapter.d.ts +26 -0
  3. package/auditLog.d.ts +54 -0
  4. package/capability.d.ts +67 -0
  5. package/cborCodec.d.ts +34 -0
  6. package/conformanceVectors.d.ts +20 -0
  7. package/encryption.d.ts +85 -0
  8. package/envelopeCbor.d.ts +33 -0
  9. package/frameworkAdapters.d.ts +72 -0
  10. package/gateway.d.ts +53 -0
  11. package/grpcBinding.d.ts +29 -0
  12. package/httpBinding.d.ts +50 -0
  13. package/index.d.ts +39 -0
  14. package/index.js +3662 -0
  15. package/keyInfra.d.ts +64 -0
  16. package/keyRegistry.d.ts +9 -0
  17. package/keyRotation.d.ts +20 -0
  18. package/mcpGateway.d.ts +37 -0
  19. package/mcpTransports.d.ts +62 -0
  20. package/mcpWrapper.d.ts +83 -0
  21. package/otel.d.ts +65 -0
  22. package/package.json +13 -79
  23. package/policyEnforcer.d.ts +50 -0
  24. package/policyTelemetryFeedback.d.ts +11 -0
  25. package/protocol.d.ts +66 -0
  26. package/protocolAgent.d.ts +58 -0
  27. package/protocolBinary.d.ts +8 -0
  28. package/protocolCapabilities.d.ts +24 -0
  29. package/protocolReplay.d.ts +35 -0
  30. package/protocolTransport.d.ts +73 -0
  31. package/queueBinding.d.ts +43 -0
  32. package/rateLimiter.d.ts +18 -0
  33. package/{src/redisClient.ts → redisClient.d.ts} +25 -75
  34. package/replayStores.d.ts +98 -0
  35. package/revocation.d.ts +71 -0
  36. package/routePolicy.d.ts +30 -0
  37. package/runtimePolicy.d.ts +24 -0
  38. package/runtimePolicyManager.d.ts +15 -0
  39. package/runtimePolicyPresets.d.ts +11 -0
  40. package/signedResponse.d.ts +21 -0
  41. package/stream.d.ts +59 -0
  42. package/telemetry.d.ts +79 -0
  43. package/webhookBinding.d.ts +30 -0
  44. package/wsBinding.d.ts +52 -0
  45. package/.dockerignore +0 -19
  46. package/.github/dependabot.yml +0 -32
  47. package/.github/workflows/ci.yml +0 -31
  48. package/.github/workflows/publish.yml +0 -59
  49. package/.github/workflows/scorecard.yml +0 -37
  50. package/7h3.example.yaml +0 -125
  51. package/CHANGELOG.md +0 -92
  52. package/CONTRIBUTING.md +0 -82
  53. package/Dockerfile +0 -73
  54. package/GOVERNANCE.md +0 -62
  55. package/SECURITY.md +0 -70
  56. package/bench-results/replay-cache-full-1777891033256.json +0 -10
  57. package/bench-results/replay-cache-full-1777896317488.json +0 -10
  58. package/bench-results/replay-cache-full-1777900993184.json +0 -10
  59. package/bench-results/replay-cache-full-1777901019285.json +0 -10
  60. package/bench-results/replay-cache-quick-1777870170126.json +0 -10
  61. package/bench-results/signature-profiles-quick-1775875160079.json +0 -85
  62. package/bench-results/signature-profiles-quick-1775983539716.json +0 -85
  63. package/bench-results/signature-profiles-quick-1776237913190.json +0 -85
  64. package/bench-results/wire-codecs-full-1777891019803.json +0 -93
  65. package/bench-results/wire-codecs-full-1777896260964.json +0 -93
  66. package/bench-results/wire-codecs-full-1777901004247.json +0 -93
  67. package/bench-results/wire-codecs-quick-1775972879056.json +0 -93
  68. package/bench-results/wire-codecs-quick-1775983541111.json +0 -93
  69. package/bench-results/wire-codecs-quick-1776237914299.json +0 -93
  70. package/bench-results/wire-codecs-quick-1777841285236.json +0 -93
  71. package/bench-results/wire-codecs-quick-1777841321772.json +0 -93
  72. package/bench-results/wire-codecs-quick-1777841330408.json +0 -93
  73. package/bench-results/wire-codecs-quick-1777852886082.json +0 -93
  74. package/bench-results/wire-codecs-quick-1777852988773.json +0 -93
  75. package/bench-results/wire-codecs-quick-1777870188095.json +0 -93
  76. package/bench-results/wire-codecs-quick-1777870263918.json +0 -93
  77. package/bench-results/wire-codecs-quick-1777870455034.json +0 -93
  78. package/bench-results/wire-codecs-quick-1778816163081.json +0 -93
  79. package/bench-results/wire-codecs-quick-1778843936130.json +0 -93
  80. package/bin/7h3.ts +0 -385
  81. package/conformance/7h3_v0_1.json +0 -77
  82. package/conformance/7h3_v0_1_binary.json +0 -20
  83. package/conformance/aip_v0_1_binary.json +0 -20
  84. package/docker-compose.yaml +0 -77
  85. package/docs/ADOPTION_PLAN.md +0 -120
  86. package/docs/AGENTS.md +0 -77
  87. package/docs/AIP_RFC_v0.1.md +0 -97
  88. package/docs/AI_DECISION_CARD.md +0 -122
  89. package/docs/AI_RUNTIME_POLICY.json +0 -126
  90. package/docs/AI_RUNTIME_POLICY.yaml +0 -110
  91. package/docs/BACKPRESSURE_TUNING.md +0 -65
  92. package/docs/BENCHMARK_CLAIM_MATRIX.md +0 -42
  93. package/docs/BENCHMARK_REPORT_TEMPLATE.md +0 -169
  94. package/docs/BINARY_CODEC_BENCH.md +0 -23
  95. package/docs/CLEAN_CLONE_RUNBOOK.md +0 -36
  96. package/docs/CLOCK_SKEW_POLICY.md +0 -30
  97. package/docs/DISTRIBUTED_REPLAY.md +0 -142
  98. package/docs/FUZZ_CAMPAIGN.md +0 -121
  99. package/docs/GATEWAY.md +0 -195
  100. package/docs/KEY_MANAGEMENT_POLICY.md +0 -53
  101. package/docs/KEY_REVOCATION.md +0 -69
  102. package/docs/MCP_WRAPPER.md +0 -159
  103. package/docs/MIGRATION_GUIDE.md +0 -40
  104. package/docs/OPERATORS.md +0 -184
  105. package/docs/PERF_REGRESSION_POLICY.md +0 -34
  106. package/docs/PROJECT_EXAMINATION_2026-05-31.md +0 -219
  107. package/docs/RELEASE_BENCHMARK_REPORT_2026-05-15.md +0 -135
  108. package/docs/RELEASE_GATE.md +0 -25
  109. package/docs/RELEASE_NOTES_v0.1.0.md +0 -54
  110. package/docs/SECURITY_REVIEW_2026-06-05.md +0 -165
  111. package/docs/TELEMETRY.md +0 -41
  112. package/docs/THREAT_MODEL.md +0 -89
  113. package/docs/VERSIONING_POLICY.md +0 -30
  114. package/docs/assets/banner.png +0 -0
  115. package/eslint.config.js +0 -15
  116. package/fuzz/ts/harness-decode.ts +0 -136
  117. package/fuzz/ts/harness-verify.ts +0 -121
  118. package/fuzz/ts/run.ts +0 -35
  119. package/mcp-server/README.md +0 -38
  120. package/mcp-server/package-lock.json +0 -1187
  121. package/mcp-server/package.json +0 -35
  122. package/mcp-server/src/index.ts +0 -236
  123. package/mcp-server/tsconfig.json +0 -14
  124. package/scripts/aip-framework-quickstart.ts +0 -110
  125. package/scripts/aip-mcp-gateway.ts +0 -38
  126. package/scripts/aip-mcp-wrap-demo.ts +0 -72
  127. package/scripts/aip-quickstart.ts +0 -60
  128. package/scripts/bench-diff.ts +0 -118
  129. package/scripts/bench-protocol-e2e.ts +0 -937
  130. package/scripts/bench-protocol-openloop.ts +0 -1397
  131. package/scripts/bench-replay-cache.ts +0 -76
  132. package/scripts/bench-signature-profiles.ts +0 -180
  133. package/scripts/bench-wire-codecs.ts +0 -161
  134. package/scripts/build-binary-conformance.ts +0 -36
  135. package/scripts/build-release-dashboard.ts +0 -175
  136. package/scripts/canary-rollout.ts +0 -38
  137. package/scripts/mcpGatewayCli.test.ts +0 -116
  138. package/scripts/prepare-aip-package.ts +0 -88
  139. package/scripts/regen-conformance-sigs.ts +0 -18
  140. package/scripts/release-gate.ts +0 -19
  141. package/scripts/validate-runtime-policy.ts +0 -18
  142. package/sdk/browser/index.test.ts +0 -162
  143. package/sdk/browser/index.ts +0 -257
  144. package/sdk/browser/package.json +0 -13
  145. package/sdk/go/go.mod +0 -3
  146. package/sdk/go/http.go +0 -135
  147. package/sdk/go/protocol.go +0 -324
  148. package/sdk/go/protocol_test.go +0 -334
  149. package/sdk/go/webhook.go +0 -136
  150. package/sdk/python/README.md +0 -18
  151. package/sdk/python/protocol_7h3/__init__.py +0 -46
  152. package/sdk/python/protocol_7h3/http.py +0 -212
  153. package/sdk/python/protocol_7h3/keys.py +0 -149
  154. package/sdk/python/protocol_7h3/protocol.py +0 -525
  155. package/sdk/python/protocol_7h3/queue.py +0 -118
  156. package/sdk/python/protocol_7h3/webhook.py +0 -116
  157. package/sdk/python/pyproject.toml +0 -40
  158. package/sdk/python/tests/test_conformance.py +0 -110
  159. package/sdk/python/tests/test_http.py +0 -305
  160. package/sdk/python/tests/test_keys.py +0 -417
  161. package/sdk/python/tests/test_queue.py +0 -120
  162. package/sdk/python/tests/test_webhook.py +0 -345
  163. package/sdk/rust/Cargo.lock +0 -371
  164. package/sdk/rust/Cargo.toml +0 -25
  165. package/sdk/rust/README.md +0 -31
  166. package/sdk/rust/fuzz/Cargo.toml +0 -29
  167. package/sdk/rust/fuzz/fuzz_targets/fuzz_canonicalize.rs +0 -46
  168. package/sdk/rust/fuzz/fuzz_targets/fuzz_decode.rs +0 -11
  169. package/sdk/rust/src/bin/aip_mcp_gateway.rs +0 -59
  170. package/sdk/rust/src/http.rs +0 -145
  171. package/sdk/rust/src/keys.rs +0 -161
  172. package/sdk/rust/src/lib.rs +0 -688
  173. package/sdk/rust/src/queue.rs +0 -79
  174. package/sdk/rust/src/webhook.rs +0 -86
  175. package/sdk/rust/tests/conformance.rs +0 -148
  176. package/sdk/rust/tests/gateway.rs +0 -130
  177. package/sdk/rust/tests/http_webhook_queue.rs +0 -201
  178. package/sdk/rust/tests/keys.rs +0 -189
  179. package/src/agentAdapter.test.ts +0 -48
  180. package/src/agentAdapter.ts +0 -56
  181. package/src/auditLog.test.ts +0 -145
  182. package/src/auditLog.ts +0 -147
  183. package/src/conformance.test.ts +0 -136
  184. package/src/conformanceVectors.ts +0 -99
  185. package/src/frameworkAdapters.test.ts +0 -290
  186. package/src/frameworkAdapters.ts +0 -261
  187. package/src/gateway.test.ts +0 -343
  188. package/src/gateway.ts +0 -171
  189. package/src/grpcBinding.test.ts +0 -211
  190. package/src/grpcBinding.ts +0 -103
  191. package/src/httpBinding.test.ts +0 -376
  192. package/src/httpBinding.ts +0 -163
  193. package/src/index.ts +0 -32
  194. package/src/keyInfra.test.ts +0 -278
  195. package/src/keyInfra.ts +0 -228
  196. package/src/keyRegistry.ts +0 -59
  197. package/src/keyRotation.test.ts +0 -78
  198. package/src/keyRotation.ts +0 -72
  199. package/src/mcpGateway.test.ts +0 -129
  200. package/src/mcpGateway.ts +0 -250
  201. package/src/mcpTransports.test.ts +0 -92
  202. package/src/mcpTransports.ts +0 -169
  203. package/src/mcpWrapper.test.ts +0 -179
  204. package/src/mcpWrapper.ts +0 -206
  205. package/src/policyEnforcer.test.ts +0 -99
  206. package/src/policyEnforcer.ts +0 -169
  207. package/src/policyTelemetryFeedback.test.ts +0 -25
  208. package/src/policyTelemetryFeedback.ts +0 -38
  209. package/src/protocol.bench.ts +0 -37
  210. package/src/protocol.test.ts +0 -155
  211. package/src/protocol.ts +0 -413
  212. package/src/protocolAgent.test.ts +0 -105
  213. package/src/protocolAgent.ts +0 -169
  214. package/src/protocolBinary.test.ts +0 -165
  215. package/src/protocolBinary.ts +0 -312
  216. package/src/protocolCapabilities.ts +0 -70
  217. package/src/protocolFuzz.advanced.test.ts +0 -235
  218. package/src/protocolFuzz.test.ts +0 -111
  219. package/src/protocolNegative.test.ts +0 -97
  220. package/src/protocolReplay.test.ts +0 -71
  221. package/src/protocolReplay.ts +0 -194
  222. package/src/protocolTransport.test.ts +0 -556
  223. package/src/protocolTransport.ts +0 -483
  224. package/src/queueBinding.test.ts +0 -130
  225. package/src/queueBinding.ts +0 -102
  226. package/src/rateLimiter.test.ts +0 -96
  227. package/src/rateLimiter.ts +0 -46
  228. package/src/redisIntegration.test.ts +0 -134
  229. package/src/replayStores.test.ts +0 -141
  230. package/src/replayStores.ts +0 -82
  231. package/src/revocation.test.ts +0 -98
  232. package/src/revocation.ts +0 -0
  233. package/src/routePolicy.test.ts +0 -87
  234. package/src/routePolicy.ts +0 -72
  235. package/src/runtimePolicy.test.ts +0 -49
  236. package/src/runtimePolicy.ts +0 -81
  237. package/src/runtimePolicyManager.test.ts +0 -29
  238. package/src/runtimePolicyManager.ts +0 -50
  239. package/src/runtimePolicyPresets.ts +0 -43
  240. package/src/signedResponse.test.ts +0 -111
  241. package/src/signedResponse.ts +0 -83
  242. package/src/webhookBinding.test.ts +0 -144
  243. package/src/webhookBinding.ts +0 -115
  244. package/src/wsBinding.test.ts +0 -221
  245. package/src/wsBinding.ts +0 -100
  246. package/tsconfig.json +0 -15
  247. package/tsconfig.lib.json +0 -23
  248. package/vite.lib.config.ts +0 -16
package/README.md CHANGED
@@ -1,333 +1,16 @@
1
- <div align="center">
2
- <img src="./docs/assets/banner.png" alt="@7h3/protocol — AIP: Sign every message. Reject every replay." width="100%">
1
+ # @7h3/protocol
3
2
 
4
- <br/><br/>
3
+ 7h3 Protocol (wire version `7h3/0.1`):
4
+ deterministic, signed, replay-safe AI-to-AI message envelopes.
5
5
 
6
- [![npm](https://img.shields.io/npm/v/@7h3/protocol?style=flat-square&color=818cf8&logo=npm&logoColor=white&label=%407h3%2Fprotocol)](https://www.npmjs.com/package/@7h3/protocol)
7
- [![npm mcp](https://img.shields.io/npm/v/@7h3/protocol-mcp?style=flat-square&color=6366f1&logo=npm&logoColor=white&label=%407h3%2Fprotocol-mcp)](https://www.npmjs.com/package/@7h3/protocol-mcp)
8
- [![PyPI](https://img.shields.io/pypi/v/aip7h3?style=flat-square&color=818cf8&logo=python&logoColor=white)](https://pypi.org/project/aip7h3/)
9
- [![Crates.io](https://img.shields.io/crates/v/aip7h3?style=flat-square&color=a5b4fc&logo=rust&logoColor=white)](https://crates.io/crates/aip7h3)
10
- [![Tests](https://img.shields.io/badge/tests-131%20passing-4ade80?style=flat-square&logo=vitest&logoColor=white)](https://github.com/IceMasterT/7h3-protocol-aip/tree/main/src)
11
- [![Zero deps](https://img.shields.io/badge/runtime%20deps-0-a5b4fc?style=flat-square)](./package.json)
12
- [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6?style=flat-square&logo=typescript&logoColor=white)](./tsconfig.json)
13
- [![License](https://img.shields.io/badge/license-MIT-94a3b8?style=flat-square)](./LICENSE)
14
- [![Wire](https://img.shields.io/badge/wire-aip%2F0.1-818cf8?style=flat-square)](./docs/VERSIONING_POLICY.md)
15
-
16
- <br/>
17
-
18
- **The signing-and-replay layer your agent protocol forgot.**
19
-
20
- <br/>
21
- </div>
22
-
23
- ---
24
-
25
- ## Why it exists
26
-
27
- The dominant agent protocols ship messages unsigned:
28
-
29
- - **MCP** uses plain JSON-RPC 2.0 — no signatures, no replay protection. Parameters can be altered in transit; valid messages can be replayed indefinitely.
30
- - **A2A** signs *Agent Cards* for domain identity — but not the per-message task traffic.
31
-
32
- AIP fills exactly that gap. It is a hardening envelope you put *around* MCP or A2A traffic — not a competitor to them. Every message gets signed, TTL-bounded, and replay-checked before it reaches your handler.
33
-
34
- Use it when agents trigger real side effects (writes, payments, tool calls) and you need tamper-evidence, replay-safety, and auditability.
35
-
36
- ---
37
-
38
- ## Guarantees
39
-
40
- | Property | Mechanism |
41
- |---|---|
42
- | **Authentic** | HMAC-SHA256 (HS256) or Ed25519 over a canonical payload — real WebCrypto, no hand-rolled crypto |
43
- | **Deterministic** | Fixed-key-order canonicalization; signatures match byte-for-byte across TS / Python / Rust |
44
- | **Replay-resistant** | `(sender, messageId, nonce)` uniqueness window + TTL / clock-skew enforcement |
45
- | **Polyglot** | Shared conformance fixture set (`conformance/aip_v0_1.json`) proves parity across all three runtimes |
46
-
47
- ---
48
-
49
- ## Install
6
+ Install:
50
7
 
51
8
  ```bash
52
9
  npm install @7h3/protocol
53
10
  ```
54
11
 
55
- Python and Rust SDKs live under `sdk/python` (`from aip7h3 import …`) and `sdk/rust` (`use aip7h3::…`).
56
-
57
- ### MCP server (for Claude Code / Claude Desktop)
58
-
59
- The companion `@7h3/protocol-mcp` package installs five tools into your AI assistant for generating secrets, keypairs, and boilerplate.
60
-
61
- ```bash
62
- # Claude Code
63
- claude mcp add aip -- npx @7h3/protocol-mcp
64
- ```
65
-
66
- ```json
67
- // Claude Desktop — claude_desktop_config.json
68
- {
69
- "mcpServers": {
70
- "aip": { "command": "npx", "args": ["@7h3/protocol-mcp"] }
71
- }
72
- }
73
- ```
74
-
75
- | Tool | What it does |
76
- |---|---|
77
- | `aip_generate_secret` | 32-byte HMAC secret → `AIP_SECRET` |
78
- | `aip_generate_keypair` | Ed25519 keypair → env vars |
79
- | `aip_wrap_mcp_server` | Ready-to-paste boilerplate for your MCP server |
80
- | `aip_sign` | Sign a test envelope (debugging / fixture generation) |
81
- | `aip_verify` | Verify an envelope's signature and shape |
82
-
83
- ---
84
-
85
- ## Quick start
86
-
87
- ### HMAC (shared secret — simplest path)
12
+ Import:
88
13
 
89
14
  ```ts
90
- import {
91
- createEnvelope, signEnvelopeHmac, verifyEnvelopeHmac, validateEnvelope,
92
- } from '@7h3/protocol'
93
-
94
- const secret = 'shared-secret'
95
- const envelope = await signEnvelopeHmac(
96
- createEnvelope({ sender: 'planner', recipient: 'worker', intent: 'TASK', content: 'do-the-thing' }),
97
- secret,
98
- )
99
-
100
- const diagnostics = validateEnvelope(envelope) // shape / TTL / version checks
101
- const ok = await verifyEnvelopeHmac(envelope, secret) // tamper + auth check
102
- // → replay-check downstream via your transport's replay cache
15
+ import { createAipAgentAdapter, receiveEnvelope } from '@7h3/protocol'
103
16
  ```
104
-
105
- ### Ed25519 (asymmetric — production recommendation)
106
-
107
- > **Why Ed25519?** HMAC is a shared secret — any peer that can verify can also forge. Ed25519 is asymmetric: you sign with a private key, peers verify with your public key only. Compromising a peer does not compromise your signing key.
108
-
109
- ```ts
110
- import {
111
- generateEd25519KeypairBase64Url, createEnvelope,
112
- signEnvelopeEd25519, verifyEnvelopeEd25519,
113
- } from '@7h3/protocol'
114
-
115
- const { privateKey, publicKey } = await generateEd25519KeypairBase64Url()
116
- const envelope = await signEnvelopeEd25519(
117
- createEnvelope({ sender: 'planner', recipient: 'worker', intent: 'TASK', content: 'do-the-thing' }),
118
- privateKey, 'k1',
119
- )
120
- const ok = await verifyEnvelopeEd25519(envelope, publicKey)
121
- ```
122
-
123
- ---
124
-
125
- ## MCP hardening wrapper
126
-
127
- Wrap any existing MCP server or client — handler signature does not change:
128
-
129
- ```ts
130
- import { wrapMcpServer, wrapMcpClient, signEnvelopeEd25519 } from '@7h3/protocol'
131
-
132
- // Server side
133
- const secureServer = wrapMcpServer(myMcpHandler, {
134
- selfAgentId: 'my-server',
135
- sign: (e) => signEnvelopeEd25519(e, serverPrivateKey, 'k1'),
136
- })
137
-
138
- // Client side
139
- const { send } = wrapMcpClient({
140
- selfAgentId: 'my-client',
141
- peerAgentId: 'my-server',
142
- sign: (e) => signEnvelopeEd25519(e, clientPrivateKey, 'k1'),
143
- receive: { signatureResolver: async ({ keyId }) => ({ alg: 'ED25519', publicKey: serverPublicKey }) },
144
- })
145
- const response = await send({ jsonrpc: '2.0', id: 1, method: 'tools/list' }, fetch)
146
- ```
147
-
148
- The wrapper enforces four bindings beyond signature verification:
149
-
150
- | Binding | Attack defeated |
151
- |---|---|
152
- | **Recipient** | Server rejects envelopes not addressed to `selfAgentId` — cross-server relay |
153
- | **Sender** | Client accepts responses only from `peerAgentId` — response spoofing |
154
- | **Correlation** | Client enforces `correlationId === request messageId` — response substitution |
155
- | **Replay** | `InMemoryReplayCache` injected by default — replay of prior requests |
156
-
157
- Demo: `npm run aip:mcp:wrap`
158
-
159
- ---
160
-
161
- ## Wire formats
162
-
163
- Three formats — choose by context:
164
-
165
- | Format | Use case |
166
- |---|---|
167
- | `json` | Human-readable, debug-friendly |
168
- | `compact` | Minified JSON — smaller over HTTP |
169
- | `binary` | MessagePack (magic `AIPB`) — highest throughput, lowest parse overhead |
170
-
171
- ```ts
172
- import { encodeEnvelope, decodeEnvelope } from '@7h3/protocol'
173
-
174
- const wire = encodeEnvelope(envelope, 'binary') // Uint8Array
175
- const back = decodeEnvelope(wire) // ProtocolEnvelope
176
- ```
177
-
178
- ---
179
-
180
- ## Distributed replay store (Redis)
181
-
182
- Production deployments need a shared replay store across agent instances:
183
-
184
- ```ts
185
- import { createRedisReplayStore, DistributedReplayCache } from '@7h3/protocol'
186
-
187
- const store = createRedisReplayStore(redisClient, {
188
- errorBehavior: 'fallback', // degrade to local store on Redis outage — never silent
189
- onDegraded: (err) => telemetry.error('replay-store-degraded', err),
190
- })
191
- const replayCache = new DistributedReplayCache(store)
192
-
193
- // Pass replayCache into receiveEnvelope or wrapMcpServer/wrapMcpClient
194
- ```
195
-
196
- - Atomic `SET NX PX` reserve — no double-processing under concurrent writes
197
- - `reserveMany` batch pipeline — low overhead for high-volume handlers
198
- - `errorBehavior: 'fallback' | 'reject' | 'allow'` — operator controls degradation posture
199
- - See `docs/DISTRIBUTED_REPLAY.md`
200
-
201
- ---
202
-
203
- ## Fleet-wide key revocation
204
-
205
- ```ts
206
- import { createRedisRevocationStore, withRevocationCheck } from '@7h3/protocol'
207
-
208
- const revocationStore = createRedisRevocationStore(redisClient) // fail-closed default
209
- const secureResolver = withRevocationCheck(mySignatureResolver, revocationStore)
210
- // Revoked key → resolver returns undefined → verification fails
211
- ```
212
-
213
- - Cached reads (5 s TTL by default) — low overhead on the verify hot path
214
- - Fail-closed default: Redis outage → reject, not allow
215
- - See `docs/KEY_REVOCATION.md`
216
-
217
- ---
218
-
219
- ## Transport adapters
220
-
221
- Zero new runtime dependencies — only Node built-ins and global `fetch`:
222
-
223
- ```ts
224
- import { serveMcpOverStdio, createStdioMcpClient } from '@7h3/protocol'
225
- import { createHttpMcpHandler, createHttpMcpClient } from '@7h3/protocol'
226
- ```
227
-
228
- | Adapter | Notes |
229
- |---|---|
230
- | `serveMcpOverStdio` + `createStdioMcpClient` | Newline-delimited; in-order sequential chain prevents response interleaving |
231
- | `createHttpMcpHandler` + `createHttpMcpClient` | `node:http` handler + `fetch` client; supports `binary` wire format |
232
-
233
- ---
234
-
235
- ## Framework adapters
236
-
237
- LangChain, LlamaIndex, and JSON-RPC bridge adapters wrap `AipAgentAdapter` to translate between AIP envelopes and framework-native message types:
238
-
239
- ```ts
240
- import { LangChainAipAdapter, LlamaIndexAipAdapter, JsonRpcBridge } from '@7h3/protocol'
241
- ```
242
-
243
- ---
244
-
245
- ## Policy and telemetry
246
-
247
- Runtime policy controls transport behavior, retry, rate limits, and safety invariants — loaded from `AI_RUNTIME_POLICY.yaml` or inline:
248
-
249
- ```ts
250
- import { loadRuntimePolicy, validateRuntimePolicy, PolicyEnforcer } from '@7h3/protocol'
251
-
252
- const policy = await loadRuntimePolicy({ path: './AI_RUNTIME_POLICY.yaml' })
253
- const enforcer = new PolicyEnforcer(policy)
254
- ```
255
-
256
- See `docs/TELEMETRY.md`, `docs/AI_DECISION_CARD.md`, `docs/OPERATORS.md`.
257
-
258
- ---
259
-
260
- ## Polyglot parity
261
-
262
- All three SDKs are driven by the same conformance fixture set at `conformance/aip_v0_1.json`. Signatures verified against known vectors in all three runtimes:
263
-
264
- ```bash
265
- npm test # TypeScript (131 tests / 23 files)
266
- npm run conformance:python # Python unittest
267
- npm run conformance:rust # Rust cargo test (7 tests)
268
- ```
269
-
270
- ---
271
-
272
- ## Status
273
-
274
- **Version: 0.1.2** · Wire protocol: `aip/0.1`
275
-
276
- | What | Status |
277
- |---|---|
278
- | Core test suite | ✅ 131 tests / 23 files — all green |
279
- | Cryptography | ✅ Real WebCrypto — HMAC-SHA256 + Ed25519 (no hand-rolled crypto) |
280
- | Deterministic canonicalization | ✅ Fixed key order; byte-identical across runtimes |
281
- | TS/Python/Rust parity | ✅ Shared conformance fixtures; all pass |
282
- | Distributed replay (Redis) | ✅ Atomic `SET NX PX`; batch pipeline; graceful degradation |
283
- | Fleet-wide revocation (Redis) | ✅ Fail-closed; cached reads; stale-serve during outage |
284
- | MCP hardening wrapper | ✅ 4 bindings; all independently tested |
285
- | Property-based fuzz tests | ✅ 8 properties via fast-check (wire decoder, canonicalization, replay) |
286
- | Live-Redis integration test | ✅ Auto-skips if no server present — no false passes |
287
- | Formal fuzz campaign | ✅ TypeScript mutation harnesses run clean (50k/20k rounds, 0 crashes); Rust targets built and run (4.9M iterations, no panics in `canonicalize_envelope`/`decode_envelope`) — see [`docs/FUZZ_CAMPAIGN.md`](./docs/FUZZ_CAMPAIGN.md) |
288
- | Independent security audit | ⚠️ Not yet performed by an external reviewer — internal AI-assisted review completed 2026-06-05, 2 bugs found and fixed (see [`docs/SECURITY_REVIEW_2026-06-05.md`](./docs/SECURITY_REVIEW_2026-06-05.md)); cryptographic primitives are standard WebCrypto; parsing/replay/canonicalization logic remains unaudited by a qualified third party |
289
- | Python Ed25519 | ✅ Pure-Python fallback — no external packages required; tries `cryptography` → `PyNaCl` → pure Python in order |
290
- | Rust crates.io publish | ✅ Metadata complete; `cargo publish --dry-run` passes — publish with `cargo publish` when ready |
291
- | Redis HA | ✅ Sentinel, Cluster, and Upstash adapter patterns documented in [`docs/DISTRIBUTED_REPLAY.md`](./docs/DISTRIBUTED_REPLAY.md) |
292
-
293
- ---
294
-
295
- ## Docs
296
-
297
- | Document | Contents |
298
- |---|---|
299
- | [`docs/THREAT_MODEL.md`](./docs/THREAT_MODEL.md) | Full threat coverage matrix |
300
- | [`docs/MCP_WRAPPER.md`](./docs/MCP_WRAPPER.md) | MCP wrapper usage, transport examples, HMAC vs Ed25519 comparison |
301
- | [`docs/DISTRIBUTED_REPLAY.md`](./docs/DISTRIBUTED_REPLAY.md) | Redis store setup, `errorBehavior` table, ops guidance |
302
- | [`docs/KEY_REVOCATION.md`](./docs/KEY_REVOCATION.md) | Revocation store setup, cache TTL tuning |
303
- | [`docs/KEY_MANAGEMENT_POLICY.md`](./docs/KEY_MANAGEMENT_POLICY.md) | Key lifecycle and rotation policy |
304
- | [`docs/CLOCK_SKEW_POLICY.md`](./docs/CLOCK_SKEW_POLICY.md) | Clock sync requirements |
305
- | [`docs/VERSIONING_POLICY.md`](./docs/VERSIONING_POLICY.md) | Wire freeze guarantees, semver policy |
306
- | [`docs/MIGRATION_GUIDE.md`](./docs/MIGRATION_GUIDE.md) | Breaking-change upgrade paths |
307
- | [`docs/OPERATORS.md`](./docs/OPERATORS.md) | Deployment and operations reference |
308
- | [`docs/TELEMETRY.md`](./docs/TELEMETRY.md) | Telemetry hooks and observability |
309
- | [`docs/SECURITY_REVIEW_2026-06-05.md`](./docs/SECURITY_REVIEW_2026-06-05.md) | AI-assisted internal security review — findings, fixes, positive findings |
310
- | [`docs/PROJECT_EXAMINATION_2026-05-31.md`](./docs/PROJECT_EXAMINATION_2026-05-31.md) | Independent examination — verified vs asserted |
311
- | [`CHANGELOG.md`](./CHANGELOG.md) | Full version history |
312
-
313
- ---
314
-
315
- ## Security
316
-
317
- Report vulnerabilities via the coordinated disclosure process in [`SECURITY.md`](./SECURITY.md). **Do not open a public issue for security findings.** 48-hour acknowledgement SLA; 14-day critical patch SLA.
318
-
319
- The cryptographic primitives are standard (WebCrypto Ed25519 / HMAC-SHA256). The envelope parsing, canonicalization, and replay-cache logic have not been formally audited. No independent security audit has been performed. Treat accordingly in high-stakes deployments.
320
-
321
- ---
322
-
323
- ## Contributing
324
-
325
- See [`CONTRIBUTING.md`](./CONTRIBUTING.md) — test commands, wire-freeze policy, conformance fixture update requirement, and PR workflow.
326
-
327
- ## Governance
328
-
329
- See [`GOVERNANCE.md`](./GOVERNANCE.md) — single-maintainer stage, decision process, co-maintainership path (LF Minimum Viable Governance style).
330
-
331
- ## License
332
-
333
- MIT
@@ -0,0 +1,26 @@
1
+ import { type AgentReceiveResult, type AgentSessionConfig } from './protocolAgent';
2
+ import { type IntentKind, type ProtocolEnvelope } from './protocol';
3
+ import { type WireEnvelope, type WireFormat } from './protocolTransport';
4
+ export interface AipAdapterConfig extends AgentSessionConfig {
5
+ wireFormat?: WireFormat;
6
+ }
7
+ export declare class AipAgentAdapter {
8
+ private readonly session;
9
+ private readonly wireFormat;
10
+ constructor(config: AipAdapterConfig);
11
+ toRaw(envelope: ProtocolEnvelope): WireEnvelope;
12
+ createRawIntent(input: {
13
+ recipient?: string;
14
+ intent: IntentKind;
15
+ content: string;
16
+ capability?: string;
17
+ correlationId?: string;
18
+ ttlMs?: number;
19
+ messageId?: string;
20
+ nonce?: string;
21
+ nowMs?: number;
22
+ }): Promise<WireEnvelope>;
23
+ receiveRaw(raw: WireEnvelope, nowMs?: number): Promise<AgentReceiveResult>;
24
+ handleRaw(raw: WireEnvelope, emitResponseRaw: (rawResponse: WireEnvelope, responseEnvelope: ProtocolEnvelope) => void | Promise<void>, nowMs?: number): Promise<AgentReceiveResult>;
25
+ }
26
+ export declare function createAipAgentAdapter(config: AipAdapterConfig): AipAgentAdapter;
package/auditLog.d.ts ADDED
@@ -0,0 +1,54 @@
1
+ export type AuditEventType = 'verify-ok' | 'verify-fail' | 'rate-limited' | 'sender-denied' | 'response-signed';
2
+ export interface AuditEntry {
3
+ id: string;
4
+ timestampMs: number;
5
+ type: AuditEventType;
6
+ sender?: string;
7
+ path?: string;
8
+ method?: string;
9
+ envelopeId?: string;
10
+ failReason?: string;
11
+ upstream?: string;
12
+ responseStatus?: number;
13
+ entrySignature: string;
14
+ }
15
+ export interface AuditLogger {
16
+ log(event: Omit<AuditEntry, 'id' | 'timestampMs' | 'entrySignature'>): Promise<void>;
17
+ query(opts?: {
18
+ type?: AuditEventType;
19
+ sender?: string;
20
+ since?: number;
21
+ limit?: number;
22
+ }): Promise<AuditEntry[]>;
23
+ verify(entry: AuditEntry, publicKey: string): Promise<boolean>;
24
+ }
25
+ declare class InMemoryAuditLog implements AuditLogger {
26
+ private entries;
27
+ private privateKey;
28
+ private maxEntries;
29
+ constructor(privateKey: string, maxEntries?: number);
30
+ log(event: Omit<AuditEntry, 'id' | 'timestampMs' | 'entrySignature'>): Promise<void>;
31
+ query(opts?: {
32
+ type?: AuditEventType;
33
+ sender?: string;
34
+ since?: number;
35
+ limit?: number;
36
+ }): Promise<AuditEntry[]>;
37
+ verify(entry: AuditEntry, publicKey: string): Promise<boolean>;
38
+ size(): number;
39
+ }
40
+ declare class NoopAuditLog implements AuditLogger {
41
+ log(_event: Omit<AuditEntry, 'id' | 'timestampMs' | 'entrySignature'>): Promise<void>;
42
+ query(_opts?: {
43
+ type?: AuditEventType;
44
+ sender?: string;
45
+ since?: number;
46
+ limit?: number;
47
+ }): Promise<AuditEntry[]>;
48
+ verify(_entry: AuditEntry, _publicKey: string): Promise<boolean>;
49
+ size(): number;
50
+ }
51
+ export declare function createAuditLog(privateKey: string, opts?: {
52
+ maxEntries?: number;
53
+ }): InMemoryAuditLog;
54
+ export { InMemoryAuditLog, NoopAuditLog };
@@ -0,0 +1,67 @@
1
+ import { generateEd25519KeypairBase64Url } from './protocol';
2
+ export { generateEd25519KeypairBase64Url };
3
+ export interface CapabilityScope {
4
+ pathGlob: string;
5
+ methods?: string[];
6
+ maxDelegations?: number;
7
+ }
8
+ export interface CapabilityToken {
9
+ id: string;
10
+ version: '7h3-cap/1';
11
+ issuer: string;
12
+ subject: string;
13
+ scopes: CapabilityScope[];
14
+ issuedAt: number;
15
+ expiresAt: number;
16
+ delegationDepth: number;
17
+ parentTokenId?: string;
18
+ /** How many more times this token can be re-delegated. undefined = unlimited, 0 = no further delegation. */
19
+ maxDelegations: number | undefined;
20
+ signature: string;
21
+ keyId: string;
22
+ }
23
+ export type CapabilityVerifyResult = {
24
+ ok: true;
25
+ token: CapabilityToken;
26
+ chain: CapabilityToken[];
27
+ } | {
28
+ ok: false;
29
+ reason: string;
30
+ };
31
+ export declare const CAP_HEADER = "x-7h3-capability";
32
+ /**
33
+ * Deterministic canonical form for signing: alphabetically sorted top-level fields,
34
+ * each scope also sorted. The `signature` field is excluded.
35
+ */
36
+ export declare function canonicalizeCapabilityToken(token: Omit<CapabilityToken, 'signature'>): string;
37
+ export declare function issueCapabilityToken(opts: {
38
+ issuerPrivateKey: string;
39
+ issuerId: string;
40
+ subject: string;
41
+ scopes: CapabilityScope[];
42
+ ttlMs: number;
43
+ maxDelegations?: number;
44
+ keyId?: string;
45
+ }): Promise<CapabilityToken>;
46
+ export declare function delegateCapabilityToken(opts: {
47
+ parentToken: CapabilityToken;
48
+ delegatorPrivateKey: string;
49
+ delegatorId: string;
50
+ newSubject: string;
51
+ scopes?: CapabilityScope[];
52
+ ttlMs: number;
53
+ keyId?: string;
54
+ }): Promise<CapabilityToken>;
55
+ export declare function verifyCapabilityToken(token: CapabilityToken, publicKey: string, opts?: {
56
+ now?: number;
57
+ }): Promise<boolean>;
58
+ export declare function verifyCapabilityChain(chain: CapabilityToken[], keyRegistry: {
59
+ getPublicKey(id: string): Promise<string | null>;
60
+ }, opts?: {
61
+ requiredPathGlob?: string;
62
+ requiredMethod?: string;
63
+ now?: number;
64
+ }): Promise<CapabilityVerifyResult>;
65
+ export declare function tokenMatchesScope(token: CapabilityToken, pathGlob: string, method?: string): boolean;
66
+ export declare function serializeCapabilityChain(chain: CapabilityToken[]): string;
67
+ export declare function parseCapabilityChain(serialized: string): CapabilityToken[];
package/cborCodec.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Minimal deterministic CBOR encoder/decoder — zero external dependencies.
3
+ * Follows RFC 8949 §4.2 deterministic encoding:
4
+ * - Shortest-length integers
5
+ * - Map keys sorted by lexicographic byte order of encoded key
6
+ */
7
+ export declare class CborEncoder {
8
+ private chunks;
9
+ encode(value: unknown): Uint8Array;
10
+ private _encode;
11
+ private _encodeNumber;
12
+ private _float64Header;
13
+ private _encodeString;
14
+ private _encodeByteString;
15
+ private _encodeArray;
16
+ private _encodeMapFromAnyEntries;
17
+ private _encodeMapFromEntries;
18
+ private _compareBytes;
19
+ private _concatPair;
20
+ private _encodeHead;
21
+ private _encodeHeadBytes;
22
+ private _concat;
23
+ }
24
+ export declare class CborDecoder {
25
+ private data;
26
+ private offset;
27
+ decode(data: Uint8Array): unknown;
28
+ private _decode;
29
+ private _decodeUint;
30
+ private _readByte;
31
+ private _readBytes;
32
+ }
33
+ export declare function encodeCbor(value: unknown): Uint8Array;
34
+ export declare function decodeCbor(data: Uint8Array): unknown;
@@ -0,0 +1,20 @@
1
+ import type { ProtocolEnvelope } from './protocol';
2
+ export interface ConformanceVector {
3
+ id: string;
4
+ secret: string;
5
+ keyId: string;
6
+ envelope: Omit<ProtocolEnvelope, 'signature'>;
7
+ canonical: string;
8
+ signature: string;
9
+ }
10
+ export interface Ed25519ConformanceVector {
11
+ id: string;
12
+ keyId: string;
13
+ publicKey: string;
14
+ privateKey: string;
15
+ envelope: Omit<ProtocolEnvelope, 'signature'>;
16
+ canonical: string;
17
+ signature: string;
18
+ }
19
+ export declare const AIP_V01_CONFORMANCE_VECTORS: ConformanceVector[];
20
+ export declare const AIP_V01_ED25519_CONFORMANCE_VECTORS: Ed25519ConformanceVector[];
@@ -0,0 +1,85 @@
1
+ /**
2
+ * E2E Encryption for 7h3 Protocol
3
+ *
4
+ * Uses X25519 Diffie-Hellman key exchange + ChaCha20-Poly1305 AEAD.
5
+ * All operations via Node.js built-in `node:crypto` — zero new dependencies.
6
+ *
7
+ * Architecture:
8
+ * EncryptedEnvelope = SignedEnvelope where body.content is a base64url-encoded
9
+ * EncryptedPayload, body.intent = 'ENCRYPTED', body.capability = 'x25519-chacha20poly1305'
10
+ */
11
+ import { type ProtocolBody, type ProtocolEnvelope } from './protocol.js';
12
+ export interface X25519KeyPair {
13
+ /** Raw 32-byte X25519 public key, base64url-encoded (no padding) */
14
+ publicKey: string;
15
+ /** Raw 32-byte X25519 private key, base64url-encoded (no padding) */
16
+ privateKey: string;
17
+ }
18
+ export interface EncryptedPayload {
19
+ /** Ephemeral X25519 public key (base64url, raw 32 bytes) */
20
+ ephemeralPublic: string;
21
+ /** ChaCha20 nonce / HKDF salt (base64url, 12 bytes) */
22
+ nonce: string;
23
+ /** Ciphertext without auth tag (base64url) */
24
+ ciphertext: string;
25
+ /** 16-byte Poly1305 auth tag (base64url) */
26
+ tag: string;
27
+ }
28
+ /**
29
+ * Generate a fresh X25519 keypair.
30
+ * Both keys are raw 32-byte values encoded as base64url (no padding).
31
+ */
32
+ export declare function generateX25519KeyPair(): X25519KeyPair;
33
+ /**
34
+ * Perform X25519 DH + HKDF-SHA256 to derive a 32-byte ChaCha20-Poly1305 key.
35
+ *
36
+ * @param privateKeyBase64Url - raw 32-byte X25519 private key (base64url)
37
+ * @param peerPublicKeyBase64Url - raw 32-byte X25519 public key (base64url)
38
+ * @param nonce - raw 12-byte nonce (base64url); used as HKDF salt
39
+ * @returns 32-byte Buffer ready for use with createCipheriv/createDecipheriv
40
+ */
41
+ export declare function deriveEncryptionKey(privateKeyBase64Url: string, peerPublicKeyBase64Url: string, nonce: string): Buffer;
42
+ /**
43
+ * Encrypt a ProtocolBody with the recipient's X25519 public key.
44
+ *
45
+ * @returns encryptedContent (base64url-encoded EncryptedPayload JSON) and ephemeralPublic
46
+ */
47
+ export declare function encryptBody(body: ProtocolBody, recipientX25519PublicKey: string): {
48
+ encryptedContent: string;
49
+ ephemeralPublic: string;
50
+ };
51
+ /**
52
+ * Decrypt an encrypted ProtocolBody.
53
+ *
54
+ * @param encryptedContent - base64url-encoded EncryptedPayload
55
+ * @param recipientX25519PrivateKey - raw 32-byte X25519 private key (base64url)
56
+ * @returns decrypted ProtocolBody
57
+ * @throws if AEAD tag verification fails
58
+ */
59
+ export declare function decryptBody(encryptedContent: string, recipientX25519PrivateKey: string): ProtocolBody;
60
+ /**
61
+ * Encrypt and sign an envelope (full pipeline).
62
+ *
63
+ * The original body is encrypted; the envelope body is replaced with:
64
+ * { intent: 'ENCRYPTED', content: <encrypted-payload>, capability: 'x25519-chacha20poly1305' }
65
+ * The modified envelope is then signed with Ed25519.
66
+ */
67
+ export declare function sealEnvelope(envelope: Omit<ProtocolEnvelope, 'signature'>, opts: {
68
+ recipientX25519PublicKey: string;
69
+ senderEd25519PrivateKey: string;
70
+ }): Promise<ProtocolEnvelope>;
71
+ /**
72
+ * Verify signature and decrypt an envelope (full pipeline).
73
+ *
74
+ * Signature is verified FIRST; decryption only proceeds if valid.
75
+ *
76
+ * @returns The signed envelope (with encrypted body) and the decrypted original body
77
+ * @throws if Ed25519 signature invalid or AEAD tag fails
78
+ */
79
+ export declare function openEnvelope(envelope: ProtocolEnvelope, opts: {
80
+ recipientX25519PrivateKey: string;
81
+ senderEd25519PublicKey: string;
82
+ }): Promise<{
83
+ envelope: ProtocolEnvelope;
84
+ body: ProtocolBody;
85
+ }>;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Higher-level CBOR codec for ProtocolEnvelope.
3
+ * Uses numeric field keys for maximum compactness.
4
+ *
5
+ * Envelope map structure:
6
+ * 1 → header map
7
+ * 2 → body map
8
+ * 3 → signature map (omitted if no signature)
9
+ *
10
+ * Header map:
11
+ * 1 → version (string)
12
+ * 2 → messageId (string)
13
+ * 3 → timestampMs (int)
14
+ * 4 → ttlMs (int)
15
+ * 5 → sender (string)
16
+ * 6 → recipient (string, omit if absent)
17
+ * 7 → nonce (string)
18
+ *
19
+ * Body map:
20
+ * 1 → intent (string)
21
+ * 2 → content (string)
22
+ * 3 → capability (string, omit if absent)
23
+ * 4 → correlationId (string, omit if absent)
24
+ *
25
+ * Signature map:
26
+ * 1 → alg (string)
27
+ * 2 → keyId (string)
28
+ * 3 → value (string — base64url signature)
29
+ */
30
+ import type { ProtocolEnvelope } from './protocol';
31
+ export declare const CBOR_CONTENT_TYPE = "application/7h3-cbor";
32
+ export declare function encodeEnvelopeCbor(env: ProtocolEnvelope): Uint8Array;
33
+ export declare function decodeEnvelopeCbor(data: Uint8Array): ProtocolEnvelope;