Skip to main content
← Back to list
01Issue
FeatureShippedSwamp CLI
Assigneesstack72

Relationships

↑ child of #662

#678 serve-auth: swamp access CLI commands

Opened by stack72 · 6/18/2026· Shipped 6/18/2026

Parent

Sub-issue of #662 (serve authentication & authorization). Layer 2.

Summary

Add the `swamp access` CLI command namespace for managing authorization grants and groups. This gives admins the ability to create, list, and revoke grants, manage local groups, and explain access decisions — all operating on the built-in models from #667.

Commands to implement

Grant management

`swamp access grant create` — create a new grant ```bash swamp access grant create \ --subject idp-group:platform-eng \ --allow run \ --on 'workflow:@acme/*'

With a CEL condition:

swamp access grant create \ --subject idp-group:platform-eng \ --allow run \ --on 'workflow:@acme/*' \ --when 'tags.env == "staging"' ```

Arguments:

  • `--subject ` — grant subject (`user:adam`, `group:release-managers`, `idp-group:platform-eng`)
  • `--allow ` or `--deny ` — effect + actions (comma-separated: `run`, `read`, `write`, `admin`)
  • `--on ` — resource selector (`workflow:@acme/`, `model:@acme/deploy`, `data:@acme/reports-`, `access:*`)
  • `--when ` — optional CEL condition (validated at creation via #670)

The command creates a named grant instance (auto-generated name) via the Grant model's `create` method with `source: method`.

`swamp access grant list` — list grants ```bash swamp access grant list swamp access grant list --subject idp-group:platform-eng swamp access grant list --on 'workflow:@acme/*' ```

Filterable by subject and/or resource. Shows all active grants with their ID, subject, effect, actions, resource, condition, and source.

`swamp access grant revoke ` — revoke a grant ```bash swamp access grant revoke 7f3a... ```

Calls the Grant model's `revoke` method. Takes effect immediately.

Group management

`swamp access group create ` — create a local group ```bash swamp access group create release-managers ```

`swamp access group add-member ` — add a principal to a group ```bash swamp access group add-member release-managers user:adam ```

`swamp access group remove-member ` — remove a principal from a group ```bash swamp access group remove-member release-managers user:adam ```

`swamp access group list` — list all groups

`swamp access group members ` — list members of a group

Access check (admin explain mode)

`swamp access check` — explain whether a subject can perform an action ```bash swamp access check --subject user:adam --action run --on workflow:@acme/deploy → ALLOW via grant 7f3a… (idp-group:platform-eng → run → workflow:@acme/*) ```

This uses the `AccessDecisionService.explain()` from #672. The admin specifies the subject, action, and resource explicitly. The command resolves group membership from the snapshot and shows all matching grants with their effect and provenance.

Note: `--subject` takes a subject string, but the AccessDecisionService needs an `AccessPrincipal` with collectives. For phase 1, the check command accepts `--collectives` as an optional flag to simulate IdP group membership. In phase 2 (after OAuth), it can look up the principal's actual claims.

Implementation pattern

Follow the existing CLI patterns:

Command hierarchy

``` swamp access (parent, groupCommandAction) ├── grant (parent, groupCommandAction) │ ├── create (leaf) │ ├── list (leaf) │ └── revoke (leaf) ├── group (parent, groupCommandAction) │ ├── create (leaf) │ ├── add-member (leaf) │ ├── remove-member (leaf) │ ├── list (leaf) │ └── members (leaf) └── check (leaf) ```

File structure

  • `src/cli/commands/access.ts` — parent command, registers subcommands
  • `src/cli/commands/access_grant.ts` — grant subcommands (create, list, revoke)
  • `src/cli/commands/access_group.ts` — group subcommands
  • `src/cli/commands/access_check.ts` — check command
  • `src/presentation/output/access_grant.ts` — grant renderers (log + json)
  • `src/presentation/output/access_group.ts` — group renderers (log + json)
  • `src/presentation/output/access_check.ts` — check renderer (log + json)
  • Tests for each

Output modes

Every command must support both `log` (human-readable) and `json` (structured) output modes, following the renderer pattern in `src/presentation/renderers/`. Use `createContext(options, ["access", "grant"])` for logger categories.

Dependencies

Grant and group operations go through model method execution — use the same `modelMethodRun` / libswamp patterns the existing CLI uses. The `access check` command needs to build a `PolicySnapshot` and `GrantBasedAccessDecisionService` to evaluate. Follow how the serve layer builds these (see `PolicySnapshotLoader` from #672).

Scope

  • All commands listed above with both output modes
  • Register `accessCommand` in the root CLI (`src/cli/mod.ts`)
  • Tests verifying command registration, option shapes
  • No serve wiring — these operate on the local repo

Out of scope

  • `can-i` command — layer 5 (needs authentication to know caller identity)
  • Declarative grants file — separate layer 2 issue
  • Admin materialization — layer 4
  • Serve enforcement wiring — layer 5

References

  • CLI command pattern: `src/cli/commands/data.ts` (parent), `src/cli/commands/data_get.ts` (leaf)
  • Group action for parents: `src/cli/group_action.ts`
  • Renderer pattern: `src/presentation/renderers/data_get.ts`
  • Root CLI registration: `src/cli/mod.ts` (line ~1239)
  • CLI test pattern: `src/cli/commands/data_get_test.ts`
  • Grant model: `src/domain/models/access/grant_model.ts`
  • Group model: `src/domain/models/access/group_model.ts`
  • AccessDecisionService: `src/domain/access/grant_based_access_decision_service.ts`
  • PolicySnapshotLoader: `src/domain/access/policy_snapshot_loader.ts`
  • Access value objects: `src/domain/access/mod.ts`
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 5 MOREREVIEW+ 3 MOREPR_MERGED+ 1 MORENOTIFICATION_SKIPPED

Shipped

6/18/2026, 4:48:18 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack726/18/2026, 3:52:59 PM
stack72 linked parent of #6626/18/2026, 3:53:35 PM

Sign in to post a ripple.