api

package
v0.1.0 Latest Latest
Warning

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

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

Documentation

Overview

Package api wires Wardyn's control-plane REST surface (the wardynd binary). It contains ZERO target-specific code (the parity rule): it talks to runners only through the runner.Runner interface, and to identity/secrets/broker only through their contract interfaces. Every security decision fails closed.

Route map (see the REST contract in the architecture brief):

Public (admin bearer):
  POST /api/v1/runs ; GET /api/v1/runs ; GET /api/v1/runs/{id}
  GET  /api/v1/runs/{id}/grants
  POST /api/v1/runs/{id}/kill
  GET  /api/v1/runs/{id}/attach   (WebSocket: interactive PTY)
  GET  /api/v1/approvals?state= ; POST /api/v1/approvals/{id}/approve|deny
  GET  /api/v1/audit?run_id=
  POST /api/v1/policies ; GET /api/v1/policies ; GET /api/v1/policies/{id}
  PUT  /api/v1/policies/{id} ; DELETE /api/v1/policies/{id}
  GET  /healthz
Internal (run-token bearer, identity.Provider.Verify aud="wardyn-internal"):
  POST /api/v1/internal/decisions
  POST /api/v1/internal/approvals ; GET /api/v1/internal/approvals/{id}
  POST /api/v1/internal/credentials/mint
Ground-truth (host-sensor bearer, identity.Provider.Verify aud="wardyn-groundtruth"):
  POST /api/v1/internal/groundtruth   (eBPF/Tetragon kernel-event batch)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func LoadPolicySpec

func LoadPolicySpec(path string) (types.RunPolicySpec, error)

LoadPolicySpec reads and validates a RunPolicySpec from a JSON file. Used by wardynd to seed the default policy from examples/policies/default.json.

Types

type ApprovalService

type ApprovalService interface {
	Request(ctx context.Context, req types.ApprovalRequest) (types.ApprovalRequest, error)
	Decide(ctx context.Context, id uuid.UUID, approve bool, decidedByType types.ActorType, decidedBy, reason string) (types.ApprovalRequest, error)
	Get(ctx context.Context, id uuid.UUID) (types.ApprovalRequest, error)
	List(ctx context.Context, state types.ApprovalState) ([]types.ApprovalRequest, error)
}

ApprovalService is the narrow approval FSM surface the API depends on. It is satisfied by package-level wrappers over internal/approval (see wardynd wiring), keeping the API decoupled from concrete storage.

type AuditSpool

type AuditSpool struct {
	// contains filtered or unexported fields
}

AuditSpool durably records audit events whose PRIMARY store write failed, so a security event is never silently lost (C1). The control-plane audit log is the system of record; silently dropping a credential.mint / run.kill / egress.deny event when the database blips would let a run proceed while reporting success — exactly the failure a governance tool must not have.

It is a mutex-guarded append-only JSONL file: intentionally simple, fit for the local-first single-host deployment, and lets an operator (or a future drain job) replay spooled events into the audit log once the store recovers. A nil *AuditSpool disables spooling (a failed primary write is then only logged loudly).

func NewAuditSpool

func NewAuditSpool(path string) (*AuditSpool, error)

NewAuditSpool opens (creating if needed) an append-only JSONL spool at path.

func (*AuditSpool) Append

func (a *AuditSpool) Append(ev types.AuditEvent) error

Append writes one event as a single JSON line and fsyncs it, so a crash right after a primary-write failure still preserves the event. It returns an error only when even the fallback write fails (the last-resort signal the event is lost).

type ComponentInfo

type ComponentInfo struct {
	Selected              string `json:"selected"`
	RecommendedProduction string `json:"recommended_production,omitempty"`
	Source                string `json:"source,omitempty"`
}

ComponentInfo describes one pluggable seam's selection for /healthz. Selected is ALWAYS the actual running implementation; RecommendedProduction is the standard Wardyn recommends converging to and may differ from Selected (and even from the shipped default — the honest recommended-vs-shipped split documented in docs/PLUGGABILITY.md). Source is "default" or "configured".

type ComposerBackendReadiness

type ComposerBackendReadiness struct {
	Name        string `json:"name"`
	Provider    string `json:"provider"`
	Model       string `json:"model"`
	Wire        string `json:"wire"`
	Transport   string `json:"transport,omitempty"` // normalized (HTTP wires => "api"); cli tool / fake variant
	Auth        string `json:"auth,omitempty"`      // openai azure only: apikey|entra
	Enabled     bool   `json:"enabled"`
	NeedsKey    bool   `json:"needs_key"`
	KeySecret   string `json:"key_secret,omitempty"`
	KeyResolved bool   `json:"key_resolved"`
}

ComposerBackendReadiness is the boot-snapshot readiness of one configured composer backend. KeySecret is a secret NAME (never a value); KeyResolved is whether that secret (or the env fallback) was present at boot.

type Config

type Config struct {
	// Store is the abstract persistence seam (run/policy/grant/approval/audit
	// CRUD + reads). The control plane talks to this instead of *pgxpool.Pool
	// directly, so a future pure-Go backend can be swapped in. Defaults to a
	// store.NewPG(Pool) adapter when wired from wardynd.
	Store store.Store
	// Pool is the Postgres pool. It backs the Store adapter and is retained for
	// the few collaborators that need a raw pool / transaction rather than the
	// single-call Store (broker tx beginner, identity revocation, the lifecycle
	// adapters wired in wardynd).
	Pool *pgxpool.Pool
	// Identity mints/verifies/revokes per-run identities (embedded by default).
	Identity identity.Provider
	// Approvals is the approval FSM service.
	Approvals ApprovalService
	// Broker mints credentials inside the approval-gated transaction.
	Broker MintBroker
	// Audit records control-plane-originated audit events.
	Audit audit.Recorder
	// AuditFallback durably spools an audit event whose PRIMARY store write
	// failed, so a security event is never silently lost when the database blips
	// (C1). Nil disables spooling (a failed write is then only logged loudly).
	AuditFallback *AuditSpool
	// Runner launches sandboxes. Nil => headless API-only mode.
	Runner runner.Runner
	// AdminToken gates the public API (constant-time bearer compare). Empty
	// disables the public API entirely (fail closed) except /healthz.
	AdminToken string
	// LocalMode enables LOCAL HOST MODE: the public-API auth (humanOrAdminAuth)
	// is bypassed entirely and every admin-gated action is attributed to
	// LocalOperator. This is the single-developer localhost path — no SSO, no
	// token, no Dex. It NEVER affects internalAuth (sidecar/run-token
	// verification), so the sidecar callback path is unchanged. The daemon
	// (cmd/wardynd) refuses LocalMode when bound to an EXPLICIT public IP, but
	// only WARNS (does not refuse) on an unspecified bind (0.0.0.0, the
	// WARDYN_LISTEN default) — operators must bind/publish loopback-only for a
	// real guarantee (the Compose default already publishes 127.0.0.1).
	LocalMode bool
	// LocalOperator is the principal stamped on runs/approvals/audit in
	// LocalMode (e.g. "local:<os-user>"). Ignored unless LocalMode is true.
	LocalOperator string
	// TrustDomain is surfaced in /healthz and used for run SPIFFE ids.
	TrustDomain string
	// DefaultPolicy is applied to runs created without an explicit policy_id.
	DefaultPolicy types.RunPolicySpec
	// RunnerTarget records which target a run is dispatched to ("docker"|"k8s").
	// Defaults to "docker"; "k8s" when a k8s runner is wired.
	RunnerTarget string
	// UIDir, when set, serves a SPA from this directory at "/".
	UIDir string
	// ControlPlaneURL is the externally-reachable base URL handed to sidecars
	// (proxy config) so they can call the internal endpoints.
	ControlPlaneURL string
	// ProxyURL, when set, overrides the WARDYN_PROXY_URL injected into sandbox
	// env. Defaults to "http://wardyn-proxy:3128" (the per-run proxy sidecar
	// hostname set by the docker driver). Non-secret: it is a network address,
	// not a credential.
	ProxyURL string
	// RecordingStore, when set, serves PTY session replays under
	// GET /api/v1/runs/{id}/recording/{id} (admin-gated) and accepts uploads
	// via PUT /api/v1/runs/{id}/recording (run-token auth).
	RecordingStore recording.Store
	// OIDC, when set, enables human SSO: it mounts /auth/login,/auth/callback,
	// /auth/logout and composes oidc.Middleware in front of the admin-gated API
	// so a valid session cookie OR the admin bearer token authenticates a caller.
	// The admin token still works for the CLI when OIDC is configured.
	OIDC *oidc.Authenticator
	// ImageBuilder, when set, builds a per-run sandbox image from the
	// devcontainer_repo in a create-run request. Nil disables devcontainer
	// builds (the request degrades to the convention image).
	ImageBuilder ImageBuilder
	// AgentImages, when set, is an agent-name -> OCI image-ref map that
	// overrides the ghcr convention image for named agents. Agents not present
	// in the map fall back to the convention. Validated at server construction
	// (must parse if set); nil disables the override and the convention is used
	// for every agent.
	AgentImages map[string]string
	// AgentAnthropicModel, when set, pins the ANTHROPIC_MODEL env inside a
	// claude-code sandbox (e.g. "opus") so the agent uses a specific model rather
	// than the account/CLI default (which a promo can push to a cheaper model like
	// Fable). Empty = unset; the CLI's own default is used. Applies in both
	// subscription and api-key auth modes.
	AgentAnthropicModel string
	// BedrockRegion / BedrockModel, when BOTH set, opt a claude-code run into the
	// Amazon Bedrock Anthropic transport (CLAUDE_CODE_USE_BEDROCK) instead of the
	// default api-key/proxy-inject path — an enterprise path with no direct
	// Anthropic egress, billed via AWS. BedrockModel is a Bedrock model id (a
	// cross-region inference-profile id like "us.anthropic.claude-..." is what
	// claude-code actually expects, not a bare foundation-model id). Boot-time
	// config only (mirrors AgentAnthropicModel — no live admin write path); the
	// AWS credentials themselves come from the secret store (aws-access-key-id /
	// aws-secret-access-key / optional aws-session-token), read directly at
	// dispatch time because Bedrock's AWS SigV4 request signing can't be
	// proxy-injected the way a static x-api-key header can (see runs.go
	// resolveBedrockAuth). Empty BedrockRegion or BedrockModel disables Bedrock
	// entirely; a subscription-mode run always takes priority over Bedrock.
	BedrockRegion string
	BedrockModel  string
	// Secrets is the at-rest secret store. It backs the admin secret-management
	// endpoints (PUT/DELETE/list — values are NEVER readable via the API) and
	// the internal injection-resolve endpoint the proxy calls at startup. Nil
	// disables both surfaces.
	Secrets secretstore.Store
	// MaskRegistry, when non-nil, is used to mask verbatim secret values from
	// PTY capture / asciicast uploads before they reach the RecordingStore.
	// A nil registry disables masking (existing tests stay green).
	MaskRegistry *secretmask.Registry
	// SubscriptionToken, when non-nil, yields the operator's LIVE Anthropic
	// subscription OAuth access token from the resident ~/.claude credentials.
	// The internal injection-resolve endpoint uses it to inject a fresh token
	// per request for subscription runs (secret name subscriptionOAuthSecret),
	// so the sandbox holds only an inert sentinel instead of a copy that goes
	// stale. Nil disables the subscription-injection path (falls back to the
	// resident-copy behavior).
	SubscriptionToken subscription.Provider
	// DisableSubscriptionInject is the operator ESCAPE HATCH: when true (env
	// WARDYN_SUBSCRIPTION_INJECT=off), subscription runs keep the legacy
	// resident-copy behavior (the mounted credential, which can go stale) instead
	// of auto-enabling TLS-MITM + injecting the live host token. Default false =
	// the safe proxy-side default whenever a SubscriptionToken provider is wired.
	DisableSubscriptionInject bool
	// Now is overridable in tests; defaults to time.Now.
	Now func() time.Time
	// BaseCtx is the process-lifetime base context used for detached background
	// work that MUST outlive the request that started it — specifically the
	// completion watcher dispatch starts after Exec. The request/dispatch ctx is
	// cancelled when the HTTP handler returns, which would kill a watcher
	// immediately; BaseCtx (threaded from main.go's rootCtx) keeps it alive for
	// the lifetime of the daemon and is cancelled on shutdown. Defaults to
	// context.Background() when unset (the watcher then only stops on process
	// exit).
	BaseCtx context.Context
	// Composer, when set and Enabled(), powers the AI Run Composer endpoints
	// (POST /api/v1/runs/compose, GET /api/v1/composer/backends): a registry of
	// LLM backends turns a natural-language task description into a PROPOSED
	// {run, inline_policy} that Wardyn risk-grades deterministically and clamps to
	// DefaultPolicy before returning for human approval. Nil / not-Enabled
	// disables the endpoints (404), so the feature is strictly opt-in.
	Composer composer.Registry
	// Components advertises, per pluggable seam (identity, secret_store,
	// recording, policy_engine, sandbox, ...), the SELECTED running implementation
	// and the recommended production default, for honest /healthz visibility. Nil
	// => the components object is omitted.
	Components map[string]ComponentInfo
	// AgeKeyDurable reports whether the secret store's age key was SUPPLIED
	// (WARDYN_AGE_KEY/-age-key non-empty) vs ephemerally generated at boot. When
	// false, stored secrets are unreadable after a restart — surfaced by
	// /setup/status as a durability warning. Computed at boot in cmd/wardynd.
	AgeKeyDurable bool
	// LocalLoopback reports whether the HTTP listen address binds only loopback.
	// It feeds SetupAuth.LocalLoopback so the wizard can explain the local-mode
	// posture. Computed at boot in cmd/wardynd (listenIsLoopback).
	LocalLoopback bool
	// ComposerBackends is the BOOT-snapshot readiness of every configured composer
	// backend (including disabled + needs-key ones the live registry can't show).
	// Surfaced by /setup/status and used to compute restart_required drift. Nil
	// when the composer is unconfigured.
	ComposerBackends []ComposerBackendReadiness
	// ScanAIAdvisor, when non-nil, enables the ADVISORY AI workspace-scan fallback
	// (internal/workspacescan/ai.go): after the deterministic DeriveProfile, when
	// the profile is low-confidence or left unrecognized samples (ShouldAdvise),
	// this gap-fills EMPTY fields only and can only RAISE NeedsReview — it never
	// overrides a deterministic fact and FAILS OPEN (any error keeps the
	// deterministic profile unchanged and the upload still succeeds). Nil (default)
	// = feature OFF, byte-identical to the deterministic-only behavior. Production
	// wires it (from WARDYN_SCAN_AI_ADVISOR) to a workspacescan.AdviseProfile
	// closure; it doubles as the test seam so tests inject a fake instead of
	// shelling out to a real coding-agent CLI.
	ScanAIAdvisor func(context.Context, workspacescan.ScanFacts, workspacescan.WorkspaceProfile) workspacescan.WorkspaceProfile
}

Config holds the API server's non-secret configuration and injected collaborators. All interface fields except Runner are required; Runner may be nil for headless API-only operation (runs stay PENDING with a clear message).

type ImageBuilder

type ImageBuilder interface {
	// BuildDevcontainer builds the devcontainer for repoURL@ref and returns the
	// local image reference to run. outputTag is the deterministic per-run tag
	// the result is committed under.
	BuildDevcontainer(ctx context.Context, repoURL, ref, outputTag string) (imageRef string, err error)
	// BuildFromDevcontainerFiles builds an image from IN-MEMORY generated
	// devcontainer files (relative path -> content, e.g.
	// ".devcontainer/devcontainer.json") rather than a repo checkout, returning
	// the local image reference. It drives the SAME hardened envbuilder path as
	// BuildDevcontainer. Used for an onboarded workspace WITHOUT a wired
	// devcontainer, where core A generates a minimal one from the detected
	// profile (plan A5). outputTag is the deterministic profile-hash-keyed tag
	// the result is committed under.
	BuildFromDevcontainerFiles(ctx context.Context, files map[string]string, outputTag string) (imageRef string, err error)
}

ImageBuilder builds a per-run sandbox image from a devcontainer repo. It is target-agnostic (the parity rule): the concrete envbuilder implementation is wired in wardynd behind the "docker" build tag, so the control-plane default build carries zero target-specific code. Nil disables devcontainer builds.

type MintBroker

type MintBroker interface {
	MintForGrant(ctx context.Context, caller *identity.Claims, grantID uuid.UUID) (broker.Minted, error)
	RevokeRun(ctx context.Context, runID uuid.UUID) error
}

MintBroker is the credential-mint surface the API depends on (internal/broker).

type RecordTaskResult

type RecordTaskResult struct {
	RunID uuid.UUID `json:"run_id"`
	// Label is the operator-chosen session name (e.g. "build & test"). Persisted
	// because sessions are user-named, not derived — the session key is a slug of
	// this, so the label carries the original display text.
	Label string `json:"label,omitempty"`
	Mode  string `json:"mode"` // auto | interactive
	// Confined distinguishes a VERIFY session (default-deny egress, limited to the
	// workspace's approved set + baseline) from a learning session (open egress).
	// Same interactive attach machinery; the flag flips AllowAllEgress and lets the
	// UI list learning sessions on the Record step and verify sessions on Verify.
	Confined bool `json:"confined,omitempty"`
	// LLMMode + Model record the auth the session actually ran with (the operator's
	// configured provider): subscription | api-key | none, plus the pinned model.
	// Saved with the session so it's visible and a verify replays the SAME auth as
	// the recording (the operator's setup, not a re-derived guess).
	LLMMode    string     `json:"llm_mode,omitempty"`
	Model      string     `json:"model,omitempty"`
	Status     string     `json:"status"` // recording | recorded | record_failed
	StartedAt  time.Time  `json:"started_at"`
	FinishedAt *time.Time `json:"finished_at,omitempty"`
	// Steps is the auto-mode per-command outcome (re-derived, capped, masked —
	// the same DeriveVerifyResult lane verify uses). Nil for interactive runs.
	Steps []workspacescan.VerifyStepResult `json:"steps,omitempty"`
	// Observations is the deterministic recordmode.Capture aggregate of what the
	// run ACTUALLY used, computed server-side from its audit events at
	// termination — never from a sandbox upload.
	Observations *recordmode.Observations `json:"observations,omitempty"`
	// SecretNamesMinted resolves Observations.MintedGrantIDs to the secret /
	// grant names actually exercised, for the "proven used" checklist render.
	SecretNamesMinted []string `json:"secret_names_minted,omitempty"`
	// EgressPromoted marks that this task's observed hosts were merged into the
	// workspace's ApprovedEgress (operator action, never automatic).
	EgressPromoted bool `json:"egress_promoted,omitempty"`
	// KernelSensorBlind: the run executed under CC3/Kata where the host eBPF
	// sensor cannot see — proxy decisions were the sole egress signal.
	KernelSensorBlind bool `json:"kernel_sensor_blind,omitempty"`
	// FailureHint explains a record_failed in operator terms (e.g. the sandbox
	// couldn't reach the control plane, so no evidence landed).
	FailureHint string   `json:"failure_hint,omitempty"`
	Caveats     []string `json:"caveats,omitempty"`
}

RecordTaskResult is one task's Record Mode state, persisted opaquely in workspaces.record_results (map taskKey → RecordTaskResult). The api layer owns this shape; the store never interprets it.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the control-plane HTTP server. It is safe for concurrent use.

func New

func New(cfg Config) *Server

New constructs a Server and builds its router. It does not start listening.

func (*Server) Handler

func (s *Server) Handler() http.Handler

Handler returns the configured http.Handler (the chi router).

func (*Server) ReconcileOnBoot

func (s *Server) ReconcileOnBoot(ctx context.Context) error

ReconcileOnBoot re-derives the state of every run left non-terminal by a PREVIOUS wardynd process (a crash, OOM, deploy, or Ctrl-C) so it is not stranded RUNNING forever with a live sandbox and un-revoked credentials (C3). The per-run completion watcher is an in-process goroutine that does not survive a restart; this rebuilds the safety net at boot. Best-effort: errors are logged, never fatal. Re-attached watchers run on the daemon base context so they outlive this call. Status (unlike Wait) reconstructs from the container's run-id label, so it works even though the previous process's in-memory exec state is gone.

type SetupAgeKey

type SetupAgeKey struct {
	Durable bool `json:"durable"`
}

SetupAgeKey reports whether the secret store survives a restart (a stable WARDYN_AGE_KEY was supplied vs an ephemeral generated one).

type SetupAuth

type SetupAuth struct {
	Mode          string `json:"mode"`
	LocalLoopback bool   `json:"local_loopback"`
}

SetupAuth is the active public-API auth mode: local (loopback bypass) | sso (OIDC) | token (admin bearer) | disabled (no auth configured, API closed).

type SetupBedrock

type SetupBedrock struct {
	Region       string `json:"region,omitempty"`
	Model        string `json:"model,omitempty"`
	CredsPresent bool   `json:"creds_present"`
}

SetupBedrock is the Amazon Bedrock Anthropic-transport readiness snapshot.

type SetupCheck

type SetupCheck struct {
	ID       string `json:"id"`
	Label    string `json:"label"`
	Status   string `json:"status"`
	Platform string `json:"platform,omitempty"`
	Detail   string `json:"detail,omitempty"`
	Fix      string `json:"fix,omitempty"`
}

SetupCheck is one environment/readiness row. Status is ok|warn|fail|info; "info" is a permanent, non-fixable condition (e.g. no /dev/kvm on macOS) that must render as informational, not as a clearable warning. Platform lets the UI show environment-appropriate copy (linux|darwin|windows|wsl|any).

type SetupComposer

type SetupComposer struct {
	Enabled  bool                       `json:"enabled"`
	Default  string                     `json:"default,omitempty"`
	Backends []ComposerBackendReadiness `json:"backends"`
}

SetupComposer is the composer enablement plus each configured backend's readiness (a BOOT snapshot, so it can surface disabled + needs-key states the live registry alone can't show).

type SetupDeployment

type SetupDeployment struct {
	HostLike bool `json:"host_like"`
}

SetupDeployment reports whether the wardynd process itself sees a resident Claude login — true in host mode (run-host.sh: wardynd runs as the operator, ~/.claude + the claude binary are on its own PATH/HOME), false in the compose path (distroless container blind to the host). HONEST framing like detectKVM: this is "does THIS process see a resident claude", not "is it literally run-host.sh" — a compose container with ~/.claude bind-mounted would also read host-like. The UI uses it to fork the getting-started guidance (laptop/local vs team/server) and to explain why the LLM-access check is or isn't green.

type SetupFix

type SetupFix struct {
	Action      string `json:"action"` // "add_secret" | "scan_workspace" | "none"
	SecretName  string `json:"secret_name,omitempty"`
	WorkspaceID string `json:"workspace_id,omitempty"` // ID, not source — api.scanWorkspace takes an id
}

SetupFix is the structured, actionable remedy a UI button drives directly — no prose-parsing. Action "none" means informational only: there is no button, because the only fix is the OPERATOR widening their own ceiling (e.g. a dropped egress domain).

ponytail: v1 verifies PRESENCE only (Decision 3: declared-present, never "verified" in the UI copy) — a stored secret, an onboarded+scanned workspace, a surviving grant. Live credential verification (does the key actually authenticate?) is a FUTURE seam at the egress proxy (broker-verified calls), not here — this stays a fast, pure read of already-stored state, no live probe and no new injection surface.

type SetupItem

type SetupItem struct {
	Kind       string    `json:"kind"` // "llm_access" | "secret" | "workspace" | "workspace_secret" | "repo_credential" | "egress" | "backend" | "config_pair"
	ID         string    `json:"id"`   // stable "<kind>:<key>", e.g. "secret:anthropic-api-key"
	Label      string    `json:"label"`
	RequiredBy string    `json:"required_by"`
	Status     string    `json:"status"` // "satisfied" | "missing" | "unverified"
	Detail     string    `json:"detail,omitempty"`
	Fix        *SetupFix `json:"fix,omitempty"`
	// Residency names WHERE the credential this item concerns actually lives at
	// run time, derived from the FINAL spec's own delivery mechanism (never
	// guessed): "proxy_injected" (an api_key grant — the value never leaves the
	// wardyn-proxy sidecar, injection.go), "resident_mount" (a host credential
	// bind-mounted into the sandbox, e.g. the Claude subscription mount), or
	// "brokered_mint" (a github_token/git_pat grant — the broker mints/resolves
	// a value and hands it directly to the in-sandbox git-credential helper at
	// task time, internal.go handleInternalMint). Empty when not applicable
	// (workspace/egress/backend rows carry no single credential).
	Residency string `json:"residency,omitempty"`
}

SetupItem is a per-requirement readiness verdict for a composed run, computed DETERMINISTICALLY from the FINAL post-clamp spec (never LLM self-assessment) — the same trust rule composer.Grade uses (risk.go:72). It generalizes the composeLLMAccess pattern (compose.go:121-127) to every setup requirement a proposal implies: secrets, onboarded workspaces, repo credentials, egress.

ponytail: NOT SetupCheck (setup.go:72) — that type's Fix is free-text prose for a human to read; SetupItem's Fix is a structured action a UI button can drive directly (add_secret/scan_workspace), so it needs its own shape rather than reusing SetupCheck's.

type SetupPlatform

type SetupPlatform struct {
	OS  string `json:"os"`
	WSL bool   `json:"wsl"`
	// KVM: the host exposes /dev/kvm — lets the UI split Vault's "incompatible
	// with this hardware" from a fixable "needs setup" (additive; old UIs ignore).
	KVM bool `json:"kvm"`
}

SetupPlatform is the wardynd host's OS + WSL posture.

type SetupProvider

type SetupProvider struct {
	Tool             string `json:"tool"`
	Installed        bool   `json:"installed"`
	LoggedIn         bool   `json:"logged_in"`
	LoginDetectedVia string `json:"login_detected_via,omitempty"`
	// AuthMode is how the CLI authenticates, when detectable: "subscription" (a
	// resident Claude OAuth token is present — fresh OR expired; freshness lives in
	// the llm_provider check Detail, not here) or "" (unknown; never guessed). The
	// "api_key" value is reserved in the contract but not inferred for a CLI (no
	// cheap honest signal); codex stays "" (no auth-file parse).
	AuthMode string `json:"auth_mode,omitempty"`
}

SetupProvider is a resident coding-agent CLI (claude|codex) detected on PATH. LoggedIn is ADVISORY (a home-dir credential-file heuristic, not a live check).

type SetupRunner

type SetupRunner struct {
	Driver                string            `json:"driver"`
	ConfinementClasses    []string          `json:"confinement_classes"`
	ConfinementSubstrates map[string]string `json:"confinement_substrates,omitempty"`
}

SetupRunner echoes the runner name and the live confinement classes/substrates.

type SetupSecrets

type SetupSecrets struct {
	Present   []string `json:"present"`
	GitHubApp bool     `json:"github_app"`
}

SetupSecrets reports present secret NAMES (reserved names excluded) and a convenience bool for whether both GitHub App secrets are set.

type SetupStatus

type SetupStatus struct {
	// Ready is server-computed and CONSERVATIVE (false when the runner is nil),
	// so the wizard opens rather than hiding a half-configured bootstrap.
	Ready bool `json:"ready"`
	// Checks is the single list of environment/readiness rows the UI renders.
	Checks []SetupCheck `json:"checks"`
	// Auth is the active public-API auth posture.
	Auth SetupAuth `json:"auth"`
	// Runner is the sandbox runner + the confinement classes actually live on
	// this host (from Runner.Capabilities, same source as /healthz).
	Runner SetupRunner `json:"runner"`
	// Composer is the AI Run Composer enablement + per-backend readiness snapshot.
	Composer SetupComposer `json:"composer"`
	// Providers reports resident coding-agent CLIs detected on the wardynd host.
	Providers []SetupProvider `json:"providers"`
	// Secrets reports which known secrets are present (NAMES only, reserved
	// names excluded) — never any value.
	Secrets SetupSecrets `json:"secrets"`
	// AgeKey reports whether the at-rest secret store survives a restart.
	AgeKey SetupAgeKey `json:"age_key"`
	// RestartRequired is true when a boot-only consumer (composer registry) has a
	// newly-available secret that will not take effect until wardynd restarts.
	// RestartReason names it. Run-time/mint-time secrets (api_key grants, git_pat,
	// the lazy GitHub minter) never set this — they are live immediately.
	RestartRequired bool   `json:"restart_required"`
	RestartReason   string `json:"restart_reason,omitempty"`
	// HasRuns drives the wizard's "launch your first run" done state.
	HasRuns bool `json:"has_runs"`
	// Platform is the OS + WSL posture the environment-step copy keys off.
	Platform SetupPlatform `json:"platform"`
	// HostProxy is the host-side proxy detection (env/shell/git/tool-config/OS)
	// the Host Proxy Getting-Started step renders. Read-only detection; it
	// never configures anything (the upstream-proxy plumbing is separate).
	HostProxy setup.HostProxyDetection `json:"host_proxy"`
	// Bedrock is the AWS Bedrock Anthropic-transport readiness the "Connect a
	// model" step renders alongside the API-key/subscription rows. Region/Model
	// are boot-time operator config (non-secret, safe to echo); the AWS
	// credentials themselves are never echoed — CredsPresent is a bool derived
	// from secret-name presence, same as every other secret in this contract.
	Bedrock SetupBedrock `json:"bedrock"`
	// Deployment reports whether wardynd itself sees a resident Claude login
	// (host mode) or is blind to it (compose/container).
	Deployment SetupDeployment `json:"deployment"`
}

SetupStatus is the aggregate readiness snapshot for GET /api/v1/setup/status.

Jump to

Keyboard shortcuts

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