agentlock-shared 0.1.0 → 0.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.
Files changed (42) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +57 -15
  3. package/dist/__tests__/crypto.test.js +137 -47
  4. package/dist/__tests__/crypto.test.js.map +1 -1
  5. package/dist/__tests__/messaging.test.d.ts +2 -0
  6. package/dist/__tests__/messaging.test.d.ts.map +1 -0
  7. package/dist/__tests__/messaging.test.js +75 -0
  8. package/dist/__tests__/messaging.test.js.map +1 -0
  9. package/dist/__tests__/policy.test.js +124 -7
  10. package/dist/__tests__/policy.test.js.map +1 -1
  11. package/dist/__tests__/signing.test (# Edit conflict 2026-04-01 z3etfmC #).js +51 -0
  12. package/dist/__tests__/signing.test.js (# Edit conflict 2026-04-01 4rndy9C #).map +1 -0
  13. package/dist/crypto.d.ts +36 -0
  14. package/dist/crypto.d.ts.map +1 -1
  15. package/dist/crypto.js +150 -5
  16. package/dist/crypto.js.map +1 -1
  17. package/dist/plans.d.ts +4 -0
  18. package/dist/plans.d.ts.map +1 -1
  19. package/dist/plans.js +16 -0
  20. package/dist/plans.js.map +1 -1
  21. package/dist/policy.d.ts.map +1 -1
  22. package/dist/policy.js +54 -29
  23. package/dist/policy.js.map +1 -1
  24. package/dist/redact.d.ts.map +1 -1
  25. package/dist/redact.js +21 -4
  26. package/dist/redact.js.map +1 -1
  27. package/dist/schemas.d.ts +72 -11
  28. package/dist/schemas.d.ts.map +1 -1
  29. package/dist/schemas.js +62 -10
  30. package/dist/schemas.js.map +1 -1
  31. package/dist/types.d.ts +1 -0
  32. package/dist/types.d.ts.map +1 -1
  33. package/package.json +1 -1
  34. package/src/__tests__/crypto.test.ts +169 -0
  35. package/src/__tests__/messaging.test.ts +83 -0
  36. package/src/__tests__/policy.test.ts +141 -7
  37. package/src/crypto.ts +153 -5
  38. package/src/plans.ts +20 -0
  39. package/src/policy.ts +58 -28
  40. package/src/redact.ts +20 -3
  41. package/src/schemas.ts +121 -53
  42. package/src/types.ts +1 -0
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const signing_js_1 = require("../signing.js");
5
+ (0, vitest_1.describe)('Ed25519 Signing', () => {
6
+ (0, vitest_1.it)('should generate valid keypair', () => {
7
+ const kp = (0, signing_js_1.generateKeypair)();
8
+ (0, vitest_1.expect)(kp.publicKey).toBeTruthy();
9
+ (0, vitest_1.expect)(kp.privateKey).toBeTruthy();
10
+ (0, vitest_1.expect)(kp.publicKey.length).toBeGreaterThan(0);
11
+ });
12
+ (0, vitest_1.it)('should sign and verify a request', () => {
13
+ const kp = (0, signing_js_1.generateKeypair)();
14
+ const body = { action_type: 'write', tool: 'demo', payload: { key: 'value' } };
15
+ const headers = (0, signing_js_1.signRequest)(body, 'agent-123', kp.privateKey);
16
+ (0, vitest_1.expect)(() => (0, signing_js_1.verifyRequest)(body, headers, kp.publicKey)).not.toThrow();
17
+ });
18
+ (0, vitest_1.it)('should reject tampered body (top-level field)', () => {
19
+ const kp = (0, signing_js_1.generateKeypair)();
20
+ const body = { action_type: 'write', tool: 'demo', payload: { key: 'value' } };
21
+ const headers = (0, signing_js_1.signRequest)(body, 'agent-123', kp.privateKey);
22
+ const tampered = { ...body, tool: 'admin' };
23
+ (0, vitest_1.expect)(() => (0, signing_js_1.verifyRequest)(tampered, headers, kp.publicKey)).toThrow('Invalid signature');
24
+ });
25
+ (0, vitest_1.it)('should reject tampered nested payload field', () => {
26
+ const kp = (0, signing_js_1.generateKeypair)();
27
+ const body = { action_type: 'write', tool: 'demo', payload: { key: 'value', amount: 100 } };
28
+ const headers = (0, signing_js_1.signRequest)(body, 'agent-123', kp.privateKey);
29
+ const tampered = { ...body, payload: { key: 'value', amount: 999999 } };
30
+ (0, vitest_1.expect)(() => (0, signing_js_1.verifyRequest)(tampered, headers, kp.publicKey)).toThrow('Invalid signature');
31
+ });
32
+ (0, vitest_1.it)('canonicalStringify should sort keys recursively at all nesting levels', () => {
33
+ const obj = { z: 1, a: { y: 2, b: 3 }, m: [{ q: 4, c: 5 }] };
34
+ const result = (0, signing_js_1.canonicalStringify)(obj);
35
+ // All object levels must have sorted keys
36
+ (0, vitest_1.expect)(result).toBe('{"a":{"b":3,"y":2},"m":[{"c":5,"q":4}],"z":1}');
37
+ });
38
+ (0, vitest_1.it)('should reject missing headers', () => {
39
+ const kp = (0, signing_js_1.generateKeypair)();
40
+ const body = { action_type: 'write', tool: 'demo', payload: {} };
41
+ (0, vitest_1.expect)(() => (0, signing_js_1.verifyRequest)(body, {}, kp.publicKey)).toThrow('Missing required signature headers');
42
+ });
43
+ (0, vitest_1.it)('should reject stale timestamp', () => {
44
+ const kp = (0, signing_js_1.generateKeypair)();
45
+ const body = { action_type: 'write', tool: 'demo', payload: {} };
46
+ const headers = (0, signing_js_1.signRequest)(body, 'agent-123', kp.privateKey);
47
+ headers['x-timestamp'] = String(Date.now() - 10 * 60 * 1000);
48
+ (0, vitest_1.expect)(() => (0, signing_js_1.verifyRequest)(body, headers, kp.publicKey)).toThrow('Timestamp skew');
49
+ });
50
+ });
51
+ //# sourceMappingURL=signing.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signing.test.js","sourceRoot":"","sources":["../../src/__tests__/signing.test.ts"],"names":[],"mappings":"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"}
package/dist/crypto.d.ts CHANGED
@@ -1,9 +1,45 @@
1
1
  export declare function generateKey(): Uint8Array;
2
+ /**
3
+ * Low-level symmetric encryption using a provided key.
4
+ * Callers that need envelope encryption (per-data DEK) should use
5
+ * envelopeEncrypt() instead.
6
+ */
2
7
  export declare function encrypt(data: string, key: Uint8Array): string;
8
+ /**
9
+ * Low-level symmetric decryption. Handles both envelope-encrypted data
10
+ * (prefixed with "env1:") and legacy direct-key encrypted data.
11
+ *
12
+ * For envelope data: unwraps the per-data DEK using the master key,
13
+ * then decrypts the payload with the DEK.
14
+ *
15
+ * For legacy data: decrypts directly with the provided key, falling
16
+ * back to MASTER_KEY_PREVIOUS for key rotation support.
17
+ */
3
18
  export declare function decrypt(encryptedData: string, key: Uint8Array): string;
19
+ /**
20
+ * Encrypt arbitrary data using a per-data DEK (envelope encryption).
21
+ * Generates a fresh 256-bit DEK, encrypts the data with it, then wraps
22
+ * the DEK with the provided master key. Returns a single string in the
23
+ * format "env1:<wrappedDEK>:<encryptedPayload>" so it fits in a single
24
+ * database column and is backward-compatible with decrypt().
25
+ *
26
+ * Use this instead of encrypt() for all data at rest. Each encrypted
27
+ * value gets its own DEK, so compromising one ciphertext does not
28
+ * expose other data -- the attacker still needs the master key to
29
+ * unwrap any individual DEK.
30
+ */
31
+ export declare function envelopeEncrypt(data: string, masterKey: Uint8Array): string;
32
+ /**
33
+ * Decrypt data produced by envelopeEncrypt(). Expects the "env1:" prefixed
34
+ * format. For general use, call decrypt() which auto-detects the format.
35
+ */
36
+ export declare function envelopeDecrypt(encryptedData: string, masterKey: Uint8Array): string;
4
37
  export declare function encryptDEK(dek: Uint8Array, masterKey: Uint8Array): string;
5
38
  export declare function decryptDEK(encryptedDEK: string, masterKey: Uint8Array): Uint8Array;
6
39
  export declare function getMasterKey(): Uint8Array;
40
+ export declare function getPreviousMasterKey(): Uint8Array | null;
41
+ /** Zero and release cached master keys. Call on graceful shutdown. */
42
+ export declare function clearCachedKeys(): void;
7
43
  export declare function generateMasterKey(): string;
8
44
  export declare function encryptCredential(payload: Record<string, unknown>, masterKey: Uint8Array): {
9
45
  encryptedDEK: string;
@@ -1 +1 @@
1
- {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAGA,wBAAgB,WAAW,IAAI,UAAU,CAExC;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,CAU7D;AAED,wBAAgB,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,CAWtE;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,GAAG,MAAM,CAEzE;AAED,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,UAAU,CAGlF;AAMD,wBAAgB,YAAY,IAAI,UAAU,CAMzC;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,SAAS,EAAE,UAAU,GACpB;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAUpD;AAED,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,SAAS,EAAE,UAAU,GACpB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzB"}
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAYA,wBAAgB,WAAW,IAAI,UAAU,CAExC;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,CAU7D;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,CA0BtE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,MAAM,CAU3E;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,MAAM,CAKpF;AAkDD,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,GAAG,MAAM,CAEzE;AAED,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,UAAU,CAGlF;AAMD,wBAAgB,YAAY,IAAI,UAAU,CAMzC;AAMD,wBAAgB,oBAAoB,IAAI,UAAU,GAAG,IAAI,CAOxD;AAED,sEAAsE;AACtE,wBAAgB,eAAe,IAAI,IAAI,CAUtC;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,SAAS,EAAE,UAAU,GACpB;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAUpD;AAED,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,SAAS,EAAE,UAAU,GACpB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzB"}
package/dist/crypto.js CHANGED
@@ -6,17 +6,34 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.generateKey = generateKey;
7
7
  exports.encrypt = encrypt;
8
8
  exports.decrypt = decrypt;
9
+ exports.envelopeEncrypt = envelopeEncrypt;
10
+ exports.envelopeDecrypt = envelopeDecrypt;
9
11
  exports.encryptDEK = encryptDEK;
10
12
  exports.decryptDEK = decryptDEK;
11
13
  exports.getMasterKey = getMasterKey;
14
+ exports.getPreviousMasterKey = getPreviousMasterKey;
15
+ exports.clearCachedKeys = clearCachedKeys;
12
16
  exports.generateMasterKey = generateMasterKey;
13
17
  exports.encryptCredential = encryptCredential;
14
18
  exports.decryptCredential = decryptCredential;
15
19
  const tweetnacl_1 = __importDefault(require("tweetnacl"));
16
20
  const tweetnacl_util_1 = require("tweetnacl-util");
21
+ /**
22
+ * Envelope encryption prefix. Data encrypted with envelopeEncrypt() is
23
+ * stored as a single string: "env1:<base64-wrappedDEK>:<base64-payload>".
24
+ * The decrypt() function detects this prefix and automatically unwraps
25
+ * using the DEK, maintaining backward compatibility with legacy data
26
+ * encrypted directly with MASTER_KEY.
27
+ */
28
+ const ENVELOPE_PREFIX = 'env1:';
17
29
  function generateKey() {
18
30
  return tweetnacl_1.default.randomBytes(32);
19
31
  }
32
+ /**
33
+ * Low-level symmetric encryption using a provided key.
34
+ * Callers that need envelope encryption (per-data DEK) should use
35
+ * envelopeEncrypt() instead.
36
+ */
20
37
  function encrypt(data, key) {
21
38
  const nonce = tweetnacl_1.default.randomBytes(tweetnacl_1.default.secretbox.nonceLength);
22
39
  const message = new TextEncoder().encode(data);
@@ -26,15 +43,118 @@ function encrypt(data, key) {
26
43
  combined.set(box, nonce.length);
27
44
  return (0, tweetnacl_util_1.encodeBase64)(combined);
28
45
  }
46
+ /**
47
+ * Low-level symmetric decryption. Handles both envelope-encrypted data
48
+ * (prefixed with "env1:") and legacy direct-key encrypted data.
49
+ *
50
+ * For envelope data: unwraps the per-data DEK using the master key,
51
+ * then decrypts the payload with the DEK.
52
+ *
53
+ * For legacy data: decrypts directly with the provided key, falling
54
+ * back to MASTER_KEY_PREVIOUS for key rotation support.
55
+ */
29
56
  function decrypt(encryptedData, key) {
57
+ // Detect envelope-encrypted format and handle transparently
58
+ if (encryptedData.startsWith(ENVELOPE_PREFIX)) {
59
+ return envelopeDecryptInternal(encryptedData, key);
60
+ }
61
+ // Legacy format: data encrypted directly with MASTER_KEY
30
62
  const combined = (0, tweetnacl_util_1.decodeBase64)(encryptedData);
31
63
  const nonce = combined.slice(0, tweetnacl_1.default.secretbox.nonceLength);
32
64
  const box = combined.slice(tweetnacl_1.default.secretbox.nonceLength);
33
65
  const message = tweetnacl_1.default.secretbox.open(box, nonce, key);
34
- if (!message) {
35
- throw new Error('Decryption failed: invalid key or corrupted data');
66
+ if (message) {
67
+ return new TextDecoder().decode(message);
68
+ }
69
+ // Try previous master key for rotation support
70
+ const prevKey = getPreviousMasterKey();
71
+ if (prevKey) {
72
+ const message2 = tweetnacl_1.default.secretbox.open(box, nonce, prevKey);
73
+ if (message2) {
74
+ return new TextDecoder().decode(message2);
75
+ }
76
+ }
77
+ throw new Error('Decryption failed: invalid key or corrupted data');
78
+ }
79
+ /**
80
+ * Encrypt arbitrary data using a per-data DEK (envelope encryption).
81
+ * Generates a fresh 256-bit DEK, encrypts the data with it, then wraps
82
+ * the DEK with the provided master key. Returns a single string in the
83
+ * format "env1:<wrappedDEK>:<encryptedPayload>" so it fits in a single
84
+ * database column and is backward-compatible with decrypt().
85
+ *
86
+ * Use this instead of encrypt() for all data at rest. Each encrypted
87
+ * value gets its own DEK, so compromising one ciphertext does not
88
+ * expose other data -- the attacker still needs the master key to
89
+ * unwrap any individual DEK.
90
+ */
91
+ function envelopeEncrypt(data, masterKey) {
92
+ const dek = generateKey();
93
+ try {
94
+ const wrappedDEK = encrypt((0, tweetnacl_util_1.encodeBase64)(dek), masterKey);
95
+ const encryptedPayload = encrypt(data, dek);
96
+ return `${ENVELOPE_PREFIX}${wrappedDEK}:${encryptedPayload}`;
97
+ }
98
+ finally {
99
+ // Zero DEK from memory after use (defense-in-depth against heap dumps)
100
+ dek.fill(0);
101
+ }
102
+ }
103
+ /**
104
+ * Decrypt data produced by envelopeEncrypt(). Expects the "env1:" prefixed
105
+ * format. For general use, call decrypt() which auto-detects the format.
106
+ */
107
+ function envelopeDecrypt(encryptedData, masterKey) {
108
+ if (!encryptedData.startsWith(ENVELOPE_PREFIX)) {
109
+ throw new Error('Not an envelope-encrypted value (missing env1: prefix)');
110
+ }
111
+ return envelopeDecryptInternal(encryptedData, masterKey);
112
+ }
113
+ /**
114
+ * Internal envelope decryption. Parses the "env1:wrappedDEK:payload" format,
115
+ * unwraps the DEK, and decrypts the payload.
116
+ */
117
+ function envelopeDecryptInternal(encryptedData, masterKey) {
118
+ // Format: "env1:<base64-wrappedDEK>:<base64-encryptedPayload>"
119
+ // The wrapped DEK itself is a base64 string produced by encrypt(), which
120
+ // can contain '+', '/', '=' but never ':'. So we split on ':' after the prefix.
121
+ const withoutPrefix = encryptedData.slice(ENVELOPE_PREFIX.length);
122
+ const separatorIndex = withoutPrefix.lastIndexOf(':');
123
+ if (separatorIndex <= 0) {
124
+ throw new Error('Invalid envelope format: missing DEK/payload separator');
125
+ }
126
+ const wrappedDEK = withoutPrefix.slice(0, separatorIndex);
127
+ const encryptedPayload = withoutPrefix.slice(separatorIndex + 1);
128
+ if (!wrappedDEK || !encryptedPayload) {
129
+ throw new Error('Invalid envelope format: empty DEK or payload');
130
+ }
131
+ // Unwrap the DEK using the master key (with key-rotation fallback)
132
+ let dekBase64;
133
+ try {
134
+ dekBase64 = decrypt(wrappedDEK, masterKey);
135
+ }
136
+ catch {
137
+ throw new Error('Envelope decryption failed: could not unwrap DEK');
138
+ }
139
+ const dek = (0, tweetnacl_util_1.decodeBase64)(dekBase64);
140
+ try {
141
+ // Decrypt the payload using the per-data DEK
142
+ // Use low-level decryption here (not decrypt()) to avoid infinite
143
+ // recursion on the envelope prefix check -- the inner payload is
144
+ // always in legacy format.
145
+ const combined = (0, tweetnacl_util_1.decodeBase64)(encryptedPayload);
146
+ const nonce = combined.slice(0, tweetnacl_1.default.secretbox.nonceLength);
147
+ const box = combined.slice(tweetnacl_1.default.secretbox.nonceLength);
148
+ const message = tweetnacl_1.default.secretbox.open(box, nonce, dek);
149
+ if (!message) {
150
+ throw new Error('Envelope decryption failed: payload decryption failed');
151
+ }
152
+ return new TextDecoder().decode(message);
153
+ }
154
+ finally {
155
+ // Zero DEK from memory after use
156
+ dek.fill(0);
36
157
  }
37
- return new TextDecoder().decode(message);
38
158
  }
39
159
  function encryptDEK(dek, masterKey) {
40
160
  return encrypt((0, tweetnacl_util_1.encodeBase64)(dek), masterKey);
@@ -48,12 +168,37 @@ function decryptDEK(encryptedDEK, masterKey) {
48
168
  let _cachedMasterKey = null;
49
169
  function getMasterKey() {
50
170
  if (_cachedMasterKey)
51
- return _cachedMasterKey;
171
+ return _cachedMasterKey.slice();
52
172
  const key = process.env.MASTER_KEY;
53
173
  if (!key)
54
174
  throw new Error('MASTER_KEY environment variable not set');
55
175
  _cachedMasterKey = (0, tweetnacl_util_1.decodeBase64)(key);
56
- return _cachedMasterKey;
176
+ return _cachedMasterKey.slice();
177
+ }
178
+ // Support MASTER_KEY rotation: try previous key when current key fails
179
+ let _cachedPrevKey = null;
180
+ let _prevKeyChecked = false;
181
+ function getPreviousMasterKey() {
182
+ if (_prevKeyChecked)
183
+ return _cachedPrevKey ? _cachedPrevKey.slice() : null;
184
+ _prevKeyChecked = true;
185
+ const key = process.env.MASTER_KEY_PREVIOUS;
186
+ if (!key)
187
+ return null;
188
+ _cachedPrevKey = (0, tweetnacl_util_1.decodeBase64)(key);
189
+ return _cachedPrevKey.slice();
190
+ }
191
+ /** Zero and release cached master keys. Call on graceful shutdown. */
192
+ function clearCachedKeys() {
193
+ if (_cachedMasterKey) {
194
+ _cachedMasterKey.fill(0);
195
+ _cachedMasterKey = null;
196
+ }
197
+ if (_cachedPrevKey) {
198
+ _cachedPrevKey.fill(0);
199
+ _cachedPrevKey = null;
200
+ }
201
+ _prevKeyChecked = false;
57
202
  }
58
203
  function generateMasterKey() {
59
204
  return (0, tweetnacl_util_1.encodeBase64)(generateKey());
@@ -1 +1 @@
1
- {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
package/dist/plans.d.ts CHANGED
@@ -4,9 +4,13 @@ export interface PlanLimits {
4
4
  agents: number;
5
5
  credentials: number;
6
6
  members: number;
7
+ policies: number;
7
8
  timelineHistoryDays: number;
8
9
  undoEnabled: boolean;
9
10
  browserSessions: number;
11
+ messagesPerMonth: number;
12
+ messageHistoryDays: number;
13
+ threadsPerAgent: number;
10
14
  }
11
15
  export interface PlanDefinition extends PlanLimits {
12
16
  id: PlanId;
@@ -1 +1 @@
1
- {"version":3,"file":"plans.d.ts","sourceRoot":"","sources":["../src/plans.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,UAAU;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CA8CvC,CAAC;AAEX,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAYtD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7C;AAED,8CAA8C;AAC9C,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO9D"}
1
+ {"version":3,"file":"plans.d.ts","sourceRoot":"","sources":["../src/plans.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,UAAU;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CA0DvC,CAAC;AAEX,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAgBtD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7C;AAED,8CAA8C;AAC9C,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO9D"}
package/dist/plans.js CHANGED
@@ -16,9 +16,13 @@ exports.PLANS = {
16
16
  agents: 3,
17
17
  credentials: 2,
18
18
  members: 1,
19
+ policies: 3,
19
20
  timelineHistoryDays: 14,
20
21
  undoEnabled: false,
21
22
  browserSessions: 0,
23
+ messagesPerMonth: 100,
24
+ messageHistoryDays: 7,
25
+ threadsPerAgent: 5,
22
26
  },
23
27
  pro: {
24
28
  id: 'pro',
@@ -31,9 +35,13 @@ exports.PLANS = {
31
35
  agents: 10,
32
36
  credentials: 25,
33
37
  members: 5,
38
+ policies: 10,
34
39
  timelineHistoryDays: 90,
35
40
  undoEnabled: true,
36
41
  browserSessions: 2,
42
+ messagesPerMonth: 5000,
43
+ messageHistoryDays: 30,
44
+ threadsPerAgent: 50,
37
45
  },
38
46
  team: {
39
47
  id: 'team',
@@ -46,9 +54,13 @@ exports.PLANS = {
46
54
  agents: 50,
47
55
  credentials: Infinity,
48
56
  members: 25,
57
+ policies: 50,
49
58
  timelineHistoryDays: 365,
50
59
  undoEnabled: true,
51
60
  browserSessions: 5,
61
+ messagesPerMonth: Infinity,
62
+ messageHistoryDays: 90,
63
+ threadsPerAgent: Infinity,
52
64
  },
53
65
  };
54
66
  function getPlanLimits(plan) {
@@ -60,9 +72,13 @@ function getPlanLimits(plan) {
60
72
  agents: def.agents,
61
73
  credentials: def.credentials,
62
74
  members: def.members,
75
+ policies: def.policies,
63
76
  timelineHistoryDays: def.timelineHistoryDays,
64
77
  undoEnabled: def.undoEnabled,
65
78
  browserSessions: def.browserSessions,
79
+ messagesPerMonth: def.messagesPerMonth,
80
+ messageHistoryDays: def.messageHistoryDays,
81
+ threadsPerAgent: def.threadsPerAgent,
66
82
  };
67
83
  }
68
84
  function canUndo(plan) {
package/dist/plans.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"plans.js","sourceRoot":"","sources":["../src/plans.ts"],"names":[],"mappings":";;;AAqEA,sCAYC;AAED,0BAEC;AAGD,0CAOC;AA1EY,QAAA,KAAK,GAAmC;IACnD,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,MAAM;QACZ,YAAY,EAAE,CAAC;QACf,WAAW,EAAE,CAAC;QACd,kBAAkB,EAAE,EAAE;QACtB,iBAAiB,EAAE,EAAE;QACrB,eAAe,EAAE,IAAI;QACrB,MAAM,EAAE,CAAC;QACT,WAAW,EAAE,CAAC;QACd,OAAO,EAAE,CAAC;QACV,mBAAmB,EAAE,EAAE;QACvB,WAAW,EAAE,KAAK;QAClB,eAAe,EAAE,CAAC;KACnB;IACD,GAAG,EAAE;QACH,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,GAAG;QACjB,WAAW,EAAE,IAAI;QACjB,kBAAkB,EAAE,gCAAgC;QACpD,iBAAiB,EAAE,gCAAgC;QACnD,eAAe,EAAE,QAAQ;QACzB,MAAM,EAAE,EAAE;QACV,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,CAAC;QACV,mBAAmB,EAAE,EAAE;QACvB,WAAW,EAAE,IAAI;QACjB,eAAe,EAAE,CAAC;KACnB;IACD,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,MAAM;QACZ,YAAY,EAAE,IAAI;QAClB,WAAW,EAAE,KAAK;QAClB,kBAAkB,EAAE,gCAAgC;QACpD,iBAAiB,EAAE,gCAAgC;QACnD,eAAe,EAAE,QAAQ;QACzB,MAAM,EAAE,EAAE;QACV,WAAW,EAAE,QAAQ;QACrB,OAAO,EAAE,EAAE;QACX,mBAAmB,EAAE,GAAG;QACxB,WAAW,EAAE,IAAI;QACjB,eAAe,EAAE,CAAC;KACnB;CACO,CAAC;AAEX,SAAgB,aAAa,CAAC,IAAY;IACxC,MAAM,GAAG,GAAG,aAAK,CAAC,IAAc,CAAC,CAAC;IAClC,IAAI,CAAC,GAAG;QAAE,OAAO,aAAK,CAAC,IAAI,CAAC;IAC5B,OAAO;QACL,eAAe,EAAE,GAAG,CAAC,eAAe;QACpC,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,mBAAmB,EAAE,GAAG,CAAC,mBAAmB;QAC5C,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,eAAe,EAAE,GAAG,CAAC,eAAe;KACrC,CAAC;AACJ,CAAC;AAED,SAAgB,OAAO,CAAC,IAAY;IAClC,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC;AACzC,CAAC;AAED,8CAA8C;AAC9C,SAAgB,eAAe,CAAC,OAAe;IAC7C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,aAAK,CAAC,EAAE,CAAC;QACxC,IAAI,IAAI,CAAC,kBAAkB,KAAK,OAAO,IAAI,IAAI,CAAC,iBAAiB,KAAK,OAAO,EAAE,CAAC;YAC9E,OAAO,IAAI,CAAC,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"plans.js","sourceRoot":"","sources":["../src/plans.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAClB,sBAAsB,EAGvB,MAAM,YAAY,CAAC;AAUpB,eAAO,MAAM,oBAAoB,EAAE,WAgBlC,CAAC;AAEF,wBAAgB,cAAc,CAC5B,MAAM,EAAE,kBAAkB,EAC1B,KAAK,EAAE,WAAW,GACjB,sBAAsB,CA+FxB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CA8CA"}
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAClB,sBAAsB,EAGvB,MAAM,YAAY,CAAC;AAUpB,eAAO,MAAM,oBAAoB,EAAE,WAiBlC,CAAC;AASF,wBAAgB,cAAc,CAC5B,MAAM,EAAE,kBAAkB,EAC1B,KAAK,EAAE,WAAW,GACjB,sBAAsB,CAsHxB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CA6CA"}
package/dist/policy.js CHANGED
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEFAULT_POLICY_RULES = void 0;
4
4
  exports.evaluatePolicy = evaluatePolicy;
5
5
  exports.buildActionPreview = buildActionPreview;
6
- const redact_js_1 = require("./redact.js");
7
6
  const RISK_MAP = {
8
7
  read: 'low',
9
8
  write: 'medium',
@@ -17,6 +16,7 @@ exports.DEFAULT_POLICY_RULES = {
17
16
  { action_type: 'write', decision: 'REQUIRE_APPROVAL' },
18
17
  { action_type: 'financial', decision: 'REQUIRE_APPROVAL' },
19
18
  { action_type: 'admin', decision: 'BLOCK' },
19
+ { tool: 'mcp.list_tools', decision: 'ALLOW' },
20
20
  ],
21
21
  http: {
22
22
  allowedDomains: [],
@@ -24,14 +24,27 @@ exports.DEFAULT_POLICY_RULES = {
24
24
  blockList: [],
25
25
  },
26
26
  limits: {
27
- maxActionsPerHour: 100,
27
+ maxActionsPerHour: 100, // Enforced in gateway via check_rate_limit RPC
28
28
  },
29
29
  };
30
+ // Default HTTP rules when rules.http is not configured
31
+ const DEFAULT_HTTP_RULES = {
32
+ allowedDomains: [],
33
+ allowedMethods: ['GET', 'POST', 'PUT', 'DELETE'],
34
+ blockList: [],
35
+ };
30
36
  function evaluatePolicy(action, rules) {
37
+ // Block unknown action types (defense-in-depth)
38
+ if (!(action.action_type in RISK_MAP)) {
39
+ return { decision: 'BLOCK', risk_level: 'critical', reason: `Unknown action type: ${action.action_type}` };
40
+ }
41
+ // SECURITY: Normalize tool name to lowercase to prevent case-sensitivity
42
+ // bypasses (e.g., "Http.get" skipping HTTP domain allowlist checks).
43
+ const normalizedTool = action.tool.toLowerCase();
31
44
  const risk_level = RISK_MAP[action.action_type] ?? 'medium';
32
45
  // Browser tools: browser.open always requires approval
33
- if (action.tool.startsWith('browser.')) {
34
- if (action.tool === 'browser.open') {
46
+ if (normalizedTool.startsWith('browser.')) {
47
+ if (normalizedTool === 'browser.open') {
35
48
  return {
36
49
  decision: 'REQUIRE_APPROVAL',
37
50
  risk_level: 'medium',
@@ -47,26 +60,31 @@ function evaluatePolicy(action, rules) {
47
60
  reason: 'Browser actions require an active session (use browser.open first)',
48
61
  };
49
62
  }
50
- // MCP tools: list_tools is a read (low risk), call_tool defers to action_type rules
51
- if (action.tool === 'mcp.list_tools') {
52
- return {
53
- decision: 'ALLOW',
54
- risk_level: 'low',
55
- reason: 'MCP tool discovery is read-only',
56
- };
57
- }
58
- if (action.tool.split('.')[0] === 'http' && rules.http) {
63
+ // MCP tools: list_tools handled via default rules (can be overridden by custom policies)
64
+ // HTTP tool checks: always enforce domain/method restrictions
65
+ const isHttpTool = normalizedTool.split('.')[0] === 'http';
66
+ if (isHttpTool) {
67
+ const httpRules = rules.http ?? DEFAULT_HTTP_RULES;
59
68
  const url = action.payload.url;
69
+ if (!url) {
70
+ // SECURITY: HTTP actions without a URL must be blocked at the policy level.
71
+ // The connector would also reject it, but policy should be the first gate.
72
+ return { decision: 'BLOCK', risk_level: 'critical', reason: 'HTTP actions require a URL in payload' };
73
+ }
60
74
  if (url) {
61
75
  try {
62
- const domain = new URL(url).hostname;
76
+ const domain = new URL(url).hostname.replace(/\.$/, '').toLowerCase();
63
77
  // Use exact match or proper subdomain match (preceded by a dot)
64
78
  // to prevent "not-trusted.com" from matching allowlist entry "trusted.com"
65
- const matchesDomain = (d, pattern) => d === pattern || d.endsWith('.' + pattern);
66
- if (rules.http.blockList.some((b) => matchesDomain(domain, b))) {
79
+ // Both sides are normalized: lowercase + trailing-dot stripped.
80
+ const matchesDomain = (d, pattern) => {
81
+ const normalizedPattern = pattern.replace(/\.$/, '').toLowerCase();
82
+ return d === normalizedPattern || d.endsWith('.' + normalizedPattern);
83
+ };
84
+ if (httpRules.blockList.some((b) => matchesDomain(domain, b))) {
67
85
  return { decision: 'BLOCK', risk_level: 'critical', reason: `Domain ${domain} is in block list` };
68
86
  }
69
- if (rules.http.allowedDomains.length === 0) {
87
+ if (httpRules.allowedDomains.length === 0) {
70
88
  // No allowlist configured: safe default is REQUIRE_APPROVAL, not ALLOW.
71
89
  // This prevents agents from exfiltrating data to arbitrary domains.
72
90
  return {
@@ -75,7 +93,7 @@ function evaluatePolicy(action, rules) {
75
93
  reason: 'HTTP allowlist not configured — approval required for all HTTP calls',
76
94
  };
77
95
  }
78
- if (!rules.http.allowedDomains.some((d) => matchesDomain(domain, d))) {
96
+ if (!httpRules.allowedDomains.some((d) => matchesDomain(domain, d))) {
79
97
  return { decision: 'BLOCK', risk_level, reason: `Domain ${domain} not in allowed list` };
80
98
  }
81
99
  }
@@ -84,7 +102,7 @@ function evaluatePolicy(action, rules) {
84
102
  }
85
103
  }
86
104
  const method = action.payload.method?.toUpperCase();
87
- if (method && !rules.http.allowedMethods.includes(method)) {
105
+ if (method && !httpRules.allowedMethods.includes(method)) {
88
106
  return { decision: 'BLOCK', risk_level, reason: `HTTP method ${method} not allowed` };
89
107
  }
90
108
  }
@@ -97,26 +115,36 @@ function evaluatePolicy(action, rules) {
97
115
  reason: `Cost estimate ${action.cost_estimate} exceeds limit ${rules.limits.maxCostPerAction}`,
98
116
  };
99
117
  }
100
- // Most specific: tool-specific rule
101
- let matched = rules.rules.find((r) => r.tool === action.tool);
118
+ // Most specific: tool-specific rule (case-insensitive to prevent bypasses)
119
+ let matched = rules.rules.find((r) => r.tool !== undefined && r.tool.toLowerCase() === normalizedTool);
102
120
  // Then action-type rule
103
121
  if (!matched)
104
122
  matched = rules.rules.find((r) => r.action_type === action.action_type);
105
123
  if (matched) {
124
+ let finalDecision = matched.decision;
125
+ // SECURITY: Never auto-allow admin/financial actions even via explicit rules
126
+ if (finalDecision === 'ALLOW' && ['admin', 'financial'].includes(action.action_type)) {
127
+ finalDecision = 'REQUIRE_APPROVAL';
128
+ }
106
129
  return {
107
- decision: matched.decision,
130
+ decision: finalDecision,
108
131
  risk_level,
109
132
  reason: `Matched rule: ${matched.action_type ?? matched.tool}`,
110
133
  matched_rule: matched,
111
134
  };
112
135
  }
113
136
  const defaultDecision = rules.defaultMode === 'allow' ? 'ALLOW' : rules.defaultMode === 'block' ? 'BLOCK' : 'REQUIRE_APPROVAL';
137
+ // SECURITY: Never auto-allow high-risk actions via permissive default mode
138
+ if (defaultDecision === 'ALLOW' && ['admin', 'financial'].includes(action.action_type)) {
139
+ return { decision: 'REQUIRE_APPROVAL', risk_level, reason: 'High-risk action types always require approval even with permissive default policy' };
140
+ }
114
141
  return { decision: defaultDecision, risk_level, reason: 'Default policy' };
115
142
  }
116
143
  function buildActionPreview(action) {
144
+ const normalizedTool = action.tool.toLowerCase();
117
145
  let summary = `${action.action_type.toUpperCase()} via ${action.tool}`;
118
146
  let target;
119
- if (action.tool.split('.')[0] === 'http') {
147
+ if (normalizedTool.split('.')[0] === 'http') {
120
148
  const url = action.payload.url;
121
149
  const method = action.payload.method;
122
150
  if (url) {
@@ -129,7 +157,7 @@ function buildActionPreview(action) {
129
157
  summary = `${method?.toUpperCase() ?? 'HTTP'} request to ${target}`;
130
158
  }
131
159
  }
132
- else if (action.tool === 'browser.open') {
160
+ else if (normalizedTool === 'browser.open') {
133
161
  const url = action.payload.url;
134
162
  if (url) {
135
163
  try {
@@ -144,20 +172,17 @@ function buildActionPreview(action) {
144
172
  summary = 'Open browser session';
145
173
  }
146
174
  }
147
- else if (action.tool === 'mcp.list_tools') {
175
+ else if (normalizedTool === 'mcp.list_tools') {
148
176
  const server = action.payload.server;
149
177
  target = server;
150
178
  summary = `List available tools on MCP server "${server ?? 'unknown'}"`;
151
179
  }
152
- else if (action.tool === 'mcp.call_tool') {
180
+ else if (normalizedTool === 'mcp.call_tool') {
153
181
  const server = action.payload.server;
154
182
  const method = action.payload.method;
155
183
  target = server;
156
184
  summary = `Call "${method ?? 'unknown'}" on MCP server "${server ?? 'unknown'}"`;
157
185
  }
158
- else if (action.tool === 'demo') {
159
- summary = `Write to demo table: ${JSON.stringify((0, redact_js_1.redact)(action.payload)).slice(0, 80)}`;
160
- }
161
186
  return {
162
187
  summary,
163
188
  target,
@@ -1 +1 @@
1
- {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}