Skip to content

Latest commit

 

History

50 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nsc-tui — a terminal front-end to nsc

nsc-tui is a Go + bubbletea / huh front-end to nsc, the NATS tool that manages operators, accounts and users. It shows the current operator as a tree, opens every entity in a dialog-style editor, and drives nsc for every change: each action becomes a plan of nsc commands that is previewed, confirmed, run and followed by a reload. Nothing is ever written except through nsc itself, so the preview is exactly what you could type in a shell.

main screen

go install github.com/olgeni/nsc-tui@latest      # or: go build -o nsc-tui .
nsc-tui                                          # nsc's current store, operator and account
nsc-tui -H /path/to/env                          # nsc's own directory flags are accepted and passed on
nsc-tui -mouse                                   # with mouse support (m toggles it at runtime)
nsc-tui -json | jq '.accounts[].users[].name'    # non-interactive dump; -tree for a text listing
go test ./...                                    # unit tests + nsc-backed tests (skipped without nsc)
man ./nsc-tui.1                                  # manual page

Main screen

Key Action
↑/↓ j/k pgup/pgdn home/end move
→ / ← / space / * expand / collapse an account (*: all)
/ filter by name, public key or tag (esc clears)
enter details of the entity; J toggles the raw JSON of its JWT
e edit the operator, account or user
a / A add a user to the account (an account on the operator row) / add an account
d / del delete the account or user (with revoke / creds / key options), or the operator — nsc has no command for that one, so the name has to be typed and the rm lines are previewed before the files go
T JetStream tiers of the account: R1/R3/R5 limits, added, edited and removed (an account has either these or the global limits)
n rename an account (nsc rename account): the JWT is reissued under the new name with the same identity key, so its users, their creds and other accounts' imports stay valid — or a user, which nsc cannot rename, so its JWT is deleted and added again with -k
x i M R exports, imports, subject mappings, revocations of the account
s signing keys of the account (or of the operator): add, remove, and give one a role to make it scoped
C authorization callout of the account
K every key of the operator context (nsc list keys -A); a generates an nkey (nsc generate nkey), E exports them to a directory, I imports a directory of nkeys
I import / export: write the selected entity's JWT to a file (nsc describe --raw), export or import keys, import an account or a user from a JWT (a user also from a .creds file), describe a JWT without importing it (nsc describe jwt)
c credentials of a user: show, save to a file, or make a nats CLI context
v revoke a user (or lift the revocation)
g generate: a server configuration (operator), an activation token (account export)
p / P push / pull the account — on the operator row, all accounts
V / X validate the store / expirations report
S make the entity nsc's current operator / account (nsc select)
O switch operator, add one, or initialize an environment
m toggle the mouse (or start with -mouse): click a row to select it, click it again to open it, wheel scrolls; in editors a click focuses a field, a second click edits or toggles it, OK/Cancel are buttons; hold shift to select text
r reload from disk
h / ? key map / help, q quit

Rows are coloured by state: expired or revoked in red, expiring within 30 days or unverified in yellow; the header counts what is expiring.

enter opens the details of the selected entity: the decoded claims, whether the signature verifies, where the JWT and the private key are, and everything the editors set. J shows the raw JWT payload as JSON.

details of an account

Editors

the user editor

Every entity is edited in the same kind of dialog: labelled fields moved with ↑/↓/tab, enter to edit a text field in place (enter keeps, esc reverts), space for checkboxes, ←/→ for choices, ctrl+s for OK. Lists (subjects, tags, networks, connection types) are comma-separated; a subscribe subject with a queue group is written subject queue. Limits are -1 for unlimited; sizes take k/m/g/t. Expiry and start are entered the way nsc takes them (0, yyyy-mm-dd, 30d, 2w, 6M, 1y) and left blank to keep the current value.

Only what changed is passed to nsc, and the preview shows the commands:

the plan preview

[1/2] remove permissions
      nsc edit user -a billing -n alice --rm 'orders.>'

[2/2] apply the changes
      nsc edit user -a billing -n alice --allow-sub 'orders.>' --bearer=false --payload 1000000

The plans know a few things about nsc that are easy to get wrong by hand (all found by the nsc-backed tests):

  • --rm strips a subject from every permission list, so a subject moved from one list to another is removed first and re-added by a second command.
  • --rm-response-perms makes nsc edit user stop right there, so it always runs alone.
  • nsc edit account resets --wildcard-exports and --disallow-bearer to their defaults on every edit unless they are restated; every generated command restates them.
  • --js-enable is refused as soon as any JetStream field was ever set, while --js-mem-storage/--js-disk-storage enable JetStream in every case; the plans use the latter, and --js-disable (alone) to turn it off.
  • Every nsc edit account writes the global JetStream stream, consumer, ack and max-stream limits as unlimited, even on an account that never asked for JetStream, and nsc then refuses to add a tier to it; the test for "this account has global limits" is therefore nsc's own (any field set), not "it has storage".
  • An account has either the global JetStream limits or the replication tiers, and nsc refuses any command that would leave both, so adding the first tier removes the global one first (--rm-js-tier 0) and the account editor drops its JetStream fields once tiers exist.
  • --js-max-bytes-required is only honoured while the limits of a tier are being created (loadLimits tests js-max-ack-required, a flag that does not exist, and restores the stored value otherwise), so it is set when a tier is added and reported as dropped on a later edit rather than run for nothing.
  • There is no delete operator, no rename operator and no rename user; nsc rename account exists but is hidden and needs --OK. A user is renamed by deleting its JWT and adding it again with -k, which needs every setting restated from the old claims — the times included, and nsc parses 2006-01-02 15:04:05 UTC back exactly, so the expiry survives to the second.
  • An export is identified by its subject and there is no edit import, so changing an export's subject or type, or editing an import, is a delete plus an add — the preview says so.

Sub-screens

  • Exports (x): add, edit, delete; t generates an activation token for a private export (for one of the store's accounts or a typed key); R manages activation revocations.

  • Imports (i): add from another account of the store (picked by name) or from an activation token file/URL; edit is delete + add.

  • JetStream tiers (T): the global tier and the R1/R3/R5 ones, added with their limits, edited and removed.

    the JetStream tiers of an account

  • Mappings (M): weighted subject mappings, add / change weight / delete.

  • Revocations (R): revoked user keys of the account, revoke another user or a typed key, lift a revocation.

  • Signing keys (s): the keys that may sign users of the account (or accounts, on the operator row), with their role, keystore status and template summary. enter edits a scope: giving a role to a plain key promotes it, and every user that key signs then gets the template's permissions, limits, source networks, times and connection types instead of its own. nsc cannot turn a scoped key back into a plain one (remove and re-add), and removing a key invalidates the users it signed — the preview says both.

  • Auth callout (C): hands authorization to an external service. The auth users bypass the callout (the service's own credentials), the allowed accounts are those it may issue users for (or *, which cannot be mixed with keys), and the curve key is the X key requests are encrypted to (generate makes one). Both key fields are pickable and free-form: enter opens the store's users (this account's first) or accounts plus *, ticked where the field already holds them — enter adds or removes one, the list stays open, and keys from outside the store are listed too so they can be removed the same way. e edits the field as plain text. nsc wants public keys there, not names, and a key that lives outside this store is equally valid. The names of the keys a field holds are shown under it. Turning it off is nsc edit authcallout --disable, which nsc accepts only on its own and which clears the whole configuration.

  • Keys (K): identity and signing keys with their keystore status; a generates an nkey of any kind — the key an account or user is later added with (--public-key), or a curve key for the authorization callout — and either stores the private half or only prints the seed; E exports them all to a directory.

  • Expirations (X): nsc expirations as a table; w changes the window, s hides what is not expiring.

  • Credentials (c), validate (V), push/pull (p/P) and the generated server configuration (g on the operator) show nsc's output.

Directories and environment

nsc-tui takes nsc's own directory flags — -H, --config-dir, --data-dir, --keystore-dir — plus -K for a signing key and -nsc for the binary, and passes them to every command. Without them nsc's defaults and environment ($XDG_CONFIG_HOME, $XDG_DATA_HOME, $NSC_HOME, $NKEYS_PATH) apply, exactly as nsc env shows.

The store is read directly: the store directory, current operator and account come from nsc env, the JWT files under <store>/<operator>/ are decoded (and their signatures verified) with nats-io/jwt, and one nsc list keys -A -J tells which private keys are in the keystore. An entity whose JWT does not decode or verify is still listed, marked, so a damaged store is visible.

To try it without touching your real environment:

D=/tmp/nsc-play
nsc --config-dir $D/config --data-dir $D/stores --keystore-dir $D/keys init --dir $D/stores --name demo
nsc-tui --config-dir $D/config --data-dir $D/stores --keystore-dir $D/keys

(-H $D alone points --data-dir at $D, so nsc init would put the operator under ~/.local/share/nats/nsc/stores instead; init --dir and the three explicit flags keep everything under $D.)

Non-interactive use

nsc-tui -json prints one JSON document with the store directory, the current operator and account, the operator names, and the operator JWT plus every account and user: name, kind, public_key, issuer (and issuer_name), issued_at, expires, not_before, expired, expires_soon (within 30 days), verified, error, key_stored, key_path, creds (users), revoked (users), system_account (accounts), tags, jwt_path and the decoded claims. -tree prints the same as an indented text listing, one entity per line with its key, expiry and flags. Both exit 1 only when the store cannot be loaded at all; nsc expirations --json remains the tool for expiry reports.

Tests

go test ./...            # everything, a few seconds
go test -v ./nsc         # the nsc-backed tests, verbose (SKIP without nsc)
go vet ./...

The "nsc-backed" tests build a throwaway store under t.TempDir() with the real nsc, run the plans the editors would produce, reload and compare the resulting JWTs with what the specs said — the same idea as facl's kernel-backed tests. They skip themselves when nsc is not installed.

About

Terminal UI for NATS nsc: operators, accounts and users as a tree, dialog editors for JWT claims, JetStream tiers, scoped signing keys and authorization callout — every change previewed as the exact nsc commands before it runs.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages