Skip to content

feat(secrets): version-adaptive .env editor in the application editor#1409

Open
dawsontoth wants to merge 2 commits into
stagefrom
feat/env-file-editor
Open

feat(secrets): version-adaptive .env editor in the application editor#1409
dawsontoth wants to merge 2 commits into
stagefrom
feat/env-file-editor

Conversation

@dawsontoth

Copy link
Copy Markdown
Contributor

Base of a stacked pair (the cluster-secrets slice sits on top in #1402). Everything this PR needs is already released in Harper: .env masking + key-level ops merged in HarperFast/harper#1527, and pre-5.2 versions work through the existing whole-file operations — so this can ship independently and quickly.

What

Secret-bearing .env files (duck-typed by basename at any depth, case-insensitive — .env, .env.local, .ENV.production; templates like .env.example / .sample / .template keep the plain text editor, matching core's exemptions) now open in a managed secrets panel instead of raw Monaco, so values aren't flashed on screen or clobbered by accident.

The panel adapts to the connected Harper by the shape of the get_component_file response, not a version check:

  • Plaintext mode (pre-5.2, raw text returned): keys/values parsed client-side; values masked behind a per-row click-to-reveal (a deliberate action); add/edit/delete rewrite the whole file through the existing set_component_file — merge-preserving (comments, formatting, untouched keys stay byte-for-byte). An "Edit as text" escape hatch keeps raw Monaco available.
  • Protected mode (>= 5.2, protected: true + masked message): key names only, nothing revealable, no raw editing (saving the masked rendering would destroy the real values — a footgun the plain editor would have had on 5.2); writes go through the key-level set_env_value / delete_env_value operations, whose responses update the key list without a refetch.

Pieces

  • lib/env/envFile.ts — browser-safe port of core's utility/envFile.ts (dotenv-16 parse semantics, quote-aware merge-preserving upsert/remove), with core's test suite ported, so plaintext-mode edits produce exactly the file 5.2's server-side ops would.
  • integrations/api/instance/applications/envValues.tsset_env_value / delete_env_value hooks; get_component_file's response type gains the protected / keys fields.
  • features/instance/applications/components/EnvEditorView/ — the panel + dispatch from ContentViewer; .env files get a key icon in the sidebar.
  • features/instance/secrets/ — shared SecretsManager / SecretModals (masked table, click-to-reveal, add/edit dialogs with injected copy/persistence). The stacked cluster-secrets PR reuses these. Includes a fix for a latent react-hook-form subscription bug: a pasted value left Save permanently disabled because isValid was never read while the form was pristine.

Verification

  • tsc, oxlint, dprint clean; full suite green (1079 tests, 43 new: core's ported envFile suite + EnvEditorView component tests asserting the exact operation payloads in both modes).
  • Plaintext mode click-tested live against a running Studio on a real Fabric cluster (.env in an application): masked table, reveal/hide toggle, edit dialog revealing the current value only on demand (Save stays disabled until an actual change), raw-editor round-trip.
  • Protected mode is covered by the component tests (no 5.2 instance available yet to click-test).

🤖 Generated with Claude Code

Secret-bearing .env files (duck-typed by basename, at any depth; template
files like .env.example keep the plain text editor) now open in a managed
secrets panel instead of raw Monaco, so values aren't flashed on screen or
clobbered by accident. The panel adapts to the connected Harper by the shape
of the get_component_file response, not a version gate:

- Plaintext (pre-5.2): keys/values parsed client-side with a per-row
  click-to-reveal; add/edit/delete rewrite the file through the existing
  set_component_file, merge-preserving via a browser-safe port of core's
  utility/envFile.ts (dotenv-16 semantics, Harper's test suite ported).
  An "Edit as text" escape hatch keeps the raw editor available.
- Protected (>= 5.2, harper#1527): key names only, nothing revealable, no
  raw editing (saving the masked rendering would destroy the real values);
  writes go through the new set_env_value / delete_env_value operations.

Includes the shared SecretsManager / SecretModals components (masked table,
click-to-reveal, add/edit dialogs) that the stacked cluster-secrets PR also
builds on, with a fix for a latent react-hook-form subscription bug (a
pasted value left Save permanently disabled because isValid was never read
while the form was pristine).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dawsontoth dawsontoth requested a review from a team as a code owner July 2, 2026 16:39
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@dawsontoth

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a dedicated secrets editor for .env files, providing a safer interface for managing environment variables by masking values and supporting key-level operations for protected files. The implementation includes a new EnvEditorView component, shared secret management modals, and robust utility functions for parsing and serializing .env files. The review feedback identified several improvements: using undefined instead of false for conditional hook arguments, improving the robustness of file path slicing, ensuring the EditSecretModal resets correctly via a unique key prop, and refining the regex used for quote stripping to avoid unintended multiline replacements.

Comment thread src/features/instance/secrets/SecretsManager.tsx
Comment thread src/lib/env/envFile.ts
…leak across secrets

Review feedback on #1409: makes the modal's reset invariant explicit
instead of relying on the dialog being modal (row clicks blocked while
open).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant