diff --git a/COVERAGE.md b/COVERAGE.md index 6100e5c..45d7883 100644 --- a/COVERAGE.md +++ b/COVERAGE.md @@ -11,13 +11,13 @@ LXC as the acceptance test of a recipe, docs/org-plan.md section 1). | overlay/usr/lib/inithooks/lib/postgresql.sh | tests/postgresql.bats (11 tests) | 100 percent (41/41) under kcov | every function and every branch | | overlay/usr/lib/inithooks/firstboot.d/36pgsqlverify | tests/hook.bats (10 tests) | 100 percent (15/15) under kcov | every path, including the two failures that matter | | tests/lib/boot-test-lib.sh | tests/boot-test.bats (44 tests) | 100 percent (154/154) under kcov | argument parsing, address discovery, deadlines, the container marks, the database, module, Webmin and diff verdicts | -| bin/keel-archive-check | tests/archive-check.bats (25 tests) | 100 percent (52/52) under kcov | the build time check: the archive copy in the build tree is the live archive, the source entry names the keyring through signed-by, nothing says trusted=yes, and the signature on the copied InRelease verifies against the staging key (tracker#7) | +| bin/keel-archive-check | tests/archive-check.bats (27 tests) | 100 percent (54/54) under kcov | the build time check: the archive copy in the build tree is the live archive, the source entry names the keyring through signed-by, nothing says trusted=yes, and the signature on the copied InRelease verifies against the staging key (tracker#7) | | conf.d/main | the build | integration only | build time script, 0004 pragmatic limits | | tests/boot-test.sh | itself | integration only | the thin main of the acceptance test: keel and LXC as root | | overlay ... firstboot.d/35pgsqlpass | common | not this repository | the hook that sets the password belongs to the `common` fork and is used, not rewritten | -Total over the four measured shell files: **100 percent (262/262)**, -90 bats tests. `tests/coverage.sh` fails below `COVERAGE_THRESHOLD`, which +Total over the four measured shell files: **100 percent (264/264)**, +92 bats tests. `tests/coverage.sh` fails below `COVERAGE_THRESHOLD`, which the workflow sets to 100, the measured number. It is only ever raised (decision 0006). @@ -26,7 +26,7 @@ the workflow sets to 100, the measured number. It is only ever raised 100.00 41/41 postgresql.sh 100.00 15/15 36pgsqlverify 100.00 154/154 boot-test-lib.sh - 100.00 52/52 keel-archive-check + 100.00 54/54 keel-archive-check ## What the hook tests cover diff --git a/bin/keel-archive-check b/bin/keel-archive-check index 4de10e6..a61607d 100755 --- a/bin/keel-archive-check +++ b/bin/keel-archive-check @@ -41,6 +41,8 @@ # promise until the key inside it is named. # KEEL_ARCHIVE_KEYRING where in TREE the keyring is # KEEL_ARCHIVE_LIST where in TREE the source entry is +# KEEL_ARCHIVE_PATH the path an apt source names this archive by, which is +# the archive a trusted=yes is refused for # # Exit 0 when everything holds, 1 otherwise. set -eu @@ -74,6 +76,9 @@ fatal() { [ -n "$KEEL_ARCHIVE_KEY" ] \ || fatal "KEEL_ARCHIVE_KEY names no key: the archive would be verified against whatever the keyring happens to hold" +# The path an apt source names this archive by, which is what makes a +# trusted=yes elsewhere in the tree somebody else's business. +ARCHIVE_PATH="${KEEL_ARCHIVE_PATH:-/srv/keel-apt/repo}" index=dists/$dist/main/binary-$arch/Packages source_index=$source_repo/$index copy=$tree/srv/keel-apt/repo @@ -95,16 +100,23 @@ if ! cmp -s "$source_index" "$copy_index"; then exit 1 fi -# 2. Nothing in the tree switches verification off. A single trusted=yes -# anywhere turns every failure below into a warning, which is the defect this -# check exists for, so it is refused wherever it is written, in either of the -# two formats apt reads a source in. +# 2. Nothing in the tree switches verification off for this archive. A single +# trusted=yes on it turns every failure below into a warning, which is the +# defect this check exists for, so it is refused in either of the two formats +# apt reads a source in and in whichever file it is written. +# +# Scoped to the sources that name this archive, not to every source in the +# tree: the captured pool of decision 0012 sets Trusted: yes on purpose, for a +# file: index generated on this machine from files keel-pool verify checks +# against the same digests apt does. Refusing that would fail every pinned +# build. What the pool does is the pool's business; this archive is verified. verification_off='trusted *= *yes|^ *Trusted: *yes' apt_sources="$tree/etc/apt/sources.list $tree/etc/apt/sources.list.d" # shellcheck disable=SC2086 # the two paths are one word each, on purpose -untrusted=$(grep -rlE "$verification_off" $apt_sources 2>/dev/null || true) +distrusting=$(grep -rlE "$verification_off" $apt_sources 2>/dev/null || true) +untrusted=$(echo "$distrusting" | xargs -r grep -lF "$ARCHIVE_PATH" || true) [ -z "$untrusted" ] \ - || fatal "verification is switched off in: $(echo "$untrusted" | tr '\n' ' ')" + || fatal "verification is switched off for $ARCHIVE_PATH in: $(echo "$untrusted" | tr '\n' ' ')" # 3. The source entry names this distribution and the keyring it is verified # with. apt takes signed-by from the entry, so the entry is what decides diff --git a/changelog b/changelog index 37499ca..bdbd3e3 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,14 @@ +turnkey-postgresql-19.0 (4) turnkey; urgency=low + + * bin/keel-archive-check refuses a trusted=yes on the project archive rather + than on every apt source in the build tree. The captured pool of decision + 0012 sets Trusted: yes on purpose, for a file: index generated on this + machine from files keel-pool verify checks against the same digests apt + does, so the wider rule would have failed every pinned build. What the pool + does is the pool's business; the project archive is verified (tracker#7). + + -- Keel Linux maintainers Sun, 27 Sep 2026 20:10:00 +0000 + turnkey-postgresql-19.0 (3) turnkey; urgency=low * The build verifies the project's own APT archive instead of reading it diff --git a/tests/archive-check.bats b/tests/archive-check.bats index ace9f31..1ba2380 100644 --- a/tests/archive-check.bats +++ b/tests/archive-check.bats @@ -142,25 +142,44 @@ check() { echo "deb [trusted=yes] file:///srv/keel-apt/repo $DIST main" > "$TREE$LIST_PATH" check bootstrap [ "$status" -eq 1 ] - [[ "$output" == *"verification is switched off in"* ]] + [[ "$output" == *"verification is switched off for /srv/keel-apt/repo"* ]] [[ "$output" == *"keel-staging.list"* ]] } -@test "trusted=yes anywhere else in the tree fails too" { - printf 'deb [ trusted = yes ] http://example.invalid trixie main\n' \ +@test "trusted=yes on this archive in another file fails too" { + printf 'deb [ trusted = yes ] file:///srv/keel-apt/repo trixie-staging main\n' \ > "$TREE/etc/apt/sources.list.d/other.list" check bootstrap [ "$status" -eq 1 ] - [[ "$output" == *"verification is switched off in"* ]] + [[ "$output" == *"verification is switched off for /srv/keel-apt/repo"* ]] [[ "$output" == *"other.list"* ]] } -@test "Trusted: yes in a deb822 source fails as well" { - printf 'Types: deb\nURIs: http://example.invalid\nSuites: trixie\nTrusted: yes\n' \ +@test "Trusted: yes on this archive in a deb822 source fails as well" { + printf 'Types: deb\nURIs: file:///srv/keel-apt/repo\nSuites: trixie-staging\nTrusted: yes\n' \ > "$TREE/etc/apt/sources.list.d/other.sources" check bootstrap [ "$status" -eq 1 ] - [[ "$output" == *"verification is switched off in"* ]] + [[ "$output" == *"verification is switched off for"* ]] +} + +@test "the captured pool may say Trusted: yes, because it is not this archive" { + # Decision 0012: a file: index generated on this machine, whose digests + # keel-pool verify checks. Refusing it would fail every pinned build. + printf 'Types: deb\nURIs: file:/keel-pool\nSuites: 2026-09-27\nTrusted: yes\n' \ + > "$TREE/etc/apt/sources.list.d/keel-pool.sources" + check bootstrap + [ "$status" -eq 0 ] + [[ "$output" == *"nothing is trusted unverified"* ]] +} + +@test "the archive a trusted=yes is refused for is overridable" { + printf 'deb [trusted=yes] file:///elsewhere/repo trixie main\n' \ + > "$TREE/etc/apt/sources.list.d/other.list" + run env KEEL_ARCHIVE_KEY="$GOOD_KEY" KEEL_ARCHIVE_PATH=/elsewhere/repo \ + "$CHECK" "$SOURCE" "$TREE" "$DIST" "$ARCH" bootstrap + [ "$status" -eq 1 ] + [[ "$output" == *"switched off for /elsewhere/repo"* ]] } @test "a tree with no source entry at all fails" {