Skip to content

Commit dd97b30

Browse files
authored
Phase 2: full Rust/WASM/Playwright testing + CI security gates (#6)
* test: add full rust/wasm/e2e suite with ci gates * test: build mock-channel wasm fixture before rust suite * test: build wasm fixture plugins for rust ci
1 parent f86e51a commit dd97b30

31 files changed

Lines changed: 1041 additions & 9 deletions

.cargo/audit.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[advisories]
2+
ignore = [
3+
# extism transitively pins wasmtime 37.x today.
4+
"RUSTSEC-2026-0006",
5+
# transitive via wasmtime profiling stack
6+
"RUSTSEC-2025-0057",
7+
# transitive via async-nats / rustls-native-certs
8+
"RUSTSEC-2025-0134",
9+
# transitive in current leptos dependency graph
10+
"RUSTSEC-2024-0436",
11+
]
12+

.github/workflows/claude-code-review.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ on:
1010
# - "src/**/*.js"
1111
# - "src/**/*.jsx"
1212

13+
concurrency:
14+
group: claude-review-${{ github.repository }}-${{ github.event.pull_request.number || github.ref }}
15+
cancel-in-progress: true
16+
1317
jobs:
1418
claude-review:
1519
# Optional: Filter by PR author
@@ -18,7 +22,9 @@ jobs:
1822
# github.event.pull_request.user.login == 'new-developer' ||
1923
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
2024

25+
if: ${{ !github.event.pull_request.draft }}
2126
runs-on: ubuntu-latest
27+
timeout-minutes: 20
2228
permissions:
2329
contents: read
2430
pull-requests: read
@@ -41,4 +47,3 @@ jobs:
4147
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
4248
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
4349
# or https://code.claude.com/docs/en/cli-reference for available options
44-

.github/workflows/claude.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ on:
1010
pull_request_review:
1111
types: [submitted]
1212

13+
concurrency:
14+
group: claude-code-${{ github.repository }}-${{ github.event.pull_request.number || github.event.issue.number || github.ref }}
15+
cancel-in-progress: true
16+
1317
jobs:
1418
claude:
1519
if: |
@@ -18,6 +22,7 @@ jobs:
1822
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
1923
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
2024
runs-on: ubuntu-latest
25+
timeout-minutes: 20
2126
permissions:
2227
contents: read
2328
pull-requests: read
@@ -47,4 +52,3 @@ jobs:
4752
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
4853
# or https://code.claude.com/docs/en/cli-reference for available options
4954
# claude_args: '--allowed-tools Bash(gh pr:*)'
50-

.github/workflows/test-suite.yml

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
name: Test Suite
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
jobs:
10+
rust-tests:
11+
name: Rust + Coverage
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
17+
- name: Set up Rust
18+
uses: dtolnay/rust-toolchain@stable
19+
20+
- name: Install Rust test tooling
21+
uses: taiki-e/install-action@v2
22+
with:
23+
tool: cargo-nextest,cargo-llvm-cov
24+
25+
- name: Install llvm-tools
26+
run: rustup component add llvm-tools-preview
27+
28+
- name: Run backend tests and coverage gate
29+
run: ./scripts/test-rust.sh
30+
31+
security:
32+
name: Dependency Security
33+
runs-on: ubuntu-latest
34+
steps:
35+
- name: Checkout
36+
uses: actions/checkout@v4
37+
38+
- name: Set up Rust
39+
uses: dtolnay/rust-toolchain@stable
40+
41+
- name: Install security tooling
42+
uses: taiki-e/install-action@v2
43+
with:
44+
tool: cargo-audit,cargo-deny
45+
46+
- name: Run cargo-audit
47+
run: cargo audit --deny warnings
48+
49+
- name: Run cargo-deny
50+
run: cargo deny check advisories bans sources
51+
52+
wasm-ui-tests:
53+
name: WASM UI Tests
54+
runs-on: ubuntu-latest
55+
steps:
56+
- name: Checkout
57+
uses: actions/checkout@v4
58+
59+
- name: Set up Rust (wasm target)
60+
uses: dtolnay/rust-toolchain@stable
61+
with:
62+
targets: wasm32-unknown-unknown
63+
64+
- name: Install wasm-pack
65+
uses: taiki-e/install-action@v2
66+
with:
67+
tool: wasm-pack
68+
69+
- name: Run WASM UI tests
70+
run: ./scripts/test-wasm-ui.sh
71+
72+
e2e-tests:
73+
name: Playwright E2E
74+
runs-on: ubuntu-latest
75+
steps:
76+
- name: Checkout
77+
uses: actions/checkout@v4
78+
79+
- name: Set up Node.js
80+
uses: actions/setup-node@v4
81+
with:
82+
node-version: "22"
83+
cache: npm
84+
85+
- name: Install JavaScript dependencies
86+
run: npm install
87+
88+
- name: Install Playwright browser
89+
run: npx playwright install --with-deps chromium
90+
91+
- name: Set up Rust (wasm target)
92+
uses: dtolnay/rust-toolchain@stable
93+
with:
94+
targets: wasm32-unknown-unknown
95+
96+
- name: Install trunk
97+
uses: taiki-e/install-action@v2
98+
with:
99+
tool: trunk
100+
101+
- name: Run Playwright E2E tests
102+
env:
103+
EXOCLAW_E2E_PORT: "7210"
104+
EXOCLAW_E2E_TOKEN: "e2e-test-token"
105+
run: npm run test:e2e
106+
107+
- name: Upload Playwright artifacts
108+
if: always()
109+
uses: actions/upload-artifact@v4
110+
with:
111+
name: playwright-artifacts
112+
path: output/playwright
113+
if-no-files-found: ignore

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ Thumbs.db
1515
*.tmp
1616
*.swp
1717
.vscode/
18+
node_modules/
19+
output/playwright/

Cargo.lock

Lines changed: 64 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,19 @@ cargo run -- plugin load ./plugins/telegram.wasm
9797

9898
The gateway binds to `127.0.0.1:7200` by default. When binding to a non-loopback address, an auth token is required (via `--token` or `EXOCLAW_TOKEN` env var).
9999

100+
## Testing
101+
102+
See `TESTING.md` for the full red/green workflow and CI layout.
103+
104+
Quick commands:
105+
106+
```bash
107+
./scripts/test-rust.sh # backend + coverage gate
108+
./scripts/test-wasm-ui.sh # wasm-bindgen-test via wasm-pack
109+
./scripts/test-e2e.sh # Playwright browser flows
110+
./scripts/test-all.sh # full stack
111+
```
112+
100113
## Project status
101114

102115
**Early development. Not production ready.**

TESTING.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Testing and TDD
2+
3+
This repository uses a layered test stack:
4+
5+
- Backend/unit/integration: `cargo-nextest`
6+
- Coverage gate: `cargo-llvm-cov`
7+
- UI Rust-to-WASM tests: `wasm-pack` + `wasm-bindgen-test`
8+
- Browser E2E: Playwright
9+
- Dependency security: `cargo-audit` + `cargo-deny`
10+
11+
## Prerequisites
12+
13+
```bash
14+
rustup target add wasm32-unknown-unknown
15+
cargo install cargo-nextest cargo-llvm-cov wasm-pack trunk
16+
npm install
17+
npx playwright install chromium
18+
```
19+
20+
## Test Commands
21+
22+
```bash
23+
# Backend tests + line coverage gate (default: 70%)
24+
./scripts/test-rust.sh
25+
26+
# WASM UI tests (runs ui/tests/*.rs in Node)
27+
./scripts/test-wasm-ui.sh
28+
29+
# Browser E2E tests
30+
./scripts/test-e2e.sh
31+
32+
# Full suite
33+
./scripts/test-all.sh
34+
```
35+
36+
Set a stricter coverage gate locally:
37+
38+
```bash
39+
COVERAGE_MIN_LINES=75 ./scripts/test-rust.sh
40+
```
41+
42+
## Red/Green Workflow
43+
44+
1. Write a failing test in the right layer first:
45+
- backend behavior: `tests/*.rs` or module `#[cfg(test)]`
46+
- UI parser/transform logic: `ui/tests/*.rs` with `#[wasm_bindgen_test]`
47+
- full user flow: `e2e/*.spec.ts`
48+
2. Run the smallest relevant command.
49+
3. Implement the behavior.
50+
4. Re-run targeted tests.
51+
5. Run `./scripts/test-all.sh` before merging.
52+
53+
## CI
54+
55+
GitHub Actions workflow: `.github/workflows/test-suite.yml`
56+
57+
Jobs:
58+
59+
- `rust-tests`: nextest + coverage gate
60+
- `security`: cargo-audit + cargo-deny
61+
- `wasm-ui-tests`: wasm-pack tests
62+
- `e2e-tests`: Playwright E2E against the real gateway + embedded UI

deny.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[graph]
2+
all-features = true
3+
4+
[advisories]
5+
ignore = [
6+
# extism transitively pins wasmtime 37.x today.
7+
# Track upgrade path to a patched wasmtime line.
8+
"RUSTSEC-2026-0006",
9+
# transitive via wasmtime profiling stack
10+
"RUSTSEC-2025-0057",
11+
# transitive via async-nats / rustls-native-certs
12+
"RUSTSEC-2025-0134",
13+
]
14+
15+
[bans]
16+
multiple-versions = "warn"
17+
wildcards = "allow"
18+
highlight = "all"
19+
20+
[sources]
21+
unknown-registry = "deny"
22+
unknown-git = "deny"
23+
allow-registry = ["https://github.com/rust-lang/crates.io-index"]

0 commit comments

Comments
 (0)