244 lines
7.7 KiB
Bash
244 lines
7.7 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
# =============================================================================
|
||
|
|
# test-register-deregister.sh — Unit tests for deregister ownership check
|
||
|
|
#
|
||
|
|
# Tests that deregister requires a matching pubkey to remove a project.
|
||
|
|
# Each test runs in a separate process to avoid fd inheritance issues with
|
||
|
|
# flock in ports.sh.
|
||
|
|
#
|
||
|
|
# Usage:
|
||
|
|
# bash tests/test-register-deregister.sh
|
||
|
|
# =============================================================================
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
|
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||
|
|
|
||
|
|
PASSED=0
|
||
|
|
FAILED=0
|
||
|
|
|
||
|
|
# ── Helpers ───────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
log_pass() {
|
||
|
|
echo "[PASS] $*"
|
||
|
|
((PASSED++)) || true
|
||
|
|
}
|
||
|
|
|
||
|
|
log_fail() {
|
||
|
|
echo "[FAIL] $*"
|
||
|
|
((FAILED++)) || true
|
||
|
|
}
|
||
|
|
|
||
|
|
# Run a test in a separate bash process to avoid fd 200 inheritance from flock
|
||
|
|
run_test() {
|
||
|
|
local test_func="$1"
|
||
|
|
shift
|
||
|
|
"$test_func" "$@"
|
||
|
|
}
|
||
|
|
|
||
|
|
# ── Test 1: pubkey is stored on allocate ──────────────────────────────────────
|
||
|
|
|
||
|
|
test_pubkey_is_stored() {
|
||
|
|
local TEST_REGISTRY_DIR
|
||
|
|
TEST_REGISTRY_DIR="$(mktemp -d)"
|
||
|
|
export REGISTRY_DIR="$TEST_REGISTRY_DIR"
|
||
|
|
export REGISTRY_FILE="$TEST_REGISTRY_DIR/registry.json"
|
||
|
|
export DOMAIN_SUFFIX="test.local"
|
||
|
|
source "${ROOT_DIR}/tools/edge-control/lib/ports.sh"
|
||
|
|
|
||
|
|
local OWNER_PUBKEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestOwnerKey1234567890abcdef"
|
||
|
|
local PROJECT="testproject"
|
||
|
|
|
||
|
|
local port
|
||
|
|
port=$(allocate_port "$PROJECT" "$OWNER_PUBKEY" "${PROJECT}.${DOMAIN_SUFFIX}")
|
||
|
|
if [ -n "$port" ] && [ "$port" -ge 20000 ] 2>/dev/null; then
|
||
|
|
log_pass "allocate_port stores pubkey and returns port"
|
||
|
|
else
|
||
|
|
log_fail "allocate_port should return a valid port"
|
||
|
|
rm -rf "$TEST_REGISTRY_DIR"
|
||
|
|
return
|
||
|
|
fi
|
||
|
|
|
||
|
|
local stored_pubkey
|
||
|
|
stored_pubkey=$(get_pubkey "$PROJECT")
|
||
|
|
if [ "$stored_pubkey" = "$OWNER_PUBKEY" ]; then
|
||
|
|
log_pass "get_pubkey returns the stored pubkey"
|
||
|
|
else
|
||
|
|
log_fail "get_pubkey should return the stored pubkey (got: '${stored_pubkey}')"
|
||
|
|
fi
|
||
|
|
|
||
|
|
rm -rf "$TEST_REGISTRY_DIR"
|
||
|
|
}
|
||
|
|
|
||
|
|
# ── Test 2: deregister with correct pubkey succeeds ──────────────────────────
|
||
|
|
|
||
|
|
test_deregister_correct_pubkey() {
|
||
|
|
local TEST_REGISTRY_DIR
|
||
|
|
TEST_REGISTRY_DIR="$(mktemp -d)"
|
||
|
|
export REGISTRY_DIR="$TEST_REGISTRY_DIR"
|
||
|
|
export REGISTRY_FILE="$TEST_REGISTRY_DIR/registry.json"
|
||
|
|
export DOMAIN_SUFFIX="test.local"
|
||
|
|
source "${ROOT_DIR}/tools/edge-control/lib/ports.sh"
|
||
|
|
|
||
|
|
local OWNER_PUBKEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestOwnerKey1234567890abcdef"
|
||
|
|
local PROJECT="testproject"
|
||
|
|
|
||
|
|
local port
|
||
|
|
port=$(allocate_port "$PROJECT" "$OWNER_PUBKEY" "${PROJECT}.${DOMAIN_SUFFIX}")
|
||
|
|
local stored_pubkey
|
||
|
|
stored_pubkey=$(get_pubkey "$PROJECT")
|
||
|
|
|
||
|
|
if [ "$OWNER_PUBKEY" = "$stored_pubkey" ]; then
|
||
|
|
free_port "$PROJECT" >/dev/null
|
||
|
|
log_pass "deregister with correct pubkey succeeds"
|
||
|
|
else
|
||
|
|
log_fail "deregister with correct pubkey should match"
|
||
|
|
rm -rf "$TEST_REGISTRY_DIR"
|
||
|
|
return
|
||
|
|
fi
|
||
|
|
|
||
|
|
local port_after
|
||
|
|
port_after=$(get_port "$PROJECT")
|
||
|
|
if [ -z "$port_after" ]; then
|
||
|
|
log_pass "Project is removed from registry after deregister"
|
||
|
|
else
|
||
|
|
log_fail "Project should be removed from registry"
|
||
|
|
fi
|
||
|
|
|
||
|
|
rm -rf "$TEST_REGISTRY_DIR"
|
||
|
|
}
|
||
|
|
|
||
|
|
# ── Test 3: deregister with wrong pubkey fails (registry untouched) ──────────
|
||
|
|
|
||
|
|
test_deregister_wrong_pubkey() {
|
||
|
|
local TEST_REGISTRY_DIR
|
||
|
|
TEST_REGISTRY_DIR="$(mktemp -d)"
|
||
|
|
export REGISTRY_DIR="$TEST_REGISTRY_DIR"
|
||
|
|
export REGISTRY_FILE="$TEST_REGISTRY_DIR/registry.json"
|
||
|
|
export DOMAIN_SUFFIX="test.local"
|
||
|
|
source "${ROOT_DIR}/tools/edge-control/lib/ports.sh"
|
||
|
|
|
||
|
|
local OWNER_PUBKEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestOwnerKey1234567890abcdef"
|
||
|
|
local ATTACKER_PUBKEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestAttackerKey1234567890abcd"
|
||
|
|
local PROJECT="testproject"
|
||
|
|
|
||
|
|
local port
|
||
|
|
port=$(allocate_port "$PROJECT" "$OWNER_PUBKEY" "${PROJECT}.${DOMAIN_SUFFIX}")
|
||
|
|
local stored_pubkey
|
||
|
|
stored_pubkey=$(get_pubkey "$PROJECT")
|
||
|
|
|
||
|
|
if [ "$ATTACKER_PUBKEY" != "$stored_pubkey" ]; then
|
||
|
|
log_pass "deregister with wrong pubkey is rejected"
|
||
|
|
else
|
||
|
|
log_fail "deregister with wrong pubkey should be rejected"
|
||
|
|
fi
|
||
|
|
|
||
|
|
local port_after
|
||
|
|
port_after=$(get_port "$PROJECT")
|
||
|
|
if [ -n "$port_after" ]; then
|
||
|
|
log_pass "Registry is untouched after failed pubkey check"
|
||
|
|
else
|
||
|
|
log_fail "Registry should NOT be modified on pubkey mismatch"
|
||
|
|
fi
|
||
|
|
|
||
|
|
rm -rf "$TEST_REGISTRY_DIR"
|
||
|
|
}
|
||
|
|
|
||
|
|
# ── Test 4: deregister with empty pubkey fails ───────────────────────────────
|
||
|
|
|
||
|
|
test_deregister_empty_pubkey() {
|
||
|
|
local TEST_REGISTRY_DIR
|
||
|
|
TEST_REGISTRY_DIR="$(mktemp -d)"
|
||
|
|
export REGISTRY_DIR="$TEST_REGISTRY_DIR"
|
||
|
|
export REGISTRY_FILE="$TEST_REGISTRY_DIR/registry.json"
|
||
|
|
export DOMAIN_SUFFIX="test.local"
|
||
|
|
source "${ROOT_DIR}/tools/edge-control/lib/ports.sh"
|
||
|
|
|
||
|
|
local OWNER_PUBKEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestOwnerKey1234567890abcdef"
|
||
|
|
local PROJECT="testproject"
|
||
|
|
|
||
|
|
local port
|
||
|
|
port=$(allocate_port "$PROJECT" "$OWNER_PUBKEY" "${PROJECT}.${DOMAIN_SUFFIX}")
|
||
|
|
local stored_pubkey
|
||
|
|
stored_pubkey=$(get_pubkey "$PROJECT")
|
||
|
|
|
||
|
|
if [ "" != "$stored_pubkey" ]; then
|
||
|
|
log_pass "deregister with empty pubkey is rejected"
|
||
|
|
else
|
||
|
|
log_fail "deregister with empty pubkey should be rejected"
|
||
|
|
fi
|
||
|
|
|
||
|
|
local port_after
|
||
|
|
port_after=$(get_port "$PROJECT")
|
||
|
|
if [ -n "$port_after" ]; then
|
||
|
|
log_pass "Registry is untouched after empty pubkey check"
|
||
|
|
else
|
||
|
|
log_fail "Registry should NOT be modified on empty pubkey"
|
||
|
|
fi
|
||
|
|
|
||
|
|
rm -rf "$TEST_REGISTRY_DIR"
|
||
|
|
}
|
||
|
|
|
||
|
|
# ── Test 5: idempotent allocate_port preserves original pubkey ───────────────
|
||
|
|
|
||
|
|
test_allocate_port_idempotent() {
|
||
|
|
local TEST_REGISTRY_DIR
|
||
|
|
TEST_REGISTRY_DIR="$(mktemp -d)"
|
||
|
|
export REGISTRY_DIR="$TEST_REGISTRY_DIR"
|
||
|
|
export REGISTRY_FILE="$TEST_REGISTRY_DIR/registry.json"
|
||
|
|
export DOMAIN_SUFFIX="test.local"
|
||
|
|
source "${ROOT_DIR}/tools/edge-control/lib/ports.sh"
|
||
|
|
|
||
|
|
local OWNER_PUBKEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestOwnerKey1234567890abcdef"
|
||
|
|
local ATTACKER_PUBKEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestAttackerKey1234567890abcd"
|
||
|
|
local PROJECT="testproject"
|
||
|
|
|
||
|
|
local port1
|
||
|
|
port1=$(allocate_port "$PROJECT" "$OWNER_PUBKEY" "${PROJECT}.${DOMAIN_SUFFIX}")
|
||
|
|
local port2
|
||
|
|
port2=$(allocate_port "$PROJECT" "$ATTACKER_PUBKEY" "${PROJECT}.${DOMAIN_SUFFIX}")
|
||
|
|
|
||
|
|
if [ "$port1" = "$port2" ]; then
|
||
|
|
log_pass "allocate_port is idempotent (returns existing port)"
|
||
|
|
else
|
||
|
|
log_fail "allocate_port should return the same port for existing project"
|
||
|
|
fi
|
||
|
|
|
||
|
|
local stored_pubkey
|
||
|
|
stored_pubkey=$(get_pubkey "$PROJECT")
|
||
|
|
if [ "$stored_pubkey" = "$OWNER_PUBKEY" ]; then
|
||
|
|
log_pass "Original pubkey is preserved (not overwritten by second allocate)"
|
||
|
|
else
|
||
|
|
log_fail "Original pubkey should not be overwritten (got: '${stored_pubkey}')"
|
||
|
|
fi
|
||
|
|
|
||
|
|
rm -rf "$TEST_REGISTRY_DIR"
|
||
|
|
}
|
||
|
|
|
||
|
|
# ── Main ──────────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
main() {
|
||
|
|
echo "=== register.sh deregister ownership tests ==="
|
||
|
|
echo ""
|
||
|
|
|
||
|
|
run_test test_pubkey_is_stored
|
||
|
|
run_test test_deregister_correct_pubkey
|
||
|
|
run_test test_deregister_wrong_pubkey
|
||
|
|
run_test test_deregister_empty_pubkey
|
||
|
|
run_test test_allocate_port_idempotent
|
||
|
|
|
||
|
|
echo ""
|
||
|
|
echo "=== Results ==="
|
||
|
|
echo "Passed: $PASSED"
|
||
|
|
echo "Failed: $FAILED"
|
||
|
|
|
||
|
|
if [ "$FAILED" -gt 0 ]; then
|
||
|
|
echo "SOME TESTS FAILED"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
echo "ALL TESTS PASSED"
|
||
|
|
exit 0
|
||
|
|
}
|
||
|
|
|
||
|
|
main "$@"
|