Skip to content

Commit a9ee483

Browse files
committed
Remove legacy endpoints
1 parent 50b0719 commit a9ee483

File tree

2 files changed

+0
-155
lines changed

2 files changed

+0
-155
lines changed

lib/tidewave/middleware.rb

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# frozen_string_literal: true
22

3-
require "open3"
43
require "ipaddr"
54
require "fast_mcp"
65
require "rack/request"
@@ -13,7 +12,6 @@
1312
class Tidewave::Middleware
1413
TIDEWAVE_ROUTE = "tidewave".freeze
1514
MCP_ROUTE = "mcp".freeze
16-
SHELL_ROUTE = "shell".freeze
1715
CONFIG_ROUTE = "config".freeze
1816

1917
INVALID_IP = <<~TEXT.freeze
@@ -64,8 +62,6 @@ def call(env)
6462
return home(request)
6563
when [ "GET", [ TIDEWAVE_ROUTE, CONFIG_ROUTE ] ]
6664
return config_endpoint(request)
67-
when [ "POST", [ TIDEWAVE_ROUTE, SHELL_ROUTE ] ]
68-
return shell(request)
6965
end
7066
end
7167

@@ -88,7 +84,6 @@ def home(request)
8884
<head>
8985
<meta charset="UTF-8" />
9086
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
91-
<meta name="tidewave:config" content="#{ERB::Util.html_escape(JSON.generate(config))}" />
9287
<script type="module" src="#{@client_url}/tc/tc.js"></script>
9388
</head>
9489
<body></body>
@@ -116,66 +111,6 @@ def forbidden(message)
116111
[ 403, { "Content-Type" => "text/plain" }, [ message ] ]
117112
end
118113

119-
def shell(request)
120-
body = request.body.read
121-
return [ 400, { "Content-Type" => "text/plain" }, [ "Command body is required" ] ] if body.blank?
122-
123-
begin
124-
parsed_body = JSON.parse(body)
125-
cmd = parsed_body["command"]
126-
return [ 400, { "Content-Type" => "text/plain" }, [ "Command field is required" ] ] if cmd.blank?
127-
rescue JSON::ParserError
128-
return [ 400, { "Content-Type" => "text/plain" }, [ "Invalid JSON in request body" ] ]
129-
end
130-
131-
response = Rack::Response.new
132-
response.status = 200
133-
response.headers["Content-Type"] = "text/plain"
134-
135-
response.finish do |res|
136-
begin
137-
Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thr|
138-
stdin.close
139-
140-
# Merge stdout and stderr streams
141-
ios = [ stdout, stderr ]
142-
143-
until ios.empty?
144-
ready = IO.select(ios, nil, nil, 0.1)
145-
next unless ready
146-
147-
ready[0].each do |io|
148-
begin
149-
data = io.read_nonblock(4096)
150-
if data
151-
# Write binary chunk: type (0 for data) + 4-byte length + data
152-
chunk = [ 0, data.bytesize ].pack("CN") + data
153-
res.write(chunk)
154-
end
155-
rescue IO::WaitReadable
156-
# No data available right now
157-
rescue EOFError
158-
# Stream ended
159-
ios.delete(io)
160-
end
161-
end
162-
end
163-
164-
# Wait for process to complete and get exit status
165-
exit_status = wait_thr.value.exitstatus
166-
status_json = JSON.generate({ status: exit_status })
167-
# Write binary chunk: type (1 for status) + 4-byte length + JSON data
168-
chunk = [ 1, status_json.bytesize ].pack("CN") + status_json
169-
res.write(chunk)
170-
end
171-
rescue => e
172-
error_json = JSON.generate({ status: 213 })
173-
chunk = [ 1, error_json.bytesize ].pack("CN") + error_json
174-
res.write(chunk)
175-
end
176-
end
177-
end
178-
179114
def valid_client_ip?(request)
180115
return true if @allow_remote_access
181116

spec/middleware_spec.rb

Lines changed: 0 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -166,96 +166,6 @@ def app
166166
end
167167
end
168168

169-
describe "/tidewave/shell" do
170-
def parse_binary_response(body)
171-
chunks = []
172-
offset = 0
173-
174-
while offset < body.bytesize
175-
type = body.getbyte(offset)
176-
length = body[offset + 1, 4].unpack1("N")
177-
data = body[offset + 5, length]
178-
chunks << { type: type, data: data }
179-
offset += 5 + length
180-
end
181-
182-
chunks
183-
end
184-
185-
it "executes simple command and returns output with status" do
186-
body = { command: "echo 'hello world'" }
187-
post "/tidewave/shell", JSON.generate(body)
188-
expect(last_response.status).to eq(200)
189-
190-
chunks = parse_binary_response(last_response.body)
191-
expect(chunks.length).to eq(2)
192-
193-
# First chunk should be stdout data
194-
expect(chunks[0][:type]).to eq(0)
195-
expect(chunks[0][:data]).to eq("hello world\n")
196-
197-
# Second chunk should be status
198-
expect(chunks[1][:type]).to eq(1)
199-
status_data = JSON.parse(chunks[1][:data])
200-
expect(status_data["status"]).to eq(0)
201-
end
202-
203-
it "handles command with non-zero exit status" do
204-
body = { command: "exit 42" }
205-
post "/tidewave/shell", JSON.generate(body)
206-
expect(last_response.status).to eq(200)
207-
208-
chunks = parse_binary_response(last_response.body)
209-
expect(chunks.length).to eq(1)
210-
211-
# Should only have status chunk
212-
expect(chunks[0][:type]).to eq(1)
213-
status_data = JSON.parse(chunks[0][:data])
214-
expect(status_data["status"]).to eq(42)
215-
end
216-
217-
it "handles multiline commands" do
218-
body = {
219-
command: "echo 'line 1'\necho 'line 2'"
220-
}
221-
post "/tidewave/shell", JSON.generate(body)
222-
expect(last_response.status).to eq(200)
223-
224-
chunks = parse_binary_response(last_response.body)
225-
226-
# The shell command outputs both lines together
227-
expect(chunks.length).to eq(2)
228-
229-
# First chunk should be stdout data with both lines
230-
expect(chunks[0][:type]).to eq(0)
231-
expect(chunks[0][:data]).to eq("line 1\nline 2\n")
232-
233-
# Second chunk should be status
234-
expect(chunks[1][:type]).to eq(1)
235-
status_data = JSON.parse(chunks[1][:data])
236-
expect(status_data["status"]).to eq(0)
237-
end
238-
239-
it "returns 400 for empty command body" do
240-
post "/tidewave/shell", ""
241-
expect(last_response.status).to eq(400)
242-
expect(last_response.body).to include("Command body is required")
243-
end
244-
245-
it "returns 400 for invalid JSON" do
246-
post "/tidewave/shell", "not json"
247-
expect(last_response.status).to eq(400)
248-
expect(last_response.body).to include("Invalid JSON in request body")
249-
end
250-
251-
it "returns 400 for missing command field" do
252-
body = { other_field: "value" }
253-
post "/tidewave/shell", JSON.generate(body)
254-
expect(last_response.status).to eq(400)
255-
expect(last_response.body).to include("Command field is required")
256-
end
257-
end
258-
259169
describe "edge cases" do
260170
it "handles trailing slashes" do
261171
get "/tidewave/"

0 commit comments

Comments
 (0)