Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
dba2e35
build(rust): bump toolchain to 1.91.1
sneurlax Sep 16, 2026
62f502c
fix(rust): stop freeing the client handle on bootstrap and set_dormant
sneurlax Oct 5, 2026
9035b65
build(rust): bump arti to 2.6.0
sneurlax Sep 16, 2026
e48a1ea
fix(rust): bind SOCKS listeners before tor_start returns
sneurlax Oct 5, 2026
fd103a5
chore: release 0.2.0
sneurlax Sep 16, 2026
be07416
build(rust): update crates with published security advisories
sneurlax Oct 6, 2026
a1125c3
Merge branch 'fix/ffi-handle-lifetime' into feat/bump-arti
sneurlax Oct 5, 2026
caf1395
Merge branch 'fix/ffi-handle-lifetime' into feat/bump-arti
sneurlax Oct 6, 2026
32a7c23
chore(ffi): document safety contracts and regenerate bindings
sneurlax Oct 6, 2026
a90b838
fix(example): resolve analyzer findings
sneurlax Oct 6, 2026
c8fb284
fix(dart): reset Tor state on stop and serialize start and stop
sneurlax Oct 6, 2026
39b6cb1
build(rust): update num-bigint-dig for compiler compatibility
sneurlax Oct 6, 2026
c1a93b3
fix(dart): let concurrent start() calls share one attempt
sneurlax Oct 6, 2026
c96bc83
fix(dart): release native handles when bootstrap fails
sneurlax Oct 6, 2026
f9cf9a9
fix(dart): make disable() stop the proxy
sneurlax Oct 6, 2026
d73b660
fix(tor): allocate the SOCKS port atomically
sneurlax Oct 6, 2026
338dec6
fix(dart): free the directory strings passed to tor_start
sneurlax Oct 6, 2026
759b278
fix(ffi): release Rust error strings after Dart reads them
sneurlax Oct 6, 2026
f681254
fix(ffi): strip NUL bytes from Rust error messages
sneurlax Oct 6, 2026
2a5d7e7
fix(rust): only import update_last_error where it is used
sneurlax Oct 6, 2026
fecbffe
fix(dart): free the native client in a worker isolate and wait for it
sneurlax Oct 6, 2026
ce90eee
fix(tor): make lifecycle cancellable and bounded
sneurlax Oct 6, 2026
62f1a88
fix(hook): skip hidden files and hash bytes in the source fingerprint
sneurlax Oct 6, 2026
51b74f1
fix(hook): harden and optimize source fingerprinting
sneurlax Oct 6, 2026
16ca224
chore(deps): upgrade Arti to 2.7.0
sneurlax Oct 7, 2026
751e63a
chore(example): update SOCKS sockets and handle Tor lifecycle
sneurlax Oct 7, 2026
40092fa
build(rust): update advisory-affected crates
sneurlax Oct 13, 2026
87c727e
build(rust): vendor the reviewed time dependency fork
sneurlax Oct 13, 2026
4d13356
ci: validate native targets and packaged apps
sneurlax Oct 13, 2026
bc90701
fix(tor): preserve literal native data directory paths
sneurlax Oct 14, 2026
c08a658
fix(hook): fingerprint the vendored crates in rust/patches
sneurlax Oct 6, 2026
5f44b07
fix(example): close connections on failure and validate the Bitcoin f…
sneurlax Oct 16, 2026
ca38b69
fix(tor): retry the IPv6 twin when Windows denies access to it
sneurlax Oct 19, 2026
4af2512
fix(rust): regenerate the C header when the crate source changes
sneurlax Oct 19, 2026
953e9ff
ci: package the example app on Windows
sneurlax Oct 19, 2026
5646ece
fix(tor): cancel a start overtaken by a stop while resolving its dire…
sneurlax Oct 20, 2026
7a54d82
fix(tor): keep the caller's duration in TorBootstrapTimeout
sneurlax Oct 20, 2026
37cde92
refactor(tor): cancel bootstrap through the retained client handle
sneurlax Oct 20, 2026
fdfcd6c
test(rust): remove the scratch directories client tests leave behind
sneurlax Oct 20, 2026
1a22032
perf(rust): run each client on two worker threads
sneurlax Oct 20, 2026
0aa0449
perf(rust): bind the SOCKS port before building the client runtime
sneurlax Oct 20, 2026
06c6c20
build(rust): rerun build.rs when the NDK location changes
sneurlax Oct 20, 2026
d9d117b
refactor(hook): list the tracked source directories once
sneurlax Oct 20, 2026
6174517
refactor(example): derive button state from Tor.status
sneurlax Oct 20, 2026
6aee897
refactor(example): share the server features request
sneurlax Oct 20, 2026
e36c899
build(rust): pin the toolchain to Rust 1.99.1
sneurlax Oct 20, 2026
b007b05
fix(example): allow network access in the macOS release build
sneurlax Oct 20, 2026
dec20e7
fix(rust): rerun build.rs per source file so the hook can cache
sneurlax Oct 20, 2026
94bbc03
test(tor): run the symlink tests on Windows when links can be made
sneurlax Oct 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 164 additions & 32 deletions .github/workflows/native-prebuilts.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: Build native prebuilts
name: Native and package validation

on:
pull_request:
push:
tags: ['native-*']
workflow_dispatch:
Expand All @@ -10,11 +11,85 @@ permissions:

concurrency:
group: native-prebuilts-${{ github.ref }}
cancel-in-progress: false
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
verify:
name: Rust, Dart, and lifecycle tests
runs-on: ubuntu-22.04
timeout-minutes: 60
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: Install Linux prerequisites
run: |
sudo apt-get update
sudo apt-get install -y build-essential libgtk-3-dev liblzma-dev ninja-build pkg-config perl
- name: Install pinned Rust toolchain
run: bash tool/ci/install_rust.sh --component clippy,rustfmt
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
workspaces: rust
- uses: subosito/flutter-action@1508160852fb97248640997f7cfb38da241df0ba # v2.9.1
with:
flutter-version: '3.47.2'
channel: stable
- name: Verify Rust
run: |
cargo fmt --manifest-path rust/Cargo.toml --check
cargo test --locked --all-targets --manifest-path rust/Cargo.toml
cargo clippy --locked --all-targets --manifest-path rust/Cargo.toml -- -D warnings
- name: Verify Dart and native lifecycle
run: |
flutter pub get
flutter analyze
flutter test
- name: Test example widgets
working-directory: example
run: flutter test
- name: Cache pinned cargo-audit binary
id: cargo-audit-cache
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ~/.cargo/bin/cargo-audit
key: cargo-audit-${{ runner.os }}-${{ runner.arch }}-0.22.2-${{ hashFiles('rust/rust-toolchain.toml') }}
- name: Install pinned cargo-audit
if: steps.cargo-audit-cache.outputs.cache-hit != 'true'
run: cargo install cargo-audit --version 0.22.2 --locked
- name: Audit Rust dependencies
run: |
cargo audit --file rust/Cargo.lock \
--deny unsound \
--deny yanked \
--ignore RUSTSEC-2021-0145 \
--ignore RUSTSEC-2023-0071

windows-tests:
if: github.event_name == 'pull_request'
name: Windows time, IPv6, and file release tests
runs-on: windows-2022
timeout-minutes: 60
env:
NATIVE_TARGET: x86_64-pc-windows-msvc
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: Use short Windows build paths
shell: pwsh
run: ./tool/ci/windows_paths.ps1
- name: Install pinned Rust toolchain
run: bash tool/ci/install_rust.sh --target "$NATIVE_TARGET"
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
workspaces: rust
key: windows-tests
cache-targets: false
- name: Test time limits, IPv6 fallback, and file release
run: bash tool/ci/test_windows.sh

build:
if: github.event.deleted != true
if: github.event_name != 'pull_request' && github.event.deleted != true
name: ${{ matrix.target }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 120
Expand Down Expand Up @@ -42,17 +117,11 @@ jobs:
run:
shell: bash
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: Use short Windows build paths
if: runner.os == 'Windows'
shell: pwsh
run: |
git config --global core.longpaths true
New-Item -ItemType Directory -Force C:\c, C:\t, C:\tmp | Out-Null
"CARGO_HOME=C:/c" >> $env:GITHUB_ENV
"CARGO_TARGET_DIR=C:/t" >> $env:GITHUB_ENV
"TEMP=C:\tmp" >> $env:GITHUB_ENV
"TMP=C:\tmp" >> $env:GITHUB_ENV
- uses: actions/checkout@v6
run: ./tool/ci/windows_paths.ps1
- name: Install Linux prerequisites
if: runner.os == 'Linux'
run: |
Expand All @@ -64,11 +133,8 @@ jobs:
"$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" 'ndk;28.2.13676358'
echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/28.2.13676358" >> "$GITHUB_ENV"
- name: Install pinned Rust toolchain
run: |
toolchain=$(sed -n 's/^channel = "\([^"]*\)".*/\1/p' rust/rust-toolchain.toml)
rustup toolchain install "$toolchain" --profile minimal --target "$NATIVE_TARGET"
echo "RUSTUP_TOOLCHAIN=$toolchain" >> "$GITHUB_ENV"
- uses: Swatinem/rust-cache@v2
run: bash tool/ci/install_rust.sh --target "$NATIVE_TARGET"
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
workspaces: rust
key: ${{ matrix.target }}
Expand Down Expand Up @@ -107,44 +173,110 @@ jobs:
esac
mkdir -p artifacts
cp "$CARGO_TARGET_DIR/$NATIVE_TARGET/release/$library" "artifacts/$NATIVE_TARGET-$library"
- name: Test time limits, IPv6 fallback, and file release
if: runner.os == 'Windows'
run: bash tool/ci/test_windows.sh
- name: Smoke test desktop library
if: ${{ !contains(matrix.target, 'android') && !contains(matrix.target, '-ios') }}
run: |
python - <<'PY'
import ctypes
from pathlib import Path
library = ctypes.CDLL(str(next(Path('artifacts').iterdir()).resolve()))
library.tor_proxy_stop.argtypes = [ctypes.c_void_p]
library.tor_proxy_stop.restype = None
library.tor_proxy_stop(None)
PY
- uses: actions/upload-artifact@v4
run: python tool/ci/smoke_native.py artifacts/*
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: prebuilt-${{ matrix.target }}
path: artifacts/*
if-no-files-found: error

package:
if: github.event_name == 'pull_request'
name: Package example (${{ matrix.platform }})
runs-on: ${{ matrix.runner }}
timeout-minutes: 120
strategy:
fail-fast: false
matrix:
include:
- {platform: linux, runner: ubuntu-22.04}
- {platform: android, runner: ubuntu-22.04}
- {platform: ios, runner: macos-15}
- {platform: macos, runner: macos-15}
- {platform: windows, runner: windows-2022}
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: Install Linux prerequisites
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y build-essential clang cmake libgtk-3-dev liblzma-dev ninja-build pkg-config perl
- name: Install Android Java
if: matrix.platform == 'android'
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0
with:
distribution: temurin
java-version: '17'
- name: Install Android NDK
if: matrix.platform == 'android'
run: |
"$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" 'ndk;28.2.13676358'
echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/28.2.13676358" >> "$GITHUB_ENV"
- name: Install pinned Rust toolchain
run: |
case "${{ matrix.platform }}" in
linux) target=x86_64-unknown-linux-gnu ;;
android) target=aarch64-linux-android ;;
ios) target=aarch64-apple-ios ;;
# flutter build macos is universal, so the hook also builds x86_64.
macos) target=aarch64-apple-darwin,x86_64-apple-darwin ;;
windows) target=x86_64-pc-windows-msvc ;;
esac
bash tool/ci/install_rust.sh --target "$target"
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
workspaces: rust
key: package-${{ matrix.platform }}
- uses: subosito/flutter-action@1508160852fb97248640997f7cfb38da241df0ba # v2.9.1
with:
flutter-version: '3.47.2'
channel: stable
- name: Build packaged example
working-directory: example
run: |
case "${{ matrix.platform }}" in
linux) flutter build linux --release ;;
android) flutter build apk --release --target-platform android-arm64 ;;
ios) flutter build ios --release --no-codesign ;;
macos) flutter build macos --release ;;
windows) flutter build windows --release ;;
esac
- name: Load packaged macOS library
if: matrix.platform == 'macos'
run: bash tool/ci/check_macos_app.sh
- name: Load packaged Windows library
if: matrix.platform == 'windows'
run: python tool/ci/smoke_native.py example/build/windows/x64/runner/Release/tor_ffi_plugin.dll

release:
needs: build
if: github.event_name != 'pull_request' && github.event.deleted != true
needs: [verify, build]
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- uses: actions/checkout@v6
- uses: actions/download-artifact@v4
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
pattern: prebuilt-*
path: artifacts
merge-multiple: true
- uses: subosito/flutter-action@v2
- uses: subosito/flutter-action@1508160852fb97248640997f7cfb38da241df0ba # v2.9.1
with:
flutter-version: '3.47.2'
channel: stable
cache: true
- run: flutter pub get
- name: Generate manifest
run: dart --packages=.dart_tool/package_config.json tool/prebuilt_manifest.dart artifacts
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: native-release
path: artifacts/*
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,9 @@ build/

rust/target/.rustc_info.json
rust/target/debug/
rust/target/release/
rust/target/CACHEDIR.TAG

# Cargo output from building a vendored crate on its own.
rust/patches/*/target/
rust/patches/*/Cargo.lock
Loading
Loading