Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions COVERAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ acceptance test of an appliance recipe, docs/org-plan.md section 1).
| overlay/usr/lib/inithooks/firstboot.d/40nodebb | tests/hook.bats (15 tests) | 96.97 percent (32/33) under kcov | the one uncovered line is inside the dialog loop, which needs a terminal |
| overlay/etc/nginx/* | tests/nginx.bats (12 tests) | not executable | asserted as content: the geo variable, the map, the listeners, the proxy headers |
| tests/lib/boot-test-lib.sh | tests/boot-test.bats (41 tests) | 100 percent (137/137) under kcov | the logic of the boot test: argument parsing, address discovery, deadlines, the HTTP 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/zz-project-packages | tests/project-packages.bats (14 tests) | 100 percent (31/31) under kcov | the build time check that each project package is the candidate of the archive and a project build, and that the archive copy, its source entry and the staging keyring leave the image |
| overlay/usr/lib/inithooks/bin/nodebb.py | none | 0 | dialog wrapper, only reached with a terminal attached |
| conf.d/main | tests/boot-test.sh (build step) | 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 |

Total over the five measured shell files: 99.66 percent (295/296) before the
terminal test, 100 percent (296/296) with it, over 132 bats tests.
Total over the five measured shell files: 99.66 percent (297/298) before the
terminal test, 100 percent (298/298) with it, over 134 bats tests.

`tests/coverage.sh` runs the whole bats suite under kcov, measures the
library, the first boot hook, the boot test's own library and the two build
Expand Down
24 changes: 18 additions & 6 deletions bin/keel-archive-check
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
11 changes: 11 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
turnkey-nodebb-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 <admin@keellinux.org> Sun, 27 Sep 2026 20:10:00 +0000

turnkey-nodebb-19.0 (3) turnkey; urgency=low

* The build verifies the project's own APT archive instead of reading it
Expand Down
33 changes: 26 additions & 7 deletions tests/archive-check.bats
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
Expand Down
Loading