Skip to content

Fix env secrets being lost after pulling from server and saving - #1177

Merged
saeedvaziry merged 4 commits into
4.xfrom
fix-env-secrets-being-lost-prry9
Jun 20, 2026
Merged

Fix env secrets being lost after pulling from server and saving#1177
saeedvaziry merged 4 commits into
4.xfrom
fix-env-secrets-being-lost-prry9

Conversation

@saeedvaziry

@saeedvaziry saeedvaziry commented Jun 19, 2026

Copy link
Copy Markdown
Member

Make the live server .env file the source of truth when restoring masked secrets on save and pull, so
secrets that drifted out of band are no longer silently overwritten with a stale DB copy.

Summary by CodeRabbit

Release Notes

  • Refactor

    • Improved environment variable processing to preserve secret values from the live server when secret fields are submitted empty, and to keep secret status consistent.
    • Updated worker environment updates to follow the same secret-preservation rules.
  • Tests

    • Added/updated integration tests to verify only secret keys are stored, secret values are masked on read, and out-of-band secret rotations are respected during updates.
    • Expanded unit tests to cover live-based secret merge behaviour, including preservation vs non-preservation for empty values.

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 66bd706a-1a03-46ca-bf0d-245e74126ef7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Refactors env secret handling to store only secret key names instead of full variable metadata, and processes all env updates through the live server .env file. EnvParser gains secretKeys() and mergeWithLive() helpers to classify and restore empty secrets from the server. UpdateEnv validates against secret wiping and extracts secret keys for storage. Both controllers unify their display pipeline using parseclassifymaskSecrets. Worker env processing inlines the merge logic, and comprehensive tests verify secret persistence, out-of-band rotation detection, and guarded updates.

Changes

Env Secret Handling via Live Server File

Layer / File(s) Summary
EnvParser: secret classification and live-file merge
app/Helpers/EnvParser.php
secretKeys() extracts secret key lists from stored metadata (supporting legacy and simplified shapes). classify() applies those classifications to parsed variables. mergeWithLive() restores empty secret values from the live server file by key.
UpdateEnv: live-file-aware processing and secret guards
app/Actions/Site/UpdateEnv.php
resolveVariables() replaces processVariables(), parsing the live server .env and guarding against secret wiping when the file is unavailable. Merges with live content via mergeWithLive() and extracts secret keys for storage.
UpdateWorkerEnvironment: inlined merge logic
app/Actions/Worker/UpdateWorkerEnvironment.php
Removes EnvParser dependency and inlines stored-secret merge behaviour, building stored maps and enforcing secret status for empty incoming secret values whilst restoring stored values when applicable.
Unified controller env display pipeline
app/Http/Controllers/API/SiteController.php, app/Http/Controllers/ApplicationController.php
Both showEnv() and env() replace conditional branches with a single parseclassifymaskSecrets pipeline for consistent secret handling across all env display paths.
Site model: getEnv() path override parameter
app/Models/Site.php
getEnv() accepts optional $path parameter for env-file override. Docblock for env_variables updated to reflect that it stores only secret keys, with values remaining on the server.
API documentation for secret handling
public/api-docs/openapi/sites.yaml
OpenAPI schema clarifies that secret variables return empty values on read. Request and response examples demonstrate the pattern of submitting empty values whilst marking keys as secret to preserve server-side values.
Feature tests: secret persistence and live-file scenarios
tests/Feature/ApplicationTest.php, tests/Feature/WorkerEnvironmentTest.php
Tests verify: secret keys only stored in DB, secrets masked on read, legacy DB shapes supported, secrets persisted when empty, out-of-band server rotations detected, secrets not wiped by marking non-secret without value, secrets dropped with new values, pattern-detected secrets masked, raw env updates write verbatim without restoring, and updates abort when live file unavailable.
Unit tests: mergeWithLive and secretKeys helpers
tests/Unit/EnvParserTest.php
Tests verify mergeWithLive() restoration of empty secret values from live content, non-restoration of empty non-secret values, and correct handling of empty live input. Tests confirm secretKeys() normalises legacy and simplified stored shapes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: fixing env secrets being lost after pulling from server and saving, which is the core problem addressed by making the live server .env file the source of truth.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-env-secrets-being-lost-prry9

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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/Actions/Site/UpdateEnv.php`:
- Around line 66-67: The `existingVariables()` method at line 66 silently falls
back to database values when the live `.env` read fails (returning an empty
string on SSHError instead of throwing). This allows the logic at lines 77-83 to
restore stale masked secrets from the database, creating a security risk. Modify
`$site->getEnv()` to throw an exception on SSH errors instead of returning an
empty string, and ensure `existingVariables()` does not catch or suppress this
exception. This will allow the SSH error to bubble up to the caller and prevent
the silent fallback to stale database state.

In `@tests/Feature/ApplicationTest.php`:
- Around line 637-654: Remove the three inline comments from within the test
method body (the comments starting with "// Save a secret through Vito...", "//
The secret is rotated directly on the server...", and "// User pulls the env,
changes a non-secret field..."). Either move this documentation to the PHPDoc
block at the method level or remove it entirely to keep the test body code-only,
following the repository's PHP coding standard that prohibits inline comments
inside function/method bodies except for migrations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: efee6336-9082-413b-9315-0b101facada2

📥 Commits

Reviewing files that changed from the base of the PR and between 10b3a4a and 4ebab09.

📒 Files selected for processing (6)
  • app/Actions/Site/UpdateEnv.php
  • app/Helpers/EnvParser.php
  • app/Http/Controllers/API/SiteController.php
  • app/Http/Controllers/ApplicationController.php
  • tests/Feature/ApplicationTest.php
  • tests/Unit/EnvParserTest.php

Comment thread app/Actions/Site/UpdateEnv.php Outdated
Comment thread tests/Feature/ApplicationTest.php Outdated
@saeedvaziry
saeedvaziry marked this pull request as draft June 19, 2026 21:30
@saeedvaziry
saeedvaziry marked this pull request as ready for review June 20, 2026 07:44
@saeedvaziry

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/Actions/Site/UpdateEnv.php`:
- Around line 82-84: The issue is that Site::getEnv() silently catches SSHError
exceptions and returns an empty string, which causes guardAgainstWipingSecrets()
to fail protecting masked secrets like APP_KEY when the live read fails. Replace
the call to getEnv() with a method that does not swallow exceptions and allows
errors to bubble up (following the coding guideline of not silently suppressing
provider/service errors), or alternatively broaden the
guardAgainstWipingSecrets() method to detect and block every empty incoming
secret value when the live read is unavailable. Apply this same fix to both the
location at lines 82-84 and the similar code mentioned at lines 132-139.
- Around line 44-46: The write operation in UpdateEnv.php is re-stringifying
parsed environment variables using EnvParser::stringify($variables), which loses
the original formatting including comments, blank lines, and ordering. Instead
of stringifying the parsed variables at Line 46, preserve and write the raw
submitted .env content directly. Use the original raw environment submission
data (that is being parsed at Lines 105-109) when calling the server's write
method, rather than reconstructing it from the parsed variables array, so that
all original formatting and unparsed content remains intact.

In `@app/Http/Controllers/API/SiteController.php`:
- Around line 160-162: Extract the env display pipeline (the sequence of
EnvParser::parse, EnvParser::classify, and EnvParser::maskSecrets) from the
SiteController method into a new Action class. Create an Action (e.g.,
ProcessSiteEnvironmentVariables or similar) that accepts the raw env string and
site env_variables, performs the three-step transformation, and returns the
result. Then replace the three-line EnvParser chain in the controller with a
single call to this new Action, ensuring the controller only handles the HTTP
request/response while the business logic resides in the dedicated Action class.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bf00530d-5b1d-4bc3-be68-b4a717de80c4

📥 Commits

Reviewing files that changed from the base of the PR and between 4ebab09 and a836616.

📒 Files selected for processing (10)
  • app/Actions/Site/UpdateEnv.php
  • app/Actions/Worker/UpdateWorkerEnvironment.php
  • app/Helpers/EnvParser.php
  • app/Http/Controllers/API/SiteController.php
  • app/Http/Controllers/ApplicationController.php
  • app/Models/Site.php
  • public/api-docs/openapi/sites.yaml
  • tests/Feature/ApplicationTest.php
  • tests/Feature/WorkerEnvironmentTest.php
  • tests/Unit/EnvParserTest.php

Comment thread app/Actions/Site/UpdateEnv.php Outdated
Comment thread app/Actions/Site/UpdateEnv.php
Comment thread app/Http/Controllers/API/SiteController.php Outdated
@saeedvaziry
saeedvaziry merged commit eb3f625 into 4.x Jun 20, 2026
3 checks passed
@saeedvaziry
saeedvaziry deleted the fix-env-secrets-being-lost-prry9 branch June 20, 2026 08:31
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