@mcpose/audit 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -51,7 +51,7 @@ This package exists for the harder problem: a record that stays credible when so
51
51
  - **Subkeys derived through the signing oracle.** Chain and encryption keys derive from the signing secret with domain separation, never from the public key id ([ADR-0003](https://github.com/amir-gorji/mcpose/blob/main/docs/adr/0003-audit-subkeys-derived-from-signing-oracle.md)).
52
52
  - **Optional erasable mode.** Supply a `SubjectKeyStore` and a subject's payloads become destroyable: `destroy(sub)` kills both decryptability and hash-confirmability for that subject, and the chain and manifest keep verifying ([ADR-0018](https://github.com/amir-gorji/mcpose/blob/main/docs/adr/0018-cryptographic-erasure-and-the-chain.md)). Omit it and nothing changes.
53
53
  - **Never blocks the call path.** Audit failures (a throwing sink, unserializable payloads) are routed to `onAuditError`; the tool call always completes with its real result or error.
54
- A throwing `onAuditError` is contained too, so a broken reporter cannot replace a tool result or mask an upstream error.
54
+ A throwing `onAuditError`, or one that returns a rejected promise, is contained too, so a broken reporter cannot replace a tool result or mask an upstream error.
55
55
  Three configuration errors are the deliberate exception, and all fail before the upstream is reached rather than after: an unavailable signing provider, a `ProxyContext` with no `proxy` identity, and an unavailable `SubjectKeyStore` in erasable mode.
56
56
  Each would otherwise produce a record that cannot be verified or cannot be attributed, so the call fails instead of running unaudited.
57
57
  A proxy built by `createProxyServer` always stamps `ctx.proxy`, so only a host that invokes the middleware with its own hand-built context needs to supply it.
@@ -291,8 +291,8 @@ Only the root the key comes from changes.
291
291
  | `createSensitivityResolver(map, override?)` | Build a `SensitivityResolverFn`. Unknown or invalid tiers resolve to `high`. |
292
292
  | `createDefaultSigningKeyProvider(secret)` | In-process HMAC-SHA256 `SigningKeyProvider`. |
293
293
  | `createInMemorySubjectKeyStore()` | Reference `SubjectKeyStore` for [erasable mode](#erasable-mode-cryptographic-erasure). **Not durable**: development and tests only. |
294
- | `verifyAuditChain(events, signingKey)` | **Keyed** chain verification: recomputes every `chainHash` and reports the first tampered index. An empty event list is invalid. |
295
- | `verifyManifestSignature(manifest, signingKey)` | **Keyed** check of the full-manifest signature, in constant time. |
294
+ | `verifyAuditChain(events, signingKey)` | **Keyed** chain verification: recomputes every `chainHash` and reports the first tampered index. An empty event list is invalid. A stored `chainHash` must be the exact lowercase hex string; a respelling is a mismatch. |
295
+ | `verifyManifestSignature(manifest, signingKey)` | **Keyed** check of the full-manifest signature, in constant time. The stored `signature` must be the exact lowercase hex string; a respelling (uppercase, an appended character) does not verify, so an independent verifier that compares strings agrees with this one. |
296
296
  | `computeMerkleRoot` · `computeMerkleProof` · `verifyMerkleProof` | Low-level Merkle helpers for independent verification. |
297
297
  | `canonicalJson` · `stableStringify` | The canonical serializations the format is defined over, exported so third parties can write their own verifier. |
298
298
 
@@ -332,7 +332,7 @@ interface AuditOptions {
332
332
  onAuditError?: (
333
333
  err: unknown,
334
334
  info: { tool: string; requestId: string; sessionId?: string },
335
- ) => void;
335
+ ) => unknown;
336
336
  }
337
337
 
338
338
  interface AuditMiddlewareHandle {
@@ -446,7 +446,10 @@ interface AuditEventBase {
446
446
  tool: string; // the tool name, or the prompt name when kind is 'prompt'
447
447
  duration_ms: number;
448
448
  outcome: 'success' | 'rejected' | 'error';
449
- /** Present when outcome is 'rejected' (from the MCP error's data field). */
449
+ /**
450
+ * Present when outcome is 'rejected': a member of the `RejectionReason` union read from the
451
+ * MCP error's data field. An unrecognized value is recorded as outcome 'error' instead.
452
+ */
450
453
  rejectionReason?: RejectionReason;
451
454
  /** Present when outcome is 'error': what the upstream call threw. */
452
455
  error?: { name: string; message: string };
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,qBAAqB,EACrB,YAAY,EACZ,cAAc,EAEf,MAAM,YAAY,CAAC;AAkJpB,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,YAAY,GACpB,qBAAqB,CA0XvB;AAED,4EAA4E;AAC5E,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,GAC1C,MAAM,CA8BR"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,qBAAqB,EACrB,YAAY,EACZ,cAAc,EAEf,MAAM,YAAY,CAAC;AA2LpB,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,YAAY,GACpB,qBAAqB,CA4avB;AAED,4EAA4E;AAC5E,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,GAC1C,MAAM,CA8BR"}
@@ -65,10 +65,50 @@ function anonymousIdentity() {
65
65
  source: 'custom',
66
66
  };
67
67
  }
68
+ /**
69
+ * Every member of the closed `RejectionReason` union, as an own-key
70
+ * membership table.
71
+ *
72
+ * The union is a type, so it is erased at runtime and `err.data.rejectionReason`
73
+ * arrives as an unchecked string. The `Record` annotation is the drift guard in
74
+ * both directions: a member added to the union without a matching key here is a
75
+ * compile error, and so is a key that is not a member of the union.
76
+ *
77
+ * Core keeps its own copy for telemetry. This one is not imported from there
78
+ * because the `mcpose` peer range admits 3.0.0, which exports no runtime guard.
79
+ */
80
+ const REJECTION_REASONS = {
81
+ TOOL_HIDDEN: true,
82
+ RESOURCE_HIDDEN: true,
83
+ BACKEND_UNROUTABLE: true,
84
+ POLICY_DENIED: true,
85
+ IDENTITY_UNRESOLVED: true,
86
+ CONSENT_MISSING: true,
87
+ SENSITIVITY_BLOCKED: true,
88
+ DELEGATION_INVALID: true,
89
+ BUDGET_EXCEEDED: true,
90
+ SESSION_LIMIT: true,
91
+ BODY_LIMIT: true,
92
+ };
93
+ /**
94
+ * The rejection reason this error carries, or `undefined` when it carries
95
+ * none.
96
+ *
97
+ * Fail CLOSED, like the sensitivity tier: a `rejectionReason` outside the
98
+ * union is not a governance rejection, so the call is recorded as an ordinary
99
+ * `error` that keeps the real name and message. Casting the string through
100
+ * instead would record a failure as a rejection with no `error` field, and
101
+ * chain the unvalidated value as a covered field, which is the identity-less
102
+ * `outputHash` weakness the structured `error` field exists to close
103
+ * (ADR-0004). Mirrors `createSensitivityResolver`.
104
+ */
68
105
  function getRejectionReason(err) {
69
106
  const data = err?.data;
70
- return typeof data?.rejectionReason === 'string'
71
- ? data.rejectionReason
107
+ const reason = data?.rejectionReason;
108
+ // `Object.hasOwn`, not `in`: the reason is upstream-controlled, so a value
109
+ // like `constructor` must not pass as a member off the prototype.
110
+ return typeof reason === 'string' && Object.hasOwn(REJECTION_REASONS, reason)
111
+ ? reason
72
112
  : undefined;
73
113
  }
74
114
  export function createAuditMiddleware(options) {
@@ -77,12 +117,23 @@ export function createAuditMiddleware(options) {
77
117
  const sealed = new Map();
78
118
  const includeRejections = options.includeRejections ?? true;
79
119
  const closeDrainTimeoutMs = options.closeDrainTimeoutMs ?? 30_000;
120
+ // `!(x >= 0)` rejects NaN too, which the `??` default above lets through:
121
+ // a NaN deadline never fires, so the drain this option exists to bound would
122
+ // wait for a call that never settles and leave the recorded events unsigned
123
+ // with nothing reported. Same form as `maxSessions` in core (#277).
124
+ if (!(closeDrainTimeoutMs >= 0)) {
125
+ throw new Error(`mcpose/audit: closeDrainTimeoutMs must be >= 0 or Infinity, got ${String(options.closeDrainTimeoutMs)}`);
126
+ }
80
127
  const reportAuditError = options.onAuditError ?? ((err) => console.error(err));
81
- // A throwing reporter is outside the audited call path too (#172): it must
82
- // not replace a tool result, mask an upstream error, or abort a drain.
128
+ // A throwing or rejecting reporter is outside the audited call path too
129
+ // (#172, #245): it must not replace a tool result, mask an upstream error,
130
+ // abort a drain, or leave an unobserved rejection that Node's default
131
+ // --unhandled-rejections=throw turns into a dead process.
83
132
  const onAuditError = (err, info) => {
84
133
  try {
85
- reportAuditError(err, info);
134
+ Promise.resolve(reportAuditError(err, info)).catch(() => {
135
+ // Nothing left to report it to.
136
+ });
86
137
  }
87
138
  catch {
88
139
  // Nothing left to report it to.
@@ -202,10 +253,32 @@ export function createAuditMiddleware(options) {
202
253
  // A call can fail without throwing: an MCP tool reports failure
203
254
  // in-band with `isError: true` (#171). The caller supplies the
204
255
  // predicate, so only tool calls pass one and prompts never match.
205
- const inBandError = !threw && isInBandError?.(result) === true;
256
+ //
257
+ // A result that is not an object is decided here too, and for the same
258
+ // reason: the predicate below narrows to a `CallToolResult` and a
259
+ // primitive has no `.content` to narrow on. A local tool handler that
260
+ // resolves to a string reaches the client as `-32602 Invalid
261
+ // tools/call result`, so recording it as a success would put a clean
262
+ // outcome, and no `error` field, in a signed chain covering a call the
263
+ // client saw fail. `isResultless` in core's telemetry draws the same
264
+ // line, so both record what the caller observed.
265
+ //
266
+ // A nullish result is decided here, BEFORE the predicate narrows it,
267
+ // because narrowing reads `.content` and a nullish value has none: a
268
+ // local tool handler with a missing `return` made the predicate throw,
269
+ // and that throw reached the `catch` below, which reports and moves on
270
+ // — so `buildEvent` never ran and the governed call reached the client
271
+ // as a failure and the trail not at all. The manifest that counted it
272
+ // still verified, a valid chain under a valid signature, one event
273
+ // short of the calls it claims to cover.
274
+ const noToolResult = !threw &&
275
+ (result === null ||
276
+ result === undefined ||
277
+ typeof result !== 'object');
278
+ const inBandError = !threw && !noToolResult && isInBandError?.(result) === true;
206
279
  const outcome = rejectionReason !== undefined
207
280
  ? 'rejected'
208
- : threw || inBandError
281
+ : threw || inBandError || noToolResult
209
282
  ? 'error'
210
283
  : 'success';
211
284
  if (outcome !== 'rejected' || includeRejections) {
@@ -246,10 +319,20 @@ export function createAuditMiddleware(options) {
246
319
  }
247
320
  : // A fixed message: `error` is never encrypted, so copying the
248
321
  // tool's own text here would leak a high-tier payload.
249
- {
250
- name: 'ToolError',
251
- message: 'Tool result returned isError: true',
252
- },
322
+ noToolResult
323
+ ? {
324
+ name: 'InvalidToolResult',
325
+ // `kind` decides the shape that was expected, and the
326
+ // message is plaintext, so it has to name the one that
327
+ // was actually missing.
328
+ message: kind === 'prompt'
329
+ ? 'Prompt fetch resolved to a value that is not a GetPromptResult'
330
+ : 'Tool call resolved to a value that is not a CallToolResult',
331
+ }
332
+ : {
333
+ name: 'ToolError',
334
+ message: 'Tool result returned isError: true',
335
+ },
253
336
  position,
254
337
  prevChainHash: session?.prevChainHash ?? '',
255
338
  tier,
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -95,9 +95,11 @@ export interface AuditEventBase {
95
95
  /** Present when outcome is 'rejected' (from the MCP error's data field). */
96
96
  rejectionReason?: RejectionReason;
97
97
  /**
98
- * Present when outcome is 'error': what the upstream call threw, or
99
- * `{ name: 'ToolError' }` with a fixed message when a tool result carried
100
- * `isError: true` in-band.
98
+ * Present when outcome is 'error': what the upstream call threw, or a fixed
99
+ * message when the call failed without throwing -- `{ name: 'ToolError' }`
100
+ * for a tool result that carried `isError: true` in-band, and
101
+ * `{ name: 'InvalidToolResult' }` when the call resolved to a value that is
102
+ * not the shape its `kind` expects.
101
103
  */
102
104
  error?: {
103
105
  name: string;
@@ -151,7 +153,8 @@ export interface ReplayManifest {
151
153
  /**
152
154
  * HMAC over the canonical serialization of the ENTIRE manifest (every
153
155
  * field above, domain-separated) — not just the Merkle root. Verify with
154
- * `verifyManifestSignature`.
156
+ * `verifyManifestSignature`, which accepts only this exact lowercase hex
157
+ * string: a respelling (uppercase, an appended character) does not verify.
155
158
  */
156
159
  signature: string;
157
160
  }
@@ -198,22 +201,25 @@ export interface AuditOptions {
198
201
  * to append and persist their events before it seals the manifest. Past
199
202
  * the deadline the manifest covers what has landed, and each straggler is
200
203
  * reported through `onAuditError` with its tool and requestId. `Infinity`
201
- * waits without bound.
204
+ * waits without bound. Any other value (NaN, a negative number) is
205
+ * rejected at construction, because it would leave the drain with no
206
+ * deadline at all.
202
207
  * @default 30_000
203
208
  */
204
209
  closeDrainTimeoutMs?: number;
205
210
  /**
206
211
  * Called when the audit layer itself fails (event serialization, a
207
212
  * throwing onEvent sink). The audit layer NEVER throws into the tool-call
208
- * path; failures are reported here instead. If this hook itself throws,
209
- * the exception is contained and never reaches the caller either.
213
+ * path; failures are reported here instead. If this hook itself throws or
214
+ * returns a rejected promise, the failure is contained and never reaches
215
+ * the caller either.
210
216
  * @default console.error
211
217
  */
212
218
  onAuditError?: (err: unknown, info: {
213
219
  tool: string;
214
220
  requestId: string;
215
221
  sessionId?: string;
216
- }) => void;
222
+ }) => unknown;
217
223
  }
218
224
  export interface AuditMiddlewareHandle {
219
225
  middleware: ToolMiddleware;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,cAAc,EACf,MAAM,QAAQ,CAAC;AAIhB,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAExD,MAAM,MAAM,qBAAqB,GAAG,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC1B,eAAe,CAAC;AAErB;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,eAAe,KACrB,eAAe,CAAC;AAIrB,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,aAAa,CAAC;CAC1B;AAID,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;;OAQG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD;;;;;OAKG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;CAC1D;AAID,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAC;IAC3B;;;;;;;;OAQG;IACH,KAAK,EAAE,aAAa,CAAC;IACrB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;IAC1C,4EAA4E;IAC5E,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG;IAC3C,eAAe,EAAE,KAAK,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG;IAC9C,eAAe,EAAE,QAAQ,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG;IAC5C,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,gBAAgB,GAAG,cAAc,CAAC;AAI3E,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB;;;;;;;;OAQG;IACH,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,mBAAmB,EAAE,qBAAqB,CAAC;IAC3C;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;OASG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,CACb,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAC1D,OAAO,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,cAAc,CAAC;IAC3B;;;;;OAKG;IACH,gBAAgB,EAAE,gBAAgB,CAAC;IACnC;;;;;;;;;;;;;;OAcG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC;CACtE"}
@@ -1 +1 @@
1
- {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EACd,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAMpB,MAAM,MAAM,iBAAiB,GAC3B;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAQpE;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,UAAU,EAAE,kBAAkB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,CA4B5B;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,cAAc,EACxB,UAAU,EAAE,kBAAkB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAMlB"}
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EACd,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAMpB,MAAM,MAAM,iBAAiB,GAC3B;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAwBpE;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,UAAU,EAAE,kBAAkB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,CA4B5B;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,cAAc,EACxB,UAAU,EAAE,kBAAkB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAMlB"}
package/dist/verify.js CHANGED
@@ -2,10 +2,26 @@ import { timingSafeEqual } from 'node:crypto';
2
2
  import { chainPreimageFields, computeChainHash } from './chain.js';
3
3
  import { manifestSigningPayload } from './middleware.js';
4
4
  const DOMAIN_CHAIN = Buffer.from('mcpose/v2/chain');
5
- function hexEqual(aHex, bHex) {
6
- const a = Buffer.from(aHex, 'hex');
7
- const b = Buffer.from(bHex, 'hex');
8
- return a.length === b.length && a.length > 0 && timingSafeEqual(a, b);
5
+ /**
6
+ * Canonical hex: lowercase, even length, hex digits only, non-empty. This
7
+ * is what the producer writes (`digest('hex')`), and the exact string a
8
+ * third-party verifier compares.
9
+ */
10
+ const CANONICAL_HEX = /^(?:[0-9a-f]{2})+$/;
11
+ /**
12
+ * Compares a stored hex string against the recomputed value in constant
13
+ * time. The stored string must be canonical first: Node's hex decoder drops
14
+ * a trailing odd nibble and stops at the first non-hex character, so
15
+ * `sig + '0'`, `sig + 'z'` and `SIG` all decode to the stored bytes and would
16
+ * otherwise verify. The verifiers authenticate the stored string itself, not
17
+ * just its decoding, so two implementations agree on one artifact (#281).
18
+ */
19
+ function hexEqual(storedHex, expectedHex) {
20
+ if (!CANONICAL_HEX.test(storedHex))
21
+ return false;
22
+ const a = Buffer.from(storedHex, 'hex');
23
+ const b = Buffer.from(expectedHex, 'hex');
24
+ return a.length === b.length && timingSafeEqual(a, b);
9
25
  }
10
26
  /**
11
27
  * KEYED chain verification: recomputes every event's chainHash from its
@@ -1 +1 @@
1
- {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAM9C,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;AAKpD,SAAS,QAAQ,CAAC,IAAY,EAAE,IAAY;IAC1C,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACnC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACnC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACxE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAA6B,EAC7B,UAA8B;IAE9B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAChE,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACrD,IAAI,aAAa,GAAG,EAAE,CAAC;IAEvB,KAAK,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QAC1C,IAAI,KAAK,CAAC,sBAAsB,KAAK,CAAC,EAAE,CAAC;YACvC,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,CAAC;gBACR,MAAM,EAAE,0BAA0B,KAAK,CAAC,sBAAsB,cAAc,CAAC,EAAE;aAChF,CAAC;QACJ,CAAC;QACD,MAAM,QAAQ,GAAG,gBAAgB,CAC/B,mBAAmB,CAAC,KAAK,CAAC,EAC1B,aAAa,EACb,QAAQ,CACT,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC;YACzC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;QAClE,CAAC;QACD,aAAa,GAAG,KAAK,CAAC,SAAS,CAAC;IAClC,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,QAAwB,EACxB,UAA8B;IAE9B,MAAM,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,GAAG,QAAQ,CAAC;IAC5C,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,IAAI,CACpC,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAC9C,CAAC;IACF,OAAO,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACvD,CAAC"}
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAM9C,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;AAKpD;;;;GAIG;AACH,MAAM,aAAa,GAAG,oBAAoB,CAAC;AAE3C;;;;;;;GAOG;AACH,SAAS,QAAQ,CAAC,SAAiB,EAAE,WAAmB;IACtD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC;IACjD,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACxC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAC1C,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACxD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAA6B,EAC7B,UAA8B;IAE9B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAChE,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACrD,IAAI,aAAa,GAAG,EAAE,CAAC;IAEvB,KAAK,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QAC1C,IAAI,KAAK,CAAC,sBAAsB,KAAK,CAAC,EAAE,CAAC;YACvC,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,CAAC;gBACR,MAAM,EAAE,0BAA0B,KAAK,CAAC,sBAAsB,cAAc,CAAC,EAAE;aAChF,CAAC;QACJ,CAAC;QACD,MAAM,QAAQ,GAAG,gBAAgB,CAC/B,mBAAmB,CAAC,KAAK,CAAC,EAC1B,aAAa,EACb,QAAQ,CACT,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC;YACzC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;QAClE,CAAC;QACD,aAAa,GAAG,KAAK,CAAC,SAAS,CAAC;IAClC,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,QAAwB,EACxB,UAA8B;IAE9B,MAAM,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,GAAG,QAAQ,CAAC;IAC5C,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,IAAI,CACpC,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAC9C,CAAC;IACF,OAAO,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACvD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcpose/audit",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Integrity-chained audit middleware for mcpose — HMAC chain, Merkle proofs, ReplayManifest",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -49,12 +49,12 @@
49
49
  "devDependencies": {
50
50
  "@stryker-mutator/core": "10.0.0",
51
51
  "@stryker-mutator/vitest-runner": "10.0.0",
52
- "@types/node": "^26.5.1",
53
- "@vitest/coverage-v8": "5.0.1",
52
+ "@types/node": "^26.6.5",
53
+ "@vitest/coverage-v8": "5.0.4",
54
54
  "fast-check": "4.10.2",
55
55
  "typescript": "6.0.3",
56
- "vitest": "5.0.1",
57
- "mcpose": "3.0.0"
56
+ "vitest": "5.0.4",
57
+ "mcpose": "3.1.0"
58
58
  },
59
59
  "scripts": {
60
60
  "build": "tsc -p tsconfig.build.json",
@@ -241,6 +241,25 @@ describe('verifyAuditChain (keyed)', () => {
241
241
  const result = await verifyAuditChain(events, otherKey);
242
242
  expect(result.valid).toBe(false);
243
243
  });
244
+
245
+ // Node's hex decoder drops a trailing odd nibble and stops at the first
246
+ // non-hex character, so these respellings decode to the stored bytes. The
247
+ // verifier authenticates the stored string, not just its decoding (#281).
248
+ it.each([
249
+ ['an appended nibble', (h: string) => h + '0'],
250
+ ['an appended non-hex character', (h: string) => h + 'z'],
251
+ ['an uppercase respelling', (h: string) => h.toUpperCase()],
252
+ ])('rejects a chainHash with %s', async (_label, respell) => {
253
+ const { events, signingKey } = await produceSession('s-respell', 3);
254
+ const respelled = events.map((e, i) =>
255
+ i === 1 ? { ...e, chainHash: respell(e.chainHash) } : e,
256
+ );
257
+ expect(await verifyAuditChain(respelled, signingKey)).toEqual({
258
+ valid: false,
259
+ index: 1,
260
+ reason: 'chainHash mismatch',
261
+ });
262
+ });
244
263
  });
245
264
 
246
265
  describe('sensitivityTier is covered by the chain (ADR-0015)', () => {
@@ -328,6 +347,21 @@ describe('verifyManifestSignature', () => {
328
347
  const otherKey = createDefaultSigningKeyProvider('other-secret');
329
348
  expect(await verifyManifestSignature(manifest, otherKey)).toBe(false);
330
349
  });
350
+
351
+ // Same decoder leniency as above: a respelled signature must not verify,
352
+ // or a tool that indexes by the stored string disagrees with this one (#281).
353
+ it.each([
354
+ ['an appended nibble', (h: string) => h + '0'],
355
+ ['an appended non-hex character', (h: string) => h + 'z'],
356
+ ['two appended non-hex characters', (h: string) => h + 'zz'],
357
+ ['an uppercase respelling', (h: string) => h.toUpperCase()],
358
+ ])('rejects a signature with %s', async (_label, respell) => {
359
+ const { manifest, signingKey } = await produceSession('m-respell', 3);
360
+ const respelled = { ...manifest, signature: respell(manifest.signature) };
361
+ expect(await verifyManifestSignature(respelled, signingKey)).toBe(false);
362
+ // Positive control: the untouched manifest still verifies.
363
+ expect(await verifyManifestSignature(manifest, signingKey)).toBe(true);
364
+ });
331
365
  });
332
366
 
333
367
  describe('domain label pinning', () => {
@@ -0,0 +1,183 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import type * as http from 'node:http';
3
+ import { startHttpProxy } from 'mcpose';
4
+ import type { LocalTool } from 'mcpose';
5
+ import { createMockBackendClient } from 'mcpose/testing';
6
+ import { createAuditMiddleware } from '../middleware.js';
7
+ import { createDefaultSigningKeyProvider } from '../signingKey.js';
8
+ import { createSensitivityResolver } from '../sensitivity.js';
9
+ import { verifyAuditChain, verifyManifestSignature } from '../verify.js';
10
+ import type { AuditEvent, AuditOptions, ReplayManifest } from '../types.js';
11
+
12
+ /**
13
+ * A call that fails is only a `rejected` event when its error carries a
14
+ * member of the closed `RejectionReason` union.
15
+ *
16
+ * The failing call is a LOCAL tool handler (ADR-0007), so it runs inside the
17
+ * pipeline and the audit middleware observes it there, exactly as the tool
18
+ * call in the issue does. The error is shaped like an `McpError` from
19
+ * `rejectionMcpError()` without importing the SDK: the middleware
20
+ * duck-types `err.data.rejectionReason`.
21
+ */
22
+
23
+ const MESSAGE = 'ledger pool reset: no capacity';
24
+
25
+ const MCP_HEADERS = {
26
+ 'Content-Type': 'application/json',
27
+ Accept: 'application/json, text/event-stream',
28
+ };
29
+
30
+ function port(server: http.Server): number {
31
+ const addr = server.address();
32
+ if (!addr || typeof addr === 'string') throw new Error('no port');
33
+ return addr.port;
34
+ }
35
+
36
+ /** A local tool that always fails, carrying `reason` in the error's data. */
37
+ function failingLocalTool(reason: string): LocalTool {
38
+ return {
39
+ tool: { name: 'ledger_entry', inputSchema: { type: 'object' } },
40
+ handler: async () => {
41
+ throw Object.assign(new Error(MESSAGE), {
42
+ code: -32603,
43
+ data: { rejectionReason: reason },
44
+ });
45
+ },
46
+ };
47
+ }
48
+
49
+ const signingKey = createDefaultSigningKeyProvider('test-secret');
50
+
51
+ async function harness(reason: string, overrides: Partial<AuditOptions> = {}) {
52
+ const events: AuditEvent[] = [];
53
+ const audit = createAuditMiddleware({
54
+ signingKey,
55
+ sensitivityResolver: createSensitivityResolver({ ledger_entry: 'low' }),
56
+ onEvent: (e) => void events.push(e),
57
+ ...overrides,
58
+ });
59
+ const server = await startHttpProxy(
60
+ createMockBackendClient(),
61
+ {
62
+ name: 'audit-rejection-test',
63
+ localTools: [failingLocalTool(reason)],
64
+ toolMiddleware: [audit.middleware],
65
+ },
66
+ { port: 0, path: '/mcp' },
67
+ );
68
+ const baseUrl = `http://localhost:${port(server)}/mcp`;
69
+ const init = await fetch(baseUrl, {
70
+ method: 'POST',
71
+ headers: MCP_HEADERS,
72
+ body: JSON.stringify({
73
+ jsonrpc: '2.0',
74
+ id: 1,
75
+ method: 'initialize',
76
+ params: {
77
+ protocolVersion: '2024-11-05',
78
+ capabilities: {},
79
+ clientInfo: { name: 'test', version: '0.0.1' },
80
+ },
81
+ }),
82
+ });
83
+ await init.text();
84
+ const sessionId = init.headers.get('mcp-session-id')!;
85
+ expect(sessionId).toBeTruthy();
86
+
87
+ const call = await fetch(baseUrl, {
88
+ method: 'POST',
89
+ headers: { ...MCP_HEADERS, 'mcp-session-id': sessionId },
90
+ body: JSON.stringify({
91
+ jsonrpc: '2.0',
92
+ id: 2,
93
+ method: 'tools/call',
94
+ params: { name: 'ledger_entry', arguments: { amount: 10 } },
95
+ }),
96
+ });
97
+ await call.text();
98
+ const manifest: ReplayManifest | undefined =
99
+ await audit.closeSession(sessionId);
100
+
101
+ return {
102
+ events,
103
+ manifest,
104
+ close: () => new Promise<void>((r) => server.close(() => r())),
105
+ };
106
+ }
107
+
108
+ describe('rejection classification — only a RejectionReason member is a rejection (#238)', () => {
109
+ it('records an error carrying a reason outside the union as an error, with the real message', async () => {
110
+ const h = await harness('LEDGER_POOL_RESET');
111
+ try {
112
+ expect(h.events).toHaveLength(1);
113
+ const event = h.events[0]!;
114
+ expect(event.outcome).toBe('error');
115
+ // The unvalidated string is not a covered field of this event: an
116
+ // omitted key keeps the preimage the event has always had
117
+ // (ADR-0012), and the classification that ADR-0004's `error` field
118
+ // exists for is restored.
119
+ expect(Object.hasOwn(event, 'rejectionReason')).toBe(false);
120
+ expect(event.error).toEqual({ name: 'Error', message: MESSAGE });
121
+ expect(event.tool).toBe('ledger_entry');
122
+ expect(await verifyAuditChain(h.events, signingKey)).toEqual({
123
+ valid: true,
124
+ });
125
+ expect(h.manifest?.eventCount).toBe(1);
126
+ expect(await verifyManifestSignature(h.manifest!, signingKey)).toBe(true);
127
+ } finally {
128
+ await h.close();
129
+ }
130
+ });
131
+
132
+ it('records a reason inside the union as a rejection, unchanged', async () => {
133
+ const h = await harness('POLICY_DENIED');
134
+ try {
135
+ expect(h.events).toHaveLength(1);
136
+ const event = h.events[0]!;
137
+ expect(event.outcome).toBe('rejected');
138
+ expect(event.rejectionReason).toBe('POLICY_DENIED');
139
+ expect(Object.hasOwn(event, 'error')).toBe(false);
140
+ expect(await verifyAuditChain(h.events, signingKey)).toEqual({
141
+ valid: true,
142
+ });
143
+ } finally {
144
+ await h.close();
145
+ }
146
+ });
147
+
148
+ it('records a reason that is a prototype key as an error, not a rejection', async () => {
149
+ const h = await harness('constructor');
150
+ try {
151
+ expect(h.events).toHaveLength(1);
152
+ expect(h.events[0]!.outcome).toBe('error');
153
+ expect(Object.hasOwn(h.events[0]!, 'rejectionReason')).toBe(false);
154
+ } finally {
155
+ await h.close();
156
+ }
157
+ });
158
+
159
+ it('includeRejections: false still drops a rejection, and still records a non-member as an error', async () => {
160
+ const dropped = await harness('POLICY_DENIED', {
161
+ includeRejections: false,
162
+ });
163
+ try {
164
+ expect(dropped.events).toEqual([]);
165
+ } finally {
166
+ await dropped.close();
167
+ }
168
+
169
+ const recorded = await harness('LEDGER_POOL_RESET', {
170
+ includeRejections: false,
171
+ });
172
+ try {
173
+ expect(recorded.events).toHaveLength(1);
174
+ expect(recorded.events[0]!.outcome).toBe('error');
175
+ expect(recorded.events[0]!.error).toEqual({
176
+ name: 'Error',
177
+ message: MESSAGE,
178
+ });
179
+ } finally {
180
+ await recorded.close();
181
+ }
182
+ });
183
+ });
@@ -221,6 +221,53 @@ describe('createAuditMiddleware — never blocks the call path', () => {
221
221
  expect(events[0]!.sensitivityTier).toBe('high');
222
222
  });
223
223
 
224
+ it('an async onAuditError reporter that rejects does not fail a successful call (#245)', async () => {
225
+ // The reporter is observability (#172). An async reporter that rejects
226
+ // after its first await escapes the synchronous guard: nothing observes
227
+ // the rejection, so Node's default --unhandled-rejections=throw ends the
228
+ // process around the tool call it must not touch.
229
+ const rejections: unknown[] = [];
230
+ const onUnhandled = (reason: unknown): void => {
231
+ rejections.push(reason);
232
+ };
233
+ process.on('unhandledRejection', onUnhandled);
234
+
235
+ try {
236
+ // A plain async function, not a vi.fn spy: a spy attaches its own
237
+ // handler to the promise it returns to track settledResults, which
238
+ // would swallow the very rejection this test observes.
239
+ let reporterCalls = 0;
240
+ const onAuditError = async (): Promise<void> => {
241
+ reporterCalls += 1;
242
+ await new Promise((resolve) => setTimeout(resolve, 1));
243
+ throw new Error('reporter down');
244
+ };
245
+ const { middleware } = createAuditMiddleware(
246
+ makeOptions({
247
+ onEvent: () => {
248
+ throw new Error('sink down');
249
+ },
250
+ onAuditError,
251
+ }),
252
+ );
253
+
254
+ await expect(
255
+ middleware(
256
+ makeReq('search'),
257
+ async () => ({ content: [{ type: 'text', text: 'ok' }] }),
258
+ makeCtx('s1'),
259
+ ),
260
+ ).resolves.toEqual({ content: [{ type: 'text', text: 'ok' }] });
261
+ expect(reporterCalls).toBe(1);
262
+ // One macrotask turn, so a rejection nobody adopted has surfaced as an
263
+ // unhandledRejection event by the time this asserts.
264
+ await new Promise((resolve) => setTimeout(resolve, 20));
265
+ expect(rejections).toHaveLength(0);
266
+ } finally {
267
+ process.removeListener('unhandledRejection', onUnhandled);
268
+ }
269
+ });
270
+
224
271
  it('circular and BigInt arguments still produce an event', async () => {
225
272
  const events: AuditEvent[] = [];
226
273
  const { middleware } = createAuditMiddleware(
@@ -522,6 +569,31 @@ describe('createAuditMiddleware — close during an in-flight call (#168)', () =
522
569
  expect(await closeSession('s')).toBeUndefined();
523
570
  });
524
571
 
572
+ // The bound is the whole reason this option exists. `packages/audit/README.md`
573
+ // says the wait is bounded and names `Infinity` as the only way to wait
574
+ // without bound, so a value that is neither -- NaN, which the `?? 30_000`
575
+ // default does not catch, or a negative number -- must not leave the drain
576
+ // with a deadline that never fires.
577
+ it('rejects a closeDrainTimeoutMs that cannot bound the drain', () => {
578
+ expect(() =>
579
+ createAuditMiddleware(
580
+ makeOptions({ closeDrainTimeoutMs: Number('not a duration') }),
581
+ ),
582
+ ).toThrow(/closeDrainTimeoutMs must be >= 0 or Infinity, got NaN/);
583
+ expect(() =>
584
+ createAuditMiddleware(makeOptions({ closeDrainTimeoutMs: -1 })),
585
+ ).toThrow(/closeDrainTimeoutMs must be >= 0 or Infinity, got -1/);
586
+ });
587
+
588
+ it('accepts 0 and Infinity as the documented bounds', () => {
589
+ expect(() =>
590
+ createAuditMiddleware(makeOptions({ closeDrainTimeoutMs: 0 })),
591
+ ).not.toThrow();
592
+ expect(() =>
593
+ createAuditMiddleware(makeOptions({ closeDrainTimeoutMs: Infinity })),
594
+ ).not.toThrow();
595
+ });
596
+
525
597
  it('concurrent closeSession calls share one manifest', async () => {
526
598
  const { middleware, closeSession } = createAuditMiddleware(makeOptions());
527
599
  const release = deferred();
@@ -0,0 +1,141 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { createAuditMiddleware } from '../middleware.js';
3
+ import { createDefaultSigningKeyProvider } from '../signingKey.js';
4
+ import { createSensitivityResolver } from '../sensitivity.js';
5
+ import { verifyAuditChain, verifyManifestSignature } from '../verify.js';
6
+ import type { AuditEvent, AuditOptions } from '../types.js';
7
+ import { createProxyContext } from 'mcpose';
8
+ import type { Identity } from 'mcpose';
9
+
10
+ /**
11
+ * A call that neither throws nor produces a tool result is a failed call, and
12
+ * the trail has to say so.
13
+ *
14
+ * `hasToolContent` narrows the pipeline's result and reads `.content` on the
15
+ * way, so a nullish one used to throw inside the post-call section — whose
16
+ * only handler reports and moves on. `buildEvent` never ran, so a governed
17
+ * call that failed reached the client and never reached the trail, while the
18
+ * manifest that counted it still verified: a valid chain under a valid
19
+ * signature, short one event of the calls it claims to cover.
20
+ */
21
+
22
+ const identity: Identity = {
23
+ sub: 'user-1',
24
+ type: 'human',
25
+ roles: ['analyst'],
26
+ claims: {},
27
+ resolvedAt: '2026-06-01T00:00:00.000Z',
28
+ source: 'jwt',
29
+ };
30
+
31
+ const signingKey = createDefaultSigningKeyProvider('test-secret');
32
+
33
+ function makeCtx(sessionId: string) {
34
+ return createProxyContext({
35
+ transport: 'http',
36
+ identity,
37
+ sessionId,
38
+ proxy: { name: 'test-proxy', version: '0.0.0' },
39
+ });
40
+ }
41
+
42
+ function makeReq(tool: string) {
43
+ return {
44
+ method: 'tools/call' as const,
45
+ params: { name: tool, arguments: {} },
46
+ };
47
+ }
48
+
49
+ function makeOptions(events: AuditEvent[]): AuditOptions {
50
+ return {
51
+ signingKey,
52
+ sensitivityResolver: createSensitivityResolver({ search: 'low' }),
53
+ onEvent: (e) => void events.push(e),
54
+ };
55
+ }
56
+
57
+ describe('a pipeline that resolves without a tool result', () => {
58
+ for (const [label, value] of [
59
+ ['undefined', undefined],
60
+ ['null', null],
61
+ ['a string', 'all good'],
62
+ ['the number 0', 0],
63
+ ] as const) {
64
+ it(`records the call as an error when the pipeline resolves to ${label}`, async () => {
65
+ const events: AuditEvent[] = [];
66
+ const handle = createAuditMiddleware(makeOptions(events));
67
+
68
+ await handle.middleware(
69
+ makeReq('search'),
70
+ async () => value as never,
71
+ makeCtx(`sess-${label}`),
72
+ );
73
+
74
+ expect(events).toHaveLength(1);
75
+ const event = events[0]!;
76
+ expect(event.outcome).toBe('error');
77
+ expect(event.error).toEqual({
78
+ name: 'InvalidToolResult',
79
+ message: 'Tool call resolved to a value that is not a CallToolResult',
80
+ });
81
+ expect(event.replayManifestPosition).toBe(0);
82
+ });
83
+ }
84
+
85
+ it('names the shape a prompt fetch was expected to return', async () => {
86
+ const events: AuditEvent[] = [];
87
+ const { promptMiddleware } = createAuditMiddleware(makeOptions(events));
88
+
89
+ await promptMiddleware(
90
+ { method: 'prompts/get' as const, params: { name: 'greet' } },
91
+ async () => undefined as never,
92
+ makeCtx('sess-prompt'),
93
+ );
94
+
95
+ expect(events).toHaveLength(1);
96
+ const event = events[0]!;
97
+ expect(event.kind).toBe('prompt');
98
+ expect(event.outcome).toBe('error');
99
+ expect(event.error).toEqual({
100
+ name: 'InvalidToolResult',
101
+ message: 'Prompt fetch resolved to a value that is not a GetPromptResult',
102
+ });
103
+ });
104
+
105
+ it('keeps the chain and the manifest honest across a dropped result', async () => {
106
+ const events: AuditEvent[] = [];
107
+ const onAuditError = vi.fn();
108
+ const handle = createAuditMiddleware({
109
+ ...makeOptions(events),
110
+ onAuditError,
111
+ });
112
+ const ctx = makeCtx('sess-mixed');
113
+
114
+ // First call fails the way a local tool handler with a missing `return`
115
+ // does; the second is an ordinary success.
116
+ await handle.middleware(
117
+ makeReq('search'),
118
+ async () => undefined as never,
119
+ ctx,
120
+ );
121
+ await handle.middleware(
122
+ makeReq('search'),
123
+ async () => ({ content: [{ type: 'text', text: 'ok' }] }),
124
+ ctx,
125
+ );
126
+
127
+ const manifest = await handle.closeSession('sess-mixed');
128
+
129
+ // Two governed calls, two records, in order.
130
+ expect(events).toHaveLength(2);
131
+ expect(events.map((e) => e.replayManifestPosition)).toEqual([0, 1]);
132
+ expect(events.map((e) => e.outcome)).toEqual(['error', 'success']);
133
+ // Nothing needed the containment report any more: the unusable result is
134
+ // in the trail, not in the operator's log.
135
+ expect(onAuditError).not.toHaveBeenCalled();
136
+
137
+ expect(await verifyAuditChain(events, signingKey)).toEqual({ valid: true });
138
+ expect(manifest?.eventCount).toBe(2);
139
+ expect(await verifyManifestSignature(manifest!, signingKey)).toBe(true);
140
+ });
141
+ });
@@ -688,6 +688,33 @@ describe('verifyManifestSignature (properties)', () => {
688
688
  }),
689
689
  );
690
690
  });
691
+
692
+ it('rejects any respelling of the signature that is not the exact string', async () => {
693
+ // `anyLengthHex` only emits canonical hex, so it cannot reach the
694
+ // decoder's leniency: an odd nibble, a non-hex tail, or uppercase all
695
+ // decode to the same bytes and used to verify (#281). Start from the
696
+ // real signature and respell it: uppercase any subset of its characters
697
+ // and append a short tail.
698
+ const respelling = fc
699
+ .tuple(
700
+ fc.array(fc.boolean(), { minLength: 64, maxLength: 64 }),
701
+ fc.array(fc.constantFrom(...'0123456789abcdefz'), { maxLength: 3 }),
702
+ )
703
+ .map(
704
+ ([upper, tail]) =>
705
+ [...manifest.signature]
706
+ .map((c, i) => (upper[i] ? c.toUpperCase() : c))
707
+ .join('') + tail.join(''),
708
+ );
709
+ await fc.assert(
710
+ fc.asyncProperty(respelling, async (signature) => {
711
+ fc.pre(signature !== manifest.signature);
712
+ expect(
713
+ await verifyManifestSignature({ ...manifest, signature }, signingKey),
714
+ ).toBe(false);
715
+ }),
716
+ );
717
+ });
691
718
  });
692
719
 
693
720
  // ── Signing key derivation ────────────────────────────────────────────────────
package/src/middleware.ts CHANGED
@@ -144,10 +144,51 @@ function anonymousIdentity(): Identity {
144
144
  };
145
145
  }
146
146
 
147
+ /**
148
+ * Every member of the closed `RejectionReason` union, as an own-key
149
+ * membership table.
150
+ *
151
+ * The union is a type, so it is erased at runtime and `err.data.rejectionReason`
152
+ * arrives as an unchecked string. The `Record` annotation is the drift guard in
153
+ * both directions: a member added to the union without a matching key here is a
154
+ * compile error, and so is a key that is not a member of the union.
155
+ *
156
+ * Core keeps its own copy for telemetry. This one is not imported from there
157
+ * because the `mcpose` peer range admits 3.0.0, which exports no runtime guard.
158
+ */
159
+ const REJECTION_REASONS: Record<RejectionReason, true> = {
160
+ TOOL_HIDDEN: true,
161
+ RESOURCE_HIDDEN: true,
162
+ BACKEND_UNROUTABLE: true,
163
+ POLICY_DENIED: true,
164
+ IDENTITY_UNRESOLVED: true,
165
+ CONSENT_MISSING: true,
166
+ SENSITIVITY_BLOCKED: true,
167
+ DELEGATION_INVALID: true,
168
+ BUDGET_EXCEEDED: true,
169
+ SESSION_LIMIT: true,
170
+ BODY_LIMIT: true,
171
+ };
172
+
173
+ /**
174
+ * The rejection reason this error carries, or `undefined` when it carries
175
+ * none.
176
+ *
177
+ * Fail CLOSED, like the sensitivity tier: a `rejectionReason` outside the
178
+ * union is not a governance rejection, so the call is recorded as an ordinary
179
+ * `error` that keeps the real name and message. Casting the string through
180
+ * instead would record a failure as a rejection with no `error` field, and
181
+ * chain the unvalidated value as a covered field, which is the identity-less
182
+ * `outputHash` weakness the structured `error` field exists to close
183
+ * (ADR-0004). Mirrors `createSensitivityResolver`.
184
+ */
147
185
  function getRejectionReason(err: unknown): RejectionReason | undefined {
148
186
  const data = (err as { data?: { rejectionReason?: unknown } } | null)?.data;
149
- return typeof data?.rejectionReason === 'string'
150
- ? (data.rejectionReason as RejectionReason)
187
+ const reason = data?.rejectionReason;
188
+ // `Object.hasOwn`, not `in`: the reason is upstream-controlled, so a value
189
+ // like `constructor` must not pass as a member off the prototype.
190
+ return typeof reason === 'string' && Object.hasOwn(REJECTION_REASONS, reason)
191
+ ? (reason as RejectionReason)
151
192
  : undefined;
152
193
  }
153
194
 
@@ -159,16 +200,31 @@ export function createAuditMiddleware(
159
200
  const sealed = new Map<string, SealedSession>();
160
201
  const includeRejections = options.includeRejections ?? true;
161
202
  const closeDrainTimeoutMs = options.closeDrainTimeoutMs ?? 30_000;
203
+ // `!(x >= 0)` rejects NaN too, which the `??` default above lets through:
204
+ // a NaN deadline never fires, so the drain this option exists to bound would
205
+ // wait for a call that never settles and leave the recorded events unsigned
206
+ // with nothing reported. Same form as `maxSessions` in core (#277).
207
+ if (!(closeDrainTimeoutMs >= 0)) {
208
+ throw new Error(
209
+ `mcpose/audit: closeDrainTimeoutMs must be >= 0 or Infinity, got ${String(
210
+ options.closeDrainTimeoutMs,
211
+ )}`,
212
+ );
213
+ }
162
214
  const reportAuditError: NonNullable<AuditOptions['onAuditError']> =
163
215
  options.onAuditError ?? ((err) => console.error(err));
164
- // A throwing reporter is outside the audited call path too (#172): it must
165
- // not replace a tool result, mask an upstream error, or abort a drain.
216
+ // A throwing or rejecting reporter is outside the audited call path too
217
+ // (#172, #245): it must not replace a tool result, mask an upstream error,
218
+ // abort a drain, or leave an unobserved rejection that Node's default
219
+ // --unhandled-rejections=throw turns into a dead process.
166
220
  const onAuditError: NonNullable<AuditOptions['onAuditError']> = (
167
221
  err,
168
222
  info,
169
223
  ) => {
170
224
  try {
171
- reportAuditError(err, info);
225
+ Promise.resolve(reportAuditError(err, info)).catch(() => {
226
+ // Nothing left to report it to.
227
+ });
172
228
  } catch {
173
229
  // Nothing left to report it to.
174
230
  }
@@ -300,11 +356,35 @@ export function createAuditMiddleware(
300
356
  // A call can fail without throwing: an MCP tool reports failure
301
357
  // in-band with `isError: true` (#171). The caller supplies the
302
358
  // predicate, so only tool calls pass one and prompts never match.
303
- const inBandError = !threw && isInBandError?.(result as Res) === true;
359
+ //
360
+ // A result that is not an object is decided here too, and for the same
361
+ // reason: the predicate below narrows to a `CallToolResult` and a
362
+ // primitive has no `.content` to narrow on. A local tool handler that
363
+ // resolves to a string reaches the client as `-32602 Invalid
364
+ // tools/call result`, so recording it as a success would put a clean
365
+ // outcome, and no `error` field, in a signed chain covering a call the
366
+ // client saw fail. `isResultless` in core's telemetry draws the same
367
+ // line, so both record what the caller observed.
368
+ //
369
+ // A nullish result is decided here, BEFORE the predicate narrows it,
370
+ // because narrowing reads `.content` and a nullish value has none: a
371
+ // local tool handler with a missing `return` made the predicate throw,
372
+ // and that throw reached the `catch` below, which reports and moves on
373
+ // — so `buildEvent` never ran and the governed call reached the client
374
+ // as a failure and the trail not at all. The manifest that counted it
375
+ // still verified, a valid chain under a valid signature, one event
376
+ // short of the calls it claims to cover.
377
+ const noToolResult =
378
+ !threw &&
379
+ (result === null ||
380
+ result === undefined ||
381
+ typeof result !== 'object');
382
+ const inBandError =
383
+ !threw && !noToolResult && isInBandError?.(result as Res) === true;
304
384
  const outcome: AuditEvent['outcome'] =
305
385
  rejectionReason !== undefined
306
386
  ? 'rejected'
307
- : threw || inBandError
387
+ : threw || inBandError || noToolResult
308
388
  ? 'error'
309
389
  : 'success';
310
390
 
@@ -348,10 +428,21 @@ export function createAuditMiddleware(
348
428
  }
349
429
  : // A fixed message: `error` is never encrypted, so copying the
350
430
  // tool's own text here would leak a high-tier payload.
351
- {
352
- name: 'ToolError',
353
- message: 'Tool result returned isError: true',
354
- },
431
+ noToolResult
432
+ ? {
433
+ name: 'InvalidToolResult',
434
+ // `kind` decides the shape that was expected, and the
435
+ // message is plaintext, so it has to name the one that
436
+ // was actually missing.
437
+ message:
438
+ kind === 'prompt'
439
+ ? 'Prompt fetch resolved to a value that is not a GetPromptResult'
440
+ : 'Tool call resolved to a value that is not a CallToolResult',
441
+ }
442
+ : {
443
+ name: 'ToolError',
444
+ message: 'Tool result returned isError: true',
445
+ },
355
446
  position,
356
447
  prevChainHash: session?.prevChainHash ?? '',
357
448
  tier,
package/src/types.ts CHANGED
@@ -125,9 +125,11 @@ export interface AuditEventBase {
125
125
  /** Present when outcome is 'rejected' (from the MCP error's data field). */
126
126
  rejectionReason?: RejectionReason;
127
127
  /**
128
- * Present when outcome is 'error': what the upstream call threw, or
129
- * `{ name: 'ToolError' }` with a fixed message when a tool result carried
130
- * `isError: true` in-band.
128
+ * Present when outcome is 'error': what the upstream call threw, or a fixed
129
+ * message when the call failed without throwing -- `{ name: 'ToolError' }`
130
+ * for a tool result that carried `isError: true` in-band, and
131
+ * `{ name: 'InvalidToolResult' }` when the call resolved to a value that is
132
+ * not the shape its `kind` expects.
131
133
  */
132
134
  error?: { name: string; message: string };
133
135
  inputHash: string;
@@ -186,7 +188,8 @@ export interface ReplayManifest {
186
188
  /**
187
189
  * HMAC over the canonical serialization of the ENTIRE manifest (every
188
190
  * field above, domain-separated) — not just the Merkle root. Verify with
189
- * `verifyManifestSignature`.
191
+ * `verifyManifestSignature`, which accepts only this exact lowercase hex
192
+ * string: a respelling (uppercase, an appended character) does not verify.
190
193
  */
191
194
  signature: string;
192
195
  }
@@ -236,21 +239,24 @@ export interface AuditOptions {
236
239
  * to append and persist their events before it seals the manifest. Past
237
240
  * the deadline the manifest covers what has landed, and each straggler is
238
241
  * reported through `onAuditError` with its tool and requestId. `Infinity`
239
- * waits without bound.
242
+ * waits without bound. Any other value (NaN, a negative number) is
243
+ * rejected at construction, because it would leave the drain with no
244
+ * deadline at all.
240
245
  * @default 30_000
241
246
  */
242
247
  closeDrainTimeoutMs?: number;
243
248
  /**
244
249
  * Called when the audit layer itself fails (event serialization, a
245
250
  * throwing onEvent sink). The audit layer NEVER throws into the tool-call
246
- * path; failures are reported here instead. If this hook itself throws,
247
- * the exception is contained and never reaches the caller either.
251
+ * path; failures are reported here instead. If this hook itself throws or
252
+ * returns a rejected promise, the failure is contained and never reaches
253
+ * the caller either.
248
254
  * @default console.error
249
255
  */
250
256
  onAuditError?: (
251
257
  err: unknown,
252
258
  info: { tool: string; requestId: string; sessionId?: string },
253
- ) => void;
259
+ ) => unknown;
254
260
  }
255
261
 
256
262
  export interface AuditMiddlewareHandle {
package/src/verify.ts CHANGED
@@ -12,10 +12,26 @@ const DOMAIN_CHAIN = Buffer.from('mcpose/v2/chain');
12
12
  export type ChainVerification =
13
13
  { valid: true } | { valid: false; index: number; reason: string };
14
14
 
15
- function hexEqual(aHex: string, bHex: string): boolean {
16
- const a = Buffer.from(aHex, 'hex');
17
- const b = Buffer.from(bHex, 'hex');
18
- return a.length === b.length && a.length > 0 && timingSafeEqual(a, b);
15
+ /**
16
+ * Canonical hex: lowercase, even length, hex digits only, non-empty. This
17
+ * is what the producer writes (`digest('hex')`), and the exact string a
18
+ * third-party verifier compares.
19
+ */
20
+ const CANONICAL_HEX = /^(?:[0-9a-f]{2})+$/;
21
+
22
+ /**
23
+ * Compares a stored hex string against the recomputed value in constant
24
+ * time. The stored string must be canonical first: Node's hex decoder drops
25
+ * a trailing odd nibble and stops at the first non-hex character, so
26
+ * `sig + '0'`, `sig + 'z'` and `SIG` all decode to the stored bytes and would
27
+ * otherwise verify. The verifiers authenticate the stored string itself, not
28
+ * just its decoding, so two implementations agree on one artifact (#281).
29
+ */
30
+ function hexEqual(storedHex: string, expectedHex: string): boolean {
31
+ if (!CANONICAL_HEX.test(storedHex)) return false;
32
+ const a = Buffer.from(storedHex, 'hex');
33
+ const b = Buffer.from(expectedHex, 'hex');
34
+ return a.length === b.length && timingSafeEqual(a, b);
19
35
  }
20
36
 
21
37
  /**