Skip to content

Enable API for everything UI can do, with same RBAC #738

Description

@xinbenlv

Original Request

Enable API for everything UI can do, with same RBAC

Agent's Two Cents (could be wrong)

Everything below is the AI agent's best guess based on the current codebase.
Take with a grain of salt — the original request above is the only thing that came from a human.

Problem / Motivation

Kener's admin UI can do many things the public/authenticated API cannot, so anyone trying to automate or provision Kener (IaC, CI, bulk imports, external dashboards) keeps hitting gaps and has to fall back to clicking in the UI. The community has filed these gaps one endpoint at a time (incidents, maintenance events, monitor delete, subscriptions, …) instead of treating "the API should cover everything the UI does" as a single principle. This issue proposes that principle directly, plus the rule that an API caller needs exactly the same permission the UI requires for the same action — no more, no less.

Proposed Solution

Establish API ⇄ UI parity as an invariant: every action reachable from the admin UI has a corresponding v4 API endpoint, and that endpoint is gated by the same RBAC permission the UI action requires.

Concretely:

  • Enumerate every mutating/reading action the admin UI performs (monitors, incidents, maintenances + events, pages + reorder, triggers/alert-configs, users, roles, permissions, API keys, subscribers, email templates, site settings, image uploads).
  • For each, ensure a v4 API route exists with full CRUD where the UI offers it.
  • Route every endpoint through one shared authorization resolver that maps (path, method) → permission id and checks it against the caller's API-key permission set — the same resource.action ids the UI/session RBAC already uses.
  • Treat "UI can do X but API can't" (or "API requires a different/looser permission than the UI") as a bug going forward, ideally backed by a parity test.

Note: the fork xinbenlv/zn-kener has already built a large reference implementation of exactly this (a per-key RBAC resolver in src/lib/server/apiPermissions.ts plus v4 routes for users/roles/permissions/api-keys/subscribers/email-templates/monitor clone-test-data, etc.). It can serve as a working proof-of-concept / source of PRs for upstream.

Architecture Diagram

        ┌──────────────────────┐        ┌──────────────────────┐
        │   Admin UI (manage)  │        │   API client / IaC   │
        │  session + role      │        │  Bearer API key      │
        └──────────┬───────────┘        └──────────┬───────────┘
                   │ action: "edit monitor"        │ PUT /api/v4/monitors/{tag}
                   ▼                                ▼
        ┌────────────────────────────────────────────────────────┐
        │   SINGLE shared authorization resolver                  │
        │   requiredPermissionFor(path, method) -> "monitors.write"│
        │   then assert caller has that permission id             │
        └──────────────────────────┬─────────────────────────────┘
                                   │ same permission id, same check
                                   ▼
                ┌───────────────────────────────────┐
                │   Controller / service layer       │
                │   (monitorsController, etc.)        │
                └───────────────────────────────────┘

Invariant: for every UI action there is an API route, and both arrive at the
controller having passed the IDENTICAL permission check. No UI-only actions;
no API endpoint looser or stricter than its UI equivalent.

Dependencies & Potential Blockers

No major blockers identified. The building blocks already exist in the project: a v4 API surface (src/routes/(api)/api/v4/), Bearer/API-key auth (VerifyAPIKey in apiController.ts), a permission catalog (src/lib/allPerms.ts), per-API-key permissions (migration 20260530000000_add_permissions_to_api_keys.ts), and a (path, method) → permission resolver pattern. The work is mostly closing coverage gaps and enforcing one consistent auth path, not new infrastructure.

How to Validate

  • Generate (or maintain) a list of every admin-UI action and assert each has a v4 endpoint — a parity test that fails when the UI gains an action with no API equivalent.
  • For a representative action per resource (e.g. monitor create/edit/delete, incident create/comment, maintenance event add, page edit/reorder, user/role/permission CRUD, subscriber add, email-template edit, site-setting update): call the v4 endpoint with an API key that has the matching permission → succeeds; with a key missing it → 403.
  • Confirm no v4 endpoint accepts an action the UI gates behind a permission the API does not check (no privilege escalation, no looser API path).
  • Smoke test: provision a fresh Kener instance end-to-end (monitors, a page, an incident, a maintenance window, a user with a scoped role) using only the API.

Scope Estimate

large

Key Files/Modules Likely Involved

  • src/routes/(api)/api/v4/ — the v4 route handlers (extend to full coverage)
  • src/lib/server/apiPermissions.ts(path, method) → permission id resolver + key-permission check (reference impl from the fork)
  • src/lib/allPerms.ts — canonical resource.action permission catalog shared by UI and API
  • src/lib/server/controllers/*Controller.ts — shared business logic both UI and API should call
  • src/routes/(manage)/ — the admin UI actions that define the parity target

Rough Implementation Sketch

  • Audit the (manage) UI to produce the authoritative list of actions and the permission each requires.
  • Diff that list against existing api/v4 routes; file/track each missing endpoint.
  • Funnel all API requests through one authorization middleware that derives the required permission from (path, method) and checks the key's permission set.
  • Have both UI handlers and API routes delegate to the same controller functions so behavior can't drift.
  • Add a parity/coverage test (and ideally a docs table) so new UI features must ship their API + permission mapping.

Open Questions

  • Should genuinely UI-only conveniences (pure presentation, preview-only flows) be explicitly exempted from parity, and how do we mark them?
  • Granularity: is resource.read / resource.write (+ a few special cases like api_keys.delete) enough, or do some actions need finer-grained permissions?
  • Versioning: extend v4 in place, or stage breaking auth-tightening behind a new version?
  • Public vs authenticated read endpoints — which reads (e.g. incident details, see Incident API updates for public consumption and additional information #423) should be public vs permissioned?

Potential Risks or Gotchas

  • Tightening auth so the API matches the UI could break existing integrations that currently call under-protected endpoints — needs a migration/communication path.
  • Keeping the permission map in lockstep with the UI is an ongoing maintenance burden; without an enforced test it will drift.
  • Resource-name/segment aliasing (e.g. alert-configsalerts, permissionsroles) must stay consistent between UI and API to avoid wrong-permission checks.

Related Issues

Existing per-feature API/RBAC requests this umbrella would subsume (surfaced while researching this proposal):

Open gaps:

Already closed (precedent / scope examples):


Suggested labels: enhancement, kener-apis, AgentsValidatable, NoNewDependencies
Suggested priority: p2 (medium — important parity improvement, non-blocking)
(Filed by an external contributor without write access, so labels/priority are noted here rather than applied directly.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions