mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 19:07:04 +01:00
The bind-mount logic goes to hosts_mount.sh, the Magisk-module and
cache-invalidation logic to hosts_magisk.sh. Both flat siblings, both in
both deploy lists; the two lists were then checked to correspond exactly
in both directions, since a push with no matching cp stages a file that
never lands and the enforcer would fail to source it.
Audited for stdin-draining `while read` loops BEFORE extracting, because
piping one would change behaviour in a way stubs cannot catch. There are
none here. Also confirmed no function writes a global, so there was no
cross-half hazard of the kind that kept NET_BUILT in curfew_enforcer.sh.
69 assertions, 43/43 and 62/62 lines, 17 mutations all killed. Two survived
the first run and both were real findings:
- the unmount give-up threshold was not pinned. Raising it from 5 to 500
changed nothing observable, so the enforcer could have spun 500 times
per poll against a mount that was never going to clear. Now asserted as
a call count.
- the `[ ! -f $HOSTS_TARGET ] && return 1` guard in
is_bind_mounted_correctly is PROVABLY EQUIVALENT: sha256_of returns
empty for a missing file, so the existing -n check already rejects that
case. No test can distinguish it. Equivalent code is a claim of a check
that is not being made, so it is deleted rather than covered by a test
that would pass either way. Old and new bodies were compared across all
four input states -- both-missing, target-missing, match, mismatch --
and agree on every one.
That deletion is the only non-verbatim function; the other 19 moved
untouched, making this the first fully verbatim extraction of the session.
Ordering is asserted where it is load-bearing: /system must go back to ro
after rw, and +i must be restored after being dropped. Presence assertions
alone would pass with either pair reversed.
UNVERIFIED ON DEVICE -- the highest-stakes of the four enforcer splits now
outstanding, since a failure to source leaves nothing blocking while the
phone looks normal. Over-cap count 20 -> 19.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
150 lines
5.5 KiB
Bash
Executable File
150 lines
5.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# lib/tests/hosts_cases_cache.sh — assertions for the cache-invalidation half
|
|
# of hosts_magisk.sh: force-stopping browsers so their in-process DNS caches
|
|
# clear, holding the canonical files immutable, and restarting netd so its
|
|
# in-memory copy of the hosts file is reloaded.
|
|
#
|
|
# Sourced by test_hosts_libs.sh after hosts_cases_magisk.sh, which owns the
|
|
# stubs and counters. Split out to stay under the 250-line cap.
|
|
set -euo pipefail
|
|
|
|
# --- flush_browser_dns_caches ----------------------------------------------
|
|
|
|
_reset_dev
|
|
flush_browser_dns_caches
|
|
calls="$(_calls)"
|
|
for pkg in org.mozilla.fenix com.android.chrome; do
|
|
case "${calls}" in
|
|
*"am force-stop ${pkg}"*) _t_pass "flush force-stops ${pkg}" ;;
|
|
*) _t_fail "flush must force-stop ${pkg}" ;;
|
|
esac
|
|
done
|
|
case "$(_log)" in
|
|
*"Flushed DNS cache"*) _t_pass "flush logs each browser it stopped" ;;
|
|
*) _t_fail "flush should log the browsers it stopped" ;;
|
|
esac
|
|
|
|
# A browser that is not running must not be reported as flushed.
|
|
_reset_dev
|
|
_fail_op am
|
|
flush_browser_dns_caches
|
|
if _log | grep -q "Flushed DNS cache"; then
|
|
_t_fail "flush claimed to stop a browser that was not running"
|
|
else
|
|
_t_pass "flush stays quiet when no browser was running"
|
|
fi
|
|
_clear_fail am
|
|
|
|
# --- ensure_canonical_immutable --------------------------------------------
|
|
|
|
_reset_dev
|
|
printf '127.0.0.1 blocked.example\n' >"${HOSTS_CANONICAL}"
|
|
rm -f "${HOSTS_CANONICAL_WORKOUT}"
|
|
ensure_canonical_immutable
|
|
case "$(_calls)" in
|
|
*"chattr +i ${HOSTS_CANONICAL}"*) _t_pass "immutable locks the active canonical" ;;
|
|
*) _t_fail "immutable must lock the canonical" ;;
|
|
esac
|
|
if _calls | grep -qF "chattr +i ${HOSTS_CANONICAL_WORKOUT}"; then
|
|
_t_fail "immutable locked a workout canonical that does not exist"
|
|
else
|
|
_t_pass "immutable skips a workout canonical that is absent"
|
|
fi
|
|
|
|
# Both variants are locked when both exist, so a later workout transition is
|
|
# just as tamper-resistant as the current state.
|
|
_reset_dev
|
|
printf '127.0.0.1 workout\n' >"${HOSTS_CANONICAL_WORKOUT}"
|
|
ensure_canonical_immutable
|
|
case "$(_calls)" in
|
|
*"chattr +i ${HOSTS_CANONICAL_WORKOUT}"*) _t_pass "immutable locks the workout canonical too" ;;
|
|
*) _t_fail "immutable must lock both canonical variants" ;;
|
|
esac
|
|
|
|
# --- restart_netd_for_hosts_cache ------------------------------------------
|
|
|
|
# netd not running: nothing to restart, and no stamp written.
|
|
_reset_dev
|
|
rm -f "${STATE_DIR}/netd_restart.pid"
|
|
restart_netd_for_hosts_cache
|
|
if [[ -f "${STATE_DIR}/netd_restart.pid" ]]; then
|
|
_t_fail "netd restart stamped a pid when netd was not running"
|
|
else
|
|
_t_pass "netd restart does nothing when netd is not running"
|
|
fi
|
|
|
|
# Same pid as last time: already restarted this boot, so skip the network
|
|
# blip. This is the check that keeps an enforcer restart from cycling netd.
|
|
_reset_dev
|
|
printf '4242\n' >"${DEV}/netd_pid"
|
|
printf '4242\n' >"${STATE_DIR}/netd_restart.pid"
|
|
restart_netd_for_hosts_cache
|
|
if _calls | grep -q "^stop netd"; then
|
|
_t_fail "netd was restarted again for a pid already stamped"
|
|
else
|
|
_t_pass "netd restart is skipped when the pid is unchanged"
|
|
fi
|
|
|
|
# A real Firefox profile (one containing prefs.js) gets the DoH-disable pref.
|
|
# Firefox reaches its DoH resolver over hardcoded bootstrap IPs, so the hosts
|
|
# file alone does not stop it — this pref is what does.
|
|
_reset_dev
|
|
real_profile="${FENIX_DIR}/abc123.default/"
|
|
mkdir -p "${real_profile}"
|
|
printf 'user_pref("x", 1);\n' >"${real_profile}prefs.js"
|
|
disable_firefox_doh
|
|
if grep -qF 'user_pref("network.trr.mode", 5);' "${real_profile}user.js" 2>/dev/null; then
|
|
_t_pass "firefox DoH writes the trr.mode pref to a real profile"
|
|
else
|
|
_t_fail "firefox DoH must write the trr.mode pref"
|
|
fi
|
|
case "$(_log)" in
|
|
*"Wrote DoH-disable pref"*) _t_pass "firefox DoH logs the profile it wrote" ;;
|
|
*) _t_fail "firefox DoH should log the write" ;;
|
|
esac
|
|
|
|
# Already present: the pref must not be appended twice on every flush.
|
|
_reset_dev
|
|
disable_firefox_doh
|
|
_t_eq "1" "$(grep -cF 'network.trr.mode' "${real_profile}user.js")" \
|
|
"firefox DoH does not duplicate an existing pref"
|
|
if _log | grep -q "Wrote DoH-disable pref"; then
|
|
_t_fail "firefox DoH logged a write it did not perform"
|
|
else
|
|
_t_pass "firefox DoH stays quiet when the pref is already set"
|
|
fi
|
|
|
|
# --- restart_netd_for_hosts_cache, the restart path -------------------------
|
|
|
|
# A different pid than last stamped means netd has been cycled since our last
|
|
# restart, so the hosts cache is stale again and must be reloaded.
|
|
_reset_dev
|
|
printf '5555\n' >"${DEV}/netd_pid"
|
|
printf '1111\n' >"${STATE_DIR}/netd_restart.pid"
|
|
restart_netd_for_hosts_cache
|
|
|
|
calls="$(_calls)"
|
|
case "${calls}" in
|
|
*"stop netd"*) _t_pass "netd restart stops netd when the pid changed" ;;
|
|
*) _t_fail "netd restart must stop netd on a changed pid" ;;
|
|
esac
|
|
case "${calls}" in
|
|
*"start netd"*) _t_pass "netd restart starts netd again" ;;
|
|
*) _t_fail "netd restart must start netd again" ;;
|
|
esac
|
|
|
|
stop_line="$(printf '%s\n' "${calls}" | grep -n "^stop netd" | head -1 | cut -d: -f1)"
|
|
start_line="$(printf '%s\n' "${calls}" | grep -n "^start netd" | head -1 | cut -d: -f1)"
|
|
if [[ "${start_line}" -gt "${stop_line}" ]]; then
|
|
_t_pass "netd restart starts only after it has stopped"
|
|
else
|
|
_t_fail "netd restart must stop before it starts"
|
|
fi
|
|
|
|
_t_eq "5555" "$(cat "${STATE_DIR}/netd_restart.pid")" \
|
|
"netd restart stamps the new pid so the next tick skips the work"
|
|
case "$(_log)" in
|
|
*"hosts cache is now live"*) _t_pass "netd restart logs completion" ;;
|
|
*) _t_fail "netd restart should log completion" ;;
|
|
esac
|