@blamejs/blamejs-shop 0.3.70 → 0.3.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/README.md +1 -1
- package/lib/admin.js +254 -2
- package/lib/asset-manifest.json +1 -1
- package/lib/customer-segments.js +150 -0
- package/lib/vendor/MANIFEST.json +95 -83
- package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +1 -1
- package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +1 -1
- package/lib/vendor/blamejs/.github/workflows/ci.yml +10 -10
- package/lib/vendor/blamejs/.github/workflows/codeql.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +2 -2
- package/lib/vendor/blamejs/.github/workflows/release-container.yml +4 -4
- package/lib/vendor/blamejs/.github/workflows/scorecard.yml +2 -2
- package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
- package/lib/vendor/blamejs/CHANGELOG.md +4 -0
- package/lib/vendor/blamejs/README.md +1 -1
- package/lib/vendor/blamejs/SECURITY.md +2 -0
- package/lib/vendor/blamejs/api-snapshot.json +108 -4
- package/lib/vendor/blamejs/lib/auth/oauth.js +736 -1
- package/lib/vendor/blamejs/lib/auth/oid4vci.js +124 -5
- package/lib/vendor/blamejs/lib/auth/oid4vp.js +14 -4
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-holder.js +46 -1
- package/lib/vendor/blamejs/lib/break-glass.js +1 -2
- package/lib/vendor/blamejs/lib/config.js +28 -31
- package/lib/vendor/blamejs/lib/crypto-field.js +274 -17
- package/lib/vendor/blamejs/lib/dora.js +8 -5
- package/lib/vendor/blamejs/lib/dsr.js +2 -2
- package/lib/vendor/blamejs/lib/flag-evaluation-context.js +7 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-aria.js +4 -2
- package/lib/vendor/blamejs/lib/guard-html-wcag-forms.js +4 -2
- package/lib/vendor/blamejs/lib/guard-html-wcag-tables.js +4 -2
- package/lib/vendor/blamejs/lib/guard-html-wcag-tagwalk.js +20 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag.js +1 -1
- package/lib/vendor/blamejs/lib/honeytoken.js +27 -20
- package/lib/vendor/blamejs/lib/mail-auth.js +333 -0
- package/lib/vendor/blamejs/lib/mail-deploy.js +1 -1
- package/lib/vendor/blamejs/lib/mail-send-deliver.js +13 -4
- package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +140 -13
- package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +3 -0
- package/lib/vendor/blamejs/lib/middleware/csp-report.js +13 -9
- package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +115 -14
- package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +3 -0
- package/lib/vendor/blamejs/lib/middleware/scim-server.js +297 -19
- package/lib/vendor/blamejs/lib/middleware/security-headers.js +47 -0
- package/lib/vendor/blamejs/lib/middleware/security-txt.js +1 -2
- package/lib/vendor/blamejs/lib/middleware/trace-log-correlation.js +1 -2
- package/lib/vendor/blamejs/lib/network-smtp-policy.js +4 -4
- package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +11 -2
- package/lib/vendor/blamejs/lib/observability-tracer.js +1 -1
- package/lib/vendor/blamejs/lib/observability.js +39 -1
- package/lib/vendor/blamejs/lib/problem-details.js +56 -11
- package/lib/vendor/blamejs/lib/pubsub-cluster.js +16 -3
- package/lib/vendor/blamejs/lib/queue-sqs.js +20 -2
- package/lib/vendor/blamejs/lib/redis-client.js +32 -4
- package/lib/vendor/blamejs/lib/safe-redirect.js +16 -2
- package/lib/vendor/blamejs/memory/specs/node-26-map-getorinsert-migration.md +3 -2
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.14.20.json +73 -0
- package/lib/vendor/blamejs/release-notes/v0.14.21.json +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +339 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asyncapi.test.js +37 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +22 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +315 -5
- package/lib/vendor/blamejs/test/layer-0-primitives/config.test.js +46 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +176 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dora.test.js +38 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +236 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +23 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html-wcag.test.js +59 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/honeytoken.test.js +26 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +179 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy-tlsrpt.test.js +16 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +108 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +269 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +28 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +39 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/openapi.test.js +37 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/problem-details.test.js +79 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +49 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-sqs.test.js +48 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +60 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-redirect.test.js +118 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +259 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +46 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +113 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-txt.test.js +111 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +62 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/smtp-policy.test.js +39 -0
- package/package.json +1 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* b.middleware.securityTxt — RFC 9116 /.well-known/security.txt emitter.
|
|
4
|
+
*
|
|
5
|
+
* Covers: required-field enforcement (Contact / Expires), future-expiry
|
|
6
|
+
* check, the served body shape, root-path opt, method gating, and the
|
|
7
|
+
* de-advertised `audit` opt (the middleware serves a static public file
|
|
8
|
+
* on a hot path — no audit-worthy event, so the knob was removed).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
var helpers = require("../helpers");
|
|
12
|
+
var b = helpers.b;
|
|
13
|
+
var check = helpers.check;
|
|
14
|
+
|
|
15
|
+
function _mkRes() {
|
|
16
|
+
return {
|
|
17
|
+
statusCode: null,
|
|
18
|
+
headers: null,
|
|
19
|
+
bodyChunks: [],
|
|
20
|
+
ended: false,
|
|
21
|
+
writeHead: function (code, headers) { this.statusCode = code; this.headers = headers; return this; },
|
|
22
|
+
end: function (chunk) { if (chunk !== undefined) this.bodyChunks.push(chunk); this.ended = true; return this; },
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function testServesWellKnown() {
|
|
27
|
+
var mw = b.middleware.securityTxt({
|
|
28
|
+
contact: ["mailto:security@example.com"],
|
|
29
|
+
expires: "2099-01-01T00:00:00Z",
|
|
30
|
+
policy: "https://example.com/security/policy",
|
|
31
|
+
});
|
|
32
|
+
var res = _mkRes();
|
|
33
|
+
var nexted = false;
|
|
34
|
+
mw({ method: "GET", url: "/.well-known/security.txt" }, res, function () { nexted = true; });
|
|
35
|
+
check("securityTxt: serves at /.well-known/security.txt", res.statusCode === 200 && res.ended && !nexted);
|
|
36
|
+
var body = Buffer.concat(res.bodyChunks.map(function (c) { return Buffer.isBuffer(c) ? c : Buffer.from(String(c)); })).toString("utf8");
|
|
37
|
+
check("securityTxt: body carries Contact line", body.indexOf("Contact: mailto:security@example.com") !== -1);
|
|
38
|
+
check("securityTxt: body carries Expires line", body.indexOf("Expires: 2099-01-01T00:00:00Z") !== -1);
|
|
39
|
+
check("securityTxt: content-type text/plain", /text\/plain/.test(res.headers["Content-Type"]));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function testPassthroughOnOtherPaths() {
|
|
43
|
+
var mw = b.middleware.securityTxt({
|
|
44
|
+
contact: ["mailto:security@example.com"],
|
|
45
|
+
expires: "2099-01-01T00:00:00Z",
|
|
46
|
+
});
|
|
47
|
+
var res = _mkRes();
|
|
48
|
+
var nexted = false;
|
|
49
|
+
mw({ method: "GET", url: "/something-else" }, res, function () { nexted = true; });
|
|
50
|
+
check("securityTxt: non-matching path falls through to next", nexted && res.statusCode === null);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function testRequiredFieldEnforcement() {
|
|
54
|
+
var threwNoContact = false;
|
|
55
|
+
try { b.middleware.securityTxt({ expires: "2099-01-01T00:00:00Z" }); }
|
|
56
|
+
catch (_e) { threwNoContact = true; }
|
|
57
|
+
check("securityTxt: missing contact throws", threwNoContact);
|
|
58
|
+
|
|
59
|
+
var threwNoExpires = false;
|
|
60
|
+
try { b.middleware.securityTxt({ contact: ["mailto:s@example.com"] }); }
|
|
61
|
+
catch (_e) { threwNoExpires = true; }
|
|
62
|
+
check("securityTxt: missing expires throws", threwNoExpires);
|
|
63
|
+
|
|
64
|
+
var threwPastExpiry = false;
|
|
65
|
+
try {
|
|
66
|
+
b.middleware.securityTxt({
|
|
67
|
+
contact: ["mailto:s@example.com"],
|
|
68
|
+
expires: "2000-01-01T00:00:00Z",
|
|
69
|
+
});
|
|
70
|
+
} catch (_e) { threwPastExpiry = true; }
|
|
71
|
+
check("securityTxt: past expires throws", threwPastExpiry);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function testRejectsAuditOpt() {
|
|
75
|
+
// `audit` was accepted-but-unread (no audit-worthy event — the
|
|
76
|
+
// middleware serves a static public file and already uses the
|
|
77
|
+
// observability sink for the served counter). De-advertised: passing
|
|
78
|
+
// it now throws at config time.
|
|
79
|
+
var threw = false;
|
|
80
|
+
try {
|
|
81
|
+
b.middleware.securityTxt({
|
|
82
|
+
contact: ["mailto:security@example.com"],
|
|
83
|
+
expires: "2099-01-01T00:00:00Z",
|
|
84
|
+
audit: true,
|
|
85
|
+
});
|
|
86
|
+
} catch (_e) { threw = true; }
|
|
87
|
+
check("securityTxt: unknown 'audit' opt rejected", threw);
|
|
88
|
+
|
|
89
|
+
// The same opts WITHOUT audit construct fine.
|
|
90
|
+
var mw = b.middleware.securityTxt({
|
|
91
|
+
contact: ["mailto:security@example.com"],
|
|
92
|
+
expires: "2099-01-01T00:00:00Z",
|
|
93
|
+
});
|
|
94
|
+
check("securityTxt: constructs without audit opt", typeof mw === "function");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function run() {
|
|
98
|
+
testServesWellKnown();
|
|
99
|
+
testPassthroughOnOtherPaths();
|
|
100
|
+
testRequiredFieldEnforcement();
|
|
101
|
+
testRejectsAuditOpt();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = { run: run };
|
|
105
|
+
|
|
106
|
+
if (require.main === module) {
|
|
107
|
+
run().then(
|
|
108
|
+
function () { console.log("OK — " + helpers.getChecks() + " checks passed"); },
|
|
109
|
+
function (e) { console.error("FAIL:", e && e.stack || e); process.exit(1); }
|
|
110
|
+
);
|
|
111
|
+
}
|
|
@@ -198,6 +198,18 @@ function testFactoryValidation() {
|
|
|
198
198
|
shouldThrow("rejects unsupported protocol",
|
|
199
199
|
{ protocol: "gcs", region: "us-east-1", accessKeyId: "x", secretAccessKey: "y" },
|
|
200
200
|
/INVALID_CONFIG/);
|
|
201
|
+
|
|
202
|
+
// `ca` was an accepted-but-dead config knob — nothing in the request
|
|
203
|
+
// path (reqOpts → http-request → httpClient.request) threads a custom
|
|
204
|
+
// CA cert (the framework's PQC-only TLS posture lives solely in
|
|
205
|
+
// lib/pqc-agent.js; operators use NODE_EXTRA_CA_CERTS / opts.agent).
|
|
206
|
+
// De-advertised: passing it must now throw as an unknown option.
|
|
207
|
+
var threwCa = null;
|
|
208
|
+
try {
|
|
209
|
+
bucketOps.create(Object.assign({}, _baseConfig(9999), { ca: "-----BEGIN CERTIFICATE-----" }));
|
|
210
|
+
} catch (e) { threwCa = e; }
|
|
211
|
+
check("factory: de-advertised `ca` knob rejected as unknown option",
|
|
212
|
+
threwCa && /unknown option 'ca'/.test(threwCa.message || ""));
|
|
201
213
|
}
|
|
202
214
|
|
|
203
215
|
// ---- Bucket name validation ----
|
|
@@ -908,6 +920,55 @@ async function testAuditSuccessFalseDisablesSuccessAudit() {
|
|
|
908
920
|
}
|
|
909
921
|
}
|
|
910
922
|
|
|
923
|
+
async function testPerCallActorOverrideHonored() {
|
|
924
|
+
// Per-method opts accept `req` (resolves IP / user-agent / userId from a
|
|
925
|
+
// live request) and `actor` (an explicit identity override for callers
|
|
926
|
+
// performing a compliance-sensitive change on behalf of an operator).
|
|
927
|
+
// Both must land on the emitted audit row's `actor` field; `actor`-set
|
|
928
|
+
// keys win over the request-derived ones.
|
|
929
|
+
var auditCap = _captureAudit();
|
|
930
|
+
var fake = _fakeS3();
|
|
931
|
+
var port = await listenOnRandomPort(fake.server);
|
|
932
|
+
try {
|
|
933
|
+
var ops = bucketOps.create(Object.assign({}, _baseConfig(port), {
|
|
934
|
+
audit: auditCap,
|
|
935
|
+
}));
|
|
936
|
+
|
|
937
|
+
var fakeReq = {
|
|
938
|
+
ip: "203.0.113.9",
|
|
939
|
+
method: "PUT",
|
|
940
|
+
headers: { "user-agent": "ops-cli/1.0" },
|
|
941
|
+
};
|
|
942
|
+
await ops.create("actor-bucket", {
|
|
943
|
+
req: fakeReq,
|
|
944
|
+
actor: { userId: "ops-admin" },
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
var rows = auditCap.byAction("objectstore.bucket.create");
|
|
948
|
+
check("actor override: audit row emitted", rows.length === 1);
|
|
949
|
+
var actor = rows.length === 1 ? rows[0].actor : {};
|
|
950
|
+
check("actor override: explicit actor.userId lands on the audit row",
|
|
951
|
+
actor.userId === "ops-admin");
|
|
952
|
+
check("actor override: request-derived ip lands on the audit row",
|
|
953
|
+
actor.ip === "203.0.113.9");
|
|
954
|
+
check("actor override: request-derived userAgent lands on the audit row",
|
|
955
|
+
actor.userAgent === "ops-cli/1.0");
|
|
956
|
+
|
|
957
|
+
// Without actor/req, the resolved actor has the resolver's null
|
|
958
|
+
// defaults (no override) — default behavior unchanged.
|
|
959
|
+
var auditCap2 = _captureAudit();
|
|
960
|
+
var ops2 = bucketOps.create(Object.assign({}, _baseConfig(port), {
|
|
961
|
+
audit: auditCap2,
|
|
962
|
+
}));
|
|
963
|
+
await ops2.create("plain-bucket");
|
|
964
|
+
var rows2 = auditCap2.byAction("objectstore.bucket.create");
|
|
965
|
+
check("actor override: default behavior unchanged when actor/req absent",
|
|
966
|
+
rows2.length === 1 && rows2[0].actor && rows2[0].actor.userId === null);
|
|
967
|
+
} finally {
|
|
968
|
+
await new Promise(function (r) { fake.server.close(function () { r(); }); });
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
911
972
|
async function run() {
|
|
912
973
|
testSurface();
|
|
913
974
|
testFactoryValidation();
|
|
@@ -940,6 +1001,7 @@ async function run() {
|
|
|
940
1001
|
// v0.6.53 — audit + observability emissions
|
|
941
1002
|
await testAuditObservabilityWiring();
|
|
942
1003
|
await testAuditSuccessFalseDisablesSuccessAudit();
|
|
1004
|
+
await testPerCallActorOverrideHonored();
|
|
943
1005
|
}
|
|
944
1006
|
|
|
945
1007
|
module.exports = { run: run };
|
|
@@ -206,6 +206,43 @@ async function testTlsRptSubmitRejectsEmptyRua() {
|
|
|
206
206
|
check("submit rejects empty rua", threw && /tls-rpt-bad-rua/.test(threw.code || ""));
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
function testTlsRptRecordShapeRejectsReportingMta() {
|
|
210
|
+
// `reportingMta` was documented in the namespace example + accepted by
|
|
211
|
+
// recordShape's allowlist but never read (RFC 8460 §4.4 has no such
|
|
212
|
+
// top-level field). De-advertised: passing it throws at config time.
|
|
213
|
+
var threw = false;
|
|
214
|
+
try {
|
|
215
|
+
b.network.smtp.tlsRpt.recordShape({
|
|
216
|
+
organization: "example.com",
|
|
217
|
+
reportingMta: "mx1.example.com",
|
|
218
|
+
policies: [{ type: "sts", domain: "example.com" }],
|
|
219
|
+
});
|
|
220
|
+
} catch (_e) { threw = true; }
|
|
221
|
+
check("tlsRpt.recordShape: unknown 'reportingMta' opt rejected", threw);
|
|
222
|
+
|
|
223
|
+
// `reportId` IS read (report-id field) and is now in the allowlist —
|
|
224
|
+
// it must be accepted and flow through to the output.
|
|
225
|
+
var rpt = b.network.smtp.tlsRpt.recordShape({
|
|
226
|
+
organization: "example.com",
|
|
227
|
+
reportId: "rpt-fixed-1234",
|
|
228
|
+
policies: [{ type: "sts", domain: "example.com" }],
|
|
229
|
+
});
|
|
230
|
+
check("tlsRpt.recordShape: operator reportId flows to report-id",
|
|
231
|
+
rpt["report-id"] === "rpt-fixed-1234");
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function testTlsRptSubmitRejectsAuditOpt() {
|
|
235
|
+
// `audit` was accepted by submit's allowlist but never read — the
|
|
236
|
+
// function emits no audit row. De-advertised.
|
|
237
|
+
var threw = false;
|
|
238
|
+
try {
|
|
239
|
+
await b.network.smtp.tlsRpt.submit(
|
|
240
|
+
{ "organization-name": "example.com" },
|
|
241
|
+
{ rua: ["https://reports.example.com/submit"], audit: true });
|
|
242
|
+
} catch (_e) { threw = true; }
|
|
243
|
+
check("tlsRpt.submit: unknown 'audit' opt rejected", threw);
|
|
244
|
+
}
|
|
245
|
+
|
|
209
246
|
async function run() {
|
|
210
247
|
testSurface();
|
|
211
248
|
testMtaStsParse();
|
|
@@ -223,6 +260,8 @@ async function run() {
|
|
|
223
260
|
await testTlsRptFetchPolicyMissing();
|
|
224
261
|
await testTlsRptSubmitMixedRua();
|
|
225
262
|
await testTlsRptSubmitRejectsEmptyRua();
|
|
263
|
+
testTlsRptRecordShapeRejectsReportingMta();
|
|
264
|
+
await testTlsRptSubmitRejectsAuditOpt();
|
|
226
265
|
}
|
|
227
266
|
|
|
228
267
|
module.exports = { run: run };
|
package/package.json
CHANGED