@blamejs/blamejs-shop 0.5.6 → 0.5.8

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.
Files changed (28) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/cost-layers.js +86 -49
  4. package/lib/plan-changes.js +14 -0
  5. package/lib/storefront.js +30 -17
  6. package/lib/vendor/MANIFEST.json +31 -15
  7. package/lib/vendor/blamejs/.github/workflows/release-container.yml +2 -2
  8. package/lib/vendor/blamejs/CHANGELOG.md +2 -0
  9. package/lib/vendor/blamejs/api-snapshot.json +2 -2
  10. package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
  11. package/lib/vendor/blamejs/lib/content-credentials.js +43 -2
  12. package/lib/vendor/blamejs/lib/guard-sql.js +29 -0
  13. package/lib/vendor/blamejs/lib/mcp.js +37 -4
  14. package/lib/vendor/blamejs/lib/metrics.js +15 -3
  15. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +9 -2
  16. package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +33 -2
  17. package/lib/vendor/blamejs/lib/safe-buffer.js +11 -1
  18. package/lib/vendor/blamejs/package-lock.json +2 -2
  19. package/lib/vendor/blamejs/package.json +1 -1
  20. package/lib/vendor/blamejs/release-notes/v0.16.3.json +71 -0
  21. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +319 -0
  22. package/lib/vendor/blamejs/test/layer-0-primitives/cycle2-bugfixes.test.js +142 -0
  23. package/lib/vendor/blamejs/test/layer-0-primitives/guard-sql-coverage.test.js +432 -0
  24. package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +443 -0
  25. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +395 -0
  26. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-tus-upload-coverage.test.js +402 -0
  27. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-yaml-coverage.test.js +292 -0
  28. package/package.json +1 -1
@@ -0,0 +1,319 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) blamejs contributors
3
+ "use strict";
4
+ /**
5
+ * b.contentCredentials — error-path + adversarial-input coverage.
6
+ *
7
+ * Complements content-credentials.test.js (happy-path + round-trips) by
8
+ * driving the validation refusals, malformed-input rejections, wrong-state
9
+ * protocol errors, and fail-closed verdicts the round-trip tests never
10
+ * reach: bad build opts, missing required fields, signCose timestamp-
11
+ * posture and reuse-signature refusals, verifyCose malformed-CBOR / bad
12
+ * hashAlg / wrong-key verdicts, CAWG identity-assertion shape + trust-
13
+ * resolution refusals, and the GB 45438-2025 CAC implicit-label gate.
14
+ */
15
+
16
+ var helpers = require("../helpers");
17
+ var b = helpers.b;
18
+ var check = helpers.check;
19
+ var nodeCrypto = require("node:crypto");
20
+
21
+ var cc = b.contentCredentials;
22
+
23
+ // Capture the error a thrower raises (or null when it does not throw) —
24
+ // one definition so the many config-time refusal checks below don't each
25
+ // re-roll a `threw = null; try {} catch {}` block.
26
+ function _err(fn) {
27
+ try { fn(); return null; } catch (e) { return e; }
28
+ }
29
+
30
+ var VALID_BUILD = {
31
+ provider: "Acme AI Inc.", system: "acme-image-v3",
32
+ systemVersion: "3.2.1", contentId: "img-001",
33
+ };
34
+ function _buildOpts(overrides) {
35
+ return Object.assign({}, VALID_BUILD, overrides);
36
+ }
37
+
38
+ async function run() {
39
+ var e;
40
+
41
+ // ---- build() / _validateBuildOpts adversarial input ----
42
+ check("build(null) rejected as bad-opts",
43
+ (e = _err(function () { cc.build(null); })) && e.code === "content-credentials/bad-opts");
44
+ check("build('str') rejected as bad-opts",
45
+ (e = _err(function () { cc.build("nope"); })) && e.code === "content-credentials/bad-opts");
46
+
47
+ check("build missing system rejected",
48
+ (e = _err(function () { cc.build({ provider: "x", systemVersion: "1.0.0", contentId: "y" }); })) &&
49
+ e.code === "MISSING_SYSTEM");
50
+ check("build missing systemVersion rejected",
51
+ (e = _err(function () { cc.build({ provider: "x", system: "s", contentId: "y" }); })) &&
52
+ e.code === "MISSING_SYSTEMVERSION");
53
+ check("build missing contentId rejected",
54
+ (e = _err(function () { cc.build({ provider: "x", system: "s", systemVersion: "1.0.0" }); })) &&
55
+ e.code === "MISSING_CONTENTID");
56
+
57
+ check("build provider over 256 chars rejected",
58
+ (e = _err(function () { cc.build(_buildOpts({ provider: "a".repeat(257) })); })) &&
59
+ e.code === "content-credentials/bad-provider");
60
+ check("build system with illegal chars rejected",
61
+ (e = _err(function () { cc.build(_buildOpts({ system: "has space!" })); })) &&
62
+ e.code === "content-credentials/bad-system");
63
+ check("build systemVersion over 64 chars rejected",
64
+ (e = _err(function () { cc.build(_buildOpts({ systemVersion: "1.0.0-" + "a".repeat(60) })); })) &&
65
+ e.code === "content-credentials/bad-version");
66
+ check("build contentId with illegal chars rejected",
67
+ (e = _err(function () { cc.build(_buildOpts({ contentId: "bad id!" })); })) &&
68
+ e.code === "content-credentials/bad-content-id");
69
+ check("build contentSha3 wrong length rejected",
70
+ (e = _err(function () { cc.build(_buildOpts({ contentSha3: "abc123" })); })) &&
71
+ e.code === "content-credentials/bad-content-hash");
72
+ check("build contentSha3 non-hex rejected",
73
+ (e = _err(function () { cc.build(_buildOpts({ contentSha3: "z".repeat(128) })); })) &&
74
+ e.code === "content-credentials/bad-content-hash");
75
+
76
+ // Valid optional fields flow through (providerContact / sha3 / visibleDisclosure).
77
+ var mFull = cc.build(_buildOpts({
78
+ providerContact: "https://acme.example/contact",
79
+ contentType: "image/png", contentSha3: "a".repeat(128),
80
+ visibleDisclosure: "AI-generated by Acme",
81
+ }));
82
+ check("build carries optional contentSha3", mFull.content.sha3_512 === "a".repeat(128));
83
+ check("build carries providerContact", mFull.provider.contact === "https://acme.example/contact");
84
+ check("build carries visibleDisclosure", mFull.visibleDisclosure === "AI-generated by Acme");
85
+
86
+ // Adversarial numeric generatedAt (NaN) must not yield a manifest whose
87
+ // ISO timestamp is a broken value — either a clean rejection or a valid
88
+ // ISO string is acceptable; an unparseable generatedAtIso is not.
89
+ var nanRes = null, nanErr = null;
90
+ try { nanRes = cc.build(_buildOpts({ generatedAt: NaN })); } catch (ne) { nanErr = ne; }
91
+ check("build NaN generatedAt: rejected or valid ISO (no Invalid-Date manifest)",
92
+ nanErr !== null || (nanRes && !isNaN(Date.parse(nanRes.generatedAtIso))));
93
+
94
+ // ---- required() ----
95
+ check("required(null) returns opts-required",
96
+ JSON.stringify(cc.required(null)) === JSON.stringify(["opts-required"]));
97
+ check("required('str') returns opts-required",
98
+ JSON.stringify(cc.required("x")) === JSON.stringify(["opts-required"]));
99
+ var reqNonString = cc.required({ provider: 123, system: "s", systemVersion: "1.0.0", contentId: "c" });
100
+ check("required treats non-string provider as missing",
101
+ reqNonString.length === 1 && reqNonString[0] === "missing-provider");
102
+
103
+ // ---- sign() ----
104
+ var pair = b.crypto.generateSigningKeyPair("ml-dsa-87");
105
+ var manifest = cc.build(VALID_BUILD);
106
+
107
+ check("sign(null) rejected as bad-manifest",
108
+ (e = _err(function () { cc.sign(null, { privateKeyPem: pair.privateKey }); })) &&
109
+ e.code === "content-credentials/bad-manifest");
110
+ check("sign missing privateKeyPem rejected",
111
+ (e = _err(function () { cc.sign(manifest, {}); })) && e.code === "BAD_KEY");
112
+ check("sign no opts rejected",
113
+ (e = _err(function () { cc.sign(manifest); })) && e.code === "BAD_KEY");
114
+
115
+ // ---- verify() fail-closed verdicts (never throws) ----
116
+ var env = cc.sign(manifest, { privateKeyPem: pair.privateKey, audit: false });
117
+ check("verify(null) returns envelope-shape", cc.verify(null, pair.publicKey, { audit: false }).reason === "envelope-shape");
118
+ check("verify({}) returns envelope-shape", cc.verify({}, pair.publicKey, { audit: false }).reason === "envelope-shape");
119
+ check("verify empty signature returns envelope-shape",
120
+ cc.verify({ manifest: manifest, signature: "" }, pair.publicKey, { audit: false }).reason === "envelope-shape");
121
+ check("verify non-string key returns public-key-required",
122
+ cc.verify(env, 123, { audit: false }).reason === "public-key-required");
123
+ check("verify empty key returns public-key-required",
124
+ cc.verify(env, "", { audit: false }).reason === "public-key-required");
125
+
126
+ // A cryptographically valid signature over a payload that is NOT a
127
+ // complete SB-942 manifest must still fail the required-field gate.
128
+ var envPartial = cc.sign({ foo: "bar" }, { privateKeyPem: pair.privateKey, audit: false });
129
+ var vPartial = cc.verify(envPartial, pair.publicKey, { audit: false });
130
+ check("verify valid-sig-but-incomplete-manifest returns missing-required",
131
+ vPartial.valid === false && vPartial.reason.indexOf("missing-required") === 0);
132
+
133
+ // ---- signCose() config-time refusals ----
134
+ check("signCose(null) rejected as bad-manifest",
135
+ (e = _err(function () { cc.signCose(null, { privateKeyPem: pair.privateKey }); })) &&
136
+ e.code === "content-credentials/bad-manifest");
137
+ check("signCose missing privateKeyPem rejected",
138
+ (e = _err(function () { cc.signCose(manifest, { alg: "ml-dsa-87", timestamp: false, timestampOptOutReason: "x" }); })) &&
139
+ e.code === "BAD_KEY");
140
+ check("signCose timestamp as string rejected",
141
+ (e = _err(function () { cc.signCose(manifest, { privateKeyPem: pair.privateKey, timestamp: "soon" }); })) &&
142
+ e.code === "content-credentials/bad-timestamp");
143
+ check("signCose timestamp as array rejected",
144
+ (e = _err(function () { cc.signCose(manifest, { privateKeyPem: pair.privateKey, timestamp: [] }); })) &&
145
+ e.code === "content-credentials/bad-timestamp");
146
+ check("signCose timestamp with unknown key rejected",
147
+ (e = _err(function () { cc.signCose(manifest, { privateKeyPem: pair.privateKey, timestamp: { bogus: 1 } }); })) &&
148
+ /unknown option/.test(e.message));
149
+ check("signCose timestamp.token non-Buffer rejected",
150
+ (e = _err(function () { cc.signCose(manifest, { privateKeyPem: pair.privateKey, timestamp: { token: "not-a-buffer" } }); })) &&
151
+ e.code === "content-credentials/bad-timestamp-token");
152
+ check("signCose timestamp.signature empty rejected",
153
+ (e = _err(function () { cc.signCose(manifest, { privateKeyPem: pair.privateKey, timestamp: { token: Buffer.from([1]), signature: "" } }); })) &&
154
+ e.code === "content-credentials/bad-reuse-signature");
155
+
156
+ // Reused (pinned) signature that does not verify against this manifest+key
157
+ // is refused — a stale or foreign signature can't be re-embedded.
158
+ check("signCose reuse-signature that does not verify is refused",
159
+ (e = _err(function () {
160
+ cc.signCose(manifest, { privateKeyPem: pair.privateKey,
161
+ timestamp: { token: Buffer.from([1, 2, 3]), signature: nodeCrypto.randomBytes(32).toString("base64") } });
162
+ })) && e.code === "content-credentials/reuse-signature-mismatch");
163
+
164
+ // certChain emission — single-cert and multi-cert branches (bytes are
165
+ // carried opaquely; a non-Buffer entry is rejected, not silently kept).
166
+ var coseSingle = cc.signCose(manifest, {
167
+ privateKeyPem: pair.privateKey, timestamp: false, timestampOptOutReason: "x",
168
+ certChain: [Buffer.from([1, 2, 3])], audit: false,
169
+ });
170
+ var coseMulti = cc.signCose(manifest, {
171
+ privateKeyPem: pair.privateKey, timestamp: false, timestampOptOutReason: "x",
172
+ certChain: [Buffer.from([1, 2, 3]), Buffer.from([4, 5, 6])], audit: false,
173
+ });
174
+ check("signCose single-cert certChain produces COSE bytes", Buffer.isBuffer(coseSingle.coseSign1));
175
+ check("signCose multi-cert certChain grows COSE bytes", coseMulti.coseSign1.length > coseSingle.coseSign1.length);
176
+ check("signCose non-Buffer certChain entry is rejected (throws)",
177
+ _err(function () {
178
+ cc.signCose(manifest, { privateKeyPem: pair.privateKey, timestamp: false,
179
+ timestampOptOutReason: "x", certChain: ["not a buffer"] });
180
+ }) !== null);
181
+
182
+ // ---- verifyCose() fail-closed verdicts (never throws) ----
183
+ var optout = cc.signCose(manifest, {
184
+ privateKeyPem: pair.privateKey, alg: "ml-dsa-87",
185
+ timestamp: false, timestampOptOutReason: "no TSA in test", audit: false,
186
+ });
187
+ check("verifyCose bad timestampHashAlg returns bad-tst-hash verdict",
188
+ cc.verifyCose(optout.coseSign1, pair.publicKey, { timestampHashAlg: "MD5", audit: false }).reason === "content-credentials/bad-tst-hash");
189
+ check("verifyCose non-CBOR (0x00) returns cose-malformed verdict",
190
+ cc.verifyCose(Buffer.from([0x00]), pair.publicKey, { audit: false }).reason === "content-credentials/cose-malformed");
191
+ check("verifyCose undecodable CBOR (0xff) returns cose-malformed verdict",
192
+ cc.verifyCose(Buffer.from([0xff]), pair.publicKey, { audit: false }).reason === "content-credentials/cose-malformed");
193
+ var otherPair = b.crypto.generateSigningKeyPair("ml-dsa-87");
194
+ var vWrongKey = cc.verifyCose(optout.coseSign1, otherPair.publicKey, { requireTimestamp: false, audit: false });
195
+ check("verifyCose wrong key returns signature-mismatch verdict",
196
+ vWrongKey.valid === false && vWrongKey.reason === "signature-mismatch");
197
+
198
+ // ---- attachIdentityAssertion() config-time refusals ----
199
+ var refs = [{ label: "c2pa.actions", data: { action: "c2pa.created" } }];
200
+ check("attach() no args rejected (bad binding)",
201
+ (e = _err(function () { cc.attachIdentityAssertion(); })) && e.code === "content-credentials/bad-identity-binding");
202
+ check("attach subject non-object rejected",
203
+ (e = _err(function () { cc.attachIdentityAssertion({ binding: "x509", subject: "nope", referencedAssertions: refs, privateKeyPem: pair.privateKey }); })) &&
204
+ e.code === "content-credentials/bad-identity-subject");
205
+ check("attach subject array rejected",
206
+ (e = _err(function () { cc.attachIdentityAssertion({ binding: "x509", subject: [], referencedAssertions: refs, privateKeyPem: pair.privateKey }); })) &&
207
+ e.code === "content-credentials/bad-identity-subject");
208
+ check("attach subject empty object rejected",
209
+ (e = _err(function () { cc.attachIdentityAssertion({ binding: "x509", subject: {}, referencedAssertions: refs, privateKeyPem: pair.privateKey }); })) &&
210
+ e.code === "content-credentials/bad-identity-subject");
211
+ check("attach referencedAssertions non-array rejected",
212
+ (e = _err(function () { cc.attachIdentityAssertion({ binding: "x509", subject: { name: "x" }, referencedAssertions: "nope", privateKeyPem: pair.privateKey }); })) &&
213
+ e.code === "content-credentials/bad-referenced-assertions");
214
+ check("attach referencedAssertions empty rejected",
215
+ (e = _err(function () { cc.attachIdentityAssertion({ binding: "x509", subject: { name: "x" }, referencedAssertions: [], privateKeyPem: pair.privateKey }); })) &&
216
+ e.code === "content-credentials/bad-referenced-assertions");
217
+ check("attach missing privateKeyPem rejected",
218
+ (e = _err(function () { cc.attachIdentityAssertion({ binding: "x509", subject: { name: "x" }, referencedAssertions: refs }); })) &&
219
+ e.code === "BAD_KEY");
220
+ check("attach unknown opt key rejected",
221
+ (e = _err(function () { cc.attachIdentityAssertion({ binding: "x509", subject: { name: "x" }, referencedAssertions: refs, privateKeyPem: pair.privateKey, bogus: 1 }); })) &&
222
+ /unknown option/.test(e.message));
223
+
224
+ // ---- verifyIdentityAssertion() fail-closed verdicts (never throws) ----
225
+ var ia = cc.attachIdentityAssertion({
226
+ binding: "x509", subject: { name: "Acme Newsroom" },
227
+ referencedAssertions: refs, privateKeyPem: pair.privateKey, audit: false,
228
+ });
229
+ check("verifyIdentity null assertion returns assertion-shape",
230
+ cc.verifyIdentityAssertion(null, pair.publicKey, { referencedAssertions: refs }).reason === "assertion-shape");
231
+ check("verifyIdentity missing signer_payload returns assertion-shape",
232
+ cc.verifyIdentityAssertion({ signature: "x" }, pair.publicKey, { referencedAssertions: refs }).reason === "assertion-shape");
233
+ check("verifyIdentity non-string key returns public-key-required",
234
+ cc.verifyIdentityAssertion(ia, 123, { referencedAssertions: refs }).reason === "public-key-required");
235
+ check("verifyIdentity bad signer_payload binding returns signer-payload-shape",
236
+ cc.verifyIdentityAssertion({ signer_payload: { binding: "bogus", referenced_assertions: [] }, signature: "AA==" }, pair.publicKey, { referencedAssertions: refs }).reason === "signer-payload-shape");
237
+ check("verifyIdentity missing referencedAssertions opt returns referenced-assertions-required",
238
+ cc.verifyIdentityAssertion(ia, pair.publicKey, { audit: false }).reason === "referenced-assertions-required");
239
+ check("verifyIdentity referencedAssertions count mismatch returns count-mismatch",
240
+ cc.verifyIdentityAssertion(ia, pair.publicKey, { referencedAssertions: [refs[0], { label: "b" }], audit: false }).reason === "referenced-assertions-count-mismatch");
241
+
242
+ // x509 trust-resolution reason branches (self-asserted -> verified:false).
243
+ var vNoChain = cc.verifyIdentityAssertion(ia, pair.publicKey, {
244
+ referencedAssertions: refs, identityTrustAnchorsPem: "anchor-pem", audit: false,
245
+ });
246
+ check("verifyIdentity anchor but no chain -> verified:false no-cert-chain",
247
+ vNoChain.valid === true && vNoChain.verified === false && vNoChain.reason === "no-cert-chain");
248
+ var vBadAnchors = cc.verifyIdentityAssertion(ia, pair.publicKey, {
249
+ referencedAssertions: refs, identityCertChainPem: "chain-pem", identityTrustAnchorsPem: "", audit: false,
250
+ });
251
+ check("verifyIdentity empty trust anchor -> verified:false bad-trust-anchors",
252
+ vBadAnchors.verified === false && vBadAnchors.reason === "bad-trust-anchors");
253
+ var vBadChain = cc.verifyIdentityAssertion(ia, pair.publicKey, {
254
+ referencedAssertions: refs, identityCertChainPem: "not a pem", identityTrustAnchorsPem: "also not a pem", audit: false,
255
+ });
256
+ check("verifyIdentity unparseable chain cert -> verified:false bad-chain-cert",
257
+ vBadChain.verified === false && vBadChain.reason === "bad-chain-cert");
258
+
259
+ // ---- cacImplicitLabel() GB 45438-2025 gate ----
260
+ var CAC_VALID = {
261
+ providerName: "Example AI", providerCode: "91110000600037341A",
262
+ contentId: "asset-2026-05-17-abc123", contentKind: "image",
263
+ generatedAt: "2026-05-17T20:00:00Z",
264
+ };
265
+ function _cac(overrides) { return Object.assign({}, CAC_VALID, overrides); }
266
+
267
+ var label = cc.cacImplicitLabel(CAC_VALID);
268
+ check("cacImplicitLabel valid returns frozen AIGC block",
269
+ Object.isFrozen(label) && label.aigcMarker === "AIGC" && label.providerCode === "91110000600037341A");
270
+ check("cacImplicitLabel(null) rejected",
271
+ (e = _err(function () { cc.cacImplicitLabel(null); })) && e.code === "cac-implicit-label/bad-opts");
272
+ check("cacImplicitLabel missing providerName rejected",
273
+ (e = _err(function () { cc.cacImplicitLabel(_cac({ providerName: undefined })); })) &&
274
+ e.code === "cac-implicit-label/bad-provider-name");
275
+ check("cacImplicitLabel oversize providerName rejected",
276
+ (e = _err(function () { cc.cacImplicitLabel(_cac({ providerName: "a".repeat(257) })); })) &&
277
+ e.code === "cac-implicit-label/oversize-provider-name");
278
+ check("cacImplicitLabel bad providerCode rejected",
279
+ (e = _err(function () { cc.cacImplicitLabel(_cac({ providerCode: "123" })); })) &&
280
+ e.code === "cac-implicit-label/bad-provider-code");
281
+ check("cacImplicitLabel illegal contentId rejected",
282
+ (e = _err(function () { cc.cacImplicitLabel(_cac({ contentId: "bad id!" })); })) &&
283
+ e.code === "cac-implicit-label/bad-content-id");
284
+ check("cacImplicitLabel unknown contentKind rejected",
285
+ (e = _err(function () { cc.cacImplicitLabel(_cac({ contentKind: "hologram" })); })) &&
286
+ e.code === "cac-implicit-label/bad-content-kind");
287
+ check("cacImplicitLabel non-ISO generatedAt rejected",
288
+ (e = _err(function () { cc.cacImplicitLabel(_cac({ generatedAt: "yesterday" })); })) &&
289
+ e.code === "cac-implicit-label/bad-generated-at");
290
+
291
+ // ---- cacImplicitLabelRead() parser ----
292
+ check("cacImplicitLabelRead object input",
293
+ cc.cacImplicitLabelRead(Object.assign({ aigcMarker: "AIGC" }, CAC_VALID)).aigcMarker === "AIGC");
294
+ check("cacImplicitLabelRead string input",
295
+ cc.cacImplicitLabelRead(JSON.stringify(Object.assign({ aigcMarker: "AIGC" }, CAC_VALID))).contentKind === "image");
296
+ check("cacImplicitLabelRead Buffer input",
297
+ cc.cacImplicitLabelRead(Buffer.from(JSON.stringify(Object.assign({ aigcMarker: "AIGC" }, CAC_VALID)))).providerCode === "91110000600037341A");
298
+ check("cacImplicitLabelRead malformed JSON string rejected",
299
+ (e = _err(function () { cc.cacImplicitLabelRead("{not json"); })) && e.code === "cac-implicit-label/bad-json");
300
+ check("cacImplicitLabelRead malformed JSON Buffer rejected",
301
+ (e = _err(function () { cc.cacImplicitLabelRead(Buffer.from("{not json")); })) && e.code === "cac-implicit-label/bad-json");
302
+ check("cacImplicitLabelRead numeric input rejected",
303
+ (e = _err(function () { cc.cacImplicitLabelRead(42); })) && e.code === "cac-implicit-label/bad-input");
304
+ check("cacImplicitLabelRead missing AIGC marker rejected",
305
+ (e = _err(function () { cc.cacImplicitLabelRead({ providerName: "x" }); })) &&
306
+ e.code === "cac-implicit-label/missing-aigc-marker");
307
+ check("cacImplicitLabelRead re-applies field gate",
308
+ (e = _err(function () { cc.cacImplicitLabelRead(Object.assign({ aigcMarker: "AIGC" }, CAC_VALID, { providerCode: "BAD" })); })) &&
309
+ e.code === "cac-implicit-label/bad-provider-code");
310
+ }
311
+
312
+ module.exports = { run: run };
313
+
314
+ if (require.main === module) {
315
+ run().then(
316
+ function () { console.log("[content-credentials-coverage] OK — " + helpers.getChecks() + " checks passed"); },
317
+ function (e) { console.error("FAIL:", (e && e.stack) || e); process.exit(1); }
318
+ );
319
+ }
@@ -0,0 +1,142 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) blamejs contributors
3
+ "use strict";
4
+ /**
5
+ * Behavioral regression tests for the error/adversarial-branch defects found
6
+ * while raising coverage on metrics / safe-buffer / tus-upload / guard-sql /
7
+ * mcp / safe-yaml / content-credentials. Each assertion reproduces a specific
8
+ * failure: it fails on the pre-fix tree (RED) and passes on the fixed tree.
9
+ *
10
+ * Run standalone: `node test/layer-0-primitives/cycle2-bugfixes.test.js`
11
+ * Or via smoke: `node test/smoke.js`
12
+ */
13
+
14
+ var helpers = require("../helpers");
15
+ var b = helpers.b;
16
+ var check = helpers.check;
17
+ var nodeCrypto = require("crypto");
18
+ var Readable = require("stream").Readable;
19
+
20
+ function threwCode(fn) {
21
+ try { fn(); return null; } catch (e) { return e.code || null; }
22
+ }
23
+ function threw(fn) {
24
+ try { fn(); return false; } catch (_e) { return true; }
25
+ }
26
+
27
+ async function main() {
28
+ // ---- metrics: credential redaction reaches the exposition stream (HIGH) ----
29
+ var m1 = b.metrics.create({ namespace: "p" });
30
+ var c1 = m1.counter("logins_total", { labelNames: ["authorization"] });
31
+ c1.inc({ authorization: "Bearer aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" });
32
+ var out = m1.exposition();
33
+ check("metrics: credential label redacted in exposition, not just the map key",
34
+ out.indexOf("[REDACTED-CREDENTIAL]") !== -1 && out.indexOf("Bearer aaaa") === -1);
35
+
36
+ // ---- metrics: +/-Infinity rejected as non-finite (was isNaN-only) ----
37
+ var m2 = b.metrics.create({ namespace: "q" });
38
+ check("metrics: gauge.set(Infinity) rejected", threw(function () { m2.gauge("g", {}).set(Infinity); }));
39
+ check("metrics: counter.inc(Infinity) rejected", threw(function () { m2.counter("c", {}).inc(Infinity); }));
40
+ check("metrics: histogram.observe(Infinity) rejected",
41
+ threw(function () { m2.histogram("h", { buckets: [0.5] }).observe(Infinity); }));
42
+ check("metrics: gauge.set(42) still accepted", !threw(function () { m2.gauge("g2", {}).set(42); }));
43
+
44
+ // ---- safe-buffer.collectStream: a defineClass errorClass keeps code/message
45
+ // the right way round (was swapped -> callers branching on e.code missed) ----
46
+ var MyError = b.frameworkError.defineClass("CollectProbeError", { alwaysPermanent: true });
47
+ var stream = new Readable({ read: function () {} });
48
+ var caught = null;
49
+ var p = b.safeBuffer.collectStream(stream, {
50
+ maxBytes: b.constants.BYTES.bytes(4), errorClass: MyError,
51
+ sizeCode: "probe/too-large", sizeMessage: "body exceeded max",
52
+ }).then(function () { /* unexpected */ }, function (e) { caught = e; });
53
+ stream.push(Buffer.from("way too many bytes"));
54
+ stream.push(null);
55
+ await p;
56
+ check("safe-buffer: collectStream defineClass error keeps .code = sizeCode (not swapped)",
57
+ !!caught && caught.code === "probe/too-large" && caught.message === "body exceeded max");
58
+
59
+ // ---- guard-sql: fragment embedded-literal floor covers dollar-quotes + lone ; ----
60
+ function frag(s) { return b.guardSql.validate(s, { contextMode: "fragment", profile: "strict" }).ok; }
61
+ check("guard-sql: $tag$ dollar-quote refused in fragment", frag("x = $tag$secret$tag$") === false);
62
+ check("guard-sql: $$ empty-tag dollar-quote refused", frag("x = $$secret$$") === false);
63
+ check("guard-sql: lone trailing ; refused in fragment", frag("x = 1;") === false);
64
+ check("guard-sql: single-quote literal still refused", frag("x = 'secret'") === false);
65
+ check("guard-sql: ? placeholder still passes", frag("x = ?") === true);
66
+
67
+ // ---- mcp: validation gates enforce without an explicit top-level type:object ----
68
+ var inferredObjSchema = { properties: { path: { type: "string" } }, required: ["path"] };
69
+ check("mcp: validateToolInput enforces required with no type:object (fail-open closed)",
70
+ threw(function () { b.mcp.validateToolInput("t", {}, inferredObjSchema); }));
71
+ check("mcp: validateToolInput rejects a scalar for an inferred object schema",
72
+ threw(function () { b.mcp.validateToolInput("t", "oops", inferredObjSchema); }));
73
+ check("mcp: validateToolInput rejects an array for an inferred object schema",
74
+ threw(function () { b.mcp.validateToolInput("t", ["x"], inferredObjSchema); }));
75
+ check("mcp: validateToolInput rejects null for an inferred object schema",
76
+ threw(function () { b.mcp.validateToolInput("t", null, inferredObjSchema); }));
77
+ check("mcp: validateToolInput still accepts a valid object for an inferred object schema",
78
+ !threw(function () { b.mcp.validateToolInput("t", { path: "ok" }, inferredObjSchema); }));
79
+ check("mcp: assertProtocolVersion honors explicit empty accepted:[]",
80
+ threw(function () {
81
+ b.mcp.assertProtocolVersion({ headers: { "mcp-protocol-version": "2024-11-05" } }, { accepted: [] });
82
+ }));
83
+ var sg = b.mcp.sampling.guard({ maxTokensPerRequest: 100 });
84
+ check("mcp: sampling.guard rejects a string maxTokens (type-confusion)",
85
+ threw(function () { sg.enforce({ messages: [{ role: "user", content: "x" }], maxTokens: "999999" }, "sid"); }));
86
+
87
+ // ---- mcp serverGuard middleware (async): /register/ refusal + 401 challenge ----
88
+ async function drive(guard, req) {
89
+ var captured = { status: 200, headers: {}, nexted: false };
90
+ var res = {
91
+ statusCode: 200,
92
+ setHeader: function (k, v) { captured.headers[k.toLowerCase()] = v; },
93
+ end: function () { captured.status = this.statusCode; },
94
+ };
95
+ await guard(req, res, function () { captured.nexted = true; });
96
+ return captured;
97
+ }
98
+ var gReg = b.mcp.serverGuard({ requireBearer: false });
99
+ check("mcp: /register/ (trailing slash) refused like /register",
100
+ (await drive(gReg, { url: "/register/", method: "POST", headers: {} })).nexted === false);
101
+ var gBear = b.mcp.serverGuard({ requireBearer: true, verifyBearer: function () { return { sub: "x" }; } });
102
+ var bearCap = await drive(gBear, { url: "/", method: "POST", headers: {} });
103
+ check("mcp: missing bearer challenge returns 401 (was 400)",
104
+ bearCap.status === 401 && !!bearCap.headers["www-authenticate"]);
105
+
106
+ // ---- safe-yaml: flow-style parity with block style + root flow correctness ----
107
+ check("safe-yaml: flow-mapping duplicate key rejected",
108
+ threwCode(function () { b.parsers.yaml.parse("root: {a: 1, a: 2}"); }) === "yaml/duplicate-key");
109
+ check("safe-yaml: flow-mapping merge key '<<' rejected",
110
+ threwCode(function () { b.parsers.yaml.parse("root: {<<: base}"); }) === "yaml/merge-key-banned");
111
+ check("safe-yaml: trailing content after flow collection rejected",
112
+ threwCode(function () { b.parsers.yaml.parse("root: [1, 2] junk"); }) === "yaml/trailing-content");
113
+ check("safe-yaml: root-level JSON object parses correctly (not mis-scanned as block key)",
114
+ JSON.stringify(b.parsers.yaml.parse('{"a": 1, "b": 2}')) === '{"a":1,"b":2}');
115
+ check("safe-yaml: root-level flow sequence still parses",
116
+ JSON.stringify(b.parsers.yaml.parse("[1, 2, 3]")) === "[1,2,3]");
117
+
118
+ // ---- content-credentials: immutability + typed rejections ----
119
+ var m = b.contentCredentials.build({ provider: "Acme", system: "s", systemVersion: "1.0.0", contentId: "c" });
120
+ var before = m.content.id;
121
+ try { m.content.id = "HACKED"; } catch (_e) { /* strict-mode throw is fine too */ }
122
+ check("content-credentials: nested claim object is deep-frozen",
123
+ m.content.id === before && Object.isFrozen(m.content));
124
+ check("content-credentials: NaN generatedAt typed-rejected",
125
+ threwCode(function () {
126
+ b.contentCredentials.build({ provider: "x", system: "s", systemVersion: "1.0.0", contentId: "c", generatedAt: NaN });
127
+ }) === "content-credentials/bad-generated-at");
128
+ var kp = nodeCrypto.generateKeyPairSync("ed25519");
129
+ var pem = kp.privateKey.export({ type: "pkcs8", format: "pem" });
130
+ check("content-credentials: non-Buffer certChain entry typed-rejected",
131
+ threwCode(function () {
132
+ b.contentCredentials.signCose(m, { privateKeyPem: pem, timestamp: false, timestampOptOutReason: "x", certChain: ["nope"] });
133
+ }) === "content-credentials/bad-cert-chain");
134
+ }
135
+
136
+ if (require.main === module) {
137
+ main().then(function () {
138
+ console.log("cycle2-bugfixes OK — " + helpers.getChecks() + " checks");
139
+ }, function (e) { console.error(e); process.exit(1); });
140
+ }
141
+
142
+ module.exports = { run: main };