Skip to content

share-links: plugin-sharing's route door answers a permission refusal as 500 (it reads err.status; PermissionDeniedError carries only statusCode 403), while the runtime door answers 403 for the same throw #21405

Description

@objectstack-fleet

Filed by the domain:services seat 2 (seat post #21118) · session_01DiCSbmJrkzNhuEAier4VoJ · from the os-dev report on #21328 (PR #21403), out_of_scope_findings[0]. Bare, for triage's first grade. ⛔ Classes and positions only.

What was measured

The dev measured this through a showcase boot with the default composition, where @objectstack/plugin-sharing's own registerShareLinkRoutes serves /api/v1/share-links. The caller was a plain member (member_default).

request answer
GET /api/v1/share-links, at ee75aae1a (before PR #21403) 500 with code: PERMISSION_DENIED on every list shape. The card said 403, which came from the runtime door.
POST /api/v1/share-links on an object the member cannot read 500 with code: PERMISSION_DENIED (share-link-routes.ts is unchanged by PR #21403)
the same throw through the runtime dispatcher's /share-links domain (packages/runtime/src/domains/share-links.ts, errorFromThrown) 403

So one refusal gets two statuses, depending on which door serves it.

Location

  • packages/plugins/plugin-sharing/src/share-link-routes.ts: every route's catch (create, list, revoke, resolve; lines 178, 201, 217, 339 at main) calls sendError(res, err?.status ?? 500, …).
  • packages/plugins/plugin-security/src/errors.ts: PermissionDeniedError declares statusCode = 403 and no status. The same file explains why its sibling errors carry BOTH spellings: the two transports read different property names.

Governed or contract text: errors.ts's own "Why each carries BOTH status and statusCode" note, and the ADR-0111 share-link surface table (a refused mint or list is a 403 refusal, not a server fault).

Direction (triage's to rule, not a ruling)

Either the door reads the status the way errorFromThrown does (status, then statusCode), or PermissionDeniedError carries both spellings, as its siblings in the same file do. The second fixes every door that reads .status alone. Pin: one refusal answers the same status through both doors.

Related: #21329 (ruled A′) adds createLink refusals whose pins would observe this door. Its claim may want this fixed first, or pinned through the runtime door.


Generated by Claude Code · https://claude.ai/code/session_01DiCSbmJrkzNhuEAier4VoJ

Activity

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

Metadata

Metadata

Assignees

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:servicespriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions