Skip to content

[APPS-2792] Clean up: revert process.env scoping and the Custom Credentials local-file mechanism - #523

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 7 commits into
masterfrom
tiffany.trinh/apps-2792-revert-custom-credentials-file
Oct 1, 2026
Merged

gh-worker-dd-mergequeue-cf854d[bot] merged 7 commits into
masterfrom
tiffany.trinh/apps-2792-revert-custom-credentials-file

Conversation

@tyffical

@tyffical tyffical commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

Reviewing this PR

5 commits:

  1. Revert [APPS-2792] Add: local-file resolution for Custom Credentials #512 — Custom Credentials local-file resolution
  2. Revert [APPS-2792] Fix: harden env-guard against bypass and reliability gaps #510 — env-guard hardening
  3. Revert [APPS-2792] Add process.env scoping for local execution (Secret Store parity) #504 — the process.env allowlist itself
  4. fix: restore Vite build-time env-inlining guard — build-config.ts's envFile/envPrefix, dropped by reverting [APPS-2792] Add process.env scoping for local execution (Secret Store parity) #504 wholesale
  5. fix: restore network-guard hardening and regression coverage — own-property registry lookup, a frozen isActive/run facade, versioned registry keys; restored action-catalog and credential-exposure tests; tests pinning adapter registration outside the blocked scope and skipped for an abandoned execution; an ambient-process.env test; local execution refuses to run when another release's guard is already installed
  • Commits 1–3 read best in order. Commits 4–5 restore what 1–3 dropped, so the PR ships as one unit.

Changes

9 changes across env-guard.ts, network-guard.ts, local-execution.ts, and supporting files
What changed File
Deleted entirely: the process.env Proxy/AsyncLocalStorage scoping mechanism, SAFE_ENV_KEYS, the /proc/.../environ and FileHandle bypass guards, process.report redaction env-guard.ts, env-guard.test.ts
Deleted: shared helpers #504 extracted solely for env-guard.ts's use guarded-wrapper.ts, shared-module-singleton.ts (+ their tests)
Restored getSharedContext with an own-property lookup, a frozen facade and versioned registry keys network-guard.ts, network-guard.test.ts
Removed all buildScopedEnv/runWithScopedEnv/resolveCustomCredentials call sites; adapter registration runs outside the blocked scope, with an abandonment check before and after it local-execution.ts, local-execution.test.ts, local-execution.resilience.test.ts
Deleted the file-based Custom Credentials resolver and its tests custom-credentials-resolver.ts, custom-credentials-resolver.test.ts
Removed the file-resolution wiring, its dev server deny entry and archive exclusion, and the README section index.ts, index.test.ts, build-package.ts, src/index.test.ts, README.md
Local execution refuses to run when another release's guard is already installed, instead of running unguarded network-guard.ts, local-execution.ts (+ tests)
Restored the build-time VITE_* env-inlining guard build-config.ts, build-config.test.ts
Removed now-obsolete env-scoping test helper packages/tests/src/_jest/helpers/env.ts (+ test)

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: 95 passed, 95 total. Tests: 1 skipped, 2395 passed, 2396 total. ✅ VERIFIED
Manual QA — real dev server against staging (dd.datad0g.com)
  • Scaffolded app whose vite.config.ts imports this branch's built plugin (packages/published/vite-plugin/dist/src/index.mjs, rebuilt at 8ff610f), launched with staging credentials:
cd qa-app && DEMO_API_KEY=local-demo-123 dd-auth --domain dd.datad0g.com -- npx vite --port 5176 --strictPort
  • Each function is called through the real endpoint, POST /__dd/executeAction with {"functionName": "<sha256('src/<file>')>.<fn>", "args": []}, after the page has loaded each .backend.ts module (registration is lazy):
# envProbe (reads process.env.DEMO_API_KEY)
# {"keyPresent":true,"keyLength":14} ✅ VERIFIED (2026-10-01 17:26:20 UTC)

# networkProbe (fetch / fs write / subprocess through a node_modules dependency)
# {"fetch":"blocked: Network access is not allowed directly in backend functions — use $.Actions instead.",
#  "fsWrite":"allowed (should have been blocked!)","subprocess":"blocked: Spawning a subprocess is not allowed in backend functions."}
# ✅ VERIFIED (2026-10-01 17:26:21 UTC); fs writes are guarded starting in #524

# getMonitorSummary (@datadog/action-catalog listMonitors against staging)
# {"monitorsReturned":100,"byState":[...]} ✅ VERIFIED (2026-10-01 17:26:22 UTC)

# authorizedDigest (@datadog/apps-backend getInitiatingUser + two action-catalog calls)
# {"authorized":true,...,"activeIncidents":25} ✅ VERIFIED (2026-10-01 17:26:23 UTC)

Blast Radius

  • Medium. npm run dev backend functions now see the real, ambient process.env of the dev server process — no allowlist, no Custom Credentials merge. This matches the pre-project baseline and the behavior of the rest of the Node ecosystem (Next.js, Vite, CRA all work this way), per the team's decision above.
  • No production behavior change — this only affects npm run dev. Production continues to resolve declared connections server-side via resolveCustomCredentialEnvConnections/ResolveConnectionToCredential, unaffected by anything in local execution.
  • A datadog-app.local.json left over from 3.4.0-dev.1 is ignored like any other project file.
  • Two different plugin releases loaded in one process now make local execution fail with a clear error instead of running unguarded.

Out of Scope / Follow-ups

2 items deferred
Item Status Next step
If this release loads before an older one (3.3.0 / 3.4.0-dev.1) in the same process, the older copy's runs are unguarded. Deferred; mixed installs look rare Separate task for a one-time warning.
as unknown as F remains in the generic guard wrappers. Won't fix here A cast-free version needs dropping the generic; revisit in #524's rewrite if wanted.

Documentation

  • Slack thread — the team's decision to launch with ambient local env vars, with any future file-based convention deferred to a security-reviewed follow-up
  • APPS-2792 Kickoff doc
  • PR #521 — dropped the now-obsolete MIGRATIONS.md entry separately (merged)
  • PR #524 — unrelated hardening from a broader security review, stacked on top of this PR

🤖 Generated with Claude Code

@tyffical tyffical changed the title [APPS-2792] Revert: local-file resolution for Custom Credentials [APPS-2792] Revert: process.env scoping and Custom Credentials local-file resolution Sep 28, 2026
tyffical added a commit that referenced this pull request Sep 28, 2026
PR #523 reverts both mechanisms entirely, so there's no local-execution
behavior change left to document for either.
@tyffical tyffical changed the title [APPS-2792] Revert: process.env scoping and Custom Credentials local-file resolution [APPS-2792] Clean up: revert process.env scoping, Custom Credentials file, and the 3.3.1 migration entry Sep 28, 2026
@tyffical tyffical changed the title [APPS-2792] Clean up: revert process.env scoping, Custom Credentials file, and the 3.3.1 migration entry [APPS-2792] Clean up: revert process.env scoping, Custom Credentials file, and the v3-to-v4 migration entry Sep 28, 2026
@tyffical
tyffical marked this pull request as ready for review September 28, 2026 23:29
@tyffical
tyffical requested review from a team as code owners September 28, 2026 23:29
@tyffical
tyffical requested review from ksun154 and a balanced review from Copilot and removed request for a team September 28, 2026 23:29
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 28, 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:19:14.324658Z 127af80 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.

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

@tyffical
tyffical removed the request for review from ksun154 September 28, 2026 23:53
tyffical added a commit that referenced this pull request Sep 28, 2026
Reverting PR #504/#510/#512 wholesale also removed several unrelated
protections that happened to live in the same diffs:

- build-config.ts's envFile:false/envPrefix:[] block Vite's own static
  .env-inlining into the production backend bundle — nothing to do
  with local execution's runtime env scoping.
- The Custom Credentials filename deny-list entries (build-package.ts's
  archive exclusion, index.ts's server.fs.deny and direct-import
  rejection) protect a leftover datadog-app.local.json a developer
  already created — removing the resolver doesn't retroactively make
  that file safe to package, serve, or import.
- network-guard.ts's getSharedContext regressed to exposing the raw
  AsyncLocalStorage instance via a Symbol on the net module instead of
  a restricted {isActive, run} facade, letting any code with
  require('net') call .disable() on it and permanently kill network
  blocking for the rest of the process.

Caught by Copilot's review of #523.
tyffical added a commit that referenced this pull request Sep 29, 2026
Reverting PR #504/#510/#512 wholesale also removed several unrelated
protections that happened to live in the same diffs:

- build-config.ts's envFile:false/envPrefix:[] block Vite's own static
  .env-inlining into the production backend bundle — nothing to do
  with local execution's runtime env scoping.
- The Custom Credentials filename deny-list entries (build-package.ts's
  archive exclusion, index.ts's server.fs.deny and direct-import
  rejection) protect a leftover datadog-app.local.json a developer
  already created — removing the resolver doesn't retroactively make
  that file safe to package, serve, or import.
- network-guard.ts's getSharedContext regressed to exposing the raw
  AsyncLocalStorage instance via a Symbol on the net module instead of
  a restricted {isActive, run} facade, letting any code with
  require('net') call .disable() on it and permanently kill network
  blocking for the rest of the process.

Caught by Copilot's review of #523.
@tyffical
tyffical force-pushed the tiffany.trinh/apps-2792-revert-custom-credentials-file branch from 7675588 to 6692a7b Compare September 29, 2026 00:11
@tyffical tyffical changed the title [APPS-2792] Clean up: revert process.env scoping, Custom Credentials file, and the v3-to-v4 migration entry [APPS-2792] Clean up: revert process.env scoping and the Custom Credentials local-file mechanism Sep 29, 2026
@tyffical
tyffical requested a balanced review from Copilot September 29, 2026 11:10
chatgpt-codex-connector[bot]

This comment was marked as resolved.

This comment was marked as resolved.

@tyffical
tyffical force-pushed the tiffany.trinh/apps-2792-revert-custom-credentials-file branch 2 times, most recently from 4eb37ce to e723d79 Compare September 29, 2026 12:57
@tyffical
tyffical requested a balanced review from Copilot September 29, 2026 13:39

This comment was marked as resolved.

@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: 9ec51a00a8

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

projectRoot,
timeoutMs,
);
await Promise.all([actionCatalogRegistration, backendRuntimeRegistration]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep adapter module loading inside the network guard

When either adapter is installed, these promises execute project-resolved package code before runBlocked begins, so module-initialization code in the adapter or its dependencies can make unrestricted network or subprocess calls while reading the newly exposed ambient environment. The fresh evidence in the reviewed tree is that the registrations are still awaited here, while runBlocked is not entered until line 874, despite the earlier thread saying this ordering was fixed; retain the registrations inside the blocked callback.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not changed, deliberately: the registration reuses the adapter module instance the customer's backend file has usually already loaded at top level, outside the guard (an accepted, documented gap for module top-level code), so running registration inside runBlocked protects little. It can also block Vite's or a project plugin's own work during that load, making registration fail and retry on every execution. The earlier reply on the other thread said it was moved inside; that was reverted on purpose afterwards and the reply is now corrected. Leaving this open for a human reviewer to confirm the trade-off.

🤖 Addressed by Claude Code

@tyffical
tyffical requested a review from sdkennedy2 October 1, 2026 15:06
@sdkennedy2

Copy link
Copy Markdown
Collaborator

Do we need to retain the protections for leftover datadog-app.local.json files? The credential-file mechanism was published in 3.4.0-dev.0 and 3.4.0-dev.1, but I don’t think we’ve rolled out the ability to configure Custom Credentials to customers yet. Is there any known customer usage that warrants keeping these guards and the warning? If not, could we remove them as part of this cleanup?

Separately, should we support standard .env / .env.local files for local backend credentials? I’d expect users to put an unprefixed credential there and read it through process.env, with shell variables taking precedence. That seems more familiar than a Datadog-specific credential file. Could we support that convention while keeping the protections against inlining credentials into backend bundles?

@tyffical

tyffical commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

Do we need to retain the protections for leftover datadog-app.local.json files? The credential-file mechanism was published in 3.4.0-dev.0 and 3.4.0-dev.1, but I don’t think we’ve rolled out the ability to configure Custom Credentials to customers yet. Is there any known customer usage that warrants keeping these guards and the warning? If not, could we remove them as part of this cleanup?

yeah i agree with removing them - i don't think i found any usage. agents kept flagging it so i put it back to be safe but with your agreement i'll remove them fully.

Separately, should we support standard .env / .env.local files for local backend credentials? I’d expect users to put an unprefixed credential there and read it through process.env, with shell variables taking precedence. That seems more familiar than a Datadog-specific credential file. Could we support that convention while keeping the protections against inlining credentials into backend bundles?

i do support this design generally. i believe I tried this for this PR initially but there was a conflict with Vite - I will re-investigate this!

@sdkennedy2

tyffical and others added 5 commits October 1, 2026 13:23
…custom-credentials-local-resolution"

This reverts commit f2482b4, reversing
changes made to 27f4f34.
…env-guard-hardening"

This reverts commit 27f4f34, reversing
changes made to 645fb5c.
…secret-store-parity"

This reverts commit 645fb5c, reversing
changes made to 4123316.
envFile: false / envPrefix: [] block Vite's own build-time
.env-file/import.meta.env machinery from copying a VITE_-prefixed real
process.env value, or a value from a build-root .env file, straight into
the production backend bundle. This has nothing to do with local
execution's runtime process.env scoping — it protects the same thing
Vite's own docs warn about (define/import.meta.env being statically
inlined at build time) and was dropped as unrelated collateral damage
when #504 was reverted wholesale.
…by the revert

The wholesale revert of #504 re-inlined getSharedContext's registry
lookup without the protections its deleted helper provided:

- The lookup is an own-property check, so a value inherited from net's
  prototype chain can't be mistaken for an installed entry and skip
  real installation.
- The registry stores a frozen isActive()/run() facade instead of the
  raw AsyncLocalStorage, so code with require('net') can't .disable()
  it or reassign its methods.
- Shared-context keys are versioned, so a copy from another plugin
  release (which may store a raw AsyncLocalStorage under the old keys)
  can't make this one throw at load. The install marker stays
  unversioned so the other copy's non-configurable accessors are
  recognized instead of redefined.

Also restores coverage the revert dropped (the action-catalog
typed-wrapper toJSON() exfiltration test and the full-$ credential
exposure scan), adds tests pinning adapter registration outside the
blocked scope (its loadModule() is Vite's own resolution, not customer
code) and skipped entirely for an execution abandoned during its own
module load, restores the busy-loop resilience test's timing margins and the
config-hook test's cast-free helper, and
updates comments still describing the reverted mechanisms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tyffical
tyffical force-pushed the tiffany.trinh/apps-2792-revert-custom-credentials-file branch from 9ec51a0 to 8ff610f Compare October 1, 2026 17:26
…2792-revert-custom-credentials-file

# Conflicts:
#	packages/plugins/apps/src/vite/index.ts
@datadog-datadog-us1-prod

datadog-datadog-us1-prod 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: f58889c | Docs | View more details | Give us feedback!

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

tyffical commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@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: 127af80ef7

ℹ️ 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 on lines +95 to +98
const frontendAssets = assets
.filter((asset) => !generatedPaths.has(path.resolve(asset.absolutePath)))
.filter((asset) => !backendPaths.has(asset.absolutePath));
const credentialsIdentity = await resolveCredentialsIdentity(buildRoot);
const nonCredentialsAssets = (
await Promise.all(
candidateAssets.map(async (asset) => ({
asset,
isCredentialsAsset: await isCustomCredentialsAsset(
asset.absolutePath,
credentialsIdentity,
),
})),
)
).filter(({ isCredentialsAsset }) => !isCredentialsAsset);
const frontendAssets = nonCredentialsAssets.map(({ asset }) => ({
...asset,
relativePath: `frontend/${asset.relativePath}`,
}));
.filter((asset) => !backendPaths.has(asset.absolutePath))
.map((asset) => ({

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep excluding legacy local credential files

Projects upgrading from the previous release may still contain the documented datadog-app.local.json with real secrets, and when apps.include matches JSON files this now maps that file directly into frontend/datadog-app.local.json in the deployable archive. Removing the credential resolver should not remove the packaging denylist for this legacy filename (including aliases such as symlinks/hardlinks), or an otherwise routine upgrade and build can upload credentials.

Useful? React with 👍 / 👎.

@tyffical tyffical Oct 1, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not changing this. Only the 3.4.0-dev.1 prerelease (npm dev tag) ever read datadog-app.local.json, so the maintainers decided on this PR to drop the name-based protections for it rather than keep them indefinitely. A leftover copy reaches the package only if the project's own apps.include matches it.

🤖 Addressed by Claude Code

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Module-initialization access to the ambient environment remains untested, and one test name needs correction.

Review effort: Balanced
Findings: 1 Medium severity · 2 Low severity

Open (3)

Comment thread packages/plugins/apps/src/vite/local-execution.test.ts Outdated
Comment thread packages/plugins/apps/src/vite/local-execution.test.ts Outdated
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tyffical

tyffical commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

@sdkennedy2

@sdkennedy2 sdkennedy2 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verified the feedback: the datadog-app.local.json guards, warning, and archive exclusion have been removed. Backend env-file and env-inlining build protections remain. Standard .env support is handled separately in the stacked follow-up #539. The focused build-config and local-execution suites pass (106 tests), and CI unit tests, end-to-end tests, and linting are green.

@tyffical

tyffical commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

/merge

@gh-worker-devflow-routing-ef8351

gh-worker-devflow-routing-ef8351 Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

View all feedbacks in Devflow UI.

2026-10-01 21:51:00 UTC ℹ️ Start processing command /merge


2026-10-01 21:51:04 UTC ℹ️ MergeQueue: pull request added to the queue

The expected merge time in master is approximately 2m (p90).


2026-10-01 21:52:39 UTC ℹ️ MergeQueue: This merge request was merged

@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot merged commit e9dbf23 into master Oct 1, 2026
9 checks passed
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot deleted the tiffany.trinh/apps-2792-revert-custom-credentials-file branch October 1, 2026 21:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants