onboard

package
v0.22.165 Latest Latest
Warning

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

Go to latest
Published: May 25, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package onboard hosts reusable wizard-step building blocks for the clawtool onboard flow. ADR-036 Phase 1 lands the first step here — DeviceCodeStep — so the OAuth Device Authorization Grant (RFC 8628) prompt has one home that both the interactive wizard (internal/cli/onboard*) and the headless `clawtool agent claim` path can call into without duplicating the poller / UX glue.

Why a tiny package instead of a method on the wizard model:

  • The agent-claim recipe runs outside the Bubble Tea wizard, so it needs the step as a library function it can drive directly with stdout-shaped UX hooks. A method on internal/cli's wizard model would couple the recipe to the TUI.
  • The step is the natural seam for additional issuers (per- source OAuth, hosted-clawtool sign-in) so they all share one persistence / error-handling shape.

What the step does NOT own: the issuer's client_id, the secrets scope name, the verification-URL renderer. Those are caller- supplied via Step.Config / Step.Render so the wizard can wrap them in lipgloss while the recipe path stays plain stdout.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type DefaultSecretsSink

type DefaultSecretsSink struct{}

DefaultSecretsSink is the production sink: load + Set + Save secrets.toml at the canonical path with mode 0600. Idempotent.

func (DefaultSecretsSink) Save

func (DefaultSecretsSink) Save(scope, key, value string) error

Save loads the canonical secrets store, writes (scope, key) = value, and saves at mode 0600.

type PromptInfo

type PromptInfo struct {
	UserCode                string
	VerificationURI         string
	VerificationURIComplete string
	ExpiresInSeconds        int
}

PromptInfo is what DeviceCodeStep hands to the renderer once the issuer returns the device-code envelope. The renderer's job is to surface UserCode + VerificationURI to the operator (and ideally launch a browser to VerificationURIComplete / VerificationURI). The step blocks on Poll until the renderer returns; renderer return value is informational (logged upstream) and never aborts the poll.

type Renderer

type Renderer func(PromptInfo)

Renderer is the caller-provided UX hook. Wizards wrap this in their boxed UX; the agent-claim recipe uses a stdout shim. A nil Renderer is fine — the step then only logs the user-code to ctx-Err and the operator never sees it. Default callers always provide one.

type SecretsSink

type SecretsSink interface {
	Save(scope, key, value string) error
}

SecretsSink is the persistence contract. The default sink writes to ~/.config/clawtool/secrets.toml under the configured scope; tests inject an in-memory sink so they don't touch the operator's real file. Save returns nil on success, the underlying error on failure (the step then surfaces a "saved-but-poll-succeeded" message so the operator knows the token is in memory but not durable).

type Step

type Step struct {
	// Cfg is the issuer-specific devicecode.Config (endpoints,
	// client_id, scopes). Required.
	Cfg devicecode.Config
	// SecretsScope is the secrets.toml [scopes.<scope>] table
	// the access token is written under. Required.
	SecretsScope string
	// SecretsKey is the field name within the scope. Defaults
	// to "oauth_token" so existing star.go-style callers don't
	// need to override.
	SecretsKey string
	// Render is the UX hook invoked once with the device code
	// envelope. Optional but strongly recommended.
	Render Renderer
	// Sink is where the token lands. Defaults to
	// DefaultSecretsSink (XDG secrets.toml, mode 0600).
	Sink SecretsSink
}

Step orchestrates one OAuth Device Authorization Grant. Construct via NewDeviceCodeStep; Run executes the full sequence (request → render → poll → persist) and returns the token + a non-nil error iff the flow failed before persistence.

func NewDeviceCodeStep

func NewDeviceCodeStep(cfg devicecode.Config, scope string, render Renderer) *Step

NewDeviceCodeStep returns a Step with sane defaults filled in (SecretsKey="oauth_token", Sink=DefaultSecretsSink). The caller must still set Cfg + SecretsScope.

func (*Step) Run

func (s *Step) Run(ctx context.Context) (string, error)

Run executes the full device-code flow. Returns the access token on success; on failure returns the underlying error (wrapping devicecode.ErrAuthorizationDenied, ErrDeviceCodeExpired, etc. so callers can errors.Is them).

Persistence is best-effort: a Save failure is appended to the returned error chain but the token itself is still returned so the caller can use it for the rest of the session.

Jump to

Keyboard shortcuts

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