uplink-cli 0.1.26 → 0.1.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/src/index.ts +2 -4
- package/cli/src/subcommands/menu/tunnels.ts +15 -2
- package/cli/src/subcommands/menu.ts +359 -96
- package/docs/AGENTS.md +139 -0
- package/docs/MENU_STRUCTURE.md +292 -0
- package/docs/OPEN_SOURCE_CLI.md +71 -0
- package/docs/PRODUCT.md +314 -0
- package/docs/guides/MANUAL.md +513 -0
- package/docs/guides/QUICKSTART.md +280 -0
- package/docs/guides/README.md +22 -0
- package/docs/guides/TESTING.md +408 -0
- package/docs/guides/TUNNEL_SETUP.md +134 -0
- package/docs/guides/USAGE.md +247 -0
- package/package.json +3 -2
- package/scripts/tunnel/client-improved.js +14 -2
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# Quick Start: Expose Your Localhost to the Internet
|
|
2
|
+
|
|
3
|
+
This guide shows you how to expose a local development server to the internet using Uplink tunnels.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js installed
|
|
8
|
+
- A local server running on a port (e.g., `localhost:3000`)
|
|
9
|
+
- An API token (minted admin/user token; dev-token only for local SQLite dev)
|
|
10
|
+
- Install the user CLI (pick one):
|
|
11
|
+
- Public npm (best UX once published):
|
|
12
|
+
```bash
|
|
13
|
+
npm install -g uplink-cli
|
|
14
|
+
# or run without global install:
|
|
15
|
+
npx uplink-cli
|
|
16
|
+
```
|
|
17
|
+
- Private repo via SSH (requires GitHub SSH access):
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g git+ssh://git@github.com/firstprinciplecode/agentcloud.git#master
|
|
20
|
+
```
|
|
21
|
+
- Private repo via HTTPS with token in env (safer than embedding in URL):
|
|
22
|
+
```bash
|
|
23
|
+
GITHUB_TOKEN=<your-github-pat-with-repo-scope> \
|
|
24
|
+
npm install -g https://github.com/firstprinciplecode/agentcloud.git#master
|
|
25
|
+
```
|
|
26
|
+
- Prebuilt tarball (no git, no token):
|
|
27
|
+
```bash
|
|
28
|
+
npm install -g ./uplink-cli-0.1.0.tgz
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Get an API token
|
|
32
|
+
|
|
33
|
+
- If you are an admin and have break-glass `ADMIN_TOKENS` on the server, mint a proper token and use that going forward:
|
|
34
|
+
```bash
|
|
35
|
+
uplink admin tokens create --role admin --label "my-laptop"
|
|
36
|
+
export AGENTCLOUD_TOKEN=<printed-admin-token>
|
|
37
|
+
```
|
|
38
|
+
- If you are not an admin, ask an admin to mint a user token for you:
|
|
39
|
+
```bash
|
|
40
|
+
uplink admin tokens create --role user --label "teammate"
|
|
41
|
+
```
|
|
42
|
+
- Keep tokens out of shell history; prefer env vars over inline CLI args.
|
|
43
|
+
|
|
44
|
+
Then set your token before running `uplink`:
|
|
45
|
+
```bash
|
|
46
|
+
export AGENTCLOUD_TOKEN=<your-token>
|
|
47
|
+
uplink
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Security note:** do not paste tokens into command lines/URLs (they land in shell history). Use `GITHUB_TOKEN` env for private installs and rotate any PAT that was previously pasted.
|
|
51
|
+
|
|
52
|
+
**Note:** The CLI connects to `https://api.uplink.spot` by default. To use a local API server, set:
|
|
53
|
+
```bash
|
|
54
|
+
export AGENTCLOUD_API_BASE=http://localhost:4000
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## The Simplest Way (Recommended)
|
|
58
|
+
|
|
59
|
+
### Step 1: Start Your Local Server
|
|
60
|
+
|
|
61
|
+
Start your development server on any port:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Example: Start a Node.js server
|
|
65
|
+
npm start
|
|
66
|
+
|
|
67
|
+
# Or start a Python server
|
|
68
|
+
python3 -m http.server 3000
|
|
69
|
+
|
|
70
|
+
# Or any other server - just make sure it's running!
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Verify it's working:** Open `http://localhost:3000` (or your port) in your browser.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### Step 2: Run Uplink and Start Tunnel
|
|
78
|
+
|
|
79
|
+
**Important:** Run `uplink` on your **local machine** (where your dev server is running), not on the server!
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# On your LOCAL machine, open the interactive menu
|
|
83
|
+
uplink
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Then:
|
|
87
|
+
1. Select **"Manage Tunnels"** → **"Start Tunnel"**
|
|
88
|
+
2. The system will scan for active servers on your **local machine**
|
|
89
|
+
3. Use arrow keys to select the port your server is running on (or choose "Enter custom port")
|
|
90
|
+
4. Press "Back" if you want to cancel
|
|
91
|
+
5. Done! Your tunnel is created and started automatically
|
|
92
|
+
|
|
93
|
+
**That's it!** You'll see your public URL like:
|
|
94
|
+
```
|
|
95
|
+
✓ Tunnel created and client started
|
|
96
|
+
|
|
97
|
+
→ Public URL https://abc123def456.t.uplink.spot
|
|
98
|
+
→ Token abc123def456
|
|
99
|
+
→ Local port 3000
|
|
100
|
+
|
|
101
|
+
Tunnel client running in background.
|
|
102
|
+
Use "Stop Tunnel" to disconnect.
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Alternative Methods
|
|
108
|
+
|
|
109
|
+
### Method 2: Direct CLI Command
|
|
110
|
+
|
|
111
|
+
If you know the port number:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Set your API token (if not using default)
|
|
115
|
+
export AGENTCLOUD_TOKEN=dev-token
|
|
116
|
+
|
|
117
|
+
# Create tunnel and connect automatically
|
|
118
|
+
npm run dev:cli -- dev --tunnel --port 3000
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Method 3: Manual Steps (Advanced)
|
|
122
|
+
|
|
123
|
+
**3a. Create tunnel via API:**
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
curl -X POST https://api.uplink.spot/v1/tunnels \
|
|
127
|
+
-H "Authorization: Bearer dev-token" \
|
|
128
|
+
-H "Content-Type: application/json" \
|
|
129
|
+
-d '{"port": 3000}'
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Response:**
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"id": "tun_abc123...",
|
|
136
|
+
"token": "abc123def456",
|
|
137
|
+
"url": "https://abc123def456.t.uplink.spot",
|
|
138
|
+
"targetPort": 3000,
|
|
139
|
+
"status": "active"
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**3b. Start the tunnel client:**
|
|
144
|
+
|
|
145
|
+
Copy the `token` from the response above, then run:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
node scripts/tunnel/client-improved.js \
|
|
149
|
+
--token abc123def456 \
|
|
150
|
+
--port 3000 \
|
|
151
|
+
--ctrl tunnel.uplink.spot:7071
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Complete Example
|
|
157
|
+
|
|
158
|
+
Here's a complete example from start to finish:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Terminal 1: Start your local server
|
|
162
|
+
cd my-app
|
|
163
|
+
npm start
|
|
164
|
+
# Server running on http://localhost:3000
|
|
165
|
+
|
|
166
|
+
# Terminal 2: Start tunnel (easiest way)
|
|
167
|
+
uplink
|
|
168
|
+
# Select "Manage Tunnels" → "Start Tunnel"
|
|
169
|
+
# Choose port 3000 from the list (use arrow keys)
|
|
170
|
+
# Done! Your tunnel URL is displayed
|
|
171
|
+
|
|
172
|
+
# Or use direct command:
|
|
173
|
+
export AGENTCLOUD_TOKEN=dev-token
|
|
174
|
+
npm run dev:cli -- dev --tunnel --port 3000
|
|
175
|
+
|
|
176
|
+
# Output:
|
|
177
|
+
# ✓ Tunnel created and client started
|
|
178
|
+
# → Public URL https://abc123def456.t.uplink.spot
|
|
179
|
+
# Open https://abc123def456.t.uplink.spot in your browser!
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Environment Variables
|
|
185
|
+
|
|
186
|
+
You can customize the tunnel behavior with environment variables:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# API endpoint (default: https://api.uplink.spot)
|
|
190
|
+
export AGENTCLOUD_API_BASE=https://api.uplink.spot
|
|
191
|
+
|
|
192
|
+
# Your API token (default: dev-token)
|
|
193
|
+
export AGENTCLOUD_TOKEN=dev-token
|
|
194
|
+
|
|
195
|
+
# Tunnel control server (default: tunnel.uplink.spot:7071)
|
|
196
|
+
export TUNNEL_CTRL=tunnel.uplink.spot:7071
|
|
197
|
+
|
|
198
|
+
# Tunnel domain (default: t.uplink.spot)
|
|
199
|
+
export TUNNEL_DOMAIN=t.uplink.spot
|
|
200
|
+
|
|
201
|
+
# Optional: show relay status in the menu (set if you want the banner)
|
|
202
|
+
# Set these before running `uplink` locally:
|
|
203
|
+
# RELAY_HEALTH_URL points to the relay /health endpoint
|
|
204
|
+
# RELAY_INTERNAL_SECRET must match the relay/backend secret if set
|
|
205
|
+
export RELAY_HEALTH_URL=http://t.uplink.spot:7070/health
|
|
206
|
+
# export RELAY_INTERNAL_SECRET=<your-relay-secret>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Ops notes (relay/backend)
|
|
210
|
+
- Relay binds HTTP ingress to loopback by default: `TUNNEL_RELAY_HTTP_HOST=127.0.0.1`
|
|
211
|
+
- Protect internal endpoints with a shared secret: `RELAY_INTERNAL_SECRET=<same-secret-on-backend>`
|
|
212
|
+
- Set the same `RELAY_INTERNAL_SECRET` on the backend service so admin tunnel status works.
|
|
213
|
+
- Admin-only menus/features require an admin token. Users with normal tokens only see their own tunnels/databases by default.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Troubleshooting
|
|
218
|
+
|
|
219
|
+
### "Connection refused" error
|
|
220
|
+
- **Check:** Is your local server running on the specified port?
|
|
221
|
+
- **Fix:** Start your server first, then create the tunnel
|
|
222
|
+
|
|
223
|
+
### "Cannot connect to relay" error
|
|
224
|
+
- **Check:** Is the relay server running?
|
|
225
|
+
- **Fix:** Verify the `TUNNEL_CTRL` address is correct
|
|
226
|
+
|
|
227
|
+
### Tunnel URL returns "Gateway timeout"
|
|
228
|
+
- **Check:** Is the tunnel client still running?
|
|
229
|
+
- **Fix:** Make sure the client process didn't exit. Restart it if needed.
|
|
230
|
+
|
|
231
|
+
### "Tunnel client failed to register"
|
|
232
|
+
- **Check:** Is the token correct?
|
|
233
|
+
- **Fix:** Create a new tunnel and use the new token
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Stopping the Tunnel
|
|
238
|
+
|
|
239
|
+
**If using CLI:** Press `Ctrl+C` in the terminal where the CLI is running.
|
|
240
|
+
|
|
241
|
+
**If using manual client:** Press `Ctrl+C` in the terminal where the client is running.
|
|
242
|
+
|
|
243
|
+
The tunnel will remain in the database but won't be accessible until you reconnect the client.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Next Steps
|
|
248
|
+
|
|
249
|
+
- **Multiple tunnels:** Create multiple tunnels for different ports
|
|
250
|
+
- **Persistent tunnels:** Keep the client running to maintain the tunnel
|
|
251
|
+
- **Production use:** Replace `dev-token` with a proper authentication token
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Quick Reference
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Easiest: Interactive menu (auto-detects ports)
|
|
259
|
+
uplink
|
|
260
|
+
# Select "Manage Tunnels" → "Start Tunnel"
|
|
261
|
+
|
|
262
|
+
# Direct command (if you know the port)
|
|
263
|
+
npm run dev:cli -- dev --tunnel --port <PORT>
|
|
264
|
+
|
|
265
|
+
# Manual: Create tunnel via API
|
|
266
|
+
curl -X POST https://api.uplink.spot/v1/tunnels \
|
|
267
|
+
-H "Authorization: Bearer dev-token" \
|
|
268
|
+
-H "Content-Type: application/json" \
|
|
269
|
+
-d '{"port": <PORT>}'
|
|
270
|
+
|
|
271
|
+
# Manual: Connect client
|
|
272
|
+
node scripts/tunnel/client-improved.js \
|
|
273
|
+
--token <TOKEN> \
|
|
274
|
+
--port <PORT> \
|
|
275
|
+
--ctrl tunnel.uplink.spot:7071
|
|
276
|
+
|
|
277
|
+
# Test tunnel
|
|
278
|
+
curl https://<TOKEN>.t.uplink.spot
|
|
279
|
+
```
|
|
280
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# User Guides
|
|
2
|
+
|
|
3
|
+
This directory contains user-facing documentation for Uplink.
|
|
4
|
+
|
|
5
|
+
## Available Guides
|
|
6
|
+
|
|
7
|
+
- **[Quick Start](QUICKSTART.md)** - Get started exposing your localhost to the internet
|
|
8
|
+
- **[Manual](MANUAL.md)** - Complete feature reference and API documentation
|
|
9
|
+
- **[Usage Guide](USAGE.md)** - Service usage examples and workflows
|
|
10
|
+
- **[Tunnel Setup](TUNNEL_SETUP.md)** - Step-by-step tunnel setup instructions
|
|
11
|
+
- **[Testing Guide](TESTING.md)** - How to test the system and new features
|
|
12
|
+
|
|
13
|
+
## Quick Links
|
|
14
|
+
|
|
15
|
+
- **New to Uplink?** Start with [Quick Start](QUICKSTART.md)
|
|
16
|
+
- **Need detailed info?** Check the [Manual](MANUAL.md)
|
|
17
|
+
- **Setting up tunnels?** See [Tunnel Setup](TUNNEL_SETUP.md)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
# Testing Guide
|
|
2
|
+
|
|
3
|
+
This guide covers how to test the Uplink system, including the new security and reliability features.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### 1. Start the Backend API
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# In one terminal
|
|
11
|
+
npm run dev:api
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The server will start on `http://localhost:4000` (or the port specified in `PORT` env var).
|
|
15
|
+
|
|
16
|
+
### 2. Run Feature Tests
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Test new features (validation, rate limiting, logging, etc.)
|
|
20
|
+
bash scripts/test-new-features.sh
|
|
21
|
+
|
|
22
|
+
# Or test against production/staging
|
|
23
|
+
AGENTCLOUD_API_BASE=https://api.uplink.spot \
|
|
24
|
+
AGENTCLOUD_TOKEN=your-token \
|
|
25
|
+
bash scripts/test-new-features.sh
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 3. Run Existing Smoke Tests
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# All smoke tests
|
|
32
|
+
npm run smoke:all
|
|
33
|
+
|
|
34
|
+
# Individual tests
|
|
35
|
+
npm run smoke:tunnel
|
|
36
|
+
npm run smoke:db
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Testing New Features
|
|
40
|
+
|
|
41
|
+
### Structured Logging
|
|
42
|
+
|
|
43
|
+
**What to test:**
|
|
44
|
+
- Logs are structured JSON in production
|
|
45
|
+
- Pretty-printed in development
|
|
46
|
+
- Audit events are logged
|
|
47
|
+
|
|
48
|
+
**How to test:**
|
|
49
|
+
1. Start the server: `npm run dev:api`
|
|
50
|
+
2. Make some API calls (create tunnel, create token, etc.)
|
|
51
|
+
3. Check console output for structured logs
|
|
52
|
+
4. Look for audit events like:
|
|
53
|
+
- `event: "tunnel.created"`
|
|
54
|
+
- `event: "auth.success"`
|
|
55
|
+
- `event: "token.created"`
|
|
56
|
+
|
|
57
|
+
**Example:**
|
|
58
|
+
```bash
|
|
59
|
+
# Start server
|
|
60
|
+
npm run dev:api
|
|
61
|
+
|
|
62
|
+
# In another terminal, create a tunnel
|
|
63
|
+
curl -X POST http://localhost:4000/v1/tunnels \
|
|
64
|
+
-H "Authorization: Bearer dev-token" \
|
|
65
|
+
-H "Content-Type: application/json" \
|
|
66
|
+
-d '{"port": 3000}'
|
|
67
|
+
|
|
68
|
+
# Check server logs for:
|
|
69
|
+
# {"level":30,"time":1234567890,"event":"tunnel.created","userId":"...","tunnelId":"..."}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Rate Limiting
|
|
73
|
+
|
|
74
|
+
**What to test:**
|
|
75
|
+
- API endpoints are rate limited
|
|
76
|
+
- Different limits for different endpoints
|
|
77
|
+
- Rate limit headers are returned
|
|
78
|
+
|
|
79
|
+
**How to test:**
|
|
80
|
+
```bash
|
|
81
|
+
# Test general API rate limiting (100 req/15min)
|
|
82
|
+
for i in {1..110}; do
|
|
83
|
+
curl -s -w "\n%{http_code}" http://localhost:4000/v1/tunnels \
|
|
84
|
+
-H "Authorization: Bearer dev-token" | tail -1
|
|
85
|
+
sleep 0.1
|
|
86
|
+
done
|
|
87
|
+
# Should eventually get 429
|
|
88
|
+
|
|
89
|
+
# Test auth rate limiting (10 req/15min)
|
|
90
|
+
for i in {1..15}; do
|
|
91
|
+
curl -s -w "\n%{http_code}" http://localhost:4000/v1/tunnels \
|
|
92
|
+
-H "Authorization: Bearer invalid-token" | tail -1
|
|
93
|
+
done
|
|
94
|
+
# Should get 429 after 10 requests
|
|
95
|
+
|
|
96
|
+
# Test tunnel creation rate limiting (50 req/hour)
|
|
97
|
+
for i in {1..55}; do
|
|
98
|
+
curl -s -X POST http://localhost:4000/v1/tunnels \
|
|
99
|
+
-H "Authorization: Bearer dev-token" \
|
|
100
|
+
-H "Content-Type: application/json" \
|
|
101
|
+
-d '{"port": 3000}' | tail -1
|
|
102
|
+
done
|
|
103
|
+
# Should get 429 after 50 requests
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Expected behavior:**
|
|
107
|
+
- First requests succeed (200/201)
|
|
108
|
+
- After limit, get 429 with error message
|
|
109
|
+
- Rate limit info in response headers
|
|
110
|
+
|
|
111
|
+
### Input Validation
|
|
112
|
+
|
|
113
|
+
**What to test:**
|
|
114
|
+
- Invalid inputs are rejected with 400
|
|
115
|
+
- Clear error messages
|
|
116
|
+
- Validation errors include field paths
|
|
117
|
+
|
|
118
|
+
**How to test:**
|
|
119
|
+
```bash
|
|
120
|
+
# Missing required field
|
|
121
|
+
curl -X POST http://localhost:4000/v1/tunnels \
|
|
122
|
+
-H "Authorization: Bearer dev-token" \
|
|
123
|
+
-H "Content-Type: application/json" \
|
|
124
|
+
-d '{}'
|
|
125
|
+
# Expected: 400 with validation error
|
|
126
|
+
|
|
127
|
+
# Invalid type
|
|
128
|
+
curl -X POST http://localhost:4000/v1/tunnels \
|
|
129
|
+
-H "Authorization: Bearer dev-token" \
|
|
130
|
+
-H "Content-Type: application/json" \
|
|
131
|
+
-d '{"port": "not-a-number"}'
|
|
132
|
+
# Expected: 400 with validation error
|
|
133
|
+
|
|
134
|
+
# Out of range
|
|
135
|
+
curl -X POST http://localhost:4000/v1/tunnels \
|
|
136
|
+
-H "Authorization: Bearer dev-token" \
|
|
137
|
+
-H "Content-Type: application/json" \
|
|
138
|
+
-d '{"port": 99999}'
|
|
139
|
+
# Expected: 400 with validation error
|
|
140
|
+
|
|
141
|
+
# Valid input
|
|
142
|
+
curl -X POST http://localhost:4000/v1/tunnels \
|
|
143
|
+
-H "Authorization: Bearer dev-token" \
|
|
144
|
+
-H "Content-Type: application/json" \
|
|
145
|
+
-d '{"port": 3000}'
|
|
146
|
+
# Expected: 201 with tunnel data
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Expected response format:**
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"error": {
|
|
153
|
+
"code": "VALIDATION_ERROR",
|
|
154
|
+
"message": "Invalid request body",
|
|
155
|
+
"details": {
|
|
156
|
+
"errors": [
|
|
157
|
+
{
|
|
158
|
+
"path": "port",
|
|
159
|
+
"message": "Expected number, received string"
|
|
160
|
+
}
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Security Headers
|
|
168
|
+
|
|
169
|
+
**What to test:**
|
|
170
|
+
- Helmet.js security headers are present
|
|
171
|
+
- XSS protection headers
|
|
172
|
+
- Content type options
|
|
173
|
+
|
|
174
|
+
**How to test:**
|
|
175
|
+
```bash
|
|
176
|
+
curl -I http://localhost:4000/health
|
|
177
|
+
|
|
178
|
+
# Should see headers like:
|
|
179
|
+
# X-Content-Type-Options: nosniff
|
|
180
|
+
# X-Frame-Options: DENY
|
|
181
|
+
# X-XSS-Protection: 1; mode=block
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Configuration Validation
|
|
185
|
+
|
|
186
|
+
**What to test:**
|
|
187
|
+
- Server fails fast with clear errors for missing config
|
|
188
|
+
- Validates on startup
|
|
189
|
+
- Logs configuration summary
|
|
190
|
+
|
|
191
|
+
**How to test:**
|
|
192
|
+
```bash
|
|
193
|
+
# Test with missing required config (if any)
|
|
194
|
+
unset CONTROL_PLANE_DATABASE_URL
|
|
195
|
+
npm run dev:api
|
|
196
|
+
# Should fail with clear error message
|
|
197
|
+
|
|
198
|
+
# Test with invalid config
|
|
199
|
+
CONTROL_PLANE_DATABASE_URL="invalid://url" npm run dev:api
|
|
200
|
+
# Should handle gracefully or fail with clear message
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Health Endpoints
|
|
204
|
+
|
|
205
|
+
**What to test:**
|
|
206
|
+
- `/health` - Basic health check
|
|
207
|
+
- `/health/live` - Liveness probe (process running)
|
|
208
|
+
- `/health/ready` - Readiness probe (can serve requests)
|
|
209
|
+
|
|
210
|
+
**How to test:**
|
|
211
|
+
```bash
|
|
212
|
+
# Basic health
|
|
213
|
+
curl http://localhost:4000/health
|
|
214
|
+
# Expected: {"status":"ok","timestamp":"..."}
|
|
215
|
+
|
|
216
|
+
# Liveness
|
|
217
|
+
curl http://localhost:4000/health/live
|
|
218
|
+
# Expected: {"status":"alive"}
|
|
219
|
+
|
|
220
|
+
# Readiness (checks DB connection)
|
|
221
|
+
curl http://localhost:4000/health/ready
|
|
222
|
+
# Expected: {"status":"ready"} or {"status":"not ready"} if DB unavailable
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Audit Logging
|
|
226
|
+
|
|
227
|
+
**What to test:**
|
|
228
|
+
- Security events are logged
|
|
229
|
+
- Token operations are audited
|
|
230
|
+
- Tunnel operations are audited
|
|
231
|
+
|
|
232
|
+
**How to test:**
|
|
233
|
+
1. Perform security-sensitive operations:
|
|
234
|
+
```bash
|
|
235
|
+
# Create token (if admin)
|
|
236
|
+
curl -X POST http://localhost:4000/v1/admin/tokens \
|
|
237
|
+
-H "Authorization: Bearer admin-token" \
|
|
238
|
+
-H "Content-Type: application/json" \
|
|
239
|
+
-d '{"role": "user"}'
|
|
240
|
+
|
|
241
|
+
# Create tunnel
|
|
242
|
+
curl -X POST http://localhost:4000/v1/tunnels \
|
|
243
|
+
-H "Authorization: Bearer dev-token" \
|
|
244
|
+
-H "Content-Type: application/json" \
|
|
245
|
+
-d '{"port": 3000}'
|
|
246
|
+
|
|
247
|
+
# Delete tunnel
|
|
248
|
+
curl -X DELETE http://localhost:4000/v1/tunnels/TUNNEL_ID \
|
|
249
|
+
-H "Authorization: Bearer dev-token"
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
2. Check server logs for audit entries:
|
|
253
|
+
```json
|
|
254
|
+
{"level":30,"component":"audit","event":"token.created","userId":"...","tokenId":"..."}
|
|
255
|
+
{"level":30,"component":"audit","event":"tunnel.created","userId":"...","tunnelId":"..."}
|
|
256
|
+
{"level":30,"component":"audit","event":"tunnel.deleted","userId":"...","tunnelId":"..."}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Manual Testing Checklist
|
|
260
|
+
|
|
261
|
+
### Authentication & Authorization
|
|
262
|
+
- [ ] Missing token returns 401
|
|
263
|
+
- [ ] Invalid token returns 401
|
|
264
|
+
- [ ] Valid token allows access
|
|
265
|
+
- [ ] Admin-only endpoints require admin role
|
|
266
|
+
- [ ] Users can only access their own resources
|
|
267
|
+
|
|
268
|
+
### Rate Limiting
|
|
269
|
+
- [ ] General API rate limit works (100/15min)
|
|
270
|
+
- [ ] Auth rate limit works (10/15min)
|
|
271
|
+
- [ ] Token creation rate limit works (20/hour)
|
|
272
|
+
- [ ] Tunnel creation rate limit works (50/hour)
|
|
273
|
+
- [ ] Rate limit headers are present
|
|
274
|
+
- [ ] Rate limit errors are clear
|
|
275
|
+
|
|
276
|
+
### Input Validation
|
|
277
|
+
- [ ] Missing required fields return 400
|
|
278
|
+
- [ ] Invalid types return 400
|
|
279
|
+
- [ ] Out of range values return 400
|
|
280
|
+
- [ ] Invalid formats return 400
|
|
281
|
+
- [ ] Error messages are helpful
|
|
282
|
+
|
|
283
|
+
### Logging
|
|
284
|
+
- [ ] Structured logs in production
|
|
285
|
+
- [ ] Pretty logs in development
|
|
286
|
+
- [ ] Audit events are logged
|
|
287
|
+
- [ ] Errors include stack traces
|
|
288
|
+
- [ ] Request/response logging works
|
|
289
|
+
|
|
290
|
+
### Security
|
|
291
|
+
- [ ] Security headers are present
|
|
292
|
+
- [ ] CORS is configured (if needed)
|
|
293
|
+
- [ ] Input sanitization works
|
|
294
|
+
- [ ] SQL injection prevention works
|
|
295
|
+
|
|
296
|
+
### Reliability
|
|
297
|
+
- [ ] Health endpoints work
|
|
298
|
+
- [ ] Graceful shutdown works
|
|
299
|
+
- [ ] Error handling is consistent
|
|
300
|
+
- [ ] Configuration validation works
|
|
301
|
+
|
|
302
|
+
## Integration Testing
|
|
303
|
+
|
|
304
|
+
### End-to-End Tunnel Test
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
# 1. Start backend API
|
|
308
|
+
npm run dev:api
|
|
309
|
+
|
|
310
|
+
# 2. Create tunnel
|
|
311
|
+
TUNNEL_RESPONSE=$(curl -s -X POST http://localhost:4000/v1/tunnels \
|
|
312
|
+
-H "Authorization: Bearer dev-token" \
|
|
313
|
+
-H "Content-Type: application/json" \
|
|
314
|
+
-d '{"port": 3000}')
|
|
315
|
+
|
|
316
|
+
TUNNEL_ID=$(echo $TUNNEL_RESPONSE | grep -o '"id":"[^"]*' | cut -d'"' -f4)
|
|
317
|
+
TOKEN=$(echo $TUNNEL_RESPONSE | grep -o '"token":"[^"]*' | cut -d'"' -f4)
|
|
318
|
+
|
|
319
|
+
# 3. Start local server
|
|
320
|
+
python3 -m http.server 3000 &
|
|
321
|
+
|
|
322
|
+
# 4. Start tunnel client (if relay is running)
|
|
323
|
+
node scripts/tunnel/client-improved.js \
|
|
324
|
+
--token $TOKEN \
|
|
325
|
+
--port 3000 \
|
|
326
|
+
--ctrl localhost:7071
|
|
327
|
+
|
|
328
|
+
# 5. Test tunnel (if configured)
|
|
329
|
+
curl https://${TOKEN}.t.uplink.spot
|
|
330
|
+
|
|
331
|
+
# 6. Clean up
|
|
332
|
+
curl -X DELETE http://localhost:4000/v1/tunnels/$TUNNEL_ID \
|
|
333
|
+
-H "Authorization: Bearer dev-token"
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Performance Testing
|
|
337
|
+
|
|
338
|
+
### Load Testing
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
# Install Apache Bench if needed
|
|
342
|
+
# macOS: brew install httpd
|
|
343
|
+
# Linux: apt-get install apache2-utils
|
|
344
|
+
|
|
345
|
+
# Test health endpoint
|
|
346
|
+
ab -n 1000 -c 10 http://localhost:4000/health
|
|
347
|
+
|
|
348
|
+
# Test authenticated endpoint
|
|
349
|
+
ab -n 100 -c 5 -H "Authorization: Bearer dev-token" \
|
|
350
|
+
http://localhost:4000/v1/tunnels
|
|
351
|
+
|
|
352
|
+
# Monitor rate limiting
|
|
353
|
+
ab -n 200 -c 20 -H "Authorization: Bearer dev-token" \
|
|
354
|
+
http://localhost:4000/v1/tunnels
|
|
355
|
+
# Should see some 429 responses
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Debugging
|
|
359
|
+
|
|
360
|
+
### Check Logs
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
# Development - logs to console
|
|
364
|
+
npm run dev:api
|
|
365
|
+
|
|
366
|
+
# Production - check systemd logs
|
|
367
|
+
journalctl -u backend-api -f
|
|
368
|
+
|
|
369
|
+
# Check for specific events
|
|
370
|
+
journalctl -u backend-api | grep "tunnel.created"
|
|
371
|
+
journalctl -u backend-api | grep "auth.failed"
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Enable Debug Logging
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
LOG_LEVEL=debug npm run dev:api
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Test Configuration
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
# Test config validation
|
|
384
|
+
node -e "require('./backend/src/utils/config.ts')"
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## Continuous Testing
|
|
388
|
+
|
|
389
|
+
Add to CI/CD pipeline:
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
# Run all tests
|
|
393
|
+
npm run smoke:all
|
|
394
|
+
|
|
395
|
+
# Run feature tests
|
|
396
|
+
bash scripts/test-new-features.sh
|
|
397
|
+
|
|
398
|
+
# Check for TypeScript errors
|
|
399
|
+
npx tsc --noEmit
|
|
400
|
+
|
|
401
|
+
# Check for linting errors (if configured)
|
|
402
|
+
npm run lint
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
|