Skip to content

[APPS-2792] Add: load .env files for local backend function credentials - #539

Open
tyffical wants to merge 2 commits into
masterfrom
tiffany.trinh/apps-2792-dotenv-credentials
Open

tyffical wants to merge 2 commits into
masterfrom
tiffany.trinh/apps-2792-dotenv-credentials

Conversation

@tyffical

@tyffical tyffical commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

  • Stacked on #523, which makes backend functions read the dev server's real process.env.
  • Scott asked for standard .env / .env.local files instead of a Datadog-specific credential file, with shell variables taking precedence.
  • Vite's own env loading can't provide this:
    • It only exposes keys with envPrefix (VITE_ by default) through import.meta.env, and it throws on envPrefix: ''.
    • It never copies unprefixed keys into process.env.
  • The protection against inlining credentials into backend bundles stays as is: backend builds keep envFile: false and envPrefix: [].

Architecture

 vite dev ── configureServer ──► loadEnvFileCredentials(user's Vite loadEnv, server.config)
                                   │  loadEnv(mode, envDir, '')  .env, .env.local, .env.[mode], .env.[mode].local
                                   │  skip: already in process.env (shell wins)
                                   │  skip: Vite envPrefix keys (frontend-only)
                                   │  skip + warn: DD_* / DATADOG_* (plugin settings, shell-only)
                                   ▼
                                 process.env  ◄── backend function reads process.env.X
                                   ▲
 .env edited ── Vite restarts ─────┘  values from the previous load (tracked on globalThis) are dropped first

 vite build ── backend build: envFile: false, envPrefix: []  ──► process.env.X stays a runtime read

Changes

8 changes across dotenv-credentials.ts, index.ts, README.md, and tests
What changed File
Copies .env-file keys into process.env with the user's own Vite loadEnv, without overriding shell variables dotenv-credentials.ts, dotenv-credentials.test.ts
Leaves keys with Vite's envPrefix to Vite, so the frontend never sees a value that's one restart stale dotenv-credentials.ts, dotenv-credentials.test.ts
Ignores DD_*/DATADOG_* keys in any case with a names-only warning, since the plugin resolves its site and auth from the shell before the dev server starts dotenv-credentials.ts, index.ts, index.test.ts
Skips .env loading in dev:verify, which runs backend functions in the cloud index.ts, index.test.ts
Drops the previous load's values on a dev server restart, even when the restart loads a fresh copy of the plugin dotenv-credentials.ts, dotenv-credentials.test.ts
Drops the previous load in the serve-mode config hook too, so Vite expands a restarted config's .env references (VITE_X=$SECRET) against the edited file index.ts, index.test.ts, dotenv-credentials.ts
A backend build keeps a loaded value as a runtime process.env read instead of inlining it build-config.test.ts
Documents the convention, precedence, the envPrefix and Datadog-key rules, and dev:verify README.md

QA Instructions

yarn build:all && yarn typecheck:all && yarn cli integrity
# All exit 0; git status --short is empty afterwards. ✅ VERIFIED

yarn test:unit
# Test Suites: 97 passed, 97 total. Tests: 1 skipped, 2463 passed, 2464 total. ✅ VERIFIED
Manual QA — real dev server against staging (dd.datad0g.com)
  • QA app whose vite.config.ts imports this branch's built plugin (packages/published/vite-plugin/dist/src/index.mjs, rebuilt at 461c886):
# .env
QA_DOTENV_FILE_KEY=from-dotenv
QA_DOTENV_LOCAL_KEY=from-dotenv
QA_DOTENV_SHELL_KEY=from-dotenv
VITE_QA_DOTENV_PUBLIC=public-a
DD_SITE=datadoghq.eu

# .env.local
QA_DOTENV_LOCAL_KEY=from-dotenv-local
// src/dotenvProbe.backend.ts (imported by App.tsx); none of these values are secrets
const fileKeyAtImport = process.env.QA_DOTENV_FILE_KEY;

export async function dotenvProbe() {
    return {
        fileKey: process.env.QA_DOTENV_FILE_KEY ?? null,
        fileKeyAtImport: fileKeyAtImport ?? null,
        localOverride: process.env.QA_DOTENV_LOCAL_KEY ?? null,
        shellPrecedence: process.env.QA_DOTENV_SHELL_KEY ?? null,
        publicViaImportMeta: import.meta.env.VITE_QA_DOTENV_PUBLIC ?? null,
    };
}
cd qa-app && QA_DOTENV_SHELL_KEY=from-shell dd-auth --domain dd.datad0g.com -- npx vite --port 5179 --strictPort
# [info|vite|apps] Backend functions can read QA_DOTENV_FILE_KEY, QA_DOTENV_LOCAL_KEY from .env files. Shell variables take precedence. ✅ VERIFIED
# (DD_SITE is already set in the shell by dd-auth, so the shell value wins silently.)
  • Each call goes through POST /__dd/executeAction after the page has loaded the .backend.ts module:
# dotenvProbe
# {"fileKey":"from-dotenv","fileKeyAtImport":"from-dotenv","localOverride":"from-dotenv-local","shellPrecedence":"from-shell","publicViaImportMeta":"public-a"} ✅ VERIFIED (2026-10-01 17:51:50 UTC)

# getMonitorSummary (action-catalog listMonitors against staging)
# {"monitorsReturned":100,"byState":[...]} ✅ VERIFIED (2026-10-01 17:51:51 UTC)
  • Edit .env while the server runs: VITE_QA_DOTENV_PUBLIC=public-b, and add DATADOG_SITE=datadoghq.eu:
# [vite] .env changed, restarting server...
# [warn|vite|apps] Ignoring DATADOG_SITE from .env files. Set Datadog settings in the shell or start the dev server with `datadog-apps dev`. ✅ VERIFIED
# dotenvProbe → "publicViaImportMeta":"public-b" ✅ VERIFIED (2026-10-01 17:52:02 UTC)
# getMonitorSummary still reaches staging ✅ VERIFIED (2026-10-01 17:52:03 UTC)
  • A public key that references a credential, QA_DOTENV_FILE_KEY=one and VITE_QA_DOTENV_PUBLIC=$QA_DOTENV_FILE_KEY, then QA_DOTENV_FILE_KEY edited to two:
# dotenvProbe after the restart → "fileKey":"two","publicViaImportMeta":"two" ✅ VERIFIED (2026-10-01 18:29:18 UTC)
# (before this fix, publicViaImportMeta stayed "one")
  • Production build:
cd qa-app && dd-auth --domain dd.datad0g.com -- npx vite --mode dev-verify --port 5180 --strictPort
# Neither the "can read" nor the "Ignoring" line is logged: dev:verify doesn't load .env files ✅ VERIFIED (2026-10-01 17:52:39 UTC)

npx vite build && unzip -p dist/datadog-app-assets.zip 'backend/*dotenvProbe.js' | grep -c 'from-dotenv\|from-shell\|public-b\|datadoghq.eu'
# 0; the bundle keeps process.env.QA_DOTENV_FILE_KEY/LOCAL_KEY/SHELL_KEY as runtime reads, and no .env file is in the archive ✅ VERIFIED (2026-10-01 17:52:08 UTC)

Blast Radius

  • Local dev only: vite build and cloud execution don't load .env files for backend functions.
  • No feature flag.
  • Low: a project with .env files now exposes their unprefixed keys to backend functions during vite dev, the same as dotenv or Next.js on the server.
  • Values are written to the dev server's global process.env, so a key that Node or a tool reads at runtime applies to the whole dev server, as with dotenv.

Out of Scope / Follow-ups

5 items deferred
Item Status Next step
Two dev servers with different .env files in one Node process share one process.env, so the second load replaces the first's values Deferred; inherent to a global process.env Revisit if a multi-server setup needs it
.env values reach the whole dev server's process.env, not only backend functions Accepted; matches dotenv and Next.js A scoped env would need the process.env proxy #523 removes
After a restart, vite.config itself is evaluated before any plugin hook, so a config that reads unprefixed process.env values (e.g. into define) sees the previous load on a restart but not on first start Deferred; needs a config that inlines process.env itself, dev bundle only Clear the previous load on server close instead, if Vite closes the old server before loading the new config
The loaded-keys confirmation logs at info, below the default warn log level Deferred Revisit if users miss it
A loaded key whose value changes at runtime stops being tracked, so later .env edits to it apply only after a full restart Deferred; needs code that rewrites process.env Track by key instead of value

Documentation

🤖 Generated with Claude Code

During vite dev, backend functions can now read unprefixed credentials from
Vite's .env, .env.local, .env.[mode] and .env.[mode].local files through
process.env, with shell variables taking precedence. Keys with Vite's
envPrefix stay frontend-only, and DD_*/DATADOG_* keys are ignored with a
warning, since the plugin resolves its own settings from the shell. Values
from an earlier load are dropped on restart so edits apply. Backend builds
keep envFile: false and envPrefix: [], so loaded values are never inlined.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Tests

✅ All CI checks and tests passed.

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 202fbc2 | Docs | View more details | Give us feedback!

@tyffical
tyffical requested a balanced review from Copilot October 1, 2026 18:17
@tyffical

tyffical commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-01T18:20:51.593423Z 461c886 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The implementation is consistent with the stated design and has comprehensive regression coverage.

Review effort: Balanced
Findings: None

What changed in this PR

Adds Vite .env credential loading for locally executed backend functions while preserving shell precedence and build-time secret protections.

Changes:

  • Loads eligible .env values into process.env during local development.
  • Excludes frontend-prefixed and Datadog configuration keys.
  • Adds unit, integration, build-safety tests, and documentation.
File Description
packages/​plugins/​apps/​src/​vite/​index.ts Integrates credential loading into dev-server startup.
packages/​plugins/​apps/​src/​vite/​index.test.ts Tests startup loading, authentication precedence, and dev:verify.
packages/​plugins/​apps/​src/​vite/​dotenv-credentials.ts Implements .env loading, filtering, and restart cleanup.
packages/​plugins/​apps/​src/​vite/​dotenv-credentials.test.ts Covers precedence, filtering, reloads, and cleanup.
packages/​plugins/​apps/​src/​vite/​dev-server.integration.test.ts Supplies Vite’s environment loader to integration tests.
packages/​plugins/​apps/​src/​vite/​build-config.test.ts Verifies credentials remain runtime reads in backend bundles.
packages/​plugins/​apps/​README.md Documents local credential behavior and restrictions.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 461c886d4e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread packages/plugins/apps/src/vite/index.ts
…ed config

Vite expands .env references against process.env while resolving a restarted
server's config, before configureServer runs, so a public key referencing an
edited credential kept its old value. The config hook now drops the previous
load in serve mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tyffical
tyffical marked this pull request as ready for review October 1, 2026 18:50
@tyffical
tyffical requested a review from a team as a code owner October 1, 2026 18:50
@tyffical
tyffical requested review from Chau-DDOG and sdkennedy2 and removed request for a team and Chau-DDOG October 1, 2026 18:50
Base automatically changed from tiffany.trinh/apps-2792-revert-custom-credentials-file to master October 1, 2026 21:52
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.

2 participants