Menu
Public repository / 67ca9028c2fad783b70c10cd9fac111ce5b10de1
AkurAI-VPN / .github/workflows/ci.yml
Latest change 50973c6c157ae8a57689d219b4327f683d24d4bb - feat(node): echo-peer + CI encrypted E2E on single macOS/Windows host by Claude Code
name: ci
on:
push:
branches: [main]
workflow_dispatch:
jobs:
# The cryptographic + transport + protocol core is pure-std and must build AND
# pass its tests on every desktop OS — this is the cross-platform foundation a
# macOS/Windows client is built on.
portable-core:
name: portable core (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: build core crates
run: cargo build -p akurai-crypto -p akurai-transport -p akurai-common -p akurai-dns
- name: test core crates
run: cargo test -p akurai-crypto -p akurai-transport -p akurai-common -p akurai-dns
# Full workspace (incl. control plane + relay + Linux node) on Linux.
linux-full:
name: linux full workspace
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- run: cargo fmt --all --check
- run: cargo clippy --workspace --all-targets
- run: cargo build --workspace
- run: cargo test --workspace
# Desktop node — builds the client daemon on macOS + Windows on real runners.
# macOS has a real utun data plane; Windows compiles (Wintun data plane pending).
# This is now a hard gate: a regression in the cross-platform build fails CI.
desktop-node:
name: desktop node (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: build node (release)
run: cargo build --release -p akurai-node
# Publish the built client so it can be downloaded and runtime-tested on
# real Mac/Windows hardware (CI runners can't create a TUN/utun to test it).
- name: upload client binary
uses: actions/upload-artifact@v4
with:
name: akurai-node-${{ matrix.os }}
path: |
target/release/akurai-node
target/release/akurai-node.exe
if-no-files-found: warn
# Runtime smoke test: RUN the client on real macOS/Windows and prove the full
# platform packet path. `selftest` brings up the utun/Wintun device and echoes
# ICMP, so a real `ping` to an overlay IP (routed to the device) only succeeds
# if BOTH TunDevice::recv and send move packets correctly on that OS — the part
# most likely to compile yet fail at runtime.
runtime-smoke:
name: runtime smoke (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: build node (release)
run: cargo build --release -p akurai-node
- name: macOS — utun recv/send via ping echo
if: runner.os == 'macOS'
run: |
BIN=./target/release/akurai-node
"$BIN" install --home /tmp/akv
sudo "$BIN" selftest --home /tmp/akv --overlay-ip 100.88.0.3 --secs 18 > smoke.log 2>&1 &
PID=$!
sleep 5
echo "--- node output ---"; cat smoke.log
echo "--- ping an overlay IP (routed to utun; selftest must echo it) ---"
if ping -c 3 -t 6 100.88.0.99; then RESULT=0; else RESULT=1; fi
sudo kill "$PID" 2>/dev/null || true
echo "--- node output after ping ---"; cat smoke.log
[ $RESULT -eq 0 ] && echo "PASS: macOS utun recv+send move packets" \
|| { echo "FAIL: no ICMP echo over utun"; exit 1; }
- name: Windows — Wintun recv/send via ping echo
if: runner.os == 'Windows'
shell: pwsh
run: |
Invoke-WebRequest -Uri "https://www.wintun.net/builds/wintun-0.14.1.zip" -OutFile wintun.zip
Expand-Archive wintun.zip -DestinationPath wintun-extract -Force
Copy-Item wintun-extract/wintun/bin/amd64/wintun.dll target/release/wintun.dll
$home2 = Join-Path $env:TEMP akv
./target/release/akurai-node.exe install --home $home2
$p = Start-Process -FilePath ./target/release/akurai-node.exe `
-ArgumentList "selftest","--home",$home2,"--overlay-ip","100.88.0.3","--secs","18" `
-RedirectStandardError smoke.log -RedirectStandardOutput smoke.out -PassThru -NoNewWindow
Start-Sleep -Seconds 6
Get-Content smoke.log -ErrorAction SilentlyContinue
Write-Host "--- ping an overlay IP (routed to Wintun; selftest must echo it) ---"
ping -n 3 -w 3000 100.88.0.99
$ok = ($LASTEXITCODE -eq 0)
Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue
Get-Content smoke.log -ErrorAction SilentlyContinue
if ($ok) { Write-Host "PASS: Windows Wintun recv+send move packets" }
else { Write-Host "FAIL: no ICMP echo over Wintun"; exit 1 }
# Full ENCRYPTED end-to-end on a single real macOS/Windows host: a relay + a
# real `tunnel` node A (utun/Wintun) + a transport-level `echo-peer` node B
# (no TUN, so its overlay IP is never local → no kernel short-circuit). A ping
# to node B traverses A's full data plane (utun → Noise-encrypt → relay →
# decrypt by B → encrypted echo → A's utun). A reply proves the whole encrypted
# client path works at runtime on that OS.
e2e-desktop:
name: e2e encrypted (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: build node + relay (release)
run: cargo build --release -p akurai-node -p akurai-relay
- name: macOS — encrypted ping A→B over the relay
if: runner.os == 'macOS'
run: |
BIN=./target/release/akurai-node
RELAY=./target/release/akurai-relay
"$BIN" install --home /tmp/a; "$BIN" install --home /tmp/b
APUB=$(cat /tmp/a/config/identity.pub); BPUB=$(cat /tmp/b/config/identity.pub)
echo "100.88.0.4 $BPUB nodeb" > /tmp/a/config/peers
echo "100.88.0.3 $APUB nodea" > /tmp/b/config/peers
RELAY_PORT=51820 "$RELAY" serve > relay.log 2>&1 &
sleep 1
"$BIN" echo-peer --home /tmp/b --overlay-ip 100.88.0.4 --relay 127.0.0.1:51820 --peers /tmp/b/config/peers --secs 40 > b.log 2>&1 &
sudo "$BIN" tunnel --home /tmp/a --overlay-ip 100.88.0.3 --relay 127.0.0.1:51820 --peers /tmp/a/config/peers > a.log 2>&1 &
APID=$!
sleep 6
echo "--- node A ---"; cat a.log; echo "--- echo-peer B ---"; cat b.log
echo "--- ENCRYPTED ping A→B (100.88.0.4) over the relay ---"
if ping -c 5 -t 10 100.88.0.4; then RESULT=0; else RESULT=1; fi
sudo kill "$APID" 2>/dev/null || true
echo "--- echo-peer B after ping ---"; cat b.log
[ $RESULT -eq 0 ] && echo "PASS: macOS encrypted end-to-end works" \
|| { echo "FAIL: no encrypted round-trip"; cat relay.log; exit 1; }
- name: Windows — encrypted ping A→B over the relay
if: runner.os == 'Windows'
shell: pwsh
run: |
Invoke-WebRequest -Uri "https://www.wintun.net/builds/wintun-0.14.1.zip" -OutFile wintun.zip
Expand-Archive wintun.zip -DestinationPath wintun-extract -Force
Copy-Item wintun-extract/wintun/bin/amd64/wintun.dll target/release/wintun.dll
$BIN = "./target/release/akurai-node.exe"
& $BIN install --home C:\a; & $BIN install --home C:\b
$apub = Get-Content C:\a\config\identity.pub; $bpub = Get-Content C:\b\config\identity.pub
"100.88.0.4 $bpub nodeb" | Out-File -Encoding ascii C:\a\config\peers
"100.88.0.3 $apub nodea" | Out-File -Encoding ascii C:\b\config\peers
$env:RELAY_PORT="51820"
Start-Process ./target/release/akurai-relay.exe -ArgumentList "serve" -RedirectStandardError relay.log -PassThru -NoNewWindow | Out-Null
Start-Sleep 1
Start-Process $BIN -ArgumentList "echo-peer","--home","C:\b","--overlay-ip","100.88.0.4","--relay","127.0.0.1:51820","--peers","C:\b\config\peers","--secs","40" -RedirectStandardError b.log -PassThru -NoNewWindow | Out-Null
$pa = Start-Process $BIN -ArgumentList "tunnel","--home","C:\a","--overlay-ip","100.88.0.3","--relay","127.0.0.1:51820","--peers","C:\a\config\peers" -RedirectStandardError a.log -PassThru -NoNewWindow
Start-Sleep 7
Write-Host "--- node A ---"; Get-Content a.log -ErrorAction SilentlyContinue
Write-Host "--- echo-peer B ---"; Get-Content b.log -ErrorAction SilentlyContinue
Write-Host "--- ENCRYPTED ping A->B (100.88.0.4) over the relay ---"
ping -n 5 -w 3000 100.88.0.4
$ok = ($LASTEXITCODE -eq 0)
Stop-Process -Id $pa.Id -Force -ErrorAction SilentlyContinue
if ($ok) { Write-Host "PASS: Windows encrypted end-to-end works" }
else { Write-Host "FAIL: no encrypted round-trip"; Get-Content relay.log -ErrorAction SilentlyContinue; exit 1 }