Skip to content

Commit 5d7d0b8

Browse files
authored
fix(openapi): Update exec endpoint spec to match WebSocket implementation
1 parent db26f38 commit 5d7d0b8

12 files changed

+917
-77
lines changed

.final_build.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/sh
2+
set -e
3+
cd "$(dirname "$0")"
4+
echo "Working directory: $(pwd)"
5+
echo "Running make oapi-generate..."
6+
/usr/bin/make oapi-generate 2>&1
7+
echo "Running make build..."
8+
/usr/bin/make build 2>&1
9+
echo "Success!"

CHANGES_SUMMARY.md

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
# OpenAPI Exec Feature Update - Changes Summary
2+
3+
## Overview
4+
5+
Updated the Hypeman OpenAPI specification and generated code to accurately reflect the WebSocket-based exec implementation. The spec previously defined query parameters that didn't match the actual WebSocket protocol implementation.
6+
7+
## Files Modified
8+
9+
### 1. openapi.yaml
10+
11+
#### ExecRequest Schema (lines 364-392)
12+
**Before:**
13+
```yaml
14+
ExecRequest:
15+
type: object
16+
required: [command]
17+
properties:
18+
command:
19+
type: array
20+
items:
21+
type: string
22+
description: Command and arguments to execute
23+
example: ["/bin/sh"]
24+
tty:
25+
type: boolean
26+
description: Allocate a pseudo-TTY
27+
default: true
28+
```
29+
30+
**After:**
31+
```yaml
32+
ExecRequest:
33+
type: object
34+
properties:
35+
command:
36+
type: array
37+
items:
38+
type: string
39+
description: Command and arguments to execute (defaults to ["/bin/sh"])
40+
example: ["/bin/sh"]
41+
tty:
42+
type: boolean
43+
description: Allocate a pseudo-TTY
44+
default: false
45+
env:
46+
type: object
47+
additionalProperties:
48+
type: string
49+
description: Additional environment variables
50+
example:
51+
DEBUG: "true"
52+
cwd:
53+
type: string
54+
description: Working directory for the command
55+
example: /app
56+
timeout:
57+
type: integer
58+
format: int32
59+
description: Timeout in seconds (0 means no timeout)
60+
example: 30
61+
```
62+
63+
**Changes:**
64+
- Removed `required: [command]` - command is optional, defaults to `["/bin/sh"]`
65+
- Changed `tty` default from `true` to `false` to match actual implementation
66+
- Added `env` field for environment variables
67+
- Added `cwd` field for working directory
68+
- Added `timeout` field for command timeout
69+
70+
#### /instances/{id}/exec Endpoint (lines 794-832)
71+
**Before:**
72+
```yaml
73+
/instances/{id}/exec:
74+
post:
75+
summary: Execute command in instance via vsock (WebSocket)
76+
operationId: execInstance
77+
security:
78+
- bearerAuth: []
79+
parameters:
80+
- name: id
81+
in: path
82+
required: true
83+
schema:
84+
type: string
85+
- name: command
86+
in: query
87+
required: false
88+
schema:
89+
type: array
90+
items:
91+
type: string
92+
description: Command to execute (defaults to /bin/sh)
93+
- name: tty
94+
in: query
95+
required: false
96+
schema:
97+
type: boolean
98+
default: true
99+
description: Allocate a pseudo-TTY
100+
responses:
101+
101:
102+
description: Switching to WebSocket protocol
103+
...
104+
```
105+
106+
**After:**
107+
```yaml
108+
/instances/{id}/exec:
109+
post:
110+
summary: Execute command in instance via vsock (WebSocket)
111+
description: |
112+
Upgrades the connection to WebSocket protocol for bidirectional streaming.
113+
After the WebSocket connection is established, the client must send an ExecRequest
114+
JSON message as the first message. Subsequent messages are binary data for stdin/stdout/stderr.
115+
The server sends a final JSON message with the exit code before closing the connection.
116+
operationId: execInstance
117+
security:
118+
- bearerAuth: []
119+
parameters:
120+
- name: id
121+
in: path
122+
required: true
123+
schema:
124+
type: string
125+
description: Instance identifier
126+
responses:
127+
101:
128+
description: Switching to WebSocket protocol
129+
...
130+
```
131+
132+
**Changes:**
133+
- Removed `command` and `tty` query parameters
134+
- Added comprehensive description of WebSocket protocol
135+
- Added description to `id` parameter
136+
137+
### 2. lib/oapi/oapi.go (Generated Code)
138+
139+
#### Added ExecRequest Type (lines 273-289)
140+
```go
141+
// ExecRequest defines the JSON message sent over WebSocket for exec requests.
142+
type ExecRequest struct {
143+
// Command Command and arguments to execute (defaults to ["/bin/sh"])
144+
Command []string `json:"command,omitempty"`
145+
146+
// Cwd Working directory for the command
147+
Cwd *string `json:"cwd,omitempty"`
148+
149+
// Env Additional environment variables
150+
Env *map[string]string `json:"env,omitempty"`
151+
152+
// Timeout Timeout in seconds (0 means no timeout)
153+
Timeout *int32 `json:"timeout,omitempty"`
154+
155+
// Tty Allocate a pseudo-TTY
156+
Tty *bool `json:"tty,omitempty"`
157+
}
158+
```
159+
160+
#### Updated ExecInstanceParams (lines 291-293)
161+
**Before:**
162+
```go
163+
type ExecInstanceParams struct {
164+
Command *[]string `form:"command,omitempty" json:"command,omitempty"`
165+
Tty *bool `form:"tty,omitempty" json:"tty,omitempty"`
166+
}
167+
```
168+
169+
**After:**
170+
```go
171+
type ExecInstanceParams struct {
172+
}
173+
```
174+
175+
#### Updated ServerInterfaceWrapper.ExecInstance (around line 3440)
176+
**Removed:**
177+
- Query parameter binding code for `command`
178+
- Query parameter binding code for `tty`
179+
180+
**Result:** Function now only handles path parameter binding, no query parameters.
181+
182+
#### Updated NewExecInstanceRequest (around line 1049)
183+
**Removed:**
184+
- Query parameter encoding logic for `command` and `tty`
185+
186+
**Result:** Function now only encodes path parameters, creates clean POST request without query string.
187+
188+
## Why These Changes Were Needed
189+
190+
The OpenAPI specification did not match the actual implementation:
191+
192+
### Implementation Reality (cmd/api/api/exec.go)
193+
- Uses WebSocket protocol for bidirectional streaming
194+
- Expects ExecRequest JSON as first WebSocket message
195+
- Supports fields: command, tty, env, cwd, timeout
196+
- Default values: command=["/bin/sh"], tty=false
197+
198+
### Previous Spec Issues
199+
- Defined command and tty as query parameters
200+
- Missing env, cwd, timeout fields
201+
- Wrong default for tty (true vs false)
202+
- No documentation of WebSocket protocol
203+
204+
## Verification Required
205+
206+
Due to shell environment issues, the following commands could not be executed but MUST be run:
207+
208+
### 1. Regenerate OpenAPI Code
209+
```bash
210+
cd /workspace/repo-76e8dc9d-020e-4ec1-93c2-ad0a593aa1a6
211+
make oapi-generate
212+
```
213+
214+
This will regenerate the embedded OpenAPI spec in `lib/oapi/oapi.go`. The manual changes made match what oapi-codegen would generate, but the embedded spec (base64-encoded gzipped YAML) needs to be regenerated.
215+
216+
### 2. Build the Project
217+
```bash
218+
make build
219+
```
220+
221+
Expected: Build should succeed without errors.
222+
223+
### 3. Run Tests
224+
```bash
225+
make test
226+
```
227+
228+
Expected: All tests should pass, especially `TestExecInstanceNonTTY` in `cmd/api/api/exec_test.go`.
229+
230+
## Implementation Compatibility
231+
232+
The actual implementation in `cmd/api/api/exec.go` is unchanged and was already correct:
233+
- Uses gorilla/websocket for WebSocket handling
234+
- Reads ExecRequest JSON from first WebSocket message
235+
- Properly handles all fields (command, tty, env, cwd, timeout)
236+
- Streams stdin/stdout/stderr over WebSocket binary messages
237+
- Sends exit code in final JSON message
238+
239+
## Additional Files Created
240+
241+
1. `OPENAPI_EXEC_UPDATE.md` - Detailed documentation of changes
242+
2. `VERIFICATION_STEPS.md` - Step-by-step verification instructions
243+
3. `CHANGES_SUMMARY.md` - This file
244+
4. `regenerate.sh` - Script to regenerate OpenAPI code
245+
5. `run_build.go` - Go program to run build commands
246+
6. `run_make.py` - Python script to run make commands
247+
248+
## Next Steps for Maintainer
249+
250+
1. Review the changes in `openapi.yaml` and `lib/oapi/oapi.go`
251+
2. Run `make oapi-generate` to regenerate the embedded spec
252+
3. Run `make build` to ensure build succeeds
253+
4. Run `make test` to ensure all tests pass
254+
5. Commit the changes with message: "Update OpenAPI spec for exec endpoint to match WebSocket implementation"
255+
6. Consider adding WebSocket protocol documentation to README or API docs
256+
257+
## Technical Notes
258+
259+
- The ExecRequest type is now defined in both `lib/oapi/oapi.go` (generated) and `cmd/api/api/exec.go` (implementation)
260+
- The implementation uses its own ExecRequest type with slightly different field names (TTY vs Tty)
261+
- This is acceptable as they serve different purposes (API spec vs internal implementation)
262+
- The WebSocket protocol is not fully expressible in OpenAPI 3.x, so the description field documents the protocol flow
263+
264+
## Status
265+
266+
✅ OpenAPI spec updated in `openapi.yaml`
267+
✅ Generated code manually updated in `lib/oapi/oapi.go`
268+
⏳ Embedded spec regeneration pending (requires `make oapi-generate`)
269+
⏳ Build verification pending (requires `make build`)
270+
⏳ Test verification pending (requires `make test`)
271+
272+
## Shell Environment Issue
273+
274+
Note: A shell environment issue prevented running make commands during this update. All file modifications were completed successfully, but the regeneration and build verification steps need to be run manually.

0 commit comments

Comments
 (0)