@mcpose/audit 2.0.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 (38) hide show
  1. package/LICENSE +21 -0
  2. package/dist/__tests__/middleware.test.d.ts +2 -0
  3. package/dist/__tests__/middleware.test.d.ts.map +1 -0
  4. package/dist/__tests__/middleware.test.js +152 -0
  5. package/dist/__tests__/middleware.test.js.map +1 -0
  6. package/dist/__tests__/sensitivity.test.d.ts +2 -0
  7. package/dist/__tests__/sensitivity.test.d.ts.map +1 -0
  8. package/dist/__tests__/sensitivity.test.js +27 -0
  9. package/dist/__tests__/sensitivity.test.js.map +1 -0
  10. package/dist/__tests__/signingKey.test.d.ts +2 -0
  11. package/dist/__tests__/signingKey.test.d.ts.map +1 -0
  12. package/dist/__tests__/signingKey.test.js +37 -0
  13. package/dist/__tests__/signingKey.test.js.map +1 -0
  14. package/dist/chain.d.ts +12 -0
  15. package/dist/chain.d.ts.map +1 -0
  16. package/dist/chain.js +66 -0
  17. package/dist/chain.js.map +1 -0
  18. package/dist/index.d.ts +6 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +5 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/middleware.d.ts +3 -0
  23. package/dist/middleware.d.ts.map +1 -0
  24. package/dist/middleware.js +140 -0
  25. package/dist/middleware.js.map +1 -0
  26. package/dist/sensitivity.d.ts +3 -0
  27. package/dist/sensitivity.d.ts.map +1 -0
  28. package/dist/sensitivity.js +8 -0
  29. package/dist/sensitivity.js.map +1 -0
  30. package/dist/signingKey.d.ts +3 -0
  31. package/dist/signingKey.d.ts.map +1 -0
  32. package/dist/signingKey.js +13 -0
  33. package/dist/signingKey.js.map +1 -0
  34. package/dist/types.d.ts +98 -0
  35. package/dist/types.d.ts.map +1 -0
  36. package/dist/types.js +2 -0
  37. package/dist/types.js.map +1 -0
  38. package/package.json +47 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Amir Gorji
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=middleware.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/middleware.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,152 @@
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 { createProxyContext } from 'mcpose';
6
+ const identity = {
7
+ sub: 'user-1',
8
+ type: 'human',
9
+ roles: ['analyst'],
10
+ claims: {},
11
+ resolvedAt: '2026-06-01T00:00:00.000Z',
12
+ source: 'jwt',
13
+ };
14
+ function makeOptions(overrides = {}) {
15
+ return {
16
+ signingKey: createDefaultSigningKeyProvider('test-secret'),
17
+ sensitivityResolver: createSensitivityResolver({ search: 'low', transfer: 'high' }),
18
+ onEvent: vi.fn(),
19
+ ...overrides,
20
+ };
21
+ }
22
+ function makeCtx(sessionId) {
23
+ return createProxyContext({ transport: 'http', identity, sessionId });
24
+ }
25
+ function makeReq(tool, args = {}) {
26
+ return {
27
+ method: 'tools/call',
28
+ params: { name: tool, arguments: args },
29
+ };
30
+ }
31
+ describe('createAuditMiddleware — tracer bullet', () => {
32
+ it('calls onEvent after a successful tool call', async () => {
33
+ const onEvent = vi.fn();
34
+ const { middleware } = createAuditMiddleware(makeOptions({ onEvent }));
35
+ const ctx = makeCtx('session-1');
36
+ await middleware(makeReq('search'), async () => ({ content: [] }), ctx);
37
+ expect(onEvent).toHaveBeenCalledOnce();
38
+ const event = onEvent.mock.calls[0][0];
39
+ expect(event.tool).toBe('search');
40
+ expect(event.outcome).toBe('success');
41
+ expect(event.identity.sub).toBe('user-1');
42
+ expect(event.sessionId).toBe('session-1');
43
+ expect(event.sensitivityTier).toBe('low');
44
+ });
45
+ it('records error outcome when next throws', async () => {
46
+ const onEvent = vi.fn();
47
+ const { middleware } = createAuditMiddleware(makeOptions({ onEvent }));
48
+ await expect(middleware(makeReq('search'), async () => { throw new Error('upstream down'); }, makeCtx())).rejects.toThrow('upstream down');
49
+ const event = onEvent.mock.calls[0][0];
50
+ expect(event.outcome).toBe('error');
51
+ });
52
+ it('sets replayManifestPosition sequentially within a session', async () => {
53
+ const events = [];
54
+ const { middleware } = createAuditMiddleware(makeOptions({ onEvent: (e) => events.push(e) }));
55
+ const ctx = makeCtx('sess-seq');
56
+ await middleware(makeReq('search'), async () => ({ content: [] }), ctx);
57
+ await middleware(makeReq('search'), async () => ({ content: [] }), ctx);
58
+ await middleware(makeReq('search'), async () => ({ content: [] }), ctx);
59
+ expect(events.map((e) => e.replayManifestPosition)).toEqual([0, 1, 2]);
60
+ });
61
+ });
62
+ describe('createAuditMiddleware — HMAC chain', () => {
63
+ it('first event chainHash is non-empty', async () => {
64
+ const events = [];
65
+ const { middleware } = createAuditMiddleware(makeOptions({ onEvent: (e) => events.push(e) }));
66
+ await middleware(makeReq('search'), async () => ({ content: [] }), makeCtx('s1'));
67
+ expect(events[0].chainHash).toBeTruthy();
68
+ expect(events[0].chainHash.length).toBeGreaterThan(0);
69
+ });
70
+ it('each chainHash differs from the previous (chain advances)', async () => {
71
+ const events = [];
72
+ const { middleware } = createAuditMiddleware(makeOptions({ onEvent: (e) => events.push(e) }));
73
+ const ctx = makeCtx('s2');
74
+ for (let i = 0; i < 5; i++) {
75
+ await middleware(makeReq('search'), async () => ({ content: [] }), ctx);
76
+ }
77
+ const hashes = events.map((e) => e.chainHash);
78
+ const unique = new Set(hashes);
79
+ expect(unique.size).toBe(5);
80
+ });
81
+ });
82
+ describe('createAuditMiddleware — sensitivity tiers', () => {
83
+ it('low-tier event has inputRaw and outputRaw', async () => {
84
+ const events = [];
85
+ const { middleware } = createAuditMiddleware(makeOptions({ onEvent: (e) => events.push(e) }));
86
+ await middleware(makeReq('search', { q: 'hello' }), async () => ({ content: [{ type: 'text', text: 'result' }] }), makeCtx());
87
+ const event = events[0];
88
+ expect(event.sensitivityTier).toBe('low');
89
+ if (event.sensitivityTier === 'low') {
90
+ expect(event.inputRaw).toEqual({ q: 'hello' });
91
+ }
92
+ });
93
+ it('high-tier event has encrypted fields, no inputRaw/outputRaw', async () => {
94
+ const events = [];
95
+ const { middleware } = createAuditMiddleware(makeOptions({ onEvent: (e) => events.push(e) }));
96
+ await middleware(makeReq('transfer', { amount: 1000 }), async () => ({ content: [] }), makeCtx());
97
+ const event = events[0];
98
+ expect(event.sensitivityTier).toBe('high');
99
+ if (event.sensitivityTier === 'high') {
100
+ expect(typeof event.inputEncrypted).toBe('string');
101
+ expect(typeof event.outputEncrypted).toBe('string');
102
+ expect('inputRaw' in event).toBe(false);
103
+ }
104
+ });
105
+ });
106
+ describe('createAuditMiddleware — closeSession', () => {
107
+ it('returns undefined for unknown session', async () => {
108
+ const { closeSession } = createAuditMiddleware(makeOptions());
109
+ const result = await closeSession('no-such-session');
110
+ expect(result).toBeUndefined();
111
+ });
112
+ it('returns undefined for session with no events', async () => {
113
+ const { closeSession } = createAuditMiddleware(makeOptions());
114
+ const result = await closeSession('empty-session');
115
+ expect(result).toBeUndefined();
116
+ });
117
+ it('returns ReplayManifest with correct fields after events', async () => {
118
+ const onManifest = vi.fn();
119
+ const { middleware, closeSession } = createAuditMiddleware(makeOptions({ onManifest }));
120
+ const ctx = makeCtx('sess-manifest');
121
+ await middleware(makeReq('search'), async () => ({ content: [] }), ctx);
122
+ await middleware(makeReq('search'), async () => ({ content: [] }), ctx);
123
+ const manifest = await closeSession('sess-manifest');
124
+ expect(manifest).toBeDefined();
125
+ expect(manifest.sessionId).toBe('sess-manifest');
126
+ expect(manifest.eventCount).toBe(2);
127
+ expect(manifest.merkleRoot).toBeTruthy();
128
+ expect(manifest.merkleProofs).toHaveLength(2);
129
+ expect(manifest.signature).toBeTruthy();
130
+ expect(manifest.signedBy).toBeTruthy();
131
+ expect(onManifest).toHaveBeenCalledOnce();
132
+ expect(onManifest.mock.calls[0][0]).toEqual(manifest);
133
+ });
134
+ });
135
+ describe('createAuditMiddleware — Merkle proof', () => {
136
+ it('proof for each event verifies against the merkle root', async () => {
137
+ const { verifyMerkleProof } = await import('../chain.js');
138
+ const events = [];
139
+ const { middleware, closeSession } = createAuditMiddleware(makeOptions({ onEvent: (e) => events.push(e) }));
140
+ const ctx = makeCtx('sess-merkle');
141
+ for (let i = 0; i < 4; i++) {
142
+ await middleware(makeReq('search'), async () => ({ content: [] }), ctx);
143
+ }
144
+ const manifest = await closeSession('sess-merkle');
145
+ expect(manifest).toBeDefined();
146
+ for (let i = 0; i < events.length; i++) {
147
+ const valid = verifyMerkleProof(events[i].chainHash, manifest.merkleProofs[i], manifest.merkleRoot);
148
+ expect(valid).toBe(true);
149
+ }
150
+ });
151
+ });
152
+ //# sourceMappingURL=middleware.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.test.js","sourceRoot":"","sources":["../../src/__tests__/middleware.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,+BAA+B,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAG9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAE5C,MAAM,QAAQ,GAAa;IACzB,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,OAAO;IACb,KAAK,EAAE,CAAC,SAAS,CAAC;IAClB,MAAM,EAAE,EAAE;IACV,UAAU,EAAE,0BAA0B;IACtC,MAAM,EAAE,KAAK;CACd,CAAC;AAEF,SAAS,WAAW,CAAC,YAAmC,EAAE;IACxD,OAAO;QACL,UAAU,EAAE,+BAA+B,CAAC,aAAa,CAAC;QAC1D,mBAAmB,EAAE,yBAAyB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnF,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE;QAChB,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,SAAkB;IACjC,OAAO,kBAAkB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,OAAO,CAAC,IAAY,EAAE,OAAgC,EAAE;IAC/D,OAAO;QACL,MAAM,EAAE,YAAqB;QAC7B,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;KACxC,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,uCAAuC,EAAE,GAAG,EAAE;IACrD,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACxB,MAAM,EAAE,UAAU,EAAE,GAAG,qBAAqB,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QACvE,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;QAEjC,MAAM,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QAExE,MAAM,CAAC,OAAO,CAAC,CAAC,oBAAoB,EAAE,CAAC;QACvC,MAAM,KAAK,GAAe,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACxB,MAAM,EAAE,UAAU,EAAE,GAAG,qBAAqB,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QAEvE,MAAM,MAAM,CACV,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,IAAI,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAC5F,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAEnC,MAAM,KAAK,GAAe,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QACzE,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,MAAM,EAAE,UAAU,EAAE,GAAG,qBAAqB,CAC1C,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAChD,CAAC;QACF,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QAEhC,MAAM,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QACxE,MAAM,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QACxE,MAAM,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QAExE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,MAAM,EAAE,UAAU,EAAE,GAAG,qBAAqB,CAC1C,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAChD,CAAC;QACF,MAAM,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAClF,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QACzE,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,MAAM,EAAE,UAAU,EAAE,GAAG,qBAAqB,CAC1C,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAChD,CAAC;QACF,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QAC1E,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,2CAA2C,EAAE,GAAG,EAAE;IACzD,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,MAAM,EAAE,UAAU,EAAE,GAAG,qBAAqB,CAC1C,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAChD,CAAC;QACF,MAAM,UAAU,CACd,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EACjC,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAC7D,OAAO,EAAE,CACV,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,KAAK,CAAC,eAAe,KAAK,KAAK,EAAE,CAAC;YACpC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,MAAM,EAAE,UAAU,EAAE,GAAG,qBAAqB,CAC1C,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAChD,CAAC;QACF,MAAM,UAAU,CACd,OAAO,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EACrC,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAC7B,OAAO,EAAE,CACV,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,KAAK,CAAC,eAAe,KAAK,MAAM,EAAE,CAAC;YACrC,MAAM,CAAC,OAAO,KAAK,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,CAAC,OAAO,KAAK,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACpD,MAAM,CAAC,UAAU,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,sCAAsC,EAAE,GAAG,EAAE;IACpD,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,EAAE,YAAY,EAAE,GAAG,qBAAqB,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,iBAAiB,CAAC,CAAC;QACrD,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,EAAE,YAAY,EAAE,GAAG,qBAAqB,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,eAAe,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,MAAM,UAAU,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,qBAAqB,CACxD,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,CAC5B,CAAC;QACF,MAAM,GAAG,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;QACrC,MAAM,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QACxE,MAAM,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QAExE,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,eAAe,CAAC,CAAC;QAErD,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/B,MAAM,CAAC,QAAS,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAClD,MAAM,CAAC,QAAS,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,QAAS,CAAC,UAAU,CAAC,CAAC,UAAU,EAAE,CAAC;QAC1C,MAAM,CAAC,QAAS,CAAC,YAAY,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,QAAS,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;QACzC,MAAM,CAAC,QAAS,CAAC,QAAQ,CAAC,CAAC,UAAU,EAAE,CAAC;QACxC,MAAM,CAAC,UAAU,CAAC,CAAC,oBAAoB,EAAE,CAAC;QAC1C,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,sCAAsC,EAAE,GAAG,EAAE;IACpD,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,qBAAqB,CACxD,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAChD,CAAC;QACF,MAAM,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;QACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QAC1E,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,aAAa,CAAC,CAAC;QACnD,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QAE/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,iBAAiB,CAC7B,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,EACnB,QAAS,CAAC,YAAY,CAAC,CAAC,CAAC,EACzB,QAAS,CAAC,UAAU,CACrB,CAAC;YACF,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sensitivity.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sensitivity.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/sensitivity.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { createSensitivityResolver } from '../sensitivity.js';
3
+ const identity = {
4
+ sub: 'u1',
5
+ type: 'human',
6
+ roles: [],
7
+ claims: {},
8
+ resolvedAt: new Date().toISOString(),
9
+ source: 'jwt',
10
+ };
11
+ describe('createSensitivityResolver', () => {
12
+ it('returns the mapped tier for a known tool', () => {
13
+ const resolve = createSensitivityResolver({ transfer_funds: 'high', get_balance: 'low' });
14
+ expect(resolve('transfer_funds', identity, {})).toBe('high');
15
+ expect(resolve('get_balance', identity, {})).toBe('low');
16
+ });
17
+ it('returns high for an unknown tool', () => {
18
+ const resolve = createSensitivityResolver({ get_balance: 'low' });
19
+ expect(resolve('unknown_tool', identity, {})).toBe('high');
20
+ });
21
+ it('override fn takes precedence over the static map', () => {
22
+ const resolve = createSensitivityResolver({ get_balance: 'low' }, (_tool, _identity, args) => (args.pii ? 'high' : 'low'));
23
+ expect(resolve('get_balance', identity, { pii: true })).toBe('high');
24
+ expect(resolve('get_balance', identity, {})).toBe('low');
25
+ });
26
+ });
27
+ //# sourceMappingURL=sensitivity.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sensitivity.test.js","sourceRoot":"","sources":["../../src/__tests__/sensitivity.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAG9D,MAAM,QAAQ,GAAa;IACzB,GAAG,EAAE,IAAI;IACT,IAAI,EAAE,OAAO;IACb,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,EAAE;IACV,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;IACpC,MAAM,EAAE,KAAK;CACd,CAAC;AAEF,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,OAAO,GAAG,yBAAyB,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7D,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,OAAO,GAAG,yBAAyB,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;QAClE,MAAM,CAAC,OAAO,CAAC,cAAc,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,OAAO,GAAG,yBAAyB,CACvC,EAAE,WAAW,EAAE,KAAK,EAAE,EACtB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CACxD,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrE,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=signingKey.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signingKey.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/signingKey.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { createDefaultSigningKeyProvider } from '../signingKey.js';
3
+ describe('createDefaultSigningKeyProvider', () => {
4
+ it('has correct shape', () => {
5
+ const provider = createDefaultSigningKeyProvider('secret');
6
+ expect(provider.algorithm).toBe('HMAC-SHA256');
7
+ expect(typeof provider.keyId).toBe('string');
8
+ expect(provider.keyId.length).toBeGreaterThan(0);
9
+ expect(typeof provider.sign).toBe('function');
10
+ });
11
+ it('sign returns a non-empty buffer', async () => {
12
+ const provider = createDefaultSigningKeyProvider('secret');
13
+ const sig = await provider.sign(Buffer.from('hello'));
14
+ expect(sig).toBeInstanceOf(Buffer);
15
+ expect(sig.length).toBeGreaterThan(0);
16
+ });
17
+ it('same secret + same data → same signature (deterministic)', async () => {
18
+ const p1 = createDefaultSigningKeyProvider('secret');
19
+ const p2 = createDefaultSigningKeyProvider('secret');
20
+ const data = Buffer.from('test-data');
21
+ const [s1, s2] = await Promise.all([p1.sign(data), p2.sign(data)]);
22
+ expect(s1.toString('hex')).toBe(s2.toString('hex'));
23
+ });
24
+ it('different secrets → different signatures', async () => {
25
+ const p1 = createDefaultSigningKeyProvider('secret-a');
26
+ const p2 = createDefaultSigningKeyProvider('secret-b');
27
+ const data = Buffer.from('test-data');
28
+ const [s1, s2] = await Promise.all([p1.sign(data), p2.sign(data)]);
29
+ expect(s1.toString('hex')).not.toBe(s2.toString('hex'));
30
+ });
31
+ it('accepts Buffer as secret', async () => {
32
+ const provider = createDefaultSigningKeyProvider(Buffer.from('secret'));
33
+ const sig = await provider.sign(Buffer.from('data'));
34
+ expect(sig).toBeInstanceOf(Buffer);
35
+ });
36
+ });
37
+ //# sourceMappingURL=signingKey.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signingKey.test.js","sourceRoot":"","sources":["../../src/__tests__/signingKey.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,+BAA+B,EAAE,MAAM,kBAAkB,CAAC;AAEnE,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,QAAQ,GAAG,+BAA+B,CAAC,QAAQ,CAAC,CAAC;QAC3D,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC/C,MAAM,CAAC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,CAAC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,QAAQ,GAAG,+BAA+B,CAAC,QAAQ,CAAC,CAAC;QAC3D,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,EAAE,GAAG,+BAA+B,CAAC,QAAQ,CAAC,CAAC;QACrD,MAAM,EAAE,GAAG,+BAA+B,CAAC,QAAQ,CAAC,CAAC;QACrD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,EAAE,GAAG,+BAA+B,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,EAAE,GAAG,+BAA+B,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,QAAQ,GAAG,+BAA+B,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QACxE,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACrD,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { MerkleProof } from './types.js';
2
+ export declare function sha256hex(data: string | Buffer): string;
3
+ export declare function hmacSha256hex(data: string | Buffer, key: Buffer): string;
4
+ /**
5
+ * HMAC-SHA256(JSON(entryWithoutChainHash) + prevChainHash, signingKey).
6
+ * The entry is serialized without its own chainHash to avoid circular dependency.
7
+ */
8
+ export declare function computeChainHash(entryWithoutChainHash: Record<string, unknown>, prevChainHash: string, signingKey: Buffer): string;
9
+ export declare function computeMerkleRoot(hashes: string[]): string;
10
+ export declare function computeMerkleProof(hashes: string[], index: number): MerkleProof;
11
+ export declare function verifyMerkleProof(leafHash: string, proof: MerkleProof, root: string): boolean;
12
+ //# sourceMappingURL=chain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAExE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9C,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,GACjB,MAAM,CAGR;AAaD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAQ1D;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,CAoB/E;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAUT"}
package/dist/chain.js ADDED
@@ -0,0 +1,66 @@
1
+ import { createHash, createHmac } from 'node:crypto';
2
+ export function sha256hex(data) {
3
+ return createHash('sha256').update(data).digest('hex');
4
+ }
5
+ export function hmacSha256hex(data, key) {
6
+ return createHmac('sha256', key).update(data).digest('hex');
7
+ }
8
+ /**
9
+ * HMAC-SHA256(JSON(entryWithoutChainHash) + prevChainHash, signingKey).
10
+ * The entry is serialized without its own chainHash to avoid circular dependency.
11
+ */
12
+ export function computeChainHash(entryWithoutChainHash, prevChainHash, signingKey) {
13
+ const data = JSON.stringify(entryWithoutChainHash) + prevChainHash;
14
+ return hmacSha256hex(data, signingKey);
15
+ }
16
+ function nextPow2Layer(hashes) {
17
+ const layer = [...hashes];
18
+ // Pad to even length by duplicating the last node (standard Merkle convention)
19
+ if (layer.length % 2 === 1)
20
+ layer.push(layer[layer.length - 1]);
21
+ const next = [];
22
+ for (let i = 0; i < layer.length; i += 2) {
23
+ next.push(sha256hex(layer[i] + layer[i + 1]));
24
+ }
25
+ return next;
26
+ }
27
+ export function computeMerkleRoot(hashes) {
28
+ if (hashes.length === 0)
29
+ return sha256hex('');
30
+ if (hashes.length === 1)
31
+ return hashes[0];
32
+ let layer = [...hashes];
33
+ while (layer.length > 1) {
34
+ layer = nextPow2Layer(layer);
35
+ }
36
+ return layer[0];
37
+ }
38
+ export function computeMerkleProof(hashes, index) {
39
+ const siblings = [];
40
+ const directions = [];
41
+ let layer = [...hashes];
42
+ let idx = index;
43
+ while (layer.length > 1) {
44
+ // Pad odd layers
45
+ if (layer.length % 2 === 1)
46
+ layer.push(layer[layer.length - 1]);
47
+ const siblingIdx = idx % 2 === 0 ? idx + 1 : idx - 1;
48
+ siblings.push(layer[siblingIdx]);
49
+ directions.push(idx % 2 === 0 ? 'right' : 'left');
50
+ layer = nextPow2Layer(layer.slice(0, layer.length));
51
+ idx = Math.floor(idx / 2);
52
+ }
53
+ return { index, siblings, directions };
54
+ }
55
+ export function verifyMerkleProof(leafHash, proof, root) {
56
+ let current = leafHash;
57
+ for (let i = 0; i < proof.siblings.length; i++) {
58
+ const sibling = proof.siblings[i];
59
+ const dir = proof.directions[i];
60
+ current = dir === 'right'
61
+ ? sha256hex(current + sibling)
62
+ : sha256hex(sibling + current);
63
+ }
64
+ return current === root;
65
+ }
66
+ //# sourceMappingURL=chain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chain.js","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export type { SensitivityTier, SensitivityResolverFn, HashAlgorithm, SigningKeyProvider, CostMetadata, AuditEventBase, LowAuditEvent, MediumAuditEvent, HighAuditEvent, AuditEvent, MerkleProof, ReplayManifest, AuditOptions, AuditMiddlewareHandle, } from './types.js';
2
+ export { createSensitivityResolver } from './sensitivity.js';
3
+ export { createDefaultSigningKeyProvider } from './signingKey.js';
4
+ export { createAuditMiddleware } from './middleware.js';
5
+ export { computeMerkleRoot, computeMerkleProof, verifyMerkleProof } from './chain.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,UAAU,EACV,WAAW,EACX,cAAc,EACd,YAAY,EACZ,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { createSensitivityResolver } from './sensitivity.js';
2
+ export { createDefaultSigningKeyProvider } from './signingKey.js';
3
+ export { createAuditMiddleware } from './middleware.js';
4
+ export { computeMerkleRoot, computeMerkleProof, verifyMerkleProof } from './chain.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { AuditMiddlewareHandle, AuditOptions } from './types.js';
2
+ export declare function createAuditMiddleware(options: AuditOptions): AuditMiddlewareHandle;
3
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,qBAAqB,EACrB,YAAY,EAKb,MAAM,YAAY,CAAC;AAkCpB,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,YAAY,GAAG,qBAAqB,CA2FlF"}
@@ -0,0 +1,140 @@
1
+ import { createCipheriv, randomBytes, createHash } from 'node:crypto';
2
+ import { computeChainHash, computeMerkleProof, computeMerkleRoot, sha256hex } from './chain.js';
3
+ function aesEncrypt(plaintext, key) {
4
+ const iv = randomBytes(12);
5
+ const cipher = createCipheriv('aes-256-gcm', key.subarray(0, 32), iv);
6
+ const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
7
+ const tag = cipher.getAuthTag();
8
+ return Buffer.concat([iv, tag, encrypted]).toString('base64');
9
+ }
10
+ function deriveEventKey(chainKey, eventId) {
11
+ return createHash('sha256').update(chainKey).update(eventId).digest();
12
+ }
13
+ function anonymousIdentity() {
14
+ return {
15
+ sub: 'anonymous',
16
+ type: 'service',
17
+ roles: [],
18
+ claims: {},
19
+ resolvedAt: new Date().toISOString(),
20
+ source: 'custom',
21
+ };
22
+ }
23
+ export function createAuditMiddleware(options) {
24
+ const sessions = new Map();
25
+ // Derive a stable 32-byte key from the signingKey.keyId (SHA-256 hex of the secret).
26
+ // Used for HMAC chain hashes (synchronous) and per-event AES-256 encryption.
27
+ // The async sign() on signingKey is reserved for signing the ReplayManifest root.
28
+ const chainKey = Buffer.from(options.signingKey.keyId, 'hex');
29
+ const middleware = async (req, next, ctx) => {
30
+ const start = Date.now();
31
+ const identity = ctx.identity ?? anonymousIdentity();
32
+ const sessionId = ctx.sessionId;
33
+ if (sessionId && !sessions.has(sessionId)) {
34
+ sessions.set(sessionId, {
35
+ events: [],
36
+ prevChainHash: '',
37
+ startedAt: new Date().toISOString(),
38
+ identity,
39
+ });
40
+ }
41
+ const session = sessionId ? sessions.get(sessionId) : undefined;
42
+ const position = session?.events.length ?? 0;
43
+ const tool = req.params.name;
44
+ const args = req.params.arguments ?? {};
45
+ const tier = options.sensitivityResolver(tool, identity, args);
46
+ let outcome = 'success';
47
+ let result;
48
+ let threw = false;
49
+ try {
50
+ result = await next(req);
51
+ }
52
+ catch (err) {
53
+ outcome = 'error';
54
+ threw = true;
55
+ result = undefined;
56
+ const event = buildEvent({
57
+ ctx, identity, tool, args, result: undefined,
58
+ duration_ms: Date.now() - start, outcome, position,
59
+ prevChainHash: session?.prevChainHash ?? '',
60
+ tier, chainKey,
61
+ });
62
+ advanceSession(session, event);
63
+ await options.onEvent(event);
64
+ throw err;
65
+ }
66
+ if (!threw) {
67
+ const event = buildEvent({
68
+ ctx, identity, tool, args, result,
69
+ duration_ms: Date.now() - start, outcome, position,
70
+ prevChainHash: session?.prevChainHash ?? '',
71
+ tier, chainKey,
72
+ });
73
+ advanceSession(session, event);
74
+ await options.onEvent(event);
75
+ }
76
+ return result;
77
+ };
78
+ const closeSession = async (sessionId) => {
79
+ const session = sessions.get(sessionId);
80
+ if (!session || session.events.length === 0)
81
+ return undefined;
82
+ sessions.delete(sessionId);
83
+ const hashes = session.events.map((e) => e.chainHash);
84
+ const merkleRoot = computeMerkleRoot(hashes);
85
+ const merkleProofs = hashes.map((_, i) => computeMerkleProof(hashes, i));
86
+ const signature = (await options.signingKey.sign(Buffer.from(merkleRoot))).toString('hex');
87
+ const manifest = {
88
+ sessionId,
89
+ identity: session.identity,
90
+ startedAt: session.startedAt,
91
+ closedAt: new Date().toISOString(),
92
+ eventCount: session.events.length,
93
+ merkleRoot,
94
+ merkleProofs,
95
+ signedBy: options.signingKey.keyId,
96
+ signature,
97
+ };
98
+ await options.onManifest?.(manifest);
99
+ return manifest;
100
+ };
101
+ return { middleware, closeSession };
102
+ }
103
+ // ── Helpers ────────────────────────────────────────────────────────────────────
104
+ function advanceSession(session, event) {
105
+ if (!session)
106
+ return;
107
+ session.events.push(event);
108
+ session.prevChainHash = event.chainHash;
109
+ }
110
+ function buildEvent(p) {
111
+ const stableFields = {
112
+ id: p.ctx.requestId,
113
+ timestamp: new Date().toISOString(),
114
+ ...(p.ctx.sessionId !== undefined ? { sessionId: p.ctx.sessionId } : {}),
115
+ ...(p.ctx.delegatedFrom !== undefined ? { delegatedFrom: p.ctx.delegatedFrom } : {}),
116
+ identity: p.identity,
117
+ tool: p.tool,
118
+ duration_ms: p.duration_ms,
119
+ outcome: p.outcome,
120
+ inputHash: sha256hex(JSON.stringify(p.args)),
121
+ outputHash: sha256hex(JSON.stringify(p.result ?? null)),
122
+ replayManifestPosition: p.position,
123
+ };
124
+ const chainHash = computeChainHash(stableFields, p.prevChainHash, p.chainKey);
125
+ const base = { ...stableFields, chainHash };
126
+ if (p.tier === 'high') {
127
+ const eventKey = deriveEventKey(p.chainKey, base.id);
128
+ return {
129
+ ...base,
130
+ sensitivityTier: 'high',
131
+ inputEncrypted: aesEncrypt(JSON.stringify(p.args), eventKey),
132
+ outputEncrypted: aesEncrypt(JSON.stringify(p.result ?? null), eventKey),
133
+ };
134
+ }
135
+ if (p.tier === 'medium') {
136
+ return { ...base, sensitivityTier: 'medium', inputRaw: p.args, outputRaw: p.result };
137
+ }
138
+ return { ...base, sensitivityTier: 'low', inputRaw: p.args, outputRaw: p.result };
139
+ }
140
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SensitivityTier, SensitivityResolverFn } from './types.js';
2
+ export declare function createSensitivityResolver(map: Record<string, SensitivityTier>, override?: SensitivityResolverFn): SensitivityResolverFn;
3
+ //# sourceMappingURL=sensitivity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sensitivity.d.ts","sourceRoot":"","sources":["../src/sensitivity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEzE,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACpC,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,qBAAqB,CAKvB"}
@@ -0,0 +1,8 @@
1
+ export function createSensitivityResolver(map, override) {
2
+ return (tool, identity, args) => {
3
+ if (override)
4
+ return override(tool, identity, args);
5
+ return map[tool] ?? 'high';
6
+ };
7
+ }
8
+ //# sourceMappingURL=sensitivity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sensitivity.js","sourceRoot":"","sources":["../src/sensitivity.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,yBAAyB,CACvC,GAAoC,EACpC,QAAgC;IAEhC,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;QAC9B,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QACpD,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC;IAC7B,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { SigningKeyProvider } from './types.js';
2
+ export declare function createDefaultSigningKeyProvider(secret: Buffer | string): SigningKeyProvider;
3
+ //# sourceMappingURL=signingKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signingKey.d.ts","sourceRoot":"","sources":["../src/signingKey.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,MAAM,GAAG,MAAM,GACtB,kBAAkB,CAWpB"}
@@ -0,0 +1,13 @@
1
+ import { createHmac, createHash } from 'node:crypto';
2
+ export function createDefaultSigningKeyProvider(secret) {
3
+ const secretBuf = typeof secret === 'string' ? Buffer.from(secret) : secret;
4
+ const keyId = createHash('sha256').update(secretBuf).digest('hex');
5
+ return {
6
+ algorithm: 'HMAC-SHA256',
7
+ keyId,
8
+ async sign(data) {
9
+ return createHmac('sha256', secretBuf).update(data).digest();
10
+ },
11
+ };
12
+ }
13
+ //# sourceMappingURL=signingKey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signingKey.js","sourceRoot":"","sources":["../src/signingKey.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGrD,MAAM,UAAU,+BAA+B,CAC7C,MAAuB;IAEvB,MAAM,SAAS,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5E,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAEnE,OAAO;QACL,SAAS,EAAE,aAAa;QACxB,KAAK;QACL,KAAK,CAAC,IAAI,CAAC,IAAY;YACrB,OAAO,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;QAC/D,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,98 @@
1
+ import type { Identity, RejectionReason, ToolMiddleware } from 'mcpose';
2
+ export type { ToolMiddleware };
3
+ export type SensitivityTier = 'low' | 'medium' | 'high';
4
+ export type SensitivityResolverFn = (tool: string, identity: Identity, args: Record<string, unknown>) => SensitivityTier;
5
+ export type HashAlgorithm = 'SHA-256';
6
+ export interface SigningKeyProvider {
7
+ sign(data: Buffer): Promise<Buffer>;
8
+ keyId: string;
9
+ algorithm: 'HMAC-SHA256';
10
+ }
11
+ export interface CostMetadata {
12
+ inputTokens?: number;
13
+ outputTokens?: number;
14
+ totalCostUsd?: number;
15
+ }
16
+ export interface AuditEventBase {
17
+ /** Equals the ProxyContext requestId. */
18
+ id: string;
19
+ timestamp: string;
20
+ sessionId?: string;
21
+ identity: Identity;
22
+ delegatedFrom?: Identity[];
23
+ tool: string;
24
+ duration_ms: number;
25
+ streamedChunkCount?: number;
26
+ outcome: 'success' | 'rejected' | 'error';
27
+ rejectionReason?: RejectionReason;
28
+ cost?: CostMetadata;
29
+ inputHash: string;
30
+ outputHash: string;
31
+ chainHash: string;
32
+ replayManifestPosition: number;
33
+ }
34
+ export type LowAuditEvent = AuditEventBase & {
35
+ sensitivityTier: 'low';
36
+ inputRaw: Record<string, unknown>;
37
+ outputRaw: unknown;
38
+ };
39
+ export type MediumAuditEvent = AuditEventBase & {
40
+ sensitivityTier: 'medium';
41
+ inputRaw: Record<string, unknown>;
42
+ outputRaw: unknown;
43
+ };
44
+ export type HighAuditEvent = AuditEventBase & {
45
+ sensitivityTier: 'high';
46
+ inputEncrypted: string;
47
+ outputEncrypted: string;
48
+ };
49
+ export type AuditEvent = LowAuditEvent | MediumAuditEvent | HighAuditEvent;
50
+ export interface MerkleProof {
51
+ index: number;
52
+ siblings: string[];
53
+ directions: ('left' | 'right')[];
54
+ }
55
+ export interface ReplayManifest {
56
+ sessionId: string;
57
+ identity: Identity;
58
+ startedAt: string;
59
+ closedAt: string;
60
+ eventCount: number;
61
+ merkleRoot: string;
62
+ merkleProofs: MerkleProof[];
63
+ signedBy: string;
64
+ signature: string;
65
+ }
66
+ export interface AuditOptions {
67
+ signingKey: SigningKeyProvider;
68
+ hashAlgorithm?: HashAlgorithm;
69
+ sensitivityResolver: SensitivityResolverFn;
70
+ onEvent: (event: AuditEvent) => void | Promise<void>;
71
+ /**
72
+ * Called with the finished ReplayManifest when the host calls closeSession().
73
+ *
74
+ * Why this exists: ToolMiddleware is a pure per-request function with no
75
+ * lifecycle hooks. Sessions are owned by the HTTP transport, not by
76
+ * middleware. There is no in-band way for middleware to observe session close.
77
+ * This callback gives consumers a push-based way to receive the manifest
78
+ * exactly when the host signals the session has ended — mirroring how audit
79
+ * substrates in financial systems work: the host controls the flush boundary;
80
+ * the audit layer reacts.
81
+ */
82
+ onManifest?: (manifest: ReplayManifest) => void | Promise<void>;
83
+ /** @default true */
84
+ includeRejections?: boolean;
85
+ /** @default true */
86
+ includeCost?: boolean;
87
+ }
88
+ export interface AuditMiddlewareHandle {
89
+ middleware: ToolMiddleware;
90
+ /**
91
+ * Signal that a session has ended. Computes the Merkle tree over all audit
92
+ * events for the session, signs the root, fires onManifest, and returns the
93
+ * ReplayManifest. Returns undefined if the session had no events or is
94
+ * unknown.
95
+ */
96
+ closeSession(sessionId: string): Promise<ReplayManifest | undefined>;
97
+ }
98
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@mcpose/audit",
3
+ "version": "2.0.0",
4
+ "description": "Integrity-chained audit middleware for mcpose — HMAC chain, Merkle proofs, ReplayManifest",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "keywords": [
19
+ "mcp",
20
+ "audit",
21
+ "compliance",
22
+ "fintech",
23
+ "hmac",
24
+ "merkle"
25
+ ],
26
+ "author": "Amir Gorji",
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/amir-gorji/mcpose.git",
31
+ "directory": "packages/audit"
32
+ },
33
+ "peerDependencies": {
34
+ "mcpose": ">=2.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^22.0.0",
38
+ "typescript": "^5.0.0",
39
+ "vitest": "^3.0.0",
40
+ "mcpose": "2.0.1"
41
+ },
42
+ "scripts": {
43
+ "build": "tsc -p tsconfig.build.json",
44
+ "ts:ci": "tsc --noEmit",
45
+ "test": "vitest run --passWithNoTests"
46
+ }
47
+ }