@blamejs/blamejs-shop 0.3.11 → 0.3.13
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/lib/admin.js +157 -117
- package/lib/asset-manifest.json +1 -1
- package/lib/currency-rounding.js +2 -14
- package/lib/index.js +1 -0
- package/lib/text-guard.js +227 -0
- package/lib/vendor/MANIFEST.json +2 -2
- package/lib/vendor/blamejs/CHANGELOG.md +2 -0
- package/lib/vendor/blamejs/README.md +3 -2
- package/lib/vendor/blamejs/SECURITY.md +3 -0
- package/lib/vendor/blamejs/api-snapshot.json +14 -2
- package/lib/vendor/blamejs/lib/agent-event-bus.js +4 -4
- package/lib/vendor/blamejs/lib/agent-idempotency.js +6 -6
- package/lib/vendor/blamejs/lib/agent-orchestrator.js +9 -9
- package/lib/vendor/blamejs/lib/agent-posture-chain.js +10 -10
- package/lib/vendor/blamejs/lib/agent-saga.js +6 -7
- package/lib/vendor/blamejs/lib/agent-snapshot.js +8 -8
- package/lib/vendor/blamejs/lib/agent-stream.js +3 -3
- package/lib/vendor/blamejs/lib/agent-tenant.js +4 -4
- package/lib/vendor/blamejs/lib/agent-trace.js +5 -5
- package/lib/vendor/blamejs/lib/ai-disclosure.js +3 -3
- package/lib/vendor/blamejs/lib/app.js +2 -2
- package/lib/vendor/blamejs/lib/archive-read.js +1 -1
- package/lib/vendor/blamejs/lib/archive-tar-read.js +1 -1
- package/lib/vendor/blamejs/lib/archive-wrap.js +5 -5
- package/lib/vendor/blamejs/lib/audit-tools.js +65 -5
- package/lib/vendor/blamejs/lib/audit.js +2 -2
- package/lib/vendor/blamejs/lib/auth/ciba.js +1 -1
- package/lib/vendor/blamejs/lib/auth/dpop.js +1 -1
- package/lib/vendor/blamejs/lib/auth/fal.js +1 -1
- package/lib/vendor/blamejs/lib/auth/fido-mds3.js +2 -3
- package/lib/vendor/blamejs/lib/auth/jwt-external.js +2 -2
- package/lib/vendor/blamejs/lib/auth/oauth.js +9 -9
- package/lib/vendor/blamejs/lib/auth/oid4vci.js +7 -7
- package/lib/vendor/blamejs/lib/auth/oid4vp.js +1 -1
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +5 -5
- package/lib/vendor/blamejs/lib/auth/passkey.js +6 -6
- package/lib/vendor/blamejs/lib/auth/saml.js +1 -1
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +3 -6
- package/lib/vendor/blamejs/lib/backup/index.js +18 -18
- package/lib/vendor/blamejs/lib/cache.js +4 -4
- package/lib/vendor/blamejs/lib/calendar.js +5 -5
- package/lib/vendor/blamejs/lib/circuit-breaker.js +1 -1
- package/lib/vendor/blamejs/lib/cms-codec.js +2 -2
- package/lib/vendor/blamejs/lib/compliance.js +14 -14
- package/lib/vendor/blamejs/lib/crypto-field.js +58 -21
- package/lib/vendor/blamejs/lib/crypto.js +5 -6
- package/lib/vendor/blamejs/lib/db-query.js +131 -9
- package/lib/vendor/blamejs/lib/db.js +106 -22
- package/lib/vendor/blamejs/lib/external-db.js +64 -16
- package/lib/vendor/blamejs/lib/framework-schema.js +4 -4
- package/lib/vendor/blamejs/lib/guard-list-id.js +2 -2
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +1 -2
- package/lib/vendor/blamejs/lib/incident-report.js +150 -0
- package/lib/vendor/blamejs/lib/mail-crypto-smime.js +1 -1
- package/lib/vendor/blamejs/lib/mail-deploy.js +3 -3
- package/lib/vendor/blamejs/lib/mail-server-managesieve.js +2 -2
- package/lib/vendor/blamejs/lib/mail-server-pop3.js +2 -2
- package/lib/vendor/blamejs/lib/mail-store.js +1 -1
- package/lib/vendor/blamejs/lib/metrics.js +8 -8
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/dpop.js +5 -5
- package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +21 -22
- package/lib/vendor/blamejs/lib/middleware/protected-resource-metadata.js +2 -2
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +2 -2
- package/lib/vendor/blamejs/lib/network-dns.js +1 -2
- package/lib/vendor/blamejs/lib/network-tls.js +0 -1
- package/lib/vendor/blamejs/lib/outbox.js +1 -1
- package/lib/vendor/blamejs/lib/pqc-agent.js +1 -1
- package/lib/vendor/blamejs/lib/retention.js +1 -1
- package/lib/vendor/blamejs/lib/retry.js +1 -1
- package/lib/vendor/blamejs/lib/safe-archive.js +2 -2
- package/lib/vendor/blamejs/lib/safe-ical.js +2 -2
- package/lib/vendor/blamejs/lib/safe-mime.js +1 -1
- package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +1 -1
- package/lib/vendor/blamejs/lib/self-update.js +2 -2
- package/lib/vendor/blamejs/lib/static.js +1 -1
- package/lib/vendor/blamejs/lib/subject.js +2 -2
- package/lib/vendor/blamejs/lib/vault/index.js +64 -1
- package/lib/vendor/blamejs/lib/vault/rotate.js +19 -0
- package/lib/vendor/blamejs/lib/vendor-data.js +1 -1
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.14.7.json +77 -0
- package/lib/vendor/blamejs/scripts/release.js +28 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-tools-dual-control.test.js +115 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +163 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +102 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-key-aad.test.js +109 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +53 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/incident-report.test.js +65 -0
- package/lib/webhook-subscriptions.js +11 -24
- package/lib/webhooks.js +12 -33
- package/package.json +1 -1
|
@@ -117,7 +117,7 @@ function _verifyProofJwt(proofJwt, expectedAud, expectedCNonce, expectedClientId
|
|
|
117
117
|
"credential issuance: proof JWT alg \"" + header.alg + "\" not in issuer-supported set " +
|
|
118
118
|
"(alg-allowlist gate — refused before key lookup)");
|
|
119
119
|
}
|
|
120
|
-
//
|
|
120
|
+
// RFC 7515 §4.1.11 — refuse non-empty `crit`. Pre-v0.9.x
|
|
121
121
|
// silently ignored, letting an attacker-controlled wallet declare
|
|
122
122
|
// critical extensions the verifier doesn't understand.
|
|
123
123
|
if (header.crit !== undefined && header.crit !== null) {
|
|
@@ -136,7 +136,7 @@ function _verifyProofJwt(proofJwt, expectedAud, expectedCNonce, expectedClientId
|
|
|
136
136
|
}
|
|
137
137
|
if (expectedCNonce !== null) {
|
|
138
138
|
// Constant-time c_nonce compare — secret-shaped value vs
|
|
139
|
-
// attacker-controlled wallet payload.
|
|
139
|
+
// attacker-controlled wallet payload.
|
|
140
140
|
if (typeof payload.nonce !== "string" ||
|
|
141
141
|
!timingSafeEqual(payload.nonce, expectedCNonce)) {
|
|
142
142
|
throw new AuthError("auth-oid4vci/wrong-proof-nonce",
|
|
@@ -148,14 +148,14 @@ function _verifyProofJwt(proofJwt, expectedAud, expectedCNonce, expectedClientId
|
|
|
148
148
|
"credential issuance: proof JWT must include iat");
|
|
149
149
|
}
|
|
150
150
|
var nowSec = Math.floor(Date.now() / C.TIME.seconds(1));
|
|
151
|
-
//
|
|
151
|
+
// Use C.TIME for the 60s skew tolerance rather than a bare
|
|
152
152
|
// 60 literal; matches the framework's constants discipline.
|
|
153
153
|
var iatSkewSec = C.TIME.seconds(60) / C.TIME.seconds(1);
|
|
154
154
|
if (payload.iat > nowSec + iatSkewSec) {
|
|
155
155
|
throw new AuthError("auth-oid4vci/proof-iat-future",
|
|
156
156
|
"credential issuance: proof JWT iat is in the future");
|
|
157
157
|
}
|
|
158
|
-
//
|
|
158
|
+
// Operator-tunable proof max-age. Default 10 minutes per
|
|
159
159
|
// OID4VCI §7.2.1.1; operators with longer-lived wallet flows raise.
|
|
160
160
|
var effectiveMaxAgeMs = (typeof proofMaxAgeMs === "number" && isFinite(proofMaxAgeMs) && proofMaxAgeMs > 0)
|
|
161
161
|
? proofMaxAgeMs
|
|
@@ -304,12 +304,12 @@ function create(opts) {
|
|
|
304
304
|
var preAuthTtl = opts.preAuthCodeTtlMs || DEFAULT_PRE_AUTH_TTL_MS;
|
|
305
305
|
var accessTokenTtl = opts.accessTokenTtlMs || DEFAULT_ACCESS_TOKEN_TTL;
|
|
306
306
|
var cNonceTtl = opts.cNonceTtlMs || DEFAULT_C_NONCE_TTL_MS;
|
|
307
|
-
//
|
|
307
|
+
// Operator-tunable proof iat-too-old window. Default 10
|
|
308
308
|
// minutes per OID4VCI §7.2.1.1.
|
|
309
309
|
var proofMaxAgeMs = (typeof opts.proofMaxAgeMs === "number" && isFinite(opts.proofMaxAgeMs) && opts.proofMaxAgeMs > 0)
|
|
310
310
|
? opts.proofMaxAgeMs
|
|
311
311
|
: C.TIME.minutes(10);
|
|
312
|
-
//
|
|
312
|
+
// Access-token single-use. OID4VCI §7's credential endpoint
|
|
313
313
|
// does NOT inherently make the access token single-use; pre-v0.9.x
|
|
314
314
|
// c_nonce rotation alone defended against proof replay, but a stolen
|
|
315
315
|
// access token combined with a fresh proof could re-mint
|
|
@@ -575,7 +575,7 @@ function create(opts) {
|
|
|
575
575
|
var newCNonce = generateToken(16); // 128-bit c_nonce
|
|
576
576
|
await cNonceStore.set(iopts.accessToken, newCNonce);
|
|
577
577
|
|
|
578
|
-
//
|
|
578
|
+
// When single-use is on (default), DELETE the access token
|
|
579
579
|
// after successful credential mint. A stolen access token paired
|
|
580
580
|
// with a fresh proof would otherwise re-mint credentials; the
|
|
581
581
|
// c_nonce rotation alone defends against proof replay but not
|
|
@@ -452,7 +452,7 @@ function create(opts) {
|
|
|
452
452
|
continue;
|
|
453
453
|
}
|
|
454
454
|
try {
|
|
455
|
-
// Per-presentation vct enforcement
|
|
455
|
+
// Per-presentation vct enforcement: when
|
|
456
456
|
// DCQL's `vct_values` has 1 entry, `expectedVct` pins it.
|
|
457
457
|
// With 2+ entries the verifier's expectedVct opt can't hold
|
|
458
458
|
// a list, so we verify-without-expected and then validate
|
|
@@ -169,7 +169,7 @@ function verifyEntityStatement(jwt, jwks, vopts) {
|
|
|
169
169
|
"verifyEntityStatement: no JWKS key matches kid \"" + parsed.header.kid + "\"");
|
|
170
170
|
}
|
|
171
171
|
} else {
|
|
172
|
-
//
|
|
172
|
+
// Refuse kid-less entity statements unless the operator
|
|
173
173
|
// explicitly opts in. JWKS rotation creates a window where the
|
|
174
174
|
// rotated-out key is still cached but the rotated-in key is already
|
|
175
175
|
// published; a kid-less statement during that window gets the
|
|
@@ -218,7 +218,7 @@ function verifyEntityStatement(jwt, jwks, vopts) {
|
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
var nowSec = Math.floor(Date.now() / C.TIME.seconds(1));
|
|
221
|
-
//
|
|
221
|
+
// Operator-tunable clock skew (sibling primitives accept
|
|
222
222
|
// tunable). Default matches the prior fixed 60s.
|
|
223
223
|
var skew = (typeof vopts.maxClockSkewSec === "number" && isFinite(vopts.maxClockSkewSec) && vopts.maxClockSkewSec >= 0)
|
|
224
224
|
? vopts.maxClockSkewSec
|
|
@@ -436,7 +436,7 @@ async function buildTrustChain(opts) {
|
|
|
436
436
|
var chain = [];
|
|
437
437
|
var current = opts.leafEntityId;
|
|
438
438
|
var depth = 0;
|
|
439
|
-
//
|
|
439
|
+
// Visited-set cycle guard. The maxDepth cap alone caps the
|
|
440
440
|
// loop count but doesn't distinguish "long chain" from "cyclic
|
|
441
441
|
// chain"; a hostile authority that lists itself in authority_hints
|
|
442
442
|
// walks the verifier until depth runs out and then surfaces as
|
|
@@ -486,7 +486,7 @@ async function buildTrustChain(opts) {
|
|
|
486
486
|
// operators with multiple federations usually have one anchor
|
|
487
487
|
// active; we walk in order and pick the first success.
|
|
488
488
|
// Track every per-authority failure reason and surface them on
|
|
489
|
-
// `no-ascent` rather than masking
|
|
489
|
+
// `no-ascent` rather than masking — silently
|
|
490
490
|
// swallowing `catch (_e) {}` lets a hostile intermediate that
|
|
491
491
|
// serves a malformed-then-valid pair shape-walk the verifier.
|
|
492
492
|
// We continue past 404 / fetch errors but refuse on
|
|
@@ -513,7 +513,7 @@ async function buildTrustChain(opts) {
|
|
|
513
513
|
chain[chain.length - 1].claims.jwks = parsedSub.claims.jwks || chain[chain.length - 1].claims.jwks;
|
|
514
514
|
chain[chain.length - 1].subordinateJwt = subordinateJwt;
|
|
515
515
|
chain[chain.length - 1].subordinate = parsedSub.claims;
|
|
516
|
-
//
|
|
516
|
+
// Refuse revisit. A trust anchor terminates the loop
|
|
517
517
|
// before re-entry, so a revisit here ALWAYS means a cyclic
|
|
518
518
|
// authority_hints graph.
|
|
519
519
|
if (visited[authority]) {
|
|
@@ -77,7 +77,7 @@ function _requireString(v, name) {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
//
|
|
80
|
+
// WebAuthn extensions allowlist. Pre-v0.9.x `opts.extensions`
|
|
81
81
|
// was forwarded verbatim to the vendor, letting an operator (or a
|
|
82
82
|
// caller threading user-input through opts) ship arbitrary extension
|
|
83
83
|
// keys to the authenticator. Restrict to the framework-supported
|
|
@@ -234,7 +234,7 @@ async function verifyRegistration(opts) {
|
|
|
234
234
|
// <input autocomplete="webauthn">.
|
|
235
235
|
// Null-prototype map so `opts.mediation === "__proto__"` /
|
|
236
236
|
// `"constructor"` can't truthy-match an inherited property and slip
|
|
237
|
-
// past the allowlist
|
|
237
|
+
// past the allowlist.
|
|
238
238
|
var ALLOWED_MEDIATION = Object.assign(Object.create(null),
|
|
239
239
|
{ silent: 1, optional: 1, required: 1, conditional: 1 });
|
|
240
240
|
|
|
@@ -314,7 +314,7 @@ function _b64urlExtInput(value, name, maxBytes) {
|
|
|
314
314
|
// browser turns it into an ArrayBuffer before passing to the
|
|
315
315
|
// authenticator).
|
|
316
316
|
//
|
|
317
|
-
//
|
|
317
|
+
// When `maxBytes` is set, refuse decoded inputs longer than
|
|
318
318
|
// the cap. Per CTAP2.1 §6.5 PRF salts are 32 bytes; pre-v0.9.x the
|
|
319
319
|
// framework accepted arbitrary length, which is undefined behavior on
|
|
320
320
|
// authenticators that may truncate / reject / behave inconsistently.
|
|
@@ -364,7 +364,7 @@ function _prfExt(args) {
|
|
|
364
364
|
throw new AuthError("auth-passkey/missing-prf-first",
|
|
365
365
|
"extensions.prf eval.first is required");
|
|
366
366
|
}
|
|
367
|
-
//
|
|
367
|
+
// CTAP2.1 §6.5 caps PRF salts at 32 bytes.
|
|
368
368
|
var out = { prf: { eval: { first: _b64urlExtInput(args.eval.first, "eval.first", MAX_EXT_INPUT_BYTES) } } };
|
|
369
369
|
if (args.eval.second !== undefined && args.eval.second !== null) {
|
|
370
370
|
out.prf.eval.second = _b64urlExtInput(args.eval.second, "eval.second", MAX_EXT_INPUT_BYTES);
|
|
@@ -461,7 +461,7 @@ async function verifyAuthentication(opts) {
|
|
|
461
461
|
throw new AuthError("auth-passkey/missing-credential",
|
|
462
462
|
"opts.credential { id, publicKey, counter? } is required");
|
|
463
463
|
}
|
|
464
|
-
// Counter regression bypass fix
|
|
464
|
+
// Counter regression bypass fix — pre-v0.9.2
|
|
465
465
|
// shape `opts.credential.counter || 0` silently zeroed an
|
|
466
466
|
// undefined / null / NaN counter, defeating CTAP 2.1 clone-
|
|
467
467
|
// detection on credentials whose stored counter is > 0. An
|
|
@@ -525,7 +525,7 @@ async function verifyAuthentication(opts) {
|
|
|
525
525
|
* @signature b.auth.passkey.compareBackupState(prev, current)
|
|
526
526
|
* @since 0.9.57
|
|
527
527
|
*
|
|
528
|
-
*
|
|
528
|
+
* WebAuthn L3 §6.1.3. Inspect the credential's persisted BE
|
|
529
529
|
* (backupEligible) + BS (backupState) flags against the values
|
|
530
530
|
* surfaced on a fresh assertion. Returns a normalized verdict the
|
|
531
531
|
* operator routes into audit / step-up decisions:
|
|
@@ -717,7 +717,7 @@ function create(opts) {
|
|
|
717
717
|
// Constant-time compare against the AuthnRequest ID the
|
|
718
718
|
// operator stored — protects against timing-based InResponseTo
|
|
719
719
|
// probing. timingSafeEqual returns false for missing /
|
|
720
|
-
// length-mismatch without leaking.
|
|
720
|
+
// length-mismatch without leaking.
|
|
721
721
|
if (inResponseTo === null || inResponseTo === undefined ||
|
|
722
722
|
!timingSafeEqual(inResponseTo, vopts.expectedInResponseTo)) {
|
|
723
723
|
throw new AuthError("auth-saml/bad-in-response-to",
|
|
@@ -492,7 +492,7 @@ async function verify(presentation, opts) {
|
|
|
492
492
|
jwtExternal._assertAlgKtyMatch(alg, issuerKey);
|
|
493
493
|
}
|
|
494
494
|
var jwtParsed = _verifyJwt(jwt, issuerKey, alg);
|
|
495
|
-
//
|
|
495
|
+
// Post-verify header compare. Pre-verify we parsed the
|
|
496
496
|
// header bytes to look up the key; _verifyJwt parses again from the
|
|
497
497
|
// cryptographically-verified signing input. Both decodes MUST yield
|
|
498
498
|
// the same JSON; a mismatch indicates a JWS-canonicalization or
|
|
@@ -538,7 +538,6 @@ async function verify(presentation, opts) {
|
|
|
538
538
|
// selective-disclosure-jwt §4.1.1). Earlier the framework defaulted
|
|
539
539
|
// to its own DEFAULT_HASH_ALG (`sha3-512`) which broke verification
|
|
540
540
|
// against spec-conformant issuers when `_sd_alg` was omitted.
|
|
541
|
-
// (Audit 2026-05-11.)
|
|
542
541
|
var hashAlg = jwtParsed.payload._sd_alg || "sha-256";
|
|
543
542
|
if (!SUPPORTED_HASH_ALGS[hashAlg]) {
|
|
544
543
|
throw new AuthError("auth-sd-jwt-vc/bad-hash",
|
|
@@ -566,7 +565,7 @@ async function verify(presentation, opts) {
|
|
|
566
565
|
// Disclosure-replay defense — a holder presenting the same _sd
|
|
567
566
|
// digest twice (with the same or different values) is malformed
|
|
568
567
|
// per spec and is the shape of a partial-disclosure smuggling
|
|
569
|
-
// attack. Refuse on duplicate digest.
|
|
568
|
+
// attack. Refuse on duplicate digest.
|
|
570
569
|
if (seenDigests[digest]) {
|
|
571
570
|
throw new AuthError("auth-sd-jwt-vc/disclosure-replay",
|
|
572
571
|
"verify: disclosure digest \"" + digest.slice(0, 12) +
|
|
@@ -622,9 +621,7 @@ async function verify(presentation, opts) {
|
|
|
622
621
|
"verify: KB-JWT nonce mismatch (replay defense)");
|
|
623
622
|
}
|
|
624
623
|
// Validate KB-JWT sd_hash matches the presentation, using the
|
|
625
|
-
// credential's declared `_sd_alg
|
|
626
|
-
// hardcoded sha256 regardless of issuer's choice, breaking
|
|
627
|
-
// verification when issuer used sha3-512).
|
|
624
|
+
// credential's declared `_sd_alg`.
|
|
628
625
|
var kbHashInput = jwt + "~";
|
|
629
626
|
if (disclosureParts.length > 0) kbHashInput += disclosureParts.join("~") + "~";
|
|
630
627
|
var kbNodeHash = SUPPORTED_HASH_ALGS[hashAlg];
|
|
@@ -81,7 +81,7 @@ var BackupError = defineClass("BackupError");
|
|
|
81
81
|
// compliance.js); list them here so bundleAdapterStorage's
|
|
82
82
|
// posture check refuses plaintext bundles under these regimes
|
|
83
83
|
// alongside the long-standing HIPAA + PCI-DSS pair.
|
|
84
|
-
//
|
|
84
|
+
// The legacy `ai-act` short
|
|
85
85
|
// name MUST appear in the backup encryption-required list too,
|
|
86
86
|
// otherwise a deployment pinned to `posture: "ai-act"` (the
|
|
87
87
|
// stated back-compat path) bypasses the cryptoStrategy refusal
|
|
@@ -339,7 +339,7 @@ function create(opts) {
|
|
|
339
339
|
"create: opts.vaultKeyJson is required (string or function returning string)");
|
|
340
340
|
}
|
|
341
341
|
|
|
342
|
-
// Posture-enforced backup encryption
|
|
342
|
+
// Posture-enforced backup encryption. HIPAA / PCI-DSS
|
|
343
343
|
// operators MUST keep encryption on. The framework's backup pipeline
|
|
344
344
|
// is encrypted-by-default — passphrase + per-file XChaCha20-Poly1305
|
|
345
345
|
// — but operators in third-party storage backends sometimes pass
|
|
@@ -361,7 +361,7 @@ function create(opts) {
|
|
|
361
361
|
}
|
|
362
362
|
}
|
|
363
363
|
|
|
364
|
-
//
|
|
364
|
+
// Backup destination residency posture. EU-tagged primary
|
|
365
365
|
// backing up to a US-region destination is a GDPR Article 46
|
|
366
366
|
// cross-border transfer; without an explicit operator opt-in the
|
|
367
367
|
// framework refuses to create the pipeline under gdpr / dpdp /
|
|
@@ -1110,7 +1110,7 @@ function bundleAdapterStorage(opts) {
|
|
|
1110
1110
|
// HIPAA + PCI-DSS recipe raises the floor to 128 bits (per
|
|
1111
1111
|
// BACKUP_ENCRYPTION_REQUIRED_POSTURES below); default 80 matches
|
|
1112
1112
|
// OWASP "strong password" guidance for generic deployments.
|
|
1113
|
-
//
|
|
1113
|
+
// Typeof NaN === "number" and
|
|
1114
1114
|
// typeof Infinity === "number" both pass the typeof gate but
|
|
1115
1115
|
// bypass downstream comparisons (NaN < 128 is false; estimated
|
|
1116
1116
|
// < NaN is false). Use Number.isFinite + a finite integer check
|
|
@@ -1136,7 +1136,7 @@ function bundleAdapterStorage(opts) {
|
|
|
1136
1136
|
"passphraseMinEntropyBits defaults to 80; HIPAA / PCI-DSS postures raise the floor to 128.");
|
|
1137
1137
|
}
|
|
1138
1138
|
}
|
|
1139
|
-
//
|
|
1139
|
+
// The wrap layers (recipient AND
|
|
1140
1140
|
// passphrase) compose only with the tar / tar.gz writeBundle
|
|
1141
1141
|
// branches. Pairing encryption strategy with format: "directory"
|
|
1142
1142
|
// would silently write plaintext per-file payloads. Refuse upfront
|
|
@@ -1168,7 +1168,7 @@ function bundleAdapterStorage(opts) {
|
|
|
1168
1168
|
passphraseMinEntropyBits = 128; // entropy-bits floor, not byte count
|
|
1169
1169
|
}
|
|
1170
1170
|
}
|
|
1171
|
-
//
|
|
1171
|
+
// Tar mode builds the whole archive
|
|
1172
1172
|
// in memory before adapter.writeFile because the v0.12.8 adapter
|
|
1173
1173
|
// contract is bytes-in (no writeStream method). The OOM-prevention
|
|
1174
1174
|
// gate is maxBundleBytes: writeBundle pre-walks the source tree,
|
|
@@ -1244,7 +1244,7 @@ function bundleAdapterStorage(opts) {
|
|
|
1244
1244
|
// wire). Bundle sizes drop ~3-5× on text-heavy backups
|
|
1245
1245
|
// (databases, JSON exports, mail spools) under tar.gz.
|
|
1246
1246
|
//
|
|
1247
|
-
//
|
|
1247
|
+
// Tar bytes are materialized in
|
|
1248
1248
|
// memory because the v0.12.8 adapter contract is bytes-in
|
|
1249
1249
|
// (writeFile takes a Buffer, no writeStream method). The
|
|
1250
1250
|
// maxBundleBytes pre-walk computes the uncompressed payload
|
|
@@ -1312,7 +1312,7 @@ function bundleAdapterStorage(opts) {
|
|
|
1312
1312
|
}
|
|
1313
1313
|
atomicFile.ensureDir(destDir);
|
|
1314
1314
|
if (hasTarGz) {
|
|
1315
|
-
//
|
|
1315
|
+
// Propagate maxBundleBytes
|
|
1316
1316
|
// to the gz restore path + disable the expansion-ratio cap.
|
|
1317
1317
|
// archive.read.gz defaults (1 GiB output / 100× ratio) are
|
|
1318
1318
|
// bomb-defense settings appropriate for adversarial input;
|
|
@@ -1386,7 +1386,7 @@ function bundleAdapterStorage(opts) {
|
|
|
1386
1386
|
// writeBundle path produced (rule §2 — the format is part
|
|
1387
1387
|
// of the storage layout, not behind a probe).
|
|
1388
1388
|
//
|
|
1389
|
-
//
|
|
1389
|
+
// Track WHICH suffixes a
|
|
1390
1390
|
// bundle carries (set of booleans) then apply explicit
|
|
1391
1391
|
// precedence at the end: tar.gz > tar > directory. Matches
|
|
1392
1392
|
// readBundle's preference (which checks hasTarGz first)
|
|
@@ -1595,7 +1595,7 @@ function bundleAdapterStorage(opts) {
|
|
|
1595
1595
|
"cloneBundle: dstBundleId '" + dstBundleId + "' already exists; " +
|
|
1596
1596
|
"pass opts.overwrite=true to replace");
|
|
1597
1597
|
}
|
|
1598
|
-
//
|
|
1598
|
+
// When overwrite=true, the
|
|
1599
1599
|
// existence guard was the only protection but it didn't
|
|
1600
1600
|
// delete the destination's existing keys before writing
|
|
1601
1601
|
// the source keys. Stale-format bundles (dst=tar, src=
|
|
@@ -1654,7 +1654,7 @@ function bundleAdapterStorage(opts) {
|
|
|
1654
1654
|
var rwKeySuffix = info.format === "tar.gz" ? TAR_GZ_KEY_SUFFIX : TAR_KEY_SUFFIX;
|
|
1655
1655
|
var sealed = await adapter.readFile(bundleId + rwKeySuffix);
|
|
1656
1656
|
var envelopeKind = info.envelopeKind;
|
|
1657
|
-
//
|
|
1657
|
+
// When the adapter has no
|
|
1658
1658
|
// readPartial capability, bundleInfo returns envelopeKind:
|
|
1659
1659
|
// "unknown" rather than risk a full payload load. For
|
|
1660
1660
|
// rewrap, we already have to load the payload (to unwrap),
|
|
@@ -1705,7 +1705,7 @@ function bundleAdapterStorage(opts) {
|
|
|
1705
1705
|
"rewrapBundle: opts.newPassphrase is required (string or Buffer) to re-seal");
|
|
1706
1706
|
}
|
|
1707
1707
|
inner = await archiveLazy().unwrapWithPassphrase(sealed, { passphrase: oldPass });
|
|
1708
|
-
//
|
|
1708
|
+
// Preserve the storage's
|
|
1709
1709
|
// configured entropy floor across rewrap. The
|
|
1710
1710
|
// writeBundle path raises the floor to 128 bits under
|
|
1711
1711
|
// HIPAA / PCI-DSS postures (per
|
|
@@ -1770,7 +1770,7 @@ function bundleAdapterStorage(opts) {
|
|
|
1770
1770
|
var inflight = [];
|
|
1771
1771
|
var aborted = false;
|
|
1772
1772
|
function _spawn() {
|
|
1773
|
-
//
|
|
1773
|
+
// Synchronously drain
|
|
1774
1774
|
// non-wrappable entries inside _spawn until we hit one
|
|
1775
1775
|
// that actually needs an async rewrap (or the pending
|
|
1776
1776
|
// queue empties). The prior implementation returned
|
|
@@ -1850,7 +1850,7 @@ function bundleAdapterStorage(opts) {
|
|
|
1850
1850
|
},
|
|
1851
1851
|
async verifyAllBundles(vOpts) {
|
|
1852
1852
|
vOpts = vOpts || {};
|
|
1853
|
-
//
|
|
1853
|
+
// Clamp fractional + zero
|
|
1854
1854
|
// floors so a stray `0.5` doesn't spawn zero workers + return
|
|
1855
1855
|
// a silent ok=0/failed=0 report on non-empty storage. Default
|
|
1856
1856
|
// 4; minimum 1; non-finite / non-positive falls back to
|
|
@@ -1876,7 +1876,7 @@ function bundleAdapterStorage(opts) {
|
|
|
1876
1876
|
if (aborted) return null;
|
|
1877
1877
|
if (pending.length === 0) return null;
|
|
1878
1878
|
var entry = pending.shift();
|
|
1879
|
-
//
|
|
1879
|
+
// Wrap each worker so any
|
|
1880
1880
|
// verifyBundle rejection becomes a failed-result entry
|
|
1881
1881
|
// rather than rejecting the whole batch. Without this, a
|
|
1882
1882
|
// mid-walk failure (payload disappeared between listBundles
|
|
@@ -2063,7 +2063,7 @@ function bundleAdapterStorage(opts) {
|
|
|
2063
2063
|
var envelopeKind = "none";
|
|
2064
2064
|
var sizeBytes = null;
|
|
2065
2065
|
var createdAt = null;
|
|
2066
|
-
//
|
|
2066
|
+
// Directory-format bundles
|
|
2067
2067
|
// leave payloadKey null but DO have a manifest.json that
|
|
2068
2068
|
// statKey can read. For createdAt parity with
|
|
2069
2069
|
// listBundles({ withStats }), stat the manifest in the
|
|
@@ -2085,7 +2085,7 @@ function bundleAdapterStorage(opts) {
|
|
|
2085
2085
|
}
|
|
2086
2086
|
}
|
|
2087
2087
|
if (payloadKey !== null) {
|
|
2088
|
-
//
|
|
2088
|
+
// Claim was a 5-byte magic
|
|
2089
2089
|
// probe; the implementation was reading the entire bundle
|
|
2090
2090
|
// into memory. For multi-GB bundles, an administrative
|
|
2091
2091
|
// metadata call would allocate the whole payload and put
|
|
@@ -2381,7 +2381,7 @@ bundleAdapterStorage.objectStoreAdapter = function (client, osOpts) {
|
|
|
2381
2381
|
// prefix manually so `listKeys("")` enumerates everything
|
|
2382
2382
|
// under the operator-supplied namespace.
|
|
2383
2383
|
var realScoped = prefix + (keyPrefix || "");
|
|
2384
|
-
//
|
|
2384
|
+
// Object-store backends page
|
|
2385
2385
|
// results (default 1000 keys). Without continuation, listKeys
|
|
2386
2386
|
// silently dropped bundles past page 1 — listBundles missed
|
|
2387
2387
|
// them, deleteBundle skipped them. Follow the
|
|
@@ -85,7 +85,7 @@ var { CacheError } = require("./framework-error");
|
|
|
85
85
|
|
|
86
86
|
var log = boot("cache");
|
|
87
87
|
var observability = lazyRequire(function () { return require("./observability"); });
|
|
88
|
-
//
|
|
88
|
+
// Opt-in vault seal for cluster-backend cache values. Lazy so
|
|
89
89
|
// vault-not-initialized in tests with a memory cache doesn't crash
|
|
90
90
|
// at module load.
|
|
91
91
|
var vault = lazyRequire(function () { return require("./vault"); });
|
|
@@ -501,7 +501,7 @@ function _clusterBackend(cfg) {
|
|
|
501
501
|
).catch(function () { /* best-effort */ });
|
|
502
502
|
}
|
|
503
503
|
var stored = row.valueJson;
|
|
504
|
-
//
|
|
504
|
+
// Sealed-row decode. Sealed entries are prefixed at write
|
|
505
505
|
// time so the unseal-on-read path is a strict opt-in: rows
|
|
506
506
|
// written without seal:true continue parsing as before.
|
|
507
507
|
if (typeof stored === "string" && stored.indexOf(CACHE_SEAL_PREFIX) === 0) {
|
|
@@ -521,7 +521,7 @@ function _clusterBackend(cfg) {
|
|
|
521
521
|
// changed value, app code treats it as the original" — a subtle
|
|
522
522
|
// freshness bug that's hard to debug.
|
|
523
523
|
var json = safeJson.stringify(value);
|
|
524
|
-
//
|
|
524
|
+
// Opt-in vault seal. When the caller passes seal: true,
|
|
525
525
|
// wrap the JSON via b.vault.seal (XChaCha20-Poly1305) before
|
|
526
526
|
// landing in _blamejs_cache.valueJson. The marker prefix is what
|
|
527
527
|
// get() looks for to know it must unseal on read.
|
|
@@ -1091,7 +1091,7 @@ function create(opts) {
|
|
|
1091
1091
|
}
|
|
1092
1092
|
}
|
|
1093
1093
|
}
|
|
1094
|
-
//
|
|
1094
|
+
// Opt-in vault seal. Strict-shape check: must be the literal
|
|
1095
1095
|
// boolean true, not just truthy. Backends that don't support seal
|
|
1096
1096
|
// (memory, custom) ignore the flag transparently; cluster backend
|
|
1097
1097
|
// wraps valueJson via b.vault.seal before INSERT.
|
|
@@ -263,7 +263,7 @@ function validate(jsCal) {
|
|
|
263
263
|
"b.calendar.validate: Group.source MUST be a string URI when present (RFC 8984 §1.4.4)");
|
|
264
264
|
}
|
|
265
265
|
if (jsCal.categories !== undefined) {
|
|
266
|
-
//
|
|
266
|
+
// `typeof null === "object"` would let `categories:
|
|
267
267
|
// null` through this check, and the subsequent Object.keys
|
|
268
268
|
// throws a raw TypeError instead of a structured CalendarError.
|
|
269
269
|
// Refuse null explicitly so callers depending on the
|
|
@@ -687,7 +687,7 @@ function _expandSingleRule(rule, startMs, ctx) {
|
|
|
687
687
|
var n = parseInt(arr[i], 10);
|
|
688
688
|
if (isFinite(n) && n >= lo && n <= hi) { s[n] = true; hasAny = true; }
|
|
689
689
|
}
|
|
690
|
-
//
|
|
690
|
+
// When every value in the BY* list is out of range,
|
|
691
691
|
// return null instead of an empty set. An empty truthy set would
|
|
692
692
|
// cause `_matchesBy` to reject every candidate (`!set[n]` is
|
|
693
693
|
// true) and silently turn malformed input into a "match nothing"
|
|
@@ -728,7 +728,7 @@ function _expandSingleRule(rule, startMs, ctx) {
|
|
|
728
728
|
if (byMonthSet && !byMonthSet[d.getUTCMonth() + 1]) return false;
|
|
729
729
|
if (byMonthDaySet && !byMonthDaySet[d.getUTCDate()]) return false;
|
|
730
730
|
if (byWeekNoSet) {
|
|
731
|
-
//
|
|
731
|
+
// ISO week-year vs Gregorian year. 2021-01-01 is ISO
|
|
732
732
|
// week 53 of WEEK-YEAR 2020 (since 2021 only has 52 ISO weeks).
|
|
733
733
|
// Comparing only the numeric week would let a Jan 1 2021 date
|
|
734
734
|
// match a BYWEEKNO=53 rule whose implicit year is 2021. Refuse
|
|
@@ -884,7 +884,7 @@ function _expandWithBysetpos(ctx) {
|
|
|
884
884
|
// Emit picked candidates in ascending order, gated by window +
|
|
885
885
|
// untilMs + per-rule count cap.
|
|
886
886
|
//
|
|
887
|
-
//
|
|
887
|
+
// Recurrence instances MUST NOT precede DTSTART (per
|
|
888
888
|
// RFC 5545 §3.8.5.3). The period-boundary enumeration above
|
|
889
889
|
// includes candidates BEFORE startMs when the period containing
|
|
890
890
|
// startMs has earlier BY*-matching days (e.g. start = May 20
|
|
@@ -960,7 +960,7 @@ function _veventToJsCalEvent(ve) {
|
|
|
960
960
|
if (tzid) {
|
|
961
961
|
jsCal.timeZone = tzid;
|
|
962
962
|
} else if (typeof dtstart === "string" && /Z$/.test(dtstart)) {
|
|
963
|
-
//
|
|
963
|
+
// RFC 8984 §1.4.4: a UTC-suffix DTSTART (`...Z`) in
|
|
964
964
|
// iCalendar maps to a JSCalendar Event with `timeZone: "Etc/UTC"`.
|
|
965
965
|
// Without this, round-tripping `fromIcal` → `toIcal` would drop
|
|
966
966
|
// the UTC anchor + emit floating time, shifting the absolute
|
|
@@ -82,7 +82,7 @@ function create(opts) {
|
|
|
82
82
|
// split the name out of opts before invoking the constructor.
|
|
83
83
|
// Caught by hermitstash-sync operator review against v0.9.12.
|
|
84
84
|
//
|
|
85
|
-
//
|
|
85
|
+
// The previous empty-string fallback was unreachable
|
|
86
86
|
// (retryHelper.CircuitBreaker validator throws on "" first) AND
|
|
87
87
|
// produced a confusing error message ("name must be a non-empty
|
|
88
88
|
// string, got string \"\"") that obscured the real opt-shape
|
|
@@ -367,7 +367,7 @@ function decode(buf, opts) {
|
|
|
367
367
|
|
|
368
368
|
// OIDs whose AlgorithmIdentifier specifies ABSENT parameters per their
|
|
369
369
|
// publishing RFC — emitting NULL here would make the CMS structure
|
|
370
|
-
// non-conformant for strict validators
|
|
370
|
+
// non-conformant for strict validators.
|
|
371
371
|
// ML-DSA per RFC 9909 §3, SLH-DSA per RFC 9881 §3, ML-KEM per
|
|
372
372
|
// RFC 9936 §3. SHAKE-family per FIPS 202 (NIST registry — absent params).
|
|
373
373
|
var ABSENT_PARAM_OIDS = new Set([
|
|
@@ -407,7 +407,7 @@ function _writeImplicitPrimitive(tagNumber, value) {
|
|
|
407
407
|
// [N] IMPLICIT context-specific PRIMITIVE — for wrapping primitive
|
|
408
408
|
// ASN.1 types (OCTET STRING / INTEGER / OID) that have been IMPLICIT-
|
|
409
409
|
// tagged. The constructed bit MUST NOT be set or strict CMS parsers
|
|
410
|
-
// reject the structure (
|
|
410
|
+
// reject the structure (RecipientIdentifier
|
|
411
411
|
// CHOICE's SubjectKeyIdentifier alternative is `[0] IMPLICIT OCTET STRING`,
|
|
412
412
|
// a primitive type).
|
|
413
413
|
var tagByte = 0x80 | (tagNumber & 0x1f); // context-specific primitive mask
|
|
@@ -280,7 +280,7 @@ var KNOWN_POSTURES = Object.freeze([
|
|
|
280
280
|
"nyc-ll144-2024", // NYC Local Law 144 — Automated Employment Decision Tool bias audits (2024 enforcement update) // statute identifier, not bytes
|
|
281
281
|
]);
|
|
282
282
|
|
|
283
|
-
//
|
|
283
|
+
// Artifact standards (SBOM / VEX format families) are NOT
|
|
284
284
|
// regulatory regimes. Pinning a posture like `cyclonedx-v1.6` to
|
|
285
285
|
// cascade audit + TLS floors conflates the act of EMITTING a SBOM
|
|
286
286
|
// format with the regulatory floor an operator needs. Operators who
|
|
@@ -385,7 +385,7 @@ function set(posture) {
|
|
|
385
385
|
STATE.setAt = Date.now();
|
|
386
386
|
_emitAudit("compliance.posture.set", { posture: posture });
|
|
387
387
|
|
|
388
|
-
//
|
|
388
|
+
// Emit a `format_as_regime` audit warning when an
|
|
389
389
|
// operator pins an artifact-standard format (cyclonedx-v1.6 /
|
|
390
390
|
// spdx-v3.0 / vex-csaf-2.1) as the regulatory posture. These names
|
|
391
391
|
// remain in KNOWN_POSTURES for back-compat but pinning them as the
|
|
@@ -400,7 +400,7 @@ function set(posture) {
|
|
|
400
400
|
"warning");
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
-
//
|
|
403
|
+
// Emit `fips_conflict` audit warning when posture is
|
|
404
404
|
// FedRAMP / CMMC L3 AND the framework's PQC-first crypto defaults
|
|
405
405
|
// are active without an explicit fipsMode opt-in. Operators see
|
|
406
406
|
// this in the audit chain and either (a) document the deviation
|
|
@@ -417,7 +417,7 @@ function set(posture) {
|
|
|
417
417
|
"warning");
|
|
418
418
|
}
|
|
419
419
|
|
|
420
|
-
//
|
|
420
|
+
// Cascade the posture into every primitive that owns a
|
|
421
421
|
// posture-conditioned default. Each primitive exposes an
|
|
422
422
|
// `applyPosture(name)` that merges the POSTURE_DEFAULTS entry for the
|
|
423
423
|
// posture into its own state and emits
|
|
@@ -429,7 +429,7 @@ function set(posture) {
|
|
|
429
429
|
// skipped rows surface in the audit chain so a forensic review can
|
|
430
430
|
// reconstruct the boot order.
|
|
431
431
|
_applyPostureCascade(posture);
|
|
432
|
-
//
|
|
432
|
+
// TZ awareness. Auditors expect timestamps in UTC.
|
|
433
433
|
// process.env.TZ controls Node's local-time conversion for any
|
|
434
434
|
// operator code that uses non-UTC formatters; under regulated
|
|
435
435
|
// postures (hipaa / pci-dss / sox / gdpr / soc2) emit a boot
|
|
@@ -447,7 +447,7 @@ function set(posture) {
|
|
|
447
447
|
}
|
|
448
448
|
}
|
|
449
449
|
|
|
450
|
-
// _applyPostureCascade —
|
|
450
|
+
// _applyPostureCascade — walks every primitive that
|
|
451
451
|
// participates in posture-conditioned defaults and asks it to merge
|
|
452
452
|
// the named posture into its state. Each step is best-effort at the
|
|
453
453
|
// audit-emission level (a primitive that isn't loaded yet emits
|
|
@@ -936,11 +936,11 @@ function describe(posture) {
|
|
|
936
936
|
// floors.
|
|
937
937
|
//
|
|
938
938
|
// Keys per posture:
|
|
939
|
-
// backupEncryptionRequired — backup.create refuses encrypt:false
|
|
939
|
+
// backupEncryptionRequired — backup.create refuses encrypt:false
|
|
940
940
|
// auditChainSignedRequired — audit emissions MUST be ML-DSA-87 chain-signed
|
|
941
941
|
// tlsMinVersion — minimum TLS version (string e.g. "TLSv1.3")
|
|
942
942
|
// sessionAbsoluteTimeoutMs — hard session expiry ceiling
|
|
943
|
-
// requireVacuumAfterErase —
|
|
943
|
+
// requireVacuumAfterErase — cryptoField.eraseRow must call
|
|
944
944
|
// b.db.vacuumAfterErase({ mode: "full" })
|
|
945
945
|
// so freed B-tree index pages don't linger
|
|
946
946
|
// with sealed-column ciphertext readable
|
|
@@ -1178,7 +1178,7 @@ var POSTURE_DEFAULTS = Object.freeze({
|
|
|
1178
1178
|
"circia": Object.freeze({ backupEncryptionRequired: false, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: false }),
|
|
1179
1179
|
// ---- v0.9.6 — exceptd framework-control-gap closure cascade ----
|
|
1180
1180
|
"nist-800-53": Object.freeze({ backupEncryptionRequired: true, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: true }),
|
|
1181
|
-
//
|
|
1181
|
+
// NIST AI-RMF MANAGE.4.3 / ISO 23894 §6.5 / ISO 42001
|
|
1182
1182
|
// §A.6 require encrypted backups for AI system state (model
|
|
1183
1183
|
// weights, training data, prompt logs all contain regulated
|
|
1184
1184
|
// payload). All AI-domain postures now enforce backupEncryption.
|
|
@@ -1186,7 +1186,7 @@ var POSTURE_DEFAULTS = Object.freeze({
|
|
|
1186
1186
|
"iso-42001-2023": Object.freeze({ backupEncryptionRequired: true, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: true }),
|
|
1187
1187
|
"iso-23894-2023": Object.freeze({ backupEncryptionRequired: true, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: true }),
|
|
1188
1188
|
"owasp-llm-top-10-2025": Object.freeze({ backupEncryptionRequired: true, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: true }),
|
|
1189
|
-
//
|
|
1189
|
+
// OWASP ASVS v5.0 §8.3.4 (sensitive-data deletion)
|
|
1190
1190
|
// requires post-delete storage reclamation. Set requireVacuumAfterErase
|
|
1191
1191
|
// so operators pinning ASVS v5.0 inherit the proper floor.
|
|
1192
1192
|
"owasp-asvs-v5.0": Object.freeze({ backupEncryptionRequired: false, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: true }),
|
|
@@ -1194,7 +1194,7 @@ var POSTURE_DEFAULTS = Object.freeze({
|
|
|
1194
1194
|
"nist-800-82-r3": Object.freeze({ backupEncryptionRequired: true, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: false }),
|
|
1195
1195
|
"nist-800-63b-rev4": Object.freeze({ backupEncryptionRequired: false, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: false }),
|
|
1196
1196
|
"iec-62443-3-3": Object.freeze({ backupEncryptionRequired: true, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: false }),
|
|
1197
|
-
//
|
|
1197
|
+
// FedRAMP Rev 5 Moderate baseline references FIPS 140-3
|
|
1198
1198
|
// validated cryptography for protect-against-disclosure controls
|
|
1199
1199
|
// (SC-13, SC-28). The framework's PQC-first defaults (ML-KEM-1024,
|
|
1200
1200
|
// XChaCha20-Poly1305, SHA3-512) are NOT FIPS-140-3 validated as of
|
|
@@ -1230,7 +1230,7 @@ var POSTURE_DEFAULTS = Object.freeze({
|
|
|
1230
1230
|
"nist-800-115": Object.freeze({ backupEncryptionRequired: false, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: false }),
|
|
1231
1231
|
"cwe-top-25-2024": Object.freeze({ backupEncryptionRequired: false, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: false }),
|
|
1232
1232
|
"cis-controls-v8": Object.freeze({ backupEncryptionRequired: true, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: false }),
|
|
1233
|
-
//
|
|
1233
|
+
// CMMC 2.0 levels differ in control mapping:
|
|
1234
1234
|
// L1 (Foundational, 15 FAR controls, FCI data only) — encrypted
|
|
1235
1235
|
// backups NOT mandated; audit-chain encouraged.
|
|
1236
1236
|
// L2 (Advanced, 110 NIST 800-171 Rev 2 controls, CUI data) —
|
|
@@ -1325,7 +1325,7 @@ var POSTURE_DEFAULTS = Object.freeze({
|
|
|
1325
1325
|
// erased from a system's storage, the residual EXIF / metadata
|
|
1326
1326
|
// entries pointing at the model must be cleared too.
|
|
1327
1327
|
"eu-ai-act": Object.freeze({ backupEncryptionRequired: true, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: true }),
|
|
1328
|
-
//
|
|
1328
|
+
// The legacy `ai-act` short
|
|
1329
1329
|
// name carries the SAME cascade as `eu-ai-act` so deployments
|
|
1330
1330
|
// pinned to the legacy alias get the new encryption / audit /
|
|
1331
1331
|
// TLS / vacuum floors instead of falling through to null. The
|
|
@@ -1526,7 +1526,7 @@ function list() {
|
|
|
1526
1526
|
* Return the set of SBOM / VEX artifact standards the framework can
|
|
1527
1527
|
* emit. These are FORMAT FAMILIES, not regulatory regimes — pinning
|
|
1528
1528
|
* one of these names as the deployment's compliance posture conflates
|
|
1529
|
-
* "format I emit" with "regulatory floor I meet"
|
|
1529
|
+
* "format I emit" with "regulatory floor I meet". Pin
|
|
1530
1530
|
* the regulatory regime (FedRAMP / SSDF / HIPAA / etc.) via
|
|
1531
1531
|
* `b.compliance.set()` and surface the emitted artifact standards via
|
|
1532
1532
|
* this read-only catalog.
|