@blamejs/core 0.14.27 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/README.md +2 -2
- package/index.js +4 -0
- package/lib/ai-content-detect.js +9 -10
- package/lib/api-key.js +107 -74
- package/lib/atomic-file.js +29 -1
- package/lib/audit-chain.js +47 -11
- package/lib/audit-sign.js +77 -2
- package/lib/audit-tools.js +79 -51
- package/lib/audit.js +218 -100
- package/lib/backup/index.js +13 -10
- package/lib/break-glass.js +202 -144
- package/lib/cache.js +174 -105
- package/lib/chain-writer.js +38 -16
- package/lib/cli.js +19 -14
- package/lib/cluster-provider-db.js +130 -104
- package/lib/cluster-storage.js +119 -22
- package/lib/cluster.js +119 -71
- package/lib/compliance.js +22 -0
- package/lib/consent.js +73 -24
- package/lib/constants.js +16 -11
- package/lib/crypto-field.js +387 -91
- package/lib/db-declare-row-policy.js +35 -22
- package/lib/db-file-lifecycle.js +3 -2
- package/lib/db-query.js +497 -255
- package/lib/db-schema.js +209 -44
- package/lib/db.js +176 -95
- package/lib/external-db-migrate.js +229 -139
- package/lib/external-db.js +25 -15
- package/lib/framework-error.js +11 -0
- package/lib/framework-files.js +73 -0
- package/lib/framework-schema.js +695 -394
- package/lib/gate-contract.js +596 -1
- package/lib/guard-agent-registry.js +26 -44
- package/lib/guard-all.js +1 -0
- package/lib/guard-auth.js +42 -112
- package/lib/guard-cidr.js +33 -154
- package/lib/guard-csv.js +46 -113
- package/lib/guard-domain.js +34 -157
- package/lib/guard-dsn.js +27 -43
- package/lib/guard-email.js +47 -69
- package/lib/guard-envelope.js +19 -32
- package/lib/guard-event-bus-payload.js +24 -42
- package/lib/guard-event-bus-topic.js +25 -43
- package/lib/guard-filename.js +42 -106
- package/lib/guard-graphql.js +42 -123
- package/lib/guard-html.js +53 -108
- package/lib/guard-idempotency-key.js +24 -42
- package/lib/guard-image.js +46 -103
- package/lib/guard-imap-command.js +18 -32
- package/lib/guard-jmap.js +16 -30
- package/lib/guard-json.js +38 -108
- package/lib/guard-jsonpath.js +38 -171
- package/lib/guard-jwt.js +49 -179
- package/lib/guard-list-id.js +25 -41
- package/lib/guard-list-unsubscribe.js +27 -43
- package/lib/guard-mail-compose.js +24 -42
- package/lib/guard-mail-move.js +26 -44
- package/lib/guard-mail-query.js +28 -46
- package/lib/guard-mail-reply.js +24 -42
- package/lib/guard-mail-sieve.js +24 -42
- package/lib/guard-managesieve-command.js +17 -31
- package/lib/guard-markdown.js +37 -104
- package/lib/guard-message-id.js +26 -45
- package/lib/guard-mime.js +39 -151
- package/lib/guard-oauth.js +54 -135
- package/lib/guard-pdf.js +45 -101
- package/lib/guard-pop3-command.js +21 -31
- package/lib/guard-posture-chain.js +24 -42
- package/lib/guard-regex.js +33 -107
- package/lib/guard-saga-config.js +24 -42
- package/lib/guard-shell.js +42 -172
- package/lib/guard-smtp-command.js +48 -54
- package/lib/guard-snapshot-envelope.js +24 -42
- package/lib/guard-sql.js +1491 -0
- package/lib/guard-stream-args.js +24 -43
- package/lib/guard-svg.js +47 -65
- package/lib/guard-template.js +35 -172
- package/lib/guard-tenant-id.js +26 -45
- package/lib/guard-time.js +32 -154
- package/lib/guard-trace-context.js +25 -44
- package/lib/guard-uuid.js +32 -153
- package/lib/guard-xml.js +38 -113
- package/lib/guard-yaml.js +51 -163
- package/lib/http-client.js +14 -0
- package/lib/inbox.js +120 -107
- package/lib/legal-hold.js +107 -50
- package/lib/log-stream-cloudwatch.js +47 -31
- package/lib/log-stream-otlp.js +32 -18
- package/lib/mail-crypto-smime.js +2 -6
- package/lib/mail-greylist.js +2 -6
- package/lib/mail-helo.js +2 -6
- package/lib/mail-journal.js +85 -64
- package/lib/mail-rbl.js +2 -6
- package/lib/mail-scan.js +2 -6
- package/lib/mail-spam-score.js +2 -6
- package/lib/mail-store.js +287 -154
- package/lib/middleware/fetch-metadata.js +17 -7
- package/lib/middleware/idempotency-key.js +54 -38
- package/lib/middleware/rate-limit.js +102 -32
- package/lib/middleware/security-headers.js +21 -5
- package/lib/migrations.js +108 -66
- package/lib/network-heartbeat.js +7 -0
- package/lib/nonce-store.js +31 -9
- package/lib/object-store/azure-blob-bucket-ops.js +9 -4
- package/lib/object-store/azure-blob.js +31 -3
- package/lib/object-store/sigv4.js +10 -0
- package/lib/outbox.js +136 -82
- package/lib/pqc-agent.js +44 -0
- package/lib/pubsub-cluster.js +42 -20
- package/lib/queue-local.js +202 -139
- package/lib/queue-redis.js +9 -1
- package/lib/queue-sqs.js +6 -0
- package/lib/retention.js +82 -39
- package/lib/safe-dns.js +29 -45
- package/lib/safe-ical.js +18 -33
- package/lib/safe-icap.js +27 -43
- package/lib/safe-sieve.js +21 -40
- package/lib/safe-sql.js +124 -3
- package/lib/safe-vcard.js +18 -33
- package/lib/scheduler.js +35 -12
- package/lib/seeders.js +122 -74
- package/lib/session-stores.js +42 -14
- package/lib/session.js +109 -72
- package/lib/sql.js +3885 -0
- package/lib/static.js +45 -7
- package/lib/subject.js +55 -17
- package/lib/vault/index.js +3 -2
- package/lib/vault/passphrase-ops.js +3 -2
- package/lib/vault/rotate.js +104 -64
- package/lib/vendor-data.js +2 -0
- package/lib/websocket.js +16 -0
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/gate-contract.js
CHANGED
|
@@ -50,7 +50,7 @@ var bCrypto = require("./crypto");
|
|
|
50
50
|
var lazyRequire = require("./lazy-require");
|
|
51
51
|
var safeAsync = require("./safe-async");
|
|
52
52
|
var validateOpts = require("./validate-opts");
|
|
53
|
-
var { GateContractError } = require("./framework-error");
|
|
53
|
+
var { GateContractError, defineClass } = require("./framework-error");
|
|
54
54
|
|
|
55
55
|
var observability = lazyRequire(function () { return require("./observability"); });
|
|
56
56
|
var compliance = lazyRequire(function () { return require("./compliance"); });
|
|
@@ -1102,6 +1102,153 @@ function lookupCompliancePosture(name, postures, errorFactory, codePrefix) {
|
|
|
1102
1102
|
return Object.assign({}, postures[name]);
|
|
1103
1103
|
}
|
|
1104
1104
|
|
|
1105
|
+
// "GuardCidrError" -> "guardCidr" — the guard's audit/message identity, derived
|
|
1106
|
+
// once from its error class name. Used for the default gate's audit/metric
|
|
1107
|
+
// prefix AND the profile resolver's error message, so neither re-cases the name.
|
|
1108
|
+
function _guardLabelFromError(ErrorClass) {
|
|
1109
|
+
var n = String(ErrorClass.name).replace(/Error$/, "");
|
|
1110
|
+
return n.charAt(0).toLowerCase() + n.slice(1);
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
/**
|
|
1114
|
+
* @primitive b.gateContract.makeProfileResolver
|
|
1115
|
+
* @signature b.gateContract.makeProfileResolver(cfg)
|
|
1116
|
+
* @since 0.15.0
|
|
1117
|
+
* @status stable
|
|
1118
|
+
* @related b.gateContract.makeProfileBuilder, b.gateContract.lookupCompliancePosture
|
|
1119
|
+
*
|
|
1120
|
+
* Closes over a guard's profile config and returns a `resolveProfile(opts)`
|
|
1121
|
+
* function: maps `opts.posture` through the compliance-posture table, else
|
|
1122
|
+
* falls back to `opts.profile || cfg.defaults`, validates the name against
|
|
1123
|
+
* `cfg.profiles`, and throws `cfg.errorClass.factory(cfg.codePrefix +
|
|
1124
|
+
* "/bad-profile")` on an unknown name. The sibling of `makeProfileBuilder` /
|
|
1125
|
+
* `makeRulePackLoader` / `lookupCompliancePosture` for the resolution step —
|
|
1126
|
+
* every `defineParser`-shaped line-protocol / mail / agent guard reuses it
|
|
1127
|
+
* instead of re-declaring an identical `_resolveProfile`.
|
|
1128
|
+
*
|
|
1129
|
+
* @opts
|
|
1130
|
+
* profiles: object, // the guard's PROFILES map; required
|
|
1131
|
+
* postures: object, // COMPLIANCE_POSTURES (posture -> profile name)
|
|
1132
|
+
* defaults: string, // fallback profile name when no posture/profile given
|
|
1133
|
+
* errorClass: function, // the guard's FrameworkError subclass
|
|
1134
|
+
* codePrefix: string, // error-code namespace (e.g. "mail-compose")
|
|
1135
|
+
* byObject: boolean, // true -> return the profile config object, not its name
|
|
1136
|
+
*
|
|
1137
|
+
* @example
|
|
1138
|
+
* var resolveProfile = b.gateContract.makeProfileResolver({
|
|
1139
|
+
* profiles: PROFILES, postures: COMPLIANCE_POSTURES,
|
|
1140
|
+
* defaults: "strict", errorClass: GuardMailComposeError,
|
|
1141
|
+
* codePrefix: "mail-compose",
|
|
1142
|
+
* });
|
|
1143
|
+
* resolveProfile({ posture: "hipaa" }); // → "strict"
|
|
1144
|
+
*/
|
|
1145
|
+
function makeProfileResolver(cfg) {
|
|
1146
|
+
var profiles = cfg.profiles;
|
|
1147
|
+
var postures = cfg.postures;
|
|
1148
|
+
var dft = cfg.defaults;
|
|
1149
|
+
var ErrorClass = cfg.errorClass;
|
|
1150
|
+
var codePrefix = cfg.codePrefix;
|
|
1151
|
+
var byObject = cfg.byObject === true;
|
|
1152
|
+
var label = _guardLabelFromError(ErrorClass);
|
|
1153
|
+
return function resolveProfile(opts) {
|
|
1154
|
+
opts = opts || {};
|
|
1155
|
+
if (opts.posture && postures && postures[opts.posture]) {
|
|
1156
|
+
var pn = postures[opts.posture];
|
|
1157
|
+
return byObject ? profiles[pn] : pn;
|
|
1158
|
+
}
|
|
1159
|
+
var p = opts.profile || dft;
|
|
1160
|
+
if (!profiles[p]) {
|
|
1161
|
+
throw ErrorClass.factory(codePrefix + "/bad-profile",
|
|
1162
|
+
label + ": unknown profile '" + p + "' (use " +
|
|
1163
|
+
Object.keys(profiles).join(" / ") + ")");
|
|
1164
|
+
}
|
|
1165
|
+
return byObject ? profiles[p] : p;
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
* @primitive b.gateContract.throwOnRefusalSeverity
|
|
1171
|
+
* @signature b.gateContract.throwOnRefusalSeverity(issues, cfg)
|
|
1172
|
+
* @since 0.15.0
|
|
1173
|
+
* @status stable
|
|
1174
|
+
* @related b.gateContract.aggregateIssues, b.gateContract.makeProfileResolver
|
|
1175
|
+
*
|
|
1176
|
+
* Throw on the first critical/high-severity issue in a detector's issue
|
|
1177
|
+
* list — the refusal step every guard `sanitize` runs after detection
|
|
1178
|
+
* (sanitize can serve a clean value but never repair a critical/high
|
|
1179
|
+
* finding). Builds the guard's error via `cfg.errorClass.factory` with code
|
|
1180
|
+
* `issue.ruleId || (cfg.codePrefix + ".refused")` and message
|
|
1181
|
+
* `guard<Name>.<op>: <issue.snippet>` (op default `"sanitize"`; the guard
|
|
1182
|
+
* identity derives from the error class name). The throw sibling of
|
|
1183
|
+
* `aggregateIssues` (which returns `{ ok, issues }` instead of throwing) —
|
|
1184
|
+
* replaces the per-guard hand-rolled severity-gating loop.
|
|
1185
|
+
*
|
|
1186
|
+
* @opts
|
|
1187
|
+
* errorClass: function, // the guard's FrameworkError subclass; required
|
|
1188
|
+
* codePrefix: string, // error-code namespace; the `.refused` fallback code
|
|
1189
|
+
* op: string, // operation name in the message (default "sanitize")
|
|
1190
|
+
* severities: string[], // refusal severities (default ["critical","high"])
|
|
1191
|
+
*
|
|
1192
|
+
* @example
|
|
1193
|
+
* var issues = detect(input, opts);
|
|
1194
|
+
* b.gateContract.throwOnRefusalSeverity(issues, {
|
|
1195
|
+
* errorClass: GuardCidrError, codePrefix: "cidr",
|
|
1196
|
+
* });
|
|
1197
|
+
* // throws GuardCidrError(ruleId || "cidr.refused", "guardCidr.sanitize: " + snippet)
|
|
1198
|
+
* // on the first critical/high issue
|
|
1199
|
+
*/
|
|
1200
|
+
function throwOnRefusalSeverity(issues, cfg) {
|
|
1201
|
+
var errFactory = cfg.errorClass.factory;
|
|
1202
|
+
var prefix = _guardLabelFromError(cfg.errorClass) + "." + (cfg.op || "sanitize");
|
|
1203
|
+
var fallback = cfg.codePrefix + ".refused";
|
|
1204
|
+
// Default refuses critical + high; cfg.severities narrows it (e.g.
|
|
1205
|
+
// ["critical"] for guards that strip high-severity findings but refuse
|
|
1206
|
+
// only unrepairable critical shapes — email / markdown / xml / yaml).
|
|
1207
|
+
var severities = cfg.severities || ["critical", "high"];
|
|
1208
|
+
for (var i = 0; i < issues.length; i += 1) {
|
|
1209
|
+
var iss = issues[i];
|
|
1210
|
+
if (severities.indexOf(iss.severity) !== -1) {
|
|
1211
|
+
throw errFactory(iss.ruleId || fallback, prefix + ": " + iss.snippet);
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
/**
|
|
1217
|
+
* @primitive b.gateContract.ALL_STRICT_POSTURES
|
|
1218
|
+
* @signature b.gateContract.ALL_STRICT_POSTURES
|
|
1219
|
+
* @since 0.15.0
|
|
1220
|
+
* @status stable
|
|
1221
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
1222
|
+
* @related b.gateContract.lookupCompliancePosture, b.gateContract.makeProfileBuilder
|
|
1223
|
+
*
|
|
1224
|
+
* Canonical strict-all `COMPLIANCE_POSTURES` map every command/parser
|
|
1225
|
+
* guard composes. Maps each of the four baseline regulatory postures —
|
|
1226
|
+
* `hipaa` / `pci-dss` / `gdpr` / `soc2` — onto the guard's `strict`
|
|
1227
|
+
* profile name. Guards whose four postures all resolve to `strict`
|
|
1228
|
+
* (the command/protocol validators: POP3 / IMAP / SMTP / ManageSieve
|
|
1229
|
+
* commands, mail-compose / query / sieve / move / reply, the envelope
|
|
1230
|
+
* and event-bus shapes, the mail pipeline scorers, and the
|
|
1231
|
+
* `safe-*` line-protocol parsers) reference this single frozen object
|
|
1232
|
+
* instead of re-declaring it. Guards that overlay per-posture
|
|
1233
|
+
* byte-limits or redaction flags (the content guards: CSV / HTML /
|
|
1234
|
+
* JSON / XML / YAML / JWT / OAuth / template, etc.) keep their own
|
|
1235
|
+
* posture map and do not compose this.
|
|
1236
|
+
*
|
|
1237
|
+
* Frozen once and shared by reference: every consumer reads it through
|
|
1238
|
+
* its own `COMPLIANCE_POSTURES` binding and never mutates it.
|
|
1239
|
+
*
|
|
1240
|
+
* @example
|
|
1241
|
+
* var COMPLIANCE_POSTURES = b.gateContract.ALL_STRICT_POSTURES;
|
|
1242
|
+
* COMPLIANCE_POSTURES.hipaa; // → "strict"
|
|
1243
|
+
* Object.isFrozen(COMPLIANCE_POSTURES); // → true
|
|
1244
|
+
*/
|
|
1245
|
+
var ALL_STRICT_POSTURES = Object.freeze({
|
|
1246
|
+
hipaa: "strict",
|
|
1247
|
+
"pci-dss": "strict",
|
|
1248
|
+
gdpr: "strict",
|
|
1249
|
+
soc2: "strict",
|
|
1250
|
+
});
|
|
1251
|
+
|
|
1105
1252
|
/**
|
|
1106
1253
|
* @primitive b.gateContract.makeRulePackLoader
|
|
1107
1254
|
* @signature b.gateContract.makeRulePackLoader(errorClass, codePrefix)
|
|
@@ -1680,8 +1827,453 @@ function composeHooks(hooks) {
|
|
|
1680
1827
|
};
|
|
1681
1828
|
}
|
|
1682
1829
|
|
|
1830
|
+
// ---- Guard-module factories ----
|
|
1831
|
+
//
|
|
1832
|
+
// Every b.guard* primitive of the gate-bearing kinds (content / filename
|
|
1833
|
+
// / identifier) hand-wires the SAME export surface: an error class, a
|
|
1834
|
+
// resolveProfileAndPosture-backed _resolveOpts, a buildGuardGate-backed
|
|
1835
|
+
// gate, a makeProfileBuilder-backed buildProfile, a
|
|
1836
|
+
// lookupCompliancePosture-backed compliancePosture, a makeRulePackLoader-
|
|
1837
|
+
// backed loadRulePack, and a frozen module.exports carrying the
|
|
1838
|
+
// guard-* registry fields (NAME / KIND / MIME_TYPES / EXTENSIONS /
|
|
1839
|
+
// PROFILES / DEFAULTS / COMPLIANCE_POSTURES / INTEGRATION_FIXTURES) plus
|
|
1840
|
+
// the per-guard inspection surface (validate / sanitize / gate). They
|
|
1841
|
+
// differ only in the per-guard inspection LOGIC + the PROFILES /
|
|
1842
|
+
// COMPLIANCE_POSTURES / DEFAULTS tables. `defineGuard` assembles the
|
|
1843
|
+
// boilerplate; the spec injects the logic and the tables.
|
|
1844
|
+
//
|
|
1845
|
+
// `defineParser` is the sibling for the minimal command / line-protocol
|
|
1846
|
+
// / safe-* parser shape — the guards whose four postures all resolve to
|
|
1847
|
+
// `strict` (ALL_STRICT_POSTURES) and whose surface is a self-contained
|
|
1848
|
+
// `validate` / `parse` plus a `compliancePosture(name)` that returns the
|
|
1849
|
+
// effective PROFILE NAME (or null) rather than an overlay clone. Those
|
|
1850
|
+
// guards carry no gate / buildProfile / loadRulePack, so forcing them
|
|
1851
|
+
// through `defineGuard` would be a leaky abstraction.
|
|
1852
|
+
|
|
1853
|
+
// _KIND_CTX_FIELDS — per-KIND ordered list of ctx field names a
|
|
1854
|
+
// buildGuardGate-backed default gate reads, mirroring the hand-written
|
|
1855
|
+
// gate bodies: filename reads ctx.filename || ctx.name, identifier reads
|
|
1856
|
+
// ctx.identifier || ctx.token || ctx.jwt, command reads ctx.line ||
|
|
1857
|
+
// ctx.command. content has no entry — it falls through to
|
|
1858
|
+
// extractBytesAsText (the ctx.bytes string/Buffer normalizer).
|
|
1859
|
+
var _KIND_CTX_FIELDS = Object.freeze({
|
|
1860
|
+
filename: ["filename", "name"],
|
|
1861
|
+
identifier: ["identifier", "token", "jwt"],
|
|
1862
|
+
command: ["line", "command"],
|
|
1863
|
+
});
|
|
1864
|
+
|
|
1865
|
+
// override (when given) replaces the per-KIND field table — lets a guard whose
|
|
1866
|
+
// gate is the standard chain but reads a custom ctx field take the default gate.
|
|
1867
|
+
function _ctxValueForKind(kind, ctx, override) {
|
|
1868
|
+
ctx = ctx || {};
|
|
1869
|
+
var fields = override || _KIND_CTX_FIELDS[kind];
|
|
1870
|
+
if (!fields) return extractBytesAsText(ctx); // content (default)
|
|
1871
|
+
for (var i = 0; i < fields.length; i += 1) {
|
|
1872
|
+
if (ctx[fields[i]]) return ctx[fields[i]];
|
|
1873
|
+
}
|
|
1874
|
+
return "";
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
/**
|
|
1878
|
+
* @primitive b.gateContract.defineGuard
|
|
1879
|
+
* @signature b.gateContract.defineGuard(spec)
|
|
1880
|
+
* @since 0.15.0
|
|
1881
|
+
* @status stable
|
|
1882
|
+
* @related b.gateContract.defineParser, b.gateContract.buildGuardGate, b.gateContract.resolveProfileAndPosture
|
|
1883
|
+
*
|
|
1884
|
+
* Assemble a complete `b.guard*` module from a spec. Mints the per-guard
|
|
1885
|
+
* error class (via `framework-error.defineClass`, or accepts a supplied
|
|
1886
|
+
* `errorClass`), wires `resolveProfileAndPosture` / `buildGuardGate` /
|
|
1887
|
+
* `makeProfileBuilder` / `lookupCompliancePosture` / `makeRulePackLoader`,
|
|
1888
|
+
* and returns the frozen module.exports object every guard ships —
|
|
1889
|
+
* `NAME` / `KIND` / `PROFILES` / `DEFAULTS` / `COMPLIANCE_POSTURES` /
|
|
1890
|
+
* `INTEGRATION_FIXTURES` / `validate` / `sanitize?` / `gate?` /
|
|
1891
|
+
* `buildProfile` / `compliancePosture` / `loadRulePack` plus the spec's
|
|
1892
|
+
* `extra` exports (verb tables, `escapeCell`, `schema`, `kidSafe`, …) and
|
|
1893
|
+
* the error class under its own name.
|
|
1894
|
+
*
|
|
1895
|
+
* The per-guard inspection logic is INJECTED, not abstracted: `validate`
|
|
1896
|
+
* / `sanitize` / `gate` are spec functions that close over the resolved
|
|
1897
|
+
* opts. A guard whose `gate` body is the standard
|
|
1898
|
+
* serve→audit-only→sanitize→refuse chain can omit `spec.gate` and take
|
|
1899
|
+
* the factory default (built from `spec.validate` + `spec.sanitize` per
|
|
1900
|
+
* KIND); a guard with a bespoke gate (CSV's sanitize-reparse-reserialize,
|
|
1901
|
+
* filename's per-policy canSanitize matrix) passes its own. Behavior is
|
|
1902
|
+
* preserved byte-for-byte because the genuinely-divergent code stays
|
|
1903
|
+
* verbatim in the spec — the factory only removes the wiring every guard
|
|
1904
|
+
* copies.
|
|
1905
|
+
*
|
|
1906
|
+
* @opts
|
|
1907
|
+
* name: string, // NAME (e.g. "csv"); required
|
|
1908
|
+
* kind: string, // "content"|"filename"|"identifier"|"command" for the default gate; any non-empty label with a bespoke spec.gate; required
|
|
1909
|
+
* errCodePrefix: string, // error-code namespace (default name)
|
|
1910
|
+
* errorName: string, // defineClass name (mutually exclusive with errorClass)
|
|
1911
|
+
* errorClass: function, // pre-built FrameworkError subclass
|
|
1912
|
+
* profiles: object, // PROFILES (must include strict/balanced/permissive); required
|
|
1913
|
+
* defaults: object, // DEFAULTS baseline (default profiles.strict)
|
|
1914
|
+
* postures: object, // COMPLIANCE_POSTURES (default ALL_STRICT_POSTURES)
|
|
1915
|
+
* mimeTypes: string[], // content guards only
|
|
1916
|
+
* extensions: string[], // content guards only
|
|
1917
|
+
* integrationFixtures: object, // INTEGRATION_FIXTURES (consumed by host harness)
|
|
1918
|
+
* validate: function, // (input, resolvedOpts) -> { ok, issues }; required
|
|
1919
|
+
* sanitize: function, // (input, resolvedOpts) -> cleaned (optional)
|
|
1920
|
+
* gate: function, // (resolvedOpts) -> async (ctx) -> decision (optional; default built per kind)
|
|
1921
|
+
* ctxFields: string[], // ordered ctx field names the default gate reads (overrides the per-KIND table; e.g. ["identifier","cidr"])
|
|
1922
|
+
* defaultGateCheck: function, // override the default gate's per-ctx check
|
|
1923
|
+
* extra: object, // additional exports merged verbatim into module.exports
|
|
1924
|
+
*
|
|
1925
|
+
* @example
|
|
1926
|
+
* module.exports = b.gateContract.defineGuard({
|
|
1927
|
+
* name: "csv", kind: "content", errorClass: GuardCsvError,
|
|
1928
|
+
* profiles: PROFILES, defaults: DEFAULTS, postures: COMPLIANCE_POSTURES,
|
|
1929
|
+
* mimeTypes: ["text/csv"], extensions: [".csv"],
|
|
1930
|
+
* integrationFixtures: INTEGRATION_FIXTURES,
|
|
1931
|
+
* validate: validate, sanitize: sanitize, gate: gate,
|
|
1932
|
+
* extra: { serialize: serialize, escapeCell: escapeCell, schema: schema },
|
|
1933
|
+
* });
|
|
1934
|
+
*/
|
|
1935
|
+
function defineGuard(spec) {
|
|
1936
|
+
validateOpts.requireObject(spec, "gateContract.defineGuard", GateContractError);
|
|
1937
|
+
validateOpts.requireNonEmptyString(spec.name, "gateContract.defineGuard: name",
|
|
1938
|
+
GateContractError, "gate-contract/bad-opt");
|
|
1939
|
+
validateOpts.requireNonEmptyString(spec.kind, "gateContract.defineGuard: kind",
|
|
1940
|
+
GateContractError, "gate-contract/bad-opt");
|
|
1941
|
+
// The four known kinds drive the default gate's ctx-field dispatch
|
|
1942
|
+
// (_ctxValueForKind). A guard with a bespoke spec.gate reads its own ctx
|
|
1943
|
+
// fields, so any non-empty kind is allowed there — the kind is then just
|
|
1944
|
+
// the KIND export label (e.g. "oauth-flow" / "graphql-request" / "sql" /
|
|
1945
|
+
// "metadata"). A custom kind WITHOUT a bespoke gate is refused, because
|
|
1946
|
+
// the default gate could not dispatch it to the right ctx field.
|
|
1947
|
+
if (["content", "filename", "identifier", "command"].indexOf(spec.kind) === -1 &&
|
|
1948
|
+
typeof spec.gate !== "function") {
|
|
1949
|
+
throw _err("gate-contract/bad-opt",
|
|
1950
|
+
"defineGuard: kind must be content|filename|identifier|command for the " +
|
|
1951
|
+
"default gate, got " + JSON.stringify(spec.kind) +
|
|
1952
|
+
" — pass spec.gate for a custom kind (the bespoke gate reads its own ctx fields)");
|
|
1953
|
+
}
|
|
1954
|
+
validateOpts.requireObject(spec.profiles, "gateContract.defineGuard: profiles",
|
|
1955
|
+
GateContractError);
|
|
1956
|
+
if (typeof spec.validate !== "function") {
|
|
1957
|
+
throw _err("gate-contract/bad-opt", "defineGuard: validate must be a function");
|
|
1958
|
+
}
|
|
1959
|
+
if (spec.errorClass && spec.errorName) {
|
|
1960
|
+
throw _err("gate-contract/bad-opt",
|
|
1961
|
+
"defineGuard: pass errorClass OR errorName, not both");
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
var prefix = spec.errCodePrefix || spec.name;
|
|
1965
|
+
var ErrorClass = spec.errorClass ||
|
|
1966
|
+
defineClass(spec.errorName || ("Guard" +
|
|
1967
|
+
spec.name.charAt(0).toUpperCase() + spec.name.slice(1) + "Error"),
|
|
1968
|
+
{ alwaysPermanent: true });
|
|
1969
|
+
var profiles = spec.profiles;
|
|
1970
|
+
var defaults = spec.defaults || profiles.strict || {};
|
|
1971
|
+
var postures = spec.postures || ALL_STRICT_POSTURES;
|
|
1972
|
+
|
|
1973
|
+
var buildProfileFn = makeProfileBuilder(profiles);
|
|
1974
|
+
function compliancePostureFn(name) {
|
|
1975
|
+
return lookupCompliancePosture(name, postures, ErrorClass.factory, prefix);
|
|
1976
|
+
}
|
|
1977
|
+
var rulePacks = makeRulePackLoader(ErrorClass, prefix);
|
|
1978
|
+
|
|
1979
|
+
// spec.ctxFields (ordered field names) overrides the per-KIND table that
|
|
1980
|
+
// the default gate's _ctxValueForKind reads — lets a guard whose gate is the
|
|
1981
|
+
// standard chain but reads a custom ctx field (e.g. ctx.cidr) drop its
|
|
1982
|
+
// bespoke gate and take the default. null -> _ctxValueForKind uses the
|
|
1983
|
+
// per-KIND table.
|
|
1984
|
+
var ctxFields = Array.isArray(spec.ctxFields) ? spec.ctxFields.slice() : null;
|
|
1985
|
+
// Gate identity is surfaced in audit events / metric counters / cache keys.
|
|
1986
|
+
// Preserve the "guard<Name>:profile" naming the hand-written gates used so
|
|
1987
|
+
// moving a guard onto the default gate does not rename its audit/metric
|
|
1988
|
+
// stream (e.g. "guardCidr:strict"), via the shared error-name derivation.
|
|
1989
|
+
var gateNamePrefix = _guardLabelFromError(ErrorClass);
|
|
1990
|
+
|
|
1991
|
+
// Default gate — the standard serve→audit-only→refuse chain, dispatched
|
|
1992
|
+
// to the right ctx field by KIND (or spec.ctxFields). Guards with a bespoke
|
|
1993
|
+
// gate pass spec.gate; guards whose gate is the standard chain take this
|
|
1994
|
+
// default.
|
|
1995
|
+
// Raw opts pass straight through to spec.validate and buildGuardGate —
|
|
1996
|
+
// matching the hand-written gates, whose validate resolves profile/posture
|
|
1997
|
+
// internally (validate calls its own _resolveOpts). Pre-resolving here
|
|
1998
|
+
// would double-resolve.
|
|
1999
|
+
function defaultGate(opts) {
|
|
2000
|
+
opts = opts || {};
|
|
2001
|
+
var perCtx = spec.defaultGateCheck || function (ctx) {
|
|
2002
|
+
var value = _ctxValueForKind(spec.kind, ctx, ctxFields);
|
|
2003
|
+
if (!value) return { ok: true, action: "serve" };
|
|
2004
|
+
var rv = spec.validate(value, opts);
|
|
2005
|
+
if (!rv.issues || rv.issues.length === 0) return { ok: true, action: "serve" };
|
|
2006
|
+
var hasBlocking = rv.issues.some(function (i) {
|
|
2007
|
+
return i.severity === "critical" || i.severity === "high";
|
|
2008
|
+
});
|
|
2009
|
+
if (!hasBlocking) return { ok: true, action: "audit-only", issues: rv.issues };
|
|
2010
|
+
return { ok: false, action: "refuse", issues: rv.issues };
|
|
2011
|
+
};
|
|
2012
|
+
return buildGuardGate(
|
|
2013
|
+
opts.name || (gateNamePrefix + ":" + (opts.profile || "default")),
|
|
2014
|
+
opts,
|
|
2015
|
+
async function (ctx) { return perCtx(ctx, opts); });
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
var gateFn = spec.gate || defaultGate;
|
|
2019
|
+
|
|
2020
|
+
var out = {
|
|
2021
|
+
NAME: spec.name,
|
|
2022
|
+
KIND: spec.kind,
|
|
2023
|
+
validate: spec.validate,
|
|
2024
|
+
buildProfile: buildProfileFn,
|
|
2025
|
+
compliancePosture: compliancePostureFn,
|
|
2026
|
+
loadRulePack: rulePacks.load,
|
|
2027
|
+
PROFILES: profiles,
|
|
2028
|
+
DEFAULTS: defaults,
|
|
2029
|
+
COMPLIANCE_POSTURES: postures,
|
|
2030
|
+
};
|
|
2031
|
+
if (spec.kind === "content") {
|
|
2032
|
+
out.MIME_TYPES = Object.freeze((spec.mimeTypes || []).slice());
|
|
2033
|
+
out.EXTENSIONS = Object.freeze((spec.extensions || []).slice());
|
|
2034
|
+
}
|
|
2035
|
+
if (spec.integrationFixtures) out.INTEGRATION_FIXTURES = spec.integrationFixtures;
|
|
2036
|
+
if (typeof spec.sanitize === "function") out.sanitize = spec.sanitize;
|
|
2037
|
+
out.gate = gateFn;
|
|
2038
|
+
// Error class exported under its own constructor name (GuardCsvError etc.)
|
|
2039
|
+
out[ErrorClass.name] = ErrorClass;
|
|
2040
|
+
// Per-guard extras (verb tables, escapeCell, schema, kidSafe, …) merged
|
|
2041
|
+
// verbatim via the prototype-safe own-enumerable copy (no computed-name
|
|
2042
|
+
// write; __proto__/constructor/prototype are skipped). Extras win over
|
|
2043
|
+
// factory defaults only when the guard explicitly re-exports a shared
|
|
2044
|
+
// name (rare; documented per guard).
|
|
2045
|
+
if (spec.extra) validateOpts.assignOwnEnumerable(out, spec.extra);
|
|
2046
|
+
return out;
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
/**
|
|
2050
|
+
* @primitive b.gateContract.defineParser
|
|
2051
|
+
* @signature b.gateContract.defineParser(spec)
|
|
2052
|
+
* @since 0.15.0
|
|
2053
|
+
* @status stable
|
|
2054
|
+
* @related b.gateContract.defineGuard, b.gateContract.ALL_STRICT_POSTURES
|
|
2055
|
+
*
|
|
2056
|
+
* Assemble the minimal command / line-protocol / `safe-*` parser module
|
|
2057
|
+
* shape — guards whose four compliance postures all resolve to `strict`
|
|
2058
|
+
* (composing `ALL_STRICT_POSTURES`) and whose surface is a single
|
|
2059
|
+
* self-contained `validate` / `parse` entry point plus a
|
|
2060
|
+
* `compliancePosture(name)` that returns the effective PROFILE NAME (or
|
|
2061
|
+
* `null` for unknown names) rather than an overlay clone. These guards
|
|
2062
|
+
* carry no `gate` / `buildProfile` / `loadRulePack`, so `defineGuard`'s
|
|
2063
|
+
* full assembly would be wrong for them.
|
|
2064
|
+
*
|
|
2065
|
+
* Mints the error class (or accepts one), exposes the spec's primary
|
|
2066
|
+
* entry point under `spec.entryName` (default `"validate"`), and returns
|
|
2067
|
+
* the frozen module.exports with `PROFILES` / `COMPLIANCE_POSTURES` /
|
|
2068
|
+
* `compliancePosture` plus the spec's `extra` exports and the error
|
|
2069
|
+
* class.
|
|
2070
|
+
*
|
|
2071
|
+
* @opts
|
|
2072
|
+
* name: string, // module identity / error-name stem; required
|
|
2073
|
+
* entry: function, // the validate/parse entry point; required
|
|
2074
|
+
* entryName: string, // export key for the entry (default "validate")
|
|
2075
|
+
* profiles: object, // PROFILES; required
|
|
2076
|
+
* postures: object, // COMPLIANCE_POSTURES (default ALL_STRICT_POSTURES)
|
|
2077
|
+
* errorClass: function, // pre-built FrameworkError subclass
|
|
2078
|
+
* errorName: string, // defineClass name (mutually exclusive with errorClass)
|
|
2079
|
+
* extra: object, // additional exports (verb tables, KNOWN_*, …)
|
|
2080
|
+
*
|
|
2081
|
+
* @example
|
|
2082
|
+
* module.exports = b.gateContract.defineParser({
|
|
2083
|
+
* name: "pop3-command", entry: validate,
|
|
2084
|
+
* errorClass: GuardPop3CommandError,
|
|
2085
|
+
* profiles: PROFILES, postures: COMPLIANCE_POSTURES,
|
|
2086
|
+
* extra: { KNOWN_VERBS: KNOWN_VERBS, ZERO_ARG_VERBS: ZERO_ARG_VERBS },
|
|
2087
|
+
* });
|
|
2088
|
+
*/
|
|
2089
|
+
function defineParser(spec) {
|
|
2090
|
+
validateOpts.requireObject(spec, "gateContract.defineParser", GateContractError);
|
|
2091
|
+
validateOpts.requireNonEmptyString(spec.name, "gateContract.defineParser: name",
|
|
2092
|
+
GateContractError, "gate-contract/bad-opt");
|
|
2093
|
+
if (typeof spec.entry !== "function") {
|
|
2094
|
+
throw _err("gate-contract/bad-opt", "defineParser: entry must be a function");
|
|
2095
|
+
}
|
|
2096
|
+
validateOpts.requireObject(spec.profiles, "gateContract.defineParser: profiles",
|
|
2097
|
+
GateContractError);
|
|
2098
|
+
if (spec.errorClass && spec.errorName) {
|
|
2099
|
+
throw _err("gate-contract/bad-opt",
|
|
2100
|
+
"defineParser: pass errorClass OR errorName, not both");
|
|
2101
|
+
}
|
|
2102
|
+
var ErrorClass = spec.errorClass ||
|
|
2103
|
+
defineClass(spec.errorName || ("Guard" +
|
|
2104
|
+
spec.name.charAt(0).toUpperCase() + spec.name.slice(1) + "Error"),
|
|
2105
|
+
{ alwaysPermanent: true });
|
|
2106
|
+
var postures = spec.postures || ALL_STRICT_POSTURES;
|
|
2107
|
+
|
|
2108
|
+
function compliancePostureFn(name) {
|
|
2109
|
+
return postures[name] || null;
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2112
|
+
var out = {
|
|
2113
|
+
compliancePosture: compliancePostureFn,
|
|
2114
|
+
PROFILES: spec.profiles,
|
|
2115
|
+
COMPLIANCE_POSTURES: postures,
|
|
2116
|
+
};
|
|
2117
|
+
out[spec.entryName || "validate"] = spec.entry;
|
|
2118
|
+
out[ErrorClass.name] = ErrorClass;
|
|
2119
|
+
if (spec.extra) validateOpts.assignOwnEnumerable(out, spec.extra);
|
|
2120
|
+
return out;
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
// ---- ABI doc templates (single-sourced; rendered per guard) ----
|
|
2124
|
+
//
|
|
2125
|
+
// Every guard built through `defineGuard` / `defineParser` exposes the
|
|
2126
|
+
// SAME factory-generated ABI methods (`compliancePosture` and, for
|
|
2127
|
+
// `defineGuard`, `buildProfile` / `loadRulePack` / a default `gate`).
|
|
2128
|
+
// Those methods have no per-guard `function` declaration — the factory
|
|
2129
|
+
// wires them — so a refactored guard that wants its wiki page to keep
|
|
2130
|
+
// listing them used to carry a floating `@primitive` block per method,
|
|
2131
|
+
// duplicating the same prose across every member of the family.
|
|
2132
|
+
//
|
|
2133
|
+
// The `@abiTemplate` blocks below are the ONE copy of that prose. The
|
|
2134
|
+
// wiki parser (`examples/wiki/lib/source-doc-parser.js`) collects them
|
|
2135
|
+
// into a per-factory template bucket (keyed `defineGuard` / `defineParser`)
|
|
2136
|
+
// instead of the gateContract primitive list, and the page generator
|
|
2137
|
+
// (`examples/wiki/lib/page-generator.js`) instantiates them per guard —
|
|
2138
|
+
// substituting `{NS}` (the guard namespace, e.g. `guardCsv`) and `{ERR}`
|
|
2139
|
+
// (its error class, e.g. `GuardCsvError`) and filling `@since` from the
|
|
2140
|
+
// guard's own `@module` / first-primitive metadata — so each guard's page
|
|
2141
|
+
// renders every ABI method with usage correct for THAT guard. The
|
|
2142
|
+
// duplicated prose collapses to a single source; the rendered surface is
|
|
2143
|
+
// unchanged. A guard that keeps a bespoke per-method block (a custom
|
|
2144
|
+
// `gate`, or a guard that documents its own `compliancePosture`) wins —
|
|
2145
|
+
// the page generator skips the template for any method already present.
|
|
2146
|
+
//
|
|
2147
|
+
// These blocks intentionally carry the placeholder primitive form
|
|
2148
|
+
// `b.{NS}.<method>` and placeholder-bearing `@example` bodies; the
|
|
2149
|
+
// validator routes them through its template-shape pass, not the
|
|
2150
|
+
// resolvable-primitive pass.
|
|
2151
|
+
|
|
2152
|
+
/**
|
|
2153
|
+
* @abiTemplate defineGuard
|
|
2154
|
+
* @method compliancePosture
|
|
2155
|
+
* @signature b.{NS}.compliancePosture(name)
|
|
2156
|
+
* @status stable
|
|
2157
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
2158
|
+
* @related b.{NS}.gate, b.{NS}.buildProfile
|
|
2159
|
+
*
|
|
2160
|
+
* Look up a compliance-posture overlay by name (one of `"hipaa"` /
|
|
2161
|
+
* `"pci-dss"` / `"gdpr"` / `"soc2"`). Returns a fresh clone of the
|
|
2162
|
+
* posture overlay so the caller may mutate it freely without disturbing
|
|
2163
|
+
* the shared table. Throws `{ERR}` with code `"{CODE}.bad-posture"` when
|
|
2164
|
+
* the name is not one this guard maps. Wired by `gateContract.defineGuard`
|
|
2165
|
+
* through `gateContract.lookupCompliancePosture`, so the clone semantics
|
|
2166
|
+
* and error code are identical across every guard in the family.
|
|
2167
|
+
*
|
|
2168
|
+
* @example
|
|
2169
|
+
* var posture = b.{NS}.compliancePosture("hipaa");
|
|
2170
|
+
* posture; // → overlay clone (mutable)
|
|
2171
|
+
*
|
|
2172
|
+
* try {
|
|
2173
|
+
* b.{NS}.compliancePosture("not-a-regime");
|
|
2174
|
+
* } catch (e) {
|
|
2175
|
+
* e.code; // → "{CODE}.bad-posture"
|
|
2176
|
+
* }
|
|
2177
|
+
*/
|
|
2178
|
+
|
|
2179
|
+
/**
|
|
2180
|
+
* @abiTemplate defineGuard
|
|
2181
|
+
* @method buildProfile
|
|
2182
|
+
* @signature b.{NS}.buildProfile(opts)
|
|
2183
|
+
* @status stable
|
|
2184
|
+
* @related b.{NS}.gate, b.{NS}.compliancePosture
|
|
2185
|
+
*
|
|
2186
|
+
* Compose a derived profile from one or more named bases plus inline
|
|
2187
|
+
* overrides, resolving names through this guard's own `PROFILES` table.
|
|
2188
|
+
* `opts.extends` is a base profile name (`"strict"` / `"balanced"` /
|
|
2189
|
+
* `"permissive"`) or an array of names — later entries shadow earlier
|
|
2190
|
+
* ones, and inline `opts` keys win last. Wired by
|
|
2191
|
+
* `gateContract.defineGuard` through `gateContract.makeProfileBuilder`,
|
|
2192
|
+
* so operator-defined profiles stay traceable to a baseline instead of a
|
|
2193
|
+
* hand-typed dictionary.
|
|
2194
|
+
*
|
|
2195
|
+
* @opts
|
|
2196
|
+
* extends: string|string[], // base profile name(s) to compose
|
|
2197
|
+
* ...: any guard key, // inline override of resolved keys
|
|
2198
|
+
*
|
|
2199
|
+
* @example
|
|
2200
|
+
* var custom = b.{NS}.buildProfile({ extends: "strict" });
|
|
2201
|
+
* custom; // → composed profile object
|
|
2202
|
+
*/
|
|
2203
|
+
|
|
2204
|
+
/**
|
|
2205
|
+
* @abiTemplate defineGuard
|
|
2206
|
+
* @method loadRulePack
|
|
2207
|
+
* @signature b.{NS}.loadRulePack(pack)
|
|
2208
|
+
* @status stable
|
|
2209
|
+
* @related b.{NS}.gate
|
|
2210
|
+
*
|
|
2211
|
+
* Register an operator-supplied rule pack with this guard's rule-pack
|
|
2212
|
+
* registry. The pack is identified by `pack.id` (a non-empty string) and
|
|
2213
|
+
* stored for later dispatch by gates that opt in via `opts.rulePackId`.
|
|
2214
|
+
* Returns the pack unchanged on success; throws `{ERR}` with code
|
|
2215
|
+
* `"{CODE}.bad-opt"` when `pack` is missing or `pack.id` is not a non-empty
|
|
2216
|
+
* string. Wired by `gateContract.defineGuard` through
|
|
2217
|
+
* `gateContract.makeRulePackLoader`, so storage shape and validation are
|
|
2218
|
+
* identical across the family.
|
|
2219
|
+
*
|
|
2220
|
+
* @example
|
|
2221
|
+
* var pack = b.{NS}.loadRulePack({ id: "tenant-policy", rules: [] });
|
|
2222
|
+
* pack.id; // → "tenant-policy"
|
|
2223
|
+
*/
|
|
2224
|
+
|
|
2225
|
+
/**
|
|
2226
|
+
* @abiTemplate defineGuard
|
|
2227
|
+
* @method gate
|
|
2228
|
+
* @signature b.{NS}.gate(opts?)
|
|
2229
|
+
* @status stable
|
|
2230
|
+
* @related b.{NS}.validate, b.gateContract.buildGuardGate
|
|
2231
|
+
*
|
|
2232
|
+
* Build the guard's request-boundary gate — a contract-shaped object
|
|
2233
|
+
* exposing `check(ctx)` that host primitives call at their byte moment.
|
|
2234
|
+
* This is the factory default chain: `serve` when no issue, `audit-only`
|
|
2235
|
+
* for `info` / `warn` issues, and `refuse` for any `high` / `critical`
|
|
2236
|
+
* issue, dispatched to the right `ctx` field by the guard's KIND. Wired
|
|
2237
|
+
* by `gateContract.defineGuard` through `gateContract.buildGuardGate`; a
|
|
2238
|
+
* guard whose gate diverges (a bespoke sanitize-and-reserialize chain,
|
|
2239
|
+
* for example) ships its own `gate` block instead of this template.
|
|
2240
|
+
*
|
|
2241
|
+
* @opts
|
|
2242
|
+
* profile: string, // one of PROFILES; default this guard's default
|
|
2243
|
+
* compliancePosture: string, // overlay one of hipaa/pci-dss/gdpr/soc2
|
|
2244
|
+
* mode: string, // one of gateContract MODES; default "enforce"
|
|
2245
|
+
*
|
|
2246
|
+
* @example
|
|
2247
|
+
* var gate = b.{NS}.gate({ profile: "strict" });
|
|
2248
|
+
* var decision = await gate.check({ bytes: Buffer.from("...") });
|
|
2249
|
+
* decision.action; // → "serve" | "refuse" | …
|
|
2250
|
+
*/
|
|
2251
|
+
|
|
2252
|
+
/**
|
|
2253
|
+
* @abiTemplate defineParser
|
|
2254
|
+
* @method compliancePosture
|
|
2255
|
+
* @signature b.{NS}.compliancePosture(name)
|
|
2256
|
+
* @status stable
|
|
2257
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
2258
|
+
* @related b.{NS}.validate, b.gateContract.ALL_STRICT_POSTURES
|
|
2259
|
+
*
|
|
2260
|
+
* Return the effective profile NAME for a compliance posture, or `null`
|
|
2261
|
+
* for a name this parser does not map. Unlike the content-guard variant
|
|
2262
|
+
* this returns the resolved profile string (every line-protocol parser
|
|
2263
|
+
* composes `gateContract.ALL_STRICT_POSTURES`, so `"hipaa"` / `"pci-dss"`
|
|
2264
|
+
* / `"gdpr"` / `"soc2"` all resolve to `"strict"`) and never throws —
|
|
2265
|
+
* the parser shape carries no overlay-clone, no `buildProfile`, and no
|
|
2266
|
+
* `loadRulePack`. Wired by `gateContract.defineParser`.
|
|
2267
|
+
*
|
|
2268
|
+
* @example
|
|
2269
|
+
* b.{NS}.compliancePosture("hipaa"); // → "strict"
|
|
2270
|
+
* b.{NS}.compliancePosture("not-a-regime"); // → null
|
|
2271
|
+
*/
|
|
2272
|
+
|
|
1683
2273
|
module.exports = {
|
|
1684
2274
|
defineGate: defineGate,
|
|
2275
|
+
defineGuard: defineGuard,
|
|
2276
|
+
defineParser: defineParser,
|
|
1685
2277
|
validateGateShape: validateGateShape,
|
|
1686
2278
|
runGate: runGate,
|
|
1687
2279
|
composeGates: composeGates,
|
|
@@ -1700,8 +2292,11 @@ module.exports = {
|
|
|
1700
2292
|
buildGuardGate: buildGuardGate,
|
|
1701
2293
|
extractBytesAsText: extractBytesAsText,
|
|
1702
2294
|
lookupCompliancePosture: lookupCompliancePosture,
|
|
2295
|
+
ALL_STRICT_POSTURES: ALL_STRICT_POSTURES,
|
|
1703
2296
|
makeRulePackLoader: makeRulePackLoader,
|
|
1704
2297
|
makeProfileBuilder: makeProfileBuilder,
|
|
2298
|
+
makeProfileResolver: makeProfileResolver,
|
|
2299
|
+
throwOnRefusalSeverity: throwOnRefusalSeverity,
|
|
1705
2300
|
badInputResultIfNotStringOrBuffer: badInputResultIfNotStringOrBuffer,
|
|
1706
2301
|
aggregateIssues: aggregateIssues,
|
|
1707
2302
|
composeHooks: composeHooks,
|