Skip to content

fix(cli): fail when --secrets-file can't be read or parsed - #67

Merged
aledbf merged 2 commits into
mainfrom
secrets-file-errors
Nov 13, 2026
Merged

aledbf merged 2 commits into
mainfrom
secrets-file-errors

Conversation

@aledbf

@aledbf aledbf commented Nov 13, 2026

Copy link
Copy Markdown
Member

Problem. A missing or unparsable --secrets-file was ignored: up, run-user-commands and build ran with no secrets injected or masked and could exit 0. (build with a Dockerfile did fail, but with a different message, and its Feature build dropped the secrets.)

Reference (TS readSecretsFromFile). It throws ContainerError({description: 'Failed to read/parse secrets'}); up and run-user-commands then print an error result and exit 1, before looking for the configuration.

Now (Go = TS)

  • Missing file: {"outcome":"error","message":"ENOENT: no such file or directory, open '<path>'","description":"Failed to read/parse secrets"}, exit 1. Other read errors use Node's wording.
  • Parse error: the same result with "message":"Invalid json data".
  • Parsed as jsonc.parse: comments and any JSON value are accepted; trailing commas, a BOM, an empty file, trailing data and unquoted keys are rejected. I checked these against jsonc-parser 3.3.1.
  • Values become env vars as JS String() makes them, in JS key order.
  • Masking follows Object.values(...).filter(v => v.length), including TS's failure on a null value.
  • No flag still means no secrets.
  • build --secrets-file (Go-only) fails the same way; docs/go-only-features.md says so.

Tests

  • 8 hermetic parity cases (4 each for up and run-user-commands): missing, invalid JSON, JSONC with non-string values, null value. 6 fail with the pre-change binary; the 2 JSONC cases also passed before, because the file was silently dropped.
  • secrets_cmd_test.go: exact output and exit code for the three commands.
  • secrets_held_test.go and secrets_repo_held_test.go asserted nil for a missing file and bad JSON, which codified the bug; they now assert the error contract.

Known remaining differences (unchanged): a non-string secret with --dotfiles-repository crashes TS (quoteValue) and not Go; a top-level string is split by rune, not by UTF-16 unit. Separately, secrets vs remoteEnv precedence (TS lets secrets win) will be a follow-up PR.

Validation (local)

  • task lint, task spec:compliance: pass.
  • task test:race with TMPDIR outside /tmp: pass.
  • task parity:contract: only the 2 known /tmp/.git cases fail.
  • TestE2E_UpSecretsFile: pass.
  • PARITY_COMMAND=up task parity:runtime: the 8 new cases pass. The failing cases, up.workspace-secrets-success among them, fail identically on main on this machine: Go treats /tmp as a git root because of a stray /tmp/.git, which changes remoteWorkspaceFolder. CI is the check for those.

🤖 Generated with Claude Code

aledbf and others added 2 commits November 12, 2026 21:23
A missing or unparsable --secrets-file was ignored: up,
run-user-commands and build ran with no secrets injected or masked and
could exit 0.

As the reference CLI's readSecretsFromFile, the file is now read once,
before anything else, and a failure ends the command with
{"outcome":"error","message":<Node's fs error or "Invalid json
data">,"description":"Failed to read/parse secrets"} and exit 1. The
file is parsed as jsonc.parse does: comments and any JSON value are
accepted, and trailing commas, a BOM and trailing data are not. Values
become env vars as JS String() makes them, in JS key order. build,
whose --secrets-file the reference lacks, fails the same way.

Eight hermetic parity cases compare the error and acceptance paths
with the reference for up and run-user-commands.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Order a secrets object's keys with the Features package's JS object
instead of a second copy of the array-index rules, write -0 as "0" as
String() does, and leave empty strings out of the values to mask, as
replaceAllLog's length filter does. Pin array-index boundaries, number
formatting and masking by length with cases computed by node from the
reference's jsonc-parser.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@aledbf
aledbf merged commit af38ca7 into main Nov 13, 2026
13 checks passed
@aledbf
aledbf deleted the secrets-file-errors branch November 13, 2026 01:38
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