Skip to content

fix(api): keep anonymous package reads in the public view - #116

Open
aleksUIX wants to merge 2 commits into
IABTechLab:mainfrom
aleksUIX:fix/public-package-reads
Open

aleksUIX wants to merge 2 commits into
IABTechLab:mainfrom
aleksUIX:fix/public-package-reads

Conversation

@aleksUIX

Copy link
Copy Markdown
Contributor

GET /packages and /packages/{package_id} currently return exact prices, floors, placements and audience segment lists to anonymous callers who supply a non-public buyer_tier. Select the public view whenever no validated API key is present.

Valid buyer and operator keys keep the authenticated view. Claimed anonymous tiers now receive public price ranges and audience summaries. Package filters and missing-package responses stay intact.

Validation: 38 route regressions use real header validation and pricing, covering forged identities, both key headers, valid roles, rejected keys, filters and 404s. Twelve regressions fail on unchanged main. Locked Python 3.12 unit tests passed 1,708 cases; integration tests passed 39 with 28 existing skips. Ruff checks passed. The repository Dockerfile built, and the isolated default container reached healthy status. No deployed seller was tested.

Fixes #114.

@atc964 atc964 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes: the fix is right, but it's one endpoint short of its own title.

The change to GET /packages and GET /packages/{package_id} is correct and strictly narrowing: anonymous callers always get PublicPackageView (a true field-allowlist model, nice), valid keys keep the authenticated view with identity taken from the key, and rejected keys 401 without falling back to public. The regression suite is strong (real header validation, both headers, role/tier/case matrices).

Blocking: POST /media-kit/search in this same file (media_kit.py, ~line 145) still contains the pre-fix pattern: if api_key_record is not None or request.buyer_tier != "public" builds a buyer context from claimed body fields, and search_packages then returns AuthenticatedPackageView with exact_price, floor_price, placements, and full segment lists. An anonymous POST /media-kit/search {"query": "...", "buyer_tier": "agency", "agency_id": "x"} retrieves everything #114 reported, for the same packages. Since this PR says "Fixes #114" and its title promises anonymous package reads stay public, please apply the same api_key_record is None gate to search (and extend the new test module to cover it); otherwise #114 closes while its leak class stays reachable.

We'll file the related pre-existing issues on our side (claimed-tier handling in POST /discovery, and the underlying _build_buyer_context fallback behavior); they're out of this PR's files and not blocking here.

Minor, non-blocking: a field-set allowlist assertion (set(package.keys()) == EXPECTED_PUBLIC_FIELDS) would make a future addition to the public view fail loudly instead of silently; datetime.utcnow() is deprecated in 3.12+; the docstring changes will need an openapi.json regen once #83's drift guard lands; and the hardcoded prices in the test will churn if #92 changes pricing.

POST /media-kit/search builds a buyer context only from a validated API key. A claimed buyer_tier in the body no longer returns exact prices, floors, placements or segment lists to anonymous callers.
@aleksUIX

Copy link
Copy Markdown
Contributor Author

The search gate is on 8b20c41. POST /media-kit/search builds a buyer context only when api_key_record is present, so a body claiming buyer_tier: agency without a key gets the public view. test_anonymous_search_keeps_the_public_view runs the same claim set as the package-read tests and checks that exact_price, floor_price, placements, and the standard segment IDs are absent. A valid buyer key still gets the exact and floor prices and the placements. I have not added the field-set allowlist assertion.

Python 3.11, 3.12, and the Docker build passed on that head.

This branch has not been deployed

No deployments
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.

GET /packages and GET /packages/{package_id} return exact_price and floor_price to an anonymous caller who adds ?buyer_tier=agency

2 participants