Make provisioned NTP settings control effective host time sources
Physical box egress audit found user-provisioned Cloudflare/Google time servers do not stop Fedora NTP pool traffic, including after a coordinated reboot. Target kaukus-streamer MAC 84:47:09:7b:fa:ac, DHCP 192.168.50.175; evidence /home/mathias/.local/state/kaukus-network-audit/20261103T091303Z/second-reboot-findings.json. At 2026-11-03 10:25:17 CET it queries 2.fedora.pool.ntp.org and exchanges UDP/123 with 162.159.200.1 and undocumented 195.16.73.226, 185.41.243.43, 79.160.225.150. Provisioning was performed by user. User authorized read-only SSH as streamer@192.168.50.175. Effective live configuration and chronyd sources now inspected; deployed provisioner binary version remains unidentified. Static investigation on clean feature/microphone-backends worktree found two independent defects relative to exclusive network requirements: - kaukus-provisioner/src/main.rs:132 defaults KP_CHRONY_DROPIN to /etc/chrony.d/50-kaukus.conf. ensure_chrony_sourcedir at :878 appends sourcedir /etc/chrony.d, but official chrony manual says sourcedir only reads .sources files; .conf belongs to confdir. Thus the default generated custom-server file is ignored by that include unless some separate config includes it. - apply_ntp_servers at :895 only adds the include and writes custom server lines; it never removes/disables existing source directives such as Fedora pool. Fixing the suffix alone still permits undocumented sources. Protocol TimeConfig comments explicitly describe servers as extra sources, contrary to operator expectation and strict egress requirements. - gather_time_sync/read_custom_ntp_servers reports configured strings by reading that file, not chronyd's effective source list; restart success and synchronization do not establish that desired servers are active or exclusive. Source: https://chrony-project.org/doc/4.8/chrony.conf.html, sourcedir/confdir definitions. Live read-only validation at 2026-11-03 10:29:28 CET confirms both faults on installed chrony-4.8-3.fc43.x86_64: /etc/chrony.d/50-kaukus.conf contains server time.cloudflare.com iburst and server time.google.com iburst, but sudo chronyd -p -f /etc/chrony.conf shows neither custom server; it shows pool 2.fedora.pool.ntp.org iburst plus sourcedir /etc/chrony.d and /run/chrony-dhcp. Only the .conf drop-in exists; no .sources and no DHCP source files. chronyc -n sources lists 79.160.225.150, 185.41.243.43, 195.16.73.226 and 162.159.200.1. Boot journal explicitly attributes selected sources to 2.fedora.pool.ntp.org. Tracking reports Cloudflare as selected solely because that address belongs to the Fedora pool; tracking alone would mask the extra connections. This is runtime parser/source evidence, not an automated regression test. SSH used the configured IdentityAgent only and strict known-host verification; normal SSH was necessary because remote_python cannot select the explicitly supplied streamer username for the numeric host. User authorized local implementation. Worktree was clean and initial implementation used fix/apply-exclusive-ntp-sources from feature/microphone-backends. During authorized publication, fetched latest main and isolated only the NTP commit onto fresh fix/enforce-configured-ntp-sources based on origin/main 27b6841, excluding both unrelated Televic/microphone commits. Published commit d30b01a (fix: Apply configured NTP servers exclusively); clean worktree with upstream tracking. Original unpublished local branch retains backup commit 9e2bb5e; no history rewrite or remote branch deletion. No deployment, clock or live service changes performed. User explicitly requested no review tool; none was run. Local implementation: extracted time_sync module using the existing time-command/status flow and atomic file writer; no new dependencies or wire fields. Non-empty server lists are exclusive. Explicit include loads the existing .conf drop-in; original direct server/pool/peer/sourcedir directives (including DHCP) are disabled with reversible markers, preserving unrelated operational options and comments. Empty list deliberately restores original site/image sources, including DHCP; it does not replace factory defaults with a new global policy. This means clearing custom settings can restore Fedora pool behavior. Existing ignored .conf is migrated on apply. Nested includes with unmanaged network sources/options are rejected before activation rather than editing unrelated site files. Candidates are parsed with chronyd -p before publication; successful apply requires chronyc -N -c sources -a to report exactly the requested names, including unresolved sources. Atomic replacement preserves modes and restores SELinux labels where enabled. Failures restore prior files and NTP state and report rollback errors. Announcements only claim custom sources when the running set matches. Protocol comments updated for exclusive settings/verified telemetry; UI unchanged. Verified local validation: the original red regression failed because the Fedora pool remained. Before base isolation, 33 provisioner and 56 protocol tests passed. Re-ran on latest main-based PR branch: 50 provisioner and 51 protocol tests pass (101 total), with one optional real-chronyd parser test still ignored. cargo fmt --all -- --check, cargo check --workspace, and complete branch git diff --check pass. The complete comparison is one commit and exactly four NTP-related files; new module/tests are byte-identical to the previously validated implementation. Final logs are /tmp/kaukus-ntp-validation/pr-{tests,check,clippy}.log. Affected all-target Clippy passes with only pre-existing collapsible_if and items_after_test_module categories allowed; unqualified strict Clippy remains blocked by those existing findings. New tests cover ignored-file migration, reversible/idempotent apply/clear and server replacement, preserving site options, direct and nested-source exclusion, invalid input/path/block handling, rollback/restart failure, startup delay, and truthful source reporting. Optional real-chronyd parser test is present but ignored/unrun without CHRONYD_TEST_BIN. Its fixture source expansion and service/source responses are otherwise simulated; do not claim real daemon or deployment validation. Concrete blocker: read-only scp of chronyd/chronyc binaries from streamer@192.168.50.175 timed out after 20 seconds. Stopped remote work, asked user to check agent approval, and did not retry SSH or change authentication/configuration. No local chronyd binary/package cache was available, so native parser validation remains outstanding. User's continue instruction concerned session restoration, not resolution of the SSH timeout. Logs: /tmp/kaukus-ntp-validation/{tests,check,clippy}.log. To run the optional local parser test once a binary is available: CHRONYD_TEST_BIN=/path/to/chronyd cargo test -p kaukus-provisioner time_sync::tests::real_chronyd_parser_loads_the_legacy_conf_file_and_excludes_other_sources -- --ignored --exact. Deployment/reboot and egress capture remain a separately coordinated acceptance gate; no workaround or live mutation attempted. Acceptance: red-green regression for the ignored drop-in and retained Fedora pool, effective chronyd configuration/source validation with custom and empty lists, repeat/apply/restart persistence and migration coverage; new custom config permits no undesired NTP destinations in coordinated packet capture after reboot. Follow relevant Rust/protocol/dashboard tests, fmt/check/Clippy; no deployment or box restart without coordination. Do not modify unrelated network configuration or fix other egress findings as part of this repair. Pull request #147: https://git.kaukus.no/Kaukus/streaming-engines/pulls/147 Title: fix: Apply configured NTP servers exclusively Head fix/enforce-configured-ntp-sources; base main. Open, not draft. Publication does not complete the native chrony or deployed-device capture acceptance gates; no live changes performed. Git fetch/push to Gitea succeeded without auth changes; the earlier box SSH timeout remains unresolved and was not retried.
Checklist
2 of 3 complete- Verify the provisioned drop-in, chronyd parsed configuration and live sources against captured egress to establish the fault.
- After implementation authorization, add regression-backed repair for loaded and exclusive NTP sources, migration, and truthful status reporting; run relevant project validation.
- Coordinate deployment/reboot separately and verify effective time sources and packet-captured egress remain within documented policy.
- Area
- Streaming
- Project
- streaming-engines
- Kind
- Bug
- Priority
- High
- Task ID
tsk_kub2juuvzj- Updated