feat(clients): add client details and secure config export
This commit is contained in:
+313
-1
@@ -11,7 +11,7 @@ source "${PROJECT_DIR}/wg-manager.sh"
|
||||
|
||||
case $# in
|
||||
0) ;;
|
||||
1) case $1 in config|parser|status|list|list-redirected|list-deterministic|transaction|rollback|locking|backups|mutation-preserves-source|secret-modes|add-client|address-allocation|add-collisions|add-rollback|no-secret-logs|add-golden-config|add-invalid-names) ;; *) printf 'Ошибка: неизвестная группа тестов или лишние аргументы\n' >&2; exit 64 ;; esac ;;
|
||||
1) case $1 in config|parser|status|list|list-redirected|list-deterministic|transaction|rollback|locking|backups|mutation-preserves-source|secret-modes|add-client|address-allocation|add-collisions|add-rollback|no-secret-logs|add-golden-config|add-invalid-names|show-client|config-export|qr|path-safety|no-secret-default-output) ;; *) printf 'Ошибка: неизвестная группа тестов или лишние аргументы\n' >&2; exit 64 ;; esac ;;
|
||||
*) printf 'Ошибка: неизвестная группа тестов или лишние аргументы\n' >&2; exit 64 ;;
|
||||
esac
|
||||
test_group=${1-}
|
||||
@@ -830,6 +830,7 @@ transaction_builder_symlink() {
|
||||
|
||||
run_m4_tests() {
|
||||
local config_file="${TEST_ROOT}/m4.conf" fixture="${TEST_ROOT}/wg0.conf" runtime_file="${TEST_ROOT}/runtime.dump" status output before
|
||||
unset TRANSACTION_FINALIZER TRANSACTION_ROLLBACK_ACTIVE ADD_PUBLISH_READY_FIFO ADD_PUBLISH_RELEASE_FIFO ADD_PUBLISH_PID_FILE ADD_PUBLISH_READY_INDEX ADD_PUBLISH_FAIL ADD_PUBLISH_RACE TRANSACTION_ADD_STAGE_FAIL TRANSACTION_ADD_DIRECTORY_FAIL
|
||||
cp -- "${PROJECT_DIR}/tests/fixtures/m3/source.conf" "$fixture"
|
||||
write_m2_config "$config_file" "$fixture"
|
||||
export WG_MANAGER_CONFIG="$config_file" WG_MANAGER_BACKUP_DIR="${TEST_ROOT}/backups" WG_MANAGER_LOG_DIR="${TEST_ROOT}/logs" WG_MANAGER_METADATA_DIR="${TEST_ROOT}/metadata" WG_MANAGER_ARCHIVE_DIR="${TEST_ROOT}/archive" WG_MANAGER_LOCK_FILE="${TEST_ROOT}/lock" WG_MANAGER_NOW=1700000100 WG_MANAGER_TEST_MODE=1 WG_MOCK_INTERFACE=wg0
|
||||
@@ -1234,6 +1235,312 @@ EOF
|
||||
esac
|
||||
}
|
||||
|
||||
run_m5_tests() {
|
||||
local config_file="${TEST_ROOT}/m5.conf" fixture="${TEST_ROOT}/wg0.conf" runtime_file="${TEST_ROOT}/runtime.dump" status output expected qr_path mode
|
||||
cp -- "${PROJECT_DIR}/tests/fixtures/m3/source.conf" "$fixture"
|
||||
write_m2_config "$config_file" "$fixture"
|
||||
export WG_MANAGER_CONFIG="$config_file" WG_MANAGER_BACKUP_DIR="${TEST_ROOT}/backups" WG_MANAGER_LOG_DIR="${TEST_ROOT}/logs" WG_MANAGER_METADATA_DIR="${TEST_ROOT}/metadata" WG_MANAGER_ARCHIVE_DIR="${TEST_ROOT}/archive" WG_MANAGER_LOCK_FILE="${TEST_ROOT}/lock" WG_MANAGER_TEST_MODE=1 WG_MOCK_INTERFACE=wg0
|
||||
printf 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\t51820\t0\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=\t(none)\tvpn.example.invalid:51820\t192.0.2.2/32\t0\t0\t0\t0\nFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF=\t(none)\tvpn.example.invalid:51820\t192.0.2.3/32\t0\t0\t0\t0\n' >"$runtime_file"
|
||||
rm -rf -- "${TEST_ROOT}/dump-sequence"; mkdir -p "${TEST_ROOT}/dump-sequence"; cp -- "$runtime_file" "${TEST_ROOT}/dump-sequence/1"; cp -- "${PROJECT_DIR}/tests/fixtures/m3/runtime.dump" "${TEST_ROOT}/dump-sequence/2"
|
||||
export WG_MOCK_DUMP_FILE="$runtime_file" WG_MOCK_DUMP_SEQUENCE_DIR="${TEST_ROOT}/dump-sequence"
|
||||
unset WG_SYNC_FAIL WG_SYNC_FAIL_ONCE_FILE WG_SYNC_FAIL_ON_CALL WG_SYNC_FAIL_COUNTER_FILE WG_QUICK_STRIP_FAIL QR_MOCK_FAIL TRANSACTION_ADD_STAGE_FAIL TRANSACTION_ADD_DIRECTORY_FAIL ADD_PUBLISH_FAIL ADD_PUBLISH_RACE
|
||||
set_runtime_paths; load_config; rm -rf -- "$METADATA_DIR" "$CLIENT_DIR"; mkdir -p "$METADATA_DIR" "$CLIENT_DIR"
|
||||
add_client alice >/dev/null
|
||||
: >"$TEST_MOCK_LOG"
|
||||
case $test_group in
|
||||
''|show-client|no-secret-default-output)
|
||||
begin_test 'show exposes only non-secret managed details'
|
||||
set +e; output=$(show_client alice 2>&1); status=$?; set -e
|
||||
assert_equal 0 "$status" 'show succeeds'
|
||||
assert_contains 'Имя: alice' "$output" 'show name'
|
||||
assert_contains 'Путь конфигурации:' "$output" 'show validated path'
|
||||
assert_equal '' "$(grep -E 'PrivateKey|PresharedKey|EEEE|GGGG' <<<"$output" || true)" 'show without secrets'
|
||||
local cli_stdout="${TEST_ROOT}/cli.stdout" cli_stderr="${TEST_ROOT}/cli.stderr"
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" show alice >"$cli_stdout" 2>"$cli_stderr"; status=$?; set -e
|
||||
assert_equal 0 "$status" 'CLI show succeeds'
|
||||
assert_contains 'Имя: alice' "$(<"$cli_stdout")" 'CLI show name'
|
||||
assert_contains 'Публичный ключ:' "$(<"$cli_stdout")" 'CLI show public key'
|
||||
assert_contains 'Адреса:' "$(<"$cli_stdout")" 'CLI show addresses'
|
||||
assert_contains 'Endpoint:' "$(<"$cli_stdout")" 'CLI show endpoint'
|
||||
assert_contains 'Последний handshake:' "$(<"$cli_stdout")" 'CLI show handshake'
|
||||
assert_contains 'RX:' "$(<"$cli_stdout")" 'CLI show RX'
|
||||
assert_contains 'TX:' "$(<"$cli_stdout")" 'CLI show TX'
|
||||
assert_contains 'Режим:' "$(<"$cli_stdout")" 'CLI show mode'
|
||||
assert_contains 'Создан:' "$(<"$cli_stdout")" 'CLI show creation time'
|
||||
assert_contains 'Происхождение: managed' "$(<"$cli_stdout")" 'CLI show origin'
|
||||
assert_equal '' "$(<"$cli_stderr")" 'CLI show stderr clean'
|
||||
assert_equal '' "$(grep -E 'PrivateKey|PresharedKey|EEEE|GGGG' "$cli_stdout" || true)" 'CLI show secret-free'
|
||||
assert_equal '' "$(grep -F $'\033' "$cli_stdout" || true)" 'CLI show has no ANSI'
|
||||
for cli_args in 'show' 'config' 'qr'; do
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" $cli_args >"$cli_stdout" 2>"$cli_stderr"; status=$?; set -e
|
||||
assert_equal "$EXIT_USAGE" "$status" "CLI ${cli_args} missing name"
|
||||
done
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" show absent >/dev/null 2>"$cli_stderr"; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'CLI missing client name validation'
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" show alice extra >/dev/null 2>&1; status=$?; set -e
|
||||
assert_equal "$EXIT_USAGE" "$status" 'CLI show extra argument'
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" qr alice extra >/dev/null 2>&1; status=$?; set -e
|
||||
assert_equal "$EXIT_USAGE" "$status" 'CLI qr extra argument'
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" config alice --show --show >/dev/null 2>&1; status=$?; set -e
|
||||
assert_equal "$EXIT_USAGE" "$status" 'CLI duplicate config show'
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" show fixture >"$cli_stdout" 2>"$cli_stderr"; status=$?; set -e
|
||||
assert_equal 0 "$status" 'CLI show legacy peer succeeds'
|
||||
assert_contains 'Происхождение: legacy' "$(<"$cli_stdout")" 'legacy origin shown'
|
||||
assert_equal '' "$(grep -F 'Путь конфигурации:' "$cli_stdout" || true)" 'legacy has no config path'
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" config fixture >/dev/null 2>"$cli_stderr"; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'legacy config export rejected'
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" qr fixture >/dev/null 2>"$cli_stderr"; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'legacy QR rejected'
|
||||
begin_test 'ambiguous legacy and mismatched identities never grant access'
|
||||
cp -- "${PROJECT_DIR}/tests/fixtures/m3/source.conf" "$fixture"
|
||||
cat >>"$fixture" <<'EOF'
|
||||
|
||||
[Peer]
|
||||
### Client fixture
|
||||
PublicKey = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF=
|
||||
AllowedIPs = 192.0.2.3/32
|
||||
EOF
|
||||
printf 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\t51820\t0\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=\t(none)\tvpn.example.invalid:51820\t192.0.2.2/32\t0\t0\t0\t0\nFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF=\t(none)\tvpn.example.invalid:51820\t192.0.2.3/32\t0\t0\t0\t0\n' >"$runtime_file"
|
||||
unset WG_MOCK_DUMP_SEQUENCE_DIR
|
||||
export WG_MOCK_DUMP_FILE="$runtime_file"
|
||||
rm -f -- "${METADATA_DIR}/alice.meta"
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" show fixture >/dev/null 2>"$cli_stderr"; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'duplicate legacy name is ambiguous'
|
||||
assert_equal '' "$(grep -E 'EEEE|GGGG|PrivateKey|PresharedKey|sentinel' "$cli_stderr" || true)" 'ambiguous identity diagnostic is secret-free'
|
||||
write_alice_metadata
|
||||
replace_config_line "${METADATA_DIR}/alice.meta" 'IPV4=' 'IPV4=192.0.2.99'
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" show alice >/dev/null 2>"$cli_stderr"; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'mismatched metadata address is rejected'
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" config alice >/dev/null 2>"$cli_stderr"; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'mismatched metadata config is rejected'
|
||||
write_alice_metadata
|
||||
replace_config_line "${METADATA_DIR}/alice.meta" 'PUBLIC_KEY=' 'PUBLIC_KEY=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH='
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" qr alice >/dev/null 2>"$cli_stderr"; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'mismatched metadata key QR is rejected'
|
||||
cp -- "${PROJECT_DIR}/tests/fixtures/m3/source.conf" "$fixture"
|
||||
write_alice_metadata
|
||||
replace_config_line "${METADATA_DIR}/alice.meta" 'PUBLIC_KEY=' 'PUBLIC_KEY=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF='
|
||||
replace_config_line "${METADATA_DIR}/alice.meta" 'IPV4=' 'IPV4=192.0.2.3'
|
||||
printf 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\t51820\t0\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=\t(none)\tvpn.example.invalid:51820\t192.0.2.2/32\t0\t0\t0\t0\nFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF=\t(none)\tvpn.example.invalid:51820\t192.0.2.3/32\t0\t0\t0\t0\n' >"$runtime_file"
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" show alice >/dev/null 2>"$cli_stderr"; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'runtime-only peer cannot use metadata path'
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" config alice >/dev/null 2>"$cli_stderr"; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'runtime-only peer config is rejected'
|
||||
set +e; "${PROJECT_DIR}/wg-manager.sh" qr alice >/dev/null 2>"$cli_stderr"; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'runtime-only peer QR is rejected'
|
||||
set -e
|
||||
if [[ $- == *e* ]]; then runtime_errexit=1; else runtime_errexit=0; fi
|
||||
assert_equal 1 "$runtime_errexit" 'errexit enabled before runtime load'
|
||||
load_runtime_state
|
||||
if [[ $- == *e* ]]; then runtime_errexit=1; else runtime_errexit=0; fi
|
||||
assert_equal 1 "$runtime_errexit" 'errexit preserved after enabled runtime load'
|
||||
set +e
|
||||
if [[ $- == *e* ]]; then runtime_errexit=1; else runtime_errexit=0; fi
|
||||
assert_equal 0 "$runtime_errexit" 'errexit disabled before runtime load'
|
||||
load_runtime_state
|
||||
if [[ $- == *e* ]]; then runtime_errexit=1; else runtime_errexit=0; fi
|
||||
assert_equal 0 "$runtime_errexit" 'errexit preserved after disabled runtime load'
|
||||
set -e
|
||||
write_alice_metadata
|
||||
rm -f -- "${CLIENT_DIR}/alice.conf"
|
||||
set +e; output=$(show_client alice 2>&1); status=$?; set -e
|
||||
assert_equal 0 "$status" 'show tolerates unavailable client config'
|
||||
assert_contains '(недоступен)' "$output" 'show marks unavailable config'
|
||||
if [[ $test_group == no-secret-default-output ]]; then assert_equal '' "$(grep -E 'PrivateKey|PresharedKey|EEEE|GGGG' "$TEST_MOCK_LOG" || true)" 'default mock log without secrets'; fi
|
||||
return
|
||||
;;
|
||||
config-export)
|
||||
begin_test 'config prints path by default and content only with --show'
|
||||
expected="${CLIENT_DIR}/alice.conf"
|
||||
output=$(export_client_config alice)
|
||||
assert_equal "$expected" "$output" 'default config export path'
|
||||
local cli_path_bin="${TEST_ROOT}/config-path" cli_out="${TEST_ROOT}/config.stdout" cli_err="${TEST_ROOT}/config.stderr"
|
||||
mkdir -p -- "$cli_path_bin"
|
||||
for utility in wg cat stat sort paste date; do ln -s -- "$(command -v "$utility")" "$cli_path_bin/$utility"; done
|
||||
set +e; PATH="$cli_path_bin" /bin/bash "${PROJECT_DIR}/wg-manager.sh" config alice >"$cli_out" 2>"$cli_err"; status=$?; set -e
|
||||
assert_equal 0 "$status" 'fresh CLI config succeeds without gum or qrencode'
|
||||
assert_equal "$expected" "$(<"$cli_out")" 'fresh CLI config prints one exact path'
|
||||
assert_equal '' "$(<"$cli_err")" 'fresh CLI config stderr is empty'
|
||||
assert_equal '' "$(grep -F $'\033' "$cli_out" || true)" 'fresh CLI config has no ANSI'
|
||||
set +e; PATH="$cli_path_bin" /bin/bash "${PROJECT_DIR}/wg-manager.sh" config alice --show >"$cli_out" 2>"$cli_err"; status=$?; set -e
|
||||
assert_equal 0 "$status" 'fresh CLI explicit config succeeds'
|
||||
assert_equal "$(<"${PROJECT_DIR}/tests/fixtures/m5/managed-client.conf")" "$(<"$cli_out")" 'fresh CLI explicit config exact bytes'
|
||||
assert_equal '' "$(<"$cli_err")" 'fresh CLI explicit config stderr is empty'
|
||||
set +e; PATH="$cli_path_bin" /bin/bash "${PROJECT_DIR}/wg-manager.sh" config alice --bad >"$cli_out" 2>"$cli_err"; status=$?; set -e
|
||||
assert_equal "$EXIT_USAGE" "$status" 'fresh CLI unknown config flag rejected'
|
||||
set +e; output=$(export_client_config alice 1); status=$?; set -e
|
||||
assert_equal 0 "$status" 'explicit full export'
|
||||
assert_equal "$(<"${PROJECT_DIR}/tests/fixtures/m5/managed-client.conf")" "$output" 'explicit config content matches fixture'
|
||||
set +e; export_client_config alice 2 >/dev/null 2>&1; status=$?; set -e
|
||||
assert_equal "$EXIT_USAGE" "$status" 'invalid export mode rejected'
|
||||
rm -f -- "${CLIENT_DIR}/alice.conf"
|
||||
set +e; output=$(export_client_config alice 1 2>&1); status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'missing export config rejected'
|
||||
assert_contains 'Файл конфигурации клиента' "$output" 'missing export diagnostic'
|
||||
printf 'placeholder\n' >"${CLIENT_DIR}/alice.conf"; chmod 600 "${CLIENT_DIR}/alice.conf"
|
||||
open_validated_client_config() { return "$EXIT_OPERATION"; }
|
||||
set +e; output=$(export_client_config alice 1 2>&1); status=$?; set -e
|
||||
assert_equal "$EXIT_OPERATION" "$status" 'export open failure status preserved'
|
||||
assert_contains 'безопасно открыть' "$output" 'export open failure diagnostic'
|
||||
return
|
||||
;;
|
||||
qr)
|
||||
begin_test 'qr uses exact argv and stdin without logging config'
|
||||
export QR_MOCK_EXPECTED_FILE="${CLIENT_DIR}/alice.conf"
|
||||
: >"$TEST_MOCK_LOG"
|
||||
output=$(qr_client alice)
|
||||
assert_contains 'MOCK-QR' "$output" 'mock QR output'
|
||||
assert_equal 1 "$(grep -c '^qrencode -t ansiutf8$' "$TEST_MOCK_LOG" || true)" 'exact QR invocation count'
|
||||
assert_equal 'qrencode -t ansiutf8' "$(tail -n 1 "$TEST_MOCK_LOG")" 'exact QR argv'
|
||||
assert_equal '' "$(grep -E 'PrivateKey|PresharedKey|EEEE|GGGG' "$TEST_MOCK_LOG" || true)" 'QR log without secrets'
|
||||
export QR_MOCK_FAIL=1
|
||||
set +e; qr_client alice >"${TEST_ROOT}/qr-fail.stdout" 2>"${TEST_ROOT}/qr-fail.stderr"; status=$?; set -e
|
||||
unset QR_MOCK_FAIL
|
||||
assert_equal "$EXIT_OPERATION" "$status" 'QR failure status'
|
||||
assert_equal '' "$(<"${TEST_ROOT}/qr-fail.stdout")" 'QR failure stdout is empty'
|
||||
assert_equal '' "$(grep -E 'PrivateKey|PresharedKey|EEEE|GGGG|\[Interface\]|\[Peer\]' "${TEST_ROOT}/qr-fail.stderr" || true)" 'QR failure diagnostic is secret-free'
|
||||
local saved_path=$PATH
|
||||
mkdir -p -- "${TEST_ROOT}/empty-path"
|
||||
ln -s -- "${PROJECT_DIR}/tests/mocks/bin/wg" "${TEST_ROOT}/empty-path/wg"
|
||||
ln -s -- "$(command -v cat)" "${TEST_ROOT}/empty-path/cat"
|
||||
ln -s -- "$(command -v stat)" "${TEST_ROOT}/empty-path/stat"
|
||||
ln -s -- "$(command -v sort)" "${TEST_ROOT}/empty-path/sort"
|
||||
ln -s -- "$(command -v paste)" "${TEST_ROOT}/empty-path/paste"
|
||||
ln -s -- "$(command -v date)" "${TEST_ROOT}/empty-path/date"
|
||||
PATH="${TEST_ROOT}/empty-path"
|
||||
set +e; qr_client alice >"${TEST_ROOT}/qr-missing.stdout" 2>"${TEST_ROOT}/qr-missing.stderr"; status=$?; set -e
|
||||
PATH=$saved_path
|
||||
assert_equal "$EXIT_DEPENDENCY" "$status" 'missing qrencode dependency status'
|
||||
assert_equal "${CLIENT_DIR}/alice.conf" "$(<"${TEST_ROOT}/qr-missing.stdout")" 'missing qrencode safe path only on stdout'
|
||||
assert_contains 'qrencode не найден' "$(<"${TEST_ROOT}/qr-missing.stderr")" 'missing qrencode diagnostic on stderr'
|
||||
assert_equal '' "$(grep -E 'PrivateKey|PresharedKey|EEEE|GGGG' "${TEST_ROOT}/qr-missing.stderr" || true)" 'missing QR diagnostic is secret-free'
|
||||
open_validated_client_config() { return "$EXIT_VALIDATION"; }
|
||||
set +e; output=$(qr_client alice 2>&1); status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'QR identity failure status preserved'
|
||||
assert_contains 'безопасно открыть' "$output" 'QR identity failure diagnostic'
|
||||
unset QR_MOCK_EXPECTED_FILE
|
||||
return
|
||||
;;
|
||||
path-safety)
|
||||
begin_test 'unsafe or permissive config paths are rejected'
|
||||
cp -- "${METADATA_DIR}/alice.meta" "${TEST_ROOT}/alice-meta.base"
|
||||
cp -- "${TEST_ROOT}/alice-meta.base" "${METADATA_DIR}/alice.meta"
|
||||
printf 'NAME=alice\nPUBLIC_KEY=BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=\nIPV4=192.0.2.2\nCREATED_AT=1700000000\nCONFIG_PATH=%s\nconf\nCLIENT_MODE=full-tunnel\nMANAGED=1\n' "$CLIENT_DIR/alice" >"${METADATA_DIR}/alice.meta"
|
||||
set +e; output=$(export_client_config alice 2>&1); status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'metadata embedded newline/control record rejected'
|
||||
assert_equal '' "$(printf '%s' "$output" | grep -E 'sentinel|PrivateKey|PresharedKey|BBBB|EEEE|GGGG' || true)" 'newline metadata diagnostic is secret-free'
|
||||
cp -- "${TEST_ROOT}/alice-meta.base" "${METADATA_DIR}/alice.meta"
|
||||
local real_stat
|
||||
real_stat=$(command -v stat)
|
||||
stat() {
|
||||
if [[ ${2:-} == '%u:%g' && ${4:-} == "${METADATA_DIR}/alice.meta" ]]; then
|
||||
printf '999:999\n'
|
||||
return 0
|
||||
fi
|
||||
"$real_stat" "$@"
|
||||
}
|
||||
set +e; output=$(export_client_config alice 2>&1); status=$?; set -e
|
||||
unset -f stat
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'metadata owner mismatch is rejected'
|
||||
assert_contains 'Владелец' "$output" 'metadata owner mismatch diagnostic'
|
||||
assert_equal '' "$(printf '%s' "$output" | grep -E 'PrivateKey|PresharedKey|BBBB|EEEE|GGGG' || true)" 'owner mismatch diagnostic is secret-free'
|
||||
real_stat=$(command -v stat)
|
||||
stat() {
|
||||
if [[ ${2:-} == '%a' && ${4:-} == "${CLIENT_DIR}/alice.conf" ]]; then
|
||||
return 1
|
||||
fi
|
||||
"$real_stat" "$@"
|
||||
}
|
||||
set +e; output=$(export_client_config alice 2>&1); status=$?; set -e
|
||||
unset -f stat
|
||||
assert_equal "$EXIT_OPERATION" "$status" 'config stat failure is operation error'
|
||||
assert_contains 'режим конфигурации клиента' "$output" 'config stat failure diagnostic'
|
||||
assert_equal '' "$(printf '%s' "$output" | grep -E 'PrivateKey|PresharedKey|BBBB|EEEE|GGGG' || true)" 'config stat diagnostic is secret-free'
|
||||
real_stat=$(command -v stat)
|
||||
stat() {
|
||||
if [[ ${2:-} == '%a' && ${4:-} == "${METADATA_DIR}/alice.meta" ]]; then
|
||||
return 1
|
||||
fi
|
||||
"$real_stat" "$@"
|
||||
}
|
||||
set +e; output=$(export_client_config alice 2>&1); status=$?; set -e
|
||||
unset -f stat
|
||||
assert_equal "$EXIT_OPERATION" "$status" 'metadata stat failure is operation error'
|
||||
assert_contains 'режим метаданных клиента' "$output" 'metadata stat failure diagnostic'
|
||||
assert_equal '' "$(printf '%s' "$output" | grep -E 'PrivateKey|PresharedKey|BBBB|EEEE|GGGG' || true)" 'metadata stat diagnostic is secret-free'
|
||||
cp -- "${TEST_ROOT}/alice-meta.base" "${METADATA_DIR}/alice.meta"
|
||||
for unsafe_path in "${CLIENT_DIR}/nested/alice.conf" "${CLIENT_DIR}/alice file.conf" "${CLIENT_DIR}/-alice.conf" "${CLIENT_DIR}/alice\$'\\n'conf"; do
|
||||
cp -- "${TEST_ROOT}/alice-meta.base" "${METADATA_DIR}/alice.meta"
|
||||
replace_config_line "${METADATA_DIR}/alice.meta" 'CONFIG_PATH=' "CONFIG_PATH=${unsafe_path}"
|
||||
set +e; output=$(export_client_config alice 2>&1); status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" "unsafe path rejected: ${unsafe_path@Q}"
|
||||
assert_equal '' "$(printf '%s' "$output" | grep -E 'sentinel|PrivateKey|PresharedKey|EEEE|GGGG' || true)" 'unsafe path diagnostic is secret-free'
|
||||
done
|
||||
cp -- "${TEST_ROOT}/alice-meta.base" "${METADATA_DIR}/alice.meta"
|
||||
mkdir -p -- "${CLIENT_DIR}/nested"
|
||||
printf 'sentinel\n' >"${CLIENT_DIR}/nested/alice.conf"
|
||||
replace_config_line "${METADATA_DIR}/alice.meta" 'CONFIG_PATH=' "CONFIG_PATH=${CLIENT_DIR}/nested/alice.conf"
|
||||
set +e; export_client_config alice >/dev/null 2>&1; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'nested client path rejected'
|
||||
rm -f -- "${CLIENT_DIR}/nested/alice.conf"; rmdir -- "${CLIENT_DIR}/nested"
|
||||
cp -- "${TEST_ROOT}/alice-meta.base" "${METADATA_DIR}/alice.meta"
|
||||
rm -- "${CLIENT_DIR}/alice.conf"; mkdir -- "${CLIENT_DIR}/alice.conf"
|
||||
set +e; export_client_config alice >/dev/null 2>&1; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'directory client target rejected'
|
||||
rmdir -- "${CLIENT_DIR}/alice.conf"
|
||||
printf 'placeholder\n' >"${CLIENT_DIR}/alice.conf"; chmod 600 "${CLIENT_DIR}/alice.conf"
|
||||
cp -- "${TEST_ROOT}/alice-meta.base" "${METADATA_DIR}/alice.meta"
|
||||
mv -- "$CLIENT_DIR" "${TEST_ROOT}/clients-real"
|
||||
ln -s -- "${TEST_ROOT}/clients-real" "$CLIENT_DIR"
|
||||
set +e; output=$(export_client_config alice 2>&1); status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'symlink client directory rejected'
|
||||
rm -- "$CLIENT_DIR"; mv -- "${TEST_ROOT}/clients-real" "$CLIENT_DIR"
|
||||
mv -- "$METADATA_DIR" "${TEST_ROOT}/metadata-real"
|
||||
ln -s -- "${TEST_ROOT}/metadata-real" "$METADATA_DIR"
|
||||
set +e; output=$(export_client_config alice 2>&1); status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'symlink metadata directory rejected'
|
||||
rm -- "$METADATA_DIR"; mv -- "${TEST_ROOT}/metadata-real" "$METADATA_DIR"
|
||||
chmod 755 "$CLIENT_DIR" "$METADATA_DIR"
|
||||
set +e; output=$(export_client_config alice 2>&1); status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'permissive client directories rejected'
|
||||
chmod 700 "$CLIENT_DIR" "$METADATA_DIR"
|
||||
replace_config_line "${METADATA_DIR}/alice.meta" 'CONFIG_PATH=' 'CONFIG_PATH="${TEST_ROOT}/outside.conf"'
|
||||
set +e; config_path=$(export_client_config alice 2>&1); status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'outside path rejected'
|
||||
sed -i "s#CONFIG_PATH=.*#CONFIG_PATH=${CLIENT_DIR}/alice.conf#" "${METADATA_DIR}/alice.meta"
|
||||
chmod 644 "${CLIENT_DIR}/alice.conf"
|
||||
set +e; export_client_config alice >/dev/null 2>&1; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'permissive config rejected'
|
||||
chmod 600 "${CLIENT_DIR}/alice.conf"
|
||||
chmod 644 "${METADATA_DIR}/alice.meta"
|
||||
set +e; export_client_config alice >/dev/null 2>&1; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'permissive metadata rejected'
|
||||
chmod 600 "${METADATA_DIR}/alice.meta"
|
||||
ln -- "${METADATA_DIR}/alice.meta" "${TEST_ROOT}/alice-meta-hardlink"
|
||||
set +e; export_client_config alice >/dev/null 2>&1; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'hardlinked metadata rejected'
|
||||
rm -f -- "${TEST_ROOT}/alice-meta-hardlink"
|
||||
ln -- "${CLIENT_DIR}/alice.conf" "${TEST_ROOT}/alice-hardlink.conf"
|
||||
set +e; export_client_config alice >/dev/null 2>&1; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'hardlinked config rejected'
|
||||
rm -f -- "${TEST_ROOT}/alice-hardlink.conf"
|
||||
mv -- "${CLIENT_DIR}/alice.conf" "${CLIENT_DIR}/alice-real.conf"
|
||||
ln -s -- "${CLIENT_DIR}/alice-real.conf" "${CLIENT_DIR}/alice.conf"
|
||||
set +e; export_client_config alice >/dev/null 2>&1; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'symlink config rejected'
|
||||
rm -- "${CLIENT_DIR}/alice.conf"
|
||||
mv -- "${CLIENT_DIR}/alice-real.conf" "${CLIENT_DIR}/alice.conf"
|
||||
printf 'sentinel\n' >"${TEST_ROOT}/outside-meta"
|
||||
mv -- "${METADATA_DIR}/alice.meta" "${METADATA_DIR}/alice.real.meta"
|
||||
rm -f -- "${METADATA_DIR}/alice.real.meta"
|
||||
ln -s -- "${TEST_ROOT}/outside-meta" "${METADATA_DIR}/alice.meta"
|
||||
set +e; export_client_config alice >/dev/null 2>&1; status=$?; set -e
|
||||
assert_equal "$EXIT_VALIDATION" "$status" 'symlink metadata rejected'
|
||||
return
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
run_m3_tests() {
|
||||
local config_file="${TEST_ROOT}/m3.conf" fixture="${TEST_ROOT}/wg0.conf" runtime_file="${TEST_ROOT}/runtime.dump" status output before after backup_count manifest_content parent_exit parent_int parent_term
|
||||
cp -- "${PROJECT_DIR}/tests/fixtures/m2/managed.conf" "$fixture"
|
||||
@@ -2037,6 +2344,8 @@ fi
|
||||
|
||||
if [[ $test_group == config ]]; then
|
||||
run_config_tests
|
||||
elif [[ $test_group == show-client || $test_group == config-export || $test_group == qr || $test_group == path-safety || $test_group == no-secret-default-output ]]; then
|
||||
run_m5_tests
|
||||
elif [[ $test_group == parser || $test_group == status || $test_group == list || $test_group == list-redirected || $test_group == list-deterministic ]]; then
|
||||
run_m2_focused "$test_group"
|
||||
elif [[ $test_group == transaction || $test_group == rollback || $test_group == locking || $test_group == backups || $test_group == mutation-preserves-source || $test_group == secret-modes ]]; then
|
||||
@@ -2052,6 +2361,9 @@ else
|
||||
run_m2_tests
|
||||
run_m3_tests
|
||||
run_m4_tests
|
||||
test_group=show-client
|
||||
run_m5_tests
|
||||
test_group=''
|
||||
fi
|
||||
|
||||
finish_tests
|
||||
|
||||
Reference in New Issue
Block a user