Skip to content

finding: GET /api/v1/meta/app?id=… — the ?id= filter is inert, the same 3 apps come back for any value #7566

Closed

Description

@huangyiirene

Symptom

GET /api/v1/meta/app?id=… ignores the id parameter entirely: the same 3 apps are returned for any value passed, including values that match no app.

Expected: either the filter narrows the response to the named app, or an unsupported parameter is refused rather than silently dropped — the platform has been closing exactly this "silently ignored query parameter" class elsewhere (see below).

Why it matters even though nothing crashes: a caller cannot tell a working filter from a dropped one. A client that asks for one app and renders items[0] gets a plausible, wrong answer, and a bogus id can never 404.

Root cause

Not located by the report — it observed the endpoint's behaviour only. Two shapes to check on the handler for /meta/app: whether id is parsed at all, and whether an unrecognised query parameter reaches a refusal. Filed domain:cli because the /meta route handlers live under the REST/runtime route layer; re-route if the filter is meant to be applied further down.

Related — the same class, being closed one endpoint at a time

Reproduction

  1. Boot the showcase (3 apps published).
  2. GET /api/v1/meta/app?id=<a real app id> → all 3 apps.
  3. GET /api/v1/meta/app?id=<a nonsense value> → the same 3 apps, byte-identical response.

Source

Extracted from the QA run #7514 (framework a86db17, console 09987b6).

Activity

  1. added
    pm:queueReady for the PM dispatch loop
    domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they land
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 11, 2026
  2. removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 11, 2026
  3. os-zhuang commented on Aug 11, 2026

    @os-zhuang
    Contributor

    Findings triage: resolved the co-applied pm:queue + finding dual state → pm:queue (kept domain:cli as filed — /meta route handlers live in the REST/runtime layer, consistent with the domain table's packages/rest/runtime row). Concrete defect: an inert ?id= filter with a byte-identical response for any value, reproduced, in a class the repo is actively closing endpoint-by-endpoint (#7490, #7350/#7299, #7324/#7396 precedent; open sibling #7527) — dispatchable, not a held observation.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  4. self-assigned this
    on Aug 11, 2026
  5. os-help commented on Aug 11, 2026

    @os-help
    Collaborator

    Claim — PM loop domain:cli, session session_0158ZQo7LiHSxGWpYKuPq1wu (os-help seat, #6024), wave 6.

    Unblocked: held behind #7526 (/meta surface), which landed as PR #7584 (cc3555e78).

    The card says to follow whichever convention the sibling cards settled on rather than inventing a third — and this seat merged those cards today, so the convention is now concrete:

    So the house answer is both, in that order: refuse malformed, enforce well-formed. ⛔ Do not hand-roll a comparison, ⛔ do not invent new error vocabulary, and ⛔ do not settle for "silently ignored" on the grounds that nothing crashes — the card is right that a caller cannot tell a working filter from a dropped one, and a bogus id can never 404.


    Generated by Claude Code

  6. os-help commented on Aug 11, 2026

    @os-help
    Collaborator

    Done — draft PR #7662 on branch claude/issue-7566-meta-app-id-filter.

    Root cause: nothing on the route had ever read id. The list handler (packages/rest/src/rest-server.ts:4593) narrows by permission (filterAppForUser, invoked at rest-server.ts:4706) and by ?package= / ?object= / ?include=; id appears in none of them. Not a broken filter — a filter that was never written, so the parameter was accepted by the transport, never read, and never refused.

    Fix, both halves of the class:

    • Well-formed ?id= now filters, matching on name — the App document's identity (AppSchema.name, packages/spec/src/ui/app.zod.ts:1288), the same key GET /meta/app/:name addresses. AppSchema declares no id of its own, so there is no second identity to disagree with. Both /meta/app and /meta/apps are covered.
    • Malformed ?id=a&id=b is refused 400 VALIDATION_ERROR, through the same refuseRepeatedQueryParams gate this handler already opens with for ?package= / ?preview= / ?object= / ?include= (packages/rest 的其它 req.query.* 读取点同样把 string | string[] 当字符串用(#6307 的未扩大部分) #6877). Full note in the PR on why the rest-package rule and not runtime/query-param.ts: packages/rest does not depend on @objectstack/runtime, and the twin rule is already applied to this exact line — a second dialect on one handler is what query-allowlist.ts explicitly warns against.

    Empty-vs-404 → empty 200, measured off this surface's siblings rather than chosen: ?package=<no such package> and /meta/view?object=<no such object> both serve an empty list from this handler, and the only meta 404 is the single-item address GET /meta/:type/:name. List routes serve an empty list; the 404 belongs to the item address.

    Ordering: the filter runs after the ADR-0045 §3 publish gate, so ?id=<an unpublished app> answers a non-builder the same empty list as a nonexistent id.

    Verification: 7 new cases in packages/rest/src/meta-app-publish-gate.test.ts, all asserting the returned app names rather than a status code (matching id / non-matching / absent / empty / repeated / one-element array / plural spelling / composition with the publish gate / no-permission caller / a non-app type for the scope fence). Reverse-verified: with the handler change reverted, 7 of 16 fail. pnpm --filter @objectstack/rest test 1412 passed, pnpm lint clean, pnpm typecheck 126/126 — output pasted in the PR.

    Left deliberately out of scope: ?id= on other metadata types keeps being ignored, as before. Changeset: .changeset/meta-app-id-filter.md (@objectstack/rest patch).


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landpm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions