@suveren/gateway 0.2.11 → 0.3.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.
Files changed (170) hide show
  1. package/README.md +21 -7
  2. package/dist/control-plane/index.mjs +146 -2
  3. package/dist/mcp-server/http.mjs +80 -38
  4. package/dist/ui/assets/index-RkZBhIxU.js +105 -0
  5. package/dist/ui/index.html +1 -1
  6. package/node_modules/@hap/core/dist/index.d.mts +147 -3
  7. package/node_modules/@hap/core/dist/index.d.ts +147 -3
  8. package/node_modules/@hap/core/dist/index.js +74 -10
  9. package/node_modules/@hap/core/dist/index.mjs +69 -10
  10. package/node_modules/@hap/core/package.json +1 -1
  11. package/node_modules/@hap/core/src/gatekeeper.ts +4 -4
  12. package/node_modules/@hap/core/src/identity.ts +77 -0
  13. package/node_modules/@hap/core/src/index.ts +2 -0
  14. package/node_modules/@hap/core/src/intent-disclosure.ts +69 -0
  15. package/node_modules/@hap/core/src/types.ts +62 -2
  16. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/README.md +16 -1
  17. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/index.js +4 -20
  18. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/lib/read.js +17 -17
  19. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/lib/types/json.js +60 -32
  20. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/lib/types/raw.js +3 -3
  21. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/lib/types/text.js +3 -3
  22. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/lib/types/urlencoded.js +16 -20
  23. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/lib/utils.js +18 -16
  24. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/LICENSE +22 -0
  25. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/README.md +69 -0
  26. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +26 -0
  27. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/dist/index.js +170 -0
  28. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -0
  29. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/node_modules/content-type/package.json +52 -0
  30. package/node_modules/@modelcontextprotocol/sdk/node_modules/body-parser/package.json +23 -10
  31. package/node_modules/@types/node/README.md +1 -1
  32. package/node_modules/@types/node/assert/strict.d.ts +10 -1
  33. package/node_modules/@types/node/assert.d.ts +144 -17
  34. package/node_modules/@types/node/async_hooks.d.ts +9 -9
  35. package/node_modules/@types/node/buffer.d.ts +0 -5
  36. package/node_modules/@types/node/child_process.d.ts +17 -21
  37. package/node_modules/@types/node/cluster.d.ts +13 -13
  38. package/node_modules/@types/node/console.d.ts +1 -1
  39. package/node_modules/@types/node/crypto.d.ts +454 -571
  40. package/node_modules/@types/node/diagnostics_channel.d.ts +37 -29
  41. package/node_modules/@types/node/dns.d.ts +14 -14
  42. package/node_modules/@types/node/events.d.ts +3 -3
  43. package/node_modules/@types/node/fs/promises.d.ts +4 -4
  44. package/node_modules/@types/node/fs.d.ts +3 -12
  45. package/node_modules/@types/node/globals.d.ts +4 -4
  46. package/node_modules/@types/node/http.d.ts +5 -5
  47. package/node_modules/@types/node/http2.d.ts +5 -1
  48. package/node_modules/@types/node/index.d.ts +0 -3
  49. package/node_modules/@types/node/inspector.d.ts +1 -1
  50. package/node_modules/@types/node/module.d.ts +16 -45
  51. package/node_modules/@types/node/net.d.ts +1 -1
  52. package/node_modules/@types/node/os.d.ts +2 -2
  53. package/node_modules/@types/node/package.json +4 -4
  54. package/node_modules/@types/node/perf_hooks.d.ts +1 -9
  55. package/node_modules/@types/node/process.d.ts +11 -11
  56. package/node_modules/@types/node/readline.d.ts +12 -11
  57. package/node_modules/@types/node/repl.d.ts +10 -10
  58. package/node_modules/@types/node/sqlite.d.ts +1 -1
  59. package/node_modules/@types/node/stream/promises.d.ts +2 -2
  60. package/node_modules/@types/node/stream/web.d.ts +1 -1
  61. package/node_modules/@types/node/stream.d.ts +5 -5
  62. package/node_modules/@types/node/test/reporters.d.ts +1 -1
  63. package/node_modules/@types/node/test.d.ts +8 -8
  64. package/node_modules/@types/node/tls.d.ts +1 -1
  65. package/node_modules/@types/node/ts5.6/index.d.ts +1 -4
  66. package/node_modules/@types/node/ts5.7/index.d.ts +0 -3
  67. package/node_modules/@types/node/url.d.ts +3 -3
  68. package/node_modules/@types/node/util/types.d.ts +1 -1
  69. package/node_modules/@types/node/util.d.ts +3 -20
  70. package/node_modules/@types/node/v8.d.ts +1 -1
  71. package/node_modules/@types/node/vm.d.ts +9 -9
  72. package/node_modules/@types/node/web-globals/domexception.d.ts +15 -0
  73. package/node_modules/@types/node/worker_threads.d.ts +2 -5
  74. package/node_modules/@types/node/zlib.d.ts +3 -3
  75. package/node_modules/fast-uri/index.js +1 -1
  76. package/node_modules/fast-uri/package.json +1 -1
  77. package/node_modules/fast-uri/test/security.test.js +28 -0
  78. package/node_modules/hono/dist/adapter/aws-lambda/handler.js +14 -20
  79. package/node_modules/hono/dist/adapter/lambda-edge/handler.js +8 -2
  80. package/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +14 -20
  81. package/node_modules/hono/dist/cjs/adapter/lambda-edge/handler.js +8 -2
  82. package/node_modules/hono/dist/cjs/helper/css/common.js +3 -1
  83. package/node_modules/hono/dist/cjs/helper/css/index.js +9 -1
  84. package/node_modules/hono/dist/cjs/jsx/base.js +8 -14
  85. package/node_modules/hono/dist/cjs/jsx/components.js +41 -21
  86. package/node_modules/hono/dist/cjs/jsx/context.js +131 -5
  87. package/node_modules/hono/dist/cjs/jsx/streaming.js +9 -7
  88. package/node_modules/hono/dist/cjs/middleware/bearer-auth/index.js +1 -1
  89. package/node_modules/hono/dist/cjs/middleware/cors/index.js +2 -5
  90. package/node_modules/hono/dist/cjs/middleware/language/language.js +10 -32
  91. package/node_modules/hono/dist/cjs/middleware/serve-static/index.js +1 -1
  92. package/node_modules/hono/dist/cjs/middleware/timing/timing.js +3 -1
  93. package/node_modules/hono/dist/cjs/utils/ipaddr.js +6 -1
  94. package/node_modules/hono/dist/helper/css/common.js +3 -1
  95. package/node_modules/hono/dist/helper/css/index.js +9 -1
  96. package/node_modules/hono/dist/jsx/base.js +15 -15
  97. package/node_modules/hono/dist/jsx/components.js +42 -22
  98. package/node_modules/hono/dist/jsx/context.js +129 -5
  99. package/node_modules/hono/dist/jsx/streaming.js +10 -8
  100. package/node_modules/hono/dist/middleware/bearer-auth/index.js +1 -1
  101. package/node_modules/hono/dist/middleware/cors/index.js +2 -5
  102. package/node_modules/hono/dist/middleware/language/language.js +10 -32
  103. package/node_modules/hono/dist/middleware/serve-static/index.js +1 -1
  104. package/node_modules/hono/dist/middleware/timing/timing.js +3 -1
  105. package/node_modules/hono/dist/tsconfig.build.tsbuildinfo +1 -1
  106. package/node_modules/hono/dist/types/adapter/aws-lambda/handler.d.ts +1 -1
  107. package/node_modules/hono/dist/types/jsx/base.d.ts +1 -3
  108. package/node_modules/hono/dist/types/jsx/context.d.ts +39 -0
  109. package/node_modules/hono/dist/utils/ipaddr.js +6 -1
  110. package/node_modules/hono/package.json +19 -13
  111. package/node_modules/http-proxy-middleware/README.md +3 -10
  112. package/node_modules/http-proxy-middleware/dist/errors.d.ts +4 -0
  113. package/node_modules/http-proxy-middleware/dist/errors.js +16 -1
  114. package/node_modules/http-proxy-middleware/dist/factory.d.ts +2 -2
  115. package/node_modules/http-proxy-middleware/dist/handlers/fix-request-body-utils/stringify-form-data.d.ts +7 -0
  116. package/node_modules/http-proxy-middleware/dist/handlers/fix-request-body-utils/stringify-form-data.js +45 -0
  117. package/node_modules/http-proxy-middleware/dist/handlers/fix-request-body.d.ts +1 -1
  118. package/node_modules/http-proxy-middleware/dist/handlers/fix-request-body.js +23 -23
  119. package/node_modules/http-proxy-middleware/dist/handlers/response-interceptor.d.ts +1 -1
  120. package/node_modules/http-proxy-middleware/dist/handlers/response-interceptor.js +1 -1
  121. package/node_modules/http-proxy-middleware/dist/http-proxy-middleware.d.ts +1 -1
  122. package/node_modules/http-proxy-middleware/dist/http-proxy-middleware.js +2 -2
  123. package/node_modules/http-proxy-middleware/dist/legacy/create-proxy-middleware.d.ts +1 -1
  124. package/node_modules/http-proxy-middleware/dist/legacy/create-proxy-middleware.js +1 -1
  125. package/node_modules/http-proxy-middleware/dist/legacy/options-adapter.js +1 -1
  126. package/node_modules/http-proxy-middleware/dist/legacy/types.d.ts +1 -1
  127. package/node_modules/http-proxy-middleware/dist/path-filter.d.ts +1 -1
  128. package/node_modules/http-proxy-middleware/dist/path-filter.js +1 -1
  129. package/node_modules/http-proxy-middleware/dist/path-rewriter.js +1 -1
  130. package/node_modules/http-proxy-middleware/dist/plugins/default/error-response-plugin.js +2 -1
  131. package/node_modules/http-proxy-middleware/dist/plugins/default/logger-plugin.js +3 -3
  132. package/node_modules/http-proxy-middleware/dist/router.js +26 -8
  133. package/node_modules/http-proxy-middleware/dist/status-code.js +15 -12
  134. package/node_modules/http-proxy-middleware/dist/types.d.ts +3 -3
  135. package/node_modules/http-proxy-middleware/dist/types.js +0 -4
  136. package/node_modules/http-proxy-middleware/dist/utils/sanitize.d.ts +1 -0
  137. package/node_modules/http-proxy-middleware/dist/utils/sanitize.js +6 -0
  138. package/node_modules/http-proxy-middleware/package.json +30 -28
  139. package/node_modules/qs/CHANGELOG.md +11 -0
  140. package/node_modules/qs/dist/qs.js +17 -17
  141. package/node_modules/qs/lib/parse.js +19 -8
  142. package/node_modules/qs/lib/utils.js +47 -8
  143. package/node_modules/qs/package.json +6 -5
  144. package/node_modules/qs/test/parse.js +230 -0
  145. package/node_modules/qs/test/utils.js +194 -0
  146. package/node_modules/side-channel/CHANGELOG.md +10 -0
  147. package/node_modules/side-channel/README.md +1 -1
  148. package/node_modules/side-channel/index.js +5 -2
  149. package/node_modules/side-channel/package.json +10 -10
  150. package/node_modules/side-channel/test/index.js +16 -0
  151. package/node_modules/undici-types/agent.d.ts +0 -2
  152. package/node_modules/undici-types/client.d.ts +25 -19
  153. package/node_modules/undici-types/dispatcher.d.ts +7 -33
  154. package/node_modules/undici-types/dispatcher1-wrapper.d.ts +7 -0
  155. package/node_modules/undici-types/fetch.d.ts +24 -4
  156. package/node_modules/undici-types/h2c-client.d.ts +6 -6
  157. package/node_modules/undici-types/handlers.d.ts +1 -2
  158. package/node_modules/undici-types/header.d.ts +5 -0
  159. package/node_modules/undici-types/index.d.ts +3 -1
  160. package/node_modules/undici-types/interceptors.d.ts +1 -1
  161. package/node_modules/undici-types/package.json +1 -1
  162. package/node_modules/undici-types/pool.d.ts +0 -2
  163. package/node_modules/undici-types/proxy-agent.d.ts +2 -2
  164. package/node_modules/undici-types/round-robin-pool.d.ts +0 -2
  165. package/node_modules/undici-types/snapshot-agent.d.ts +4 -0
  166. package/node_modules/undici-types/socks5-proxy-agent.d.ts +2 -2
  167. package/node_modules/undici-types/webidl.d.ts +0 -1
  168. package/package.json +3 -3
  169. package/dist/ui/assets/index-D3srGi9r.js +0 -102
  170. package/node_modules/@types/node/compatibility/iterators.d.ts +0 -21
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Suveren</title>
7
- <script type="module" crossorigin src="/assets/index-D3srGi9r.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-RkZBhIxU.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/index-BUgn3e63.css">
9
9
  </head>
10
10
  <body>
@@ -14,7 +14,7 @@ interface ResolvedDomain {
14
14
  }
15
15
  interface AttestationPayload {
16
16
  attestation_id: string;
17
- version: '0.3' | '0.4';
17
+ version: '0.3' | '0.4' | '0.5';
18
18
  profile_id: string;
19
19
  /** v0.3 (deprecated) — hash of the authorization frame */
20
20
  frame_hash?: string;
@@ -23,8 +23,37 @@ interface AttestationPayload {
23
23
  /** v0.4 — hash of the context parameters */
24
24
  context_hash?: string;
25
25
  execution_context_hash: string;
26
- resolved_domains: ResolvedDomain[];
26
+ /**
27
+ * v0.4 (deprecated in v0.5) — domain-scoped owners. Optional so v0.5
28
+ * attestations that carry only `resolved_owners` remain valid. During the
29
+ * transition the AS emits BOTH `resolved_domains` (internal coverage) and
30
+ * `resolved_owners` (the v0.5 signed wire field).
31
+ */
32
+ resolved_domains?: ResolvedDomain[];
33
+ /**
34
+ * v0.5 — the Decision Owner DIDs this attestation covers (person-centric
35
+ * model; replaces the abstract domain in `resolved_domains`). Carried in the
36
+ * signed payload so verifiers bind the action to the human(s) who authorized it.
37
+ */
38
+ resolved_owners?: string[];
27
39
  gate_content_hashes: Record<string, string>;
40
+ /**
41
+ * v0.5 (companion spec `intent-disclosure@0.1`) — present iff the attestation
42
+ * carries an encrypted-intent disclosure object. `sha256:`-prefixed hash that
43
+ * binds the disclosure's `intent_ciphertext` + `approvers_frozen` into the
44
+ * signed payload (see {@link computeIntentDisclosureHash}), so a compromised
45
+ * AS cannot swap the ciphertext/wrapped keys or alter the approver set
46
+ * without invalidating the attestation signature (companion invariant C2).
47
+ */
48
+ intent_disclosure_hash?: string;
49
+ /**
50
+ * v0.6 (Identity Assurance) — optional signed overlay carrying the verified
51
+ * real-world identity of the Decision Owner(s), one entry per owner. Present
52
+ * only when identity is disclosed; an attestation with no `subjects` renders
53
+ * as `low` (pseudonymous, no name). See {@link Subject} and
54
+ * {@link deriveIdentityLine}.
55
+ */
56
+ subjects?: Subject[];
28
57
  /**
29
58
  * v0.4 — commitment mode chosen by the decision owner at attestation time.
30
59
  * - 'automatic': agent may invoke bounded tools without per-action review.
@@ -38,6 +67,38 @@ interface AttestationPayload {
38
67
  issued_at: number;
39
68
  expires_at: number;
40
69
  }
70
+ /**
71
+ * v0.6 Identity Assurance — a signed overlay binding a Decision Owner's verified
72
+ * real-world identity to the attestation, gated by HOW the identity was verified.
73
+ *
74
+ * Two display levels (`assurance`): `low` discloses no name; `high` MAY disclose a
75
+ * name. At `high`, two trust roots: `as` (the AS operator vouches — valid only
76
+ * within its own domain) and `external` (an external eID such as EUDI — carries the
77
+ * owner's own signature, AS-independent). See review.md → "Identity Assurance".
78
+ */
79
+ interface Subject {
80
+ /** The Decision Owner DID this subject describes (matches an entry in resolved_owners). */
81
+ did: string;
82
+ /** `low` → no name shown; `high` → the name MAY be shown. */
83
+ assurance: 'low' | 'high';
84
+ /** How identity was established. */
85
+ method: 'self_declared' | 'as_vouched' | 'eudi';
86
+ /** Who vouches: `self` (owner's claim), `as` (operator), `external` (eID scheme). */
87
+ trust_root: 'self' | 'as' | 'external';
88
+ /** Verifier id — the AS operator (as_vouched) or the eID scheme (eudi). Required at `high`. */
89
+ verifier?: string;
90
+ /** Disclosed attributes. `name` present ONLY at `assurance:"high"` and when disclosure is on. */
91
+ disclose?: {
92
+ name: string;
93
+ };
94
+ /** When the underlying verification was performed (unix seconds). */
95
+ verified_at?: number;
96
+ /**
97
+ * eudi only (Phase 2) — the owner's per-event wallet signature, making the
98
+ * identity claim non-repudiable independent of the AS. Null/absent otherwise.
99
+ */
100
+ owner_signature?: string | null;
101
+ }
41
102
  interface Attestation {
42
103
  header: AttestationHeader;
43
104
  payload: AttestationPayload;
@@ -518,6 +579,89 @@ declare function contentCanonicalBytes(kind: ContentBinding['kind'], content: Re
518
579
  */
519
580
  declare function computeContentHash(binding: ContentBinding, content: Record<string, unknown> | string): string;
520
581
 
582
+ /**
583
+ * Intent hashing + intent-disclosure binding (HAP v0.5).
584
+ *
585
+ * Two shared, environment-independent hashes that the attester (gateway), the
586
+ * Authority Server, and any approver MUST compute identically:
587
+ *
588
+ * 1. {@link computeIntentHash} — `gate_content_hashes.intent`. The intent text
589
+ * is canonicalized (Unicode NFC, LF line endings, trailing-whitespace strip
590
+ * — the same rule as content-binding's `canonicalizeText`) before hashing,
591
+ * so independent multi-owner approvers reproduce an identical hash from the
592
+ * same logical statement. See protocol.md → "Intent canonicalization".
593
+ *
594
+ * 2. {@link computeIntentDisclosureHash} — `intent_disclosure_hash`, the C2
595
+ * binding from companion spec `intent-disclosure@0.1`. It commits the
596
+ * encrypted disclosure object (`intent_ciphertext` + `approvers_frozen`)
597
+ * into the SIGNED attestation payload, so a compromised AS cannot swap the
598
+ * ciphertext/wrapped keys or widen/shrink the approver set without breaking
599
+ * the attestation signature.
600
+ *
601
+ * Both produce `sha256:<hex>` to match the frame/bounds/context hash format.
602
+ */
603
+ /**
604
+ * `gate_content_hashes.intent` for an intent statement.
605
+ * Canonicalizes the text (NFC / LF / trailing-whitespace strip) before hashing.
606
+ */
607
+ declare function computeIntentHash(intentText: string): string;
608
+ /**
609
+ * The exact bytes `intent_disclosure_hash` is taken over, WITHOUT hashing —
610
+ * exposed so an implementer debugging a mismatch can inspect the serialization
611
+ * both sides must agree on:
612
+ *
613
+ * intent_ciphertext ‖ "\n" ‖ JCS(sort(approvers_frozen))
614
+ *
615
+ * where `intent_ciphertext` is the exact base64url string of the disclosure
616
+ * object, `sort` orders the approver DIDs by Unicode code point, and `JCS` is
617
+ * RFC 8785 canonicalization of the sorted array (via {@link canonicalize}).
618
+ */
619
+ declare function intentDisclosureCanonicalBytes(intentCiphertext: string, approversFrozen: string[]): string;
620
+ /**
621
+ * `intent_disclosure_hash` — `sha256:<hex>` over
622
+ * {@link intentDisclosureCanonicalBytes}. Computed by the attester after
623
+ * encryption and signed into the attestation; recomputed by the AS (at
624
+ * issuance) and by each approver (on receipt) and compared, fail-closed.
625
+ */
626
+ declare function computeIntentDisclosureHash(intentCiphertext: string, approversFrozen: string[]): string;
627
+
628
+ /**
629
+ * Identity Assurance (HAP v0.6) — validation + footer derivation for the signed
630
+ * {@link Subject} overlay. See review.md → "Identity Assurance".
631
+ *
632
+ * Two pure helpers, the single source of truth for both the gateway footer and
633
+ * the AS verify page:
634
+ * - {@link validateSubject} — enforces the level/method/trust-root invariants.
635
+ * - {@link deriveIdentityLine} — the human-readable footer line for a subject.
636
+ */
637
+
638
+ interface SubjectValidation {
639
+ valid: boolean;
640
+ errors: string[];
641
+ }
642
+ /**
643
+ * Enforce the Identity-Assurance invariants on a single subject:
644
+ * - `self_declared` ⇒ `low` / `self`, no disclosed name.
645
+ * - `as_vouched` ⇒ `high` / `as`, `verifier` required.
646
+ * - `eudi` ⇒ `high` / `external`, `verifier` + `owner_signature` required.
647
+ * - `disclose.name` only at `assurance:"high"`.
648
+ */
649
+ declare function validateSubject(subject: Subject): SubjectValidation;
650
+ /**
651
+ * The footer line for a subject — the ONE place this wording lives.
652
+ * The name appears only at `high` with a disclosed name; otherwise no name.
653
+ *
654
+ * - low / no disclosure → "Sent by an AI agent via «operator»"
655
+ * - high / as_vouched → "Sent by an AI agent of «name» — verified by «operator»"
656
+ * - high / eudi → "Sent by an AI agent of «name» — identity verified (EUDI)"
657
+ *
658
+ * `operatorName` is the rendered AS operator (e.g. "Suveren") — never hardcode it
659
+ * upstream; a different operator self-vouches under its own name.
660
+ */
661
+ declare function deriveIdentityLine(subject: Subject | undefined | null, { operatorName }: {
662
+ operatorName: string;
663
+ }): string;
664
+
521
665
  /**
522
666
  * Frame Canonicalization for Agent Profiles
523
667
  *
@@ -715,4 +859,4 @@ declare function listProfiles(): string[];
715
859
  declare function getAllProfiles(): AgentProfile[];
716
860
  declare function clearProfiles(): void;
717
861
 
718
- export { type AgentBoundsParams, type AgentContextParams, type AgentFrameParams, type AgentProfile, type Attestation, type AttestationHeader, type AttestationPayload, type BoundType, type ContentBinding, type CumulativeFieldDef, type CumulativeWindow, type DeclaredFieldDef, type ExecutionContextFieldDef, type ExecutionLogEntry, type ExecutionLogQuery, type ExecutionMappingTransform, type ExecutionMappingValue, type ExecutionPath, type FieldConstraint, type FieldUnit, type GateQuestion, type GatekeeperError, type GatekeeperRequest, type GatekeeperResult, type ProfileBoundsField, type ProfileContextField, type ProfileFrameField, type ProfileToolGating, type ProfileToolGatingEntry, type ResolvedDomain, attestationId, canonicalBounds, canonicalContext, canonicalFrame, canonicalize, canonicalizeText, checkAttestationExpiry, clearProfiles, computeBoundsHash, computeContentHash, computeContextHash, computeFrameHash, contentCanonicalBytes, decodeAttestationBlob, encodeAttestationBlob, frameHash, getAllProfiles, getProfile, isV4Attestation, listProfiles, registerProfile, validateBoundsParams, validateContextParams, validateFrameParams, verify, verifyAttestation, verifyAttestationSignature, verifyAttestationV4, verifyBoundsHash, verifyContextHash, verifyFrameHash };
862
+ export { type AgentBoundsParams, type AgentContextParams, type AgentFrameParams, type AgentProfile, type Attestation, type AttestationHeader, type AttestationPayload, type BoundType, type ContentBinding, type CumulativeFieldDef, type CumulativeWindow, type DeclaredFieldDef, type ExecutionContextFieldDef, type ExecutionLogEntry, type ExecutionLogQuery, type ExecutionMappingTransform, type ExecutionMappingValue, type ExecutionPath, type FieldConstraint, type FieldUnit, type GateQuestion, type GatekeeperError, type GatekeeperRequest, type GatekeeperResult, type ProfileBoundsField, type ProfileContextField, type ProfileFrameField, type ProfileToolGating, type ProfileToolGatingEntry, type ResolvedDomain, type Subject, type SubjectValidation, attestationId, canonicalBounds, canonicalContext, canonicalFrame, canonicalize, canonicalizeText, checkAttestationExpiry, clearProfiles, computeBoundsHash, computeContentHash, computeContextHash, computeFrameHash, computeIntentDisclosureHash, computeIntentHash, contentCanonicalBytes, decodeAttestationBlob, deriveIdentityLine, encodeAttestationBlob, frameHash, getAllProfiles, getProfile, intentDisclosureCanonicalBytes, isV4Attestation, listProfiles, registerProfile, validateBoundsParams, validateContextParams, validateFrameParams, validateSubject, verify, verifyAttestation, verifyAttestationSignature, verifyAttestationV4, verifyBoundsHash, verifyContextHash, verifyFrameHash };
@@ -14,7 +14,7 @@ interface ResolvedDomain {
14
14
  }
15
15
  interface AttestationPayload {
16
16
  attestation_id: string;
17
- version: '0.3' | '0.4';
17
+ version: '0.3' | '0.4' | '0.5';
18
18
  profile_id: string;
19
19
  /** v0.3 (deprecated) — hash of the authorization frame */
20
20
  frame_hash?: string;
@@ -23,8 +23,37 @@ interface AttestationPayload {
23
23
  /** v0.4 — hash of the context parameters */
24
24
  context_hash?: string;
25
25
  execution_context_hash: string;
26
- resolved_domains: ResolvedDomain[];
26
+ /**
27
+ * v0.4 (deprecated in v0.5) — domain-scoped owners. Optional so v0.5
28
+ * attestations that carry only `resolved_owners` remain valid. During the
29
+ * transition the AS emits BOTH `resolved_domains` (internal coverage) and
30
+ * `resolved_owners` (the v0.5 signed wire field).
31
+ */
32
+ resolved_domains?: ResolvedDomain[];
33
+ /**
34
+ * v0.5 — the Decision Owner DIDs this attestation covers (person-centric
35
+ * model; replaces the abstract domain in `resolved_domains`). Carried in the
36
+ * signed payload so verifiers bind the action to the human(s) who authorized it.
37
+ */
38
+ resolved_owners?: string[];
27
39
  gate_content_hashes: Record<string, string>;
40
+ /**
41
+ * v0.5 (companion spec `intent-disclosure@0.1`) — present iff the attestation
42
+ * carries an encrypted-intent disclosure object. `sha256:`-prefixed hash that
43
+ * binds the disclosure's `intent_ciphertext` + `approvers_frozen` into the
44
+ * signed payload (see {@link computeIntentDisclosureHash}), so a compromised
45
+ * AS cannot swap the ciphertext/wrapped keys or alter the approver set
46
+ * without invalidating the attestation signature (companion invariant C2).
47
+ */
48
+ intent_disclosure_hash?: string;
49
+ /**
50
+ * v0.6 (Identity Assurance) — optional signed overlay carrying the verified
51
+ * real-world identity of the Decision Owner(s), one entry per owner. Present
52
+ * only when identity is disclosed; an attestation with no `subjects` renders
53
+ * as `low` (pseudonymous, no name). See {@link Subject} and
54
+ * {@link deriveIdentityLine}.
55
+ */
56
+ subjects?: Subject[];
28
57
  /**
29
58
  * v0.4 — commitment mode chosen by the decision owner at attestation time.
30
59
  * - 'automatic': agent may invoke bounded tools without per-action review.
@@ -38,6 +67,38 @@ interface AttestationPayload {
38
67
  issued_at: number;
39
68
  expires_at: number;
40
69
  }
70
+ /**
71
+ * v0.6 Identity Assurance — a signed overlay binding a Decision Owner's verified
72
+ * real-world identity to the attestation, gated by HOW the identity was verified.
73
+ *
74
+ * Two display levels (`assurance`): `low` discloses no name; `high` MAY disclose a
75
+ * name. At `high`, two trust roots: `as` (the AS operator vouches — valid only
76
+ * within its own domain) and `external` (an external eID such as EUDI — carries the
77
+ * owner's own signature, AS-independent). See review.md → "Identity Assurance".
78
+ */
79
+ interface Subject {
80
+ /** The Decision Owner DID this subject describes (matches an entry in resolved_owners). */
81
+ did: string;
82
+ /** `low` → no name shown; `high` → the name MAY be shown. */
83
+ assurance: 'low' | 'high';
84
+ /** How identity was established. */
85
+ method: 'self_declared' | 'as_vouched' | 'eudi';
86
+ /** Who vouches: `self` (owner's claim), `as` (operator), `external` (eID scheme). */
87
+ trust_root: 'self' | 'as' | 'external';
88
+ /** Verifier id — the AS operator (as_vouched) or the eID scheme (eudi). Required at `high`. */
89
+ verifier?: string;
90
+ /** Disclosed attributes. `name` present ONLY at `assurance:"high"` and when disclosure is on. */
91
+ disclose?: {
92
+ name: string;
93
+ };
94
+ /** When the underlying verification was performed (unix seconds). */
95
+ verified_at?: number;
96
+ /**
97
+ * eudi only (Phase 2) — the owner's per-event wallet signature, making the
98
+ * identity claim non-repudiable independent of the AS. Null/absent otherwise.
99
+ */
100
+ owner_signature?: string | null;
101
+ }
41
102
  interface Attestation {
42
103
  header: AttestationHeader;
43
104
  payload: AttestationPayload;
@@ -518,6 +579,89 @@ declare function contentCanonicalBytes(kind: ContentBinding['kind'], content: Re
518
579
  */
519
580
  declare function computeContentHash(binding: ContentBinding, content: Record<string, unknown> | string): string;
520
581
 
582
+ /**
583
+ * Intent hashing + intent-disclosure binding (HAP v0.5).
584
+ *
585
+ * Two shared, environment-independent hashes that the attester (gateway), the
586
+ * Authority Server, and any approver MUST compute identically:
587
+ *
588
+ * 1. {@link computeIntentHash} — `gate_content_hashes.intent`. The intent text
589
+ * is canonicalized (Unicode NFC, LF line endings, trailing-whitespace strip
590
+ * — the same rule as content-binding's `canonicalizeText`) before hashing,
591
+ * so independent multi-owner approvers reproduce an identical hash from the
592
+ * same logical statement. See protocol.md → "Intent canonicalization".
593
+ *
594
+ * 2. {@link computeIntentDisclosureHash} — `intent_disclosure_hash`, the C2
595
+ * binding from companion spec `intent-disclosure@0.1`. It commits the
596
+ * encrypted disclosure object (`intent_ciphertext` + `approvers_frozen`)
597
+ * into the SIGNED attestation payload, so a compromised AS cannot swap the
598
+ * ciphertext/wrapped keys or widen/shrink the approver set without breaking
599
+ * the attestation signature.
600
+ *
601
+ * Both produce `sha256:<hex>` to match the frame/bounds/context hash format.
602
+ */
603
+ /**
604
+ * `gate_content_hashes.intent` for an intent statement.
605
+ * Canonicalizes the text (NFC / LF / trailing-whitespace strip) before hashing.
606
+ */
607
+ declare function computeIntentHash(intentText: string): string;
608
+ /**
609
+ * The exact bytes `intent_disclosure_hash` is taken over, WITHOUT hashing —
610
+ * exposed so an implementer debugging a mismatch can inspect the serialization
611
+ * both sides must agree on:
612
+ *
613
+ * intent_ciphertext ‖ "\n" ‖ JCS(sort(approvers_frozen))
614
+ *
615
+ * where `intent_ciphertext` is the exact base64url string of the disclosure
616
+ * object, `sort` orders the approver DIDs by Unicode code point, and `JCS` is
617
+ * RFC 8785 canonicalization of the sorted array (via {@link canonicalize}).
618
+ */
619
+ declare function intentDisclosureCanonicalBytes(intentCiphertext: string, approversFrozen: string[]): string;
620
+ /**
621
+ * `intent_disclosure_hash` — `sha256:<hex>` over
622
+ * {@link intentDisclosureCanonicalBytes}. Computed by the attester after
623
+ * encryption and signed into the attestation; recomputed by the AS (at
624
+ * issuance) and by each approver (on receipt) and compared, fail-closed.
625
+ */
626
+ declare function computeIntentDisclosureHash(intentCiphertext: string, approversFrozen: string[]): string;
627
+
628
+ /**
629
+ * Identity Assurance (HAP v0.6) — validation + footer derivation for the signed
630
+ * {@link Subject} overlay. See review.md → "Identity Assurance".
631
+ *
632
+ * Two pure helpers, the single source of truth for both the gateway footer and
633
+ * the AS verify page:
634
+ * - {@link validateSubject} — enforces the level/method/trust-root invariants.
635
+ * - {@link deriveIdentityLine} — the human-readable footer line for a subject.
636
+ */
637
+
638
+ interface SubjectValidation {
639
+ valid: boolean;
640
+ errors: string[];
641
+ }
642
+ /**
643
+ * Enforce the Identity-Assurance invariants on a single subject:
644
+ * - `self_declared` ⇒ `low` / `self`, no disclosed name.
645
+ * - `as_vouched` ⇒ `high` / `as`, `verifier` required.
646
+ * - `eudi` ⇒ `high` / `external`, `verifier` + `owner_signature` required.
647
+ * - `disclose.name` only at `assurance:"high"`.
648
+ */
649
+ declare function validateSubject(subject: Subject): SubjectValidation;
650
+ /**
651
+ * The footer line for a subject — the ONE place this wording lives.
652
+ * The name appears only at `high` with a disclosed name; otherwise no name.
653
+ *
654
+ * - low / no disclosure → "Sent by an AI agent via «operator»"
655
+ * - high / as_vouched → "Sent by an AI agent of «name» — verified by «operator»"
656
+ * - high / eudi → "Sent by an AI agent of «name» — identity verified (EUDI)"
657
+ *
658
+ * `operatorName` is the rendered AS operator (e.g. "Suveren") — never hardcode it
659
+ * upstream; a different operator self-vouches under its own name.
660
+ */
661
+ declare function deriveIdentityLine(subject: Subject | undefined | null, { operatorName }: {
662
+ operatorName: string;
663
+ }): string;
664
+
521
665
  /**
522
666
  * Frame Canonicalization for Agent Profiles
523
667
  *
@@ -715,4 +859,4 @@ declare function listProfiles(): string[];
715
859
  declare function getAllProfiles(): AgentProfile[];
716
860
  declare function clearProfiles(): void;
717
861
 
718
- export { type AgentBoundsParams, type AgentContextParams, type AgentFrameParams, type AgentProfile, type Attestation, type AttestationHeader, type AttestationPayload, type BoundType, type ContentBinding, type CumulativeFieldDef, type CumulativeWindow, type DeclaredFieldDef, type ExecutionContextFieldDef, type ExecutionLogEntry, type ExecutionLogQuery, type ExecutionMappingTransform, type ExecutionMappingValue, type ExecutionPath, type FieldConstraint, type FieldUnit, type GateQuestion, type GatekeeperError, type GatekeeperRequest, type GatekeeperResult, type ProfileBoundsField, type ProfileContextField, type ProfileFrameField, type ProfileToolGating, type ProfileToolGatingEntry, type ResolvedDomain, attestationId, canonicalBounds, canonicalContext, canonicalFrame, canonicalize, canonicalizeText, checkAttestationExpiry, clearProfiles, computeBoundsHash, computeContentHash, computeContextHash, computeFrameHash, contentCanonicalBytes, decodeAttestationBlob, encodeAttestationBlob, frameHash, getAllProfiles, getProfile, isV4Attestation, listProfiles, registerProfile, validateBoundsParams, validateContextParams, validateFrameParams, verify, verifyAttestation, verifyAttestationSignature, verifyAttestationV4, verifyBoundsHash, verifyContextHash, verifyFrameHash };
862
+ export { type AgentBoundsParams, type AgentContextParams, type AgentFrameParams, type AgentProfile, type Attestation, type AttestationHeader, type AttestationPayload, type BoundType, type ContentBinding, type CumulativeFieldDef, type CumulativeWindow, type DeclaredFieldDef, type ExecutionContextFieldDef, type ExecutionLogEntry, type ExecutionLogQuery, type ExecutionMappingTransform, type ExecutionMappingValue, type ExecutionPath, type FieldConstraint, type FieldUnit, type GateQuestion, type GatekeeperError, type GatekeeperRequest, type GatekeeperResult, type ProfileBoundsField, type ProfileContextField, type ProfileFrameField, type ProfileToolGating, type ProfileToolGatingEntry, type ResolvedDomain, type Subject, type SubjectValidation, attestationId, canonicalBounds, canonicalContext, canonicalFrame, canonicalize, canonicalizeText, checkAttestationExpiry, clearProfiles, computeBoundsHash, computeContentHash, computeContextHash, computeFrameHash, computeIntentDisclosureHash, computeIntentHash, contentCanonicalBytes, decodeAttestationBlob, deriveIdentityLine, encodeAttestationBlob, frameHash, getAllProfiles, getProfile, intentDisclosureCanonicalBytes, isV4Attestation, listProfiles, registerProfile, validateBoundsParams, validateContextParams, validateFrameParams, validateSubject, verify, verifyAttestation, verifyAttestationSignature, verifyAttestationV4, verifyBoundsHash, verifyContextHash, verifyFrameHash };
@@ -42,18 +42,23 @@ __export(index_exports, {
42
42
  computeContentHash: () => computeContentHash,
43
43
  computeContextHash: () => computeContextHash,
44
44
  computeFrameHash: () => computeFrameHash,
45
+ computeIntentDisclosureHash: () => computeIntentDisclosureHash,
46
+ computeIntentHash: () => computeIntentHash,
45
47
  contentCanonicalBytes: () => contentCanonicalBytes,
46
48
  decodeAttestationBlob: () => decodeAttestationBlob,
49
+ deriveIdentityLine: () => deriveIdentityLine,
47
50
  encodeAttestationBlob: () => encodeAttestationBlob,
48
51
  frameHash: () => frameHash,
49
52
  getAllProfiles: () => getAllProfiles,
50
53
  getProfile: () => getProfile,
54
+ intentDisclosureCanonicalBytes: () => intentDisclosureCanonicalBytes,
51
55
  isV4Attestation: () => isV4Attestation,
52
56
  listProfiles: () => listProfiles,
53
57
  registerProfile: () => registerProfile,
54
58
  validateBoundsParams: () => validateBoundsParams,
55
59
  validateContextParams: () => validateContextParams,
56
60
  validateFrameParams: () => validateFrameParams,
61
+ validateSubject: () => validateSubject,
57
62
  verify: () => verify,
58
63
  verifyAttestation: () => verifyAttestation,
59
64
  verifyAttestationSignature: () => verifyAttestationSignature,
@@ -116,8 +121,62 @@ function computeContentHash(binding, content) {
116
121
  return `sha256:${sha256Hex(contentCanonicalBytes(binding.kind, content))}`;
117
122
  }
118
123
 
119
- // src/frame.ts
124
+ // src/intent-disclosure.ts
120
125
  var import_crypto2 = require("crypto");
126
+ function sha256Hex2(bytes) {
127
+ return (0, import_crypto2.createHash)("sha256").update(bytes, "utf8").digest("hex");
128
+ }
129
+ function computeIntentHash(intentText) {
130
+ return `sha256:${sha256Hex2(canonicalizeText(intentText))}`;
131
+ }
132
+ function intentDisclosureCanonicalBytes(intentCiphertext, approversFrozen) {
133
+ const sorted = [...approversFrozen].sort();
134
+ return `${intentCiphertext}
135
+ ${canonicalize(sorted)}`;
136
+ }
137
+ function computeIntentDisclosureHash(intentCiphertext, approversFrozen) {
138
+ return `sha256:${sha256Hex2(intentDisclosureCanonicalBytes(intentCiphertext, approversFrozen))}`;
139
+ }
140
+
141
+ // src/identity.ts
142
+ function validateSubject(subject) {
143
+ const errors = [];
144
+ const { did, assurance, method, trust_root, verifier, disclose, owner_signature } = subject;
145
+ if (!did) errors.push("subject.did is required");
146
+ if (assurance === "low") {
147
+ if (method !== "self_declared") errors.push(`low assurance requires method "self_declared", got "${method}"`);
148
+ if (trust_root !== "self") errors.push(`low assurance requires trust_root "self", got "${trust_root}"`);
149
+ if (disclose) errors.push("low assurance MUST NOT disclose a name");
150
+ } else if (assurance === "high") {
151
+ if (method === "as_vouched") {
152
+ if (trust_root !== "as") errors.push('as_vouched requires trust_root "as"');
153
+ if (!verifier) errors.push("as_vouched requires a verifier");
154
+ } else if (method === "eudi") {
155
+ if (trust_root !== "external") errors.push('eudi requires trust_root "external"');
156
+ if (!verifier) errors.push("eudi requires a verifier");
157
+ if (!owner_signature) errors.push("eudi requires an owner_signature");
158
+ } else {
159
+ errors.push(`high assurance requires method "as_vouched" or "eudi", got "${method}"`);
160
+ }
161
+ if (disclose && typeof disclose.name !== "string") errors.push("disclose.name must be a string");
162
+ } else {
163
+ errors.push(`assurance must be "low" or "high", got "${assurance}"`);
164
+ }
165
+ return { valid: errors.length === 0, errors };
166
+ }
167
+ function deriveIdentityLine(subject, { operatorName }) {
168
+ const name = subject?.assurance === "high" ? subject.disclose?.name : void 0;
169
+ if (!name) {
170
+ return `Sent by an AI agent via ${operatorName}`;
171
+ }
172
+ if (subject.method === "eudi") {
173
+ return `Sent by an AI agent of ${name} \u2014 identity verified (EUDI)`;
174
+ }
175
+ return `Sent by an AI agent of ${name} \u2014 verified by ${operatorName}`;
176
+ }
177
+
178
+ // src/frame.ts
179
+ var import_crypto3 = require("crypto");
121
180
  function validateFrameParams(params, profile) {
122
181
  const errors = [];
123
182
  if (!profile.frameSchema) {
@@ -154,7 +213,7 @@ function canonicalFrame(params, profile) {
154
213
  return lines.join("\n");
155
214
  }
156
215
  function frameHash(canonicalFrameString) {
157
- const hash = (0, import_crypto2.createHash)("sha256").update(canonicalFrameString, "utf8").digest("hex");
216
+ const hash = (0, import_crypto3.createHash)("sha256").update(canonicalFrameString, "utf8").digest("hex");
158
217
  return `sha256:${hash}`;
159
218
  }
160
219
  function computeFrameHash(params, profile) {
@@ -238,17 +297,17 @@ function canonicalContext(params, profile) {
238
297
  }
239
298
  function computeBoundsHash(params, profile) {
240
299
  const canonical = canonicalBounds(params, profile);
241
- const hash = (0, import_crypto2.createHash)("sha256").update(canonical, "utf8").digest("hex");
300
+ const hash = (0, import_crypto3.createHash)("sha256").update(canonical, "utf8").digest("hex");
242
301
  return `sha256:${hash}`;
243
302
  }
244
303
  function computeContextHash(params, profile) {
245
304
  const canonical = canonicalContext(params, profile);
246
- const hash = (0, import_crypto2.createHash)("sha256").update(canonical, "utf8").digest("hex");
305
+ const hash = (0, import_crypto3.createHash)("sha256").update(canonical, "utf8").digest("hex");
247
306
  return `sha256:${hash}`;
248
307
  }
249
308
 
250
309
  // src/attestation.ts
251
- var import_crypto3 = require("crypto");
310
+ var import_crypto4 = require("crypto");
252
311
  var ed = __toESM(require("@noble/ed25519"));
253
312
  function decodeAttestationBlob(blob) {
254
313
  try {
@@ -266,7 +325,7 @@ function encodeAttestationBlob(attestation) {
266
325
  return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
267
326
  }
268
327
  function attestationId(blob) {
269
- const hash = (0, import_crypto3.createHash)("sha256").update(blob, "utf8").digest("hex");
328
+ const hash = (0, import_crypto4.createHash)("sha256").update(blob, "utf8").digest("hex");
270
329
  return `sha256:${hash}`;
271
330
  }
272
331
  async function verifyAttestationSignature(attestation, publicKeyHex) {
@@ -396,11 +455,11 @@ async function verifyV3(request, profile, publicKeyHex, now, executionLog, error
396
455
  try {
397
456
  checkAttestationExpiry(attestation.payload, now);
398
457
  } catch {
399
- const domainNames = attestation.payload.resolved_domains.map((d) => d.domain).join(", ");
458
+ const domainNames = (attestation.payload.resolved_domains ?? []).map((d) => d.domain).join(", ");
400
459
  errors.push({ code: "TTL_EXPIRED", message: `Attestation for domain "${domainNames}" has expired` });
401
460
  continue;
402
461
  }
403
- for (const rd of attestation.payload.resolved_domains) {
462
+ for (const rd of attestation.payload.resolved_domains ?? []) {
404
463
  coveredDomains.add(rd.domain);
405
464
  }
406
465
  }
@@ -475,11 +534,11 @@ async function verifyV4(request, profile, publicKeyHex, now, executionLog) {
475
534
  try {
476
535
  checkAttestationExpiry(attestation.payload, now);
477
536
  } catch {
478
- const domainNames = attestation.payload.resolved_domains.map((d) => d.domain).join(", ");
537
+ const domainNames = (attestation.payload.resolved_domains ?? []).map((d) => d.domain).join(", ");
479
538
  errors.push({ code: "TTL_EXPIRED", message: `Attestation for domain "${domainNames}" has expired` });
480
539
  continue;
481
540
  }
482
- for (const rd of attestation.payload.resolved_domains) {
541
+ for (const rd of attestation.payload.resolved_domains ?? []) {
483
542
  coveredDomains.add(rd.domain);
484
543
  }
485
544
  }
@@ -783,18 +842,23 @@ function resolveCumulativeFields(request, profile, executionLog, now) {
783
842
  computeContentHash,
784
843
  computeContextHash,
785
844
  computeFrameHash,
845
+ computeIntentDisclosureHash,
846
+ computeIntentHash,
786
847
  contentCanonicalBytes,
787
848
  decodeAttestationBlob,
849
+ deriveIdentityLine,
788
850
  encodeAttestationBlob,
789
851
  frameHash,
790
852
  getAllProfiles,
791
853
  getProfile,
854
+ intentDisclosureCanonicalBytes,
792
855
  isV4Attestation,
793
856
  listProfiles,
794
857
  registerProfile,
795
858
  validateBoundsParams,
796
859
  validateContextParams,
797
860
  validateFrameParams,
861
+ validateSubject,
798
862
  verify,
799
863
  verifyAttestation,
800
864
  verifyAttestationSignature,