Documentation
¶
Overview ¶
Package enroll handles agent authentication for the hosted control plane: per-agent enrollment tokens (validated against Neon) and the browser-session + PKCE handshake behind `ushr login`. See DESIGN-enrollment.md.
OSS single-host does not use this — it keeps the static shared token (or loopback with no token). Enrollment is the hosted, multi-tenant path.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type PG ¶
type PG struct {
// contains filtered or unexported fields
}
PG is the Neon-backed enroll.Store. The hosted web app web app writes agent_tokens (mint) and approves cli_sessions; this reads/validates and serves the CLI poll. It shares the control plane's pgxpool (see NewWithPool).
func NewWithPool ¶
NewWithPool applies any unapplied enrollment migrations on an existing pool and returns a store sharing it (the control plane's dispatch store owns the pool's lifetime). An advisory lock serializes concurrent boots.
func (*PG) CreateSession ¶
func (p *PG) CreateSession(id, challenge string, meta SessionMeta) error
CreateSession records a pending login session and prunes expired ones.
func (*PG) FetchSession ¶
func (p *PG) FetchSession(id, verifier string) (Session, SessionStatus, error)
FetchSession consumes an approved session and returns its token. The delete and read are one statement, so a session is single-use: two racing fetches can't both receive the token. A wrong verifier fails the challenge match and reads as expired — no oracle for pending vs unknown.
type SessionMeta ¶
type SessionMeta struct {
// AgentName is the enrolling host's own declared name (its agent config
// name or hostname). The approval page displays it read-only.
AgentName string
// RequesterIP is the CLI's egress address as seen by the control plane.
RequesterIP string
// UserCode is the short confirmation code the CLI prints; the approver
// checks it matches the page before approving (RFC 8628-style binding).
UserCode string
}
SessionMeta is requester context captured at session creation and shown on the browser approval page, so the approver can recognize (or reject) the machine asking to enroll — the defense against device-flow phishing.
type SessionStatus ¶
type SessionStatus int
SessionStatus is the state of a CLI login session when the CLI polls for it.
const ( // Pending: the browser side hasn't approved yet. Pending SessionStatus = iota // Ready: approved, token available. Ready // Expired: unknown or past its TTL. Expired )
type Store ¶
type Store interface {
// ValidateToken reports the orgs an enrollment token may serve and the agent
// name it is bound to. A token covers the set of orgs the enrolling account
// selected (all verified by that account), so one agent can serve several.
// ok is false for unknown or revoked tokens; errors are treated as not-ok.
ValidateToken(token string) (orgs []string, name string, ok bool)
// CreateSession records a pending login session (idempotent on id).
CreateSession(id, challenge string, meta SessionMeta) error
// FetchSession returns the approved Session iff verifier matches the stored
// challenge, consuming it. Pending/expired sessions return no token.
FetchSession(id, verifier string) (Session, SessionStatus, error)
}
Store authenticates enrollment tokens and drives the CLI login handshake. The web app (hosted web app) writes agent_tokens and approves cli_sessions; the control plane only reads/validates here.