Skip to content

[security][observability] resolvePermissionSets swallows dbLoader failures silently — custom permission sets vanish with no log #2565

Description

@os-zhuang

From the 2026-07 pre-launch authorization architecture assessment (context: #2561, PR #2562).

Problem

permission-evaluator.tsresolvePermissionSets resolves permission-set names through three sources: metadata service → bootstrap defaults → dbLoader (user-defined sets persisted in sys_permission_set). The dbLoader call swallows all failures:

try {
  const dbRows = await dbLoader(unresolved);
  ...
} catch {
  // Swallow — the request shouldn't fail just because the DB
  // lookup is unavailable.
}

The metadata-service list() call at the top of the function has the same shape (catch { allPermSets = []; }).

Failure direction is correct (fail-closed: unresolvable sets grant nothing, the user gets 403 rather than an open door). The problem is observability: a transient DB error makes every custom permission set silently disappear for the affected requests — users are denied, admins see nothing in the logs, and the symptom ("permissions randomly stop working") points nowhere near the cause.

Fix

Surface the swallow: emit a warn with the unresolved names and the error when dbLoader (or the metadata list()) throws. PermissionEvaluator has no logger today — either accept an optional logger (constructor or method param), or move the try/catch responsibility to the caller (security-plugin.ts, which has ctx.logger). Keep the fail-closed behavior unchanged; this is logging only.

Acceptance

  • dbLoader throwing produces exactly one warn per request naming the unresolved permission sets; enforcement behavior is byte-identical.
  • Same for the metadata list() failure path.
  • Unit test: stub a throwing dbLoader, assert the warn fires and resolution still returns the metadata/bootstrap results.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions