Skip to content

fix(iroh): don't kill noq endpoint on first transport recv error #17800

fix(iroh): don't kill noq endpoint on first transport recv error

fix(iroh): don't kill noq endpoint on first transport recv error #17800

Workflow file for this run

name: CI
on:
pull_request:
types: ["labeled", "unlabeled", "opened", "synchronize", "reopened"]
merge_group:
push:
branches:
- main
concurrency:
group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
RUST_BACKTRACE: 1
RUSTFLAGS: -Dwarnings
RUSTDOCFLAGS: -Dwarnings
MSRV: "1.91"
SCCACHE_CACHE_SIZE: "10G"
IROH_FORCE_STAGING_RELAYS: "1"
jobs:
pick-runner:
uses: "./.github/workflows/pick-runner.yml"
with:
min_free_runners: 3
secrets:
RUNNER_READ_TOKEN: ${{ secrets.RUNNER_READ_TOKEN }}
tests:
name: CI Test Suite
if: "github.event_name != 'pull_request' || ! contains(github.event.pull_request.labels.*.name, 'flaky-test')"
uses: "./.github/workflows/tests.yaml"
cross_build:
name: Cross Build Only
if: "github.event_name != 'pull_request' || ! contains(github.event.pull_request.labels.*.name, 'flaky-test')"
timeout-minutes: 30
needs: pick-runner
runs-on: ${{ fromJSON(needs.pick-runner.outputs.overflow_1) }}
# runs-on: [self-hosted, linux, X64]
env:
RUSTFLAGS: "-Dwarnings --cfg skip_patchbay"
strategy:
fail-fast: false
matrix:
target:
# cross tests are currently broken vor armv7 and aarch64
# see https://github.com/cross-rs/cross/issues/1311
# - armv7-linux-androideabi
# - aarch64-linux-android
# Freebsd execution fails in cross
# - i686-unknown-freebsd # Linking fails :/
- x86_64-unknown-freebsd
# Netbsd execution fails to link in cross
# - x86_64-unknown-netbsd
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: recursive
- name: Install rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cleanup Docker
continue-on-error: true
run: |
docker kill $(docker ps -q)
# See https://github.com/cross-rs/cross/issues/1222
- name: Cache cross
id: cache-cross
uses: actions/cache@v5
with:
path: ~/.cargo/bin/cross
key: cross-${{ runner.os }}-${{ runner.arch }}
- name: Install cross
if: steps.cache-cross.outputs.cache-hit != 'true'
uses: taiki-e/install-action@cross
- name: build
# cross tests are currently broken vor armv7 and aarch64
# see https://github.com/cross-rs/cross/issues/1311. So on
# those platforms we only build but do not run tests.
run: cross build --all --target ${{ matrix.target }}
env:
RUST_LOG: ${{ runner.debug && 'TRACE' || 'DEBUG'}}
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER: cc
android:
name: Android Build & Test
if: "github.event_name != 'pull_request' || ! contains(github.event.pull_request.labels.*.name, 'flaky-test')"
timeout-minutes: 60
# runs-on: [self-hosted, linux, X64]
needs: pick-runner
runs-on: ${{ fromJSON(needs.pick-runner.outputs.overflow_2) }}
strategy:
fail-fast: false
matrix:
include:
- target: aarch64-linux-android
- target: armv7-linux-androideabi
- target: x86_64-linux-android
api-level: 35
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Enable KVM for nested virtualization
if: matrix.target == 'x86_64-linux-android'
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666"' \
| sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Set up Rust
uses: dtolnay/rust-toolchain@stable
with:
target: ${{ matrix.target }}
- name: Setup Java
uses: actions/setup-java@v5
with:
distribution: "temurin"
java-version: "17"
- name: Setup Android SDK
uses: android-actions/setup-android@v4
# Pinned to a release tag (rather than @main) for supply-chain hygiene.
- name: Setup Android NDK
uses: nttld/setup-ndk@v1
id: setup-ndk
with:
ndk-version: r25c
add-to-path: true
- name: Install cargo-ndk
run: cargo install --version 4.1.2 cargo-ndk
# Replace cargo-ndk-runner with a wrapper that forwards RUST_LOG
# and RUST_BACKTRACE into the emulator shell. The upstream binary
# does `adb shell <bin>` without inheriting any host env.
- name: Wrap cargo-ndk-runner to forward logging env
if: matrix.target == 'x86_64-linux-android'
run: |
cat > "$(which cargo-ndk-runner)" <<'WRAPPER'
#!/bin/sh
set -e
dev=/data/local/tmp/$(basename "$1")
adb push "$1" "$dev" >/dev/null
adb shell chmod 755 "$dev"
shift
adb shell "RUST_LOG=$RUST_LOG RUST_BACKTRACE=$RUST_BACKTRACE $dev $*"
WRAPPER
chmod +x "$(which cargo-ndk-runner)"
- name: Build
if: matrix.target != 'x86_64-linux-android'
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: cargo ndk --target ${{ matrix.target }} build
# Build all the test binaries up front so the emulator boot can
# overlap with compilation. cargo-ndk runs `cargo test --no-run`
# against each crate; the binaries land in
# target/$CARGO_NDK_TARGET/debug/deps/.
- name: Build workspace test binaries
if: matrix.target == 'x86_64-linux-android'
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
CARGO_NDK_TARGET: ${{ matrix.target }}
run: |
cargo ndk test --no-run -p iroh-base --all-features
cargo ndk test --no-run -p iroh-dns --features tls-ring
cargo ndk test --no-run -p iroh-relay --features tls-ring,metrics
cargo ndk test --no-run -p iroh --features tls-ring,metrics,portmapper,test-utils
- name: Run workspace tests on Android emulator
if: matrix.target == 'x86_64-linux-android'
uses: reactivecircus/android-emulator-runner@v2
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
# Forwarded into the emulator by the cargo-ndk-runner wrapper.
RUST_LOG: trace
RUST_BACKTRACE: "1"
CARGO_NDK_TARGET: ${{ matrix.target }}
with:
api-level: ${{ matrix.api-level }}
arch: x86_64
target: google_apis
force-avd-creation: false
# `-dns-server` + `-netfast` + `-no-metrics` is the combination reported to give
# working public-internet connectivity on the GH-hosted runner; without them wlan0
# stays NO-CARRIER and every connect() to a public IP fails with ENETUNREACH.
# See https://github.com/ReactiveCircus/android-emulator-runner/issues/348#issuecomment-2578082030
emulator-options: -no-window -no-audio -no-boot-anim -gpu swiftshader_indirect -dns-server 8.8.8.8 -netfast -no-metrics
disable-animations: true
script: |
adb wait-for-device
# Wait for full boot and a working outbound TCP. `sys.boot_completed=1` fires
# before the radio/Wi-Fi stack comes up, and `ip route get 8.8.8.8` reports
# success while the kernel's per-network fwmark route is still missing. Probe
# an actual TCP connect to 8.8.8.8:53 instead - it exercises the same path
# the test sockets will use.
adb shell 'i=0; while [ -z "$(getprop sys.boot_completed | tr -d "\r")" ]; do i=$((i+1)); if [ $i -gt 300 ]; then exit 1; fi; sleep 2; done'
adb shell 'i=0; while ! nc -w 2 8.8.8.8 53 </dev/null >/dev/null 2>&1; do i=$((i+1)); if [ $i -gt 30 ]; then exit 1; fi; sleep 2; done'
# Disable IPv6: the emulator has site-local + link-local v6 but no global v6
# route, so connect() to a global v6 address hangs instead of returning ENETUNREACH.
adb root && adb wait-for-device
adb shell sysctl -w net.ipv6.conf.all.disable_ipv6=1 || true
adb shell sysctl -w net.ipv6.conf.default.disable_ipv6=1 || true
adb shell sysctl -w net.ipv6.conf.lo.disable_ipv6=1 || true
adb shell ip addr
cargo ndk test -p iroh-base --all-features
cargo ndk test -p iroh-dns --features tls-ring
cargo ndk test -p iroh-relay --features tls-ring,metrics
cargo ndk test -p iroh --features tls-ring,metrics,portmapper,test-utils
cross_test:
name: Cross Test
if: "github.event_name != 'pull_request' || ! contains(github.event.pull_request.labels.*.name, 'flaky-test')"
timeout-minutes: 30
needs: pick-runner
runs-on: ${{ fromJSON(needs.pick-runner.outputs.overflow_3) }}
# runs-on: [self-hosted, linux, X64]
strategy:
fail-fast: false
matrix:
target:
- i686-unknown-linux-gnu
env:
RUSTFLAGS: "-Dwarnings --cfg skip_patchbay"
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: recursive
- name: Install rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cleanup Docker
continue-on-error: true
run: |
docker kill $(docker ps -q)
# See https://github.com/cross-rs/cross/issues/1222
- name: Cache cross
id: cache-cross
uses: actions/cache@v5
with:
path: ~/.cargo/bin/cross
key: cross-${{ runner.os }}-${{ runner.arch }}
- name: Install cross
if: steps.cache-cross.outputs.cache-hit != 'true'
uses: taiki-e/install-action@cross
- name: test
run: cross test --all --target ${{ matrix.target }} -- --test-threads=12
env:
RUST_LOG: ${{ runner.debug && 'TRACE' || 'DEBUG' }}
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER: cc
wasm_test:
name: Build & test wasm32 for browsers
needs: pick-runner
runs-on: ${{ fromJSON(needs.pick-runner.outputs.overflow_4) }}
# runs-on: [self-hosted, linux, X64]
env:
RUSTFLAGS: '--cfg getrandom_backend="wasm_js"'
steps:
- name: Checkout sources
uses: actions/checkout@v6
- name: Setup node.js version 22.5 # needed for browser-like websocket API support in node.js
uses: actions/setup-node@v6
with:
node-version: 22.5
- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable
- name: Add wasm target
run: rustup target add wasm32-unknown-unknown
- name: Install cargo-binstall
uses: cargo-bins/cargo-binstall@v1.18.1
- name: Install wasm-bindgen-test-runner
# Match the version of wasm-bindgen used in Cargo.lock
run: cargo binstall wasm-bindgen-cli@0.2.122 --locked --no-confirm
- name: Install wasm-tools
uses: bytecodealliance/actions/wasm-tools/setup@v1
- name: wasm32 build (iroh-base)
run: cargo build --target wasm32-unknown-unknown -p iroh-base --all-features
- name: wasm32 build (iroh-relay)
run: cargo build --target wasm32-unknown-unknown -p iroh-relay
- name: wasm32 build (iroh)
run: cargo build --target wasm32-unknown-unknown -p iroh
# If the Wasm file contains any 'import "env"' declarations, then
# some non-Wasm-compatible code made it into the final code.
- name: Ensure no 'import "env"' in iroh-relay Wasm
run: |
! wasm-tools print --skeleton target/wasm32-unknown-unknown/debug/iroh_relay.wasm | grep 'import "env"'
- name: Ensure no 'import "env"' in iroh Wasm
run: |
! wasm-tools print --skeleton target/wasm32-unknown-unknown/debug/iroh.wasm | grep 'import "env"'
- name: Run integration test in wasm
run: cargo test -p iroh --test integration --target=wasm32-unknown-unknown
check_semver:
needs: pick-runner
runs-on: ${{ fromJSON(needs.pick-runner.outputs.overflow_5) }}
# runs-on: [self-hosted, linux, X64]
env:
RUSTC_WRAPPER: "sccache"
SCCACHE_GHA_ENABLED: "on"
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install sccache
uses: mozilla-actions/sccache-action@v0.0.10
continue-on-error: true
- uses: ./.github/workflows/sccache-probe
- name: Setup Environment (PR)
if: ${{ github.event_name == 'pull_request' }}
shell: bash
run: |
echo "HEAD_COMMIT_SHA=$(git rev-parse origin/${{ github.base_ref }})" >> ${GITHUB_ENV}
- name: Setup Environment (Push)
if: ${{ github.event_name == 'push' || github.event_name == 'merge_group' }}
shell: bash
run: |
echo "HEAD_COMMIT_SHA=$(git rev-parse origin/main)" >> ${GITHUB_ENV}
- name: Check semver
# uses: obi1kenobi/cargo-semver-checks-action@v2
uses: n0-computer/cargo-semver-checks-action@feat-baseline
with:
package: iroh, iroh-base, iroh-dns-server, iroh-relay, iroh-net-report
baseline-rev: ${{ env.HEAD_COMMIT_SHA }}
use-cache: false
check_external_types:
timeout-minutes: 30
name: Check external types in public API
if: "github.event_name != 'pull_request' || ! contains(github.event.pull_request.labels.*.name, 'flaky-test')"
needs: pick-runner
runs-on: ${{ fromJSON(needs.pick-runner.outputs.overflow_9) }}
# runs-on: [self-hosted, linux, X64]
env:
RUSTC_WRAPPER: "sccache"
SCCACHE_GHA_ENABLED: "on"
# The tool drives an internal rustdoc invocation that only emits JSON
# for the analyzer, so the workflow-wide `-Dwarnings` would just turn
# unrelated rustdoc lints (e.g. `private-intra-doc-links`) into hard
# failures here. Clear it for this job.
RUSTDOCFLAGS: ""
# Pin to the nightly that the pinned `cargo-check-external-types`
# release was last tested against. Update both together.
CARGO_CHECK_EXTERNAL_TYPES_VERSION: "0.4.0"
TOOLCHAIN: "nightly-2025-10-18"
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.TOOLCHAIN }}
- name: Install sccache
uses: mozilla-actions/sccache-action@v0.0.9
- name: Install cargo-binstall
uses: cargo-bins/cargo-binstall@v1.18.1
- uses: taiki-e/install-action@cargo-make
- name: Install cargo-check-external-types
run: cargo binstall cargo-check-external-types@${{ env.CARGO_CHECK_EXTERNAL_TYPES_VERSION }} --locked --no-confirm
- name: Check external types
run: cargo make check-external-types
check_fmt:
timeout-minutes: 30
name: Checking fmt
runs-on: ubuntu-latest
env:
RUSTC_WRAPPER: "sccache"
SCCACHE_GHA_ENABLED: "on"
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- uses: mozilla-actions/sccache-action@v0.0.10
continue-on-error: true
- uses: ./.github/workflows/sccache-probe
- uses: taiki-e/install-action@cargo-make
- run: cargo make format-check
check_docs:
timeout-minutes: 30
name: Checking docs
needs: pick-runner
runs-on: ${{ fromJSON(needs.pick-runner.outputs.overflow_6) }}
# runs-on: [self-hosted, linux, X64]
env:
RUSTC_WRAPPER: "sccache"
SCCACHE_GHA_ENABLED: "on"
RUSTDOCFLAGS: --cfg docsrs
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2025-10-09
- name: Install sccache
uses: mozilla-actions/sccache-action@v0.0.10
continue-on-error: true
- uses: ./.github/workflows/sccache-probe
- name: Docs
run: cargo doc --workspace --all-features --no-deps --document-private-items
clippy_check:
timeout-minutes: 30
needs: pick-runner
runs-on: ${{ fromJSON(needs.pick-runner.outputs.overflow_7) }}
# runs-on: [self-hosted, linux, X64]
env:
RUSTC_WRAPPER: "sccache"
SCCACHE_GHA_ENABLED: "on"
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Install sccache
uses: mozilla-actions/sccache-action@v0.0.10
continue-on-error: true
- uses: ./.github/workflows/sccache-probe
# TODO: We have a bunch of platform-dependent code so should
# probably run this job on the full platform matrix
- name: clippy check (all features)
run: cargo clippy --workspace --all-features --all-targets --lib --bins --tests --benches --examples
- name: clippy check (no features)
run: cargo clippy --workspace --no-default-features --all-targets --lib --bins --tests --benches --examples
- name: clippy check (default features)
run: cargo clippy --workspace --all-targets --lib --bins --tests --benches --examples
check_optional_deps:
timeout-minutes: 10
name: Check optional deps are absent without features
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- name: Verify optional deps are absent without features
run: |
fail=0
for dep in portmapper igd-next swarm-discovery ring aws-lc-rs; do
echo "cargo tree -p iroh --no-default-features --edges normal --target all -i $dep";
output=$(cargo tree -p iroh --no-default-features --edges normal --target all -i "$dep" 2>&1) || true
if ! echo "$output" | grep -qE "(nothing to print|did not match any packages)"; then
echo "ERROR: $dep should not be in the dependency tree without its feature"
echo "$output"
fail=1
fi
done
exit $fail
msrv:
if: "github.event_name != 'pull_request' || ! contains(github.event.pull_request.labels.*.name, 'flaky-test')"
timeout-minutes: 30
name: Minimal Supported Rust Version
needs: pick-runner
runs-on: ${{ fromJSON(needs.pick-runner.outputs.overflow_8) }}
# runs-on: [self-hosted, linux, X64]
env:
RUSTC_WRAPPER: "sccache"
SCCACHE_GHA_ENABLED: "on"
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.MSRV }}
- name: Install sccache
uses: mozilla-actions/sccache-action@v0.0.10
continue-on-error: true
- uses: ./.github/workflows/sccache-probe
- name: Check MSRV all features
run: |
cargo +$MSRV check --workspace --all-targets
cargo_deny:
timeout-minutes: 30
name: cargo deny
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: EmbarkStudios/cargo-deny-action@v2
with:
arguments: --workspace --all-features
command: check
command-arguments: "-Dwarnings"
netsim-integration-tests:
permissions: write-all
if: "github.event_name != 'pull_request' || ! contains(github.event.pull_request.labels.*.name, 'flaky-test')"
uses: "./.github/workflows/netsim_runner.yaml"
secrets: inherit
with:
branch: ${{ github.ref }}
max_workers: 6
netsim_branch: "main"
sim_paths: ${{ github.event_name == 'pull_request' && 'sims/integration' || 'sims/iroh/iroh.json,sims/integration' }}
pr_number: ${{ github.event.pull_request.number || '' }}
filter: ${{ github.event_name == 'pull_request' && 'skip:intg_iroh_full__1_to_3,intg_iroh_full__1_to_1x3,intg_iroh_relay_only__1_to_3' || '' }}
codespell:
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Cache pip
uses: actions/cache@v5
with:
path: ~/.cache/pip
key: pip-codespell-2.4.1
- run: pip install --user codespell[toml]==2.4.1
- run: codespell --ignore-words-list=ans,atmost,crate,inout,ratatui,ser,stayin,swarmin,worl,keep-alives --skip=CHANGELOG.md