refactor: block::run helpers, test --fn mode, param defaults

This commit is contained in:
Nuno Duque Nunes 2026-05-12 01:21:25 +00:00
parent 8ca3669c6c
commit b3a9c69cab
3 changed files with 106 additions and 34 deletions

View file

@ -109,12 +109,7 @@ function cmd::block::run() {
public_key=$(keys::public "$name") || return 1 public_key=$(keys::public "$name") || return 1
local endpoint local endpoint
endpoint=$(monitor::endpoint_for_key "$public_key") endpoint=$(cmd::block::_get_endpoint "$name" "$public_key")
# Fall back to cache if live endpoint not available
if [[ -z "$endpoint" || "$endpoint" == "(none)" ]]; then
endpoint=$(monitor::get_cached_endpoint "$name")
fi
local client_ip local client_ip
client_ip=$(cmd::block::get_client_ip "$name") || return 1 client_ip=$(cmd::block::get_client_ip "$name") || return 1
@ -122,28 +117,7 @@ function cmd::block::run() {
# $quiet || log::section "Blocking client: ${name} (${client_ip})" # $quiet || log::section "Blocking client: ${name} (${client_ip})"
# No specific target — block everything # No specific target — block everything
if [[ ${#ips[@]} -eq 0 && ${#subnets[@]} -eq 0 && ${#ports[@]} -eq 0 ]]; then cmd::block::_block_all "$name" "$client_ip" "$quiet"
# Get real endpoint IP before removing peer from server
local public_key endpoint
public_key=$(keys::public "$name") || return 1
endpoint=$(monitor::endpoint_for_key "$public_key")
fw::block_all "$client_ip" "$name"
fw::save_block "$name" "$client_ip"
# Watch real endpoint IP if available
if [[ -n "$endpoint" ]]; then
monitor::unwatch "$client_ip" # remove tunnel IP if added by block_all
monitor::watch "$endpoint" "$name"
fi
# Remove peer from server to kill active connection
peers::remove_from_server "$name"
peers::reload
$quiet || log::wg_success "${name} has been blocked."
return 0
fi
# Block specific IPs # Block specific IPs
for ip in "${ips[@]}"; do for ip in "${ips[@]}"; do
@ -171,3 +145,39 @@ function cmd::block::run() {
log::debug "Block rules applied for: ${name}" log::debug "Block rules applied for: ${name}"
} }
function cmd::block::_get_endpoint() {
local name="$1" public_key="$2"
local endpoint
endpoint=$(monitor::endpoint_for_key "$public_key")
if [[ -z "$endpoint" || "$endpoint" == "(none)" ]]; then
endpoint=$(monitor::get_cached_endpoint "$name")
fi
echo "$endpoint"
}
function cmd::block::_block_all() {
local name="${1:-}"
local client_ip="${2:-}"
local quiet="${3:-false}"
[[ -z "$name" ]] && log::error "name required" && return 1
[[ -z "$client_ip" ]] && log::error "client_ip required" && return 1
local public_key endpoint
public_key=$(keys::public "$name") || return 1
endpoint=$(cmd::block::_get_endpoint "$name" "$public_key")
fw::block_all "$client_ip" "$name"
fw::save_block "$name" "$client_ip"
if [[ -n "$endpoint" ]]; then
monitor::unwatch "$client_ip"
monitor::watch "$endpoint" "$name"
fi
peers::remove_from_server "$name"
peers::reload
$quiet || log::wg_success "${name} has been blocked."
}

View file

@ -1,5 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
WGCTL_BINARY="/usr/local/bin/wgctl"
# ============================================ # ============================================
# Lifecycle # Lifecycle
# ============================================ # ============================================
@ -7,6 +9,8 @@
function cmd::test::on_load() { function cmd::test::on_load() {
flag::register --destructive flag::register --destructive
flag::register --section flag::register --section
flag::register --fn
flag::register --function
} }
function cmd::test::help() { function cmd::test::help() {
@ -40,7 +44,7 @@ function cmd::test::run_cmd() {
set +e # disable exit on error (return 1) set +e # disable exit on error (return 1)
timeout 30 /usr/local/bin/wgctl "$@" > "$tmp" 2>&1 & timeout 30 "$WGCTL_BINARY" "$@" > "$tmp" 2>&1 &
local pid=$! local pid=$!
wait $pid wait $pid
exit_code=$? exit_code=$?
@ -80,7 +84,7 @@ function cmd::test::run_cmd_fails() {
local tmp exit_code local tmp exit_code
tmp=$(mktemp) tmp=$(mktemp)
timeout 10 setsid /usr/local/bin/wgctl "$@" > "$tmp" 2>&1 timeout 10 setsid "$WGCTL_BINARY" "$@" > "$tmp" 2>&1
exit_code=$? exit_code=$?
set -e # re-enable exit on error set -e # re-enable exit on error
@ -100,6 +104,30 @@ function cmd::test::run_cmd_fails() {
test::pass "$desc" test::pass "$desc"
} }
function cmd::test::run_function() {
local fn="$1"
local namespace
namespace=$(echo "$fn" | cut -d':' -f3)
load_command "$namespace" 2>/dev/null || true
test::reset
log::section "Function Test: ${fn}"
case "$fn" in
cmd::block::run) cmd::test::fn_block ;;
cmd::unblock::run) cmd::test::fn_unblock ;;
cmd::remove::run) cmd::test::fn_remove ;;
cmd::rule::assign) cmd::test::fn_rule_assign ;;
*)
log::error "No function test defined for: ${fn}"
return 1
;;
esac
test::summary
}
# ============================================ # ============================================
# Test sections # Test sections
# ============================================ # ============================================
@ -180,8 +208,8 @@ function cmd::test::section_destructive() {
test::section "Destructive (modifying state)" test::section "Destructive (modifying state)"
# Cleanup from any previous failed run # Cleanup from any previous failed run
/usr/local/bin/wgctl remove --name phone-testunit --force > /dev/null 2>&1 || true "$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
/usr/local/bin/wgctl group remove --name testgroup --force > /dev/null 2>&1 || true "$WGCTL_BINARY" group remove --name testgroup --force > /dev/null 2>&1 || true
# Add test peer # Add test peer
cmd::test::run_cmd "add phone peer" "added successfully" \ cmd::test::run_cmd "add phone peer" "added successfully" \
@ -218,19 +246,47 @@ function cmd::test::section_destructive() {
remove --name phone-testunit --force remove --name phone-testunit --force
} }
# ============================================
# Function Blocks
# ============================================
function cmd::test::fn_block() {
test::section "cmd::block::run"
# Setup
"$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
"$WGCTL_BINARY" add --name testunit --type phone > /dev/null 2>&1
# Tests
cmd::test::run_cmd "block peer" "blocked" block --name phone-testunit
cmd::test::run_cmd "block already blocked" "already" block --name phone-testunit
"$WGCTL_BINARY" unblock --name phone-testunit > /dev/null 2>&1 || true
cmd::test::run_cmd "block with --type" "blocked" block --name testunit --type phone
cmd::test::run_cmd_fails "block nonexistent" block --name truly-nonexistent-xyz
# Cleanup
"$WGCTL_BINARY" unblock --name phone-testunit > /dev/null 2>&1 || true
"$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
}
# ============================================ # ============================================
# Run # Run
# ============================================ # ============================================
function cmd::test::run() { function cmd::test::run() {
local destructive=false section="" local destructive=false section=""
local fn=""
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
--destructive) destructive=true; shift ;; --destructive) destructive=true; shift ;;
--section) --section)
util::require_flag "--section" "${2:-}" || return 1 util::require_flag "--section" "${2:-}" || return 1
section="$2"; shift 2 ;; section="$2"; shift 2
;;
--fn|--function) fn="$2"; shift 2 ;;
--verbose|-v) WGCTL_TEST_VERBOSE=true; shift ;; --verbose|-v) WGCTL_TEST_VERBOSE=true; shift ;;
--help) cmd::test::help; return ;; --help) cmd::test::help; return ;;
*) *)
@ -240,6 +296,12 @@ function cmd::test::run() {
esac esac
done done
# After flag parsing:
if [[ -n "$fn" ]]; then
cmd::test::run_function "$fn"
return
fi
test::reset test::reset
log::section "wgctl Test Suite" log::section "wgctl Test Suite"

View file

@ -1,6 +1,6 @@
{ {
"phone-fred": "94.63.0.129", "phone-fred": "94.63.0.129",
"phone-helena": "148.69.38.9", "phone-helena": "148.69.39.194",
"phone-nuno": "94.63.0.129", "phone-nuno": "94.63.0.129",
"tablet-nuno": "148.69.202.5", "tablet-nuno": "148.69.202.5",
"guest-zephyr": "5.13.82.5", "guest-zephyr": "5.13.82.5",