feat(config): pass listed host env vars to app.command with inheritEnv
Merged
OK
12d ago+288+288+012345678901234567890123456789-53-53-01234567890123456789
What and why
app.command.inheritEnvcopies host variables into the app process, by exact name or trailing-*prefix. A host that sets per-run values (a per-taskDATABASE_URL, check secrets) no longer has to list each one ine2e.config.tsor spreadprocess.env, which also hands the app the model keys.- A variable is copied only when it is set.
command.envwins over an inherited value. WithoutinheritEnv, nothing changes. - Validation at config load (
INVALID_CONFIG): a bare*(it would undo the isolation), a*anywhere but the end, an empty entry,=, or whitespace. - Inherited values are redacted from a quoted startup failure the same way
command.envvalues are (packages/e2e/src/run/managed-process.ts). openHostand the runner copy from theenvthey resolve against, not alwaysprocess.env, so a programmatic host passingenvgets its own values.- The
E2E_APP_INHERIT_ENVenv var form from the issue is left out on purpose: a host that controls the environment can already set the listed variables.
app: {
url: 'http://localhost:3000',
command: {
executable: 'npm',
args: ['run', 'dev'],
inheritEnv: ['DATABASE_URL', 'STRIPE_*'],
},
},
Closes #1119
Verified
Ran it locally: yes
- Scratch project in
/tmpwith the builte2eand@e2e-dev/weblinked in, and anapp.command(a node server) that prints the variables it sees and serves them as a page. Config:inheritEnv: ['DATABASE_URL', 'STRIPE_*'],env: { STRIPE_HOOK: 'from-config' }.
DATABASE_URL=postgres://host/db STRIPE_KEY=sk_test_host STRIPE_HOOK=from-host OPENAI_API_KEY=sk-fake-model-key AI_GATEWAY_API_KEY=fake-gateway-key e2e run tests/env.e2e.ts
✓ target "web" command ready 95ms
✓ |web| tests/env.e2e.ts (1 test) 252ms
✓ app sees only the listed host env 252ms
App log: the listed variables arrive, command.env beats the host value, and the model keys stay out:
DATABASE_URL=postgres://host/db STRIPE_KEY=sk_test_host STRIPE_HOOK=from-config OPENAI_API_KEY=(unset) AI_GATEWAY_API_KEY=(unset)
- The same config without
inheritEnvbehaves as before:DATABASE_URL=(unset) STRIPE_KEY=(unset) .... openHost({ env: { ...process.env, DATABASE_URL: 'postgres://per-task/db' } })withDATABASE_URL=postgres://orchestrator/dbin the shell: the app loggedDATABASE_URL=postgres://per-task/db.- Invalid entries:
ERROR configuration error INVALID_CONFIG (config)
target "web" app.command.inheritEnv[1] cannot be "*": it would pass every variable to the app, model keys included; list the names or prefixes it needs
target "web" app.command.inheritEnv[0] must be a variable name or a prefix ending in * (such as "STRIPE_*"), got "STR*PE"
- Unit tests cover matching, precedence, the passed
env, redaction, and validation. The precedence test fails when the merge order is swapped. Testbed suite not run (its fixed port could clash with other local runs); the change only applies wheninheritEnvis set.
Checklist
- Changeset added (
pnpm changeset) for any change to a published package, or the change is testbed, docs, or CI only. - Breaking change: title carries
!, the changeset body names what breaks and what replaces it, and the deprecation warning landed a window earlier (stability policy in CONTRIBUTING.md). - Docs updated in the same PR: the
docs/**/*.mdxpage for the behavior, andskills/e2e/if the skill describes it. - Contract change: emitted
.d.tsreviewed,tests/types/sdk-types.tsupdated; wire change edits the schema and both fixtures. - Engine contract change (
e2e/engine): changesets fore2e,@e2e-dev/web, and@e2e-dev/mobile.