#!/bin/bash # Unit tests for dns/drift-check.sh [#420][#469] # Tests the redaction and normalization functions without touching hosts. set -euo pipefail PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" SCRIPT="$PROJECT_ROOT/dns/drift-check.sh" failed=0 if [[ -f "$SCRIPT" ]] && (source "$SCRIPT"); then echo "✅ script exists + sources cleanly" else echo "❌ script missing or fails to source: $SCRIPT" exit 1 fi # shellcheck disable=SC1091 source "$SCRIPT" test_redact_strips_secrets() { local out out=$(printf ' pwhash = "SECRETBALLOONHASH"\n totp_secret = "ABC234"\n password = "hunter2"\n port = 53\n' | redact_config) if grep -qE "SECRETBALLOON|ABC234|hunter2" <<<"$out"; then echo "❌ redact_config leaked a secret" ((++failed)) elif grep -q '"REDACTED"' <<<"$out" && grep -q "port = 53" <<<"$out"; then echo "✅ redact_config strips secrets, keeps config" else echo "❌ redact_config mangled output" ((++failed)) fi } test_normalize_drops_timestamp() { local out out=$(printf '# Last updated on 2026-09-01 17:01:15 CDT\n dnsmasq_lines = []\n' | normalize_toml) if grep -q "Last updated" <<<"$out"; then echo "❌ normalize_toml kept the timestamp churn line" ((++failed)) elif grep -q "dnsmasq_lines" <<<"$out"; then echo "✅ normalize_toml drops timestamp, keeps config" else echo "❌ normalize_toml dropped config lines" ((++failed)) fi } test_normalize_implies_redaction() { local out out=$(printf ' totp_secret = "XYZ789"\n a = 1\n' | normalize_toml) if grep -q XYZ789 <<<"$out"; then echo "❌ normalize_toml leaked a secret" ((++failed)) else echo "✅ normalize_toml redacts secrets" fi } test_redact_strips_secrets test_normalize_drops_timestamp test_normalize_implies_redaction test_ntp_conf_tracked() { if [[ -n "${NTP_FILE:-}" && -f "$NTP_FILE" ]]; then echo "✅ NTP_FILE points at tracked canonical config" else echo "❌ NTP_FILE missing or file absent: ${NTP_FILE:-unset}" ((++failed)) fi } test_zones_dir_tracked() { if [[ -n "${ZONES_DIR:-}" && -d "$ZONES_DIR" ]] && compgen -G "${ZONES_DIR}/*.zone" > /dev/null; then echo "✅ ZONES_DIR present with zone files" else echo "❌ ZONES_DIR missing or empty: ${ZONES_DIR:-unset}" ((++failed)) fi } test_gen_manifest_sorted_md5() { local fxt out n fxt="$(mktemp -d)" printf 'A' > "$fxt/zz.zone" printf 'B' > "$fxt/aa.zone" printf 'S' > "$fxt/ignored.txt" out="$(gen_manifest "$fxt")" n="$(wc -l <<<"$out")" if [[ "$n" -eq 2 ]] \ && grep -qE '^[0-9a-f]{32} (aa|zz)\.zone$' <<<"$out" \ && [[ "$(head -1 <<<"$out")" == *"aa.zone" ]] \ && ! grep -q 'ignored' <<<"$out"; then echo "✅ gen_manifest: md5 of *.zone only, name-sorted" else echo "❌ gen_manifest wrong output" ((++failed)) fi rm -rf "$fxt" } test_ntp_conf_tracked test_zones_dir_tracked test_gen_manifest_sorted_md5 if ((failed > 0)); then echo "❌ $failed drift-check test(s) failed" exit 1 fi echo "✅ all drift-check tests passed"