feat: @clawdstrike/swarm-engine — browser-safe swarm orchestration with guard pipeline #1673
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| security-regressions: | |
| name: Fast Security Regressions | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Run security regression contract tests | |
| run: | | |
| cargo test -p hush-cli --test abuse_harness -- --nocapture | |
| cargo test -p hush-cli --test hunt_e2e -- --nocapture --test-threads=1 | |
| cargo test -p clawdstrike --test security_regressions -- --nocapture | |
| cargo test -p hushd --test security_regressions -- --nocapture | |
| cargo test -p hush-cli hush_run::tests::connect_proxy_rejects_ip_target_with_allowlisted_sni_mismatch -- --exact | |
| cargo test -p hush-cli hush_run::tests::connect_proxy_hostname_target_is_ip_pinned_after_policy_check -- --exact | |
| policy-torture: | |
| name: Policy Torture (PR Gate) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| needs: security-regressions | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Run policy torture battery | |
| run: bash rulesets/tests/policy-torture/run.sh | |
| - name: Upload policy torture JSON reports | |
| if: always() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: policy-torture-reports | |
| path: rulesets/tests/policy-torture/reports/*.json | |
| if-no-files-found: error | |
| check: | |
| name: Check | |
| runs-on: ubuntu-latest | |
| needs: [security-regressions, policy-torture] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt, clippy | |
| - name: Cache cargo registry | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo- | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Check formatting | |
| run: cargo fmt --all -- --check | |
| - name: Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: "24" | |
| - name: Install TypeScript compiler | |
| run: npm install -g typescript@5.9.3 | |
| - name: Smoke test TS file dependency workflows | |
| run: bash scripts/smoke-ts-file-deps.sh | |
| - name: Validate Docker Compose topology | |
| run: docker compose -f infra/docker/docker-compose.services.yaml config > /dev/null | |
| - name: Lint moved paths | |
| run: bash scripts/path-lint.sh | |
| - name: Validate moved path targets | |
| run: bash scripts/move-validation.sh | |
| - name: Validate architecture guardrails | |
| run: bash scripts/architecture-guardrails.sh | |
| - name: Slop audit (critical paths) | |
| run: bash scripts/slop-audit.sh | |
| - name: Setup Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Install mypy | |
| run: python -m pip install --disable-pip-version-check mypy==1.19.1 | |
| - name: Validate docs code blocks | |
| run: tools/scripts/validate-docs | |
| - name: Clippy | |
| run: cargo clippy --all-targets --all-features -- -D warnings | |
| - name: Build | |
| run: cargo build --all-targets | |
| - name: Test | |
| run: cargo test --all --exclude sdr-integration-tests | |
| sdk-conformance: | |
| name: SDK Conformance Vectors | |
| runs-on: ubuntu-latest | |
| needs: check | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version-file: packages/sdk/hush-go/go.mod | |
| cache: true | |
| cache-dependency-path: packages/sdk/hush-go/go.sum | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| cache-dependency-path: | | |
| packages/sdk/hush-ts/package-lock.json | |
| packages/adapters/clawdstrike-adapter-core/package-lock.json | |
| - name: Setup Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Run SDK conformance runner | |
| run: bash scripts/run-sdk-conformance.sh | |
| terminal-tui: | |
| name: Terminal TUI | |
| runs-on: ubuntu-latest | |
| needs: check | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| - name: Install dependencies | |
| working-directory: apps/terminal | |
| run: bun install --frozen-lockfile | |
| - name: Type check | |
| working-directory: apps/terminal | |
| run: bun run typecheck | |
| - name: Unit tests | |
| working-directory: apps/terminal | |
| run: bun test | |
| - name: Wrapper smoke tests | |
| run: cargo test -p hush-cli tui::tests -- --nocapture | |
| - name: Installed wrapper smoke | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cargo build -p hush-cli --bin clawdstrike --bin hush | |
| STAGE="$RUNNER_TEMP/clawdstrike-tui-stage" | |
| mkdir -p "$STAGE/bin" "$STAGE/share/clawdstrike/tui" | |
| cp target/debug/clawdstrike "$STAGE/bin/clawdstrike" | |
| cp target/debug/hush "$STAGE/bin/hush" | |
| cp apps/terminal/package.json "$STAGE/share/clawdstrike/tui/" | |
| cp apps/terminal/bun.lockb "$STAGE/share/clawdstrike/tui/" | |
| cp crates/services/hush-cli/assets/tui/cli.js "$STAGE/share/clawdstrike/tui/" | |
| cp -R apps/terminal/src "$STAGE/share/clawdstrike/tui/src" | |
| ( | |
| cd "$STAGE/share/clawdstrike/tui" | |
| bun install --production --frozen-lockfile | |
| ) | |
| "$STAGE/bin/clawdstrike" tui doctor --json > "$RUNNER_TEMP/tui-doctor.json" | |
| grep '"runtime"' "$RUNNER_TEMP/tui-doctor.json" | |
| tauri-rust-check: | |
| name: Tauri Rust Crates | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Linux dependencies for Tauri | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| libgtk-3-dev \ | |
| libayatana-appindicator3-dev \ | |
| librsvg2-dev \ | |
| protobuf-compiler | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev || sudo apt-get install -y libwebkit2gtk-4.0-dev | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache cargo registry | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-tauri-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-tauri- | |
| ${{ runner.os }}-cargo- | |
| - name: Check desktop Tauri crate | |
| run: cargo check --manifest-path apps/desktop/src-tauri/Cargo.toml | |
| - name: Check agent Tauri crate | |
| run: cargo check --manifest-path apps/agent/src-tauri/Cargo.toml | |
| desktop-frontend: | |
| name: Desktop Frontend | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| - name: Install dependencies | |
| working-directory: apps/desktop | |
| run: bun install --frozen-lockfile | |
| - name: Type check | |
| working-directory: apps/desktop | |
| run: bun run typecheck | |
| - name: Unit tests | |
| working-directory: apps/desktop | |
| run: bun run test | |
| - name: Build | |
| working-directory: apps/desktop | |
| run: bun run build | |
| workbench-frontend: | |
| name: Workbench Frontend | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| cache-dependency-path: apps/workbench/package-lock.json | |
| - name: Install dependencies | |
| working-directory: apps/workbench | |
| run: npm ci | |
| - name: Type check | |
| working-directory: apps/workbench | |
| run: npm run typecheck | |
| - name: Unit tests | |
| working-directory: apps/workbench | |
| run: npm test -- --run | |
| - name: Build | |
| working-directory: apps/workbench | |
| run: npm run build | |
| control-console: | |
| name: Control Console | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| cache-dependency-path: apps/control-console/package-lock.json | |
| - name: Install dependencies | |
| working-directory: apps/control-console | |
| run: npm ci | |
| - name: Type check | |
| working-directory: apps/control-console | |
| run: npm run typecheck | |
| - name: Unit tests | |
| working-directory: apps/control-console | |
| run: npm test | |
| - name: Build | |
| working-directory: apps/control-console | |
| run: npm run build | |
| sdr-integration-tests: | |
| name: SDR Integration Tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| needs: check | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache cargo registry | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-sdr-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-sdr- | |
| ${{ runner.os }}-cargo- | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Spine pipeline tests | |
| run: cargo test -p hush-spine --test pipeline_test | |
| - name: Bridge roundtrip tests | |
| run: cargo test -p sdr-integration-tests --test bridge_roundtrip_test | |
| - name: K8s audit bridge reliability tests | |
| run: cargo test -p sdr-integration-tests --test k8s_audit_bridge_reliability -- --nocapture | |
| - name: E2E pipeline tests | |
| run: cargo test -p sdr-integration-tests --test e2e_pipeline | |
| adaptive-control-integration: | |
| name: Adaptive Control Integration (NATS + Postgres) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| needs: check | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Run control-api adaptive integration tests | |
| run: 'cargo test -p clawdstrike-control-api integration_tests:: -- --nocapture' | |
| msrv: | |
| name: Minimum Supported Rust Version | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install MSRV toolchain | |
| uses: dtolnay/rust-toolchain@1.93 | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Build with MSRV | |
| run: cargo build --all-targets | |
| offline: | |
| name: Offline Build/Test (vendored) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Free disk space | |
| run: | | |
| echo "Disk before cleanup:" | |
| df -h | |
| sudo rm -rf /usr/local/lib/android | |
| sudo rm -rf /usr/share/dotnet | |
| sudo rm -rf /opt/ghc | |
| sudo rm -rf /opt/hostedtoolcache/CodeQL | |
| echo "Disk after cleanup:" | |
| df -h | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Test offline | |
| run: scripts/cargo-offline.sh test --workspace --all-targets | |
| env: | |
| CARGO_NET_OFFLINE: "true" | |
| docs: | |
| name: Documentation | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Install Z3 toolchain for all-features docs | |
| run: sudo apt-get update && sudo apt-get install -y z3 libz3-dev clang libclang-dev | |
| - name: Build documentation | |
| run: cargo doc --no-deps --all-features | |
| env: | |
| RUSTDOCFLAGS: -D warnings | |
| security-audit: | |
| name: Security Audit | |
| runs-on: ubuntu-latest | |
| needs: security-regressions | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install cargo-audit | |
| run: cargo install cargo-audit --locked --version 0.22.0 | |
| - name: Enforce advisory exception policy metadata | |
| run: tools/scripts/check-advisory-expiry.sh | |
| - name: Run security audits | |
| run: | | |
| audit_ignores=( | |
| --ignore RUSTSEC-2024-0375 \ | |
| --ignore RUSTSEC-2025-0141 \ | |
| --ignore RUSTSEC-2024-0388 \ | |
| --ignore RUSTSEC-2024-0411 \ | |
| --ignore RUSTSEC-2024-0412 \ | |
| --ignore RUSTSEC-2024-0413 \ | |
| --ignore RUSTSEC-2024-0414 \ | |
| --ignore RUSTSEC-2024-0415 \ | |
| --ignore RUSTSEC-2024-0416 \ | |
| --ignore RUSTSEC-2024-0417 \ | |
| --ignore RUSTSEC-2024-0418 \ | |
| --ignore RUSTSEC-2024-0419 \ | |
| --ignore RUSTSEC-2024-0420 \ | |
| --ignore RUSTSEC-2024-0429 \ | |
| --ignore RUSTSEC-2024-0436 \ | |
| --ignore RUSTSEC-2025-0057 \ | |
| --ignore RUSTSEC-2025-0134 \ | |
| --ignore RUSTSEC-2024-0370 \ | |
| --ignore RUSTSEC-2021-0145 \ | |
| --ignore RUSTSEC-2025-0075 \ | |
| --ignore RUSTSEC-2025-0080 \ | |
| --ignore RUSTSEC-2025-0081 \ | |
| --ignore RUSTSEC-2025-0098 \ | |
| --ignore RUSTSEC-2025-0100 \ | |
| --ignore RUSTSEC-2025-0119 \ | |
| # Temporary: transitive via portable-pty->serial in workbench PTY stack. | |
| # Mitigated by command hardening (shell/env allowlists + backend-minted | |
| # capability tokens bound to trusted-window context). | |
| # Tracking removal: SEC-PTY-001. | |
| --ignore RUSTSEC-2017-0008 | |
| ) | |
| cargo audit --deny warnings "${audit_ignores[@]}" | |
| cargo audit --deny warnings --file apps/desktop/src-tauri/Cargo.lock "${audit_ignores[@]}" | |
| cargo audit --deny warnings --file apps/workbench/src-tauri/Cargo.lock "${audit_ignores[@]}" | |
| license-check: | |
| name: License Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install cargo-deny | |
| uses: taiki-e/install-action@cargo-deny | |
| - name: Generate desktop Tauri cargo metadata | |
| run: cargo metadata --manifest-path apps/desktop/src-tauri/Cargo.toml --format-version 1 --locked > desktop-tauri-metadata.json | |
| - name: Run cargo-deny for workspace | |
| run: cargo deny check | |
| - name: Run cargo-deny for desktop Tauri crate | |
| run: cargo deny check --metadata-path desktop-tauri-metadata.json licenses sources | |
| coverage: | |
| name: Code Coverage | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: llvm-tools-preview | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Install Z3 toolchain for all-features coverage | |
| run: sudo apt-get update && sudo apt-get install -y z3 libz3-dev clang libclang-dev | |
| - name: Install Linux dependencies for desktop Tauri coverage | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| libgtk-3-dev \ | |
| libayatana-appindicator3-dev \ | |
| librsvg2-dev | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev || sudo apt-get install -y libwebkit2gtk-4.0-dev | |
| - name: Install cargo-llvm-cov | |
| uses: taiki-e/install-action@cargo-llvm-cov | |
| - name: Generate workspace coverage report | |
| run: cargo llvm-cov --all-features --lcov --output-path lcov.workspace.info | |
| - name: Generate desktop Tauri coverage report | |
| run: cargo llvm-cov --manifest-path apps/desktop/src-tauri/Cargo.toml --lcov --output-path lcov.desktop.info | |
| - name: Generate workbench Tauri coverage report | |
| run: cargo llvm-cov --manifest-path apps/workbench/src-tauri/Cargo.toml --lcov --output-path lcov.workbench.info | |
| - name: Combine coverage reports | |
| run: | | |
| { | |
| cat lcov.workspace.info | |
| printf '\n' | |
| cat lcov.desktop.info | |
| printf '\n' | |
| cat lcov.workbench.info | |
| printf '\n' | |
| } > lcov.info | |
| - name: Enforce changed-file Rust coverage floor | |
| env: | |
| GITHUB_BASE_REF: ${{ github.base_ref }} | |
| CHANGED_RUST_COVERAGE_THRESHOLD: "70" | |
| run: | | |
| if [ -z "${GITHUB_BASE_REF}" ]; then | |
| echo "No base ref (non-PR run); skipping changed-file Rust coverage gate." | |
| exit 0 | |
| fi | |
| git fetch --no-tags --depth=1 origin "${GITHUB_BASE_REF}:refs/remotes/origin/${GITHUB_BASE_REF}" | |
| # In shallow PR checkouts, merge-base may be missing even when origin/<base> exists. | |
| # Retry after fetching full history so three-dot diff stays stable. | |
| if ! git diff --name-only "origin/${GITHUB_BASE_REF}...HEAD" -- '*.rs' ':(exclude)infra/vendor/**' > changed_rust_files.txt; then | |
| echo "Shallow diff failed; fetching additional history for merge-base resolution" | |
| git fetch --no-tags --prune --unshallow origin || git fetch --no-tags --prune origin | |
| git fetch --no-tags origin "${GITHUB_BASE_REF}:refs/remotes/origin/${GITHUB_BASE_REF}" | |
| git diff --name-only "origin/${GITHUB_BASE_REF}...HEAD" -- '*.rs' ':(exclude)infra/vendor/**' > changed_rust_files.txt | |
| fi | |
| if [ ! -s changed_rust_files.txt ]; then | |
| echo "No changed Rust files; skipping changed-file Rust coverage gate." | |
| exit 0 | |
| fi | |
| # This job merges coverage from the root Rust workspace plus the | |
| # desktop and workbench Tauri crates. Keep excluding the long-lived | |
| # desktop Tauri surface from the changed-line floor until it has a | |
| # dedicated changed-line gate instead of inheriting legacy branch | |
| # churn. Also exclude vendored upstream Rust snapshots, standalone | |
| # crates still outside the combined coverage set, the out-of-workspace | |
| # `logos-z3` crate, and test-only Rust sources that do not emit stable | |
| # LCOV entries in this job. The root workspace coverage run installs | |
| # Z3 and uses `--all-features`, so `clawdstrike-logos` solver-gated | |
| # paths remain in scope here. | |
| grep -v '^apps/agent/src-tauri/' changed_rust_files.txt \ | |
| | grep -v '^apps/desktop/src-tauri/' \ | |
| | grep -v '^apps/workbench/src-tauri/' \ | |
| | grep -v '^crates/bridges/hush-go-native/' \ | |
| | grep -v '^crates/libs/logos-z3/' \ | |
| | grep -v '^packages/sdk/hush-py/hush-native/' \ | |
| | grep -v '^vendor/hushspec/' \ | |
| | grep -Ev '(^|/)build\.rs$' \ | |
| | grep -Ev '(^|/)tests/|_test\.rs$|_tests\.rs$|integration_tests\.rs$' \ | |
| | grep -Ev '^crates/libs/hunt-(correlate|query|scan)/src/(lib|error)\.rs$' \ | |
| | grep -Ev '^crates/libs/(hush-core|clawdstrike)/src/lib\.rs$' \ | |
| | grep -Ev '^crates/services/hush-cli/src/tests\.rs$' \ | |
| > changed_rust_files.coverage.txt || true | |
| if [ ! -s changed_rust_files.coverage.txt ]; then | |
| echo "No workspace Rust files changed; skipping changed-file Rust coverage gate." | |
| exit 0 | |
| fi | |
| tools/scripts/check-changed-rust-coverage.py \ | |
| --lcov lcov.info \ | |
| --changed-files-file changed_rust_files.coverage.txt \ | |
| --git-diff-range "origin/${GITHUB_BASE_REF}...HEAD" \ | |
| --threshold "${CHANGED_RUST_COVERAGE_THRESHOLD}" | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v5 | |
| with: | |
| files: lcov.info | |
| fail_ci_if_error: false | |
| wasm: | |
| name: WASM Build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: wasm32-unknown-unknown | |
| - name: Cache cargo registry | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-wasm-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-wasm- | |
| - name: Install wasm-pack | |
| run: cargo install wasm-pack --locked --version 0.14.0 | |
| - name: Build WASM | |
| run: | | |
| cd crates/libs/hush-wasm | |
| wasm-pack build --target web --release | |
| - name: Verify committed Node.js WASM artifacts are in sync | |
| run: | | |
| cd crates/libs/hush-wasm | |
| wasm-pack build --target nodejs --release --out-dir pkg-node | |
| for f in hush_wasm.js hush_wasm.d.ts hush_wasm_bg.wasm.d.ts; do | |
| if ! cmp -s "$f" "pkg-node/$f"; then | |
| echo "ERROR: $f is out of sync with wasm-pack --target nodejs output" | |
| echo "Run: cd crates/libs/hush-wasm && ./build.sh" | |
| exit 1 | |
| fi | |
| done | |
| - name: Check bundle size | |
| run: | | |
| SIZE=$(wc -c < crates/libs/hush-wasm/pkg/hush_wasm_bg.wasm) | |
| echo "Bundle size: $SIZE bytes ($(( SIZE / 1024 ))KB)" | |
| # Limit raised from 1.75MiB after adding policy-event + OCSF conversion | |
| # support to hush-wasm (via clawdstrike-policy-event/clawdstrike-ocsf). | |
| # Current baseline ~2.25MiB; 2.5MiB cap leaves ~10% headroom. | |
| if [ $SIZE -gt 2621440 ]; then | |
| echo "ERROR: Bundle exceeds 2.5MiB limit" | |
| exit 1 | |
| fi | |
| echo "Bundle size is within 2.5MiB limit" | |
| proptest: | |
| name: Property Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Cache cargo registry | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-proptest-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-proptest- | |
| - name: Run property tests | |
| run: cargo test --workspace proptest | |
| env: | |
| PROPTEST_CASES: 500 | |
| integration-tests: | |
| name: Integration Tests | |
| runs-on: ubuntu-latest | |
| needs: check | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install protoc | |
| run: sudo apt-get update && sudo apt-get install -y protobuf-compiler | |
| - name: Cache cargo registry | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-integration-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-integration- | |
| ${{ runner.os }}-cargo- | |
| - name: Build daemon | |
| run: cargo build -p hushd | |
| - name: Start daemon in background | |
| run: | | |
| ./target/debug/hushd start & | |
| echo $! > /tmp/hushd.pid | |
| env: | |
| RUST_LOG: info | |
| - name: Wait for daemon health | |
| run: | | |
| for i in {1..30}; do | |
| if curl -s http://127.0.0.1:9876/health | grep -q '"status":"healthy"'; then | |
| echo "Daemon is healthy" | |
| exit 0 | |
| fi | |
| echo "Waiting for daemon... (attempt $i/30)" | |
| sleep 1 | |
| done | |
| echo "Daemon failed to start" | |
| exit 1 | |
| - name: Run integration tests | |
| run: cargo test -p hushd --test integration | |
| env: | |
| HUSHD_TEST_URL: http://127.0.0.1:9876 | |
| - name: Stop daemon | |
| if: always() | |
| run: | | |
| if [ -f /tmp/hushd.pid ]; then | |
| kill $(cat /tmp/hushd.pid) 2>/dev/null || true | |
| rm /tmp/hushd.pid | |
| fi | |
| fuzz-check: | |
| name: Fuzz Smoke (PR) | |
| runs-on: ubuntu-latest | |
| needs: security-regressions | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust nightly | |
| uses: dtolnay/rust-toolchain@nightly | |
| - name: Install cargo-fuzz | |
| run: cargo install cargo-fuzz --locked --version 0.13.1 | |
| - name: Build fuzz targets | |
| run: | | |
| cd fuzz | |
| cargo +nightly build | |
| - name: Run fuzz smoke targets | |
| run: | | |
| cd fuzz | |
| cargo +nightly fuzz run fuzz_policy_parse -- -max_total_time=30 | |
| cargo +nightly fuzz run fuzz_irm_net_parse -- -max_total_time=30 | |
| cargo +nightly fuzz run fuzz_remote_extends_parse -- -max_total_time=30 | |
| typescript-sdk: | |
| name: TypeScript SDK | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: packages/sdk/hush-ts | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| cache-dependency-path: | | |
| packages/sdk/hush-ts/package-lock.json | |
| packages/adapters/clawdstrike-adapter-core/package-lock.json | |
| - name: Bootstrap file deps (adapter-core) | |
| working-directory: packages/adapters/clawdstrike-adapter-core | |
| run: npm ci | |
| - name: Build file deps (adapter-core) | |
| working-directory: packages/adapters/clawdstrike-adapter-core | |
| run: npm run build | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Type check | |
| run: npm run typecheck | |
| - name: Build | |
| run: npm run build | |
| - name: Test | |
| run: npm test | |
| - name: Verify package exports | |
| run: | | |
| node -e "const sdk = require('./dist/index.cjs'); console.log('CJS exports:', Object.keys(sdk).slice(0, 10))" | |
| node --input-type=module -e "import * as sdk from './dist/index.js'; console.log('ESM exports:', Object.keys(sdk).slice(0, 10))" | |
| agent-fail-closed-smoke: | |
| name: Agent Fail-Closed Smoke | |
| runs-on: ubuntu-latest | |
| needs: security-regressions | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| cache-dependency-path: | | |
| packages/adapters/clawdstrike-adapter-core/package-lock.json | |
| packages/adapters/clawdstrike-broker-client/package-lock.json | |
| packages/adapters/clawdstrike-openai/package-lock.json | |
| packages/adapters/clawdstrike-claude/package-lock.json | |
| packages/adapters/clawdstrike-hush-cli-engine/package-lock.json | |
| packages/adapters/clawdstrike-hushd-engine/package-lock.json | |
| - name: Install dependencies | |
| run: | | |
| npm --prefix packages/adapters/clawdstrike-adapter-core ci | |
| npm --prefix packages/adapters/clawdstrike-broker-client ci | |
| npm --prefix packages/adapters/clawdstrike-openai ci | |
| npm --prefix packages/adapters/clawdstrike-claude ci | |
| npm --prefix packages/adapters/clawdstrike-hush-cli-engine ci | |
| npm --prefix packages/adapters/clawdstrike-hushd-engine ci | |
| - name: Build dependencies and adapters | |
| run: | | |
| npm --prefix packages/adapters/clawdstrike-adapter-core run build | |
| npm --prefix packages/adapters/clawdstrike-broker-client run build | |
| npm --prefix packages/adapters/clawdstrike-openai run build | |
| npm --prefix packages/adapters/clawdstrike-claude run build | |
| npm --prefix packages/adapters/clawdstrike-hush-cli-engine run build | |
| npm --prefix packages/adapters/clawdstrike-hushd-engine run build | |
| - name: Run fail-closed smoke POCs | |
| run: node tools/scripts/agent-fail-closed-smoke.mjs | |
| - name: Upload fail-closed smoke report | |
| if: always() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: agent-fail-closed-smoke-report | |
| path: | | |
| docs/reports/agent-fail-closed-smoke.json | |
| docs/reports/agent-fail-closed-smoke.md | |
| if-no-files-found: error | |
| adapter-core-cross-adapter: | |
| name: Adapter Core Cross-Adapter | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: packages/adapters/clawdstrike-adapter-core | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| cache-dependency-path: packages/adapters/clawdstrike-adapter-core/package-lock.json | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run cross-adapter decision parity suite | |
| run: npm run test:cross-adapter | |
| openclaw-plugin: | |
| name: OpenClaw Plugin | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: packages/adapters/clawdstrike-openclaw | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| cache-dependency-path: packages/adapters/clawdstrike-openclaw/package-lock.json | |
| - name: Bootstrap file deps (adapter-core) | |
| working-directory: packages/adapters/clawdstrike-adapter-core | |
| run: npm ci | |
| - name: Build file deps (adapter-core) | |
| working-directory: packages/adapters/clawdstrike-adapter-core | |
| run: npm run build | |
| - name: Bootstrap file deps (policy) | |
| working-directory: packages/policy/clawdstrike-policy | |
| run: npm ci | |
| - name: Build file deps (policy) | |
| working-directory: packages/policy/clawdstrike-policy | |
| run: npm run build | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Type check | |
| run: npm run typecheck | |
| - name: Build | |
| run: npm run build | |
| - name: Test | |
| run: npm test | |
| - name: OpenClaw E2E (simulated runtime) | |
| run: npm run e2e | |
| openclaw-plugin-runtime-matrix: | |
| name: OpenClaw Runtime (${{ matrix.openclaw_version }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| openclaw_version: ['2026.2.15', '2026.2.25', 'latest'] | |
| defaults: | |
| run: | |
| working-directory: packages/adapters/clawdstrike-openclaw | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| cache-dependency-path: packages/adapters/clawdstrike-openclaw/package-lock.json | |
| - name: Bootstrap file deps (adapter-core) | |
| working-directory: packages/adapters/clawdstrike-adapter-core | |
| run: npm ci | |
| - name: Build file deps (adapter-core) | |
| working-directory: packages/adapters/clawdstrike-adapter-core | |
| run: npm run build | |
| - name: Bootstrap file deps (policy) | |
| working-directory: packages/policy/clawdstrike-policy | |
| run: npm ci | |
| - name: Build file deps (policy) | |
| working-directory: packages/policy/clawdstrike-policy | |
| run: npm run build | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build | |
| run: npm run build | |
| - name: Install OpenClaw CLI (${{ matrix.openclaw_version }}) | |
| working-directory: . | |
| run: npm install -g openclaw@${{ matrix.openclaw_version }} | |
| - name: Prepare OpenClaw runtime artifact directories | |
| working-directory: . | |
| run: | | |
| mkdir -p \ | |
| artifacts/openclaw-install-link-smoke-${{ matrix.openclaw_version }} \ | |
| artifacts/openclaw-runtime-smoke-${{ matrix.openclaw_version }} \ | |
| artifacts/openclaw-runtime-blocked-e2e-${{ matrix.openclaw_version }} | |
| touch \ | |
| artifacts/openclaw-install-link-smoke-${{ matrix.openclaw_version }}/.keep \ | |
| artifacts/openclaw-runtime-smoke-${{ matrix.openclaw_version }}/.keep \ | |
| artifacts/openclaw-runtime-blocked-e2e-${{ matrix.openclaw_version }}/.keep | |
| - name: OpenClaw install-link smoke | |
| working-directory: . | |
| run: OPENCLAW_RUNTIME_ARTIFACT_DIR=artifacts/openclaw-install-link-smoke-${{ matrix.openclaw_version }} bash scripts/openclaw-plugin-install-link-smoke.sh | |
| - name: Assert install-link summary checks | |
| working-directory: . | |
| run: | | |
| jq -e ' | |
| .result == "pass" | |
| and .checks.installCommandSucceeded | |
| and .checks.enableCommandSucceeded | |
| and .checks.pluginInfoJsonPresent | |
| and .checks.pluginIdMatches | |
| and .checks.pluginStatusLoaded | |
| and .checks.configLoadPathContainsLink | |
| and .checks.configEntryEnabled | |
| and .checks.allExpectedHooksPresent | |
| and (.checks.idMismatchWarningPresent | not) | |
| ' artifacts/openclaw-install-link-smoke-${{ matrix.openclaw_version }}/summary.json >/dev/null | |
| - name: OpenClaw runtime smoke (hook registration) | |
| working-directory: . | |
| run: OPENCLAW_RUNTIME_ARTIFACT_DIR=artifacts/openclaw-runtime-smoke-${{ matrix.openclaw_version }} bash scripts/openclaw-plugin-runtime-smoke.sh | |
| - name: Assert runtime smoke summary checks | |
| working-directory: . | |
| run: | | |
| jq -e ' | |
| .result == "pass" | |
| and .checks.pluginInfoJsonPresent | |
| and .checks.pluginIdMatches | |
| and .checks.pluginStatusLoaded | |
| and .checks.allExpectedHooksPresent | |
| and (.checks.idMismatchWarningPresent | not) | |
| ' artifacts/openclaw-runtime-smoke-${{ matrix.openclaw_version }}/summary.json >/dev/null | |
| - name: OpenClaw blocked-call runtime e2e | |
| working-directory: . | |
| run: OPENCLAW_RUNTIME_ARTIFACT_DIR=artifacts/openclaw-runtime-blocked-e2e-${{ matrix.openclaw_version }} bash scripts/openclaw-plugin-blocked-call-e2e.sh | |
| - name: Assert blocked-call summary checks | |
| working-directory: . | |
| run: | | |
| jq -e ' | |
| .result == "pass" | |
| and .checks.gatewayHealthOk | |
| and .checks.pluginInfoJsonPresent | |
| and .checks.pluginStatusLoaded | |
| and .checks.hookPreflightPresent | |
| and .checks.hookCuaPresent | |
| and .checks.policyCheckCallOk | |
| and .checks.policyCheckDenied | |
| and .checks.targetFileAbsent | |
| ' artifacts/openclaw-runtime-blocked-e2e-${{ matrix.openclaw_version }}/summary.json >/dev/null | |
| - name: Upload OpenClaw runtime artifacts (${{ matrix.openclaw_version }}) | |
| if: always() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: openclaw-runtime-artifacts-${{ matrix.openclaw_version }} | |
| path: | | |
| artifacts/openclaw-install-link-smoke-${{ matrix.openclaw_version }} | |
| artifacts/openclaw-runtime-smoke-${{ matrix.openclaw_version }} | |
| artifacts/openclaw-runtime-blocked-e2e-${{ matrix.openclaw_version }} | |
| if-no-files-found: warn | |
| clawdstrike-policy: | |
| name: Canonical Policy Engine (TS) | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: packages/policy/clawdstrike-policy | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache cargo registry | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-policy-parity-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-policy-parity- | |
| ${{ runner.os }}-cargo- | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| cache-dependency-path: | | |
| packages/policy/clawdstrike-policy/package-lock.json | |
| packages/adapters/clawdstrike-adapter-core/package-lock.json | |
| packages/sdk/hush-ts/package-lock.json | |
| - name: Bootstrap file deps (adapter-core) | |
| working-directory: packages/adapters/clawdstrike-adapter-core | |
| run: npm ci | |
| - name: Build file deps (adapter-core) | |
| working-directory: packages/adapters/clawdstrike-adapter-core | |
| run: npm run build | |
| - name: Build hush CLI (for policy parity) | |
| working-directory: . | |
| run: cargo build -p hush-cli --bin hush | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Type check | |
| run: npm run typecheck | |
| - name: Build | |
| run: npm run build | |
| - name: Bootstrap file deps (hush-ts) | |
| working-directory: packages/sdk/hush-ts | |
| run: npm ci | |
| - name: Build file deps (hush-ts) | |
| working-directory: packages/sdk/hush-ts | |
| run: npm run build | |
| - name: Policy parity (Rust ↔ TS) | |
| working-directory: . | |
| run: node tools/scripts/policy-parity.mjs | |
| - name: Test | |
| run: npm test | |
| agent-framework-integrations: | |
| name: Agent Framework Integrations (${{ matrix.name }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - name: Adapter Core | |
| dir: packages/adapters/clawdstrike-adapter-core | |
| bootstrap_adapter_core: false | |
| bootstrap_broker_client: false | |
| bootstrap_sdk: false | |
| - name: Hush CLI Engine | |
| dir: packages/adapters/clawdstrike-hush-cli-engine | |
| bootstrap_adapter_core: true | |
| bootstrap_broker_client: false | |
| bootstrap_sdk: false | |
| bootstrap_hush: true | |
| - name: OpenAI | |
| dir: packages/adapters/clawdstrike-openai | |
| bootstrap_adapter_core: true | |
| bootstrap_broker_client: true | |
| bootstrap_sdk: false | |
| bootstrap_hush: false | |
| - name: OpenCode | |
| dir: packages/adapters/clawdstrike-opencode | |
| bootstrap_adapter_core: true | |
| bootstrap_broker_client: false | |
| bootstrap_sdk: false | |
| bootstrap_hush: false | |
| - name: Claude | |
| dir: packages/adapters/clawdstrike-claude | |
| bootstrap_adapter_core: true | |
| bootstrap_broker_client: false | |
| bootstrap_sdk: false | |
| bootstrap_hush: false | |
| - name: Vercel AI | |
| dir: packages/adapters/clawdstrike-vercel-ai | |
| bootstrap_adapter_core: true | |
| bootstrap_broker_client: false | |
| bootstrap_sdk: true | |
| bootstrap_hush: false | |
| - name: LangChain | |
| dir: packages/adapters/clawdstrike-langchain | |
| bootstrap_adapter_core: true | |
| bootstrap_broker_client: false | |
| bootstrap_sdk: false | |
| bootstrap_hush: false | |
| - name: Hushd Engine | |
| dir: packages/adapters/clawdstrike-hushd-engine | |
| bootstrap_adapter_core: true | |
| bootstrap_broker_client: false | |
| bootstrap_sdk: false | |
| bootstrap_hush: false | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| cache-dependency-path: | | |
| ${{ matrix.dir }}/package-lock.json | |
| packages/adapters/clawdstrike-adapter-core/package-lock.json | |
| packages/adapters/clawdstrike-broker-client/package-lock.json | |
| packages/sdk/hush-ts/package-lock.json | |
| - name: Install Rust toolchain | |
| if: ${{ matrix.bootstrap_hush }} | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Build hush binary | |
| if: ${{ matrix.bootstrap_hush }} | |
| run: cargo build -p hush-cli | |
| - name: Export HUSH_PATH for e2e tests | |
| if: ${{ matrix.bootstrap_hush }} | |
| run: echo "HUSH_PATH=${{ github.workspace }}/target/debug/hush" >> "$GITHUB_ENV" | |
| - name: Bootstrap file deps (adapter-core) | |
| if: ${{ matrix.bootstrap_adapter_core }} | |
| working-directory: packages/adapters/clawdstrike-adapter-core | |
| run: npm ci | |
| - name: Build file deps (adapter-core) | |
| if: ${{ matrix.bootstrap_adapter_core }} | |
| working-directory: packages/adapters/clawdstrike-adapter-core | |
| run: npm run build | |
| - name: Bootstrap file deps (broker-client) | |
| if: ${{ matrix.bootstrap_broker_client }} | |
| working-directory: packages/adapters/clawdstrike-broker-client | |
| run: npm ci | |
| - name: Build file deps (broker-client) | |
| if: ${{ matrix.bootstrap_broker_client }} | |
| working-directory: packages/adapters/clawdstrike-broker-client | |
| run: npm run build | |
| - name: Bootstrap file deps (sdk) | |
| if: ${{ matrix.bootstrap_sdk }} | |
| working-directory: packages/sdk/hush-ts | |
| run: npm ci | |
| - name: Build file deps (sdk) | |
| if: ${{ matrix.bootstrap_sdk }} | |
| working-directory: packages/sdk/hush-ts | |
| run: npm run build | |
| - name: Install dependencies | |
| working-directory: ${{ matrix.dir }} | |
| run: npm ci | |
| - name: Type check | |
| working-directory: ${{ matrix.dir }} | |
| run: npm run typecheck | |
| - name: Build | |
| working-directory: ${{ matrix.dir }} | |
| run: npm run build | |
| - name: Test | |
| working-directory: ${{ matrix.dir }} | |
| run: npm test | |
| parity-tests: | |
| name: Cross-Language Parity | |
| runs-on: ubuntu-latest | |
| needs: check | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache cargo registry | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-parity-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-parity- | |
| ${{ runner.os }}-cargo- | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| - name: Bootstrap file deps (adapter-core) | |
| working-directory: packages/adapters/clawdstrike-adapter-core | |
| run: npm ci | |
| - name: Build file deps (adapter-core) | |
| working-directory: packages/adapters/clawdstrike-adapter-core | |
| run: npm run build | |
| - name: Install TS parity deps | |
| working-directory: packages/adapters/clawdstrike-hush-cli-engine | |
| run: npm ci | |
| - name: Run parity tests | |
| run: scripts/run-parity.sh | |
| python-sdk: | |
| name: Python SDK | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: packages/sdk/hush-py | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| cache: 'pip' | |
| cache-dependency-path: packages/sdk/hush-py/pyproject.toml | |
| - name: Install package (editable) | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install -e ".[dev]" | |
| python -m pip install "jsonschema>=4,<5" | |
| - name: Run CUA roadmap fixture harnesses | |
| working-directory: ${{ github.workspace }} | |
| run: | | |
| python docs/roadmaps/cua/research/verify_cua_migration_fixtures.py | |
| python docs/roadmaps/cua/research/verify_remote_desktop_policy_matrix.py | |
| python docs/roadmaps/cua/research/verify_remote_desktop_ruleset_alignment.py | |
| python docs/roadmaps/cua/research/verify_injection_capabilities.py | |
| python docs/roadmaps/cua/research/verify_policy_event_mapping.py | |
| python docs/roadmaps/cua/research/verify_postcondition_probes.py | |
| python docs/roadmaps/cua/research/verify_remote_session_continuity.py | |
| python docs/roadmaps/cua/research/verify_envelope_semantic_equivalence.py | |
| python docs/roadmaps/cua/research/verify_repeatable_latency_harness.py | |
| python docs/roadmaps/cua/research/verify_verification_bundle.py | |
| python docs/roadmaps/cua/research/verify_browser_action_policy.py | |
| python docs/roadmaps/cua/research/verify_session_recording_evidence.py | |
| python docs/roadmaps/cua/research/verify_orchestration_isolation.py | |
| python docs/roadmaps/cua/research/verify_cua_policy_evaluation.py | |
| python docs/roadmaps/cua/research/verify_canonical_adapter_contract.py | |
| python docs/roadmaps/cua/research/verify_provider_conformance.py | |
| python docs/roadmaps/cua/research/verify_openclaw_cua_bridge.py | |
| python docs/roadmaps/cua/research/verify_trycua_connector.py | |
| - name: Run tests | |
| run: python -m pytest | |
| python-native-wheel-smoke: | |
| name: Python Native Wheel Smoke (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Sync Python sources for native wheel build | |
| shell: bash | |
| run: scripts/sync-hush-py-native-sources.sh | |
| - name: Build native wheel | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| python -m pip install --upgrade pip | |
| python -m pip install maturin | |
| cd packages/sdk/hush-py/hush-native | |
| maturin build --release --interpreter python --out dist-native | |
| ls -la dist-native | |
| - name: Install native wheel artifact | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| python -m pip install --force-reinstall packages/sdk/hush-py/hush-native/dist-native/clawdstrike-*.whl | |
| - name: Verify bundled native backend is active | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| python - <<'PY' | |
| import clawdstrike | |
| from clawdstrike import NATIVE_AVAILABLE | |
| assert NATIVE_AVAILABLE is True, "Expected bundled native backend to be available" | |
| import clawdstrike._native as native_mod | |
| assert hasattr(native_mod, "NativeEngine") | |
| engine = native_mod.NativeEngine.from_ruleset("strict") | |
| report = engine.check_file_access("/etc/shadow") | |
| assert report["overall"]["allowed"] is False | |
| print("Native smoke check passed") | |
| PY | |
| - name: Verify explicit pure-Python fallback toggle | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| CLAWDSTRIKE_DISABLE_NATIVE=1 python - <<'PY' | |
| from clawdstrike import NATIVE_AVAILABLE, init_native | |
| assert NATIVE_AVAILABLE is False | |
| assert init_native() is False | |
| print("Fallback toggle smoke check passed") | |
| PY |