Repository navigation
fix(env): keep local values out of Astro's Worker bundle - #729
Open
morinokami wants to merge 5 commits into
Open
morinokami wants to merge 5 commits into
morinokami wants to merge 5 commits into
Conversation
When a module reads `import.meta.env` as a whole, Astro's env plugin adds every local variable whose name occurs anywhere in that module, identifiers and comments included. `void/env` does that read, so `astro build` copied values such as STRIPE_KEY from `.env` or the build shell into the server output and the deploy upload. In Astro builds, Void now replaces that read in `void/env` with the object Vite's define would give it, limited to the public `VITE_*` keys, before Astro's plugin sees the module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…alues - Match the void/env module by real path, so a symlinked or Windows short-name id still gets the transform instead of silently leaking again. - Find `import.meta.env` with a small scan instead of a regex; it also skips longer names such as `$import.meta.env` and `a.import.meta.env`. - Move the plugin into createAstroPublicEnvPlugin() with fast unit tests for the scan, define values, the client skip and the path match. - The integration test also checks a build-shell canary: Astro treats every shell variable as private too. - Fix comments: Astro copies values from .env and the build shell, and Void's env plugin adds schema defaults to the shared env object (it does not remove .env values there). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Member
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. Nice work! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
cpojer
pushed a commit
that referenced
this pull request
Nov 6, 2026
…ndles (#732) In a SvelteKit app on D1 with `void` installed from npm, `void deploy --platform cloudflare` puts the `VITE_*` values from the local `.env` into the uploaded Worker: ```sh # .env VITE_API_ORIGIN=http://localhost:8787 VITE_LOCAL_NOTE=only-on-my-laptop ``` ```js // uploaded Worker (minified) function m() { return Object.fromEntries(Object.entries({ BASE_URL: "/", DEV: !1, MODE: "production", PROD: !0, SSR: !1, VITE_API_ORIGIN: "http://localhost:8787", VITE_LOCAL_NOTE: "only-on-my-laptop" }).filter(([e]) => e.startsWith("VITE_"))); } ``` With `VITE_API_ORIGIN: url().default('https://api.example.com')` in `env.ts` and no value in the build shell, the deployed Worker answers `env.VITE_API_ORIGIN` with `http://localhost:8787`, while the browser bundle has `https://api.example.com`. `VITE_LOCAL_NOTE` is not declared in `env.ts` and is readable too. The docs say builds ignore client values from `.env`. Void's env plugin removes `.env` client values during Kit's build, but Kit's server build leaves an installed `void/env` as an import, so that module is not compiled there. Before the upload, `prepareBundledBuildOutput` bundles the adapter's Worker once more with Vite, with the project root as `root` and no `envDir`. Vite reads `.env` there and replaces `import.meta.env` in `void/env` with its values. Managed deploys bundle the same entry from `.void/bundle`, which has no `.env`. ## Fix The bundle sets `envDir: false`. Vite reads no env files there; values from the build shell still reach `import.meta.env`. ## Tests `packages/void/test/unit/cf-build-output.test.ts` bundles a framework Worker that imports a package reading `import.meta.env` as a whole, with `VITE_ORIGIN` in `.env` and `VITE_SHELL_ORIGIN` in the environment. The bundle contains the shell value and not the `.env` value. Without this fix, it contains both. The SvelteKit playground does not show the problem: it links `void` from the workspace, so Kit bundles it in its own build and the second bundle finds no `import.meta.env` to replace. ## Verification - `vp test run`: 781 files pass, 1 skipped (16,159 tests pass, 29 skipped). - `vp run check`: 33/33 pass. - By hand on a copy of the SvelteKit playground, with `void` copied into `node_modules` as a real directory: build, then `prepareCfFrameworkBuildOutput` and `bundleEntry`, each run in Miniflare. Without this fix, the native Worker returns the `.env` values from an API route and renders `http://localhost:8787` in a page. With it, the native and managed Workers return the same values: none without a build-shell value, and the build-shell value when `VITE_API_ORIGIN` is set. - Not run: `void deploy` against Cloudflare, and Nuxt, Analog and Astro, which go through the same bundle. Related: #729 keeps local values out of Astro's Worker through a different path (Astro's env plugin). The two changes touch different files and don't depend on each other. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
In an Astro app whose server code imports
void/env,astro buildcopies local values into the Worker:# .env STRIPE_KEY=sk_local_valueThe value also reaches the deploy upload. It stays out of
dist/client, and the Worker can't read it at runtime becausevoid/envkeeps onlyVITE_*keys, but.envis meant to stay local.When a module reads
import.meta.envas a whole, Astro adds every private variable whose name occurs anywhere in that module, identifiers and comments included.void/envreads it that way to pick theVITE_*keys, and its source contains names such asSTRIPE_KEY(in its docs),registryandgetClientEnvValues.Fix
In Astro builds, a
preplugin replacesimport.meta.envin thevoid/envmodule with an object of the build'sVITE_*values, built the way Vite's define buildsimport.meta.env: the values from the finalconfig.env, then eachdefineof animport.meta.env.VITE_*key, which wins and is kept as code. Astro's plugin then finds no read in the module, so no name in it can match. Development is unchanged.Astro's own
actions/runtimemodules readimport.meta.envin the same way, so a variable named in their source, such asPORT, still lands in the output of any Astro app. The common secret names I checked, such asAPI_KEY,SECRET,TOKENandDATABASE_URL, don't occur there.Tests
packages/void/test/integration/astro.test.tsbuilds the playground withSTRIPE_KEY,registryandgetClientEnvValuesin.env,VITE_added toenvPrefix, anddefineentries forimport.meta.env.VITE_DEFINEDandimport.meta.env.VITE_OVERRIDDEN:.envvalues is indist. Without this fix, all three are inserver/chunks/env_*.mjs.STRIPE_KEYfrom the Worker env,VITE_ORIGINfrom the build shell,VITE_DEFINEDfromdefine, andVITE_OVERRIDDENfromdefineover its build-shell value. Without this fix, the preview serves the same values.Verification
vp test run: 776 files pass, 1 skipped (16,003 tests pass, 29 skipped).vp run check: 33/33 pass.generateWrapper, then the upload preparation, run in Miniflare withnodejs_als. The.envvalue is in neither the build output nor the upload. A route readsSTRIPE_KEYfrom a binding and, withVITE_inenvPrefix,VITE_ORIGINfrom the build shell..envvariables namedvaluesandenvstill land inserver/entry.mjs, through Astro's ownactions/runtimemodules.void deployagainst Cloudflare, and an installed package layout.Maintainer polish (4d2783b)
import.meta.envis found with a small scan instead of a regex; it skips longer names like$import.meta.envanda.import.meta.env.createAstroPublicEnvPlugin(), with fast unit tests (test/unit/astro-public-env.test.ts) for the scan, define values, the client skip and the path match..env..envvalues there.main.Known gap, not changed here (older than this PR): in Astro builds a
.envVITE_*value still reaches the Worker bundle, because the Cloudflare adapter copies.envintoprocess.envbefore Void's strip step runs. Left for a follow-up.Verification:
vp run check33/33;vp run test --base origin/main542 files passed; the unit test andastro.test.tspass (15/15).🤖 Generated with Claude Code