Skip to content

fix(security): require JSON Content-Type on mutating routes#357

Open
kevinnft wants to merge 1 commit into
Quantarq:mainfrom
kevinnft:fix/require-json-content-type
Open

fix(security): require JSON Content-Type on mutating routes#357
kevinnft wants to merge 1 commit into
Quantarq:mainfrom
kevinnft:fix/require-json-content-type

Conversation

@kevinnft

Copy link
Copy Markdown

Summary

Closes #205.

Adds RequireJsonContentTypeMiddleware so mutating routes reject non-JSON bodies with HTTP 415 and an Accept: application/json hint. Default prefixes cover /api/add-extra-deposit/* and /api/save-bug-report. GET/health and non-listed paths are unchanged.

Changes

  • quantara/web_app/api/middleware.py: new middleware + prefix config
  • quantara/web_app/api/main.py: register middleware
  • quantara/web_app/tests/test_middleware_content_type.py: 415 vs JSON vs GET coverage

Test plan

  • pytest tests/test_middleware_content_type.py → 7 passed
  • POST text/plain → 415
  • POST application/json → 200
  • GET /health → 200
  • CI full suite

Add RequireJsonContentTypeMiddleware that rejects non-JSON bodies on
/api/add-extra-deposit/* and /api/save-bug-report with 415 + Accept
hint. GET/health and non-listed paths are unchanged.

Closes Quantarq#205

Signed-off-by: NossXBT <kevinnft@users.noreply.github.com>
if state is not None and not isinstance(state, dict):
try:
state.is_mutating = is_mutating
except Exception:
content=b"not-json",
headers={"Content-Type": "text/plain"},
)
assert response.status_code == 415
)
assert response.status_code == 415
body = response.json()
assert "application/json" in body.get("accept", "")
assert response.status_code == 415
body = response.json()
assert "application/json" in body.get("accept", "")
assert response.headers.get("accept") == "application/json"
"/api/save-bug-report",
json={"title": "x", "body": "y"},
)
assert response.status_code == 200
def test_get_health_never_triggers_check(client):
response = client.get("/health")
assert response.status_code == 200
assert response.json() == {"ok": True}
content=b"anything",
headers={"Content-Type": "text/plain"},
)
assert response.status_code == 200
headers={"Content-Type": "text/plain"},
)
assert response.status_code == 200
assert response.json() == {"other": True}


def test_default_prefixes_cover_issue_targets():
assert any(p.startswith("/api/add-extra-deposit") for p in DEFAULT_MUTATING_PATH_PREFIXES)

def test_default_prefixes_cover_issue_targets():
assert any(p.startswith("/api/add-extra-deposit") for p in DEFAULT_MUTATING_PATH_PREFIXES)
assert "/api/save-bug-report" in DEFAULT_MUTATING_PATH_PREFIXES
if state is not None and not isinstance(state, dict):
try:
state.is_mutating = is_mutating
except Exception:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Universal RequireJsonContentTypeMiddleware

2 participants