From 36a6f9efc5ae105501568db71f67a15159876414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20M=C3=A9ndez?= Date: Mon, 28 Sep 2026 08:10:31 +0000 Subject: [PATCH] test: a negated command only asserts in final position `! cmd` on its own line asserts nothing in a bats body unless it happens to be the last command of that body: bash does not apply errexit to a negated command, so the verdict is the exit status of the final command and every earlier `! cmd` is inert. shellcheck names the class SC2314 and grades the two cases apart, error for the inert ones and note for the rest. Four negations here were inert, and they are the refutations this component exists to make: - conf.bats, the bind fragment: that it never says `localhost`. That is the exact line docs/traps.md records the PostgreSQL appliance getting wrong, and the test that was put there to stop it happening again did not run. - conf.bats, the acl fragment: that it declares no `admin` user and no `requirepass`. Those two are what make the duplicate user declaration impossible and keep the password off the disk at build time; only the third refusal, `+@all`, ran. - unit.bats, the shipped tree: that no `requirepass` line is anywhere in the overlay. The comment above it calls this "the one property the whole design rests on". All of them become `run !`, together with the six that were in final position and did assert, because a line whose meaning depends on its position is the trap itself. No assertion changed its verdict: the fragments and the overlay are as the tests believed. Suite green, 70 tests. Coverage unchanged at 100.00 percent, 35redispass 31 of 31 lines and redis.sh 56 of 56, threshold 100. --- tests/conf.bats | 10 +++++----- tests/hook.bats | 4 ++-- tests/unit.bats | 8 +++++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/conf.bats b/tests/conf.bats index 60487c9..5511127 100644 --- a/tests/conf.bats +++ b/tests/conf.bats @@ -250,8 +250,8 @@ exit 0' # The fragment is content, not code, so it is asserted here: this is the # one line the PostgreSQL appliance got wrong (docs/traps.md). grep -qx 'bind ::1 127.0.0.1' "$REDIS_CONF_D/10-keel-bind.conf" - ! grep -qE '^bind .*localhost' "$REDIS_CONF_D/10-keel-bind.conf" - ! grep -qE '^bind .*-::1' "$REDIS_CONF_D/10-keel-bind.conf" + run ! grep -qE '^bind .*localhost' "$REDIS_CONF_D/10-keel-bind.conf" + run ! grep -qE '^bind .*-::1' "$REDIS_CONF_D/10-keel-bind.conf" } @test "the acl fragment declares one user, and it is not the administrative one" { @@ -260,9 +260,9 @@ exit 0' # it is declared once, at the first boot, or not at all. grep -qx 'user default on nopass +info' "$REDIS_CONF_D/20-keel-acl.conf" [ "$(grep -c '^user ' "$REDIS_CONF_D/20-keel-acl.conf")" -eq 1 ] - ! grep -qE '^user admin' "$REDIS_CONF_D/20-keel-acl.conf" - ! grep -qE '^requirepass' "$REDIS_CONF_D/20-keel-acl.conf" - ! grep -qE '^user default .*\+@all' "$REDIS_CONF_D/20-keel-acl.conf" + run ! grep -qE '^user admin' "$REDIS_CONF_D/20-keel-acl.conf" + run ! grep -qE '^requirepass' "$REDIS_CONF_D/20-keel-acl.conf" + run ! grep -qE '^user default .*\+@all' "$REDIS_CONF_D/20-keel-acl.conf" } @test "no account is declared twice, which Redis refuses outright" { diff --git a/tests/hook.bats b/tests/hook.bats index 899e7cb..fdbc322 100644 --- a/tests/hook.bats +++ b/tests/hook.bats @@ -99,7 +99,7 @@ write_conf() { write_conf run "$HOOK" [ "$status" -eq 0 ] - ! grep -rq "$DECLARED_PASS" "$REDIS_CONF_D" + run ! grep -rq "$DECLARED_PASS" "$REDIS_CONF_D" } @test "the password never reaches a command line either" { @@ -108,7 +108,7 @@ write_conf() { [ "$status" -eq 0 ] # It is in the environment of the recorded call and in no argument. grep -q "REDISCLI_AUTH=$DECLARED_PASS" "$CALLS" - ! grep -E "^redis-cli .*$DECLARED_PASS.* REDISCLI_AUTH" "$CALLS" + run ! grep -E "^redis-cli .*$DECLARED_PASS.* REDISCLI_AUTH" "$CALLS" } @test "the fragment is not readable by everybody" { diff --git a/tests/unit.bats b/tests/unit.bats index 4442341..ec416c1 100644 --- a/tests/unit.bats +++ b/tests/unit.bats @@ -9,6 +9,8 @@ # one variable per line and fab refuses anything that is not a variable # name; the version is a single token the layer manifest can carry. +bats_require_minimum_version 1.5.0 + setup() { unit="$(cd "$BATS_TEST_DIRNAME/.." && pwd)" } @@ -28,7 +30,7 @@ setup() { # reads none, and a dead interface is not carried (the same reasoning # unit-mariadb records for MYSQL_PASS). [ ! -e "$unit/conf-vars" ] - ! grep -qE '\$\{?(REDIS_PASS|APP_PASS|DB_PASS)' "$unit/conf" + run ! grep -qE '\$\{?(REDIS_PASS|APP_PASS|DB_PASS)' "$unit/conf" } @test "the version is one line a layer manifest can carry" { @@ -74,6 +76,6 @@ setup() { @test "the component writes no password anywhere in the tree it ships" { # The one property the whole design rests on: what lands on the machine # is a digest. A requirepass line anywhere here would undo it. - ! grep -rqE '^[[:space:]]*requirepass' "$unit/overlay" - ! grep -rq 'masterauth' "$unit/overlay" + run ! grep -rqE '^[[:space:]]*requirepass' "$unit/overlay" + run ! grep -rq 'masterauth' "$unit/overlay" }