Skip to content

fix: read env vars by name instead of Deno.env.toObject() (#64) - #71

Merged
jonbaldie merged 2 commits into
mainfrom
fix/64-restricted-env-access
Aug 31, 2026
Merged

fix: read env vars by name instead of Deno.env.toObject() (#64)#71
jonbaldie merged 2 commits into
mainfrom
fix/64-restricted-env-access

Conversation

@jonbaldie

Copy link
Copy Markdown
Owner

Summary

The compiled binary (Dockerfile / CI) is built with a scoped --allow-env allowlist, but main.ts called Deno.env.toObject(), which enumerates the entire process environment and therefore requires unrestricted env access. The compiled binary crashed on startup with a NotCapable error every time — no CI job actually runs the compiled artifact, so this shipped green.

Fix

  • main.ts now reads each of the 7 known config vars individually via Deno.env.get(name), which respects a scoped allowlist.
  • Widened the Dockerfile/CI --allow-env list to include QUEUE_DEPTH_LIMIT, QUEUE_COUNT_LIMIT, RATE_LIMIT_REQUESTS (already runtime-configurable per config.ts, but missing from the compile-time allowlist).
  • Added tests/compiled_binary_test.ts: a permanent regression seam that compiles the actual binary with the scoped allowlist and asserts it reaches Listening on.

Verification

  • Confirmed RED against the original main.ts (binary crashed with the exact NotCapable error on Deno.env.toObject()).
  • Confirmed GREEN after the fix.
  • Full deno test suite: 217 passed, 0 failed.

Fixes #64

🤖 Generated with Claude Code

Deno.env.toObject() enumerates the entire process environment, which
requires unrestricted --allow-env. A compiled binary built with a
scoped --allow-env allowlist (as the Dockerfile/CI already declare)
crashes on startup with a NotCapable error the moment main.ts calls
toObject(), because the allowlist only grants access to specific
variable names, not enumeration.

Root cause: main.ts called Deno.env.toObject() while the Dockerfile
and CI compile step already used a scoped --allow-env allowlist,
so the binary they produced could never actually start. The build
step alone couldn't have caught this because no CI job runs the
compiled artifact.

Fix reads each of the 7 known config vars individually via
Deno.env.get(name), which respects the allowlist. Widened the
Dockerfile/CI --allow-env list to include the two vars that were
previously missing from it (QUEUE_DEPTH_LIMIT, QUEUE_COUNT_LIMIT,
RATE_LIMIT_REQUESTS were already runtime-configurable per config.ts
but not present in the compile-time allowlist).

Added tests/compiled_binary_test.ts as a permanent regression seam:
it compiles the actual binary with the scoped allowlist and asserts
it reaches "Listening on", closing the gap that let this ship green
previously.

Fixes #64

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q25veeccRvgA5zjp6Fhijq
The Stryker commandRunner runs the full deno test suite (coverageAnalysis
is off, so every mutant re-runs it in full). Two problems surfaced when
tests/compiled_binary_test.ts (added for #64) was included:

1. Stryker instruments src/persist.ts with mutant-switching code that
   reads process.env.__STRYKER_ACTIVE_MUTANT__. compiled_binary_test.ts
   compiles main.ts with a fixed, scoped --allow-env allowlist that
   doesn't grant that name, so the inner compiled binary crashed with
   NotCapable during Stryker's dry run — failing CI on PR #71.
2. Even without that crash, spawning `deno compile` (a ~95MB binary)
   inside every mutant's test run would multiply the Stryker job's
   runtime by however many mutants exist in src/**/*.ts, which the
   30s per-mutant timeout can't absorb.

compiled_binary_test.ts is a build/integration test, not a unit test
covering src/ mutations, so it has nothing to contribute to Stryker's
mutation score. Excluded it via --ignore on the commandRunner, mirroring
how mutation/mutasaurus_ci.ts already scopes to an explicit test file
list that doesn't include it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q25veeccRvgA5zjp6Fhijq
@jonbaldie
jonbaldie merged commit 1eca213 into main Aug 31, 2026
4 checks passed
@jonbaldie
jonbaldie deleted the fix/64-restricted-env-access branch August 31, 2026 12:18
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.

Compiled binary crashes on startup: Deno.env.toObject() needs unrestricted env access but compile whitelists only 4 vars

1 participant