From ec3a63caca4f2d955e594318a9a690e4c28af19e Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Wed, 19 Aug 2026 12:32:02 -0700 Subject: fix(check): read NTP sources only from files chrony is told to read Check 6 globbed /etc/chrony.d unconditionally. A drop-in is inert unless chrony.conf names its directory, and Arch's stock chrony.conf names none, so a machine with the IP-addressed source on disk and no confdir line would show the literal and pass. That is a false pass on exactly the misconfiguration the check exists to catch, and it describes a file chrony never opens. Sources now come only from chrony.conf plus whatever confdir or sourcedir it actually names. The config path is a seam so the confdir logic can be tested against a fixture instead of the real /etc. This should have been in the previous commit, whose message already describes it. I staged before reviewing, fixed the finding, then committed the stale index. --- scripts/post-rebuild-check | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'scripts/post-rebuild-check') diff --git a/scripts/post-rebuild-check b/scripts/post-rebuild-check index c18ae8f..24e99a4 100755 --- a/scripts/post-rebuild-check +++ b/scripts/post-rebuild-check @@ -56,6 +56,8 @@ # the special value MISSING = binary absent # PRC_NTP_SOURCES newline list of configured NTP server addresses; # the special value MISSING = no NTP daemon active +# PRC_CHRONY_CONF path to chrony.conf (a fixture, under test) -- the +# confdir it names is what decides which drop-ins count # PRC_SYSTEMCTL path to the systemctl binary (a fake, under test) # PRC_SYSTEMCTL_TIMEOUT seconds to allow each systemctl call (default 5) # @@ -101,6 +103,7 @@ ntp_missing="" # own outage, and the machine most in need of checking is the one it hangs on. # A timeout yields empty output and a non-zero status, and both are already # handled as findings, so bounding the call is all that is needed to fail closed. +CHRONY_CONF=${PRC_CHRONY_CONF:-/etc/chrony.conf} SCTL_TIMEOUT=${PRC_SYSTEMCTL_TIMEOUT:-5} SYSTEMCTL=${PRC_SYSTEMCTL:-systemctl} @@ -435,9 +438,25 @@ if [ -n "${PRC_NTP_SOURCES+set}" ]; then ntp_missing=1 fi elif sctl is-active chronyd >/dev/null 2>&1; then - # Both the main file and any drop-in: the IP-addressed source belongs in a - # drop-in, so reading only chrony.conf would miss every correct machine. - ntp_sources=$(cat /etc/chrony.conf /etc/chrony.d/*.conf 2>/dev/null \ + # The main file, plus any drop-in directory chrony.conf actually names. + # + # The confdir read is the load-bearing part. A drop-in is inert unless + # chrony.conf points at its directory, and Arch's stock chrony.conf points + # at none -- so globbing /etc/chrony.d unconditionally would find the + # IP-addressed source, report the machine healthy, and be describing a file + # chrony never opens. That is a false pass on exactly the misconfiguration + # this check exists to catch, so the sources are read only from files + # chrony is actually told to read. + ntp_conf_files=$CHRONY_CONF + for ntp_dir in $(awk '$1 == "confdir" || $1 == "sourcedir" { print $2 }' \ + "$CHRONY_CONF" 2>/dev/null); do + for ntp_f in "$ntp_dir"/*.conf "$ntp_dir"/*.sources; do + [ -f "$ntp_f" ] && ntp_conf_files="$ntp_conf_files $ntp_f" + done + done + # Unquoted on purpose: the accumulated list is several paths, and none of + # this script's own paths contain spaces. + ntp_sources=$(cat $ntp_conf_files 2>/dev/null \ | awk '$1 == "server" || $1 == "pool" { print $2 }') elif sctl is-active systemd-timesyncd >/dev/null 2>&1; then ntp_sources=$(awk -F= '/^[[:space:]]*NTP=/ { print $2 }' \ -- cgit v1.2.3