Skip to content

fix(cli): reject non-success HTTP responses - #903

Open
andriypolanski wants to merge 2 commits into
GeniePod:mainfrom
andriypolanski:fix/cli-http-status-handling
Open

fix(cli): reject non-success HTTP responses#903
andriypolanski wants to merge 2 commits into
GeniePod:mainfrom
andriypolanski:fix/cli-http-status-handling

Conversation

@andriypolanski

@andriypolanski andriypolanski commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

The genie-ctl HTTP helper discarded the HTTP status line and returned every
response body as Ok. A 403, 404, or 500 therefore looked like a
successful request to callers. For example, an authentication error from the
conversation-history endpoint could be parsed as an empty result and displayed
as “no messages yet,” while diagnostics could report a service as up merely
because it returned an HTTP response.

Parse CLI responses with the shared bounded HTTP parser and reject non-2xx
statuses with the status code and server-provided error detail.

Changes

  • Replace the status-blind line reader with genie_common::http::read_response.
  • Apply an 8 MiB response-body ceiling to CLI HTTP requests.
  • Return an error for every non-2xx response.
  • Preserve useful response detail in CLI error messages.
  • Add socket-level regression tests for successful and forbidden responses.

Real Behavior Proof

  • I have built and run the affected code locally.
  • I have verified the change end-to-end on Jetson hardware.
  • I have NOT verified on Jetson hardware, and I explain the validation gap
    below.

Tested profile / hardware:

  • jetson
  • raspberry_pi
  • portable_sbc
  • laptop
  • mac
  • CI-only / docs-only
  • Not run locally

What I ran

git diff --check

What I observed

  • git diff --check passes.
  • Rust tests were not run because this environment does not provide cargo.

Test Plan

  • Run cargo fmt --all -- --check.
  • Run cargo test -p genie-ctl http_get.
  • Verify a 200 response returns its body unchanged.
  • Verify a 403 response returns an error containing HTTP 403 and the
    server response detail.
  • Verify 404 and 500 responses cause CLI commands to exit with errors.
  • Verify chunked responses are decoded by the shared parser.
  • Verify an oversized response is rejected at the configured body limit.

Notes for Reviewers

  • The success-body behavior remains trimmed for compatibility with existing
    CLI callers.
  • Both GET and POST helpers use the corrected response path.
  • No server route or authentication policy changes are included.

Summary by CodeRabbit

  • Bug Fixes
    • Improved HTTP response handling in the command-line tool by using a standardized response reader.
    • Added a hard cap on maximum response body size to improve safety.
    • Enhanced non-success error messages to include the HTTP status and trimmed response body details.
    • Improved successful response processing to reliably return the response body content.
  • Tests
    • Added Tokio-based HTTP tests with a local TCP server helper to verify 200 responses and non-2xx error details.

@github-actions github-actions Bot added the bug Something isn't working label Jul 30, 2026
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 72b01b4d-737a-44d9-ae48-ca82fccf7f4b

📥 Commits

Reviewing files that changed from the base of the PR and between 64ba58b and 518a96f.

📒 Files selected for processing (1)
  • crates/genie-ctl/src/main.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/genie-ctl/src/main.rs

📝 Walkthrough

Walkthrough

genie-ctl now uses bounded shared HTTP response parsing, accepts only 2xx responses, reports non-2xx body details, and adds tests covering successful and failed HTTP requests.

Changes

HTTP response handling

Layer / File(s) Summary
Bounded HTTP response parsing
crates/genie-ctl/src/main.rs
Uses read_response with an 8 MiB limit, returns trimmed successful bodies, and reports non-2xx statuses with response details.
HTTP response handling tests
crates/genie-ctl/src/main.rs
Adds a local TCP response server and Tokio tests for 200 responses and non-2xx errors.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested labels: bug

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: CLI HTTP handling now rejects non-2xx responses.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/genie-ctl/src/main.rs`:
- Around line 2894-2899: Sanitize the server-provided detail in the non-success
response handling before passing it to anyhow::bail!. Update the response.body
processing in the visible status-check block to remove carriage returns and ANSI
escape sequences, while preserving the existing trimming, empty-detail fallback,
and HTTP status formatting behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 115d3ec4-91fc-4e7a-b5c8-c211cd4e3ce0

📥 Commits

Reviewing files that changed from the base of the PR and between 02a577d and 64ba58b.

📒 Files selected for processing (1)
  • crates/genie-ctl/src/main.rs

Comment on lines +2894 to +2899
if !(200..300).contains(&response.status) {
let detail = response.body.trim().replace('\n', " ");
if detail.is_empty() {
anyhow::bail!("HTTP {}", response.status);
}
anyhow::bail!("HTTP {}: {}", response.status, detail);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Sanitize server-provided error text before formatting it.

Replacing only \n leaves embedded \r and ANSI escape sequences intact. A responding server can therefore forge or manipulate terminal/log output through the CLI diagnostic.

Proposed fix
-        let detail = response.body.trim().replace('\n', " ");
+        let detail = response
+            .body
+            .chars()
+            .map(|ch| if ch.is_control() { ' ' } else { ch })
+            .collect::<String>()
+            .split_whitespace()
+            .collect::<Vec<_>>()
+            .join(" ");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if !(200..300).contains(&response.status) {
let detail = response.body.trim().replace('\n', " ");
if detail.is_empty() {
anyhow::bail!("HTTP {}", response.status);
}
anyhow::bail!("HTTP {}: {}", response.status, detail);
if !(200..300).contains(&response.status) {
let detail = response
.body
.chars()
.map(|ch| if ch.is_control() { ' ' } else { ch })
.collect::<String>()
.split_whitespace()
.collect::<Vec<_>>()
.join(" ");
if detail.is_empty() {
anyhow::bail!("HTTP {}", response.status);
}
anyhow::bail!("HTTP {}: {}", response.status, detail);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/genie-ctl/src/main.rs` around lines 2894 - 2899, Sanitize the
server-provided detail in the non-success response handling before passing it to
anyhow::bail!. Update the response.body processing in the visible status-check
block to remove carriage returns and ANSI escape sequences, while preserving the
existing trimming, empty-detail fallback, and HTTP status formatting behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant