Repo X-ray

sample-service: architecture & health

Two endpoints, five tests, one bug found by running them.

Source: data/sample-service/ — caap-devops-rca-agent wasn't reachable from this session within the two-minute window, so this run uses the bundled fallback, as the brief allows.

Plan

  1. Shows: the module/endpoint map, a live pass/fail test summary, the three ranked risks with evidence, and the fix for the worst one as a diff.
  2. Data: the actual pytest run captured below (4 passed, 1 failed) plus direct probes of the running code with bad, empty, huge, and malformed input — nothing invented.
  3. Interaction: click a risk to expand its evidence; the fix is shown as a diff block underneath the top risk.

Modules

app/main.py
The entire service: a FastAPI app, an in-memory ORDERS dict, one pricing function, two routes. No other modules, no persistence layer, no auth.
34 lines · owns: routing, pricing math, the in-memory data store
tests/test_orders.py
5 tests over a TestClient: order lookup (found/missing), line-item totals (two lines, empty), and one account rollup.
5 tests · owns: endpoint + pricing verification

Endpoints

MethodPathInputOutput
GET /orders/{order_id} path param order_id (e.g. A-1001) 200: order + computed total · 404 {"detail":"order not found"} if unknown
GET /accounts/{account}/total path param account (e.g. Account A) 200: account, order count, summed total · 404 if no orders match

Test summary

5
tests collected
4
passed
1
failed
FAILED test_orders.py::test_total_two_lines
assert order_total(ORDERS["A-1002"]) == 10 * 45.0 + 1 * 1200.0
AssertionError: assert 1256.0 == ((10 * 45.0) + (1 * 1200.0))
  where 1256.0 = order_total(A-1002)   # expected 1650.0

Top 3 risks

01 Critical Line totals sum qty + unit instead of qty × unit app/main.py:17

Every total returned by both endpoints is wrong. order_total() adds quantity and unit price instead of multiplying them, so the error compounds with scale — it is not a rounding issue, it is the wrong formula.

# confirmed by the failing test, then reproduced directly: order_total(ORDERS["A-1002"]) -> 1256.0 (expected 1650.0) # and at scale, a 100,000-line order: computed total -> 199,999,000.0 correct total -> 99,999,000,000.0 (500,000x understated)

Proposed fix — the smallest change that fixes it, verified against the failing test:

def order_total(order: dict) -> float:
total = 0.0
for line in order["lines"]:
- total += line["qty"] + line["unit"]
+ total += line["qty"] * line["unit"]
return round(total, 2)
02 Serious A malformed line crashes the endpoint with a raw 500, not a clean 4xx app/main.py:17, 22–26

order_total() reads line["qty"] and line["unit"] with no validation. Neither endpoint wraps the call, so any order whose line is missing a key throws an unhandled KeyError straight through FastAPI as an unhandled 500.

# a line with no "unit" key: order_total({"id": "BAD-1", "lines": [{"sku": "X", "qty": 2}]}) -> KeyError: 'unit' # surfaces to the caller as an unhandled 500

There is no schema validation on line items and no try/except at the call site — any bad upstream write (or a future write endpoint) takes the service down per request instead of failing one bad record cleanly.

03 Warning No authorization — any caller can read any account's orders and totals app/main.py (whole file)

The API models two separate accounts (Account A, Account B) but has no auth dependency anywhere. Both routes are open: any caller who can reach the service, or guess/enumerate an order id, can read another account's order lines and revenue.

# no credentials supplied, both accounts fully readable: GET /orders/A-1001 -> 200, Account A's order, no auth check GET /accounts/Account B/total -> 200, Account B's total, no auth check

Fine for a single-tenant lab demo; a real cross-tenant deployment needs a per-account auth check before this ships.

Attacked with bad, empty, and huge input

Bad order id
GET /orders/nope → clean 404, {"detail":"order not found"}. Handled correctly.
Empty order
B-2001 has zero lines → total: 0.0, no divide-by-zero or loop error. Handled correctly.
Huge order (100,000 lines)
Ran in 3ms — performance is fine — but the qty+unit bug means the total is 500,000× too low at this scale. Same root cause as risk 01.
Malformed line (missing key)
Throws an unhandled KeyError rather than a 4xx. This is risk 02, reproduced directly against the code.
One thing to check by hand

Confirm the two numbers in the top risk yourself: run pytest -q in data/sample-service/ and check that test_total_two_lines is the one test that fails, with the same 1256.0-vs-1650.0 mismatch shown above. If that matches, the rest of this page traces to the same run.