sample-service — Repo X-ray

Architecture & health snapshot of data/sample-service/, generated by reading the code and running its tests.
No real repo was reachable from this session (no code system connected), so this run used the bundled sample as the brief allows. Every number below comes from app/main.py, tests/test_orders.py, and an actual pytest -q run — nothing here is invented.

Modules

app/main.py

The whole service: a FastAPI app, a hardcoded 3-order in-memory store, one helper (order_total), and both endpoints. 34 lines.

app/__init__.py

Empty. Makes app importable as a package.

tests/test_orders.py

5 tests against a FastAPI TestClient. Covers both endpoints' happy paths and one 404.

Endpoints

GET/orders/{order_id}

Input

  • order_id — path string, e.g. A-1001

Output

  • 200 order object plus computed total
  • 404 {"detail": "order not found"}
GET/accounts/{account}/total

Input

  • account — path string, e.g. Account A (exact match, case-sensitive)

Output

  • 200 {account, orders: count, total}
  • 404 {"detail": "account not found"}

Test summary

5
passed
0
failed
test_get_order_okGET /orders/A-1001 → 200, id matches
test_get_order_missingGET /orders/nope → 404
test_total_two_linesorder_total() on a 2-line order
test_empty_order_total_is_zeroorder_total() on a 0-line order
test_account_totalGET /accounts/Account A/total → 200, count matches
The sample's README claims one test fails; it doesn't, right now. app/main.py's file timestamp is newer than the rest of the kit, which points to the seeded bug already having been fixed in an earlier pass over this same folder. Rather than fabricate a failure to match the README, this run reports what actually happened: 5/5 green.

Two real coverage gaps, though: no test ever hits the missing-account 404 path on /accounts/{account}/total, and the order test only checks id — it never asserts the computed total in the response body.

Top three risks

1
No authentication on either endpoint
app/main.py:21, :29

Anyone who can reach the service reads every order's line items and every account's running total. Nothing scopes a caller to their own account, and there's no key, token, or session check anywhere in the file. Worst of the three because it's a live data-exposure path, not a latent one.

Proposed fix (draft — not applied)
 from fastapi import FastAPI, HTTPException
+from fastapi import FastAPI, HTTPException, Header, Depends
+import hmac
+import os
+
+API_KEY = os.environ.get("SAMPLE_SERVICE_API_KEY", "")
+
+def require_api_key(x_api_key: str = Header(default="")):
+    if not API_KEY or not hmac.compare_digest(x_api_key, API_KEY):
+        raise HTTPException(status_code=401, detail="missing or invalid API key")

 app = FastAPI(title="sample-service")
 ...
-@app.get("/orders/{order_id}")
+@app.get("/orders/{order_id}", dependencies=[Depends(require_api_key)])
 def get_order(order_id: str):
 ...
-@app.get("/accounts/{account}/total")
+@app.get("/accounts/{account}/total", dependencies=[Depends(require_api_key)])
 def account_total(account: str):
2
Money math in floating point
app/main.py:17

total += line["qty"] * line["unit"] accumulates in a plain float. Repeated addition can drift for prices that aren't exact binary fractions (like $19.99), and the closing round(total, 2) on the next line only rounds the final, already-drifted sum — it doesn't prevent the drift. The current fixture prices (1200.0, 45.0) are exact in binary, so no test exposes this; it would show up the first time someone adds a real-world price.

3
Ambiguous 404 on account lookup
app/main.py:32-33

A typo'd account name and a real account that happens to have zero orders return the identical "account not found". Today the store never empties, so this can't happen yet — but the moment orders become deletable, a caller can no longer tell "this account doesn't exist" from "this account has nothing right now" without extra lookups.

Attack testing

Ran bad, empty, and huge input against the live app (not just this page) with TestClient. Bad — SQL-like strings, path traversal (../../etc/passwd), emoji, wrong-case and space-padded account names: all correctly 404 through the app's own handler; it's a dict lookup, not a query, so there's no injection surface. Empty — a blank order_id or account 404s at the routing layer before app code runs. Huge — a 100,000-character order_id/account: the HTTP client itself refused to build a request that long ("URL too long"), and in production a reverse proxy or the ASGI server's own max-URL-length limit sits in front of this route before app code ever sees it; even if one got through, the lookup is against a 3-entry dict, so a long key costs nothing extra. No bug found in the app under any of the three.

What I did find and fix was in this page: the risk cards used a JS-only accordion with a hardcoded 700px cap, which would go blank with JavaScript off and could clip a longer diff. Both are now native <details> elements — open with a click, a tap, or the keyboard, work with zero JavaScript, and can't overflow.