Files
fips/testing/firewall/table-check.sh
Johnathan Corgan 4b72e995eb Check firewall case (e) against a captured nft listing
Case (e) of the firewall suite piped `docker exec ... nft list table inet
fips` into `grep -q` under pipefail. grep exits at its match; when the exec
client was still writing the rest of the listing it took SIGPIPE (141), and
pipefail turned a rule that was present into "the sed did not change the
scoping rule". It false-failed intermittently in local and GitHub CI.

The check moves into table_has in testing/firewall/table-check.sh, which
captures the whole listing and then matches it with grep -qF on a
here-string, so no pipe is left. It returns 0 when the rule is present, 1
when it is absent and 2 when the table could not be listed; case (e) gives
each failure its own message. The assertion is unchanged: same container,
same table, same rule text.

testing/firewall/table-check-test.sh replaces docker with a shell function
that prints the listing in two chunks, the rule in the first and a 0.2 s
pause before the second, which is the race's shape. It runs as a guard in
every local run (run_fwtable) and as a matching GitHub CI step.

With table_has written as the old pipeline, moved verbatim, the test failed
(the pipeline's status was 141, the producer's SIGPIPE):

  FAIL  rule present, writer still writing after the match (run 1): returns 0  (rc=1)
  ... runs 2 to 5 the same
  PASS  rule absent: returns 1  (rc=1)
  FAIL  listing could not be read: returns 2  (rc=1)
  6 table_has check(s) failed

With the capture form all seven checks pass.
2026-10-15 20:56:31 +00:00

18 lines
745 B
Bash

#!/bin/bash
# Sourced by test.sh. Not run on its own.
# Return 0 if container $1's `inet fips` table listing contains the fixed text
# $2, 1 if it does not, and 2 if the listing could not be read.
#
# The listing is captured whole before it is matched. Piping `docker exec`
# straight into `grep -q` under pipefail fails a present rule: grep exits at
# its match, the exec client still writing the rest takes SIGPIPE (141), and
# pipefail reports the pipeline as failed. The here-string leaves no pipe, so
# the result does not depend on how much of the listing follows the match.
table_has() {
local listing
listing=$(docker exec "$1" nft list table inet fips) || return 2
grep -qF -- "$2" <<<"$listing" && return 0
return 1
}