Skip to content

Commit 95815a2

Browse files
authored
test: add unified test runner (bin/test.sh) (#6)
1 parent 436d1ee commit 95815a2

5 files changed

Lines changed: 93 additions & 46 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,11 @@ jobs:
3434
with:
3535
node-version: "22"
3636

37-
- name: Install slack-bridge dependencies
37+
- name: Install dependencies
3838
run: cd slack-bridge && npm ci
3939

40-
- name: Test — bridge security (71 tests)
41-
run: cd slack-bridge && node --test security.test.mjs
42-
43-
- name: Test — tool-guard (60 tests)
44-
run: cd pi/extensions && node --test tool-guard.test.mjs
45-
46-
- name: Test — extension scanner (15 tests)
47-
run: cd bin && node --test scan-extensions.test.mjs
48-
49-
- name: Test — safe-bash wrapper (24 tests)
50-
run: cd bin && bash hornet-safe-bash.test.sh
51-
52-
- name: Test — log redaction (11 tests)
53-
run: cd bin && bash redact-logs.test.sh
40+
- name: Run all tests
41+
run: bin/test.sh
5442

5543
# security-audit.sh checks live system state (running services, firewall,
5644
# /proc mounts) that doesn't exist in CI. Run it locally instead:

AGENTS.md

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -87,28 +87,18 @@ tmux new-window -n hornet 'sudo -u hornet_agent ~/runtime/start.sh'
8787
## Running Tests
8888

8989
```bash
90-
# Tool-guard tests (86 tests)
91-
cd pi/extensions && node --test tool-guard.test.mjs
90+
# All tests (207 across 5 suites)
91+
bin/test.sh
9292

93-
# Bridge security tests
94-
cd slack-bridge && node --test security.test.mjs
93+
# Only JS/TS tests
94+
bin/test.sh js
9595

96-
# Extension scanner tests
97-
cd bin && node --test scan-extensions.test.mjs
98-
99-
# Shell deny list tests
100-
cd bin && bash hornet-safe-bash.test.sh
101-
102-
# Log redaction tests
103-
cd bin && bash redact-logs.test.sh
104-
105-
# From deployed copies (as agent)
106-
sudo -u hornet_agent bash -c '
107-
export PATH=~/opt/node-v22.14.0-linux-x64/bin:$PATH
108-
cd ~/.pi/agent/extensions && node --test tool-guard.test.mjs
109-
'
96+
# Only shell tests
97+
bin/test.sh shell
11098
```
11199

100+
Add new test files to `bin/test.sh` — don't scatter test invocations across CI or docs.
101+
112102
## Conventions
113103

114104
- Security functions must be pure, testable modules (no side effects, no env vars at module scope).

README.md

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -140,19 +140,17 @@ sudo -u hornet_agent cat ~/.pi/agent/hornet-version.json
140140
## Tests
141141

142142
```bash
143-
# All tests (run from source as admin — agent can't read source)
144-
cd ~/hornet && \
145-
node slack-bridge/security.test.mjs && \
146-
node pi/extensions/tool-guard.test.mjs && \
147-
node bin/scan-extensions.test.mjs && \
148-
bash bin/hornet-safe-bash.test.sh && \
149-
bash bin/redact-logs.test.sh
150-
151-
# Or from deployed copies (as agent)
152-
sudo -u hornet_agent bash -c '
153-
export PATH=~/opt/node-v22.14.0-linux-x64/bin:$PATH
154-
cd ~/.pi/agent/extensions && node --test tool-guard.test.mjs
155-
'
143+
# All 207 tests across 5 suites
144+
bin/test.sh
145+
146+
# JS/TS only
147+
bin/test.sh js
148+
149+
# Shell only
150+
bin/test.sh shell
151+
152+
# Lint + typecheck
153+
npm run lint && npm run typecheck
156154
```
157155

158156
## How It Works

bin/test.sh

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/bin/bash
2+
# Run all Hornet tests. Exit code reflects overall pass/fail.
3+
#
4+
# Usage:
5+
# bin/test.sh # run all tests
6+
# bin/test.sh js # only JS/TS tests
7+
# bin/test.sh shell # only shell tests
8+
#
9+
# Add new test files here — don't scatter test invocations across CI/docs.
10+
11+
set -uo pipefail
12+
cd "$(dirname "$0")/.."
13+
14+
FILTER="${1:-all}"
15+
FAILED=0
16+
PASSED=0
17+
TOTAL=0
18+
19+
run() {
20+
local name="$1"
21+
shift
22+
TOTAL=$((TOTAL + 1))
23+
printf " %-40s " "$name"
24+
local output=""
25+
local rc=0
26+
output=$("$@" 2>&1) || rc=$?
27+
if [ "$rc" -eq 0 ]; then
28+
# Extract test count if available
29+
count=$(echo "$output" | awk '/ℹ pass [0-9]/ {for(i=1;i<=NF;i++) if($i=="pass") print $(i+1)}' | tail -1)
30+
if [ -z "$count" ]; then
31+
count=$(echo "$output" | awk '/[0-9]+ passed/ {for(i=1;i<=NF;i++) if($(i+1)=="passed," || $(i+1)=="passed") print $i}' | tail -1)
32+
fi
33+
if [ -n "$count" ]; then
34+
echo "✓ ($count tests)"
35+
else
36+
echo ""
37+
fi
38+
PASSED=$((PASSED + 1))
39+
else
40+
echo "✗ FAILED (exit $rc)"
41+
echo "$output" | tail -20 | sed 's/^/ /'
42+
FAILED=$((FAILED + 1))
43+
fi
44+
}
45+
46+
echo "=== Hornet Tests ==="
47+
echo ""
48+
49+
if [ "$FILTER" = "all" ] || [ "$FILTER" = "js" ]; then
50+
echo "JS/TS:"
51+
run "tool-guard" node --test pi/extensions/tool-guard.test.mjs
52+
run "bridge security" node --test slack-bridge/security.test.mjs
53+
run "extension scanner" node --test bin/scan-extensions.test.mjs
54+
echo ""
55+
fi
56+
57+
if [ "$FILTER" = "all" ] || [ "$FILTER" = "shell" ]; then
58+
echo "Shell:"
59+
run "safe-bash wrapper" bash bin/hornet-safe-bash.test.sh
60+
run "log redaction" bash bin/redact-logs.test.sh
61+
echo ""
62+
fi
63+
64+
echo "=== $PASSED/$TOTAL passed, $FAILED failed ==="
65+
66+
if [ "$FAILED" -gt 0 ]; then
67+
exit 1
68+
fi

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
"name": "hornet",
33
"private": true,
44
"scripts": {
5+
"test": "bin/test.sh",
6+
"test:js": "bin/test.sh js",
7+
"test:shell": "bin/test.sh shell",
58
"lint": "biome lint",
69
"lint:fix": "biome lint --write --unsafe",
710
"typecheck": "tsc --noEmit"

0 commit comments

Comments
 (0)