1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
name: "HTTP API Authentication (RECURSIVE_HTTP_AUTH_KEYS)"
description: |
Verify the HTTP server's inbound API-key authentication (src/http/auth.rs).
Uses the same in-container curl pattern as 08-http-api.yaml because the
server is started inside the container and is only reachable from within.
- When RECURSIVE_HTTP_AUTH_KEYS is set, requests without X-API-Key return 401.
- Requests with the correct key are accepted (200).
- Requests with a wrong key are rejected (401).
- /health and /metrics bypass auth (liveness probes must work unauthenticated).
sequential: true
setup:
- name: "Kill any leftover server on port 9097"
ignoreError: true
exec:
container: recursive-e2e
command: |
# Allocate a free port for this suite (host-mode port randomization).
PORT=$(python3 -c "import socket; s=socket.socket(); s.bind(('',0)); p=s.getsockname()[1]; s.close(); print(p)")
echo "$PORT" > /tmp/e2e-host-port-39.txt
echo "suite-port=$PORT"
export PORT=$(cat /tmp/e2e-host-port-39.txt)
pkill -f 'recursive.*http --addr' 2>/dev/null || true
sleep 0.5
echo cleaned
- name: "Start HTTP server on 9097 with auth key 'test-secret-key'"
exec:
container: recursive-e2e
command: |
export PORT=$(cat /tmp/e2e-host-port-39.txt)
nohup sh -c "RECURSIVE_HTTP_AUTH_KEYS=test-secret-key \
recursive \
--api-base http://aimock:4010/v1 \
--api-key mock-key -m mock-chat \
http --addr 0.0.0.0:$PORT" \
> /tmp/http-$PORT.log 2>&1 &
for i in $(seq 1 20); do
curl -sf http://localhost:$PORT/health > /dev/null 2>&1 && echo "server-ready" && break
sleep 0.5
done
cases:
# ── /health and /metrics bypass auth ─────────────────────────────────────────
- name: "GET /health without key returns 200 (auth-exempt endpoint)"
exec:
container: recursive-e2e
command: >
export PORT=$(cat /tmp/e2e-host-port-39.txt); curl -s -o /dev/null -w 'status=%{http_code}'
http://localhost:$PORT/health
expect:
exitCode: 0
output:
contains: "status=200"
- name: "GET /metrics without key returns 200 (auth-exempt endpoint)"
exec:
container: recursive-e2e
command: >
export PORT=$(cat /tmp/e2e-host-port-39.txt); curl -s -o /dev/null -w 'status=%{http_code}'
http://localhost:$PORT/metrics
expect:
exitCode: 0
output:
contains: "status=200"
# ── Auth-protected endpoints without key ─────────────────────────────────────
- name: "GET /sessions without X-API-Key returns 401"
exec:
container: recursive-e2e
command: >
export PORT=$(cat /tmp/e2e-host-port-39.txt); curl -s -o /dev/null -w 'status=%{http_code}'
http://localhost:$PORT/sessions
expect:
exitCode: 0
output:
contains: "status=401"
- name: "POST /sessions without key returns 401"
exec:
container: recursive-e2e
command: >
export PORT=$(cat /tmp/e2e-host-port-39.txt); curl -s -o /dev/null -w 'status=%{http_code}'
-X POST http://localhost:$PORT/sessions
-H 'Content-Type: application/json'
-d '{}'
expect:
exitCode: 0
output:
contains: "status=401"
- name: "POST /run without key returns 401"
exec:
container: recursive-e2e
command: >
export PORT=$(cat /tmp/e2e-host-port-39.txt); curl -s -o /dev/null -w 'status=%{http_code}'
-X POST http://localhost:$PORT/run
-H 'Content-Type: application/json'
-d '{"goal":"test"}'
expect:
exitCode: 0
output:
contains: "status=401"
# ── Wrong key ────────────────────────────────────────────────────────────────
- name: "GET /sessions with wrong X-API-Key returns 401"
exec:
container: recursive-e2e
command: >
export PORT=$(cat /tmp/e2e-host-port-39.txt); curl -s -o /dev/null -w 'status=%{http_code}'
-H 'X-API-Key: wrong-key'
http://localhost:$PORT/sessions
expect:
exitCode: 0
output:
contains: "status=401"
# ── Correct key grants access ─────────────────────────────────────────────────
- name: "GET /sessions with correct X-API-Key returns 200"
exec:
container: recursive-e2e
command: >
export PORT=$(cat /tmp/e2e-host-port-39.txt); curl -s -o /dev/null -w 'status=%{http_code}'
-H 'X-API-Key: test-secret-key'
http://localhost:$PORT/sessions
expect:
exitCode: 0
output:
contains: "status=200"
- name: "POST /sessions with correct key creates a session (200 or 201)"
exec:
container: recursive-e2e
command: |
export PORT=$(cat /tmp/e2e-host-port-39.txt)
OUT=$(curl -sf \
-H 'X-API-Key: test-secret-key' \
-X POST http://localhost:$PORT/sessions \
-H 'Content-Type: application/json' \
-d '{"system_prompt":"auth test"}')
echo "$OUT" | grep -q '"id"' && echo "has-id" || echo "no-id"
expect:
exitCode: 0
output:
contains: "has-id"
teardown:
- name: "Stop HTTP server on 9097"
ignoreError: true
exec:
container: recursive-e2e
command: |
export PORT=$(cat /tmp/e2e-host-port-39.txt)
pkill -f 'recursive.*http --addr' 2>/dev/null || true
rm -f /tmp/http-$PORT.log
echo stopped