diff options
| author | Craig Jennings <c@cjennings.net> | 2026-08-19 12:32:02 -0700 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-08-19 12:32:02 -0700 |
| commit | ec3a63caca4f2d955e594318a9a690e4c28af19e (patch) | |
| tree | 4ad5a438b38f92d49dbbcd2dd22e950831535f37 /scripts/post-rebuild-check | |
| parent | afbf011aa0937b5702b6d8c1bfca0809ed809425 (diff) | |
| download | archsetup-ec3a63caca4f2d955e594318a9a690e4c28af19e.tar.gz archsetup-ec3a63caca4f2d955e594318a9a690e4c28af19e.zip | |
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.
Diffstat (limited to 'scripts/post-rebuild-check')
| -rwxr-xr-x | scripts/post-rebuild-check | 25 |
1 files changed, 22 insertions, 3 deletions
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 }' \ |
