mirror of
https://github.com/cfal/shoes.git
synced 2026-11-06 16:14:11 +00:00
Broadens unit and integration coverage of WebSocket framing, ShadowTLS and REALITY ClientHello parsing, VLESS fallback, Hysteria2 and TUIC authentication, DNS, and connection budgets across reloads, and fixes the defects it exposed: WebSocket streams now accept control frames up to RFC 6455's 125-byte limit, no longer report EOF into partly filled read buffers, and flush buffered frames before shutting down; the shared ClientHello parser reassembles hellos split across TLS records, as Go TLS stacks do; and message-stream shutdown after EOF is bounded like the stream relay's. It also builds the binary on the library crate instead of compiling every module twice, removes the unused UdpMessageStream, moves ShadowTLS interop tests to local handshake servers, makes filtered CI test steps fail when they select no tests, consolidates the WebSocket payload-reading code, and documents how to measure coverage along with the remaining gaps, including why WebSocket Close frames stay unanswered.
410 lines
15 KiB
YAML
410 lines
15 KiB
YAML
name: Test
|
|
|
|
on:
|
|
push:
|
|
branches: [ master ]
|
|
pull_request:
|
|
branches: [ master ]
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: always
|
|
RUST_BACKTRACE: 1
|
|
SING_BOX_VERSION: 1.14.1
|
|
SING_BOX_SHA256: 12cb2816b52febb356f6a885b740cc8758c3f30b8ae0ca8edba80f0d2d35343f
|
|
MIHOMO_VERSION: 1.19.31
|
|
MIHOMO_SHA256: 04cf9f09671704f839ddbee2e93069dc831a4123a75281e725d1d96ab9ac1afc
|
|
XRAY_VERSION: 26.10.21
|
|
XRAY_SHA256: 0eec3ed4163c273d8c8bf821f7d219e257921cf584aa3fb970715e458e631978
|
|
XRAY_COMMIT: 1b1647cd9ddf0abc34b981d4611fc03bcac1ca74
|
|
MIHOMO_ALPHA_COMMIT: 94b13aed49b8dc41973e4bb3f721c5fa2c5c5c1f
|
|
NAIVE_CADDY_VERSION: 2.11.7-naive
|
|
NAIVE_CADDY_SHA256: ac97057c925bb098eb575e7b0cb8bd547d4c5f845b09a3dedfbe34444aa7ae88
|
|
|
|
jobs:
|
|
dependency-notices:
|
|
name: Dependency notices
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
- uses: taiki-e/install-action@v2
|
|
with:
|
|
tool: cargo-about@0.9.2
|
|
- name: Verify generated dependency licenses and artifact checks
|
|
run: |
|
|
python3 scripts/generate-release-notices.py
|
|
git diff --exit-code -- licenses/dependencies.txt
|
|
cargo fetch --locked
|
|
python3 scripts/test-release-notices.py
|
|
|
|
wireguard-interop:
|
|
name: WireGuard interoperability
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 60
|
|
env:
|
|
GOMAXPROCS: 1
|
|
WG_SING_BOX_COMMIT: 7054cac5124465ffdb145870d7c01885566711b1
|
|
WG_XRAY_COMMIT: 1b1647cd9ddf0abc34b981d4611fc03bcac1ca74
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
- name: Restore pinned WireGuard peers
|
|
id: wireguard-peers
|
|
uses: actions/cache/restore@v6
|
|
with:
|
|
path: ~/.cache/shoes-wireguard
|
|
key: ${{ runner.os }}-${{ runner.arch }}-wireguard-peers-go1.27.3-${{ env.WG_SING_BOX_COMMIT }}-${{ env.WG_XRAY_COMMIT }}
|
|
- uses: actions/setup-go@v7
|
|
if: steps.wireguard-peers.outputs.cache-hit != 'true'
|
|
with:
|
|
go-version: '1.27.3'
|
|
cache: false
|
|
- uses: actions/cache@v6
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
target
|
|
~/go/pkg/mod
|
|
~/.cache/go-build
|
|
key: ${{ runner.os }}-wireguard-${{ hashFiles('**/Cargo.lock') }}-${{ env.WG_SING_BOX_COMMIT }}-${{ env.WG_XRAY_COMMIT }}
|
|
- name: Build pinned independent WireGuard peers
|
|
if: steps.wireguard-peers.outputs.cache-hit != 'true'
|
|
run: |
|
|
mkdir -p "$HOME/.cache/shoes-wireguard"
|
|
git clone --filter=blob:none --no-checkout https://github.com/SagerNet/sing-box.git "$HOME/wg-sing-box"
|
|
git -C "$HOME/wg-sing-box" checkout --detach "$WG_SING_BOX_COMMIT"
|
|
test "$(git -C "$HOME/wg-sing-box" rev-parse HEAD)" = "$WG_SING_BOX_COMMIT"
|
|
git clone --filter=blob:none --no-checkout https://github.com/XTLS/Xray-core.git "$HOME/wg-xray"
|
|
git -C "$HOME/wg-xray" checkout --detach "$WG_XRAY_COMMIT"
|
|
test "$(git -C "$HOME/wg-xray" rev-parse HEAD)" = "$WG_XRAY_COMMIT"
|
|
cd "$HOME/wg-sing-box"
|
|
go build -mod=readonly -p 1 -tags with_gvisor,with_wireguard -o "$HOME/.cache/shoes-wireguard/sing-box" ./cmd/sing-box
|
|
cd "$HOME/wg-xray"
|
|
go build -mod=readonly -p 1 -o "$HOME/.cache/shoes-wireguard/xray" ./main
|
|
- name: Save pinned WireGuard peers
|
|
if: steps.wireguard-peers.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@v6
|
|
with:
|
|
path: ~/.cache/shoes-wireguard
|
|
key: ${{ steps.wireguard-peers.outputs.cache-primary-key }}
|
|
- name: Select WireGuard peers
|
|
run: |
|
|
echo "SHOES_TEST_SING_BOX_BIN=$HOME/.cache/shoes-wireguard/sing-box" >> "$GITHUB_ENV"
|
|
echo "SHOES_TEST_XRAY_BIN=$HOME/.cache/shoes-wireguard/xray" >> "$GITHUB_ENV"
|
|
"$HOME/.cache/shoes-wireguard/sing-box" version
|
|
"$HOME/.cache/shoes-wireguard/xray" version
|
|
- name: Test both roles, inner address families, and real rekey
|
|
env:
|
|
RUST_LOG: warn
|
|
run: >-
|
|
.github/require-tests.sh cargo test -p shoes --locked --features optional-peer-tests
|
|
--test optional_peer wireguard -- --ignored --test-threads=1
|
|
|
|
unit-tests:
|
|
name: Unit tests
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 25
|
|
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: Cache cargo registry
|
|
uses: actions/cache@v6
|
|
with:
|
|
path: ~/.cargo/registry
|
|
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
|
|
|
|
- name: Cache cargo index
|
|
uses: actions/cache@v6
|
|
with:
|
|
path: ~/.cargo/git
|
|
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
|
|
|
|
- name: Cache cargo build
|
|
uses: actions/cache@v6
|
|
with:
|
|
path: target
|
|
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
|
|
|
|
- name: Build
|
|
run: cargo build --workspace --locked --verbose
|
|
|
|
- name: Run local tests
|
|
run: cargo test --workspace --locked --lib --bins --verbose
|
|
|
|
- name: Run process contract tests
|
|
run: cargo test -p shoes --locked --test process_contract --verbose -- --test-threads=1
|
|
|
|
- name: Run rule compilation allocation regression
|
|
run: cargo test -p shoes --locked --test rule_allocation --verbose
|
|
|
|
- name: Run host FFI tests
|
|
run: cargo test -p shoes --locked --lib --features ffi -- --test-threads=1
|
|
|
|
benchmark-tooling:
|
|
name: Benchmark tooling
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
- uses: actions/setup-node@v7
|
|
with:
|
|
node-version: '24'
|
|
package-manager-cache: false
|
|
- name: Test benchmark harness and manifests
|
|
run: node --test benches/*.test.mjs
|
|
|
|
tun-macos:
|
|
name: Rootless TUN (macOS)
|
|
runs-on: macos-latest
|
|
timeout-minutes: 30
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: Cache Rust build
|
|
uses: actions/cache@v6
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
target
|
|
key: ${{ runner.os }}-tun-cargo-${{ hashFiles('**/Cargo.lock') }}
|
|
|
|
- name: Run raw-FD and packet tests without a TUN device
|
|
run: >-
|
|
.github/require-tests.sh cargo test -p shoes --locked --lib --features ffi tun:: -- --test-threads=1
|
|
|
|
- name: Run rootless WireGuard, FFI, and process lifecycle tests
|
|
run: >-
|
|
.github/require-tests.sh cargo test -p shoes --locked --lib --test process_contract --features ffi wireguard -- --test-threads=1
|
|
|
|
- name: Run FFI rule-source startup and packet tests
|
|
run: >-
|
|
.github/require-tests.sh cargo test -p shoes --locked --lib --features ffi ffi::common::rule_source_tests -- --test-threads=1
|
|
|
|
- name: Run rule-source routing and filesystem reload tests
|
|
run: >-
|
|
.github/require-tests.sh cargo test -p shoes --locked --test process_contract --features ffi rule_sets:: -- --test-threads=1
|
|
|
|
- name: Run process filesystem watcher unit tests
|
|
run: >-
|
|
.github/require-tests.sh cargo test -p shoes --locked --lib process:: -- --test-threads=1
|
|
|
|
integration-tests:
|
|
name: Integration (${{ matrix.name }})
|
|
needs: unit-tests
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- name: local protocols
|
|
features: integration-tests
|
|
target: integration
|
|
filters: ""
|
|
peer: sing-box
|
|
- name: optional peer interoperability
|
|
features: optional-peer-tests
|
|
target: optional_peer
|
|
filters: ""
|
|
peer: mihomo
|
|
- name: XHTTP interoperability
|
|
features: integration-tests
|
|
target: xhttp_interop
|
|
filters: ""
|
|
peer: xhttp
|
|
- name: external DNS
|
|
features: external-network-tests
|
|
target: external_network
|
|
filters: dns resolver vless_doh vless_dot
|
|
peer: sing-box
|
|
- name: external proxies
|
|
features: external-network-tests
|
|
target: external_network
|
|
filters: portforward shadowtls
|
|
peer: sing-box
|
|
- name: external REALITY
|
|
features: external-network-tests
|
|
target: external_network
|
|
filters: reality
|
|
peer: sing-box
|
|
- name: kernel WireGuard
|
|
features: privileged-tests
|
|
target: privileged
|
|
filters: wireguard_kernel
|
|
peer: kernel-wireguard
|
|
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: Cache cargo registry
|
|
uses: actions/cache@v6
|
|
with:
|
|
path: ~/.cargo/registry
|
|
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
|
|
|
|
- name: Cache cargo index
|
|
uses: actions/cache@v6
|
|
with:
|
|
path: ~/.cargo/git
|
|
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
|
|
|
|
- name: Cache cargo build
|
|
uses: actions/cache@v6
|
|
with:
|
|
path: target
|
|
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
|
|
|
|
- name: Install kernel WireGuard test tools
|
|
if: matrix.peer == 'kernel-wireguard'
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install --yes --no-install-recommends wireguard-tools iproute2
|
|
uname -r
|
|
wg --version
|
|
|
|
- name: Install sing-box test peer
|
|
if: matrix.peer == 'sing-box' || matrix.target == 'optional_peer'
|
|
run: |
|
|
archive="$RUNNER_TEMP/sing-box.tar.gz"
|
|
curl --fail --location --retry 3 \
|
|
--output "$archive" \
|
|
"https://github.com/SagerNet/sing-box/releases/download/v${SING_BOX_VERSION}/sing-box-${SING_BOX_VERSION}-linux-amd64.tar.gz"
|
|
echo "${SING_BOX_SHA256} ${archive}" | sha256sum --check --strict
|
|
tar --extract --gzip --file "$archive" --directory "$RUNNER_TEMP"
|
|
binary="$RUNNER_TEMP/sing-box-${SING_BOX_VERSION}-linux-amd64/sing-box"
|
|
chmod +x "$binary"
|
|
echo "SHOES_TEST_SING_BOX_BIN=$binary" >> "$GITHUB_ENV"
|
|
|
|
- name: Install Mihomo test peer
|
|
if: matrix.peer == 'mihomo'
|
|
run: |
|
|
archive="$RUNNER_TEMP/mihomo.gz"
|
|
binary="$RUNNER_TEMP/mihomo"
|
|
curl --fail --location --retry 3 \
|
|
--output "$archive" \
|
|
"https://github.com/MetaCubeX/mihomo/releases/download/v${MIHOMO_VERSION}/mihomo-linux-amd64-compatible-v${MIHOMO_VERSION}.gz"
|
|
echo "${MIHOMO_SHA256} ${archive}" | sha256sum --check --strict
|
|
gzip --decompress --stdout "$archive" > "$binary"
|
|
chmod +x "$binary"
|
|
echo "SHOES_TEST_MIHOMO_BIN=$binary" >> "$GITHUB_ENV"
|
|
|
|
- name: Install Xray test peer
|
|
if: matrix.target == 'optional_peer'
|
|
run: |
|
|
archive="$RUNNER_TEMP/xray.zip"
|
|
curl --fail --location --retry 3 \
|
|
--output "$archive" \
|
|
"https://github.com/XTLS/Xray-core/releases/download/v${XRAY_VERSION}/Xray-linux-64.zip"
|
|
echo "${XRAY_SHA256} ${archive}" | sha256sum --check --strict
|
|
unzip "$archive" xray -d "$RUNNER_TEMP/xray-peer"
|
|
binary="$RUNNER_TEMP/xray-peer/xray"
|
|
chmod +x "$binary"
|
|
echo "SHOES_TEST_XRAY_BIN=$binary" >> "$GITHUB_ENV"
|
|
|
|
- name: Install native Naive Caddy test peer
|
|
if: matrix.target == 'optional_peer'
|
|
run: |
|
|
archive="$RUNNER_TEMP/caddy-forwardproxy-naive.tar.xz"
|
|
curl --fail --location --retry 3 \
|
|
--output "$archive" \
|
|
"https://github.com/klzgrad/forwardproxy/releases/download/v${NAIVE_CADDY_VERSION}/caddy-forwardproxy-naive.tar.xz"
|
|
echo "${NAIVE_CADDY_SHA256} ${archive}" | sha256sum --check --strict
|
|
tar --extract --xz --file "$archive" --directory "$RUNNER_TEMP"
|
|
binary="$RUNNER_TEMP/caddy-forwardproxy-naive/caddy"
|
|
chmod +x "$binary"
|
|
echo "SHOES_TEST_NAIVE_CADDY_BIN=$binary" >> "$GITHUB_ENV"
|
|
|
|
- name: Run sing-box mux lifecycle tests
|
|
if: matrix.name == 'local protocols'
|
|
run: >-
|
|
.github/require-tests.sh cargo test -p shoes --locked --lib --features integration-tests
|
|
h2mux::h2mux_server_session::singbox_interop_tests:: -- --test-threads=1
|
|
|
|
- name: Restore pinned XHTTP peers
|
|
if: matrix.target == 'xhttp_interop'
|
|
id: xhttp-peers
|
|
uses: actions/cache/restore@v6
|
|
with:
|
|
path: |
|
|
~/.cache/shoes-xray/xray
|
|
~/.cache/shoes-mihomo/mihomo
|
|
key: ${{ runner.os }}-xhttp-peers-go1.27.3-${{ env.XRAY_COMMIT }}-${{ env.MIHOMO_ALPHA_COMMIT }}
|
|
|
|
- name: Install Go for XHTTP peers
|
|
if: matrix.target == 'xhttp_interop' && steps.xhttp-peers.outputs.cache-hit != 'true'
|
|
uses: actions/setup-go@v7
|
|
with:
|
|
go-version: '1.27.3'
|
|
cache: false
|
|
|
|
- name: Build pinned Xray test peer
|
|
if: matrix.target == 'xhttp_interop' && steps.xhttp-peers.outputs.cache-hit != 'true'
|
|
run: |
|
|
source="$HOME/.cache/shoes-xray"
|
|
git clone --filter=blob:none --no-checkout https://github.com/XTLS/Xray-core.git "$source"
|
|
git -C "$source" checkout --detach "$XRAY_COMMIT"
|
|
test "$(git -C "$source" rev-parse HEAD)" = "$XRAY_COMMIT"
|
|
cd "$source"
|
|
GOMAXPROCS=1 go build -p 1 -o "$source/xray" ./main
|
|
|
|
- name: Build pinned Mihomo Alpha test peer
|
|
if: matrix.target == 'xhttp_interop' && steps.xhttp-peers.outputs.cache-hit != 'true'
|
|
run: |
|
|
source="$HOME/.cache/shoes-mihomo"
|
|
git clone --filter=blob:none --no-checkout https://github.com/MetaCubeX/mihomo.git "$source"
|
|
git -C "$source" checkout --detach "$MIHOMO_ALPHA_COMMIT"
|
|
test "$(git -C "$source" rev-parse HEAD)" = "$MIHOMO_ALPHA_COMMIT"
|
|
cd "$source"
|
|
GOMAXPROCS=1 CGO_ENABLED=0 go build -p 1 \
|
|
-ldflags "-X github.com/metacubex/mihomo/constant.Version=alpha-${MIHOMO_ALPHA_COMMIT:0:8}" \
|
|
-o "$source/mihomo" .
|
|
|
|
- name: Save pinned XHTTP peers
|
|
if: matrix.target == 'xhttp_interop' && steps.xhttp-peers.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@v6
|
|
with:
|
|
path: |
|
|
~/.cache/shoes-xray/xray
|
|
~/.cache/shoes-mihomo/mihomo
|
|
key: ${{ steps.xhttp-peers.outputs.cache-primary-key }}
|
|
|
|
- name: Select XHTTP peers
|
|
if: matrix.target == 'xhttp_interop'
|
|
run: |
|
|
echo "SHOES_TEST_XRAY_BIN=$HOME/.cache/shoes-xray/xray" >> "$GITHUB_ENV"
|
|
echo "SHOES_TEST_MIHOMO_BIN=$HOME/.cache/shoes-mihomo/mihomo" >> "$GITHUB_ENV"
|
|
"$HOME/.cache/shoes-xray/xray" version
|
|
"$HOME/.cache/shoes-mihomo/mihomo" -v
|
|
|
|
- name: Run integration tests
|
|
env:
|
|
TEST_FILTERS: ${{ matrix.filters }}
|
|
RUST_LOG: warn
|
|
run: |
|
|
if [ -z "$TEST_FILTERS" ]; then
|
|
cargo test -p shoes --locked \
|
|
--features "${{ matrix.features }}" \
|
|
--test "${{ matrix.target }}" \
|
|
--verbose -- --test-threads=1
|
|
else
|
|
for filter in $TEST_FILTERS; do
|
|
.github/require-tests.sh cargo test -p shoes --locked \
|
|
--features "${{ matrix.features }}" \
|
|
--test "${{ matrix.target }}" \
|
|
--verbose "$filter::" -- --test-threads=1
|
|
done
|
|
fi
|