Skip to content

Upgrade vitest 2 → 4, pool-workers 0.5 → 0.15, patch Hono CVEs, add CI#39

Merged
rianvdm merged 2 commits into
mainfrom
perfectify/production-hardening
May 2, 2026
Merged

Upgrade vitest 2 → 4, pool-workers 0.5 → 0.15, patch Hono CVEs, add CI#39
rianvdm merged 2 commits into
mainfrom
perfectify/production-hardening

Conversation

@rianvdm
Copy link
Copy Markdown
Owner

@rianvdm rianvdm commented May 2, 2026

Summary

Closes #38. Three production-hardening items in one branch:

  1. Hono CVE patch (4.11.14.12.16) — fixes a critical HTML injection in hono/jsx SSR and a high-severity middleware bypass via repeated slashes in serveStatic. npm audit --omit=dev now clean.

  2. vitest 4 + pool-workers 0.15 upgrade — the previous baseline reported 462/477 passing with 3 unhandled errors, all from a known pool-workers 0.5 bug where the storage isolation snapshot asserts every persist file ends in .sqlite, but SQLite-backed Durable Objects in WAL mode also produce .sqlite-shm / .sqlite-wal. Upstream fix landed in pool-workers 0.13 (vitest 4 only). Migrating fixed all 3 tooling errors and exposed 7 latent test bugs that were masked by the broken isolation. Now 477/477 passing.

  3. Add CI (.github/workflows/ci.yml) — runs typecheck and npm test on push to main + every PR. Node 22 (required by vitest 4).

What's in the upgrade

  • vitest.config.tsdefineWorkersConfig (removed in v4) → defineConfig({ plugins: [cloudflareTest({...})] })
  • tsconfig.json — types entry is now @cloudflare/vitest-pool-workers/types; node added to surface Error.captureStackTrace and node:crypto
  • src/types/index.ts — keep JOB_STATUS: DurableObjectNamespace (no generic). JobStatusDO uses the old implements DurableObject interface and doesn't satisfy the new Rpc.DurableObjectBranded constraint
  • 6 test files — as Envas unknown as Env (DO generic is stricter now)
  • test/{api,consumer}.test.tsclearTestData now wipes the episodes: prefix so the index key (episodes:index) doesn't carry stale entries across tests
  • test/consumer.test.tscreateMockBatch takes { attempts }; 7 failure-case tests now pass attempts: 3 so the consumer's attempts >= maxAttempts check trips and marks the job failed (previously these were exercising the retry path while asserting failed state, which is impossible — pool-workers tooling bug masked the contradiction)
  • .nvmrc22

Test plan

  • npm run typecheck exit 0
  • npx vitest run → 36/36 files, 477/477 tests, exit 0
  • npm audit --omit=dev → 0 vulnerabilities
  • CI green on this PR

🤖 Generated with Claude Code

rianvdm and others added 2 commits May 2, 2026 14:21
Resolves two npm audit advisories:
- Critical: HTML injection in hono/jsx SSR via attribute names
  (GHSA-458j-xx4x-4375)
- High: middleware bypass via repeated slashes in serveStatic
  (GHSA-wmmm-f939-6g9c)

`npm audit --omit=dev` now reports 0 vulnerabilities. Remaining advisories
are all in devDependencies (miniflare/undici/vite/esbuild) and don't
ship to production.

Refs #38.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous test suite reported 462/477 passing with 3 unhandled errors —
all from a known @cloudflare/vitest-pool-workers v0.5 bug where the storage
isolation snapshot asserts every persist file ends in `.sqlite`, but
SQLite-backed Durable Objects in WAL mode also produce `.sqlite-shm` and
`.sqlite-wal` files. Upstream fix landed in pool-workers 0.13, which
requires vitest 4.

Changes:
- Bump vitest 2 → 4, @cloudflare/vitest-pool-workers 0.5 → 0.15+; add
  @types/node (no longer transitive). Node 22 required (.nvmrc + CI).
- Migrate vitest.config.ts from `defineWorkersConfig` (now removed) to
  `defineConfig({ plugins: [cloudflareTest({...})] })`. Same options shape,
  different wiring.
- tsconfig: types entry is now `@cloudflare/vitest-pool-workers/types`
  (new export path); add `node` to surface Error.captureStackTrace and
  `node:crypto` typings.
- src/types/index.ts: keep `JOB_STATUS: DurableObjectNamespace` (no
  generic). The class uses the older `implements DurableObject` interface
  and doesn't satisfy the new `Rpc.DurableObjectBranded` constraint;
  worker-configuration.d.ts already carries the precise generic.
- 6 test files: `as Env` → `as unknown as Env`. Workers-types' DO generic
  is stricter now and the spread `{...env}` produces a precise
  `DurableObjectNamespace<JobStatusDO>` that doesn't assign to the loose
  `Env` cast.
- test/{api,consumer}.test.ts: `clearTestData` now also wipes the
  `episodes:` prefix so the episode index key (`episodes:index`) doesn't
  carry stale entries across tests. Fixes 1 latent failure.
- test/consumer.test.ts: `createMockBatch` accepts an `attempts` option.
  7 failure-case tests now pass `attempts: 3` so the consumer's
  `attempts >= maxAttempts` check trips and marks the job failed —
  previously these tests were exercising the retry path while asserting
  failed state, which is impossible. The pool-workers tooling bug was
  masking the contradiction.
- .github/workflows/ci.yml: run typecheck + tests on push/PR (Node 22).

Result: 477/477 tests passing (was 462), typecheck clean, exit 0.
Production deps: 0 vulnerabilities (Hono CVE patched in prior commit).

Closes #38.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rianvdm rianvdm merged commit 9242056 into main May 2, 2026
1 check passed
@rianvdm rianvdm deleted the perfectify/production-hardening branch May 2, 2026 22:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Production hardening: patch Hono CVEs, fix red test, add test CI

1 participant