Skip to content

fix(cli): propagate TLS env vars from .gemini/.env in parent process#26011

Open
gaurav0107 wants to merge 2 commits intogoogle-gemini:mainfrom
gaurav0107:fix/25987-regression-node-extra-ca-certs-env-ignored
Open

fix(cli): propagate TLS env vars from .gemini/.env in parent process#26011
gaurav0107 wants to merge 2 commits intogoogle-gemini:mainfrom
gaurav0107:fix/25987-regression-node-extra-ca-certs-env-ignored

Conversation

@gaurav0107
Copy link
Copy Markdown
Contributor

Summary

Fixes #25987. NODE_EXTRA_CA_CERTS and other TLS-initialization env
vars defined in .gemini/.env were ignored after PR #24667 introduced
the lightweight parent / heavy child process model, because the
child's Node TLS layer initializes from process.env before its
loadEnvironment() call ever runs.

Details

Node reads NODE_EXTRA_CA_CERTS, SSL_CERT_FILE, HTTPS_PROXY, etc.
once at process start, in C++ before any user JS runs. Pre-#24667 the
CLI ran as a single process, so there was no observable ordering
problem — no outbound TLS happened until after .env was loaded.
After #24667 the child is spawned with a pre-built env, and by the
time the child's JS gets around to parsing .env the TLS layer is
already initialized without the cert.

This PR keeps the parent lightweight (no dotenv import, no heavy
module loads) by hand-parsing .gemini/.env for a small allowlist of
env vars that Node and libcurl require at init time:

  • `NODE_EXTRA_CA_CERTS`
  • `NODE_TLS_REJECT_UNAUTHORIZED`
  • `SSL_CERT_FILE`, `SSL_CERT_DIR`
  • `HTTPS_PROXY`, `HTTP_PROXY`, `NO_PROXY`

Values from `.gemini/.env` are injected into the child's spawn env
only when the key is not already set in the shell env, preserving
the existing "shell env wins" rule from `loadEnvironment()`.

Lookup order (matches `findEnvFile` in `settings.ts`):

  1. Nearest `/.gemini/.env` walking up parent directories
  2. `$HOME/.gemini/.env`

Scope is deliberately narrow: seven well-known network/TLS vars, and
only the `.gemini/.env` path (not arbitrary `.env`). Non-TLS vars
continue to flow through the child's full `loadEnvironment()` path
with its trust checks unchanged.

The PR also adds a small is-main-module guard around `run()` so the
new helpers (`parseSimpleEnv`, `findProjectGeminiEnvFile`,
`loadTlsEnvFromGemini`) can be imported from unit tests without
triggering a child spawn.

Related Issues

Fixes #25987
Related to #24667 (introduced the regression)

How to Validate

  1. Create `~/.gemini/.env` with
    `NODE_EXTRA_CA_CERTS=/path/to/cert.pem`.
  2. Ensure `NODE_EXTRA_CA_CERTS` is NOT set in your shell env.
  3. Run any command that makes an HTTPS request through a CA covered by
    that cert (e.g. `gemini mcp list` against an internal MCP server).
  4. Before this PR: `TypeError: fetch failed`.
  5. After this PR: succeeds.

Also verified:

  • `npm run typecheck --workspace @google/gemini-cli` — clean
  • `npx eslint packages/cli/index.ts packages/cli/index.test.ts --max-warnings 0` — clean
  • `npx vitest run index.test.ts` — 20/20 new tests pass
  • Full `npm run test --workspace @google/gemini-cli` — the 6 unrelated
    failures on my machine (`extension_integrity.json` local-state
    issue) also fail on stock `main`, so they are not regressions
    from this PR.

Pre-Merge Checklist

  • Tests added (packages/cli/index.test.ts, 20 cases covering the parser, the dir walker, and the orchestrator helper)
  • No breaking changes (helper is additive; existing `newEnv` spread order preserves `process.env` precedence)
  • No docs changes needed
  • Validated on required platforms/methods:
    • MacOS — npm run, vitest
    • Windows — not available locally (reporter is on win32; reporter steps apply)
    • Linux — not available locally

NODE_EXTRA_CA_CERTS and other TLS-initialization env vars defined in
.gemini/.env were ignored after PR google-gemini#24667 introduced the lightweight
parent / heavy child process model. Node reads these vars once at
process start (before any JS runs), so by the time the child's
loadEnvironment() parses .env, it is too late to influence the TLS
trust store.

This change keeps the parent lightweight (no dotenv import, no heavy
module loads) by hand-parsing .gemini/.env for a small allowlist of
env vars that Node and libcurl require at init time:

  - NODE_EXTRA_CA_CERTS
  - NODE_TLS_REJECT_UNAUTHORIZED
  - SSL_CERT_FILE, SSL_CERT_DIR
  - HTTPS_PROXY, HTTP_PROXY, NO_PROXY

Values are injected into the child's spawn env only when the key is
not already set in the shell environment, preserving the existing
"shell env wins" rule from loadEnvironment(). Non-TLS vars continue
to flow through the child's full loadEnvironment() path with its
trust checks unchanged.

Also adds an is-main-module guard around run() so that the helpers
can be imported from unit tests without triggering a child spawn.

Fixes google-gemini#25987
Drop project-local (cwd-walking) .gemini/.env lookup from the parent
helper. The existing child-side loadEnvironment() already gates
project files behind the full workspace-trust model; reproducing that
logic in the lightweight parent would require either duplicating the
longest-match + TRUST_PARENT resolution or importing heavy modules
(defeating PR google-gemini#24667's goal).

Scoping this first fix to HOME-only:
  - Resolves the reporter's own use case on google-gemini#25987 (enterprise CA
    cert placed in ~/.gemini/.env for the whole machine).
  - Closes a small security-surface widening (untrusted project
    .gemini/.env could have forced NODE_EXTRA_CA_CERTS into the
    parent env without a trust check).
  - Shrinks the diff and removes one exported helper
    (findProjectGeminiEnvFile) that is no longer needed.

Project-local support remains a clean follow-up once the trust
check is factored into a shared standalone helper.
@gaurav0107 gaurav0107 marked this pull request as ready for review April 26, 2026 19:39
@gaurav0107 gaurav0107 requested a review from a team as a code owner April 26, 2026 19:39
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a regression where TLS-initialization environment variables defined in .gemini/.env were ignored due to the recent introduction of a parent/child process model. By hand-parsing a specific allowlist of network-critical variables in the lightweight parent process and injecting them into the child's spawn environment, the fix ensures that Node.js correctly picks up these settings before the TLS layer initializes, while preserving existing precedence rules.

Highlights

  • TLS Environment Variable Propagation: Implemented a mechanism to parse and propagate critical TLS-related environment variables (e.g., NODE_EXTRA_CA_CERTS) from the user's ~/.gemini/.env file directly into the child process's spawn environment, ensuring they are available during Node.js initialization.
  • Lightweight Environment Parser: Added a custom, minimal KEY=VALUE parser to the parent process to avoid loading heavy dependencies like 'dotenv', maintaining the performance benefits of the parent/child process model.
  • Testability Improvements: Introduced an 'is-main-module' guard around the CLI's execution logic, allowing helper functions to be imported and unit-tested without triggering the child process spawn.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gaurav0107
Copy link
Copy Markdown
Contributor Author

Marking this PR ready for review.

Quick summary of what's in the patch:

  • Narrowly scoped to $HOME/.gemini/.env in the lightweight parent, so project-local trust logic in the child's loadEnvironment() is not bypassed.
  • Seven-key allowlist (NODE_EXTRA_CA_CERTS, NODE_TLS_REJECT_UNAUTHORIZED, SSL_CERT_FILE, SSL_CERT_DIR, HTTPS_PROXY, HTTP_PROXY, NO_PROXY) matches the vars Node and libcurl read before any JS runs.
  • Shell-env precedence is preserved (we only inject keys not already in process.env), matching the existing rule in loadEnvironment().
  • Hand-rolled parser (~30 LOC) keeps the parent free of dotenv, preserving the startup-latency goal of fix(cli): optimize startup with lightweight parent process #24667.
  • 17 unit tests cover quoting, CRLF, export prefix, inline #, malformed lines, allowlist filtering, shell-env precedence, and an explicit assertion that project-local .gemini/.env is not read by the parent.

Happy to iterate on scope, naming, or trust model if reviewers prefer a different cut.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a mechanism to propagate TLS and proxy-related environment variables from a user's $HOME/.gemini/.env file to the child process. It includes a lightweight .env parser and a helper function to load allowlisted variables, ensuring that critical settings like NODE_EXTRA_CA_CERTS are available during process initialization. Additionally, the entry point was refactored to support unit testing of these new utilities. I have no feedback to provide.

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.

Regression: NODE_EXTRA_CA_CERTS in .gemini/.env is ignored since v0.39.0 (PR #24667)

1 participant