name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
schedule:
- cron: '0 0 * * *'
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
CARGO_INCREMENTAL: 0
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
fmt:
name: Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cargo fmt --all -- --check
clippy:
name: Clippy Lints
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- name: Clippy (library)
run: cargo clippy --lib --features "client,server,http2,padding,rustls" -- -D warnings
- name: Clippy (tests & examples)
run: cargo clippy --tests --examples --benches --features "client,server,http2,padding,rustls" -- -W clippy::unwrap_used
test:
name: Test (${{ matrix.os }}, ${{ matrix.rust }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
rust: [stable, beta]
include:
- os: ubuntu-latest
rust: nightly
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- uses: Swatinem/rust-cache@v2
- name: Run tests (rustls)
if: matrix.os != 'windows-latest'
run: cargo test --features "client,server,http2,padding,rustls" --workspace
- name: Run tests (rustls + static-sqlite)
if: matrix.os == 'windows-latest'
run: cargo test --features "client,server,http2,padding,rustls,static-sqlite" --workspace
- name: Run tests (native-tls)
if: matrix.os != 'windows-latest'
run: cargo test --no-default-features --features "client,server,http2,padding,native-tls" --workspace
features:
name: Feature Combinations
runs-on: ubuntu-latest
strategy:
matrix:
features:
- ""
- "client"
- "server"
- "http2"
- "padding"
- "rustls"
- "native-tls"
- "client,server,http2,rustls"
- "client,server,http2,native-tls"
- "full"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Check features (${{ matrix.features || 'default' }})
run: cargo check --features "${{ matrix.features }}"
docs:
name: Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- uses: Swatinem/rust-cache@v2
- name: Build docs
run: RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --features "client,server,http2,padding,rustls" --no-deps
env:
RUSTDOCFLAGS: --cfg docsrs -D warnings
audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Generate Cargo.lock
run: cargo generate-lockfile
- name: Install cargo-audit
run: cargo install cargo-audit --locked
- name: Run security audit
run: cargo audit --ignore RUSTSEC-2023-0071
semver:
name: Semver Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install cargo-semver-checks
uses: taiki-e/install-action@cargo-semver-checks
- name: Check semver compatibility
run: cargo semver-checks check-release --default-features
continue-on-error: true
deny:
name: Cargo Deny
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: EmbarkStudios/cargo-deny-action@v2
with:
command: check bans advisories sources
coverage:
name: Code Coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Generate coverage
run: cargo llvm-cov --features "client,server,http2,padding,rustls" --workspace --lcov --output-path lcov.info
- name: Upload to Codecov
uses: codecov/codecov-action@v4
with:
files: lcov.info
fail_ci_if_error: false
msrv:
name: Minimum Supported Rust Version (1.86)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.86
- uses: Swatinem/rust-cache@v2
- run: cargo check --features "client,server,http2,padding,rustls"
python:
name: Python Bindings (${{ matrix.python }})
runs-on: ubuntu-latest
strategy:
matrix:
python: ['3.9', '3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- uses: Swatinem/rust-cache@v2
- name: Install maturin and pytest
run: pip install maturin pytest
- name: Build wheel
run: maturin build --features python --release
- name: Install wheel
run: pip install target/wheels/*.whl
- name: Run Python tests
run: pytest python/tests/ -v --tb=short
- name: Test Python import
run: |
python -c "
import hypertor
print(f'hypertor version: {hypertor.__version__}')
from hypertor import Client, AsyncClient, OnionApp, AppConfig
print('All imports successful')
"
security-tests:
name: Security Test Suite
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Run security tests
run: cargo test --test security -- --nocapture
- name: Verify no unsafe code
run: |
# Search for 'unsafe' keyword in Rust files, excluding legitimate uses
# Uses find + grep instead of grep -r for consistent behavior across platforms
UNSAFE_FOUND=$(find src -name "*.rs" -exec grep -l "unsafe" {} \; | xargs grep -n "unsafe" 2>/dev/null | \
grep -v "forbid(unsafe_code)" | \
grep -v "// SAFETY:" | \
grep -v "#!\[" | \
grep -v "#\[" || true)
if [ -n "$UNSAFE_FOUND" ]; then
echo "Found unexpected unsafe code:"
echo "$UNSAFE_FOUND"
exit 1
fi
echo "✓ No unexpected unsafe code found"
benchmark:
name: Performance Benchmarks
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Run benchmarks
run: cargo bench --features "client,server,http2,padding,rustls" --bench benchmarks -- --noplot
- name: Store benchmark result
uses: benchmark-action/github-action-benchmark@v1
with:
tool: 'cargo'
output-file-path: target/criterion/report/index.html
fail-on-alert: false
continue-on-error: true
release-check:
name: Release Readiness
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Check package
run: cargo package --allow-dirty
- name: Check publish (dry-run)
run: cargo publish --dry-run --allow-dirty