-
Notifications
You must be signed in to change notification settings - Fork 37
219 lines (194 loc) · 9.88 KB
/
Copy pathtest.yml
File metadata and controls
219 lines (194 loc) · 9.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
name: Test
on: [ push, pull_request ]
jobs:
test:
# run job on all pushes OR external PR, not both
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest, macos-latest ]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install Go
uses: actions/setup-go@v6
with:
go-version: 1.26.x
cache: true
- name: Create stub static/
run: mkdir static && touch static/index.html
- name: Check deps
shell: bash
run: ./build.sh deps
- name: gofmt && go mod tidy
if: matrix.os == 'ubuntu-latest'
run: |
go mod tidy -compat=1.26
cd cmd/awl-tray && go mod tidy -compat=1.26 && cd ../..
test -z "$(gofmt -d .)" || (gofmt -d . && false)
test -z "$(git status --porcelain)" || (git status; git diff && false)
- name: Test
run: go test -count=1 -v ./...
- name: Test with -race
run: go test -race -count=1 -v ./...
- name: VPN gateway host-network integration test (Linux, root)
# Hidden behind the `vpn_hostnet` build tag and excluded from `go test ./...`.
# Exercises the real netlink/iptables plumbing (SetupNAT/SetupGatewayRoutes
# + teardown/stale-recovery) against the runner's own network, so it needs
# root and only runs on Linux. Compile as the normal user, then run the
# binary under sudo so root never pollutes the Go build cache.
# TODO: if a hard failure ever leaves the runner's egress black-holed
# (default route via a dead awl0) and breaks log upload, add a separate
# `if: always()` cleanup step
if: matrix.os == 'ubuntu-latest'
run: |
go test -c -tags vpn_hostnet -o gw-hostnet.test ./vpn/routes/
sudo ./gw-hostnet.test -test.run '^TestGatewayHostNet' -test.v
- name: Build cmd/awl
run: go build github.com/anywherelan/awl/cmd/awl
- name: Upload cmd/awl build
uses: actions/upload-artifact@v7
with:
name: awl-build-${{ runner.os }}
path: |
awl
awl.exe
if-no-files-found: error
end-to-end-test:
# run only on pushes because we use repository secrets which are unavailable to forks
if: ${{ github.event_name == 'push' }}
needs: [ test ]
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest, macos-latest ]
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
steps:
- name: Retrieve saved cmd/awl build
uses: actions/download-artifact@v8
with:
name: awl-build-${{ runner.os }}
- name: Download librespeed-cli
env:
CONFIG_AWL_LINUX: ${{ secrets.CONFIG_AWL_LINUX }}
CONFIG_AWL_MACOS: ${{ secrets.CONFIG_AWL_MACOS }}
CONFIG_AWL_WINDOWS: ${{ secrets.CONFIG_AWL_WINDOWS }}
CONFIG_LIBRESPEED: ${{ secrets.CONFIG_LIBRESPEED }}
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
curl -sSL https://github.com/librespeed/speedtest-cli/releases/download/v1.0.10/librespeed-cli_1.0.10_linux_amd64.tar.gz | tar -xzf -
echo $CONFIG_AWL_LINUX > config_awl.json
elif [ "$RUNNER_OS" == "macOS" ]; then
curl -sSL https://github.com/librespeed/speedtest-cli/releases/download/v1.0.10/librespeed-cli_1.0.10_darwin_arm64.tar.gz | tar -xzf -
echo $CONFIG_AWL_MACOS > config_awl.json
elif [ "$RUNNER_OS" == "Windows" ]; then
curl -sSL https://github.com/librespeed/speedtest-cli/releases/download/v1.0.10/librespeed-cli_1.0.10_windows_amd64.zip > download.zip
unzip download.zip
echo $CONFIG_AWL_WINDOWS > config_awl.json
else
echo "$RUNNER_OS not supported"
exit 1
fi
echo $CONFIG_LIBRESPEED > config_librespeed.json
- name: Run librespeed-cli, awl, librespeed-cli through awl
if: matrix.os == 'ubuntu-latest'
run: |
chmod +x awl
sudo ./awl &
./librespeed-cli --local-json config_librespeed.json --server 1 --json --share --telemetry-level disabled | python3 -m json.tool
sleep 10
awl_pid=`jobs -l | grep './awl' | awk '{print $2}'`
./awl cli peers status
./librespeed-cli --local-json config_librespeed.json --server 2 --json --share --telemetry-level disabled | python3 -m json.tool
ping 10.66.0.2 -w 20 -c 10
# TODO: remove this temporal hack for linux
ping awl-tester.awl -w 20 -c 10 || true
# ---- VPN gateway server (exit-node) mode: runtime enable/disable round-trips OS state ----
# awl runs as root here, so enabling the server installs real NAT
# (iptables MASQUERADE + AWL-FORWARD chain) in this netns. We assert the
# commands succeed AND that they actually mutate then fully restore the
# netfilter state. `iptables -S` (no packet/byte counters, unlike
# iptables-save) makes the before/after comparison stable.
nat_state() { sudo iptables -S; sudo iptables -t nat -S; }
NAT_BEFORE=$(nat_state)
./awl cli gateway server enable
test "$(nat_state)" != "$NAT_BEFORE" # enable actually changed netfilter
sudo iptables -S | grep -q AWL-FORWARD # exit-node chain installed
./awl cli gateway server disable
test "$(nat_state)" = "$NAT_BEFORE" # disable restored netfilter exactly
# ---- VPN gateway full-tunnel e2e: client = this runner, exit node = awl-tester ----
# Requires the awl-tester peer to have VPN gateway server enabled AND to
# permit this CI peer as an exit node (WeAllowUsingAsExitNode); both are
# advertised to us via the status protocol. Wait until it shows up as a
# connected, available gateway.
for i in $(seq 1 15); do
if ./awl cli gateway list | grep -E 'awl-tester.*\[connected\]'; then break; fi
sleep 2
done
./awl cli gateway list | grep -E 'awl-tester.*\[connected\]' # fail if never became available
# Probe the egress IP via https://ifconfig.me
curl4() { curl -4 -s --max-time 20 --retry 3 --retry-delay 2 https://ifconfig.me/; }
IP_DIRECT=$(curl4); echo "egress IP (direct): $IP_DIRECT"
./awl cli gateway client use --name awl-tester
./awl cli gateway status
RULE_ON=$(ip rule show); ROUTE_ON=$(ip route show)
# Tolerate a failed curl here so we always reach `client stop` below
# (a broken tunnel must not leave the runner black-holed); the
# `test -n "$IP_GW"` assertion after teardown turns it into a clean failure.
IP_GW=$(curl4 || true); echo "egress IP (via gateway): $IP_GW"
./awl cli gateway client stop
RULE_OFF=$(ip rule show); ROUTE_OFF=$(ip route show)
IP_REVERTED=$(curl4); echo "egress IP (reverted): $IP_REVERTED"
# Assertions run with the gateway already disabled, so a failure here
# can't leave the runner's egress black-holed.
echo "$RULE_ON" | grep -q fwmark # client policy route installed
echo "$ROUTE_ON" | grep -q 'default dev awl0' # full-tunnel default via TUN
test -n "$IP_GW" # traffic really flowed through the exit node
test "$IP_GW" != "$IP_DIRECT" # egress changed => full-tunnel works
test "$IP_REVERTED" = "$IP_DIRECT" # runtime disable reverted egress
! echo "$RULE_OFF" | grep -q fwmark # policy route removed on disable
! echo "$ROUTE_OFF" | grep -q 'default dev awl0' # TUN default removed on disable
# Re-enable so the SIGINT shutdown path (teardownGatewayAtShutdown) is exercised.
./awl cli gateway client use --name awl-tester
sleep 1
sudo kill -SIGINT $awl_pid
sleep 2
# awl is gone: its TUN and the default route via it vanished with the
# process, but the fwmark ip rule is interface-independent — its absence
# proves the shutdown teardown ran. (NAT/ip_forward are server-side only.)
! ip rule show | grep -q fwmark
- name: Run librespeed-cli, awl, librespeed-cli through awl
if: matrix.os == 'macos-latest'
run: |
chmod +x awl
sudo ./awl &
./librespeed-cli --local-json config_librespeed.json --server 1 --json --share --telemetry-level disabled | python3 -m json.tool
sleep 10
awl_pid=`jobs -l | grep './awl' | awk '{print $2}'`
./awl cli peers status
./librespeed-cli --local-json config_librespeed.json --server 2 --json --share --telemetry-level disabled | python3 -m json.tool
ping 10.66.0.2 -c 10
ping awl-tester.awl -c 10
sleep 1
sudo kill -SIGINT $awl_pid
sleep 1
- name: Run librespeed-cli, awl, librespeed-cli through awl
if: matrix.os == 'windows-latest'
run: |
chmod +x awl.exe
./awl.exe &
./librespeed-cli.exe --local-json config_librespeed.json --server 1 --json --share --telemetry-level disabled | python3 -m json.tool
sleep 10
awl_pid=`jobs -l | grep './awl' | awk '{print $2}'`
./awl.exe cli peers status
./librespeed-cli.exe --local-json config_librespeed.json --server 2 --json --share --telemetry-level disabled | python3 -m json.tool
ping -w 20000 -n 10 10.66.0.2
ping -w 20000 -n 10 -a awl-tester.awl
sleep 1
kill -SIGINT $awl_pid
sleep 1