switchroom 0.19.35 → 0.19.37
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/dist/cli/skill-validate-pretool.mjs +15 -2
- package/dist/cli/switchroom.js +678 -444
- package/dist/host-control/main.js +149 -3
- package/package.json +4 -2
- package/profiles/_base/start.sh.hbs +37 -12
- package/telegram-plugin/bridge/bridge.ts +4 -4
- package/telegram-plugin/dist/bridge/bridge.js +4 -4
- package/telegram-plugin/dist/gateway/gateway.js +317 -95
- package/telegram-plugin/dist/server.js +4 -4
- package/telegram-plugin/format.ts +100 -29
- package/telegram-plugin/gateway/gateway.ts +22 -29
- package/telegram-plugin/gateway/ipc-server.ts +18 -15
- package/telegram-plugin/gateway/model-command.ts +34 -0
- package/telegram-plugin/gateway/outbound-send-path.ts +12 -1
- package/telegram-plugin/operator-events.ts +40 -16
- package/telegram-plugin/render/unsupported-token-guard.ts +10 -6
- package/telegram-plugin/secret-detect/db-uri.ts +90 -0
- package/telegram-plugin/secret-detect/index.ts +24 -1
- package/telegram-plugin/secret-detect/inert-values.ts +147 -0
- package/telegram-plugin/secret-detect/kv-scanner.ts +108 -0
- package/telegram-plugin/secret-detect/patterns.ts +24 -4
- package/telegram-plugin/tests/format-consistency.test.ts +111 -0
- package/telegram-plugin/tests/gateway-session-model-relaunch.test.ts +40 -2
- package/telegram-plugin/tests/ipc-server-validate-operator.test.ts +20 -11
- package/telegram-plugin/tests/mcp-instructions-budget.test.ts +8 -1
- package/telegram-plugin/tests/outbound-send-path.test.ts +1 -1
- package/telegram-plugin/tests/render/unsupported-token-guard.test.ts +36 -5
- package/telegram-plugin/tests/secret-detect-cross-engine.test.ts +263 -0
- package/telegram-plugin/tests/secret-detect-write-path.test.ts +403 -0
- package/telegram-plugin/tests/turn-flush-safety.test.ts +2 -2
- package/vendor/hindsight-memory/scripts/lib/client.py +58 -0
- package/vendor/hindsight-memory/scripts/lib/secret_patterns.json +431 -0
- package/vendor/hindsight-memory/scripts/lib/secret_redact.py +563 -0
- package/vendor/hindsight-memory/scripts/lib/secret_redaction_vectors.json +397 -0
- package/vendor/hindsight-memory/scripts/tests/test_secret_redact.py +522 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_purpose": "Shared behaviour vectors for the secret redactor. The TypeScript engine (telegram-plugin/secret-detect/redact.ts) and the Python engine (vendor/hindsight-memory/scripts/lib/secret_redact.py) must produce IDENTICAL output for every case here. Asserted by telegram-plugin/tests/secret-detect-write-path.test.ts and vendor/hindsight-memory/scripts/tests/test_secret_redact.py.",
|
|
3
|
+
"_secrets_note": "Every value below is synthetic. Token-shaped strings are assembled from repeated filler so no real credential is committed and GitHub Push Protection has nothing to match.",
|
|
4
|
+
"vectors": [
|
|
5
|
+
{
|
|
6
|
+
"name": "postgres connection string password is masked",
|
|
7
|
+
"input": "connect with postgres://appuser:HunterTwo99@db.internal:5432/prod",
|
|
8
|
+
"expected": "connect with postgres://appuser:[REDACTED:db_uri_password]@db.internal:5432/prod"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "mysql connection string password is masked",
|
|
12
|
+
"input": "mysql://root:t0psecretpw@127.0.0.1:3306/app",
|
|
13
|
+
"expected": "mysql://root:[REDACTED:db_uri_password]@127.0.0.1:3306/app"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "mongodb+srv connection string password is masked",
|
|
17
|
+
"input": "MONGO=mongodb+srv://svc:aB3dEf9hJ2@cluster0.example.net/db",
|
|
18
|
+
"expected": "MONGO=mongodb+srv://svc:[REDACTED:db_uri_password]@cluster0.example.net/db"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "redis connection string password is masked",
|
|
22
|
+
"input": "redis://default:cachePass42@redis.internal:6379/0",
|
|
23
|
+
"expected": "redis://default:[REDACTED:db_uri_password]@redis.internal:6379/0"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "postgres URI without credentials is untouched",
|
|
27
|
+
"input": "postgres://db.internal:5432/prod is the read replica",
|
|
28
|
+
"expected": "postgres://db.internal:5432/prod is the read replica"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "already-masked connection string is stable",
|
|
32
|
+
"input": "postgres://appuser:[REDACTED:db_uri_password]@db.internal:5432/prod",
|
|
33
|
+
"expected": "postgres://appuser:[REDACTED:db_uri_password]@db.internal:5432/prod"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "human-memorable password after a colon is masked",
|
|
37
|
+
"input": "password: FluffyBarnaby1998",
|
|
38
|
+
"expected": "password: [REDACTED:memorable_password]"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "human-memorable password in prose is masked",
|
|
42
|
+
"input": "the wifi password is MangoTreeHouse77 if you need it",
|
|
43
|
+
"expected": "the wifi password is [REDACTED:memorable_password] if you need it"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "prefixed password identifier is masked",
|
|
47
|
+
"input": "db_password=Rutherford2024x",
|
|
48
|
+
"expected": "db_password=[REDACTED:memorable_password]"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "passphrase label is covered",
|
|
52
|
+
"input": "passphrase: CorrectHorse9Battery",
|
|
53
|
+
"expected": "passphrase: [REDACTED:memorable_password]"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "single-class prose after 'password is' is NOT masked",
|
|
57
|
+
"input": "the password is rotated quarterly by the platform team",
|
|
58
|
+
"expected": "the password is rotated quarterly by the platform team"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "password policy prose is NOT masked",
|
|
62
|
+
"input": "The password policy requires rotation every 90 days.",
|
|
63
|
+
"expected": "The password policy requires rotation every 90 days."
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "shell variable reference is NOT masked",
|
|
67
|
+
"input": "password: ${DB_PASSWORD}",
|
|
68
|
+
"expected": "password: ${DB_PASSWORD}"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"name": "angle-bracket placeholder is NOT masked",
|
|
72
|
+
"input": "password=<your-password-here>",
|
|
73
|
+
"expected": "password=<your-password-here>"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"name": "vault reference is NOT masked",
|
|
77
|
+
"input": "password: vault:postgres/app_password",
|
|
78
|
+
"expected": "password: vault:postgres/app_password"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"name": "already-masked memorable password is stable",
|
|
82
|
+
"input": "password: [REDACTED:memorable_password]",
|
|
83
|
+
"expected": "password: [REDACTED:memorable_password]"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "https url credentials are stripped by the url pass",
|
|
87
|
+
"input": "see https://alice:s3cretpw@api.example.com/v1/things",
|
|
88
|
+
"expected": "see https://***@api.example.com/v1/things"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"name": "sensitive query param is masked",
|
|
92
|
+
"input": "hit https://api.example.com/v1?api_key=abcdef123456&trace=42",
|
|
93
|
+
"expected": "hit https://api.example.com/v1?api_key=***&trace=42"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"name": "plain url is untouched",
|
|
97
|
+
"input": "docs at https://example.com/guide?page=2",
|
|
98
|
+
"expected": "docs at https://example.com/guide?page=2"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "ordinary prose is untouched",
|
|
102
|
+
"input": "I told him the answer was probably Gandalf the Grey.",
|
|
103
|
+
"expected": "I told him the answer was probably Gandalf the Grey."
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"name": "empty string passes through",
|
|
107
|
+
"input": "",
|
|
108
|
+
"expected": ""
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "multi-secret line masks every hit",
|
|
112
|
+
"input": "db postgres://u:PineappleRoof8@h/d and wifi password: SparrowKettle31",
|
|
113
|
+
"expected": "db postgres://u:[REDACTED:db_uri_password]@h/d and wifi password: [REDACTED:memorable_password]"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"name": "anthropic api key is masked",
|
|
117
|
+
"input": "the key is \u0073k-ant-api03-AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJ ok",
|
|
118
|
+
"expected": "the key is [REDACTED:anthropic_api_key] ok"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"name": "anthropic api key adjacent to CJK text is masked",
|
|
122
|
+
"input": "トークンは\u0073k-ant-api03-AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJです",
|
|
123
|
+
"expected": "トークンは[REDACTED:anthropic_api_key]です"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"name": "openai style key is masked",
|
|
127
|
+
"input": "OPENAI sk-AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKK",
|
|
128
|
+
"expected": "OPENAI [REDACTED:openai_api_key]"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"name": "github pat is masked next to Cyrillic text",
|
|
132
|
+
"input": "ключ \u0067hp_AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIк",
|
|
133
|
+
"expected": "ключ [REDACTED:github_pat_classic]к"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"name": "aws access key id is masked",
|
|
137
|
+
"input": "\u0041KIAAAAABBBBCCCCDDDD is the id",
|
|
138
|
+
"expected": "[REDACTED:aws_access_key] is the id"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"name": "google api key is masked",
|
|
142
|
+
"input": "\u0041IzaAAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIII",
|
|
143
|
+
"expected": "[REDACTED:google_api_key]"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"name": "slack bot token is masked",
|
|
147
|
+
"input": "\u0078oxb-111111111111-AAAABBBBCCCCDDDDEEEEFFFF",
|
|
148
|
+
"expected": "[REDACTED:slack_token]"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "jwt is masked next to accented latin text",
|
|
152
|
+
"input": "jetón eyJAAAABBBBCCCC.DDDDEEEEFFFF.GGGGHHHHIIIIé",
|
|
153
|
+
"expected": "jetón [REDACTED:jwt]é"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"name": "telegram bot token is masked",
|
|
157
|
+
"input": "bot1234567:AAAABBBBCCCCDDDDEEEEFFFFGGGGHH",
|
|
158
|
+
"expected": "bot[REDACTED:telegram_bot_token_prefixed]"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"name": "sanctum style token is masked",
|
|
162
|
+
"input": "17|AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJ",
|
|
163
|
+
"expected": "[REDACTED:laravel_sanctum_token]"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"name": "uppercase env assignment is masked",
|
|
167
|
+
"input": "API_TOKEN=zQ7xVb2nKd9wRt4y",
|
|
168
|
+
"expected": "API_TOKEN=[REDACTED]"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"name": "uppercase env assignment adjacent to Thai text is masked",
|
|
172
|
+
"input": "กุญ API_TOKEN=zQ7xVb2nKd9wRt4yก",
|
|
173
|
+
"expected": "กุญ API_TOKEN=[REDACTED]"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"name": "authorization bearer header is masked",
|
|
177
|
+
"input": "Authorization: Bearer AAAABBBBCCCCDDDDEEEEFFFF",
|
|
178
|
+
"expected": "Authorization: Bearer [REDACTED:bearer_auth_header]"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"name": "lowercase authorization bearer header is masked",
|
|
182
|
+
"input": "authorization: bearer AAAABBBBCCCCDDDDEEEEFFFF",
|
|
183
|
+
"expected": "authorization: bearer [REDACTED:bearer_auth_header]"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"name": "authorization basic header is masked",
|
|
187
|
+
"input": "Authorization: Basic YWxpY2U6c3VwZXJzZWNyZXQ=",
|
|
188
|
+
"expected": "Authorization: Basic [REDACTED:basic_auth_header]"
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"name": "json secret field is masked",
|
|
192
|
+
"input": "{\"apiKey\": \"zQ7xVb2nKd9wRt4y\"}",
|
|
193
|
+
"expected": "{\"apiKey\": \"[REDACTED:json_secret_field]\"}"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"name": "cli flag value is masked",
|
|
197
|
+
"input": "run --api-key zQ7xVb2nKd9wRt4y",
|
|
198
|
+
"expected": "run --api-key [REDACTED:cli_flag]"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"name": "no-break-space (U+00A0) separator after the key still masks",
|
|
202
|
+
"input": "API_TOKEN: zQ7xVb2nKd9wRt4y",
|
|
203
|
+
"expected": "API_TOKEN: [REDACTED]"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"name": "pem private key block is masked",
|
|
207
|
+
"input": "-----BEGIN RSA PRIVATE KEY-----\nAAAABBBBCCCC\n-----END RSA PRIVATE KEY-----",
|
|
208
|
+
"expected": "[REDACTED:pem_private_key]"
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"name": "sentence-final 'required' after 'password is' is NOT masked",
|
|
212
|
+
"input": "The password is required.",
|
|
213
|
+
"expected": "The password is required."
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"name": "sentence-final 'incorrect' after 'password is' is NOT masked",
|
|
217
|
+
"input": "The password is incorrect.",
|
|
218
|
+
"expected": "The password is incorrect."
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"name": "sentence-final 'unchanged' after 'password is' is NOT masked",
|
|
222
|
+
"input": "Ken confirmed the password is unchanged.",
|
|
223
|
+
"expected": "Ken confirmed the password is unchanged."
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"name": "comma-terminated prose after a password label is NOT masked",
|
|
227
|
+
"input": "password: required, minimum twelve characters, mixed case",
|
|
228
|
+
"expected": "password: required, minimum twelve characters, mixed case"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"name": "uppercase env vault reference is NOT masked",
|
|
232
|
+
"input": "POSTGRES_PASSWORD: vault:pg/password",
|
|
233
|
+
"expected": "POSTGRES_PASSWORD: vault:pg/password"
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"name": "lowercase env vault reference is NOT masked",
|
|
237
|
+
"input": "postgres_password: vault:pg/password",
|
|
238
|
+
"expected": "postgres_password: vault:pg/password"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"name": "uppercase env shell placeholder is NOT masked",
|
|
242
|
+
"input": "PASSWORD: ${DB_PASSWORD}",
|
|
243
|
+
"expected": "PASSWORD: ${DB_PASSWORD}"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"name": "uppercase env angle placeholder is NOT masked",
|
|
247
|
+
"input": "JWT_SECRET=<generate-with-openssl-rand>",
|
|
248
|
+
"expected": "JWT_SECRET=<generate-with-openssl-rand>"
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"name": "api key vault reference is NOT masked",
|
|
252
|
+
"input": "ANTHROPIC_API_KEY: vault:anthropic/api_key",
|
|
253
|
+
"expected": "ANTHROPIC_API_KEY: vault:anthropic/api_key"
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"name": "process.env reference is NOT masked",
|
|
257
|
+
"input": "const API_KEY = process.env.ANTHROPIC_API_KEY",
|
|
258
|
+
"expected": "const API_KEY = process.env.ANTHROPIC_API_KEY"
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"name": "cli flag placeholder in help text is NOT masked",
|
|
262
|
+
"input": "--token <value> the API token",
|
|
263
|
+
"expected": "--token <value> the API token"
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"name": "changeme placeholder is NOT masked",
|
|
267
|
+
"input": "DB_PASSWORD=changeme-in-production",
|
|
268
|
+
"expected": "DB_PASSWORD=changeme-in-production"
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
"name": "json doc string is NOT masked",
|
|
272
|
+
"input": "{\"token\": \"the bearer token to use\"}",
|
|
273
|
+
"expected": "{\"token\": \"the bearer token to use\"}"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"name": "ssh public key is NOT masked",
|
|
277
|
+
"input": "ssh-rsa AAAAB3NzaAAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH deploy@host",
|
|
278
|
+
"expected": "ssh-rsa AAAAB3NzaAAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH deploy@host"
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"name": "dsn password containing an unencoded at-sign is fully masked",
|
|
282
|
+
"input": "postgres://appuser:p@ssW0rd123@db.internal:5432/prod",
|
|
283
|
+
"expected": "postgres://appuser:[REDACTED:db_uri_password]@db.internal:5432/prod"
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"name": "memorable password at the end of a sentence is masked",
|
|
287
|
+
"input": "The wifi password is MangoTreeHouse77.",
|
|
288
|
+
"expected": "The wifi password is [REDACTED:memorable_password]"
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"name": "inert angle wrapper does NOT smuggle a value past env_key_value",
|
|
292
|
+
"input": "POSTGRES_PASSWORD: <a8f3c1d2e4b50f6a9c7d3e81b2f45a6cd90e17bb>",
|
|
293
|
+
"expected": "POSTGRES_PASSWORD: [REDACTED]"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"name": "inert angle wrapper does NOT smuggle a value past json_secret_field",
|
|
297
|
+
"input": "{\"token\": \"<tok_Zq7xVb2nKd9wRt4y>\"}",
|
|
298
|
+
"expected": "{\"token\": \"[REDACTED:json_secret_field]\"}"
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"name": "inert angle wrapper does NOT smuggle a value past cli_flag",
|
|
302
|
+
"input": "--token <a8f3c1d2e4b50f6a9c7d3e81b2f45a6cd90e17bb>",
|
|
303
|
+
"expected": "--token [REDACTED:cli_flag]"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"name": "handlebars wrapper does NOT smuggle a value through",
|
|
307
|
+
"input": "POSTGRES_PASSWORD: {{a8f3c1d2e4b50f6a9c7d3e81b2f45a6cd90e17bb}}",
|
|
308
|
+
"expected": "POSTGRES_PASSWORD: [REDACTED]"
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"name": "handlebars wrapper does NOT smuggle a value past cli_flag",
|
|
312
|
+
"input": "--token {{tok_Zq7xVb2nKd9wRt4y}}",
|
|
313
|
+
"expected": "--token [REDACTED:cli_flag]"
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"name": "vault: prefix does NOT smuggle a trailing value through",
|
|
317
|
+
"input": "POSTGRES_PASSWORD: vault:pg/password<a8f3c1d2e4b50f6a9c7d3e81b2f45a6cd90e17bb>",
|
|
318
|
+
"expected": "POSTGRES_PASSWORD: [REDACTED]"
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
"name": "vault: key slot does NOT smuggle a value through",
|
|
322
|
+
"input": "{\"token\": \"vault:pg/a8f3c1d2e4b50f6a9c7d3e81b2f45a6cd90e17bb\"}",
|
|
323
|
+
"expected": "{\"token\": \"[REDACTED:json_secret_field]\"}"
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
"name": "[REDACTED] marker prefix does NOT smuggle a trailing value through",
|
|
327
|
+
"input": "POSTGRES_PASSWORD: [REDACTED]a8f3c1d2e4b50f6a9c7d3e81b2f45a6cd90e17bb",
|
|
328
|
+
"expected": "POSTGRES_PASSWORD: [REDACTED]"
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"name": "[REDACTED:rule] marker prefix does NOT smuggle a trailing value through",
|
|
332
|
+
"input": "--token [REDACTED:cli_flag]a8f3c1d2e4b50f6a9c7d3e81b2f45a6cd90e17bb",
|
|
333
|
+
"expected": "--token [REDACTED:cli_flag]"
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
"name": "process.env prefix does NOT smuggle a trailing value through",
|
|
337
|
+
"input": "POSTGRES_PASSWORD: process.env.a8f3c1d2e4b50f6a9c7d3e81b2f45a6cd90e17bb",
|
|
338
|
+
"expected": "POSTGRES_PASSWORD: [REDACTED]"
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"name": "changeme prefix does NOT smuggle a trailing value through",
|
|
342
|
+
"input": "{\"token\": \"changeme-a8f3c1d2e4b50f6a9c7d3e81b2f45a6cd90e17bb\"}",
|
|
343
|
+
"expected": "{\"token\": \"[REDACTED:json_secret_field]\"}"
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
"name": "todo prefix does NOT smuggle a trailing value through",
|
|
347
|
+
"input": "--token todo_a8f3c1d2e4b50f6a9c7d3e81b2f45a6cd90e17bb",
|
|
348
|
+
"expected": "--token [REDACTED:cli_flag]"
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"name": "handlebars placeholder is NOT masked",
|
|
352
|
+
"input": "POSTGRES_PASSWORD: {{ db_password }}",
|
|
353
|
+
"expected": "POSTGRES_PASSWORD: {{ db_password }}"
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"name": "os.environ subscript reference is NOT masked",
|
|
357
|
+
"input": "API_KEY = os.environ[\"ANTHROPIC_API_KEY\"]",
|
|
358
|
+
"expected": "API_KEY = os.environ[\"ANTHROPIC_API_KEY\"]"
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"name": "import.meta.env reference is NOT masked",
|
|
362
|
+
"input": "VITE_API_KEY = import.meta.env.VITE_API_KEY",
|
|
363
|
+
"expected": "VITE_API_KEY = import.meta.env.VITE_API_KEY"
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
"name": "already-masked env value is stable under a second pass",
|
|
367
|
+
"input": "POSTGRES_PASSWORD: [REDACTED]",
|
|
368
|
+
"expected": "POSTGRES_PASSWORD: [REDACTED]"
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
"name": "already-masked rule-tagged cli flag is stable under a second pass",
|
|
372
|
+
"input": "--token [REDACTED:cli_flag]",
|
|
373
|
+
"expected": "--token [REDACTED:cli_flag]"
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
"name": "bare todo placeholder is NOT masked",
|
|
377
|
+
"input": "POSTGRES_PASSWORD: todo-before-launch",
|
|
378
|
+
"expected": "POSTGRES_PASSWORD: todo-before-launch"
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
"name": "single-class 16-char run in an angle wrapper is still masked",
|
|
382
|
+
"input": "POSTGRES_PASSWORD: <abcdefghijklmnop>",
|
|
383
|
+
"expected": "POSTGRES_PASSWORD: [REDACTED]"
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
"name": "single-class 16-char run in a handlebars wrapper is still masked",
|
|
387
|
+
"input": "--token {{abcdefghijklmnop}}",
|
|
388
|
+
"expected": "--token [REDACTED:cli_flag]"
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
"name": "a 10-letter word inside a placeholder is NOT masked",
|
|
392
|
+
"input": "DB_PASSWORD=changeme-in-production",
|
|
393
|
+
"expected": "DB_PASSWORD=changeme-in-production"
|
|
394
|
+
}
|
|
395
|
+
],
|
|
396
|
+
"_coverage": "Two classes of vector live here. (a) The IMPERATIVE gates that cannot be generated: the entropy floors, the inert-value list, the memorable-password character-class rule, the connection-URI scanner. (b) The GENERATED pattern table itself -- one vector per credential family, several of them deliberately ADJACENT to non-ASCII text. (b) exists because #3982's review found the two engines forking on Unicode word boundaries (Python re is Unicode-aware, JS RegExp without /u is not) while the byte-compare parity guard stayed green: the SOURCES were identical, the BEHAVIOUR was not, and no vector touched a generated rule. Keep at least one non-ASCII-adjacent vector per new family. Every credential here is synthetic. JSON has no runtime string concatenation, so token-shaped prefixes are broken up with \\uXXXX escapes instead -- json.load / JSON.parse restore the intended bytes, while the file on disk holds no contiguous token literal (CLAUDE.md 'Secrets in tests', scripts/check-no-pii-secrets.mjs, and GitHub Push Protection all require that). The WRAPPER vectors (#3982 review MAJOR 7) pin the other half of the inert gate: a value is skipped only when the WHOLE value is inert, so an inert-looking prefix or bracket pair left around a real credential must NOT suppress the mask."
|
|
397
|
+
}
|