Skip to content

fix: resolve process.env variables in global environment level#7600

Open
abhishek-bruno wants to merge 3 commits intousebruno:mainfrom
abhishek-bruno:fix/global-env-process-env-resolution
Open

fix: resolve process.env variables in global environment level#7600
abhishek-bruno wants to merge 3 commits intousebruno:mainfrom
abhishek-bruno:fix/global-env-process-env-resolution

Conversation

@abhishek-bruno
Copy link
Copy Markdown
Member

@abhishek-bruno abhishek-bruno commented Mar 27, 2026

Description

  • Fix process.env variable resolution in the global environment editor UI — tooltip/preview now correctly shows resolved values from workspace .env files
  • Fix process.env variable resolution at runtime for workspace-level (scratch pad) requests by mapping scratch collections to their workspace path

Root Cause

Two missing data connections:

  • The global environment editor passes collection={null} to EnvironmentVariablesTable, so getAllVariables() had no access to workspace process.env values
  • Scratch collections were never mapped to their workspace via setCollectionWorkspace, so getProcessEnvVars() couldn't find workspace .env values at runtime

Changes

EnvironmentVariablesTable — when collection is null, read processEnvVariables directly from the active workspace in Redux
mountScratchCollection — call renderer:set-collection-workspace to map scratch collection to workspace path

Fixes #7572

Contribution Checklist:

  • I've used AI significantly to create this pull request
  • The pull request only addresses one issue or adds one feature.
  • The pull request does not introduce any breaking changes
  • I have added screenshots or gifs to help explain the change if applicable.
  • I have read the contribution guidelines.
  • Create an issue and link to the pull request.

Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests.

Publishing to New Package Managers

Please see here for more information.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed resolution of {{process.env.X}} so workspace/global .env values are applied correctly in requests.
    • Ensured newly mounted workspace scratch collections are associated with their workspace so .env values resolve as expected.
  • Tests

    • Added end-to-end test and fixtures validating global .env / process.env resolution.
    • Added test selectors across environment UI and raw .env editor to support targeted testing.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Injects workspace-level process.env values into global (no-collection) environment rendering, registers scratch collections with their workspace via an IPC call to enable .env resolution across workspace/global scopes, adds UI test selectors, and adds Playwright E2E test + fixtures validating process.env resolution.

Changes

Cohort / File(s) Summary
Environment Variables UI
packages/bruno-app/src/components/EnvironmentVariablesTable/index.js
Read activeWorkspace from Redux and, when collection is falsy, inject _collection.workspaceProcessEnvVariables so MultiLineEditor can resolve {{process.env.X}}.
Workspace actions / IPC
packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js
During mountScratchCollection, call renderer:set-collection-workspace(scratchCollectionUid, workspace.pathname) when workspace.pathname exists to link scratch collections to workspaces for .env resolution.
Test selectors / Environments UI
packages/bruno-app/src/components/Environments/CollapsibleSection/index.js, .../DotEnvFileDetails/index.js, .../DotEnvFileEditor/DotEnvRawView.js, .../EnvironmentSelector/.../index.js, .../EnvironmentSettings/EnvironmentList/index.js, packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js
Add testId / data-testid attributes across environment-related components to enable reliable UI test targeting.
End-to-end tests & fixtures
tests/environments/global-env-process-env-resolution/*
Add fixtures, init user-data, a Bruno collection, and a Playwright spec that creates a workspace .env, saves MY_SECRET, and verifies a global environment variable using {{process.env.MY_SECRET}} resolves in a request response.

Sequence Diagram(s)

sequenceDiagram
    participant UI as Renderer UI
    participant Redux as Redux Store
    participant Main as Main (IPC)
    participant FS as Workspace/.env

    UI->>Redux: read state.workspaces.activeWorkspaceUid & workspaces
    Redux-->>UI: return activeWorkspace (includes processEnvVariables)
    UI->>UI: if collection == null → set _collection.workspaceProcessEnvVariables
    UI->>Main: renderer:add-collection-watcher(scratchCollectionUid)
    Main-->>UI: watcher registered
    UI->>Main: renderer:set-collection-workspace(scratchCollectionUid, workspace.pathname)
    Main->>FS: persist association / enable getProcessEnvVars lookup
    UI->>UI: render EnvironmentVariablesTable → MultiLineEditor resolves {{process.env.X}}
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • helloanoop
  • lohit-bruno
  • naman-bruno
  • bijin-bruno

Poem

🌱 Small IPC, a workspace hums along,
.env whispers secrets into variable song,
Tests click through editors, values bloom,
Redux hands the keys, UI lights the room,
A tiny change — end-to-end, all strong.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and specifically describes the main fix: enabling process.env variable resolution at the global environment level, which is the core objective.
Linked Issues check ✅ Passed Changes fully address issue #7572: EnvironmentVariablesTable now reads workspace processEnvVariables when collection is null [EnvironmentVariablesTable], and scratch collections are mapped to workspace paths [mountScratchCollection], enabling process.env resolution at global environment level and runtime.
Out of Scope Changes check ✅ Passed All changes directly support process.env resolution: core functionality changes, UI test attributes for end-to-end coverage, test fixtures, and a comprehensive Playwright test verifying the fix—no unrelated modifications present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/bruno-app/src/components/EnvironmentVariablesTable/index.js (1)

48-51: Consider combining selectors for efficiency.

The second selector runs .find() on every render. You could combine these into a single selector or use a memoized selector to avoid repeated array traversals.

♻️ Optional: combined selector
-  const activeWorkspaceUid = useSelector((state) => state.workspaces?.activeWorkspaceUid);
-  const activeWorkspace = useSelector((state) =>
-    state.workspaces?.workspaces?.find((w) => w.uid === activeWorkspaceUid)
-  );
+  const { activeWorkspaceUid, activeWorkspace } = useSelector((state) => {
+    const uid = state.workspaces?.activeWorkspaceUid;
+    return {
+      activeWorkspaceUid: uid,
+      activeWorkspace: state.workspaces?.workspaces?.find((w) => w.uid === uid)
+    };
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bruno-app/src/components/EnvironmentVariablesTable/index.js` around
lines 48 - 51, The code calls useSelector twice causing
state.workspaces.workspaces.find(...) to run on every render; replace with a
single memoized selector that returns the activeWorkspace along with/derived
from activeWorkspaceUid (or move the logic into a reselect selector in the
workspaces slice) so you only traverse the workspaces array once; update
references to activeWorkspaceUid and activeWorkspace to use the new selector (or
import the reselect selector) to avoid repeated .find() calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/bruno-app/src/components/EnvironmentVariablesTable/index.js`:
- Around line 48-51: The code calls useSelector twice causing
state.workspaces.workspaces.find(...) to run on every render; replace with a
single memoized selector that returns the activeWorkspace along with/derived
from activeWorkspaceUid (or move the logic into a reselect selector in the
workspaces slice) so you only traverse the workspaces array once; update
references to activeWorkspaceUid and activeWorkspace to use the new selector (or
import the reselect selector) to avoid repeated .find() calls.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4f483840-552e-48dc-9eaa-2ff6d4be7839

📥 Commits

Reviewing files that changed from the base of the PR and between bef4b6b and dbcd51d.

📒 Files selected for processing (2)
  • packages/bruno-app/src/components/EnvironmentVariablesTable/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js

Copy link
Copy Markdown
Collaborator

@sanish-bruno sanish-bruno left a comment

Choose a reason for hiding this comment

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

PR Review

Found 2 issue(s): 0 major, 0 minor, 1 suggestion, 1 nit.

Summary

  • The fix correctly connects the missing data paths: populating workspaceProcessEnvVariables on _collection when collection is null, and mapping scratch collections to their workspace via renderer:set-collection-workspace.
  • The downstream getAllVariables function already supports workspaceProcessEnvVariables (merges it with processEnvVariables), so no changes are needed there.
  • The IPC handler renderer:set-collection-workspace exists and is already used for non-scratch collections — extending it to scratch collections is the right approach.
  • Overall a clean, well-scoped fix.

@sanish-bruno
Copy link
Copy Markdown
Collaborator

@abhishek-bruno is it possible to have playwright test cases for this?

@pull-request-size pull-request-size bot added size/L and removed size/S labels Mar 31, 2026
@abhishek-bruno abhishek-bruno force-pushed the fix/global-env-process-env-resolution branch from 40f6e44 to 6d747d8 Compare April 2, 2026 13:24
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js (1)

1004-1007: ⚠️ Potential issue | 🟡 Minor

Avoid aborting scratch mount when workspace mapping IPC fails.

At Line 1006, if renderer:set-collection-workspace throws, execution never reaches Line 1009 (openScratchCollectionEvent), even though the watcher was already added at Line 998. Prefer making this mapping call non-blocking (log + continue) so mount flow completes.

Suggested defensive change
       // Map scratch collection to workspace so getProcessEnvVars can resolve workspace .env values
       if (workspace.pathname) {
-        await ipcRenderer.invoke('renderer:set-collection-workspace', scratchCollectionUid, workspace.pathname);
+        await ipcRenderer
+          .invoke('renderer:set-collection-workspace', scratchCollectionUid, workspace.pathname)
+          .catch((error) => {
+            console.error('Failed to map scratch collection to workspace:', error);
+          });
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js`
around lines 1004 - 1007, The ipc call
ipcRenderer.invoke('renderer:set-collection-workspace', scratchCollectionUid,
workspace.pathname) can throw and currently aborts the scratch mount before
openScratchCollectionEvent runs; wrap that invoke in a try/catch so a failure
only logs the error (including scratchCollectionUid and workspace.pathname) and
does not rethrow, allowing openScratchCollectionEvent and the existing watcher
logic to proceed; ensure logging uses the same logger used elsewhere and keep
the mapping attempt non-blocking (no await that blocks critical flow) so mount
completes even if mapping fails.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js`:
- Around line 1004-1007: The ipc call
ipcRenderer.invoke('renderer:set-collection-workspace', scratchCollectionUid,
workspace.pathname) can throw and currently aborts the scratch mount before
openScratchCollectionEvent runs; wrap that invoke in a try/catch so a failure
only logs the error (including scratchCollectionUid and workspace.pathname) and
does not rethrow, allowing openScratchCollectionEvent and the existing watcher
logic to proceed; ensure logging uses the same logger used elsewhere and keep
the mapping attempt non-blocking (no await that blocks critical flow) so mount
completes even if mapping fails.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9d81ef28-3dec-4b51-a47d-ab9cd8ab91eb

📥 Commits

Reviewing files that changed from the base of the PR and between 40f6e44 and 6d747d8.

📒 Files selected for processing (13)
  • packages/bruno-app/src/components/EnvironmentVariablesTable/index.js
  • packages/bruno-app/src/components/Environments/CollapsibleSection/index.js
  • packages/bruno-app/src/components/Environments/DotEnvFileDetails/index.js
  • packages/bruno-app/src/components/Environments/DotEnvFileEditor/DotEnvRawView.js
  • packages/bruno-app/src/components/Environments/EnvironmentSelector/EnvironmentListContent/index.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js
  • tests/environments/global-env-process-env-resolution/fixtures/collection/bruno.json
  • tests/environments/global-env-process-env-resolution/fixtures/collection/echo-post.bru
  • tests/environments/global-env-process-env-resolution/global-env-process-env-resolution.spec.ts
  • tests/environments/global-env-process-env-resolution/init-user-data/collection-security.json
  • tests/environments/global-env-process-env-resolution/init-user-data/global-environments.json
  • tests/environments/global-env-process-env-resolution/init-user-data/preferences.json
✅ Files skipped from review due to trivial changes (9)
  • packages/bruno-app/src/components/Environments/DotEnvFileDetails/index.js
  • packages/bruno-app/src/components/Environments/DotEnvFileEditor/DotEnvRawView.js
  • tests/environments/global-env-process-env-resolution/fixtures/collection/bruno.json
  • packages/bruno-app/src/components/Environments/EnvironmentSelector/EnvironmentListContent/index.js
  • tests/environments/global-env-process-env-resolution/init-user-data/preferences.json
  • tests/environments/global-env-process-env-resolution/init-user-data/collection-security.json
  • tests/environments/global-env-process-env-resolution/fixtures/collection/echo-post.bru
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js
  • tests/environments/global-env-process-env-resolution/init-user-data/global-environments.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/bruno-app/src/components/EnvironmentVariablesTable/index.js
  • packages/bruno-app/src/components/Environments/CollapsibleSection/index.js
  • tests/environments/global-env-process-env-resolution/global-env-process-env-resolution.spec.ts

…Table

- Added logic to populate process environment variables from the active workspace when no collection is selected, allowing for proper resolution of {{process.env.X}}.
- Updated workspace actions to map scratch collections to their respective workspaces, ensuring that environment variables can be resolved correctly.

This improves the user experience by providing access to workspace-specific environment variables in the environment variables table.
- Refactored the state selection logic in EnvironmentVariablesTable for clarity.
- Added data-testid attributes to various components including CollapsibleSection, DotEnvFileDetails, DotEnvRawView, and EnvironmentList to enhance testability.
- This change aims to streamline component interactions and facilitate easier testing.
- Introduced data-testid attributes to the EnvironmentList component, enhancing the ability to target elements in tests.
- This update includes test IDs for the CollapsibleSection, create .env file button, and the input field for the .env name, facilitating better integration with testing frameworks.
@abhishek-bruno abhishek-bruno force-pushed the fix/global-env-process-env-resolution branch from ba048bb to e6aa1e8 Compare April 3, 2026 07:24
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/environments/global-env-process-env-resolution/global-env-process-env-resolution.spec.ts (1)

54-56: Consider using data-testid for the environment indicator.

The .current-environment CSS class selector works, but data-testid provides better resilience against styling refactors.

♻️ Suggested improvement
 await test.step('Verify global environment is active', async () => {
-  await expect(page.locator('.current-environment')).toContainText('ProcessEnv Test');
+  await expect(page.getByTestId('current-environment')).toContainText('ProcessEnv Test');
 });

This would require adding data-testid="current-environment" to the corresponding element in the UI component.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tests/environments/global-env-process-env-resolution/global-env-process-env-resolution.spec.ts`
around lines 54 - 56, Replace the brittle CSS selector '.current-environment'
with a stable test id: add data-testid="current-environment" to the UI element
that renders the environment indicator, then update the test step that uses
page.locator('.current-environment') (in the test named "Verify global
environment is active") to target the test id (e.g., using
page.locator('[data-testid="current-environment"]' or getByTestId) and keep the
same expect toContainText('ProcessEnv Test').
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@tests/environments/global-env-process-env-resolution/global-env-process-env-resolution.spec.ts`:
- Around line 54-56: Replace the brittle CSS selector '.current-environment'
with a stable test id: add data-testid="current-environment" to the UI element
that renders the environment indicator, then update the test step that uses
page.locator('.current-environment') (in the test named "Verify global
environment is active") to target the test id (e.g., using
page.locator('[data-testid="current-environment"]' or getByTestId) and keep the
same expect toContainText('ProcessEnv Test').

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 66617b5b-d13a-43f4-bbec-aabfa8974ed5

📥 Commits

Reviewing files that changed from the base of the PR and between ba048bb and e6aa1e8.

📒 Files selected for processing (14)
  • packages/bruno-app/src/components/EnvironmentVariablesTable/index.js
  • packages/bruno-app/src/components/Environments/CollapsibleSection/index.js
  • packages/bruno-app/src/components/Environments/DotEnvFileDetails/index.js
  • packages/bruno-app/src/components/Environments/DotEnvFileEditor/DotEnvRawView.js
  • packages/bruno-app/src/components/Environments/EnvironmentSelector/EnvironmentListContent/index.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js
  • tests/environments/global-env-process-env-resolution/fixtures/collection/bruno.json
  • tests/environments/global-env-process-env-resolution/fixtures/collection/echo-post.bru
  • tests/environments/global-env-process-env-resolution/global-env-process-env-resolution.spec.ts
  • tests/environments/global-env-process-env-resolution/init-user-data/collection-security.json
  • tests/environments/global-env-process-env-resolution/init-user-data/global-environments.json
  • tests/environments/global-env-process-env-resolution/init-user-data/preferences.json
✅ Files skipped from review due to trivial changes (10)
  • packages/bruno-app/src/components/Environments/EnvironmentSelector/EnvironmentListContent/index.js
  • packages/bruno-app/src/components/Environments/DotEnvFileEditor/DotEnvRawView.js
  • tests/environments/global-env-process-env-resolution/fixtures/collection/bruno.json
  • packages/bruno-app/src/components/Environments/DotEnvFileDetails/index.js
  • tests/environments/global-env-process-env-resolution/init-user-data/preferences.json
  • tests/environments/global-env-process-env-resolution/fixtures/collection/echo-post.bru
  • tests/environments/global-env-process-env-resolution/init-user-data/collection-security.json
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js
  • tests/environments/global-env-process-env-resolution/init-user-data/global-environments.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js
  • packages/bruno-app/src/components/Environments/CollapsibleSection/index.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot use process.env at global environment level

2 participants