@blamejs/core 0.6.67 → 0.6.68

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 CHANGED
@@ -8,6 +8,8 @@ upgrading across more than a few patches at a time.
8
8
 
9
9
  ## v0.6.x
10
10
 
11
+ - **0.6.68** (2026-05-03) — `b.atomicFile.read` / `readSync` enforce strict `maxBytes` validation. Same bug class as v0.6.57's `safeBuffer.boundedChunkCollector` fix: pre-fix the size check was `if (stat.size > opts.maxBytes)`, which silently accepted `Infinity` (`stat.size > Infinity` always false → reads any file regardless of size, defeating the OOM cap). Operators with `Number(env.MAX_READ_BYTES || "")` coercion bugs got `NaN` on missing values and unbounded reads on Infinity-typo'd values. New `_validateMaxBytes` runs before the size check and rejects `Infinity` / `NaN` / non-integer / negative / zero / non-number with `atomic-file/bad-opt`. Real-world consumers (vault.initPlaintext, audit-sign, db.loadOrCreateDbKey, etc.) all pass real positive integers via `C.BYTES.*` helpers and are unaffected. **Tests** — 7 new layer-0 boot-validation assertions in `test/00-primitives.js` (Infinity, NaN, 0, -1, 3.5, "100", null all reject). Smoke 7251 → 7258 / wiki e2e 178 / Linux 86.0s / eslint clean / shellcheck clean.
12
+
11
13
  - **0.6.67** (2026-05-03) — canonical-JSON walker extracted to `lib/canonical-json.js` and applied to `lib/audit-tools.js` + `lib/config-drift.js`. Same bug class as v0.6.60 (pagination) and v0.6.66 (audit-chain) lived in two more sites: `audit-tools._canonicalize` (used for backup-bundle JSONL serialisation, requires byte-equivalence with audit-chain) and `config-drift._stableStringify` (used to hash framework config for post-boot tamper detection). Both still had the silent-data-loss walk — Date → `{}`, Buffer → `{"0":97,…}`, Map / Set → `{}`, BigInt throws, circular references stack-overflow. New `lib/canonical-json.js` exposes `stringify(value, opts?)` with `opts.bufferAs = "hex" | "reject"` (default `"hex"` for crypto / config / audit; `"reject"` for pagination's strict-cursor policy). All four call sites — audit-chain, audit-tools, config-drift, pagination — now route through it; the four near-identical inline walkers collapse to one. **Stored-row + bundle compatibility** preserved: existing audit rows verify identically (their `metadata` columns are JSON strings); backup bundles produced pre-v0.6.67 round-trip correctly because byte output for plain types is unchanged. **Tests** — 17 layer-0 audit-chain assertions from v0.6.66 cover the unified walker; existing pagination tests cover `bufferAs: "reject"`. Smoke 7251 / wiki e2e 178 / Linux 86.3s / eslint clean / shellcheck clean.
12
14
 
13
15
  - **0.6.66** (2026-05-03) — `b.auditChain.canonicalize` deep-walks values and rejects non-plain types instead of silently round-tripping garbage. Same bug class as the v0.6.60 pagination canonicalize fix: pre-fix the walker did `Object.keys(row).map(...)` and JSON.stringify'd whatever fell through, which silently encoded **Map / Set / RegExp** as `{}`, **Symbol / function** as missing keys, **BigInt** as a thrown `Do not know how to serialize` mid-emit (DoS-shape on any operator routing bigint IDs into audit metadata), and **circular references** as the unwrapped JSON.stringify error message. The post-fix walker: BigInt → decimal string (no data loss for large account IDs / 64-bit counters from external-DB drivers); Date → ISO string (already worked via JSON.stringify but now explicit before the recursive walk); Map / Set / RegExp / Symbol / function reject with a clear constructor-name message; circular refs detected via WeakSet and rejected as a framework error. Walks recursively so nested structures (`{ a: [BigInt(1), BigInt(2)] }`, `{ a: { b: Uint8Array(…) } }`) all serialise correctly. **Stored-row compat** — existing audit rows verify identically because their stored `metadata` columns are already JSON strings; the change only affects EMIT-time serialisation. **Tests** — 17 new layer-0 assertions in `test/00-primitives.js`. Smoke 7234 → 7251 / wiki e2e 178 / Linux 86.1s / eslint clean / shellcheck clean.
@@ -331,12 +331,28 @@ function readSync(filepath, opts) {
331
331
  return _readSyncCore(filepath, opts);
332
332
  }
333
333
 
334
+ // maxBytes must be a positive finite integer. Pre-validation catches the
335
+ // `Infinity` typo / coercion case where an operator's
336
+ // `Number(env.MAX_READ_BYTES || "")` produced Infinity, which would
337
+ // otherwise make `stat.size > Infinity` always false and read any file
338
+ // regardless of size — defeating the OOM cap entirely. Same bug class
339
+ // as v0.6.57's safeBuffer.boundedChunkCollector fix.
340
+ function _validateMaxBytes(maxBytes) {
341
+ if (typeof maxBytes !== "number" || !Number.isFinite(maxBytes) ||
342
+ !Number.isInteger(maxBytes) || maxBytes <= 0) {
343
+ throw new AtomicFileError(
344
+ "maxBytes must be a positive finite integer; got " + JSON.stringify(maxBytes),
345
+ "atomic-file/bad-opt");
346
+ }
347
+ }
348
+
334
349
  function _readSyncCore(filepath, opts) {
335
350
  if (!fs.existsSync(filepath)) {
336
351
  var e = new AtomicFileError("file not found: " + filepath, "atomic-file/not-found");
337
352
  e.code = "ENOENT";
338
353
  throw e;
339
354
  }
355
+ _validateMaxBytes(opts.maxBytes);
340
356
  var stat = fs.statSync(filepath);
341
357
  if (stat.size > opts.maxBytes) {
342
358
  throw new AtomicFileError(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.6.67",
3
+ "version": "0.6.68",
4
4
  "description": "The Node framework that owns its stack.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:28be00e0-fbc9-4324-9213-5bfe704f8667",
5
+ "serialNumber": "urn:uuid:3d7e40d6-b790-48ba-ab7c-c25a893da190",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-03T14:50:38.247Z",
8
+ "timestamp": "2026-05-03T15:00:01.675Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "build"
@@ -19,14 +19,14 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@blamejs/core@0.6.67",
22
+ "bom-ref": "@blamejs/core@0.6.68",
23
23
  "type": "library",
24
24
  "name": "blamejs",
25
- "version": "0.6.67",
25
+ "version": "0.6.68",
26
26
  "scope": "required",
27
27
  "author": "blamejs contributors",
28
28
  "description": "The Node framework that owns its stack.",
29
- "purl": "pkg:npm/%40blamejs/core@0.6.67",
29
+ "purl": "pkg:npm/%40blamejs/core@0.6.68",
30
30
  "properties": [],
31
31
  "externalReferences": [
32
32
  {
@@ -54,7 +54,7 @@
54
54
  "components": [],
55
55
  "dependencies": [
56
56
  {
57
- "ref": "@blamejs/core@0.6.67",
57
+ "ref": "@blamejs/core@0.6.68",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]