keymgmtcmd

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 14, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

Documentation

Overview

Package keymgmtcmd implements the key & keystore management commands — `setup`, the `key` group (add/bind/use/rename/remove/list/show/set-base-url/ set-default-account-seq), and the `keystore` group (status/migrate/default). It runs against the clienv.Cmd seam, so the cli dispatches into it without it importing cli. The keystore results render their own human output via FormatText (textout.TextFormatter); the key/setup path additionally exports KeyContext + RunKeyCommand so the mcp server can drive the exact CLI key-creation path and capture its JSON document (see keycmd.go).

Index

Constants

View Source
const (
	PermAll = permTrading | permTransfers // 127
)

permTrading is the default permission bitmask prefilled into the registration deep link: all read scopes plus place-orders — readBalances(1)|readOrders(2)|writeOrders(4)|readDeposits(8)|readWithdrawals(32) = 47. The deposit/withdrawal *write* bits (writeDeposits=16, writeWithdrawals=64) are off by default — a plain trading key never requests withdrawal permission. `setup`/`key add --with-transfers` opts those bits in (PermAll) for users who need `deposit generate`, `withdraw request/cancel`, or the `krw` push commands. The human still reviews and adjusts the boxes on the portal before confirming.

Variables

This section is empty.

Functions

func RunKeyCommand

func RunKeyCommand(c *spec.Command, flags map[string]string, positionals []string, ctx KeyContext) error

RunKeyCommand dispatches the builtin `key *` subcommands. flags holds the set string-flag values; output goes to stdout, diagnostics to stderr. It is exported so the mcp server can drive the same path with a buffer-backed KeyContext and capture the emitted JSON document. It handles only `key *` (`setup` has its own entry, RunSetup).

func RunKeystore

func RunKeystore(cx *clienv.Cmd, c *spec.Command, cmd *cobra.Command, args []string) error

RunKeystore handles the `keystore` builtin group (status, migrate, default). It is special-cased in dispatch like doctor/ip/logs because it manages the keystore backends themselves rather than signing a request with a key.

func RunSetup

func RunSetup(flags map[string]string, positionals []string, ctx KeyContext) error

RunSetup implements the `setup` command (key name defaults to "default"). Every path that ends already-configured runs the complementary health check (see runSetupDoctor). The full behavior matrix:

situation                            result
-----------------------------------  ------------------------------------------
setup (new key)                      generate + registration link, no doctor
setup (unbound key exists)           resume (re-print link), no doctor
setup (bound key exists)             already configured + doctor
setup --wait (new or unbound key)    print link, poll, then bind + doctor on
                                     claim (headless; resume doc on stop/timeout)
setup --api-key (new key)            error — register the public key first
setup --api-key (unbound key)        bind + doctor
setup --api-key (bound, same id)     no-op (already configured) + doctor
setup --api-key (bound, diff id)     error — setup never rebinds
setup --api-key SANDBOX_…            error — not created via setup
inline KORBIT_CLI_API_KEY_* set      report env credential + doctor; --api-key errors

The awaiting rows (new/unbound, no --api-key/--wait) finish per the wired path: the on-TTY interactive prompt, else print-and-exit. --wait selects the headless poll instead and is a no-op on an already-finished (bound/inline) key.

Types

type ClaimUpdate

type ClaimUpdate struct {
	Status  string
	Result  []string
	Done    bool
	Stop    bool
	Prefill string
}

ClaimUpdate is one event from the background auto-claim poll, surfaced by the interactive runner; it mirrors setupui.ClaimUpdate so this package stays independent of the UI layer (root.go maps between the two). A non-terminal update carries only Status. A terminal update sets exactly one of Done (success: Result holds the lines to show before the session ends) or Stop (polling stopped without a claim; the prompt stays open and Status says why). Prefill (Stop only) is the claimed api key id to drop into the empty input, so a fall-back after the id was already retrieved doesn't make the user re-find it.

type KeyContext

type KeyContext struct {
	IO       output.IO
	JSONMode bool
	Compact  bool
	Home     string
	KM       *keys.Manager
	// IP, when set (by `setup`), carries the probed public IP(s) so the
	// guidance can name the exact allowlist entries to register.
	IP *probe.Report
	// Perms is the permission bitmask to prefill into the registration deep link.
	// Zero means "unset" — treated as permTrading (the safe default).
	Perms int
	// BaseURL / BaseURLSet carry an explicit --base-url. `setup` (only when it
	// first creates the key) and `key add` persist it as the new key's default
	// endpoint, mirroring `key set-base-url`. Unset leaves the key on the default
	// host.
	BaseURL    string
	BaseURLSet bool
	// WSBaseURL / WSBaseURLSet carry an explicit --ws-base-url for `key
	// set-base-url` and the create commands: when set, it is persisted verbatim;
	// when unset, the WebSocket URL is derived from the REST base URL.
	WSBaseURL    string
	WSBaseURLSet bool
	// Verify, when set, smoke-tests the REST + WebSocket endpoints after `key
	// set-base-url` stores them. Nil when the check is skipped (--no-verify) or
	// not applicable to the command.
	Verify func(restURL, wsBaseURL string) probe.EndpointVerification
	// Getenv reads the process environment; `setup` uses it to detect an inline
	// credential (KORBIT_CLI_API_KEY_*). May be nil (the check is then skipped).
	Getenv func(string) string
	// Doctor, when set, runs the read-only health check for a just-configured
	// BOUND key and returns its report. It is advisory: setup embeds the report in
	// its result and surfaces problems as warnings, but a failing check NEVER
	// changes setup's exit code. Nil when the check is skipped.
	Doctor func(keyName string) *doctorcmd.Report
	// VerifyAPIKey, when set, signs a read-only whoami for the named key using a
	// CANDIDATE api key id — with no binding persisted — to confirm the id is
	// registered and the key can sign with it. Both setup lanes call it before
	// binding. wait selects the tolerance: false (manual paste) is one-shot — any
	// rejection (KEY_NOT_FOUND, signature mismatch) is returned so the prompt can
	// retry without ever writing a bad id; true (auto-claim) rides out the
	// just-registered KEY_NOT_FOUND window within a short budget and is best-effort
	// (the caller treats a failure as soft and binds anyway). ctx lets a session
	// cancel abort the wait. nil means an id is bound without checking.
	VerifyAPIKey func(ctx context.Context, name, apiKeyID string, wait bool) error
	// RunInteractive, when set, takes over the awaiting-registration outcome of
	// `setup` on a TTY: instead of printing the registration link and exiting, it
	// shows intro (the lead-in prose + the public key when there is no link) and
	// prompts for the issued key id, then calls submit, which binds the key and runs
	// the health check. registrationURL is the portal deep link (empty when none
	// could be built); the UI renders it as its own width-wrapped, clickable block
	// and offers copy/QR shortcuts for it, so it is passed separately rather than
	// baked into intro. submit returns the lines to display, done=true when setup is
	// complete, or a retryable error to show while keeping the prompt open. The UI
	// renders on stderr; the final result document is still emitted to stdout after
	// it closes. canceled=true means the user aborted with Ctrl-C: the caller emits
	// nothing (matching the non-interactive SIGINT abort). Nil disables interactive
	// setup (a pipe, --json, the MCP server, --no-interactive), and setup falls back
	// to print-and-exit.
	//
	// autoClaim, when non-nil, runs concurrently with the paste prompt: the runner
	// starts it, shows its status, and lets it complete setup automatically when it
	// detects the registered key (see ClaimUpdate). nil leaves manual paste as the
	// only path.
	RunInteractive func(intro []string, registrationURL string, submit func(token string) (lines []string, done bool, err error), autoClaim func(ctx context.Context) <-chan ClaimUpdate) (canceled bool, err error)

	// PollClaim, when set, runs the background auto-claim poll for the freshly
	// generated key `name`, signing the keyless GET /v2/keys/claim with the key's
	// not-yet-bound private key. It calls onStatus with a short live status for
	// transient states (e.g. a brief back-off) and returns one of:
	//   - (id, "", nil)       the key was claimed — the caller binds it
	//   - ("", code, nil)     polling stopped without a claim; code is the API error
	//                         code (e.g. KEY_CLAIM_CONFLICT, IP_NOT_ALLOWED,
	//                         KEY_DEACTIVATED), "" for a generic/malformed stop. The
	//                         caller renders the user notice (claimStopNotice).
	//   - ("", "", err)       ctx was canceled (session ending) or an unexpected fault
	// It journals nothing and logs through the standard logger. nil disables
	// auto-claim (setup falls back to manual paste only).
	PollClaim func(ctx context.Context, name string, onStatus func(status string)) (apiKeyID, stopCode string, err error)

	// WaitForClaim enables the non-interactive headless auto-claim path (`setup
	// --wait`): instead of printing the registration link and exiting, setup prints
	// the link, then blocks polling PollClaim until the key is claimed (or
	// WaitTimeout elapses) and binds + health-checks it automatically — no prompt,
	// no manual paste. It reuses the same PollClaim / VerifyAPIKey / Doctor seams as
	// the interactive auto-claim and works with or without a TTY (so an agent driving
	// the CLI never has to copy the issued id back). Ignored unless PollClaim is set.
	WaitForClaim bool
	// WaitTimeout bounds the headless wait; zero means wait indefinitely. Only
	// consulted when WaitForClaim is set.
	WaitTimeout time.Duration
}

KeyContext carries the dependencies the builtin key/setup commands need. It is exported so both cli root dispatch and the mcp server can drive the exact CLI key-creation path: mcp substitutes a buffer-backed IO to capture the JSON document for its tool result (see RunKeyCommand).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL