@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/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
- // Review item 2: Google AI Studio API keys are `AIza` + 35 chars.
1204
- // No rule existed pre-fix.
1205
- pattern: /\bAIza[A-Za-z0-9_-]{35}\b/g,
1206
- replacement: "[REDACTED:GEMINI_API_KEY]"
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]"