test: add isolated Bash test harness and project skeleton
This commit is contained in:
+18
@@ -1,2 +1,20 @@
|
|||||||
/.idea/
|
/.idea/
|
||||||
/.obsidian/
|
/.obsidian/
|
||||||
|
|
||||||
|
# Local administrator configuration and runtime data
|
||||||
|
/wg-manager.conf
|
||||||
|
/backups/
|
||||||
|
/logs/
|
||||||
|
/state/
|
||||||
|
/bin/gum
|
||||||
|
|
||||||
|
# Generated client material
|
||||||
|
*.key
|
||||||
|
*.pub
|
||||||
|
*.psk
|
||||||
|
*-client-*.conf
|
||||||
|
*.conf.tmp
|
||||||
|
|
||||||
|
# Isolated test output
|
||||||
|
/tests/tmp/
|
||||||
|
/tests/output/
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ Allowed status values: `NOT STARTED`, `IN PROGRESS`, `BLOCKED`, `DONE`.
|
|||||||
|
|
||||||
| Milestone | Status | Outcome |
|
| Milestone | Status | Outcome |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| M0 | NOT STARTED | Test harness and safe project skeleton |
|
| M0 | DONE | Test harness and safe project skeleton |
|
||||||
| M1 | NOT STARTED | Runtime foundation, CLI shell, and config loading |
|
| M1 | NOT STARTED | Runtime foundation, CLI shell, and config loading |
|
||||||
| M2 | NOT STARTED | WireGuard parser, client model, `status`, and `list` |
|
| M2 | NOT STARTED | WireGuard parser, client model, `status`, and `list` |
|
||||||
| M3 | NOT STARTED | Locking, backups, atomic apply, and rollback engine |
|
| M3 | NOT STARTED | Locking, backups, atomic apply, and rollback engine |
|
||||||
@@ -1551,6 +1551,20 @@ Use this template:
|
|||||||
- Next milestone: My
|
- Next milestone: My
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 2026-10-11 — M0 — DONE
|
||||||
|
|
||||||
|
- Implemented: strict source-safe `wg-manager.sh` help shell, placeholder configuration, runtime ignores, isolated pure-Bash test harness, minimal WireGuard fixture, and deny-by-default logged mocks for all planned external commands.
|
||||||
|
- Coordinator: `gpt-5.6-sol` (`high`)
|
||||||
|
- Subagents: `milestone_worker` / `milestone_repairer`, `gpt-5.6-luna` (`medium`)
|
||||||
|
- Repair cycles: 2
|
||||||
|
- Sol review: replaced a tautological host-path check with a recursive pure-Bash guard; made mocks deny empty calls unless explicitly authorized and assert exact invocation logs; removed an unused production path variable, added a narrow ShellCheck source directive, and cleared unintended index staging.
|
||||||
|
- Verification: `bash -n wg-manager.sh`, `bash -n tests/run.sh`, `bash -n tests/helpers.sh`, `bash -n tests/mocks/bin/*`, `bash tests/run.sh`, `./wg-manager.sh help`, `(cd /tmp && /home/sasa/share/bash/wireguard-scripts/wg-manager.sh help)`, `git diff --check`, `git diff --no-index --check /dev/null <new-file>`, `git status --short`
|
||||||
|
- Result: all required checks passed; 13 test assertions passed; unknown commands and extra arguments returned status 64; executable modes and isolated mock behavior were verified. Optional `shellcheck wg-manager.sh tests/run.sh tests/helpers.sh tests/mocks/bin/*` was `SKIP` because ShellCheck is unavailable.
|
||||||
|
- Decisions: none
|
||||||
|
- Known limitations: real WireGuard, networking, service, firewall, route, sysctl, journal, and deployment-server checks were not run; M0 verification is fixture- and mock-based as required.
|
||||||
|
- Suggested commit message: `test: add isolated Bash test harness and project skeleton`
|
||||||
|
- Next milestone: M1
|
||||||
|
|
||||||
# 8. Final completion rule
|
# 8. Final completion rule
|
||||||
|
|
||||||
The MVP is complete only when:
|
The MVP is complete only when:
|
||||||
|
|||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
[Interface]
|
||||||
|
Address = 192.0.2.1/24
|
||||||
|
ListenPort = 51820
|
||||||
|
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
# Non-secret fixture placeholder; not used against a live host.
|
||||||
|
PublicKey = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=
|
||||||
|
AllowedIPs = 192.0.2.2/32
|
||||||
Executable
+97
@@ -0,0 +1,97 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
readonly HELPERS_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
readonly PROJECT_DIR="$(cd -- "${HELPERS_DIR}/.." && pwd)"
|
||||||
|
TEST_ROOT=''
|
||||||
|
TEST_MOCK_LOG=''
|
||||||
|
TEST_FAILURES=0
|
||||||
|
TEST_ASSERTIONS=0
|
||||||
|
|
||||||
|
setup_test_environment() {
|
||||||
|
TEST_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/wg-manager-tests.XXXXXX")"
|
||||||
|
TEST_MOCK_LOG="${TEST_ROOT}/mock-invocations.log"
|
||||||
|
: >"$TEST_MOCK_LOG"
|
||||||
|
chmod 700 "$TEST_ROOT"
|
||||||
|
cp -- "${PROJECT_DIR}/tests/fixtures/wg0.conf" "${TEST_ROOT}/wg0.conf"
|
||||||
|
export TEST_ROOT TEST_MOCK_LOG
|
||||||
|
export PATH="${PROJECT_DIR}/tests/mocks/bin:${PATH:-}"
|
||||||
|
trap cleanup_test_environment EXIT INT TERM
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_test_environment() {
|
||||||
|
local status=$?
|
||||||
|
trap - EXIT INT TERM
|
||||||
|
if [[ -n "$TEST_ROOT" && -d "$TEST_ROOT" ]]; then
|
||||||
|
rm -rf -- "$TEST_ROOT"
|
||||||
|
fi
|
||||||
|
return "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
begin_test() {
|
||||||
|
printf 'TEST %s\n' "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
record_failure() {
|
||||||
|
printf ' FAIL: %s\n' "$1" >&2
|
||||||
|
((TEST_FAILURES += 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal() {
|
||||||
|
local expected=$1 actual=$2 message=${3:-значения равны}
|
||||||
|
((TEST_ASSERTIONS += 1))
|
||||||
|
if [[ "$expected" != "$actual" ]]; then
|
||||||
|
record_failure "${message}: ожидалось [${expected}], получено [${actual}]"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_status() {
|
||||||
|
local expected=$1 actual=$2 message=${3:-код завершения}
|
||||||
|
assert_equal "$expected" "$actual" "$message"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_contains() {
|
||||||
|
local needle=$1 haystack=$2 message=${3:-строка содержит ожидаемый текст}
|
||||||
|
((TEST_ASSERTIONS += 1))
|
||||||
|
if [[ "$haystack" != *"$needle"* ]]; then
|
||||||
|
record_failure "${message}: не найдено [${needle}]"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_file_exists() {
|
||||||
|
local path=$1 message=${2:-файл существует}
|
||||||
|
((TEST_ASSERTIONS += 1))
|
||||||
|
if [[ ! -e "$path" ]]; then
|
||||||
|
record_failure "${message}: отсутствует [${path}]"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_file_mode() {
|
||||||
|
local expected=$1 path=$2 actual message
|
||||||
|
actual=$(stat -c '%a' -- "$path")
|
||||||
|
message=${3:-режим файла}
|
||||||
|
assert_equal "$expected" "$actual" "$message"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_success() {
|
||||||
|
local status=$1 message=${2:-команда успешна}
|
||||||
|
assert_status 0 "$status" "$message"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_failure() {
|
||||||
|
local status=$1 message=${2:-команда завершилась с ошибкой}
|
||||||
|
((TEST_ASSERTIONS += 1))
|
||||||
|
if (( status == 0 )); then
|
||||||
|
record_failure "$message: ожидался ненулевой код"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
finish_tests() {
|
||||||
|
if (( TEST_FAILURES == 0 )); then
|
||||||
|
printf 'PASS: %d проверок\n' "$TEST_ASSERTIONS"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
printf 'FAIL: %d ошибок из %d проверок\n' "$TEST_FAILURES" "$TEST_ASSERTIONS" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
command_name=${0##*/}
|
||||||
|
: "${TEST_MOCK_LOG:?TEST_MOCK_LOG must identify the isolated test log}"
|
||||||
|
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 [[ -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
|
||||||
|
fi
|
||||||
|
if [[ $# == 0 && "$allow_empty" == "$command_name" ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
printf 'Unexpected mock invocation: %s received arguments\n' "$command_name" >&2
|
||||||
|
exit 99
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
command_name=${0##*/}
|
||||||
|
: "${TEST_MOCK_LOG:?TEST_MOCK_LOG must identify the isolated test log}"
|
||||||
|
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 [[ -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
|
||||||
|
fi
|
||||||
|
if [[ $# == 0 && "$allow_empty" == "$command_name" ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
printf 'Unexpected mock invocation: %s received arguments\n' "$command_name" >&2
|
||||||
|
exit 99
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
command_name=${0##*/}
|
||||||
|
: "${TEST_MOCK_LOG:?TEST_MOCK_LOG must identify the isolated test log}"
|
||||||
|
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 [[ -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
|
||||||
|
fi
|
||||||
|
if [[ $# == 0 && "$allow_empty" == "$command_name" ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
printf 'Unexpected mock invocation: %s received arguments\n' "$command_name" >&2
|
||||||
|
exit 99
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
command_name=${0##*/}
|
||||||
|
: "${TEST_MOCK_LOG:?TEST_MOCK_LOG must identify the isolated test log}"
|
||||||
|
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 [[ -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
|
||||||
|
fi
|
||||||
|
if [[ $# == 0 && "$allow_empty" == "$command_name" ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
printf 'Unexpected mock invocation: %s received arguments\n' "$command_name" >&2
|
||||||
|
exit 99
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
command_name=${0##*/}
|
||||||
|
: "${TEST_MOCK_LOG:?TEST_MOCK_LOG must identify the isolated test log}"
|
||||||
|
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 [[ -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
|
||||||
|
fi
|
||||||
|
if [[ $# == 0 && "$allow_empty" == "$command_name" ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
printf 'Unexpected mock invocation: %s received arguments\n' "$command_name" >&2
|
||||||
|
exit 99
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
command_name=${0##*/}
|
||||||
|
: "${TEST_MOCK_LOG:?TEST_MOCK_LOG must identify the isolated test log}"
|
||||||
|
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 [[ -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
|
||||||
|
fi
|
||||||
|
if [[ $# == 0 && "$allow_empty" == "$command_name" ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
printf 'Unexpected mock invocation: %s received arguments\n' "$command_name" >&2
|
||||||
|
exit 99
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
command_name=${0##*/}
|
||||||
|
: "${TEST_MOCK_LOG:?TEST_MOCK_LOG must identify the isolated test log}"
|
||||||
|
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 [[ -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
|
||||||
|
fi
|
||||||
|
if [[ $# == 0 && "$allow_empty" == "$command_name" ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
printf 'Unexpected mock invocation: %s received arguments\n' "$command_name" >&2
|
||||||
|
exit 99
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
command_name=${0##*/}
|
||||||
|
: "${TEST_MOCK_LOG:?TEST_MOCK_LOG must identify the isolated test log}"
|
||||||
|
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 [[ -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
|
||||||
|
fi
|
||||||
|
if [[ $# == 0 && "$allow_empty" == "$command_name" ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
printf 'Unexpected mock invocation: %s received arguments\n' "$command_name" >&2
|
||||||
|
exit 99
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
command_name=${0##*/}
|
||||||
|
: "${TEST_MOCK_LOG:?TEST_MOCK_LOG must identify the isolated test log}"
|
||||||
|
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 [[ -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
|
||||||
|
fi
|
||||||
|
if [[ $# == 0 && "$allow_empty" == "$command_name" ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
printf 'Unexpected mock invocation: %s received arguments\n' "$command_name" >&2
|
||||||
|
exit 99
|
||||||
Executable
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
command_name=${0##*/}
|
||||||
|
: "${TEST_MOCK_LOG:?TEST_MOCK_LOG must identify the isolated test log}"
|
||||||
|
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 [[ -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
|
||||||
|
fi
|
||||||
|
if [[ $# == 0 && "$allow_empty" == "$command_name" ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
printf 'Unexpected mock invocation: %s received arguments\n' "$command_name" >&2
|
||||||
|
exit 99
|
||||||
Executable
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
command_name=${0##*/}
|
||||||
|
: "${TEST_MOCK_LOG:?TEST_MOCK_LOG must identify the isolated test log}"
|
||||||
|
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 [[ -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
|
||||||
|
fi
|
||||||
|
if [[ $# == 0 && "$allow_empty" == "$command_name" ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
printf 'Unexpected mock invocation: %s received arguments\n' "$command_name" >&2
|
||||||
|
exit 99
|
||||||
Executable
+85
@@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
readonly TESTS_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
# shellcheck source=helpers.sh
|
||||||
|
source "${TESTS_DIR}/helpers.sh"
|
||||||
|
|
||||||
|
setup_test_environment
|
||||||
|
|
||||||
|
begin_test 'sourcing entry point does not execute main'
|
||||||
|
source_output=$(bash -c 'source "$1"; printf sourced' _ "${PROJECT_DIR}/wg-manager.sh")
|
||||||
|
assert_equal sourced "$source_output" 'безопасная загрузка'
|
||||||
|
|
||||||
|
begin_test 'help succeeds without root or dependencies'
|
||||||
|
set +e
|
||||||
|
help_output=$("${PROJECT_DIR}/wg-manager.sh" help 2>&1)
|
||||||
|
help_status=$?
|
||||||
|
set -e
|
||||||
|
assert_success "$help_status" 'команда help'
|
||||||
|
assert_contains 'Использование:' "$help_output" 'справка'
|
||||||
|
|
||||||
|
begin_test 'unknown command fails'
|
||||||
|
set +e
|
||||||
|
unknown_output=$("${PROJECT_DIR}/wg-manager.sh" unknown 2>&1)
|
||||||
|
unknown_status=$?
|
||||||
|
set -e
|
||||||
|
assert_failure "$unknown_status" 'неизвестная команда'
|
||||||
|
assert_contains 'неизвестная команда' "$unknown_output" 'сообщение об ошибке'
|
||||||
|
|
||||||
|
begin_test 'help works outside project directory'
|
||||||
|
set +e
|
||||||
|
outside_output=$(cd /tmp && "${PROJECT_DIR}/wg-manager.sh" help 2>&1)
|
||||||
|
outside_status=$?
|
||||||
|
set -e
|
||||||
|
assert_success "$outside_status" 'запуск из /tmp'
|
||||||
|
assert_contains 'Использование:' "$outside_output" 'справка из /tmp'
|
||||||
|
|
||||||
|
begin_test 'mock guard accepts only explicitly supported empty invocation'
|
||||||
|
set +e
|
||||||
|
MOCK_ALLOW_EMPTY_INVOCATION=wg wg
|
||||||
|
expected_mock_status=$?
|
||||||
|
wg
|
||||||
|
unapproved_empty_status=$?
|
||||||
|
wg unexpected
|
||||||
|
unexpected_mock_status=$?
|
||||||
|
set -e
|
||||||
|
assert_success "$expected_mock_status" 'разрешённый вызов мока'
|
||||||
|
assert_failure "$unapproved_empty_status" 'неразрешённый пустой вызов мока'
|
||||||
|
assert_failure "$unexpected_mock_status" 'неожиданный вызов мока'
|
||||||
|
expected_mock_log=$'wg\nwg\nwg unexpected\n'
|
||||||
|
actual_mock_log=$(<"$TEST_MOCK_LOG")
|
||||||
|
actual_mock_log+=$'\n'
|
||||||
|
assert_equal "$expected_mock_log" "$actual_mock_log" 'точный журнал вызовов мока'
|
||||||
|
|
||||||
|
begin_test 'test writes stay below isolated root'
|
||||||
|
assert_file_exists "${TEST_ROOT}/wg0.conf" 'копия фикстуры'
|
||||||
|
assert_equal "$TEST_ROOT" "${TEST_MOCK_LOG%/*}" 'журнал находится в тестовом корне'
|
||||||
|
|
||||||
|
scan_test_sources_for_host_path() {
|
||||||
|
local forbidden_path='/etc'
|
||||||
|
forbidden_path+='/wireguard'
|
||||||
|
|
||||||
|
scan_path() {
|
||||||
|
local path line
|
||||||
|
for path in "$1"/*; do
|
||||||
|
if [[ -d "$path" ]]; then
|
||||||
|
scan_path "$path"
|
||||||
|
elif [[ -f "$path" ]]; then
|
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||||
|
if [[ "$line" == *"$forbidden_path"* ]]; then
|
||||||
|
record_failure "тестовый файл содержит запрещённый путь: ${path}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done <"$path"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
scan_path "$TESTS_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
scan_test_sources_for_host_path
|
||||||
|
|
||||||
|
finish_tests
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Safe example configuration. Copy to wg-manager.conf and review before use.
|
||||||
|
WG_INTERFACE="wg0"
|
||||||
|
WG_CONF="/etc/wireguard/wg0.conf"
|
||||||
|
CLIENT_DIR="/etc/wireguard/clients"
|
||||||
|
|
||||||
|
SERVER_ENDPOINT="vpn.example.invalid"
|
||||||
|
SERVER_PORT="51820"
|
||||||
|
SERVER_VPN_IP="192.0.2.1"
|
||||||
|
CLIENT_DNS="192.0.2.53"
|
||||||
|
|
||||||
|
VPN_SUBNET_PREFIX="192.0.2"
|
||||||
|
START_HOST="2"
|
||||||
|
END_HOST="254"
|
||||||
|
|
||||||
|
USE_IPV6="0"
|
||||||
|
IPV6_PREFIX="2001:db8:ffff::"
|
||||||
|
|
||||||
|
DEFAULT_CLIENT_MODE="full-tunnel"
|
||||||
|
RECENT_HANDSHAKE_SECONDS="180"
|
||||||
Executable
+35
@@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
print_usage() {
|
||||||
|
cat <<'USAGE'
|
||||||
|
Использование:
|
||||||
|
wg-manager.sh help
|
||||||
|
|
||||||
|
Команды WireGuard Manager будут добавлены в следующих версиях.
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
if (( $# != 1 )); then
|
||||||
|
printf 'Ошибка: ожидается одна команда.\n' >&2
|
||||||
|
print_usage >&2
|
||||||
|
return 64
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
help)
|
||||||
|
print_usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'Ошибка: неизвестная команда: %s\n' "$1" >&2
|
||||||
|
print_usage >&2
|
||||||
|
return 64
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
||||||
|
main "$@"
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user