@blamejs/core 0.14.27 → 0.15.1

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 (134) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +2 -2
  3. package/index.js +4 -0
  4. package/lib/ai-content-detect.js +9 -10
  5. package/lib/api-key.js +158 -77
  6. package/lib/atomic-file.js +29 -1
  7. package/lib/audit-chain.js +47 -11
  8. package/lib/audit-sign.js +77 -2
  9. package/lib/audit-tools.js +79 -51
  10. package/lib/audit.js +228 -100
  11. package/lib/backup/index.js +13 -10
  12. package/lib/break-glass.js +202 -144
  13. package/lib/cache.js +174 -105
  14. package/lib/chain-writer.js +38 -16
  15. package/lib/cli.js +19 -14
  16. package/lib/cluster-provider-db.js +130 -104
  17. package/lib/cluster-storage.js +119 -22
  18. package/lib/cluster.js +119 -71
  19. package/lib/compliance.js +22 -0
  20. package/lib/consent.js +82 -29
  21. package/lib/constants.js +16 -11
  22. package/lib/crypto-field.js +387 -91
  23. package/lib/db-declare-row-policy.js +35 -22
  24. package/lib/db-file-lifecycle.js +3 -2
  25. package/lib/db-query.js +517 -256
  26. package/lib/db-schema.js +209 -44
  27. package/lib/db.js +202 -95
  28. package/lib/external-db-migrate.js +229 -139
  29. package/lib/external-db.js +25 -15
  30. package/lib/framework-error.js +11 -0
  31. package/lib/framework-files.js +73 -0
  32. package/lib/framework-schema.js +695 -394
  33. package/lib/gate-contract.js +596 -1
  34. package/lib/guard-agent-registry.js +26 -44
  35. package/lib/guard-all.js +1 -0
  36. package/lib/guard-auth.js +42 -112
  37. package/lib/guard-cidr.js +33 -154
  38. package/lib/guard-csv.js +46 -113
  39. package/lib/guard-domain.js +34 -157
  40. package/lib/guard-dsn.js +27 -43
  41. package/lib/guard-email.js +47 -69
  42. package/lib/guard-envelope.js +19 -32
  43. package/lib/guard-event-bus-payload.js +24 -42
  44. package/lib/guard-event-bus-topic.js +25 -43
  45. package/lib/guard-filename.js +42 -106
  46. package/lib/guard-graphql.js +42 -123
  47. package/lib/guard-html.js +53 -108
  48. package/lib/guard-idempotency-key.js +24 -42
  49. package/lib/guard-image.js +46 -103
  50. package/lib/guard-imap-command.js +18 -32
  51. package/lib/guard-jmap.js +16 -30
  52. package/lib/guard-json.js +38 -108
  53. package/lib/guard-jsonpath.js +38 -171
  54. package/lib/guard-jwt.js +49 -179
  55. package/lib/guard-list-id.js +25 -41
  56. package/lib/guard-list-unsubscribe.js +27 -43
  57. package/lib/guard-mail-compose.js +24 -42
  58. package/lib/guard-mail-move.js +26 -44
  59. package/lib/guard-mail-query.js +28 -46
  60. package/lib/guard-mail-reply.js +24 -42
  61. package/lib/guard-mail-sieve.js +24 -42
  62. package/lib/guard-managesieve-command.js +17 -31
  63. package/lib/guard-markdown.js +37 -104
  64. package/lib/guard-message-id.js +26 -45
  65. package/lib/guard-mime.js +39 -151
  66. package/lib/guard-oauth.js +54 -135
  67. package/lib/guard-pdf.js +45 -101
  68. package/lib/guard-pop3-command.js +21 -31
  69. package/lib/guard-posture-chain.js +24 -42
  70. package/lib/guard-regex.js +33 -107
  71. package/lib/guard-saga-config.js +24 -42
  72. package/lib/guard-shell.js +42 -172
  73. package/lib/guard-smtp-command.js +48 -54
  74. package/lib/guard-snapshot-envelope.js +24 -42
  75. package/lib/guard-sql.js +1491 -0
  76. package/lib/guard-stream-args.js +24 -43
  77. package/lib/guard-svg.js +47 -65
  78. package/lib/guard-template.js +35 -172
  79. package/lib/guard-tenant-id.js +26 -45
  80. package/lib/guard-time.js +32 -154
  81. package/lib/guard-trace-context.js +25 -44
  82. package/lib/guard-uuid.js +32 -153
  83. package/lib/guard-xml.js +38 -113
  84. package/lib/guard-yaml.js +51 -163
  85. package/lib/http-client.js +14 -0
  86. package/lib/inbox.js +120 -107
  87. package/lib/legal-hold.js +107 -50
  88. package/lib/log-stream-cloudwatch.js +47 -31
  89. package/lib/log-stream-otlp.js +32 -18
  90. package/lib/mail-crypto-smime.js +2 -6
  91. package/lib/mail-greylist.js +2 -6
  92. package/lib/mail-helo.js +2 -6
  93. package/lib/mail-journal.js +85 -64
  94. package/lib/mail-rbl.js +2 -6
  95. package/lib/mail-scan.js +2 -6
  96. package/lib/mail-spam-score.js +2 -6
  97. package/lib/mail-store.js +293 -154
  98. package/lib/middleware/fetch-metadata.js +17 -7
  99. package/lib/middleware/idempotency-key.js +54 -38
  100. package/lib/middleware/rate-limit.js +102 -32
  101. package/lib/middleware/security-headers.js +21 -5
  102. package/lib/migrations.js +108 -66
  103. package/lib/network-heartbeat.js +7 -0
  104. package/lib/nonce-store.js +31 -9
  105. package/lib/object-store/azure-blob-bucket-ops.js +9 -4
  106. package/lib/object-store/azure-blob.js +31 -3
  107. package/lib/object-store/sigv4.js +10 -0
  108. package/lib/outbox.js +136 -82
  109. package/lib/pqc-agent.js +44 -0
  110. package/lib/pubsub-cluster.js +42 -20
  111. package/lib/queue-local.js +202 -139
  112. package/lib/queue-redis.js +9 -1
  113. package/lib/queue-sqs.js +6 -0
  114. package/lib/retention.js +82 -39
  115. package/lib/safe-dns.js +29 -45
  116. package/lib/safe-ical.js +18 -33
  117. package/lib/safe-icap.js +27 -43
  118. package/lib/safe-sieve.js +21 -40
  119. package/lib/safe-sql.js +124 -3
  120. package/lib/safe-vcard.js +18 -33
  121. package/lib/scheduler.js +35 -12
  122. package/lib/seeders.js +122 -74
  123. package/lib/session-stores.js +42 -14
  124. package/lib/session.js +116 -72
  125. package/lib/sql.js +3885 -0
  126. package/lib/static.js +45 -7
  127. package/lib/subject.js +89 -49
  128. package/lib/vault/index.js +3 -2
  129. package/lib/vault/passphrase-ops.js +3 -2
  130. package/lib/vault/rotate.js +104 -64
  131. package/lib/vendor-data.js +2 -0
  132. package/lib/websocket.js +16 -0
  133. package/package.json +1 -1
  134. package/sbom.cdx.json +6 -6
@@ -20,6 +20,7 @@
20
20
  */
21
21
 
22
22
  var { defineClass } = require("./framework-error");
23
+ var gateContract = require("./gate-contract");
23
24
 
24
25
  var GuardStreamArgsError = defineClass("GuardStreamArgsError", { alwaysPermanent: true });
25
26
 
@@ -31,11 +32,14 @@ var PROFILES = Object.freeze({
31
32
  permissive: { maxBatchSize: 16384, minBatchSize: 1, maxOpenStreams: 64 },
32
33
  });
33
34
 
34
- var COMPLIANCE_POSTURES = Object.freeze({
35
- hipaa: "strict",
36
- "pci-dss": "strict",
37
- gdpr: "strict",
38
- soc2: "strict",
35
+ var COMPLIANCE_POSTURES = gateContract.ALL_STRICT_POSTURES;
36
+
37
+ var _resolveProfile = gateContract.makeProfileResolver({
38
+ profiles: PROFILES,
39
+ postures: COMPLIANCE_POSTURES,
40
+ defaults: DEFAULT_PROFILE,
41
+ errorClass: GuardStreamArgsError,
42
+ codePrefix: "stream-args",
39
43
  });
40
44
 
41
45
  /**
@@ -90,23 +94,6 @@ function validate(args, opts) {
90
94
  return args;
91
95
  }
92
96
 
93
- /**
94
- * @primitive b.guardStreamArgs.compliancePosture
95
- * @signature b.guardStreamArgs.compliancePosture(posture)
96
- * @since 0.9.24
97
- * @status stable
98
- *
99
- * Return the effective profile for a given compliance posture name.
100
- * Returns `null` for unknown posture names so operator typos surface
101
- * here instead of silently falling through to the default profile.
102
- *
103
- * @example
104
- * b.guardStreamArgs.compliancePosture("hipaa"); // → "strict"
105
- */
106
- function compliancePosture(posture) {
107
- return COMPLIANCE_POSTURES[posture] || null;
108
- }
109
-
110
97
  function _checkCursorOpts(cursorOpts, depth) {
111
98
  depth = depth || 0;
112
99
  if (depth > 8) { // recursion depth cap
@@ -143,24 +130,18 @@ function _checkCursorOpts(cursorOpts, depth) {
143
130
  }
144
131
  }
145
132
 
146
- function _resolveProfile(opts) {
147
- if (opts.posture && COMPLIANCE_POSTURES[opts.posture]) {
148
- return COMPLIANCE_POSTURES[opts.posture];
149
- }
150
- var p = opts.profile || DEFAULT_PROFILE;
151
- if (!PROFILES[p]) {
152
- throw new GuardStreamArgsError("stream-args/bad-profile",
153
- "guardStreamArgs: unknown profile '" + p + "'");
154
- }
155
- return p;
156
- }
157
-
158
- module.exports = {
159
- validate: validate,
160
- compliancePosture: compliancePosture,
161
- PROFILES: PROFILES,
162
- COMPLIANCE_POSTURES: COMPLIANCE_POSTURES,
163
- GuardStreamArgsError: GuardStreamArgsError,
164
- NAME: "streamArgs",
165
- KIND: "stream-args",
166
- };
133
+ // compliancePosture is assembled by gateContract.defineParser below; its
134
+ // wiki section renders from the single-sourced @abiTemplate (defineParser)
135
+ // block in gate-contract.js, instantiated for this guard by the page
136
+ // generator.
137
+ module.exports = gateContract.defineParser({
138
+ name: "stream-args",
139
+ entry: validate,
140
+ errorClass: GuardStreamArgsError,
141
+ profiles: PROFILES,
142
+ postures: COMPLIANCE_POSTURES,
143
+ extra: {
144
+ NAME: "streamArgs",
145
+ KIND: "stream-args",
146
+ },
147
+ });
package/lib/guard-svg.js CHANGED
@@ -1093,71 +1093,53 @@ function gate(opts) {
1093
1093
  });
1094
1094
  }
1095
1095
 
1096
- var buildProfile = gateContract.makeProfileBuilder(PROFILES);
1097
-
1098
- /**
1099
- * @primitive b.guardSvg.compliancePosture
1100
- * @signature b.guardSvg.compliancePosture(name)
1101
- * @since 0.7.7
1102
- * @status stable
1103
- * @compliance hipaa, pci-dss, gdpr, soc2
1104
- * @related b.guardSvg.gate, b.compliance.set
1105
- *
1106
- * Look up a regulatory-posture override. Returns a shallow clone
1107
- * of the named posture's option overlay; throws
1108
- * `GuardSvgError` (`svg.bad-posture`) on unknown names. Operators
1109
- * pass it through `gate({ compliancePosture: "hipaa" })` rather
1110
- * than calling this directly — exposed for introspection and
1111
- * audit-evidence collection.
1112
- *
1113
- * @example
1114
- * var hipaa = b.guardSvg.compliancePosture("hipaa");
1115
- * hipaa.bidiPolicy; // → "reject"
1116
- * hipaa.allowExternalRefs; // → false
1117
- * hipaa.allowAnimation; // → false
1118
- */
1119
- function compliancePosture(name) {
1120
- return gateContract.lookupCompliancePosture(name, COMPLIANCE_POSTURES, _err, "svg");
1121
- }
1122
-
1123
- var _svgRulePacks = gateContract.makeRulePackLoader(GuardSvgError, "svg");
1124
- var loadRulePack = _svgRulePacks.load;
1096
+ // buildProfile / compliancePosture / loadRulePack are assembled by
1097
+ // gateContract.defineGuard below (makeProfileBuilder(PROFILES) /
1098
+ // lookupCompliancePosture(_, COMPLIANCE_POSTURES) / makeRulePackLoader).
1099
+ // Their wiki sections render from the single-sourced @abiTemplate blocks
1100
+ // in gate-contract.js, instantiated per guard by the page generator.
1125
1101
 
1126
1102
  void safeUrl;
1127
1103
 
1128
- module.exports = {
1129
- // ---- guard-* family registry exports ----
1130
- NAME: "svg",
1131
- KIND: "content",
1132
- MIME_TYPES: Object.freeze(["image/svg+xml"]),
1133
- EXTENSIONS: Object.freeze([".svg", ".svgz"]),
1134
- INTEGRATION_FIXTURES: Object.freeze({
1135
- kind: "content",
1136
- contentType: "image/svg+xml",
1137
- extension: ".svg",
1138
- benignBytes: Buffer.from('<svg><circle r="10"/></svg>', "utf8"),
1139
- // Hostile: <script> inside SVG; refused regardless of profile.
1140
- hostileBytes: Buffer.from('<svg><script>alert(1)</script></svg>', "utf8"),
1141
- }),
1142
- // ---- primitive surface ----
1143
- validate: validate,
1144
- sanitize: sanitize,
1145
- gate: gate,
1146
- buildProfile: buildProfile,
1147
- compliancePosture: compliancePosture,
1148
- loadRulePack: loadRulePack,
1149
- PROFILES: PROFILES,
1150
- DEFAULTS: DEFAULTS,
1151
- COMPLIANCE_POSTURES: COMPLIANCE_POSTURES,
1152
- DANGEROUS_TAGS: DANGEROUS_TAGS,
1153
- ANIMATION_TAGS: ANIMATION_TAGS,
1154
- ANIMATION_SAFE_TARGETS: ANIMATION_SAFE_TARGETS,
1155
- STRICT_ALLOWED_TAGS: STRICT_ALLOWED_TAGS,
1156
- BALANCED_ALLOWED_TAGS: BALANCED_ALLOWED_TAGS,
1157
- PERMISSIVE_ALLOWED_TAGS: PERMISSIVE_ALLOWED_TAGS,
1158
- DANGEROUS_ATTRS: DANGEROUS_ATTRS,
1159
- URL_ATTRS: URL_ATTRS,
1160
- SAFE_SCHEMES: SAFE_SCHEMES,
1161
- DANGEROUS_SCHEMES: DANGEROUS_SCHEMES,
1162
- GuardSvgError: GuardSvgError,
1163
- };
1104
+ // ---- adaptive integration-test fixtures (consumed by layer-5 host harness) ----
1105
+ var INTEGRATION_FIXTURES = Object.freeze({
1106
+ kind: "content",
1107
+ contentType: "image/svg+xml",
1108
+ extension: ".svg",
1109
+ benignBytes: Buffer.from('<svg><circle r="10"/></svg>', "utf8"),
1110
+ // Hostile: <script> inside SVG; refused regardless of profile.
1111
+ hostileBytes: Buffer.from('<svg><script>alert(1)</script></svg>', "utf8"),
1112
+ });
1113
+
1114
+ // Assembled from the gate-contract guard factory: error class, registry
1115
+ // exports (NAME / KIND / MIME_TYPES / EXTENSIONS / INTEGRATION_FIXTURES),
1116
+ // buildProfile / compliancePosture / loadRulePack wiring, plus the
1117
+ // per-guard inspection surface (validate / sanitize / gate) and the SVG
1118
+ // tag / scheme tables passed through verbatim. The bespoke `gate` carries
1119
+ // SVG's sanitize-reserialize chain and SVGZ refuse unchanged.
1120
+ module.exports = gateContract.defineGuard({
1121
+ name: "svg",
1122
+ kind: "content",
1123
+ errorClass: GuardSvgError,
1124
+ profiles: PROFILES,
1125
+ defaults: DEFAULTS,
1126
+ postures: COMPLIANCE_POSTURES,
1127
+ mimeTypes: ["image/svg+xml"],
1128
+ extensions: [".svg", ".svgz"],
1129
+ integrationFixtures: INTEGRATION_FIXTURES,
1130
+ validate: validate,
1131
+ sanitize: sanitize,
1132
+ gate: gate,
1133
+ extra: {
1134
+ DANGEROUS_TAGS: DANGEROUS_TAGS,
1135
+ ANIMATION_TAGS: ANIMATION_TAGS,
1136
+ ANIMATION_SAFE_TARGETS: ANIMATION_SAFE_TARGETS,
1137
+ STRICT_ALLOWED_TAGS: STRICT_ALLOWED_TAGS,
1138
+ BALANCED_ALLOWED_TAGS: BALANCED_ALLOWED_TAGS,
1139
+ PERMISSIVE_ALLOWED_TAGS: PERMISSIVE_ALLOWED_TAGS,
1140
+ DANGEROUS_ATTRS: DANGEROUS_ATTRS,
1141
+ URL_ATTRS: URL_ATTRS,
1142
+ SAFE_SCHEMES: SAFE_SCHEMES,
1143
+ DANGEROUS_SCHEMES: DANGEROUS_SCHEMES,
1144
+ },
1145
+ });
@@ -311,180 +311,43 @@ function sanitize(input, opts) {
311
311
  throw _err("template.bad-input", "sanitize requires string input");
312
312
  }
313
313
  var issues = _detectIssues(input, opts);
314
- for (var i = 0; i < issues.length; i += 1) {
315
- if (issues[i].severity === "critical" || issues[i].severity === "high") {
316
- throw _err(issues[i].ruleId || "template.refused",
317
- "guardTemplate.sanitize: " + issues[i].snippet);
318
- }
319
- }
314
+ gateContract.throwOnRefusalSeverity(issues, { errorClass: GuardTemplateError, codePrefix: "template" });
320
315
  return input;
321
316
  }
322
317
 
323
- /**
324
- * @primitive b.guardTemplate.gate
325
- * @signature b.guardTemplate.gate(opts)
326
- * @since 0.7.13
327
- * @status stable
328
- * @compliance hipaa, pci-dss, gdpr, soc2
329
- * @related b.guardTemplate.validate, b.guardTemplate.sanitize
330
- *
331
- * Build a `b.gateContract` gate that screens `ctx.identifier` (or
332
- * `ctx.text`) before any template engine renders the input.
333
- * Action chain: `serve` (no issues) → `audit-only` (warn-only) →
334
- * `refuse` (any `critical` or `high`). No `sanitize` action —
335
- * template input cannot be repaired. Compose into form handlers /
336
- * comment renderers / model fields fed to Mustache / Handlebars /
337
- * Liquid so operator-untrusted strings never reach the rendering
338
- * engine carrying engine syntax.
339
- *
340
- * @opts
341
- * profile: "strict"|"balanced"|"permissive",
342
- * compliancePosture: "hipaa"|"pci-dss"|"gdpr"|"soc2",
343
- * name: string, // override gate name in audit emissions
344
- * jinjaPolicy: "reject"|"audit"|"allow",
345
- * erbPolicy: "reject"|"audit"|"allow",
346
- * pugPolicy: "reject"|"audit"|"allow",
347
- * dollarBracePolicy: "reject"|"audit"|"allow",
348
- * velocityDirectivePolicy: "reject"|"audit"|"allow",
349
- * maxBytes: number,
350
- *
351
- * @example
352
- * var gate = b.guardTemplate.gate({ profile: "strict" });
353
- *
354
- * gate({ identifier: "Hello {{7*7}}" }).then(function (rv) {
355
- * rv.ok; // → false
356
- * rv.action; // → "refuse"
357
- * });
358
- *
359
- * gate({ identifier: "Hello world" }).then(function (rv) {
360
- * rv.action; // → "serve"
361
- * });
362
- */
363
- function gate(opts) {
364
- opts = _resolveOpts(opts);
365
- return gateContract.buildGuardGate(
366
- opts.name || "guardTemplate:" + (opts.profile || "default"),
367
- opts,
368
- async function (ctx) {
369
- var text = ctx && (ctx.identifier || ctx.text);
370
- if (text === undefined || text === null) {
371
- return { ok: true, action: "serve" };
372
- }
373
- var rv = validate(text, opts);
374
- if (rv.issues.length === 0) return { ok: true, action: "serve" };
375
- var hasCritical = rv.issues.some(function (i) {
376
- return i.severity === "critical";
377
- });
378
- var hasHigh = rv.issues.some(function (i) {
379
- return i.severity === "high";
380
- });
381
- if (!hasCritical && !hasHigh) {
382
- return { ok: true, action: "audit-only", issues: rv.issues };
383
- }
384
- return { ok: false, action: "refuse", issues: rv.issues };
385
- });
386
- }
318
+ // gate / buildProfile / compliancePosture / loadRulePack are assembled by
319
+ // gateContract.defineGuard below. The gate is the standard
320
+ // serve -> audit-only -> refuse chain (template input cannot be repaired, so
321
+ // there is no sanitize action), dispatched to ctx.identifier || ctx.text via
322
+ // the spec's ctxFields. Its wiki section renders from the single-sourced
323
+ // @abiTemplate (defineGuard) blocks in gate-contract.js, instantiated per
324
+ // guard by the page generator.
387
325
 
388
- /**
389
- * @primitive b.guardTemplate.buildProfile
390
- * @signature b.guardTemplate.buildProfile(opts)
391
- * @since 0.7.13
392
- * @status stable
393
- * @related b.guardTemplate.gate, b.guardTemplate.compliancePosture
394
- *
395
- * Compose a derived guardTemplate profile from one or more named
396
- * bases plus inline overrides. `opts.extends` is a profile name
397
- * (`"strict"` / `"balanced"` / `"permissive"`) or an array of
398
- * names; later entries shadow earlier ones. Inline `opts` keys win
399
- * last. Used to keep operator-defined profiles traceable to a
400
- * baseline rather than re-typing every key.
401
- *
402
- * @opts
403
- * extends: string|string[], // base profile name(s) to compose
404
- * ...: any guardTemplate key, // inline override of resolved keys
405
- *
406
- * @example
407
- * var custom = b.guardTemplate.buildProfile({
408
- * extends: "balanced",
409
- * dollarBracePolicy: "reject",
410
- * });
411
- * custom.dollarBracePolicy; // → "reject"
412
- * custom.jinjaPolicy; // → "reject"
413
- */
414
- var buildProfile = gateContract.makeProfileBuilder(PROFILES);
415
-
416
- /**
417
- * @primitive b.guardTemplate.compliancePosture
418
- * @signature b.guardTemplate.compliancePosture(name)
419
- * @since 0.7.13
420
- * @status stable
421
- * @compliance hipaa, pci-dss, gdpr, soc2
422
- * @related b.guardTemplate.gate, b.guardTemplate.buildProfile
423
- *
424
- * Look up a compliance-posture overlay by name (`"hipaa"` /
425
- * `"pci-dss"` / `"gdpr"` / `"soc2"`). Returns a shallow clone of
426
- * the posture object — the caller may mutate freely. Throws
427
- * `GuardTemplateError("template.bad-posture")` on unknown name.
428
- *
429
- * @example
430
- * var posture = b.guardTemplate.compliancePosture("hipaa");
431
- * posture.jinjaPolicy; // → "reject"
432
- * posture.forensicSnippetBytes; // → 512
433
- */
434
- function compliancePosture(name) {
435
- return gateContract.lookupCompliancePosture(name, COMPLIANCE_POSTURES,
436
- _err, "template");
437
- }
438
-
439
- var _tplRulePacks = gateContract.makeRulePackLoader(GuardTemplateError, "template");
440
- /**
441
- * @primitive b.guardTemplate.loadRulePack
442
- * @signature b.guardTemplate.loadRulePack(pack)
443
- * @since 0.7.13
444
- * @status stable
445
- * @related b.guardTemplate.gate
446
- *
447
- * Register an operator-supplied rule pack with the guardTemplate
448
- * registry. The pack is identified by `pack.id` (non-empty string)
449
- * and stored for later inspection / dispatch by gates that opt in
450
- * via `opts.rulePackId`. Returns the pack object unchanged on
451
- * success; throws `GuardTemplateError("template.bad-opt")` when
452
- * `pack` is missing or `pack.id` is not a non-empty string.
453
- *
454
- * @example
455
- * var pack = b.guardTemplate.loadRulePack({
456
- * id: "no-prototype-keys",
457
- * rules: [
458
- * { id: "proto-key", severity: "critical",
459
- * detect: function (text) { return /__proto__|constructor/.test(text); },
460
- * reason: "input references prototype-pollution sink" },
461
- * ],
462
- * });
463
- * pack.id; // → "no-prototype-keys"
464
- */
465
- var loadRulePack = _tplRulePacks.load;
326
+ var INTEGRATION_FIXTURES = Object.freeze({
327
+ kind: "identifier",
328
+ benignBytes: Buffer.from("Hello world", "utf8"),
329
+ hostileBytes: Buffer.from("Hello {{7*7}}", "utf8"),
330
+ benignIdentifier: "Hello world",
331
+ // Hostile: Jinja-shape SSTI probe.
332
+ hostileIdentifier: "Hello {{7*7}}",
333
+ });
466
334
 
467
- module.exports = {
468
- // ---- guard-* family registry exports ----
469
- NAME: "template",
470
- KIND: "identifier",
471
- INTEGRATION_FIXTURES: Object.freeze({
472
- kind: "identifier",
473
- benignBytes: Buffer.from("Hello world", "utf8"),
474
- hostileBytes: Buffer.from("Hello {{7*7}}", "utf8"),
475
- benignIdentifier: "Hello world",
476
- // Hostile: Jinja-shape SSTI probe.
477
- hostileIdentifier: "Hello {{7*7}}",
478
- }),
479
- // ---- primitive surface ----
480
- validate: validate,
481
- sanitize: sanitize,
482
- gate: gate,
483
- buildProfile: buildProfile,
484
- compliancePosture: compliancePosture,
485
- loadRulePack: loadRulePack,
486
- PROFILES: PROFILES,
487
- DEFAULTS: DEFAULTS,
488
- COMPLIANCE_POSTURES: COMPLIANCE_POSTURES,
489
- GuardTemplateError: GuardTemplateError,
490
- };
335
+ // Assembled from the gate-contract guard factory: error class, registry
336
+ // exports (NAME / KIND / INTEGRATION_FIXTURES), the default gate, buildProfile
337
+ // / compliancePosture / loadRulePack wiring, plus the per-guard inspection
338
+ // surface (validate / sanitize) passed through verbatim. The gate is the
339
+ // factory default serve -> audit-only -> refuse chain; ctxFields names the
340
+ // ctx fields it reads (ctx.identifier, then ctx.text) so untrusted strings on
341
+ // either field reach the SSTI validator before any engine renders them.
342
+ module.exports = gateContract.defineGuard({
343
+ name: "template",
344
+ kind: "identifier",
345
+ errorClass: GuardTemplateError,
346
+ profiles: PROFILES,
347
+ defaults: DEFAULTS,
348
+ postures: COMPLIANCE_POSTURES,
349
+ integrationFixtures: INTEGRATION_FIXTURES,
350
+ validate: validate,
351
+ sanitize: sanitize,
352
+ ctxFields: ["identifier", "text"],
353
+ });
@@ -23,6 +23,7 @@
23
23
  */
24
24
 
25
25
  var { defineClass } = require("./framework-error");
26
+ var gateContract = require("./gate-contract");
26
27
 
27
28
  var GuardTenantIdError = defineClass("GuardTenantIdError", { alwaysPermanent: true });
28
29
 
@@ -34,15 +35,18 @@ var PROFILES = Object.freeze({
34
35
  permissive: { maxBytes: 512 },
35
36
  });
36
37
 
37
- var COMPLIANCE_POSTURES = Object.freeze({
38
- hipaa: "strict",
39
- "pci-dss": "strict",
40
- gdpr: "strict",
41
- soc2: "strict",
42
- });
38
+ var COMPLIANCE_POSTURES = gateContract.ALL_STRICT_POSTURES;
43
39
 
44
40
  var RESERVED = Object.freeze({ "ROOT": true, "FRAMEWORK": true, "*": true });
45
41
 
42
+ var _resolveProfile = gateContract.makeProfileResolver({
43
+ profiles: PROFILES,
44
+ postures: COMPLIANCE_POSTURES,
45
+ defaults: DEFAULT_PROFILE,
46
+ errorClass: GuardTenantIdError,
47
+ codePrefix: "tenant-id",
48
+ });
49
+
46
50
  /**
47
51
  * @primitive b.guardTenantId.validate
48
52
  * @signature b.guardTenantId.validate(tenantId, opts?)
@@ -97,42 +101,19 @@ function validate(tenantId, opts) {
97
101
  return tenantId;
98
102
  }
99
103
 
100
- /**
101
- * @primitive b.guardTenantId.compliancePosture
102
- * @signature b.guardTenantId.compliancePosture(posture)
103
- * @since 0.9.26
104
- * @status stable
105
- *
106
- * Return the effective profile for a given compliance posture name.
107
- * Returns `null` for unknown posture names so operator typos surface
108
- * here instead of silently falling through to the default profile.
109
- *
110
- * @example
111
- * b.guardTenantId.compliancePosture("hipaa"); // → "strict"
112
- */
113
- function compliancePosture(posture) {
114
- return COMPLIANCE_POSTURES[posture] || null;
115
- }
116
-
117
- function _resolveProfile(opts) {
118
- if (opts.posture && COMPLIANCE_POSTURES[opts.posture]) {
119
- return COMPLIANCE_POSTURES[opts.posture];
120
- }
121
- var p = opts.profile || DEFAULT_PROFILE;
122
- if (!PROFILES[p]) {
123
- throw new GuardTenantIdError("tenant-id/bad-profile",
124
- "guardTenantId: unknown profile '" + p + "'");
125
- }
126
- return p;
127
- }
128
-
129
- module.exports = {
130
- validate: validate,
131
- compliancePosture: compliancePosture,
132
- PROFILES: PROFILES,
133
- COMPLIANCE_POSTURES: COMPLIANCE_POSTURES,
134
- RESERVED: RESERVED,
135
- GuardTenantIdError: GuardTenantIdError,
136
- NAME: "tenantId",
137
- KIND: "tenant-id",
138
- };
104
+ // compliancePosture is assembled by gateContract.defineParser below; its
105
+ // wiki section renders from the single-sourced @abiTemplate (defineParser)
106
+ // block in gate-contract.js, instantiated for this guard by the page
107
+ // generator.
108
+ module.exports = gateContract.defineParser({
109
+ name: "tenant-id",
110
+ entry: validate,
111
+ errorClass: GuardTenantIdError,
112
+ profiles: PROFILES,
113
+ postures: COMPLIANCE_POSTURES,
114
+ extra: {
115
+ RESERVED: RESERVED,
116
+ NAME: "tenantId",
117
+ KIND: "tenant-id",
118
+ },
119
+ });