Files
cli/sunbeam-net/tests/run.sh
Sienna Meridian Satterwhite 94fb6155f7 test(net): TLS-enabled docker stack and active e2e test
The docker-compose stack now serves Headscale (and its embedded DERP)
over TLS on port 8443 with a self-signed cert covering localhost,
127.0.0.1, and the docker-network hostname `headscale`. Tailscale
peers trust the cert via SSL_CERT_FILE; our test daemon uses
`derp_tls_insecure: true` (gated on the SUNBEAM_NET_TEST_DERP_INSECURE
env var) since pinning a self-signed root in tests is more trouble
than it's worth.

With TLS DERP working, the previously-ignored
`test_e2e_tcp_through_tunnel` test now passes: the daemon spawns,
registers, completes a Noise handshake over TLS, opens a TLS DERP
relay session, runs a real WireGuard handshake with peer-a (verified
via boringtun ↔ tailscale interop), and TCP-tunnels an HTTP GET
through smoltcp ↔ engine ↔ proxy ↔ test client. The 191-byte echo
response round-trips and the test asserts on its body.

- tests/config/headscale.yaml: tls_cert_path + tls_key_path, listen on
  8443, server_url=https://headscale:8443
- tests/config/test-cert.pem + test-key.pem: 365-day self-signed RSA
  cert with SAN DNS:localhost, DNS:headscale, IP:127.0.0.1
- tests/docker-compose.yml: mount certs into headscale + both peers,
  set SSL_CERT_FILE on the peers, expose 8443 instead of 8080
- tests/run.sh: switch to https://localhost:8443, set
  SUNBEAM_NET_TEST_DERP_INSECURE=1
- tests/integration.rs: drop the #[ignore] on test_e2e_tcp_through_tunnel,
  read derp_tls_insecure from env in all four test configs
2026-04-07 15:29:03 +01:00

68 lines
2.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Integration test runner for sunbeam-net.
#
# Spins up Headscale + two Tailscale peers, creates pre-auth keys,
# runs the Rust integration tests, then tears everything down.
set -euo pipefail
cd "$(dirname "$0")"
COMPOSE="docker compose -f docker-compose.yml"
cleanup() { $COMPOSE down -v 2>/dev/null; }
trap cleanup EXIT
echo "==> Starting Headscale..."
$COMPOSE up -d headscale
$COMPOSE exec -T headscale sh -c 'until headscale health 2>/dev/null; do sleep 1; done'
echo "==> Creating pre-auth keys..."
# Helper that handles both compact and pretty-printed JSON shapes from
# headscale preauthkeys create.
extract_key() {
grep -o '"key":[[:space:]]*"[^"]*"' | sed 's/.*"\([^"]*\)"$/\1/'
}
# Test client uses an ephemeral key so headscale auto-deletes the node when
# the streaming map connection drops, keeping the test database clean.
PEER_A_KEY=$($COMPOSE exec -T headscale headscale preauthkeys create --user test --reusable --expiration 1h -o json | extract_key)
PEER_B_KEY=$($COMPOSE exec -T headscale headscale preauthkeys create --user test --reusable --expiration 1h -o json | extract_key)
CLIENT_KEY=$($COMPOSE exec -T headscale headscale preauthkeys create --user test --reusable --ephemeral --expiration 1h -o json | extract_key)
echo "==> Starting peers..."
PEER_A_AUTH_KEY="$PEER_A_KEY" PEER_B_AUTH_KEY="$PEER_B_KEY" $COMPOSE up -d peer-a peer-b echo
echo "==> Waiting for peers to register..."
for i in $(seq 1 30); do
NODES=$($COMPOSE exec -T headscale headscale nodes list -o json 2>/dev/null | grep -c '"id"' || true)
if [ "$NODES" -ge 2 ]; then
echo " $NODES peers registered."
break
fi
sleep 2
done
# In TUN mode tailscale installs a stateful firewall that DROPs incoming
# tailnet traffic by default. Disable it on both peers so the integration
# tests can actually exchange TCP through the tunnel.
echo "==> Disabling tailscale firewall on peers..."
$COMPOSE exec -T peer-a tailscale set --shields-up=false 2>/dev/null || true
$COMPOSE exec -T peer-b tailscale set --shields-up=false 2>/dev/null || true
# Get the server's Noise public key
SERVER_KEY=$($COMPOSE exec -T headscale cat /var/lib/headscale/noise_private.key 2>/dev/null | head -1 || echo "")
echo "==> Peer A tailnet IP:"
$COMPOSE exec -T peer-a tailscale ip -4 || true
echo "==> Peer B tailnet IP:"
$COMPOSE exec -T peer-b tailscale ip -4 || true
echo "==> Running integration tests..."
cd ../..
SUNBEAM_NET_TEST_AUTH_KEY="$CLIENT_KEY" \
SUNBEAM_NET_TEST_COORD_URL="https://localhost:8443" \
SUNBEAM_NET_TEST_DERP_INSECURE=1 \
SUNBEAM_NET_TEST_PEER_A_IP=$($COMPOSE -f sunbeam-net/tests/docker-compose.yml exec -T peer-a tailscale ip -4 2>/dev/null | tr -d '[:space:]') \
cargo test -p sunbeam-net --features integration --test integration -- --nocapture
echo "==> Done."