@agentuity/cli 0.0.69 → 0.0.70
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/AGENTS.md +1 -1
- package/README.md +1 -1
- package/dist/cmd/ai/capabilities/show.d.ts.map +1 -1
- package/dist/cmd/ai/capabilities/show.js +0 -13
- package/dist/cmd/ai/capabilities/show.js.map +1 -1
- package/dist/cmd/ai/prompt/agent.js +1 -1
- package/dist/cmd/ai/prompt/api.js +1 -1
- package/dist/cmd/build/ast.d.ts +1 -2
- package/dist/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +261 -260
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/bundler.d.ts +2 -1
- package/dist/cmd/build/bundler.d.ts.map +1 -1
- package/dist/cmd/build/bundler.js +11 -2
- package/dist/cmd/build/bundler.js.map +1 -1
- package/dist/cmd/build/index.js +1 -1
- package/dist/cmd/build/index.js.map +1 -1
- package/dist/cmd/build/plugin.d.ts.map +1 -1
- package/dist/cmd/build/plugin.js +152 -414
- package/dist/cmd/build/plugin.js.map +1 -1
- package/dist/cmd/build/route-registry.d.ts +36 -0
- package/dist/cmd/build/route-registry.d.ts.map +1 -0
- package/dist/cmd/build/route-registry.js +151 -0
- package/dist/cmd/build/route-registry.js.map +1 -0
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +1 -0
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/cloud/index.d.ts.map +1 -1
- package/dist/cmd/cloud/index.js +0 -2
- package/dist/cmd/cloud/index.js.map +1 -1
- package/dist/cmd/dev/index.js +3 -3
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/dev/sync.d.ts.map +1 -1
- package/dist/cmd/dev/sync.js +0 -15
- package/dist/cmd/dev/sync.js.map +1 -1
- package/dist/cmd/dev/templates.d.ts.map +1 -1
- package/dist/cmd/dev/templates.js +11 -35
- package/dist/cmd/dev/templates.js.map +1 -1
- package/dist/cmd/profile/create.d.ts.map +1 -1
- package/dist/cmd/profile/create.js +0 -1
- package/dist/cmd/profile/create.js.map +1 -1
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.js +64 -53
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -3
- package/dist/config.js.map +1 -1
- package/dist/tui/box.d.ts +19 -0
- package/dist/tui/box.d.ts.map +1 -0
- package/dist/tui/box.js +160 -0
- package/dist/tui/box.js.map +1 -0
- package/dist/tui/colors.d.ts +20 -0
- package/dist/tui/colors.d.ts.map +1 -0
- package/dist/tui/colors.js +52 -0
- package/dist/tui/colors.js.map +1 -0
- package/dist/tui/group.d.ts +25 -0
- package/dist/tui/group.d.ts.map +1 -0
- package/dist/tui/group.js +32 -0
- package/dist/tui/group.js.map +1 -0
- package/dist/tui/prompt.d.ts +65 -0
- package/dist/tui/prompt.d.ts.map +1 -0
- package/dist/tui/prompt.js +377 -0
- package/dist/tui/prompt.js.map +1 -0
- package/dist/tui/symbols.d.ts +32 -0
- package/dist/tui/symbols.d.ts.map +1 -0
- package/dist/tui/symbols.js +52 -0
- package/dist/tui/symbols.js.map +1 -0
- package/dist/tui.d.ts +6 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +6 -0
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +0 -24
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
- package/src/cmd/ai/capabilities/show.ts +0 -13
- package/src/cmd/ai/prompt/agent.ts +1 -1
- package/src/cmd/ai/prompt/api.ts +1 -1
- package/src/cmd/build/ast.ts +364 -334
- package/src/cmd/build/bundler.ts +16 -1
- package/src/cmd/build/index.ts +1 -1
- package/src/cmd/build/plugin.ts +171 -493
- package/src/cmd/build/route-registry.ts +198 -0
- package/src/cmd/cloud/deploy.ts +1 -0
- package/src/cmd/cloud/index.ts +0 -2
- package/src/cmd/dev/index.ts +3 -3
- package/src/cmd/dev/sync.ts +0 -28
- package/src/cmd/dev/templates.ts +11 -35
- package/src/cmd/profile/create.ts +0 -1
- package/src/cmd/project/template-flow.ts +77 -57
- package/src/config.ts +0 -3
- package/src/tui/box.ts +202 -0
- package/src/tui/colors.ts +55 -0
- package/src/tui/group.ts +56 -0
- package/src/tui/prompt.ts +506 -0
- package/src/tui/symbols.ts +64 -0
- package/src/tui.ts +14 -0
- package/src/types.ts +0 -1
- package/dist/cmd/cloud/objectstore/delete-bucket.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/delete-bucket.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/delete-bucket.js +0 -72
- package/dist/cmd/cloud/objectstore/delete-bucket.js.map +0 -1
- package/dist/cmd/cloud/objectstore/delete.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/delete.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/delete.js +0 -65
- package/dist/cmd/cloud/objectstore/delete.js.map +0 -1
- package/dist/cmd/cloud/objectstore/get.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/get.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/get.js +0 -75
- package/dist/cmd/cloud/objectstore/get.js.map +0 -1
- package/dist/cmd/cloud/objectstore/index.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/index.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/index.js +0 -36
- package/dist/cmd/cloud/objectstore/index.js.map +0 -1
- package/dist/cmd/cloud/objectstore/list-buckets.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/list-buckets.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/list-buckets.js +0 -46
- package/dist/cmd/cloud/objectstore/list-buckets.js.map +0 -1
- package/dist/cmd/cloud/objectstore/list-keys.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/list-keys.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/list-keys.js +0 -58
- package/dist/cmd/cloud/objectstore/list-keys.js.map +0 -1
- package/dist/cmd/cloud/objectstore/put.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/put.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/put.js +0 -66
- package/dist/cmd/cloud/objectstore/put.js.map +0 -1
- package/dist/cmd/cloud/objectstore/repl.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/repl.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/repl.js +0 -224
- package/dist/cmd/cloud/objectstore/repl.js.map +0 -1
- package/dist/cmd/cloud/objectstore/url.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/url.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/url.js +0 -64
- package/dist/cmd/cloud/objectstore/url.js.map +0 -1
- package/dist/cmd/cloud/objectstore/util.d.ts +0 -11
- package/dist/cmd/cloud/objectstore/util.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/util.js +0 -18
- package/dist/cmd/cloud/objectstore/util.js.map +0 -1
- package/src/cmd/build/ast.test.ts +0 -418
- package/src/cmd/build/fix-duplicate-exports.test.ts +0 -387
- package/src/cmd/cloud/objectstore/delete-bucket.ts +0 -77
- package/src/cmd/cloud/objectstore/delete.ts +0 -67
- package/src/cmd/cloud/objectstore/get.ts +0 -77
- package/src/cmd/cloud/objectstore/index.ts +0 -36
- package/src/cmd/cloud/objectstore/list-buckets.ts +0 -51
- package/src/cmd/cloud/objectstore/list-keys.ts +0 -63
- package/src/cmd/cloud/objectstore/put.ts +0 -74
- package/src/cmd/cloud/objectstore/repl.ts +0 -239
- package/src/cmd/cloud/objectstore/url.ts +0 -67
- package/src/cmd/cloud/objectstore/util.ts +0 -29
- package/src/crypto/box.test.ts +0 -431
- package/src/env-util.test.ts +0 -194
package/src/crypto/box.test.ts
DELETED
|
@@ -1,431 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect, beforeAll } from 'bun:test';
|
|
2
|
-
import { generateKeyPairSync, KeyObject } from 'node:crypto';
|
|
3
|
-
import { Readable, Writable } from 'node:stream';
|
|
4
|
-
import { encryptFIPSKEMDEMStream, decryptFIPSKEMDEMStream } from './box';
|
|
5
|
-
|
|
6
|
-
function createReadableStream(data: Buffer): Readable {
|
|
7
|
-
return Readable.from([data]);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
class CollectorStream extends Writable {
|
|
11
|
-
private chunks: Buffer[] = [];
|
|
12
|
-
|
|
13
|
-
_write(chunk: Buffer, _encoding: string, callback: () => void): void {
|
|
14
|
-
this.chunks.push(chunk);
|
|
15
|
-
callback();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
getData(): Buffer {
|
|
19
|
-
return Buffer.concat(this.chunks);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function generateP256KeyPair(): { publicKey: KeyObject; privateKey: KeyObject } {
|
|
24
|
-
return generateKeyPairSync('ec', {
|
|
25
|
-
namedCurve: 'prime256v1',
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function generateP384KeyPair(): { publicKey: KeyObject; privateKey: KeyObject } {
|
|
30
|
-
return generateKeyPairSync('ec', {
|
|
31
|
-
namedCurve: 'secp384r1',
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
describe('crypto/box', () => {
|
|
36
|
-
describe('TestBasicEncryptDecrypt', () => {
|
|
37
|
-
let keyPair: { publicKey: KeyObject; privateKey: KeyObject };
|
|
38
|
-
|
|
39
|
-
beforeAll(() => {
|
|
40
|
-
keyPair = generateP256KeyPair();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const testCases = [
|
|
44
|
-
{ name: 'empty', data: Buffer.alloc(0) },
|
|
45
|
-
{ name: 'small', data: Buffer.from('hello world') },
|
|
46
|
-
{ name: 'medium', data: Buffer.alloc(1000).fill('A') },
|
|
47
|
-
{ name: 'large', data: Buffer.alloc(100000).fill('B') },
|
|
48
|
-
{ name: 'exactly_one_frame', data: Buffer.alloc(64 * 1024).fill('C') },
|
|
49
|
-
{ name: 'just_over_one_frame', data: Buffer.alloc(64 * 1024 + 1).fill('D') },
|
|
50
|
-
];
|
|
51
|
-
|
|
52
|
-
for (const tc of testCases) {
|
|
53
|
-
test(tc.name, async () => {
|
|
54
|
-
const src = createReadableStream(tc.data);
|
|
55
|
-
const encrypted = new CollectorStream();
|
|
56
|
-
const written = await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
57
|
-
|
|
58
|
-
expect(written).toBe(tc.data.length);
|
|
59
|
-
|
|
60
|
-
const encryptedData = encrypted.getData();
|
|
61
|
-
const decryptSrc = createReadableStream(encryptedData);
|
|
62
|
-
const decrypted = new CollectorStream();
|
|
63
|
-
const read = await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted);
|
|
64
|
-
|
|
65
|
-
expect(read).toBe(tc.data.length);
|
|
66
|
-
|
|
67
|
-
const decryptedData = decrypted.getData();
|
|
68
|
-
expect(decryptedData.equals(tc.data)).toBe(true);
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
describe('TestDifferentKeys', () => {
|
|
74
|
-
test('should fail to decrypt with wrong key', async () => {
|
|
75
|
-
const keyPair1 = generateP256KeyPair();
|
|
76
|
-
const keyPair2 = generateP256KeyPair();
|
|
77
|
-
|
|
78
|
-
const data = Buffer.from('test data');
|
|
79
|
-
|
|
80
|
-
const src = createReadableStream(data);
|
|
81
|
-
const encrypted = new CollectorStream();
|
|
82
|
-
await encryptFIPSKEMDEMStream(keyPair1.publicKey, src, encrypted);
|
|
83
|
-
|
|
84
|
-
const encryptedData = encrypted.getData();
|
|
85
|
-
const decryptSrc = createReadableStream(encryptedData);
|
|
86
|
-
const decrypted = new CollectorStream();
|
|
87
|
-
|
|
88
|
-
await expect(
|
|
89
|
-
decryptFIPSKEMDEMStream(keyPair2.privateKey, decryptSrc, decrypted)
|
|
90
|
-
).rejects.toThrow('DEK unwrap failed');
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
describe('TestMalformedHeaders', () => {
|
|
95
|
-
let keyPair: { publicKey: KeyObject; privateKey: KeyObject };
|
|
96
|
-
|
|
97
|
-
beforeAll(() => {
|
|
98
|
-
keyPair = generateP256KeyPair();
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
const testCases = [
|
|
102
|
-
{ name: 'empty', data: Buffer.alloc(0), err: 'unexpected EOF' },
|
|
103
|
-
{ name: 'partial_len', data: Buffer.from([0]), err: 'unexpected EOF' },
|
|
104
|
-
{
|
|
105
|
-
name: 'invalid_wrapped_len',
|
|
106
|
-
data: Buffer.from([0x10, 0x00]),
|
|
107
|
-
err: 'invalid wrapped DEK length',
|
|
108
|
-
},
|
|
109
|
-
{ name: 'zero_len', data: Buffer.from([0x00, 0x00]), err: 'invalid wrapped DEK length' },
|
|
110
|
-
];
|
|
111
|
-
|
|
112
|
-
for (const tc of testCases) {
|
|
113
|
-
test(tc.name, async () => {
|
|
114
|
-
const src = createReadableStream(tc.data);
|
|
115
|
-
const decrypted = new CollectorStream();
|
|
116
|
-
|
|
117
|
-
await expect(
|
|
118
|
-
decryptFIPSKEMDEMStream(keyPair.privateKey, src, decrypted)
|
|
119
|
-
).rejects.toThrow(tc.err);
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
describe('TestMalformedChunks', () => {
|
|
125
|
-
test('should fail authentication for malformed chunk', async () => {
|
|
126
|
-
const keyPair = generateP256KeyPair();
|
|
127
|
-
|
|
128
|
-
const buf = Buffer.alloc(2 + 113 + 12 + 2 + 32);
|
|
129
|
-
let offset = 0;
|
|
130
|
-
|
|
131
|
-
buf.writeUInt16BE(113, offset); // reasonable wrapped length (65+32+16)
|
|
132
|
-
offset += 2;
|
|
133
|
-
offset += 113;
|
|
134
|
-
offset += 12;
|
|
135
|
-
|
|
136
|
-
buf.writeUInt16BE(32, offset); // reasonable chunk size
|
|
137
|
-
offset += 2;
|
|
138
|
-
|
|
139
|
-
const src = createReadableStream(buf);
|
|
140
|
-
const decrypted = new CollectorStream();
|
|
141
|
-
|
|
142
|
-
await expect(
|
|
143
|
-
decryptFIPSKEMDEMStream(keyPair.privateKey, src, decrypted)
|
|
144
|
-
).rejects.toThrow();
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
describe('TestStreamEOF', () => {
|
|
149
|
-
test('should handle empty stream', async () => {
|
|
150
|
-
const keyPair = generateP256KeyPair();
|
|
151
|
-
|
|
152
|
-
const src = createReadableStream(Buffer.alloc(0));
|
|
153
|
-
const encrypted = new CollectorStream();
|
|
154
|
-
|
|
155
|
-
const written = await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
156
|
-
expect(written).toBe(0);
|
|
157
|
-
|
|
158
|
-
const encryptedData = encrypted.getData();
|
|
159
|
-
const decryptSrc = createReadableStream(encryptedData);
|
|
160
|
-
const decrypted = new CollectorStream();
|
|
161
|
-
|
|
162
|
-
const read = await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted);
|
|
163
|
-
expect(read).toBe(0);
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
describe('TestNonceReuseProtection', () => {
|
|
168
|
-
test('different encryptions should produce different ciphertexts', async () => {
|
|
169
|
-
const keyPair = generateP256KeyPair();
|
|
170
|
-
const data = Buffer.from('test data for nonce reuse protection');
|
|
171
|
-
|
|
172
|
-
const src1 = createReadableStream(data);
|
|
173
|
-
const encrypted1 = new CollectorStream();
|
|
174
|
-
await encryptFIPSKEMDEMStream(keyPair.publicKey, src1, encrypted1);
|
|
175
|
-
|
|
176
|
-
const src2 = createReadableStream(data);
|
|
177
|
-
const encrypted2 = new CollectorStream();
|
|
178
|
-
await encryptFIPSKEMDEMStream(keyPair.publicKey, src2, encrypted2);
|
|
179
|
-
|
|
180
|
-
const enc1Data = encrypted1.getData();
|
|
181
|
-
const enc2Data = encrypted2.getData();
|
|
182
|
-
expect(enc1Data.equals(enc2Data)).toBe(false);
|
|
183
|
-
|
|
184
|
-
const decryptSrc1 = createReadableStream(enc1Data);
|
|
185
|
-
const decrypted1 = new CollectorStream();
|
|
186
|
-
await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc1, decrypted1);
|
|
187
|
-
|
|
188
|
-
const decryptSrc2 = createReadableStream(enc2Data);
|
|
189
|
-
const decrypted2 = new CollectorStream();
|
|
190
|
-
await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc2, decrypted2);
|
|
191
|
-
|
|
192
|
-
expect(decrypted1.getData().equals(data)).toBe(true);
|
|
193
|
-
expect(decrypted2.getData().equals(data)).toBe(true);
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
describe('TestFrameSizeBoundaries', () => {
|
|
198
|
-
let keyPair: { publicKey: KeyObject; privateKey: KeyObject };
|
|
199
|
-
|
|
200
|
-
beforeAll(() => {
|
|
201
|
-
keyPair = generateP256KeyPair();
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
const FRAME = 65519;
|
|
205
|
-
const testCases = [
|
|
206
|
-
{ name: 'exactly_max_frame', size: FRAME },
|
|
207
|
-
{ name: 'max_frame_minus_1', size: FRAME - 1 },
|
|
208
|
-
{ name: 'max_frame_plus_1', size: FRAME + 1 },
|
|
209
|
-
{ name: 'half_frame', size: Math.floor(FRAME / 2) },
|
|
210
|
-
{ name: 'double_frame', size: FRAME * 2 },
|
|
211
|
-
];
|
|
212
|
-
|
|
213
|
-
for (const tc of testCases) {
|
|
214
|
-
test(tc.name, async () => {
|
|
215
|
-
const data = Buffer.alloc(tc.size).fill('A');
|
|
216
|
-
|
|
217
|
-
const src = createReadableStream(data);
|
|
218
|
-
const encrypted = new CollectorStream();
|
|
219
|
-
const written = await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
220
|
-
|
|
221
|
-
expect(written).toBe(tc.size);
|
|
222
|
-
|
|
223
|
-
const encryptedData = encrypted.getData();
|
|
224
|
-
const decryptSrc = createReadableStream(encryptedData);
|
|
225
|
-
const decrypted = new CollectorStream();
|
|
226
|
-
const read = await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted);
|
|
227
|
-
|
|
228
|
-
expect(read).toBe(tc.size);
|
|
229
|
-
|
|
230
|
-
const decryptedData = decrypted.getData();
|
|
231
|
-
expect(decryptedData.equals(data)).toBe(true);
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
describe('TestUint16OverflowProtection', () => {
|
|
237
|
-
test('should not overflow with maximum frame size', async () => {
|
|
238
|
-
const FRAME = 65519;
|
|
239
|
-
const GCM_TAG = 16;
|
|
240
|
-
|
|
241
|
-
const maxExpected = FRAME + GCM_TAG;
|
|
242
|
-
expect(maxExpected).toBeLessThanOrEqual(0xffff);
|
|
243
|
-
|
|
244
|
-
const keyPair = generateP256KeyPair();
|
|
245
|
-
const data = Buffer.alloc(FRAME).fill('B');
|
|
246
|
-
|
|
247
|
-
const src = createReadableStream(data);
|
|
248
|
-
const encrypted = new CollectorStream();
|
|
249
|
-
|
|
250
|
-
await expect(encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted)).resolves.toBe(
|
|
251
|
-
FRAME
|
|
252
|
-
);
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
describe('TestUnsupportedCurves', () => {
|
|
257
|
-
test('should reject P-384 keys', async () => {
|
|
258
|
-
const keyPair384 = generateP384KeyPair();
|
|
259
|
-
const data = Buffer.from('test data');
|
|
260
|
-
|
|
261
|
-
const src = createReadableStream(data);
|
|
262
|
-
const encrypted = new CollectorStream();
|
|
263
|
-
|
|
264
|
-
await expect(
|
|
265
|
-
encryptFIPSKEMDEMStream(keyPair384.publicKey, src, encrypted)
|
|
266
|
-
).rejects.toThrow('only P-256 keys supported');
|
|
267
|
-
|
|
268
|
-
const decryptSrc = createReadableStream(Buffer.alloc(0));
|
|
269
|
-
const decrypted = new CollectorStream();
|
|
270
|
-
|
|
271
|
-
await expect(
|
|
272
|
-
decryptFIPSKEMDEMStream(keyPair384.privateKey, decryptSrc, decrypted)
|
|
273
|
-
).rejects.toThrow('only P-256 keys supported');
|
|
274
|
-
});
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
describe('TestConcurrentOperations', () => {
|
|
278
|
-
test('should handle concurrent encrypt/decrypt operations', async () => {
|
|
279
|
-
const keyPair = generateP256KeyPair();
|
|
280
|
-
const numGoroutines = 10;
|
|
281
|
-
const dataSize = 10000;
|
|
282
|
-
|
|
283
|
-
const promises: Promise<void>[] = [];
|
|
284
|
-
|
|
285
|
-
for (let i = 0; i < numGoroutines; i++) {
|
|
286
|
-
const promise = (async (id: number) => {
|
|
287
|
-
const data = Buffer.alloc(Math.floor(dataSize / 10))
|
|
288
|
-
.fill(`data${id}`)
|
|
289
|
-
.subarray(0, Math.floor(dataSize / 10));
|
|
290
|
-
|
|
291
|
-
const src = createReadableStream(data);
|
|
292
|
-
const encrypted = new CollectorStream();
|
|
293
|
-
await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
294
|
-
|
|
295
|
-
const encryptedData = encrypted.getData();
|
|
296
|
-
const decryptSrc = createReadableStream(encryptedData);
|
|
297
|
-
const decrypted = new CollectorStream();
|
|
298
|
-
await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted);
|
|
299
|
-
|
|
300
|
-
const decryptedData = decrypted.getData();
|
|
301
|
-
if (!decryptedData.equals(data)) {
|
|
302
|
-
throw new Error(`goroutine ${id} data mismatch`);
|
|
303
|
-
}
|
|
304
|
-
})(i);
|
|
305
|
-
|
|
306
|
-
promises.push(promise);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
await Promise.all(promises);
|
|
310
|
-
});
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
describe('TestDifferentKeyPairs', () => {
|
|
314
|
-
test('should work with correct key and fail with wrong key', async () => {
|
|
315
|
-
const keyPair1 = generateP256KeyPair();
|
|
316
|
-
const keyPair2 = generateP256KeyPair();
|
|
317
|
-
const data = Buffer.from('test data');
|
|
318
|
-
|
|
319
|
-
const src = createReadableStream(data);
|
|
320
|
-
const encrypted = new CollectorStream();
|
|
321
|
-
const written = await encryptFIPSKEMDEMStream(keyPair1.publicKey, src, encrypted);
|
|
322
|
-
|
|
323
|
-
expect(written).toBe(data.length);
|
|
324
|
-
|
|
325
|
-
const encryptedData = encrypted.getData();
|
|
326
|
-
const decryptSrc1 = createReadableStream(encryptedData);
|
|
327
|
-
const decrypted1 = new CollectorStream();
|
|
328
|
-
const read = await decryptFIPSKEMDEMStream(keyPair1.privateKey, decryptSrc1, decrypted1);
|
|
329
|
-
|
|
330
|
-
expect(read).toBe(data.length);
|
|
331
|
-
expect(decrypted1.getData().equals(data)).toBe(true);
|
|
332
|
-
|
|
333
|
-
const decryptSrc2 = createReadableStream(encryptedData);
|
|
334
|
-
const decrypted2 = new CollectorStream();
|
|
335
|
-
|
|
336
|
-
await expect(
|
|
337
|
-
decryptFIPSKEMDEMStream(keyPair2.privateKey, decryptSrc2, decrypted2)
|
|
338
|
-
).rejects.toThrow();
|
|
339
|
-
|
|
340
|
-
expect(decrypted2.getData().length).toBe(0);
|
|
341
|
-
});
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
describe('TestPartialCorruption', () => {
|
|
345
|
-
test('should handle corrupted data gracefully', async () => {
|
|
346
|
-
const keyPair = generateP256KeyPair();
|
|
347
|
-
const testData = Buffer.from('This is test data for corruption testing');
|
|
348
|
-
|
|
349
|
-
const src = createReadableStream(testData);
|
|
350
|
-
const encrypted = new CollectorStream();
|
|
351
|
-
await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
352
|
-
|
|
353
|
-
const validEncrypted = encrypted.getData();
|
|
354
|
-
|
|
355
|
-
const corruptPositions = [
|
|
356
|
-
0, // Header start
|
|
357
|
-
1, // Header middle
|
|
358
|
-
Math.floor(validEncrypted.length / 4), // Early data
|
|
359
|
-
Math.floor(validEncrypted.length / 2), // Middle data
|
|
360
|
-
Math.floor((3 * validEncrypted.length) / 4), // Late data
|
|
361
|
-
validEncrypted.length - 1, // End data
|
|
362
|
-
];
|
|
363
|
-
|
|
364
|
-
for (const pos of corruptPositions) {
|
|
365
|
-
if (pos >= validEncrypted.length) {
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
const corrupted = Buffer.from(validEncrypted);
|
|
370
|
-
corrupted[pos] ^= 0x01; // Flip one bit
|
|
371
|
-
|
|
372
|
-
const decryptSrc = createReadableStream(corrupted);
|
|
373
|
-
const decrypted = new CollectorStream();
|
|
374
|
-
|
|
375
|
-
await expect(
|
|
376
|
-
decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted)
|
|
377
|
-
).rejects.toThrow();
|
|
378
|
-
}
|
|
379
|
-
});
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
describe('TestLargeData', () => {
|
|
383
|
-
test('should handle multi-megabyte data', async () => {
|
|
384
|
-
const keyPair = generateP256KeyPair();
|
|
385
|
-
const data = Buffer.alloc(1024 * 1024).fill('X');
|
|
386
|
-
|
|
387
|
-
const src = createReadableStream(data);
|
|
388
|
-
const encrypted = new CollectorStream();
|
|
389
|
-
const written = await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
390
|
-
|
|
391
|
-
expect(written).toBe(data.length);
|
|
392
|
-
|
|
393
|
-
const encryptedData = encrypted.getData();
|
|
394
|
-
const decryptSrc = createReadableStream(encryptedData);
|
|
395
|
-
const decrypted = new CollectorStream();
|
|
396
|
-
const read = await decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted);
|
|
397
|
-
|
|
398
|
-
expect(read).toBe(data.length);
|
|
399
|
-
|
|
400
|
-
const decryptedData = decrypted.getData();
|
|
401
|
-
expect(decryptedData.equals(data)).toBe(true);
|
|
402
|
-
});
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
describe('TestChunkTooLarge', () => {
|
|
406
|
-
test('should reject chunks that are too large', async () => {
|
|
407
|
-
const keyPair = generateP256KeyPair();
|
|
408
|
-
const data = Buffer.from('test data');
|
|
409
|
-
|
|
410
|
-
const src = createReadableStream(data);
|
|
411
|
-
const encrypted = new CollectorStream();
|
|
412
|
-
await encryptFIPSKEMDEMStream(keyPair.publicKey, src, encrypted);
|
|
413
|
-
|
|
414
|
-
const validEncrypted = encrypted.getData();
|
|
415
|
-
const headerSize = 2 + validEncrypted.readUInt16BE(0) + 12;
|
|
416
|
-
const chunkSizeOffset = headerSize;
|
|
417
|
-
|
|
418
|
-
const corrupted = Buffer.from(validEncrypted);
|
|
419
|
-
const FRAME = 65519;
|
|
420
|
-
const GCM_TAG = 16;
|
|
421
|
-
corrupted.writeUInt16BE(FRAME + GCM_TAG, chunkSizeOffset);
|
|
422
|
-
|
|
423
|
-
const decryptSrc = createReadableStream(corrupted);
|
|
424
|
-
const decrypted = new CollectorStream();
|
|
425
|
-
|
|
426
|
-
await expect(
|
|
427
|
-
decryptFIPSKEMDEMStream(keyPair.privateKey, decryptSrc, decrypted)
|
|
428
|
-
).rejects.toThrow();
|
|
429
|
-
});
|
|
430
|
-
});
|
|
431
|
-
});
|
package/src/env-util.test.ts
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect } from 'bun:test';
|
|
2
|
-
import { looksLikeSecret } from './env-util';
|
|
3
|
-
|
|
4
|
-
describe('looksLikeSecret', () => {
|
|
5
|
-
describe('key name patterns', () => {
|
|
6
|
-
test('detects _SECRET suffix', () => {
|
|
7
|
-
expect(looksLikeSecret('API_SECRET', 'value')).toBe(true);
|
|
8
|
-
expect(looksLikeSecret('DB_SECRET', 'value')).toBe(true);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
test('detects _KEY suffix', () => {
|
|
12
|
-
expect(looksLikeSecret('API_KEY', 'value')).toBe(true);
|
|
13
|
-
expect(looksLikeSecret('STRIPE_KEY', 'value')).toBe(true);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
test('detects _TOKEN suffix', () => {
|
|
17
|
-
expect(looksLikeSecret('AUTH_TOKEN', 'value')).toBe(true);
|
|
18
|
-
expect(looksLikeSecret('GITHUB_TOKEN', 'value')).toBe(true);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test('detects _PASSWORD suffix', () => {
|
|
22
|
-
expect(looksLikeSecret('DB_PASSWORD', 'value')).toBe(true);
|
|
23
|
-
expect(looksLikeSecret('ADMIN_PASSWORD', 'value')).toBe(true);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('detects _PRIVATE suffix', () => {
|
|
27
|
-
expect(looksLikeSecret('SSH_PRIVATE', 'value')).toBe(true);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('detects _CERT and _CERTIFICATE suffixes', () => {
|
|
31
|
-
expect(looksLikeSecret('SSL_CERT', 'value')).toBe(true);
|
|
32
|
-
expect(looksLikeSecret('SSL_CERTIFICATE', 'value')).toBe(true);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test('detects SECRET_ prefix', () => {
|
|
36
|
-
expect(looksLikeSecret('SECRET_VALUE', 'value')).toBe(true);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test('detects APIKEY and API_KEY patterns', () => {
|
|
40
|
-
expect(looksLikeSecret('APIKEY', 'value')).toBe(true);
|
|
41
|
-
expect(looksLikeSecret('API_KEY', 'value')).toBe(true);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test('detects JWT prefix', () => {
|
|
45
|
-
expect(looksLikeSecret('JWT_SECRET', 'value')).toBe(true);
|
|
46
|
-
expect(looksLikeSecret('JWT', 'value')).toBe(true);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('detects PASSWORD in key name', () => {
|
|
50
|
-
expect(looksLikeSecret('DATABASE_PASSWORD', 'value')).toBe(true);
|
|
51
|
-
expect(looksLikeSecret('PASSWORD', 'value')).toBe(true);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('detects CREDENTIAL in key name', () => {
|
|
55
|
-
expect(looksLikeSecret('AWS_CREDENTIALS', 'value')).toBe(true);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test('detects AUTH.*KEY pattern', () => {
|
|
59
|
-
expect(looksLikeSecret('AUTH_API_KEY', 'value')).toBe(true);
|
|
60
|
-
expect(looksLikeSecret('AUTHKEY', 'value')).toBe(true);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test('is case insensitive for key patterns', () => {
|
|
64
|
-
expect(looksLikeSecret('api_secret', 'value')).toBe(true);
|
|
65
|
-
expect(looksLikeSecret('Api_Key', 'value')).toBe(true);
|
|
66
|
-
expect(looksLikeSecret('AUTH_token', 'value')).toBe(true);
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
describe('value patterns', () => {
|
|
71
|
-
test('detects JWT tokens', () => {
|
|
72
|
-
const jwt =
|
|
73
|
-
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
|
|
74
|
-
expect(looksLikeSecret('TOKEN', jwt)).toBe(true);
|
|
75
|
-
expect(looksLikeSecret('SOME_VAR', jwt)).toBe(true);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test('detects Bearer tokens', () => {
|
|
79
|
-
expect(looksLikeSecret('AUTH', 'Bearer abc123def456ghi789jkl012mno345pqr')).toBe(true);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
test('detects AWS access keys', () => {
|
|
83
|
-
expect(looksLikeSecret('AWS', 'AKIAIOSFODNN7EXAMPLE')).toBe(true);
|
|
84
|
-
expect(looksLikeSecret('AWS', 'ASIAIOSFODNN7EXAMPLE')).toBe(true);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test('detects GitHub tokens', () => {
|
|
88
|
-
expect(looksLikeSecret('GH', 'ghp_1234567890abcdefghijklmnopqrstuvwxyz')).toBe(true);
|
|
89
|
-
expect(looksLikeSecret('GH', 'ghs_1234567890abcdefghijklmnopqrstuvwxyz')).toBe(true);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test('detects long alphanumeric strings (API keys)', () => {
|
|
93
|
-
// 32+ characters, mixed alphanumeric
|
|
94
|
-
expect(
|
|
95
|
-
looksLikeSecret('KEY', 'sk_test_51A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0U1V2W3X4Y5Z6')
|
|
96
|
-
).toBe(true);
|
|
97
|
-
expect(looksLikeSecret('KEY', 'abc123def456ghi789jkl012mno345pqr678stu901vwx234yz')).toBe(
|
|
98
|
-
true
|
|
99
|
-
);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
test('does not flag numeric-only long strings', () => {
|
|
103
|
-
expect(looksLikeSecret('ID', '12345678901234567890123456789012')).toBe(false);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test('detects PEM certificates', () => {
|
|
107
|
-
expect(looksLikeSecret('CERT', '-----BEGIN CERTIFICATE-----\nMIIC...')).toBe(true);
|
|
108
|
-
expect(looksLikeSecret('CERT', '-----BEGIN PRIVATE KEY-----\nMIIC...')).toBe(true);
|
|
109
|
-
expect(looksLikeSecret('CERT', '-----BEGIN RSA PRIVATE KEY-----\nMIIC...')).toBe(true);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
test('does not flag short values', () => {
|
|
113
|
-
expect(looksLikeSecret('VAR', 'short')).toBe(false);
|
|
114
|
-
expect(looksLikeSecret('VAR', '1234567')).toBe(false);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
test('does not flag empty values', () => {
|
|
118
|
-
expect(looksLikeSecret('VAR', '')).toBe(false);
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe('non-secret patterns', () => {
|
|
123
|
-
test('regular environment variables are not flagged', () => {
|
|
124
|
-
expect(looksLikeSecret('NODE_ENV', 'production')).toBe(false);
|
|
125
|
-
expect(looksLikeSecret('PORT', '3500')).toBe(false);
|
|
126
|
-
expect(looksLikeSecret('HOST', 'localhost')).toBe(false);
|
|
127
|
-
expect(looksLikeSecret('DATABASE_URL', 'postgres://localhost:5432/mydb')).toBe(false);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
test('configuration values are not flagged', () => {
|
|
131
|
-
expect(looksLikeSecret('LOG_LEVEL', 'debug')).toBe(false);
|
|
132
|
-
expect(looksLikeSecret('CACHE_TTL', '3600')).toBe(false);
|
|
133
|
-
expect(looksLikeSecret('MAX_CONNECTIONS', '100')).toBe(false);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
test('URLs without secrets are not flagged', () => {
|
|
137
|
-
expect(looksLikeSecret('API_URL', 'https://api.example.com')).toBe(false);
|
|
138
|
-
expect(looksLikeSecret('WEBHOOK_URL', 'https://example.com/webhook')).toBe(false);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
test('paths are not flagged', () => {
|
|
142
|
-
expect(looksLikeSecret('DATA_PATH', '/var/data/app')).toBe(false);
|
|
143
|
-
expect(looksLikeSecret('CONFIG_FILE', '/etc/app/config.json')).toBe(false);
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
describe('edge cases', () => {
|
|
148
|
-
test('handles mixed key and value patterns', () => {
|
|
149
|
-
// Key pattern triggers detection
|
|
150
|
-
expect(looksLikeSecret('API_KEY', 'simple')).toBe(true);
|
|
151
|
-
|
|
152
|
-
// Value pattern triggers detection even without key pattern
|
|
153
|
-
const jwt =
|
|
154
|
-
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
|
|
155
|
-
expect(looksLikeSecret('CONFIG', jwt)).toBe(true);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
test('real-world API key formats', () => {
|
|
159
|
-
// Stripe (contains underscore, 32+ chars)
|
|
160
|
-
expect(looksLikeSecret('STRIPE', 'sk_test_51HqL7xAbCdEfGhIjK12345678901234567890')).toBe(
|
|
161
|
-
true
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
// Long API key format (32+ alphanumeric)
|
|
165
|
-
expect(looksLikeSecret('OPENAI', 'sk-proj-1234567890abcdefghijklmnopqrstuvwxyz')).toBe(
|
|
166
|
-
true
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
// Contains dots (periods not in our pattern, but key name helps)
|
|
170
|
-
expect(
|
|
171
|
-
looksLikeSecret(
|
|
172
|
-
'SENDGRID_API_KEY',
|
|
173
|
-
'SG.1234567890abcdefghijklmnopqrstuvwxyz.1234567890abcdefghijklmnopqrstuvwxyz'
|
|
174
|
-
)
|
|
175
|
-
).toBe(true);
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
test('UUIDs are correctly identified as non-secrets', () => {
|
|
179
|
-
// Standard UUID format should not be flagged
|
|
180
|
-
expect(looksLikeSecret('REQUEST_ID', '550e8400-e29b-41d4-a716-446655440000')).toBe(false);
|
|
181
|
-
expect(looksLikeSecret('USER_ID', '123e4567-e89b-12d3-a456-426614174000')).toBe(false);
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
test('hex hashes are flagged (better safe than sorry)', () => {
|
|
185
|
-
// 32+ character hex strings could be secrets or hashes - we flag them
|
|
186
|
-
// Users can confirm they're just hashes if needed
|
|
187
|
-
expect(looksLikeSecret('BUILD_HASH', 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6')).toBe(true);
|
|
188
|
-
|
|
189
|
-
// But with context that clearly indicates it's not a secret, the key name won't trigger
|
|
190
|
-
// So short hex strings without secret-like key names won't be flagged
|
|
191
|
-
expect(looksLikeSecret('COMMIT', 'abc123def')).toBe(false);
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
});
|