@3030-labs/wotw 0.8.4 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -0
- package/dist/cli/index.js +615 -24
- package/dist/cli/index.js.map +1 -1
- package/dist/daemon/entry.js +624 -53
- package/dist/daemon/entry.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.js +41 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -588,6 +588,15 @@ interface RedactionRule {
|
|
|
588
588
|
name: string;
|
|
589
589
|
pattern: RegExp;
|
|
590
590
|
replacement: string;
|
|
591
|
+
/**
|
|
592
|
+
* Cloud-side rule_id this rule maps to in the PASS-024 `redaction_log`
|
|
593
|
+
* whitelist (`credential_pattern_01..10` + `truncation_32kb`). When set,
|
|
594
|
+
* sanitizeWithEvents() emits a row tagged with this id. When omitted,
|
|
595
|
+
* the redaction still fires but no outbound event is recorded — used
|
|
596
|
+
* for PII rules (credit-card, us-ssn) that stay daemon-local per the
|
|
597
|
+
* cloud's explicit whitelist (FEATURE-PASS-011 rule mapping).
|
|
598
|
+
*/
|
|
599
|
+
cloud_rule_id?: string;
|
|
591
600
|
}
|
|
592
601
|
/**
|
|
593
602
|
* Default redaction rules. Ordered by likely-to-match first for efficiency.
|
package/dist/index.js
CHANGED
|
@@ -346,6 +346,7 @@ async function loadConfig(searchFrom) {
|
|
|
346
346
|
const withEnv = applyEnvOverrides(merged);
|
|
347
347
|
const validated = validateConfig(withEnv);
|
|
348
348
|
validateHostedConfig(validated);
|
|
349
|
+
validateHostedRedactionSink(validated);
|
|
349
350
|
return { config: validated, path };
|
|
350
351
|
}
|
|
351
352
|
__name(loadConfig, "loadConfig");
|
|
@@ -430,6 +431,16 @@ function applyEnvOverrides(config) {
|
|
|
430
431
|
}
|
|
431
432
|
__name(applyEnvOverrides, "applyEnvOverrides");
|
|
432
433
|
var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
434
|
+
function validateHostedRedactionSink(config, env = process.env) {
|
|
435
|
+
if (!config.hosted.enabled) return;
|
|
436
|
+
const secret = env.WOTW_CLOUD_SINK_SECRET;
|
|
437
|
+
if (!secret || secret.length === 0) {
|
|
438
|
+
throw new Error(
|
|
439
|
+
"Config error: hosted.enabled is true but WOTW_CLOUD_SINK_SECRET is unset. The redaction-emit wire requires this secret to authenticate with /api/internal/redaction-log; running hosted-mode without it would silently drop every compliance redaction event."
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
__name(validateHostedRedactionSink, "validateHostedRedactionSink");
|
|
433
444
|
function validateHostedConfig(config) {
|
|
434
445
|
if (!config.hosted.enabled) return;
|
|
435
446
|
if (!config.hosted.tenant_id || config.hosted.tenant_id.length === 0) {
|
|
@@ -1167,19 +1178,22 @@ var DEFAULT_REDACTIONS = [
|
|
|
1167
1178
|
{
|
|
1168
1179
|
name: "aws-access-key",
|
|
1169
1180
|
pattern: /\bAKIA[0-9A-Z]{16}\b/g,
|
|
1170
|
-
replacement: "[REDACTED:AWS_ACCESS_KEY]"
|
|
1181
|
+
replacement: "[REDACTED:AWS_ACCESS_KEY]",
|
|
1182
|
+
cloud_rule_id: "credential_pattern_01"
|
|
1171
1183
|
},
|
|
1172
1184
|
{
|
|
1173
1185
|
name: "aws-secret-key",
|
|
1174
1186
|
pattern: /\b[A-Za-z0-9/+=]{40}\b(?=.*(?:secret|aws))/gi,
|
|
1175
|
-
replacement: "[REDACTED:AWS_SECRET_KEY]"
|
|
1187
|
+
replacement: "[REDACTED:AWS_SECRET_KEY]",
|
|
1188
|
+
cloud_rule_id: "credential_pattern_02"
|
|
1176
1189
|
},
|
|
1177
1190
|
{
|
|
1178
1191
|
name: "github-token",
|
|
1179
1192
|
// Review item 2: also catch GitHub fine-grained personal access
|
|
1180
1193
|
// tokens (`github_pat_*`, 82+ chars per docs).
|
|
1181
1194
|
pattern: /\bgh[pousr]_[A-Za-z0-9]{36,255}\b|\bgithub_pat_[A-Za-z0-9_]{50,}\b/g,
|
|
1182
|
-
replacement: "[REDACTED:GITHUB_TOKEN]"
|
|
1195
|
+
replacement: "[REDACTED:GITHUB_TOKEN]",
|
|
1196
|
+
cloud_rule_id: "credential_pattern_03"
|
|
1183
1197
|
},
|
|
1184
1198
|
{
|
|
1185
1199
|
name: "anthropic-api-key",
|
|
@@ -1187,7 +1201,8 @@ var DEFAULT_REDACTIONS = [
|
|
|
1187
1201
|
// window stays generous enough to catch both legacy and current
|
|
1188
1202
|
// formats including api03- prefix.
|
|
1189
1203
|
pattern: /\bsk-ant-[A-Za-z0-9-_]{80,120}\b/g,
|
|
1190
|
-
replacement: "[REDACTED:ANTHROPIC_API_KEY]"
|
|
1204
|
+
replacement: "[REDACTED:ANTHROPIC_API_KEY]",
|
|
1205
|
+
cloud_rule_id: "credential_pattern_04"
|
|
1191
1206
|
},
|
|
1192
1207
|
{
|
|
1193
1208
|
name: "openai-api-key",
|
|
@@ -1196,31 +1211,38 @@ var DEFAULT_REDACTIONS = [
|
|
|
1196
1211
|
// `sk-svcacct-*`, `sk-admin-*` all use `-` separators after the
|
|
1197
1212
|
// prefix and longer character set. Updated character class.
|
|
1198
1213
|
pattern: /\bsk-(?:proj|svcacct|admin)-[A-Za-z0-9_-]{20,200}\b|\bsk-[A-Za-z0-9]{20,200}\b/g,
|
|
1199
|
-
replacement: "[REDACTED:OPENAI_API_KEY]"
|
|
1214
|
+
replacement: "[REDACTED:OPENAI_API_KEY]",
|
|
1215
|
+
cloud_rule_id: "credential_pattern_05"
|
|
1200
1216
|
},
|
|
1201
1217
|
{
|
|
1202
1218
|
name: "gemini-api-key",
|
|
1203
|
-
//
|
|
1204
|
-
//
|
|
1205
|
-
|
|
1206
|
-
|
|
1219
|
+
// Google AI Studio API keys come in two formats:
|
|
1220
|
+
// - legacy: `AIza` + 35 chars
|
|
1221
|
+
// - current: `AQ.` + ~40-80 url-safe chars (rolled out 2024-2025; the
|
|
1222
|
+
// `AIza`-only rule silently missed these, leaking new-format keys)
|
|
1223
|
+
pattern: /\bAIza[A-Za-z0-9_-]{35}\b|\bAQ\.[A-Za-z0-9_-]{40,80}\b/g,
|
|
1224
|
+
replacement: "[REDACTED:GEMINI_API_KEY]",
|
|
1225
|
+
cloud_rule_id: "credential_pattern_06"
|
|
1207
1226
|
},
|
|
1208
1227
|
{
|
|
1209
1228
|
name: "wotw-daemon-token",
|
|
1210
1229
|
// Review item 2: daemon tokens emitted by `wotw user add` are
|
|
1211
1230
|
// `wotw_` + base64url chars. Pre-fix these went unredacted.
|
|
1212
1231
|
pattern: /\bwotw_[A-Za-z0-9_-]{30,200}\b/g,
|
|
1213
|
-
replacement: "[REDACTED:WOTW_TOKEN]"
|
|
1232
|
+
replacement: "[REDACTED:WOTW_TOKEN]",
|
|
1233
|
+
cloud_rule_id: "credential_pattern_07"
|
|
1214
1234
|
},
|
|
1215
1235
|
{
|
|
1216
1236
|
name: "private-key-block",
|
|
1217
1237
|
pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
1218
|
-
replacement: "[REDACTED:PRIVATE_KEY_BLOCK]"
|
|
1238
|
+
replacement: "[REDACTED:PRIVATE_KEY_BLOCK]",
|
|
1239
|
+
cloud_rule_id: "credential_pattern_08"
|
|
1219
1240
|
},
|
|
1220
1241
|
{
|
|
1221
1242
|
name: "jwt",
|
|
1222
1243
|
pattern: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g,
|
|
1223
|
-
replacement: "[REDACTED:JWT]"
|
|
1244
|
+
replacement: "[REDACTED:JWT]",
|
|
1245
|
+
cloud_rule_id: "credential_pattern_09"
|
|
1224
1246
|
},
|
|
1225
1247
|
{
|
|
1226
1248
|
// L-SEC-3: This pattern is deliberately scoped to full `scheme://`
|
|
@@ -1231,14 +1253,20 @@ var DEFAULT_REDACTIONS = [
|
|
|
1231
1253
|
// Verified by unit tests in test/unit/sanitize.test.ts.
|
|
1232
1254
|
name: "password-in-url",
|
|
1233
1255
|
pattern: /(\w+:\/\/[^:/\s]+:)[^@\s]+(@)/g,
|
|
1234
|
-
replacement: "$1[REDACTED]$2"
|
|
1256
|
+
replacement: "$1[REDACTED]$2",
|
|
1257
|
+
cloud_rule_id: "credential_pattern_10"
|
|
1235
1258
|
},
|
|
1236
1259
|
{
|
|
1260
|
+
// PII — stays daemon-local. cloud_rule_id intentionally omitted: the
|
|
1261
|
+
// PASS-024 cloud whitelist accepts only credential_pattern_01..10 +
|
|
1262
|
+
// truncation_32kb, treating PII metadata as data-that-shouldn't-leave-
|
|
1263
|
+
// the-daemon. Redaction still fires on-disk; sink emission is skipped.
|
|
1237
1264
|
name: "credit-card",
|
|
1238
1265
|
pattern: /\b(?:\d[ -]*?){13,16}\b/g,
|
|
1239
1266
|
replacement: "[REDACTED:PAN]"
|
|
1240
1267
|
},
|
|
1241
1268
|
{
|
|
1269
|
+
// PII — see credit-card note above.
|
|
1242
1270
|
name: "us-ssn",
|
|
1243
1271
|
pattern: /\b\d{3}-\d{2}-\d{4}\b/g,
|
|
1244
1272
|
replacement: "[REDACTED:SSN]"
|