@blamejs/core 0.8.43 → 0.8.50
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 +93 -0
- package/README.md +10 -10
- package/index.js +52 -0
- package/lib/a2a.js +159 -34
- package/lib/acme.js +762 -0
- package/lib/ai-pref.js +166 -43
- package/lib/api-key.js +108 -47
- package/lib/api-snapshot.js +157 -40
- package/lib/app-shutdown.js +113 -77
- package/lib/archive.js +337 -40
- package/lib/arg-parser.js +697 -0
- package/lib/asyncapi.js +99 -55
- package/lib/atomic-file.js +465 -104
- package/lib/audit-chain.js +123 -34
- package/lib/audit-daily-review.js +389 -0
- package/lib/audit-sign.js +302 -56
- package/lib/audit-tools.js +412 -63
- package/lib/audit.js +656 -35
- package/lib/auth/jwt-external.js +17 -0
- package/lib/auth/oauth.js +7 -0
- package/lib/auth-bot-challenge.js +505 -0
- package/lib/auth-header.js +92 -25
- package/lib/backup/bundle.js +26 -0
- package/lib/backup/index.js +512 -89
- package/lib/backup/manifest.js +168 -7
- package/lib/break-glass.js +415 -39
- package/lib/budr.js +103 -30
- package/lib/bundler.js +86 -66
- package/lib/cache.js +192 -72
- package/lib/chain-writer.js +65 -40
- package/lib/circuit-breaker.js +56 -33
- package/lib/cli-helpers.js +106 -75
- package/lib/cli.js +6 -30
- package/lib/cloud-events.js +99 -32
- package/lib/cluster-storage.js +162 -37
- package/lib/cluster.js +340 -49
- package/lib/codepoint-class.js +66 -0
- package/lib/compliance.js +424 -24
- package/lib/config-drift.js +111 -46
- package/lib/config.js +94 -40
- package/lib/consent.js +165 -18
- package/lib/constants.js +1 -0
- package/lib/content-credentials.js +153 -48
- package/lib/cookies.js +154 -62
- package/lib/credential-hash.js +133 -61
- package/lib/crypto-field.js +702 -18
- package/lib/crypto-hpke.js +256 -0
- package/lib/crypto.js +744 -22
- package/lib/csv.js +178 -35
- package/lib/daemon.js +456 -0
- package/lib/dark-patterns.js +186 -55
- package/lib/db-query.js +79 -2
- package/lib/db.js +1431 -60
- package/lib/ddl-change-control.js +523 -0
- package/lib/deprecate.js +195 -40
- package/lib/dev.js +82 -39
- package/lib/dora.js +67 -48
- package/lib/dr-runbook.js +368 -0
- package/lib/dsr.js +142 -11
- package/lib/dual-control.js +91 -56
- package/lib/events.js +120 -41
- package/lib/external-db-migrate.js +192 -2
- package/lib/external-db.js +795 -50
- package/lib/fapi2.js +122 -1
- package/lib/fda-21cfr11.js +395 -0
- package/lib/fdx.js +132 -2
- package/lib/file-type.js +87 -0
- package/lib/file-upload.js +93 -0
- package/lib/flag.js +82 -20
- package/lib/forms.js +132 -29
- package/lib/framework-error.js +169 -0
- package/lib/framework-schema.js +163 -35
- package/lib/gate-contract.js +849 -175
- package/lib/graphql-federation.js +68 -7
- package/lib/guard-all.js +172 -55
- package/lib/guard-archive.js +286 -124
- package/lib/guard-auth.js +194 -21
- package/lib/guard-cidr.js +190 -28
- package/lib/guard-csv.js +397 -51
- package/lib/guard-domain.js +213 -91
- package/lib/guard-email.js +236 -29
- package/lib/guard-filename.js +307 -75
- package/lib/guard-graphql.js +263 -30
- package/lib/guard-html.js +310 -116
- package/lib/guard-image.js +243 -30
- package/lib/guard-json.js +260 -54
- package/lib/guard-jsonpath.js +235 -23
- package/lib/guard-jwt.js +284 -30
- package/lib/guard-markdown.js +204 -22
- package/lib/guard-mime.js +190 -26
- package/lib/guard-oauth.js +277 -28
- package/lib/guard-pdf.js +251 -27
- package/lib/guard-regex.js +226 -18
- package/lib/guard-shell.js +229 -26
- package/lib/guard-svg.js +177 -10
- package/lib/guard-template.js +232 -21
- package/lib/guard-time.js +195 -29
- package/lib/guard-uuid.js +189 -30
- package/lib/guard-xml.js +259 -36
- package/lib/guard-yaml.js +241 -44
- package/lib/honeytoken.js +63 -27
- package/lib/html-balance.js +83 -0
- package/lib/http-client.js +486 -59
- package/lib/http-message-signature.js +582 -0
- package/lib/i18n.js +102 -49
- package/lib/iab-mspa.js +112 -32
- package/lib/iab-tcf.js +107 -2
- package/lib/inbox.js +90 -52
- package/lib/keychain.js +865 -0
- package/lib/legal-hold.js +374 -0
- package/lib/local-db-thin.js +320 -0
- package/lib/log-stream.js +281 -51
- package/lib/log.js +184 -86
- package/lib/mail-bounce.js +107 -62
- package/lib/mail.js +295 -58
- package/lib/mcp.js +108 -27
- package/lib/metrics.js +98 -89
- package/lib/middleware/age-gate.js +36 -0
- package/lib/middleware/ai-act-disclosure.js +37 -0
- package/lib/middleware/api-encrypt.js +45 -0
- package/lib/middleware/assetlinks.js +40 -0
- package/lib/middleware/asyncapi-serve.js +35 -0
- package/lib/middleware/attach-user.js +40 -0
- package/lib/middleware/bearer-auth.js +40 -0
- package/lib/middleware/body-parser.js +230 -0
- package/lib/middleware/bot-disclose.js +34 -0
- package/lib/middleware/bot-guard.js +39 -0
- package/lib/middleware/compression.js +37 -0
- package/lib/middleware/cookies.js +32 -0
- package/lib/middleware/cors.js +40 -0
- package/lib/middleware/csp-nonce.js +40 -0
- package/lib/middleware/csp-report.js +34 -0
- package/lib/middleware/csrf-protect.js +43 -0
- package/lib/middleware/daily-byte-quota.js +53 -85
- package/lib/middleware/db-role-for.js +40 -0
- package/lib/middleware/dpop.js +40 -0
- package/lib/middleware/error-handler.js +37 -14
- package/lib/middleware/fetch-metadata.js +39 -0
- package/lib/middleware/flag-context.js +34 -0
- package/lib/middleware/gpc.js +33 -0
- package/lib/middleware/headers.js +35 -0
- package/lib/middleware/health.js +46 -0
- package/lib/middleware/host-allowlist.js +30 -0
- package/lib/middleware/network-allowlist.js +38 -0
- package/lib/middleware/openapi-serve.js +34 -0
- package/lib/middleware/rate-limit.js +160 -18
- package/lib/middleware/request-id.js +36 -18
- package/lib/middleware/request-log.js +37 -0
- package/lib/middleware/require-aal.js +29 -0
- package/lib/middleware/require-auth.js +32 -0
- package/lib/middleware/require-bound-key.js +41 -0
- package/lib/middleware/require-content-type.js +32 -0
- package/lib/middleware/require-methods.js +27 -0
- package/lib/middleware/require-mtls.js +33 -0
- package/lib/middleware/require-step-up.js +37 -0
- package/lib/middleware/security-headers.js +44 -0
- package/lib/middleware/security-txt.js +38 -0
- package/lib/middleware/span-http-server.js +37 -0
- package/lib/middleware/sse.js +36 -0
- package/lib/middleware/trace-log-correlation.js +33 -0
- package/lib/middleware/trace-propagate.js +32 -0
- package/lib/middleware/tus-upload.js +90 -0
- package/lib/middleware/web-app-manifest.js +53 -0
- package/lib/mtls-ca.js +100 -70
- package/lib/network-byte-quota.js +308 -0
- package/lib/network-heartbeat.js +135 -0
- package/lib/network-tls.js +534 -4
- package/lib/network.js +103 -0
- package/lib/notify.js +114 -43
- package/lib/ntp-check.js +192 -51
- package/lib/observability.js +145 -47
- package/lib/openapi.js +90 -44
- package/lib/outbox.js +99 -1
- package/lib/pagination.js +168 -86
- package/lib/parsers/index.js +16 -5
- package/lib/permissions.js +93 -40
- package/lib/pqc-agent.js +84 -8
- package/lib/pqc-software.js +94 -60
- package/lib/process-spawn.js +95 -21
- package/lib/pubsub.js +96 -66
- package/lib/queue.js +375 -54
- package/lib/redact.js +793 -21
- package/lib/render.js +139 -47
- package/lib/request-helpers.js +485 -121
- package/lib/restore-bundle.js +142 -39
- package/lib/restore-rollback.js +136 -45
- package/lib/retention.js +178 -50
- package/lib/retry.js +116 -33
- package/lib/router.js +475 -23
- package/lib/safe-async.js +543 -94
- package/lib/safe-buffer.js +337 -41
- package/lib/safe-json.js +467 -62
- package/lib/safe-jsonpath.js +285 -0
- package/lib/safe-schema.js +631 -87
- package/lib/safe-sql.js +221 -59
- package/lib/safe-url.js +278 -46
- package/lib/sandbox-worker.js +135 -0
- package/lib/sandbox.js +358 -0
- package/lib/scheduler.js +135 -70
- package/lib/self-update.js +647 -0
- package/lib/session-device-binding.js +431 -0
- package/lib/session.js +259 -49
- package/lib/slug.js +138 -26
- package/lib/ssrf-guard.js +316 -56
- package/lib/storage.js +433 -70
- package/lib/subject.js +405 -23
- package/lib/template.js +148 -8
- package/lib/tenant-quota.js +545 -0
- package/lib/testing.js +440 -53
- package/lib/time.js +291 -23
- package/lib/tls-exporter.js +239 -0
- package/lib/tracing.js +90 -74
- package/lib/uuid.js +97 -22
- package/lib/vault/index.js +284 -22
- package/lib/vault/seal-pem-file.js +66 -0
- package/lib/watcher.js +368 -0
- package/lib/webhook.js +196 -63
- package/lib/websocket.js +393 -68
- package/lib/wiki-concepts.js +338 -0
- package/lib/worker-pool.js +464 -0
- package/package.json +3 -3
- package/sbom.cyclonedx.json +7 -7
package/lib/guard-graphql.js
CHANGED
|
@@ -1,38 +1,80 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* @module b.guardGraphql
|
|
4
|
+
* @nav Guards
|
|
5
|
+
* @title Guard Graphql
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* @intro
|
|
8
|
+
* GraphQL request-shape safety guard — validates user-supplied
|
|
9
|
+
* request bundles against the canonical query-shape DoS catalog
|
|
10
|
+
* BEFORE the framework hands the query to a schema-aware
|
|
11
|
+
* executor. KIND is `graphql-request`; the gate consumes
|
|
12
|
+
* `ctx.graphqlRequest` (or `ctx.gql`) shape `{ query,
|
|
13
|
+
* operationName?, variables?, extensions? }`. Pair downstream
|
|
14
|
+
* with the operator's schema-aware parser — this layer is the
|
|
15
|
+
* shape / depth / breadth contract that runs before any
|
|
16
|
+
* schema-resolution work.
|
|
10
17
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* (string for ID expecting Int, object for scalar). Many
|
|
19
|
-
* executors coerce silently; the guard refuses non-shape-matching
|
|
20
|
-
* types when the operator declares variable shapes.
|
|
21
|
-
* - Introspection in production — `__schema` / `__type` queries
|
|
22
|
-
* leak schema details; refused unless operator opts in.
|
|
23
|
-
* - Batch query DoS — operators supporting [{},{}] batch arrays
|
|
24
|
-
* get N requests for one HTTP hit; the guard caps batch length.
|
|
25
|
-
* - Persisted-query opt-in — when operatorRequiresPersistedQuery,
|
|
26
|
-
* refuse free-form queries that don't carry a persisted-query
|
|
27
|
-
* hash extension.
|
|
28
|
-
* - Operation-name allowlist — operator may pin operationName to
|
|
29
|
-
* a whitelist of named operations (denylist for ad-hoc queries).
|
|
30
|
-
* - Excessive query / variable / total byte length — parser DoS.
|
|
31
|
-
* - BIDI / null / control / zero-width universal refuse on the
|
|
32
|
-
* query string.
|
|
18
|
+
* Query depth caps: deeply-nested selection sets multiply
|
|
19
|
+
* exponentially against schema depth, bypassing per-field rate
|
|
20
|
+
* limits. The gate's `_measureQueryShape` walker counts
|
|
21
|
+
* brace-depth without a full lex/parse (the operator's executor
|
|
22
|
+
* handles full parsing); strict caps at 8, balanced 12,
|
|
23
|
+
* permissive 24. The cap fires as `graphql.depth-exceeded` —
|
|
24
|
+
* the canonical N²-amplification DoS class.
|
|
33
25
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
26
|
+
* Alias-amplification caps: the same field repeated under
|
|
27
|
+
* different aliases (`a:friend b:friend c:friend ...`) bypasses
|
|
28
|
+
* per-field limits because each alias is a separate selection.
|
|
29
|
+
* Strict caps at 8 aliases per selection-set, balanced 16,
|
|
30
|
+
* permissive 32. Fires as `graphql.alias-bomb` —
|
|
31
|
+
* breadth-amplification DoS class.
|
|
32
|
+
*
|
|
33
|
+
* Fragment-cycle defense: operator's executor handles cyclic
|
|
34
|
+
* fragment refs at parse time; the guard's contribution is the
|
|
35
|
+
* total-bytes cap (`maxBytes`) and per-query cap
|
|
36
|
+
* (`maxQueryBytes`), which bound the worst-case parser-DoS
|
|
37
|
+
* shape regardless of cycle structure.
|
|
38
|
+
*
|
|
39
|
+
* Introspection toggle: `__schema` / `__type` queries leak
|
|
40
|
+
* schema details and tooling expects them in development but
|
|
41
|
+
* not production. Strict refuses (production posture); balanced
|
|
42
|
+
* audits; permissive allows. Detection is substring-match on
|
|
43
|
+
* the query string — fast and impossible to evade with
|
|
44
|
+
* whitespace tricks.
|
|
45
|
+
*
|
|
46
|
+
* Persisted-query allowlist: when the operator opts in via
|
|
47
|
+
* `persistedQueryPolicy: "require"`, the request must carry
|
|
48
|
+
* `extensions.persistedQuery.sha256Hash`. Free-form queries
|
|
49
|
+
* are refused as `graphql.persisted-query-missing` — eliminates
|
|
50
|
+
* ad-hoc query attack surface entirely (operator pre-approves
|
|
51
|
+
* the catalog of permitted queries by hash).
|
|
52
|
+
*
|
|
53
|
+
* Operation-name allowlist: when `opts.allowedOperations` is
|
|
54
|
+
* set, the request `operationName` must be in the list.
|
|
55
|
+
* Complements the persisted-query approach for operators that
|
|
56
|
+
* keep free-form queries on but want a denylist for ad-hoc
|
|
57
|
+
* shapes.
|
|
58
|
+
*
|
|
59
|
+
* Variable shape validation: when `opts.variableShapes` declares
|
|
60
|
+
* `{ varName: "string"|"number"|"boolean"|"object" }`, the gate
|
|
61
|
+
* refuses any `variables` entry whose `typeof` doesn't match.
|
|
62
|
+
* Catches type-confusion exploits where executors silently
|
|
63
|
+
* coerce (string-for-ID-expecting-Int).
|
|
64
|
+
*
|
|
65
|
+
* Batch defense: operators supporting `[{},{}]` batch arrays get
|
|
66
|
+
* N requests for one HTTP hit. Strict refuses batches outright;
|
|
67
|
+
* balanced caps at 10; permissive 50. Each batch entry is
|
|
68
|
+
* validated with the same threat catalog applied recursively.
|
|
69
|
+
*
|
|
70
|
+
* Profiles: `strict` / `balanced` / `permissive`. Compliance
|
|
71
|
+
* postures: `hipaa` / `pci-dss` / `gdpr` / `soc2`. BIDI / null /
|
|
72
|
+
* control / zero-width universal-refuse applies on the query
|
|
73
|
+
* string at every profile so trojan-source codepoints can't
|
|
74
|
+
* ride inside a query identifier.
|
|
75
|
+
*
|
|
76
|
+
* @card
|
|
77
|
+
* GraphQL request-shape safety guard — validates user-supplied request bundles against the canonical query-shape DoS catalog BEFORE the framework hands the query to a schema-aware executor.
|
|
36
78
|
*/
|
|
37
79
|
|
|
38
80
|
var codepointClass = require("./codepoint-class");
|
|
@@ -370,6 +412,59 @@ function _detectIssues(req, opts) {
|
|
|
370
412
|
return issues;
|
|
371
413
|
}
|
|
372
414
|
|
|
415
|
+
/**
|
|
416
|
+
* @primitive b.guardGraphql.validate
|
|
417
|
+
* @signature b.guardGraphql.validate(input, opts?)
|
|
418
|
+
* @since 0.7.49
|
|
419
|
+
* @status stable
|
|
420
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
421
|
+
* @related b.guardGraphql.sanitize, b.guardGraphql.gate
|
|
422
|
+
*
|
|
423
|
+
* Apply the full guard-graphql threat catalog to a request bundle
|
|
424
|
+
* (or batch array). Returns `{ ok, issues, refusal? }` per
|
|
425
|
+
* `gateContract.aggregateIssues`. Detected classes include
|
|
426
|
+
* `query-missing`, `query-cap`, `variables-cap`, `request-cap`,
|
|
427
|
+
* `batch-size`, `introspection`, `persisted-query-missing`,
|
|
428
|
+
* `operation-not-allowed`, `depth-exceeded`, `alias-bomb`,
|
|
429
|
+
* `variable-type-confusion`, plus codepoint-class issues on the
|
|
430
|
+
* query string. Operator-supplied opts are bounds-checked; bad
|
|
431
|
+
* opts throw `GuardGraphqlError("graphql.bad-opt")`.
|
|
432
|
+
*
|
|
433
|
+
* @opts
|
|
434
|
+
* profile: "strict"|"balanced"|"permissive",
|
|
435
|
+
* compliance: "hipaa"|"pci-dss"|"gdpr"|"soc2",
|
|
436
|
+
* introspectionPolicy: "reject"|"audit"|"allow",
|
|
437
|
+
* persistedQueryPolicy: "require"|"audit"|"allow",
|
|
438
|
+
* operationNamePolicy: "reject"|"audit"|"allow",
|
|
439
|
+
* batchPolicy: "reject"|"audit"|"allow",
|
|
440
|
+
* aliasBombPolicy: "reject"|"audit"|"allow",
|
|
441
|
+
* depthPolicy: "reject"|"audit"|"allow",
|
|
442
|
+
* variableShapePolicy: "reject"|"audit"|"allow",
|
|
443
|
+
* allowedOperations: string[],
|
|
444
|
+
* variableShapes: { [name: string]: "string"|"number"|"boolean"|"object" },
|
|
445
|
+
* maxDepth: number,
|
|
446
|
+
* maxAliasesPerSelection: number,
|
|
447
|
+
* maxBatchSize: number,
|
|
448
|
+
* maxQueryBytes: number,
|
|
449
|
+
* maxVariableBytes: number,
|
|
450
|
+
* maxBytes: number,
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* var hostile = {
|
|
454
|
+
* query: "query Inspect { __schema { types { name } } }",
|
|
455
|
+
* operationName: "Inspect",
|
|
456
|
+
* };
|
|
457
|
+
* var rv = b.guardGraphql.validate(hostile, { profile: "strict" });
|
|
458
|
+
* rv.ok; // → false
|
|
459
|
+
* rv.issues[0].ruleId; // → "graphql.introspection"
|
|
460
|
+
*
|
|
461
|
+
* var benign = {
|
|
462
|
+
* query: "query GetMe { me { id name } }",
|
|
463
|
+
* operationName: "GetMe",
|
|
464
|
+
* };
|
|
465
|
+
* var ok = b.guardGraphql.validate(benign, { profile: "strict" });
|
|
466
|
+
* ok.ok; // → true
|
|
467
|
+
*/
|
|
373
468
|
function validate(input, opts) {
|
|
374
469
|
opts = _resolveOpts(opts);
|
|
375
470
|
numericBounds.requireAllPositiveFiniteIntIfPresent(opts,
|
|
@@ -379,6 +474,36 @@ function validate(input, opts) {
|
|
|
379
474
|
return gateContract.aggregateIssues(_detectIssues(input, opts));
|
|
380
475
|
}
|
|
381
476
|
|
|
477
|
+
/**
|
|
478
|
+
* @primitive b.guardGraphql.sanitize
|
|
479
|
+
* @signature b.guardGraphql.sanitize(input, opts?)
|
|
480
|
+
* @since 0.7.49
|
|
481
|
+
* @status stable
|
|
482
|
+
* @related b.guardGraphql.validate, b.guardGraphql.gate
|
|
483
|
+
*
|
|
484
|
+
* Pass-through-or-throw form of `validate`. GraphQL request
|
|
485
|
+
* bundles can't be partially repaired — depth bombs, alias
|
|
486
|
+
* amplification, and introspection leaks are refuse-class
|
|
487
|
+
* outcomes, not something the guard can patch up safely.
|
|
488
|
+
* Returns the input unchanged when the issue list contains no
|
|
489
|
+
* `critical` / `high` entries; throws `GuardGraphqlError`
|
|
490
|
+
* carrying the offending `ruleId` otherwise.
|
|
491
|
+
*
|
|
492
|
+
* @opts
|
|
493
|
+
* profile: "strict"|"balanced"|"permissive",
|
|
494
|
+
* compliance: "hipaa"|"pci-dss"|"gdpr"|"soc2",
|
|
495
|
+
* ...: every guardGraphql.validate opt is honored,
|
|
496
|
+
*
|
|
497
|
+
* @example
|
|
498
|
+
* try {
|
|
499
|
+
* b.guardGraphql.sanitize({
|
|
500
|
+
* query: "query Inspect { __schema { types { name } } }",
|
|
501
|
+
* operationName: "Inspect",
|
|
502
|
+
* }, { profile: "strict" });
|
|
503
|
+
* } catch (e) {
|
|
504
|
+
* e.code; // → "graphql.introspection"
|
|
505
|
+
* }
|
|
506
|
+
*/
|
|
382
507
|
function sanitize(input, opts) {
|
|
383
508
|
opts = _resolveOpts(opts);
|
|
384
509
|
var issues = _detectIssues(input, opts);
|
|
@@ -391,6 +516,42 @@ function sanitize(input, opts) {
|
|
|
391
516
|
return input;
|
|
392
517
|
}
|
|
393
518
|
|
|
519
|
+
/**
|
|
520
|
+
* @primitive b.guardGraphql.gate
|
|
521
|
+
* @signature b.guardGraphql.gate(opts?)
|
|
522
|
+
* @since 0.7.49
|
|
523
|
+
* @status stable
|
|
524
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
525
|
+
* @related b.guardGraphql.validate, b.guardGraphql.sanitize
|
|
526
|
+
*
|
|
527
|
+
* Build a `gateContract.buildGuardGate`-shaped gate that pulls
|
|
528
|
+
* `ctx.graphqlRequest` (or `ctx.gql`) and dispatches to
|
|
529
|
+
* `validate`. Returns `{ ok: true, action: "serve" }` when the
|
|
530
|
+
* issue list is empty, `{ ok: true, action: "audit-only", issues }`
|
|
531
|
+
* when only low-severity issues fire, and `{ ok: false, action:
|
|
532
|
+
* "refuse", issues }` on any `critical` / `high` issue. Compose
|
|
533
|
+
* into the GraphQL request handler before any schema-resolution
|
|
534
|
+
* work — refusal short-circuits hostile depth / alias / batch
|
|
535
|
+
* shapes before they reach the executor.
|
|
536
|
+
*
|
|
537
|
+
* @opts
|
|
538
|
+
* profile: "strict"|"balanced"|"permissive",
|
|
539
|
+
* compliance: "hipaa"|"pci-dss"|"gdpr"|"soc2",
|
|
540
|
+
* name: string, // gate label for audit trails
|
|
541
|
+
* ...: every guardGraphql.validate opt is honored,
|
|
542
|
+
*
|
|
543
|
+
* @example
|
|
544
|
+
* var gqlGate = b.guardGraphql.gate({ profile: "strict" });
|
|
545
|
+
* var rv = await gqlGate.run({
|
|
546
|
+
* graphqlRequest: {
|
|
547
|
+
* query: "{ a:me { id } b:me { id } c:me { id } d:me { id } " +
|
|
548
|
+
* "e:me { id } f:me { id } g:me { id } h:me { id } " +
|
|
549
|
+
* "i:me { id } }",
|
|
550
|
+
* },
|
|
551
|
+
* });
|
|
552
|
+
* rv.action; // → "refuse"
|
|
553
|
+
* rv.issues[0].ruleId; // → "graphql.alias-bomb"
|
|
554
|
+
*/
|
|
394
555
|
function gate(opts) {
|
|
395
556
|
opts = _resolveOpts(opts);
|
|
396
557
|
return gateContract.buildGuardGate(
|
|
@@ -414,14 +575,86 @@ function gate(opts) {
|
|
|
414
575
|
});
|
|
415
576
|
}
|
|
416
577
|
|
|
578
|
+
/**
|
|
579
|
+
* @primitive b.guardGraphql.buildProfile
|
|
580
|
+
* @signature b.guardGraphql.buildProfile(opts)
|
|
581
|
+
* @since 0.7.49
|
|
582
|
+
* @status stable
|
|
583
|
+
* @related b.guardGraphql.gate, b.guardGraphql.compliancePosture
|
|
584
|
+
*
|
|
585
|
+
* Compose a derived profile from one or more named bases plus
|
|
586
|
+
* inline overrides. `opts.extends` is a profile name (`"strict"` /
|
|
587
|
+
* `"balanced"` / `"permissive"`) or an array of names; later
|
|
588
|
+
* entries shadow earlier ones, and inline `opts` keys win last.
|
|
589
|
+
* Operators stage profile overlays here so the final shape is
|
|
590
|
+
* traceable to a baseline rather than a hand-typed dictionary.
|
|
591
|
+
*
|
|
592
|
+
* @opts
|
|
593
|
+
* extends: string|string[], // base profile name(s) to compose
|
|
594
|
+
* ...: any guardGraphql key, // inline override of resolved keys
|
|
595
|
+
*
|
|
596
|
+
* @example
|
|
597
|
+
* var custom = b.guardGraphql.buildProfile({
|
|
598
|
+
* extends: "balanced",
|
|
599
|
+
* introspectionPolicy: "reject",
|
|
600
|
+
* maxDepth: 6,
|
|
601
|
+
* });
|
|
602
|
+
* custom.introspectionPolicy; // → "reject"
|
|
603
|
+
* custom.maxDepth; // → 6
|
|
604
|
+
*/
|
|
417
605
|
var buildProfile = gateContract.makeProfileBuilder(PROFILES);
|
|
418
606
|
|
|
607
|
+
/**
|
|
608
|
+
* @primitive b.guardGraphql.compliancePosture
|
|
609
|
+
* @signature b.guardGraphql.compliancePosture(name)
|
|
610
|
+
* @since 0.7.49
|
|
611
|
+
* @status stable
|
|
612
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
613
|
+
* @related b.guardGraphql.gate, b.guardGraphql.buildProfile
|
|
614
|
+
*
|
|
615
|
+
* Look up a compliance-posture overlay by name (`"hipaa"` /
|
|
616
|
+
* `"pci-dss"` / `"gdpr"` / `"soc2"`). Returns a shallow clone of
|
|
617
|
+
* the posture object — the caller may mutate freely. Throws
|
|
618
|
+
* `GuardGraphqlError("graphql.bad-posture")` on unknown name.
|
|
619
|
+
* Postures extend the strict profile (or balanced for `gdpr`)
|
|
620
|
+
* with a `forensicSnippetBytes` cap appropriate to the regime.
|
|
621
|
+
*
|
|
622
|
+
* @example
|
|
623
|
+
* var posture = b.guardGraphql.compliancePosture("soc2");
|
|
624
|
+
* posture.introspectionPolicy; // → "reject"
|
|
625
|
+
* posture.forensicSnippetBytes; // → 1024
|
|
626
|
+
*/
|
|
419
627
|
function compliancePosture(name) {
|
|
420
628
|
return gateContract.lookupCompliancePosture(name, COMPLIANCE_POSTURES,
|
|
421
629
|
_err, "graphql");
|
|
422
630
|
}
|
|
423
631
|
|
|
424
632
|
var _gqlRulePacks = gateContract.makeRulePackLoader(GuardGraphqlError, "graphql");
|
|
633
|
+
/**
|
|
634
|
+
* @primitive b.guardGraphql.loadRulePack
|
|
635
|
+
* @signature b.guardGraphql.loadRulePack(pack)
|
|
636
|
+
* @since 0.7.49
|
|
637
|
+
* @status stable
|
|
638
|
+
* @related b.guardGraphql.gate
|
|
639
|
+
*
|
|
640
|
+
* Register an operator-supplied rule pack with the guard-graphql
|
|
641
|
+
* registry. The pack is identified by `pack.id` (non-empty
|
|
642
|
+
* string) and stored for later inspection / dispatch by gates
|
|
643
|
+
* that opt in via `opts.rulePackId`. Returns the pack object
|
|
644
|
+
* unchanged on success; throws `GuardGraphqlError("graphql.bad-opt")`
|
|
645
|
+
* when `pack` is missing or `pack.id` is not a non-empty string.
|
|
646
|
+
*
|
|
647
|
+
* @example
|
|
648
|
+
* var pack = b.guardGraphql.loadRulePack({
|
|
649
|
+
* id: "no-mutation-on-read-replica",
|
|
650
|
+
* rules: [
|
|
651
|
+
* { id: "no-mutation", severity: "high",
|
|
652
|
+
* detect: function (req) { return /^\s*mutation\b/.test(req.query || ""); },
|
|
653
|
+
* reason: "read-replica refuses mutation operations" },
|
|
654
|
+
* ],
|
|
655
|
+
* });
|
|
656
|
+
* pack.id; // → "no-mutation-on-read-replica"
|
|
657
|
+
*/
|
|
425
658
|
var loadRulePack = _gqlRulePacks.load;
|
|
426
659
|
|
|
427
660
|
module.exports = {
|