@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/docs/TELEMETRY.md DELETED
@@ -1,41 +0,0 @@
1
- # Telemetry Events
2
-
3
- Transport-level telemetry can be attached to `receiveEnvelope` via `telemetry` callback.
4
-
5
- ## Event phases
6
-
7
- - `decoded`
8
- - `rejected_clock_skew`
9
- - `rejected_validation`
10
- - `rejected_replay`
11
- - `rejected_missing_signature`
12
- - `rejected_missing_material`
13
- - `rejected_bad_signature`
14
- - `accepted`
15
-
16
- ## Usage
17
-
18
- ```ts
19
- import { receiveEnvelope } from './src/protocolTransport'
20
-
21
- await receiveEnvelope(rawEnvelope, {
22
- nowMs: Date.now(),
23
- replayCache,
24
- secretResolver: async () => sharedSecret,
25
- telemetry: async (event) => {
26
- console.log(event.phase, event.sender, event.messageId, event.reason)
27
- },
28
- })
29
- ```
30
-
31
- ## Gateway audit events
32
-
33
- `createAipMcpGatewayRuntime` supports `onAuditEvent` for request/policy traces.
34
-
35
- Phases:
36
-
37
- - `request_received`
38
- - `policy`
39
- - `verification_failed`
40
- - `request_success`
41
- - `request_error`
@@ -1,89 +0,0 @@
1
- # 7h3 Protocol AIP Threat Model (v1.0 draft)
2
-
3
- ## Scope
4
-
5
- This model covers `aip/0.1` envelope transport and verification paths in:
6
-
7
- - `src/protocol.ts`
8
- - `src/protocolTransport.ts`
9
- - `src/mcpGateway.ts`
10
- - `sdk/rust/src/lib.rs`
11
-
12
- ## Assets
13
-
14
- - Message integrity and authenticity
15
- - Agent identity binding (`sender`, `keyId`, signature material)
16
- - Freshness (TTL + replay resistance)
17
- - Gateway policy decisions (allowlist/auth/rate-limit)
18
-
19
- ## Assumptions
20
-
21
- - Clocks are roughly synchronized within deployment skew limits.
22
- - Secret/private-key material is provisioned securely outside protocol logic.
23
- - Transport channel can be observed/modified by adversaries; protocol must detect tamper.
24
-
25
- ## Threats and controls
26
-
27
- ## Tampering
28
-
29
- - Threat: attacker modifies envelope body/header in transit.
30
- - Controls:
31
- - canonical payload signing (`HS256` / `ED25519`)
32
- - signature verification before acceptance
33
- - canonical key order fixed to prevent ambiguous signing forms
34
-
35
- ## Replay
36
-
37
- - Threat: attacker replays previously valid signed envelopes.
38
- - Controls:
39
- - TTL checks (`timestampMs + ttlMs`)
40
- - replay cache consumption (`messageId` + `sender` + `nonce` semantics)
41
-
42
- ## Sender impersonation
43
-
44
- - Threat: attacker signs as trusted sender with incorrect key material.
45
- - Controls:
46
- - verifier resolves material by `(keyId, sender)` context
47
- - `signatureResolver`/`secretResolver` mapping policy in transport layer
48
-
49
- ## Algorithm confusion / downgrade
50
-
51
- - Threat: attacker swaps `alg` or relies on omitted compact alg fields.
52
- - Controls:
53
- - explicit algorithm field in canonical signature object
54
- - compact wire supports `sig.a`; default compatibility path only for legacy HS256
55
- - verifier rejects material when resolved algorithm does not match envelope signature
56
-
57
- ## Gateway abuse
58
-
59
- - Threat: unauthorized or abusive JSON-RPC method calls.
60
- - Controls:
61
- - method allowlist
62
- - authorization policy hook
63
- - rate-limit policy hook with context-aware keys
64
-
65
- ## Mitigated risks
66
-
67
- - **Distributed replay** — a Redis-backed `DistributedReplayStore` is shipped
68
- (`createRedisReplayStore`, `src/replayStores.ts`). It uses atomic `SET NX PX`,
69
- batches via pipeline (`reserveMany`), and degrades to a local store on a Redis
70
- outage so a node never blindly accepts replays and never hard-stops. See
71
- `DISTRIBUTED_REPLAY.md`.
72
- - **Fleet-wide key revocation** — a shared `RevocationStore`
73
- (`createRedisRevocationStore`, `src/revocation.ts`) is consulted on the verify
74
- path via `withRevocationCheck`. A key revoked on one node is rejected on all
75
- nodes; reads are cached and fail **closed** by default. See `KEY_REVOCATION.md`.
76
-
77
- ## Remaining risks (open)
78
-
79
- - No formal fuzz campaign yet for parser/canonicalization boundaries.
80
- - Revocation/replay stores rely on a correctly provisioned, available Redis (or
81
- equivalent) control plane; operators own its HA and clock synchronization.
82
- - No third-party cryptographic audit yet.
83
-
84
- ## Required production mitigations
85
-
86
- - Keep signature verification enabled by default in production paths.
87
- - Deploy a shared replay store (`createRedisReplayStore`) for horizontally scaled gateways.
88
- - Wire a shared revocation store (`createRedisRevocationStore` + `withRevocationCheck`)
89
- and enforce key lifecycle policy (rotation, expiry, revocation) in the control plane.
@@ -1,30 +0,0 @@
1
- # AIP Versioning Policy
2
-
3
- ## Protocol versions
4
-
5
- - Protocol version is declared in `header.version` (for example `aip/0.1`).
6
- - New major protocol versions must not silently alter canonicalization or signature semantics.
7
- - Backward-incompatible wire or verification changes require a new minor/major protocol tag.
8
-
9
- ## Compatibility rules
10
-
11
- - Patch releases: bug fixes only, no wire-format or canonicalization changes.
12
- - Minor releases: additive changes only (new optional fields/capabilities, no required-field breakage).
13
- - Major releases: allowed to remove or alter semantics with explicit migration documentation.
14
-
15
- ## Signature profile policy
16
-
17
- - Supported profiles are explicitly declared by `signature.alg`.
18
- - Adding a new signature profile is a minor release only if existing profiles continue to verify unchanged.
19
- - Removing a profile requires a major release.
20
-
21
- ## SDK versioning
22
-
23
- - TypeScript, Python, and Rust SDKs follow semver independently.
24
- - Conformance fixture changes require SDK conformance updates in the same release train.
25
-
26
- ## Release evidence requirements
27
-
28
- - Conformance suites (TS/Python/Rust) pass.
29
- - Bench regression checks attached for performance-sensitive changes.
30
- - Migration guide updated for any behavior change that impacts consumers.
Binary file
package/eslint.config.js DELETED
@@ -1,15 +0,0 @@
1
- import js from '@eslint/js'
2
- import globals from 'globals'
3
- import tseslint from 'typescript-eslint'
4
-
5
- export default tseslint.config(
6
- { ignores: ['dist', 'node_modules', 'sdk/rust/target'] },
7
- {
8
- extends: [js.configs.recommended, ...tseslint.configs.recommended],
9
- files: ['**/*.ts'],
10
- languageOptions: {
11
- ecmaVersion: 2022,
12
- globals: { ...globals.node, ...globals.browser },
13
- },
14
- },
15
- )
@@ -1,136 +0,0 @@
1
- /**
2
- * Fuzz harness: wire decoder resilience.
3
- *
4
- * Invariant: decodeEnvelope must NEVER throw on any input — arbitrary strings
5
- * and arbitrary bytes both. On garbage it must return {ok: false}.
6
- *
7
- * Strategy: start from the conformance corpus, apply mutations, run N rounds.
8
- */
9
-
10
- import { readFileSync } from 'node:fs'
11
- import { join, dirname } from 'node:path'
12
- import { fileURLToPath } from 'node:url'
13
- import { decodeEnvelope } from '../../src/index.js'
14
-
15
- const __dir = dirname(fileURLToPath(import.meta.url))
16
- const VECTORS_PATH = join(__dir, '../../conformance/7h3_v0_1.json')
17
- const ROUNDS = parseInt(process.env.FUZZ_ROUNDS ?? '50000', 10)
18
-
19
- const { vectors, ed25519Vectors = [] } = JSON.parse(readFileSync(VECTORS_PATH, 'utf-8'))
20
-
21
- // --- corpus: valid JSON and compact encodings from conformance vectors ---
22
- const corpus: (string | Uint8Array)[] = []
23
- for (const v of [...vectors, ...ed25519Vectors]) {
24
- const env = v.envelope
25
- corpus.push(JSON.stringify(env))
26
- // compact encoding
27
- corpus.push(
28
- JSON.stringify({
29
- v: env.header?.version,
30
- mid: env.header?.messageId,
31
- ts: env.header?.timestampMs,
32
- ttl: env.header?.ttlMs,
33
- s: env.header?.sender,
34
- n: env.header?.nonce,
35
- i: env.body?.intent,
36
- c: env.body?.content,
37
- }),
38
- )
39
- }
40
- // seed with known-bad corpus
41
- corpus.push('', '{}', '[]', 'null', '"string"', '{', '{"header":{}}', '{"header":{},"body":{}}')
42
-
43
- // --- mutators ---
44
- type Mutator = (input: string, rand: () => number) => string
45
-
46
- const mutators: Mutator[] = [
47
- // bit flip a byte
48
- (s, r) => {
49
- const buf = Buffer.from(s, 'utf-8')
50
- if (!buf.length) return s
51
- buf[Math.floor(r() * buf.length)] ^= 1 << Math.floor(r() * 8)
52
- return buf.toString('utf-8')
53
- },
54
- // insert random byte
55
- (s, r) => {
56
- const buf = Buffer.from(s, 'utf-8')
57
- const idx = Math.floor(r() * (buf.length + 1))
58
- const b = Math.floor(r() * 256)
59
- return Buffer.concat([buf.subarray(0, idx), Buffer.from([b]), buf.subarray(idx)]).toString('utf-8')
60
- },
61
- // delete a byte
62
- (s, r) => {
63
- const buf = Buffer.from(s, 'utf-8')
64
- if (!buf.length) return s
65
- const idx = Math.floor(r() * buf.length)
66
- return Buffer.concat([buf.subarray(0, idx), buf.subarray(idx + 1)]).toString('utf-8')
67
- },
68
- // truncate
69
- (s, r) => {
70
- const buf = Buffer.from(s, 'utf-8')
71
- return buf.subarray(0, Math.floor(r() * buf.length)).toString('utf-8')
72
- },
73
- // mutate a JSON field
74
- (s, r) => {
75
- try {
76
- const obj = JSON.parse(s) as Record<string, unknown>
77
- const keys = Object.keys(obj)
78
- if (!keys.length) return s
79
- const key = keys[Math.floor(r() * keys.length)]
80
- const replacement = [null, 0, 1, -1, '', [], {}, true, false][Math.floor(r() * 9)]
81
- obj[key] = replacement
82
- return JSON.stringify(obj)
83
- } catch {
84
- return s
85
- }
86
- },
87
- // replace a known token with another
88
- (s, r) => {
89
- const tokens = ['7h3/0.1', 'TASK', 'PING', 'RESULT', 'HS256', 'ED25519', '"sender"', '"body"']
90
- const replacements = ['aip/0.2', 'INVALID', '', '0', 'NONE', 'RSA', '"SENDER"', '"Body"']
91
- const i = Math.floor(r() * tokens.length)
92
- return s.split(tokens[i]).join(replacements[i])
93
- },
94
- ]
95
-
96
- // --- runner ---
97
- let crashes = 0
98
- let okFalse = 0
99
- let okTrue = 0
100
-
101
- function rand(): number {
102
- return Math.random()
103
- }
104
-
105
- let current = corpus[0] as string
106
-
107
- for (let i = 0; i < ROUNDS; i++) {
108
- // pick a mutator and apply it
109
- const mutator = mutators[Math.floor(rand() * mutators.length)]
110
- current = mutator(current, rand)
111
-
112
- // occasionally reset to a fresh corpus item
113
- if (i % 500 === 0) {
114
- current = corpus[Math.floor(rand() * corpus.length)] as string
115
- }
116
-
117
- try {
118
- const result = decodeEnvelope(current)
119
- if (result.ok) {
120
- okTrue++
121
- } else {
122
- okFalse++
123
- }
124
- } catch (err) {
125
- crashes++
126
- console.error(`\nCRASH at round ${i}:`)
127
- console.error(' Input (first 200 chars):', JSON.stringify(current.slice(0, 200)))
128
- console.error(' Error:', err)
129
- }
130
- }
131
-
132
- console.log(`[harness-decode] rounds=${ROUNDS} ok=${okTrue} ok:false=${okFalse} crashes=${crashes}`)
133
- if (crashes > 0) {
134
- console.error(`FAIL: ${crashes} crash(es) detected`)
135
- process.exit(1)
136
- }
@@ -1,121 +0,0 @@
1
- /**
2
- * Fuzz harness: signature verification with tampered envelopes.
3
- *
4
- * Invariants:
5
- * 1. verifyEnvelopeHmac must NEVER throw — tampered or malformed envelopes
6
- * must return false, not crash.
7
- * 2. A valid envelope always verifies as true (regression check).
8
- * 3. Single-byte tampering of any signed field must make verification fail.
9
- *
10
- * Strategy: start from valid signed envelopes, apply structural and byte mutations.
11
- */
12
-
13
- import { readFileSync } from 'node:fs'
14
- import { join, dirname } from 'node:path'
15
- import { fileURLToPath } from 'node:url'
16
- import { createEnvelope, signEnvelopeHmac, verifyEnvelopeHmac } from '../../src/index.js'
17
-
18
- const __dir = dirname(fileURLToPath(import.meta.url))
19
- const VECTORS_PATH = join(__dir, '../../conformance/7h3_v0_1.json')
20
- const ROUNDS = parseInt(process.env.FUZZ_ROUNDS ?? '20000', 10)
21
-
22
- const { vectors } = JSON.parse(readFileSync(VECTORS_PATH, 'utf-8'))
23
-
24
- const SECRET = vectors[0].secret as string
25
-
26
- // Build and sign a fresh envelope so we have a known-valid baseline
27
- const BASE_ENVELOPE = await signEnvelopeHmac(
28
- createEnvelope({ sender: 'fuzzer', recipient: 'target', intent: 'TASK', content: 'baseline' }),
29
- SECRET,
30
- )
31
-
32
- // Regression: valid envelope must verify
33
- const baseOk = await verifyEnvelopeHmac(BASE_ENVELOPE, SECRET)
34
- if (!baseOk) {
35
- console.error('FAIL: baseline verification returned false — test setup error')
36
- process.exit(1)
37
- }
38
-
39
- // --- corpus of tampered envelopes ---
40
- function deepClone<T>(x: T): T {
41
- return JSON.parse(JSON.stringify(x)) as T
42
- }
43
-
44
- type Env = typeof BASE_ENVELOPE
45
-
46
- async function tamper(env: Env, rand: () => number): Promise<Env> {
47
- const e = deepClone(env)
48
- const target = rand() < 0.5 ? 'header' : 'body'
49
- const obj = e[target] as unknown as Record<string, unknown>
50
- const keys = Object.keys(obj)
51
- const key = keys[Math.floor(rand() * keys.length)]
52
- const v = obj[key]
53
- // Mutate the value
54
- if (typeof v === 'string') {
55
- if (v.length === 0) {
56
- obj[key] = 'mutated'
57
- } else {
58
- const buf = Buffer.from(v, 'utf-8')
59
- const idx = Math.floor(rand() * buf.length)
60
- buf[idx] ^= 1 << Math.floor(rand() * 8)
61
- obj[key] = buf.toString('utf-8')
62
- }
63
- } else if (typeof v === 'number') {
64
- // Ensure delta is non-zero: map [0, 999] → [-500, -1] ∪ [1, 500]
65
- const raw = Math.floor(rand() * 1000)
66
- const delta = raw < 500 ? raw - 500 : raw - 499 // skips 0
67
- obj[key] = v + delta
68
- } else {
69
- obj[key] = null
70
- }
71
-
72
- // Guard: if the mutation produced no net change (e.g. bit flip round-tripped
73
- // through invalid UTF-8 to the same replacement character), force a known change.
74
- if (JSON.stringify(e) === JSON.stringify(env)) {
75
- const guard = e.body as unknown as Record<string, unknown>
76
- guard['content'] = '__forced_tamper__'
77
- }
78
-
79
- return e
80
- }
81
-
82
- // --- runner ---
83
- let crashes = 0
84
- let tamperFalsePositive = 0
85
-
86
- for (let i = 0; i < ROUNDS; i++) {
87
- const rand = () => Math.random()
88
- const tampered = await tamper(BASE_ENVELOPE, rand)
89
-
90
- try {
91
- const result = await verifyEnvelopeHmac(tampered, SECRET)
92
- if (result === true) {
93
- tamperFalsePositive++
94
- console.error(`\nFAIL false positive at round ${i} — tampered envelope verified as ok`)
95
- console.error(' Tampered:', JSON.stringify(tampered).slice(0, 300))
96
- }
97
- } catch (err) {
98
- crashes++
99
- console.error(`\nCRASH at round ${i}:`)
100
- console.error(' Input:', JSON.stringify(tampered).slice(0, 300))
101
- console.error(' Error:', err)
102
- }
103
-
104
- // Occasionally test with a structurally broken envelope (missing fields)
105
- if (i % 200 === 0) {
106
- const broken = { header: {}, body: {}, signature: BASE_ENVELOPE.signature } as unknown as Env
107
- try {
108
- await verifyEnvelopeHmac(broken, SECRET)
109
- } catch (err) {
110
- crashes++
111
- console.error(`\nCRASH (broken envelope) at round ${i}:`, err)
112
- }
113
- }
114
- }
115
-
116
- console.log(
117
- `[harness-verify] rounds=${ROUNDS} tamper-false-positives=${tamperFalsePositive} crashes=${crashes}`,
118
- )
119
- if (crashes > 0 || tamperFalsePositive > 0) {
120
- process.exit(1)
121
- }
package/fuzz/ts/run.ts DELETED
@@ -1,35 +0,0 @@
1
- /**
2
- * Fuzz campaign runner — executes all TypeScript harnesses in sequence.
3
- *
4
- * Usage:
5
- * npm run fuzz:ts # default 50k/20k rounds
6
- * FUZZ_ROUNDS=200000 npm run fuzz:ts
7
- */
8
-
9
- import { spawnSync } from 'node:child_process'
10
- import { dirname, join } from 'node:path'
11
- import { fileURLToPath } from 'node:url'
12
-
13
- const __dir = dirname(fileURLToPath(import.meta.url))
14
-
15
- const HARNESSES = ['harness-decode.ts', 'harness-verify.ts']
16
-
17
- let failed = false
18
- for (const harness of HARNESSES) {
19
- process.stdout.write(`Running ${harness} ... `)
20
- const result = spawnSync('npx', ['tsx', join(__dir, harness)], {
21
- stdio: ['ignore', 'pipe', 'pipe'],
22
- env: { ...process.env },
23
- })
24
- const out = result.stdout.toString().trim()
25
- const err = result.stderr.toString().trim()
26
- if (result.status !== 0) {
27
- console.error(`FAIL\n${out}\n${err}`)
28
- failed = true
29
- } else {
30
- console.log(`PASS ${out}`)
31
- if (err) console.error(err)
32
- }
33
- }
34
-
35
- process.exit(failed ? 1 : 0)
@@ -1,38 +0,0 @@
1
- # @7h3/protocol-mcp
2
-
3
- MCP server for [@7h3/protocol](https://github.com/IceMasterT/7h3-protocol-aip) — install into Claude to generate AIP secrets, keypairs, and server boilerplate.
4
-
5
- ## Install into Claude Code
6
-
7
- ```bash
8
- claude mcp add aip -- npx @7h3/protocol-mcp
9
- ```
10
-
11
- ## Install into Claude Desktop
12
-
13
- Add to your `claude_desktop_config.json`:
14
-
15
- ```json
16
- {
17
- "mcpServers": {
18
- "aip": {
19
- "command": "npx",
20
- "args": ["@7h3/protocol-mcp"]
21
- }
22
- }
23
- }
24
- ```
25
-
26
- ## Tools
27
-
28
- | Tool | What it does |
29
- |---|---|
30
- | `aip_generate_secret` | Generates a 32-byte HMAC secret — store as `AIP_SECRET` |
31
- | `aip_generate_keypair` | Generates an Ed25519 keypair — store keys as env vars |
32
- | `aip_wrap_mcp_server` | Outputs ready-to-paste boilerplate for your MCP server |
33
- | `aip_sign` | Signs a test envelope (debugging / fixture generation) |
34
- | `aip_verify` | Verifies an envelope signature and shape |
35
-
36
- ## License
37
-
38
- MIT