Skip to content

fix: config:get --shell does not double-escape backslashes in single-quoted output - #3833

Merged
heroku-johnny merged 2 commits into
mainfrom
W-23597884
Jul 28, 2026
Merged

fix: config:get --shell does not double-escape backslashes in single-quoted output#3833
heroku-johnny merged 2 commits into
mainfrom
W-23597884

Conversation

@heroku-johnny

Copy link
Copy Markdown
Contributor

Summary

  • Bug: heroku config:get --shell double-escapes backslashes inside single-quoted output. A config value like foo\nbar (one literal backslash) was emitted as 'foo\\nbar', which the shell interprets as two backslashes, corrupting the value when the output is eval'd.

  • Root cause: src/lib/config/quote.ts:12 ran s.replaceAll(/(['\\])/g, String.raw\$1`)` before wrapping the string in single quotes. POSIX single-quoted strings are fully literal — backslashes have no special meaning and must not be escaped. The single-quote branch is only reached when the string contains no single quotes and no newlines, so there are nothing to escape at all.

  • Fix: Remove the replaceAll from the quote() single-quote branch (src/lib/config/quote.ts:12) and remove the compensating replaceAll('\\\\', '\\') from the parse() single-quote branch (src/lib/config/quote.ts:22) that was undoing the double-escaping on read-back.

  • Test: Updated test/unit/lib/config/quote.test.ts:11 to assert the correct (un-escaped) single-quoted output. Roundtrip tests continue to pass.

Fixes #1384
Fixes W-23597884

Changes

File Line Change
src/lib/config/quote.ts 12 Remove replaceAll from single-quote branch in quote()
src/lib/config/quote.ts 22 Remove replaceAll('\\\\', '\\') from single-quote branch in parse()
test/unit/lib/config/quote.test.ts 11 Update expected output for backslash-containing input to use un-escaped single quotes

Test plan

  • npm test -- --grep quote passes (quote/parse unit tests including roundtrip)
  • heroku config:set FOO='foo\nbar' then eval $(heroku config:get FOO --shell) yields a single backslash in $FOO

🤖 Generated with Claude Code

…quoted output

POSIX single-quoted strings treat all characters literally — backslashes
are NOT special and must NOT be escaped. The previous implementation ran
s.replaceAll(/(['\\])/g, String.raw\`\$1\`) on the value before wrapping
it in single quotes, so a literal backslash in a config value (e.g.
foo\nbar) was emitted as 'foo\\nbar', which the shell would interpret as
two characters, not one.

Because the single-quote branch is only reached when the string contains
no single quotes and no newlines, there are no special characters to
escape at all. The fix removes the replaceAll call entirely
(src/lib/config/quote.ts:12).

The corresponding parse() branch had a compensating
replaceAll('\\\\', '\\') to undo the double-escaping; that is also
removed since it is no longer needed and would incorrectly modify strings
that genuinely contain two consecutive backslashes
(src/lib/config/quote.ts:22).

Fixes #1384 (W-23597884)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@heroku-johnny
heroku-johnny requested a review from a team as a code owner July 27, 2026 19:15

@tlowrimore-heroku tlowrimore-heroku 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.

LGTM

@heroku-johnny
heroku-johnny merged commit bbf0d22 into main Jul 28, 2026
19 checks passed
@heroku-johnny
heroku-johnny deleted the W-23597884 branch July 28, 2026 17:15
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.

Outputting a Firebase private key in shell format adds unnecessary backslashes(\)

2 participants