Skip to content

fix(engine): launch Chrome with only the env it needs - #7629

Merged
jrusso1020 merged 2 commits into
mainfrom
fix/engine-chrome-launch-env
Nov 13, 2026
Merged

jrusso1020 merged 2 commits into
mainfrom
fix/engine-chrome-launch-env

Conversation

@jrusso1020

@jrusso1020 jrusso1020 commented Nov 13, 2026 •

Copy link
Copy Markdown
Collaborator

Chrome launches with only the env it needs. Every Chrome HyperFrames starts now gets an allowlisted environment instead of the whole process env, and renders come out unchanged. Refs #7623

Claude Opus 5.5

What

  • New @hyperframes/core/chrome-env: one exported CHROME_ENV_ALLOWLIST and a pure buildChromeLaunchEnv(env). Names match case-insensitively, since Windows treats them that way and proxy vars come in both cases. A trailing * is a prefix.
  • Every production Chrome start uses it:
    • engine render launch (launchEnv, which keeps its WAYLAND_DISPLAY and SwiftShader Vulkan handling)
    • engine GPU probe
    • HDR capture
    • startup diagnosis spawn
    • shellStarts probe
    • CLI launchOwnedBrowser, which covers every CLI browser and the CLI GPU probe
    • CLI preflight chrome --version
    • inspector server
  • HYPERFRAMES_CHROME_ENV_PASSTHROUGH takes a comma list of extra names, for hosts whose GPU driver or proxy auth needs a variable the list lacks. Driver variables have no closed set (RADV_*, ANV_*, KRB5CCNAME for Negotiate proxies). Documented in docs/packages/cli.mdx next to HYPERFRAMES_CHROME_SANDBOX.

Why

Chrome inherited everything the CLI, producer or Lambda handler held. It needs a small, known set of variables.

Allowlist

Category Names Why
Process basics PATH HOME USER LOGNAME TMPDIR TMP TEMP binary lookup, profile, temp dirs, identity
Locale and time LANG LANGUAGE LC_* TZ TZDIR LOCALE_ARCHIVE text shaping, Intl and Date; Nix locale archive
Display and session DISPLAY WAYLAND_DISPLAY XAUTHORITY XDG_* DBUS_SESSION_BUS_ADDRESS Linux desktops and WSLg, runtime/config/cache dirs
Fonts FONTCONFIG_FILE FONTCONFIG_PATH the Lambda Chromium layer sets FONTCONFIG_PATH; tests pin FONTCONFIG_FILE
Shared libraries LD_LIBRARY_PATH the Lambda Chromium layer prepends its lib dir; WSL GPU libs
GPU drivers MESA_* LIBGL_* GALLIUM_* VK_* __GLX_* __EGL_* __GL_* __NV_* DRI_PRIME EGL_PLATFORM LIBVA_* Mesa, libglvnd, Vulkan loader (SwiftShader ICD pinning), NVIDIA, VA-API
Network HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY AUTO_PROXY SOCKS_SERVER SOCKS_VERSION SSL_CERT_FILE SSL_CERT_DIR compositions load remote fonts and images; Chrome reads these on Linux
Chrome sandbox CHROME_DEVEL_SANDBOX setuid helper location, now that #7625 keeps the sandbox on
Windows SYSTEMROOT WINDIR SYSTEMDRIVE PROGRAMFILES* PROGRAMW6432 COMMONPROGRAM* PROGRAMDATA ALLUSERSPROFILE PUBLIC APPDATA LOCALAPPDATA USERPROFILE USERNAME USERDOMAIN HOMEDRIVE HOMEPATH COMPUTERNAME COMSPEC PATHEXT OS PROCESSOR_ARCHITECTURE NUMBER_OF_PROCESSORS system, profile and shell locations Chrome and its DLLs resolve
macOS __CF_USER_TEXT_ENCODING (plus HOME/TMPDIR/USER above) CoreFoundation text encoding

HYPERFRAMES_*, PRODUCER_*, NODE_OPTIONS, LD_PRELOAD, npm_* and the rest are not passed: Chrome's process tree reads none of them. The node side still reads them from its own env.

How

launchEnv used to return undefined (inherit) unless it had to drop WAYLAND_DISPLAY or the Vulkan pins. Now it always returns the filtered env, with the same two adjustments. The helper lives in core because engine, CLI and inspector all depend on it, and inspector does not depend on engine.

Related work

Refs #7623. Open-PR file overlap: #7622 edits launchOwnedBrowser in packages/cli/src/browser/launch.ts, about 5 lines from this hunk, and should merge cleanly. #7413 edits other functions in packages/cli/src/browser/preflight.ts. #7433 adds a different core subpath, so package.json and package-subpaths.json may need a trivial rebase. Several open PRs touch other sections of docs/packages/cli.mdx. #7630 (sandbox-retry diagnosis) edits different hunks of browserManager.ts and launch.ts, and the two branches merge cleanly together.

Test plan

  • Unit tests: chromeEnv.test.ts (27). Credential-shaped names are dropped, each category is kept, lower-case proxies and Windows-cased names match, and the passthrough adds exactly the named vars. Also launch.env.test.ts (CLI browsers are filtered, including a caller's own env), and the engine Vulkan and WSL env tests are updated to the always-filtered env.
  • Mutation probes, each caught: case-sensitive matching (5 failures), no prefix matching (6), allow everything (25), passthrough ignored (1), engine launch inheriting process.env (1), Vulkan pins kept for SwiftShader (1), CLI launch unfiltered (2).
  • Real render: hyperframes render of the css-spinner-render-compat fixture with this branch's CLI and with a main build. Decoded frames are identical (same framemd5 over all 150 frames, PSNR inf).
  • Chrome's actual env, names only: a pass-through shim set as HYPERFRAMES_BROWSER_PATH recorded the variable names each Chrome start received. The render ran with AWS_SECRET_ACCESS_KEY, GITHUB_TOKEN, DATABASE_URL and OPENAI_API_KEY set. On main, all 8 Chrome starts saw all of them. On this branch, the 8 starts saw only DBUS_SESSION_BUS_ADDRESS HOME LANG LOGNAME PATH USER XDG_DATA_DIRS XDG_RUNTIME_DIR. The shim run is also what found the preflight --version probe.
  • oxfmt, oxlint, tsc --noEmit for core/engine/cli/inspector, fallow audit, comment ratchet, package-subpaths, workspace-contracts, package-cycles, cli-process-ownership, cli-lazy-deps.
  • Not run on a real host: Windows, macOS, AWS Lambda, Cloud Run, or a hardware-GPU Linux box (this box renders on SwiftShader).

Not covered here: dev-only launches (studio's Vite thumbnail plugin, verifyStaticPage used by a repo script, test and e2e harnesses) keep their env.

— Rames Jusso

🤖 Generated with Claude Code

Every Chrome HyperFrames starts (render, GPU probe, HDR capture, startup
diagnosis, version and shell probes, CLI browsers, inspector) now gets an
allowlisted environment from @hyperframes/core/chrome-env instead of the
whole process env. HYPERFRAMES_CHROME_ENV_PASSTHROUGH names any extra
variable a host needs.

Refs #7623

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mintlify

mintlify Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
hyperframes 🟢 Ready View Preview Nov 13, 2026, 12:14 AM

💡 Tip: Enable Automations to automatically generate PRs for you.

@github-actions

github-actions Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 267 (base branch 267), smooth 90 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (8)

Unstable (1)

  • seqinflight-none-pct-r0-root-z100: tracking 0.05, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true / tracking 0.05, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true / tracking 0.05, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE · 0 blocker · 1 important · 1 nit · 57972de3

Rule 2 sweep: every production Chrome start (engine render/GPU probe/HDR/diagnosis/shellStarts, CLI launchOwnedBrowser/preflight, inspector) is filtered; openBrowser (the user's own browser) correctly isn't. CI green; merges cleanly with main and #7630.

— Genesis

Comment thread packages/core/src/chromeEnv.ts Resolved
return await new Promise<string>((resolve) => {
let stderr = "";
const child = spawn(executablePath, startupArgs(args, profile), {
env: buildChromeLaunchEnv(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the docstring says this replays "the failed launch's flags", but the env is a fresh buildChromeLaunchEnv() from process.env, not the failed attempt's env. For an engine launch, launchEnv may have removed WAYLAND_DISPLAY (WSL) or the Vulkan pins (SwiftShader), and the diagnosis Chrome gets them back. This is the env counterpart of #7630's args fix. Passing the attempt's env through explainChromeLaunchFailure would close it; fine as a follow-up.

The CLI GPU probe filters its env twice, which dropped the names
HYPERFRAMES_CHROME_ENV_PASSTHROUGH adds, so the probe and the render
saw different envs. Keep the passthrough variable itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE — 1 resolved, 0 open (diagnosis-env nit deferred to a follow-up), 0 new · 57972de → 71956c0 · CI green

@jrusso1020
jrusso1020 added this pull request to the merge queue Nov 13, 2026
Merged via the queue into main with commit 24d56e6 Nov 13, 2026
99 checks passed
@jrusso1020
jrusso1020 deleted the fix/engine-chrome-launch-env branch November 13, 2026 01:10
@miguel-heygen miguel-heygen mentioned this pull request Nov 13, 2026
3 of 5 tasks
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.

1 participant