@blamejs/core 0.14.6 → 0.14.7

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.
Files changed (74) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +3 -2
  3. package/lib/agent-event-bus.js +4 -4
  4. package/lib/agent-idempotency.js +6 -6
  5. package/lib/agent-orchestrator.js +9 -9
  6. package/lib/agent-posture-chain.js +10 -10
  7. package/lib/agent-saga.js +6 -7
  8. package/lib/agent-snapshot.js +8 -8
  9. package/lib/agent-stream.js +3 -3
  10. package/lib/agent-tenant.js +4 -4
  11. package/lib/agent-trace.js +5 -5
  12. package/lib/ai-disclosure.js +3 -3
  13. package/lib/app.js +2 -2
  14. package/lib/archive-read.js +1 -1
  15. package/lib/archive-tar-read.js +1 -1
  16. package/lib/archive-wrap.js +5 -5
  17. package/lib/audit-tools.js +65 -5
  18. package/lib/audit.js +2 -2
  19. package/lib/auth/ciba.js +1 -1
  20. package/lib/auth/dpop.js +1 -1
  21. package/lib/auth/fal.js +1 -1
  22. package/lib/auth/fido-mds3.js +2 -3
  23. package/lib/auth/jwt-external.js +2 -2
  24. package/lib/auth/oauth.js +9 -9
  25. package/lib/auth/oid4vci.js +7 -7
  26. package/lib/auth/oid4vp.js +1 -1
  27. package/lib/auth/openid-federation.js +5 -5
  28. package/lib/auth/passkey.js +6 -6
  29. package/lib/auth/saml.js +1 -1
  30. package/lib/auth/sd-jwt-vc.js +3 -6
  31. package/lib/backup/index.js +18 -18
  32. package/lib/cache.js +4 -4
  33. package/lib/calendar.js +5 -5
  34. package/lib/circuit-breaker.js +1 -1
  35. package/lib/cms-codec.js +2 -2
  36. package/lib/compliance.js +14 -14
  37. package/lib/crypto-field.js +58 -21
  38. package/lib/crypto.js +5 -6
  39. package/lib/db-query.js +131 -9
  40. package/lib/db.js +106 -22
  41. package/lib/external-db.js +64 -16
  42. package/lib/framework-schema.js +4 -4
  43. package/lib/guard-list-id.js +2 -2
  44. package/lib/guard-list-unsubscribe.js +1 -2
  45. package/lib/incident-report.js +150 -0
  46. package/lib/mail-crypto-smime.js +1 -1
  47. package/lib/mail-deploy.js +3 -3
  48. package/lib/mail-server-managesieve.js +2 -2
  49. package/lib/mail-server-pop3.js +2 -2
  50. package/lib/mail-store.js +1 -1
  51. package/lib/metrics.js +8 -8
  52. package/lib/middleware/csrf-protect.js +1 -1
  53. package/lib/middleware/dpop.js +5 -5
  54. package/lib/middleware/idempotency-key.js +21 -22
  55. package/lib/middleware/protected-resource-metadata.js +2 -2
  56. package/lib/network-dns-resolver.js +2 -2
  57. package/lib/network-dns.js +1 -2
  58. package/lib/network-tls.js +0 -1
  59. package/lib/outbox.js +1 -1
  60. package/lib/pqc-agent.js +1 -1
  61. package/lib/retention.js +1 -1
  62. package/lib/retry.js +1 -1
  63. package/lib/safe-archive.js +2 -2
  64. package/lib/safe-ical.js +2 -2
  65. package/lib/safe-mime.js +1 -1
  66. package/lib/self-update-standalone-verifier.js +1 -1
  67. package/lib/self-update.js +2 -2
  68. package/lib/static.js +1 -1
  69. package/lib/subject.js +2 -2
  70. package/lib/vault/index.js +64 -1
  71. package/lib/vault/rotate.js +19 -0
  72. package/lib/vendor-data.js +1 -1
  73. package/package.json +1 -1
  74. package/sbom.cdx.json +6 -6
@@ -57,7 +57,7 @@ function _emitMetric(name, value, labels) {
57
57
  catch (_e) { /* hot-path observability sink — drop silent by design */ }
58
58
  }
59
59
 
60
- // Statement-class classifier for auth-failure forensics (D-M2). Inspects
60
+ // Statement-class classifier for auth-failure forensics. Inspects
61
61
  // the leading keyword only so an attacker-controlled trailing fragment
62
62
  // can't smuggle a false classification. Skips leading whitespace plus
63
63
  // SQL line / block comments before reading the keyword.
@@ -83,8 +83,49 @@ function _classifyStatement(sql) {
83
83
  return _STATEMENT_CLASS_MAP[m[1].toUpperCase()] || "OTHER";
84
84
  }
85
85
 
86
+ // Best-effort target-relation extractor for auth-failure forensics: the
87
+ // table the denied role attempted to touch, so the audit row records
88
+ // the OBJECT (SOC2 CC7.2 / NIST SP 800-53 AU-3 "what was accessed"),
89
+ // not just the statement class. Defensive reader — returns null on
90
+ // anything unparseable and NEVER throws: it runs in the live failure
91
+ // path and must not mask the real 28000 / 42501 error. The extracted
92
+ // identifier is captured into audit METADATA (a JSON string, never
93
+ // re-executed as SQL), so the only sink risk is log-injection: any
94
+ // segment carrying a control / NUL character is refused. Spaces and
95
+ // ordinary punctuation inside a quoted identifier are kept so a
96
+ // legitimately-quoted relation name still surfaces in the audit row.
97
+ var _RELATION_RE = /\b(?:FROM|INTO|UPDATE|JOIN|TABLE|COPY)\s+((?:"[^"]+"|`[^`]+`|[A-Za-z_][\w$]*)(?:\.(?:"[^"]+"|`[^`]+`|[A-Za-z_][\w$]*))?)/ig;
98
+ function _hasControlChar(s) {
99
+ for (var i = 0; i < s.length; i += 1) {
100
+ var c = s.charCodeAt(i);
101
+ if (c < 0x20 || c === 0x7f) return true;
102
+ }
103
+ return false;
104
+ }
105
+ function _extractTargetRelation(sql) {
106
+ if (typeof sql !== "string" || sql.length === 0) return null;
107
+ var clean = sql.replace(/--[^\n]*/g, " ").replace(/\/\*[\s\S]*?\*\//g, " ");
108
+ _RELATION_RE.lastIndex = 0;
109
+ var m = _RELATION_RE.exec(clean);
110
+ if (!m) return null;
111
+ var segs = m[1].split(".").map(function (s) { return s.replace(/^["`]|["`]$/g, ""); });
112
+ for (var i = 0; i < segs.length; i += 1) {
113
+ if (segs[i].length === 0 || _hasControlChar(segs[i])) return null;
114
+ }
115
+ return segs.join(".");
116
+ }
117
+
118
+ function _countTargetRelations(sql) {
119
+ if (typeof sql !== "string") return 0;
120
+ var clean = sql.replace(/--[^\n]*/g, " ").replace(/\/\*[\s\S]*?\*\//g, " ");
121
+ _RELATION_RE.lastIndex = 0;
122
+ var n = 0;
123
+ while (_RELATION_RE.exec(clean) !== null) n += 1;
124
+ return n;
125
+ }
126
+
86
127
  // Postgres SQLSTATE classes that indicate authentication / authorization
87
- // failure at the DB level. SOC2 forensic gap (D-M2) — every match emits
128
+ // failure at the DB level. SOC2 forensic gap — every match emits
88
129
  // db.auth.failed with the SQL identity attempted, the database, and
89
130
  // the statement class.
90
131
  var _AUTH_FAILURE_CODES = Object.freeze({
@@ -97,18 +138,24 @@ function _emitAuthFailureAudit(backend, role, sql, e) {
97
138
  if (!e || !e.code) return;
98
139
  var kind = _AUTH_FAILURE_CODES[e.code];
99
140
  if (!kind) return;
141
+ var attemptedTable = _extractTargetRelation(sql);
142
+ var relationCount = _countTargetRelations(sql);
143
+ var resource = { kind: "db.backend", id: backend.name };
144
+ if (attemptedTable !== null) resource.attemptedTable = attemptedTable;
100
145
  audit().safeEmit({
101
146
  action: "db.auth.failed",
102
147
  actor: {},
103
- resource: { kind: "db.backend", id: backend.name },
148
+ resource: resource,
104
149
  outcome: "denied",
105
150
  reason: kind,
106
151
  metadata: {
107
- backend: backend.name,
108
- dialect: backend.dialect,
109
- sqlIdentity: role || null,
110
- sqlstate: e.code,
111
- statementClass: _classifyStatement(sql),
152
+ backend: backend.name,
153
+ dialect: backend.dialect,
154
+ sqlIdentity: role || null,
155
+ sqlstate: e.code,
156
+ statementClass: _classifyStatement(sql),
157
+ attemptedTable: attemptedTable,
158
+ attemptedRelationCount: relationCount,
112
159
  },
113
160
  });
114
161
  _emitMetric("db.auth.failed", 1, {
@@ -118,7 +165,7 @@ function _emitAuthFailureAudit(backend, role, sql, e) {
118
165
  });
119
166
  }
120
167
 
121
- // Slow-query bucket emitter (D-L7). Single-shot per query — highest
168
+ // Slow-query bucket emitter. Single-shot per query — highest
122
169
  // matched bucket wins. Operators dashboard on the `bucket` label
123
170
  // rather than separate counters per threshold.
124
171
  var _SLOW_QUERY_BUCKETS = Object.freeze([
@@ -628,7 +675,7 @@ async function query(sql, params, opts) {
628
675
  _emitMetric("db.role.denied", 1,
629
676
  { backend: b.name, role: role || "(none)" });
630
677
  }
631
- // D-M2 — DB-auth audit visibility. Every 28000 / 28P01 / 42501
678
+ // DB-auth audit visibility. Every 28000 / 28P01 / 42501
632
679
  // surfaces an auditable db.auth.failed row tagged with the SQL
633
680
  // identity and the statement class so SOC2 reviewers can
634
681
  // reconstruct the denial timeline.
@@ -693,13 +740,13 @@ async function transaction(fn, opts) {
693
740
  var prebuiltGucs = _buildSessionGucsStatements(opts.sessionGucs);
694
741
 
695
742
  var t0 = Date.now();
696
- // D-H4 — per-statement timeout. SET LOCAL statement_timeout binds
697
- // the query-cancel ceiling to this transaction; D-M7 wires
743
+ // Per-statement timeout. SET LOCAL statement_timeout binds
744
+ // the query-cancel ceiling to this transaction; this wires
698
745
  // idle_in_transaction_session_timeout from the same opt. Both
699
746
  // emit at SET LOCAL scope so the next pool checkout starts clean.
700
747
  var stmtTimeoutMs = opts.statementTimeoutMs;
701
748
  var idleTimeoutMs = opts.idleInTransactionTimeoutMs;
702
- // D-M8 — deadlock-retry policy. 40P01 (deadlock_detected) and 40001
749
+ // Deadlock-retry policy. 40P01 (deadlock_detected) and 40001
703
750
  // (serialization_failure) are transient — retry with capped attempts
704
751
  // and a small jittered backoff. Operators tune retries via opts.deadlockRetries (default 3).
705
752
  // numeric-bounds doesn't have a non-negative-int helper; use a
@@ -771,7 +818,7 @@ async function transaction(fn, opts) {
771
818
  _emitMetric("db.role.denied", 1,
772
819
  { backend: b.name, role: role || "(none)" });
773
820
  }
774
- // D-M2 — DB-auth audit visibility on transaction-shaped denials.
821
+ // DB-auth audit visibility on transaction-shaped denials.
775
822
  // Statement class always reads as "TX" since the failure
776
823
  // surface inside a transaction body could be any statement;
777
824
  // operators correlate via the transaction's audit row.
@@ -1017,7 +1064,7 @@ function _requireInit() {
1017
1064
 
1018
1065
  var REPLICA_UNHEALTHY_COOLDOWN_MS = C.TIME.seconds(30);
1019
1066
 
1020
- // F-CBT-2 — replica residency-tag compatibility.
1067
+ // Replica residency-tag compatibility.
1021
1068
  //
1022
1069
  // A primary tagged "EU" replicating to a "US" replica is a GDPR
1023
1070
  // Article 46 cross-border transfer; without an explicit operator
@@ -1194,7 +1241,7 @@ async function _readQuery(sql, params, opts) {
1194
1241
  _emitMetric("db.role.denied", 1,
1195
1242
  { backend: b.name, role: role || "(none)" });
1196
1243
  }
1197
- // D-M2 — DB-auth audit visibility for read-replica denials too.
1244
+ // DB-auth audit visibility for read-replica denials too.
1198
1245
  _emitAuthFailureAudit(b, role, sql, e);
1199
1246
  // Fallback to primary on a failed replica read when allowed.
1200
1247
  if (b.replicaFallbackToPrimary) {
@@ -1874,4 +1921,5 @@ module.exports = {
1874
1921
  migrate: externalDbMigrate,
1875
1922
  Pool: Pool,
1876
1923
  _resetForTest: _resetForTest,
1924
+ _extractTargetRelation: _extractTargetRelation,
1877
1925
  };
@@ -648,8 +648,8 @@ function _breakGlassPoliciesDDL(dialect) {
648
648
  }
649
649
 
650
650
  // _blamejs_break_glass_grants — issued grants. One row per successful
651
- // step-up. Default maxRowsPerGrant=1 enforces row-by-row auth per the
652
- // operator-confirmed shape ("each row access = its own grant").
651
+ // step-up. Default maxRowsPerGrant=1 enforces row-by-row auth
652
+ // ("each row access = its own grant").
653
653
  function _breakGlassGrantsDDL(dialect) {
654
654
  var t = _types(dialect);
655
655
  var name = LOCAL_TO_EXTERNAL._blamejs_break_glass_grants;
@@ -766,7 +766,7 @@ async function ensureSchema(opts) {
766
766
  created.push(d.create.match(/CREATE TABLE IF NOT EXISTS\s+(\S+)/)[1]);
767
767
  }
768
768
 
769
- // D-M11 — append-only WORM enforcement on audit_log / consent_log /
769
+ // Append-only WORM enforcement on audit_log / consent_log /
770
770
  // audit_checkpoints in cluster mode. Local-SQLite path already
771
771
  // installs CREATE TRIGGER IF NOT EXISTS via lib/db.js's
772
772
  // _installAppendOnlyTriggers; Postgres needs equivalent rules
@@ -779,7 +779,7 @@ async function ensureSchema(opts) {
779
779
  return { tables: created };
780
780
  }
781
781
 
782
- // D-M11 — WORM enforcement helper. Idempotent: rebuilding triggers
782
+ // WORM enforcement helper. Idempotent: rebuilding triggers
783
783
  // per boot is cheap and any operator-applied DROP TRIGGER is restored
784
784
  // at the next ensureSchema pass.
785
785
  async function _installWormTriggers(backend, dialect) {
@@ -203,8 +203,8 @@ function validate(headerValue, opts) {
203
203
  // recover the boundary without Public Suffix List awareness
204
204
  // (`team.example.com` could be label=team / ns=example.com OR
205
205
  // label=team.example / ns=com). The earlier last-2-segment
206
- // heuristic produced empty `label` for 2-label IDs (Codex P1 on
207
- // PR #64), which violates RFC 2919 §2's required label "."
206
+ // heuristic produced empty `label` for 2-label IDs
207
+ // which violates RFC 2919 §2's required label "."
208
208
  // namespace decomposition.
209
209
  //
210
210
  // Drop the heuristic split — surface only the raw `listId` (and
@@ -349,8 +349,7 @@ function _extractUris(raw, maxUris) {
349
349
  // bracket pairs directly via String.matchAll so URIs containing
350
350
  // commas (legitimate, e.g. `<https://x/u?tags=a,b>`) parse
351
351
  // correctly. Earlier split(",")-based scan misclassified such
352
- // URIs as "no <URI> elements" and refused legitimate mail
353
- // (Codex P1 on PR #63).
352
+ // URIs as "no <URI> elements" and refused legitimate mail.
354
353
  var matches = raw.matchAll(/<([^<>]*)>/g); // allow:regex-no-length-cap — input length-bounded by maxBytes check upstream
355
354
  var uris = [];
356
355
  for (var m of matches) {
@@ -305,8 +305,158 @@ function create(opts) {
305
305
  };
306
306
  }
307
307
 
308
+ // Breach detection -> notification running clock. The reporter
309
+ // (`create`) computes the static per-stage deadlines; this clock turns
310
+ // them into a live escalation loop: it tracks open incident records and,
311
+ // on each tick, fires "approaching" warnings as a stage's deadline nears
312
+ // and a "passed" alert when it elapses — once per (incident, stage,
313
+ // state) so a busy tick interval can't storm the operator. It re-uses
314
+ // the reporter's REGIME_DEADLINES / dueBy timestamps and re-encodes no
315
+ // jurisdiction hour-counts (GDPR Art.33 72h, NIS2 Art.23(4) 24h, DORA
316
+ // Art.19 + RTS 2024/1772 4h, CRA Art.14, HIPAA 45 CFR 164.404/408).
317
+ // `approachThresholds` are unitless proportions of detected-to-due.
318
+ function createDeadlineClock(opts) {
319
+ opts = opts || {};
320
+ validateOpts(opts, [
321
+ "audit", "notify", "approachThresholds", "intervalMs", "autoStart", "now",
322
+ ], "incident.report.createDeadlineClock");
323
+
324
+ var auditOn = opts.audit !== false;
325
+ var notify = (opts.notify && typeof opts.notify.send === "function") ? opts.notify : null;
326
+ var thresholds = Array.isArray(opts.approachThresholds) ? opts.approachThresholds.slice() : [0.5, 0.75, 0.9];
327
+ for (var ti = 0; ti < thresholds.length; ti += 1) {
328
+ if (typeof thresholds[ti] !== "number" || !(thresholds[ti] > 0 && thresholds[ti] < 1)) {
329
+ throw new IncidentReportError("incident-report/bad-threshold",
330
+ "createDeadlineClock: approachThresholds must be numbers strictly between 0 and 1");
331
+ }
332
+ }
333
+ thresholds.sort(function (a, b) { return a - b; });
334
+ var now = typeof opts.now === "function" ? opts.now : function () { return Date.now(); };
335
+ var intervalMs = (typeof opts.intervalMs === "number" && isFinite(opts.intervalMs) && opts.intervalMs > 0)
336
+ ? opts.intervalMs : C.TIME.minutes(1);
337
+ var autoStart = opts.autoStart !== false;
338
+
339
+ var tracked = new Map(); // incidentId -> { detectedAt, dueBy, regime, acked, fired }
340
+ var timer = null;
341
+
342
+ function _emit(action, outcome, metadata) {
343
+ if (!auditOn) return;
344
+ try {
345
+ audit().safeEmit({ action: "incident.report.clock." + action, outcome: outcome, metadata: metadata || {} });
346
+ } catch (_e) { /* drop-silent — by design */ }
347
+ }
348
+ function _notify(payload) {
349
+ if (!notify) return;
350
+ try {
351
+ var r = notify.send(payload);
352
+ if (r && typeof r.then === "function") r.then(null, function () {});
353
+ } catch (_e) { /* drop-silent — escalation is best-effort, never crashes a tick */ }
354
+ }
355
+
356
+ function track(record) {
357
+ if (!record || typeof record !== "object" || typeof record.id !== "string" || record.id.length === 0) {
358
+ throw new IncidentReportError("incident-report/bad-record",
359
+ "createDeadlineClock.track: record must be an incident.report record with a string id");
360
+ }
361
+ if (!record.dueBy || typeof record.dueBy !== "object" ||
362
+ typeof record.detectedAt !== "number") {
363
+ throw new IncidentReportError("incident-report/bad-record",
364
+ "createDeadlineClock.track: record must carry detectedAt + dueBy { initial, intermediate, final }");
365
+ }
366
+ tracked.set(record.id, {
367
+ detectedAt: record.detectedAt,
368
+ dueBy: record.dueBy,
369
+ regime: record.regime || null,
370
+ acked: {},
371
+ fired: {},
372
+ });
373
+ return record.id;
374
+ }
375
+
376
+ function untrack(id) { return tracked.delete(id); }
377
+
378
+ function acknowledgeSubmission(id, stage, info) {
379
+ if (!VALID_STAGES[stage]) {
380
+ throw new IncidentReportError("incident-report/bad-stage",
381
+ "createDeadlineClock.acknowledgeSubmission: stage must be one of " + Object.keys(VALID_STAGES).join(", "));
382
+ }
383
+ var t = tracked.get(id);
384
+ if (!t) {
385
+ throw new IncidentReportError("incident-report/unknown-incident",
386
+ "createDeadlineClock.acknowledgeSubmission: no tracked incident '" + id + "'");
387
+ }
388
+ t.acked[stage] = true;
389
+ _emit("submission_acknowledged", "success", { incidentId: id, regime: t.regime, stage: stage, info: info || null });
390
+ return true;
391
+ }
392
+
393
+ // Pure evaluation seam — operators (and tests) can pass an explicit
394
+ // nowMs. Each (incident, stage, state) fires AT MOST once; a stage
395
+ // that has been acknowledged is skipped entirely.
396
+ function tick(nowMsArg) {
397
+ var nowMs = typeof nowMsArg === "number" ? nowMsArg : now();
398
+ tracked.forEach(function (t, id) {
399
+ var stages = ["initial", "intermediate", "final"];
400
+ for (var si = 0; si < stages.length; si += 1) {
401
+ var stage = stages[si];
402
+ if (t.acked[stage]) continue;
403
+ var due = t.dueBy[stage];
404
+ if (typeof due !== "number") continue;
405
+ var span = due - t.detectedAt;
406
+ if (span <= 0) continue;
407
+ if (nowMs >= due) {
408
+ var pk = stage + ":passed";
409
+ if (!t.fired[pk]) {
410
+ t.fired[pk] = true;
411
+ _emit("deadline_passed", "failure", { incidentId: id, regime: t.regime, stage: stage, dueBy: due });
412
+ _notify({ kind: "deadline_passed", incidentId: id, regime: t.regime, stage: stage, dueBy: due });
413
+ }
414
+ continue;
415
+ }
416
+ var proportion = (nowMs - t.detectedAt) / span;
417
+ for (var thi = thresholds.length - 1; thi >= 0; thi -= 1) {
418
+ if (proportion >= thresholds[thi]) {
419
+ var ak = stage + ":approaching:" + thresholds[thi];
420
+ if (!t.fired[ak]) {
421
+ t.fired[ak] = true;
422
+ _emit("deadline_approaching", "warning",
423
+ { incidentId: id, regime: t.regime, stage: stage, dueBy: due, threshold: thresholds[thi] });
424
+ _notify({ kind: "deadline_approaching", incidentId: id, regime: t.regime, stage: stage, dueBy: due, threshold: thresholds[thi] });
425
+ }
426
+ break;
427
+ }
428
+ }
429
+ }
430
+ });
431
+ }
432
+
433
+ function start() {
434
+ if (timer) return;
435
+ timer = setInterval(function () { tick(); }, intervalMs);
436
+ if (timer && typeof timer.unref === "function") timer.unref();
437
+ }
438
+ function stop() {
439
+ if (timer) { clearInterval(timer); timer = null; }
440
+ }
441
+ function status() {
442
+ return { tracked: tracked.size, running: timer !== null, intervalMs: intervalMs };
443
+ }
444
+
445
+ if (autoStart) start();
446
+ return {
447
+ track: track,
448
+ untrack: untrack,
449
+ acknowledgeSubmission: acknowledgeSubmission,
450
+ tick: tick,
451
+ start: start,
452
+ stop: stop,
453
+ status: status,
454
+ };
455
+ }
456
+
308
457
  module.exports = {
309
458
  create: create,
459
+ createDeadlineClock: createDeadlineClock,
310
460
  IncidentReportError: IncidentReportError,
311
461
  REGIME_DEADLINES: REGIME_DEADLINES,
312
462
  DEFAULT_DEADLINES: DEFAULT_DEADLINES,
@@ -763,7 +763,7 @@ function checkCert(opts) {
763
763
  }
764
764
 
765
765
  // Validity window — refuse certs outside their notBefore / notAfter
766
- // window. Codex P1: checkCert's docstring promises this throws
766
+ // window. checkCert's docstring promises this throws
767
767
  // `mail-crypto/smime/expired-cert` but the impl was missing, letting
768
768
  // expired or not-yet-valid signing certs pass boot-time preflight
769
769
  // and fail interop later when peers verify signatures against the
@@ -720,7 +720,7 @@ function _validateTlsRptReport(raw, ctx) {
720
720
  "parseTlsRptReport: report has " + policies.length +
721
721
  " policies (cap " + TLSRPT_MAX_POLICIES + ")");
722
722
  }
723
- // Codex P2 (v0.10.15) — validate summary counts as finite non-negative
723
+ // Validate summary counts as finite non-negative
724
724
  // integers before summing. `Number(...) || 0` would accept
725
725
  // `Infinity` (from JSON literal `1e309` or string "Infinity"),
726
726
  // negative values, and arbitrary strings (coerced to NaN→0). Each
@@ -882,7 +882,7 @@ function tlsRptReportSchema() {
882
882
  * posture-aware payload (organization-name, report-id,
883
883
  * policy-domain set, session totals).
884
884
  *
885
- * Authentication discipline (Codex P2 v0.10.15):
885
+ * Authentication discipline:
886
886
  * - `trustedReporters` is a CONTENT-SIDE soft filter — it compares
887
887
  * the reporter's self-declared `organization-name` field (the
888
888
  * report body, operator-untrusted) against the operator's
@@ -962,7 +962,7 @@ function tlsRptIngestHttp(opts) {
962
962
  res.end("RFC 8460 §6.4-6.5 media types required\n");
963
963
  return;
964
964
  }
965
- // Codex P2 (v0.10.15) — real-authentication boundary BEFORE body
965
+ // Real-authentication boundary BEFORE body
966
966
  // collection. The operator-supplied `authenticate(req)` hook
967
967
  // routes to mTLS peer-cert / IP-allowlist / signed-header /
968
968
  // reverse-proxy header inspection. Sync-or-async; falsy → 401.
@@ -43,7 +43,7 @@
43
43
  * `opts.auth.mechanisms`. The framework hardcodes no defaults; an
44
44
  * operator who omits `mechanisms` gets a listener that refuses
45
45
  * every AUTHENTICATE attempt with "mechanism not advertised"
46
- * (avoids the IMAP v0.9.49 Codex P2 class — advertising AUTH=PLAIN
46
+ * (otherwise advertising AUTH=PLAIN
47
47
  * when authConfig is null sets clients up to attempt PLAIN against
48
48
  * a listener that hasn't wired the verifier).
49
49
  *
@@ -482,7 +482,7 @@ function create(opts) {
482
482
  }
483
483
  socket.write('"SIEVE" "' + sieveCaps.join(" ") + '"\r\n');
484
484
  // Advertise SASL mechanisms — ONLY the mechs the operator wired
485
- // in opts.auth.mechanisms (Codex P2 IMAP lesson: don't hardcode).
485
+ // in opts.auth.mechanisms (do not hardcode the advertised mechanisms).
486
486
  if (authConfig && Array.isArray(authConfig.mechanisms) && authConfig.mechanisms.length > 0) {
487
487
  var mechs = authConfig.mechanisms.map(function (m) {
488
488
  return String(m).toUpperCase();
@@ -368,8 +368,8 @@ function create(opts) {
368
368
  socket.write("UIDL\r\n");
369
369
  socket.write("RESP-CODES\r\n");
370
370
  if (!state.tls) socket.write("STLS\r\n");
371
- // Advertise AUTH mechanisms ONLY when wired (Codex P2 IMAP lesson:
372
- // don't hardcode SASL mechs in caps).
371
+ // Advertise AUTH mechanisms ONLY when wired
372
+ // (do not hardcode SASL mechs in caps).
373
373
  if (authConfig && Array.isArray(authConfig.mechanisms) && authConfig.mechanisms.length > 0) {
374
374
  var mechs = authConfig.mechanisms.map(function (m) {
375
375
  return String(m).toUpperCase();
package/lib/mail-store.js CHANGED
@@ -753,7 +753,7 @@ function _setFlags(args) {
753
753
  // Per-message modseq bump — without this, queryByModseq filters
754
754
  // `messages.modseq > sinceModseq` and misses the flag change. CONDSTORE
755
755
  // (RFC 7162) / JMAP Email/changes both depend on the per-message
756
- // modseq being current. Per Codex P1 on PR #49.
756
+ // modseq being current.
757
757
  if (args.objectids.length > 0 && (setFlags.length > 0 || unsetFlags.length > 0)) {
758
758
  // Bulk-update via IN-clause. SQLite caps IN-clause at 32766 (max
759
759
  // bound parameters); chunk for very large operands.
package/lib/metrics.js CHANGED
@@ -143,7 +143,7 @@ function _normalizeLabelArg(callLabels, value, defaultValue) {
143
143
  };
144
144
  }
145
145
 
146
- // CRYPTO-18 — credential-shape detector. Operators routinely tap their
146
+ // Credential-shape detector. Operators routinely tap their
147
147
  // own observability with `{ token: req.headers.authorization }` or
148
148
  // `{ apiKey: req.headers["x-api-key"] }`, which then leak through the
149
149
  // /metrics scrape surface to any reader of the metrics endpoint. The
@@ -199,7 +199,7 @@ function _validateLabelValue(value) {
199
199
  // counters indexed by various input types still work.
200
200
  if (value === null || value === undefined) return "";
201
201
  var coerced = String(value);
202
- // CRYPTO-18 — credential-shape detector. Operators who tap their
202
+ // Credential-shape detector. Operators who tap their
203
203
  // observability with raw header values leak bearer tokens / API
204
204
  // keys through /metrics to every scrape reader. Refuse the value
205
205
  // and surface a redaction marker so the metric still labels (so
@@ -642,8 +642,8 @@ function create(opts) {
642
642
  // `Accept: application/openmetrics-text; version=1.0.0`. The
643
643
  // handler returns the OpenMetrics-1.0 wire format when that
644
644
  // media type has the highest q-value among supported types;
645
- // defaults to Prometheus 0.0.4 otherwise. Codex P1 v0.12.5 —
646
- // honor RFC 9110 §12.5.1 weighted negotiation: a client that
645
+ // defaults to Prometheus 0.0.4 otherwise.
646
+ // Honor RFC 9110 §12.5.1 weighted negotiation: a client that
647
647
  // sends `Accept: text/plain;q=1.0, application/openmetrics-
648
648
  // text;q=0.5` (or `;q=0`) gets text/plain back, even though
649
649
  // both media types are supported.
@@ -719,7 +719,7 @@ function create(opts) {
719
719
  // (Prometheus 2.x, Grafana exemplar-renderer) can pivot
720
720
  // from a slow-request bucket to the trace that produced it.
721
721
  //
722
- // Codex P2 v0.12.5 — the span_id MUST be the server-handling
722
+ // The span_id MUST be the server-handling
723
723
  // span (created by b.middleware.spanHttpServer + stamped on
724
724
  // req.span), not the upstream `traceparent`'s parent-id.
725
725
  // The parent-id points at the CALLER's span (or nothing for
@@ -986,7 +986,7 @@ function snapshotStartWriter(opts) {
986
986
  var fieldsFn = opts.fields;
987
987
  var registry = opts.registry || null;
988
988
  var intervalMs = opts.intervalMs;
989
- // CRYPTO-6 — file mode for the atomic write. Default 0o640
989
+ // File mode for the atomic write. Default 0o640
990
990
  // (owner rw, group r, world none). Operators with a sidecar
991
991
  // reader in a different group override to 0o644; multi-tenant
992
992
  // hosts may even tighten to 0o600.
@@ -1019,7 +1019,7 @@ function snapshotStartWriter(opts) {
1019
1019
  catch (e2) { log("snapshot.metrics serialize failed: " + ((e2 && e2.message) || String(e2))); }
1020
1020
  }
1021
1021
  try {
1022
- // CRYPTO-6 — default 0o640 (owner rw, group r, world none) so
1022
+ // Default 0o640 (owner rw, group r, world none) so
1023
1023
  // operator-supplied snapshot fields aren't world-readable on a
1024
1024
  // multi-tenant host. Operators with a sidecar reader running as
1025
1025
  // a different group override via opts.fileMode at startWriter
@@ -1078,7 +1078,7 @@ function snapshotRead(p) {
1078
1078
  // is well above the framework's expected snapshot size (~5-50 KiB)
1079
1079
  // and the safeJson absolute cap stays within reach.
1080
1080
  try {
1081
- // CRYPTO-21 — route through C.BYTES.mib(4); the raw byte literal
1081
+ // Route through C.BYTES.mib(4); the raw byte literal
1082
1082
  // was a drift smell flagged by codebase-patterns.
1083
1083
  parsed = safeJson.parse(raw, { maxBytes: C.BYTES.mib(4) });
1084
1084
  } catch (e) {
@@ -316,7 +316,7 @@ function create(opts) {
316
316
  // refuse before the token check.
317
317
  //
318
318
  // Default: enabled (defense-in-depth — same shape as bot-guard /
319
- // rate-limit / CSP nonce — every default ON per Core Rule §3).
319
+ // rate-limit / CSP nonce — every default ON).
320
320
  // Operator opt-out: opts.checkOrigin = false.
321
321
  // Operator allowlist: opts.allowedOrigins = ["https://app.example.com"].
322
322
  var checkOrigin = opts.checkOrigin !== false;
@@ -119,7 +119,7 @@ function _nonceManager(rotateSec) {
119
119
  if (previous && bCrypto.timingSafeEqual(n, previous.nonce)) return true;
120
120
  return false;
121
121
  },
122
- // AUTH-36 — hot-reload coexistence. Operators redeploying without
122
+ // Hot-reload coexistence. Operators redeploying without
123
123
  // a clean process restart need a way to drain in-flight clients
124
124
  // before swapping the middleware instance. shutdown() returns no
125
125
  // fresh nonces and refuses every presented nonce, so the
@@ -156,7 +156,7 @@ function _reconstructHtu(req, mopts) {
156
156
  //
157
157
  // Default: ignore X-Forwarded-* and derive proto/host from the
158
158
  // socket. Operators with a confirmed-trusted front proxy opt in
159
- // via opts.trustForwardedHeaders: true. (Audit 2026-05-11.)
159
+ // via opts.trustForwardedHeaders: true.
160
160
  mopts = mopts || {};
161
161
  var trustForwarded = mopts.trustForwardedHeaders === true;
162
162
  var proto;
@@ -229,7 +229,7 @@ function create(opts) {
229
229
  "getAccessToken", "getNonce", "getHtu", "audit",
230
230
  "nonceStore", "nonceWindowSec", "nonceRotateSec", "requireNonce",
231
231
  // v0.9.4 — opt-in trust gate for X-Forwarded-Proto/Host when
232
- // reconstructing htu. Default off (audit 2026-05-11); operators
232
+ // reconstructing htu. Default off; operators
233
233
  // with a confirmed-trusted front proxy set this to `true`.
234
234
  "trustForwardedHeaders", "onDeny", "problemDetails",
235
235
  ], "middleware.dpop");
@@ -287,7 +287,7 @@ function create(opts) {
287
287
  return _writeUnauthorized(req, res, "invalid_dpop_proof",
288
288
  "multiple DPoP headers are not allowed", null, onDeny, problemMode);
289
289
  }
290
- // AUTH-15 — RFC 9449 §4.1 single-value invariant. node:http
290
+ // RFC 9449 §4.1 single-value invariant. node:http
291
291
  // collapses repeated headers into a comma-joined string when the
292
292
  // client ships `DPoP: proof1, DPoP: proof2`; the Array.isArray
293
293
  // check above catches the multi-value array shape but a
@@ -399,7 +399,7 @@ function create(opts) {
399
399
  return next();
400
400
  };
401
401
 
402
- // AUTH-36 — surface the nonce manager's lifecycle hooks on the
402
+ // Surface the nonce manager's lifecycle hooks on the
403
403
  // returned middleware so hot-reload deploys can drain in-flight
404
404
  // clients before swapping instances. shutdown() refuses every
405
405
  // subsequent proof + issues no fresh nonces; revoke() rotates the