Skip to content

fix: 404 an unknown product_id in curated deals, don't fabricate a price - #58

Open
garvitkaushik-123 wants to merge 1 commit into
IABTechLab:mainfrom
garvitkaushik-123:fix/curated-deal-product-not-found
Open

fix: 404 an unknown product_id in curated deals, don't fabricate a price#58
garvitkaushik-123 wants to merge 1 commit into
IABTechLab:mainfrom
garvitkaushik-123:fix/curated-deal-product-not-found

Conversation

@garvitkaushik-123

Copy link
Copy Markdown
Contributor

Summary

Fixes #57. create_curated_deal's comment says "A known-but-unpriced product... is a 422 — never a fabricated price," and the code delivers on that for a product that exists but has no base_cpm/floor_cpm (via catalog_service.priceable_cpm). It didn't deliver on it for a product_id that doesn't exist in the catalog at all: that case skipped price resolution entirely and fell through to the hardcoded $12 CPM default meant only for the no-product_id-supplied case, then minted and persisted a confirmed deal at that fabricated price. No error, anywhere.

POST /api/v1/deals/curated has no auth dependency at all, so this was reachable by anyone — a typo, a stale product reference, a deliberately made-up product_id — and unlike a mispriced quote, this endpoint creates a live confirmed deal record directly, not something pending booking. See #57 for the full repro (typo'd product_id against a $45/$35 real product → confirmed deal at $13.20 total CPM).

Fix

When product_id is supplied but not found in the catalog, 404 product_not_found — the same error shape quote_service.create_quote already uses for the identical situation. The $12 CPM default now only applies when no product_id is given at all, which the code was always treating as a separate, legitimate case (a generic curated deal with no specific product reference).

base_cpm = 12.0  # Default when no product_id is supplied at all
if request.product_id:
    product = catalog["products"].get(request.product_id)
    if not product:
        raise HTTPException(
            status_code=404,
            detail={"error": "product_not_found", "message": f"Product '{request.product_id}' not found in catalog."},
        )
    from . import catalog_service
    base_cpm = catalog_service.priceable_cpm(product)

Test plan

create_curated_deal had zero test coverage before this. Added tests/unit/test_curated_deal.py:

  • unknown product_id → 404, no deal minted (the bug)
  • known product prices off its real base_cpm + curator fee
  • known-but-unpriced product → 422 (unchanged by this fix, confirms the existing guard still works)
  • no product_id at all → generic $12 default (unchanged, confirms this legitimate case wasn't broken)
  • curator_not_found → 404, for completeness

Full suite: 1408 passed, no regressions. ruff check / format --check clean.

Closes #57

create_curated_deal's comment says "A known-but-unpriced product...
is a 422 -- never a fabricated price," and the code delivers on that
for a product that exists but has no base/floor CPM (via
catalog_service.priceable_cpm). It didn't deliver on it for a
product_id that doesn't exist in the catalog at all: that case skipped
price resolution entirely and fell through to the hardcoded $12 CPM
default meant only for the no-product-id-supplied case, then minted
and persisted a "confirmed" deal at that fabricated price. No error,
anywhere.

POST /api/v1/deals/curated has no auth dependency, so this was
reachable by anyone with a typo, a stale product reference, or a
deliberately made-up product_id -- and unlike a mispriced quote, this
endpoint creates a live confirmed deal record directly.

Fix: when product_id is supplied but not found in the catalog, 404
product_not_found -- same error shape quote_service.create_quote
already uses for the identical situation. The $12 CPM default now only
applies when no product_id is given at all, which the code was always
treating as a separate, legitimate case.

create_curated_deal had zero test coverage before this. Added
tests/unit/test_curated_deal.py: the 404 case (the bug), a known
product pricing off its real base_cpm + curator fee, the 422
known-but-unpriced case (unchanged by this fix), the no-product-id
generic-default case (also unchanged), and curator_not_found for
completeness.

Full suite: 1408 passed. ruff check / format clean.

Closes IABTechLab#57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant