From 8e071580eb68cfa3601b681a2a6889d55c2e8b80 Mon Sep 17 00:00:00 2001 From: navigator Date: Wed, 30 Sep 2026 02:22:59 +0000 Subject: [PATCH 1/3] fix: read apt's *** marker when the installed version is the candidate bt_policy_verdict looked for the candidate as the first field of its version line, but apt prints the installed version as ' *** 2.3.6+keel5 1001', so a current appliance, whose installed version is the candidate, failed the check. The gate never reached it until tracker#5 was fixed on 2026-09-30; its first run past the archive failed here. The old fixture wrote two lines where apt writes one; the new test uses apt's real output and fails on the old code. --- tests/boot-test.bats | 18 ++++++++++++++++++ tests/lib/boot-test-lib.sh | 7 ++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/boot-test.bats b/tests/boot-test.bats index 8dd37f8..776723d 100644 --- a/tests/boot-test.bats +++ b/tests/boot-test.bats @@ -606,6 +606,24 @@ EOF [ "$status" -eq 0 ] } +@test "policy_verdict reads apt's own layout for an installed candidate" { + # what apt-cache policy printed inside the appliance in the boot gate on + # 2026-09-30, once the gate could reach the archive (tracker#5): one line + # for the version, marked ***, and both of its sources under it + cat > "$S/policy" < "$S/policy" run bt_policy_verdict inithooks "$S/policy" diff --git a/tests/lib/boot-test-lib.sh b/tests/lib/boot-test-lib.sh index ff944f0..1658ddd 100644 --- a/tests/lib/boot-test-lib.sh +++ b/tests/lib/boot-test-lib.sh @@ -635,8 +635,13 @@ bt_policy_verdict() { echo "boot-test: $BT_ARCHIVE_URI is not a source of $package at priority $BT_ARCHIVE_PIN" >&2 return 1 fi + # apt marks the installed version with *** in front of it, so when the + # candidate is what is installed (a current appliance) its line reads + # " *** 2.3.6+keel5 1001": the marker is dropped before comparing if ! awk -v version="$candidate" -v pin="$BT_ARCHIVE_PIN" \ - '$1 == version && $2 == pin { found = 1 } END { exit !found }' "$file"; then + '$1 == "***" { $1 = ""; $0 = $0 } + $1 == version && $2 == pin { found = 1 } END { exit !found }' \ + "$file"; then echo "boot-test: the candidate $package $candidate does not come from" \ "$BT_ARCHIVE_URI at priority $BT_ARCHIVE_PIN" >&2 return 1 From bbb3ce54d8da01c3b0b857ff30d48ce349615780 Mon Sep 17 00:00:00 2001 From: navigator Date: Wed, 30 Sep 2026 02:29:03 +0000 Subject: [PATCH 2/3] fix: the candidate's own version block must list our archive at our pin From the review of #13: the version line's number is the highest priority of its sources, so matching it proved nothing about where the candidate comes from; any repository claiming our origin gets our pin. The parse now requires ' ' inside the candidate's block, and a new test refuses an installed candidate from another source at the same pin. --- tests/boot-test.bats | 19 +++++++++++++++++++ tests/lib/boot-test-lib.sh | 18 ++++++++++++------ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/tests/boot-test.bats b/tests/boot-test.bats index 776723d..3ac33e4 100644 --- a/tests/boot-test.bats +++ b/tests/boot-test.bats @@ -624,6 +624,25 @@ EOF [[ "$output" == *"candidate 2.3.6+keel5"* ]] } +@test "policy_verdict refuses an installed candidate from another source at our pin" { + # a repository that calls itself our origin gets our pin too; the + # candidate must come from our archive, not merely share its priority + cat > "$S/policy" < "$S/policy" run bt_policy_verdict inithooks "$S/policy" diff --git a/tests/lib/boot-test-lib.sh b/tests/lib/boot-test-lib.sh index 1658ddd..71aca9b 100644 --- a/tests/lib/boot-test-lib.sh +++ b/tests/lib/boot-test-lib.sh @@ -635,13 +635,19 @@ bt_policy_verdict() { echo "boot-test: $BT_ARCHIVE_URI is not a source of $package at priority $BT_ARCHIVE_PIN" >&2 return 1 fi - # apt marks the installed version with *** in front of it, so when the - # candidate is what is installed (a current appliance) its line reads - # " *** 2.3.6+keel5 1001": the marker is dropped before comparing + # The candidate's own block of the version table has to list our archive + # at our pin: the number on a version line is only the highest priority + # of its sources, so it does not say which source the version comes + # from. apt marks the installed version with *** in front of it (a + # current appliance: " *** 2.3.6+keel5 1001"); the marker is dropped. if ! awk -v version="$candidate" -v pin="$BT_ARCHIVE_PIN" \ - '$1 == "***" { $1 = ""; $0 = $0 } - $1 == version && $2 == pin { found = 1 } END { exit !found }' \ - "$file"; then + -v uri="$BT_ARCHIVE_URI" ' + { if ($1 == "***") { $1 = ""; $0 = $0 } } + $1 == "Version" && $2 == "table:" { table = 1; next } + !table { next } + NF == 2 && $2 ~ /^-?[0-9]+$/ && $1 !~ /^-?[0-9]+$/ { cur = $1; next } + cur == version && $1 == pin && $2 == uri { found = 1 } + END { exit !found }' "$file"; then echo "boot-test: the candidate $package $candidate does not come from" \ "$BT_ARCHIVE_URI at priority $BT_ARCHIVE_PIN" >&2 return 1 From 0e7ee1f50849ac139faeef6d37eb2635dddb9a3a Mon Sep 17 00:00:00 2001 From: navigator Date: Wed, 30 Sep 2026 02:33:47 +0000 Subject: [PATCH 3/3] refactor: the candidate-source parse in its own awk file kcov counted the lines of the inline awk program as unexecuted bash and put boot-test-lib.sh under the 97 percent gate. The program moves to tests/lib/candidate-source.awk, beside the library, with its explanation, and the library finds it through BT_LIB_DIR. --- tests/lib/boot-test-lib.sh | 18 ++++++------------ tests/lib/candidate-source.awk | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 tests/lib/candidate-source.awk diff --git a/tests/lib/boot-test-lib.sh b/tests/lib/boot-test-lib.sh index 71aca9b..cdd60f1 100644 --- a/tests/lib/boot-test-lib.sh +++ b/tests/lib/boot-test-lib.sh @@ -62,6 +62,8 @@ etc/apt/keyrings/keel-staging-keyring.asc" # sets. BT_POLICY_PACKAGE="inithooks" BT_ARCHIVE_PIN=1001 +# Where this library and the awk programs beside it live. +BT_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # And the package path itself, in two steps, neither of which needs a version # newer than the image to exist. Requiring one would mean either inventing a # release or shipping the image deliberately stale so the archive is always @@ -635,19 +637,11 @@ bt_policy_verdict() { echo "boot-test: $BT_ARCHIVE_URI is not a source of $package at priority $BT_ARCHIVE_PIN" >&2 return 1 fi - # The candidate's own block of the version table has to list our archive - # at our pin: the number on a version line is only the highest priority - # of its sources, so it does not say which source the version comes - # from. apt marks the installed version with *** in front of it (a - # current appliance: " *** 2.3.6+keel5 1001"); the marker is dropped. + # the candidate's own block of the version table has to list our archive + # at our pin (candidate-source.awk says why) if ! awk -v version="$candidate" -v pin="$BT_ARCHIVE_PIN" \ - -v uri="$BT_ARCHIVE_URI" ' - { if ($1 == "***") { $1 = ""; $0 = $0 } } - $1 == "Version" && $2 == "table:" { table = 1; next } - !table { next } - NF == 2 && $2 ~ /^-?[0-9]+$/ && $1 !~ /^-?[0-9]+$/ { cur = $1; next } - cur == version && $1 == pin && $2 == uri { found = 1 } - END { exit !found }' "$file"; then + -v uri="$BT_ARCHIVE_URI" -f "$BT_LIB_DIR/candidate-source.awk" \ + "$file"; then echo "boot-test: the candidate $package $candidate does not come from" \ "$BT_ARCHIVE_URI at priority $BT_ARCHIVE_PIN" >&2 return 1 diff --git a/tests/lib/candidate-source.awk b/tests/lib/candidate-source.awk new file mode 100644 index 0000000..a86723e --- /dev/null +++ b/tests/lib/candidate-source.awk @@ -0,0 +1,15 @@ +# candidate-source.awk: succeeds when the version table of "apt-cache policy" +# lists `uri` at priority `pin` inside the block of `version`, the candidate. +# +# The number on a version line is only the highest priority of that version's +# sources, so it does not say which source the version comes from; the source +# lines under the version do. apt marks the installed version with *** in front +# of it (a current appliance: " *** 2.3.6+keel5 1001"); the marker is dropped. +# +# awk -v version=V -v pin=P -v uri=U -f candidate-source.awk POLICY_FILE +{ if ($1 == "***") { $1 = ""; $0 = $0 } } +$1 == "Version" && $2 == "table:" { table = 1; next } +!table { next } +NF == 2 && $2 ~ /^-?[0-9]+$/ && $1 !~ /^-?[0-9]+$/ { cur = $1; next } +cur == version && $1 == pin && $2 == uri { found = 1 } +END { exit !found }