From 011ee80067df9a2281811d09efc0b79181f4f970 Mon Sep 17 00:00:00 2001 From: Dai Ha Date: Sat, 3 Oct 2026 16:02:50 +0200 Subject: [PATCH] fleetd #656: add regression tests for the two cases #639's redact() fix covers Criterion 19 covers a block-scalar body whose key line falls outside diff -u's default 3-line context (an 8-line body with only the 6th line changed). Criterion 20 covers a blank line inside the value, which used to reset the old indentation-anchored mask. Both are RED against the pre-#639 redact() (git show 28ea0de) and GREEN against the current one; each asserts both the secret's absence and a non-secret control line's presence. --- scripts/test-config-edit.sh | 88 +++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/scripts/test-config-edit.sh b/scripts/test-config-edit.sh index 1f3b9dc..56695d0 100755 --- a/scripts/test-config-edit.sh +++ b/scripts/test-config-edit.sh @@ -474,6 +474,90 @@ test_passphrase_key_is_redacted() { assert_not_contains "FAKELEAK-PASSPHRASE" "$RUN_OUTPUT" "passphrase case: the passphrase VALUE must never leak" } +# ------------------- acceptance criterion 19: the key line falls outside the printed hunk +# fleetd #656 — criteria 15a/15b both put the edit right next to the key line, so the key line is +# always inside diff -u's default 3-line context. Neither covers the actual case #639 fixed: an +# 8-line block-scalar body with only its SIXTH line changed, so the printed hunk (3 lines of +# context on each side of the change) covers body lines 3-8 and never includes the "token:" key +# line at all. The old, line-by-line redact() only ever masks after it has SEEN the key line go +# past; with the key line outside the hunk it never sets its mask, and the whole body — the +# changed line included — passes through raw. The control key sits right after the body, inside +# the same hunk, so the positive control below proves the fix is not simply printing nothing. +new_fixture_hunk_without_key_line() { + local dir + dir="$(mktemp -d "$TMP/fixture.XXXXXX")" + cat > "$dir/fleetd.yaml" <<'YAML' +bind: + host: 127.0.0.1 + port: 19999 +broker: + uri: amqp://user:hunter2@host/vhost +auth: + token: | + SECRET-LINE-1 + SECRET-LINE-2 + SECRET-LINE-3 + SECRET-LINE-4 + SECRET-LINE-5 + SECRET-LINE-6 + SECRET-LINE-7 + SECRET-LINE-8 + control: CTRL-MUST-APPEAR +profiles: + sonnet: + weight: 3 + maxLoad: 5 +YAML + : > "$dir/fleetd.out" + printf '%s' "$dir" +} + +test_key_line_outside_hunk_is_still_redacted() { + local dir + dir="$(new_fixture_hunk_without_key_line)" + sed 's/SECRET-LINE-6$/SECRET-LINE-6-CHANGED/' "$dir/fleetd.yaml" > "$dir/candidate.yaml" + + start_run "$dir" 5 --from "$dir/candidate.yaml" + sleep 1 + printf 'config reloaded\n' >> "$dir/fleetd.out" + collect_run "$dir" + + assert_equals 0 "$RUN_RC" "hunk-without-key-line case reload exit code" + # Positive control FIRST: without this, a diff that printed nothing at all would pass the + # negative assertion right below identically to a correctly redacted one. + assert_contains "CTRL-MUST-APPEAR" "$RUN_OUTPUT" "hunk-without-key-line case: the non-secret control line must still print unmasked" + assert_not_contains "SECRET-LINE-6-CHANGED" "$RUN_OUTPUT" "hunk-without-key-line case: the changed body line must never leak, even with the key line outside the printed hunk" +} + +# ------------------------------- acceptance criterion 20: a blank line inside the value +# fleetd #656 — the old, line-by-line redact() reset its mask on any line whose indentation was +# not STRICTLY greater than the key's, and a wholly blank line has indentation 0, so it reset the +# mask exactly like the "control:" line that legitimately ends the block scalar. Everything after +# the blank line then printed raw. The current fix tracks masked lines by FILE line number instead +# of by indentation seen so far, so a blank line inside the value stays masked. +new_fixture_blank_line_in_value() { + local dir + dir="$(mktemp -d "$TMP/fixture.XXXXXX")" + printf 'bind:\n host: 127.0.0.1\n port: 19999\nbroker:\n uri: amqp://user:hunter2@host/vhost\nauth:\n token: |\n LEAK-BEFORE-BLANK\n\n LEAK-AFTER-BLANK\n control: CTRL-MUST-APPEAR\nprofiles:\n sonnet:\n weight: 3\n maxLoad: 5\n' > "$dir/fleetd.yaml" + : > "$dir/fleetd.out" + printf '%s' "$dir" +} + +test_blank_line_inside_value_is_still_redacted() { + local dir + dir="$(new_fixture_blank_line_in_value)" + sed 's/LEAK-AFTER-BLANK$/LEAK-AFTER-BLANK-CHANGED/' "$dir/fleetd.yaml" > "$dir/candidate.yaml" + + start_run "$dir" 5 --from "$dir/candidate.yaml" + sleep 1 + printf 'config reloaded\n' >> "$dir/fleetd.out" + collect_run "$dir" + + assert_equals 0 "$RUN_RC" "blank-line-in-value case reload exit code" + assert_contains "CTRL-MUST-APPEAR" "$RUN_OUTPUT" "blank-line-in-value case: the non-secret control line must still print unmasked" + assert_not_contains "LEAK-AFTER-BLANK-CHANGED" "$RUN_OUTPUT" "blank-line-in-value case: the line after the blank must never leak" +} + # ----------------------------------- acceptance criterion 16: a failing --set must not echo value # fleetd #635 follow-up (ticket comment 17673, defect 8) — apply_set_pairs used to echo the FULL # "$kv" (path=value, exactly as typed) in its yq-failure messages, so a broken --set with a @@ -624,6 +708,10 @@ echo "== acceptance criterion 15a: a block scalar's continuation lines are redac test_block_scalar_continuation_is_redacted echo "== acceptance criterion 15b: a passphrase key is also recognised ==" test_passphrase_key_is_redacted +echo "== acceptance criterion 19: the key line falls outside the printed hunk ==" +test_key_line_outside_hunk_is_still_redacted +echo "== acceptance criterion 20: a blank line inside the value ==" +test_blank_line_inside_value_is_still_redacted echo "== acceptance criterion 16: a failing --set must not echo its value ==" test_failing_set_does_not_echo_its_value echo "== extra: dry-run never installs, and redacts =="