feat(safety): add atomic WireGuard mutation and rollback engine

This commit is contained in:
2026-10-12 23:04:22 +03:00
parent e5e3064885
commit 4e3c5347f2
10 changed files with 1122 additions and 6 deletions
+44 -1
View File
@@ -6,10 +6,53 @@ allow_empty=${MOCK_ALLOW_EMPTY_INVOCATION:-}
printf '%q' "$command_name" >>"$TEST_MOCK_LOG"
for argument in "$@"; do printf ' %q' "$argument" >>"$TEST_MOCK_LOG"; done
printf '\n' >>"$TEST_MOCK_LOG"
if [[ $# == 3 && $1 == show && -n ${WG_MOCK_INTERFACE:-} && $2 == "$WG_MOCK_INTERFACE" && $3 == dump && -n ${WG_MOCK_DUMP_FILE:-} && -f $WG_MOCK_DUMP_FILE ]]; then
if [[ $# == 3 && $1 == show && -n ${WG_MOCK_INTERFACE:-} && $2 == "$WG_MOCK_INTERFACE" && $3 == dump && -z ${WG_MOCK_DUMP_SEQUENCE_DIR:-} && -n ${WG_MOCK_DUMP_FILE:-} && -f $WG_MOCK_DUMP_FILE ]]; then
if [[ -n ${WG_MOCK_DUMP_FAIL_ON_CALL:-} ]]; then
dump_counter=${WG_MOCK_DUMP_FAIL_COUNTER_FILE:-${TEST_ROOT}/dump-counter}
dump_calls=0; [[ -f $dump_counter ]] && read -r dump_calls <"$dump_counter"; ((dump_calls += 1)); printf '%s\n' "$dump_calls" >"$dump_counter"
[[ $dump_calls != "$WG_MOCK_DUMP_FAIL_ON_CALL" ]] || exit 98
fi
cat -- "$WG_MOCK_DUMP_FILE"
exit 0
fi
if [[ $# == 3 && $1 == show && -n ${WG_MOCK_INTERFACE:-} && $2 == "$WG_MOCK_INTERFACE" && $3 == dump && -n ${WG_MOCK_DUMP_SEQUENCE_DIR:-} ]]; then
[[ ${WG_MOCK_DUMP_SEQUENCE_DIR} == "${TEST_ROOT}"/* && -d ${WG_MOCK_DUMP_SEQUENCE_DIR} && ! -L ${WG_MOCK_DUMP_SEQUENCE_DIR} ]] || exit 99
sequence_counter=${WG_MOCK_DUMP_SEQUENCE_DIR}/counter
[[ ! -L "$sequence_counter" && ( -f "$sequence_counter" || ! -e "$sequence_counter" ) ]] || exit 99
sequence_number=0
[[ -f "$sequence_counter" ]] && read -r sequence_number <"$sequence_counter"
((sequence_number += 1))
printf '%s\n' "$sequence_number" >"$sequence_counter"
sequence_file=${WG_MOCK_DUMP_SEQUENCE_DIR}/${sequence_number}
[[ -f "$sequence_file" ]] && cat -- "$sequence_file" && exit 0
printf 'Mock wg dump sequence exhausted\n' >&2
exit 98
fi
if [[ $# == 3 && $1 == syncconf ]]; then
[[ -n ${WG_MOCK_INTERFACE:-} && $2 == "$WG_MOCK_INTERFACE" ]] || { printf 'Mock wg wrong interface\n' >&2; exit 99; }
if [[ ${WG_SYNC_FAIL_ONCE_FILE:-} && ! -e ${WG_SYNC_FAIL_ONCE_FILE} ]]; then
: >"$WG_SYNC_FAIL_ONCE_FILE"
printf 'Mock wg syncconf failure once\n' >&2
exit 97
fi
if [[ -n ${WG_SYNC_FAIL_ON_CALL:-} ]]; then
sync_counter=${WG_SYNC_FAIL_COUNTER_FILE:-${TEST_ROOT}/sync-counter}
sync_calls=0; [[ -f $sync_counter ]] && read -r sync_calls <"$sync_counter"; ((sync_calls += 1)); printf '%s\n' "$sync_calls" >"$sync_counter"
[[ $sync_calls != "$WG_SYNC_FAIL_ON_CALL" ]] || { printf 'Mock wg syncconf failure\n' >&2; exit 97; }
fi
[[ -f $3 && ! -L $3 && ${WG_SYNC_FAIL:-0} != 1 && -n ${TEST_ROOT:-} && $3 == "${TEST_ROOT}"/* ]] || { printf 'Mock wg syncconf failure\n' >&2; exit 97; }
[[ $(stat -c '%a' -- "$3") == 600 ]] || { printf 'Mock wg syncconf unsafe mode\n' >&2; exit 97; }
if [[ -n ${WG_SYNC_EXPECTED_STRIP:-} ]]; then
[[ -f $WG_SYNC_EXPECTED_STRIP ]] || exit 97
cmp -s -- "$3" "$WG_SYNC_EXPECTED_STRIP" || { printf 'Mock wg syncconf unexpected stripped content\n' >&2; exit 97; }
fi
if [[ -n ${WG_SYNC_READY_FIFO:-} ]]; then
[[ ${WG_SYNC_READY_FIFO} == "${TEST_ROOT}"/* && -p ${WG_SYNC_READY_FIFO} && ${WG_SYNC_RELEASE_FIFO:-} == "${TEST_ROOT}"/* && -p ${WG_SYNC_RELEASE_FIFO} ]] || exit 99
printf 'ready\n' >"$WG_SYNC_READY_FIFO"
IFS= read -r _ <"${WG_SYNC_RELEASE_FIFO:?WG_SYNC_RELEASE_FIFO must be set}"
fi
exit 0
fi
if [[ -n "$allow_empty" && "$allow_empty" != "$command_name" ]]; then
printf 'Unexpected mock invocation: %s does not allow empty calls for %s\n' "$command_name" "$allow_empty" >&2
exit 99