@blamejs/blamejs-shop 0.4.101 → 0.4.102

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 (55) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/vendor/MANIFEST.json +55 -51
  4. package/lib/vendor/blamejs/.gitignore +5 -0
  5. package/lib/vendor/blamejs/CHANGELOG.md +4 -0
  6. package/lib/vendor/blamejs/api-snapshot.json +2 -2
  7. package/lib/vendor/blamejs/lib/sandbox.js +23 -5
  8. package/lib/vendor/blamejs/package.json +1 -1
  9. package/lib/vendor/blamejs/release-notes/v0.15.25.json +18 -0
  10. package/lib/vendor/blamejs/release-notes/v0.15.26.json +18 -0
  11. package/lib/vendor/blamejs/test/layer-0-primitives/ai-adverse-decision.test.js +5 -2
  12. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-open-nofollow.test.js +7 -2
  13. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-bucket-ops.test.js +30 -10
  14. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +21 -0
  15. package/lib/vendor/blamejs/test/layer-0-primitives/bearer-auth.test.js +22 -17
  16. package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-chunked-malformed.test.js +23 -18
  17. package/lib/vendor/blamejs/test/layer-0-primitives/breach-deadline.test.js +8 -3
  18. package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +22 -0
  19. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +50 -0
  20. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +13 -5
  21. package/lib/vendor/blamejs/test/layer-0-primitives/cra-report.test.js +5 -2
  22. package/lib/vendor/blamejs/test/layer-0-primitives/daily-byte-quota.test.js +20 -9
  23. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +8 -2
  24. package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +34 -15
  25. package/lib/vendor/blamejs/test/layer-0-primitives/gcs-bucket-ops.test.js +30 -9
  26. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +15 -3
  27. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +41 -18
  28. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +33 -14
  29. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-throttle-transform.test.js +21 -2
  30. package/lib/vendor/blamejs/test/layer-0-primitives/incident-report.test.js +5 -2
  31. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp.test.js +29 -8
  32. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +42 -23
  33. package/lib/vendor/blamejs/test/layer-0-primitives/network-byte-quota.test.js +5 -2
  34. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +20 -0
  35. package/lib/vendor/blamejs/test/layer-0-primitives/network-nts-handshake-byte-cap.test.js +20 -1
  36. package/lib/vendor/blamejs/test/layer-0-primitives/nis2-report.test.js +5 -2
  37. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +22 -1
  38. package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +8 -2
  39. package/lib/vendor/blamejs/test/layer-0-primitives/parser-verify-hardening.test.js +21 -16
  40. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +5 -2
  41. package/lib/vendor/blamejs/test/layer-0-primitives/queue-sqs.test.js +31 -11
  42. package/lib/vendor/blamejs/test/layer-0-primitives/request-id-async-context.test.js +21 -4
  43. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +35 -0
  44. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +5 -2
  45. package/lib/vendor/blamejs/test/layer-0-primitives/self-update-poll-asset-digest.test.js +21 -2
  46. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +29 -10
  47. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +51 -33
  48. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-multipart-sse.test.js +31 -13
  49. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +41 -21
  50. package/lib/vendor/blamejs/test/layer-0-primitives/testing-request.test.js +25 -0
  51. package/lib/vendor/blamejs/test/layer-0-primitives/tls-exporter.test.js +30 -6
  52. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +22 -0
  53. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +10 -6
  54. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +91 -20
  55. package/package.json +1 -1
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "../scripts/release-notes-schema.json",
3
+ "version": "0.15.26",
4
+ "date": "2026-06-25",
5
+ "headline": "Internal test-harness correctness only — the published library is byte-for-byte identical to 0.15.25",
6
+ "summary": "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.",
7
+ "sections": [
8
+ {
9
+ "heading": "Fixed",
10
+ "items": [
11
+ {
12
+ "title": "Detached-IIFE tests now run their full assertion set under the smoke runner",
13
+ "body": "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."
14
+ }
15
+ ]
16
+ }
17
+ ]
18
+ }
@@ -3,7 +3,7 @@ var helpers = require("../helpers");
3
3
  var b = helpers.b;
4
4
  var check = helpers.check;
5
5
 
6
- (async function run() {
6
+ async function run() {
7
7
  var captured = null;
8
8
  var hire = b.ai.adverseDecision.wrap({
9
9
  audit: false,
@@ -41,4 +41,7 @@ var check = helpers.check;
41
41
  check("ai.adverseDecision refuses missing legalBasis", threwBadLegal);
42
42
 
43
43
  console.log("OK — ai.adverseDecision tests");
44
- })().catch(function (e) { console.error(e); process.exit(1); });
44
+ }
45
+
46
+ module.exports = { run: run };
47
+ if (require.main === module) run().catch(function (e) { console.error(e); process.exit(1); });
@@ -12,7 +12,7 @@ var helpers = require("../helpers");
12
12
  var b = helpers.b;
13
13
  var check = helpers.check;
14
14
 
15
- function run() {
15
+ async function run() {
16
16
  check("b.atomicFile.openNoFollowSync is a function",
17
17
  typeof b.atomicFile.openNoFollowSync === "function");
18
18
 
@@ -58,12 +58,17 @@ function run() {
58
58
  }
59
59
  }
60
60
 
61
- return new Promise(function (resolve) {
61
+ // Await the stream's end BEFORE the finally cleanup. Without the await,
62
+ // the try block returns its promise and the finally runs synchronously —
63
+ // removing the dir and leaving the stream's in-flight read (FSReqCallback)
64
+ // alive past run(). Awaiting drains the read before cleanup.
65
+ await new Promise(function (resolve, reject) {
62
66
  rs.on("end", function () {
63
67
  check("an fd from openNoFollowSync is consumable by createReadStream",
64
68
  streamed === "payload-bytes");
65
69
  resolve();
66
70
  });
71
+ rs.on("error", reject);
67
72
  });
68
73
  } finally {
69
74
  try { fs.rmSync(dir, { recursive: true, force: true }); } catch (_e) { /* best-effort */ }
@@ -235,17 +235,37 @@ async function testSetLifecycleNotSupported() {
235
235
  } finally { await l.close(); }
236
236
  }
237
237
 
238
+ // bucketOps.create issues its requests through the shared b.httpClient
239
+ // keep-alive agent, whose cached client sockets (and the mock servers they
240
+ // keep open) would otherwise outlive run() and hold the forked worker's
241
+ // event loop open. Tear the pool down and poll until the TCP handles have
242
+ // actually closed — agent.destroy() schedules the teardown asynchronously,
243
+ // so polling drives the event-loop turns needed to complete it inside run().
244
+ async function _drainTcpHandles() {
245
+ b.httpClient._resetForTest();
246
+ if (typeof process.getActiveResourcesInfo !== "function") return;
247
+ await helpers.waitUntil(function () {
248
+ return process.getActiveResourcesInfo().filter(function (t) {
249
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
250
+ }).length === 0;
251
+ }, { timeoutMs: 5000, label: "azure-blob-bucket-ops: TCP handle drain after _resetForTest" });
252
+ }
253
+
238
254
  async function run() {
239
- await testSurface();
240
- await testFactoryValidation();
241
- await testContainerNameValidation();
242
- await testCreateContainerWireShape();
243
- await testCreateContainerConflict();
244
- await testDeleteContainer();
245
- await testListContainers();
246
- await testSetCorsRulesValidation();
247
- await testSetCorsRulesWireShape();
248
- await testSetLifecycleNotSupported();
255
+ try {
256
+ await testSurface();
257
+ await testFactoryValidation();
258
+ await testContainerNameValidation();
259
+ await testCreateContainerWireShape();
260
+ await testCreateContainerConflict();
261
+ await testDeleteContainer();
262
+ await testListContainers();
263
+ await testSetCorsRulesValidation();
264
+ await testSetCorsRulesWireShape();
265
+ await testSetLifecycleNotSupported();
266
+ } finally {
267
+ await _drainTcpHandles();
268
+ }
249
269
  }
250
270
 
251
271
  module.exports = { run: run };
@@ -49,7 +49,28 @@ function _client(port) {
49
49
  });
50
50
  }
51
51
 
52
+ // The azure adapter issues requests through the shared b.httpClient
53
+ // keep-alive agent, whose cached client socket (and the mock server it
54
+ // keeps open) would otherwise outlive run() and hold the forked worker's
55
+ // event loop open. Tear the pool down and poll until the TCP handles have
56
+ // actually closed — agent.destroy() schedules the teardown asynchronously,
57
+ // so polling drives the event-loop turns needed to complete it inside run().
58
+ async function _drainTcpHandles() {
59
+ b.httpClient._resetForTest();
60
+ if (typeof process.getActiveResourcesInfo !== "function") return;
61
+ await helpers.waitUntil(function () {
62
+ return process.getActiveResourcesInfo().filter(function (t) {
63
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
64
+ }).length === 0;
65
+ }, { timeoutMs: 5000, label: "azure-blob-key-encoding: TCP handle drain after _resetForTest" });
66
+ }
67
+
52
68
  async function run() {
69
+ try { await _runTests(); }
70
+ finally { await _drainTcpHandles(); }
71
+ }
72
+
73
+ async function _runTests() {
53
74
  var srv = await listenRecording();
54
75
  try {
55
76
  var c = _client(srv.port);
@@ -16,24 +16,26 @@ var _bodyReq = helpers._bodyReq;
16
16
  var _bodyRes = helpers._bodyRes;
17
17
 
18
18
  function _runMiddleware(mw, req, res) {
19
- return new Promise(function (resolve) {
20
- var settled = false;
21
- mw(req, res, function () {
22
- if (settled) return;
23
- settled = true;
24
- resolve({ next: true, status: res._endedStatus, user: req.user });
19
+ // The middleware settles by calling next() or by ending the response. Wrap
20
+ // in withTestTimeout so a middleware that hangs becomes a hard "test timed
21
+ // out" reject (1500ms budget) instead of stalling the suite — its guard
22
+ // timer clears on settle, so no Timeout handle lingers past run().
23
+ return helpers.withTestTimeout("bearer-auth: middleware settles", function () {
24
+ return new Promise(function (resolve) {
25
+ var settled = false;
26
+ function _settle(value) {
27
+ if (settled) return;
28
+ settled = true;
29
+ resolve(value);
30
+ }
31
+ mw(req, res, function () {
32
+ _settle({ next: true, status: res._endedStatus, user: req.user });
33
+ });
34
+ res.on("finish", function () {
35
+ _settle({ next: false, status: res._endedStatus, user: req.user });
36
+ });
25
37
  });
26
- res.on("finish", function () {
27
- if (settled) return;
28
- settled = true;
29
- resolve({ next: false, status: res._endedStatus, user: req.user });
30
- });
31
- setTimeout(function () {
32
- if (settled) return;
33
- settled = true;
34
- resolve({ next: false, status: res._endedStatus, timeout: true });
35
- }, 1500); // allow:raw-byte-literal — test safety timeout ms
36
- });
38
+ }, { timeoutMs: 1500 }); // allow:raw-byte-literal — middleware-settle budget ms
37
39
  }
38
40
 
39
41
  function testBearerSurface() {
@@ -97,6 +99,9 @@ async function run() {
97
99
  await testBearerInvalidTokenRejected();
98
100
  await testBearerVerifyThrowsRejected();
99
101
  await testBearerValidAttachesUser();
102
+ // The 401-reject paths emit an audit event, which schedules the audit
103
+ // handler's age-flush timer. Drain it so no timer lingers past run().
104
+ await b.audit.flush();
100
105
  }
101
106
 
102
107
  module.exports = { run: run };
@@ -35,25 +35,27 @@ function _runWithError(headers, parserError) {
35
35
  var bp = b.middleware.bodyParser();
36
36
  var req = _chunkedReq(headers);
37
37
  var res = _bodyRes();
38
- return new Promise(function (resolve) {
39
- var settled = false;
40
- bp(req, res, function () {
41
- if (settled) return;
42
- settled = true;
43
- resolve({ next: true, status: res._endedStatus, req: req });
38
+ // The parser settles by calling next() or by ending the response after the
39
+ // emitted error. Wrap in withTestTimeout so a parser that hangs becomes a
40
+ // hard "test timed out" reject (1500ms budget) instead of stalling the
41
+ // suite — its guard timer clears on settle, so no Timeout handle lingers.
42
+ return helpers.withTestTimeout("body-parser: malformed-body parser settles", function () {
43
+ return new Promise(function (resolve) {
44
+ var settled = false;
45
+ function _settle(value) {
46
+ if (settled) return;
47
+ settled = true;
48
+ resolve(value);
49
+ }
50
+ bp(req, res, function () {
51
+ _settle({ next: true, status: res._endedStatus, req: req });
52
+ });
53
+ res.on("finish", function () {
54
+ _settle({ next: false, status: res._endedStatus, headers: res._headers, req: req });
55
+ });
56
+ setImmediate(function () { req.emit("error", parserError); });
44
57
  });
45
- res.on("finish", function () {
46
- if (settled) return;
47
- settled = true;
48
- resolve({ next: false, status: res._endedStatus, headers: res._headers, req: req });
49
- });
50
- setImmediate(function () { req.emit("error", parserError); });
51
- setTimeout(function () {
52
- if (settled) return;
53
- settled = true;
54
- resolve({ next: false, timeout: true, req: req });
55
- }, 1500);
56
- });
58
+ }, { timeoutMs: 1500 }); // allow:raw-byte-literal — parser-settle budget ms
57
59
  }
58
60
 
59
61
  async function testInvalidChunkSizeRefused() {
@@ -123,6 +125,9 @@ async function run() {
123
125
  await testInvalidTransferEncodingRefused();
124
126
  await testInvalidEofStateRefused();
125
127
  await testNonChunkedErrorAlsoClosesConnection();
128
+ // The malformed-body rejects emit an audit event, which schedules the
129
+ // audit handler's age-flush timer. Drain it so no timer lingers past run().
130
+ await b.audit.flush();
126
131
  }
127
132
 
128
133
  module.exports = { run: run };
@@ -3,7 +3,7 @@ var helpers = require("../helpers");
3
3
  var b = helpers.b;
4
4
  var check = helpers.check;
5
5
 
6
- (async function run() {
6
+ async function run() {
7
7
  var now = Date.now();
8
8
  var d = b.breach.deadline.forStates(["CA", "TX"], now);
9
9
  check("forStates returns 2", d.length === 2);
@@ -118,6 +118,11 @@ var check = helpers.check;
118
118
  check("auto-tick timer fired the passed alert", true);
119
119
  autoClock.stop();
120
120
  check("clock stops cleanly", autoClock.status().running === false);
121
+ }
121
122
 
122
- console.log("OK breach-deadline tests");
123
- })().catch(function (e) { console.error(e); process.exit(1); });
123
+ module.exports = { run: run };
124
+
125
+ if (require.main === module) {
126
+ run().then(function () { console.log("OK — breach-deadline tests"); })
127
+ .catch(function (e) { console.error(e); process.exit(1); });
128
+ }
@@ -82,7 +82,29 @@ function _push(idToken, bodyAuthReqId) {
82
82
  };
83
83
  }
84
84
 
85
+ // The CIBA client's discovery + JWKS fetches go through the shared
86
+ // b.httpClient keep-alive agent, whose cached client socket (and the mock
87
+ // IdP server it keeps open) would otherwise outlive run() and hold the
88
+ // forked worker's event loop open. Tear the pool down and poll until the
89
+ // TCP handles have actually closed — agent.destroy() schedules the teardown
90
+ // asynchronously, so polling drives the event-loop turns needed to complete
91
+ // it inside run().
92
+ async function _drainTcpHandles() {
93
+ b.httpClient._resetForTest();
94
+ if (typeof process.getActiveResourcesInfo !== "function") return;
95
+ await helpers.waitUntil(function () {
96
+ return process.getActiveResourcesInfo().filter(function (t) {
97
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
98
+ }).length === 0;
99
+ }, { timeoutMs: 5000, label: "ciba-authreqid-binding: TCP handle drain after _resetForTest" });
100
+ }
101
+
85
102
  async function run() {
103
+ try { await _runTests(); }
104
+ finally { await _drainTcpHandles(); }
105
+ }
106
+
107
+ async function _runTests() {
86
108
  await _withIdp(async function (issuer) {
87
109
  var ciba = _cibaClient(issuer);
88
110
 
@@ -9425,6 +9425,20 @@ var KNOWN_ANTIPATTERNS = [
9425
9425
  allowlist: [],
9426
9426
  reason: "The smoke worker requires each test module and awaits its exported run(); a column-0 `run()` / `run().then(...process.exit...)` fires a second unawaited run() at require-time that races the worker's result print (and process.exit() exits before the result line, read as 'no result line' / 'fork failed' on a slow runner). Export `run` and wrap the invocation in `if (require.main === module)`. Fires on any `run(` at the start of a line; `function run()`, `module.exports = { run }`, and an indented `run()` inside the require-main guard stay silent.",
9427
9427
  },
9428
+ {
9429
+ id: "test-detached-async-iife",
9430
+ primitive: "define `async function run() {...}`, `module.exports = { run }`, and invoke under `if (require.main === module) run().catch(...)` — never a top-level `(async function () {...})()` IIFE",
9431
+ scanScope: "test",
9432
+ regex: /^\(async\b/m,
9433
+ skipCommentLines: true,
9434
+ allowlist: [
9435
+ // The smoke runner itself — its top-level `(async function () {...})()` is
9436
+ // the orchestrator's process entry point (it forks the per-file workers),
9437
+ // not a worker-awaited test body. It has no run() to export.
9438
+ "test/smoke.js",
9439
+ ],
9440
+ reason: "The smoke worker requires each test module and only `await mod.run()`. A test written as a top-level `(async function run(){...})()` IIFE runs DETACHED on require: the worker measures + prints its result before the IIFE's post-await assertions execute, so every check after the first await silently never counts (parsers-standalone reported 4 of 26 checks this way) and a failing post-await assertion is never seen — a false pass. Export `run` and invoke under `if (require.main === module)`. Fires on a column-0 `(async` (function or arrow IIFE); `async function run()` (no leading paren), `module.exports = { run }`, and an indented async IIFE inside a helper stay silent. Synchronous `(function(){...})()` IIFEs complete during require, so they do not undercount and are out of scope here.",
9441
+ },
9428
9442
  {
9429
9443
  // `Promise + setTimeout` direct sleep in tests is forbidden;
9430
9444
  // tests waiting on an asynchronous condition MUST use
@@ -12273,6 +12287,41 @@ function testEsbuildPinAgreesAcrossArtifacts() {
12273
12287
  bad);
12274
12288
  }
12275
12289
 
12290
+ // The test-detached-async-iife antipattern (scanScope: "test") covers *.test.js,
12291
+ // but the legacy single-layer entry files (test/00-primitives.js …
12292
+ // 50-integration.js) are required + run directly by smoke.js via _runLayer and
12293
+ // are NOT in _testFiles(). A top-level `(async function () {...})()` there would
12294
+ // have the same detached false-pass — the worker awaits mod.run / mod.groups,
12295
+ // never a require-time IIFE — so scan those files for the same shape here. Scoped
12296
+ // to the IIFE pattern ONLY (not the full test-discipline catalog): those files
12297
+ // carry a separate, larger setTimeout-sleep cleanup that is its own task.
12298
+ function testNoDetachedAsyncIifeInLegacyLayerFiles() {
12299
+ var bad = [];
12300
+ var entries;
12301
+ try { entries = fs.readdirSync(TEST_ROOT); }
12302
+ catch (_e) { entries = []; }
12303
+ for (var i = 0; i < entries.length; i++) {
12304
+ if (!/^[0-9]{2}-[\w-]+\.js$/.test(entries[i])) continue;
12305
+ var content;
12306
+ try { content = fs.readFileSync(path.join(TEST_ROOT, entries[i]), "utf8"); }
12307
+ catch (_e) { continue; }
12308
+ var lines = content.split(/\r?\n/);
12309
+ for (var j = 0; j < lines.length; j++) {
12310
+ if (/^\s*(\/\/|\*|\/\*)/.test(lines[j])) continue; // skip comment lines
12311
+ if (/^\(async\b/.test(lines[j])) {
12312
+ bad.push({ file: "test/" + entries[i], line: j + 1,
12313
+ content: "top-level `(async` IIFE — define `async function run()` + `module.exports = { run }` " +
12314
+ "and invoke under `if (require.main === module)`; a detached async IIFE false-passes its " +
12315
+ "post-await assertions (the worker awaits mod.run / mod.groups, not a require-time IIFE)" });
12316
+ }
12317
+ }
12318
+ }
12319
+ bad = _filterMarkers(bad, "test-detached-async-iife-legacy");
12320
+ _report("no detached top-level async IIFE in the legacy single-layer smoke entry files " +
12321
+ "(test/NN-*.js run via smoke.js _runLayer — an IIFE there false-passes like in a *.test.js)",
12322
+ bad);
12323
+ }
12324
+
12276
12325
  // v1 — error codes are the operator-grep contract and must be
12277
12326
  // `namespace/kebab-case`. The first string argument to `new XError(...)`
12278
12327
  // and `XError.factory(...)` IS the code (defineClass constructor signature
@@ -13235,6 +13284,7 @@ async function run() {
13235
13284
  // step's port mapping + curl host.
13236
13285
  testWikiPortAgreesAcrossArtifacts();
13237
13286
  testEsbuildPinAgreesAcrossArtifacts();
13287
+ testNoDetachedAsyncIifeInLegacyLayerFiles();
13238
13288
  testNoTrackedInternalNotes();
13239
13289
  testResidencyGatesWired();
13240
13290
  testWikiStopGraceExceedsShutdownBudget();
@@ -681,7 +681,7 @@ function testFetcherValidation() {
681
681
 
682
682
  // ---- Run all ----
683
683
 
684
- (function run() {
684
+ function _syncTests() {
685
685
  testNormalize();
686
686
  testTokenize();
687
687
  testLevenshtein();
@@ -715,12 +715,20 @@ function testFetcherValidation() {
715
715
  testAliasEmpty();
716
716
  testAliasExtraPairs();
717
717
  testAliasIntegrationWithScreen();
718
- })();
718
+ }
719
719
 
720
- // Fetcher tests are async; run them in their own block
721
- (async function fetcherTests() {
720
+ // Fetcher tests are async; run them in their own block.
721
+ async function _fetcherTests() {
722
722
  await testFetcherTickRefresh();
723
723
  await testFetcherFetchFailure();
724
724
  await testFetcherEmptyResult();
725
725
  testFetcherValidation();
726
- })().catch(function (e) { console.error(e); process.exit(1); });
726
+ }
727
+
728
+ async function run() {
729
+ _syncTests();
730
+ await _fetcherTests();
731
+ }
732
+
733
+ module.exports = { run: run };
734
+ if (require.main === module) run().catch(function (e) { console.error(e); process.exit(1); });
@@ -3,7 +3,7 @@ var helpers = require("../helpers");
3
3
  var b = helpers.b;
4
4
  var check = helpers.check;
5
5
 
6
- (async function run() {
6
+ async function run() {
7
7
  var cra = b.cra.report.create({
8
8
  audit: false,
9
9
  productId: "blamejs-1.x",
@@ -28,4 +28,7 @@ var check = helpers.check;
28
28
  check("cra refuses missing manufacturer", threwNoMfg);
29
29
 
30
30
  console.log("OK — cra.report tests");
31
- })().catch(function (e) { console.error(e); process.exit(1); });
31
+ }
32
+
33
+ module.exports = { run: run };
34
+ if (require.main === module) run().catch(function (e) { console.error(e); process.exit(1); });
@@ -47,12 +47,17 @@ function _mockRes() {
47
47
  };
48
48
  }
49
49
 
50
- function _drive(mw, req, res) {
51
- return new Promise(function (resolve) {
52
- mw(req, res, function () { resolve("next"); });
53
- helpers.passiveObserve(200, "daily-byte-quota: middleware-hung detection window")
54
- .then(function () { if (!res._captured.ended) resolve("hung"); });
55
- });
50
+ async function _drive(mw, req, res) {
51
+ // Hung-detection: the middleware is given a real-time window to either call
52
+ // next() or end the response; whichever happened decides the outcome. This
53
+ // is a verify-over-a-window observation (we let the full window elapse to
54
+ // see what the middleware did), so passiveObserve is the right primitive —
55
+ // it clears its own timer when the window completes, leaving nothing behind.
56
+ var nextCalled = false;
57
+ mw(req, res, function () { nextCalled = true; });
58
+ await helpers.passiveObserve(200, "daily-byte-quota: middleware-hung detection window"); // allow:raw-byte-literal — detection window ms
59
+ if (nextCalled) return "next";
60
+ return res._captured.ended ? "next" : "hung";
56
61
  }
57
62
 
58
63
  async function testQuotaBelowLimitPasses() {
@@ -142,12 +147,18 @@ function testSkipPathsBypass() {
142
147
  check("skipPaths bypass calls next", seen.length === 2);
143
148
  }
144
149
 
145
- (async function run() {
150
+ async function run() {
146
151
  await testQuotaBelowLimitPasses();
147
152
  await testQuotaAboveLimitRefuses();
148
153
  await testGetKeyOverride();
149
154
  await testNullKeyBypassesQuota();
150
155
  testCreateRefusesBadQuota();
151
156
  testSkipPathsBypass();
152
- console.log("OK — daily-byte-quota tests");
153
- })().catch(function (e) { console.error(e); process.exit(1); });
157
+ }
158
+
159
+ module.exports = { run: run };
160
+
161
+ if (require.main === module) {
162
+ run().then(function () { console.log("OK — daily-byte-quota tests"); })
163
+ .catch(function (e) { console.error(e); process.exit(1); });
164
+ }
@@ -1002,7 +1002,7 @@ async function testResealValidationAndStore() {
1002
1002
 
1003
1003
  // ---- Run all ----
1004
1004
 
1005
- (async function run() {
1005
+ async function run() {
1006
1006
  await testSubmitAccess();
1007
1007
  await testSubmitErasure();
1008
1008
  await testSubmitInvalidType();
@@ -1062,4 +1062,10 @@ async function testResealValidationAndStore() {
1062
1062
  // AAD_ROTATION descriptor + reseal
1063
1063
  testAadRotationDescriptor();
1064
1064
  await testResealValidationAndStore();
1065
- })().catch(function (e) { console.error(e); process.exit(1); });
1065
+ }
1066
+
1067
+ module.exports = { run: run };
1068
+
1069
+ if (require.main === module) {
1070
+ run().catch(function (e) { console.error(e); process.exit(1); });
1071
+ }
@@ -445,22 +445,41 @@ async function testInternalVerifyRejectsBadJws() {
445
445
 
446
446
  // ---- run ----
447
447
 
448
+ // fido-mds3.fetch dials the MDS3 endpoint through the shared httpClient
449
+ // keep-alive transport pool; a cached client socket finalizes its destroy on a
450
+ // later event-loop turn, past the forked worker's grace window. Reset the pool,
451
+ // then poll until every TCP handle has actually drained so it doesn't outlive
452
+ // run().
453
+ async function _drainTcpHandles() {
454
+ b.httpClient._resetForTest();
455
+ if (typeof process.getActiveResourcesInfo !== "function") return;
456
+ await helpers.waitUntil(function () {
457
+ return process.getActiveResourcesInfo().filter(function (t) {
458
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
459
+ }).length === 0;
460
+ }, { timeoutMs: 5000, label: "fido-mds3: TCP handle drain after _resetForTest" });
461
+ }
462
+
448
463
  async function run() {
449
- testSurface();
450
- testLookupAaguid();
451
- testVerifyAuthenticatorClean();
452
- testVerifyAuthenticatorRevoked();
453
- testVerifyAuthenticatorDecertified();
454
- testVerifyAuthenticatorPhysicalCompromise();
455
- testVerifyAuthenticatorRemoteCompromise();
456
- testVerifyAuthenticatorUnknownAaguid();
457
- testVerifyAuthenticatorBadInputs();
458
- testCertifiedLevelPlus();
459
- await testFetchRoundTrip();
460
- await testFetchRejectsNonHttps();
461
- await testFetchRejectsEmptyUrl();
462
- await testFetchRejectsBadTimeout();
463
- await testInternalVerifyRejectsBadJws();
464
+ try {
465
+ testSurface();
466
+ testLookupAaguid();
467
+ testVerifyAuthenticatorClean();
468
+ testVerifyAuthenticatorRevoked();
469
+ testVerifyAuthenticatorDecertified();
470
+ testVerifyAuthenticatorPhysicalCompromise();
471
+ testVerifyAuthenticatorRemoteCompromise();
472
+ testVerifyAuthenticatorUnknownAaguid();
473
+ testVerifyAuthenticatorBadInputs();
474
+ testCertifiedLevelPlus();
475
+ await testFetchRoundTrip();
476
+ await testFetchRejectsNonHttps();
477
+ await testFetchRejectsEmptyUrl();
478
+ await testFetchRejectsBadTimeout();
479
+ await testInternalVerifyRejectsBadJws();
480
+ } finally {
481
+ await _drainTcpHandles();
482
+ }
464
483
  }
465
484
 
466
485
  module.exports = { run: run };
@@ -299,16 +299,37 @@ async function testSetCorsRulesShape() {
299
299
  } finally { await l.close(); }
300
300
  }
301
301
 
302
+ // bucketOps.create issues its requests (storage API + token endpoint)
303
+ // through the shared b.httpClient keep-alive agent, whose cached client
304
+ // sockets (and the mock servers they keep open) would otherwise outlive
305
+ // run() and hold the forked worker's event loop open. Tear the pool down
306
+ // and poll until the TCP handles have actually closed — agent.destroy()
307
+ // schedules the teardown asynchronously, so polling drives the event-loop
308
+ // turns needed to complete it inside run().
309
+ async function _drainTcpHandles() {
310
+ b.httpClient._resetForTest();
311
+ if (typeof process.getActiveResourcesInfo !== "function") return;
312
+ await helpers.waitUntil(function () {
313
+ return process.getActiveResourcesInfo().filter(function (t) {
314
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
315
+ }).length === 0;
316
+ }, { timeoutMs: 5000, label: "gcs-bucket-ops: TCP handle drain after _resetForTest" });
317
+ }
318
+
302
319
  async function run() {
303
- await testSurface();
304
- await testFactoryValidation();
305
- await testBucketNameValidation();
306
- await testCreateBucketWireShape();
307
- await testCreateBucketConflict();
308
- await testDeleteBucket();
309
- await testListBuckets();
310
- await testSetLifecycleValidationAndShape();
311
- await testSetCorsRulesShape();
320
+ try {
321
+ await testSurface();
322
+ await testFactoryValidation();
323
+ await testBucketNameValidation();
324
+ await testCreateBucketWireShape();
325
+ await testCreateBucketConflict();
326
+ await testDeleteBucket();
327
+ await testListBuckets();
328
+ await testSetLifecycleValidationAndShape();
329
+ await testSetCorsRulesShape();
330
+ } finally {
331
+ await _drainTcpHandles();
332
+ }
312
333
  }
313
334
 
314
335
  module.exports = { run: run };
@@ -124,18 +124,30 @@ async function testGateContractShadowMode() {
124
124
  }
125
125
 
126
126
  async function testGateContractRuntimeCap() {
127
+ // The slow check deliberately elapses a real-time window longer than the
128
+ // 50ms runtime cap so the gate refuses. passiveObserve is the right
129
+ // primitive for letting that window pass (it clears its own timer when the
130
+ // window completes). The gate aborts the check at the cap but the check's
131
+ // own observation keeps running, so we await its completion below before
132
+ // returning — that drains the in-check window so nothing lingers past run().
133
+ var checkDone = null;
127
134
  var g = b.gateContract.defineGate({
128
135
  name: "test:runtime-cap",
129
136
  maxRuntimeMs: 50,
130
- check: async function () {
131
- await helpers.passiveObserve(200, "guard-csv: simulated slow check for runtime-cap test");
132
- return { ok: true, action: "serve" };
137
+ check: function () {
138
+ checkDone = helpers.passiveObserve(120, "guard-csv: slow check elapses past the runtime cap") // allow:raw-byte-literal — slow-check window > runtime cap
139
+ .then(function () { return { ok: true, action: "serve" }; });
140
+ return checkDone;
133
141
  },
134
142
  });
135
143
  var d = await g.check({ bytes: Buffer.from("x") });
136
144
  check("runtime cap: refuses with check-threw issue", d.action === "refuse");
137
145
  check("runtime cap: issues array carries check-threw",
138
146
  d.issues.length === 1 && d.issues[0].kind === "check-threw");
147
+ // Let the abandoned in-check observation finish so its window-timer self-
148
+ // clears rather than lingering past run() (the gate already returned at the
149
+ // 50ms cap; this just waits out the remaining check window).
150
+ await checkDone;
139
151
  }
140
152
 
141
153
  async function testGateContractBeforeCheckHook() {