@blamejs/core 0.14.26 → 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 +6 -0
- package/README.md +2 -2
- package/index.js +4 -0
- package/lib/agent-envelope-mac.js +104 -0
- package/lib/agent-event-bus.js +105 -4
- package/lib/agent-posture-chain.js +8 -42
- package/lib/ai-content-detect.js +9 -10
- package/lib/api-key.js +107 -74
- package/lib/atomic-file.js +62 -4
- 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 +249 -123
- package/lib/auth/openid-federation.js +108 -47
- 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 +169 -4
- package/lib/consent.js +73 -24
- package/lib/constants.js +16 -11
- package/lib/crypto-field.js +474 -92
- 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/error-page.js +14 -1
- package/lib/external-db-migrate.js +229 -139
- package/lib/external-db.js +25 -15
- package/lib/file-upload.js +52 -7
- package/lib/framework-error.js +14 -1
- package/lib/framework-files.js +73 -0
- package/lib/framework-schema.js +695 -394
- package/lib/gate-contract.js +649 -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 +37 -9
- 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-server-jmap.js +117 -12
- package/lib/mail-spam-score.js +2 -6
- package/lib/mail-store.js +287 -154
- package/lib/middleware/body-parser.js +71 -25
- package/lib/middleware/csrf-protect.js +19 -8
- 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 +57 -3
- package/lib/object-store/sigv4.js +10 -0
- package/lib/observability.js +87 -0
- package/lib/otel-export.js +25 -1
- package/lib/outbox.js +136 -82
- package/lib/parsers/safe-xml.js +47 -7
- 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/redact.js +68 -11
- package/lib/redis-client.js +160 -31
- package/lib/retention.js +82 -39
- package/lib/router.js +212 -5
- 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/ssrf-guard.js +51 -4
- package/lib/static.js +177 -34
- 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 +35 -5
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
var { defineClass } = require("./framework-error");
|
|
28
|
+
var gateContract = require("./gate-contract");
|
|
28
29
|
|
|
29
30
|
var GuardEventBusTopicError = defineClass("GuardEventBusTopicError", { alwaysPermanent: true });
|
|
30
31
|
|
|
@@ -36,12 +37,7 @@ var PROFILES = Object.freeze({
|
|
|
36
37
|
permissive: { maxBytes: 512, minDots: 1 },
|
|
37
38
|
});
|
|
38
39
|
|
|
39
|
-
var COMPLIANCE_POSTURES =
|
|
40
|
-
hipaa: "strict",
|
|
41
|
-
"pci-dss": "strict",
|
|
42
|
-
gdpr: "strict",
|
|
43
|
-
soc2: "strict",
|
|
44
|
-
});
|
|
40
|
+
var COMPLIANCE_POSTURES = gateContract.ALL_STRICT_POSTURES;
|
|
45
41
|
|
|
46
42
|
var RESERVED_PREFIXES = Object.freeze(["framework.", "FRAMEWORK."]);
|
|
47
43
|
|
|
@@ -109,42 +105,28 @@ function validate(name, opts) {
|
|
|
109
105
|
return name;
|
|
110
106
|
}
|
|
111
107
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
* @status stable
|
|
117
|
-
*
|
|
118
|
-
* Return the effective profile for a given compliance posture name.
|
|
119
|
-
* Returns `null` for unknown posture names so operator typos surface
|
|
120
|
-
* here instead of silently falling through to the default profile.
|
|
121
|
-
*
|
|
122
|
-
* @example
|
|
123
|
-
* b.guardEventBusTopic.compliancePosture("hipaa"); // → "strict"
|
|
124
|
-
*/
|
|
125
|
-
function compliancePosture(posture) {
|
|
126
|
-
return COMPLIANCE_POSTURES[posture] || null;
|
|
127
|
-
}
|
|
108
|
+
// compliancePosture is assembled by gateContract.defineParser below; its
|
|
109
|
+
// wiki section renders from the single-sourced @abiTemplate (defineParser)
|
|
110
|
+
// block in gate-contract.js, instantiated for this guard by the page
|
|
111
|
+
// generator.
|
|
128
112
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
"guardEventBusTopic: unknown profile '" + p + "'");
|
|
137
|
-
}
|
|
138
|
-
return p;
|
|
139
|
-
}
|
|
113
|
+
var _resolveProfile = gateContract.makeProfileResolver({
|
|
114
|
+
profiles: PROFILES,
|
|
115
|
+
postures: COMPLIANCE_POSTURES,
|
|
116
|
+
defaults: DEFAULT_PROFILE,
|
|
117
|
+
errorClass: GuardEventBusTopicError,
|
|
118
|
+
codePrefix: "event-bus-topic",
|
|
119
|
+
});
|
|
140
120
|
|
|
141
|
-
module.exports = {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
121
|
+
module.exports = gateContract.defineParser({
|
|
122
|
+
name: "event-bus-topic",
|
|
123
|
+
entry: validate,
|
|
124
|
+
errorClass: GuardEventBusTopicError,
|
|
125
|
+
profiles: PROFILES,
|
|
126
|
+
postures: COMPLIANCE_POSTURES,
|
|
127
|
+
extra: {
|
|
128
|
+
RESERVED_PREFIXES: RESERVED_PREFIXES,
|
|
129
|
+
NAME: "eventBusTopic",
|
|
130
|
+
KIND: "event-bus-topic",
|
|
131
|
+
},
|
|
132
|
+
});
|
package/lib/guard-filename.js
CHANGED
|
@@ -871,80 +871,10 @@ function gate(opts) {
|
|
|
871
871
|
});
|
|
872
872
|
}
|
|
873
873
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
* @status stable
|
|
879
|
-
* @related b.guardFilename.gate, b.guardFilename.compliancePosture
|
|
880
|
-
*
|
|
881
|
-
* Compose a derived profile from one or more named bases plus inline
|
|
882
|
-
* overrides. `opts.extends` is a profile name (`"strict"` /
|
|
883
|
-
* `"balanced"` / `"permissive"`) or an array of names; later entries
|
|
884
|
-
* shadow earlier ones. Inline `opts` keys win last.
|
|
885
|
-
*
|
|
886
|
-
* @opts
|
|
887
|
-
* extends: string|string[], // base profile name(s) to compose
|
|
888
|
-
*
|
|
889
|
-
* @example
|
|
890
|
-
* var custom = b.guardFilename.buildProfile({
|
|
891
|
-
* extends: "balanced",
|
|
892
|
-
* extensionAllowlist: [".pdf", ".png", ".jpg"],
|
|
893
|
-
* });
|
|
894
|
-
* custom.extensionAllowlist.length; // → 3
|
|
895
|
-
* custom.traversalPolicy; // → "reject"
|
|
896
|
-
*/
|
|
897
|
-
var buildProfile = gateContract.makeProfileBuilder(PROFILES);
|
|
898
|
-
|
|
899
|
-
/**
|
|
900
|
-
* @primitive b.guardFilename.compliancePosture
|
|
901
|
-
* @signature b.guardFilename.compliancePosture(name)
|
|
902
|
-
* @since 0.7.5
|
|
903
|
-
* @status stable
|
|
904
|
-
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
905
|
-
* @related b.guardFilename.gate, b.guardFilename.buildProfile
|
|
906
|
-
*
|
|
907
|
-
* Look up a compliance-posture overlay by name (`"hipaa"` /
|
|
908
|
-
* `"pci-dss"` / `"gdpr"` / `"soc2"`). Returns the posture object —
|
|
909
|
-
* the caller may mutate freely. Throws
|
|
910
|
-
* `GuardFilenameError("filename.bad-posture")` on unknown name.
|
|
911
|
-
*
|
|
912
|
-
* @example
|
|
913
|
-
* var posture = b.guardFilename.compliancePosture("hipaa");
|
|
914
|
-
* posture.requireAscii; // → true
|
|
915
|
-
* posture.shellExecExtPolicy; // → "reject"
|
|
916
|
-
*/
|
|
917
|
-
function compliancePosture(name) {
|
|
918
|
-
return gateContract.lookupCompliancePosture(name, COMPLIANCE_POSTURES, _err, "filename");
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
var _filenameRulePacks = gateContract.makeRulePackLoader(GuardFilenameError, "filename");
|
|
922
|
-
/**
|
|
923
|
-
* @primitive b.guardFilename.loadRulePack
|
|
924
|
-
* @signature b.guardFilename.loadRulePack(pack)
|
|
925
|
-
* @since 0.7.5
|
|
926
|
-
* @status stable
|
|
927
|
-
* @related b.guardFilename.gate
|
|
928
|
-
*
|
|
929
|
-
* Register an operator-supplied rule pack with the guard-filename
|
|
930
|
-
* registry. The pack is identified by `pack.id` (non-empty string)
|
|
931
|
-
* and stored for later inspection / dispatch by gates that opt in
|
|
932
|
-
* via `opts.rulePackId`. Returns the pack object unchanged on
|
|
933
|
-
* success; throws `GuardFilenameError("filename.bad-opt")` when
|
|
934
|
-
* `pack` is missing or `pack.id` is not a non-empty string.
|
|
935
|
-
*
|
|
936
|
-
* @example
|
|
937
|
-
* var pack = b.guardFilename.loadRulePack({
|
|
938
|
-
* id: "tenant-uploads-policy",
|
|
939
|
-
* rules: [
|
|
940
|
-
* { id: "tenant-prefix", severity: "high",
|
|
941
|
-
* detect: function (n) { return n.indexOf("tenant_") !== 0; },
|
|
942
|
-
* reason: "tenant policy: filenames must be tenant_-prefixed" },
|
|
943
|
-
* ],
|
|
944
|
-
* });
|
|
945
|
-
* pack.id; // → "tenant-uploads-policy"
|
|
946
|
-
*/
|
|
947
|
-
var loadRulePack = _filenameRulePacks.load;
|
|
874
|
+
// buildProfile / compliancePosture / loadRulePack are assembled by
|
|
875
|
+
// gateContract.defineGuard below; their wiki sections render from the
|
|
876
|
+
// single-sourced @abiTemplate blocks in gate-contract.js, instantiated
|
|
877
|
+
// per guard by the page generator.
|
|
948
878
|
|
|
949
879
|
// ---- verifyExtractionPath -------------------------------------------------
|
|
950
880
|
|
|
@@ -1212,35 +1142,41 @@ function verifyExtractionPath(entryName, extractionRoot, opts) {
|
|
|
1212
1142
|
return stringResolved;
|
|
1213
1143
|
}
|
|
1214
1144
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1145
|
+
// ---- guard-* family identity ----
|
|
1146
|
+
// Filename is a different axis from content-bytes (operators typically
|
|
1147
|
+
// apply both: guardFilename on the upload's name, plus guardCsv /
|
|
1148
|
+
// guardHtml / guardSvg / etc. on the body). guard-filename is therefore
|
|
1149
|
+
// a STANDALONE primitive — it does NOT register into b.guardAll's
|
|
1150
|
+
// content-type-routed dispatch (no canonical mime / ext per the registry
|
|
1151
|
+
// contract). Operators wire it directly via b.fileUpload({ filenameSafety:
|
|
1152
|
+
// gate }) and similar host opts.
|
|
1153
|
+
var INTEGRATION_FIXTURES = Object.freeze({
|
|
1154
|
+
kind: "filename",
|
|
1155
|
+
benignFilename: "report-2026-Q1.txt",
|
|
1156
|
+
// Hostile: path-traversal in filename (CWE-22 class).
|
|
1157
|
+
hostileFilename: "../etc/passwd",
|
|
1158
|
+
});
|
|
1159
|
+
|
|
1160
|
+
// Assembled from the gate-contract guard factory. KIND "filename" makes
|
|
1161
|
+
// the default gate read ctx.filename || ctx.name, but this guard passes
|
|
1162
|
+
// its own bespoke `gate` (the per-policy canSanitize matrix), so the
|
|
1163
|
+
// factory only supplies the error class, registry exports, buildProfile /
|
|
1164
|
+
// compliancePosture / loadRulePack wiring, and the verifyExtractionPath /
|
|
1165
|
+
// WIN_RESERVED_NAMES / SHELL_EXEC_EXTS extras.
|
|
1166
|
+
module.exports = gateContract.defineGuard({
|
|
1167
|
+
name: "filename",
|
|
1168
|
+
kind: "filename",
|
|
1169
|
+
errorClass: GuardFilenameError,
|
|
1170
|
+
profiles: PROFILES,
|
|
1171
|
+
defaults: DEFAULTS,
|
|
1172
|
+
postures: COMPLIANCE_POSTURES,
|
|
1173
|
+
integrationFixtures: INTEGRATION_FIXTURES,
|
|
1174
|
+
validate: validate,
|
|
1175
|
+
sanitize: sanitize,
|
|
1176
|
+
gate: gate,
|
|
1177
|
+
extra: {
|
|
1178
|
+
WIN_RESERVED_NAMES: WIN_RESERVED_NAMES,
|
|
1179
|
+
SHELL_EXEC_EXTS: SHELL_EXEC_EXTS,
|
|
1180
|
+
verifyExtractionPath: verifyExtractionPath,
|
|
1181
|
+
},
|
|
1182
|
+
});
|
package/lib/guard-graphql.js
CHANGED
|
@@ -87,8 +87,6 @@ var { GuardGraphqlError } = require("./framework-error");
|
|
|
87
87
|
var observability = lazyRequire(function () { return require("./observability"); });
|
|
88
88
|
void observability;
|
|
89
89
|
|
|
90
|
-
var _err = GuardGraphqlError.factory;
|
|
91
|
-
|
|
92
90
|
// Query-body proto-poison literal (CVE-2026-32621). Matches the bare
|
|
93
91
|
// identifier in field / alias / variable-declaration positions —
|
|
94
92
|
// `$__proto__: String`, `__proto__: realField`, `__proto__ { ... }`,
|
|
@@ -544,12 +542,7 @@ function validate(input, opts) {
|
|
|
544
542
|
function sanitize(input, opts) {
|
|
545
543
|
opts = _resolveOpts(opts);
|
|
546
544
|
var issues = _detectIssues(input, opts);
|
|
547
|
-
|
|
548
|
-
if (issues[i].severity === "critical" || issues[i].severity === "high") {
|
|
549
|
-
throw _err(issues[i].ruleId || "graphql.refused",
|
|
550
|
-
"guardGraphql.sanitize: " + issues[i].snippet);
|
|
551
|
-
}
|
|
552
|
-
}
|
|
545
|
+
gateContract.throwOnRefusalSeverity(issues, { errorClass: GuardGraphqlError, codePrefix: "graphql" });
|
|
553
546
|
return input;
|
|
554
547
|
}
|
|
555
548
|
|
|
@@ -612,120 +605,46 @@ function gate(opts) {
|
|
|
612
605
|
});
|
|
613
606
|
}
|
|
614
607
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
* @since 0.7.49
|
|
619
|
-
* @status stable
|
|
620
|
-
* @related b.guardGraphql.gate, b.guardGraphql.compliancePosture
|
|
621
|
-
*
|
|
622
|
-
* Compose a derived profile from one or more named bases plus
|
|
623
|
-
* inline overrides. `opts.extends` is a profile name (`"strict"` /
|
|
624
|
-
* `"balanced"` / `"permissive"`) or an array of names; later
|
|
625
|
-
* entries shadow earlier ones, and inline `opts` keys win last.
|
|
626
|
-
* Operators stage profile overlays here so the final shape is
|
|
627
|
-
* traceable to a baseline rather than a hand-typed dictionary.
|
|
628
|
-
*
|
|
629
|
-
* @opts
|
|
630
|
-
* extends: string|string[], // base profile name(s) to compose
|
|
631
|
-
* ...: any guardGraphql key, // inline override of resolved keys
|
|
632
|
-
*
|
|
633
|
-
* @example
|
|
634
|
-
* var custom = b.guardGraphql.buildProfile({
|
|
635
|
-
* extends: "balanced",
|
|
636
|
-
* introspectionPolicy: "reject",
|
|
637
|
-
* maxDepth: 6,
|
|
638
|
-
* });
|
|
639
|
-
* custom.introspectionPolicy; // → "reject"
|
|
640
|
-
* custom.maxDepth; // → 6
|
|
641
|
-
*/
|
|
642
|
-
var buildProfile = gateContract.makeProfileBuilder(PROFILES);
|
|
643
|
-
|
|
644
|
-
/**
|
|
645
|
-
* @primitive b.guardGraphql.compliancePosture
|
|
646
|
-
* @signature b.guardGraphql.compliancePosture(name)
|
|
647
|
-
* @since 0.7.49
|
|
648
|
-
* @status stable
|
|
649
|
-
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
650
|
-
* @related b.guardGraphql.gate, b.guardGraphql.buildProfile
|
|
651
|
-
*
|
|
652
|
-
* Look up a compliance-posture overlay by name (`"hipaa"` /
|
|
653
|
-
* `"pci-dss"` / `"gdpr"` / `"soc2"`). Returns a shallow clone of
|
|
654
|
-
* the posture object — the caller may mutate freely. Throws
|
|
655
|
-
* `GuardGraphqlError("graphql.bad-posture")` on unknown name.
|
|
656
|
-
* Postures extend the strict profile (or balanced for `gdpr`)
|
|
657
|
-
* with a `forensicSnippetBytes` cap appropriate to the regime.
|
|
658
|
-
*
|
|
659
|
-
* @example
|
|
660
|
-
* var posture = b.guardGraphql.compliancePosture("soc2");
|
|
661
|
-
* posture.introspectionPolicy; // → "reject"
|
|
662
|
-
* posture.forensicSnippetBytes; // → 1024
|
|
663
|
-
*/
|
|
664
|
-
function compliancePosture(name) {
|
|
665
|
-
return gateContract.lookupCompliancePosture(name, COMPLIANCE_POSTURES,
|
|
666
|
-
_err, "graphql");
|
|
667
|
-
}
|
|
608
|
+
// buildProfile / compliancePosture / loadRulePack are assembled by
|
|
609
|
+
// gateContract.defineGuard below — their wiki sections render from the
|
|
610
|
+
// single-sourced @abiTemplate blocks in gate-contract.js.
|
|
668
611
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
* detect: function (req) { return /^\s*mutation\b/.test(req.query || ""); },
|
|
690
|
-
* reason: "read-replica refuses mutation operations" },
|
|
691
|
-
* ],
|
|
692
|
-
* });
|
|
693
|
-
* pack.id; // → "no-mutation-on-read-replica"
|
|
694
|
-
*/
|
|
695
|
-
var loadRulePack = _gqlRulePacks.load;
|
|
612
|
+
// ---- adaptive integration-test fixtures (consumed by layer-5 host harness) ----
|
|
613
|
+
var INTEGRATION_FIXTURES = Object.freeze({
|
|
614
|
+
kind: "graphql-request",
|
|
615
|
+
benignBytes: Buffer.from(JSON.stringify({
|
|
616
|
+
query: "query GetMe { me { id name } }",
|
|
617
|
+
operationName: "GetMe",
|
|
618
|
+
}), "utf8"),
|
|
619
|
+
hostileBytes: Buffer.from(JSON.stringify({
|
|
620
|
+
query: "query Inspect { __schema { types { name } } }",
|
|
621
|
+
operationName: "Inspect",
|
|
622
|
+
}), "utf8"),
|
|
623
|
+
benignGraphqlRequest: {
|
|
624
|
+
query: "query GetMe { me { id name } }",
|
|
625
|
+
operationName: "GetMe",
|
|
626
|
+
},
|
|
627
|
+
hostileGraphqlRequest: {
|
|
628
|
+
query: "query Inspect { __schema { types { name } } }",
|
|
629
|
+
operationName: "Inspect",
|
|
630
|
+
},
|
|
631
|
+
});
|
|
696
632
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
hostileGraphqlRequest: {
|
|
716
|
-
query: "query Inspect { __schema { types { name } } }",
|
|
717
|
-
operationName: "Inspect",
|
|
718
|
-
},
|
|
719
|
-
}),
|
|
720
|
-
// ---- primitive surface ----
|
|
721
|
-
validate: validate,
|
|
722
|
-
sanitize: sanitize,
|
|
723
|
-
gate: gate,
|
|
724
|
-
buildProfile: buildProfile,
|
|
725
|
-
compliancePosture: compliancePosture,
|
|
726
|
-
loadRulePack: loadRulePack,
|
|
727
|
-
PROFILES: PROFILES,
|
|
728
|
-
DEFAULTS: DEFAULTS,
|
|
729
|
-
COMPLIANCE_POSTURES: COMPLIANCE_POSTURES,
|
|
730
|
-
GuardGraphqlError: GuardGraphqlError,
|
|
731
|
-
};
|
|
633
|
+
// Assembled from the gate-contract guard factory: error class, registry
|
|
634
|
+
// exports (NAME / KIND / INTEGRATION_FIXTURES), buildProfile /
|
|
635
|
+
// compliancePosture / loadRulePack wiring, plus the per-guard inspection
|
|
636
|
+
// surface (validate / sanitize / bespoke gate) passed through verbatim.
|
|
637
|
+
// The custom KIND ("graphql-request") is accepted because the bespoke
|
|
638
|
+
// gate reads its own ctx fields (ctx.graphqlRequest / ctx.gql).
|
|
639
|
+
module.exports = gateContract.defineGuard({
|
|
640
|
+
name: "graphql",
|
|
641
|
+
kind: "graphql-request",
|
|
642
|
+
errorClass: GuardGraphqlError,
|
|
643
|
+
profiles: PROFILES,
|
|
644
|
+
defaults: DEFAULTS,
|
|
645
|
+
postures: COMPLIANCE_POSTURES,
|
|
646
|
+
integrationFixtures: INTEGRATION_FIXTURES,
|
|
647
|
+
validate: validate,
|
|
648
|
+
sanitize: sanitize,
|
|
649
|
+
gate: gate,
|
|
650
|
+
});
|
package/lib/guard-html.js
CHANGED
|
@@ -1096,114 +1096,59 @@ function gate(opts) {
|
|
|
1096
1096
|
});
|
|
1097
1097
|
}
|
|
1098
1098
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
*
|
|
1105
|
-
* Resolve a named profile against `PROFILES` and return the merged
|
|
1106
|
-
* options bag. Operators introspecting the active limits (without
|
|
1107
|
-
* calling `validate` / `sanitize` / `gate`) call this. Throws
|
|
1108
|
-
* `GuardHtmlError` with code `html.bad-profile` when the name
|
|
1109
|
-
* doesn't appear in the profile catalog.
|
|
1110
|
-
*
|
|
1111
|
-
* @opts
|
|
1112
|
-
* profile: string, // "strict" | "balanced" | "permissive"
|
|
1113
|
-
*
|
|
1114
|
-
* @example
|
|
1115
|
-
* var resolved = b.guardHtml.buildProfile({ profile: "strict" });
|
|
1116
|
-
* resolved.maxBytes; // → 2097152 (2 MiB)
|
|
1117
|
-
* resolved.maxAttrValueBytes; // → 8192 (8 KiB)
|
|
1118
|
-
*/
|
|
1119
|
-
var buildProfile = gateContract.makeProfileBuilder(PROFILES);
|
|
1120
|
-
|
|
1121
|
-
/**
|
|
1122
|
-
* @primitive b.guardHtml.compliancePosture
|
|
1123
|
-
* @signature b.guardHtml.compliancePosture(name)
|
|
1124
|
-
* @since 0.7.6
|
|
1125
|
-
* @related b.guardHtml.buildProfile, b.guardHtml.gate
|
|
1126
|
-
*
|
|
1127
|
-
* Return the option overlay for a named compliance posture
|
|
1128
|
-
* (`hipaa` / `pci-dss` / `gdpr` / `soc2`). Operators compose this
|
|
1129
|
-
* over a base profile to harden the default per regulatory regime.
|
|
1130
|
-
* Throws `GuardHtmlError` with code `html.bad-posture` on unknown
|
|
1131
|
-
* names.
|
|
1132
|
-
*
|
|
1133
|
-
* @example
|
|
1134
|
-
* var hipaa = b.guardHtml.compliancePosture("hipaa");
|
|
1135
|
-
* hipaa.bidiPolicy; // → "reject"
|
|
1136
|
-
* hipaa.cssPolicy; // → "reject"
|
|
1137
|
-
* hipaa.mxssHintPolicy; // → "reject"
|
|
1138
|
-
*/
|
|
1139
|
-
function compliancePosture(name) {
|
|
1140
|
-
return gateContract.lookupCompliancePosture(name, COMPLIANCE_POSTURES, _err, "html");
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
/**
|
|
1144
|
-
* @primitive b.guardHtml.loadRulePack
|
|
1145
|
-
* @signature b.guardHtml.loadRulePack(pack)
|
|
1146
|
-
* @since 0.7.6
|
|
1147
|
-
* @related b.guardHtml.gate, b.guardHtml.buildProfile
|
|
1148
|
-
*
|
|
1149
|
-
* Register an operator-supplied rule pack (a versioned bundle of
|
|
1150
|
-
* extra tag / attribute / scheme overrides) into the guard's
|
|
1151
|
-
* private store. Subsequent `gate` calls referencing the pack by
|
|
1152
|
-
* its `id` overlay these rules on top of the resolved profile.
|
|
1153
|
-
* Validates pack shape and throws `GuardHtmlError` on malformed
|
|
1154
|
-
* input.
|
|
1155
|
-
*
|
|
1156
|
-
* @example
|
|
1157
|
-
* b.guardHtml.loadRulePack({
|
|
1158
|
-
* id: "kb-2026-html",
|
|
1159
|
-
* version: "1.0.0",
|
|
1160
|
-
* extraDangerousTags: ["custom-element"],
|
|
1161
|
-
* });
|
|
1162
|
-
*/
|
|
1163
|
-
var _htmlRulePacks = gateContract.makeRulePackLoader(GuardHtmlError, "html");
|
|
1164
|
-
var loadRulePack = _htmlRulePacks.load;
|
|
1099
|
+
// buildProfile / compliancePosture / loadRulePack are assembled by
|
|
1100
|
+
// gateContract.defineGuard below (makeProfileBuilder(PROFILES) /
|
|
1101
|
+
// lookupCompliancePosture(_, COMPLIANCE_POSTURES) / makeRulePackLoader).
|
|
1102
|
+
// Their wiki sections render from the single-sourced @abiTemplate blocks
|
|
1103
|
+
// in gate-contract.js, instantiated per guard by the page generator.
|
|
1165
1104
|
|
|
1166
1105
|
void safeUrl; // reserved for future scheme-allowlist composition
|
|
1167
1106
|
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1107
|
+
var INTEGRATION_FIXTURES = Object.freeze({
|
|
1108
|
+
kind: "content",
|
|
1109
|
+
contentType: "text/html",
|
|
1110
|
+
extension: ".html",
|
|
1111
|
+
benignBytes: Buffer.from("<p>hello world</p>", "utf8"),
|
|
1112
|
+
// Hostile: <script> tag is in the dangerous-tag denylist; refused
|
|
1113
|
+
// unconditionally regardless of profile.
|
|
1114
|
+
hostileBytes: Buffer.from('<p>hi</p><script>alert(1)</script>', "utf8"),
|
|
1115
|
+
});
|
|
1116
|
+
|
|
1117
|
+
// Assembled from the gate-contract guard factory: error class, registry
|
|
1118
|
+
// exports (NAME / KIND / MIME_TYPES / EXTENSIONS / INTEGRATION_FIXTURES),
|
|
1119
|
+
// buildProfile / compliancePosture / loadRulePack wiring, plus the
|
|
1120
|
+
// per-guard inspection surface (validate / sanitize) and HTML extras
|
|
1121
|
+
// (escapeText / escapeAttr / wcag + the tag/attr/scheme/clobber tables)
|
|
1122
|
+
// passed through verbatim. The bespoke `gate` carries HTML's
|
|
1123
|
+
// sanitize-and-reemit chain unchanged.
|
|
1124
|
+
module.exports = gateContract.defineGuard({
|
|
1125
|
+
name: "html",
|
|
1126
|
+
kind: "content",
|
|
1127
|
+
errorClass: GuardHtmlError,
|
|
1128
|
+
profiles: PROFILES,
|
|
1129
|
+
defaults: DEFAULTS,
|
|
1130
|
+
postures: COMPLIANCE_POSTURES,
|
|
1131
|
+
mimeTypes: ["text/html", "application/xhtml+xml"],
|
|
1132
|
+
extensions: [".html", ".htm", ".xhtml"],
|
|
1133
|
+
integrationFixtures: INTEGRATION_FIXTURES,
|
|
1134
|
+
validate: validate,
|
|
1135
|
+
sanitize: sanitize,
|
|
1136
|
+
gate: gate,
|
|
1137
|
+
extra: {
|
|
1138
|
+
escapeText: escapeText,
|
|
1139
|
+
escapeAttr: escapeAttr,
|
|
1140
|
+
DANGEROUS_TAGS: DANGEROUS_TAGS,
|
|
1141
|
+
STRICT_ALLOWED_TAGS: STRICT_ALLOWED_TAGS,
|
|
1142
|
+
BALANCED_ALLOWED_TAGS: BALANCED_ALLOWED_TAGS,
|
|
1143
|
+
PERMISSIVE_ALLOWED_TAGS: PERMISSIVE_ALLOWED_TAGS,
|
|
1144
|
+
DANGEROUS_ATTRS: DANGEROUS_ATTRS,
|
|
1145
|
+
URL_ATTRS: URL_ATTRS,
|
|
1146
|
+
SAFE_SCHEMES: SAFE_SCHEMES,
|
|
1147
|
+
DANGEROUS_SCHEMES: DANGEROUS_SCHEMES,
|
|
1148
|
+
CLOBBER_GLOBALS: CLOBBER_GLOBALS,
|
|
1149
|
+
CLOBBER_PRONE_TAGS: CLOBBER_PRONE_TAGS,
|
|
1150
|
+
// WCAG 2.2 audit-only mode (b.guardHtml.wcag.audit) — accessibility
|
|
1151
|
+
// scanner that emits violations without modifying HTML.
|
|
1152
|
+
wcag: guardHtmlWcag,
|
|
1153
|
+
},
|
|
1154
|
+
});
|