fix: a repeated STACK key is an error
commit 14dda3a13d7e2fe821cb86d930e27c0250dec7e9 · parent 9cd6edf32e
· browse this tree
Ximianth, 2026-10-21 16:11:50 UTC
parse_stack let a later `ref`, `base`, or `tip` line silently replace an earlier one, so a STACK carrying two different refs was read as the last, and verify passed on it. Which value was meant can't be known, so FORMAT.md now says each key appears at most once, and parse_stack refuses a repeat by name. The check sits ahead of the per-key arms, so it covers every key without repeating itself per arm; an unrecognized key still dies on its first occurrence as before. The new fail-closed case failed before this change.
diff --git a/bin/patchette b/bin/patchette index cd4762e..54189a1 100755 --- a/bin/patchette +++ b/bin/patchette @@ -90,9 +90,9 @@ absdir() { ## - @param $1 path to the STACK file ## - @state STACK_REF, STACK_BASE, STACK_TIP, STACK_SERIES[] -- the parsed fields parse_stack() { - local f=$1 line mode=head + local f=$1 line mode=head key local oid='^[0-9a-f]{40}([0-9a-f]{24})?$' # SHA-1 or SHA-256, full and lowercase - declare -A seen=() + declare -A seen=() keys_seen=() STACK_REF='' STACK_BASE='' STACK_TIP='' STACK_SERIES=() while IFS= read -r line; do if [[ $mode == series ]]; then @@ -102,6 +102,9 @@ parse_stack() { STACK_SERIES+=("$line") continue fi + key=${line%% *} + [[ -z ${keys_seen[$key]:-} ]] || die "$f: duplicate $key line" + keys_seen[$key]=1 case $line in "ref "*) STACK_REF=${line#ref } ;; "base "*) diff --git a/docs/hacking/FORMAT.md b/docs/hacking/FORMAT.md index 99d14dc..07f9df8 100644 --- a/docs/hacking/FORMAT.md +++ b/docs/hacking/FORMAT.md @@ -97,6 +97,7 @@ fix-the-frobnicator-2 Several pieces of `key value` format data start the file, then a literal `series` line denotes the end of that section, and then one patch file name is per line, until EOF. +Each key appears at most once. Of the key value entries: diff --git a/tests/test-failclosed.sh b/tests/test-failclosed.sh index 92754d6..31a0164 100755 --- a/tests/test-failclosed.sh +++ b/tests/test-failclosed.sh @@ -86,6 +86,12 @@ sed -i 's/^tip .*/tip /' "$TAMPER/$fancy/STACK" EXPECT refusal "a tip line with no value is an error, not an absent tip" "tip is not a full commit ID" -- \ "$PATCHETTE" verify "$work/corpus/dev" "$TAMPER" +# A repeated STACK key is an error: which value is meant can't be known. +clone_layout dupkey +sed -i '1a ref refs/heads/other' "$TAMPER/$fancy/STACK" +EXPECT refusal "a repeated STACK key is an error" "duplicate ref line" -- \ + "$PATCHETTE" verify "$work/corpus/dev" "$TAMPER" + # A duplicate series entry is an error. clone_layout dupseries echo "note-to-self" >>"$TAMPER/$fancy/STACK"