Skip to content

feat: keep a .env's comments with the variables they describe - #6

Open
ilmakio wants to merge 1 commit into
fix/env-write-fidelityfrom
feat/env-layout-preservation
Open

ilmakio wants to merge 1 commit into
fix/env-write-fidelityfrom
feat/env-layout-preservation

Conversation

@ilmakio

@ilmakio ilmakio commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Stacked on #5 — review that one first; this PR's diff is against fix/env-write-fidelity.

Why

Importing a .env flattened every comment in the file into one notes block. The note explaining a variable ended up several screens away from the variable, and a file with section banners came out as an unreadable wall of text. Copying the item back out was worse: the document was regenerated from the item's fields — keys in the item's order, every value quoted, no comments — which for a file somebody maintains by hand is simply a different file.

Reported by a user who keeps his .env files commented per variable and wanted to move one to another machine with its notes intact. He also uses the stripped form, because some tools discard comments anyway — so this is two outputs, not one setting.

How

An item now stores the shape of the .env it came from and no values: comments, blank lines, ordering, indentation, export prefixes, the quoting each value had, and which values were written across several lines. A value lives in exactly one place — its field — so the layout can never become a stale second copy of a secret. Rendering a document means putting the current fields back into the owner's own file, which needs no access to that file: it works from a backup, on another Mac, and when the original is gone.

  • Copy .env reproduces the file. Copy .env Values Only (⇧⌥⌘E, and in the copy menu / command palette) keeps the previous keys-and-values output.
  • The detail pane reads the comments the way the file does: a banner block followed by a blank line becomes a heading, a block sitting above a run of variables introduces that run, and a # note after a value appears under that value. Getting this reading wrong could only ever misplace a comment on screen — the file itself is reproduced from the stored lines, never from this interpretation of them.
  • The layout is captured on import, on every pull, and when a file is linked. Linking (or re-linking) is how an item imported by an earlier version picks up its formatting.
  • Pulling a file no longer overwrites the item's notes. It used to replace them with the file's comments flattened together, which could take away notes the owner had written themselves.
  • A variable the item no longer holds renders as no line at all, rather than as an empty assignment that would read as "deliberately emptied". One added in PassStore is appended.
  • An empty value keeps the bare KEY= form where that is what the file used.

envContents — what the sync digests are computed from — deliberately stays values-only. Making it layout-aware would have made every already-linked item look like it had changed the moment this shipped, and invited a push nobody asked for.

Compatibility

envLayout is a new optional field on the item snapshot, decoded with decodeIfPresent. Vaults written by earlier versions load with no layout and behave exactly as before. Structural size is capped with the rest of the vault's resource limits.

Tests

New EnvLayoutTests / EnvLayoutIntegrationTests: byte-for-byte reproduction of a realistic commented file (banners, indented export, single quotes, a trailing comment, an empty value, a wrapped PEM key); a changed value altering exactly one line; a removed variable leaving no stale line; an added one appended; a wrapped value staying wrapped; the comment-to-variable reading; layout surviving a snapshot round-trip; an older snapshot decoding without one; copy-after-import returning the original file; a pull leaving notes alone; linking teaching an older item its formatting; and editing or duplicating an item keeping it.

Importing a `.env` flattened every comment in it into one notes block, so
the note explaining a variable ended up several screens away from it, and
copying the item back out produced a document regenerated from its fields:
keys in the item's order, every value quoted, no comments at all. For a file
somebody maintains by hand, that is not the same file.

An item now stores the shape of the `.env` it came from — comments, blank
lines, ordering, indentation, `export` prefixes, quoting, and which values
were written across several lines — and no values at all. A value lives only
in its field, so the layout cannot become a stale second copy of a secret,
and rendering means putting the current fields back into the owner's own
file. It needs no access to the file, so it works from a backup and on
another Mac.

- Copy .env now reproduces that file. Copy .env Values Only (⇧⌥⌘E) keeps the
  keys-and-values form for anything that strips comments anyway.
- The detail pane reads the comments the way the file does: banner blocks
  become headings, a block above a run of variables introduces that run, and
  a `# note` after a value sits under that value.
- The layout is captured on import, on every pull, and when a file is linked,
  which is how an item imported by an earlier version picks it up.
- Pulling a file no longer overwrites the item's notes. Notes are the
  owner's; the file's comments have somewhere better to live now.
- A variable the item no longer holds renders as no line at all rather than
  as an empty assignment, and one added in PassStore is appended.
- An empty value keeps the bare `KEY=` form when that is what the file used.

Vaults written by earlier versions decode with no layout and behave exactly
as they did.
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