Skip to content

feat(cli): campus user * management commands — currently nonexistent, and gated on a users:* server-side vocabulary #42

Closed
1 of 1 issue completed

Description

@ngjunsiang

Current state

The CLI ships three command groups: auth, client, vault. There are no campus user * commands — user management (list / get / create / activate / delete, served by /auth/v1/users/*) is unreachable from the CLI.

Even if the commands were added today, they would 403 for every caller: the users blueprint requires the operator principal (campus#854), and the users:* management-scope vocabulary was explicitly reserved in campus#865's phasing ("stay operator-only until a need exists"). The CLI authenticates with user bearer tokens only (no client-credential mode), and since #865 a user token can carry management authority only through the ANDed legs: AUTH_ADMIN_USER_IDS designation + a management scope — none of which exist yet for users:*.

Path to add them (when a need exists — that's the deliberate gate)

Mirroring the clients rollout (campus#865 → #866):

  1. Server (nyjc-computing/campus): define the users:read|write|admin vocabulary, wire require_operator(action, admin_scope=...) on the users routes (the composite gates already support it — clients did exactly this in #866), extend the invariant A8 wording, add the contract matrix. Deploy fail-closed (empty allowlist change).
  2. Operator: widen the CLI client's allowed_scopes with the users scopes + designate the admin(s).
  3. CLI: campus user list/get/new/activate/delete passing --scope users:admin at login; 403 messages already distinguish the failed leg server-side.

Related (same class of gap, separate decisions)

  • campus vault * commands exist but are equally inert from the CLI today: vault routes deny user principals outright (require_vault_permission), authority lives in per-label vault_access bitflags held by client principals. A bearer-only CLI can never satisfy that. Options: a vaults:* vocabulary, client-credential mode for the CLI, or documenting vault as operator/tooling-only.
  • credentials:* — same reserved bucket in campus#865.

Acceptance (when picked up)

  • Server vocabulary landed and deployed fail-closed (prerequisite).
  • campus user list/get/new/activate/delete implemented with dry-run support like client/vault.
  • README "Token scopes" section updated with the users:* vocabulary.

Refs: nyjc-computing/campus#865, nyjc-computing/campus#854

Activity

  1. ngjunsiang commented on Oct 9, 2026

    @ngjunsiang
    ContributorAuthor

    Phase 1 (server) is up for review: nyjc-computing/campus#873

    Decisions locked in during implementation (supersede the issue's step-3 shorthand where they differ):

    • Scope granularity: users:read (list/get) < users:mod (activate only — NEW level between read and write in the shared algebra) < users:write (create + update, implies mod) < users:admin (delete, implies write). campus user command mapping: list/get→read, activate→mod, new/edit→write, delete→admin.
    • Per-vocabulary designation: users:* scopes consult a dedicated AUTH_USERS_ADMIN_USER_IDS env var — a clients-designated admin is NOT a users-admin. Generalization matrix tracked in feat(auth): per-resource designated-admin matrix (generalize AUTH_ADMIN_USER_IDS) campus#872.
    • PATCH /users implemented in the same PR (was an unguarded 501 stub), accepting name only: a user's id IS its email, so identity fields stay fixed. Revisit if email changes are ever needed.
    • Audit: verified no new wiring needed — tracing spans bind g.current_user deployment-wide (#802) and already cover /users.
    • Consent labels deferred to feat(auth): consent-page labels for the users:* management-scope vocabulary campus#871 (generic fallback renders the new scopes safely).
    • vaults/credentials stay operator-only (reserved vocabularies).

    Related sub-issues: #45 (campus auth status, filed).

    Phase 2 (client-side): users.update() in campus-api-python, then the campus user sub-app in campus-cli — next up.

  2. ngjunsiang commented on Oct 9, 2026

    @ngjunsiang
    ContributorAuthor

    Phase 2 (client-side) is up for review:

    Command → scope map: list/get → users:read, activate → users:mod, new/edit → users:write, delete → users:admin.

  3. added a commit that references this issue on Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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