@syntesseraai/opencode-feature-factory 0.2.7 → 0.2.8

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.
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Unit tests for stop-quality-gate module
3
4
  *
@@ -5,7 +6,8 @@
5
6
  * - sanitizeOutput: redacts secrets from CI output
6
7
  * - isSessionReadOnly: determines if session has write permissions
7
8
  */
8
- import { sanitizeOutput, truncateOutput } from './stop-quality-gate';
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ const stop_quality_gate_1 = require("./stop-quality-gate");
9
11
  function isSessionReadOnly(permission) {
10
12
  if (!permission)
11
13
  return false;
@@ -15,178 +17,178 @@ describe('sanitizeOutput', () => {
15
17
  describe('AWS credentials', () => {
16
18
  it('should redact AWS Access Key IDs', () => {
17
19
  const input = 'Found credentials: AKIAIOSFODNN7EXAMPLE in config';
18
- const result = sanitizeOutput(input);
20
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
19
21
  expect(result).toBe('Found credentials: [REDACTED_AWS_KEY] in config');
20
22
  });
21
23
  it('should redact multiple AWS keys', () => {
22
24
  const input = 'Key1: AKIAIOSFODNN7EXAMPLE Key2: AKIAI44QH8DHBEXAMPLE';
23
- const result = sanitizeOutput(input);
25
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
24
26
  expect(result).toBe('Key1: [REDACTED_AWS_KEY] Key2: [REDACTED_AWS_KEY]');
25
27
  });
26
28
  it('should not redact partial AWS key patterns', () => {
27
29
  const input = 'AKIA123'; // Too short
28
- const result = sanitizeOutput(input);
30
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
29
31
  expect(result).toBe('AKIA123');
30
32
  });
31
33
  });
32
34
  describe('GitHub tokens', () => {
33
35
  it('should redact GitHub Personal Access Tokens (classic)', () => {
34
36
  const input = 'Using ghp_aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789';
35
- const result = sanitizeOutput(input);
37
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
36
38
  expect(result).toBe('Using [REDACTED_GH_TOKEN]');
37
39
  });
38
40
  it('should redact GitHub Personal Access Tokens (fine-grained)', () => {
39
41
  const input = 'Using github_pat_11ABCDEFG_abcdefghijklmnopqrstuvwxyz';
40
- const result = sanitizeOutput(input);
42
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
41
43
  expect(result).toBe('Using [REDACTED_GH_TOKEN]');
42
44
  });
43
45
  it('should redact GitHub OAuth tokens', () => {
44
46
  const input = 'oauth=gho_aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789';
45
- const result = sanitizeOutput(input);
47
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
46
48
  expect(result).toBe('oauth=[REDACTED_GH_TOKEN]');
47
49
  });
48
50
  it('should redact GitHub App user-to-server tokens', () => {
49
51
  const input = 'Using ghu_aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789';
50
- const result = sanitizeOutput(input);
52
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
51
53
  expect(result).toBe('Using [REDACTED_GH_TOKEN]');
52
54
  });
53
55
  it('should redact GitHub App server-to-server tokens', () => {
54
56
  const input = 'Using ghs_aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789';
55
- const result = sanitizeOutput(input);
57
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
56
58
  expect(result).toBe('Using [REDACTED_GH_TOKEN]');
57
59
  });
58
60
  it('should not redact partial GitHub token patterns', () => {
59
61
  const input = 'ghp_abc'; // Too short
60
- const result = sanitizeOutput(input);
62
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
61
63
  expect(result).toBe('ghp_abc');
62
64
  });
63
65
  });
64
66
  describe('GitLab tokens', () => {
65
67
  it('should redact GitLab Personal Access Tokens', () => {
66
68
  const input = 'Using glpat-abcdefghij1234567890';
67
- const result = sanitizeOutput(input);
69
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
68
70
  expect(result).toBe('Using [REDACTED_GITLAB_TOKEN]');
69
71
  });
70
72
  it('should redact GitLab tokens with hyphens', () => {
71
73
  const input = 'Using glpat-abc-def-ghi-jkl-mnop-qrs';
72
- const result = sanitizeOutput(input);
74
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
73
75
  expect(result).toBe('Using [REDACTED_GITLAB_TOKEN]');
74
76
  });
75
77
  it('should not redact partial GitLab token patterns', () => {
76
78
  const input = 'glpat-short'; // Too short
77
- const result = sanitizeOutput(input);
79
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
78
80
  expect(result).toBe('glpat-short');
79
81
  });
80
82
  });
81
83
  describe('npm tokens', () => {
82
84
  it('should redact npm tokens', () => {
83
85
  const input = 'Using npm_aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789';
84
- const result = sanitizeOutput(input);
86
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
85
87
  expect(result).toBe('Using [REDACTED_NPM_TOKEN]');
86
88
  });
87
89
  it('should not redact partial npm token patterns', () => {
88
90
  const input = 'npm_abc'; // Too short
89
- const result = sanitizeOutput(input);
91
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
90
92
  expect(result).toBe('npm_abc');
91
93
  });
92
94
  });
93
95
  describe('Bearer tokens', () => {
94
96
  it('should redact Bearer tokens', () => {
95
97
  const input = 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9';
96
- const result = sanitizeOutput(input);
98
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
97
99
  expect(result).toBe('Authorization: Bearer [REDACTED]');
98
100
  });
99
101
  it('should handle case-insensitive Bearer', () => {
100
102
  const input = 'bearer abc123-token.value';
101
- const result = sanitizeOutput(input);
103
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
102
104
  expect(result).toBe('Bearer [REDACTED]');
103
105
  });
104
106
  });
105
107
  describe('API keys', () => {
106
108
  it('should redact api_key assignments', () => {
107
109
  const input = 'api_key=sk-1234567890abcdef';
108
- const result = sanitizeOutput(input);
110
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
109
111
  expect(result).toBe('api_key=[REDACTED]');
110
112
  });
111
113
  it('should redact api-key with hyphen', () => {
112
114
  const input = 'api-key: my-secret-key';
113
- const result = sanitizeOutput(input);
115
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
114
116
  expect(result).toBe('api_key=[REDACTED]');
115
117
  });
116
118
  it('should redact apikey without separator', () => {
117
119
  const input = 'apikey=abc123';
118
- const result = sanitizeOutput(input);
120
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
119
121
  expect(result).toBe('api_key=[REDACTED]');
120
122
  });
121
123
  it('should redact quoted api keys', () => {
122
124
  const input = "api_key='secret-value'";
123
- const result = sanitizeOutput(input);
125
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
124
126
  expect(result).toBe('api_key=[REDACTED]');
125
127
  });
126
128
  });
127
129
  describe('tokens', () => {
128
130
  it('should redact token assignments with 8+ char values', () => {
129
131
  const input = 'token=ghp_xxxxxxxxxxxxxxxxxxxx';
130
- const result = sanitizeOutput(input);
132
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
131
133
  expect(result).toBe('token=[REDACTED]');
132
134
  });
133
135
  it('should redact tokens plural with 8+ char values', () => {
134
136
  const input = 'tokens: secret12345';
135
- const result = sanitizeOutput(input);
137
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
136
138
  expect(result).toBe('token=[REDACTED]');
137
139
  });
138
140
  it('should NOT redact token with short values (less than 8 chars)', () => {
139
141
  const input = 'token=abc123';
140
- const result = sanitizeOutput(input);
142
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
141
143
  expect(result).toBe('token=abc123');
142
144
  });
143
145
  it('should NOT redact phrases like "token count: 5" (value too short)', () => {
144
146
  const input = 'token count: 5';
145
- const result = sanitizeOutput(input);
147
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
146
148
  expect(result).toBe('token count: 5');
147
149
  });
148
150
  it('should NOT redact "token: abc" (value too short)', () => {
149
151
  const input = 'token: abc';
150
- const result = sanitizeOutput(input);
152
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
151
153
  expect(result).toBe('token: abc');
152
154
  });
153
155
  it('should redact actual token values that are 8+ chars', () => {
154
156
  const input = 'token=abcd1234efgh';
155
- const result = sanitizeOutput(input);
157
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
156
158
  expect(result).toBe('token=[REDACTED]');
157
159
  });
158
160
  it('should redact quoted tokens with 8+ char values', () => {
159
161
  const input = 'token="my-secret-token-value"';
160
- const result = sanitizeOutput(input);
162
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
161
163
  expect(result).toBe('token=[REDACTED]');
162
164
  });
163
165
  });
164
166
  describe('passwords', () => {
165
167
  it('should redact password assignments', () => {
166
168
  const input = 'password=super-secret-123!';
167
- const result = sanitizeOutput(input);
169
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
168
170
  expect(result).toBe('password=[REDACTED]');
169
171
  });
170
172
  it('should redact passwords plural', () => {
171
173
  const input = 'passwords: "admin123"';
172
- const result = sanitizeOutput(input);
174
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
173
175
  expect(result).toBe('password=[REDACTED]');
174
176
  });
175
177
  it('should handle special characters in passwords', () => {
176
178
  const input = 'password=P@$$w0rd!#%';
177
- const result = sanitizeOutput(input);
179
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
178
180
  expect(result).toBe('password=[REDACTED]');
179
181
  });
180
182
  });
181
183
  describe('generic secrets', () => {
182
184
  it('should redact secret assignments', () => {
183
185
  const input = 'secret=my-app-secret-key';
184
- const result = sanitizeOutput(input);
186
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
185
187
  expect(result).toBe('secret=[REDACTED]');
186
188
  });
187
189
  it('should redact secrets plural', () => {
188
190
  const input = 'secrets: "confidential-data"';
189
- const result = sanitizeOutput(input);
191
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
190
192
  expect(result).toBe('secret=[REDACTED]');
191
193
  });
192
194
  });
@@ -194,40 +196,40 @@ describe('sanitizeOutput', () => {
194
196
  it('should redact long base64-like strings', () => {
195
197
  const base64 = 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODk=';
196
198
  const input = `Encoded value: ${base64}`;
197
- const result = sanitizeOutput(input);
199
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
198
200
  expect(result).toBe('Encoded value: [REDACTED_BASE64]');
199
201
  });
200
202
  it('should not redact short base64 strings', () => {
201
203
  const input = 'Short: abc123';
202
- const result = sanitizeOutput(input);
204
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
203
205
  expect(result).toBe('Short: abc123');
204
206
  });
205
207
  it('should redact base64 without padding', () => {
206
208
  const base64 = 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkw';
207
- const result = sanitizeOutput(base64);
209
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(base64);
208
210
  expect(result).toBe('[REDACTED_BASE64]');
209
211
  });
210
212
  it('should redact base64 strings up to 500 chars (ReDoS prevention)', () => {
211
213
  // Generate a 500-char base64 string
212
214
  const base64 = 'A'.repeat(500);
213
- const result = sanitizeOutput(base64);
215
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(base64);
214
216
  expect(result).toBe('[REDACTED_BASE64]');
215
217
  });
216
218
  it('should handle base64 strings over 500 chars by matching only first 500 (ReDoS prevention)', () => {
217
219
  // Generate a 501-char base64 string - only first 500 chars match
218
220
  const base64 = 'A'.repeat(501);
219
- const result = sanitizeOutput(base64);
221
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(base64);
220
222
  // Pattern matches the first 500 chars, leaving 1 char behind
221
223
  expect(result).toBe('[REDACTED_BASE64]A');
222
224
  });
223
225
  it('should handle base64 at exactly 40 chars (minimum threshold)', () => {
224
226
  const base64 = 'A'.repeat(40);
225
- const result = sanitizeOutput(base64);
227
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(base64);
226
228
  expect(result).toBe('[REDACTED_BASE64]');
227
229
  });
228
230
  it('should NOT redact base64 strings under 40 chars', () => {
229
231
  const base64 = 'A'.repeat(39);
230
- const result = sanitizeOutput(base64);
232
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(base64);
231
233
  expect(result).toBe(base64);
232
234
  });
233
235
  });
@@ -238,7 +240,7 @@ describe('sanitizeOutput', () => {
238
240
  Auth: Bearer my-jwt-token
239
241
  password=admin123
240
242
  `;
241
- const result = sanitizeOutput(input);
243
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
242
244
  expect(result).toContain('[REDACTED_AWS_KEY]');
243
245
  expect(result).toContain('Bearer [REDACTED]');
244
246
  expect(result).toContain('password=[REDACTED]');
@@ -252,28 +254,28 @@ describe('sanitizeOutput', () => {
252
254
  const input = `-----BEGIN RSA PRIVATE KEY-----
253
255
  MIIEowIBAAKCAQEA0Z3VS5JJcds3xfn/ygWyF8PbnGy
254
256
  -----END RSA PRIVATE KEY-----`;
255
- const result = sanitizeOutput(input);
257
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
256
258
  expect(result).toBe('[REDACTED_PRIVATE_KEY]');
257
259
  });
258
260
  it('should redact OpenSSH private keys', () => {
259
261
  const input = `-----BEGIN OPENSSH PRIVATE KEY-----
260
262
  b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAA
261
263
  -----END OPENSSH PRIVATE KEY-----`;
262
- const result = sanitizeOutput(input);
264
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
263
265
  expect(result).toBe('[REDACTED_PRIVATE_KEY]');
264
266
  });
265
267
  it('should redact EC private keys', () => {
266
268
  const input = `-----BEGIN EC PRIVATE KEY-----
267
269
  MHQCAQEEICg7E4NN6YPWoU6/FXa5ON6Pt6LKBfA8WL
268
270
  -----END EC PRIVATE KEY-----`;
269
- const result = sanitizeOutput(input);
271
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
270
272
  expect(result).toBe('[REDACTED_PRIVATE_KEY]');
271
273
  });
272
274
  it('should redact generic private keys', () => {
273
275
  const input = `-----BEGIN PRIVATE KEY-----
274
276
  MIIEvgIBADANBgkqhkiG9w0BAQEFAASC
275
277
  -----END PRIVATE KEY-----`;
276
- const result = sanitizeOutput(input);
278
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
277
279
  expect(result).toBe('[REDACTED_PRIVATE_KEY]');
278
280
  });
279
281
  it('should redact private keys embedded in output', () => {
@@ -282,7 +284,7 @@ MIIEvgIBADANBgkqhkiG9w0BAQEFAASC
282
284
  MIIEowIBAAKCAQEA0Z3VS5JJcds3xfn/ygWyF8PbnGy
283
285
  -----END RSA PRIVATE KEY-----
284
286
  Done loading.`;
285
- const result = sanitizeOutput(input);
287
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
286
288
  expect(result).toBe(`Loading configuration...
287
289
  [REDACTED_PRIVATE_KEY]
288
290
  Done loading.`);
@@ -291,49 +293,49 @@ Done loading.`);
291
293
  describe('GCP credentials', () => {
292
294
  it('should redact GCP API keys', () => {
293
295
  const input = 'Using GCP key: AIzaSyDaGmWKa4JsXZ-HjGw7ISLn_3namBGewQe';
294
- const result = sanitizeOutput(input);
296
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
295
297
  expect(result).toBe('Using GCP key: [REDACTED_GCP_KEY]');
296
298
  });
297
299
  it('should redact multiple GCP API keys', () => {
298
300
  const input = 'Key1: AIzaSyDaGmWKa4JsXZ-HjGw7ISLn_3namBGewQe Key2: AIzaSyB-1234567890abcdefghijklmnopqrstu';
299
- const result = sanitizeOutput(input);
301
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
300
302
  expect(result).toBe('Key1: [REDACTED_GCP_KEY] Key2: [REDACTED_GCP_KEY]');
301
303
  });
302
304
  it('should not redact partial GCP API key patterns', () => {
303
305
  const input = 'AIza123'; // Too short
304
- const result = sanitizeOutput(input);
306
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
305
307
  expect(result).toBe('AIza123');
306
308
  });
307
309
  it('should redact GCP OAuth tokens', () => {
308
310
  const input = 'Authorization: ya29.a0AfH6SMBx-example-token-value_123';
309
- const result = sanitizeOutput(input);
311
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
310
312
  expect(result).toBe('Authorization: [REDACTED_GCP_TOKEN]');
311
313
  });
312
314
  it('should redact GCP OAuth tokens with various characters', () => {
313
315
  const input = 'token=ya29.Gl-abc_XYZ-123';
314
- const result = sanitizeOutput(input);
316
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
315
317
  expect(result).toBe('token=[REDACTED_GCP_TOKEN]');
316
318
  });
317
319
  });
318
320
  describe('Slack tokens', () => {
319
321
  it('should redact Slack bot tokens', () => {
320
322
  const input = 'SLACK_BOT_TOKEN=xoxb-123456789012-1234567890123-AbCdEfGhIjKlMnOpQrStUvWx';
321
- const result = sanitizeOutput(input);
323
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
322
324
  expect(result).toBe('SLACK_BOT_TOKEN=[REDACTED_SLACK_TOKEN]');
323
325
  });
324
326
  it('should redact Slack user tokens', () => {
325
327
  const input = 'Using xoxp-123456789012-123456789012-123456789012-abcdef1234567890abcdef1234567890';
326
- const result = sanitizeOutput(input);
328
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
327
329
  expect(result).toBe('Using [REDACTED_SLACK_TOKEN]');
328
330
  });
329
331
  it('should redact Slack app tokens', () => {
330
332
  const input = 'APP_TOKEN=xapp-1-A0123BCDEFG-1234567890123-abcdefghijklmnopqrstuvwxyz0123456789';
331
- const result = sanitizeOutput(input);
333
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
332
334
  expect(result).toBe('APP_TOKEN=[REDACTED_SLACK_TOKEN]');
333
335
  });
334
336
  it('should redact Slack webhook URLs', () => {
335
337
  const input = 'Webhook: https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX';
336
- const result = sanitizeOutput(input);
338
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
337
339
  expect(result).toBe('Webhook: https://[REDACTED_SLACK_WEBHOOK]');
338
340
  });
339
341
  it('should redact multiple different Slack token types', () => {
@@ -342,7 +344,7 @@ Done loading.`);
342
344
  User: xoxp-789-012-def
343
345
  App: xapp-345-ghi
344
346
  `;
345
- const result = sanitizeOutput(input);
347
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
346
348
  expect(result).toContain('[REDACTED_SLACK_TOKEN]');
347
349
  expect(result).not.toContain('xoxb-');
348
350
  expect(result).not.toContain('xoxp-');
@@ -353,100 +355,100 @@ Done loading.`);
353
355
  it('should redact Stripe live secret keys', () => {
354
356
  // 24 chars after sk_live_: 51ABC123DEF456GHI789JKLM
355
357
  const input = 'STRIPE_SECRET_KEY=sk_live_51ABC123DEF456GHI789JKLM';
356
- const result = sanitizeOutput(input);
358
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
357
359
  expect(result).toBe('STRIPE_SECRET_KEY=[REDACTED_STRIPE_KEY]');
358
360
  });
359
361
  it('should redact Stripe test secret keys', () => {
360
362
  // 24 chars after sk_test_: 51ABC123DEF456GHI789JKLM
361
363
  const input = 'Using sk_test_51ABC123DEF456GHI789JKLM for testing';
362
- const result = sanitizeOutput(input);
364
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
363
365
  expect(result).toBe('Using [REDACTED_STRIPE_KEY] for testing');
364
366
  });
365
367
  it('should redact Stripe live restricted keys', () => {
366
368
  // 24 chars after rk_live_: 51ABC123DEF456GHI789JKLM
367
369
  const input = 'RESTRICTED_KEY=rk_live_51ABC123DEF456GHI789JKLM';
368
- const result = sanitizeOutput(input);
370
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
369
371
  expect(result).toBe('RESTRICTED_KEY=[REDACTED_STRIPE_KEY]');
370
372
  });
371
373
  it('should redact Stripe test restricted keys', () => {
372
374
  // 24 chars after rk_test_: 51ABC123DEF456GHI789JKLM
373
375
  const input = 'Using rk_test_51ABC123DEF456GHI789JKLM for testing';
374
- const result = sanitizeOutput(input);
376
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
375
377
  expect(result).toBe('Using [REDACTED_STRIPE_KEY] for testing');
376
378
  });
377
379
  it('should not redact Stripe keys that are too short', () => {
378
380
  const input = 'sk_live_short'; // Less than 24 characters after prefix
379
- const result = sanitizeOutput(input);
381
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
380
382
  expect(result).toBe('sk_live_short');
381
383
  });
382
384
  it('should redact multiple Stripe keys', () => {
383
385
  // 24 chars after each prefix
384
386
  const input = 'Live: sk_live_51ABC123DEF456GHI789JKLM Test: sk_test_51XYZ789ABC123DEF456GHIJ';
385
- const result = sanitizeOutput(input);
387
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
386
388
  expect(result).toBe('Live: [REDACTED_STRIPE_KEY] Test: [REDACTED_STRIPE_KEY]');
387
389
  });
388
390
  it('should redact long Stripe keys', () => {
389
391
  const input = 'sk_live_51ABC123DEF456GHI789JKLmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOP';
390
- const result = sanitizeOutput(input);
392
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
391
393
  expect(result).toBe('[REDACTED_STRIPE_KEY]');
392
394
  });
393
395
  });
394
396
  describe('database connection strings', () => {
395
397
  it('should redact PostgreSQL connection strings', () => {
396
398
  const input = 'DATABASE_URL=postgres://admin:secretpass123@db.example.com:5432/mydb';
397
- const result = sanitizeOutput(input);
399
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
398
400
  expect(result).toBe('DATABASE_URL=[REDACTED_CONNECTION_STRING]');
399
401
  });
400
402
  it('should redact MongoDB connection strings with +srv', () => {
401
403
  const input = 'Connecting to mongodb+srv://user:p@ssw0rd@cluster.mongodb.net/database';
402
- const result = sanitizeOutput(input);
404
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
403
405
  expect(result).toBe('Connecting to [REDACTED_CONNECTION_STRING]');
404
406
  });
405
407
  it('should redact Redis connection strings', () => {
406
408
  const input = 'REDIS_URL=redis://default:myredispassword@redis.example.com:6379';
407
- const result = sanitizeOutput(input);
409
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
408
410
  expect(result).toBe('REDIS_URL=[REDACTED_CONNECTION_STRING]');
409
411
  });
410
412
  it('should redact MySQL connection strings', () => {
411
413
  const input = 'mysql://root:rootpassword@localhost:3306/testdb';
412
- const result = sanitizeOutput(input);
414
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
413
415
  expect(result).toBe('[REDACTED_CONNECTION_STRING]');
414
416
  });
415
417
  it('should redact rediss (TLS) connection strings', () => {
416
418
  const input = 'rediss://user:password@secure-redis.example.com:6380';
417
- const result = sanitizeOutput(input);
419
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
418
420
  expect(result).toBe('[REDACTED_CONNECTION_STRING]');
419
421
  });
420
422
  it('should redact connection strings with URL-encoded passwords', () => {
421
423
  const input = 'mongodb://user:p%40ss%23word@host/db';
422
- const result = sanitizeOutput(input);
424
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
423
425
  expect(result).toBe('[REDACTED_CONNECTION_STRING]');
424
426
  });
425
427
  it('should redact PostgreSQL with URL-encoded @ in password', () => {
426
428
  const input = 'postgres://admin:secret%40pass@db.example.com:5432/mydb';
427
- const result = sanitizeOutput(input);
429
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
428
430
  expect(result).toBe('[REDACTED_CONNECTION_STRING]');
429
431
  });
430
432
  it('should redact connection strings with multiple URL-encoded characters', () => {
431
433
  const input = 'mysql://root:p%40ss%3Dw%26rd%21@localhost:3306/testdb';
432
- const result = sanitizeOutput(input);
434
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
433
435
  expect(result).toBe('[REDACTED_CONNECTION_STRING]');
434
436
  });
435
437
  it('should redact MongoDB+srv with URL-encoded password', () => {
436
438
  const input = 'mongodb+srv://user:my%40complex%23pass@cluster.mongodb.net/database';
437
- const result = sanitizeOutput(input);
439
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
438
440
  expect(result).toBe('[REDACTED_CONNECTION_STRING]');
439
441
  });
440
442
  });
441
443
  describe('non-secret content', () => {
442
444
  it('should preserve normal log output', () => {
443
445
  const input = 'Build completed successfully in 2.5s';
444
- const result = sanitizeOutput(input);
446
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
445
447
  expect(result).toBe(input);
446
448
  });
447
449
  it('should preserve error messages without secrets', () => {
448
450
  const input = 'Error: Cannot find module "./missing-file"';
449
- const result = sanitizeOutput(input);
451
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
450
452
  expect(result).toBe(input);
451
453
  });
452
454
  it('should preserve stack traces', () => {
@@ -455,7 +457,7 @@ Done loading.`);
455
457
  at Object.<anonymous> (/app/test.js:10:5)
456
458
  at Module._compile (internal/modules/cjs/loader.js:1085:14)
457
459
  `;
458
- const result = sanitizeOutput(input);
460
+ const result = (0, stop_quality_gate_1.sanitizeOutput)(input);
459
461
  expect(result).toBe(input);
460
462
  });
461
463
  });
@@ -506,17 +508,17 @@ describe('isSessionReadOnly', () => {
506
508
  describe('truncateOutput', () => {
507
509
  it('should return output unchanged if under maxLines', () => {
508
510
  const input = 'line1\nline2\nline3';
509
- expect(truncateOutput(input, 20)).toBe(input);
511
+ expect((0, stop_quality_gate_1.truncateOutput)(input, 20)).toBe(input);
510
512
  });
511
513
  it('should return output unchanged if exactly at maxLines', () => {
512
514
  const lines = Array.from({ length: 20 }, (_, i) => `line${i + 1}`);
513
515
  const input = lines.join('\n');
514
- expect(truncateOutput(input, 20)).toBe(input);
516
+ expect((0, stop_quality_gate_1.truncateOutput)(input, 20)).toBe(input);
515
517
  });
516
518
  it('should truncate to last 20 lines by default', () => {
517
519
  const lines = Array.from({ length: 30 }, (_, i) => `line${i + 1}`);
518
520
  const input = lines.join('\n');
519
- const result = truncateOutput(input);
521
+ const result = (0, stop_quality_gate_1.truncateOutput)(input);
520
522
  expect(result).toContain('... (10 lines omitted)');
521
523
  expect(result).toContain('line11');
522
524
  expect(result).toContain('line30');
@@ -526,7 +528,7 @@ describe('truncateOutput', () => {
526
528
  it('should truncate to custom maxLines', () => {
527
529
  const lines = Array.from({ length: 15 }, (_, i) => `line${i + 1}`);
528
530
  const input = lines.join('\n');
529
- const result = truncateOutput(input, 5);
531
+ const result = (0, stop_quality_gate_1.truncateOutput)(input, 5);
530
532
  expect(result).toContain('... (10 lines omitted)');
531
533
  expect(result).toContain('line11');
532
534
  expect(result).toContain('line15');
@@ -534,15 +536,15 @@ describe('truncateOutput', () => {
534
536
  });
535
537
  it('should handle single line output', () => {
536
538
  const input = 'single line';
537
- expect(truncateOutput(input, 20)).toBe(input);
539
+ expect((0, stop_quality_gate_1.truncateOutput)(input, 20)).toBe(input);
538
540
  });
539
541
  it('should handle empty output', () => {
540
- expect(truncateOutput('', 20)).toBe('');
542
+ expect((0, stop_quality_gate_1.truncateOutput)('', 20)).toBe('');
541
543
  });
542
544
  it('should preserve line content exactly', () => {
543
545
  const lines = Array.from({ length: 25 }, (_, i) => `Error at line ${i + 1}: something failed`);
544
546
  const input = lines.join('\n');
545
- const result = truncateOutput(input, 10);
547
+ const result = (0, stop_quality_gate_1.truncateOutput)(input, 10);
546
548
  expect(result).toContain('Error at line 16: something failed');
547
549
  expect(result).toContain('Error at line 25: something failed');
548
550
  });
package/dist/types.js CHANGED
@@ -1 +1,2 @@
1
- export {};
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,23 +1,14 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@syntesseraai/opencode-feature-factory",
4
- "version": "0.2.7",
4
+ "version": "0.2.8",
5
5
  "description": "OpenCode plugin for Feature Factory agents - provides sub-agents and skills for validation, review, security, and architecture assessment",
6
- "type": "module",
7
6
  "license": "MIT",
8
7
  "main": "./dist/index.js",
9
- "module": "./dist/index.js",
10
8
  "types": "./dist/index.d.ts",
11
9
  "bin": {
12
10
  "ff-deploy": "./bin/ff-deploy.js"
13
11
  },
14
- "exports": {
15
- ".": {
16
- "types": "./dist/index.d.ts",
17
- "import": "./dist/index.js",
18
- "default": "./dist/index.js"
19
- }
20
- },
21
12
  "files": [
22
13
  "dist",
23
14
  "assets",