Validate ?projectId= references a live project on scoped writes (referential integrity)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 48/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Quiet
- Tech stack
- typescript
Research direction
Start at apps/api/src/routes/criteria.ts and trace getQueryProjectId through projectStore.get, then compare the same root-create pattern for profiles, prompt-features, mcp-servers, report-templates, skills, extensions, codebases, and requests. Done means nonexistent project IDs are rejected with 404, soft-deleted IDs are rejected with 409 or handled explicitly, and behavior is consistent across all root-create routes.
Written by the indexing model from the issue text.
Description
Original author: @manekinekko
Context
Surfaced during a data-model review of the per-project data organization work (PR #1241, design #1210).
Scoped write routes resolve the target project from a client-supplied ?projectId= via getQueryProjectId, which only checks that the value is a non-empty string. There is no verification that the id refers to a project that actually exists and is not soft-deleted.
Example: apps/api/src/routes/criteria.ts →
const doc = await getCriteriaStore(projectId).create({ projectId, id, prompt, dependsOn, gates });
The same pattern applies to every root-create route (profiles, criteria, prompt-features, mcp-servers, report-templates, skills, extensions, codebases, requests).
Problem
- A client can create entities under a non-existent or soft-deleted
projectId, producing orphaned rows that no/projectsentry owns. projectIdis stored as a bare string with no foreign-key guarantee, so nothing at the data layer keeps scoped entities pointing at a live project.- Combined with soft-delete being allowed on non-empty projects, data can be created into a project that is already deleted.
Proposed resolution
- On scoped writes (at minimum root-creates), validate the resolved
projectIdagainstprojectStore.get(projectId)(excluding soft-deleted) before writing. - Reject with 404 (unknown project) or 409 (deleted project) instead of silently writing an orphan.
- A small in-process cache keeps this cheap on hot paths.
- Consider whether scoped list/read should likewise treat an unknown/deleted
projectIdas an error rather than returning an empty set.
Acceptance criteria
- Creating a scoped entity with a
projectIdthat does not exist is rejected (404). - Creating a scoped entity with a soft-deleted
projectIdis rejected (409) or otherwise handled explicitly. - Behavior is consistent across all root-create routes.
Related
- PR #1241 — per-project data organization
- Design #1210
- Related review threads on #1241 (fail-open scoped-store default, double
projectIdsource of truth inCriteriaStore)
- Dominant language
- TypeScript
- Stars
- 5
- Forks
- 5
- Avg merge
- 4d 13h
- Merged PRs (30d)
- 17
Getting set up
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from microsoft/scope
-
type: worker-update
Difficulty 1/5 1-3 hours Newbie friendliness 85/100
Maintainers usually reply within 1 day
-
type: worker-update
Difficulty 1/5 Under an hour Newbie friendliness 88/100
Maintainers usually reply within 1 day
-
type: worker-update
Difficulty 1/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
author: JaGord documentation good first issue UI
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
author: cedricvidal bug portal
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Maintainers usually reply within 1 day
Similar issues
-
Mend: dependency security vulnerability untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
opensearch-project/security-dashboards-plugin#2545 ·
Maintainers usually reply within 1 day
-
Add: Dream TR SDOpencheck:passed streams:add
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day
-
doctor integrity sample scans soft-deleted pages on Postgres (batch path has no deleted_at filter)Open
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 72/100
SocialGouv/egapro#4672 · 1 comment ·
Maintainers usually reply within 2 days
-
area:agents area:tui bug
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
anthropics/claude-code#98358 ·
Maintainers usually reply within 1 day