@blamejs/core 0.11.20 → 0.11.21
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/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,8 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.11.x
|
|
10
10
|
|
|
11
|
+
- v0.11.21 (2026-05-20) — **Supply-chain hardening — pinact + zizmor + actionlint gate, sha-to-tag tag-integrity verifier, GOVERNANCE.md.** Closes the input + tag-integrity halves of the supply-chain trust boundary. `pinact` refuses any `uses:` reference that isn't pinned to a 40-char SHA with a verified version-comment (defense against the CVE-2025-30066 retroactive-tag-rewrite class). `zizmor` audits every workflow for the documented security anti-pattern catalog (template-injection / excessive-permissions / cache-poisoning / impostor-commit / unredacted-secrets / etc.). The new `sha-to-tag-verify` workflow refuses to let the publish workflow proceed if a release tag's commit SHA isn't on `main`'s first-parent history OR wasn't the result of a merged PR — the source-side gate that TanStack's 2026-05-11 attack (84 malicious `@tanstack/*` versions published with valid SLSA L3 provenance) demonstrated as a structural defense alongside provenance verification. SECURITY.md gains operator-facing `slsa-verifier` and tag-SHA-integrity recipes. New top-level `GOVERNANCE.md` documents the solo-maintainer governance model, succession plan, key-loss recovery, and dependent-notification protocol. **Added:** *`.github/workflows/actions-lint.yml` — pinact + zizmor + actionlint gate* — Three tools, three layers per the arxiv.org "Unpacking Security Scanners for GitHub Actions Workflows" taxonomy. `pinact run --check` refuses any `uses:` reference that isn't SHA-pinned with a matching version-comment; `pinact run --verify` re-resolves each pinned SHA's registered tag at check time and refuses if the workflow's version-comment disagrees (catches retroactive tag rewrites). `zizmor` audits at `--min-severity low` across every documented rule class (template-injection, excessive-permissions, dangerous-triggers, unpinned-uses, cache-poisoning, github-env, hardcoded-container-credentials, impostor-commit, known-vulnerable-actions, obfuscation, ref-confusion, secrets-inherit, self-hosted-runner, unredacted-secrets, unsound-contains, use-trusted-publishing); SARIF emitted to GitHub Code Scanning. `actionlint` runs YAML + expression validation + shellcheck on every `run:` block. Single documented exception in `.pinact.yaml` — the SLSA reusable workflow MUST be tag-pinned because its internal builder-fetch step refuses non-tag refs. · *`.github/workflows/sha-to-tag-verify.yml` — tag-SHA integrity gate* — Runs on every `v*` tag push and refuses to let the publish workflow start if the tag's commit SHA isn't on `main`'s first-parent history OR wasn't the result of a merged PR. Defends against the tag-mutation class (CVE-2025-30066: 23,000+ affected repos in March 2025) and the source-side-malicious-publish class (TanStack 2026-05-11: 84 valid-SLSA-L3-provenance malicious versions). The same chain is documented for operator-side re-verification in SECURITY.md's new "Verifying release-commit integrity" subsection. · *`GOVERNANCE.md` — solo-maintainer governance, succession, key-loss recovery, dependent-notification* — New top-level document covering: (a) current governance model (solo maintainer pre-1.0, maintainer-final on technical direction); (b) succession plan with TBD-successor-with-documented-re-open-trigger, repository ownership, npm publish credentials, SSH signing key rotation procedure, Sigstore identity rotation; (c) key-loss recovery for every asset (npm publish, GitHub org, SSH signing key, Sigstore, domain); (d) dependent-notification protocol via `security@blamejs.com` with 30-day no-activity escalation. Bus-factor-1 is the largest non-technical risk pre-1.0; this document makes the recovery path defensible. · *SECURITY.md — `slsa-verifier` and tag-SHA-integrity operator-verification recipes* — "Verifying release authenticity" gains a `slsa-verifier verify-artifact` recipe (pinned to v2.7.1) for offline / API-independent provenance verification — `gh attestation verify` walks the chain via the GitHub API; `slsa-verifier` does it from disk. The recipe explicitly states the limit: SLSA provenance binds the tarball bytes to a workflow+commit+tag, but does NOT prove the source is clean (the TanStack incident shipped valid-provenance malicious versions because the source side was compromised). A new "Verifying release-commit integrity" subsection documents the sha-to-tag chain operators run alongside provenance verification — the source-side gate. · *`.pinact.yaml` — pinact configuration with documented SLSA exception* — Defines a single tag-pin exception for `slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml`. The SLSA reusable workflow's internal builder-fetch step refuses non-tag `BUILDER_REF` values, so the call MUST be tag-pinned; mitigated by slsa-framework's upstream tag-protection + immutable-release rules. The same exception also appears as a per-line `# allow:slsa-framework-action-not-sha-pinned` marker in `npm-publish.yml` for the framework's own codebase-patterns gate. **Changed:** *Workflow version-comment integrity — every pinned action's `# vX.Y.Z` comment now matches the registered tag for that SHA* — Pre-existing pins carried stale version-comments (`actions/checkout@de0fac2e... # v6.0.0` where that SHA is actually `v6.0.2`, `actions/setup-node@48b55a01... # v6.0.0` where the SHA is `v6.4.0`, `actions/download-artifact@3e5f45b2... # v7.0.1` where the SHA is `v8.0.1`, `github/codeql-action@9e0d7b8d... # v3.30.9` where the SHA is `v4.35.5`). The SHAs themselves stay (they're the actual-released versions); the comments now match. This is what pinact's `--verify` check enforces structurally going forward — a stale version-comment is the early-warning signal that a retroactive tag rewrite landed without operator notice. **References:** [CVE-2025-30066 (tj-actions/changed-files retroactive tag rewrite)](https://nvd.nist.gov/vuln/detail/CVE-2025-30066) · [TanStack npm publish incident 2025-05-11](https://blog.tanstack.com/the-tanstack-may-2025-supply-chain-attack/) · [pinact](https://github.com/suzuki-shunsuke/pinact) · [zizmor](https://github.com/woodruffw/zizmor) · [actionlint](https://github.com/rhysd/actionlint) · [slsa-verifier](https://github.com/slsa-framework/slsa-verifier)
|
|
12
|
+
|
|
11
13
|
- v0.11.20 (2026-05-20) — **`b.backup.localStorage` legacy alias removed + test-discipline backlog fully drained.** Two pieces bundled into one patch. (1) The `b.backup.localStorage` legacy alias introduced in v0.11.2 as a deprecation cycle for the rename to `b.backup.diskStorage` is removed entirely — pre-v1 the project's stated policy is no backwards-compat shims, and the cleanup no longer needs to wait for the Node 26 floor-bump. (2) Every test file in the `test-promise-settimeout-sleep` detector's 49-file migration backlog is converted from `await new Promise(r => setTimeout(r, N))` sleeps to `helpers.waitUntil(predicate, opts)` (condition-waits) or the new `helpers.passiveObserve(ms, label)` (verify-absence-of-event windows). The previously-split `test-codebase-patterns.test.js` catalog is folded into the main `codebase-patterns.test.js` `KNOWN_ANTIPATTERNS` array with `scanScope: "test"`. **Added:** *`helpers.passiveObserve(ms, label)` — real-time observation budget* — Distinct from `helpers.waitUntil`: the goal is NOT to poll until a condition is truthy, but to let real time elapse so the test can verify ABSENCE of an event over a window. Required `label` (string) surfaces in audit logs / future flake diagnostics so a grep through a CI log immediately identifies which observation budget was consumed. Throws TypeError on non-positive `ms` or missing label. Use sparingly — if there IS an observable predicate, `waitUntil` is the right primitive (faster on fast platforms; passive observation always burns the full budget). **Changed:** *Test-discipline catalog unified — `codebase-patterns.test.js` is now the single source of truth* — The previously-split `test-codebase-patterns.test.js` runner is merged into the main `codebase-patterns.test.js` catalog. Six test-side detectors are now inline `KNOWN_ANTIPATTERNS` entries with `scanScope: "test"`: `test-promise-settimeout-sleep` (broadened regex catches block-bodied arrows + multi-arg arrows + function bodies with leading statements), `test-uses-stream-pipeline-without-withtesttimeout` (per-test wall-clock ceiling for node:stream.pipeline tests), `release-named-test-file` (basename-mode; refuses `v0-8-41-additions.test.js` / `slot-19-enhancements.test.js` / `batch-N.test.js`), `test-hardcoded-server-bind-port` (`.listen(0)` + `server.address().port`), `test-fs-watch-direct-call` (`helpers.backdateFile` + `helpers.waitForWatcher` instead), `test-future-utimes-without-backdated-baseline` (pair future-mtime writes with `backdateFile`), `test-creates-db-handle-without-isolation` (`b.db.create()` must compose `setupTestDb` / `setupVaultOnly` / `mkdtempSync`). The test-scope walker now also includes `examples/*/test/` so wiki integration tests share the same discipline. Single catalog means a single allowlist per detector, single migration backlog, and one runner to invoke from CI. · *Test-discipline migration — `setTimeout(r, N)` backlog fully drained (49 → 0 migration entries)* — Converted every test file in the migration backlog to `helpers.waitUntil` / `helpers.passiveObserve`: `a2a`, `a2a-tasks`, `agent-event-bus`, `agent-idempotency`, `agent-orchestrator`, `agent-snapshot`, `api-encrypt`, `app-shutdown`, `audit-segregation`, `break-glass`, `config`, `cors`, `daily-byte-quota`, `dsr`, `external-db-routing`, `guard-csv`, `http-client-cache`, `log-stream-cloudwatch`, `log-stream-otlp` (dead `_sleep` helper removed), `log-stream-otlp-grpc`, `mail-greylist`, `middleware-compose-pipeline`, `network`, `network-dns-resolver`, `network-heartbeat-passive`, `notify`, `observability-tracing`, `promise-pool`, `pubsub`, `queue-dlq-extend-lease`, `queue-flow-repeat`, `queue-priority-rate-progress`, `require-auth-cache-control`, `retry`, `safe-async-loops`, `safe-async-parallel`, `scim-server`, `sse`, `vault-seal-pem-file`, `watcher` (3 fs.watchFile poll-event waits), `webhook`, `websocket-channels`, `ws-client`, `api-key` (layer-1), and integration tests `cache`, `cluster-provider-mysql`, `log-stream`, `network-heartbeat`, `object-store-sigv4`, `pubsub`, `queue-redis`, `websocket-permessage-deflate`, `ws-client-roundtrip`. Each condition-wait now has a grep'able label and an automatic 5000ms ceiling. Two files are permanent structural FPs (not migration backlog): `test/helpers/services.js` (TCP/TLS/UDP probe primitives — race-with-socket-event pattern, not condition-wait) and `examples/wiki/test/integration.js` (consumes `@blamejs/core` via npm symlink, doesn't have access to the framework's internal test helpers; single 100ms post-shutdown flush window). **Removed:** *`b.backup.localStorage` — the legacy alias is gone* — The property no longer resolves on `b.backup` and the one-time deprecation warning is no longer emitted. Migration is a literal-name find-and-replace: `b.backup.localStorage({ root: ... })` becomes `b.backup.diskStorage({ root: ... })`. The returned storage backend object, its options shape, and its wire contract with `b.backupBundle.create` are unchanged. See SECURITY.md's Node 26 compatibility section for the original rename rationale. **References:** [Node.js 26 release notes (localStorage global)](https://nodejs.org/en/blog/release/v26.0.0)
|
|
12
14
|
|
|
13
15
|
- v0.11.18 (2026-05-20) — **ML-DSA-65 release-signing key onboarded — `.mldsa.sig` sidecar lights up.** v0.11.17 was the first release the new pipeline published end-to-end, but the `.mldsa.sig` PQC sidecar was missing because the operator-side `RELEASE_PQC_SIGNING_KEY` setup hadn't been done yet. v0.11.18 onboards the keypair: `keys/release-pqc-pub.json` is committed in-tree, the matching private key lives only in the `npm-publish` environment's `RELEASE_PQC_SIGNING_KEY` secret, and `SECURITY.md` documents the SHA3-512 fingerprint + the operator-side verification recipe (no external verifier binary required — verifies via the framework's own vendored noble-post-quantum primitive). **Added:** *`keys/release-pqc-pub.json` — ML-DSA-65 release-signing public key committed in-tree* — Generated locally via `node scripts/generate-release-signing-key.js`; the matching private key was set as the `RELEASE_PQC_SIGNING_KEY` secret in the `npm-publish` GitHub Actions environment (same scope as `NPM_TOKEN`). The publish workflow's PQC sidecar step now finds both pieces present and computes a `<tarball>.mldsa.sig` for every release tarball. Self-verify-before-write inside `sign-release-artifact.js` catches a stale env-secret-vs-in-tree-pubkey mismatch — refuses to write a non-verifiable sig. · *`SECURITY.md` — `PQC release-signing key` fingerprint + verification recipe* — New SECURITY.md table records the algorithm (ML-DSA-65, FIPS 204), the in-tree public-key file path, and the SHA3-512 fingerprint (`ad6bee96…2ede`). Verification recipe uses the framework's own `b.pqcSoftware.ml_dsa_65.verify` — no external verifier binary required, no dependency on Sigstore's classical-crypto chain. Operators with a PQC-only verification posture have a self-contained path: `gh release download`, then `node -e` against the vendored noble-post-quantum primitive. **Changed:** *`Verifying release authenticity` — four trust roots, not three* — SECURITY.md's closing summary updated to count the ML-DSA-65 release-signing sidecar as the fourth independently-verifiable trust root, alongside SLSA L3 npm provenance + Sigstore-keyless SBOM signing + SSH-signed tags. Each remains verifiable without trusting any of the others; tampering with one is detected by the others. **References:** [FIPS 204 — ML-DSA](https://csrc.nist.gov/pubs/fips/204/final) · [FIPS 202 — SHA-3 + SHAKE](https://csrc.nist.gov/pubs/fips/202/final) · [RFC 9909 — ML-DSA in X.509 + CMS](https://www.rfc-editor.org/rfc/rfc9909.html) · [noble-post-quantum (vendored under lib/vendor)](https://github.com/paulmillr/noble-post-quantum)
|
package/package.json
CHANGED
package/sbom.cdx.json
CHANGED
|
@@ -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:
|
|
5
|
+
"serialNumber": "urn:uuid:a3658057-6230-4935-a5ba-f8e7aaa9a3c7",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-05-
|
|
8
|
+
"timestamp": "2026-05-20T23:16:52.590Z",
|
|
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.11.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.11.21",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.11.
|
|
25
|
+
"version": "0.11.21",
|
|
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.11.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.11.21",
|
|
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.11.
|
|
57
|
+
"ref": "@blamejs/core@0.11.21",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|