@kya-os/mcp-i 0.1.0 → 1.2.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 +406 -71
- package/dist/149.js +1 -0
- package/dist/189.js +1 -0
- package/dist/261.js +1 -0
- package/dist/28.js +1 -0
- package/dist/295.js +1 -0
- package/dist/460.js +1 -0
- package/dist/570.js +1 -0
- package/dist/634.js +1 -0
- package/dist/647.js +1 -0
- package/dist/67.js +1 -0
- package/dist/739.js +1 -0
- package/dist/742.js +1 -0
- package/dist/904.js +1 -0
- package/dist/938.js +1 -0
- package/dist/auth/api-key.d.ts +16 -0
- package/dist/auth/api-key.js +82 -0
- package/dist/auth/jwt.d.ts +43 -0
- package/dist/auth/jwt.js +51 -0
- package/dist/auth/oauth/factory.d.ts +12 -0
- package/dist/auth/oauth/factory.js +36 -0
- package/dist/auth/oauth/index.d.ts +5 -0
- package/dist/auth/oauth/index.js +27 -0
- package/dist/auth/oauth/providers/proxy-provider.d.ts +13 -0
- package/dist/auth/oauth/providers/proxy-provider.js +159 -0
- package/dist/auth/oauth/router.d.ts +4 -0
- package/dist/auth/oauth/router.js +294 -0
- package/dist/auth/oauth/storage/memory-storage.d.ts +12 -0
- package/dist/auth/oauth/storage/memory-storage.js +40 -0
- package/dist/auth/oauth/types.d.ts +112 -0
- package/dist/auth/oauth/types.js +2 -0
- package/dist/cache/__tests__/cloudflare-kv-nonce-cache.test.d.ts +4 -0
- package/dist/cache/__tests__/cloudflare-kv-nonce-cache.test.js +176 -0
- package/dist/cache/__tests__/concurrency.test.d.ts +5 -0
- package/dist/cache/__tests__/concurrency.test.js +300 -0
- package/dist/cache/__tests__/dynamodb-nonce-cache.test.d.ts +4 -0
- package/dist/cache/__tests__/dynamodb-nonce-cache.test.js +176 -0
- package/dist/cache/__tests__/memory-nonce-cache.test.d.ts +4 -0
- package/dist/cache/__tests__/memory-nonce-cache.test.js +132 -0
- package/dist/cache/__tests__/nonce-cache-factory-simple.test.d.ts +4 -0
- package/dist/cache/__tests__/nonce-cache-factory-simple.test.js +133 -0
- package/dist/cache/__tests__/nonce-cache-factory.test.d.ts +4 -0
- package/dist/cache/__tests__/nonce-cache-factory.test.js +252 -0
- package/dist/cache/__tests__/redis-nonce-cache.test.d.ts +4 -0
- package/dist/cache/__tests__/redis-nonce-cache.test.js +95 -0
- package/dist/cache/cloudflare-kv-nonce-cache.d.ts +14 -0
- package/dist/cache/cloudflare-kv-nonce-cache.js +93 -0
- package/dist/cache/dynamodb-nonce-cache.d.ts +15 -0
- package/dist/cache/dynamodb-nonce-cache.js +92 -0
- package/dist/cache/index.d.ts +16 -0
- package/dist/cache/index.js +32 -0
- package/dist/cache/memory-nonce-cache.d.ts +44 -0
- package/dist/cache/memory-nonce-cache.js +105 -0
- package/dist/cache/nonce-cache-factory.d.ts +20 -0
- package/dist/cache/nonce-cache-factory.js +208 -0
- package/dist/cache/redis-nonce-cache.d.ts +14 -0
- package/dist/cache/redis-nonce-cache.js +53 -0
- package/dist/compiler/compiler-context.d.ts +23 -0
- package/dist/compiler/compiler-context.js +24 -0
- package/dist/compiler/config/constants.d.ts +41 -0
- package/dist/compiler/config/constants.js +45 -0
- package/dist/compiler/config/index.d.ts +252 -0
- package/dist/compiler/config/index.js +15 -0
- package/dist/compiler/config/injection.d.ts +26 -0
- package/dist/compiler/config/injection.js +58 -0
- package/dist/compiler/config/schemas/experimental/index.d.ts +91 -0
- package/dist/compiler/config/schemas/experimental/index.js +16 -0
- package/dist/compiler/config/schemas/experimental/oauth.d.ts +74 -0
- package/dist/compiler/config/schemas/experimental/oauth.js +25 -0
- package/dist/compiler/config/schemas/index.d.ts +6 -0
- package/dist/compiler/config/schemas/index.js +17 -0
- package/dist/compiler/config/schemas/paths.d.ts +9 -0
- package/dist/compiler/config/schemas/paths.js +12 -0
- package/dist/compiler/config/schemas/transport/http.d.ts +82 -0
- package/dist/compiler/config/schemas/transport/http.js +33 -0
- package/dist/compiler/config/schemas/transport/stdio.d.ts +9 -0
- package/dist/compiler/config/schemas/transport/stdio.js +15 -0
- package/dist/compiler/config/schemas/webpack.d.ts +3 -0
- package/dist/compiler/config/schemas/webpack.js +15 -0
- package/dist/compiler/config/types.d.ts +1 -0
- package/dist/compiler/config/types.js +2 -0
- package/dist/compiler/config/utils.d.ts +20 -0
- package/dist/compiler/config/utils.js +36 -0
- package/dist/compiler/generate-env-code.d.ts +1 -0
- package/dist/compiler/generate-env-code.js +8 -0
- package/dist/compiler/generate-import-code.d.ts +1 -0
- package/dist/compiler/generate-import-code.js +24 -0
- package/dist/compiler/get-webpack-config/get-entries.d.ts +3 -0
- package/dist/compiler/get-webpack-config/get-entries.js +29 -0
- package/dist/compiler/get-webpack-config/get-externals.d.ts +7 -0
- package/dist/compiler/get-webpack-config/get-externals.js +88 -0
- package/dist/compiler/get-webpack-config/get-injected-variables.d.ts +8 -0
- package/dist/compiler/get-webpack-config/get-injected-variables.js +25 -0
- package/dist/compiler/get-webpack-config/index.d.ts +4 -0
- package/dist/compiler/get-webpack-config/index.js +101 -0
- package/dist/compiler/get-webpack-config/plugins.d.ts +8 -0
- package/dist/compiler/get-webpack-config/plugins.js +132 -0
- package/dist/compiler/get-webpack-config/resolve-tsconfig-paths.d.ts +9 -0
- package/dist/compiler/get-webpack-config/resolve-tsconfig-paths.js +40 -0
- package/dist/compiler/index.d.ts +6 -0
- package/dist/compiler/index.js +194 -0
- package/dist/compiler/on-first-build.d.ts +3 -0
- package/dist/compiler/on-first-build.js +58 -0
- package/dist/compiler/parse-xmcp-config.d.ts +9 -0
- package/dist/compiler/parse-xmcp-config.js +155 -0
- package/dist/compiler/start-http-server.d.ts +1 -0
- package/dist/compiler/start-http-server.js +34 -0
- package/dist/index.d.ts +12 -54
- package/dist/index.js +22 -190
- package/dist/index.js.LICENSE.txt +49 -0
- package/dist/runtime/__tests__/audit.test.d.ts +4 -0
- package/dist/runtime/__tests__/audit.test.js +328 -0
- package/dist/runtime/__tests__/identity.test.d.ts +4 -0
- package/dist/runtime/__tests__/identity.test.js +164 -0
- package/dist/runtime/__tests__/mcpi-runtime.test.d.ts +4 -0
- package/dist/runtime/__tests__/mcpi-runtime.test.js +372 -0
- package/dist/runtime/__tests__/proof.test.d.ts +4 -0
- package/dist/runtime/__tests__/proof.test.js +302 -0
- package/dist/runtime/__tests__/session.test.d.ts +4 -0
- package/dist/runtime/__tests__/session.test.js +254 -0
- package/dist/runtime/__tests__/well-known.test.d.ts +4 -0
- package/dist/runtime/__tests__/well-known.test.js +312 -0
- package/dist/runtime/adapter-express.js +2 -0
- package/dist/runtime/adapter-express.js.LICENSE.txt +252 -0
- package/dist/runtime/adapter-nextjs.js +2 -0
- package/dist/runtime/adapter-nextjs.js.LICENSE.txt +53 -0
- package/dist/runtime/adapters/express/index.d.ts +2 -0
- package/dist/runtime/adapters/express/index.js +48 -0
- package/dist/runtime/adapters/nextjs/index.d.ts +8 -0
- package/dist/runtime/adapters/nextjs/index.js +18 -0
- package/dist/runtime/audit.d.ts +93 -0
- package/dist/runtime/audit.js +212 -0
- package/dist/runtime/debug.d.ts +118 -0
- package/dist/runtime/debug.js +612 -0
- package/dist/runtime/delegation-hooks.d.ts +85 -0
- package/dist/runtime/delegation-hooks.js +116 -0
- package/dist/runtime/demo.d.ts +71 -0
- package/dist/runtime/demo.js +135 -0
- package/dist/runtime/headers.d.ts +1 -0
- package/dist/runtime/headers.js +9 -0
- package/dist/runtime/http.js +2 -0
- package/dist/runtime/http.js.LICENSE.txt +252 -0
- package/dist/runtime/identity.d.ts +105 -0
- package/dist/runtime/identity.js +232 -0
- package/dist/runtime/index.d.ts +16 -0
- package/dist/runtime/index.js +56 -0
- package/dist/runtime/mcpi-runtime.d.ts +164 -0
- package/dist/runtime/mcpi-runtime.js +352 -0
- package/dist/runtime/proof.d.ts +87 -0
- package/dist/runtime/proof.js +223 -0
- package/dist/runtime/session.d.ts +88 -0
- package/dist/runtime/session.js +216 -0
- package/dist/runtime/stdio.js +2 -0
- package/dist/runtime/stdio.js.LICENSE.txt +1 -0
- package/dist/runtime/templates/home.d.ts +2 -0
- package/dist/runtime/templates/home.js +50 -0
- package/dist/runtime/transports/http/base-streamable-http.d.ts +25 -0
- package/dist/runtime/transports/http/base-streamable-http.js +16 -0
- package/dist/runtime/transports/http/http-context.d.ts +9 -0
- package/dist/runtime/transports/http/http-context.js +8 -0
- package/dist/runtime/transports/http/index.d.ts +1 -0
- package/dist/runtime/transports/http/index.js +55 -0
- package/dist/runtime/transports/http/setup-cors.d.ts +4 -0
- package/dist/runtime/transports/http/setup-cors.js +24 -0
- package/dist/runtime/transports/http/stateless-streamable-http.d.ts +39 -0
- package/dist/runtime/transports/http/stateless-streamable-http.js +331 -0
- package/dist/runtime/transports/stdio/index.d.ts +1 -0
- package/dist/runtime/transports/stdio/index.js +51 -0
- package/dist/runtime/utils/server.d.ts +42 -0
- package/dist/runtime/utils/server.js +39 -0
- package/dist/runtime/utils/tools.d.ts +8 -0
- package/dist/runtime/utils/tools.js +115 -0
- package/dist/runtime/verifier-middleware.d.ts +76 -0
- package/dist/runtime/verifier-middleware.js +322 -0
- package/dist/runtime/well-known.d.ts +151 -0
- package/dist/runtime/well-known.js +258 -0
- package/dist/storage/config.d.ts +28 -0
- package/dist/storage/config.js +79 -0
- package/dist/storage/delegation.d.ts +59 -0
- package/dist/storage/delegation.js +130 -0
- package/dist/storage/merkle-verifier.d.ts +84 -0
- package/dist/storage/merkle-verifier.js +261 -0
- package/dist/test/__tests__/nonce-cache-integration.test.d.ts +1 -0
- package/dist/test/__tests__/nonce-cache-integration.test.js +116 -0
- package/dist/test/__tests__/nonce-cache.test.d.ts +1 -0
- package/dist/test/__tests__/nonce-cache.test.js +122 -0
- package/dist/test/__tests__/runtime-integration.test.d.ts +4 -0
- package/dist/test/__tests__/runtime-integration.test.js +192 -0
- package/dist/test/__tests__/test-infrastructure.test.d.ts +4 -0
- package/dist/test/__tests__/test-infrastructure.test.js +178 -0
- package/dist/test/deterministic-keys.d.ts +31 -0
- package/dist/test/deterministic-keys.js +108 -0
- package/dist/test/examples/test-usage-example.d.ts +140 -0
- package/dist/test/examples/test-usage-example.js +175 -0
- package/dist/test/index.d.ts +11 -0
- package/dist/test/index.js +27 -0
- package/dist/test/local-verification.d.ts +28 -0
- package/dist/test/local-verification.js +342 -0
- package/dist/test/mock-identity-provider.d.ts +96 -0
- package/dist/test/mock-identity-provider.js +243 -0
- package/dist/test/runtime-integration.d.ts +63 -0
- package/dist/test/runtime-integration.js +140 -0
- package/dist/test/test-environment.d.ts +26 -0
- package/dist/test/test-environment.js +50 -0
- package/dist/types/declarations.d.ts +1 -0
- package/dist/types/declarations.js +6 -0
- package/dist/types/middleware.d.ts +2 -0
- package/dist/types/middleware.js +2 -0
- package/dist/types/tool.d.ts +80 -0
- package/dist/types/tool.js +2 -0
- package/dist/utils/cli-icons.d.ts +3 -0
- package/dist/utils/cli-icons.js +7 -0
- package/dist/utils/constants.d.ts +6 -0
- package/dist/utils/constants.js +13 -0
- package/dist/utils/context.d.ts +33 -0
- package/dist/utils/context.js +58 -0
- package/dist/utils/file-watcher.d.ts +19 -0
- package/dist/utils/file-watcher.js +49 -0
- package/dist/utils/fs-utils.d.ts +2 -0
- package/dist/utils/fs-utils.js +22 -0
- package/dist/utils/path-validation.d.ts +3 -0
- package/dist/utils/path-validation.js +56 -0
- package/dist/utils/spawn-process.d.ts +9 -0
- package/dist/utils/spawn-process.js +50 -0
- package/dist/utils/subscribable.d.ts +12 -0
- package/dist/utils/subscribable.js +44 -0
- package/package.json +99 -21
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tests for Audit Logging System
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const vitest_1 = require("vitest");
|
|
7
|
+
const audit_js_1 = require("../audit.js");
|
|
8
|
+
(0, vitest_1.describe)("AuditLogger", () => {
|
|
9
|
+
let auditLogger;
|
|
10
|
+
let mockLogFunction;
|
|
11
|
+
let mockIdentity;
|
|
12
|
+
let mockSession;
|
|
13
|
+
(0, vitest_1.beforeEach)(() => {
|
|
14
|
+
mockLogFunction = vitest_1.vi.fn();
|
|
15
|
+
auditLogger = new audit_js_1.AuditLogger({
|
|
16
|
+
logFunction: mockLogFunction,
|
|
17
|
+
});
|
|
18
|
+
mockIdentity = {
|
|
19
|
+
did: "did:web:example.com:agents:test-agent",
|
|
20
|
+
keyId: "key-test-123",
|
|
21
|
+
privateKey: "test-private-key",
|
|
22
|
+
publicKey: "test-public-key",
|
|
23
|
+
createdAt: new Date().toISOString(),
|
|
24
|
+
};
|
|
25
|
+
mockSession = {
|
|
26
|
+
sessionId: "sess_test_123",
|
|
27
|
+
audience: "example.com",
|
|
28
|
+
nonce: "test-nonce-456",
|
|
29
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
30
|
+
createdAt: Math.floor(Date.now() / 1000),
|
|
31
|
+
lastActivity: Math.floor(Date.now() / 1000),
|
|
32
|
+
ttlMinutes: 30,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
(0, vitest_1.describe)("Audit Record Generation", () => {
|
|
36
|
+
(0, vitest_1.it)("should emit audit record on first call per session", async () => {
|
|
37
|
+
const context = {
|
|
38
|
+
identity: mockIdentity,
|
|
39
|
+
session: mockSession,
|
|
40
|
+
requestHash: "sha256:abc123",
|
|
41
|
+
responseHash: "sha256:def456",
|
|
42
|
+
verified: "yes",
|
|
43
|
+
scopeId: "orders.create",
|
|
44
|
+
};
|
|
45
|
+
await auditLogger.logAuditRecord(context);
|
|
46
|
+
(0, vitest_1.expect)(mockLogFunction).toHaveBeenCalledOnce();
|
|
47
|
+
const auditLine = mockLogFunction.mock.calls[0][0];
|
|
48
|
+
(0, vitest_1.expect)(auditLine).toContain("audit.v1");
|
|
49
|
+
(0, vitest_1.expect)(auditLine).toContain("session=sess_test_123");
|
|
50
|
+
(0, vitest_1.expect)(auditLine).toContain("audience=example.com");
|
|
51
|
+
(0, vitest_1.expect)(auditLine).toContain("did=did:web:example.com:agents:test-agent");
|
|
52
|
+
(0, vitest_1.expect)(auditLine).toContain("kid=key-test-123");
|
|
53
|
+
(0, vitest_1.expect)(auditLine).toContain("reqHash=sha256:abc123");
|
|
54
|
+
(0, vitest_1.expect)(auditLine).toContain("resHash=sha256:def456");
|
|
55
|
+
(0, vitest_1.expect)(auditLine).toContain("verified=yes");
|
|
56
|
+
(0, vitest_1.expect)(auditLine).toContain("scope=orders.create");
|
|
57
|
+
});
|
|
58
|
+
(0, vitest_1.it)("should not emit duplicate audit records for same session", async () => {
|
|
59
|
+
const context = {
|
|
60
|
+
identity: mockIdentity,
|
|
61
|
+
session: mockSession,
|
|
62
|
+
requestHash: "sha256:abc123",
|
|
63
|
+
responseHash: "sha256:def456",
|
|
64
|
+
verified: "yes",
|
|
65
|
+
};
|
|
66
|
+
// First call should emit audit record
|
|
67
|
+
await auditLogger.logAuditRecord(context);
|
|
68
|
+
(0, vitest_1.expect)(mockLogFunction).toHaveBeenCalledOnce();
|
|
69
|
+
// Second call for same session should not emit
|
|
70
|
+
await auditLogger.logAuditRecord(context);
|
|
71
|
+
(0, vitest_1.expect)(mockLogFunction).toHaveBeenCalledOnce(); // Still only once
|
|
72
|
+
});
|
|
73
|
+
(0, vitest_1.it)("should emit separate audit records for different sessions", async () => {
|
|
74
|
+
const context1 = {
|
|
75
|
+
identity: mockIdentity,
|
|
76
|
+
session: mockSession,
|
|
77
|
+
requestHash: "sha256:abc123",
|
|
78
|
+
responseHash: "sha256:def456",
|
|
79
|
+
verified: "yes",
|
|
80
|
+
};
|
|
81
|
+
const context2 = {
|
|
82
|
+
identity: mockIdentity,
|
|
83
|
+
session: { ...mockSession, sessionId: "sess_test_456" },
|
|
84
|
+
requestHash: "sha256:ghi789",
|
|
85
|
+
responseHash: "sha256:jkl012",
|
|
86
|
+
verified: "no",
|
|
87
|
+
};
|
|
88
|
+
await auditLogger.logAuditRecord(context1);
|
|
89
|
+
await auditLogger.logAuditRecord(context2);
|
|
90
|
+
(0, vitest_1.expect)(mockLogFunction).toHaveBeenCalledTimes(2);
|
|
91
|
+
});
|
|
92
|
+
(0, vitest_1.it)('should use "-" for missing scope', async () => {
|
|
93
|
+
const context = {
|
|
94
|
+
identity: mockIdentity,
|
|
95
|
+
session: mockSession,
|
|
96
|
+
requestHash: "sha256:abc123",
|
|
97
|
+
responseHash: "sha256:def456",
|
|
98
|
+
verified: "yes",
|
|
99
|
+
// No scopeId provided
|
|
100
|
+
};
|
|
101
|
+
await auditLogger.logAuditRecord(context);
|
|
102
|
+
const auditLine = mockLogFunction.mock.calls[0][0];
|
|
103
|
+
(0, vitest_1.expect)(auditLine).toContain("scope=-");
|
|
104
|
+
});
|
|
105
|
+
(0, vitest_1.it)("should not log when disabled", async () => {
|
|
106
|
+
const disabledLogger = new audit_js_1.AuditLogger({
|
|
107
|
+
enabled: false,
|
|
108
|
+
logFunction: mockLogFunction,
|
|
109
|
+
});
|
|
110
|
+
const context = {
|
|
111
|
+
identity: mockIdentity,
|
|
112
|
+
session: mockSession,
|
|
113
|
+
requestHash: "sha256:abc123",
|
|
114
|
+
responseHash: "sha256:def456",
|
|
115
|
+
verified: "yes",
|
|
116
|
+
};
|
|
117
|
+
await disabledLogger.logAuditRecord(context);
|
|
118
|
+
(0, vitest_1.expect)(mockLogFunction).not.toHaveBeenCalled();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
(0, vitest_1.describe)("Audit Line Format", () => {
|
|
122
|
+
(0, vitest_1.it)("should format audit line with frozen format", async () => {
|
|
123
|
+
const context = {
|
|
124
|
+
identity: mockIdentity,
|
|
125
|
+
session: mockSession,
|
|
126
|
+
requestHash: "sha256:abc123",
|
|
127
|
+
responseHash: "sha256:def456",
|
|
128
|
+
verified: "yes",
|
|
129
|
+
scopeId: "orders.create",
|
|
130
|
+
};
|
|
131
|
+
await auditLogger.logAuditRecord(context);
|
|
132
|
+
const auditLine = mockLogFunction.mock.calls[0][0];
|
|
133
|
+
const parts = auditLine.split(" ");
|
|
134
|
+
(0, vitest_1.expect)(parts[0]).toBe("audit.v1");
|
|
135
|
+
(0, vitest_1.expect)(parts[1]).toMatch(/^ts=\d+$/);
|
|
136
|
+
(0, vitest_1.expect)(parts[2]).toBe("session=sess_test_123");
|
|
137
|
+
(0, vitest_1.expect)(parts[3]).toBe("audience=example.com");
|
|
138
|
+
(0, vitest_1.expect)(parts[4]).toBe("did=did:web:example.com:agents:test-agent");
|
|
139
|
+
(0, vitest_1.expect)(parts[5]).toBe("kid=key-test-123");
|
|
140
|
+
(0, vitest_1.expect)(parts[6]).toBe("reqHash=sha256:abc123");
|
|
141
|
+
(0, vitest_1.expect)(parts[7]).toBe("resHash=sha256:def456");
|
|
142
|
+
(0, vitest_1.expect)(parts[8]).toBe("verified=yes");
|
|
143
|
+
(0, vitest_1.expect)(parts[9]).toBe("scope=orders.create");
|
|
144
|
+
});
|
|
145
|
+
(0, vitest_1.it)("should include timestamp in unix seconds", async () => {
|
|
146
|
+
const beforeTime = Math.floor(Date.now() / 1000);
|
|
147
|
+
const context = {
|
|
148
|
+
identity: mockIdentity,
|
|
149
|
+
session: mockSession,
|
|
150
|
+
requestHash: "sha256:abc123",
|
|
151
|
+
responseHash: "sha256:def456",
|
|
152
|
+
verified: "yes",
|
|
153
|
+
};
|
|
154
|
+
await auditLogger.logAuditRecord(context);
|
|
155
|
+
const afterTime = Math.floor(Date.now() / 1000);
|
|
156
|
+
const auditLine = mockLogFunction.mock.calls[0][0];
|
|
157
|
+
const tsMatch = auditLine.match(/ts=(\d+)/);
|
|
158
|
+
(0, vitest_1.expect)(tsMatch).toBeTruthy();
|
|
159
|
+
const timestamp = parseInt(tsMatch[1], 10);
|
|
160
|
+
(0, vitest_1.expect)(timestamp).toBeGreaterThanOrEqual(beforeTime);
|
|
161
|
+
(0, vitest_1.expect)(timestamp).toBeLessThanOrEqual(afterTime);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
(0, vitest_1.describe)("Configuration and Statistics", () => {
|
|
165
|
+
(0, vitest_1.it)("should provide accurate statistics", async () => {
|
|
166
|
+
const context = {
|
|
167
|
+
identity: mockIdentity,
|
|
168
|
+
session: mockSession,
|
|
169
|
+
requestHash: "sha256:abc123",
|
|
170
|
+
responseHash: "sha256:def456",
|
|
171
|
+
verified: "yes",
|
|
172
|
+
};
|
|
173
|
+
const initialStats = auditLogger.getStats();
|
|
174
|
+
(0, vitest_1.expect)(initialStats.sessionsLogged).toBe(0);
|
|
175
|
+
(0, vitest_1.expect)(initialStats.enabled).toBe(true);
|
|
176
|
+
(0, vitest_1.expect)(initialStats.includePayloads).toBe(false);
|
|
177
|
+
await auditLogger.logAuditRecord(context);
|
|
178
|
+
const finalStats = auditLogger.getStats();
|
|
179
|
+
(0, vitest_1.expect)(finalStats.sessionsLogged).toBe(1);
|
|
180
|
+
});
|
|
181
|
+
(0, vitest_1.it)("should allow configuration updates", () => {
|
|
182
|
+
auditLogger.updateConfig({ enabled: false, includePayloads: true });
|
|
183
|
+
const stats = auditLogger.getStats();
|
|
184
|
+
(0, vitest_1.expect)(stats.enabled).toBe(false);
|
|
185
|
+
(0, vitest_1.expect)(stats.includePayloads).toBe(true);
|
|
186
|
+
});
|
|
187
|
+
(0, vitest_1.it)("should clear session log", async () => {
|
|
188
|
+
const context = {
|
|
189
|
+
identity: mockIdentity,
|
|
190
|
+
session: mockSession,
|
|
191
|
+
requestHash: "sha256:abc123",
|
|
192
|
+
responseHash: "sha256:def456",
|
|
193
|
+
verified: "yes",
|
|
194
|
+
};
|
|
195
|
+
await auditLogger.logAuditRecord(context);
|
|
196
|
+
(0, vitest_1.expect)(auditLogger.getStats().sessionsLogged).toBe(1);
|
|
197
|
+
auditLogger.clearSessionLog();
|
|
198
|
+
(0, vitest_1.expect)(auditLogger.getStats().sessionsLogged).toBe(0);
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
(0, vitest_1.describe)("Key Rotation Audit", () => {
|
|
203
|
+
let mockLogFunction;
|
|
204
|
+
let mockIdentity;
|
|
205
|
+
(0, vitest_1.beforeEach)(() => {
|
|
206
|
+
mockLogFunction = vitest_1.vi.fn();
|
|
207
|
+
mockIdentity = {
|
|
208
|
+
did: "did:web:example.com:agents:test-agent",
|
|
209
|
+
keyId: "key-new-456",
|
|
210
|
+
privateKey: "test-private-key",
|
|
211
|
+
publicKey: "test-public-key",
|
|
212
|
+
createdAt: new Date().toISOString(),
|
|
213
|
+
};
|
|
214
|
+
});
|
|
215
|
+
(0, vitest_1.it)("should log key rotation audit record", () => {
|
|
216
|
+
const context = {
|
|
217
|
+
identity: mockIdentity,
|
|
218
|
+
oldKeyId: "key-old-123",
|
|
219
|
+
newKeyId: "key-new-456",
|
|
220
|
+
mode: "dev",
|
|
221
|
+
delegated: "no",
|
|
222
|
+
force: "no",
|
|
223
|
+
};
|
|
224
|
+
(0, audit_js_1.logKeyRotationAudit)(context, mockLogFunction);
|
|
225
|
+
(0, vitest_1.expect)(mockLogFunction).toHaveBeenCalledOnce();
|
|
226
|
+
const auditLine = mockLogFunction.mock.calls[0][0];
|
|
227
|
+
(0, vitest_1.expect)(auditLine).toContain("keys.rotate.v1");
|
|
228
|
+
(0, vitest_1.expect)(auditLine).toContain("did=did:web:example.com:agents:test-agent");
|
|
229
|
+
(0, vitest_1.expect)(auditLine).toContain("oldKid=key-old-123");
|
|
230
|
+
(0, vitest_1.expect)(auditLine).toContain("newKid=key-new-456");
|
|
231
|
+
(0, vitest_1.expect)(auditLine).toContain("mode=dev");
|
|
232
|
+
(0, vitest_1.expect)(auditLine).toContain("delegated=no");
|
|
233
|
+
(0, vitest_1.expect)(auditLine).toContain("force=no");
|
|
234
|
+
});
|
|
235
|
+
(0, vitest_1.it)("should log production key rotation with delegation", () => {
|
|
236
|
+
const context = {
|
|
237
|
+
identity: mockIdentity,
|
|
238
|
+
oldKeyId: "key-old-123",
|
|
239
|
+
newKeyId: "key-new-456",
|
|
240
|
+
mode: "prod",
|
|
241
|
+
delegated: "yes",
|
|
242
|
+
force: "no",
|
|
243
|
+
};
|
|
244
|
+
(0, audit_js_1.logKeyRotationAudit)(context, mockLogFunction);
|
|
245
|
+
const auditLine = mockLogFunction.mock.calls[0][0];
|
|
246
|
+
(0, vitest_1.expect)(auditLine).toContain("mode=prod");
|
|
247
|
+
(0, vitest_1.expect)(auditLine).toContain("delegated=yes");
|
|
248
|
+
});
|
|
249
|
+
(0, vitest_1.it)("should log forced key rotation", () => {
|
|
250
|
+
const context = {
|
|
251
|
+
identity: mockIdentity,
|
|
252
|
+
oldKeyId: "key-old-123",
|
|
253
|
+
newKeyId: "key-new-456",
|
|
254
|
+
mode: "prod",
|
|
255
|
+
delegated: "no",
|
|
256
|
+
force: "yes",
|
|
257
|
+
};
|
|
258
|
+
(0, audit_js_1.logKeyRotationAudit)(context, mockLogFunction);
|
|
259
|
+
const auditLine = mockLogFunction.mock.calls[0][0];
|
|
260
|
+
(0, vitest_1.expect)(auditLine).toContain("force=yes");
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
(0, vitest_1.describe)("Audit Line Parsing", () => {
|
|
264
|
+
(0, vitest_1.it)("should parse valid audit line", () => {
|
|
265
|
+
const auditLine = "audit.v1 ts=1640995200 session=sess_test_123 audience=example.com did=did:web:example.com:agents:test-agent kid=key-test-123 reqHash=sha256:abc123 resHash=sha256:def456 verified=yes scope=orders.create";
|
|
266
|
+
const record = (0, audit_js_1.parseAuditLine)(auditLine);
|
|
267
|
+
(0, vitest_1.expect)(record).toBeTruthy();
|
|
268
|
+
(0, vitest_1.expect)(record.version).toBe("audit.v1");
|
|
269
|
+
(0, vitest_1.expect)(record.ts).toBe(1640995200);
|
|
270
|
+
(0, vitest_1.expect)(record.session).toBe("sess_test_123");
|
|
271
|
+
(0, vitest_1.expect)(record.audience).toBe("example.com");
|
|
272
|
+
(0, vitest_1.expect)(record.did).toBe("did:web:example.com:agents:test-agent");
|
|
273
|
+
(0, vitest_1.expect)(record.kid).toBe("key-test-123");
|
|
274
|
+
(0, vitest_1.expect)(record.reqHash).toBe("sha256:abc123");
|
|
275
|
+
(0, vitest_1.expect)(record.resHash).toBe("sha256:def456");
|
|
276
|
+
(0, vitest_1.expect)(record.verified).toBe("yes");
|
|
277
|
+
(0, vitest_1.expect)(record.scope).toBe("orders.create");
|
|
278
|
+
});
|
|
279
|
+
(0, vitest_1.it)("should parse audit line with no scope", () => {
|
|
280
|
+
const auditLine = "audit.v1 ts=1640995200 session=sess_test_123 audience=example.com did=did:web:example.com:agents:test-agent kid=key-test-123 reqHash=sha256:abc123 resHash=sha256:def456 verified=no scope=-";
|
|
281
|
+
const record = (0, audit_js_1.parseAuditLine)(auditLine);
|
|
282
|
+
(0, vitest_1.expect)(record).toBeTruthy();
|
|
283
|
+
(0, vitest_1.expect)(record.verified).toBe("no");
|
|
284
|
+
(0, vitest_1.expect)(record.scope).toBe("-");
|
|
285
|
+
});
|
|
286
|
+
(0, vitest_1.it)("should return null for invalid audit line", () => {
|
|
287
|
+
const invalidLines = [
|
|
288
|
+
"invalid line",
|
|
289
|
+
"audit.v1 incomplete",
|
|
290
|
+
"wrong.version ts=123 session=test",
|
|
291
|
+
"audit.v1 ts=invalid session=test audience=test",
|
|
292
|
+
];
|
|
293
|
+
for (const line of invalidLines) {
|
|
294
|
+
(0, vitest_1.expect)((0, audit_js_1.parseAuditLine)(line)).toBeNull();
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
(0, vitest_1.describe)("Audit Record Validation", () => {
|
|
299
|
+
(0, vitest_1.it)("should validate correct audit record", () => {
|
|
300
|
+
const validRecord = {
|
|
301
|
+
version: "audit.v1",
|
|
302
|
+
ts: 1640995200,
|
|
303
|
+
session: "sess_test_123",
|
|
304
|
+
audience: "example.com",
|
|
305
|
+
did: "did:web:example.com:agents:test-agent",
|
|
306
|
+
kid: "key-test-123",
|
|
307
|
+
reqHash: "sha256:abc123",
|
|
308
|
+
resHash: "sha256:def456",
|
|
309
|
+
verified: "yes",
|
|
310
|
+
scope: "orders.create",
|
|
311
|
+
};
|
|
312
|
+
(0, vitest_1.expect)((0, audit_js_1.validateAuditRecord)(validRecord)).toBe(true);
|
|
313
|
+
});
|
|
314
|
+
(0, vitest_1.it)("should reject invalid audit records", () => {
|
|
315
|
+
const invalidRecords = [
|
|
316
|
+
null,
|
|
317
|
+
undefined,
|
|
318
|
+
{},
|
|
319
|
+
{ version: "wrong.version" },
|
|
320
|
+
{ version: "audit.v1", ts: "invalid" },
|
|
321
|
+
{ version: "audit.v1", ts: 123, verified: "maybe" },
|
|
322
|
+
{ version: "audit.v1", ts: 123, reqHash: "invalid-hash" },
|
|
323
|
+
];
|
|
324
|
+
for (const record of invalidRecords) {
|
|
325
|
+
(0, vitest_1.expect)((0, audit_js_1.validateAuditRecord)(record)).toBe(false);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
});
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tests for Identity Management System
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const vitest_1 = require("vitest");
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const promises_1 = require("fs/promises");
|
|
9
|
+
const path_1 = require("path");
|
|
10
|
+
const identity_js_1 = require("../identity.js");
|
|
11
|
+
// Mock environment variables
|
|
12
|
+
const originalEnv = process.env;
|
|
13
|
+
(0, vitest_1.describe)("IdentityManager", () => {
|
|
14
|
+
let tempDir;
|
|
15
|
+
let identityManager;
|
|
16
|
+
(0, vitest_1.beforeEach)(async () => {
|
|
17
|
+
// Create temp directory for tests
|
|
18
|
+
tempDir = (0, path_1.join)(process.cwd(), ".test-mcpi");
|
|
19
|
+
await (0, promises_1.mkdir)(tempDir, { recursive: true });
|
|
20
|
+
// Reset environment
|
|
21
|
+
process.env = { ...originalEnv };
|
|
22
|
+
delete process.env.AGENT_PRIVATE_KEY;
|
|
23
|
+
delete process.env.AGENT_KEY_ID;
|
|
24
|
+
delete process.env.AGENT_DID;
|
|
25
|
+
delete process.env.KYA_VOUCHED_API_KEY;
|
|
26
|
+
});
|
|
27
|
+
(0, vitest_1.afterEach)(async () => {
|
|
28
|
+
// Cleanup
|
|
29
|
+
try {
|
|
30
|
+
if ((0, fs_1.existsSync)(tempDir)) {
|
|
31
|
+
await (0, promises_1.rmdir)(tempDir, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
// Ignore cleanup errors
|
|
36
|
+
}
|
|
37
|
+
// Restore environment
|
|
38
|
+
process.env = originalEnv;
|
|
39
|
+
});
|
|
40
|
+
(0, vitest_1.describe)("Development Environment", () => {
|
|
41
|
+
(0, vitest_1.beforeEach)(() => {
|
|
42
|
+
identityManager = new identity_js_1.IdentityManager({
|
|
43
|
+
environment: "development",
|
|
44
|
+
devIdentityPath: (0, path_1.join)(tempDir, "identity.json"),
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
(0, vitest_1.it)("should generate new identity when none exists", async () => {
|
|
48
|
+
const identity = await identityManager.ensureIdentity();
|
|
49
|
+
(0, vitest_1.expect)(identity).toBeDefined();
|
|
50
|
+
(0, vitest_1.expect)(identity.did).toMatch(/^did:web:localhost:3000:agents:key-[a-f0-9]{8}$/);
|
|
51
|
+
(0, vitest_1.expect)(identity.keyId).toMatch(/^key-[a-f0-9]{8}$/);
|
|
52
|
+
(0, vitest_1.expect)(identity.privateKey).toBeTruthy();
|
|
53
|
+
(0, vitest_1.expect)(identity.publicKey).toBeTruthy();
|
|
54
|
+
(0, vitest_1.expect)(identity.createdAt).toBeTruthy();
|
|
55
|
+
// Verify keys are base64 encoded
|
|
56
|
+
(0, vitest_1.expect)(() => Buffer.from(identity.privateKey, "base64")).not.toThrow();
|
|
57
|
+
(0, vitest_1.expect)(() => Buffer.from(identity.publicKey, "base64")).not.toThrow();
|
|
58
|
+
});
|
|
59
|
+
(0, vitest_1.it)("should load existing identity from file", async () => {
|
|
60
|
+
// Generate first identity
|
|
61
|
+
const identity1 = await identityManager.ensureIdentity();
|
|
62
|
+
// Create new manager instance
|
|
63
|
+
const identityManager2 = new identity_js_1.IdentityManager({
|
|
64
|
+
environment: "development",
|
|
65
|
+
devIdentityPath: (0, path_1.join)(tempDir, "identity.json"),
|
|
66
|
+
});
|
|
67
|
+
// Should load the same identity
|
|
68
|
+
const identity2 = await identityManager2.ensureIdentity();
|
|
69
|
+
(0, vitest_1.expect)(identity2.did).toBe(identity1.did);
|
|
70
|
+
(0, vitest_1.expect)(identity2.keyId).toBe(identity1.keyId);
|
|
71
|
+
(0, vitest_1.expect)(identity2.privateKey).toBe(identity1.privateKey);
|
|
72
|
+
(0, vitest_1.expect)(identity2.publicKey).toBe(identity1.publicKey);
|
|
73
|
+
});
|
|
74
|
+
(0, vitest_1.it)("should cache identity after first load", async () => {
|
|
75
|
+
const identity1 = await identityManager.ensureIdentity();
|
|
76
|
+
const identity2 = await identityManager.ensureIdentity();
|
|
77
|
+
(0, vitest_1.expect)(identity1).toBe(identity2); // Same object reference
|
|
78
|
+
});
|
|
79
|
+
(0, vitest_1.it)("should regenerate identity if file is corrupted", async () => {
|
|
80
|
+
const identityPath = (0, path_1.join)(tempDir, "identity.json");
|
|
81
|
+
// Write corrupted file
|
|
82
|
+
await import("fs/promises").then((fs) => fs.writeFile(identityPath, "invalid json", "utf-8"));
|
|
83
|
+
// Should generate new identity
|
|
84
|
+
const identity = await identityManager.ensureIdentity();
|
|
85
|
+
(0, vitest_1.expect)(identity).toBeDefined();
|
|
86
|
+
(0, vitest_1.expect)(identity.did).toMatch(/^did:web:localhost:3000:agents:key-[a-f0-9]{8}$/);
|
|
87
|
+
});
|
|
88
|
+
(0, vitest_1.it)("should validate identity correctly", async () => {
|
|
89
|
+
const identity = await identityManager.ensureIdentity();
|
|
90
|
+
const isValid = await identityManager.validateIdentity(identity);
|
|
91
|
+
(0, vitest_1.expect)(isValid).toBe(true);
|
|
92
|
+
});
|
|
93
|
+
(0, vitest_1.it)("should reject invalid identity", async () => {
|
|
94
|
+
const invalidIdentity = {
|
|
95
|
+
did: "invalid-did",
|
|
96
|
+
keyId: "key-1",
|
|
97
|
+
privateKey: "invalid-key",
|
|
98
|
+
publicKey: "invalid-key",
|
|
99
|
+
createdAt: new Date().toISOString(),
|
|
100
|
+
};
|
|
101
|
+
const isValid = await identityManager.validateIdentity(invalidIdentity);
|
|
102
|
+
(0, vitest_1.expect)(isValid).toBe(false);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
(0, vitest_1.describe)("Production Environment", () => {
|
|
106
|
+
(0, vitest_1.beforeEach)(() => {
|
|
107
|
+
identityManager = new identity_js_1.IdentityManager({
|
|
108
|
+
environment: "production",
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
(0, vitest_1.it)("should load identity from environment variables", async () => {
|
|
112
|
+
// Set up environment variables
|
|
113
|
+
process.env.AGENT_PRIVATE_KEY = Buffer.from("test-private-key-32-bytes-long!!").toString("base64");
|
|
114
|
+
process.env.AGENT_KEY_ID = "key-prod-123";
|
|
115
|
+
process.env.AGENT_DID = "did:web:example.com:agents:my-agent";
|
|
116
|
+
process.env.KYA_VOUCHED_API_KEY = "test-api-key";
|
|
117
|
+
const identity = await identityManager.ensureIdentity();
|
|
118
|
+
(0, vitest_1.expect)(identity.did).toBe("did:web:example.com:agents:my-agent");
|
|
119
|
+
(0, vitest_1.expect)(identity.keyId).toBe("key-prod-123");
|
|
120
|
+
(0, vitest_1.expect)(identity.privateKey).toBe(process.env.AGENT_PRIVATE_KEY);
|
|
121
|
+
(0, vitest_1.expect)(identity.publicKey).toBeTruthy();
|
|
122
|
+
});
|
|
123
|
+
(0, vitest_1.it)("should fail fast when environment variables are missing", async () => {
|
|
124
|
+
// Only set some variables
|
|
125
|
+
process.env.AGENT_DID = "did:web:example.com:agents:my-agent";
|
|
126
|
+
process.env.AGENT_KEY_ID = "key-prod-123";
|
|
127
|
+
await (0, vitest_1.expect)(identityManager.ensureIdentity()).rejects.toThrow(vitest_1.expect.objectContaining({
|
|
128
|
+
message: vitest_1.expect.stringContaining("Missing required environment variables"),
|
|
129
|
+
code: identity_js_1.IDENTITY_ERRORS.ENOIDENTITY,
|
|
130
|
+
}));
|
|
131
|
+
});
|
|
132
|
+
(0, vitest_1.it)("should list all missing environment variables", async () => {
|
|
133
|
+
const error = await identityManager.ensureIdentity().catch((e) => e);
|
|
134
|
+
(0, vitest_1.expect)(error.message).toContain("AGENT_PRIVATE_KEY, AGENT_KEY_ID, AGENT_DID, KYA_VOUCHED_API_KEY");
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
(0, vitest_1.describe)("Configuration", () => {
|
|
138
|
+
(0, vitest_1.it)("should use single public DID by default", () => {
|
|
139
|
+
const manager = new identity_js_1.IdentityManager();
|
|
140
|
+
const config = manager.getConfig();
|
|
141
|
+
(0, vitest_1.expect)(config.privacyMode).toBe(false);
|
|
142
|
+
});
|
|
143
|
+
(0, vitest_1.it)("should allow privacy mode configuration", () => {
|
|
144
|
+
const manager = new identity_js_1.IdentityManager({
|
|
145
|
+
environment: "development",
|
|
146
|
+
privacyMode: true,
|
|
147
|
+
});
|
|
148
|
+
const config = manager.getConfig();
|
|
149
|
+
(0, vitest_1.expect)(config.privacyMode).toBe(true);
|
|
150
|
+
});
|
|
151
|
+
(0, vitest_1.it)("should clear cache when requested", async () => {
|
|
152
|
+
const manager = new identity_js_1.IdentityManager({
|
|
153
|
+
environment: "development",
|
|
154
|
+
devIdentityPath: (0, path_1.join)(tempDir, "identity.json"),
|
|
155
|
+
});
|
|
156
|
+
const identity1 = await manager.ensureIdentity();
|
|
157
|
+
manager.clearCache();
|
|
158
|
+
const identity2 = await manager.ensureIdentity();
|
|
159
|
+
// Should be different object references but same content
|
|
160
|
+
(0, vitest_1.expect)(identity1).not.toBe(identity2);
|
|
161
|
+
(0, vitest_1.expect)(identity1.did).toBe(identity2.did);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|