fix: read env vars by name instead of Deno.env.toObject() (#64) - #71
Merged
Conversation
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
This was referenced Aug 31, 2026
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The compiled binary (Dockerfile / CI) is built with a scoped
--allow-envallowlist, butmain.tscalledDeno.env.toObject(), which enumerates the entire process environment and therefore requires unrestricted env access. The compiled binary crashed on startup with aNotCapableerror every time — no CI job actually runs the compiled artifact, so this shipped green.Fix
main.tsnow reads each of the 7 known config vars individually viaDeno.env.get(name), which respects a scoped allowlist.--allow-envlist to includeQUEUE_DEPTH_LIMIT,QUEUE_COUNT_LIMIT,RATE_LIMIT_REQUESTS(already runtime-configurable perconfig.ts, but missing from the compile-time allowlist).tests/compiled_binary_test.ts: a permanent regression seam that compiles the actual binary with the scoped allowlist and asserts it reachesListening on.Verification
main.ts(binary crashed with the exactNotCapableerror onDeno.env.toObject()).deno testsuite: 217 passed, 0 failed.Fixes #64
🤖 Generated with Claude Code