From c67b10e45a6a9e02a28ef54cf71b50df5b585a04 Mon Sep 17 00:00:00 2001 From: darken Date: Tue, 12 May 2026 10:11:30 +0200 Subject: [PATCH 1/2] Fix extract_key to match bash double-quote escape grammar extract_key previously consumed every backslash as an escape and dropped it, so hand-edited values like USER="abc\xyz" (where \x is not in bash's recognized escape set) silently lost the backslash on migration. Match bash semantics: only consume the backslash when followed by \, ", $, or backtick; otherwise preserve it literally. --- helpers/migrate-config.sh | 19 ++++++++++--- test/migrate-config-test.sh | 57 +++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/helpers/migrate-config.sh b/helpers/migrate-config.sh index 946b248..fc89f2c 100755 --- a/helpers/migrate-config.sh +++ b/helpers/migrate-config.sh @@ -95,16 +95,27 @@ extract_key() { case "$raw" in '"'*) - # Double-quoted: handle \\, \", \$, \` escapes; reject if - # closing quote is missing. - local result="" i len=${#raw} escaped=0 closed=0 c + # Double-quoted: bash double-quote grammar only treats `\` as + # an escape when followed by `\`, `"`, `$`, or backtick. For + # any other character the backslash is preserved literally + # (so `USER="a\xb"` sources to the 4-byte value a\xb). Reject + # if the closing quote is missing. + local result="" i len=${#raw} escaped=0 closed=0 c next for (( i=1; i/dev/null || rc=$? + [[ "$rc" -ne 0 ]] || fail "escaped close-quote not rejected" + assert_file_eq "$before" "$f" "malformed file unchanged" + echo "PASS: extract_key rejects escaped close-quote (no real close)" +} + # --- MLAT_MARKER → MLAT_PRIVATE migration (co-emit, MLAT_MARKER preserved) --- test_marker_no_emits_private_true_alongside() { @@ -443,6 +497,9 @@ main() { test_missing_file_is_noop test_backup_not_overwritten test_crlf_tolerated + test_extract_key_preserves_literal_backslash + test_extract_key_resolves_recognized_escapes + test_extract_key_escaped_close_quote_no_real_close test_marker_no_emits_private_true_alongside test_marker_yes_emits_private_false_alongside test_marker_uppercase_tolerated From bf370858b2d648ec7001d8bb51162404abd4f0ba Mon Sep 17 00:00:00 2001 From: darken Date: Tue, 12 May 2026 10:18:57 +0200 Subject: [PATCH 2/2] Note single-line-only parser scope in extract_key comment --- helpers/migrate-config.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/helpers/migrate-config.sh b/helpers/migrate-config.sh index fc89f2c..1bdd280 100755 --- a/helpers/migrate-config.sh +++ b/helpers/migrate-config.sh @@ -99,7 +99,10 @@ extract_key() { # an escape when followed by `\`, `"`, `$`, or backtick. For # any other character the backslash is preserved literally # (so `USER="a\xb"` sources to the 4-byte value a\xb). Reject - # if the closing quote is missing. + # if the closing quote is missing. Note: this parser is + # single-line; line-continuation (`\` + newline) is not + # supported — multi-line values are out of scope for the + # boot-config file format. local result="" i len=${#raw} escaped=0 closed=0 c next for (( i=1; i