bug: POST/PUT bodies are silently truncated at the first space
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 67/100
Research direction
Start with build_request_parts in git_api/cli.py and trace how the REPL passes the raw command line through shlex.split; read tests/test_cli.py, especially test_repl_post_substitutes_variables_in_body. Add coverage for JSON and space-separated bodies, then verify the body arrives intact, including quotes and all text after the URL.
Written by the indexing model from the issue text.
Description
Summary
GET/POST/PUT bodies are taken from parts[2] only, so any body containing a space is silently truncated — everything after the first space is dropped. shlex.split() has already shredded the rest, and for JSON bodies it also strips every " quote character, so the API receives a body that is not the JSON the user typed.
Steps to reproduce
Start the REPL in an empty directory, set a base_url, then send a normal JSON body:
mkdir /tmp/gapi-demo && cd /tmp/gapi-demo
git init -q
git-api
Inside the REPL:
var base_url=http://127.0.0.1:8000
POST /users {"name":"Yunare Maia","active":true}
The request never needs to be a real API — build_request_parts produces the body before any socket is opened, so this reproduces with no server at all.
Actual output
Direct call against the real code:
input line : POST /users {"name":"Yunare Maia","active":true}
shlex.split: ['POST', '/users', '{name:Yunare Maia,active:true}']
url : https://api.example.com/users
body sent : '{name:Yunare Maia,active:true}'
expected body: '{"name":"Yunare Maia","active":true}'
TRUNCATED? True
The truncation is worse for bodies where the space-separated tokens do not happen to be inside quotes:
line : POST /users {"a": 1, "b": 2}
parts : ['POST', '/users', '{a:', '1,', 'b:', '2}']
BODY : '{a:'
rest after parts[2] DROPPED: ['1,', 'b:', '2}']
line : PUT /users/1 name=Yunare role=admin
parts : ['PUT', '/users/1', 'name=Yunare', 'role=admin']
BODY : 'name=Yunare'
rest after parts[2] DROPPED: ['role=admin']
End-to-end through the real REPL binary, with a local server echoing back the exact bytes it received:
========== REPL stdout (verbatim) ==========
🌿 Git-API REPL 0.1.0
Type 'help' for commands, 'quit' to exit.
default> Set base_url = http://127.0.0.1:39881
default>
→ POST http://127.0.0.1:39881/users
← 200
{
"ok": true
}
(use 'save post--users' to save)
default> Bye.
--- exit code: 0 ---
========== SERVER RECEIVED ==========
[
{
"method": "POST",
"path": "/users",
"body": "{name:Yunare Maia,active:true}"
}
]
The server received {name:Yunare Maia,active:true}. The " characters are gone and the payload is not valid JSON — yet the REPL printed a green ← 200 and gave no warning that anything was dropped.
Expected output
The body should arrive exactly as typed. Two things need fixing:
-
Everything after the URL is the body, not just the third token:
raw_body = " ".join(parts[2:]) if len(parts) > 2 else None -
A JSON body must survive shell-style quote stripping.
shlex.splittreats"as a quoting character, so{"name":"x"}loses them. Either parse the body out of the raw line beforeshlex.split(e.g. split on the first two whitespace runs), or read JSON bodies from a variable / saved request.
Worth noting that PUT /users/1 name=Yunare role=admin losing role=admin is the more dangerous variant of this bug: the request still succeeds, and the field that silently vanished is the one the user cared about.
Root cause
git_api/cli.py:140
raw_body = parts[2] if len(parts) > 2 else None
parts is the output of shlex.split(line) (cli.py:323). shlex.split tokenises on whitespace and strips quotes, so a body with spaces becomes many tokens and parts[2] keeps only the first. parts[3:] is never read, so the remainder is discarded without any diagnostic.
The help text at cli.py:249-250 advertises POST <url> [body], which implies the body is the rest of the line, and README.md shows POST as a first-class command — so this is the documented path, not an edge case.
There is no test covering a multi-token body. tests/test_cli.py:397 (test_repl_post_substitutes_variables_in_body) uses a single-token body, which is why the suite passes.
Suggested fix
--- a/git_api/cli.py
+++ b/git_api/cli.py
@@ def build_request_parts(parts: list[str], env: dict):
url = resolve_url(parts[1], env)
- raw_body = parts[2] if len(parts) > 2 else None
+ # The body is the rest of the line, not just the third token.
+ raw_body = " ".join(parts[2:]) if len(parts) > 2 else None
Note this alone still loses the " characters, because shlex.split has already removed them. The complete fix needs the body extracted from the raw line, e.g.:
import re
_BODY_SPLIT = re.compile(r"\S+\s+\S+(?:\s+(.*))?\s*$")
def split_command(line: str) -> list[str]:
"""Split into command + url + the untouched remainder as the body."""
parts = shlex.split(line)
if len(parts) > 2:
m = _BODY_SPLIT.match(line)
parts[2:] = [m.group(1)] if m and m.group(1) else []
return parts
Related
- Related to the
{{base_url}}double-prefix defect: samebuild_request_partsfunction, same parse-then-resolve ordering. - #34 (closed) hardened
execute_requestagainst bad input, but nothing guards body parsing.
- Dominant language
- Python
- Stars
- 0
- Forks
- 1
- PR merge metrics
- No merged PRs in 30d
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
pydantic/pydantic-ai#12091 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Maintainers usually reply within 1 day
-
CSS enhancement good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
pychess/pychess-variants#2448 ·
Maintainers usually reply within 1 day
-
Bump locked PyTensor so Apple clang 21 does not pass -ld64Possibly taken @drbenvincent claimed this today. Openbug dev ops
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 2 days
-
ai_p2 bug comp-datalake
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
ClickHouse/ClickHouse#128306 · 1 comment ·
Maintainers usually reply within 1 day