@blamejs/core 0.14.19 → 0.14.21

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 (41) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +1 -1
  3. package/lib/auth/oauth.js +736 -1
  4. package/lib/auth/oid4vci.js +124 -5
  5. package/lib/auth/oid4vp.js +14 -4
  6. package/lib/auth/sd-jwt-vc-holder.js +46 -1
  7. package/lib/break-glass.js +1 -2
  8. package/lib/config.js +28 -31
  9. package/lib/crypto-field.js +274 -17
  10. package/lib/dora.js +8 -5
  11. package/lib/dsr.js +2 -2
  12. package/lib/flag-evaluation-context.js +7 -0
  13. package/lib/guard-html-wcag-aria.js +4 -2
  14. package/lib/guard-html-wcag-forms.js +4 -2
  15. package/lib/guard-html-wcag-tables.js +4 -2
  16. package/lib/guard-html-wcag-tagwalk.js +20 -0
  17. package/lib/guard-html-wcag.js +1 -1
  18. package/lib/honeytoken.js +27 -20
  19. package/lib/mail-auth.js +333 -0
  20. package/lib/mail-deploy.js +1 -1
  21. package/lib/mail-send-deliver.js +13 -4
  22. package/lib/middleware/api-encrypt.js +140 -13
  23. package/lib/middleware/asyncapi-serve.js +3 -0
  24. package/lib/middleware/csp-report.js +13 -9
  25. package/lib/middleware/fetch-metadata.js +115 -14
  26. package/lib/middleware/openapi-serve.js +3 -0
  27. package/lib/middleware/scim-server.js +297 -19
  28. package/lib/middleware/security-headers.js +47 -0
  29. package/lib/middleware/security-txt.js +1 -2
  30. package/lib/middleware/trace-log-correlation.js +1 -2
  31. package/lib/network-smtp-policy.js +4 -4
  32. package/lib/object-store/sigv4-bucket-ops.js +11 -2
  33. package/lib/observability-tracer.js +1 -1
  34. package/lib/observability.js +39 -1
  35. package/lib/problem-details.js +56 -11
  36. package/lib/pubsub-cluster.js +16 -3
  37. package/lib/queue-sqs.js +20 -2
  38. package/lib/redis-client.js +32 -4
  39. package/lib/safe-redirect.js +16 -2
  40. package/package.json +1 -1
  41. package/sbom.cdx.json +6 -6
@@ -57,7 +57,7 @@ var BEARER_RE = /^Bearer\s+(.+)$/i;
57
57
  * users: ScimResourceImpl,
58
58
  * groups?: ScimResourceImpl,
59
59
  * bearer?: (token) => Promise<actor>,
60
- * maxPageSize?: number,
60
+ * maxPageSize?: number, // default: 200 (config-time positive int)
61
61
  * bulk?: {
62
62
  * maxOperations?: number, // default: 1000 (config-time positive int)
63
63
  * maxPayloadSize?: number, // default: 1 MiB (config-time positive int, bytes)
@@ -80,6 +80,12 @@ function create(opts) {
80
80
  if (opts.groups) _validateResourceImpl(opts.groups, "groups");
81
81
 
82
82
  var basePath = opts.basePath || "/scim/v2";
83
+ // Config-time / entry-point tier: a bad page-size cap THROWS so the
84
+ // operator catches the typo at boot rather than at request time, where
85
+ // a non-number would propagate NaN into impl.list({ count }) and
86
+ // ServiceProviderConfig.filter.maxResults.
87
+ validateOpts.optionalPositiveInt(opts.maxPageSize, "middleware.scimServer: opts.maxPageSize",
88
+ ScimServerError, "middleware/scim-server/bad-max-page-size");
83
89
  var maxPageSize = opts.maxPageSize || 200; // page-size count, not bytes
84
90
  var bearer = opts.bearer || null;
85
91
  var bulkCfg = _resolveBulkConfig(opts.bulk);
@@ -297,11 +303,15 @@ async function _dispatch(req, res, basePath, bearer, opts, maxPageSize, bulkCfg)
297
303
  }
298
304
 
299
305
  // RFC 7644 §3.7 — /Bulk POST. Parses a BulkRequest, enforces the
300
- // config-time maxOperations / maxPayloadSize caps, optionally
301
- // short-circuits at failOnErrors, resolves bulkId cross-references
302
- // (§3.7.2), dispatches each operation through the same per-resource
303
- // create/update/delete logic the singleton endpoints use, and returns
304
- // a BulkResponse carrying one result object per operation.
306
+ // config-time maxOperations / maxPayloadSize caps, plans a
307
+ // dependency-ordered execution so bulkId cross-references (§3.7.2) —
308
+ // including forward references resolve to real ids before dispatch,
309
+ // fails operations with undeclared / circular / failed-dependency
310
+ // references per-op, optionally short-circuits at failOnErrors,
311
+ // dispatches each surviving operation through the same per-resource
312
+ // create/update/delete logic the singleton endpoints use, and returns a
313
+ // BulkResponse carrying one result object per operation in the ORIGINAL
314
+ // request order.
305
315
  async function _handleBulk(req, res, opts, bulkCfg, ctx) {
306
316
  var body;
307
317
  try {
@@ -336,26 +346,265 @@ async function _handleBulk(req, res, opts, bulkCfg, ctx) {
336
346
 
337
347
  var failOnErrors = _parseFailOnErrors(body.failOnErrors);
338
348
  var bulkIdMap = Object.create(null); // client bulkId -> assigned resource id
339
- var results = [];
340
- var errorCount = 0;
349
+ var ops = body.Operations;
350
+
351
+ // RFC 7644 §3.7.2 — a bulkId reference may point at a resource a LATER
352
+ // operation creates (a forward reference), so processing strictly in
353
+ // request order leaves the token unresolved. Pre-scan to (a) collect
354
+ // every declared bulkId and (b) build each operation's dependency set
355
+ // by walking its data for "bulkId:<id>" cross-references, then execute
356
+ // in dependency order. The response array is still emitted in the
357
+ // ORIGINAL request order (results indexed by request position).
358
+ var plan = _planBulkOperations(ops);
359
+
360
+ var results = new Array(ops.length); // request-order result entries
361
+ var executed = new Array(ops.length); // index -> { isError } once run
362
+ var errorCount = 0;
363
+ var stopped = false;
364
+
365
+ for (var s = 0; s < plan.order.length && !stopped; s++) {
366
+ var idx = plan.order[s];
367
+ var planned = plan.ops[idx];
368
+ var outcome;
369
+
370
+ if (planned.staticError) {
371
+ // Undeclared reference or a reference that lands in a dependency
372
+ // cycle — fail the op without ever dispatching to the adapter.
373
+ outcome = _bulkErr(ops[idx], planned.staticError.status,
374
+ planned.staticError.scimType, planned.staticError.detail);
375
+ } else if (_anyDependencyFailed(planned.refs, plan, executed, bulkIdMap)) {
376
+ // RFC 7644 §3.7.2 — a reference to an operation that FAILED cannot
377
+ // resolve to a real id; fail the dependent op with invalidValue
378
+ // rather than letting a literal "bulkId:<id>" token reach the
379
+ // adapter as if it were a real resource identifier.
380
+ outcome = _bulkErr(ops[idx], "400", "invalidValue",
381
+ "Operations[" + idx + "] references a bulkId whose creating operation failed");
382
+ } else {
383
+ outcome = await _runBulkOperation(ops[idx], idx, opts, ctx, bulkIdMap);
384
+ }
341
385
 
342
- for (var i = 0; i < body.Operations.length; i++) {
343
- var result = await _runBulkOperation(body.Operations[i], i, opts, ctx, bulkIdMap);
344
- results.push(result.entry);
345
- if (result.isError) {
386
+ results[idx] = outcome.entry;
387
+ executed[idx] = { isError: outcome.isError };
388
+ if (outcome.isError) {
346
389
  errorCount++;
347
390
  // RFC 7644 §3.7 — once the error count reaches failOnErrors the
348
- // service stops processing and returns the results so far.
349
- if (failOnErrors !== null && errorCount >= failOnErrors) break;
391
+ // service stops processing and returns the results so far. Results
392
+ // already produced keep their request-order slots; unreached
393
+ // operations are omitted from the response.
394
+ if (failOnErrors !== null && errorCount >= failOnErrors) stopped = true;
350
395
  }
351
396
  }
352
397
 
398
+ // Compact to the operations actually reached, preserving request order.
399
+ var emitted = [];
400
+ for (var e = 0; e < results.length; e++) {
401
+ if (results[e] !== undefined) emitted.push(results[e]);
402
+ }
403
+
353
404
  _writeJson(res, H.OK, {
354
405
  schemas: [SCIM_MESSAGE_BULK_RESPONSE],
355
- Operations: results,
406
+ Operations: emitted,
356
407
  });
357
408
  }
358
409
 
410
+ // RFC 7644 §3.7.2 — build the dependency-ordered execution plan for a
411
+ // bulk job. Returns { ops, order } where ops[i] = { refs, staticError? }
412
+ // (refs = the set of declared bulkIds operation i depends on) and order
413
+ // is the request indices in a dependency-respecting (topological)
414
+ // sequence. Operations referencing an UNDECLARED bulkId, or caught in a
415
+ // dependency CYCLE, carry a staticError so the executor fails them
416
+ // without dispatching to the adapter. A POST that declares a bulkId is
417
+ // the only operation kind that can satisfy a reference.
418
+ function _planBulkOperations(ops) {
419
+ var declared = Object.create(null); // bulkId -> declaring index
420
+ var planned = new Array(ops.length);
421
+
422
+ for (var i = 0; i < ops.length; i++) {
423
+ var op = ops[i];
424
+ var bulkId = op && typeof op.bulkId === "string" ? op.bulkId : null;
425
+ var method = op && typeof op.method === "string" ? op.method.toUpperCase() : null;
426
+ // Only a POST (resource creation) assigns a server id to a bulkId.
427
+ if (bulkId && method === "POST" && declared[bulkId] === undefined) {
428
+ declared[bulkId] = i;
429
+ }
430
+ planned[i] = { refs: [], staticError: null, ownBulkId: method === "POST" ? bulkId : null };
431
+ }
432
+
433
+ for (var j = 0; j < ops.length; j++) {
434
+ // RFC 7644 §3.7.2 — a reference can appear in the operation DATA
435
+ // ("value": "bulkId:u1") or as the resource id in the operation
436
+ // PATH ("PATCH /Groups/bulkId:g1" targeting a group another
437
+ // operation in this request creates). Both surfaces feed the same
438
+ // dependency set so path-referencing operations order and fail
439
+ // exactly like data-referencing ones.
440
+ var refs = _collectBulkIdRefs(ops[j] && ops[j].data).concat(_pathBulkIdRefs(ops[j]));
441
+ var depSet = [];
442
+ for (var r = 0; r < refs.length; r++) {
443
+ var refId = refs[r];
444
+ var decl = declared[refId];
445
+ if (decl === undefined) {
446
+ // RFC 7644 §3.7.2 — a reference to a bulkId no operation declares
447
+ // can never resolve; fail this op with invalidValue.
448
+ planned[j].staticError = {
449
+ status: "400",
450
+ scimType: "invalidValue",
451
+ detail: "Operations[" + j + "] references undeclared bulkId '" + refId + "'",
452
+ };
453
+ depSet = [];
454
+ break;
455
+ }
456
+ if (decl !== j && depSet.indexOf(decl) === -1) depSet.push(decl);
457
+ }
458
+ planned[j].refs = depSet;
459
+ }
460
+
461
+ var order = _topoOrderBulk(planned);
462
+ return { ops: planned, order: order };
463
+ }
464
+
465
+ // Walk operation data for "bulkId:<id>" cross-references, returning the
466
+ // list of referenced bulkIds (the "<id>" portion). Bounded: the whole
467
+ // payload was capped at maxPayloadSize before parse.
468
+ function _collectBulkIdRefs(value) {
469
+ var out = [];
470
+ _walkBulkIdRefs(value, out);
471
+ return out;
472
+ }
473
+
474
+ // RFC 7644 §3.7.2 — bulkId references in an operation's PATH segments
475
+ // (e.g. "PATCH /Groups/bulkId:g1"). Returns the referenced bulkIds.
476
+ function _pathBulkIdRefs(op) {
477
+ if (!op || typeof op.path !== "string") return [];
478
+ var out = [];
479
+ var segs = op.path.split("/");
480
+ for (var i = 0; i < segs.length; i++) {
481
+ var ref = BULK_ID_REF_RE.exec(segs[i]);
482
+ if (ref) out.push(ref[1]);
483
+ }
484
+ return out;
485
+ }
486
+
487
+ // Substitute "bulkId:<id>" PATH segments with the server-assigned id,
488
+ // exactly like data references resolve (RFC 7644 §3.7.2). Throws on an
489
+ // unresolved token — surfaced as a per-op invalidValue by the caller —
490
+ // so a literal token never reaches the path parser or the adapter.
491
+ function _resolvePathBulkIdRefs(path, bulkIdMap) {
492
+ var segs = path.split("/");
493
+ for (var i = 0; i < segs.length; i++) {
494
+ var ref = BULK_ID_REF_RE.exec(segs[i]);
495
+ if (!ref) continue;
496
+ var resolved = bulkIdMap[ref[1]];
497
+ if (resolved === undefined) {
498
+ throw new ScimServerError("middleware/scim-server/unresolved-bulkid",
499
+ "references unresolved bulkId '" + ref[1] + "' in path");
500
+ }
501
+ segs[i] = resolved;
502
+ }
503
+ return segs.join("/");
504
+ }
505
+
506
+ function _walkBulkIdRefs(value, out) {
507
+ if (typeof value === "string") {
508
+ var ref = BULK_ID_REF_RE.exec(value);
509
+ if (ref) out.push(ref[1]);
510
+ return;
511
+ }
512
+ if (Array.isArray(value)) {
513
+ for (var i = 0; i < value.length; i++) _walkBulkIdRefs(value[i], out);
514
+ return;
515
+ }
516
+ if (value && typeof value === "object") {
517
+ var keys = Object.keys(value);
518
+ for (var k = 0; k < keys.length; k++) {
519
+ if (keys[k] === "__proto__" || keys[k] === "constructor" || keys[k] === "prototype") continue;
520
+ _walkBulkIdRefs(value[keys[k]], out);
521
+ }
522
+ }
523
+ }
524
+
525
+ // Dependency-respecting order over the planned operations. Operations
526
+ // already carrying a staticError (undeclared reference) are treated as
527
+ // dependency-free roots so they surface their own error in request
528
+ // order. Any operation that cannot be ordered because it participates in
529
+ // a CYCLE is marked with a 409 staticError per RFC 7644 §3.7.1 — "The
530
+ // service provider MUST try to resolve circular cross-references ... but
531
+ // MAY ... return HTTP status code 409 (Conflict)". The returned order
532
+ // always covers every index exactly once.
533
+ function _topoOrderBulk(planned) {
534
+ var n = planned.length;
535
+ var visited = new Array(n); // 0 = unseen, 1 = on-stack, 2 = done
536
+ for (var v = 0; v < n; v++) visited[v] = 0;
537
+ var order = [];
538
+ var inCycle = Object.create(null);
539
+
540
+ // Iterative depth-first post-order so a dependency is emitted before
541
+ // the operation that needs it. A back-edge (a node still on-stack)
542
+ // marks a cycle; every node on the active stack at that point is part
543
+ // of an unresolvable circular reference.
544
+ for (var start = 0; start < n; start++) {
545
+ if (visited[start] !== 0) continue;
546
+ var stack = [{ node: start, edge: 0 }];
547
+ while (stack.length > 0) {
548
+ var top = stack[stack.length - 1];
549
+ var node = top.node;
550
+ if (top.edge === 0) visited[node] = 1;
551
+ var deps = (planned[node].staticError) ? [] : planned[node].refs;
552
+ if (top.edge < deps.length) {
553
+ var dep = deps[top.edge];
554
+ top.edge++;
555
+ if (visited[dep] === 0) {
556
+ stack.push({ node: dep, edge: 0 });
557
+ } else if (visited[dep] === 1) {
558
+ // Back-edge to a node still on the active stack — every node
559
+ // from that node up to the current top forms the cycle.
560
+ var depPos = -1;
561
+ for (var p = 0; p < stack.length; p++) {
562
+ if (stack[p].node === dep) { depPos = p; break; }
563
+ }
564
+ for (var q = depPos; q >= 0 && q < stack.length; q++) {
565
+ inCycle[stack[q].node] = true;
566
+ }
567
+ }
568
+ } else {
569
+ visited[node] = 2;
570
+ order.push(node);
571
+ stack.pop();
572
+ }
573
+ }
574
+ }
575
+
576
+ for (var c = 0; c < n; c++) {
577
+ if (inCycle[c] && !planned[c].staticError) {
578
+ planned[c].staticError = {
579
+ status: "409",
580
+ scimType: "invalidValue",
581
+ detail: "Operations[" + c + "] is part of an unresolvable circular bulkId reference",
582
+ };
583
+ }
584
+ }
585
+ return order;
586
+ }
587
+
588
+ // True when any of the bulkIds this operation references belongs to a
589
+ // creating operation that ran and FAILED (so no id was recorded in
590
+ // bulkIdMap). A still-pending dependency cannot occur here because the
591
+ // topological order guarantees dependencies execute first.
592
+ function _anyDependencyFailed(refs, plan, executed, bulkIdMap) {
593
+ for (var i = 0; i < refs.length; i++) {
594
+ var declIdx = refs[i];
595
+ var rec = executed[declIdx];
596
+ if (rec && rec.isError) return true;
597
+ // A successfully-created dependency records its id in bulkIdMap; if
598
+ // it ran without error but produced no id, it cannot satisfy a
599
+ // reference either.
600
+ var declOp = plan.ops[declIdx];
601
+ if (rec && !rec.isError && declOp.ownBulkId && bulkIdMap[declOp.ownBulkId] === undefined) {
602
+ return true;
603
+ }
604
+ }
605
+ return false;
606
+ }
607
+
359
608
  // RFC 7644 §3.7 — failOnErrors is an OPTIONAL integer >= 1. Absent /
360
609
  // non-conforming values mean "process every operation" (null).
361
610
  function _parseFailOnErrors(value) {
@@ -380,7 +629,19 @@ async function _runBulkOperation(op, index, opts, ctx, bulkIdMap) {
380
629
  "Operations[" + index + "].method '" + op.method + "' not in POST/PUT/PATCH/DELETE");
381
630
  }
382
631
 
383
- var parsed = _parseBulkPath(op.path);
632
+ // Resolve path bulkId references BEFORE parsing — the dependency-
633
+ // ordered executor guarantees a referenced creation already ran, so
634
+ // an unresolved token here is an unsatisfiable reference, failed
635
+ // per-op (RFC 7644 §3.7.2) rather than handed to the adapter.
636
+ var path = op.path;
637
+ if (typeof path === "string" && path.indexOf("bulkId:") !== -1) {
638
+ try { path = _resolvePathBulkIdRefs(path, bulkIdMap); }
639
+ catch (refErr) {
640
+ return _bulkErr(op, "400", "invalidValue",
641
+ "Operations[" + index + "] " + (refErr && refErr.message ? refErr.message : "has an unresolved bulkId reference in path"));
642
+ }
643
+ }
644
+ var parsed = _parseBulkPath(path);
384
645
  if (!parsed) {
385
646
  return _bulkErr(op, "400", "invalidValue",
386
647
  "Operations[" + index + "].path '" + String(op.path) + "' is not a valid bulk path");
@@ -402,8 +663,17 @@ async function _runBulkOperation(op, index, opts, ctx, bulkIdMap) {
402
663
  var data = op.data;
403
664
  if (method === "POST" || method === "PUT" || method === "PATCH") {
404
665
  // RFC 7644 §3.7.2 — substitute any bulkId cross-references that
405
- // earlier operations have resolved before handing data to the adapter.
406
- data = _resolveBulkIdRefs(op.data, bulkIdMap);
666
+ // earlier operations resolved before handing data to the adapter.
667
+ // The dependency-ordered executor guarantees every referenced
668
+ // operation ran first; an unresolved token here would mean an
669
+ // unsatisfiable reference, which is failed per-op rather than passed
670
+ // through to the adapter as a literal "bulkId:<id>" string.
671
+ try {
672
+ data = _resolveBulkIdRefs(op.data, bulkIdMap);
673
+ } catch (refErr) {
674
+ return _bulkErr(op, "400", "invalidValue",
675
+ "Operations[" + index + "] " + (refErr && refErr.message ? refErr.message : "has an unresolved bulkId reference"));
676
+ }
407
677
  }
408
678
 
409
679
  try {
@@ -462,7 +732,15 @@ function _resolveBulkIdRefs(value, bulkIdMap) {
462
732
  var ref = BULK_ID_REF_RE.exec(value);
463
733
  if (ref) {
464
734
  var resolved = bulkIdMap[ref[1]];
465
- return resolved !== undefined ? resolved : value;
735
+ // A literal "bulkId:<id>" token MUST never reach the adapter as a
736
+ // real id. The dependency-ordered executor resolves every
737
+ // reference before dispatch; an unresolved token here signals an
738
+ // unsatisfiable reference, surfaced as a per-op error by the caller.
739
+ if (resolved === undefined) {
740
+ throw new ScimServerError("middleware/scim-server/unresolved-bulkid",
741
+ "references unresolved bulkId '" + ref[1] + "'");
742
+ }
743
+ return resolved;
466
744
  }
467
745
  return value;
468
746
  }
@@ -34,6 +34,18 @@
34
34
  * dnsPrefetchControl: 'off' (default) or 'on' or false
35
35
  * csp: '<full CSP string>' or false to disable
36
36
  * }
37
+ *
38
+ * Monitor-mode opt-ins (all default-off; unset emits no new header):
39
+ *
40
+ * coopReportOnly / coepReportOnly / documentPolicyReportOnly — set a
41
+ * policy string to emit the matching `*-Report-Only` header so the
42
+ * operator can roll out the enforcing policy in monitor mode first.
43
+ * The browser reports violations (to a Reporting-Endpoints group named
44
+ * in the value, e.g. `same-origin; report-to="coop"`) without blocking.
45
+ * requireDocumentPolicy — the embedder-required Document-Policy a
46
+ * subframe must advertise before this document will embed it.
47
+ * serviceWorkerAllowed — broadens the max scope a service worker
48
+ * registered from this script may claim (the operator opts in).
37
49
  */
38
50
 
39
51
  var requestHelpers = require("../request-helpers");
@@ -186,6 +198,11 @@ function _validatePermissionsPolicy(value) {
186
198
  * criticalCh: string|false,
187
199
  * reportingEndpoints: object,
188
200
  * trustProxy: boolean|number,
201
+ * coopReportOnly: string, // default: off — monitor-mode COOP
202
+ * coepReportOnly: string, // default: off — monitor-mode COEP
203
+ * documentPolicyReportOnly: string, // default: off — monitor-mode Document-Policy
204
+ * requireDocumentPolicy: string, // default: off — embedder-required subframe policy
205
+ * serviceWorkerAllowed: string, // default: off — broadens SW registration scope
189
206
  * }
190
207
  *
191
208
  * @example
@@ -202,6 +219,8 @@ function create(opts) {
202
219
  "permissionsPolicy", "coop", "coep", "corp",
203
220
  "originAgentCluster", "dnsPrefetchControl", "csp", "trustProxy",
204
221
  "reportingEndpoints", "documentPolicy", "criticalCh", "acceptCh",
222
+ "coopReportOnly", "coepReportOnly", "documentPolicyReportOnly",
223
+ "requireDocumentPolicy", "serviceWorkerAllowed",
205
224
  ], "middleware.securityHeaders");
206
225
  if (opts.permissionsPolicy && typeof opts.permissionsPolicy === "string") {
207
226
  _validatePermissionsPolicy(opts.permissionsPolicy);
@@ -222,6 +241,26 @@ function create(opts) {
222
241
  var docPolicy = opts.documentPolicy === undefined ? DEFAULT_DOCUMENT_POLICY : opts.documentPolicy;
223
242
  var criticalCh = opts.criticalCh && typeof opts.criticalCh === "string" ? opts.criticalCh : false;
224
243
  var acceptCh = opts.acceptCh && typeof opts.acceptCh === "string" ? opts.acceptCh : false;
244
+ // Monitor-mode + scope opt-ins — all default-off. Each only emits its
245
+ // header when the operator passes a non-empty string; unset = silent.
246
+ // coopReportOnly / coepReportOnly — WHATWG HTML cross-origin isolation
247
+ // report-only variants: the UA evaluates the policy and reports
248
+ // violations to the named Reporting-Endpoints group without
249
+ // enforcing, so an operator can verify a same-origin / require-corp
250
+ // rollout won't break embeds before flipping the enforcing header.
251
+ // documentPolicyReportOnly — W3C Document Policy report-only variant
252
+ // (same monitor-mode semantics for the Document-Policy feature set).
253
+ // requireDocumentPolicy — W3C Document Policy: the policy a subframe
254
+ // must itself advertise (via Document-Policy) before this document
255
+ // will embed it; the embedder declares its floor.
256
+ // serviceWorkerAllowed — W3C Service Workers §Service-Worker-Allowed:
257
+ // widens the max scope a worker registered from this script may
258
+ // claim beyond the script's own path. Operator opts in explicitly.
259
+ var coopReportOnly = opts.coopReportOnly && typeof opts.coopReportOnly === "string" ? opts.coopReportOnly : false;
260
+ var coepReportOnly = opts.coepReportOnly && typeof opts.coepReportOnly === "string" ? opts.coepReportOnly : false;
261
+ var docPolicyReportOnly = opts.documentPolicyReportOnly && typeof opts.documentPolicyReportOnly === "string" ? opts.documentPolicyReportOnly : false;
262
+ var requireDocPolicy = opts.requireDocumentPolicy && typeof opts.requireDocumentPolicy === "string" ? opts.requireDocumentPolicy : false;
263
+ var serviceWorkerAllowed = opts.serviceWorkerAllowed && typeof opts.serviceWorkerAllowed === "string" ? opts.serviceWorkerAllowed : false;
225
264
  // Reporting-Endpoints (W3C Reporting API) — when operator passes a
226
265
  // map of endpoint-name → URL, we emit `Reporting-Endpoints: name="url",
227
266
  // name2="url2", ...` and (when default CSP is in force) append
@@ -273,6 +312,14 @@ function create(opts) {
273
312
  if (acceptCh) res.setHeader("Accept-CH", acceptCh);
274
313
  if (criticalCh) res.setHeader("Critical-CH", criticalCh);
275
314
  if (reportingEndpoints) res.setHeader("Reporting-Endpoints", reportingEndpoints);
315
+ // Monitor-mode + scope opt-ins — emitted only when the operator set
316
+ // the corresponding opt; the enforcing COOP/COEP/Document-Policy
317
+ // headers above are unaffected.
318
+ if (coopReportOnly) res.setHeader("Cross-Origin-Opener-Policy-Report-Only", coopReportOnly);
319
+ if (coepReportOnly) res.setHeader("Cross-Origin-Embedder-Policy-Report-Only", coepReportOnly);
320
+ if (docPolicyReportOnly) res.setHeader("Document-Policy-Report-Only", docPolicyReportOnly);
321
+ if (requireDocPolicy) res.setHeader("Require-Document-Policy", requireDocPolicy);
322
+ if (serviceWorkerAllowed) res.setHeader("Service-Worker-Allowed", serviceWorkerAllowed);
276
323
  next();
277
324
  };
278
325
  }
@@ -82,7 +82,6 @@ function _isoFuture(s) {
82
82
  * hiring: string,
83
83
  * canonical: string|string[],
84
84
  * alsoAtRoot: boolean,
85
- * audit: boolean,
86
85
  * }
87
86
  *
88
87
  * @example
@@ -99,7 +98,7 @@ function create(opts) {
99
98
  validateOpts(opts, [
100
99
  "contact", "expires", "encryption", "policy", "ack",
101
100
  "preferredLanguages", "hiring", "canonical",
102
- "alsoAtRoot", "audit",
101
+ "alsoAtRoot",
103
102
  ], "middleware.securityTxt");
104
103
 
105
104
  var contact = _arrayOfStrings(opts.contact, "contact");
@@ -123,7 +123,6 @@ function _wrapLogger(baseLogger, req, opts) {
123
123
  * logger: object, // required b.log instance
124
124
  * reqField: string, // default "log" → req.log
125
125
  * includeBaggage: boolean, // default true
126
- * audit: boolean,
127
126
  * }
128
127
  *
129
128
  * @example
@@ -138,7 +137,7 @@ function _wrapLogger(baseLogger, req, opts) {
138
137
  function create(opts) {
139
138
  validateOpts.requireObject(opts, "middleware.traceLogCorrelation", TraceLogError);
140
139
  validateOpts(opts, [
141
- "logger", "reqField", "includeBaggage", "audit",
140
+ "logger", "reqField", "includeBaggage",
142
141
  ], "middleware.traceLogCorrelation");
143
142
 
144
143
  if (!opts.logger || typeof opts.logger !== "object") {
@@ -21,7 +21,7 @@
21
21
  *
22
22
  * policy.tlsRpt.recordShape({
23
23
  * organization: "example.com",
24
- * reportingMta: "mx1.example.com",
24
+ * policies: [ ... ],
25
25
  * ...
26
26
  * }) → { ... RFC 8460 TLS-RPT JSON shape ... }
27
27
  *
@@ -519,8 +519,8 @@ function daneVerifyChain(certChain, tlsaRecords, opts) {
519
519
  function tlsRptRecordShape(opts) {
520
520
  opts = opts || {};
521
521
  validateOpts(opts, [
522
- "organization", "reportingMta", "contact",
523
- "datestart", "dateend", "policies",
522
+ "organization", "contact",
523
+ "datestart", "dateend", "policies", "reportId",
524
524
  ], "tlsRpt.recordShape");
525
525
 
526
526
  if (typeof opts.organization !== "string") {
@@ -637,7 +637,7 @@ async function tlsRptSubmit(report, opts) {
637
637
  "tlsRpt.submit: report must be an object");
638
638
  }
639
639
  opts = opts || {};
640
- validateOpts(opts, ["rua", "httpClient", "timeoutMs", "audit"], "tlsRpt.submit");
640
+ validateOpts(opts, ["rua", "httpClient", "timeoutMs"], "tlsRpt.submit");
641
641
  if (!Array.isArray(opts.rua) || opts.rua.length === 0) {
642
642
  throw new SmtpPolicyError("smtp/tls-rpt-bad-rua",
643
643
  "tlsRpt.submit: opts.rua must be a non-empty array of URIs");
@@ -418,7 +418,6 @@ function create(config) {
418
418
  "protocol", "region", "accessKeyId", "secretAccessKey", "sessionToken",
419
419
  "endpoint", "pathStyle", "forcePathStyle",
420
420
  "allowedProtocols", "allowInternal", "timeoutMs",
421
- "ca",
422
421
  "audit", "observability", "auditSuccess", "auditFailures",
423
422
  ], "bucketOps");
424
423
  if (config.protocol && config.protocol !== "sigv4") {
@@ -464,7 +463,17 @@ function create(config) {
464
463
  }
465
464
 
466
465
  function _actor(callerOpts) {
467
- return requestHelpers.resolveActorWithOverride(callerOpts || {}, null);
466
+ // `req` resolves IP / user-agent / userId from the live request;
467
+ // `actor` is an explicit override bag (e.g. { userId: "ops-admin" })
468
+ // for callers that perform a compliance-sensitive bucket change on
469
+ // behalf of an operator and want that identity on the audit row.
470
+ // Passed as the override seed: explicit `actor` fields win over the
471
+ // request-derived ones, while request-derived fields fill any key the
472
+ // operator left unset.
473
+ var seed = (callerOpts && callerOpts.actor && typeof callerOpts.actor === "object")
474
+ ? callerOpts.actor
475
+ : null;
476
+ return requestHelpers.resolveActorWithOverride(callerOpts || {}, seed);
468
477
  }
469
478
 
470
479
  // S3 subresource queries (`?lifecycle`, `?cors`, `?object-lock`,
@@ -156,7 +156,7 @@ function create(opts) {
156
156
  validateOpts(opts, [
157
157
  "service", "resource", "scope",
158
158
  "maxAttributes", "maxEvents", "maxAttributeValueLength",
159
- "onEnd", "onStart", "audit",
159
+ "onEnd", "onStart",
160
160
  ], "tracer.create");
161
161
  validateOpts.requireNonEmptyString(opts.service,
162
162
  "tracer.create: service", TracerError, "tracer/bad-service");
@@ -309,7 +309,12 @@ function timed(name, fn, labels) {
309
309
  // pass attribute keys that should match the keys below. The map is
310
310
  // frozen — adding a new attribute requires a release.
311
311
  //
312
- // Reference: https://opentelemetry.io/docs/specs/semconv/general/attributes/
312
+ // References:
313
+ // https://opentelemetry.io/docs/specs/semconv/general/attributes/
314
+ // https://opentelemetry.io/docs/specs/semconv/resource/ (resource,
315
+ // telemetry-sdk, deployment-environment)
316
+ // https://opentelemetry.io/docs/specs/semconv/resource/k8s/
317
+ // https://opentelemetry.io/docs/specs/semconv/resource/faas/
313
318
  var SEMCONV = Object.freeze({
314
319
  // HTTP server (stable per OTel semconv)
315
320
  HTTP_REQUEST_METHOD: "http.request.method",
@@ -370,10 +375,33 @@ var SEMCONV = Object.freeze({
370
375
  SERVICE_NAME: "service.name",
371
376
  SERVICE_VERSION: "service.version",
372
377
  SERVICE_INSTANCE_ID: "service.instance.id",
378
+ // peer.service — logical name of the remote service a span talks to,
379
+ // distinct from server.address (the host). OTel semconv (general).
380
+ PEER_SERVICE: "peer.service",
381
+ // Deployment environment (aka deployment tier: "production",
382
+ // "staging"). The bare `deployment.environment` key was deprecated in
383
+ // favour of `deployment.environment.name`; this carries the current
384
+ // stable key. OTel semconv resource/deployment-environment.
385
+ DEPLOYMENT_ENVIRONMENT_NAME: "deployment.environment.name",
373
386
  // Telemetry SDK self-identification
374
387
  TELEMETRY_SDK_NAME: "telemetry.sdk.name",
375
388
  TELEMETRY_SDK_LANGUAGE: "telemetry.sdk.language",
376
389
  TELEMETRY_SDK_VERSION: "telemetry.sdk.version",
390
+ // Telemetry distribution self-identification — the redistribution of
391
+ // an OTel SDK an operator runs (e.g. a vendor distro). OTel semconv
392
+ // resource/telemetry-sdk.
393
+ TELEMETRY_DISTRO_NAME: "telemetry.distro.name",
394
+ TELEMETRY_DISTRO_VERSION: "telemetry.distro.version",
395
+ // Instrumentation scope self-identification — the scope (library)
396
+ // that produced a span/metric. OTel semconv otel namespace.
397
+ OTEL_SCOPE_NAME: "otel.scope.name",
398
+ OTEL_SCOPE_VERSION: "otel.scope.version",
399
+ // FaaS (serverless) — function-as-a-service execution context. OTel
400
+ // semconv resource/faas + attributes-registry/faas.
401
+ FAAS_NAME: "faas.name",
402
+ FAAS_VERSION: "faas.version",
403
+ FAAS_INSTANCE: "faas.instance",
404
+ FAAS_TRIGGER: "faas.trigger",
377
405
  // GenAI — OpenTelemetry semantic conventions for generative AI
378
406
  // workloads (LLM clients, vector DB queries, agent frameworks).
379
407
  // Tracking the otel-spec experimental namespace; covers the stable
@@ -410,9 +438,19 @@ var SEMCONV = Object.freeze({
410
438
  CONTAINER_ID: "container.id",
411
439
  CONTAINER_IMAGE_NAME: "container.image.name",
412
440
  CONTAINER_IMAGE_TAG: "container.image.tag",
441
+ // Kubernetes — OTel semconv resource/k8s. Namespace / pod /
442
+ // deployment plus the surrounding workload + node + cluster context.
413
443
  K8S_NAMESPACE_NAME: "k8s.namespace.name",
414
444
  K8S_POD_NAME: "k8s.pod.name",
415
445
  K8S_DEPLOYMENT_NAME: "k8s.deployment.name",
446
+ K8S_NODE_NAME: "k8s.node.name",
447
+ K8S_CLUSTER_NAME: "k8s.cluster.name",
448
+ K8S_CONTAINER_NAME: "k8s.container.name",
449
+ K8S_STATEFULSET_NAME: "k8s.statefulset.name",
450
+ K8S_DAEMONSET_NAME: "k8s.daemonset.name",
451
+ K8S_JOB_NAME: "k8s.job.name",
452
+ K8S_CRONJOB_NAME: "k8s.cronjob.name",
453
+ K8S_REPLICASET_NAME: "k8s.replicaset.name",
416
454
  });
417
455
 
418
456
  // W3C Trace Context — parse / build the `traceparent` HTTP header