Documentation
¶
Overview ¶
Package daemon implements the proxy daemon's management API.
Backwards Compatibility ¶
The daemon is a long-lived process that may run a different binary version than the CLI or the moat-run process. This happens during development (rebuilding moat while runs are active) and during upgrades.
To keep old and new versions interoperable, the daemon API follows these rules:
- Additive only: new fields in request/response structs are fine (encoding/json ignores unknown fields). Never remove or rename fields.
- New endpoints are fine: old clients won't call them. New clients must handle 404 gracefully when talking to an older daemon.
- Never change the semantics of existing fields.
When adding new API surface, consider: "will a CLI built today still work if the daemon is an older binary?" and vice versa.
Package daemon implements the proxy daemon for multi-run credential injection.
Index ¶
- Variables
- func RemoveLockFile(dir string)
- func RestoreRuns(ctx context.Context, registry *Registry, runs []PersistedRun) int
- func StartTokenRefresh(ctx context.Context, rc *RunContext, grants []string)
- func WriteLockFile(dir string, info LockInfo) error
- type AWSConfig
- type Client
- func (c *Client) Health(ctx context.Context) (*HealthResponse, error)
- func (c *Client) ListRuns(ctx context.Context) ([]RunInfo, error)
- func (c *Client) RegisterRoutes(ctx context.Context, agent string, services map[string]string) error
- func (c *Client) RegisterRun(ctx context.Context, regReq RegisterRequest) (*RegisterResponse, error)
- func (c *Client) Shutdown(ctx context.Context) error
- func (c *Client) UnregisterRoutes(ctx context.Context, agent string) error
- func (c *Client) UnregisterRun(ctx context.Context, token string) error
- func (c *Client) UpdateRun(ctx context.Context, token, containerID string) error
- type CommandContainerChecker
- type ContainerChecker
- type CredentialEntry
- type CredentialSpec
- type ExtraHeaderEntry
- type ExtraHeaderSpec
- type HealthResponse
- type IdleTimer
- type LivenessChecker
- type LockInfo
- type PersistedRun
- type RegisterRequest
- type RegisterResponse
- type Registry
- func (r *Registry) Count() int
- func (r *Registry) List() []*RunContext
- func (r *Registry) Lookup(token string) (*RunContext, bool)
- func (r *Registry) Register(rc *RunContext) string
- func (r *Registry) RegisterWithToken(rc *RunContext, token string)
- func (r *Registry) Unregister(token string)
- func (r *Registry) UpdateContainerID(token, containerID string) bool
- type RemoveHeaderSpec
- type RouteRegistration
- type RunContext
- func (rc *RunContext) AddExtraHeader(host, headerName, headerValue string)
- func (rc *RunContext) AddResponseTransformer(host string, transformer credential.ResponseTransformer)
- func (rc *RunContext) CancelRefresh()
- func (rc *RunContext) GetContainerID() string
- func (rc *RunContext) GetCredential(host string) (CredentialEntry, bool)
- func (rc *RunContext) GetExtraHeaders(host string) []ExtraHeaderEntry
- func (rc *RunContext) GetRemoveHeaders(host string) []string
- func (rc *RunContext) GetResponseTransformers(host string) []credential.ResponseTransformer
- func (rc *RunContext) GetTokenSubstitution(host string) (TokenSubstitutionEntry, bool)
- func (rc *RunContext) RemoveRequestHeader(host, headerName string)
- func (rc *RunContext) SetAWSHandler(h http.Handler)
- func (rc *RunContext) SetCredential(host, value string)
- func (rc *RunContext) SetCredentialHeader(host, headerName, headerValue string)
- func (rc *RunContext) SetCredentialWithGrant(host, headerName, headerValue, grant string)
- func (rc *RunContext) SetRefreshCancel(cancel context.CancelFunc)
- func (rc *RunContext) SetTokenSubstitution(host, placeholder, realToken string)
- func (rc *RunContext) ToProxyContextData() *proxy.RunContextData
- type RunInfo
- type RunPersister
- type Server
- func (s *Server) Registry() *Registry
- func (s *Server) SetOnEmpty(fn func())
- func (s *Server) SetOnRegister(fn func())
- func (s *Server) SetOnShutdown(fn func())
- func (s *Server) SetOnUnregister(fn func(runID string))
- func (s *Server) SetPersister(p *RunPersister)
- func (s *Server) SetProxyPort(port int)
- func (s *Server) SetRoutes(rt *routing.RouteTable)
- func (s *Server) Start() error
- func (s *Server) Stop(ctx context.Context) error
- type TokenSubstitutionEntry
- type TokenSubstitutionSpec
- type TransformerSpec
- type UpdateRunRequest
Constants ¶
This section is empty.
Variables ¶
var BuildCommit string
BuildCommit is the git commit hash of the running binary. Set by the CLI at startup so the health endpoint can report the daemon's version. This allows diagnosing version skew between daemon and CLI.
var ErrRunNotFound = errors.New("run not found")
ErrRunNotFound is returned when a run is not registered with the daemon.
Functions ¶
func RestoreRuns ¶ added in v0.3.2
func RestoreRuns(ctx context.Context, registry *Registry, runs []PersistedRun) int
RestoreRuns re-registers persisted runs by re-resolving credentials from the encrypted credential store. Returns the number of successfully restored runs.
func StartTokenRefresh ¶
func StartTokenRefresh(ctx context.Context, rc *RunContext, grants []string)
StartTokenRefresh begins a background goroutine that periodically refreshes credentials for the given run context.
func WriteLockFile ¶
WriteLockFile writes the daemon lock file.
Types ¶
type AWSConfig ¶
type AWSConfig struct {
RoleARN string `json:"role_arn"`
Region string `json:"region"`
SessionDuration time.Duration `json:"session_duration"`
ExternalID string `json:"external_id,omitempty"`
}
AWSConfig holds AWS credential provider configuration.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client communicates with the daemon over a Unix socket.
func EnsureRunning ¶
EnsureRunning checks if the daemon is already running and returns a client. If not running, it starts the daemon via self-exec and waits for it to be ready.
An advisory file lock serializes the check-and-spawn sequence so concurrent callers don't each spawn a separate daemon process.
func (*Client) Health ¶
func (c *Client) Health(ctx context.Context) (*HealthResponse, error)
Health returns the daemon's health status.
func (*Client) RegisterRoutes ¶
func (c *Client) RegisterRoutes(ctx context.Context, agent string, services map[string]string) error
RegisterRoutes registers service routes for an agent.
func (*Client) RegisterRun ¶
func (c *Client) RegisterRun(ctx context.Context, regReq RegisterRequest) (*RegisterResponse, error)
RegisterRun registers a new run with the daemon.
func (*Client) UnregisterRoutes ¶
UnregisterRoutes removes service routes for an agent.
func (*Client) UnregisterRun ¶
UnregisterRun removes a run from the daemon.
type CommandContainerChecker ¶
type CommandContainerChecker struct {
// contains filtered or unexported fields
}
CommandContainerChecker checks container liveness by shelling out to the container runtime CLI. It tries Docker first, then Apple containers.
func NewCommandContainerChecker ¶
func NewCommandContainerChecker() *CommandContainerChecker
NewCommandContainerChecker creates a new container checker that uses CLI commands.
func (*CommandContainerChecker) IsContainerRunning ¶
IsContainerRunning checks if a container is still running. Returns (true, nil) when the container is confirmed alive, (false, nil) when confirmed dead, and (false, err) when the check itself failed (e.g. transient CLI error).
type ContainerChecker ¶
type ContainerChecker interface {
IsContainerRunning(ctx context.Context, id string) (alive bool, err error)
}
ContainerChecker checks if a container is still running. Returns (true, nil) when confirmed alive, (false, nil) when confirmed dead, and (false, err) when the check failed (transient error).
type CredentialEntry ¶
type CredentialEntry struct {
Name string `json:"name"` // Header name (e.g., "Authorization", "x-api-key")
Value string `json:"value"` // Header value
Grant string `json:"grant"` // Grant name for logging
}
CredentialEntry holds a credential header for proxy injection.
type CredentialSpec ¶
type CredentialSpec struct {
Host string `json:"host"`
Header string `json:"header"`
Value string `json:"value"`
Grant string `json:"grant,omitempty"`
}
CredentialSpec describes a credential to inject for a host.
type ExtraHeaderEntry ¶
ExtraHeaderEntry holds an additional header to inject.
type ExtraHeaderSpec ¶
type ExtraHeaderSpec struct {
Host string `json:"host"`
HeaderName string `json:"header_name"`
Value string `json:"value"`
}
ExtraHeaderSpec describes an additional header to inject.
type HealthResponse ¶
type HealthResponse struct {
PID int `json:"pid"`
ProxyPort int `json:"proxy_port"`
RunCount int `json:"run_count"`
StartedAt string `json:"started_at"`
Commit string `json:"commit,omitempty"` // Git commit hash of the daemon binary
}
HealthResponse is returned from GET /v1/health.
type IdleTimer ¶
type IdleTimer struct {
// contains filtered or unexported fields
}
IdleTimer triggers a callback after a period of inactivity.
func NewIdleTimer ¶
NewIdleTimer creates an idle timer (does not start automatically).
type LivenessChecker ¶
type LivenessChecker struct {
// contains filtered or unexported fields
}
LivenessChecker periodically checks container liveness and cleans up dead runs.
func NewLivenessChecker ¶
func NewLivenessChecker(registry *Registry, checker ContainerChecker) *LivenessChecker
NewLivenessChecker creates a new liveness checker with 30-second default interval.
func (*LivenessChecker) CheckOnce ¶
func (lc *LivenessChecker) CheckOnce(ctx context.Context)
CheckOnce performs a single liveness check for all registered runs.
func (*LivenessChecker) Run ¶
func (lc *LivenessChecker) Run(ctx context.Context)
Run starts the periodic liveness check loop. Blocks until ctx is canceled.
func (*LivenessChecker) SetOnCleanup ¶
func (lc *LivenessChecker) SetOnCleanup(fn func(token, runID string))
SetOnCleanup sets a callback invoked when a run is cleaned up. The callback receives both the auth token and run ID.
func (*LivenessChecker) SetOnEmpty ¶
func (lc *LivenessChecker) SetOnEmpty(fn func())
SetOnEmpty sets a callback invoked when the registry becomes empty after cleanup.
func (*LivenessChecker) SetPersister ¶ added in v0.3.2
func (lc *LivenessChecker) SetPersister(p *RunPersister)
SetPersister sets the run persister for saving registry state after cleanup.
type LockInfo ¶
type LockInfo struct {
PID int `json:"pid"`
ProxyPort int `json:"proxy_port"`
SockPath string `json:"sock_path"`
StartedAt time.Time `json:"started_at"`
Commit string `json:"commit,omitempty"` // Git commit hash of the daemon binary
}
LockInfo holds information about a running daemon.
func ReadLockFile ¶
ReadLockFile reads the daemon lock file. Returns nil, nil if not found.
type PersistedRun ¶ added in v0.3.2
type PersistedRun struct {
AuthToken string `json:"auth_token"`
RunID string `json:"run_id"`
ContainerID string `json:"container_id,omitempty"`
Grants []string `json:"grants,omitempty"`
MCPServers []config.MCPServerConfig `json:"mcp_servers,omitempty"`
NetworkPolicy string `json:"network_policy,omitempty"`
NetworkAllow []string `json:"network_allow,omitempty"`
AWSConfig *AWSConfig `json:"aws_config,omitempty"`
TransformerSpecs []TransformerSpec `json:"transformer_specs,omitempty"`
}
PersistedRun is the on-disk representation of a registered run. It stores grant names (not raw credentials) so provider tokens are never written to disk. The auth token (proxy-local random string) is stored in plaintext, protected by file permissions (0600). On restore, provider credentials are re-resolved from the encrypted credential store.
type RegisterRequest ¶
type RegisterRequest struct {
RunID string `json:"run_id"`
AuthToken string `json:"auth_token,omitempty"` // Re-registration: use existing token
Credentials []CredentialSpec `json:"credentials,omitempty"`
ExtraHeaders []ExtraHeaderSpec `json:"extra_headers,omitempty"`
RemoveHeaders []RemoveHeaderSpec `json:"remove_headers,omitempty"`
TokenSubstitutions []TokenSubstitutionSpec `json:"token_substitutions,omitempty"`
MCPServers []config.MCPServerConfig `json:"mcp_servers,omitempty"`
NetworkPolicy string `json:"network_policy,omitempty"`
NetworkAllow []string `json:"network_allow,omitempty"`
Grants []string `json:"grants,omitempty"`
AWSConfig *AWSConfig `json:"aws_config,omitempty"`
ResponseTransformers []TransformerSpec `json:"response_transformers,omitempty"`
}
RegisterRequest is sent to POST /v1/runs.
func (*RegisterRequest) ToRunContext ¶
func (req *RegisterRequest) ToRunContext() *RunContext
ToRunContext converts a RegisterRequest into a RunContext.
type RegisterResponse ¶
type RegisterResponse struct {
AuthToken string `json:"auth_token"`
ProxyPort int `json:"proxy_port"`
}
RegisterResponse is returned from POST /v1/runs.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry is a thread-safe mapping of auth tokens to RunContexts. It provides the central lookup mechanism for the daemon proxy to resolve incoming requests to their per-run configuration and credentials.
func (*Registry) List ¶
func (r *Registry) List() []*RunContext
List returns all registered RunContexts.
func (*Registry) Lookup ¶
func (r *Registry) Lookup(token string) (*RunContext, bool)
Lookup finds a RunContext by auth token.
func (*Registry) Register ¶
func (r *Registry) Register(rc *RunContext) string
Register adds a RunContext and returns a generated auth token. The token is a 32-byte cryptographically random hex string.
func (*Registry) RegisterWithToken ¶
func (r *Registry) RegisterWithToken(rc *RunContext, token string)
RegisterWithToken adds a RunContext with a specific auth token. This is used for re-registration after a daemon restart so the container can keep using the same proxy auth token it was configured with.
func (*Registry) Unregister ¶
Unregister removes a RunContext by its auth token.
func (*Registry) UpdateContainerID ¶
UpdateContainerID sets the container ID for a registered run. Returns false if the token is not found.
type RemoveHeaderSpec ¶
RemoveHeaderSpec describes a header to remove from requests.
type RouteRegistration ¶
RouteRegistration is sent to POST /v1/routes/{agent}.
type RunContext ¶
type RunContext struct {
RunID string `json:"run_id"`
ContainerID string `json:"container_id,omitempty"`
AuthToken string `json:"auth_token"`
Credentials map[string]CredentialEntry `json:"credentials"`
ExtraHeaders map[string][]ExtraHeaderEntry `json:"extra_headers"`
RemoveHeaders map[string][]string `json:"remove_headers"`
TokenSubstitutions map[string]TokenSubstitutionEntry `json:"token_substitutions"`
ResponseTransformers map[string][]credential.ResponseTransformer `json:"-"` // not serialized
MCPServers []config.MCPServerConfig `json:"mcp_servers,omitempty"`
NetworkPolicy string `json:"network_policy,omitempty"`
NetworkAllow []string `json:"network_allow,omitempty"`
AWSConfig *AWSConfig `json:"aws_config,omitempty"`
TransformerSpecs []TransformerSpec `json:"transformer_specs,omitempty"`
Grants []string `json:"grants,omitempty"`
RegisteredAt time.Time `json:"registered_at"`
// contains filtered or unexported fields
}
RunContext holds per-run proxy state. It implements credential.ProxyConfigurer so providers can configure it identically to how they configure proxy.Proxy.
func NewRunContext ¶
func NewRunContext(runID string) *RunContext
NewRunContext creates a new RunContext for a run.
func (*RunContext) AddExtraHeader ¶
func (rc *RunContext) AddExtraHeader(host, headerName, headerValue string)
AddExtraHeader implements credential.ProxyConfigurer.
func (*RunContext) AddResponseTransformer ¶
func (rc *RunContext) AddResponseTransformer(host string, transformer credential.ResponseTransformer)
AddResponseTransformer implements credential.ProxyConfigurer.
func (*RunContext) CancelRefresh ¶
func (rc *RunContext) CancelRefresh()
CancelRefresh cancels the token refresh goroutine, if any. Safe to call concurrently and multiple times.
func (*RunContext) GetContainerID ¶
func (rc *RunContext) GetContainerID() string
GetContainerID returns the container ID safely.
func (*RunContext) GetCredential ¶
func (rc *RunContext) GetCredential(host string) (CredentialEntry, bool)
GetCredential returns the credential for a host, checking host:port fallback.
func (*RunContext) GetExtraHeaders ¶
func (rc *RunContext) GetExtraHeaders(host string) []ExtraHeaderEntry
GetExtraHeaders returns extra headers for a host, checking host:port fallback.
func (*RunContext) GetRemoveHeaders ¶
func (rc *RunContext) GetRemoveHeaders(host string) []string
GetRemoveHeaders returns headers to remove for a host, checking host:port fallback.
func (*RunContext) GetResponseTransformers ¶
func (rc *RunContext) GetResponseTransformers(host string) []credential.ResponseTransformer
GetResponseTransformers returns response transformers for a host, checking host:port fallback.
func (*RunContext) GetTokenSubstitution ¶
func (rc *RunContext) GetTokenSubstitution(host string) (TokenSubstitutionEntry, bool)
GetTokenSubstitution returns the token substitution for a host, checking host:port fallback.
func (*RunContext) RemoveRequestHeader ¶
func (rc *RunContext) RemoveRequestHeader(host, headerName string)
RemoveRequestHeader implements credential.ProxyConfigurer.
func (*RunContext) SetAWSHandler ¶
func (rc *RunContext) SetAWSHandler(h http.Handler)
SetAWSHandler stores the AWS credential endpoint handler for this run.
func (*RunContext) SetCredential ¶
func (rc *RunContext) SetCredential(host, value string)
SetCredential implements credential.ProxyConfigurer.
func (*RunContext) SetCredentialHeader ¶
func (rc *RunContext) SetCredentialHeader(host, headerName, headerValue string)
SetCredentialHeader implements credential.ProxyConfigurer.
func (*RunContext) SetCredentialWithGrant ¶
func (rc *RunContext) SetCredentialWithGrant(host, headerName, headerValue, grant string)
SetCredentialWithGrant implements credential.ProxyConfigurer.
func (*RunContext) SetRefreshCancel ¶
func (rc *RunContext) SetRefreshCancel(cancel context.CancelFunc)
SetRefreshCancel stores the cancel function for the token refresh goroutine.
func (*RunContext) SetTokenSubstitution ¶
func (rc *RunContext) SetTokenSubstitution(host, placeholder, realToken string)
SetTokenSubstitution implements credential.ProxyConfigurer.
func (*RunContext) ToProxyContextData ¶
func (rc *RunContext) ToProxyContextData() *proxy.RunContextData
ToProxyContextData converts this RunContext into a proxy.RunContextData for use in per-request credential resolution.
type RunInfo ¶
type RunInfo struct {
RunID string `json:"run_id"`
ContainerID string `json:"container_id,omitempty"`
RegisteredAt string `json:"registered_at"`
}
RunInfo is an element of the list returned by GET /v1/runs.
type RunPersister ¶ added in v0.3.2
type RunPersister struct {
// contains filtered or unexported fields
}
RunPersister manages saving and loading the run registry to disk.
func NewRunPersister ¶ added in v0.3.2
func NewRunPersister(path string, registry *Registry) *RunPersister
NewRunPersister creates a persister that saves to the given file path.
func (*RunPersister) Flush ¶ added in v0.3.2
func (p *RunPersister) Flush() error
Flush stops any pending debounce timer and performs a synchronous Save. Call during daemon shutdown to ensure the final state is persisted.
func (*RunPersister) Load ¶ added in v0.3.2
func (p *RunPersister) Load() ([]PersistedRun, error)
Load reads persisted runs from disk. Returns nil, nil if the file doesn't exist. Handles both the versioned format ({"version":1,"runs":[...]}) and the legacy bare-array format for backwards compatibility.
func (*RunPersister) Save ¶ added in v0.3.2
func (p *RunPersister) Save() error
Save serializes the current registry to disk atomically (temp file + rename). The file is written with 0600 permissions. Safe to call concurrently.
func (*RunPersister) SaveDebounced ¶ added in v0.3.2
func (p *RunPersister) SaveDebounced()
SaveDebounced coalesces rapid save calls with a short timer. Safe to call from multiple goroutines.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the daemon's HTTP API server over a Unix socket.
func NewServer ¶
NewServer creates a daemon API server that will listen on the given Unix socket path.
func (*Server) SetOnEmpty ¶
func (s *Server) SetOnEmpty(fn func())
SetOnEmpty sets a callback that is invoked when the last run is unregistered.
func (*Server) SetOnRegister ¶
func (s *Server) SetOnRegister(fn func())
SetOnRegister sets a callback invoked when a new run is registered.
func (*Server) SetOnShutdown ¶
func (s *Server) SetOnShutdown(fn func())
SetOnShutdown sets a callback that is invoked when shutdown is requested via the API. This should signal the main daemon loop to exit (e.g., by sending SIGTERM to self).
func (*Server) SetOnUnregister ¶
SetOnUnregister sets a callback that is invoked when a run is unregistered. The callback receives the run ID for per-run resource cleanup.
func (*Server) SetPersister ¶ added in v0.3.2
func (s *Server) SetPersister(p *RunPersister)
SetPersister sets the run persister for saving registry state to disk.
func (*Server) SetProxyPort ¶
SetProxyPort updates the proxy port reported in API responses. Call after the credential proxy starts to set the actual port.
func (*Server) SetRoutes ¶
func (s *Server) SetRoutes(rt *routing.RouteTable)
SetRoutes sets the route table used for route registration handlers.
type TokenSubstitutionEntry ¶
type TokenSubstitutionEntry struct {
Placeholder string `json:"placeholder"`
RealToken string `json:"real_token"`
}
TokenSubstitutionEntry holds a placeholder-to-real-token mapping.
type TokenSubstitutionSpec ¶
type TokenSubstitutionSpec struct {
Host string `json:"host"`
Placeholder string `json:"placeholder"`
RealToken string `json:"real_token"`
}
TokenSubstitutionSpec describes a token substitution.
type TransformerSpec ¶
type TransformerSpec struct {
Host string `json:"host"`
Kind string `json:"kind"` // "oauth-endpoint-workaround" or "response-scrub"
}
TransformerSpec describes a response transformer to apply for a host. Since transformers are Go functions (not serializable), this spec allows the daemon to reconstruct them from well-known kinds.
type UpdateRunRequest ¶
type UpdateRunRequest struct {
ContainerID string `json:"container_id"`
}
UpdateRunRequest is sent to PATCH /v1/runs/{token}.