mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 20:27:02 +01:00
Two levels of pure taxonomy carrying no information, and a 2-directory
cap leaves no room for them. Categories now sit directly under
linux_configuration/: features, fixes, utils, misc, fresh-install,
installers, diagnostics, gaming, boot_recovery, periodic_background, lib,
meta, tests. A script's own lib/ and tests/ are exempt from the cap, so
those stay put.
Depth violations 248 -> 139; roughly 40 of the remainder are inside
digital_wellbeing and hosts, deferred until the guard-lib repoint.
The moves are the easy half. What breaks is every path that counted
levels, and three classes of it had to be found by resolving paths rather
than reading diffs:
- 52 relative `source` lines for lib/common.sh and lib/android.sh. The
correct prefix differs per file: 40 were ../../ and 12 were ../../../,
so a blanket replace would have fixed one set and broken the other.
- REPO_ROOT in 7 fixes/lib/tests harnesses and setup_syncyomi_guard.sh,
each walking up four levels from a directory now two levels shallower.
This caused a real regression -- the fixes suite went red with
"log_warn: command not found" -- caught by running it and comparing
against the pre-move baseline worktree.
- conftest.py's sys.path entries, which took the pytest gate down with
14 collection errors, and the `# shellcheck source=` directives, which
took shellcheck down with SC1091.
16 symlinks in $HOME broke, including the entire i3blocks bar. All
repointed, and cpu_monitor/memory/disk/time/volume were run to confirm
they emit real output rather than merely resolving.
Verified: 1798 tests pass at 100% coverage, 8 of 9 lib/tests suites pass
(the ninth needs the coverage jail, identically at baseline), pre-commit
is clean, and the two untracked secret configs are still ignored after
their gitignore paths changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
187 lines
8.4 KiB
Bash
Executable File
187 lines
8.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Tests for dot_resolver_install.sh — the DoT resolver's install half.
|
|
#
|
|
# Every function here sudo-writes a systemd unit, an stunnel config or an
|
|
# nftables rule against LIVE infrastructure (dns.kuhy.duckdns.org:853). They
|
|
# are executed for real, not mocked, because the generated CONTENT is the
|
|
# thing worth asserting -- a unit file with the wrong ExecStart is exactly the
|
|
# bug a presence check would miss.
|
|
#
|
|
# This is only safe under meta/scripts/shell_coverage_jail.sh, which runs the
|
|
# suite inside a user+mount namespace with /etc, /usr/local/bin and /var/lib
|
|
# bind-mounted to a throwaway dir. Run directly on a real host it would
|
|
# rewrite the resolver, so it refuses to start unless the jail is in place.
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
# shellcheck source=./features_harness.sh
|
|
. "$SCRIPT_DIR/features_harness.sh"
|
|
|
|
# --- Refuse to run outside the jail -----------------------------------------
|
|
# The jail bind-mounts /etc, so the real resolver's config is absent inside it.
|
|
# Seeing the host's own stunnel config means we are NOT contained.
|
|
if [[ -f /etc/stunnel/dot-resolver.conf ]] && [[ ! -w /etc ]]; then
|
|
printf 'REFUSING: this suite must run under shell_coverage_jail.sh\n' >&2
|
|
exit 1
|
|
fi
|
|
|
|
_t_setup_env
|
|
trap _t_teardown EXIT
|
|
|
|
# The values the entry script defines above its source line.
|
|
SCRIPT_NAME="setup_dot_resolver.sh"
|
|
CERT_DIR="/etc/stunnel/dot"
|
|
STUNNEL_CONF="/etc/stunnel/dot-resolver.conf"
|
|
SYNC_SCRIPT="/usr/local/bin/sync-dot-cert.sh"
|
|
DOT_PORT=853
|
|
DOMAIN="dns.kuhy.duckdns.org"
|
|
BIND_ADDR="10.8.0.1"
|
|
CADDY_CONTAINER="caddy"
|
|
|
|
# install_cert_sync interpolates this at GENERATION time (the heredoc is
|
|
# unquoted), baking the resolved path into the script it writes. That is
|
|
# deliberate, not a bug -- the live /usr/local/bin/sync-dot-cert.sh carries a
|
|
# fully populated src=. The fixture must therefore define it exactly as the
|
|
# entry script does, or the generated script gets src="" and the assertion
|
|
# below silently passes over an empty path.
|
|
cert_source_dir() {
|
|
printf '/data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/%s' \
|
|
"$DOMAIN"
|
|
}
|
|
|
|
# shellcheck source=../dot_resolver_install.sh
|
|
. "$FEATURES_LIB_DIR/dot_resolver_install.sh"
|
|
|
|
# Fixture self-check: a typo in one of these names would turn every assertion
|
|
# below into a silent no-op rather than a failure.
|
|
[[ -n $CERT_DIR && -n $STUNNEL_CONF && -n $SYNC_SCRIPT ]] ||
|
|
{
|
|
printf 'fixture globals are not populated\n' >&2
|
|
exit 1
|
|
}
|
|
|
|
mkdir -p /etc/stunnel /etc/systemd/system /usr/local/bin
|
|
|
|
# --- install_cert_sync ------------------------------------------------------
|
|
install_cert_sync
|
|
_t_file_has "$SYNC_SCRIPT" 'combined.pem' "cert sync script assembles combined.pem"
|
|
_t_file_has "$SYNC_SCRIPT" "src=\"/data/caddy/certificates" "cert source path is baked in, not left empty"
|
|
_t_file_has "$SYNC_SCRIPT" 'reload-or-restart' "cert sync restarts stunnel after renewal"
|
|
if [[ -d $CERT_DIR ]]; then
|
|
_t_pass "cert dir created"
|
|
else
|
|
_t_fail "cert dir created"
|
|
fi
|
|
_t_eq "700" "$(stat -c '%a' "$CERT_DIR")" "cert dir is mode 700 (it holds a private key)"
|
|
_t_eq "755" "$(stat -c '%a' "$SYNC_SCRIPT")" "sync script is executable"
|
|
|
|
# --- install_stunnel_conf ---------------------------------------------------
|
|
install_stunnel_conf
|
|
_t_file_has "$STUNNEL_CONF" "accept = $BIND_ADDR:$DOT_PORT" "stunnel accepts on the bind address"
|
|
_t_file_has "$STUNNEL_CONF" 'connect = 127.0.0.1:53' "stunnel forwards to local dnsmasq"
|
|
_t_file_has "$STUNNEL_CONF" 'sslVersionMin = TLSv1.2' "stunnel refuses pre-TLS1.2 (Android requires it)"
|
|
_t_file_has "$STUNNEL_CONF" "cert = $CERT_DIR/combined.pem" "stunnel reads the synced cert"
|
|
|
|
# --- install_units ----------------------------------------------------------
|
|
_t_stub systemctl
|
|
install_units
|
|
_t_file_has /etc/systemd/system/stunnel-dot.service 'stunnel' "stunnel unit installed"
|
|
_t_file_has /etc/systemd/system/dot-cert-sync.service "$SYNC_SCRIPT" "cert-sync service runs the sync script"
|
|
_t_file_has /etc/systemd/system/dot-cert-sync.timer 'OnCalendar' "cert-sync timer is scheduled"
|
|
_t_called 'daemon-reload' "units are followed by a daemon-reload"
|
|
|
|
# --- open_firewall: the WireGuard-only branch -------------------------------
|
|
# nft absent entirely: the function must still return cleanly rather than
|
|
# aborting the install on a host without nftables.
|
|
out="$(open_firewall 2>&1)"
|
|
_t_has "$out" 'WireGuard-only' "wg-bound install needs no router forward"
|
|
|
|
# nft present and the rule already there: must not add a duplicate.
|
|
_t_stub nft
|
|
printf '#!/usr/bin/env bash\nprintf "nft %%s\\n" "$*" >>"%s/calls.log"\nif [[ $* == *list* ]]; then printf "iifname \\"wg0\\" tcp dport %s accept\\n" ; fi\nexit 0\n' \
|
|
"$TEST_TMPDIR" "$DOT_PORT" >"$TEST_TMPDIR/bin/nft"
|
|
chmod +x "$TEST_TMPDIR/bin/nft"
|
|
out="$(open_firewall 2>&1)"
|
|
_t_has "$out" 'already permits' "an existing wg0 rule is not duplicated"
|
|
|
|
# nft present and the rule missing: must add it, scoped to wg0.
|
|
printf '#!/usr/bin/env bash\nprintf "nft %%s\\n" "$*" >>"%s/calls.log"\nexit 0\n' \
|
|
"$TEST_TMPDIR" >"$TEST_TMPDIR/bin/nft"
|
|
chmod +x "$TEST_TMPDIR/bin/nft"
|
|
out="$(open_firewall 2>&1)"
|
|
_t_has "$out" 'wg0 only' "a missing wg0 rule is added"
|
|
_t_called 'add rule inet filter input iifname wg0' "the added rule is scoped to the tunnel"
|
|
|
|
# nft present but the ADD fails (a locked-down or read-only ruleset): the
|
|
# install must warn and carry on, never abort. `nft list` still has to succeed
|
|
# or the outer guard short-circuits before the add is attempted.
|
|
cat >"$TEST_TMPDIR/bin/nft" <<'NFT'
|
|
#!/usr/bin/env bash
|
|
printf 'nft %s\n' "$*" >>"$TEST_TMPDIR/calls.log"
|
|
[[ $* == *add* ]] && exit 1
|
|
exit 0
|
|
NFT
|
|
chmod +x "$TEST_TMPDIR/bin/nft"
|
|
out="$(open_firewall 2>&1)"
|
|
_t_has "$out" 'WARNING: could not add nftables rule' "a failed wg0 rule add warns instead of aborting"
|
|
|
|
# --- open_firewall: the publicly-bound branch -------------------------------
|
|
# A public bind is an open resolver, so the rule MUST carry a rate limit.
|
|
BIND_ADDR="0.0.0.0"
|
|
out="$(open_firewall 2>&1)"
|
|
_t_has "$out" 'rate limited' "a public bind is rate limited"
|
|
_t_called 'limit rate 25/second burst 50' "the public rule carries the documented limit"
|
|
_t_has "$out" 'router forwards' "a public bind asks for a router forward"
|
|
|
|
# The same add-failure path on the public branch.
|
|
out="$(open_firewall 2>&1)"
|
|
_t_has "$out" 'WARNING: could not add rate-limited nftables rule' \
|
|
"a failed public rule add warns instead of aborting"
|
|
BIND_ADDR="10.8.0.1"
|
|
|
|
# --- run_check --------------------------------------------------------------
|
|
# Everything healthy: stunnel active, port listening, cert present.
|
|
printf '#!/usr/bin/env bash\nexit 0\n' >"$TEST_TMPDIR/bin/systemctl"
|
|
chmod +x "$TEST_TMPDIR/bin/systemctl"
|
|
printf '#!/usr/bin/env bash\nprintf "LISTEN 0 0 10.8.0.1:%s\\n"\n' "$DOT_PORT" >"$TEST_TMPDIR/bin/ss"
|
|
chmod +x "$TEST_TMPDIR/bin/ss"
|
|
install -m 600 /dev/null "$CERT_DIR/combined.pem"
|
|
printf 'cert\n' >"$CERT_DIR/combined.pem"
|
|
if run_check >/dev/null 2>&1; then
|
|
_t_pass "run_check passes on a healthy install"
|
|
else
|
|
_t_fail "run_check passes on a healthy install"
|
|
fi
|
|
|
|
# stunnel down: must fail and say which check failed.
|
|
printf '#!/usr/bin/env bash\n[[ $* == *is-active* ]] && exit 1\nexit 0\n' >"$TEST_TMPDIR/bin/systemctl"
|
|
chmod +x "$TEST_TMPDIR/bin/systemctl"
|
|
out="$(run_check 2>&1 || true)"
|
|
_t_has "$out" 'FAIL stunnel-dot.service not active' "a stopped stunnel is reported"
|
|
|
|
# Certificate missing: the check that must be run as root to be correct.
|
|
rm -f "$CERT_DIR/combined.pem"
|
|
printf '#!/usr/bin/env bash\nexit 0\n' >"$TEST_TMPDIR/bin/systemctl"
|
|
chmod +x "$TEST_TMPDIR/bin/systemctl"
|
|
out="$(run_check 2>&1 || true)"
|
|
_t_has "$out" 'FAIL certificate missing' "a missing certificate is reported"
|
|
|
|
# Nothing listening on the port.
|
|
printf '#!/usr/bin/env bash\nexit 0\n' >"$TEST_TMPDIR/bin/ss"
|
|
chmod +x "$TEST_TMPDIR/bin/ss"
|
|
out="$(run_check 2>&1 || true)"
|
|
_t_has "$out" 'FAIL nothing listening' "a silent port is reported"
|
|
|
|
# kdig present and the DoT query failing. The check is skipped entirely when
|
|
# kdig is absent, so this arm only exists on a host that has knot-utils --
|
|
# which makes it exactly the arm most likely to rot unnoticed.
|
|
printf '#!/usr/bin/env bash\nexit 1\n' >"$TEST_TMPDIR/bin/kdig"
|
|
chmod +x "$TEST_TMPDIR/bin/kdig"
|
|
printf 'cert\n' >"$CERT_DIR/combined.pem"
|
|
printf '#!/usr/bin/env bash\nprintf "LISTEN 0 0 10.8.0.1:%s\\n"\n' "$DOT_PORT" >"$TEST_TMPDIR/bin/ss"
|
|
chmod +x "$TEST_TMPDIR/bin/ss"
|
|
out="$(run_check 2>&1 || true)"
|
|
_t_has "$out" 'FAIL DoT query did not answer' "an unanswered DoT query is reported"
|
|
|
|
_t_report "test_dot_resolver_install.sh"
|