Skip to content

POST /api/v1/orders accepts and persists an unresolvable quote_id for a valid deal #70

Description

@jaanijuk

POST /api/v1/orders accepts a quote_id that does not resolve to any quote and persists it against a valid deal. The persisted order-level quote_id therefore differs from the quote validated on the deal it references, leaving durable order provenance that is neither resolvable nor consistent with the commercial episode.

The adjacent endpoint in the same chain does resolve its parent: POST /api/v1/deals rejects the same unresolvable quote_id with 404 quote_not_found.

Observed on v2.4.2 (e5b367d) in WSL2 Ubuntu 24.04 and a clean Ubuntu 24.04 container. The underlying container behaviour was also exercised from a freshly initialised datastore with no pre-existing quote, deal or order fixtures. The final read-back-enabled script below was subsequently run unchanged in both environments; its container run used the store as it stood.

The script below is the exact file run in both environments:

sha256 9467ef15c36042160d4801cf1ee18b3ce25d0afc789c1a1a21f5fd9afabd0335

It discovers catalogue inventory rather than relying on environment-specific fixture IDs; the two environments have different catalogues. In WSL2, fixture order responses were byte-identical with no credential and with an operator credential, so the observed order fields are not attributable to credential tiering or response projection.

Reproduction

#!/usr/bin/env bash
# K reproduction — POST /api/v1/orders accepts and persists an unresolvable quote_id
#
# Published reproduction. Prints what the server does and summarises whether the
# behaviour reproduced. Always exits 0: a build that does NOT reproduce is a valid
# and useful result, not a script failure.
#
# Usage: [BASE=host:port] [PRODUCT_ID=xxx] bash repro-k.sh
# Requires: a running seller-agent with a non-empty product catalogue.
# Creates: one quote, one deal, one order, and one rejected deal-booking attempt.

H="Content-Type: application/json"
B="${BASE:-localhost:8001}"
RUN="k-$(date +%Y%m%dT%H%M%S)-$$"

# Discover a product rather than hard-coding a catalogue ID, which is
# environment-specific. Override with PRODUCT_ID if the first product does not
# support a PG quote.
PID="${PRODUCT_ID:-$(curl -fsS "$B/products" | python3 -c '
import json,sys
d=json.load(sys.stdin); p=d.get("products",d)
if not isinstance(p,list) or not p: raise SystemExit("GET /products returned none")
print(p[0]["product_id"])')}"
[ -n "$PID" ] || { echo "SETUP FAILED: no product available"; exit 0; }
echo "product: $PID"

QT=$(curl -fsS -X POST "$B/api/v1/quotes" -H "$H" \
  -d "{\"idempotency_key\":\"$RUN-q\",\"product_id\":\"$PID\",\"deal_type\":\"PG\",\"impressions\":500000,\"target_cpm\":{\"currency\":\"USD\",\"amount_micros\":20000000}}" \
  | python3 -c "import json,sys;print(json.load(sys.stdin)['quote']['quote_id'])")
[ -n "$QT" ] || { echo "SETUP FAILED: no quote created"; exit 0; }
echo "quote:   $QT"

DL=$(curl -fsS -X POST "$B/api/v1/deals" -H "$H" \
  -d "{\"idempotency_key\":\"$RUN-d\",\"quote_id\":\"$QT\"}" \
  | python3 -c "import json,sys;print(json.load(sys.stdin)['deal']['deal_id'])")
[ -n "$DL" ] || { echo "SETUP FAILED: no deal created"; exit 0; }
echo "deal:    $DL"

echo
echo "-- 1. order asserting a quote that does not exist --"
ORDER_CODE=$(curl -sS -X POST "$B/api/v1/orders" -H "$H" \
  -d "{\"deal_id\":\"$DL\",\"quote_id\":\"qt-000000000000\"}" \
  -o /tmp/k-order.json -w "%{http_code}")
export ORDER_CODE
echo "HTTP $ORDER_CODE"
python3 -c "
import json
d=json.load(open('/tmp/k-order.json'))
print('  order_id:          ',d.get('order_id'))
print('  persisted deal_id: ',repr(d.get('deal_id')))
print('  persisted quote_id:',repr(d.get('quote_id')))"

ORDER_ID=$(python3 -c "
import json;print(json.load(open('/tmp/k-order.json')).get('order_id') or '')")
[ -n "$ORDER_ID" ] || { echo "SETUP FAILED: order response had no order_id"; exit 0; }

echo
echo "-- 1b. read the order back --"
curl -fsS "$B/api/v1/orders/$ORDER_ID" -o /tmp/k-order-readback.json
python3 -c "
import json
d=json.load(open('/tmp/k-order-readback.json'))
print('  read-back deal_id: ',repr(d.get('deal_id')))
print('  read-back quote_id:',repr(d.get('quote_id')))"

echo
echo "-- 2. the deal's authoritative quote --"
curl -fsS "$B/api/v1/deals/$DL" -o /tmp/k-deal.json
python3 -c "
import json
d=json.load(open('/tmp/k-deal.json')); d=d.get('deal',d)
print('  validated quote_id:',repr(d.get('quote_id')))"

echo
echo "-- 3. control: the same unresolvable quote at deal booking --"
CTL_CODE=$(curl -sS -X POST "$B/api/v1/deals" -H "$H" \
  -d "{\"idempotency_key\":\"$RUN-ctl\",\"quote_id\":\"qt-000000000000\"}" \
  -o /tmp/k-ctl.json -w "%{http_code}")
export CTL_CODE
echo "HTTP $CTL_CODE"
cat /tmp/k-ctl.json; echo

echo
echo "-- summary --"
python3 - "$DL" "$QT" <<'PYEOF'
import json, os, sys
deal, quote = sys.argv[1], sys.argv[2]
o = json.load(open('/tmp/k-order.json'))
r = json.load(open('/tmp/k-order-readback.json'))
d = json.load(open('/tmp/k-deal.json'))
d = d.get('deal', d)
c = json.load(open('/tmp/k-ctl.json'))
checks = [
    ("order creation returned HTTP 200",          os.environ.get('ORDER_CODE') == '200'),
    ("order was accepted (has order_id)",         bool(o.get('order_id'))),
    ("order persisted deal_id == the real deal",  o.get('deal_id') == deal),
    ("order persisted quote_id qt-000000000000",  o.get('quote_id') == 'qt-000000000000'),
    ("read-back deal_id == the real deal",        r.get('deal_id') == deal),
    ("read-back quote_id unchanged",              r.get('quote_id') == 'qt-000000000000'),
    ("deal's own quote differs from the order's", d.get('quote_id') == quote != 'qt-000000000000'),
    ("deal booking returned HTTP 404",            os.environ.get('CTL_CODE') == '404'),
    ("deal booking refused the same quote",       c.get('detail', {}).get('error') == 'quote_not_found'),
]
for label, ok in checks:
    print(f"  [{'x' if ok else ' '}] {label}")
print()
print("  REPRODUCED:", "yes" if all(v for _, v in checks) else "NO — see unchecked boxes above")
PYEOF
exit 0

Observed

The order returns HTTP 200 and persists quote_id: qt-000000000000. A subsequent GET /api/v1/orders/{order_id} returns the same quote ID and the valid referenced deal ID. GET /api/v1/deals/{deal_id} returns the real quote used to book that deal. The control returns HTTP 404 with detail.error: "quote_not_found".

Separately, omitting quote_id also returns 200 and persists null; the endpoint does not derive the quote reference from the referenced deal.

Not tested: whether the endpoint accepts a different valid quote belonging to another deal.

Distinct from #68, which covers an unresolvable deal_id.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions