Skip to content

Dd academy - improved formatting (ELEVEN LABS theme inspiration). #1717

Dd academy - improved formatting (ELEVEN LABS theme inspiration).

Dd academy - improved formatting (ELEVEN LABS theme inspiration). #1717

Workflow file for this run

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 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
# aws-lc-rs advisories (2026-03-23). Transitive via rustls.
# Awaiting patched release. Owner: @deps-maintainers.
--ignore RUSTSEC-2026-0044
--ignore RUSTSEC-2026-0045
--ignore RUSTSEC-2026-0046
--ignore RUSTSEC-2026-0047
--ignore RUSTSEC-2026-0048
--ignore RUSTSEC-2026-0049
--ignore RUSTSEC-2026-0067
--ignore RUSTSEC-2026-0068
)
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.chatSendStarted
and .checks.historyHasMessages
and (.checks.assistantBlockSignal or .checks.assistantAuthMissing)
and .checks.policyCheckHttpOk
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_sdk: false
- name: Hush CLI Engine
dir: packages/adapters/clawdstrike-hush-cli-engine
bootstrap_adapter_core: true
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