app

package
v0.0.0-...-f045d41 Latest Latest
Warning

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

Go to latest
Published: May 29, 2026 License: Apache-2.0 Imports: 66 Imported by: 0

Documentation

Overview

Package app wires together the Aileron control plane components and exposes them as an http.Handler. It is imported by the standalone server binary.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewHandlerWithConfig

func NewHandlerWithConfig(log *slog.Logger, cfg Config) (http.Handler, error)

NewHandlerWithConfig is the configurable entry point. The launcher uses this with a passphrase-unlocked Vault; the standalone server binary uses NewHandler (dev-mode fallback).

func RequestID

func RequestID(ctx context.Context) string

RequestID returns the request ID from the context, or empty string if none.

Types

type Config

type Config struct {
	// Vault overrides the default in-memory random-KEK vault. Pass a
	// vault produced by [vault.Init] / [vault.Unlock] when the
	// runtime is being driven by `aileron launch`, so credentials
	// land in the user's encrypted file at ~/.aileron/secrets.json
	// rather than in a process-lifetime memory vault.
	Vault vault.Vault

	// WebappURL is the base URL the action-approval review surface is
	// reachable at (#418). The notification's ReviewURL is built as
	// `<WebappURL>/approvals?focus=<id>` so the terminal-printed block
	// and agent-facing approval message carry a per-approval deep link
	// the user can click or re-open via `aileron open approval <id>`.
	//
	// The daemon serves the webapp itself (see webapp_embed.go), so the
	// natural default is the daemon's own bound URL. Production wiring
	// (`internal/server`) sets that default after binding. This field
	// and the `AILERON_WEBAPP_URL` environment variable are overrides
	// for deployments where the daemon's bound URL is not what users
	// hit: reverse-proxied installs, `--bind 0.0.0.0:...` containers, or
	// a future split-origin webapp.
	//
	// Precedence: cfg.WebappURL (this field) → AILERON_WEBAPP_URL env →
	// empty. Empty surfaces a generic prompt instead of a URL — the
	// operator at least learns something needs attention.
	WebappURL string

	// LocalDaemonToken enables always-on bearer authentication for the
	// local daemon's /v1/* surface. CLI and in-container clients read
	// the token from daemon.json and send Authorization: Bearer <token>.
	// The local webapp obtains an HttpOnly same-origin cookie through
	// GET /v1/auth/handshake so EventSource can authenticate too.
	LocalDaemonToken string

	// Notifier overrides the default notification dispatcher (log +
	// terminal multi). Production wiring leaves this nil; tests inject
	// a recorder to observe the action-approval notification payload
	// without writing to stderr. The injected notifier replaces the
	// default — when set, no log / terminal notifications fire from
	// this handler, only the supplied notifier.
	Notifier notify.Notifier

	// LocalVaultPath, when set, runs the daemon with a deferred-unlock
	// local file vault (#429): NewHandlerWithConfig wraps the supplied
	// Vault in a [vault.LockableVault] and marks vaultLocked = true.
	// Vault-needing endpoints return 423 Locked until the user POSTs
	// their passphrase to /v1/vault/unlock — typically via the webapp
	// passphrase modal.
	//
	// Distinct from Vault: when LocalVaultPath is set, Vault is the
	// initial (locked) inner — usually nil, so the LockableVault
	// returns ErrCredentialUnavailable on credential reads until
	// unlock. Setting Vault to a pre-unlocked vault while also
	// setting LocalVaultPath is supported (`vaultLocked` stays false)
	// for tests that want to drive the UnlockLocalVault handler
	// without provisioning a real vault file.
	LocalVaultPath string

	// ActionApprovals overrides the default in-process action-
	// approval queue. Production wiring under `aileron launch`
	// passes a shared queue here so the embedded gateway *and* the
	// CommsServer (which fields `aileron-mcp`'s send-shaped tool
	// calls per #428) register their pending entries on the same
	// queue — one webapp surface, one SSE stream, one decision path.
	// Nil falls back to a fresh queue, preserving the historic
	// behaviour for callers that don't need cross-component sharing.
	ActionApprovals *approval.ActionApprovalQueue

	// ActionApprovalPersister is the durable backing for the
	// action-approval queue (#649). Wired alongside the queue itself;
	// every state transition is appended so a daemon restart can
	// resume in-flight approvals. The daemon constructs a JSONL-
	// backed store pointed at ~/.aileron/approvals.jsonl and passes
	// it here. Nil keeps the queue purely in-memory (tests / cloud-
	// shaped daemons).
	ActionApprovalPersister approval.Persister

	// LoadedActionApprovals seeds the queue from a previously-
	// persisted snapshot at startup. Records arrive in registration
	// order; entries left in [approval.OutcomeRunning] at replay
	// have already been reaped by the wiring layer (mapped to
	// [approval.OutcomeFailed] with a reconciliation reason) before
	// they are passed here, so the queue can load them verbatim.
	// Non-terminal entries get respawned executor goroutines after
	// the queue is fully wired. Nil / empty disables replay.
	LoadedActionApprovals []approval.PersistedRecord

	// Sessions is the persistent store for `aileron launch` session
	// records (ADR-0012). The daemon constructs a JSONL-backed store
	// pointed at ~/.aileron/sessions.jsonl and passes it here. Nil
	// disables the /v1/sessions endpoints — they return 503 — which
	// is the right behavior for cloud-shaped deployments and tests
	// that don't exercise the launch session surface.
	Sessions sessions.Store

	// NotifyQueue is the daemon-wide queue of incoming channel
	// messages (ADR-0012, step 9B-2). Populated by listener goroutines
	// after [OnVaultUnlock] resolves credentials; consumed by the
	// `/v1/sessions/{id}/comms/messages` endpoint that powers
	// `aileron-mcp`'s `read_messages` tool. Nil disables every comms
	// endpoint.
	NotifyQueue *comms.NotifyQueue

	// Listeners is the registry of active channel listeners keyed
	// by service name. Populated by the vault-unlock callback;
	// consumed by `/comms/send` and `/comms/draft` to dispatch
	// outbound messages after the user approves. Pair with
	// [NotifyQueue] — both nil or both set.
	Listeners *comms.ListenerRegistry

	// OnVaultUnlock fires after a successful POST /v1/vault/unlock,
	// stamped with the freshly-unlocked vault. The daemon registers
	// a callback here when channel listeners need credentials
	// resolved at unlock time. Nil is fine for tests / cloud
	// daemons that have nothing to do on unlock.
	//
	// Synchronous from the perspective of the unlock handler — the
	// HTTP response holds open until the callback returns. Listener
	// startup itself is fire-and-forget inside the callback so the
	// handler never blocks on remote handshakes.
	OnVaultUnlock func(vault.Vault)

	// AuditStateDir scopes the daily-rotated `audit-YYYY-MM-DD.jsonl`
	// files that `message_received` events land in. Empty disables
	// audit emission for inbound messages. Production passes
	// ~/.aileron; tests pass t.TempDir().
	AuditStateDir string
}

Config customizes NewHandlerWithConfig. The zero value is valid: every field is optional and defaults reproduce the historic [NewHandler] behaviour.

Jump to

Keyboard shortcuts

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