@blamejs/blamejs-shop 0.4.107 → 0.4.108
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 +2 -0
- package/lib/asset-manifest.json +1 -1
- package/lib/vendor/MANIFEST.json +19 -17
- package/lib/vendor/blamejs/CHANGELOG.md +2 -0
- package/lib/vendor/blamejs/api-snapshot.json +2 -2
- package/lib/vendor/blamejs/lib/network-dns.js +28 -1
- package/lib/vendor/blamejs/lib/network-tls.js +21 -1
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.15.28.json +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/access-lock.test.js +5 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +5 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-eaa.test.js +5 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +5 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html-wcag.test.js +5 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +31 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +33 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/require-mtls.test.js +5 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +5 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,8 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.4.x
|
|
10
10
|
|
|
11
|
+
- v0.4.108 (2026-06-26) — **Vendored framework refreshed to 0.15.28.** Updates the vendored blamejs framework to 0.15.28. The upstream change corrects the terminal-vs-transient retry signal (err.permanent) on the framework's DNS and TLS network errors, so the vendored HTTP client's internal retry behavior only re-attempts failures a retry can actually fix and stops retrying hopeless ones. This storefront consumes those network primitives only transitively through the vendored HTTP client (payment-provider and outbound-webhook calls), so the improvement applies automatically with no API or configuration change and no operator action required. **Changed:** *Vendored framework refreshed to 0.15.28* — Refreshes the vendored blamejs framework to 0.15.28. Upstream, the DNS and TLS network errors now expose a correct err.permanent flag (fail-closed: an unknown code is treated as permanent), so a retry loop re-attempts only transient network round-trip failures and never spins on a permanent one — while a trust-verification failure stays terminal and is never silently retried. This storefront uses these primitives only through the vendored HTTP client, so the better retry behavior applies transitively to payment-provider and outbound-webhook calls; there is no API change and no operator action required.
|
|
12
|
+
|
|
11
13
|
- v0.4.107 (2026-06-25) — **Vendored framework refreshed to 0.15.27.** Updates the vendored blamejs framework to 0.15.27. The 0.15.27 release is an upstream test-harness reliability change only — its published library is byte-for-byte identical to 0.15.26, with no runtime API or behavior change. No operator action required. **Changed:** *Vendored framework refreshed to 0.15.27* — Refreshes the vendored blamejs framework to 0.15.27, an upstream release whose shipped library is byte-for-byte identical to 0.15.26 (the change is to the framework's own test harness). There are no runtime API changes and no operator-visible behavior change; no action is required.
|
|
12
14
|
|
|
13
15
|
- v0.4.106 (2026-06-25) — **A capped discount rule's redemption counter no longer drifts toward its limit after a transient database error mid-claim.** Claiming a redemption against a discount rule with a total-redemption cap reserves a slot by incrementing the rule's used-count, then writes the per-order claim row. If writing that claim row failed for a reason other than the expected duplicate-claim collision — a transient backend error — the reserved slot was not returned, so the rule's used-count drifted one higher than the claims actually made and a capped rule could reach its limit early and start refusing legitimate redemptions. The claim path already returns the reservation when it reuses an existing claim and when the per-customer cap refuses; it now also returns it on this transient-failure path. The return is safe and cannot over-grant: the code re-reads the claim by its unique key and only returns the slot when that read confirms no claim row was written, so there is no case where a slot is returned for a claim that actually landed. **Fixed:** *A failed redemption claim returns its reserved cap slot instead of leaking it* — A redemption claim against a total-capped discount rule increments the rule's used-count to reserve a slot before inserting the per-order claim row. A failure inserting that row that was not the expected duplicate-claim collision (a transient backend error) left the reserved slot un-returned, drifting the used-count above the real claim count so the rule could hit its cap and refuse valid redemptions prematurely. The claim path now returns the reserved slot on that path too, matching the existing reuse and per-customer-cap refusals. It is safe against over-granting because it returns the slot only after a re-read on the claim's unique key confirms no row was written — a claim that actually landed is detected and reused, never double-counted.
|
package/lib/asset-manifest.json
CHANGED
package/lib/vendor/MANIFEST.json
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"_about": "blamejs.shop vendors a single framework — blamejs — which itself bundles every server-side crypto/identity dependency. The transitive packages blamejs ships are surfaced in its own MANIFEST.json at lib/vendor/blamejs/lib/vendor/MANIFEST.json — Trivy / Grype rely on that nested data for CVE attribution.",
|
|
4
4
|
"packages": {
|
|
5
5
|
"blamejs": {
|
|
6
|
-
"version": "0.15.
|
|
7
|
-
"tag": "v0.15.
|
|
6
|
+
"version": "0.15.28",
|
|
7
|
+
"tag": "v0.15.28",
|
|
8
8
|
"license": "Apache-2.0",
|
|
9
9
|
"author": "blamejs contributors",
|
|
10
10
|
"source": "https://github.com/blamejs/blamejs",
|
|
@@ -849,6 +849,7 @@
|
|
|
849
849
|
"release-notes/v0.15.25.json": "lib/vendor/blamejs/release-notes/v0.15.25.json",
|
|
850
850
|
"release-notes/v0.15.26.json": "lib/vendor/blamejs/release-notes/v0.15.26.json",
|
|
851
851
|
"release-notes/v0.15.27.json": "lib/vendor/blamejs/release-notes/v0.15.27.json",
|
|
852
|
+
"release-notes/v0.15.28.json": "lib/vendor/blamejs/release-notes/v0.15.28.json",
|
|
852
853
|
"release-notes/v0.15.3.json": "lib/vendor/blamejs/release-notes/v0.15.3.json",
|
|
853
854
|
"release-notes/v0.15.4.json": "lib/vendor/blamejs/release-notes/v0.15.4.json",
|
|
854
855
|
"release-notes/v0.15.5.json": "lib/vendor/blamejs/release-notes/v0.15.5.json",
|
|
@@ -1527,7 +1528,7 @@
|
|
|
1527
1528
|
"test/smoke.js": "lib/vendor/blamejs/test/smoke.js"
|
|
1528
1529
|
},
|
|
1529
1530
|
"bundler": "shallow git clone of release tag from github.com/blamejs/blamejs",
|
|
1530
|
-
"bundledAt": "2026-06-
|
|
1531
|
+
"bundledAt": "2026-06-26",
|
|
1531
1532
|
"hashes": {
|
|
1532
1533
|
".clusterfuzzlite/Dockerfile": "sha256:1eed98fcc49172efc1c1a7740dba20ce6cfcb3830cccd9f28cf114b4b39794f3",
|
|
1533
1534
|
".clusterfuzzlite/build.sh": "sha256:b9f5a627272c65f6569fa20dcbb32c383ca3a1183ce2562d481408a2fbaf9881",
|
|
@@ -1558,7 +1559,7 @@
|
|
|
1558
1559
|
".npmrc": "sha256:66f104e7d07c496d2d0409988225e8c0e4ceb8d247dbcac3be75b2128d20ce66",
|
|
1559
1560
|
".pinact.yaml": "sha256:0213ffda55961dc49b64c0a5dfa3c0567419633b1499d57eaf7c8d842d7da6c7",
|
|
1560
1561
|
"ARCHITECTURE.md": "sha256:9b1c8d2b1b7a41838eb348b0a008e4b4369718fd72bfe2974b37155f7536d35b",
|
|
1561
|
-
"CHANGELOG.md": "sha256:
|
|
1562
|
+
"CHANGELOG.md": "sha256:44632bfff523c7ec344cf3394b536b476c3ff41ec7c2926f50d5f8b8322a863d",
|
|
1562
1563
|
"CODE_OF_CONDUCT.md": "sha256:148a281960fff7c2fe6554dab66da572c72245ddeb00b0d14811558397bff386",
|
|
1563
1564
|
"CONTRIBUTING.md": "sha256:bb4dbdbc8598da31dbce653a8ed322e08ff46560173f2eb67a4d684653948332",
|
|
1564
1565
|
"GOVERNANCE.md": "sha256:906df6afb1f552b27b9acb50f7f96c47b917a2f1021cd4e987dbf4ee0e0a821b",
|
|
@@ -1568,7 +1569,7 @@
|
|
|
1568
1569
|
"NOTICE": "sha256:f487fa47a11aca0f89e2615cdd3c713e9842abf7a30d8d328eeeae1c864aa774",
|
|
1569
1570
|
"README.md": "sha256:3ddcc197b003da0b02db8bdd1aef1e943c94f7eab613c633d6a45bb11d0a80e9",
|
|
1570
1571
|
"SECURITY.md": "sha256:77d8c2bcc04b425a08ef30e51204cebddbd48954b028a259c7a8412dbfeab40a",
|
|
1571
|
-
"api-snapshot.json": "sha256:
|
|
1572
|
+
"api-snapshot.json": "sha256:99a6f96b8f2044cace0fa369fd1cebc772043fd6bb1fdb76c722a5cb0729a502",
|
|
1572
1573
|
"assets/BlameJS_Logo.png": "sha256:3c65699753c771b48ef9ac7f45bb40815ec19a23afcdd0cd30ef4601bbbe293e",
|
|
1573
1574
|
"assets/BlameJS_Logo.svg": "sha256:dda44f3fb1343d5de9db6b1fcdb75fc649c57e7a99a8e8239fcf852e3841e1a8",
|
|
1574
1575
|
"bench/README.md": "sha256:74202f2507fd840bfc1ac6c681975d9273cf36cca6e0f72655f138337304033c",
|
|
@@ -2167,13 +2168,13 @@
|
|
|
2167
2168
|
"lib/network-byte-quota.js": "sha256:79eafbf602a10ced990d89cfd26bea3992e42b177407b8e512bd4790999d17e3",
|
|
2168
2169
|
"lib/network-dane.js": "sha256:1f60a47618bd99a487d6c2faad423546896f753e33b516bdbc354138438d06f8",
|
|
2169
2170
|
"lib/network-dns-resolver.js": "sha256:3fd08605a077a8de1c15b3f436d2c2910af77e0078d27ce9d62fdce2e5949b7e",
|
|
2170
|
-
"lib/network-dns.js": "sha256:
|
|
2171
|
+
"lib/network-dns.js": "sha256:ff986202f7800719efe32d6f49900432783eb40a21185f4e8acdb7da45ba4139",
|
|
2171
2172
|
"lib/network-dnssec.js": "sha256:2b0758d09d5af89b49c69892fabaebabba125c3f9f162996c12b9abbbbae4bca",
|
|
2172
2173
|
"lib/network-heartbeat.js": "sha256:f14ec7fa4667cbb04477d91ae59d6253b6c9ccc43071bc558e737cc672f43975",
|
|
2173
2174
|
"lib/network-nts.js": "sha256:90ce47584ad58c171e8029eb1d5df8ba4ba130c4038d1fe260109685c34c8f75",
|
|
2174
2175
|
"lib/network-proxy.js": "sha256:9342c534863f905000d2432b67c26dd7a5ea02be25aaf9ebe05976079e61d4c9",
|
|
2175
2176
|
"lib/network-smtp-policy.js": "sha256:a7b6c91983b312a16c436d3e15259f8f6a84579e2e55f64106285b22795e1510",
|
|
2176
|
-
"lib/network-tls.js": "sha256:
|
|
2177
|
+
"lib/network-tls.js": "sha256:554b64c77389e1c961da8d061c63c806be994960466fb26f2b2268dbec0a369b",
|
|
2177
2178
|
"lib/network-tsig.js": "sha256:41dc85a6e816cce1c58c36891dfc6bafc612b68978936107a09a5a553563e0d7",
|
|
2178
2179
|
"lib/network.js": "sha256:40cb01627bf45741cac22ef79f5985f69323e47732d54cf3ce28c06882830c25",
|
|
2179
2180
|
"lib/nis2-report.js": "sha256:fa106a4f95dd9301d7da966c5792197bdbebac477a4f1d2fd2ac2481fbd818fd",
|
|
@@ -2339,7 +2340,7 @@
|
|
|
2339
2340
|
"oss-fuzz/projects/blamejs/README.md": "sha256:ae13b7bb79ed8d69b1b3276e5562807a0349fb6e6b7d11cf1f683aad1eafdb4b",
|
|
2340
2341
|
"oss-fuzz/projects/blamejs/build.sh": "sha256:0ced1cf21782c97be7f8d74faf5e27a308b60b2f858836fb5ca3b8c4e939a8f7",
|
|
2341
2342
|
"oss-fuzz/projects/blamejs/project.yaml": "sha256:59f2cb83aa622325a175b77416fe155be15b70a9c798bd1a78bba05763b1b03d",
|
|
2342
|
-
"package.json": "sha256:
|
|
2343
|
+
"package.json": "sha256:0e42d663df6e40194fe8542b545b73f46681f6e81b0047a4a6b87284f6ab27bf",
|
|
2343
2344
|
"release-notes/v0.0.x.json": "sha256:7a49819f30068ee119000cad7010194882bb8bfaa12acbdab4dfc066efb7982f",
|
|
2344
2345
|
"release-notes/v0.1.x.json": "sha256:6742a8c17f947c5cb76f69dead7eea86b942d80621d914b774ba5488e09937e5",
|
|
2345
2346
|
"release-notes/v0.10.x.json": "sha256:fe498045daf88337bd3d987e5964aa42c99a50e1685b6f09e51f698b8687726f",
|
|
@@ -2368,6 +2369,7 @@
|
|
|
2368
2369
|
"release-notes/v0.15.25.json": "sha256:6f7c4eb0d57068317bfb68f739d93b5926f9723a57a0701c966b0f96eb46ed69",
|
|
2369
2370
|
"release-notes/v0.15.26.json": "sha256:a96b1c7409f863b5a920f51a92b653d5f7a0b671e000bb5dfc2e9bf47e4120dc",
|
|
2370
2371
|
"release-notes/v0.15.27.json": "sha256:f9e8309bc32c2245ec8d0682e6205417879f090403727d4780b42c0536125f02",
|
|
2372
|
+
"release-notes/v0.15.28.json": "sha256:86d4b034ccd17a51abd706fcd3ec0c1dfca224ae92a74e8d501af1e6f57cb6aa",
|
|
2371
2373
|
"release-notes/v0.15.3.json": "sha256:19a0074c445545468ca3cc411b21ec8bdb27be2669ae1950347cc244f6aa348c",
|
|
2372
2374
|
"release-notes/v0.15.4.json": "sha256:6ac7fa0ef1728c27e71b2050d1b07a810f9b4b1440ccddbf28ad56e2f54d8585",
|
|
2373
2375
|
"release-notes/v0.15.5.json": "sha256:cca1d0edd5d6fc41b512d19d98be224b990dcab41478622c11962f0fcb1bb09a",
|
|
@@ -2484,9 +2486,9 @@
|
|
|
2484
2486
|
"test/integration/ws-client-roundtrip.test.js": "sha256:e6e9592dcc3962fffbc2ad399567befea6177fd48e31541a79f4cb630fcf7006",
|
|
2485
2487
|
"test/layer-0-primitives/a2a-tasks.test.js": "sha256:094532bd9306e76c87db08b678edd88792b64855147501963b156f612bb8ec2f",
|
|
2486
2488
|
"test/layer-0-primitives/a2a.test.js": "sha256:fb5d0ad7e3d0e4fb3d4b2e85acb344a4ba5140f9a9dc533b75d7ab81a64bba43",
|
|
2487
|
-
"test/layer-0-primitives/access-lock.test.js": "sha256:
|
|
2489
|
+
"test/layer-0-primitives/access-lock.test.js": "sha256:26f14cad57db47c88546186393fbdd7a4adc47675d7b45407cd803c3ee3fa080",
|
|
2488
2490
|
"test/layer-0-primitives/acme.test.js": "sha256:23ac86ef3b4ab261a9bf55ee936ea543e245d6600ab79c00d167aa4e145e2cba",
|
|
2489
|
-
"test/layer-0-primitives/age-gate.test.js": "sha256:
|
|
2491
|
+
"test/layer-0-primitives/age-gate.test.js": "sha256:b5b2813c423a2dd817c69bb05dbce1aa690ffb40cac7a76227ebf515244cabfc",
|
|
2490
2492
|
"test/layer-0-primitives/agent-event-bus.test.js": "sha256:d428f6237d48a101837ff77ae62a94de885a1d99864346c8d78561dcf97351d2",
|
|
2491
2493
|
"test/layer-0-primitives/agent-idempotency.test.js": "sha256:cfe26bf5890d70d634659199292a525efd4885c55bfd1384e05bd3dca07ac398",
|
|
2492
2494
|
"test/layer-0-primitives/agent-orchestrator.test.js": "sha256:122bc275b5dbec60efc541f48d8e121f37d1d1e9f0d3b914a2c27d8ebe28a0e2",
|
|
@@ -2619,7 +2621,7 @@
|
|
|
2619
2621
|
"test/layer-0-primitives/codepoint-class.test.js": "sha256:19d1b69efa7e0e9f7ef2392ca264167767a5ec5890ee339b2cfd8a7818035d27",
|
|
2620
2622
|
"test/layer-0-primitives/compliance-ai-act.test.js": "sha256:5ee4ad05d12233cb3c5457ef10a727833710bbc1ce1318838f9f9ef5d2cb8d4b",
|
|
2621
2623
|
"test/layer-0-primitives/compliance-cascade.test.js": "sha256:ee02cf14541a837a9d7977c6ea6bf7f9210bed293925d93c976e31f270aebec4",
|
|
2622
|
-
"test/layer-0-primitives/compliance-eaa.test.js": "sha256:
|
|
2624
|
+
"test/layer-0-primitives/compliance-eaa.test.js": "sha256:2eb41e48e9face72cb0d21ee0cd2b69ca7fcaba305cb9e30741d35cd2bd9f4a7",
|
|
2623
2625
|
"test/layer-0-primitives/compliance-eu-ai-act-posture.test.js": "sha256:3f45bb76ef390b7cc4396a37153d48f0f9465c5abc59851f0971fcc40c28dcea",
|
|
2624
2626
|
"test/layer-0-primitives/compliance-sanctions.test.js": "sha256:e4cb4e7b73cb0834958c1c18c9d3bb70087ee784216a888991dbe41b518b87f0",
|
|
2625
2627
|
"test/layer-0-primitives/compliance.test.js": "sha256:d743b6e2df985daed1df4a7808e7e5bf91207d5909f5bd7d8f882e0c27dcfe1b",
|
|
@@ -2724,7 +2726,7 @@
|
|
|
2724
2726
|
"test/layer-0-primitives/fsm.test.js": "sha256:7037831083426478ed4efd7d1c17d4b96c3609816a41819b5c9da71d2b6187e8",
|
|
2725
2727
|
"test/layer-0-primitives/gate-contract-content-gate.test.js": "sha256:d9f8b94231efb0e02a94b7934bf58a3f8e343829ce11346b7302e69e13efd551",
|
|
2726
2728
|
"test/layer-0-primitives/gcs-bucket-ops.test.js": "sha256:c1a0982190506dba72430c16972a296abc2de865786cc72c63c971edf450502c",
|
|
2727
|
-
"test/layer-0-primitives/gdpr-ropa.test.js": "sha256:
|
|
2729
|
+
"test/layer-0-primitives/gdpr-ropa.test.js": "sha256:de4d2b6db19c87a0ea00c49bc865c39802a664f0ee6b6a3f98f62319d79a4fe7",
|
|
2728
2730
|
"test/layer-0-primitives/graphql-federation.test.js": "sha256:c920cdc6f8740733b712d139d11da08c4fa5c8add3b0749fa74c6fbce04965cf",
|
|
2729
2731
|
"test/layer-0-primitives/guard-agent-registry.test.js": "sha256:d432339273cde552cde8101ac1b32df44c36e7dd9381a328669f63884ac9016b",
|
|
2730
2732
|
"test/layer-0-primitives/guard-all.test.js": "sha256:fdd9a746ecfa6e29f0e5f727fbd66c5ab2e29a263ef0d8c2c1d62fc430cdd59f",
|
|
@@ -2737,7 +2739,7 @@
|
|
|
2737
2739
|
"test/layer-0-primitives/guard-event-bus-topic.test.js": "sha256:538e6d338541b724fc5bedb7f2fd33fae12777d292c771bb5d70720e30bf9156",
|
|
2738
2740
|
"test/layer-0-primitives/guard-filename.test.js": "sha256:6718194054554e246e171e1c23a970dfc5e618fa3bd6a79a8925289fd339fd06",
|
|
2739
2741
|
"test/layer-0-primitives/guard-gate-disposition-coverage.test.js": "sha256:e4e3a971fe2659593bb76aebed6d65ddea937eda558191085c1ad31fb1c5eaf3",
|
|
2740
|
-
"test/layer-0-primitives/guard-html-wcag.test.js": "sha256:
|
|
2742
|
+
"test/layer-0-primitives/guard-html-wcag.test.js": "sha256:cdbec2cc892cbe615865a1cfc6b69fe128af81ad953fc35fb6f00c284a5a7fc4",
|
|
2741
2743
|
"test/layer-0-primitives/guard-html.test.js": "sha256:31ac5ba5728ad18df1e188c5251ec97698f7d7bd840011c2870fccd115b35969",
|
|
2742
2744
|
"test/layer-0-primitives/guard-idempotency-key.test.js": "sha256:18b233de627ea68cc289cb2fcd6ad5ca18db3bf911581747fd293e1bd3ee8789",
|
|
2743
2745
|
"test/layer-0-primitives/guard-image.test.js": "sha256:0f45eae95851d2e9f5b8338d2a99dddabb59b60e1be69ac9ec5d0e4d7cd21428",
|
|
@@ -2861,12 +2863,12 @@
|
|
|
2861
2863
|
"test/layer-0-primitives/network-dns-lookup-timeout-default.test.js": "sha256:6251b8d093f6402a13d08afea2d7164fccdb8d2edbbbe63915b88b4e2bcba47b",
|
|
2862
2864
|
"test/layer-0-primitives/network-dns-resolver-timeout.test.js": "sha256:9ba8ca49b8095ec4780959134520ac869c80ca9b9664b5beadce2d135037777d",
|
|
2863
2865
|
"test/layer-0-primitives/network-dns-resolver.test.js": "sha256:8966ba1b24c9ceb5754a3ef21a6d6e61a6cade983367bece1034110b7928fc1c",
|
|
2864
|
-
"test/layer-0-primitives/network-dns.test.js": "sha256:
|
|
2866
|
+
"test/layer-0-primitives/network-dns.test.js": "sha256:b627a0c6006229be8d0c3409857dcff6bd7b97a22f5ff5c3b4f9fdd28178997a",
|
|
2865
2867
|
"test/layer-0-primitives/network-heartbeat-passive.test.js": "sha256:4dae1d9f61c85489d1a91a6f4a242198d0bee89fdbacff9efba143e78e882ad0",
|
|
2866
2868
|
"test/layer-0-primitives/network-nts-handshake-byte-cap.test.js": "sha256:b20b7a6e218613282d7d817d7a675f9ee81ba07af1ed5c089283e62736e2c515",
|
|
2867
2869
|
"test/layer-0-primitives/network-tls-build-options.test.js": "sha256:0380ef886acc0a3bb0f7bc032c11991891fe9f19648e9f8d38829c7ea16b61b0",
|
|
2868
2870
|
"test/layer-0-primitives/network-tls-ct-inclusion.test.js": "sha256:951b5eeded5762f667c534c0433e4b5f4b0a6a48c7c66a88492c0d4cebd21636",
|
|
2869
|
-
"test/layer-0-primitives/network-tls.test.js": "sha256:
|
|
2871
|
+
"test/layer-0-primitives/network-tls.test.js": "sha256:f914692bc98176d2f425bcca7a7023eee5f0258eb293da2d56afc8232c10fa2f",
|
|
2870
2872
|
"test/layer-0-primitives/network-tsig.test.js": "sha256:8845cb8f23876e6c68436491a412bbbd2c5415af23438c5ab2613358b3a4168f",
|
|
2871
2873
|
"test/layer-0-primitives/network.test.js": "sha256:5424adaab9c3fe6e1b96e21eef90e51c5cf4c7fa8e96132306399d95cdfacdf1",
|
|
2872
2874
|
"test/layer-0-primitives/nis2-report.test.js": "sha256:4ee2d6a5c6e05c317c34a4f7eef91a0c91079d227b8b69c65e1d58e4444613e0",
|
|
@@ -2920,7 +2922,7 @@
|
|
|
2920
2922
|
"test/layer-0-primitives/request-id-async-context.test.js": "sha256:3aad8f145e7ca37c7220767779050ffaa5da2b2bb2cb7e4b65d3652d554b0322",
|
|
2921
2923
|
"test/layer-0-primitives/request-log.test.js": "sha256:31479f63311b31a74aa7f636b7f9ef04c2f6bcb152b8b8c465a40d08461cc03f",
|
|
2922
2924
|
"test/layer-0-primitives/require-auth-cache-control.test.js": "sha256:36b9d77791285e2b2606a5d2f8f8c8536a46e7ec1f4f2c5e54ee1b17a3dece3d",
|
|
2923
|
-
"test/layer-0-primitives/require-mtls.test.js": "sha256:
|
|
2925
|
+
"test/layer-0-primitives/require-mtls.test.js": "sha256:355759e9a2e03add272af8f18f8297c60444d30fceac99455dd6ce339e8980f6",
|
|
2924
2926
|
"test/layer-0-primitives/resource-access-lock.test.js": "sha256:f436bcd187b317229266b4f27d89e7f87cb28c7dc400643594b22d05232dbac4",
|
|
2925
2927
|
"test/layer-0-primitives/restore-blob-remap.test.js": "sha256:8caee31bd1c75dc15fb51ffc3db7981660c7bc20a01ff8e82e9dccbdefe9e671",
|
|
2926
2928
|
"test/layer-0-primitives/retention-dryrun-no-vacuum.test.js": "sha256:b454fb508b22418097839a20f7b1ff5240a57f8ee37e575768780e7b8cc772b6",
|
|
@@ -2951,7 +2953,7 @@
|
|
|
2951
2953
|
"test/layer-0-primitives/safe-url-canonicalize.test.js": "sha256:5a85baeec34770f9efef04fe8036fc75f80278188ed6f09adcb97f72d39a0dc8",
|
|
2952
2954
|
"test/layer-0-primitives/safe-url-idn-homograph.test.js": "sha256:a68b8307a0711270ce865d80937793c3bd48445f0ac6adb5814bd9b948e06193",
|
|
2953
2955
|
"test/layer-0-primitives/safe-vcard.test.js": "sha256:10a0695050afee64599411352b34382e15b8f9bd9045ed3951cc6bc561918c89",
|
|
2954
|
-
"test/layer-0-primitives/safe-xml.test.js": "sha256:
|
|
2956
|
+
"test/layer-0-primitives/safe-xml.test.js": "sha256:0a2127b6803bea6e028a0350c02ffd6812c17de5c6c0a260c54ea2c642eb0c93",
|
|
2955
2957
|
"test/layer-0-primitives/saml-slo.test.js": "sha256:b8b3a5e71ad28a0a3e9b69bca9f570410bc8b8eab6a7fdfd186fdf12cd90854f",
|
|
2956
2958
|
"test/layer-0-primitives/saml-subjectconfirmation-notbefore.test.js": "sha256:2deac25891a4eb2c5d1073d99c352a01322e6fab6497616209ec6a15cc1fbf71",
|
|
2957
2959
|
"test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js": "sha256:1396afcc34135ab025880ac74738f3eb1984f5725dcf2e676e6a2f1bd7f852c2",
|
|
@@ -8,6 +8,8 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.15.x
|
|
10
10
|
|
|
11
|
+
- v0.15.28 (2026-06-25) — **`b.network.dns` and `b.network.tls` errors now carry a usable terminal-vs-transient signal on `err.permanent`, so a caller's retry loop re-attempts only the failures a retry can fix.** DnsError was declared always-transient and NetworkTlsError always-permanent, so a consumer driving its own retry loop got the wrong signal in both directions: it would retry a permanent DNS failure (a bad host, bad options, an unsupported query, an NXDOMAIN-style no-result, or a caller-shape/config error such as an unconfigured transport or an invalid resolver list) forever, and it would refuse to retry a transient TLS-over-network failure (an ECH connection failure, a handshake timeout, DNS momentarily unavailable). err.permanent now reflects each error's actual transience, derived from its code and failing closed (an unknown code is permanent, so a hopeless target is not retried indefinitely): for DnsError only a failed network round-trip (a lookup timeout, a resolve/reverse query that failed on the wire, a failed DoH/DoT exchange, a DDR discovery that found nothing) is transient — config, input, and environment errors raised before any network work are permanent; for NetworkTlsError only the network-layer ECH failures are transient. TlsTrustError remains always-permanent by design — a trust-verification failure (bad CA, fingerprint mismatch, OCSP not-good, CT violation, an unreachable OCSP responder) must never be silently retried past the trust decision. **Fixed:** *DnsError / NetworkTlsError expose a correct terminal/transient signal; TlsTrustError stays terminal* — b.network.dns's DnsError was always-transient and b.network.tls's NetworkTlsError always-permanent, so err.permanent misled a consumer's retry loop in both directions — retrying a permanent DNS error (bad host / options / unsupported type / no-result) indefinitely, and never retrying a transient TLS network error (ECH connect failure, handshake timeout, DNS unavailable). err.permanent now reflects each error's actual transience by code and fails closed (unknown codes are permanent): DnsError is transient only for a failed network round-trip (dns/lookup-timeout, dns/resolve-failed, dns/reverse-failed, dns/doh-failed, dns/dot-failed, dns/dot-handshake-failed, dns/ddr-not-discovered, dns/system-failed), and permanent otherwise — including the caller-shape / environment errors raised before any network work (dns/transport-unavailable for an unconfigured transport, dns/dnr-no-resolvers for an empty/invalid resolver list, dns/setservers-failed for an invalid address, dns/no-system-resolvers when none are configured). NetworkTlsError is transient only for the network-layer ECH failures (tls/ech-connect-failed, tls/ech-timeout, tls/ech-dns-unavailable), permanent otherwise. TlsTrustError remains always-permanent so a trust-verification failure is never silently retried.
|
|
12
|
+
|
|
11
13
|
- v0.15.27 (2026-06-25) — **Internal test-harness reliability only — the published library is byte-for-byte identical to 0.15.26.** The legacy single-layer smoke files used fixed-duration setTimeout sleeps to wait for asynchronous conditions (a job processed, a lease TTL lapsing, an audit flush completing). On a contended CI runner a fixed sleep is both flake-prone (too short under load) and slow (it always burns the full budget). Those condition-waits are converted to the harness's polling helpers — waitUntil for observable predicates, passiveObserve for deliberate real-time elapses, withTestTimeout for hang guards — which exit early on fast platforms and give contended platforms the full budget. No shipped framework code changed; this release is byte-for-byte identical to 0.15.26 for operators. **Fixed:** *Smoke layer files poll for conditions instead of fixed setTimeout sleeps* — The single-layer smoke files waited on asynchronous conditions with fixed-duration setTimeout sleeps, which flake under SMOKE_PARALLEL load and always burn their full budget. The condition-waits are converted to the polling helpers (waitUntil / passiveObserve / withTestTimeout) so they exit early on fast platforms and stay robust on contended ones; non-wait timers (abort triggers, child/socket watchdogs, simulated-latency mocks) are unchanged. This is test-harness reliability only — no shipped framework behavior changed.
|
|
12
14
|
|
|
13
15
|
- v0.15.26 (2026-06-25) — **Internal test-harness correctness only — the published library is byte-for-byte identical to 0.15.25.** The smoke runner requires each test module and awaits its exported run(). Several tests were instead written as a top-level (async function () {...})() IIFE that runs detached at require-time, so the runner measured and reported the test's result before the IIFE's post-await assertions executed — those checks silently never ran (one parser test exercised 4 of its 26 assertions, and a failure after the first await would have gone unseen as a false pass). Those tests are converted to the exported-run form so the runner awaits their full assertion set, and a codebase-patterns detector now refuses a top-level async IIFE in a test file so the pattern cannot return. No shipped framework code changed; this release is byte-for-byte identical to 0.15.25 for operators. **Fixed:** *Detached-IIFE tests now run their full assertion set under the smoke runner* — A test written as a top-level (async function () {...})() IIFE runs detached when the runner requires it: the runner only awaits an exported run(), so it reported the file's result before the IIFE's awaited assertions executed, and every check after the first await silently did not count (one parsers test ran 4 of 26). Such tests are rewritten to define async function run(), export it, and invoke it under if (require.main === module), so the runner awaits the complete set; a detector refuses a re-introduced top-level async IIFE in a test file. This is test-harness correctness only — no shipped framework behavior changed.
|
|
@@ -16,7 +16,34 @@ var validateOpts = require("./validate-opts");
|
|
|
16
16
|
var { defineClass } = require("./framework-error");
|
|
17
17
|
var { boundedMap } = require("./bounded-map");
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
// DnsError carries a terminal-vs-transient signal on err.permanent so a caller
|
|
20
|
+
// driving a retry loop knows which failures are worth re-attempting. Fail
|
|
21
|
+
// CLOSED: only a failure of an actual network round-trip that a retry can
|
|
22
|
+
// plausibly fix is transient (a lookup timeout, a resolve/reverse query that
|
|
23
|
+
// failed on the wire, a DoH/DoT exchange that failed, a DDR discovery query that
|
|
24
|
+
// found nothing). Everything else is permanent — bad config / options, an
|
|
25
|
+
// unsupported query, a malformed or empty/NXDOMAIN-style reply, AND the
|
|
26
|
+
// caller-shape / environment errors raised BEFORE any network work: requesting a
|
|
27
|
+
// transport that was never configured (dns/transport-unavailable), an
|
|
28
|
+
// empty/invalid designated-resolver list (dns/dnr-no-resolvers), an invalid
|
|
29
|
+
// setServers address (dns/setservers-failed), or no system resolvers configured
|
|
30
|
+
// (dns/no-system-resolvers). A retry cannot make invalid input or absent
|
|
31
|
+
// configuration valid.
|
|
32
|
+
var DNS_TRANSIENT_CODES = {
|
|
33
|
+
"dns/lookup-timeout": true,
|
|
34
|
+
"dns/system-failed": true,
|
|
35
|
+
"dns/resolve-failed": true,
|
|
36
|
+
"dns/reverse-failed": true,
|
|
37
|
+
"dns/doh-http": true,
|
|
38
|
+
"dns/doh-failed": true,
|
|
39
|
+
"dns/dot-handshake-failed": true,
|
|
40
|
+
"dns/dot-failed": true,
|
|
41
|
+
"dns/ddr-not-discovered": true,
|
|
42
|
+
};
|
|
43
|
+
function _dnsErrorIsPermanent(code) {
|
|
44
|
+
return !Object.prototype.hasOwnProperty.call(DNS_TRANSIENT_CODES, code);
|
|
45
|
+
}
|
|
46
|
+
var DnsError = defineClass("DnsError", { permanentClassifier: _dnsErrorIsPermanent });
|
|
20
47
|
|
|
21
48
|
// Protocol-fixed byte counts and radixes — passthrough through C.BYTES
|
|
22
49
|
// keeps every numeric literal routed through one helper.
|
|
@@ -16,8 +16,28 @@ var lazyRequire = require("./lazy-require");
|
|
|
16
16
|
var safeAsync = require("./safe-async");
|
|
17
17
|
var { defineClass } = require("./framework-error");
|
|
18
18
|
|
|
19
|
+
// TlsTrustError is a TRUST-verification failure (bad CA/PEM, fingerprint
|
|
20
|
+
// mismatch, OCSP not-good / revoked, CT violation, hostname/PKIX failure, an
|
|
21
|
+
// unreachable OCSP responder). These are ALWAYS permanent: a caller must never
|
|
22
|
+
// silently retry past a trust decision — a transient-looking OCSP-fetch failure
|
|
23
|
+
// is the operator's soft-fail policy to make explicitly, not something a retry
|
|
24
|
+
// loop should paper over. Fail closed.
|
|
19
25
|
var TlsTrustError = defineClass("TlsTrustError", { alwaysPermanent: true });
|
|
20
|
-
|
|
26
|
+
|
|
27
|
+
// NetworkTlsError carries a terminal-vs-transient signal on err.permanent. Fail
|
|
28
|
+
// CLOSED: only the network-layer ECH failures a retry can plausibly fix (a
|
|
29
|
+
// connect failure, a timeout, DNS being momentarily unavailable) are transient;
|
|
30
|
+
// bad options, a malformed ECH config, and PKIX hostname/SAN validation failures
|
|
31
|
+
// are permanent (config / validation errors a retry cannot fix).
|
|
32
|
+
var TLS_TRANSIENT_CODES = {
|
|
33
|
+
"tls/ech-connect-failed": true,
|
|
34
|
+
"tls/ech-timeout": true,
|
|
35
|
+
"tls/ech-dns-unavailable": true,
|
|
36
|
+
};
|
|
37
|
+
function _networkTlsErrorIsPermanent(code) {
|
|
38
|
+
return !Object.prototype.hasOwnProperty.call(TLS_TRANSIENT_CODES, code);
|
|
39
|
+
}
|
|
40
|
+
var NetworkTlsError = defineClass("NetworkTlsError", { permanentClassifier: _networkTlsErrorIsPermanent });
|
|
21
41
|
|
|
22
42
|
var observability = lazyRequire(function () { return require("./observability"); });
|
|
23
43
|
var audit = lazyRequire(function () { return require("./audit"); });
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../scripts/release-notes-schema.json",
|
|
3
|
+
"version": "0.15.28",
|
|
4
|
+
"date": "2026-06-25",
|
|
5
|
+
"headline": "`b.network.dns` and `b.network.tls` errors now carry a usable terminal-vs-transient signal on `err.permanent`, so a caller's retry loop re-attempts only the failures a retry can fix",
|
|
6
|
+
"summary": "DnsError was declared always-transient and NetworkTlsError always-permanent, so a consumer driving its own retry loop got the wrong signal in both directions: it would retry a permanent DNS failure (a bad host, bad options, an unsupported query, an NXDOMAIN-style no-result, or a caller-shape/config error such as an unconfigured transport or an invalid resolver list) forever, and it would refuse to retry a transient TLS-over-network failure (an ECH connection failure, a handshake timeout, DNS momentarily unavailable). err.permanent now reflects each error's actual transience, derived from its code and failing closed (an unknown code is permanent, so a hopeless target is not retried indefinitely): for DnsError only a failed network round-trip (a lookup timeout, a resolve/reverse query that failed on the wire, a failed DoH/DoT exchange, a DDR discovery that found nothing) is transient — config, input, and environment errors raised before any network work are permanent; for NetworkTlsError only the network-layer ECH failures are transient. TlsTrustError remains always-permanent by design — a trust-verification failure (bad CA, fingerprint mismatch, OCSP not-good, CT violation, an unreachable OCSP responder) must never be silently retried past the trust decision.",
|
|
7
|
+
"sections": [
|
|
8
|
+
{
|
|
9
|
+
"heading": "Fixed",
|
|
10
|
+
"items": [
|
|
11
|
+
{
|
|
12
|
+
"title": "DnsError / NetworkTlsError expose a correct terminal/transient signal; TlsTrustError stays terminal",
|
|
13
|
+
"body": "b.network.dns's DnsError was always-transient and b.network.tls's NetworkTlsError always-permanent, so err.permanent misled a consumer's retry loop in both directions — retrying a permanent DNS error (bad host / options / unsupported type / no-result) indefinitely, and never retrying a transient TLS network error (ECH connect failure, handshake timeout, DNS unavailable). err.permanent now reflects each error's actual transience by code and fails closed (unknown codes are permanent): DnsError is transient only for a failed network round-trip (dns/lookup-timeout, dns/resolve-failed, dns/reverse-failed, dns/doh-failed, dns/dot-failed, dns/dot-handshake-failed, dns/ddr-not-discovered, dns/system-failed), and permanent otherwise — including the caller-shape / environment errors raised before any network work (dns/transport-unavailable for an unconfigured transport, dns/dnr-no-resolvers for an empty/invalid resolver list, dns/setservers-failed for an invalid address, dns/no-system-resolvers when none are configured). NetworkTlsError is transient only for the network-layer ECH failures (tls/ech-connect-failed, tls/ech-timeout, tls/ech-dns-unavailable), permanent otherwise. TlsTrustError remains always-permanent so a trust-verification failure is never silently retried."
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -124,7 +124,7 @@ function testCreateRefusesBadStartMode() {
|
|
|
124
124
|
check("create refuses bad startMode", threw);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
function run() {
|
|
128
128
|
testOpenModePassesEverything();
|
|
129
129
|
testReadOnlyModeRefusesWrites();
|
|
130
130
|
testLockedModeRefusesEverythingExceptPassthrough();
|
|
@@ -133,4 +133,7 @@ function testCreateRefusesBadStartMode() {
|
|
|
133
133
|
testSetRefusesUnknownMode();
|
|
134
134
|
testCreateRefusesBadStartMode();
|
|
135
135
|
console.log("OK — access-lock tests");
|
|
136
|
-
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
module.exports = { run: run };
|
|
139
|
+
if (require.main === module) run();
|
|
@@ -18,7 +18,7 @@ function _mockRes() {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
function run() {
|
|
22
22
|
var aboveCalls = 0;
|
|
23
23
|
var ag = b.middleware.ageGate({
|
|
24
24
|
audit: false,
|
|
@@ -88,4 +88,7 @@ function _mockRes() {
|
|
|
88
88
|
check("ageGate refuses non-fn getAge", threwBadGetAge);
|
|
89
89
|
|
|
90
90
|
console.log("OK — ageGate tests");
|
|
91
|
-
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
module.exports = { run: run };
|
|
94
|
+
if (require.main === module) run();
|
|
@@ -3,7 +3,7 @@ var helpers = require("../helpers");
|
|
|
3
3
|
var b = helpers.b;
|
|
4
4
|
var check = helpers.check;
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
function run() {
|
|
7
7
|
var eaa = b.compliance.eaa.create({
|
|
8
8
|
audit: false,
|
|
9
9
|
productName: "Acme Portal",
|
|
@@ -33,4 +33,7 @@ var check = helpers.check;
|
|
|
33
33
|
check("eaa refuses bad conformance", threwBadConformance);
|
|
34
34
|
|
|
35
35
|
console.log("OK — compliance.eaa tests");
|
|
36
|
-
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = { run: run };
|
|
39
|
+
if (require.main === module) run();
|
|
@@ -3,7 +3,7 @@ var helpers = require("../helpers");
|
|
|
3
3
|
var b = helpers.b;
|
|
4
4
|
var check = helpers.check;
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
function run() {
|
|
7
7
|
var ropa = b.gdpr.ropa.create({
|
|
8
8
|
audit: false,
|
|
9
9
|
controller: { name: "Acme", contact: "dpo@acme.example" },
|
|
@@ -38,4 +38,7 @@ var check = helpers.check;
|
|
|
38
38
|
check("ropa.remove deletes", ropa.list().length === 0);
|
|
39
39
|
|
|
40
40
|
console.log("OK — gdpr.ropa tests");
|
|
41
|
-
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { run: run };
|
|
44
|
+
if (require.main === module) run();
|
|
@@ -844,7 +844,7 @@ function testFormsStandalone() {
|
|
|
844
844
|
|
|
845
845
|
// ---- Run all ----
|
|
846
846
|
|
|
847
|
-
|
|
847
|
+
function run() {
|
|
848
848
|
testHtmlLangMissing();
|
|
849
849
|
testHtmlLangPresent();
|
|
850
850
|
testPageTitleMissing();
|
|
@@ -915,4 +915,7 @@ function testFormsStandalone() {
|
|
|
915
915
|
testInputEmailNoAutocomplete();
|
|
916
916
|
testSkipForms();
|
|
917
917
|
testFormsStandalone();
|
|
918
|
-
}
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
module.exports = { run: run };
|
|
921
|
+
if (require.main === module) run();
|
|
@@ -220,6 +220,35 @@ async function _drainTcpHandles() {
|
|
|
220
220
|
}, { timeoutMs: 5000, label: "network-dns: TCP handle drain after _resetForTest" });
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
+
// DnsError carries a terminal-vs-transient signal on err.permanent so a caller
|
|
224
|
+
// driving a retry loop re-attempts only the failures a retry can fix. Fails
|
|
225
|
+
// CLOSED: network / resolver-availability failures are transient; bad config,
|
|
226
|
+
// malformed input, NXDOMAIN-style no-result, and any unknown code are permanent.
|
|
227
|
+
function testDnsErrorPermanentClassification() {
|
|
228
|
+
var DnsError = dnsModule.DnsError;
|
|
229
|
+
check("DnsError exported", typeof DnsError === "function");
|
|
230
|
+
// Permanent — config / input / no-answer (retrying cannot fix these).
|
|
231
|
+
check("DnsError dns/bad-host is permanent", new DnsError("dns/bad-host", "x").permanent === true);
|
|
232
|
+
check("DnsError dns/bad-transport is permanent", new DnsError("dns/bad-transport", "x").permanent === true);
|
|
233
|
+
check("DnsError dns/unsupported-type is permanent", new DnsError("dns/unsupported-type", "x").permanent === true);
|
|
234
|
+
check("DnsError dns/no-result is permanent", new DnsError("dns/no-result", "x").permanent === true);
|
|
235
|
+
check("DnsError unknown code is permanent (fail closed)", new DnsError("dns/never-defined", "x").permanent === true);
|
|
236
|
+
// Caller-shape / environment config errors raised before any network work are
|
|
237
|
+
// permanent — a retry cannot make absent config or invalid input valid.
|
|
238
|
+
check("DnsError dns/transport-unavailable is permanent (transport not configured)",
|
|
239
|
+
new DnsError("dns/transport-unavailable", "x").permanent === true);
|
|
240
|
+
check("DnsError dns/dnr-no-resolvers is permanent (empty/invalid resolver list)",
|
|
241
|
+
new DnsError("dns/dnr-no-resolvers", "x").permanent === true);
|
|
242
|
+
check("DnsError dns/setservers-failed is permanent (invalid resolver address)",
|
|
243
|
+
new DnsError("dns/setservers-failed", "x").permanent === true);
|
|
244
|
+
check("DnsError dns/no-system-resolvers is permanent (none configured)",
|
|
245
|
+
new DnsError("dns/no-system-resolvers", "x").permanent === true);
|
|
246
|
+
// Transient — a network round-trip that a retry can plausibly fix.
|
|
247
|
+
check("DnsError dns/lookup-timeout is transient", new DnsError("dns/lookup-timeout", "x").permanent === false);
|
|
248
|
+
check("DnsError dns/resolve-failed is transient", new DnsError("dns/resolve-failed", "x").permanent === false);
|
|
249
|
+
check("DnsError dns/dot-failed is transient", new DnsError("dns/dot-failed", "x").permanent === false);
|
|
250
|
+
}
|
|
251
|
+
|
|
223
252
|
async function run() {
|
|
224
253
|
try { await _runTests(); }
|
|
225
254
|
finally { await _drainTcpHandles(); }
|
|
@@ -228,6 +257,8 @@ async function run() {
|
|
|
228
257
|
async function _runTests() {
|
|
229
258
|
_resetAll();
|
|
230
259
|
|
|
260
|
+
testDnsErrorPermanentClassification();
|
|
261
|
+
|
|
231
262
|
// ============================================================
|
|
232
263
|
// Item B4 — SVCB / HTTPS rdata parsing
|
|
233
264
|
// ============================================================
|
|
@@ -452,7 +452,40 @@ function testInsecureTlsAudit() {
|
|
|
452
452
|
check("auditInsecureTls is drop-silent on bad input (never throws into a connect)", threw === false);
|
|
453
453
|
}
|
|
454
454
|
|
|
455
|
+
// NetworkTlsError carries a terminal-vs-transient signal on err.permanent;
|
|
456
|
+
// TlsTrustError is always permanent (a trust-verification failure must never be
|
|
457
|
+
// silently retried). Fails CLOSED: only the network-layer ECH failures are
|
|
458
|
+
// transient; bad options, malformed config, PKIX validation, and unknown codes
|
|
459
|
+
// are permanent.
|
|
460
|
+
function testNetworkTlsErrorPermanentClassification() {
|
|
461
|
+
var NetworkTlsError = b.network.tls.NetworkTlsError;
|
|
462
|
+
var TlsTrustError = b.network.tls.TlsTrustError;
|
|
463
|
+
// NetworkTlsError — permanent (config / validation, retry cannot fix).
|
|
464
|
+
check("NetworkTlsError bad-tls-options is permanent",
|
|
465
|
+
new NetworkTlsError("network-tls/bad-tls-options", "x").permanent === true);
|
|
466
|
+
check("NetworkTlsError pkix-hostname-mismatch is permanent",
|
|
467
|
+
new NetworkTlsError("tls/pkix-hostname-mismatch", "x").permanent === true);
|
|
468
|
+
check("NetworkTlsError ech-config-malformed is permanent",
|
|
469
|
+
new NetworkTlsError("tls/ech-config-malformed", "x").permanent === true);
|
|
470
|
+
check("NetworkTlsError unknown code is permanent (fail closed)",
|
|
471
|
+
new NetworkTlsError("tls/never-defined", "x").permanent === true);
|
|
472
|
+
// NetworkTlsError — transient (network-layer ECH failure, a retry may succeed).
|
|
473
|
+
check("NetworkTlsError ech-connect-failed is transient",
|
|
474
|
+
new NetworkTlsError("tls/ech-connect-failed", "x").permanent === false);
|
|
475
|
+
check("NetworkTlsError ech-timeout is transient",
|
|
476
|
+
new NetworkTlsError("tls/ech-timeout", "x").permanent === false);
|
|
477
|
+
check("NetworkTlsError ech-dns-unavailable is transient",
|
|
478
|
+
new NetworkTlsError("tls/ech-dns-unavailable", "x").permanent === false);
|
|
479
|
+
// TlsTrustError — ALWAYS permanent (trust failures, incl. a network failure
|
|
480
|
+
// during the trust check, must not auto-retry past a trust decision).
|
|
481
|
+
check("TlsTrustError ocsp-not-good is permanent",
|
|
482
|
+
new TlsTrustError("tls/ocsp-not-good", "x").permanent === true);
|
|
483
|
+
check("TlsTrustError connect-failed during trust is still permanent",
|
|
484
|
+
new TlsTrustError("tls/connect-failed", "x").permanent === true);
|
|
485
|
+
}
|
|
486
|
+
|
|
455
487
|
async function run() {
|
|
488
|
+
testNetworkTlsErrorPermanentClassification();
|
|
456
489
|
testInsecureTlsAudit();
|
|
457
490
|
testEchSurface();
|
|
458
491
|
testEchParseDraft22();
|
|
@@ -24,11 +24,14 @@ function _mockRes() {
|
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
function run() {
|
|
28
28
|
var requireMtls = b.middleware.requireMtls({ audit: false });
|
|
29
29
|
var noPeerRes = _mockRes();
|
|
30
30
|
requireMtls(_mockReq({ authorized: false }), noPeerRes, function () {});
|
|
31
31
|
check("requireMtls refuses unauthorized peer 401", noPeerRes._captured.status === 401);
|
|
32
32
|
|
|
33
33
|
console.log("OK — requireMtls tests");
|
|
34
|
-
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = { run: run };
|
|
37
|
+
if (require.main === module) run();
|
|
@@ -124,7 +124,7 @@ function testConstructorAttributeNoFalseDuplicate() {
|
|
|
124
124
|
threw && threw.code === "xml/forbidden-name");
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
function run() {
|
|
128
128
|
try {
|
|
129
129
|
testParsesAttributedElement();
|
|
130
130
|
testRejectsDoctype();
|
|
@@ -140,4 +140,7 @@ function testConstructorAttributeNoFalseDuplicate() {
|
|
|
140
140
|
process.exit(1);
|
|
141
141
|
}
|
|
142
142
|
console.log("OK — safe-xml tests");
|
|
143
|
-
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
module.exports = { run: run };
|
|
146
|
+
if (require.main === module) run();
|
package/package.json
CHANGED