fix(prompts): stop exposing the sequential DB id on the prompts API - #1201
fix(prompts): stop exposing the sequential DB id on the prompts API#1201seonghobae wants to merge 2 commits into
Conversation
`PromptResponse` declared `id: int` with `from_attributes=True`, so both
`GET /api/prompts` and `POST /api/prompts` serialized the raw sequential
`PromptTemplate.id` surrogate PK straight onto the API surface (e.g.
`{"id": 1, "prompt_uid": "prompt_ab12…", …}`), leaking row ordinals/volume to
the client. This violates the repo convention: "Never expose sequential
database ids through APIs or UI — use opaque public ids". The model already
carries the opaque `prompt_uid` beside it, no route in this router consumes a
prompt integer id (identity is `prompt_uid`; there is no `/{id}` path), and the
sibling AI-hub renderer already keys off `prompt_uid` — so the field only
leaked the surrogate.
Fix: drop `id` from `PromptResponse`; `prompt_uid` is the sole public identity.
TDD: added assertions to `test_prompt_crud` that the create and list responses
omit `id` and carry `prompt_uid` — confirmed they fail on the pre-fix code
(`assert 'id' not in {'id': 1, ...}`) and pass after. Verified with CI parity:
`DISABLE_BACKGROUND_WORKERS=1 PYTHONWARNINGS=error pytest tests/test_prompts_api.py`
→ 20 passed (no Timeout/Fatal/Warn/Denied); `ruff check` clean. The frontend
prompt-studio keys UI off static template constants, not this response `id`.
Follow-up (same anti-pattern, out of scope for this atomic fix): `llm_providers.py`
exposes `id: int` (a clean analogous drop), while `emails.py`/`search.py` use the
int as a path key and need an opaque-id migration.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HdCssGnNMhKHNu3TXFstWH
|
Warning Review limit reached
Next review available in: 5 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Comment |
|
Superseded by clean reimplementation on current develop (opaque prompt_uid only). See the Loop PR that also lands CardDAV encoded path traversal. |
Description
PromptResponse(backend/api/prompts.py) declaredid: intwithmodel_config = {"from_attributes": True}, so bothGET /api/promptsandPOST /api/promptsserialized the raw sequentialPromptTemplate.idsurrogate PK straight onto the API surface — e.g.{"id": 1, "prompt_uid": "prompt_ab12…", …}— leaking row ordinals/volume (enumeration / count inference) to the client.This violates the repo convention (
CLAUDE.md→ Key conventions):It is a genuine violation, not design intent:
prompt_uidright beside the surrogate.prompt_uid, and there is no/{id}update/delete path.backend/api/ai_hub.py) already keys offprompt.prompt_uidand hashes provider ids into opaque keys, so this field only leaked the surrogate.Fix: drop
idfromPromptResponse;prompt_uidis the sole public identity. The frontend prompt-studio keys its UI off static template constants, not this responseid, so nothing downstream breaks.Fixes # (no tracked issue — surfaced by an internal contract audit)
Type of change
Checklist:
Verification (CI parity)
TDD: the added
test_prompt_crudassertions ("id" not in dataon both the create and list responses) were confirmed to fail on the pre-fix code (assert 'id' not in {'id': 1, ...}) and pass after the fix. NoTimeout/Fatal/Warn/Deniedin output.Follow-up (same anti-pattern, intentionally out of scope for this atomic fix)
backend/api/llm_providers.pyexposesid: int(a clean analogous drop);backend/api/emails.pyandbackend/api/search.pyuse the int as a path key and need an opaque-id migration before the surrogate can be removed.🤖 Generated with Claude Code
https://claude.ai/code/session_01HdCssGnNMhKHNu3TXFstWH
Generated by Claude Code