api

package
v0.8.3 Latest Latest
Warning

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

Go to latest
Published: Oct 24, 2026 License: Apache-2.0 Imports: 277 Imported by: 0

Documentation ¶

Overview ¶

Package api implements the HTTP API the web frontend (1.10) and, later, the MCP layer both build on. Scope for this pass: GET /api/v1/brand, apps CRUD, deploy trigger and deploy history, single-admin-user session auth. No teams, no RBAC: explicitly out of scope until Phase 4.

Routing uses the standard library's Go 1.22+ pattern-based http.ServeMux ("GET /api/v1/apps/{name}") rather than a router framework like Chi, per the project's rule against pulling in a heavy framework; the one thing a framework would earn its weight on here is auth middleware, and requireAuth below is a plain http.HandlerFunc-wrapping closure that stdlib's mux composes with directly, so there is no ergonomics gap stdlib doesn't already close.

"App" here is layered directly on store.DesiredService (internal/store/service.go), the closest existing resource, rather than a new, speculative domain type. That surfaces real gaps instead of papering over them with a fuller model this package doesn't actually need to build yet:

  • No replicas or strategy fields on an app: internal/spec's app.yaml Service has them, store.DesiredService doesn't yet, so this API can't expose what the store can't hold. Adding them is a store-schema and deploy-pipeline change, not something this package should invent on its own. Domains closed once that column was added: appResource now carries Domains too.
  • Deploy trigger (deploys.go) only updates desired_services.image; it doesn't build anything. internal/build and internal/deploy already exist and do that, but they're owned by a different concurrent session as this package was written, so this endpoint takes an already-built image tag as input, the same mechanism used for rollback, run forward instead of backward. POST /api/v1/apps/{name}/builds (builds.go, handleTriggerBuild) closes this gap: it invokes the same internal/deploy.Pipeline the git webhook receiver uses, given a git source (repo_url/ref) in the request body, since no app has a stored git/build config anywhere in this codebase yet (see specServiceFromDesired's own doc comment for what that means for fidelity versus the original app.yaml).
  • Deploy history (deploys.go) returns the latest reconcile condition per (controller, condition type) pair, which is genuinely all internal/store.UpsertConditions persists today, not a row-per- deploy-attempt log. A real deploy history table is a store-schema addition this package deliberately didn't invent speculatively.

cmd/levelrail/main.go's reconcile engine closed the gap noted above in an earlier draft of this comment: it now derives a dynamic controller set from the store every pass (reconcile.Engine.Source), so a deploy triggered through this API does reconcile on the next pass.

Secrets: PUT /api/v1/apps/{name}/secrets/{key} sets a value, encrypted at rest via internal/secrets.Manager. Deliberately set-only, no GET: this package never decrypts a value for a response body, only internal/reconcile/application does, immediately before container creation. Available only when the control plane was started with a master key (WithSecretSetter); without one, the route returns 501.

Auth foundation ("Dashboard & auth"): POST /api/v1/auth/register is the interactive first-run counterpart to BootstrapAdmin's env-var path, gated on "no admin row exists yet" at both the route and the mutation layer. Session auth stays exactly what this package was scoped as (single admin user, no teams, no RBAC); API tokens (POST/GET /api/v1/auth/tokens, DELETE .../{id}) are a separate, additive credential type for non-interactive callers (a future CLI, an MCP server), scoped to abilities (abilities.go: read, read:sensitive, write, deploy, root) checked fresh on every call by requireAbility, never a cached decision. Token management itself is session-only via requireAuth: a token can never mint or revoke another token on its own behalf. This shape (not theauth-go, not an all-or-nothing key) was a deliberate choice.

Index ¶

Constants ¶

View Source
const (
	AbilityRead           = "read"
	AbilityReadSensitive  = "read:sensitive"
	AbilityWrite          = "write"
	AbilityWriteSensitive = "write:sensitive"
	AbilityDeploy         = "deploy"
	AbilityRoot           = "root"
	// AbilitySignInApprove lets a token reveal its owner's sign-in codes and
	// decide new-browser approvals. Root never implies it.
	AbilitySignInApprove = "signin:approve"
)

Ability strings an api_tokens row can be scoped to. AbilityRoot is exclusive: validateAbilities rejects it combined with others.

View Source
const (
	AIAssistantTokenName = "AI Assistant (internal)"
	AIAssistantAgentName = "ai-assistant"
)

AIAssistantTokenName and AIAssistantAgentName identify the internal token the in-app assistant holds.

View Source
const (
	AlertProfileWeb      = "web"
	AlertProfileWorker   = "worker"
	AlertProfileDatabase = "database"
)

Alert template profiles: the app shapes a one-click rule set exists for.

View Source
const (
	HealthScoreStatusPass = "pass"
	HealthScoreStatusWarn = "warn"
	HealthScoreStatusFail = "fail"
)

Shared pass/warn/fail values, so the CLI and category code never retype them.

View Source
const (
	ClientKindCLI       = "cli"
	ClientKindDashboard = "dashboard"
	ClientKindMCP       = "mcp"
	ClientKindAPI       = "api"
	// ClientKindSystem is written directly by internal/ingress's
	// SQLiteStorage for a certificate issuance/renewal it detects, not
	// derived here: there is no User-Agent, because there is no request.
	ClientKindSystem = "system"
)

Client kind values audit_log.client_kind (migrations/0077) is normalized into: which surface actually made the request, not just which auth method it used (store.AuditEntry.ActorType already covers session-vs-token).

View Source
const (
	OutcomeInProgress = "in_progress"
	OutcomeHealthy    = "healthy"
	OutcomeFailed     = "failed"
	OutcomeCanceled   = "canceled"
	OutcomeSuperseded = "superseded"
	OutcomeBlocked    = "blocked"
)

Deploy outcomes reported by GET /apps/{name}/deploys/{deployId}.

View Source
const (
	StatusBuilding   = "building"
	StatusRollingOut = "rolling_out"
)

Non-terminal and derived statuses reported by the single-deploy endpoint.

View Source
const (
	EnvTracePollInterval = "APP_DEPLOY_TRACE_POLL_INTERVAL"
	EnvTraceTailIdle     = "APP_DEPLOY_TRACE_TAIL_IDLE"
)

EnvTracePollInterval and EnvTraceTailIdle tune how a stream follows trace rows the reconciler writes after the deploy attempt itself has finished.

View Source
const (
	EnvGateSessionTTL     = "APP_GATE_SESSION_TTL"
	EnvGateTokenTTL       = "APP_GATE_TOKEN_TTL" //nolint:gosec // env var name, not a credential
	EnvGateEventRetention = "APP_GATE_EVENT_RETENTION"
	EnvGateAllowHTTP      = "APP_GATE_ALLOW_HTTP"
)

Env vars for the built-in auth gate provider.

View Source
const (

	// ImageVerifyOff skips signature checks on promotion.
	ImageVerifyOff = "off"
	// ImageVerifyEnforce refuses a promotion whose image is unsigned or signed by another key.
	ImageVerifyEnforce = "enforce"
)
View Source
const (
	OnboardingStageWaiting        = "waiting_for_agent"
	OnboardingStageConnected      = "connected"
	OnboardingStageReady          = "ready"
	OnboardingStageNeedsAttention = "needs_attention"
)

Onboarding stages, in the order a joining node moves through them.

View Source
const (
	RoleAdmin    = "admin"
	RoleOperator = "operator"
	RoleViewer   = "viewer"
)

Curated role names, roles's own Name values.

View Source
const (
	StorageClassBackups   = "backups"
	StorageClassArchives  = "archives"
	StorageClassArtifacts = "artifacts"
	StorageClassCache     = "cache"
	StorageClassDumps     = "dumps"
)

Data classes a destination can be the default for. Node directories only serve backups and dumps because the rest needs an S3 API.

View Source
const (
	TopologyKindApp      = "app"
	TopologyKindDatabase = "database"
	TopologyKindVolume   = "volume"
	TopologyKindDomain   = "domain"
	TopologyKindLB       = "load_balancer"
	TopologyKindNode     = "node"

	TopologyEdgeDatabaseBinding = "database_binding"
	TopologyEdgeDependsOn       = "depends_on"
	TopologyEdgeVolume          = "volume_attachment"
	TopologyEdgeEgressAllow     = "egress_allow"
	TopologyEdgeRouting         = "routing"
	TopologyEdgeLoadBalances    = "load_balances"
	TopologyEdgePlacedOn        = "placed_on"
)

Topology node/edge kinds: the vocabulary GET /api/v1/projects/{id}/topology (topology.go) reports, and web/src/routes/projects/$id/topology.tsx renders. An "app" node is one store.DesiredService, the same unit GET /api/v1/apps already calls an app (appListResource); multi-service apps (store.App) show up as one node per member service, not one collapsed node, since depends_on and database bindings are declared per service, not per App row.

View Source
const (
	UpdateStateUpgradeAvailable = "upgrade_available"
	UpdateStateUpToDate         = "up_to_date"
	UpdateStateAheadOfReleases  = "ahead_of_releases"
	UpdateStateBlockedOlder     = "blocked_older"
	UpdateStateUnknown          = "unknown"
)

Install states reported by the update preflight and release list.

View Source
const ACMEStagingDirectoryURL = "https://acme-staging-v02.api.letsencrypt.org/directory"

ACMEStagingDirectoryURL is Let's Encrypt's staging CA: no rate limits that matter, certificates browsers do not trust.

View Source
const AbilitySecretsReveal = "secrets:reveal"

AbilitySecretsReveal lets an API token reveal secret values, and only together with read:sensitive, APP_SECRET_REVEAL_TOKENS=on and a proof of its owner's password. Root never implies it.

View Source
const AgentClientHeader = "X-Agent-Client"

AgentClientHeader carries the MCP client name and version an agent-side server reports for the request. It is self-reported and informational.

View Source
const (
	AuditActionFirewallPrefix = "firewall."
)

Audit action names for firewall changes; the Firewall audit view lists exactly the rows whose action starts with AuditActionFirewallPrefix.

View Source
const AuditActionSensitiveRead = "sensitive_read"

AuditActionSensitiveRead marks a GET that returned value-bearing env or secret metadata.

View Source
const (
	// DefaultCertDrillTimeout is how long a rotation drill waits for the new certificate.
	DefaultCertDrillTimeout = 30 * time.Second
)
View Source
const EnvAITurnTokenTTL = "APP_AI_TURN_TOKEN_TTL" //nolint:gosec // an env var name, not a credential

EnvAITurnTokenTTL overrides how long one assistant turn's token lives.

View Source
const EnvGitStatusEnabled = "APP_GIT_STATUS_ENABLED"

EnvGitStatusEnabled is the server kill switch for posting commit statuses and deployments back to git forges. Unset means on.

View Source
const (
	// EnvTrafficSlowRouteMin is the fewest requests a route needs in the
	// window before it can rank among the slowest routes.
	EnvTrafficSlowRouteMin = "APP_TRAFFIC_SLOW_ROUTE_MIN"
)
View Source
const ExperimentalDisabledCode = "experimental_feature_disabled"

ExperimentalDisabledCode is the error code returned for a gated route.

View Source
const (

	// NodeGuardrailLocalID names the control plane's own node in guardrail routes and storage.
	NodeGuardrailLocalID = "local"
)
View Source
const SetupTokenFilename = "setup-token"

SetupTokenFilename is the file under the data dir holding the one-time first-admin token.

View Source
const SubjectProxy = "proxy"

SubjectProxy groups the fixes that start or repair the managed proxy.

View Source
const SubjectSettings = "settings"

SubjectSettings groups the fixes the Settings health card lists.

Variables ¶

This section is empty.

Functions ¶

func ApprovalMatch ¶

func ApprovalMatch(browserHash string) int

ApprovalMatch is the two digit number a waiting browser shows for its sign-in.

func AttentionResolvedWindow ¶ added in v0.2.0

func AttentionResolvedWindow() time.Duration

AttentionResolvedWindow is how long expired, denied and approved device logins stay visible, APP_ATTENTION_RESOLVED_WINDOW.

func BootstrapAdmin ¶

func BootstrapAdmin(ctx context.Context, s AuthStore, username, password string) error

BootstrapAdmin ensures at least one user exists, creating one from username/password if none does yet, with AbilityRoot: it's the only user on the instance, so it has to be. No-op once any user exists, so a restart with the same env vars never resets a changed password. username becomes the new user's email verbatim (no "@" required), matching migrations/0035's backfill leniency for a pre-existing admin_user row.

func BuildLimitsSource ¶

func BuildLimitsSource(s BuildPerformanceStore, env build.Limits) build.LimitsSource

BuildLimitsSource resolves saved overrides over the env defaults on every build.

func BuildRunRecorder ¶

func BuildRunRecorder(s BuildPerformanceStore) build.RunRecorder

BuildRunRecorder adapts the store to the build limiter's recorder.

func DeviceCodeTTL ¶ added in v0.2.0

func DeviceCodeTTL() time.Duration

DeviceCodeTTL is how long a device login request stays approvable, APP_DEVICE_CODE_TTL as a Go duration when set.

func DeviceTokenTTL ¶ added in v0.2.0

func DeviceTokenTTL() time.Duration

DeviceTokenTTL is the lifetime of a device-login token (APP_DEVICE_TOKEN_TTL_DAYS).

func DockerGuardAuditEntry ¶ added in v0.2.0

func DockerGuardAuditEntry(d dockerguard.Decision) (store.AuditEntry, error)

DockerGuardAuditEntry turns a guard decision into an audit_log row. The path carries the container name, never the request body.

func EnsureSetupToken ¶ added in v0.2.0

func EnsureSetupToken(ctx context.Context, users UserCounter, dataDir string) (token string, created bool, err error)

EnsureSetupToken returns the setup token for an instance with no users, creating it (mode 0600) if missing; created reports whether it is new. Once any user exists the file is removed and "" is returned.

func HostFirewallSSHPorts ¶ added in v0.2.0

func HostFirewallSSHPorts() []int

HostFirewallSSHPorts exposes the SSH ports the firewall switch keeps open, so the exposure lockout guard protects the same set.

func ImageVerifyConfigFromEnv ¶

func ImageVerifyConfigFromEnv(keyFile string) (*ecdsa.PublicKey, error)

ImageVerifyConfigFromEnv loads the signature public key from the file named by keyFile. An empty keyFile disables verification.

func LoadBetaFeatures ¶ added in v0.2.0

func LoadBetaFeatures(ctx context.Context, s BetaFeatureStore) error

LoadBetaFeatures applies stored Settings switches at startup; a feature never switched in Settings follows the active server profile.

func MaybeBootstrapDevAdmin ¶

func MaybeBootstrapDevAdmin(ctx context.Context, s AuthStore, logger *slog.Logger) error

MaybeBootstrapDevAdmin is cmd/levelrail/main.go's entry point, called unconditionally on every startup the same way BootstrapAdmin already is: a no-op unless APP_DEV_MODE=1 in a non -tags embedweb build (see devmode_debug.go/devmode_release.go). BootstrapAdmin itself is a no-op once any admin account exists, so this only ever creates the fixed dev/dev account on a genuinely empty data directory; an operator who already set APP_ADMIN_USERNAME/APP_ADMIN_PASSWORD keeps that account regardless of call order between the two.

func MaybeSeedDevFixturesFromFile ¶

func MaybeSeedDevFixturesFromFile(ctx context.Context, s TokenStore, logger *slog.Logger, path string) error

MaybeSeedDevFixturesFromFile is cmd/levelrail/main.go's entry point, called unconditionally on every startup the same way MaybeBootstrapDevAdmin already is. A missing fixtures file is not an error: dev mode works without one (only the fixed dev/dev admin account), a test/fixtures/dev-fixtures.yml is an opt-in convenience layered on top.

func MintAPIToken ¶ added in v0.2.0

func MintAPIToken(ctx context.Context, tokens TokenStore, name string, abilities []string, expiresAt *time.Time) (string, store.APIToken, error)

MintAPIToken generates, hashes, and persists a new API token, returning its plaintext exactly once, same as handleCreateToken's own response. Exported so a non-HTTP caller (cmd/levelrail's own internal AI assistant self-call token, minted once at startup rather than by a human through this handler) can mint through the identical path instead of duplicating it.

func MintAgentAPIToken ¶ added in v0.2.0

func MintAgentAPIToken(ctx context.Context, tokens TokenStore, name string, abilities []string, expiresAt *time.Time, agent agentIdentity, ownerUserID string) (string, store.APIToken, error)

MintAgentAPIToken is MintAPIToken with an agent label and an owning user (empty for system tokens).

func NewDeviceApprovalFromEnv ¶ added in v0.2.0

func NewDeviceApprovalFromEnv() bool

NewDeviceApprovalFromEnv reads APP_AUTH_NEW_DEVICE_APPROVAL: on unless set to a false value, the break-glass switch for a locked-out operator.

func PeerIsTrustedProxy ¶ added in v0.3.0

func PeerIsTrustedProxy(r *http.Request) bool

PeerIsTrustedProxy is peerIsTrustedProxy for wiring outside this package.

func ReadSetupToken ¶ added in v0.2.0

func ReadSetupToken(dataDir string) (string, error)

ReadSetupToken returns the current setup token, or "" if none exists.

func SetupTokenPath ¶ added in v0.2.0

func SetupTokenPath(dataDir string) string

SetupTokenPath returns the setup token file path inside dataDir.

Types ¶

type AIChatStore ¶ added in v0.2.0

type AIChatStore interface {
	CreateAIChatSession(ctx context.Context, id, owner string, now time.Time) (store.AIChatSession, error)
	GetAIChatSession(ctx context.Context, id string) (store.AIChatSession, error)
	ListAIChatSessions(ctx context.Context, owner string) ([]store.AIChatSession, error)
	DeleteAIChatSession(ctx context.Context, id, owner string) error
	ListAIChatMessages(ctx context.Context, sessionID string) ([]store.AIChatMessage, error)
	GetAIChatConfirmation(ctx context.Context, id string) (store.AIChatConfirmation, error)
}

AIChatStore is the core store surface the chat routes need, always set since missing rows are normal not-found.

type AIControlStore ¶ added in v0.2.0

type AIControlStore interface {
	GetAIControlSettings(ctx context.Context) (store.AIControlSettings, error)
	UpdateAIControlSettings(ctx context.Context, mode string, kinds []string, updatedBy string) error
	RevokeAgentTokens(ctx context.Context, internalName, internalAgent string) (int, error)
	CountAgentTokens(ctx context.Context, internalName, internalAgent string) (int, error)
	EnvironmentOfApp(ctx context.Context, appName string) (*store.EnvironmentRef, error)
	EnvironmentOfDatabase(ctx context.Context, databaseName string) (*store.EnvironmentRef, error)
}

AIControlStore is the store surface the AI control gate and settings routes need.

type AIEngine ¶ added in v0.2.0

type AIEngine interface {
	IsConfigured(ctx context.Context) (bool, error)
	RunTurn(ctx context.Context, sessionID, userContent string, sink ai.Sink) error
	ResolveConfirmation(ctx context.Context, sessionID, confirmationID string, approve bool, sink ai.Sink) error
}

AIEngine is the internal/ai.Engine surface the chat routes need; nil makes every /api/v1/ai route return 501.

type AIUsageStore ¶

type AIUsageStore interface {
	AIUsageByDay(ctx context.Context, since time.Time) ([]store.AIUsageDay, error)
	SumAITokensSince(ctx context.Context, since time.Time) (int64, error)
}

AIUsageStore is the metering surface the usage endpoint and budget display need.

type AIVault ¶

type AIVault interface {
	List(ctx context.Context) ([]ai.ProviderView, error)
	Set(ctx context.Context, id string, in ai.SetInput, privateAllowed bool) (ai.ProviderView, ai.SetResult, error)
	Test(ctx context.Context, id string) (ai.TestResult, error)
	Remove(ctx context.Context, id string) error
	Models(ctx context.Context, id string) ([]ai.ModelInfo, error)
	Get(ctx context.Context, id string) (ai.ProviderView, error)
	Settings(ctx context.Context) (ai.AssistantSettings, error)
	SetChoice(ctx context.Context, active *store.AIModelRef, fallback *[]store.AIModelRef) error
}

AIVault is the internal/ai.Vault surface the provider and settings routes need. nil is valid: those routes return 501.

type AccessPolicyStore ¶

type AccessPolicyStore interface {
	ListSessionPolicies(ctx context.Context) ([]store.SessionPolicy, error)
	SessionPoliciesForUser(ctx context.Context, userID string) ([]store.SessionPolicy, error)
	GetSessionPolicy(ctx context.Context, teamID string) (store.SessionPolicy, error)
	SaveSessionPolicy(ctx context.Context, p store.SessionPolicy) error
	DeleteSessionPolicy(ctx context.Context, teamID string) error
	GetSessionActivity(ctx context.Context, sessionID string) (store.SessionActivity, error)
	TouchSessionActivity(ctx context.Context, sessionID, userID string, now time.Time) error
	SetSessionMethod(ctx context.Context, sessionID, userID, method string, now time.Time) error
	TeamMemberRole(ctx context.Context, teamID, userID string) (string, error)
}

AccessPolicyStore is the persistence the session policy needs. *store.DB satisfies it.

type AccessReplaySource ¶

type AccessReplaySource interface {
	AppAccessSince(app string, since time.Time) []ingress.AccessRecord
}

AccessReplaySource lists every retained edge request of an app since a time, oldest first, for the abuse dry run.

type AccessSource ¶

type AccessSource interface {
	AppAccess(app string, f ingress.AccessFilter) []ingress.AccessRecord
}

AccessSource reads recent edge requests for an app.

type AlertDefaults ¶

type AlertDefaults interface {
	ListDefaultRules(ctx context.Context) ([]alerting.Rule, error)
	SetDefaultRuleEnabled(ctx context.Context, id string, enabled bool) (*alerting.Rule, error)
	ResetDefaultRules(ctx context.Context) ([]alerting.Rule, error)
	CertExpiryEmail(ctx context.Context) (bool, error)
	SetCertExpiryEmail(ctx context.Context, address string, on bool) error
}

AlertDefaults is the surface the seeded default alert routes need from internal/alerting.DB.

type AlertNoise ¶ added in v0.2.0

type AlertNoise interface {
	CreateSilence(ctx context.Context, s alerting.Silence) error
	GetSilence(ctx context.Context, id string) (*alerting.Silence, error)
	ListSilences(ctx context.Context, now time.Time, includeExpired bool, limit int) ([]alerting.Silence, error)
	ListActiveSilences(ctx context.Context, now time.Time) ([]alerting.Silence, error)
	ExpireSilence(ctx context.Context, id string, now time.Time) (*alerting.Silence, error)
	SaveMaintenanceWindow(ctx context.Context, w alerting.MaintenanceWindow) error
	GetMaintenanceWindow(ctx context.Context, id string) (*alerting.MaintenanceWindow, error)
	ListMaintenanceWindows(ctx context.Context) ([]alerting.MaintenanceWindow, error)
	DeleteMaintenanceWindow(ctx context.Context, id string) error
	ListHistory(ctx context.Context, f alerting.HistoryFilter) ([]alerting.HistoryEntry, error)
}

AlertNoise is the surface the silence, maintenance window and alert history handlers need from internal/alerting.DB.

type AlertRules ¶

type AlertRules interface {
	SaveRule(ctx context.Context, r alerting.Rule) error
	GetRule(ctx context.Context, id string) (*alerting.Rule, error)
	ListRulesForResource(ctx context.Context, resourceID string) ([]alerting.Rule, error)
	DeleteRule(ctx context.Context, id string) error
}

AlertRules is the narrow surface the alert-rule handlers need from alerting.DB.

type AppComposeStore ¶

type AppComposeStore interface {
	SaveApp(ctx context.Context, a store.App) error
	GetAppByName(ctx context.Context, name string) (store.App, error)
	SaveDesiredService(ctx context.Context, svc store.DesiredService) error
}

AppComposeStore is the store surface POST /api/v1/apps/{name}/compose needs (apps_compose.go): create-or-reuse the owning store.App, then save each of its member services.

type AppGitHubActionsStore ¶

type AppGitHubActionsStore interface {
	GetAppGitHubActions(ctx context.Context, serviceName string) (store.AppGitHubActions, error)
	SetAppGitHubActions(ctx context.Context, s store.AppGitHubActions) error
}

AppGitHubActionsStore is the store surface for the GitHub Actions report settings.

type AppGroupLister ¶

type AppGroupLister interface {
	ListServicesByApp(ctx context.Context, appID string) ([]store.DesiredService, error)
	DeleteApp(ctx context.Context, id string) error
	SaveApp(ctx context.Context, a store.App) error
	GetAppByName(ctx context.Context, name string) (store.App, error)
}

AppGroupLister is the store surface for GET /api/v1/apps/{name}/group and the app-linking write path. *store.DB satisfies this structurally.

type AppImportStore ¶ added in v0.2.0

type AppImportStore interface {
	CreateAppImportSession(ctx context.Context, s store.AppImportSession, items []store.AppImportItem) error
	GetAppImportSession(ctx context.Context, id string) (store.AppImportSession, error)
	ListAppImportSessions(ctx context.Context) ([]store.AppImportSession, error)
	UpdateAppImportSession(ctx context.Context, s store.AppImportSession, now time.Time) error
	DeleteAppImportSession(ctx context.Context, id string) error
	ListAppImportItems(ctx context.Context, sessionID string) ([]store.AppImportItem, error)
	SaveAppImportItem(ctx context.Context, it store.AppImportItem, now time.Time) error
}

AppImportStore is the store surface the guided app import routes need.

type AppIntegrationStore ¶ added in v0.2.0

type AppIntegrationStore interface {
	SaveAppIntegration(ctx context.Context, ai store.AppIntegration) error
	GetAppIntegration(ctx context.Context, id string) (store.AppIntegration, error)
	ListAppIntegrationsForService(ctx context.Context, serviceName string) ([]store.AppIntegration, error)
	DeleteAppIntegration(ctx context.Context, id string) error
}

AppIntegrationStore is the store surface the app integration handlers need, mirroring ScheduledTaskStore's own shape for a different per-app child resource.

type AppScheduleStore ¶ added in v0.2.0

type AppScheduleStore interface {
	GetAppSchedule(ctx context.Context, serviceName string) (*store.AppSchedule, error)
	SetAppSchedule(ctx context.Context, serviceName, cron, branch, timezone string, enabled bool) error
	SetAppScheduleRunAt(ctx context.Context, serviceName, branch, timezone string, runAt time.Time, enabled bool) error
	ArmAppScheduleNextRun(ctx context.Context, serviceName string, next time.Time) error
	ListAppScheduleHistory(ctx context.Context, serviceName string, limit int) ([]store.AppScheduleHistoryEntry, error)
}

AppScheduleStore is the store surface the schedule handlers and internal/scheduledeploy.Scheduler both need. *store.DB satisfies this structurally.

type AppSleepStore ¶ added in v0.2.0

type AppSleepStore interface {
	SetAppSleepIdle(ctx context.Context, serviceName string, minutes int, now time.Time) error
	SetAppSleeping(ctx context.Context, serviceName string, sleeping bool, now time.Time) error
	SetAppSleepHold(ctx context.Context, serviceName string, hold bool, now time.Time) error
	SetAppSleepOptions(ctx context.Context, serviceName string, ignorePaths []string, portWake *bool, now time.Time) error
	GetAppSleep(ctx context.Context, serviceName string) (store.AppSleep, error)
	ListAppSleep(ctx context.Context) ([]store.AppSleep, error)
}

AppSleepStore is the store surface the sleep routes need.

type AppStore ¶

type AppStore interface {
	SaveDesiredService(ctx context.Context, svc store.DesiredService) error
	GetDesiredService(ctx context.Context, name string) (*store.DesiredService, error)
	ListDesiredServices(ctx context.Context) ([]store.DesiredService, error)
	DeleteDesiredService(ctx context.Context, name string) error
	// ListAppStreamsForService backs internal/reconcile/application's
	// ServiceStore (the same interface this type satisfies for the
	// application controller's own New call): one extra published
	// container port per raw TCP stream (migrations/0279_app_streams.sql).
	ListAppStreamsForService(ctx context.Context, serviceName string) ([]store.AppStream, error)
	// UpdateServiceNode is the placement mutation, separate
	// from SaveDesiredService on purpose: see store.DB.SaveDesiredService's
	// own doc comment for why an ordinary app update must never be able
	// to silently move a service between nodes.
	UpdateServiceNode(ctx context.Context, name, nodeID string) error
	// ListDesiredServicesByNode is the drain and
	// delete-guard primitive (handleDrainNode, handleDeleteNode): find
	// what's placed on a node without listing every service.
	ListDesiredServicesByNode(ctx context.Context, nodeID string) ([]store.DesiredService, error)
	// ListDesiredServicesByProject is ListDesiredServicesByNode's
	// project-kind counterpart: handleStopProject/handleStartProject
	// (project_stop_start.go) and handleRestartProject
	// (project_restart.go) use it to find every app in a project without
	// listing every service.
	ListDesiredServicesByProject(ctx context.Context, projectID string) ([]store.DesiredService, error)
	// ListDesiredServicesByEnvironment is ListDesiredServicesByProject's
	// environment-kind counterpart: environment_clone.go's own clone
	// preview/execute handlers use it to find every app tagged with the
	// environment being cloned.
	ListDesiredServicesByEnvironment(ctx context.Context, environmentID string) ([]store.DesiredService, error)
	// RestartService is the only way to force a running container to be
	// recreated without an image change: a redeploy of the same image
	// tag is otherwise a genuine reconciler no-op (see
	// internal/reconcile/application.ContainerName's own doc comment).
	// See store.DB.RestartService's own doc comment for why this is
	// deliberately excluded from SaveDesiredService's full-record-replace
	// semantics, the same reasoning UpdateServiceNode already establishes
	// for NodeID.
	RestartService(ctx context.Context, name string) error
	// UpdateServiceProject is UpdateServiceNode's project-kind
	// counterpart (projects.go): same separation-from-ordinary-update
	// reasoning, see store.DB.UpdateServiceProject's own doc comment.
	UpdateServiceProject(ctx context.Context, name, projectID string) error
	// UpdateServiceStorageTarget backs PUT/DELETE
	// /api/v1/apps/{name}/storage (apps_storage.go): which store.BackupTarget
	// (already-established interface, BackupTargetStore below) this app's
	// own object-storage credentials resolve from. Same
	// separation-from-ordinary-update reasoning as UpdateServiceNode/
	// UpdateServiceProject, see store.DB.UpdateServiceStorageTarget's own
	// doc comment.
	UpdateServiceStorageTarget(ctx context.Context, name, storageTargetID string) error
	// UpdateServiceSuspended backs POST /api/v1/apps/{name}/stop and
	// .../start (handleStopApp/handleStartApp): same
	// separation-from-ordinary-update reasoning as UpdateServiceNode/
	// UpdateServiceProject/UpdateServiceStorageTarget, see
	// store.DB.UpdateServiceSuspended's own doc comment.
	UpdateServiceSuspended(ctx context.Context, name string, suspended bool) error
	// UpdateServiceApp is stage 2 of multi-service apps
	// (migrations/0039_apps.sql)'s own service-side setter: which
	// store.App a service belongs to. Same separation-from-ordinary-
	// update reasoning as UpdateServiceNode/UpdateServiceProject/
	// UpdateServiceStorageTarget/UpdateServiceSuspended, see
	// store.DB.UpdateServiceApp's own doc comment. Called from
	// ensureAppLinked (apps_multi.go), the shared create-or-reuse-and-link
	// path both handleCreateApp (an ordinary single-service app) and
	// handleDeploySpec (a multi-service fan-out) go through.
	UpdateServiceApp(ctx context.Context, name, appID string) error
	// UpdateServiceLogDrain backs PUT/DELETE
	// /api/v1/apps/{name}/log-drain (apps_log_drain.go): which external
	// sink (internal/telemetry.DrainForwarder) this app's container logs
	// additionally forward to. Same separation-from-ordinary-update
	// reasoning as UpdateServiceStorageTarget, see
	// store.DB.UpdateServiceLogDrain's own doc comment.
	UpdateServiceLogDrain(ctx context.Context, name string, drain *store.LogDrain) error
	// UpdateServiceDatabaseAttachment backs PUT/DELETE
	// /api/v1/apps/{name}/database (apps_database.go): which managed
	// database (DatabaseStore below) this app resolves one connection env
	// var from. Same separation-from-ordinary-update reasoning as
	// UpdateServiceStorageTarget, see store.DB.UpdateServiceDatabaseAttachment's
	// own doc comment.
	UpdateServiceDatabaseAttachment(ctx context.Context, name string, att *store.DatabaseAttachment) error
	// SetServiceAutoRollbackOnCrashloop backs PUT
	// /api/v1/apps/{name}/auto-rollback (deploys.go): whether
	// internal/alerting.MaybeAutoRollback rolls this app back
	// automatically the next time a KindCrashloop rule fires for it. Same
	// separation-from-ordinary-update reasoning as UpdateServiceStorageTarget,
	// see store.DB.SetServiceAutoRollbackOnCrashloop's own doc comment.
	SetServiceAutoRollbackOnCrashloop(ctx context.Context, name string, enabled bool) error
	// SetServiceAutoRollbackOnSLOBurn backs PUT
	// /api/v1/apps/{name}/auto-rollback-slo-burn (deploys.go): which mode
	// internal/alerting.MaybeAutoRollbackOnSLOBurn acts in the next time a
	// KindSLOBurn rule fires for this app. Same separation-from-ordinary-
	// update reasoning as SetServiceAutoRollbackOnCrashloop, see
	// store.DB.SetServiceAutoRollbackOnSLOBurn's own doc comment.
	SetServiceAutoRollbackOnSLOBurn(ctx context.Context, name, mode string) error
	// SetServiceExecEnabled backs PUT /api/v1/apps/{name}/exec-access
	// (exec.go): whether POST .../exec and GET .../terminal are even
	// attempted for this app, independent of the caller's own IAM
	// abilities. Same separation-from-ordinary-update reasoning as
	// SetServiceAutoRollbackOnCrashloop, see
	// store.DB.SetServiceExecEnabled's own doc comment.
	SetServiceExecEnabled(ctx context.Context, name string, enabled bool) error
	// SetServiceBadgeEnabled backs PUT /api/v1/apps/{name}/badge
	// (app_badge.go): whether GET .../badge.svg serves anything for
	// this app, or 404s. Same separation-from-ordinary-update reasoning
	// as SetServiceAutoRollbackOnCrashloop, see
	// store.DB.SetServiceBadgeEnabled's own doc comment.
	SetServiceBadgeEnabled(ctx context.Context, name string, enabled bool) error
	// SetServiceVaultEnvVar backs PUT/DELETE
	// /api/v1/apps/{name}/vault-env/{key} (apps_vault_env.go): the
	// UI/CLI-facing way to declare (or remove) one Vault-sourced env var
	// on an app that already exists, without going through the general
	// PUT /api/v1/apps/{name}, which would silently drop every other
	// declarative field (VaultEnv included) it doesn't itself carry
	// forward. Same separation-from-ordinary-update reasoning as
	// UpdateServiceDatabaseAttachment, see store.DB.SetServiceVaultEnvVar's
	// own doc comment.
	SetServiceVaultEnvVar(ctx context.Context, name, envVar string, ref *store.VaultEnvRef) error
	// SetServiceDatabaseEnvVar backs POST/DELETE
	// /api/v1/apps/{name}/connections[/{env_var}] (apps_connections.go):
	// the UI/CLI-facing way to declare (or remove) one entry in an app's
	// DatabaseEnv map, letting an app connect to more than one managed
	// database without app.yaml. Same separation-from-ordinary-update
	// reasoning as SetServiceVaultEnvVar, see
	// store.DB.SetServiceDatabaseEnvVar's own doc comment.
	SetServiceDatabaseEnvVar(ctx context.Context, name, envVar string, ref *store.DatabaseEnvRef) error
	// SetServicePreviewEnvOverride backs PUT/DELETE
	// /api/v1/apps/{name}/preview-env/{key} (apps_preview_env.go): the
	// UI/CLI-facing way to declare (or remove), on an app that already
	// exists, a preview-specific value for one env var that replaces
	// whatever this app's own Env/SecretEnv/VaultEnv holds for that key,
	// applied only when a preview environment is next created from this
	// app (deployPreviewSingle, preview_environments.go), never to this
	// app's own deploy. Same separation-from-ordinary-update reasoning as
	// SetServiceVaultEnvVar, see store.DB.SetServicePreviewEnvOverride's
	// own doc comment.
	SetServicePreviewEnvOverride(ctx context.Context, name, envVar string, value *string) error
	// UpdateServiceEgressPolicy backs GET/PUT/DELETE
	// /api/v1/apps/{name}/egress-policy (apps_egress.go): the UI/CLI-
	// facing way to set (or clear) an app's outbound network allowlist
	// outside a redeploy, mirroring SetServiceVaultEnvVar's own dual
	// write path (app.yaml's egress: block also sets this, via the
	// ordinary SaveDesiredService full-record-replace). Same
	// separation-from-ordinary-update reasoning as
	// UpdateServiceStorageTarget, see
	// store.DB.UpdateServiceEgressPolicy's own doc comment.
	UpdateServiceEgressPolicy(ctx context.Context, name string, policy *store.ServiceEgressPolicy) error
	// UpdateServiceHealth backs PUT /api/v1/apps/{name}/health (apps_health.go).
	UpdateServiceHealth(ctx context.Context, name string, health *store.ServiceHealth) error
	// UpdateServiceVolumes backs PUT /api/v1/apps/{name}/volumes
	// (apps_volumes_attach.go): the UI/CLI-facing way to attach or
	// remove a named Docker volume outside a redeploy, mirroring
	// UpdateServiceEgressPolicy's own dual write path. See
	// store.DB.UpdateServiceVolumes's own doc comment.
	UpdateServiceVolumes(ctx context.Context, name string, volumes []store.ServiceVolume) error
	// SetServiceBranchEnvOverride, DeleteServiceBranchEnvOverride, and
	// ListServiceBranchEnvOverrides back POST/DELETE/GET
	// /api/v1/apps/{name}/branch-env (apps_branch_env.go): a narrower,
	// branch-pattern-matched sibling of SetServicePreviewEnvOverride
	// above, applied only when a preview's own branch matches, see
	// store.SetServiceBranchEnvOverride's own doc comment.
	SetServiceBranchEnvOverride(ctx context.Context, serviceName, branchPattern, key, value string, secret bool) (string, error)
	DeleteServiceBranchEnvOverride(ctx context.Context, serviceName, id string) error
	ListServiceBranchEnvOverrides(ctx context.Context, serviceName string) ([]store.ServiceBranchEnvOverride, error)
}

AppStore is the store surface the apps and deploys handlers need. *store.DB satisfies this structurally; tests use a real temp-file store the same way internal/store's own tests do, not a mock.

type AppStreamStore ¶ added in v0.2.0

type AppStreamStore interface {
	SaveAppStream(ctx context.Context, s store.AppStream) error
	ListAppStreamsForService(ctx context.Context, serviceName string) ([]store.AppStream, error)
	ListAllAppStreams(ctx context.Context) ([]store.AppStream, error)
	DeleteAppStream(ctx context.Context, id string) error
	GetAppStream(ctx context.Context, id string) (store.AppStream, error)
}

AppStreamStore is the store surface the app stream handlers need.

type AppVolumeMoveStore ¶ added in v0.2.0

type AppVolumeMoveStore interface {
	StartAppVolumeMove(ctx context.Context, m store.AppVolumeMove) error
	UpdateAppVolumeMoveSteps(ctx context.Context, id string, steps []store.AppVolumeMoveStep) error
	FinishAppVolumeMove(ctx context.Context, id, status, errMsg, finishedAt string) error
	GetAppVolumeMove(ctx context.Context, id string) (store.AppVolumeMove, error)
	ListAppVolumeMoves(ctx context.Context, serviceName string) ([]store.AppVolumeMove, error)
}

AppVolumeMoveStore is the store surface handleMoveAppWithVolumes and its history endpoints need: recording a "move with volumes" attempt's steps and final outcome as it happens, so a caller can see exactly how far a partially-failed move got instead of a single black-box result. *store.DB satisfies this structurally.

type ApprovalChatNotifier ¶ added in v0.2.0

type ApprovalChatNotifier interface {
	SendApprovalRequest(ctx context.Context, c alerting.NotificationChannel, info alerting.ApprovalRequestInfo) error
}

ApprovalChatNotifier is the surface requestDeployApproval needs to post an interactive Approve/Deny message. *alerting.DeployDispatcher satisfies this structurally, the same "one dispatcher, several narrow interfaces" shape NotificationChannelTester already establishes.

type ArchiveSettingsStore ¶

type ArchiveSettingsStore interface {
	GetArchiveSettings(ctx context.Context) (store.ArchiveSettings, error)
	UpdateArchiveSettings(ctx context.Context, s store.ArchiveSettings, now time.Time) error
	RecordArchiveRun(ctx context.Context, at time.Time, runErr string) error
}

ArchiveSettingsStore persists the archive policy.

type AuditStore ¶

type AuditStore interface {
	SaveAuditEntry(ctx context.Context, e store.AuditEntry) error
	ListAuditEntries(ctx context.Context, limit int, before *time.Time, filter store.AuditEntryFilter) ([]store.AuditEntry, error)
	DeleteAuditEntriesOlderThan(ctx context.Context, cutoff time.Time) (int64, error)
}

AuditStore is the store surface requireAbility's audit hook (internal/api/auth.go), GET /api/v1/audit-log (audit.go), and the retention sweep/manual purge (audit_retention.go) need: insert-only recording, newest-first cursor-paginated reading, and age-based deletion. Always set, the same "core Store interface, not an optional plug-in" shape certs/staticSites/backupTargets already have.

type AuthLibOAuth ¶ added in v0.2.0

type AuthLibOAuth interface {
	OAuthEnabled() bool
	Prefix() string
	OAuthStart(r *http.Request, provider string) authengine.OAuthOutcome
	OAuthCallback(r *http.Request, provider string) authengine.OAuthOutcome
	ResolveOAuthUser(ctx context.Context, provider, providerUserID, newUserRoleID string) (userID string, created bool, err error)
	LinkOAuthIdentity(ctx context.Context, legacyUserID, provider, providerUserID string) error
	InvalidateProvider(name string)
}

AuthLibOAuth is the slice of the library auth engine the OAuth sign-in routes drive.

type AuthStore ¶

type AuthStore interface {
	GetUserByEmail(ctx context.Context, email string) (*store.User, error)
	GetUserByID(ctx context.Context, id string) (*store.User, error)
	CreateUser(ctx context.Context, u store.User) error
	UpdateUserPasswordHash(ctx context.Context, id string, hash *string) error
	UpdateUserLastLogin(ctx context.Context, id string, when time.Time) error
	CountUsers(ctx context.Context) (int, error)
	ListUsers(ctx context.Context) ([]store.User, error)
	DeleteUser(ctx context.Context, id string) error
	UpdateUserAbilities(ctx context.Context, id string, abilities []string) error
	UpdateUserDisplayName(ctx context.Context, id, name string) error
}

AuthStore is the store surface the auth handlers need.

type BackupDeleter ¶ added in v0.2.0

type BackupDeleter interface {
	DeleteBackup(ctx context.Context, historyID string) error
}

BackupDeleter is the delete surface internal/api needs from internal/backup, so internal/api never imports that package.

type BackupDownloader ¶

type BackupDownloader interface {
	Download(ctx context.Context, historyID string) (io.ReadCloser, error)
}

BackupDownloader is the surface the backup download handler needs from internal/backup.DownloadRunner: resolve one already-succeeded backup attempt's live object into a stream, the read-only counterpart of BackupRunner and RestoreRunner. *backup.DownloadRunner satisfies this structurally; internal/api never imports internal/backup directly, the same boundary BackupRunner's own doc comment describes.

type BackupHistoryStore ¶

type BackupHistoryStore interface {
	ListBackupHistory(ctx context.Context, databaseName string, limit int, before *time.Time) ([]store.BackupHistory, error)
	ListAllBackupHistory(ctx context.Context, limit int, before *time.Time) ([]store.BackupHistory, error)
	GetBackupHistory(ctx context.Context, id string) (store.BackupHistory, error)
}

BackupHistoryStore is the store surface the backup history handler needs. GetBackupHistory was added for handleTriggerRestore (restore.go): resolving the one backup attempt a restore names, not just listing every attempt for a database, the same "look up one row by ID" need GetBackupTarget already serves for backup targets.

type BackupProtection ¶ added in v0.2.0

type BackupProtection interface {
	Health(ctx context.Context) ([]backup.ResourceHealth, error)
	Encryption() backup.EncryptionStatus
	StartDrill(ctx context.Context, backupID string) (string, error)
	RefreshProtection(ctx context.Context, targetIDs []string) ([]store.BackupTargetProtection, error)
	VolumeExists(ctx context.Context, rtm docker.Runtime, name string) (exists, known bool, err error)
	RestoreVolumeTo(ctx context.Context, rtm docker.Runtime, historyID, sourceService, sourceVolume, newVolume, backupID string) error
}

BackupProtection is the surface the backup health, drill and restore-to routes need from internal/backup.Protection.

type BackupProtectionStore ¶ added in v0.2.0

type BackupProtectionStore interface {
	ListBackupDrills(ctx context.Context, serviceName, volumeName, databaseName string, limit int) ([]store.BackupDrill, error)
	GetBackupDrill(ctx context.Context, id string) (store.BackupDrill, error)
	GetVolumeBackupPolicy(ctx context.Context, serviceName, volumeName string) (store.VolumeBackupPolicy, error)
	SetVolumeBackupPolicy(ctx context.Context, p store.VolumeBackupPolicy) error
	ListBackupTargetProtection(ctx context.Context) ([]store.BackupTargetProtection, error)
}

BackupProtectionStore is the store surface the same routes read and write.

type BackupRunner ¶

type BackupRunner interface {
	RunBackup(ctx context.Context, historyID, databaseName, engine, containerName, targetID string) error
}

BackupRunner is the surface the backup trigger handler needs from internal/backup.Runner: run one backup attempt end to end, from an already-minted history ID through to a finished store.BackupHistory row. *backup.Runner satisfies this structurally; internal/api never imports internal/backup directly (the same reconciler-internals boundary databaseContainerName's own doc comment describes), only this narrow interface, wired in by cmd/levelrail at startup.

type BackupSecretsSetter ¶

type BackupSecretsSetter interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
}

BackupSecretsSetter is the surface backup target creation needs from internal/secrets.Manager: store a credential value, the same "set a value, never read one back through this interface" shape SecretSetter already establishes for app secrets. A distinct type from SecretSetter even though both are structurally satisfied by *secrets.Manager, because a backup target's credentials do get resolved back out server-side, just not through this interface or this package: that's internal/backup.Runner's own, separate, narrower internal/backup.SecretsResolver, wired directly in cmd/levelrail, not through the Router at all.

type BackupTargetStore ¶

type BackupTargetStore interface {
	SaveBackupTarget(ctx context.Context, t store.BackupTarget) error
	GetBackupTarget(ctx context.Context, id string) (store.BackupTarget, error)
	ListBackupTargets(ctx context.Context) ([]store.BackupTarget, error)
	UpdateBackupTarget(ctx context.Context, id, name, provider, endpoint, region, bucket string) error
	DeleteBackupTarget(ctx context.Context, id string) error
}

BackupTargetStore is the store surface the backup target handlers need.

type BackupTargetTester ¶

type BackupTargetTester interface {
	TestTarget(ctx context.Context, targetID string) error
}

BackupTargetTester is the surface the test-connection handler needs from internal/backup.TargetTester: probe one target's configured bucket over its stored credentials, without uploading or deleting anything. *backup.TargetTester satisfies this structurally; internal/api never resolves a backup target's credentials directly, the same boundary BackupSecretsSetter's own doc comment describes.

type BackupVerificationStore ¶

type BackupVerificationStore interface {
	ListBackupVerifications(ctx context.Context, backupHistoryID string, limit int) ([]store.BackupVerification, error)
}

BackupVerificationStore is the store surface the backup verification handlers need: listing past verification attempts for one backup, the same "core Store interface, no runner configuration needed" shape BackupHistoryStore's own doc comment establishes for backup history itself.

type BackupVerifier ¶

type BackupVerifier interface {
	VerifyBackup(ctx context.Context, verificationID, backupHistoryID, engine, checkedBy string) error
}

BackupVerifier is the surface the verify-trigger handler needs from internal/backup.VerifyRunner: run one verification attempt end to end, from an already-minted verification ID through to a finished store.BackupVerification row. *backup.VerifyRunner satisfies this structurally; internal/api never imports internal/backup directly, the same boundary BackupRunner's own doc comment describes.

type BaseBackupHistoryStore ¶ added in v0.2.0

type BaseBackupHistoryStore interface {
	ListBaseBackupHistory(ctx context.Context, databaseName string) ([]store.BaseBackupHistory, error)
}

BaseBackupHistoryStore is the store surface the base backup handlers need.

type BaseBackupRunner ¶ added in v0.2.0

type BaseBackupRunner interface {
	RunBaseBackup(ctx context.Context, historyID, databaseName, containerName, targetID string) error
}

BaseBackupRunner is the surface the base backup trigger handler needs from internal/backup.BaseBackupRunner: run one physical base backup attempt end to end. *backup.BaseBackupRunner satisfies this structurally; internal/api never imports internal/backup directly (databaseContainerName's own doc comment describes this boundary), only this narrow interface, wired in by cmd/levelrail at startup.

type BenchmarkStore ¶

type BenchmarkStore interface {
	RecordBenchmarkRun(ctx context.Context, run store.BenchmarkRun, keep int) (string, bool, error)
	ListBenchmarkRuns(ctx context.Context, limit int) ([]store.BenchmarkRunSummary, error)
	GetBenchmarkRun(ctx context.Context, id string) (store.BenchmarkRun, error)
	DeleteBenchmarkRun(ctx context.Context, id string) error
}

BenchmarkStore persists benchmark results files.

type BetaFeatureStore ¶ added in v0.2.0

type BetaFeatureStore interface {
	ListBetaFeatures(ctx context.Context) (map[string]bool, error)
}

BetaFeatureStore persists the Settings switches for beta features.

type BitbucketAppClient ¶

type BitbucketAppClient interface {
	ExchangeCode(ctx context.Context, key, secret, code string) (bitbucketapp.Tokens, error)
	RefreshToken(ctx context.Context, key, secret, refreshToken string) (bitbucketapp.Tokens, error)
	CurrentUser(ctx context.Context, accessToken string) (bitbucketapp.Account, error)
	ListRepos(ctx context.Context, accessToken string, opts gitprovider.ListOptions) ([]bitbucketapp.Repo, gitprovider.ListResult, error)
	GetRepo(ctx context.Context, accessToken, fullName string) (bitbucketapp.Repo, error)
	ListBranches(ctx context.Context, accessToken, fullName string) ([]bitbucketapp.Branch, error)
	CreateRepoWebhook(ctx context.Context, accessToken, fullName, hookURL, secret string) error
	CreatePullRequestComment(ctx context.Context, accessToken, fullName string, prID int, body string) (int64, error)
	ListPullRequestComments(ctx context.Context, accessToken, fullName string, prID int) ([]gitprovider.Comment, error)
	UpdatePullRequestComment(ctx context.Context, accessToken, fullName string, prID int, commentID int64, body string) error
	CreateCommitBuildStatus(ctx context.Context, accessToken, fullName, commit string, state bitbucketapp.BuildStatusState, targetURL, description, key string) error
}

BitbucketAppClient is the surface internal/api needs from internal/bitbucketapp.Client.

type BitbucketServerClient ¶

type BitbucketServerClient interface {
	CurrentUser(ctx context.Context, instanceURL, token string) (bitbucketserver.Account, error)
	ListRepos(ctx context.Context, instanceURL, token string, opts gitprovider.ListOptions) ([]bitbucketserver.Repo, gitprovider.ListResult, error)
	GetRepo(ctx context.Context, instanceURL, token, repo string) (bitbucketserver.Repo, error)
	DefaultBranch(ctx context.Context, instanceURL, token, repo string) (string, error)
	ListBranches(ctx context.Context, instanceURL, token, repo string) ([]bitbucketserver.Branch, error)
	CreateRepoWebhook(ctx context.Context, instanceURL, token, repo, hookURL, secret string) error
	DeleteRepoWebhook(ctx context.Context, instanceURL, token, repo, hookURL string) error
}

BitbucketServerClient is the surface internal/api needs from internal/bitbucketserver.Client.

type BranchDeployStore ¶

type BranchDeployStore interface {
	GetBranchDeploySettings(ctx context.Context, appName string) (store.BranchDeploySettings, error)
	SaveBranchDeploySettings(ctx context.Context, s store.BranchDeploySettings) error
	SaveBranchDeploy(ctx context.Context, b store.BranchDeploy) error
	UpdateBranchDeploy(ctx context.Context, b store.BranchDeploy) error
	GetBranchDeployBySlug(ctx context.Context, appName, slug string) (*store.BranchDeploy, error)
	ListBranchDeploysByApp(ctx context.Context, appName string) ([]store.BranchDeploy, error)
	ListBranchDeploys(ctx context.Context) ([]store.BranchDeploy, error)
	DeleteBranchDeploy(ctx context.Context, id string) error
}

BranchDeployStore is the store surface branch deploys need. *store.DB satisfies it.

type BucketRowStore ¶

type BucketRowStore interface {
	CreateStorageBucket(ctx context.Context, b store.StorageBucket) (store.StorageBucket, error)
	GetStorageBucket(ctx context.Context, id string) (store.StorageBucket, error)
	ListStorageBuckets(ctx context.Context) ([]store.StorageBucket, error)
	UpdateStorageBucketSettings(ctx context.Context, id string, public bool, quotaBytes int64, lifecycleDays int) error
	DeleteStorageBucket(ctx context.Context, id string) error
	BindStorageBucket(ctx context.Context, bucketID, appName, envPrefix string) error
	UnbindStorageBucket(ctx context.Context, bucketID, appName string) error
	ListStorageBucketBindings(ctx context.Context, appName string) ([]store.StorageBucketBinding, error)
}

BucketRowStore persists named buckets and their app bindings.

type BucketSweepService ¶

type BucketSweepService interface {
	Sweep(ctx context.Context, b store.StorageBucket) (objectstore.SweepResult, error)
}

BucketSweepService runs a bucket's lifecycle rule on demand.

type BuildCacheResolver ¶

type BuildCacheResolver func(nodeID string) (docker.BuildCacheAdmin, error)

BuildCacheResolver returns the build cache admin of one node, "" being the control plane's own.

type BuildCacheService ¶ added in v0.2.0

type BuildCacheService interface {
	KeyPrefix(app string) (string, error)
	Stats(ctx context.Context, app string) (objectstore.CacheStats, error)
	Clear(ctx context.Context, app string) (objectstore.ClearResult, error)
}

BuildCacheService runs bucket-side cache hygiene.

type BuildCacheSettingsStore ¶ added in v0.2.0

type BuildCacheSettingsStore interface {
	UpsertBuildCacheSetting(ctx context.Context, s store.BuildCacheSetting) error
	GetBuildCacheSetting(ctx context.Context, appName string) (store.BuildCacheSetting, error)
	ListBuildCacheSettings(ctx context.Context) ([]store.BuildCacheSetting, error)
	DeleteBuildCacheSetting(ctx context.Context, appName string) error
}

BuildCacheSettingsStore persists build cache settings.

type BuildHookStore ¶

type BuildHookStore interface {
	CreateBuildHook(ctx context.Context, h store.BuildHook) error
	ListBuildHooks(ctx context.Context, serviceName string) ([]store.BuildHook, error)
	GetBuildHook(ctx context.Context, id string) (store.BuildHook, error)
	SetBuildHookTokenHash(ctx context.Context, serviceName, id, hash string) error
	DeleteBuildHook(ctx context.Context, serviceName, id string) error
	RecordBuildHookTrigger(ctx context.Context, id, result string, at time.Time) error
	RecordBuildHookResult(ctx context.Context, id, result string) error
}

BuildHookStore is the store surface for per-app incoming build hooks.

type BuildLoadSource ¶

type BuildLoadSource interface {
	Load() []build.NodeLoad
}

BuildLoadSource reports per-node build slot usage.

type BuildPerformanceStore ¶

type BuildPerformanceStore interface {
	RecordBuildRun(ctx context.Context, r store.BuildRun) error
	ListBuildRuns(ctx context.Context, app string, limit int) ([]store.BuildRun, error)
	ListAllBuildRuns(ctx context.Context, limit int) ([]store.BuildRun, error)
	ListBuildAttempts(ctx context.Context, limit int) ([]store.DeployAttempt, error)
	GetBuildLimitSetting(ctx context.Context, key string) (int64, bool, error)
	SetBuildLimitSetting(ctx context.Context, key string, value int64, actor string, now time.Time) error
	ClearBuildLimitSetting(ctx context.Context, key string) error
}

BuildPerformanceStore is the persistence behind build limits and build stats.

type Builder ¶

type Builder interface {
	Deploy(ctx context.Context, req deploy.Request, progress func(build.ProgressEvent)) (string, error)
	// DeploySpec is handleDeploySpec's (apps_multi.go) own narrow need:
	// the multi-service fan-out entry point. Same *deploy.Pipeline
	// satisfies both methods, so this stays one interface rather than a
	// second router field, the same "one concrete type, one interface"
	// shape every other narrow store/builder interface in this codebase
	// already follows.
	DeploySpec(ctx context.Context, req deploy.MultiRequest, progress func(serviceKey string, ev build.ProgressEvent)) ([]deploy.ServiceOutcome, error)
}

Builder is the surface the manual build trigger handler (handleTriggerBuild) needs from internal/deploy.Pipeline, the exact same narrow-interface shape internal/webhook.Deployer already establishes for the identical method, so both call sites can be satisfied by the one real *deploy.Pipeline cmd/levelrail/main.go builds. *deploy.Pipeline satisfies this structurally.

type CIClaims ¶

type CIClaims struct {
	Repository  string
	Ref         string
	Environment string
	Subject     string
}

CIClaims are the verified claims of a CI provider identity token.

type CIIDTokenVerifier ¶

type CIIDTokenVerifier interface {
	Verify(ctx context.Context, rawToken, audience string) (CIClaims, error)
}

CIIDTokenVerifier checks a CI identity token's signature, issuer, audience and expiry.

type CIOIDCTrustStore ¶

type CIOIDCTrustStore interface {
	SaveCIOIDCTrust(ctx context.Context, t store.CIOIDCTrust) error
	ListCIOIDCTrusts(ctx context.Context, serviceName string) ([]store.CIOIDCTrust, error)
	ListCIOIDCTrustsForRepo(ctx context.Context, repository, serviceName string) ([]store.CIOIDCTrust, error)
	DeleteCIOIDCTrust(ctx context.Context, serviceName, id string) (store.CIOIDCTrust, error)
}

CIOIDCTrustStore is the store surface for CI OIDC trusts.

type CachePurgeStore ¶

type CachePurgeStore interface {
	AddCachePurge(ctx context.Context, p store.CachePurge) error
	ListCachePurges(ctx context.Context, app string, limit int) ([]store.CachePurge, error)
}

CachePurgeStore keeps the per-app purge history shown on the Caches page.

type CanaryProgress ¶

type CanaryProgress interface {
	Progress(rel store.CanaryRelease) (canary.Progress, bool)
}

CanaryProgress reports the live stage comparison of a staged canary.

type CanaryStore ¶ added in v0.2.0

type CanaryStore interface {
	SetCanaryRelease(ctx context.Context, c store.CanaryRelease) error
	GetCanaryRelease(ctx context.Context, serviceName string) (store.CanaryRelease, bool, error)
	DeleteCanaryRelease(ctx context.Context, serviceName string) error
	ListCanaryReleases(ctx context.Context) ([]store.CanaryRelease, error)
	GetCanaryPolicy(ctx context.Context, serviceName string) (store.CanaryPolicy, bool, error)
	SetCanaryOutcome(ctx context.Context, o store.CanaryOutcome) error
	GetCanaryOutcome(ctx context.Context, serviceName string) (store.CanaryOutcome, bool, error)
}

CanaryStore is the store surface the canary routes need.

type CertObservationSource ¶ added in v0.2.0

type CertObservationSource interface {
	ListAllCertExpiryObservations(ctx context.Context) ([]alerting.CertExpiryObservation, error)
}

CertObservationSource lists the expiry observations kind=cert_expiry rules record; *alerting.DB satisfies it.

type CertStore ¶

type CertStore interface {
	ListCertStorageKeys(ctx context.Context, prefix string, recursive bool) ([]string, error)
	GetCertStorageValue(ctx context.Context, key string) (*store.CertStorageValue, error)
	DeleteCertStorageValue(ctx context.Context, key string) error
}

CertStore is the store surface handleListCertificates and handleRenewDomainCertificate need: the two read methods internal/ingress.SQLiteStorage also uses, plus the delete method renew needs to clear a domain's stored certificate. *store.DB satisfies this structurally, same as every other Store sub-interface in this package.

type ChannelQuietHours ¶

type ChannelQuietHours interface {
	GetChannelQuietHours(ctx context.Context, channelID string) (*alerting.QuietHours, error)
	SetChannelQuietHours(ctx context.Context, q alerting.QuietHours) error
	DeleteChannelQuietHours(ctx context.Context, channelID string) error
}

ChannelQuietHours is the quiet-hours surface of alerting.DB.

type ChaosStore ¶

type ChaosStore interface {
	RecordChaosResult(ctx context.Context, r chaos.Result, recordedBy string) (string, error)
	ListChaosResults(ctx context.Context, limit int) ([]chaos.Result, error)
}

ChaosStore persists measured chaos scenario runs.

type CloneRestoreHistoryStore ¶

type CloneRestoreHistoryStore interface {
	ListCloneRestores(ctx context.Context, sourceDatabaseName string) ([]store.CloneRestore, error)
}

CloneRestoreHistoryStore is the store surface the clone-restore history handler needs, the "restore as new database" counterpart to RestoreHistoryStore (restore.go).

type CloneRestoreRunner ¶

type CloneRestoreRunner interface {
	RunCloneRestore(ctx context.Context, historyID, sourceDatabaseName, newDatabaseName, backupHistoryID, engine, containerName, controllerName string) error
}

CloneRestoreRunner is the surface the clone-restore trigger handler needs from internal/backup.CloneRestoreRunner: wait for a newly created database to come up and restore a backup into it, from an already-minted history ID through to a finished store.CloneRestore row. *backup.CloneRestoreRunner satisfies this structurally; internal/api never imports internal/backup directly, the same boundary RestoreRunner's own doc comment describes.

type CloudflareDNSSecrets ¶

type CloudflareDNSSecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	DeleteAll(ctx context.Context, serviceName string) error
}

CloudflareDNSSecrets is the surface the Cloudflare DNS-01 settings handlers need from internal/secrets.Manager, the same shape CloudflareTunnelSecrets already establishes for a distinct credential (a scoped Cloudflare API token, not the cloudflared connector token).

type CloudflareDNSStore ¶

type CloudflareDNSStore interface {
	GetCloudflareDNSSettings(ctx context.Context) (store.CloudflareDNSSettings, error)
	UpdateCloudflareDNSSettings(ctx context.Context, s store.CloudflareDNSSettings) error
}

CloudflareDNSStore is the store surface GET/PUT /api/v1/settings/cloudflare-dns need, the same "single platform-wide row" shape CloudflareTunnelStore already establishes.

type CloudflareDNSTokenResolver ¶ added in v0.2.0

type CloudflareDNSTokenResolver interface {
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
}

CloudflareDNSTokenResolver is the narrow surface GET/POST/PUT/DELETE .../dns-records need from internal/secrets.Manager to read back the plaintext Cloudflare DNS-01 token this control plane already stores: CloudflareDNSSecrets (cloudflare_dns.go) only checks presence, it never reads the value back, since the settings resource never needs to. *secrets.Manager satisfies this structurally, the same shape internal/reconcile/ingress's own identically-named interface already establishes for the same credential.

type CloudflareTunnelSecrets ¶

type CloudflareTunnelSecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	DeleteAll(ctx context.Context, serviceName string) error
}

CloudflareTunnelSecrets is the surface the Cloudflare Tunnel settings handlers need from internal/secrets.Manager: set the token (PUT), check whether one exists (GET's has_token, and PUT's "was a token already set" check for the omitted-token case), and clear it (DELETE). *secrets.Manager satisfies this structurally, the same "narrow, consumer-defined interface" shape GitHubAppSecrets already establishes.

type CloudflareTunnelStore ¶

type CloudflareTunnelStore interface {
	GetCloudflareTunnelSettings(ctx context.Context) (store.CloudflareTunnelSettings, error)
	UpdateCloudflareTunnelSettings(ctx context.Context, s store.CloudflareTunnelSettings) error
}

CloudflareTunnelStore is the store surface GET/PUT/DELETE /api/v1/settings/cloudflare-tunnel need: the single platform-wide row, always present, the same shape EmailSettingsStore has for its own row.

type ComposeRevisionStore ¶ added in v0.2.0

type ComposeRevisionStore interface {
	AddComposeRevision(ctx context.Context, rev store.ComposeRevision) (int, error)
	ListComposeRevisions(ctx context.Context, appID string, limit int) ([]store.ComposeRevision, error)
	GetComposeRevision(ctx context.Context, appID string, revision int) (store.ComposeRevision, error)
	ListComposeApps(ctx context.Context) ([]string, error)
	DeleteComposeRevisions(ctx context.Context, appID string) error
}

ComposeRevisionStore is the store surface compose stacks need for history and rollback.

type ComposeSecretStore ¶

type ComposeSecretStore interface {
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
}

ComposeSecretStore is the surface POST /api/v1/apps/{name}/compose needs to resolve a compose file's SERVICE_ magic vars (compose.ResolveMagicVars): a canonical generate-once-per-app value (Resolve/SetValue keyed by the app's own name, a synthetic bucket distinct from any real service), plus one SetValue per real service that references it, since internal/secrets.Manager itself is keyed per real service, not per app.

type ContainerLister ¶

type ContainerLister interface {
	ListByPrefix(ctx context.Context, prefix string) ([]docker.ContainerState, error)
}

ContainerLister lists every container on the node, managed or not (empty prefix matches all). *docker.Client satisfies it.

type ContextConfigStore ¶

type ContextConfigStore interface {
	SaveAppContextConfig(ctx context.Context, c store.AppContextConfig) error
	DeleteAppContextConfig(ctx context.Context, appName, contextName string) (bool, error)
	ListAppContextConfigs(ctx context.Context, appName string) ([]store.AppContextConfig, error)
}

ContextConfigStore is the store surface deploy contexts need. *store.DB satisfies it.

type ControlPlaneBackupManager ¶ added in v0.2.0

type ControlPlaneBackupManager interface {
	Create(ctx context.Context) (cpbackup.Info, error)
	List() ([]cpbackup.Info, error)
	Open(name string) (*os.File, cpbackup.Info, error)
	Delete(name string) error
	Verify(ctx context.Context, name string) (cpbackup.VerifyResult, error)
}

ControlPlaneBackupManager is the surface the /system/backups routes need.

type ControlPlaneDB ¶

type ControlPlaneDB interface {
	Metrics() store.DBMetrics
	CheckpointWAL(ctx context.Context, truncate bool) error
	Optimize(ctx context.Context) error
	ResetSlowQueries()
}

ControlPlaneDB is the database surface the health page reads and fixes.

type ControlPlaneDR ¶ added in v0.2.0

type ControlPlaneDR interface {
	Status(ctx context.Context) (cpbackup.Status, error)
	UpdateConfig(ctx context.Context, u cpbackup.ConfigUpdate) error
	ListRemote(ctx context.Context) ([]cpbackup.Remote, error)
	StartBackup() error
	StartDrill() error
	BuildEscrow(ctx context.Context, in cpbackup.EscrowInput) (cpbackup.EscrowBundle, error)
	AckEscrow(ctx context.Context) error
}

ControlPlaneDR is the surface the /system/control-plane-dr routes need.

type ControlPlaneProbe ¶

type ControlPlaneProbe struct {
	DB             ControlPlaneDB
	Reconcile      func() reconcile.Stats
	ResyncInterval time.Duration
	Telemetry      TelemetryStore
	MemoryLimit    footprint.MemoryLimit
	Integrity      IntegrityProbe
	Guard          GuardProbe
	AppCount       func(ctx context.Context) int
}

ControlPlaneProbe wires the health page to the running process.

type CustomTemplateStore ¶ added in v0.2.0

type CustomTemplateStore interface {
	SaveCustomTemplate(ctx context.Context, t store.CustomTemplate) error
	GetCustomTemplate(ctx context.Context, id string) (store.CustomTemplate, error)
	ListCustomTemplates(ctx context.Context) ([]store.CustomTemplate, error)
	DeleteCustomTemplate(ctx context.Context, id string) error
}

CustomTemplateStore is the store surface save-as-template needs (service_templates_custom.go): CRUD on operator-defined templates, the growth-loop counterpart to internal/catalog's static built-in catalog. See store.CustomTemplate's own doc comment for why a template row never holds a real secret value.

type DBPinger ¶

type DBPinger interface {
	PingContext(ctx context.Context) error
}

DBPinger is the surface GET /api/v1/system/doctor needs to report the control plane's own SQLite reachability, the same narrow, single-purpose shape DockerPinger above already establishes. *store.DB satisfies this structurally via its embedded *sql.DB's PingContext method.

type DashboardStore ¶

type DashboardStore interface {
	CreateCustomDashboard(ctx context.Context, d store.CustomDashboard) error
	UpdateCustomDashboard(ctx context.Context, d store.CustomDashboard) error
	GetCustomDashboard(ctx context.Context, id string) (store.CustomDashboard, error)
	ListCustomDashboards(ctx context.Context, owner, projectID string) ([]store.CustomDashboard, error)
	DeleteCustomDashboard(ctx context.Context, id string) error
}

DashboardStore persists custom dashboards.

type DataExportService ¶ added in v0.2.0

type DataExportService interface {
	List(ctx context.Context) ([]store.ExportDestination, error)
	Get(ctx context.Context, id string) (store.ExportDestination, error)
	Create(ctx context.Context, in dataexport.Input) (store.ExportDestination, error)
	Update(ctx context.Context, id string, p dataexport.Patch) (store.ExportDestination, error)
	Delete(ctx context.Context, id string) error
	Test(ctx context.Context, id string) error
	Status(ctx context.Context, id string) (store.ExportStatus, error)
	Series(ctx context.Context, allow dataexport.ResourceFilter) ([]dataexport.Series, error)
	StreamAudit(ctx context.Context, from, to time.Time, fn func(dataexport.AuditRecord) error) error
}

DataExportService is the surface the export routes need from internal/dataexport; *dataexport.Service satisfies it.

type DataImportStore ¶ added in v0.2.0

type DataImportStore interface {
	ClaimDatabaseDataImport(ctx context.Context, name, host string, port int, srcDB string, now time.Time, staleAfter time.Duration) error
	FinishDatabaseDataImport(ctx context.Context, name, status, reason string, checked, mismatched int, detail string, now time.Time) error
	GetDatabaseDataImport(ctx context.Context, name string) (store.DatabaseDataImport, bool, error)
	ListDatabaseDataImports(ctx context.Context) ([]store.DatabaseDataImport, error)
}

DataImportStore is the store surface the live data copy routes need.

type DatabaseAccessStore ¶ added in v0.2.0

type DatabaseAccessStore interface {
	RecordDatabaseAccessUser(ctx context.Context, u store.DatabaseAccessUser) error
	ListDatabaseAccessUsers(ctx context.Context, database, kind string) ([]store.DatabaseAccessUser, error)
	GetDatabaseAccessUser(ctx context.Context, database, role string) (*store.DatabaseAccessUser, error)
	GetDatabaseAccessUserByID(ctx context.Context, id string) (*store.DatabaseAccessUser, error)
	MarkDatabaseAccessUserRevoked(ctx context.Context, database, role string, now time.Time) error
	GetDatabaseAccessSettings(ctx context.Context, database string) (store.DatabaseAccessSettings, error)
	SaveDatabaseAccessSettings(ctx context.Context, s store.DatabaseAccessSettings) error
	ListDatabaseNetworkRuleNotes(ctx context.Context, database string) (map[string]string, error)
	ReplaceDatabaseNetworkRuleNotes(ctx context.Context, database string, notes map[string]string) error
	EnvironmentOfDatabase(ctx context.Context, databaseName string) (*store.EnvironmentRef, error)
	EnvironmentOfApp(ctx context.Context, appName string) (*store.EnvironmentRef, error)
}

DatabaseAccessStore is the persistence the database access, network and temporary credential handlers need. *store.DB satisfies it.

type DatabaseQueryStore ¶ added in v0.2.0

type DatabaseQueryStore interface {
	AddDatabaseQueryHistory(ctx context.Context, h store.DatabaseQueryHistory, keep int) (store.DatabaseQueryHistory, error)
	ListDatabaseQueryHistory(ctx context.Context, database, principalType, principalID string, limit int) ([]store.DatabaseQueryHistory, error)
	ClearDatabaseQueryHistory(ctx context.Context, database, principalType, principalID string) error
	SaveDatabaseQuery(ctx context.Context, q store.DatabaseSavedQuery) (store.DatabaseSavedQuery, error)
	ListDatabaseSavedQueries(ctx context.Context, database, principalType, principalID string) ([]store.DatabaseSavedQuery, error)
	DeleteDatabaseSavedQuery(ctx context.Context, database, principalType, principalID, id string) error
}

DatabaseQueryStore is the store surface the console's history and saved query routes need.

type DatabaseStore ¶

type DatabaseStore interface {
	SaveDesiredDatabase(ctx context.Context, d store.DesiredDatabase) error
	GetDesiredDatabase(ctx context.Context, name string) (*store.DesiredDatabase, error)
	ListDesiredDatabases(ctx context.Context) ([]store.DesiredDatabase, error)
	DeleteDesiredDatabase(ctx context.Context, name string) error
	// UpdateDatabaseNode is AppStore.UpdateServiceNode's counterpart,
	// same separation-from-ordinary-update reasoning. Originally added
	// unexposed by 3.3; handleDrainNode is the first caller with an
	// actual route to reuse it through.
	UpdateDatabaseNode(ctx context.Context, name, nodeID string) error
	// ListDesiredDatabasesByNode is the database-kind counterpart to
	// AppStore.ListDesiredServicesByNode.
	ListDesiredDatabasesByNode(ctx context.Context, nodeID string) ([]store.DesiredDatabase, error)
	// ListDesiredDatabasesByProject is the database-kind counterpart to
	// AppStore.ListDesiredServicesByProject.
	ListDesiredDatabasesByProject(ctx context.Context, projectID string) ([]store.DesiredDatabase, error)
	// UpdateDatabaseSuspended is AppStore.UpdateServiceSuspended's
	// counterpart, backing POST /api/v1/projects/{id}/stop and .../start
	// (project_stop_start.go) and POST /api/v1/databases/{name}/stop and
	// .../start (database_stop_start.go): same separation-from-ordinary-
	// update reasoning as UpdateDatabaseNode/UpdateDatabaseProject, see
	// store.DB.UpdateDatabaseSuspended's own doc comment.
	UpdateDatabaseSuspended(ctx context.Context, name string, suspended bool) error
	// UpdateDatabaseProject is AppStore.UpdateServiceProject's
	// counterpart (projects.go).
	UpdateDatabaseProject(ctx context.Context, name, projectID string) error
	// SetDatabaseBackupSchedule backs
	// PUT/DELETE /api/v1/databases/{name}/backup-schedule (backups.go):
	// wave-2 roadmap item 6, scheduled backups. Same "own endpoint, own
	// store method" separation UpdateDatabaseNode/UpdateDatabaseProject
	// already establish for their own single-purpose updates.
	SetDatabaseBackupSchedule(ctx context.Context, name, targetID, schedule string, retain, retainDays int) error
	// SetDatabasePITR backs POST/DELETE /api/v1/databases/{name}/pitr
	// (pitr.go): same "own endpoint, own store method" separation
	// SetDatabaseBackupSchedule above establishes.
	SetDatabasePITR(ctx context.Context, name string, enabled bool, enabledAt string) error
	// SetDatabasePublicAccess backs
	// PUT/DELETE /api/v1/databases/{name}/public-access
	// (database_public_access.go): the same "own endpoint, own store
	// method" separation SetDatabaseBackupSchedule already establishes,
	// applied to whether this database's container port is bound to a
	// host port. requestedBindAddress empty resolves to
	// store.DefaultBindAddress; ignored when enabled is false. Returns
	// the port actually assigned (0 when disabling).
	SetDatabasePublicAccess(ctx context.Context, name string, enabled bool, requestedPort int, requestedBindAddress string) (int, error)
}

DatabaseStore is the store surface the databases handlers need, the database-kind counterpart to AppStore.

type DatabaseUpgrader ¶ added in v0.2.0

type DatabaseUpgrader interface {
	Overview(ctx context.Context, name string) (dbupgrade.Overview, error)
	EffectivePolicy(ctx context.Context, name string) (dbupgrade.Policy, bool, error)
	SetPolicy(ctx context.Context, name string, p dbupgrade.Policy, inherit bool, by string) error
	UpgradeNow(ctx context.Context, name, version, by string) (store.DBUpgradeRun, error)
	Summary(ctx context.Context, visible func(string) bool) ([]dbupgrade.SummaryItem, error)
}

DatabaseUpgrader is the upgrade advisor, policy store and runner (internal/dbupgrade.Manager).

type DatabaseVersionCatalog ¶

type DatabaseVersionCatalog interface {
	Engines() []string
	Versions(engine string) (dbupgrade.VersionsView, error)
	LiveRefresh(ctx context.Context, engine string) (dbupgrade.VersionsView, bool, error)
	Status() dbupgrade.Status
	Refresh(ctx context.Context) error
	SetRemoteEnabled(enabled bool) error
}

DatabaseVersionCatalog is the remote-refreshed version catalog (internal/dbupgrade.RemoteCatalog).

type DemoConfig ¶

type DemoConfig struct {
	// VisitorUserID is the seeded read-only account sessions are minted for.
	VisitorUserID string
	Username      string
	Password      string
	// Verifier is optional; nil means no human check is enforced.
	Verifier HumanVerifier
	// SessionsPerMinute caps session mints per client IP; zero uses the default.
	SessionsPerMinute int
	ResetsAt          func() time.Time
	InstallCommand    string
	RepoURL           string
	DocsURL           string
	Version           string
}

DemoConfig turns the Router into the read-only public demo. It is only ever built by the demo entrypoint, never from the ordinary process wiring.

type DemoStats ¶

type DemoStats struct {
	SessionsMinted int            `json:"sessions_minted"`
	CTAClicks      map[string]int `json:"cta_clicks"`
}

DemoStats is the aggregate, PII-free counter snapshot the demo host flushes.

type DeployApprovalStore ¶ added in v0.2.0

type DeployApprovalStore interface {
	SaveDeployApproval(ctx context.Context, a store.DeployApproval) error
	GetDeployApproval(ctx context.Context, id string) (store.DeployApproval, error)
	ListDeployApprovals(ctx context.Context, status, serviceName string) ([]store.DeployApproval, error)
	DecideDeployApproval(ctx context.Context, id, newStatus, approvedByType, approvedBy, approvedByName, reason, decidedAt string) (bool, error)
}

DeployApprovalStore is the surface deploy_approvals.go needs: create a pending approval gate for a deploy/promote into a protected environment, list/get it, and record a terminal decision (approve, reject, or expire). Always set, the same "core Store interface, not an optional plug-in" shape HookRunStore above establishes.

type DeployAttemptStore ¶

type DeployAttemptStore interface {
	SaveDeployAttempt(ctx context.Context, a store.DeployAttempt) error
	SetDeployAttemptCommit(ctx context.Context, id, image, commitSHA string) error
	FinishDeployAttempt(ctx context.Context, id, status string, finishedAt time.Time, errMsg string) error
	GetDeployAttempt(ctx context.Context, id string) (*store.DeployAttempt, error)
	ListDeployAttempts(ctx context.Context, serviceName string) ([]store.DeployAttempt, error)
	ListFailedDeploysSince(ctx context.Context, since time.Time) ([]store.FailedDeploy, error)
}

DeployAttemptStore is the store surface for row-per-attempt deploy history, backing GET /api/v1/apps/{name}/deploy-attempts. *store.DB satisfies this structurally.

type DeployExitStore ¶

type DeployExitStore interface {
	GetDeployExit(ctx context.Context, serviceName, attemptID string) (*store.DeployExit, error)
	LatestDeployExit(ctx context.Context, serviceName string) (*store.DeployExit, error)
}

DeployExitStore reads the exits the application controller captured. *store.DB satisfies it.

type DeployGateStore ¶ added in v0.2.0

type DeployGateStore interface {
	ListGateEvents(ctx context.Context, attemptID string) ([]store.DeployGateEvent, error)
	GetDeploySafetySettings(ctx context.Context, serviceName string) (store.DeploySafetySettings, error)
	SaveDeploySafetySettings(ctx context.Context, s store.DeploySafetySettings) error
	ListRollbackPins(ctx context.Context, serviceName string) ([]store.RollbackPin, error)
	GetRollbackPin(ctx context.Context, serviceName, attemptID string) (*store.RollbackPin, error)
	RecordGateEvent(ctx context.Context, e store.DeployGateEvent) error
}

DeployGateStore is the store surface behind the readiness gate timeline, per-app gate settings and rollback pins. *store.DB satisfies it.

type DeployLogQuerier ¶

type DeployLogQuerier interface {
	QueryDeployLog(ctx context.Context, attemptID string) ([]telemetry.DeployLogEntry, error)
}

DeployLogQuerier replays a finished attempt's logs for handleDeployLogStream. Optional: nil returns 501 for finished attempts, the live tail is unaffected. *telemetry.DB satisfies it.

type DeployNotifier ¶

type DeployNotifier interface {
	Dispatch(ctx context.Context, resourceID string, ev alerting.DeployOutcome)
}

DeployNotifier is the narrow surface recordPlainDeployAttempt (deploys.go) and beginBuildDeployAttempt (deploy_attempts.go) need to fire a deploy-outcome notification once a deploy attempt reaches a terminal state. *alerting.DeployDispatcher satisfies this structurally. resourceID is resourceIDForApp(ev.AppName), computed by the caller (see alerting.DeployDispatcher.Dispatch's own doc comment for why it takes resourceID as a parameter rather than importing resourceIDForApp itself).

type DeployNotifyTargets ¶

type DeployNotifyTargets interface {
	SaveDeployTarget(ctx context.Context, t alerting.DeployTarget) error
	GetDeployTarget(ctx context.Context, id string) (*alerting.DeployTarget, error)
	ListDeployTargetsForResource(ctx context.Context, resourceID string) ([]alerting.DeployTarget, error)
	DeleteDeployTarget(ctx context.Context, id string) error
}

DeployNotifyTargets is the surface the deploy-notify-target handlers need from internal/alerting.DB. *alerting.DB satisfies this structurally, the same convention AlertRules already establishes.

type DeployQueueStore ¶ added in v0.2.0

type DeployQueueStore interface {
	ListQueuedDeployAttempts(ctx context.Context) ([]store.DeployAttempt, error)
	ListRunningDeployAttempts(ctx context.Context) ([]store.DeployAttempt, error)
	StartQueuedDeployAttempt(ctx context.Context, id string, now time.Time) (bool, error)
	FinishRunningDeployAttempt(ctx context.Context, id, status string, finishedAt time.Time, errMsg string) (bool, error)
	CancelDeployAttempt(ctx context.Context, id, from, by string, now time.Time) (bool, error)
	SupersedeQueuedDeployAttempt(ctx context.Context, id, by string, now time.Time) (bool, error)
	GetServiceCancelSuperseded(ctx context.Context, name string) (bool, error)
	SetServiceCancelSuperseded(ctx context.Context, name string, enabled bool) error
}

DeployQueueStore is the store surface for queued and canceled deploys. *store.DB satisfies this structurally.

type DeploySafetyStore ¶ added in v0.2.0

type DeploySafetyStore interface {
	deploy.OrderedStore
	deploy.Sequencer
	deploy.FreezeStore
	deploy.HeldStore
	ReplaceDeployFreezeWindows(ctx context.Context, scope string, windows []store.DeployFreezeWindow) ([]store.DeployFreezeWindow, error)
	SetDeployAttemptReason(ctx context.Context, id, reason string) error
	DeployQueueStore
}

DeploySafetyStore is the store surface for deploy ordering, freeze windows and digest history. *store.DB satisfies this structurally.

type DeployStore ¶

type DeployStore interface {
	GetConditions(ctx context.Context, controllerName string) ([]reconcile.Condition, error)
	// GetConditionsForControllers is handleListApps' batched status
	// source (apps.go): one query for every app's application
	// controller, not a GetConditions call per app.
	GetConditionsForControllers(ctx context.Context, controllerNames []string) (map[string][]reconcile.Condition, error)
}

DeployStore is the store surface the deploy-history handler needs.

type DevFixtureToken ¶

type DevFixtureToken struct {
	Name      string   `yaml:"name"`
	Plaintext string   `yaml:"plaintext"`
	Abilities []string `yaml:"abilities"`
}

DevFixtureToken is one entry in a test/fixtures/dev-fixtures.yml file: a fixed plaintext API token, minted with a known ability set, so local testing of the auth flow (does a read-only token get 403'd on a write route, does a write:sensitive token reach the secrets handler, and so on) doesn't require registering, logging in, and minting a real token by hand every time. Only ever seeded under dev mode, see devmode_debug.go/devmode_release.go's devModeEnabled gate.

type DevFixtures ¶

type DevFixtures struct {
	Tokens []DevFixtureToken `yaml:"tokens"`
}

DevFixtures is the top-level shape of test/fixtures/dev-fixtures.yml.

func ParseDevFixtures ¶

func ParseDevFixtures(data []byte) (*DevFixtures, error)

ParseDevFixtures validates as much as validateAbilities already validates a real token mint request: an empty or unrecognized ability list is rejected here too, so a typo in test/fixtures/dev-fixtures.yml fails loudly at startup instead of silently minting a token nobody can use as intended.

type DeviceLoginNotifier ¶ added in v0.2.0

type DeviceLoginNotifier interface {
	SendNotice(ctx context.Context, c alerting.NotificationChannel, text string) error
}

DeviceLoginNotifier sends one plain-text notice through a channel. *alerting.DeployDispatcher satisfies it.

type DockerDiskUsager ¶

type DockerDiskUsager interface {
	DiskUsage(ctx context.Context) (docker.DiskUsage, error)
}

DockerDiskUsager reports Docker's own storage accounting for GET /api/v1/system/status, distinct from the data dir totals. *docker.Client satisfies it via DiskUsage.

type DockerGuardController ¶ added in v0.2.0

type DockerGuardController interface {
	Status() dockerguard.Status
	SetMode(mode dockerguard.Mode, actor string, now time.Time) (dockerguard.Status, error)
}

DockerGuardController is the Docker API guard as the API sees it; *dockerguard.Controller satisfies it.

type DockerHubClient ¶ added in v0.2.0

type DockerHubClient interface {
	SearchRepositories(ctx context.Context, query string, pageSize int) ([]dockerhub.Repository, error)
	ListTags(ctx context.Context, namespace, repository string, pageSize int) ([]dockerhub.Tag, error)
}

DockerHubClient is the surface GET /api/v1/dockerhub/search and GET /api/v1/dockerhub/repositories/{namespace}/{repo}/tags need: query Docker Hub's public, unauthenticated Hub API for repository search and tag listing. *dockerhub.Client satisfies this structurally.

type DockerPinger ¶

type DockerPinger interface {
	Ping(ctx context.Context) error
}

DockerPinger is the liveness check behind GET /api/v1/system/status. Narrower than docker.Runtime on purpose, to avoid rippling into its fakes. *docker.Client satisfies it.

type DockerPruner ¶

type DockerPruner interface {
	Prune(ctx context.Context, keep []string) docker.PruneResult
}

DockerPruner backs POST /api/v1/system/prune (AbilityRoot). Split from DockerDiskUsager so a read and a destructive action stay independently swappable. *docker.Client satisfies it.

type DoctorIngressEdge ¶ added in v0.2.0

type DoctorIngressEdge struct {
	SocketActivation bool
	Hardening        bool
	TrustedProxies   int
	MaxBodyBytes     int64
	RetryWindow      time.Duration
	// Snapshot reports the ingress route snapshot; nil means the control plane has none.
	Snapshot func() ingressdriver.SnapshotStatus
}

DoctorIngressEdge is the ingress edge policy GET /api/v1/system/doctor reports.

type Document ¶

type Document struct {
	Statement []Statement `json:"Statement"`
}

Document is the whole parsed policy body stored as JSON in store.Policy.Document.

func ParseDocument ¶

func ParseDocument(raw string) (*Document, error)

ParseDocument unmarshals and validates a policy document. A document must have at least one statement, every statement must have an Effect of Allow or Deny, at least one Action (each either "*" or a known ability string from validAbilities), and at least one Resource (each either "*" or a non-empty resource identifier).

type DomainAuthGateStore ¶ added in v0.2.0

type DomainAuthGateStore interface {
	GetDomainAuthGate(ctx context.Context, domain string) (store.DomainAuthGate, bool, error)
	SetDomainAuthGate(ctx context.Context, g store.DomainAuthGate) error
	DeleteDomainAuthGate(ctx context.Context, domain string) error
	ListDomainAuthGates(ctx context.Context) ([]store.DomainAuthGate, error)
}

DomainAuthGateStore is the store surface .../domains/{domain}/auth-gate needs.

type DomainBasicAuthSecrets ¶

type DomainBasicAuthSecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	DeleteAll(ctx context.Context, serviceName string) error
}

DomainBasicAuthSecrets is the surface these handlers need from internal/secrets.Manager for a domain's basic-auth password: set it (PUT), check whether one exists (GET's has_password, and PUT's "already set" check for the omitted-password case), and clear it (DELETE). *secrets.Manager satisfies this structurally, the same narrow shape CloudflareTunnelSecrets already establishes.

type DomainBasicAuthStore ¶

type DomainBasicAuthStore interface {
	GetDomainBasicAuth(ctx context.Context, domain string) (store.DomainBasicAuth, bool, error)
	SetDomainBasicAuth(ctx context.Context, domain, username string) error
	DeleteDomainBasicAuth(ctx context.Context, domain string) error
	// ListDomainBasicAuth backs GET /api/v1/domains's has_basic_auth
	// flag: one bulk read instead of a per-domain GetDomainBasicAuth
	// call, avoiding an N+1 query over the domain list.
	ListDomainBasicAuth(ctx context.Context) ([]store.DomainBasicAuth, error)
}

DomainBasicAuthStore is the store surface GET/PUT/DELETE .../domains/{domain}/auth need: the username claimed for a domain, always set, same "core Store interface" shape as DomainStore above.

type DomainErrorPagesStore ¶ added in v0.2.0

type DomainErrorPagesStore interface {
	ListDomainErrorPages(ctx context.Context, domain string) ([]store.DomainErrorPage, error)
	SetDomainErrorPage(ctx context.Context, domain string, statusCode int, body string) error
	DeleteDomainErrorPage(ctx context.Context, domain string, statusCode int) error
	DeleteDomainErrorPages(ctx context.Context, domain string) error
}

DomainErrorPagesStore is the store surface GET/PUT/DELETE .../domains/{domain}/error-pages need: a domain's status-code-to-HTML mappings, always set, same "core Store interface" shape as DomainRedirectStore above; no secrets dependency either.

type DomainMaintenanceSettingsStore ¶

type DomainMaintenanceSettingsStore interface {
	GetDomainMaintenanceSettings(ctx context.Context, domain string, now time.Time) (store.DomainMaintenance, bool, error)
	SaveDomainMaintenance(ctx context.Context, m store.DomainMaintenance) error
}

DomainMaintenanceSettingsStore is optional on DomainMaintenanceStore: it carries the page copy, Retry-After, bypass rules and the end time link.

type DomainMaintenanceStore ¶

type DomainMaintenanceStore interface {
	GetDomainMaintenance(ctx context.Context, domain string) (bool, error)
	SetDomainMaintenance(ctx context.Context, domain string) error
	DeleteDomainMaintenance(ctx context.Context, domain string) error
	// ListDomainMaintenance backs GET /api/v1/domains's maintenance_enabled
	// flag in one bulk read.
	ListDomainMaintenance(ctx context.Context) ([]string, error)
}

DomainMaintenanceStore is the store surface GET/PUT/DELETE .../domains/{domain}/maintenance need.

type DomainRedirectStore ¶ added in v0.2.0

type DomainRedirectStore interface {
	GetDomainRedirect(ctx context.Context, domain string) (store.DomainRedirect, bool, error)
	SetDomainRedirect(ctx context.Context, domain, targetURL string, statusCode int) error
	DeleteDomainRedirect(ctx context.Context, domain string) error
	// ListDomainRedirects backs GET /api/v1/domains's has_redirect flag:
	// one bulk read instead of a per-domain GetDomainRedirect call,
	// avoiding an N+1 query over the domain list.
	ListDomainRedirects(ctx context.Context) ([]store.DomainRedirect, error)
}

DomainRedirectStore is the core store surface for domain redirects. It has no secrets dependency, since neither the target URL nor the status code is credential material.

type DomainSearchVisibilityStore ¶ added in v0.2.0

type DomainSearchVisibilityStore interface {
	IsDomainHidden(ctx context.Context, domain string) (bool, error)
	SetDomainHidden(ctx context.Context, domain string, hidden bool) error
}

DomainSearchVisibilityStore is the store surface for .../domains/{domain}/search-visibility.

type DomainStore ¶

type DomainStore interface {
	ListServiceDomains(ctx context.Context) ([]store.ServiceDomain, error)
}

DomainStore is the store surface GET /api/v1/domains needs: every domain currently claimed by a service, for the centralized cross-app domains list (web/src/routes/domains). Reuses internal/store's existing service_domains table (kept in sync by SaveDesiredService on every write, see that method's own doc comment); this is a plain read of already-tracked state, not a new tracking mechanism.

type DomainTLSCertSecrets ¶

type DomainTLSCertSecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	DeleteAll(ctx context.Context, serviceName string) error
}

DomainTLSCertSecrets is the surface these handlers need from internal/secrets.Manager for a domain's certificate and private key: set both (PUT) and clear both (DELETE). *secrets.Manager satisfies this structurally, the same narrow shape DomainBasicAuthSecrets already establishes.

type DomainTLSCertStore ¶

type DomainTLSCertStore interface {
	GetDomainTLSCert(ctx context.Context, domain string) (store.DomainTLSCert, bool, error)
	SetDomainTLSCert(ctx context.Context, domain string, uploadedAt, expiresAt time.Time) error
	DeleteDomainTLSCert(ctx context.Context, domain string) error
	// ListDomainTLSCerts backs handleListCertificates' Source field (api/
	// certificates.go): every domain with a custom cert on file, so the
	// certificate center page can tell "custom" apart from "acme" per row.
	ListDomainTLSCerts(ctx context.Context) ([]store.DomainTLSCert, error)
}

DomainTLSCertStore is the store surface GET/PUT/DELETE .../domains/{domain}/tls-cert need: the upload/expiry metadata for a domain's BYO certificate, same "core Store interface" shape as DomainBasicAuthStore.

type DomainTrafficPolicyStore ¶ added in v0.2.0

type DomainTrafficPolicyStore interface {
	GetDomainTrafficPolicy(ctx context.Context, domain, kind string) (store.DomainTrafficPolicy, bool, error)
	ListDomainTrafficPoliciesFor(ctx context.Context, domain string) ([]store.DomainTrafficPolicy, error)
	SetDomainTrafficPolicy(ctx context.Context, domain, kind string, spec []byte) error
	DeleteDomainTrafficPolicy(ctx context.Context, domain, kind string) error
}

DomainTrafficPolicyStore is the store surface for the per-domain traffic controls (headers, forwarders, geo, cache, redirects, shield).

type DomainWAFStore ¶ added in v0.2.0

type DomainWAFStore interface {
	GetDomainWAF(ctx context.Context, domain string) (store.DomainWAF, bool, error)
	SetDomainWAF(ctx context.Context, domain string, wafEnabled bool, mode string, rateLimitRPS, rateLimitBurst int) error
	DeleteDomainWAF(ctx context.Context, domain string) error
	// ListDomainWAF backs GET /api/v1/domains's waf_enabled flag: one
	// bulk read instead of a per-domain GetDomainWAF call, avoiding an
	// N+1 query over the domain list.
	ListDomainWAF(ctx context.Context) ([]store.DomainWAF, error)
}

DomainWAFStore is the store surface GET/PUT/DELETE .../domains/{domain}/waf need: opt-in WAF and rate-limit settings for a domain, always set, same "core Store interface" shape as DomainMaintenanceStore above; like that store, there is no secrets dependency at all, since neither setting involves credential material.

type EdgeAccess ¶

type EdgeAccess struct {
	Stats *ingress.RequestStats
	Log   *ingress.AccessLog
}

EdgeAccess adapts the process-wide stats and access log to AccessSource.

func (EdgeAccess) AppAccess ¶

func (e EdgeAccess) AppAccess(app string, f ingress.AccessFilter) []ingress.AccessRecord

AppAccess implements AccessSource.

func (EdgeAccess) AppAccessSince ¶

func (e EdgeAccess) AppAccessSince(app string, since time.Time) []ingress.AccessRecord

AppAccessSince implements AccessReplaySource.

type EdgeFirewallStore ¶

type EdgeFirewallStore interface {
	ListEdgeFirewallRules(ctx context.Context) ([]store.EdgeFirewallRule, error)
	GetEdgeFirewallRule(ctx context.Context, id string) (store.EdgeFirewallRule, error)
	CountEdgeFirewallRules(ctx context.Context) (int, error)
	CreateEdgeFirewallRule(ctx context.Context, r store.EdgeFirewallRule) (store.EdgeFirewallRule, error)
	UpdateEdgeFirewallRule(ctx context.Context, r store.EdgeFirewallRule) error
	DeleteEdgeFirewallRule(ctx context.Context, id string) error
	ReorderEdgeFirewallRules(ctx context.Context, ids []string) error
	GetEdgeFirewallSettings(ctx context.Context) (string, error)
	SetEdgeFirewallSettings(ctx context.Context, settings string) error
}

EdgeFirewallStore is the store surface for the ingress firewall rules and settings.

type Effect ¶

type Effect string

Effect is a statement's outcome when it matches: Allow or Deny, exactly AWS IAM's own two-value vocabulary.

const (
	EffectAllow Effect = "Allow"
	EffectDeny  Effect = "Deny"
)

EffectAllow and EffectDeny are the only two valid Statement.Effect values.

type EmailDeliveryStore ¶

type EmailDeliveryStore interface {
	ListEmailDeliveries(ctx context.Context, f store.EmailDeliveryFilter) ([]store.EmailDelivery, error)
	GetEmailDelivery(ctx context.Context, id string) (store.EmailDelivery, error)
	EmailDeliveryStats(ctx context.Context, since time.Time) (store.EmailDeliveryStats, error)
}

EmailDeliveryStore is the delivery log surface the email handlers read; *store.DB satisfies it.

type EmailProviderStore ¶

type EmailProviderStore interface {
	ListEmailProviders(ctx context.Context) ([]store.EmailProvider, error)
	GetEmailProvider(ctx context.Context, id string) (store.EmailProvider, error)
	UpsertEmailProvider(ctx context.Context, p store.EmailProvider) error
	DeleteEmailProvider(ctx context.Context, id string) error
	PromoteEmailProvider(ctx context.Context, id string) error
}

EmailProviderStore is the provider surface the email provider handlers need; *store.DB satisfies it.

type EmailSecretsStore ¶

type EmailSecretsStore interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	// Resolve, DeleteValue and DeleteAll serve provider promote and delete; Resolve's result never reaches a response.
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
	DeleteValue(ctx context.Context, serviceName, envKey string) error
	DeleteAll(ctx context.Context, serviceName string) error
}

EmailSecretsStore is the surface the email settings handlers need from internal/secrets.Manager. *secrets.Manager satisfies this structurally.

type EmailSettingsStore ¶

type EmailSettingsStore interface {
	GetEmailSettings(ctx context.Context) (store.EmailSettings, error)
	UpdateEmailSettings(ctx context.Context, s store.EmailSettings) error
	GetEmailBranding(ctx context.Context) (store.EmailBranding, error)
	SetEmailBranding(ctx context.Context, b store.EmailBranding) error
}

EmailSettingsStore is the store surface GET/PUT /api/v1/settings/email need: the single platform-wide row, always present, the same shape IngressSettingsStore has for its own row.

type EncryptionKeyRotator ¶

type EncryptionKeyRotator interface {
	RotateOne(ctx context.Context, serviceName string) (secrets.DEKRotateResult, error)
	RotateAll(ctx context.Context, actor string) (secrets.DEKRotateAllResult, error)
	Status(ctx context.Context) (secrets.DEKStatus, error)
}

EncryptionKeyRotator is the per-app data key surface of internal/secrets.DEKRotator.

type EndpointService ¶

type EndpointService interface {
	TestEndpointInput(ctx context.Context, in models.ProbeInput) (models.EndpointProbe, error)
	TestEndpoint(ctx context.Context, name string) (models.EndpointProbe, error)
	SetEndpointRouting(ctx context.Context, name, fallback, fallbackRef string, budget time.Duration) error
	SetEndpointCredential(ctx context.Context, name, credential string) (models.EndpointProbe, error)
}

EndpointService is the external endpoint surface of the model service. A ModelService that also implements it enables the endpoint routes.

type EnvironmentStore ¶

type EnvironmentStore interface {
	SaveEnvironment(ctx context.Context, e store.Environment) error
	GetEnvironment(ctx context.Context, id string) (store.Environment, error)
	GetEnvironmentsByIDs(ctx context.Context, ids []string) (map[string]store.Environment, error)
	ListEnvironmentsByProject(ctx context.Context, projectID string) ([]store.Environment, error)
	DeleteEnvironment(ctx context.Context, id string) error
	SetEnvironmentProtected(ctx context.Context, id string, protected bool) error
	UpdateEnvironment(ctx context.Context, id string, patch store.EnvironmentPatch) error
	ListAllEnvironments(ctx context.Context) ([]store.EnvironmentWithCounts, error)
	EnvironmentMemberCounts(ctx context.Context, envID string) (apps, databases int, err error)
	MoveEnvironmentMembers(ctx context.Context, fromID, toID string) error
	EnvironmentOfDatabase(ctx context.Context, databaseName string) (*store.EnvironmentRef, error)
	SetServiceEnvironment(ctx context.Context, serviceName, envID string) error
	// SetEnvironmentEnvVars/ListEnvironmentEnvVars back GET/PUT
	// /api/v1/environments/{id}/env (environment_env.go): shared env vars
	// every service tagged with this environment inherits, sitting
	// between ProjectStore's own project_env_vars tier and a service's
	// own env (internal/reconcile/application's resolveEnv), full-replace
	// on write, mirroring SetOrganizationEnvVars/ListOrganizationEnvVars.
	SetEnvironmentEnvVars(ctx context.Context, environmentID string, vars map[string]string) error
	ListEnvironmentEnvVars(ctx context.Context, environmentID string) (map[string]string, error)
	// ListEnvironmentEnvVarsDetailed/SetEnvironmentSecretEnvVar/
	// DeleteEnvironmentSecretEnvVar/ListEnvironmentSecretEnvKeys back GET
	// /api/v1/environments/{id}/env/all and the secret-var sub-resource
	// routes (environment_env.go), mirroring ProjectStore/
	// OrganizationStore's own secret-capable extension.
	ListEnvironmentEnvVarsDetailed(ctx context.Context, environmentID string) ([]store.SharedEnvVar, error)
	SetEnvironmentSecretEnvVar(ctx context.Context, environmentID, key string) error
	DeleteEnvironmentSecretEnvVar(ctx context.Context, environmentID, key string) error
	ListEnvironmentSecretEnvKeys(ctx context.Context, environmentID string) ([]string, error)
}

EnvironmentStore is the store surface the environments handlers need.

type ErrorStore ¶

type ErrorStore interface {
	WriteErrorEvent(ctx context.Context, ev telemetry.ErrorEvent, keep int) (bool, error)
	ListErrorIssues(ctx context.Context, f telemetry.ErrorFilter) ([]telemetry.ErrorIssue, error)
	GetErrorIssue(ctx context.Context, resourceID, fingerprint string) (telemetry.ErrorIssue, []telemetry.ErrorSample, error)
	SetErrorIssueStatus(ctx context.Context, resourceID, fingerprint, status string) error
}

ErrorStore is the issue storage the error tracking routes need.

type EscrowMaterialReader ¶ added in v0.2.0

type EscrowMaterialReader func() (cpbackup.EscrowMaterial, error)

EscrowMaterialReader returns the master key and the other recovery files an escrow bundle protects. It is called only to build a bundle and its result is never logged.

type EventWebhookService ¶

type EventWebhookService interface {
	Emit(e eventhook.Event)
	List(ctx context.Context) ([]store.EventWebhook, error)
	Get(ctx context.Context, id string) (store.EventWebhook, error)
	Create(ctx context.Context, in eventhook.Input) (store.EventWebhook, string, error)
	Update(ctx context.Context, id string, p eventhook.Patch) (store.EventWebhook, error)
	Delete(ctx context.Context, id string) error
	RotateSecret(ctx context.Context, id string) (string, error)
	Test(ctx context.Context, id string) (int, error)
	Replay(ctx context.Context, deliveryID string) (store.EventWebhookDelivery, error)
	Deliveries(ctx context.Context, webhookID string, limit int) ([]store.EventWebhookDelivery, error)
	Summary(ctx context.Context, id string) (eventhook.Counts, error)
}

EventWebhookService is the surface the event webhook routes need from internal/eventhook; *eventhook.Service satisfies it.

type ExposureStore ¶ added in v0.2.0

type ExposureStore interface {
	SaveExposureRestriction(ctx context.Context, r store.ExposureRestriction) error
	ListExposureRestrictions(ctx context.Context) ([]store.ExposureRestriction, error)
	DeleteExposureRestriction(ctx context.Context, port int, protocol string) error
}

ExposureStore is the store surface the exposure handlers need.

type ExternalDatabaseStore ¶ added in v0.2.0

type ExternalDatabaseStore interface {
	CreateExternalDatabase(ctx context.Context, d store.ExternalDatabase) error
	UpdateExternalDatabase(ctx context.Context, d store.ExternalDatabase) error
	GetExternalDatabase(ctx context.Context, name string) (*store.ExternalDatabase, error)
	ListExternalDatabases(ctx context.Context) ([]store.ExternalDatabase, error)
	DeleteExternalDatabase(ctx context.Context, name string) error
	SetExternalDatabaseHealth(ctx context.Context, name, status, reason string, latencyMs int, checkedAt time.Time) error
}

ExternalDatabaseStore is the store surface for databases this platform connects to but does not run.

type FeatureFlagStore ¶

type FeatureFlagStore interface {
	SaveFeatureFlag(ctx context.Context, f store.FeatureFlag) error
	GetFeatureFlag(ctx context.Context, id string) (store.FeatureFlag, error)
	GetFeatureFlagByKey(ctx context.Context, key string) (store.FeatureFlag, error)
	ListFeatureFlagsForService(ctx context.Context, serviceName string) ([]store.FeatureFlag, error)
	UpdateFeatureFlag(ctx context.Context, id, name, description string, enabled bool, rolloutPercentage int, updatedAt time.Time) error
	DeleteFeatureFlag(ctx context.Context, id string) error
}

FeatureFlagStore is the store surface the feature flag handlers need, mirroring ScheduledTaskStore's own shape for a different child resource.

type FirewallRuleStore ¶ added in v0.2.0

type FirewallRuleStore interface {
	SaveFirewallRule(ctx context.Context, r store.FirewallRule) error
	ListFirewallRules(ctx context.Context) ([]store.FirewallRule, error)
	DeleteFirewallRule(ctx context.Context, id string) error
}

FirewallRuleStore is the store surface the firewall rule handlers need.

type FixitStore ¶

type FixitStore interface {
	RecentFixitAttempts(ctx context.Context, fixID, subject string, limit int) ([]store.FixitAttempt, error)
	CountFixitAttemptsSince(ctx context.Context, fixID string, since time.Time) (int, error)
	RecordFixitAttempt(ctx context.Context, a store.FixitAttempt) error
	GetFixitSetting(ctx context.Context, key string) (string, bool, error)
	SetFixitSetting(ctx context.Context, key, value, actor string, now time.Time) error
}

FixitStore is the persistence the fix engine needs; *store.DB satisfies it.

type FleetMaintenanceStore ¶

type FleetMaintenanceStore interface {
	ListActiveDomainMaintenance(ctx context.Context, now time.Time) ([]store.DomainMaintenance, error)
	ListServiceDomains(ctx context.Context) ([]store.ServiceDomain, error)
}

FleetMaintenanceStore lists every domain in maintenance with its owner.

type ForgeDeploymentStore ¶ added in v0.2.0

type ForgeDeploymentStore interface {
	CreateForgeDeployment(ctx context.Context, d store.ForgeDeployment) error
	SetForgeDeploymentState(ctx context.Context, id, state, warning string, at time.Time) error
	ListForgeDeploymentsByState(ctx context.Context, app, environment, state, excludeID string) ([]store.ForgeDeployment, error)
}

ForgeDeploymentStore persists the deployments created on a git forge. *store.DB satisfies it.

type FormsStore ¶

type FormsStore interface {
	forms.Store
	CreateForm(ctx context.Context, f store.Form) error
	UpdateForm(ctx context.Context, f store.Form) error
	GetForm(ctx context.Context, app, name string) (store.Form, error)
	ListForms(ctx context.Context, app string) ([]store.Form, map[string]store.FormCounts, error)
	DeleteForm(ctx context.Context, id string) error
	ListFormSubmissions(ctx context.Context, formID string, q store.FormSubmissionQuery) ([]store.FormSubmission, error)
	SetFormSubmissionSpam(ctx context.Context, formID string, id int64, spam bool, reason string) error
	DeleteFormSubmission(ctx context.Context, formID string, id int64) error
}

FormsStore is the persistence surface for form capture; nil on the router means the routes answer 501.

type FunctionInvocation ¶

type FunctionInvocation struct {
	ID         string    `json:"id"`
	Time       time.Time `json:"time"`
	Method     string    `json:"method"`
	Path       string    `json:"path"`
	Status     int       `json:"status"`
	DurationMs float64   `json:"duration_ms"`
	ColdStart  bool      `json:"cold_start"`
	BytesIn    int64     `json:"bytes_in"`
	BytesOut   int64     `json:"bytes_out"`
	TraceID    string    `json:"trace_id,omitempty"`
	Replayable bool      `json:"replayable"`
	LogsFrom   time.Time `json:"logs_from"`
	LogsTo     time.Time `json:"logs_to"`
}

FunctionInvocation is one recorded call at the edge.

type FunctionInvokeRequest ¶

type FunctionInvokeRequest struct {
	Method  string            `json:"method"`
	Path    string            `json:"path"`
	Headers map[string]string `json:"headers,omitempty"`
	Body    string            `json:"body,omitempty"`
}

FunctionInvokeRequest is one test call to a function through its public route.

type FunctionInvokeResult ¶

type FunctionInvokeResult struct {
	RequestID     string              `json:"request_id"`
	Status        int                 `json:"status"`
	Headers       map[string][]string `json:"headers"`
	Body          string              `json:"body"`
	BodyTruncated bool                `json:"body_truncated,omitempty"`
	DurationMs    float64             `json:"duration_ms"`
	ColdStart     bool                `json:"cold_start"`
	Stored        bool                `json:"input_stored"`
}

FunctionInvokeResult is what the function answered, plus how the call went.

type FunctionRoute ¶

type FunctionRoute struct {
	Domain      string `json:"domain"`
	Path        string `json:"path"`
	StripPrefix bool   `json:"strip_prefix"`
}

FunctionRoute is one path a function answers on, stored as a forwarder rule on the domain.

type FunctionTriggerStore ¶

type FunctionTriggerStore interface {
	SetFunctionWebhook(ctx context.Context, fn, path string, rotated bool, now time.Time) error
	GetFunctionWebhook(ctx context.Context, fn string) (store.FunctionWebhook, error)
	DeleteFunctionWebhook(ctx context.Context, fn string) error
	EnqueueFunctionInvocation(ctx context.Context, inv store.FunctionInvocation, maxQueued int) error
	GetFunctionInvocation(ctx context.Context, id string) (store.FunctionInvocation, error)
	ListFunctionInvocations(ctx context.Context, fn, status string, limit int) ([]store.FunctionInvocation, error)
	CountFunctionInvocations(ctx context.Context, fn string) (map[string]int, error)
	RetryFunctionInvocation(ctx context.Context, id string, now time.Time) error
	DeleteFunctionInvocation(ctx context.Context, id string) error
}

FunctionTriggerStore persists webhook triggers and the async invocation queue.

type GPUHostDiagnoser ¶ added in v0.2.0

type GPUHostDiagnoser func(ctx context.Context) gpu.HostDiagnosis

GPUHostDiagnoser inspects the control plane host's GPU stack in detail: driver, toolkit, CDI specs and how containers can attach GPUs.

type GateSettings ¶ added in v0.2.0

type GateSettings struct {
	SessionTTL     time.Duration
	TokenTTL       time.Duration
	EventRetention time.Duration
	// AllowHTTP lets gated apps served over plain http sign in; the session
	// cookie then cannot be Secure.
	AllowHTTP bool
}

GateSettings tunes the built-in auth gate provider.

func DefaultGateSettings ¶ added in v0.2.0

func DefaultGateSettings() GateSettings

DefaultGateSettings returns the settings used when no env var is set.

func GateSettingsFromEnv ¶ added in v0.2.0

func GateSettingsFromEnv(getenv func(string) string) (GateSettings, error)

GateSettingsFromEnv reads the APP_GATE_* env vars. On a bad value it keeps that setting's default and reports the first error.

type GateStore ¶ added in v0.2.0

type GateStore interface {
	GetDomainAuthGate(ctx context.Context, domain string) (store.DomainAuthGate, bool, error)
	ListGateRules(ctx context.Context, domain string) ([]store.GateRule, error)
	ReplaceGateRules(ctx context.Context, domain string, rules []store.GateRule) error
	CreateGateToken(ctx context.Context, t store.GateToken) error
	ConsumeGateToken(ctx context.Context, tokenHash string) (store.GateToken, bool, error)
	CreateGateSession(ctx context.Context, s store.GateSession) error
	GetGateSession(ctx context.Context, tokenHash string) (store.GateSession, bool, error)
	RevokeGateSessions(ctx context.Context, domain string) (int64, error)
	CountLiveGateSessions(ctx context.Context, domain string) (int, error)
	DashboardSessionLive(ctx context.Context, sessionID string) (bool, error)
	DomainEnvironmentID(ctx context.Context, domain string) (string, error)
	RecordAuthGateEvent(ctx context.Context, e store.GateEvent) error
	ListAuthGateEvents(ctx context.Context, domain string, since time.Time, limit int) ([]store.GateEvent, error)
	PruneGateData(ctx context.Context, cutoff time.Time) (int64, error)
	GetUserByID(ctx context.Context, id string) (*store.User, error)
	GetUserByEmail(ctx context.Context, email string) (*store.User, error)
	UserTeamRoles(ctx context.Context, userID string) (map[string]string, error)
	UserRoleID(ctx context.Context, userID string) (string, error)
	UserVisibility(ctx context.Context, userID string) (store.Visibility, error)
	GetOrganization(ctx context.Context, id string) (store.Organization, error)
	ListOrganizations(ctx context.Context) ([]store.Organization, error)
	GetRole(ctx context.Context, id string) (store.Role, error)
	ListRoles(ctx context.Context) ([]store.Role, error)
}

GateStore is the store surface the built-in auth gate provider needs.

type GitConnSecrets ¶

type GitConnSecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	DeleteAll(ctx context.Context, serviceName string) error
}

GitConnSecrets is the internal/secrets.Manager surface the git provider connection handlers need: the OAuth application's client secret and each connection's tokens, under the connection's own secrets key.

type GitConnectionsStore ¶

type GitConnectionsStore interface {
	CreateGitConnection(ctx context.Context, c store.GitConnection) error
	GetGitConnection(ctx context.Context, id string) (store.GitConnection, error)
	ListGitConnections(ctx context.Context, provider string) ([]store.GitConnection, error)
	FindGitConnectionByAccount(ctx context.Context, provider, host, accountID, clientID, excludeID string) (store.GitConnection, bool, error)
	RenameGitConnection(ctx context.Context, id, label string) error
	SetGitConnectionAccount(ctx context.Context, id, accountID, accountName, scopes string) error
	SetGitConnectionOAuthApp(ctx context.Context, id, instanceURL, clientID string) error
	SetDefaultGitConnection(ctx context.Context, id string) error
	DeleteGitConnection(ctx context.Context, id string) error
	SetGitSourceConnection(ctx context.Context, serviceName, connectionID string) error
	ListGitSourcesByConnection(ctx context.Context, connectionID string) ([]string, error)
	RelinkOrphanedGitSources(ctx context.Context, host, connectionID string) (int, error)
}

GitConnectionsStore is the store surface for provider connections. *store.DB satisfies it.

type GitHubAppClient ¶

type GitHubAppClient interface {
	CheckInstanceReachable(ctx context.Context, instanceURL string) error
	ExchangeManifestCode(ctx context.Context, instanceURL, code string) (githubapp.Credentials, error)
	GetInstallation(ctx context.Context, instanceURL, appJWT string, installationID int64) (githubapp.InstallationInfo, error)
	MintInstallationToken(ctx context.Context, instanceURL, appJWT string, installationID int64) (githubapp.InstallationToken, error)
	ListInstallationRepos(ctx context.Context, instanceURL, token string, opts githubapp.ListOptions) ([]githubapp.Repo, githubapp.ListResult, error)
	GetRepo(ctx context.Context, instanceURL, token, owner, repo string) (githubapp.Repo, error)
	ListBranches(ctx context.Context, instanceURL, token, owner, repo string) ([]githubapp.Branch, error)
	CreateRepoWebhook(ctx context.Context, instanceURL, token, owner, repo, hookURL, secret string) error
	CreateIssueComment(ctx context.Context, instanceURL, token, owner, repo string, number int, body string) (int64, error)
	ListIssueComments(ctx context.Context, instanceURL, token, owner, repo string, number int) ([]gitprovider.Comment, error)
	UpdateIssueComment(ctx context.Context, instanceURL, token, owner, repo string, commentID int64, body string) error
	CreateCommitStatus(ctx context.Context, instanceURL, token, owner, repo, sha string, state githubapp.CommitStatusState, targetURL, description, statusContext string) error
}

GitHubAppClient is the surface internal/api needs from internal/githubapp.Client: manifest code exchange, installation lookup and token minting, repo/branch listing, repo webhook registration, and posting a preview deploy's own PR comment/commit status (preview_environments_github.go). *githubapp.Client satisfies this structurally; tests substitute a hand-written fake (github_app_test.go), the same "narrow, consumer-defined interface" shape every other external-system boundary in this package uses (Builder, DockerPinger, BackupRunner).

type GitHubAppSecrets ¶

type GitHubAppSecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
	DeleteAll(ctx context.Context, serviceName string) error
}

GitHubAppSecrets is the surface the GitHub App handlers need from internal/secrets.Manager: both SetValue (storing client_secret/ webhook_secret/private_key right after a successful code exchange) and Resolve (decrypting the private key back out, in memory only, immediately before signing a JWT). A different shape from BackupSecretsSetter (set-only) and internal/backup.SecretsResolver (resolve-only): this is the one credential-bearing feature in this codebase that both writes and reads back through internal/secrets from inside internal/api itself, because minting a fresh installation token on every repo/branch-listing call (see github_app_repos.go) needs the private key synchronously in the same request, not on a separate worker path the way internal/backup.Runner's own Resolve calls are. *secrets.Manager satisfies this structurally.

type GitHubAppStore ¶

type GitHubAppStore interface {
	GetGitHubAppConnection(ctx context.Context) (store.GitHubAppConnection, error)
	SaveGitHubAppConnection(ctx context.Context, c store.GitHubAppConnection) error
	UpdateGitHubAppInstallation(ctx context.Context, installationID int64, accountLogin string) error
	DeleteGitHubAppConnection(ctx context.Context) error
	UpsertGitHubAppInstallation(ctx context.Context, installationID int64, accountLogin, accountType string) error
	ListGitHubAppInstallations(ctx context.Context) ([]store.GitHubAppInstallation, error)
	DeleteGitHubAppInstallation(ctx context.Context, id int64) error
}

GitHubAppStore is the store surface the GitHub App connection handlers need. *store.DB satisfies this structurally, part of the core Store interface (github_app_connections always exists as a table even when empty, the same "core store, not an optional plug-in" shape ingressSettings/domains already establish).

type GitLabAppClient ¶

type GitLabAppClient interface {
	ExchangeCode(ctx context.Context, instanceURL, clientID, clientSecret, redirectURI, code string) (gitlabapp.Tokens, error)
	RefreshToken(ctx context.Context, instanceURL, clientID, clientSecret, refreshToken string) (gitlabapp.Tokens, error)
	RevokeToken(ctx context.Context, instanceURL, clientID, clientSecret, token string) error
	CurrentUser(ctx context.Context, instanceURL, accessToken string) (gitlabapp.Account, error)
	ListProjects(ctx context.Context, instanceURL, accessToken string, opts gitprovider.ListOptions) ([]gitlabapp.Project, gitprovider.ListResult, error)
	GetProject(ctx context.Context, instanceURL, accessToken string, projectID int64) (gitlabapp.Project, error)
	ListBranches(ctx context.Context, instanceURL, accessToken string, projectID int64) ([]gitlabapp.Branch, error)
	CreateProjectWebhook(ctx context.Context, instanceURL, accessToken string, projectID int64, hookURL, secretToken string) error
	CreateMergeRequestNote(ctx context.Context, instanceURL, accessToken, projectPath string, mrIID int, body string) (int64, error)
	ListMergeRequestNotes(ctx context.Context, instanceURL, accessToken, projectPath string, mrIID int) ([]gitprovider.Comment, error)
	UpdateMergeRequestNote(ctx context.Context, instanceURL, accessToken, projectPath string, mrIID int, noteID int64, body string) error
	CreateCommitStatus(ctx context.Context, instanceURL, accessToken, projectPath, sha string, state gitlabapp.CommitState, targetURL, description, name string) error
}

GitLabAppClient is the surface internal/api needs from internal/gitlabapp.Client.

type GitPushStore ¶

type GitPushStore interface {
	GetGitPushRemote(ctx context.Context, name string) (*store.GitPushRemote, error)
	SaveGitPushRemoteToken(ctx context.Context, name, tokenHash, defaultBranch string, now time.Time) error
	SetGitPushRemoteBranch(ctx context.Context, name, branch string) error
	RecordGitPush(ctx context.Context, name, commit, result string, at time.Time) error
	DeleteGitPushRemote(ctx context.Context, name string) error
}

GitPushStore is the persistence the git push remote needs.

type GitSourceSecrets ¶

type GitSourceSecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
}

GitSourceSecrets is the surface a git source's connect flow and the git-push webhook route (git_webhook.go) both need from internal/secrets.Manager: unlike SecretSetter and BackupSecretsSetter (write-only, a secret's value never resolved back through internal/api at all), this package genuinely does call Resolve, but only for its own server-side use, HMAC-verifying an incoming webhook and authenticating a git clone, never to populate an HTTP response body. See handleSetGitSource's and handleGitPushWebhook's own doc comments for that boundary; *secrets.Manager satisfies this structurally.

type GitSourceStore ¶

type GitSourceStore interface {
	SaveGitSource(ctx context.Context, g store.GitSource) error
	GetGitSource(ctx context.Context, serviceName string) (*store.GitSource, error)
	DeleteGitSource(ctx context.Context, serviceName string) error
	// ListGitSources backs GET /api/v1/apps/git-sources: every connected
	// source's service name, repo URL and branch, filtered to the
	// caller's visible apps by handleListGitSources itself (callerAppVisibility),
	// the same shape handleListApps already uses for its own bulk list.
	ListGitSources(ctx context.Context) ([]store.GitSourceSummary, error)
	// SetGitSourcePreviewEnabled backs PUT
	// /api/v1/apps/{name}/preview-settings (preview_environments_handlers.go):
	// the opt-in toggle for preview environments per pull request.
	SetGitSourcePreviewEnabled(ctx context.Context, serviceName string, enabled bool) error
	// SetGitSourcePostPRComments backs the same PUT
	// /api/v1/apps/{name}/preview-settings route: the opt-in toggle for
	// posting a GitHub PR comment/commit status about a preview deploy.
	SetGitSourcePostPRComments(ctx context.Context, serviceName string, enabled bool) error
	// SetGitSourceDeploySettings backs PUT
	// /api/v1/apps/{name}/git-source/deploy-settings: push path filters
	// and forge status reporting.
	SetGitSourceDeploySettings(ctx context.Context, serviceName string, paths, pathsIgnore []string, reportStatus bool) error
	// SetGitSourceBuild backs PUT /api/v1/apps/{name}/git-source/build.
	SetGitSourceBuild(ctx context.Context, serviceName, buildType, buildPath, baseDirectory, buildCommand, publishDir string) error
}

GitSourceStore is the store surface the git source handlers need. *store.DB satisfies this structurally.

type GiteaAppClient ¶ added in v0.2.0

type GiteaAppClient interface {
	ExchangeCode(ctx context.Context, instanceURL, clientID, clientSecret, redirectURI, code string) (giteaapp.Tokens, error)
	RefreshToken(ctx context.Context, instanceURL, clientID, clientSecret, refreshToken string) (giteaapp.Tokens, error)
	CurrentUser(ctx context.Context, instanceURL, accessToken string) (giteaapp.Account, error)
	ListRepos(ctx context.Context, instanceURL, accessToken string, opts gitprovider.ListOptions) ([]giteaapp.Repo, gitprovider.ListResult, error)
	GetRepo(ctx context.Context, instanceURL, accessToken, fullName string) (giteaapp.Repo, error)
	ListBranches(ctx context.Context, instanceURL, accessToken, fullName string) ([]giteaapp.Branch, error)
	CreateRepoWebhook(ctx context.Context, instanceURL, accessToken, fullName, hookURL, secret string) error
	CreateIssueComment(ctx context.Context, instanceURL, accessToken, fullName string, number int, body string) (int64, error)
	ListIssueComments(ctx context.Context, instanceURL, accessToken, fullName string, number int) ([]gitprovider.Comment, error)
	UpdateIssueComment(ctx context.Context, instanceURL, accessToken, fullName string, commentID int64, body string) error
	CreateCommitStatus(ctx context.Context, instanceURL, accessToken, fullName, sha string, state giteaapp.CommitStatusState, targetURL, description, statusContext string) error
}

GiteaAppClient is the surface internal/api needs from internal/giteaapp.Client.

type GoogleCloudDNSSecrets ¶

type GoogleCloudDNSSecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	DeleteAll(ctx context.Context, serviceName string) error
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
}

GoogleCloudDNSSecrets is the surface the Cloud DNS handlers need from internal/secrets.Manager. Resolve reads the key back for record paths only.

type GoogleCloudDNSStore ¶

type GoogleCloudDNSStore interface {
	GetGoogleCloudDNSSettings(ctx context.Context) (store.GoogleCloudDNSSettings, error)
	UpdateGoogleCloudDNSSettings(ctx context.Context, s store.GoogleCloudDNSSettings) error
}

GoogleCloudDNSStore is the store surface GET/PUT/DELETE /api/v1/settings/google-cloud-dns need.

type GuardProbe ¶

type GuardProbe interface {
	Status() reconcile.GuardStatus
	Reset(name string) int
}

GuardProbe is the reconcile storm protection the health page reads and resets.

type HookRunStore ¶

type HookRunStore interface {
	GetHookRuns(ctx context.Context, serviceName string) ([]store.HookRun, error)
}

HookRunStore is the store surface GET /api/v1/apps/{name}/hook-runs (apps_hooks.go) needs: the most recent outcome of each of a service's pre/post-deploy hooks (internal/reconcile/application's own HookRunRecorder, migrations/0083_service_hook_runs.sql). Always set, the same "core Store interface, not an optional plug-in" shape domainMaintenance above establishes.

type HumanVerifier ¶

type HumanVerifier interface {
	Verify(ctx context.Context, token, remoteIP string) error
}

HumanVerifier is the pluggable human check in front of the passwordless demo session. Verify returns nil when the visitor passed.

type IdempotencyStore ¶

type IdempotencyStore interface {
	GetIdempotencyRecord(ctx context.Context, principal, key string) (store.IdempotencyRecord, bool, error)
	PutIdempotencyRecord(ctx context.Context, rec store.IdempotencyRecord) error
	PruneIdempotencyRecords(ctx context.Context, cutoff time.Time) (int64, error)
}

IdempotencyStore caches responses of retried mutating calls.

type ImageAutoUpdateStore ¶ added in v0.2.0

type ImageAutoUpdateStore interface {
	SetImageAutoUpdate(ctx context.Context, serviceName string, enabled bool) error
	GetImageAutoUpdate(ctx context.Context, serviceName string) (store.ImageAutoUpdate, error)
	RecordImageAutoUpdateCheck(ctx context.Context, serviceName, result string, at time.Time) error
	SetImageAutoUpdateWebhookHash(ctx context.Context, serviceName, hash string) error
}

ImageAutoUpdateStore is the store surface for per-app image auto-update.

type ImageInventoryResolver ¶

type ImageInventoryResolver func(nodeID string) (docker.ImageInventory, error)

ImageInventoryResolver returns the image inventory of one node ("" is the control plane's own node).

type ImageLister ¶

type ImageLister interface {
	ListImages(ctx context.Context, repo string) ([]docker.ImageInfo, error)
}

ImageLister discovers previously built tags under a repo for the deploy form. It mirrors docker.Runtime.ListImages. *docker.Client satisfies it.

type InboxStore ¶

type InboxStore interface {
	ListInbox(ctx context.Context, principal string, f alerting.InboxFilter) ([]alerting.InboxItem, error)
	InboxUnreadCount(ctx context.Context, principal string) (int, error)
	MarkInboxRead(ctx context.Context, principal string, ids []string) error
	MarkAllInboxRead(ctx context.Context, principal string, now time.Time) error
	GetInboxState(ctx context.Context, principal string) (alerting.InboxState, error)
	ArchiveInbox(ctx context.Context, principal string, ids []string, archived bool) error
	DeleteInbox(ctx context.Context, principal string, ids []string, restore bool, now time.Time) error
	ClearInbox(ctx context.Context, principal, action string, sel alerting.InboxSelector, dryRun bool) (int, error)
	GetInboxPrefs(ctx context.Context, principal string) (alerting.InboxPrefs, error)
	SaveInboxPrefs(ctx context.Context, p alerting.InboxPrefs, now time.Time) error
}

InboxStore is the surface the notification inbox handlers need from alerting.DB.

type IngressEdgeStore ¶

type IngressEdgeStore interface {
	GetIngressEdgeSettings(ctx context.Context) (store.IngressEdgeSettings, error)
	UpdateIngressEdgeSettings(ctx context.Context, s store.IngressEdgeSettings) error
	GetAppIngressLimit(ctx context.Context, app string) (store.AppIngressLimit, error)
	SetAppIngressLimit(ctx context.Context, l store.AppIngressLimit) error
	DeleteAppIngressLimit(ctx context.Context, app string) error
}

IngressEdgeStore is the optional store surface for edge limits; *store.DB satisfies it.

type IngressPortOwner ¶ added in v0.2.0

type IngressPortOwner interface {
	OwnsPort(port int) bool
}

IngressPortOwner reports whether this control plane's own embedded ingress (internal/ingress.Driver) currently has a listener bound to port. *ingress.Driver satisfies this.

type IngressResilience ¶

type IngressResilience struct {
	Status   func() ingressdriver.SnapshotStatus
	Verify   func() (ingressdriver.SnapshotCheck, error)
	SaveNow  func() error
	CertKeys func(ctx context.Context) (int, error)
}

IngressResilience is the persisted ingress state the resilience check reads.

type IngressSettingsStore ¶

type IngressSettingsStore interface {
	GetIngressSettings(ctx context.Context) (store.IngressSettings, error)
	UpdateIngressSettings(ctx context.Context, s store.IngressSettings) error
	GetDashboardURL(ctx context.Context) (string, error)
	SetDashboardURL(ctx context.Context, u string) error
}

IngressSettingsStore is the store surface the ingress settings handlers need. *store.DB satisfies this structurally, the same consumer-defined interface convention every other Store sub-interface in this package follows (see CertStore, StaticSiteStore).

type InstanceStore ¶

type InstanceStore interface {
	GetInstanceInfo(ctx context.Context) (store.InstanceInfo, error)
	ConfirmSameInstance(ctx context.Context) error
	BindOrCheckToken(ctx context.Context, tokenID, instanceID, ip string) (bool, error)
	ListTokenBindings(ctx context.Context) (map[string]store.TokenBinding, error)
}

InstanceStore is the identity and token-binding surface of the store.

type IntegrityProbe ¶

type IntegrityProbe interface {
	Status() integrity.Status
	View() (integrity.View, error)
	Check(ctx context.Context, mode string) integrity.Status
	Restore(ctx context.Context, name, by string) (integrity.Pending, error)
	CancelRestore() error
}

IntegrityProbe is the database integrity surface behind the health page and CLI.

type InviteStore ¶

type InviteStore interface {
	SaveInvite(ctx context.Context, inv store.Invite) error
	GetInviteByHash(ctx context.Context, hash string) (*store.Invite, error)
	GetInviteByID(ctx context.Context, id string) (*store.Invite, error)
	ListPendingInvites(ctx context.Context) ([]store.Invite, error)
	RevokeInvite(ctx context.Context, id string) error
	ClaimInvite(ctx context.Context, id string) error
}

InviteStore is the store surface the team-invite flow needs: always set, part of the core Store interface, same shape as PasswordResetTokenStore above.

type LBAdminStateStore ¶ added in v0.2.0

type LBAdminStateStore interface {
	SetLBUpstreamAdminState(ctx context.Context, service string, replica int, state string) error
	ListLBUpstreamAdminStates(ctx context.Context) (map[string]map[int]string, error)
}

LBAdminStateStore persists per-upstream admin state. *store.DB satisfies this; a LoadBalancerStore that does not implement it serves no admin state.

type LoadBalancerStore ¶ added in v0.2.0

type LoadBalancerStore interface {
	GetServiceLoadBalancer(ctx context.Context, service string) (string, bool, error)
	SetServiceLoadBalancer(ctx context.Context, service, configJSON string) error
	DeleteServiceLoadBalancer(ctx context.Context, service string) error
	ListLoadBalancerRows(ctx context.Context) ([]store.LoadBalancerRow, error)
}

LoadBalancerStore is the persistence surface for per-app load balancer config. *store.DB satisfies this.

type LocalContainerLister ¶ added in v0.2.0

type LocalContainerLister interface {
	ListLocalContainers(ctx context.Context) ([]docker.LocalContainer, error)
}

LocalContainerLister is implemented by the real Docker client. A runtime that is not one cannot discover local source containers.

type LogArchiveStore ¶ added in v0.2.0

type LogArchiveStore interface {
	UpsertLogArchivePolicy(ctx context.Context, p store.LogArchivePolicy) error
	GetLogArchivePolicy(ctx context.Context, appName string) (store.LogArchivePolicy, error)
	ListLogArchivePolicies(ctx context.Context) ([]store.LogArchivePolicy, error)
	DeleteLogArchivePolicy(ctx context.Context, appName string) error
	CountLogArchivePoliciesForTarget(ctx context.Context, targetID string) (int, error)
	ListLogArchiveRuns(ctx context.Context, appName string, all bool, limit int) ([]store.LogArchiveRun, error)
}

LogArchiveStore persists log archive policies and run history.

type LogArchiver ¶ added in v0.2.0

type LogArchiver interface {
	StartDump(ctx context.Context, req objectstore.DumpRequest) (store.LogArchiveRun, error)
}

LogArchiver starts manual log dumps.

type LogBudgetResource ¶

type LogBudgetResource struct {
	MaxMB            int64 `json:"max_mb"`
	DefaultMB        int64 `json:"default_mb"`
	EffectiveMaxByte int64 `json:"effective_max_bytes"`
}

LogBudgetResource is the per-app budget; MaxMB 0 means no override.

type LogBudgetStore ¶

type LogBudgetStore interface {
	GetLogBudget(ctx context.Context, resourceID string) (int64, error)
	SetLogBudget(ctx context.Context, resourceID string, maxBytes int64) error
	DeleteLogBudget(ctx context.Context, resourceID string) error
	LogUsageAll(ctx context.Context, now time.Time, defaultMax int64) ([]telemetry.LogUsage, error)
	TrimLogBudget(ctx context.Context, resourceID string, defaultMax int64) (telemetry.LogBudgetTrim, bool, error)
}

LogBudgetStore is the per-app log budget and usage storage the routes need.

type LogPipelineStore ¶

type LogPipelineStore interface {
	GetLogPipeline(ctx context.Context, resourceID string) ([]telemetry.PipelineRule, error)
	SetLogPipeline(ctx context.Context, resourceID string, rules []telemetry.PipelineRule) error
	DeleteLogPipeline(ctx context.Context, resourceID string) error
}

LogPipelineStore is the per-app log pipeline storage the routes need.

type LogTrimResult ¶

type LogTrimResult struct {
	TrimmedLines int64 `json:"trimmed_lines"`
	TrimmedBytes int64 `json:"trimmed_bytes"`
	StillOver    bool  `json:"still_over"`
}

LogTrimResult is POST /api/v1/apps/{name}/log-budget/trim.

type LogUsageApp ¶

type LogUsageApp struct {
	App          string   `json:"app"`
	Bytes        int64    `json:"bytes"`
	Lines        int64    `json:"lines"`
	RateBytesMin float64  `json:"rate_bytes_per_min"`
	BudgetBytes  int64    `json:"budget_bytes"`
	BudgetCustom bool     `json:"budget_custom"`
	Percent      *float64 `json:"percent"`
	ForecastDays *float64 `json:"forecast_days"`
	TrimmedLines int64    `json:"trimmed_lines"`
	TrimmedBytes int64    `json:"trimmed_bytes"`
}

LogUsageApp is one app's stored log volume against its budget.

type LogUsageResponse ¶

type LogUsageResponse struct {
	DefaultBudgetBytes int64         `json:"default_budget_bytes"`
	Apps               []LogUsageApp `json:"apps"`
}

LogUsageResponse is GET /api/v1/logs/usage.

type LoginCodeStore ¶ added in v0.2.0

type LoginCodeStore interface {
	CreateLoginCodeChallenge(ctx context.Context, c store.LoginCodeChallenge) error
	GetLiveLoginCodeByBrowser(ctx context.Context, browserHash string, now time.Time) (store.LoginCodeChallenge, error)
	ReserveLoginCodeAttempt(ctx context.Context, id string, maxAttempts int) (int, bool, error)
	LockLoginCode(ctx context.Context, id string, now time.Time) (bool, error)
	RedeemLoginCode(ctx context.Context, id string, now time.Time) (bool, error)
	ListLiveLoginCodesForUser(ctx context.Context, userID string, now time.Time) ([]store.LoginCodeChallenge, error)
	ClaimLapsedLoginCodes(ctx context.Context, now time.Time, limit int) ([]store.LoginCodeChallenge, error)
	PruneLoginCodes(ctx context.Context, cutoff time.Time) error
	CreateLoginApproval(ctx context.Context, a store.LoginApproval) error
	GetLoginApproval(ctx context.Context, id string) (store.LoginApproval, error)
	GetLoginApprovalByBrowser(ctx context.Context, browserHash string) (store.LoginApproval, error)
	DecideLoginApproval(ctx context.Context, id, userID string, approve bool, decidedBy string, now time.Time) (bool, error)
	ConsumeLoginApproval(ctx context.Context, id string, now time.Time) (bool, error)
	ListPendingLoginApprovalsForUser(ctx context.Context, userID string, now time.Time) ([]store.LoginApproval, error)
	ClaimLapsedLoginApprovals(ctx context.Context, now time.Time, limit int) ([]store.LoginApproval, error)
	CreateTrustedDevice(ctx context.Context, d store.TrustedDevice) error
	GetTrustedDeviceByHash(ctx context.Context, tokenHash string, now time.Time) (store.TrustedDevice, error)
	TouchTrustedDevice(ctx context.Context, id string, now time.Time) error
	ListTrustedDevices(ctx context.Context, userID string, now time.Time) ([]store.TrustedDevice, error)
	RevokeTrustedDevice(ctx context.Context, userID, id string, now time.Time) (bool, error)
	RevokeAllTrustedDevices(ctx context.Context, userID string, now time.Time) (int, error)
	ExtendTrustedDevice(ctx context.Context, id string, expiresAt, now time.Time) error
	PruneTrustedDevices(ctx context.Context, cutoff time.Time) error
	SupersedeLoginApprovals(ctx context.Context, userID string, now time.Time) ([]store.LoginApproval, error)
	ReplaceLoginApproval(ctx context.Context, a store.LoginApproval) ([]store.LoginApproval, error)
	ExpireLoginCode(ctx context.Context, id string, now time.Time) (bool, error)
	LockLoginCodesForUser(ctx context.Context, userID string, now time.Time) ([]string, error)
	GetCodeLoginSettings(ctx context.Context) (store.CodeLoginSettings, bool, error)
	SaveCodeLoginSettings(ctx context.Context, s store.CodeLoginSettings) error
}

LoginCodeStore is the store surface sign in with a code, new-device approval and trusted devices need.

type MailStore ¶

type MailStore interface {
	mailcast.Store
	ListMailTemplates(ctx context.Context) ([]store.MailTemplate, error)
	GetMailTemplate(ctx context.Context, key string) (*store.MailTemplate, error)
	SaveMailTemplate(ctx context.Context, t store.MailTemplate) error
	DeleteMailTemplate(ctx context.Context, key string) error
	ListMailTemplateVersions(ctx context.Context, key string) ([]store.MailTemplateVersion, error)
	GetMailTemplateVersion(ctx context.Context, key string, version int) (*store.MailTemplateVersion, error)
	GetMailLayout(ctx context.Context) (store.MailLayout, error)
	SetMailLayout(ctx context.Context, l store.MailLayout) error
	ListMailGroups(ctx context.Context) ([]store.MailGroup, error)
	GetMailGroup(ctx context.Context, idOrName string) (*store.MailGroup, error)
	SaveMailGroup(ctx context.Context, g store.MailGroup) error
	DeleteMailGroup(ctx context.Context, id string) error
	AddMailSuppression(ctx context.Context, email, reason string) error
	RemoveMailSuppression(ctx context.Context, email string) error
	CreateMailBroadcast(ctx context.Context, b store.MailBroadcast, recipients []store.MailRecipient) error
	ListMailBroadcasts(ctx context.Context, limit int) ([]store.MailBroadcast, error)
	CountMailBroadcastRecipientsSince(ctx context.Context, since time.Time) (int, error)
	ListUsers(ctx context.Context) ([]store.User, error)
	UserTeamRoles(ctx context.Context, userID string) (map[string]string, error)
	ListProjects(ctx context.Context) ([]store.Project, error)
	ListOrganizations(ctx context.Context) ([]store.Organization, error)
}

MailStore is the persistence behind templates, audiences and broadcasts; *store.DB satisfies it, and the routes return 501 without it.

type MajorUpgradeStore ¶ added in v0.2.0

type MajorUpgradeStore interface {
	ListMajorUpgrades(ctx context.Context, databaseName string) ([]store.MajorUpgrade, error)
	GetMajorUpgrade(ctx context.Context, id string) (store.MajorUpgrade, error)
	ListMajorUpgradeSnapshots(ctx context.Context) ([]store.MajorUpgrade, error)
}

MajorUpgradeStore is the store surface the major upgrade routes read.

type MajorUpgrader ¶ added in v0.2.0

type MajorUpgrader interface {
	RunMajorUpgrade(ctx context.Context, historyID, databaseName, toVersion string) error
	Rollback(ctx context.Context, upgradeID string) error
	DiscardSnapshot(ctx context.Context, upgradeID string) error
}

MajorUpgrader runs guarded major version upgrades (internal/backup's MajorUpgradeRunner).

type MasterKeyRotator ¶

type MasterKeyRotator interface {
	RotateMasterKey(ctx context.Context, newMasterKey string) (rotatedAt time.Time, err error)
	GetMasterKeyRotatedAt(ctx context.Context) (rotatedAt time.Time, ok bool, err error)
}

MasterKeyRotator rotates every stored DEK to a new master key and reports the last success. Separate from SecretSetter because it is gated at AbilityRoot.

type MeshKeyRotator ¶ added in v0.2.0

type MeshKeyRotator interface {
	RotateKey(ctx context.Context, nodeID string) (network.RotationResult, error)
	RotationStatusFor(nodeID string) (network.RotationStatus, bool)
}

MeshKeyRotator is the narrow surface this package needs from *network.Coordinator for rotation: rotate one node's key, and read back what Coordinator itself knows about in-flight rotations. *network.Coordinator satisfies this structurally.

type MeshSettingsStore ¶ added in v0.2.0

type MeshSettingsStore interface {
	GetMeshSetting(ctx context.Context) (store.MeshSetting, error)
	SetMeshSetting(ctx context.Context, enabled bool, actor string, now time.Time) error
}

MeshSettingsStore persists the operator's mesh on/off choice; *store.DB satisfies it.

type MeshStatusProvider ¶ added in v0.2.0

type MeshStatusProvider interface {
	Status(ctx context.Context) (network.Status, error)
}

MeshStatusProvider is the narrow surface this package needs from this node's live network.Mesh: exactly Status, never Apply or Close, since this package only ever reads the mesh, never drives it (the reconcile loop owns that). *network.Device, *network.Disabled, and any test fake implementing Status alone all satisfy this.

type MigrationAgentService ¶

type MigrationAgentService interface {
	Create(ctx context.Context, label, actor string) (migrateagent.Created, error)
	List(ctx context.Context) ([]migrateagent.SessionView, error)
	Get(ctx context.Context, id string) (migrateagent.SessionView, migrateagent.InventoryDoc, migrateagent.ScanDoc, error)
	Revoke(ctx context.Context, id, actor string) error
	Discover(ctx context.Context, id string) (migrateagent.InventoryDoc, error)
	Scan(ctx context.Context, id string, targets []string) (migrateagent.ScanDoc, error)
	Auditor() *migrateagent.Auditor
	Config() migrateagent.Config
}

MigrationAgentService is the control plane side of the read-only migration agent. *migrateagent.Service satisfies it.

type MigrationChecklistStore ¶

type MigrationChecklistStore interface {
	SaveMigrationChecklist(ctx context.Context, c store.MigrationChecklist) error
	GetMigrationChecklist(ctx context.Context, app string) (store.MigrationChecklist, error)
	ListMigrationChecklists(ctx context.Context) ([]store.MigrationChecklist, error)
}

MigrationChecklistStore is the store surface the cutover checklist needs.

type MigrationHubStore ¶ added in v0.2.0

type MigrationHubStore interface {
	CreateMigrationSession(ctx context.Context, s store.MigrationSession, items []store.MigrationItem) error
	GetMigrationSession(ctx context.Context, id string) (store.MigrationSession, error)
	ListMigrationSessions(ctx context.Context) ([]store.MigrationSession, error)
	SetMigrationStep(ctx context.Context, id, step string, now time.Time) error
	DeleteMigrationSession(ctx context.Context, id string) error
	ListMigrationItems(ctx context.Context, sessionID string) ([]store.MigrationItem, error)
	SetMigrationItemPlan(ctx context.Context, sessionID, sourceDB, targetName, targetVersion string, selected bool) error
	MarkMigrationItemTargetCreated(ctx context.Context, sessionID, sourceDB, version string) error
	SetMigrationItemStatus(ctx context.Context, sessionID, sourceDB, status, reason string, checked, mismatched int, detail string, now time.Time) error
}

MigrationHubStore is the store surface the migration hub routes need.

type MigrationVerifyStore ¶

type MigrationVerifyStore interface {
	SaveMigrationVerifyReport(ctx context.Context, r store.MigrationVerifyReport) error
	GetMigrationVerifyReport(ctx context.Context) (store.MigrationVerifyReport, error)
}

MigrationVerifyStore keeps the latest parity report.

type ModelCPUService ¶

type ModelCPUService interface {
	LocalCatalogView(ctx context.Context, nodeID string) (models.CatalogView, error)
	CPUFitCheck(ctx context.Context, req models.CPUFitRequest) (models.CPUFitReport, error)
	Benchmark(ctx context.Context, name string) (models.BenchResult, error)
}

ModelCPUService is the CPU-mode surface of the model service, asserted at request time so a service without it answers 501.

type ModelPreflightService ¶ added in v0.2.0

type ModelPreflightService interface {
	PreflightEnabled() bool
	Preflight(ctx context.Context, in models.PreflightInput) (models.PreflightResult, error)
	CacheEnabled() bool
	CacheList(ctx context.Context) (models.CacheReport, error)
	CachePrune(ctx context.Context, volumes []string, dryRun bool) (models.CachePruneResult, error)
}

ModelPreflightService is the optional surface behind the Hugging Face preflight and model cache routes. The models service implements it.

type ModelService ¶ added in v0.2.0

type ModelService interface {
	Create(ctx context.Context, in models.CreateInput) (models.Created, error)
	List(ctx context.Context) ([]models.View, error)
	Get(ctx context.Context, name string) (models.View, error)
	Delete(ctx context.Context, name string) error
	Restart(ctx context.Context, name string) error
	RotateKey(ctx context.Context, name string) (string, error)
	ListKeys(ctx context.Context, model string) ([]models.KeyView, error)
	CreateKey(ctx context.Context, model string, in models.CreateKeyInput) (models.CreatedKey, error)
	RevokeKey(ctx context.Context, model, id string) error
	RotateKeyByID(ctx context.Context, model, id, actor string, grace *time.Duration) (models.CreatedKey, error)
	Usage(ctx context.Context, model string, window time.Duration) (models.UsageReport, error)
	EngineMetrics(ctx context.Context, name string, window time.Duration) (models.EngineMetricsReport, error)
	FitCheck(ctx context.Context, req models.FitRequest) (models.FitReport, error)
	SetResidency(ctx context.Context, name, residency string, idleTTL time.Duration) error
	SetSwapGroup(ctx context.Context, name, group string) error
	Wake(ctx context.Context, name string) error
	Sleep(ctx context.Context, name string) error
	ModelFit(ctx context.Context, name string) (models.FitReport, error)
	SetHFToken(ctx context.Context, name, token string) error
	GPUNodes(ctx context.Context) ([]models.GPUNode, error)
	NodeGPU(ctx context.Context, nodeID string) (gpu.Info, bool, error)
	UnplacedWorkloads(ctx context.Context) ([]models.Unplaced, error)
	SetLocalNodeID(id string)
}

ModelService is the surface the /api/v1/models handlers need from internal/models.

type MySQLPITRRestoreRunner ¶

type MySQLPITRRestoreRunner interface {
	WindowBounds(ctx context.Context, databaseName, containerName string) (hasBaseBackup bool, start, end time.Time, err error)
	ValidateTarget(ctx context.Context, databaseName, containerName string, target time.Time) error
	RunPITRCloneRestore(ctx context.Context, historyID, sourceName, newName, baseBackupHistoryID, engine, sourceContainer, newContainer, newController string, target time.Time) error
}

MySQLPITRRestoreRunner is the MySQL and MariaDB counterpart of PITRRestoreRunner. Their restore lands in a new database, so it takes the new database's names.

type NetworkShareSecretsSetter ¶ added in v0.2.0

type NetworkShareSecretsSetter interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
}

NetworkShareSecretsSetter is the surface network share create/update needs from internal/secrets.Manager, the same two-method shape RegistryCredentialSecretsSetter establishes: SetValue writes a CIFS share's password, never read back by any handler in this file.

type NetworkShareStore ¶ added in v0.2.0

type NetworkShareStore interface {
	SaveNetworkShare(ctx context.Context, s store.NetworkShare) error
	GetNetworkShare(ctx context.Context, id string) (store.NetworkShare, error)
	GetNetworkShareByName(ctx context.Context, name string) (store.NetworkShare, error)
	ListNetworkShares(ctx context.Context) ([]store.NetworkShare, error)
	UpdateNetworkShare(ctx context.Context, id, name, protocol, host, remotePath, mountOptions, username string) error
	DeleteNetworkShare(ctx context.Context, id string) error
}

NetworkShareStore is the store surface the network share handlers need.

type NodeGuardrailStore ¶

type NodeGuardrailStore interface {
	GetNodeGuardrails(ctx context.Context, nodeID string) (store.NodeGuardrails, bool, error)
	SetNodeGuardrails(ctx context.Context, g store.NodeGuardrails, now time.Time) error
	ListAutoCleanNodes(ctx context.Context) ([]string, error)
	InsertNodeCleanupRun(ctx context.Context, r store.NodeCleanupRun, keep int) error
	ListNodeCleanupRuns(ctx context.Context, nodeID string, limit int) ([]store.NodeCleanupRun, error)
}

NodeGuardrailStore persists per-node threshold overrides and cleanup history. *store.DB satisfies it.

type NodeHostReports ¶ added in v0.2.2

type NodeHostReports interface {
	Get(nodeID string) (agent.HostReport, bool)
}

NodeHostReports is the control plane's latest per-node agent host report.

type NodeMeshStatusSource ¶ added in v0.2.0

type NodeMeshStatusSource interface {
	MeshStatus(ctx context.Context, nodeID string) (network.Status, error)
}

NodeMeshStatusSource reads a remote node's own WireGuard view over its agent session.

type NodeOnboardingSource ¶

type NodeOnboardingSource interface {
	Get(nodeID string) (agent.StoredOnboarding, bool)
	Snapshot() map[string]agent.StoredOnboarding
}

NodeOnboardingSource is the control plane's latest onboarding report per node; *agent.OnboardingStore satisfies it.

type NodeProviderConnectionStore ¶

type NodeProviderConnectionStore interface {
	SaveNodeProviderConnection(ctx context.Context, c store.NodeProviderConnection) error
	RecordNodeProviderTest(ctx context.Context, provider string, ok bool, detail string, at time.Time) error
	DeleteNodeProviderConnection(ctx context.Context, provider string) error
	ListNodeProviderConnections(ctx context.Context) ([]store.NodeProviderConnection, error)
}

NodeProviderConnectionStore is the store surface for connection metadata.

type NodeProviderSecrets ¶ added in v0.2.0

type NodeProviderSecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
}

NodeProviderSecrets is the surface the node provider credential handlers need from internal/secrets.Manager: unlike CloudflareDNSSecrets (write-only from this package's own perspective), this package does call Resolve, to authenticate the live provider API calls handleCreateNodeProvision and the catalog handlers below make. *secrets.Manager satisfies this structurally.

type NodeProvisionStore ¶ added in v0.2.0

type NodeProvisionStore interface {
	SaveNodeProvision(ctx context.Context, p store.NodeProvision) error
	GetNodeProvision(ctx context.Context, id string) (store.NodeProvision, error)
	ListNodeProvisions(ctx context.Context) ([]store.NodeProvision, error)
	UpdateNodeProvisionStatus(ctx context.Context, id, status, providerServerID, ipAddress, nodeID, failureReason string, updatedAt time.Time) error
}

NodeProvisionStore is the store surface the node provisioning handlers need.

type NodeProvisioner ¶ added in v0.2.0

type NodeProvisioner interface {
	ListRegions(ctx context.Context) ([]provision.Region, error)
	ListSizes(ctx context.Context, region string) ([]provision.Size, error)
	CreateServer(ctx context.Context, opts provision.CreateOpts) (serverID, ipAddr string, err error)
	GetServer(ctx context.Context, id string) (status provision.ServerStatus, ipAddr string, err error)
	DeleteServer(ctx context.Context, id string) error
}

NodeProvisioner is the surface internal/provision.Provisioner implementations satisfy: a narrow, consumer-defined interface so this package's own tests inject a fake instead of hitting a real cloud API.

type NodeProvisionerFactory ¶ added in v0.2.0

type NodeProvisionerFactory func(provider, token string) (NodeProvisioner, error)

NodeProvisionerFactory builds a NodeProvisioner for a known provider name given its resolved API token. Overridable in this package's own tests via WithNodeProvisionerFactory, the same "seam, not an interface" shape gitSourceFetch/fetch already use elsewhere in this package.

type NodeRuntimeResolver ¶

type NodeRuntimeResolver func(nodeID string) (docker.Runtime, error)

NodeRuntimeResolver picks the docker.Runtime owning a nodeID: the local daemon for "", a connected agent's Transport otherwise. A func type so this package avoids importing internal/agent. handleExecApp needs per-request node routing, unlike the fixed local-daemon interfaces above.

type NodeSessionCloser ¶ added in v0.2.0

type NodeSessionCloser interface {
	Disconnect(nodeID string)
}

NodeSessionCloser ends a node's live agent session. *agent.Server satisfies it; nil means a revoked node is only refused at its next connection.

type NodeStore ¶

type NodeStore interface {
	ListNodes(ctx context.Context) ([]store.Node, error)
	GetNode(ctx context.Context, id string) (*store.Node, error)
	DeleteNode(ctx context.Context, id string) error
	SaveNodeJoinToken(ctx context.Context, t store.NodeJoinToken) error
	UpdateNodeWorkloads(ctx context.Context, id string, acceptsApp, acceptsBuild bool) error
	// UpdateNodeRegion sets a node's optional location label, backing
	// PUT /api/v1/nodes/{id}/region.
	UpdateNodeRegion(ctx context.Context, id, region string) error
	// UpdateNodeFailureDomain replaces provider, region and zone together.
	UpdateNodeFailureDomain(ctx context.Context, id, provider, region, zone string) error
	// SetNodeSchedulable is the cordon/uncordon mutation.
	SetNodeSchedulable(ctx context.Context, id string, schedulable bool) error
	RevokeNodeCert(ctx context.Context, id string, now time.Time) error
}

NodeStore is the store surface the node-management handlers need. *store.DB satisfies this structurally, the same narrow consumer-defined interface convention every other Store sub-interface in this package already follows.

type NodeTrustControl ¶

type NodeTrustControl interface {
	RequestRenew(nodeID string) error
	RecordSecurityEvent(ev store.NodeSecurityEvent)
}

NodeTrustControl is the live-agent surface the trust routes need. *agent.Server satisfies it.

type NotificationChannelTester ¶

type NotificationChannelTester interface {
	SendTest(ctx context.Context, kind alerting.NotifyKind, notifyURL string) error
	SendChannelTest(ctx context.Context, c alerting.NotificationChannel) error
}

NotificationChannelTester is the surface the test-send routes need: a real send through kind/notifyURL, not just a format check. *alerting.DeployDispatcher satisfies this structurally.

type NotificationChannels ¶

type NotificationChannels interface {
	SaveNotificationChannel(ctx context.Context, c alerting.NotificationChannel) error
	GetNotificationChannel(ctx context.Context, id string) (*alerting.NotificationChannel, error)
	ListNotificationChannels(ctx context.Context) ([]alerting.NotificationChannel, error)
	DeleteNotificationChannel(ctx context.Context, id string) error
	RevealNotificationChannel(ctx context.Context, c alerting.NotificationChannel) (alerting.NotificationChannel, error)
}

NotificationChannels is the store surface the channel handlers need. *alerting.DB satisfies this structurally.

type NotificationDeliveryStore ¶

type NotificationDeliveryStore interface {
	RecordNotificationDelivery(ctx context.Context, d alerting.NotificationDelivery) error
	ListNotificationDeliveries(ctx context.Context, channelID string, limit int, before *time.Time) ([]alerting.NotificationDelivery, error)
}

NotificationDeliveryStore is the surface the delivery-history route and test-send recording need. *alerting.DB satisfies this structurally.

type OAuthIdentityStore ¶

type OAuthIdentityStore interface {
	GetOAuthIdentity(ctx context.Context, provider, providerUserID string) (*store.OAuthIdentity, error)
	SaveOAuthIdentity(ctx context.Context, i store.OAuthIdentity) error
	ListOAuthIdentitiesForUser(ctx context.Context, userID string) ([]store.OAuthIdentity, error)
}

OAuthIdentityStore is the store surface the sign-in and account- linking handlers need. *store.DB satisfies this structurally.

type OAuthSecrets ¶

type OAuthSecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
}

OAuthSecrets is the surface the OAuth flow needs from internal/secrets.Manager: unlike SecretSetter (write-only), a provider's client secret must be resolved on every sign-in attempt.

type OAuthSettingsStore ¶

type OAuthSettingsStore interface {
	GetOAuthProviderSettings(ctx context.Context, provider string) (store.OAuthProviderSettings, error)
	ListOAuthProviderSettings(ctx context.Context) ([]store.OAuthProviderSettings, error)
	UpdateOAuthProviderSettings(ctx context.Context, s store.OAuthProviderSettings) error
	SetOAuthSSOPolicy(ctx context.Context, provider string, p store.OAuthSSOPolicy) error
}

OAuthSettingsStore is the store surface the OAuth settings and sign-in handlers need for provider configuration (oauth_settings.go, this file). *store.DB satisfies this structurally.

type OIDCJWKSProvider ¶ added in v0.2.0

type OIDCJWKSProvider interface {
	JWKS(ctx context.Context) (oidc.JWKS, error)
}

OIDCJWKSProvider serves the public half of the signing key pipeline jobs' OIDC tokens are signed with. *oidc.Manager satisfies it.

type OIDCKeyRotator ¶ added in v0.2.0

type OIDCKeyRotator interface {
	RotateKey(ctx context.Context, retireAfter time.Duration) (oidc.RotationResult, error)
}

OIDCKeyRotator rotates the pipeline OIDC signing key. *oidc.Manager satisfies it. A separate interface from OIDCJWKSProvider, not a wider one: a fake in a JWKS-only test has no reason to implement rotation too.

type ObjectClientResolver ¶ added in v0.2.0

type ObjectClientResolver interface {
	Client(ctx context.Context, targetID string) (*objectstore.Client, store.BackupTarget, error)
}

ObjectClientResolver builds a bucket client for a stored destination.

type ObservabilityStore ¶ added in v0.2.0

type ObservabilityStore interface {
	GetObservabilitySettings(ctx context.Context) (store.ObservabilitySettings, error)
	UpdateObservabilitySettings(ctx context.Context, s store.ObservabilitySettings) error
}

ObservabilityStore is the store surface GET/PUT /api/v1/settings/observability need: the single platform-wide row, always present, the same shape EmailSettingsStore has for its own row.

type OnboardingStore ¶

type OnboardingStore interface {
	GetOnboardingState(ctx context.Context) (store.OnboardingState, error)
	MarkOnboardingCompleted(ctx context.Context) error
	SetOnboardingProgress(ctx context.Context, currentStep string, steps map[string]string) error
}

OnboardingStore is the store surface the /api/v1/onboarding routes need.

type Option ¶

type Option func(*Router)

Option configures optional Router behavior.

func WithACMEDefaultDirectory ¶ added in v0.2.0

func WithACMEDefaultDirectory(url string) Option

WithACMEDefaultDirectory sets the CA directory enable-https uses when the caller does not ask for staging. Empty means Let's Encrypt production.

func WithAIEngine ¶ added in v0.2.0

func WithAIEngine(e AIEngine) Option

WithAIEngine enables every /api/v1/ai/... chat session route. Without one configured (the default), they all return 501, the same "not configured" shape WithBuilder's absence produces for the build trigger route.

func WithAIUsage ¶

func WithAIUsage(u AIUsageStore) Option

WithAIUsage enables GET /api/v1/ai/usage and the monthly token count.

func WithAIVault ¶

func WithAIVault(v AIVault) Option

WithAIVault enables the routes under /api/v1/settings/ai-assistant.

func WithAPIRateLimit ¶

func WithAPIRateLimit(readPerMinute, writePerMinute int) Option

WithAPIRateLimit enables a general per-actor rate limit across every requireAbility-gated route (api_rate_limit.go): read-tier (AbilityRead) requests get readPerMinute budget, everything else (write, write:sensitive, deploy, root) gets the stricter writePerMinute budget, keyed per bearer token, per session user, or per client IP for an unauthenticated caller. Either argument <= 0 disables that tier. Without this option (the default), the whole check is skipped: existing tests and any embedder that never opts in see unthrottled behavior, the same "nil is valid" shape WithSecretSetter's own absence already establishes. This package never reads the environment directly: cmd/levelrail/main.go reads APP_API_RATE_LIMIT_READ_RPM / APP_API_RATE_LIMIT_WRITE_RPM and calls this unconditionally with their resolved (env-or-default) values, so the real control plane is always protected even when an operator never sets either env var.

func WithAccessSource ¶

func WithAccessSource(s AccessSource) Option

WithAccessSource turns on GET /api/v1/apps/{name}/access.

func WithAgentCAFingerprint ¶ added in v0.2.0

func WithAgentCAFingerprint(fp string) Option

WithAgentCAFingerprint sets the agent CA fingerprint returned with each new node join token, so the enrollment command can pin it.

func WithAlertDefaults ¶

func WithAlertDefaults(a AlertDefaults) Option

WithAlertDefaults enables the default alert list and toggle routes.

func WithAlertNoise ¶ added in v0.2.0

func WithAlertNoise(a AlertNoise) Option

WithAlertNoise enables the silence, maintenance window and alert history routes.

func WithAlertRules ¶

func WithAlertRules(a AlertRules) Option

WithAlertRules enables POST/GET /api/v1/apps/{name}/alerts and DELETE /api/v1/apps/{name}/alerts/{id}. Without one configured (the default), all three routes return 501, the same "not configured" shape WithSecretSetter and WithTelemetryQuerier's absence already produce: this control plane still starts and serves everything else without an alerting.DB wired in.

func WithAllowInsecureLogin ¶ added in v0.2.0

func WithAllowInsecureLogin(allow bool) Option

WithAllowInsecureLogin permits plain-HTTP sign-in even when an https dashboard URL is configured.

func WithAppTeardownOptions ¶ added in v0.2.0

func WithAppTeardownOptions(opts ...application.Option) Option

WithAppTeardownOptions sets the application options (instance ID, network prefix) used to match containers when an app is deleted, so delete never touches containers another control plane created on a shared daemon.

func WithApprovalChatNotifier ¶ added in v0.2.0

func WithApprovalChatNotifier(n ApprovalChatNotifier) Option

WithApprovalChatNotifier enables posting an interactive Approve/Deny message (deploy_approval_chat_notify.go) when a deploy approval is requested, to every notification channel that opted into InteractiveApprovals. Without one, requestDeployApproval simply doesn't post anything, the same "optional signal" shape as WithDeployNotifier.

func WithArchives ¶

func WithArchives(m *archive.Manager, st ArchiveSettingsStore) Option

WithArchives enables the /api/v1/archives routes. Without it they return 501.

func WithAuditLogRetention ¶

func WithAuditLogRetention(d time.Duration) Option

WithAuditLogRetention overrides how long an audit_log row survives before PurgeOldAuditEntries removes it. Without one configured (or passed as 0), defaultAuditLogRetention (90 days) applies. Same "no hardcoded thresholds, use env vars" shape as WithPreviewTTL: this package never reads the environment directly, cmd/levelrail/main.go reads APP_AUDIT_LOG_RETENTION_DAYS and passes the parsed duration here.

func WithAuthEngine ¶ added in v0.2.0

func WithAuthEngine(e *authengine.Engine) Option

WithAuthEngine supplies the library auth engine. NewRouter builds a default one over the store database when none is given.

func WithAuthEngineMFA ¶ added in v0.2.0

func WithAuthEngineMFA(m *authengine.MFA) Option

WithAuthEngineMFA serves TOTP and passkeys through the library on the existing routes. A nil service is a no-op, which keeps the built-in handlers.

func WithAutoPlacement ¶ added in v0.2.0

func WithAutoPlacement(enabled bool) Option

WithAutoPlacement overrides whether handleCreateApp/handleCreateDatabase auto-place a create request that omits node_id onto the least-loaded registered node (scheduling.go's autoPlaceNode), instead of leaving it on this control plane's own local node. Defaults to true (NewRouter's own struct literal); cmd/levelrail/main.go reads APP_AUTO_PLACEMENT and calls this with false to disable it, the same "this package never reads the environment directly" convention WithSessionTTL's own doc comment establishes. An explicit node_id in a create request always overrides this regardless of its value, on or off.

func WithBackupDeleter ¶ added in v0.2.0

func WithBackupDeleter(d BackupDeleter) Option

WithBackupDeleter enables DELETE /api/v1/databases/{name}/backups/{historyId} and its app volume counterpart. Without one configured (the default), both routes return 501, the same "not configured" shape WithBackupDownloader's absence produces: deleting the stored object behind a backup needs the same live secretsManager to resolve a target's credentials that downloading or uploading one does.

func WithBackupDownloader ¶

func WithBackupDownloader(d BackupDownloader) Option

WithBackupDownloader enables GET /api/v1/databases/{name}/backups/{historyId}/download. Without one configured (the default), that route returns 501, the same "not configured" shape WithBackupRunner's absence produces: both need a live secretsManager to resolve a target's credentials, WithBackupRunner to upload with them, this to download with them.

func WithBackupProtection ¶ added in v0.2.0

func WithBackupProtection(p BackupProtection, st BackupProtectionStore) Option

WithBackupProtection enables the backup health, restore drill, volume backup policy and restore-to routes. Without it they return 501.

func WithBackupRunner ¶

func WithBackupRunner(r BackupRunner) Option

WithBackupRunner enables POST /api/v1/databases/{name}/backups. Without one configured (the default), that route returns 501, the same "not configured" shape WithBackupSecrets' absence produces; listing backup history (GET .../backups) works regardless, since it only reads store.BackupHistory rows a runner already wrote in the past, nothing about it needs a live runner today.

func WithBackupSecrets ¶

func WithBackupSecrets(s BackupSecretsSetter) Option

WithBackupSecrets enables POST /api/v1/backup-targets. Without one configured (the default), that route returns 501, the same "not configured" shape WithSecretSetter's absence produces; listing, getting, and deleting an already-connected backup target work regardless, since none of those need to write a credential.

func WithBackupTargetTester ¶

func WithBackupTargetTester(t BackupTargetTester) Option

WithBackupTargetTester enables POST /api/v1/backup-targets/{id}/test. Without one configured (the default), that route returns 501, the same "not configured" shape WithRegistryAuthTester's absence produces for registry credentials: both need a live secretsManager to resolve a stored credential before using it.

func WithBackupVerifier ¶

func WithBackupVerifier(v BackupVerifier) Option

WithBackupVerifier enables POST /api/v1/databases/{name}/backups/{historyId}/verify. Without one configured (the default), that route returns 501, the same "not configured" shape WithBackupRunner's absence produces: verifying needs the identical live secretsManager WithBackupRunner and WithBackupDownloader already depend on, to resolve a target's credentials and re-download the object. Listing past verification attempts (GET .../verifications) works regardless, the same "listing needs no live runner" reasoning WithBackupRunner's own doc comment gives for backup history.

func WithBaseBackupRunner ¶ added in v0.2.0

func WithBaseBackupRunner(r BaseBackupRunner) Option

WithBaseBackupRunner enables POST /api/v1/databases/{name}/base-backups. Without one configured (the default), that route returns 501, the same "not configured" shape WithBackupRunner's absence produces; listing base backup history (GET .../base-backups) works regardless, the same "listing needs no live runner" reasoning WithBackupRunner's own doc comment gives.

func WithBuildCache ¶

func WithBuildCache(r BuildCacheResolver) Option

WithBuildCache enables the /api/v1/builds/cache routes.

func WithBuildPerformance ¶

func WithBuildPerformance(s BuildPerformanceStore) Option

WithBuildPerformance enables the build stats and build limits routes.

func WithBuilder ¶

func WithBuilder(b Builder) Option

WithBuilder enables POST /api/v1/apps/{name}/builds: a manual build trigger for an operator with no working git webhook configured (see internal/webhook.Config's own doc comment on why that path is deliberately static, single-app configuration). Without one configured (the default), that route returns 501, the same "not configured" shape WithSecretSetter/WithTelemetryQuerier/WithAlertRules absence already share. cmd/levelrail/main.go passes the same *deploy.Pipeline the git webhook receiver uses, when a BuildKit connection was successfully established at startup.

func WithCapacityForecastLookback ¶ added in v0.2.0

func WithCapacityForecastLookback(d time.Duration) Option

WithCapacityForecastLookback overrides how far back GET /api/v1/nodes/{id}/capacity-forecast looks for disk/memory history (handleNodeCapacityForecast). Without one configured (or passed as 0), defaultCapacityForecastLookback (14 days) applies. Same "no hardcoded thresholds, use env vars" shape as WithResourceRecommendationLookback: this package never reads the environment directly, cmd/levelrail/main.go reads APP_CAPACITY_FORECAST_LOOKBACK and passes the parsed duration here.

func WithCertExpiryWarningWindow ¶

func WithCertExpiryWarningWindow(d time.Duration) Option

WithCertExpiryWarningWindow overrides how far ahead of a certificate's expiry GET /api/v1/certificates starts reporting "expiring_soon" instead of "healthy" (see alerting.CertExpiryStatus). Without one configured (or passed as 0), alerting.DefaultCertExpiryWarningWindow (14 days) applies. Same "no hardcoded thresholds, use env vars" shape as WithSessionTTL: this package never reads the environment directly, cmd/levelrail/main.go reads APP_CERT_EXPIRY_WARNING_WINDOW and passes the parsed duration here, and to alerting.NewEngine for a kind=cert_expiry rule's own evaluation.

func WithCertRenewalTracking ¶ added in v0.2.0

func WithCertRenewalTracking(src CertObservationSource, stalledThreshold time.Duration) Option

WithCertRenewalTracking lets GET /api/v1/certificates report a stalled renewal from the observations kind=cert_expiry rules record. A zero threshold falls back to alerting.DefaultCertRenewalStalledThreshold.

func WithChangelog ¶ added in v0.2.0

func WithChangelog(entries []changelog.Entry) Option

WithChangelog supplies the entries GET /api/v1/changelog serves, parsed once at startup from the repo's own CHANGELOG.md (see cmd/levelrail's loadChangelog). Without one configured (the default, nil), that route answers an empty entries list rather than failing: a bare, non-Docker install that hasn't shipped CHANGELOG.md next to the binary yet just sees an empty "what's new" panel, not a broken one.

func WithCloneRestoreRunner ¶

func WithCloneRestoreRunner(r CloneRestoreRunner) Option

WithCloneRestoreRunner enables POST /api/v1/databases/{name}/restore-as-new. Without one configured (the default), that route returns 501, the same "not configured" shape WithRestoreRunner's absence produces; listing clone-restore history (GET .../clone-restores) works regardless, the same "listing needs no live runner" reasoning WithRestoreRunner's own doc comment gives.

func WithCloudflareDNSSecrets ¶

func WithCloudflareDNSSecrets(s CloudflareDNSSecrets) Option

WithCloudflareDNSSecrets enables PUT/DELETE /api/v1/settings/cloudflare-dns. Without one configured (the default), both return 501; GET works regardless, the same shape WithCloudflareTunnelSecrets establishes.

func WithCloudflareDNSTokenResolver ¶ added in v0.2.0

func WithCloudflareDNSTokenResolver(r CloudflareDNSTokenResolver) Option

WithCloudflareDNSTokenResolver enables GET/POST/PUT/DELETE .../dns-records whenever Cloudflare DNS is the configured provider: without one set (the default), those routes return 501 unless Route53 DNS is configured instead. Distinct from WithCloudflareDNSSecrets, which can only check whether a token is stored, not read it back.

func WithCloudflareTunnelSecrets ¶

func WithCloudflareTunnelSecrets(s CloudflareTunnelSecrets) Option

WithCloudflareTunnelSecrets enables PUT/DELETE /api/v1/settings/cloudflare-tunnel. Without one configured (the default), both return 501; GET works regardless, the same shape WithEmailSecrets establishes.

func WithComposeSecrets ¶

func WithComposeSecrets(s ComposeSecretStore) Option

WithComposeSecrets enables POST /api/v1/apps/{name}/compose to resolve a compose file's generatable SERVICE_ magic vars. Without one configured (the default), that endpoint still works for compose files with no such vars, and fails with a clear error for ones that need one.

func WithContainerLister ¶

func WithContainerLister(l ContainerLister) Option

WithContainerLister enables GET /api/v1/system/containers. Without one configured (the default), that route returns 501, the same "not configured" shape WithExecRuntime's own absence already has.

func WithControlPlaneBackupScheduleDisabled ¶ added in v0.2.0

func WithControlPlaneBackupScheduleDisabled(disabled bool) Option

WithControlPlaneBackupScheduleDisabled tells the doctor check that scheduled snapshots are switched off, so it reports unknown, not a warning.

func WithControlPlaneBackups ¶ added in v0.2.0

func WithControlPlaneBackups(m ControlPlaneBackupManager) Option

WithControlPlaneBackups enables the /api/v1/system/backups routes. Without one, they return 501.

func WithControlPlaneDR ¶ added in v0.2.0

func WithControlPlaneDR(dr ControlPlaneDR, material EscrowMaterialReader) Option

WithControlPlaneDR enables the /api/v1/system/control-plane-dr routes and the doctor's disaster recovery check. Without it the routes return 501.

func WithDBPinger ¶

func WithDBPinger(p DBPinger) Option

WithDBPinger enables the database check on GET /api/v1/system/doctor. Without one configured (the default), that check reports unknown, the same "optional signal, absence is not an error" shape WithDockerPinger's own absence already has.

func WithDashboardCache ¶ added in v0.2.0

func WithDashboardCache(ttl, stale time.Duration) Option

WithDashboardCache enables the short TTL cache behind the dashboard's aggregate endpoints and the docker disk usage warm-up. ttl <= 0 keeps every request live; the binary resolves APP_DASHBOARD_CACHE_TTL and _STALE.

func WithDashboardListenAddr ¶ added in v0.2.0

func WithDashboardListenAddr(addr string) Option

WithDashboardListenAddr tells the reverse proxy guide where the dashboard listens.

func WithDashboardURL ¶ added in v0.2.0

func WithDashboardURL(u string) Option

WithDashboardURL sets the base URL used for links in outbound notices.

func WithDataDir ¶

func WithDataDir(path string) Option

WithDataDir enables disk-usage reporting on GET /api/v1/system/status. path should be the same APP_DATA_DIR the control plane itself was started with. Without one configured (the default), the status response simply omits the two data-dir byte fields, the same "optional signal, absence is not an error" shape WithSecretSetter's own absence already has for secret-setting.

func WithDatabaseAccess ¶ added in v0.2.0

func WithDatabaseAccess(s DatabaseAccessStore, ttl dbaccess.TTLLimits) Option

WithDatabaseAccess enables database users, temporary credentials and the network controls. ttl bounds temporary credential lifetimes.

func WithDatabasePasswordRotation ¶

func WithDatabasePasswordRotation(s dbrotate.Store) Option

WithDatabasePasswordRotation enables database owner password rotation and its schedule. *store.DB satisfies s.

func WithDatabaseUpgrader ¶ added in v0.2.0

func WithDatabaseUpgrader(u DatabaseUpgrader) Option

WithDatabaseUpgrader enables the database upgrade routes; without it they return 501.

func WithDeleteTeardownTimeout ¶ added in v0.2.0

func WithDeleteTeardownTimeout(d time.Duration) Option

WithDeleteTeardownTimeout bounds how long DELETE /apps/{name} waits for containers to stop.

func WithDemoMode ¶

func WithDemoMode(cfg DemoConfig) Option

WithDemoMode puts the Router in read-only demo mode: default-deny write gate, read elevation for the visitor account, noindex headers and the demo routes.

func WithDeployApprovalTTL ¶ added in v0.2.0

func WithDeployApprovalTTL(d time.Duration) Option

WithDeployApprovalTTL overrides how long a pending deploy approval (deploy_approvals.go) stays decidable before it's treated as expired. Without one configured (or passed as 0), defaultDeployApprovalTTL (24 hours) applies. Same "no hardcoded thresholds, use env vars" shape as WithAuditLogRetention: this package never reads the environment directly, cmd/levelrail/main.go reads APP_DEPLOY_APPROVAL_TTL and passes the parsed duration here.

func WithDeployGate ¶ added in v0.2.0

func WithDeployGate(s DeployGateStore, defaults deploysafety.Effective) Option

WithDeployGate enables the gate timeline, deploy safety settings and rollback target endpoints, resolving settings over defaults.

func WithDeployLogQuerier ¶

func WithDeployLogQuerier(s DeployLogQuerier) Option

WithDeployLogQuerier enables a finished deploy attempt's full log replay on GET /api/v1/apps/{name}/deploys/{deployId}/logs. Without one configured (the default), that route returns 501 for an attempt that has already finished; an in-progress attempt's live tail is unaffected (see WithDeployRecorder). cmd/levelrail/main.go passes the same *telemetry.DB internal/deploylog.Recorder writes to.

func WithDeployMaxConcurrent ¶ added in v0.2.0

func WithDeployMaxConcurrent(n int) Option

WithDeployMaxConcurrent caps how many deploys run at once across all apps; deploys over the cap wait as queued. Zero or less means unlimited.

func WithDeployNotifier ¶

func WithDeployNotifier(n DeployNotifier) Option

WithDeployNotifier enables the actual send: without one configured (the default), a deploy attempt still finishes and is still recorded exactly as it is today, it just never dispatches a notification, even if WithDeployNotifyTargets has targets configured. Kept as a separate option from WithDeployNotifyTargets on purpose, the same "listing doesn't need a live runner" split WithBackupRunner/WithRestoreRunner already establish: a control plane can serve deploy-notify-target CRUD without necessarily having a dispatcher wired (e.g. in a test), and vice versa cmd/levelrail/main.go always wires both together from the same *alerting.DeployDispatcher, which itself embeds the *alerting.DB that WithDeployNotifyTargets is given.

func WithDeployNotifyTargets ¶

func WithDeployNotifyTargets(t DeployNotifyTargets) Option

WithDeployNotifyTargets enables POST/GET /api/v1/apps/{name}/deploy-notify-targets and DELETE .../deploy-notify-targets/{id}: CRUD for deploy-outcome notification destinations, the sibling surface to WithAlertRules for wave-2 deploy-outcome notifications. Without one configured (the default), all three routes return 501, the same "not configured" shape WithAlertRules' own absence produces.

func WithDeployRecorder ¶

func WithDeployRecorder(r *deploylog.Recorder) Option

WithDeployRecorder enables live build-log fan-out for the manual build trigger (handleTriggerBuild) and the in-progress side of GET /api/v1/apps/{name}/deploys/{deployId}/logs. Without one configured (the default), handleTriggerBuild falls back to build.SlogProgress (no persisted log, matching this package's pre-existing behavior) and the SSE log route returns 501 for any attempt still in progress. r must be the exact same *deploylog.Recorder instance passed to internal/webhook.New when a webhook handler is also wired: see that package's own doc comment for why a shared instance, not two independent ones, is required for a webhook-triggered attempt's live log to be visible through this router's SSE route.

func WithDeploySafety ¶ added in v0.2.0

func WithDeploySafety(s DeploySafetyStore, resolver docker.ImageResolver) Option

WithDeploySafety enables freeze windows, the stale-deploy guard and digest resolution for image deploys. resolver may be nil.

func WithDeviceLoginNotifier ¶ added in v0.2.0

func WithDeviceLoginNotifier(n DeviceLoginNotifier) Option

WithDeviceLoginNotifier enables the opt-in notice sent through channels with NotifyDeviceLogin when a CLI device login is waiting.

func WithDockerDiskUsager ¶

func WithDockerDiskUsager(u DockerDiskUsager) Option

WithDockerDiskUsager enables the docker_disk_usage field on GET /api/v1/system/status. Without one configured (the default), that field is simply omitted, the same "optional signal, absence is not an error" shape WithDockerPinger's own absence already has.

func WithDockerGuard ¶ added in v0.2.0

func WithDockerGuard(c DockerGuardController) Option

WithDockerGuard enables GET/PUT /api/v1/system/docker-guard, its doctor check and its attention item. Without it those report the guard as unknown.

func WithDockerPinger ¶

func WithDockerPinger(p DockerPinger) Option

WithDockerPinger enables Docker daemon connectivity reporting on GET /api/v1/system/status. Without one configured (the default), the response's DockerConnected field simply stays false, the same "optional signal, absence is not an error" shape WithDataDir and WithSecretSetter's own absence already have.

func WithDockerPruner ¶

func WithDockerPruner(p DockerPruner) Option

WithDockerPruner enables POST /api/v1/system/prune. Without one configured (the default), that route returns 501, the same "not configured" shape WithBuilder's own absence produces.

func WithDoctorAgentAdvertise ¶ added in v0.2.0

func WithDoctorAgentAdvertise(host string, port int) Option

WithDoctorAgentAdvertise tells the agent_advertise_reachability check which address a real agent would dial: APP_AGENT_ADVERTISE_HOST and the port cmd/levelrail/main.go's own agentAddr() binds the agent gRPC service on. Empty host or zero port makes that check report unknown.

func WithDoctorClockSkewWarnAge ¶ added in v0.2.0

func WithDoctorClockSkewWarnAge(d time.Duration) Option

WithDoctorClockSkewWarnAge overrides how far this host's clock may drift from the remote HTTP Date header the clock_skew check compares against before it warns. Zero keeps defaultDoctorClockSkewWarnAge.

func WithDoctorDiskIOWarnLatency ¶ added in v0.2.0

func WithDoctorDiskIOWarnLatency(d time.Duration) Option

WithDoctorDiskIOWarnLatency overrides the write+fsync latency the disk_io_latency check warns above, in place of defaultDoctorDiskIOWarnLatency. Zero keeps that default.

func WithDoctorDiskWarningBytes ¶

func WithDoctorDiskWarningBytes(n int64) Option

WithDoctorDiskWarningBytes overrides the free-space floor GET /api/v1/system/doctor's disk_space check warns below. Without one configured (or passed as 0), defaultDoctorDiskWarningBytes (1GiB) applies. Same "no hardcoded thresholds, use env vars" shape as WithCertExpiryWarningWindow: this package never reads the environment directly, cmd/levelrail/main.go reads APP_DOCTOR_DISK_WARNING_BYTES and passes the parsed value here.

func WithDoctorIngressPorts ¶ added in v0.2.0

func WithDoctorIngressPorts(httpPort, httpsPort int) Option

WithDoctorIngressPorts overrides the two ports GET /api/v1/system/ doctor's port_<n> checks probe, in place of the literal 80/443 defaultDoctorHTTPPort/defaultDoctorHTTPSPort ports. cmd/levelrail/ main.go passes the same APP_INGRESS_HTTP_ADDR/APP_INGRESS_HTTPS_ADDR- derived ports already threaded to ingressreconcile.WithHTTPListenAddr/ WithListenAddr, so doctor stays accurate for an instance running its ingress on non-default ports. Either argument being 0 keeps that port's own default.

func WithDoctorMasterKeyRotationWarnAge ¶

func WithDoctorMasterKeyRotationWarnAge(d time.Duration) Option

WithDoctorMasterKeyRotationWarnAge overrides the age GET /api/v1/system/doctor's master_key_rotation check warns beyond, the same env-var-overridable-threshold shape WithDoctorDiskWarningBytes already establishes for disk_space.

func WithDoctorMinCPUCount ¶ added in v0.2.0

func WithDoctorMinCPUCount(n int) Option

WithDoctorMinCPUCount overrides the recommended-minimum CPU core count the cpu check warns below. Zero keeps defaultDoctorMinCPUCount.

func WithDoctorMinRAMBytes ¶ added in v0.2.0

func WithDoctorMinRAMBytes(n int64) Option

WithDoctorMinRAMBytes overrides the recommended-minimum total memory the ram check warns below. Zero keeps defaultDoctorMinRAMBytes.

func WithDoctorNetworkTimeout ¶ added in v0.2.0

func WithDoctorNetworkTimeout(d time.Duration) Option

WithDoctorNetworkTimeout overrides the bounded overall timeout GET /api/v1/system/doctor's network checks (public_ip, external_reachability_*, acme_reachability, clock_skew) share, the same "no hardcoded thresholds" shape as WithDoctorDiskWarningBytes. Zero keeps defaultDoctorNetworkTimeout.

func WithDoctorPublicIPEndpoint ¶ added in v0.2.0

func WithDoctorPublicIPEndpoint(url string) Option

WithDoctorPublicIPEndpoint overrides the plain-text-IP endpoint the public_ip check queries, in place of defaultDoctorPublicIPEndpoint. Lets an operator behind an egress proxy, or one who simply distrusts a third-party default, point this at their own endpoint.

func WithDomainBasicAuthSecrets ¶

func WithDomainBasicAuthSecrets(s DomainBasicAuthSecrets) Option

WithDomainBasicAuthSecrets enables PUT/DELETE /api/v1/apps/{name}/domains/{domain}/auth. Without one configured (the default), both return 501; GET works regardless, the same shape WithCloudflareTunnelSecrets establishes.

func WithDomainTLSCertSecrets ¶

func WithDomainTLSCertSecrets(s DomainTLSCertSecrets) Option

WithDomainTLSCertSecrets enables PUT/DELETE /api/v1/apps/{name}/domains/{domain}/tls-cert. Without one configured (the default), both return 501; GET works regardless, the same shape WithDomainBasicAuthSecrets establishes.

func WithEmailSecrets ¶

func WithEmailSecrets(s EmailSecretsStore) Option

WithEmailSecrets enables PUT /api/v1/settings/email. Without one configured (the default), that route returns 501; GET works regardless.

func WithEmailSender ¶

func WithEmailSender(s email.Sender) Option

WithEmailSender enables the actual send behind POST /api/v1/auth/forgot-password. Without one, that route still returns its generic success response, it just never sends anything.

func WithErrorStore ¶

func WithErrorStore(s ErrorStore) Option

WithErrorStore turns on the Sentry-compatible receiver and the error routes.

func WithExecRuntime ¶

func WithExecRuntime(r NodeRuntimeResolver) Option

WithExecRuntime enables POST /apps/{name}/exec (exec.go's handleExecApp). Without one configured (the default), that route returns 501, the same "not configured" shape WithDockerPruner's absence produces: a control plane can run every other route with no resolver wired in, exec is the one action that needs live node routing (NodeRuntimeResolver's own doc comment).

func WithExposure ¶ added in v0.2.0

func WithExposure(m *exposure.Manager, s ExposureStore) Option

WithExposure enables the exposure audit and its guided restrictions. Without it, the exposure routes return 501 and the doctor group is absent.

func WithFirewallRequiredPorts ¶ added in v0.2.0

func WithFirewallRequiredPorts(ports []int) Option

WithFirewallRequiredPorts overrides the ports POST /api/v1/firewall-rules refuses to deny or CIDR-restrict, defaulting to firewall.DefaultRequiredPorts. Pass this instance's actually configured management API, agent gRPC, and ingress ports whenever any of them were moved off their default address: a lockout check against the wrong port number is no check at all.

func WithFixit ¶

func WithFixit(s FixitStore) Option

WithFixit enables the fix-it engine routes and the DB-backed advertise host.

func WithFunctionTriggers ¶

func WithFunctionTriggers(s FunctionTriggerStore, cfg functions.TriggerConfig, kick func()) Option

WithFunctionTriggers enables the signed webhook trigger and the async invocation queue of functions; kick wakes the queue worker when a call is enqueued. Without it the trigger routes return 501.

func WithGPUHostDiagnoser ¶ added in v0.2.0

func WithGPUHostDiagnoser(d GPUHostDiagnoser) Option

WithGPUHostDiagnoser adds the detailed host GPU checks to the doctor report. Without it the doctor shows only what nodes report.

func WithGitConnectionSecrets ¶

func WithGitConnectionSecrets(s GitConnSecrets) Option

WithGitConnectionSecrets enables the GitLab, Bitbucket and Gitea connection routes that read or write secrets. Without it they answer 501.

func WithGitHubAppManifestConfig ¶

func WithGitHubAppManifestConfig(cfg githubapp.ManifestConfig) Option

WithGitHubAppManifestConfig overrides the permissions/events a fresh App registration requests (githubapp.BuildManifest's own doc comment). Without one configured, NewRouter defaults to githubapp.DefaultManifestConfig(), the same request this codebase has always sent.

func WithGitHubAppSecrets ¶

func WithGitHubAppSecrets(s GitHubAppSecrets) Option

WithGitHubAppSecrets enables the GitHub App routes that read or write a credential (manifest callback, installation callback, repo/branch listing). Without one configured, those return 501; GET/DELETE /api/v1/github-app work regardless.

func WithGitSourceSecrets ¶

func WithGitSourceSecrets(s GitSourceSecrets) Option

WithGitSourceSecrets enables PUT /api/v1/apps/{name}/git-source and the git-push webhook route. Without one configured (the default), both return 501; listing/getting/deleting a git source works regardless, since neither needs to resolve a credential.

func WithGoLiveProviderDeps ¶

func WithGoLiveProviderDeps(d hostprovider.Deps) Option

WithGoLiveProviderDeps replaces how the cloud provider is detected, for tests.

func WithGoogleCloudDNSSecrets ¶

func WithGoogleCloudDNSSecrets(s GoogleCloudDNSSecrets) Option

WithGoogleCloudDNSSecrets enables PUT/DELETE /api/v1/settings/google-cloud-dns and lets the records, zones and domain automation paths read the key back.

func WithHSTS ¶ added in v0.2.0

func WithHSTS(enabled bool) Option

WithHSTS enables the Strict-Transport-Security response header. Without it (the default), Strict-Transport-Security is never sent, see Router.hstsEnabled's own doc comment for why that's the safe default.

func WithHTTPSEnableLimits ¶ added in v0.2.0

func WithHTTPSEnableLimits(maxPerHour int, pendingTimeout time.Duration) Option

WithHTTPSEnableLimits sets how many production enable attempts are allowed per hour (a guard against burning Let's Encrypt's failed-validation limit) and how long a certificate may stay pending before it is reported failed. Zero values keep the defaults.

func WithHostFirewallRunner ¶ added in v0.2.0

func WithHostFirewallRunner(run func(ctx context.Context, name string, args ...string) ([]byte, error), lookPath func(string) (string, error)) Option

WithHostFirewallRunner replaces how the host firewall endpoints run and find ufw, so tests never touch the real firewall.

func WithImageInventory ¶

func WithImageInventory(r ImageInventoryResolver) Option

WithImageInventory enables the /api/v1/images routes.

func WithImageLister ¶

func WithImageLister(l ImageLister) Option

WithImageLister enables GET /api/v1/apps/{name}/images. Without one configured (the default), that route returns an empty list rather than 501 or 404: the deploy trigger form's manual text input always works regardless, so a missing image lister is "no suggestions available" (an empty array), not a request error, the same "optional signal, absence is not an error" shape WithDockerPinger's own absence already has.

func WithImageVerify ¶

func WithImageVerify(pub *ecdsa.PublicKey, mode string) Option

WithImageVerify sets the public key signatures are checked against and the mode promotions run in. A nil key with ImageVerifyEnforce refuses every promotion, so callers only pass enforce together with a key.

func WithImageVerifyIssue ¶

func WithImageVerifyIssue(issue, requestedMode string) Option

WithImageVerifyIssue records a signature policy that could not be applied at boot, so Validate can say why.

func WithInbox ¶

func WithInbox(s InboxStore) Option

WithInbox enables the notification inbox routes.

func WithIngressPortOwner ¶ added in v0.2.0

func WithIngressPortOwner(o IngressPortOwner) Option

WithIngressPortOwner lets GET /api/v1/system/doctor's port_<n> checks recognize a bind failure caused by this control plane's own embedded ingress (internal/ingress.Driver) as expected rather than a real problem. Without one configured (the default), a bound port always reports fail, the same behavior this check had before ingress ownership was distinguishable.

func WithInviteTTL ¶

func WithInviteTTL(d time.Duration) Option

WithInviteTTL overrides how long a team invite stays acceptable before GetInviteByHash's expiry check rejects it. Without one configured (or passed as 0), defaultInviteTTL (7 days) applies. Same "no hardcoded thresholds, use env vars" shape as WithPreviewTTL: this package never reads the environment directly, cmd/levelrail/main.go reads APP_INVITE_TTL and passes the parsed duration here.

func WithJobLimits ¶ added in v0.2.0

func WithJobLimits(maxPerApp int) Option

WithJobLimits sets the per-app job count cap (APP_JOBS_MAX_PER_APP).

func WithLoadBalancers ¶ added in v0.2.0

func WithLoadBalancers(s LoadBalancerStore, registry *loadbalancer.Registry, stats loadbalancer.StatsSource) Option

WithLoadBalancers enables the /api/v1/apps/{name}/loadbalancer routes. registry and stats feed the live status route and may be nil.

func WithLogBroadcaster ¶

func WithLogBroadcaster(b *telemetry.LogBroadcaster) Option

WithLogBroadcaster enables GET /api/v1/apps/{name}/logs/stream, the live-tailing counterpart to WithTelemetryQuerier's historical GET .../logs. Without one configured (the default), that route returns 501, the same "not configured" shape WithDeployRecorder's absence produces for the in-progress side of a deploy attempt's log. Deliberately a separate option from WithTelemetryQuerier even though both are telemetry-flavored and cmd/levelrail/main.go always configures them together in practice: a control plane could in principle want historical log search without live tailing (or the reverse), and keeping them as two options leaves that possible instead of one silently implying the other. b must be the exact same *telemetry.LogBroadcaster instance passed to telemetry.NewLogCollector: see that constructor's own doc comment for why a shared instance, not two independent ones, is required for a line StreamOne receives from Docker to ever reach a viewer connected through this router's SSE route.

func WithLogBudgetStore ¶

func WithLogBudgetStore(s LogBudgetStore) Option

WithLogBudgetStore turns on the log budget and usage routes.

func WithLogPipelineStore ¶

func WithLogPipelineStore(s LogPipelineStore) Option

WithLogPipelineStore turns on the app log pipeline routes.

func WithLoginCodeKey ¶ added in v0.2.0

func WithLoginCodeKey(key []byte) Option

WithLoginCodeKey peppers stored sign-in code hashes with a key derived from the control plane's own secret, so a database copy alone cannot brute-force a live code.

func WithMajorUpgrader ¶ added in v0.2.0

func WithMajorUpgrader(u MajorUpgrader) Option

WithMajorUpgrader enables the major upgrade routes; without it they return 501.

func WithMasterKeyRotation ¶

func WithMasterKeyRotation(r MasterKeyRotator, masterKeyFilePath string) Option

WithMasterKeyRotation enables POST /api/v1/system/master-key/rotate and the doctor's rotation-age check. masterKeyFilePath should be the on-disk path the running control plane loaded its master key from, or "" if it came from APP_MASTER_KEY instead: see MasterKeyRotator's own doc comment for what that distinction changes about a rotation's response. Without this option configured (the default), the route returns 501, the same shape WithSecretSetter's own absence produces.

func WithMasterKeyWrapper ¶

func WithMasterKeyWrapper(w secrets.KeyWrapper) Option

WithMasterKeyWrapper makes rotation persist the new key wrapped by the external key service.

func WithMeshSettings ¶ added in v0.2.0

func WithMeshSettings(s MeshSettingsStore) Option

WithMeshSettings enables GET/PUT /api/v1/mesh/settings.

func WithMinAgentVersion ¶ added in v0.2.0

func WithMinAgentVersion(v string) Option

WithMinAgentVersion flags nodes whose agent reports an older version. Empty disables the check.

func WithModels ¶ added in v0.2.0

func WithModels(s ModelService) Option

WithModels enables the /api/v1/models routes. Without it they return 501.

func WithMultiNode ¶ added in v0.2.0

func WithMultiNode(s PlacementStore, cfg nodemove.Config, meshPortMin, meshPortMax int) Option

WithMultiNode enables persisted node moves, drains, labels and selectors. Without it those routes return 501 and drain keeps no history.

func WithMySQLPITRRestoreRunner ¶

func WithMySQLPITRRestoreRunner(r MySQLPITRRestoreRunner) Option

WithMySQLPITRRestoreRunner enables point-in-time restore for MySQL and MariaDB, which restores into a new database instead of overwriting the source.

func WithNetworkShareSecrets ¶ added in v0.2.0

func WithNetworkShareSecrets(s NetworkShareSecretsSetter) Option

WithNetworkShareSecrets enables POST/PUT /api/v1/network-shares for a cifs share. Without one configured (the default), those return 501; GET, DELETE, and an nfs share's create/update work regardless, the same shape WithRegistryCredentialSecrets establishes.

func WithNewDeviceApproval ¶ added in v0.2.0

func WithNewDeviceApproval(on bool) Option

WithNewDeviceApproval pauses a password login from an untrusted browser until another live session of the account approves it.

func WithNodeAlertThresholds ¶

func WithNodeAlertThresholds(patchStatus, nodeDiskSpace, nodeCPU, nodeMemory float64) Option

WithNodeAlertThresholds sets the thresholds GET /api/v1/nodes/{id} uses for its live alert_status section, the same values cmd/levelrail/main.go already resolves (from APP_ALERT_PATCH_STATUS_THRESHOLD, APP_ALERT_NODE_DISK_SPACE_THRESHOLD_PERCENT, APP_ALERT_NODE_CPU_THRESHOLD_PERCENT, APP_ALERT_NODE_MEMORY_THRESHOLD_BYTES) and passes to alerting.NewEngine, so a rule's scheduled evaluation and a node's on-demand check never disagree.

func WithNodeCertDrillTimeout ¶

func WithNodeCertDrillTimeout(d time.Duration) Option

WithNodeCertDrillTimeout sets how long a certificate rotation drill waits for the new certificate.

func WithNodeCertThresholds ¶ added in v0.2.0

func WithNodeCertThresholds(warning, critical time.Duration) Option

WithNodeCertThresholds sets when a node's agent certificate is reported as expiring (warning) and critical. Zero keeps the alerting defaults.

func WithNodeFailure ¶

func WithNodeFailure(s nodefailure.Store, cfg nodefailure.Config) Option

WithNodeFailure enables the node failure policy controller and its routes.

func WithNodeJoinTokenTTL ¶ added in v0.2.0

func WithNodeJoinTokenTTL(d time.Duration) Option

WithNodeJoinTokenTTL sets how long a dashboard or CLI join token stays redeemable, clamped to [1m, 24h]. Zero keeps the 15 minute default.

func WithNodeProviderSecrets ¶ added in v0.2.0

func WithNodeProviderSecrets(s NodeProviderSecrets) Option

WithNodeProviderSecrets enables POST /api/v1/node-providers and every node-providers/{provider}/... route. Without it (the default), those routes return 501, the same shape WithCloudflareDNSSecrets establishes for its own credential.

func WithNodeProvisionerFactory ¶ added in v0.2.0

func WithNodeProvisionerFactory(f NodeProvisionerFactory) Option

WithNodeProvisionerFactory overrides how a NodeProvisioner is built from a provider name and resolved token, for this package's own tests. Production callers leave this unset; NewRouter's default, defaultNodeProvisionerFactory, builds real internal/provision clients.

func WithNodeProvisions ¶ added in v0.2.0

func WithNodeProvisions(s NodeProvisionStore) Option

WithNodeProvisions overrides the node provision store NewRouter otherwise wires to s (the *store.DB passed to NewRouter, which satisfies NodeProvisionStore structurally). This package's own tests use it to inject a store that fails a specific call, for the half-succeeded-write path handleCreateNodeProvision must handle.

func WithNodeSessionCloser ¶ added in v0.2.0

func WithNodeSessionCloser(c NodeSessionCloser) Option

WithNodeSessionCloser lets certificate revocation close the node's live session immediately.

func WithNodeTrustControl ¶

func WithNodeTrustControl(c NodeTrustControl) Option

WithNodeTrustControl wires renew-now and operator security events.

func WithNotificationChannelTester ¶

func WithNotificationChannelTester(t NotificationChannelTester) Option

WithNotificationChannelTester enables the test-send routes: a real send, not just a format check. Without one, they return 501.

func WithNotificationChannels ¶

func WithNotificationChannels(c NotificationChannels) Option

WithNotificationChannels enables the notification-channel CRUD routes. Without one configured (the default), they return 501.

func WithNotificationDeliveries ¶

func WithNotificationDeliveries(d NotificationDeliveryStore) Option

WithNotificationDeliveries enables the delivery-history route and records a delivery row for every existing-channel test-send. Without one, the deliveries route returns 501 and test-send simply skips recording.

func WithOAuthSecrets ¶

func WithOAuthSecrets(s OAuthSecrets) Option

WithOAuthSecrets enables OAuth sign-in end to end. Without one configured (the default), those routes return 501, the same "not configured" shape WithSecretSetter's absence produces.

func WithOrphanedContainerManager ¶ added in v0.2.0

func WithOrphanedContainerManager(m OrphanedContainerManager) Option

WithOrphanedContainerManager enables POST /api/v1/system/containers/{name}/stop and .../remove. Without one configured (the default), both routes return 501, the same "not configured" shape WithOrphanedVolumeManager's absence produces.

func WithOrphanedVolumeManager ¶ added in v0.2.0

func WithOrphanedVolumeManager(m OrphanedVolumeManager) Option

WithOrphanedVolumeManager enables GET /api/v1/system/volumes/orphaned and POST /api/v1/system/volumes/orphaned/cleanup. Without one configured (the default), both routes return 501, the same "not configured" shape WithDockerPruner's absence produces.

func WithPITRRestoreRunner ¶ added in v0.2.0

func WithPITRRestoreRunner(r PITRRestoreRunner) Option

WithPITRRestoreRunner enables POST /api/v1/databases/{name}/pitr-restore and GET /api/v1/databases/{name}/pitr's own live window computation. Without one configured (the default), the restore route returns 501 and the status route reports enabled/enabled_at only, no window: the same "not configured" shape WithRestoreRunner's absence produces.

func WithPipelines ¶ added in v0.2.0

func WithPipelines(st PipelineStore, runner PipelineRunner) Option

WithPipelines enables the pipeline endpoints. runner may be nil, in which case definitions can be edited but starting, cancelling, and re-running return 501.

func WithPlacementPolicy ¶

func WithPlacementPolicy(p placement.Policy) Option

WithPlacementPolicy sets the overcommit and headroom policy placement applies.

func WithPreviewLimits ¶ added in v0.2.0

func WithPreviewLimits(l PreviewLimits) Option

WithPreviewLimits sets the per-app and global preview caps (cmd/levelrail reads APP_PREVIEW_ENV_MAX_PER_APP and APP_PREVIEW_ENV_MAX_TOTAL).

func WithPreviewStuckAfter ¶ added in v0.2.0

func WithPreviewStuckAfter(d time.Duration) Option

WithPreviewStuckAfter sets how long a preview may stay in deploying before the startup sweep marks it failed. Zero keeps the default.

func WithPreviewTTL ¶

func WithPreviewTTL(d time.Duration) Option

WithPreviewTTL overrides how long a preview environment can go without a webhook update before SweepStalePreviewEnvironments tears it down. Without one configured (or passed as 0), defaultPreviewTTL (7 days) applies. Same "no hardcoded thresholds, use env vars" shape as WithCertExpiryWarningWindow: this package never reads the environment directly, cmd/levelrail/main.go reads APP_PREVIEW_TTL and passes the parsed duration here.

func WithPrivateNetworks ¶

func WithPrivateNetworks(cfg PrivateNetworkConfig) Option

WithPrivateNetworks enables the private network routes (501 without it).

func WithPublicHost ¶

func WithPublicHost(host string) Option

WithPublicHost sets the IP or hostname GET /api/v1/apps/{name}/domains/{domain}/check tells an operator to point their DNS record at (domain_check.go's advertisedHost). Without one configured (the default), that handler falls back to a best-effort guess from the request's own Host header instead of failing: this package never reads the environment directly, cmd/levelrail/main.go reads APP_PUBLIC_HOST and passes it here, the same shape WithCertExpiryWarningWindow already follows for its own env var.

func WithPublicHostSource ¶ added in v0.2.0

func WithPublicHostSource(source string) Option

WithPublicHostSource records how the public host was found ("env", "detected", "disabled" or "none"), shown on the ingress settings page.

func WithPublishLocks ¶

func WithPublishLocks(s PublishLockStore) Option

WithPublishLocks enables per-app publish locks: pushes and hooks keep building but are held until an operator publishes them.

func WithPushVAPIDPublicKey ¶ added in v0.2.0

func WithPushVAPIDPublicKey(publicKey string) Option

WithPushVAPIDPublicKey enables browser push notifications: GET .../push-subscriptions/vapid-public-key returns publicKey, and POST .../push-subscriptions accepts new registrations. Without one configured (the default, no master key set), both return 501: the VAPID private key half can only ever be stored through secretsManager.

func WithReadinessProbes ¶ added in v0.2.0

func WithReadinessProbes(p ReadinessProbes) Option

WithReadinessProbes enables the database, migration and engine checks on GET /readyz.

func WithReconcileNudger ¶ added in v0.2.0

func WithReconcileNudger(n ReconcileNudger) Option

WithReconcileNudger lets desired-state-changing handlers (app/database create, stop, start, restart, delete) request an immediate reconcile pass right after they save, instead of every such action waiting up to a full resyncInterval to visibly take effect. Without one configured (the default), those handlers still work exactly as before: the resync ticker and Docker's own event stream are what converge desired and observed state regardless.

func WithRegistryAuthTester ¶

func WithRegistryAuthTester(t RegistryAuthTester) Option

WithRegistryAuthTester enables POST /api/v1/registry-credentials/{id}/test. Without one configured (the default), that route returns 501, the same shape WithDockerPinger's own absence produces for GET /api/v1/system/status.

func WithRegistryCatalogSecrets ¶ added in v0.2.0

func WithRegistryCatalogSecrets(s RegistryCatalogSecrets) Option

WithRegistryCatalogSecrets enables GET /api/v1/registry/repositories and GET /api/v1/registry/tags. Without one configured (the default), both return 501, the same shape WithRegistrySecrets establishes.

func WithRegistryCredentialSecrets ¶

func WithRegistryCredentialSecrets(s RegistryCredentialSecretsSetter) Option

WithRegistryCredentialSecrets enables POST /api/v1/registry-credentials. Without one configured (the default), that route returns 501; GET and DELETE work regardless, the same shape WithBackupSecrets establishes.

func WithRegistryRefresher ¶

func WithRegistryRefresher(r RegistryTokenRefresher) Option

WithRegistryRefresher enables the ECR, Artifact Registry and ACR presets. Without it those requests return 501.

func WithRegistrySecrets ¶

func WithRegistrySecrets(s RegistrySecrets) Option

WithRegistrySecrets enables PUT/DELETE /api/v1/settings/registry. Without one configured (the default), both return 501; GET works regardless, the same shape WithCloudflareTunnelSecrets establishes.

func WithReleaseSchemaSource ¶

func WithReleaseSchemaSource(f ReleaseSchemaFetcher) Option

WithReleaseSchemaSource turns on the pre-click schema compatibility check.

func WithRequestLogThresholds ¶ added in v0.2.0

func WithRequestLogThresholds(slow, critical time.Duration) Option

WithRequestLogThresholds sets requestLoggingMiddleware's Warn/Error duration bands. Either argument <= 0 keeps that band's own default. cmd/levelrail/main.go resolves APP_SLOW_REQUEST_THRESHOLD/ APP_CRITICAL_REQUEST_THRESHOLD and calls this unconditionally, the same "no hardcoded thresholds" convention WithSessionTTL's own doc comment establishes.

func WithRequestSummaryWindow ¶ added in v0.2.0

func WithRequestSummaryWindow(d time.Duration) Option

WithRequestSummaryWindow sets the lookback of the request summary attached to GET /api/v1/apps/{name}; non-positive keeps the 5 minute default.

func WithResourceRecommendationLookback ¶

func WithResourceRecommendationLookback(d time.Duration) Option

WithResourceRecommendationLookback overrides how far back GET /api/v1/apps/{name}/resource-recommendation looks for usage history (handleAppResourceRecommendation). Without one configured (or passed as 0), defaultResourceRecommendationLookback (7 days) applies. Same "no hardcoded thresholds, use env vars" shape as WithSessionTTL/ WithCertExpiryWarningWindow: this package never reads the environment directly, cmd/levelrail/main.go reads APP_RESOURCE_RECOMMENDATION_LOOKBACK and passes the parsed duration here.

func WithRestoreRunner ¶

func WithRestoreRunner(r RestoreRunner) Option

WithRestoreRunner enables POST /api/v1/databases/{name}/restore. Without one configured (the default), that route returns 501, the same "not configured" shape WithBackupRunner's absence produces; listing restore history (GET .../restores) works regardless, the same "listing needs no live runner" reasoning WithBackupRunner's own doc comment gives for backup history.

func WithRoute53DNSCredentialResolver ¶ added in v0.2.0

func WithRoute53DNSCredentialResolver(r Route53DNSCredentialResolver) Option

WithRoute53DNSCredentialResolver is the same shape as WithCloudflareDNSTokenResolver for the Route53 access key pair.

func WithRoute53DNSSecrets ¶ added in v0.2.0

func WithRoute53DNSSecrets(s Route53DNSSecrets) Option

WithRoute53DNSSecrets enables PUT/DELETE /api/v1/settings/route53-dns. Without one configured (the default), both return 501; GET works regardless, the same shape WithCloudflareDNSSecrets establishes for its own, independent ACME DNS-01 provider.

func WithSSHNodeProvisions ¶ added in v0.2.0

func WithSSHNodeProvisions(s SSHNodeProvisionStore) Option

WithSSHNodeProvisions overrides the SSH node provision store NewRouter otherwise wires to s (the *store.DB passed to NewRouter, which satisfies SSHNodeProvisionStore structurally), the same "seam for a failing fake" shape WithNodeProvisions establishes for the cloud path.

func WithSSHProvisioner ¶ added in v0.2.0

func WithSSHProvisioner(p SSHProvisioner) Option

WithSSHProvisioner overrides the SSH provisioner NewRouter otherwise defaults to (sshprovision.New()), for this package's own tests: a fake that never dials a real network.

func WithScheduledTaskRunner ¶

func WithScheduledTaskRunner(r ScheduledTaskRunner) Option

WithScheduledTaskRunner enables POST /api/v1/apps/{name}/scheduled-tasks/{id}/run. Without one configured (the default), that route returns 501: scheduled task CRUD still works either way (rt.scheduledTasks is always set), only actually running one on demand needs this. r should be the exact same *scheduledtask.Runner instance cmd/levelrail/main.go wires into scheduledtask.NewScheduler, the same "construct once, share by reference" reasoning WithBackupRunner's own doc comment gives for backupRunner.

func WithSecretBinding ¶ added in v0.2.0

func WithSecretBinding(b SecretBinder) Option

WithSecretBinding enables GET /api/v1/system/secrets/binding, POST /api/v1/system/secrets/rebind, the doctor's secret_binding check, and the automatic rebind after a master key rotation.

func WithSecretRotationWarnAge ¶ added in v0.2.0

func WithSecretRotationWarnAge(d time.Duration) Option

WithSecretRotationWarnAge overrides how old a secret's last-set value can get before it is flagged as due for rotation (GET /apps/{name}/secrets, GET .../env/all, and the doctor's stale_secrets check). Without one configured (or passed as 0), defaultSecretRotationWarnAge (90 days) applies. Same "no hardcoded thresholds, use env vars" shape as WithAuditLogRetention: this package never reads the environment directly, cmd/levelrail/main.go reads APP_SECRET_ROTATION_WARN_DAYS and passes the parsed duration here.

func WithSecretSetter ¶

func WithSecretSetter(s SecretSetter) Option

WithSecretSetter enables PUT /api/v1/apps/{name}/secrets/{key}. Without one configured (the default), that route returns 501: an operator running Levelrail without APP_MASTER_KEY set gets a clear "not configured" response instead of the route not existing at all or silently discarding the value.

func WithSelfUpgrade ¶ added in v0.2.0

func WithSelfUpgrade(s SelfUpgradeStore, launch SelfUpgradeLauncher) Option

WithSelfUpgrade enables the self-upgrade plan, start and attempts routes. launch may be nil to use systemd-run on a root host.

func WithServerProfile ¶

func WithServerProfile(s ServerProfileStore) Option

WithServerProfile enables GET/PUT /api/v1/settings/server-profile.

func WithServiceVolumeBackupRunner ¶

func WithServiceVolumeBackupRunner(r ServiceVolumeBackupRunner) Option

WithServiceVolumeBackupRunner enables POST /api/v1/apps/{name}/volumes/{volume}/backups. Without one configured (the default), that route returns 501, the same "not configured" shape WithBackupRunner's absence produces; listing history and reading the schedule work regardless, the same "no live runner needed" reasoning WithBackupRunner's own doc comment gives.

func WithServiceVolumeRestoreRunner ¶

func WithServiceVolumeRestoreRunner(r ServiceVolumeRestoreRunner) Option

WithServiceVolumeRestoreRunner enables POST /api/v1/apps/{name}/volumes/{volume}/restore. Without one configured (the default), that route returns 501, the same "not configured" shape WithRestoreRunner's absence produces.

func WithSessionTTL ¶

func WithSessionTTL(d time.Duration) Option

WithSessionTTL overrides how long a session cookie stays valid. Without one configured, defaultSessionTTL (24h) applies. The project's "no hardcoded thresholds, use env vars" rule is honored one layer up, at cmd/levelrail/main.go, which reads APP_SESSION_TTL and passes the parsed duration here; this package itself never reads the environment directly (NewRouter takes everything as constructor args, matching every other option here).

func WithSourceCache ¶

func WithSourceCache(c *sourcecache.Cache) Option

WithSourceCache sets the mirror every git fetch goes through. Without it each fetch is a throwaway clone with the same timeouts and retries.

func WithStaleSecretCounter ¶ added in v0.2.0

func WithStaleSecretCounter(c StaleSecretCounter) Option

WithStaleSecretCounter enables the stale_secrets check on GET /api/v1/system/doctor. Without one configured (the default), that check reports unknown, the same "optional signal, absence is not an error" shape WithDBPinger's own absence already has.

func WithStandaloneSafety ¶ added in v0.2.0

func WithStandaloneSafety(s StandaloneSafety) Option

WithStandaloneSafety sets the control and ingress ports standalone domain targets are checked against.

func WithStaticOrphanGrace ¶

func WithStaticOrphanGrace(d time.Duration) Option

WithStaticOrphanGrace sets how old an orphaned static site must be before the sweep removes it. Zero keeps the default.

func WithStaticRootDir ¶

func WithStaticRootDir(dir string) Option

WithStaticRootDir sets the directory static deploys publish under, so a rollback can find a past deploy's tree again.

func WithStatusPage ¶ added in v0.2.0

func WithStatusPage(db StatusPageDB, cfg statuspage.Config, perMinute int) Option

WithStatusPage enables the status page management routes, the public page and the health sampler (see RunStatusPageSampler). perMinute is the per-client-IP budget on public reads.

func WithStatusPageViewer ¶ added in v0.2.0

func WithStatusPageViewer(st StatusPageStore, v StatusPageViewer, perMinute int) Option

WithStatusPageViewer wires a custom view builder, for tests.

func WithStorage ¶ added in v0.2.0

func WithStorage(d StorageDeps) Option

WithStorage enables the /api/v1/storage and /api/v1/log-archive routes. Without it they return 501.

func WithTelemetryQuerier ¶

func WithTelemetryQuerier(q TelemetryQuerier) Option

WithTelemetryQuerier enables GET /api/v1/apps/{name}/metrics and GET /api/v1/apps/{name}/logs. Without one configured, both routes return 501, the same "not configured" shape WithSecretSetter's absence produces, rather than the routes not existing at all or panicking on a nil dereference.

func WithTokenRedeemRateLimit ¶ added in v0.2.0

func WithTokenRedeemRateLimit(perMinute int) Option

WithTokenRedeemRateLimit enables a per-client-IP budget on the unauthenticated POST /api/v1/auth/reset-password and POST /api/v1/invites/accept routes. perMinute <= 0 disables it.

func WithTraceStore ¶

func WithTraceStore(s TraceStore) Option

WithTraceStore turns on the OTLP receiver and the trace routes.

func WithTrafficExport ¶

func WithTrafficExport(secrets TrafficExportSecrets, exporter TrafficExporter) Option

WithTrafficExport enables sink writes (secrets) and the status and test routes. Either argument may be nil: writes then return 501, as do status and test.

func WithTrustRoot ¶

func WithTrustRoot(p TrustRootProbe) Option

WithTrustRoot sets the probe the update preflight uses for release signature verification.

func WithUpgradeHistory ¶ added in v0.2.0

func WithUpgradeHistory(s UpgradeHistoryStore) Option

WithUpgradeHistory enables GET /api/v1/updates/history and the ack route. Without one the history is empty and acknowledging answers 501.

func WithUpgradeScheduling ¶ added in v0.2.0

func WithUpgradeScheduling(s UpgradeScheduleStore, sender dbupgrade.NoticeSender, cfg upgradesched.Config) Option

WithUpgradeScheduling enables scheduled and automatic upgrades. sender delivers the alerts (the deploy dispatcher), nil keeps them in the log.

func WithVaultSecrets ¶ added in v0.2.0

func WithVaultSecrets(s VaultSecrets) Option

WithVaultSecrets enables PUT/DELETE /api/v1/settings/vault. Without one configured (the default), both return 501; GET works regardless, the same shape WithCloudflareTunnelSecrets establishes.

func WithVolumeCloneRestoreRunner ¶

func WithVolumeCloneRestoreRunner(r VolumeCloneRestoreRunner) Option

WithVolumeCloneRestoreRunner enables POST /api/v1/apps/{name}/volumes/{volume}/restore-as-new. Without one configured (the default), that route returns 501, the same "not configured" shape WithServiceVolumeRestoreRunner's absence produces; listing clone-restore history (GET .../clone-restores) works regardless, the same "listing needs no live runner" reasoning WithCloneRestoreRunner's own doc comment gives.

func WithWakeToken ¶ added in v0.2.0

func WithWakeToken(token string) Option

WithWakeToken sets the secret the ingress wake route presents to the control plane. Without one, the wake hook answers 404 for everyone.

func WithWebhookDeliveryRetention ¶ added in v0.2.0

func WithWebhookDeliveryRetention(d time.Duration) Option

WithWebhookDeliveryRetention overrides how long a webhook_deliveries row survives before PurgeOldWebhookDeliveries removes it. Without one configured (or passed as 0), defaultWebhookDeliveryRetention (30 days) applies. Same "no hardcoded thresholds, use env vars" shape as WithAuditLogRetention: this package never reads the environment directly, cmd/levelrail/main.go reads APP_WEBHOOK_DELIVERY_RETENTION_DAYS and passes the parsed duration here.

func WithWebhookFailedDeliveryLimits ¶ added in v0.3.0

func WithWebhookFailedDeliveryLimits(keep, bodyBytes int) Option

WithWebhookFailedDeliveryLimits sets how many unsigned webhook deliveries are kept per app and how many body bytes each retains. A zero value keeps the default (20 rows, 2048 bytes). cmd/levelrail/main.go reads APP_WEBHOOK_FAILED_DELIVERY_KEEP and APP_WEBHOOK_FAILED_BODY_BYTES.

func WithWebhookRateLimit ¶ added in v0.2.0

func WithWebhookRateLimit(perMinute int) Option

WithWebhookRateLimit enables a per-(client IP, app name) budget on POST /api/v1/webhooks/github/{name} (git_webhook.go), checked before that route's DB lookup, secret resolution, and delivery-history write: a request rejected here never reaches any of that work. perMinute <= 0 disables it, the same "nil is valid" shape WithAPIRateLimit's own absence establishes; without this option (the default), the route is unthrottled. cmd/levelrail/main.go reads APP_WEBHOOK_RATE_LIMIT_RPM and calls this unconditionally with its resolved (env-or-default) value, so the real control plane is always protected even when an operator never sets the env var.

type OrganizationStore ¶

type OrganizationStore interface {
	SaveOrganization(ctx context.Context, o store.Organization) error
	GetOrganization(ctx context.Context, id string) (store.Organization, error)
	ListOrganizations(ctx context.Context) ([]store.Organization, error)
	DeleteOrganization(ctx context.Context, id string) error
	SetProjectOrganization(ctx context.Context, projectID, orgID string) error
	// SetOrganizationEnvVars/ListOrganizationEnvVars back GET/PUT
	// /api/v1/organizations/{id}/env (organization_env.go): shared env
	// vars every project filed under this organization inherits as the
	// base layer beneath its own project_env_vars tier
	// (internal/reconcile/application's resolveEnv), full-replace on
	// write, mirroring ProjectStore's SetProjectEnvVars/ListProjectEnvVars
	// one level up.
	SetOrganizationEnvVars(ctx context.Context, orgID string, vars map[string]string) error
	ListOrganizationEnvVars(ctx context.Context, orgID string) (map[string]string, error)
	// ListOrganizationEnvVarsDetailed/SetOrganizationSecretEnvVar/
	// DeleteOrganizationSecretEnvVar/ListOrganizationSecretEnvKeys back
	// GET /api/v1/organizations/{id}/env/all and the secret-var
	// sub-resource routes (organization_env.go), mirroring ProjectStore's
	// own secret-capable extension one tier down.
	ListOrganizationEnvVarsDetailed(ctx context.Context, orgID string) ([]store.SharedEnvVar, error)
	SetOrganizationSecretEnvVar(ctx context.Context, orgID, key string) error
	DeleteOrganizationSecretEnvVar(ctx context.Context, orgID, key string) error
	ListOrganizationSecretEnvKeys(ctx context.Context, orgID string) ([]string, error)
}

OrganizationStore is the store surface the organizations handlers need.

type OrphanSweepResult ¶ added in v0.2.0

type OrphanSweepResult struct {
	StuckDeploys     int
	OrphanedServices int
}

OrphanSweepResult counts what SweepOrphanPreviews repaired.

type OrphanedContainerManager ¶ added in v0.2.0

type OrphanedContainerManager interface {
	Stop(ctx context.Context, id string, timeout time.Duration) error
	Remove(ctx context.Context, id string, force bool) error
}

OrphanedContainerManager stops or removes one container by ID. Every calling route first re-confirms the container is orphaned (isManagedContainer), never trusting a client flag. *docker.Client satisfies it.

type OrphanedVolumeManager ¶ added in v0.2.0

type OrphanedVolumeManager interface {
	ListNamedVolumes(ctx context.Context) ([]docker.NamedVolume, error)
	RemoveVolume(ctx context.Context, name string) error
}

OrphanedVolumeManager lists this instance's named volumes and removes one by name. This package decides which are orphaned; internal/docker stays store-agnostic. *docker.Client satisfies it.

type PITRRestoreHistoryStore ¶ added in v0.2.0

type PITRRestoreHistoryStore interface {
	ListPITRRestoreHistory(ctx context.Context, databaseName string) ([]store.PITRRestoreHistory, error)
}

PITRRestoreHistoryStore is the store surface the PITR restore history handler needs.

type PITRRestoreRunner ¶ added in v0.2.0

type PITRRestoreRunner interface {
	// WindowBounds returns the same information *backup.PITRRunner.Window
	// does, destructured into plain values instead of that method's own
	// PITRWindow struct: an interface method's return type must be
	// identical across a package boundary, and internal/api never
	// imports internal/backup's types directly (databaseContainerName's
	// own doc comment describes this boundary), so a struct return here
	// would need its own separately-declared, ever-so-slightly duplicate
	// type for no real benefit over returning the three values plain.
	WindowBounds(ctx context.Context, databaseName, containerName string) (hasBaseBackup bool, start, end time.Time, err error)
	ValidateTarget(ctx context.Context, databaseName, containerName string, target time.Time) error
	RunPITRRestore(ctx context.Context, historyID, databaseName, containerName, dataVolumeName, baseBackupHistoryID string, targetTime time.Time) error
}

PITRRestoreRunner is the surface the PITR restore endpoints need from internal/backup.PITRRunner: compute the currently recoverable window, validate a target timestamp against it, and run one restore attempt end to end. *backup.PITRRunner satisfies this structurally, the same boundary BaseBackupRunner above describes.

type PackageRegistryStore ¶

type PackageRegistryStore interface {
	SavePackageRegistry(ctx context.Context, p store.PackageRegistry) error
	GetPackageRegistry(ctx context.Context, id string) (store.PackageRegistry, error)
	ListPackageRegistries(ctx context.Context) ([]store.PackageRegistry, error)
	DeletePackageRegistry(ctx context.Context, id string) error
	ListServicesUsingRegistryCredential(ctx context.Context, credentialID string) ([]string, error)
}

PackageRegistryStore is the store surface the package registry and registry credential usage handlers need.

type PipelineArtifactFiles ¶

type PipelineArtifactFiles interface {
	Open(meta store.PipelineArtifact) (*os.File, error)
}

PipelineArtifactFiles opens a stored artifact after verifying its sha256. *pipeline.ArtifactStore satisfies it.

type PipelineEvents ¶ added in v0.2.0

type PipelineEvents interface {
	TriggerEvent(ctx context.Context, app string, ev pipeline.Event, ref, sha, actor string) []store.PipelineRun
}

PipelineEvents starts runs of every matching pipeline for a git event. *pipeline.Engine satisfies it.

type PipelineExtraStore ¶

type PipelineExtraStore interface {
	GetPipeline(ctx context.Context, id string) (store.Pipeline, error)
	ListPipelineArtifacts(ctx context.Context, runID string) ([]store.PipelineArtifact, error)
	GetPipelineArtifact(ctx context.Context, id string) (store.PipelineArtifact, error)
	GetPipelineWebhookTrigger(ctx context.Context, pipelineID string) (store.PipelineWebhookTrigger, error)
	SavePipelineWebhookTrigger(ctx context.Context, t store.PipelineWebhookTrigger) error
	DeletePipelineWebhookTrigger(ctx context.Context, pipelineID string) error
	TouchPipelineWebhookTrigger(ctx context.Context, pipelineID string, at time.Time) error
	AddPipelineWebhookDelivery(ctx context.Context, d store.PipelineWebhookDelivery) (store.PipelineWebhookDelivery, error)
	FinishPipelineWebhookDelivery(ctx context.Context, id, outcome, reason, runID string, status int) error
	GetPipelineWebhookDelivery(ctx context.Context, pipelineID, id string) (store.PipelineWebhookDelivery, error)
	ListPipelineWebhookDeliveries(ctx context.Context, pipelineID string, limit int) ([]store.PipelineWebhookDelivery, error)
	PrunePipelineWebhookDeliveries(ctx context.Context, pipelineID string, keep int) error
}

PipelineExtraStore is the store surface for artifacts and inbound webhook triggers. *store.DB satisfies it; WithPipelines picks it up from the main pipeline store when that store implements it.

type PipelineOverviewStore ¶ added in v0.2.0

type PipelineOverviewStore interface {
	ListPipelineRunRows(ctx context.Context, f store.PipelineRunFilter) ([]store.PipelineRunRow, error)
	PipelineAppCounts(ctx context.Context, since time.Time) ([]store.PipelineAppCounts, error)
}

PipelineOverviewStore is the cross-app read surface behind the Pipelines overview. *store.DB satisfies it.

type PipelineRunner ¶ added in v0.2.0

type PipelineRunner interface {
	Start(ctx context.Context, p store.Pipeline, opt pipeline.StartOptions) (store.PipelineRun, error)
	Cancel(ctx context.Context, runID string) error
	Rerun(ctx context.Context, runID, actor string) (store.PipelineRun, error)
	// DecideHold releases or rejects a run held for approval.
	DecideHold(ctx context.Context, runID string, approved bool, by string) (bool, error)
	Nudge()
}

PipelineRunner starts, cancels, and re-runs pipeline runs. *pipeline.Engine satisfies it.

type PipelineStore ¶ added in v0.2.0

type PipelineStore interface {
	SavePipeline(ctx context.Context, p store.Pipeline) (store.Pipeline, error)
	GetPipelineByName(ctx context.Context, app, name string) (store.Pipeline, error)
	ListPipelines(ctx context.Context, app string) ([]store.Pipeline, error)
	DeletePipeline(ctx context.Context, id string) error
	ListPipelineRuns(ctx context.Context, app, pipelineID string, limit int) ([]store.PipelineRun, error)
	GetPipelineRun(ctx context.Context, id string) (store.PipelineRun, error)
	ListPipelineJobs(ctx context.Context, runID string) ([]store.PipelineJob, error)
	ListPipelineLogs(ctx context.Context, runID, jobKey string, afterID int64, limit int) ([]store.PipelineLogLine, error)
	ListPipelineStepLogs(ctx context.Context, runID, jobKey string, step *int, afterID int64, limit int) ([]store.PipelineLogLine, error)
	ListPipelineApprovals(ctx context.Context, runID string) ([]store.PipelineApproval, error)
	DecidePipelineApproval(ctx context.Context, id int64, decision, by, comment string, now time.Time) (bool, error)
	ListPipelineTriggerLog(ctx context.Context, app string, limit int) ([]store.PipelineTriggerLog, error)
}

PipelineStore is the store surface the pipeline handlers need.

type PipelineSyncStore ¶ added in v0.2.0

type PipelineSyncStore interface {
	GetPipelineSync(ctx context.Context, app string) (store.PipelineSync, error)
	SavePipelineSync(ctx context.Context, s store.PipelineSync) error
}

PipelineSyncStore holds the per-app sync settings. *store.DB satisfies it.

type PipelineSyncer ¶ added in v0.2.0

type PipelineSyncer interface {
	Sync(ctx context.Context, app string) (pipeline.SyncResult, error)
	SyncOnPush(ctx context.Context, app, ref, sha string) (pipeline.SyncResult, bool, error)
}

PipelineSyncer copies an app's repository pipeline files into its saved definitions. *pipeline.Syncer satisfies it.

type PlacementDecisionStore ¶

type PlacementDecisionStore interface {
	SavePlacementDecision(ctx context.Context, d store.PlacementDecision) error
	GetPlacementDecision(ctx context.Context, kind, resource string) (store.PlacementDecision, bool, error)
}

PlacementDecisionStore persists the latest placement decision per resource.

type PlacementStore ¶ added in v0.2.0

type PlacementStore interface {
	nodemove.Store
	ListNodeLabels(ctx context.Context) (map[string]map[string]string, error)
	GetNodeLabels(ctx context.Context, nodeID string) (map[string]string, error)
	SetNodeLabels(ctx context.Context, nodeID string, labels map[string]string) error
	GetPlacementSelector(ctx context.Context, kind, resource string) (map[string]string, error)
	SetPlacementSelector(ctx context.Context, kind, resource string, selector map[string]string) error
	EnsureDatabaseMeshPort(ctx context.Context, name string, minPort, maxPort int) (int, error)
}

PlacementStore is the persistence multi-node placement needs; *store.DB satisfies it.

type PluginAuditor ¶

type PluginAuditor struct{ DB *store.DB }

PluginAuditor writes plugin audit events into the audit log.

func (PluginAuditor) Record ¶

Record implements plugin.Auditor.

type PolicyStore ¶

type PolicyStore interface {
	SavePolicy(ctx context.Context, p store.Policy) error
	UpdatePolicy(ctx context.Context, id, name, description, document string) error
	GetPolicy(ctx context.Context, id string) (*store.Policy, error)
	ListPolicies(ctx context.Context) ([]store.Policy, error)
	DeletePolicy(ctx context.Context, id string) error
	AttachPolicy(ctx context.Context, id, policyID, principalType, principalID string) error
	DetachPolicy(ctx context.Context, policyID, principalType, principalID string) error
	ListPoliciesForPrincipal(ctx context.Context, principalType, principalID string) ([]store.Policy, error)
	ListAttachmentsForPolicy(ctx context.Context, policyID string) ([]store.PolicyAttachment, error)
}

PolicyStore is the store surface the IAM policy handlers need, defined here next to the handlers that use it, the same "single-file feature" shape OnboardingStore/AuditStore already use rather than every store interface living in store_interfaces.go.

type PreviewEnvironmentStore ¶

type PreviewEnvironmentStore interface {
	SavePreviewEnvironment(ctx context.Context, p store.PreviewEnvironment) error
	UpdatePreviewEnvironment(ctx context.Context, p store.PreviewEnvironment) error
	GetPreviewEnvironmentByAppAndPR(ctx context.Context, appName string, prNumber int) (*store.PreviewEnvironment, error)
	ListPreviewEnvironmentsByApp(ctx context.Context, appName string) ([]store.PreviewEnvironment, error)
	DeletePreviewEnvironment(ctx context.Context, id string) error
	ListStalePreviewEnvironments(ctx context.Context, cutoff time.Time) ([]store.PreviewEnvironment, error)
	ListPreviewEnvironments(ctx context.Context) ([]store.PreviewEnvironment, error)
	SetPreviewEnvironmentCommentID(ctx context.Context, id string, commentID int64) error
	SetPreviewEnvironmentExtendedUntil(ctx context.Context, id, until string) error
	GetPreviewAppSettings(ctx context.Context, appName string) (store.PreviewAppSettings, error)
	ListPreviewAppSettings(ctx context.Context) (map[string]store.PreviewAppSettings, error)
	SavePreviewAppSettings(ctx context.Context, s store.PreviewAppSettings) error

	// The PR env override methods back per-pull-request env overrides
	// (preview_pr_env.go), removed with the preview.
	SetPRPreviewEnvOverride(ctx context.Context, serviceName string, prNumber int, key, value string, secret bool) (string, error)
	ListPRPreviewEnvOverrides(ctx context.Context, serviceName string, prNumber int) ([]store.PRPreviewEnvOverride, error)
	DeletePRPreviewEnvOverride(ctx context.Context, serviceName string, prNumber int, id string) error
	DeleteAllPRPreviewEnvOverrides(ctx context.Context, serviceName string, prNumber int) error
	AddPreviewPendingVolumes(ctx context.Context, previewAppID string, names []string) error
	ListPreviewPendingVolumes(ctx context.Context, previewAppID string) ([]string, error)
	ClearPreviewPendingVolumes(ctx context.Context, previewAppID string) error

	// SavePreviewEphemeralDatabase through DeletePreviewEphemeralDatabase
	// back the ephemeralInPreviews lifecycle
	// (preview_environments_databases.go): provisioning a preview-scoped
	// database instance, listing them for the API's own status surface,
	// and tearing them down alongside the preview that owns them.
	SavePreviewEphemeralDatabase(ctx context.Context, p store.PreviewEphemeralDatabase) error
	GetPreviewEphemeralDatabaseByPreviewAndKey(ctx context.Context, previewEnvironmentID, sourceKey string) (*store.PreviewEphemeralDatabase, error)
	ListPreviewEphemeralDatabasesByPreview(ctx context.Context, previewEnvironmentID string) ([]store.PreviewEphemeralDatabase, error)
	UpdatePreviewEphemeralDatabaseStatus(ctx context.Context, id, status, statusReason, updatedAt string) error
	DeletePreviewEphemeralDatabase(ctx context.Context, id string) error

	// SavePreviewDatabaseIsolation through DeletePreviewDatabaseIsolation
	// back the isolatedInPreviews lifecycle
	// (preview_environments_database_isolation.go): an isolated Postgres
	// role on an existing database, one per (preview, sourceKey).
	SavePreviewDatabaseIsolation(ctx context.Context, p store.PreviewDatabaseIsolation) error
	GetPreviewDatabaseIsolationByPreviewAndKey(ctx context.Context, previewEnvironmentID, sourceKey string) (*store.PreviewDatabaseIsolation, error)
	ListPreviewDatabaseIsolationsByPreview(ctx context.Context, previewEnvironmentID string) ([]store.PreviewDatabaseIsolation, error)
	UpdatePreviewDatabaseIsolationStatus(ctx context.Context, id, status, statusReason, updatedAt string) error
	DeletePreviewDatabaseIsolation(ctx context.Context, id string) error
}

PreviewEnvironmentStore is the store surface preview environment webhook handling and its HTTP routes (preview_environments_handlers.go) need. *store.DB satisfies this structurally.

type PreviewLimits ¶ added in v0.2.0

type PreviewLimits struct {
	MaxPerApp int
	MaxTotal  int
}

PreviewLimits caps simultaneous live preview environments. Zero means unlimited for that scope.

type PreviewService ¶ added in v0.2.0

type PreviewService interface {
	Config() preview.Config
	Settings(ctx context.Context, app string) (preview.AppSettings, error)
	SaveSettings(ctx context.Context, app string, patch preview.SettingsPatch) (preview.AppSettings, error)
	List(ctx context.Context, app string) ([]preview.Record, error)
	OpenImage(ctx context.Context, app, deploymentID string) (string, preview.Record, error)
	Capture(ctx context.Context, app string) error
	Prune(ctx context.Context, app string, all bool) (preview.PruneResult, error)
	Status(ctx context.Context, app string) (preview.Summary, error)
	DeleteApp(ctx context.Context, app string) error
}

PreviewService is the deploy preview surface; *preview.Manager satisfies it.

type PrivateNetworkConfig ¶

type PrivateNetworkConfig struct {
	Store    PrivateNetworkStore
	Enforcer reconcile.Controller
	// Containers lists local containers for observed connectivity; nil skips it.
	Containers func(ctx context.Context) ([]docker.ContainerState, error)
	Prefix     string
	// Nodes resolves an app's node ID; nil treats every app as local.
	Nodes func(ctx context.Context) (map[string]string, error)
}

PrivateNetworkConfig wires the private network feature into the router.

type PrivateNetworkStore ¶

type PrivateNetworkStore interface {
	privnet.Source
	SavePrivateNetwork(ctx context.Context, n store.PrivateNetwork) error
	UpdatePrivateNetwork(ctx context.Context, id string, defaultDeny bool, members []string) error
	DeletePrivateNetwork(ctx context.Context, id string) error
	SavePrivateNetworkRule(ctx context.Context, r store.PrivateNetworkRule) error
	DeletePrivateNetworkRule(ctx context.Context, id string) error
}

PrivateNetworkStore is the store surface the private network handlers need.

type ProbeAttemptStore ¶ added in v0.2.0

type ProbeAttemptStore interface {
	ListProbeAttempts(ctx context.Context, deployID string) ([]store.ProbeAttempt, error)
}

ProbeAttemptStore is the store surface GET /api/v1/apps/{name}/deploys/{deployId}/probes needs: the individual readiness-probe attempts (migrations/0284_probe_attempts.sql, internal/probe.WithOnAttempt) one deploy attempt's cutover made. *store.DB satisfies this structurally.

type ProjectStore ¶

type ProjectStore interface {
	SaveProject(ctx context.Context, p store.Project) error
	GetProject(ctx context.Context, id string) (store.Project, error)
	ListProjects(ctx context.Context) ([]store.Project, error)
	DeleteProject(ctx context.Context, id string) error
	// SetProjectEnvVars/ListProjectEnvVars back GET/PUT
	// /api/v1/projects/{id}/env (project_env.go): shared env vars every
	// app filed under this project inherits as its resolveEnv base
	// layer (internal/reconcile/application), full-replace on write, the
	// same shape PUT /api/v1/apps/{name}'s own env field already has.
	SetProjectEnvVars(ctx context.Context, projectID string, vars map[string]string) error
	ListProjectEnvVars(ctx context.Context, projectID string) (map[string]string, error)
	// ListProjectEnvVarsDetailed/SetProjectSecretEnvVar/
	// DeleteProjectSecretEnvVar/ListProjectSecretEnvKeys back GET
	// /api/v1/projects/{id}/env/all and the secret-var sub-resource
	// routes (project_env.go): the secret-capable extension of the
	// plain-only pair above, reusing internal/secrets.Manager (via
	// Router.secrets) for the actual encryption rather than a second
	// path.
	ListProjectEnvVarsDetailed(ctx context.Context, projectID string) ([]store.SharedEnvVar, error)
	SetProjectSecretEnvVar(ctx context.Context, projectID, key string) error
	DeleteProjectSecretEnvVar(ctx context.Context, projectID, key string) error
	ListProjectSecretEnvKeys(ctx context.Context, projectID string) ([]string, error)
}

ProjectStore is the store surface the projects handlers need (projects.go). See that file's own package doc comment for why a project is deliberately not the start of the deferred Phase 4 teams/ RBAC work (repo-plan section 6's own scope note): no owner, no member list, no per-project ability, just create/list/get/delete.

type ProxyIntegrationStore ¶ added in v0.2.0

type ProxyIntegrationStore interface {
	GetProxyIntegrationSettings(ctx context.Context) (store.ProxyIntegrationSettings, error)
	UpdateProxyIntegrationSettings(ctx context.Context, s store.ProxyIntegrationSettings) error
	ListProxyRouteStatus(ctx context.Context) ([]store.ProxyRouteStatus, error)
	SaveProxyRouteVerification(ctx context.Context, s store.ProxyRouteStatus) error
}

ProxyIntegrationStore is the persistence the proxy integration routes need beyond what the syncer reads.

type PublishLockStore ¶

type PublishLockStore interface {
	GetPublishLock(ctx context.Context, name string) (*store.PublishLock, error)
	SetPublishLock(ctx context.Context, l store.PublishLock) (store.PublishLock, error)
	ClearPublishLock(ctx context.Context, name string) (bool, error)
	ListHeldBuildIDs(ctx context.Context, name string) (map[string]bool, error)
	GetHeldBuild(ctx context.Context, deployID string) (*store.DesiredService, error)
	MarkHeldBuildPublished(ctx context.Context, deployID, by string, at time.Time) error
}

PublishLockStore is the store surface for per-app publish locks and the builds they hold. *store.DB satisfies this structurally.

type PushSubscriptions ¶ added in v0.2.0

type PushSubscriptions interface {
	SavePushSubscription(ctx context.Context, s store.PushSubscription) error
	ListPushSubscriptionsForUser(ctx context.Context, userID string) ([]store.PushSubscription, error)
	DeletePushSubscription(ctx context.Context, id, userID string) error
}

PushSubscriptions is the store surface the handlers below need. *store.DB satisfies this structurally.

type ReadinessProbes ¶ added in v0.2.0

type ReadinessProbes struct {
	Database      func(ctx context.Context) error
	Migrations    func(ctx context.Context) error
	EngineStarted func() bool
}

ReadinessProbes are the cheap checks GET /readyz runs. A nil probe is skipped.

type ReconcileNudger ¶ added in v0.2.0

type ReconcileNudger interface {
	Nudge()
}

ReconcileNudger is *reconcile.Engine's own Nudge method, narrowed the same consumer-defined way DockerPinger is above: a handler that just changed desired state calls it to request an immediate reconcile pass instead of leaving an operator watching a create/stop/start/restart take up to a full resyncInterval (default 30s) to visibly do anything. Reconcile's own idempotent, level-triggered contract is what makes an extra, unscheduled pass always safe.

type RegistryAuthTester ¶

type RegistryAuthTester interface {
	TestRegistryAuth(ctx context.Context, host, username, password string) error
}

RegistryAuthTester asks the local Docker daemon to authenticate against a registry without pulling. Kept off docker.Runtime to avoid rippling into its fakes. *docker.Client satisfies it.

type RegistryCatalogClient ¶ added in v0.2.0

type RegistryCatalogClient interface {
	ListRepositories(ctx context.Context, baseURL, username, password string) ([]string, error)
	ListTags(ctx context.Context, baseURL, username, password, repository string) ([]string, error)
}

RegistryCatalogClient is the surface GET /api/v1/registry/repositories, GET /api/v1/registry/tags, and the registry-credential browse routes below need: query a Docker Registry HTTP API v2 server's catalog (_catalog, <name>/tags/list) over Basic Auth. The same client serves both Levelrail's own built-in registry (baseURL fixed to its loopback address) and an operator's stored external credential (baseURL taken from that credential's RegistryHost), since the protocol is identical either way. *registrycatalog.Client satisfies this structurally.

type RegistryCatalogSecrets ¶ added in v0.2.0

type RegistryCatalogSecrets interface {
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
}

RegistryCatalogSecrets is the surface the catalog handlers need from internal/secrets.Manager: resolve the built-in registry's generated password to authenticate the catalog query server-side. Never echoed back to the caller, the same boundary RegistryCredentialSecretsSetter.Resolve already draws for handleTestRegistryCredential.

type RegistryCredentialSecretsSetter ¶

type RegistryCredentialSecretsSetter interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
}

RegistryCredentialSecretsSetter is the surface registry credential create/update/test/browse needs from internal/secrets.Manager. Resolve is used by handleTestRegistryCredential and the two credential browse handlers in registry_catalog.go, to authenticate against the real registry on the operator's behalf; it is never used to echo a password back in an HTTP response, the same boundary GitSourceSecrets already draws for its own Resolve use.

type RegistryCredentialStore ¶

type RegistryCredentialStore interface {
	SaveRegistryCredential(ctx context.Context, c store.RegistryCredential) error
	GetRegistryCredential(ctx context.Context, id string) (store.RegistryCredential, error)
	GetRegistryCredentialByName(ctx context.Context, name string) (store.RegistryCredential, error)
	ListRegistryCredentials(ctx context.Context) ([]store.RegistryCredential, error)
	UpdateRegistryCredential(ctx context.Context, id, name, registryHost, username string, expiresAt *time.Time) error
	DeleteRegistryCredential(ctx context.Context, id string) error
}

RegistryCredentialStore is the store surface the registry credential handlers need.

type RegistrySecrets ¶

type RegistrySecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	DeleteAll(ctx context.Context, serviceName string) error
}

RegistrySecrets is the surface the built-in registry settings handlers need from internal/secrets.Manager: set the generated password (first enable), check whether one exists, and clear it (disable). *secrets.Manager satisfies this structurally, the same "narrow, consumer-defined interface" shape CloudflareTunnelSecrets already establishes.

type RegistryStore ¶

type RegistryStore interface {
	GetRegistrySettings(ctx context.Context) (store.RegistrySettings, error)
	UpdateRegistrySettings(ctx context.Context, s store.RegistrySettings) error
}

RegistryStore is the store surface GET/PUT/DELETE /api/v1/settings/registry need: the single platform-wide row, always present, the same shape CloudflareTunnelStore has for its own row.

type RegistryTokenRefresher ¶

type RegistryTokenRefresher interface {
	Preview(ctx context.Context, preset string, cfg registrytoken.Config) (registrytoken.Minted, error)
	Refresh(ctx context.Context, id string) (store.RegistryCredential, error)
	NextRefresh(now, expires time.Time) time.Time
	Tick(ctx context.Context) error
	Interval() time.Duration
}

RegistryTokenRefresher mints and renews cloud registry logins; *registrytoken.Refresher satisfies it.

type ReleaseSchemaFetcher ¶

type ReleaseSchemaFetcher func(ctx context.Context, tag string) (selfupgrade.SchemaResult, error)

ReleaseSchemaFetcher returns the verified schema version a release tag supports.

func NewReleaseSchemaFetcher ¶

func NewReleaseSchemaFetcher(dataDir string, trust TrustRootProbe) ReleaseSchemaFetcher

NewReleaseSchemaFetcher builds the production fetcher: release manifest, signed checksums and bundle from the project's GitHub releases only.

type ResourceConsoleStore ¶

type ResourceConsoleStore interface {
	AttachResourceTag(ctx context.Context, tagID string, ref store.ResourceRef) error
	DetachResourceTag(ctx context.Context, tagID string, ref store.ResourceRef) error
	ListAllResourceTags(ctx context.Context) (map[string][]store.Tag, error)
	SaveResourceView(ctx context.Context, v store.ResourceView) error
	ListResourceViews(ctx context.Context, owner string) ([]store.ResourceView, error)
	DeleteResourceView(ctx context.Context, owner, id string) error
}

ResourceConsoleStore is the tag and saved-view surface the resource console needs beyond TagStore.

type Restarter ¶ added in v0.2.0

type Restarter struct {
	Supervised bool
	Trigger    func()
}

Restarter lets the HTTP layer ask the process to exit so its supervisor relaunches it. Supervised is false when nothing would bring it back.

func (Restarter) Supported ¶ added in v0.2.0

func (r Restarter) Supported() bool

Supported reports whether a supervisor will relaunch the process.

type RestoreHistoryStore ¶

type RestoreHistoryStore interface {
	ListRestoreHistory(ctx context.Context, databaseName string) ([]store.RestoreHistory, error)
}

RestoreHistoryStore is the store surface the restore history handler needs.

type RestoreRunner ¶

type RestoreRunner interface {
	RunRestore(ctx context.Context, historyID, databaseName, backupHistoryID, engine, containerName string) error
}

RestoreRunner is the surface the restore trigger handler needs from internal/backup.RestoreRunner: run one restore attempt end to end, from an already-minted history ID through to a finished store.RestoreHistory row. *backup.RestoreRunner satisfies this structurally; internal/api never imports internal/backup directly, the same boundary BackupRunner's own doc comment describes.

type Role ¶

type Role struct {
	Name        string   `json:"name"`
	Description string   `json:"description"`
	Abilities   []string `json:"abilities"`
	ID          string   `json:"id,omitempty"`
	Visibility  string   `json:"visibility,omitempty"`
	Builtin     bool     `json:"builtin"`
	UserCount   int      `json:"user_count"`
}

Role is a curated, named preset over the raw ability list (abilities.go): picking one sets a user's Abilities to exactly this set in one action, instead of hand-picking abilities individually. It is a convenience layer, not a second permission model: every existing ability check still only ever sees the resolved Abilities.

type RoleStore ¶ added in v0.2.0

type RoleStore interface {
	ListRoles(ctx context.Context) ([]store.Role, error)
	GetRole(ctx context.Context, id string) (store.Role, error)
	CreateRole(ctx context.Context, r store.Role) error
	UpdateRole(ctx context.Context, r store.Role) error
	DeleteRole(ctx context.Context, id string) error
	RoleUserCounts(ctx context.Context) (map[string]int, error)
	UserRoleID(ctx context.Context, userID string) (string, error)
	SetUserRole(ctx context.Context, userID, roleID string) error
	ListUserEnvironmentGrants(ctx context.Context, userID string) ([]string, error)
	SetUserEnvironmentGrants(ctx context.Context, userID string, environmentIDs []string) error
	CountRootUsersExcept(ctx context.Context, userID string) (int, error)
	CountRootUsersOutsideRole(ctx context.Context, roleID string) (int, error)
	SyncRoleAbilities(ctx context.Context, roleID string) error
	UpdateRoleAndSync(ctx context.Context, r store.Role) error
}

RoleStore is the store surface the stored-role, role-assignment and environment-grant routes need.

type Route53DNSCredentialResolver ¶ added in v0.2.0

type Route53DNSCredentialResolver interface {
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
}

Route53DNSCredentialResolver is the same shape as CloudflareDNSTokenResolver for the Route53 access key pair.

type Route53DNSSecrets ¶ added in v0.2.0

type Route53DNSSecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	DeleteAll(ctx context.Context, serviceName string) error
}

Route53DNSSecrets is the surface the Route53 DNS-01 settings handlers need from internal/secrets.Manager, the same shape CloudflareDNSSecrets already establishes for a distinct credential shape: an AWS IAM access key pair instead of a single API token.

type Route53DNSStore ¶ added in v0.2.0

type Route53DNSStore interface {
	GetRoute53DNSSettings(ctx context.Context) (store.Route53DNSSettings, error)
	UpdateRoute53DNSSettings(ctx context.Context, s store.Route53DNSSettings) error
}

Route53DNSStore is the store surface GET/PUT /api/v1/settings/route53-dns need, the same "single platform-wide row" shape CloudflareDNSStore already establishes for a distinct ACME DNS-01 provider.

type Router ¶

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

Router wires every internal/api handler onto one http.Handler.

func NewRouter ¶

func NewRouter(logger *slog.Logger, b *brand.Brand, s Store, opts ...Option) *Router

NewRouter builds a Router. logger defaults to slog.Default() if nil.

func (*Router) AppReadyAfter ¶

func (rt *Router) AppReadyAfter(ctx context.Context, name string, since time.Time) bool

AppReadyAfter reports whether name's application controller recorded a Ready condition after since; port wake uses it to know a woken app is up.

func (*Router) AutoscaleTick ¶

func (rt *Router) AutoscaleTick(ctx context.Context)

AutoscaleTick is the scheduler entry point for the autoscale controller.

func (*Router) BeginShutdown ¶

func (rt *Router) BeginShutdown() int

BeginShutdown stops new queued deploys from starting and ends every live SSE stream so http.Server.Shutdown does not wait on them. Safe to call twice.

func (*Router) BudgetStatuses ¶ added in v0.2.0

func (rt *Router) BudgetStatuses(ctx context.Context) ([]usagecost.BudgetStatus, error)

BudgetStatuses returns every budget's month to date position, for the budget_threshold alert rule.

func (*Router) CanaryActions ¶

func (rt *Router) CanaryActions() canary.Actions

CanaryActions returns the side effects the canary reconciler applies on a decision: a promote through the normal deploy path, or a rollback that records why and removes the canary.

func (*Router) CheckDomainStatus ¶

func (rt *Router) CheckDomainStatus(ctx context.Context, domain string) (string, error)

CheckDomainStatus exposes runDomainCheck to alerting's domain_health rule, using only APP_PUBLIC_HOST since engine ticks have no Host header.

func (*Router) CheckImageUpdate ¶ added in v0.2.0

func (rt *Router) CheckImageUpdate(ctx context.Context, serviceName string) (string, error)

CheckImageUpdate compares serviceName's tag against its registry and redeploys when the digest moved. Skips (with a reason, not an error) apps built from source, stopped, frozen, or in a protected environment: an unattended pull must never bypass the gates a manual deploy goes through.

func (*Router) CleanupUploads ¶

func (rt *Router) CleanupUploads(ctx context.Context)

CleanupUploads removes stored uploads older than the retention window.

func (*Router) ComplianceSecuritySnapshot ¶

func (rt *Router) ComplianceSecuritySnapshot(ctx context.Context) (any, error)

ComplianceSecuritySnapshot is the evidence pack's settings source: the stored policy, the live posture checks and the effective retention.

func (*Router) ComplianceUserRemover ¶

func (rt *Router) ComplianceUserRemover() compliance.UserRemover

ComplianceUserRemover removes an account with the same guards as the users API: never yourself, never the last user, never the last root.

func (*Router) CostBudgetBreaches ¶

func (rt *Router) CostBudgetBreaches(ctx context.Context) ([]costbudget.Breach, error)

CostBudgetBreaches feeds the budget_threshold alert rule with the highest threshold each budget fired this period.

func (*Router) CostBudgetTick ¶

func (rt *Router) CostBudgetTick(ctx context.Context)

CostBudgetTick is the scheduler entry point: it derives every budget's state from current spend, so a restart or a missed tick changes nothing.

func (*Router) DatabaseConnections ¶

func (rt *Router) DatabaseConnections(ctx context.Context, name string) (used, limit int, err error)

DatabaseConnections implements alerting.DatabaseHealthSource.

func (*Router) DatabaseDiskUsedPercent ¶

func (rt *Router) DatabaseDiskUsedPercent(ctx context.Context, name string) (float64, error)

DatabaseDiskUsedPercent implements alerting.DatabaseHealthSource.

func (*Router) DatabaseUp ¶

func (rt *Router) DatabaseUp(ctx context.Context, name string) (bool, error)

DatabaseUp implements alerting.DatabaseLivenessSource from the container's own state: a running container is up, a stopped or exited one is down. A suspended database, a missing runtime or an unreadable container reads as unavailable so the rule goes quiet instead of guessing.

func (*Router) DemoStats ¶

func (rt *Router) DemoStats() DemoStats

DemoStats returns a copy of the demo counters, or the zero value outside demo mode.

func (*Router) DeployURLHost ¶

func (rt *Router) DeployURLHost(ctx context.Context, serviceName string) string

DeployURLHost is the hostname a retained deploy service is served on: one label under the apps base domain, else the sslip fallback for the public IP.

func (*Router) DrainDeployQueue ¶ added in v0.2.0

func (rt *Router) DrainDeployQueue(ctx context.Context)

DrainDeployQueue starts every queued deploy that is no longer blocked. It runs after each deploy finishes and on a timer, so a queue survives restarts.

func (*Router) GitSourceCloneToken ¶ added in v0.2.0

func (rt *Router) GitSourceCloneToken(ctx context.Context, name, repoURL string) string

GitSourceCloneToken resolves the clone credential for a git source's own repository for in-process callers outside this package (the pipeline engine's repo reads and builds): name's stored deploy token, else the connected GitHub App's installation token. repoURL must be the stored git source URL, never a request-supplied value, since this mints a live installation token. Empty when neither exists.

func (*Router) Handler ¶

func (rt *Router) Handler() http.Handler

Handler builds the *http.ServeMux with every route registered. Called once at startup; the returned handler is what gets wrapped in an *http.Server. Registration is split per domain across routes_core_*.go and routes_platform_*.go purely to keep each file readable.

func (*Router) LoadEdgeFirewall ¶

func (rt *Router) LoadEdgeFirewall(ctx context.Context) error

LoadEdgeFirewall installs the stored rules and settings into the running engine; call it once at startup.

func (*Router) NewJanitor ¶

func (rt *Router) NewJanitor(db janitor.Store, dk janitor.Docker) *janitor.Engine

NewJanitor builds the cleanup engine over this router's stores and attaches it, so the API, the disk Fix button and the reconcile loop share one engine.

func (*Router) NudgeReconciler ¶

func (rt *Router) NudgeReconciler()

NudgeReconciler asks for a prompt reconcile pass, for background jobs that change routing state outside a request.

func (*Router) NudgeReconcilers ¶

func (rt *Router) NudgeReconcilers()

NudgeReconcilers asks the reconcilers to run now.

func (*Router) PipelineRunEnv ¶ added in v0.2.0

func (rt *Router) PipelineRunEnv(ctx context.Context, run store.PipelineRun) map[string]string

PipelineRunEnv gives a pull request pipeline run the PREVIEW_PR_NUMBER, PREVIEW_BRANCH and PREVIEW_URL of the live preview built from its branch. Other runs, and runs with no live preview, get nothing.

func (*Router) PipelineStatusReporter ¶ added in v0.2.0

func (rt *Router) PipelineStatusReporter() pipeline.StatusReporter

PipelineStatusReporter returns the reporter that posts pipeline run state to the git forge hosting an app's repository.

func (*Router) PurgeOldAuditEntries ¶

func (rt *Router) PurgeOldAuditEntries(ctx context.Context) (int64, error)

PurgeOldAuditEntries deletes every audit_log row older than effectiveAuditLogRetention, returning how many rows were removed.

func (*Router) PurgeOldWebhookDeliveries ¶ added in v0.2.0

func (rt *Router) PurgeOldWebhookDeliveries(ctx context.Context) (int64, error)

PurgeOldWebhookDeliveries deletes every webhook_deliveries row older than effectiveWebhookDeliveryRetention, returning how many rows were removed.

func (*Router) RecordRevoked ¶ added in v0.2.0

func (rt *Router) RecordRevoked(ctx context.Context, c dbaccess.TempCredential)

RecordRevoked implements dbaccess.SweepAuditor: the sweeper's own audit row.

func (*Router) ReleaseHandlers ¶ added in v0.2.0

func (rt *Router) ReleaseHandlers() map[string]deploy.ReleaseHandler

ReleaseHandlers replays held deploys; cmd/levelrail wires them into a deploy.Releaser.

func (*Router) RemoveDeployURLService ¶

func (rt *Router) RemoveDeployURLService(ctx context.Context, serviceName string) error

RemoveDeployURLService deletes a retained deploy service and tears its containers down. A teardown that is still pending is retried by the reconciler.

func (*Router) ResumeCutoverRuns ¶ added in v0.2.0

func (rt *Router) ResumeCutoverRuns(ctx context.Context)

ResumeCutoverRuns continues or rolls back cutover runs a restart interrupted. Call it once after the router is built.

func (*Router) ResumeTakeover ¶

func (rt *Router) ResumeTakeover(ctx context.Context)

ResumeTakeover finishes a takeover or rollback a restart interrupted. It blocks until that work ends, so call it in a goroutine after the router is built.

func (*Router) RetryDatabaseTeardowns ¶

func (rt *Router) RetryDatabaseTeardowns(ctx context.Context) error

RetryDatabaseTeardowns reruns every pending teardown. Safe to call repeatedly: a finished job is gone, a failed one stays.

func (*Router) RevokeTemp ¶ added in v0.2.0

func (rt *Router) RevokeTemp(ctx context.Context, name, role string) error

RevokeTemp implements dbaccess.Revoker for the expiry sweeper. A database that no longer exists has nothing left to revoke.

func (*Router) RunArchiveSweeper ¶

func (rt *Router) RunArchiveSweeper(ctx context.Context, interval time.Duration) error

RunArchiveSweeper applies the archive policy on interval until ctx is done. While the policy is off it holds no timer and waits for the policy to be saved.

func (*Router) RunArchives ¶

func (rt *Router) RunArchives(ctx context.Context, manual bool) (archive.RunResult, error)

RunArchives applies the archive policy once. A scheduled call does nothing while the policy is disabled; a manual one always runs.

func (*Router) RunAuditLogSweeper ¶

func (rt *Router) RunAuditLogSweeper(ctx context.Context, interval time.Duration) error

RunAuditLogSweeper calls PurgeOldAuditEntries on interval until ctx is done, the same ticker shape RunPreviewSweeper already establishes.

func (*Router) RunCertWatchdog ¶

func (rt *Router) RunCertWatchdog(ctx context.Context)

RunCertWatchdog retries stuck or failing certificate renewals with backoff until ctx ends.

func (*Router) RunDatabasePasswordRotation ¶

func (rt *Router) RunDatabasePasswordRotation(ctx context.Context, interval time.Duration) error

RunDatabasePasswordRotation settles interrupted rotations and runs scheduled ones until ctx ends. It returns nil at once when rotation is not wired.

func (*Router) RunDeployApprovalExpirySweep ¶ added in v0.2.0

func (rt *Router) RunDeployApprovalExpirySweep(ctx context.Context, interval time.Duration) error

RunDeployApprovalExpirySweep calls expireIfStale-style cleanup across every pending approval on interval until ctx is done, the same ticker shape RunAuditLogSweeper (audit_retention.go) already establishes. The lazy per-request expiry in expireIfStale already guarantees a stale request never proceeds; this sweep only matters for a pending row no one ever looks at again, so its own status reflects reality in the UI without waiting for a read that may never come.

func (*Router) RunDeviceLoginExpirySweeper ¶ added in v0.2.0

func (rt *Router) RunDeviceLoginExpirySweeper(ctx context.Context) error

RunDeviceLoginExpirySweeper sweeps once at start, so expiries that passed while the server was down are audited, then on every interval tick.

func (*Router) RunGateSweeper ¶ added in v0.2.0

func (rt *Router) RunGateSweeper(ctx context.Context, interval time.Duration) error

RunGateSweeper prunes old gate events and expired tokens and sessions on interval until ctx is done.

func (*Router) RunGitHostWatch ¶

func (rt *Router) RunGitHostWatch(ctx context.Context)

RunGitHostWatch re-probes failing git hosts until ctx ends and replays the newest push that was waiting on each app once its host answers.

func (*Router) RunGitPoller ¶

func (rt *Router) RunGitPoller(ctx context.Context)

RunGitPoller periodically compares each git source's remote branch head with what it last saw and queues a deploy when a webhook was missed. It returns when ctx is cancelled. Builds never run here: a missed head is queued like a webhook push and the deploy queue runs it.

func (*Router) RunMailQueue ¶

func (rt *Router) RunMailQueue(ctx context.Context)

RunMailQueue starts scheduled broadcasts when due and resumes interrupted ones, until ctx ends. A no-op without a mail store.

func (*Router) RunNodeFailure ¶

func (rt *Router) RunNodeFailure(ctx context.Context)

RunNodeFailure evaluates node failure state until ctx is done.

func (*Router) RunNodeGuardrailWatcher ¶

func (rt *Router) RunNodeGuardrailWatcher(ctx context.Context)

RunNodeGuardrailWatcher notifies on level changes and runs opted-in auto-clean until ctx ends.

func (*Router) RunNodeMoves ¶ added in v0.2.0

func (rt *Router) RunNodeMoves(ctx context.Context)

RunNodeMoves advances node moves and drains until ctx is done, resuming any left running by a previous process.

func (*Router) RunNodeOnboarding ¶

func (rt *Router) RunNodeOnboarding(ctx context.Context)

RunNodeOnboarding applies each node's detected provider, region and zone until ctx is done. It only fills values the operator has not set, so a manual label always wins, and it re-checks every tick so a node that enrolled before its first report is still labeled.

func (*Router) RunPreviewSweeper ¶

func (rt *Router) RunPreviewSweeper(ctx context.Context, interval time.Duration) error

RunPreviewSweeper calls SweepStalePreviewEnvironments on interval until ctx is done, matching the shape of every other periodic loop in this codebase (backup.Scheduler.Run, scheduledtask.Scheduler.Run, alerting.Engine.Run).

func (*Router) RunRegistryRefresher ¶

func (rt *Router) RunRegistryRefresher(ctx context.Context) error

RunRegistryRefresher renews preset registry credentials until ctx ends.

func (*Router) RunStatusPageSampler ¶ added in v0.2.0

func (rt *Router) RunStatusPageSampler(ctx context.Context) error

RunStatusPageSampler probes status page components until ctx ends. It returns nil at once when the status page is not configured.

func (*Router) RunUploadCleanup ¶

func (rt *Router) RunUploadCleanup(ctx context.Context)

RunUploadCleanup expires stored uploads hourly until ctx ends.

func (*Router) RunWebhookDeliverySweeper ¶ added in v0.2.0

func (rt *Router) RunWebhookDeliverySweeper(ctx context.Context, interval time.Duration) error

RunWebhookDeliverySweeper calls PurgeOldWebhookDeliveries on interval until ctx is done, the same ticker shape RunAuditLogSweeper already establishes: without it, webhook_deliveries would be the one inbound- request history table in this codebase that only ever grows.

func (*Router) SetAppTeardownOptions ¶ added in v0.2.0

func (rt *Router) SetAppTeardownOptions(opts ...application.Option)

SetAppTeardownOptions is WithAppTeardownOptions for callers that learn the instance ID only after the router is built.

func (*Router) SetBuildLoad ¶

func (rt *Router) SetBuildLoad(s BuildLoadSource)

SetBuildLoad enables live slot usage in the build center.

func (*Router) SetCIIDTokenVerifier ¶

func (rt *Router) SetCIIDTokenVerifier(v CIIDTokenVerifier)

SetCIIDTokenVerifier overrides the GitHub OIDC verifier, for tests.

func (*Router) SetCanaryProgress ¶

func (rt *Router) SetCanaryProgress(p CanaryProgress)

SetCanaryProgress wires the canary reconciler's live view into GET responses.

func (*Router) SetCompliance ¶

func (rt *Router) SetCompliance(s *compliance.Service)

SetCompliance enables the access review and evidence pack routes.

func (*Router) SetControlPlaneDR ¶ added in v0.2.0

func (rt *Router) SetControlPlaneDR(dr ControlPlaneDR, material EscrowMaterialReader)

SetControlPlaneDR enables the disaster recovery routes after the router is built, for wiring that needs the router's own dependencies first.

func (*Router) SetControlPlaneProbe ¶

func (rt *Router) SetControlPlaneProbe(p ControlPlaneProbe)

SetControlPlaneProbe enables GET /api/v1/system/control-plane-health.

func (*Router) SetDataExport ¶ added in v0.2.0

func (rt *Router) SetDataExport(s DataExportService)

SetDataExport enables the data export routes and the /metrics scrape endpoint after the router is built.

func (*Router) SetDatabaseUpgrader ¶ added in v0.2.0

func (rt *Router) SetDatabaseUpgrader(u DatabaseUpgrader)

SetDatabaseUpgrader is WithDatabaseUpgrader for wiring after NewRouter.

func (*Router) SetDatabaseVersionCatalog ¶

func (rt *Router) SetDatabaseVersionCatalog(c DatabaseVersionCatalog)

SetDatabaseVersionCatalog enables the database version catalog routes.

func (*Router) SetDiskGuard ¶

func (rt *Router) SetDiskGuard(g *diskguard.Guard)

SetDiskGuard enables the low-disk refusals and GET /api/v1/resilience/disk.

func (*Router) SetDockerGuard ¶ added in v0.2.0

func (rt *Router) SetDockerGuard(c DockerGuardController)

SetDockerGuard is WithDockerGuard for a guard booted before the router.

func (*Router) SetDoctorIngressEdge ¶ added in v0.2.0

func (rt *Router) SetDoctorIngressEdge(edge DoctorIngressEdge)

SetDoctorIngressEdge makes doctor report the ingress edge policy. Call it before the router serves requests.

func (*Router) SetEncryptionKeys ¶

func (rt *Router) SetEncryptionKeys(r EncryptionKeyRotator, p SecretKeyPolicyStore)

SetEncryptionKeys enables the /api/v1/system/encryption-keys routes.

func (*Router) SetEventWebhooks ¶

func (rt *Router) SetEventWebhooks(s EventWebhookService)

SetEventWebhooks enables the event webhook routes and starts feeding audited mutations to subscribers.

func (*Router) SetForgeDeployments ¶ added in v0.2.0

func (rt *Router) SetForgeDeployments(s ForgeDeploymentStore)

SetForgeDeployments wires the store that tracks forge deployments. Unset, deployments are not reported.

func (*Router) SetGate ¶ added in v0.2.0

func (rt *Router) SetGate(secret string, settings GateSettings)

SetGate enables the built-in auth gate provider. An empty secret leaves the check endpoint refusing every request.

func (*Router) SetIngressResilience ¶

func (rt *Router) SetIngressResilience(src IngressResilience)

SetIngressResilience wires the resilience check to the ingress driver. Call it before the router serves requests.

func (*Router) SetLoadBalancers ¶ added in v0.2.0

func (rt *Router) SetLoadBalancers(s LoadBalancerStore, registry *loadbalancer.Registry, stats loadbalancer.StatsSource)

SetLoadBalancers enables the load balancer routes after construction, for wiring that needs the router before the reconciler exists.

func (*Router) SetLocalNodeID ¶ added in v0.2.0

func (rt *Router) SetLocalNodeID(id string)

SetLocalNodeID marks which node's row in GET /api/v1/nodes is the one HostDiskCollector/HostMemoryCollector's readings are real for: the node running the control plane process itself. A late setter, not a construction Option, because cmd/levelrail's mesh setup (the only source of this ID) runs after NewRouter is called; safe to call any time before the HTTP server starts accepting requests.

func (*Router) SetMesh ¶ added in v0.2.0

func (rt *Router) SetMesh(mesh MeshStatusProvider, rotator MeshKeyRotator)

SetMesh wires GET /api/v1/mesh and POST /api/v1/nodes/{id}/mesh/rotate-key to this node's live mesh device and coordinator. A late setter for the same reason SetLocalNodeID is: cmd/levelrail's mesh setup runs after NewRouter is called. Either argument may be nil independently (a test or an embedder that wants status but not rotation, or vice versa); both routes check their own dependency and return 501 rather than assuming the other was set too.

func (*Router) SetMeshPaths ¶ added in v0.2.0

func (rt *Router) SetMeshPaths(r meshpath.Resolver)

SetMeshPaths sets the resolver the doctor and app status use to tell whether a remote node's app can be routed over the WireGuard mesh.

func (*Router) SetMeshPeerStatus ¶ added in v0.2.0

func (rt *Router) SetMeshPeerStatus(src NodeMeshStatusSource)

SetMeshPeerStatus wires node-pair diagnostics to remote agents' mesh views.

func (*Router) SetMeshStartError ¶ added in v0.2.0

func (rt *Router) SetMeshStartError(err error)

SetMeshStartError records why the mesh failed to start, so the settings card can show it instead of a bare "restart required".

func (*Router) SetMeshZone ¶ added in v0.2.0

func (rt *Router) SetMeshZone(zone string)

SetMeshZone mirrors SetLocalNodeID's own late-setter shape, for the identical reason: cmd/levelrail's mesh setup (the only source of this value, application.WithMeshZone's own call site) runs after NewRouter is called. Empty means mesh DNS resolution is off, the same "not configured, not broken" default application.Controller itself uses.

func (*Router) SetMigrationAgent ¶

func (rt *Router) SetMigrationAgent(s MigrationAgentService)

SetMigrationAgent enables the /api/v1/migration/agent routes.

func (*Router) SetNodeGuardrails ¶

func (rt *Router) SetNodeGuardrails(s NodeGuardrailStore, notify func(ctx context.Context, text string))

SetNodeGuardrails enables the per-node capacity guardrails. notify may be nil.

func (*Router) SetNodeHostReports ¶ added in v0.2.2

func (rt *Router) SetNodeHostReports(src NodeHostReports)

SetNodeHostReports wires remote nodes' agent-reported host memory split into GET /api/v1/nodes/resource-usage.

func (*Router) SetNodeOnboarding ¶

func (rt *Router) SetNodeOnboarding(src NodeOnboardingSource, cfg nodepreflight.Config)

SetNodeOnboarding wires agent onboarding reports into the preflight and failure-domain auto-detect routes. Without it those routes report that no agent has sent facts yet.

func (*Router) SetOIDCManager ¶ added in v0.2.0

func (rt *Router) SetOIDCManager(m OIDCJWKSProvider, issuerURL string, ratePerMinute int)

SetOIDCManager wires the OIDC signing key manager: it serves the public GET /.well-known/jwks.json document and the authenticated summary GET /api/v1/pipelines/oidc reads for the dashboard. Minting the tokens themselves is wired separately, into internal/pipeline.Config.OIDCIssuer, since that lives on the pipeline engine, not this router.

func (*Router) SetOIDCRotator ¶ added in v0.2.0

func (rt *Router) SetOIDCRotator(r OIDCKeyRotator)

SetOIDCRotator wires POST /api/v1/pipelines/oidc/rotate-key. Optional: nil (the default) means the endpoint returns 501, the same not-configured shape SetOIDCManager's own JWKS route uses.

func (*Router) SetOrphanReaper ¶ added in v0.2.0

func (rt *Router) SetOrphanReaper(r *orphans.Reaper)

SetOrphanReaper enables GET /api/v1/system/orphans and POST /api/v1/system/orphans/reap, backed by the same reaper the reconcile loop runs.

func (*Router) SetPipelineArtifactFiles ¶

func (rt *Router) SetPipelineArtifactFiles(f PipelineArtifactFiles)

SetPipelineArtifactFiles enables artifact downloads.

func (*Router) SetPipelineEvents ¶ added in v0.2.0

func (rt *Router) SetPipelineEvents(e PipelineEvents)

SetPipelineEvents wires git webhook deliveries to pipeline triggers.

func (*Router) SetPipelineSync ¶ added in v0.2.0

func (rt *Router) SetPipelineSync(syncer PipelineSyncer, st PipelineSyncStore)

SetPipelineSync enables repository sync of pipeline files: on a push to the tracked branch, and on demand through /pipeline-sync.

func (*Router) SetPipelineWebhookLimits ¶

func (rt *Router) SetPipelineWebhookLimits(maxBody int64, keep int)

SetPipelineWebhookLimits sets the inbound webhook body cap and how many deliveries each pipeline keeps. Zero values keep the defaults.

func (*Router) SetPipelines ¶ added in v0.2.0

func (rt *Router) SetPipelines(st PipelineStore, runner PipelineRunner)

SetPipelines wires the pipeline endpoints after construction, for wiring code that builds the engine after the router.

func (*Router) SetPluginManager ¶

func (rt *Router) SetPluginManager(m *plugin.Manager)

SetPluginManager enables the plugin routes and plugin channel kinds.

func (*Router) SetPluginMarketplace ¶

func (rt *Router) SetPluginMarketplace(m *plugin.Marketplace)

SetPluginMarketplace enables the plugin marketplace routes.

func (*Router) SetPreview ¶ added in v0.2.0

func (rt *Router) SetPreview(p PreviewService)

SetPreview enables the deploy preview routes.

func (*Router) SetPrivateNetworks ¶

func (rt *Router) SetPrivateNetworks(cfg PrivateNetworkConfig)

SetPrivateNetworks enables the private network routes after construction.

func (*Router) SetProxyIntegration ¶ added in v0.2.0

func (rt *Router) SetProxyIntegration(syncer *proxyroutes.Syncer, st ProxyIntegrationStore, verifyTimeout time.Duration)

SetProxyIntegration enables the managed proxy routes API. syncer must be the same instance the reconciler uses.

func (*Router) SetProxyRouteCheck ¶

func (rt *Router) SetProxyRouteCheck(rc ingress.RouteCheck)

SetProxyRouteCheck lets verification prove that a proxy route reaches the built-in ingress. Call after SetProxyIntegration.

func (*Router) SetRestarter ¶ added in v0.2.0

func (rt *Router) SetRestarter(r Restarter)

SetRestarter enables POST /api/v1/system/restart.

func (*Router) SetScheduledMaintenance ¶

func (rt *Router) SetScheduledMaintenance(s ScheduledMaintenanceStore)

SetScheduledMaintenance enables the /api/v1/scheduled-maintenance routes.

func (*Router) SetSecretRotation ¶

func (rt *Router) SetSecretRotation(st SecretRotationStore, maxPerPass int, dueSoon time.Duration) *secretrotation.Engine

SetSecretRotation enables the rotation policy API and returns the engine the caller runs on a timer.

func (*Router) SetSecretScan ¶

func (rt *Router) SetSecretScan(s SecretScanService)

SetSecretScan enables the secret scanning routes.

func (*Router) SetSleepRuntime ¶

func (rt *Router) SetSleepRuntime(pw appsleep.PortWaker, act SleepActivity)

SetSleepRuntime wires the live port wake manager and the scheduler's activity view into the sleep routes. Either may be nil.

func (*Router) SetStorage ¶ added in v0.2.0

func (rt *Router) SetStorage(d StorageDeps)

SetStorage enables the storage routes after construction, for wiring that needs the built Router first. Call it before the server starts serving.

func (*Router) SetSupplyChain ¶ added in v0.2.0

func (rt *Router) SetSupplyChain(s SupplyChainService)

SetSupplyChain enables the SBOM and scan routes.

func (*Router) SetWALShipStatus ¶ added in v0.2.0

func (rt *Router) SetWALShipStatus(src WALShipStatusSource)

SetWALShipStatus attaches the source "pitr status" reads shipping state from.

func (*Router) SourceCache ¶

func (rt *Router) SourceCache() *sourcecache.Cache

SourceCache is the mirror every fetch of this router goes through.

func (*Router) SpendCapBreaches ¶

func (rt *Router) SpendCapBreaches(ctx context.Context) ([]spendcap.Breach, error)

SpendCapBreaches feeds the budget_threshold alert rule.

func (*Router) SpendCapTick ¶

func (rt *Router) SpendCapTick(ctx context.Context)

SpendCapTick is the scheduler entry point for the spend cap controller.

func (*Router) SpendCapUsage ¶

func (rt *Router) SpendCapUsage(ctx context.Context, now time.Time) (map[string]spendcap.Usage, error)

SpendCapUsage reports each app's month to date egress and cost from the same rows the cost showback uses.

func (*Router) StartSplitTesting ¶

func (rt *Router) StartSplitTesting(ctx context.Context)

StartSplitTesting restores running tests into ingress and persists request counts until ctx ends.

func (*Router) StaticOrphanGrace ¶

func (rt *Router) StaticOrphanGrace() time.Duration

StaticOrphanGrace is the grace period the sweep uses.

func (*Router) StatusHostHandler ¶ added in v0.2.0

func (rt *Router) StatusHostHandler(next http.Handler) http.Handler

StatusHostHandler serves only the public status page when a request's Host matches the configured custom domain, and 404s everything else on that host so the dashboard and API are never reachable through it. Requests for any other host pass through to next untouched.

func (*Router) StatusPageAppStatus ¶ added in v0.2.0

func (rt *Router) StatusPageAppStatus(ctx context.Context, name string) (string, error)

StatusPageAppStatus reports an app's status for the status page sampler.

func (*Router) SweepDeviceLoginExpiry ¶ added in v0.2.0

func (rt *Router) SweepDeviceLoginExpiry(ctx context.Context, now time.Time) (int, error)

SweepDeviceLoginExpiry marks every pending request past its TTL as expired and audits each exactly once, returning how many it claimed.

func (*Router) SweepOrphanPreviews ¶ added in v0.2.0

func (rt *Router) SweepOrphanPreviews(ctx context.Context) (OrphanSweepResult, error)

SweepOrphanPreviews repairs state a crash can leave behind: previews stuck in deploying (the control plane died mid-build) are marked failed, and services tagged as preview workloads that no preview row owns are removed with their containers. Owned resources are never touched.

func (*Router) SweepOrphanStaticSites ¶

func (rt *Router) SweepOrphanStaticSites(ctx context.Context) ([]string, error)

SweepOrphanStaticSites removes static sites with no desired service and no queued or running deploy, once older than the grace period, so a site whose app is still being created is never removed. It returns the removed names.

func (*Router) SweepSignInExpiry ¶ added in v0.2.0

func (rt *Router) SweepSignInExpiry(ctx context.Context, now time.Time) error

SweepSignInExpiry expires lapsed codes and approvals, auditing each once.

func (*Router) SweepStaleBranchDeploys ¶

func (rt *Router) SweepStaleBranchDeploys(ctx context.Context) (swept int, err error)

SweepStaleBranchDeploys removes branch deploys with no push for the idle TTL. One failing teardown never blocks the rest; a partial teardown counts as handled because it bumps the row's update time.

func (*Router) SweepStalePreviewEnvironments ¶

func (rt *Router) SweepStalePreviewEnvironments(ctx context.Context) (swept int, err error)

SweepStalePreviewEnvironments tears down every preview environment last updated before now minus effectivePreviewTTL, reusing teardownPreviewRecord, the exact same deletion path the pull-request- closed webhook and the manual teardown route already use. One preview's teardown failure never blocks the rest, the same "one broken resource must not block others" principle every other periodic loop in this codebase follows (alerting.Engine.Tick, backup.Scheduler.Tick, scheduledtask.Scheduler.Tick).

A partial teardown (http.StatusMultiStatus) counts as handled, not an error: teardownPreviewRecord already marks the row Failed with a reason and bumps its UpdatedAt, so the next sweep won't immediately retry the same broken preview every tick.

func (*Router) SweepTokenHygiene ¶ added in v0.2.0

func (rt *Router) SweepTokenHygiene(ctx context.Context, now time.Time) error

SweepTokenHygiene runs the unused-token policy and prunes expired sign-in alert links and long-unseen browsers. System tokens (no owner) are never touched: the platform itself may depend on them.

func (*Router) TriggerScheduledDeploy ¶ added in v0.2.0

func (rt *Router) TriggerScheduledDeploy(ctx context.Context, serviceName, branch string) (string, error)

TriggerScheduledDeploy deploys serviceName's git source at the latest commit on branch, which may differ from gs.Branch. Called only by the scheduler, so it returns a plain error.

func (*Router) UpgradeScheduler ¶ added in v0.2.0

func (rt *Router) UpgradeScheduler() *upgradesched.Scheduler

UpgradeScheduler returns the scheduler to run, or nil when scheduling is not configured. It is built once and shared with the HTTP handlers so a cancel and a fire serialise on the same lock.

func (*Router) UsageRollupTick ¶ added in v0.2.0

func (rt *Router) UsageRollupTick(ctx context.Context)

UsageRollupTick is the scheduler entry point: it snapshots missing days and evaluates nothing else, so a failure only delays history.

func (*Router) WaitDeploys ¶

func (rt *Router) WaitDeploys(ctx context.Context) bool

WaitDeploys blocks until every detached queued deploy has finished or ctx ends, and reports whether all of them finished.

func (*Router) WarmTrustRoot ¶

func (rt *Router) WarmTrustRoot()

WarmTrustRoot starts the background Sigstore trust data download at startup.

func (*Router) WithHSTS ¶ added in v0.2.0

func (rt *Router) WithHSTS(next http.Handler) http.Handler

WithHSTS wraps the embedded dashboard handler, which the API's own header middleware never sees, so the HTML document also carries Strict-Transport-Security when it is enabled (env or settings) and the request really arrived over https.

type SSHNodeProvisionStore ¶ added in v0.2.0

type SSHNodeProvisionStore interface {
	SaveSSHNodeProvision(ctx context.Context, p store.SSHNodeProvision) error
	GetSSHNodeProvision(ctx context.Context, id string) (store.SSHNodeProvision, error)
	ListSSHNodeProvisions(ctx context.Context) ([]store.SSHNodeProvision, error)
	UpdateSSHNodeProvisionProgress(ctx context.Context, id, status, detectedOS, detectedArch, log, nodeID, failureReason string, updatedAt time.Time) error
}

SSHNodeProvisionStore is the store surface the SSH node provisioning handlers need.

type SSHProvisioner ¶ added in v0.2.0

type SSHProvisioner interface {
	Provision(ctx context.Context, creds sshprovision.Credentials, params sshprovision.InstallParams, onEvent func(sshprovision.Event)) (sshprovision.DetectedHost, error)
	ScanHostKeys(ctx context.Context, host string, port int) ([]sshprovision.HostKey, error)
}

SSHProvisioner is the surface *sshprovision.Provisioner satisfies, narrowed to what this package calls: a seam for this package's own tests to inject a fake that never dials a real network, the same "consumer-defined interface" shape NodeProvisioner already establishes for the cloud path.

type SSOStore ¶

type SSOStore interface {
	ListSSOConnections(ctx context.Context) ([]store.SSOConnection, error)
	GetSSOConnection(ctx context.Context, id string) (store.SSOConnection, error)
	SaveSSOConnection(ctx context.Context, c store.SSOConnection, create bool, now time.Time) error
	DeleteSSOConnection(ctx context.Context, id string) error
	ListSSOGroupMappings(ctx context.Context) ([]store.SSOGroupMapping, error)
	ReplaceSSOGroupMappings(ctx context.Context, mappings []store.SSOGroupMapping, now time.Time) error
	GetSSOSettings(ctx context.Context) (store.SSOSettings, error)
	SetSSOEnforce(ctx context.Context, on bool, now time.Time) error
	SetSCIMDefaultRole(ctx context.Context, roleID string, now time.Time) error
	SaveSCIMTokenMeta(ctx context.Context, tokenID string, m store.SCIMTokenMeta) error
	SCIMTokenMetas(ctx context.Context) (map[string]store.SCIMTokenMeta, error)
	CreateProvisionedUser(ctx context.Context, u store.User, roleID string) error
}

SSOStore is the platform-side SSO state: connection policy, group to role mappings, enforcement and SCIM token labels. The IdP bindings, identities, directory and token hashes live in the auth library. *store.DB satisfies it.

type ScheduledMaintenanceStore ¶

type ScheduledMaintenanceStore interface {
	InsertMaintenanceWindow(ctx context.Context, w store.MaintenanceWindow) (store.MaintenanceWindow, error)
	ListMaintenanceWindows(ctx context.Context, since time.Time) ([]store.MaintenanceWindow, error)
	DeleteMaintenanceWindow(ctx context.Context, id string) error
}

ScheduledMaintenanceStore is the store surface for scheduled maintenance windows. *store.DB satisfies it.

type ScheduledTaskHTTPStore ¶

type ScheduledTaskHTTPStore interface {
	SetScheduledTaskHTTP(ctx context.Context, h store.ScheduledTaskHTTP) error
	GetScheduledTaskHTTP(ctx context.Context, taskID string) (store.ScheduledTaskHTTP, error)
	DeleteScheduledTaskHTTP(ctx context.Context, taskID string) error
}

ScheduledTaskHTTPStore persists the request an http-mode job sends. It is optional on the scheduled task store: without it http jobs are refused.

type ScheduledTaskRunner ¶

type ScheduledTaskRunner interface {
	Run(ctx context.Context, task store.ScheduledTask) error
}

ScheduledTaskRunner runs a job on demand. *scheduledtask.Runner satisfies it structurally, and cmd/levelrail/main.go wires that same instance into the scheduler, so a scheduled tick and "run now" share one execution path.

type ScheduledTaskStarter ¶ added in v0.2.0

type ScheduledTaskStarter interface {
	Start(ctx context.Context, task store.ScheduledTask, trigger string) (runID string, err error)
}

ScheduledTaskStarter is the richer on-demand surface: it records the run's history row synchronously and returns its ID while the run itself proceeds in the background. Preferred over ScheduledTaskRunner when the wired runner provides it.

type ScheduledTaskStore ¶

type ScheduledTaskStore interface {
	SaveScheduledTask(ctx context.Context, t store.ScheduledTask) error
	GetScheduledTask(ctx context.Context, id string) (store.ScheduledTask, error)
	ListScheduledTasksForService(ctx context.Context, serviceName string) ([]store.ScheduledTask, error)
	UpdateScheduledTask(ctx context.Context, id string, command []string, schedule string, enabled bool, concurrencyPolicy string, updatedAt time.Time) error
	UpdateScheduledTaskConfig(ctx context.Context, t store.ScheduledTask, now time.Time) error
	CountScheduledTasksForService(ctx context.Context, serviceName string) (int, error)
	DeleteScheduledTask(ctx context.Context, id string) error
	ListScheduledTaskRuns(ctx context.Context, f store.ScheduledTaskRunFilter) ([]store.ScheduledTaskRun, error)
	GetScheduledTaskRun(ctx context.Context, id string) (store.ScheduledTaskRun, error)
}

ScheduledTaskStore is the store surface the scheduled job handlers need.

type SecretBinder ¶ added in v0.2.0

type SecretBinder interface {
	BindingStatus(ctx context.Context) (secrets.BindingStatus, error)
	Rebind(ctx context.Context) (secrets.RebindResult, error)
}

SecretBinder is the surface the secrets binding routes need from internal/secrets.Manager: count legacy unbound values and rebind them.

type SecretKeyPolicyStore ¶

type SecretKeyPolicyStore interface {
	GetSecretKeyPolicy(ctx context.Context) (store.SecretKeyPolicy, error)
	SaveSecretKeyPolicy(ctx context.Context, p store.SecretKeyPolicy, now time.Time) error
}

SecretKeyPolicyStore persists the maximum key age policy.

type SecretRotationStore ¶

type SecretRotationStore interface {
	secretrotation.Store
	UpsertSecretRotationPolicy(ctx context.Context, p store.SecretRotationPolicy, now time.Time) error
}

SecretRotationStore is the policy persistence the rotation API needs. *store.DB satisfies it.

type SecretScanService ¶

type SecretScanService interface {
	Limits() secretscan.Limits
	Policy(ctx context.Context, app string) (secretscan.Policy, error)
	SetPolicy(ctx context.Context, app, policy string) (secretscan.Policy, error)
	AllowList(ctx context.Context, app string) ([]secretscan.AllowEntry, error)
	Allow(ctx context.Context, app, fingerprint, reason, actor string) (secretscan.AllowEntry, error)
	Unallow(ctx context.Context, app, fingerprint string) (bool, error)
	Run(ctx context.Context, attemptID string) (secretscan.Run, error)
	ScanEnvNow(ctx context.Context, app string, env map[string]string) (secretscan.Result, error)
	DeleteApp(ctx context.Context, app string) error
}

SecretScanService is the deploy-time secret scanning surface; *secretscan.Service satisfies it.

type SecretSetter ¶

type SecretSetter interface {
	SetValueGuarded(ctx context.Context, serviceName, envKey, plaintext string, overwriteLocked bool) error
	ListKeys(ctx context.Context, serviceName string) ([]store.SecretKeyInfo, error)
	SetLocked(ctx context.Context, serviceName, envKey string, locked bool) error
	// SetBuildEnabled flips whether build.secrets may mount the secret.
	SetBuildEnabled(ctx context.Context, serviceName, envKey string, enabled bool) error
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	// ExistsForServices is Exists batched over many service names in one
	// call, used by databases.go's handleListDatabases to show every
	// row's TLS status without an Exists call per database.
	ExistsForServices(ctx context.Context, serviceNames []string, envKey string) (map[string]bool, error)
	// Resolve decrypts and returns one secret's plaintext value, the same
	// read internal/reconcile/application already does immediately before
	// container creation. environment_clone.go's own explicit,
	// opt-in-only CopySecretValues path is the one HTTP-reachable caller
	// that ever moves a decrypted value between two secret namespaces
	// (source app/environment -> cloned app/environment) rather than
	// only ever writing a caller-supplied plaintext the way
	// SetValueGuarded's other callers do.
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
	// DeleteAll permanently removes every value stored under a
	// namespace, used by handleDetachAppIntegration to clear one
	// attached integration's field values in the same request that
	// removes its app_integrations row.
	DeleteAll(ctx context.Context, serviceName string) error
}

SecretSetter is the surface the secrets handlers need from internal/secrets.Manager: set a value (with a reversible per-key lock guard), list which keys exist, toggle a key's lock, and check whether one exists without decrypting it (Exists, used by databases.go's databaseTLSEnabled to show a database's TLS status, never to read the certificate back). Every other secret-backed feature in this file keeps using Manager's plain SetValue/Resolve directly, unaffected by this narrower interface.

type SecurityStore ¶ added in v0.2.0

type SecurityStore interface {
	GetSecurityPolicy(ctx context.Context) (store.SecurityPolicy, bool, error)
	SaveSecurityPolicy(ctx context.Context, p store.SecurityPolicy) error
	GetUserSecuritySettings(ctx context.Context, userID string) (store.UserSecuritySettings, error)
	ListUserSecuritySettings(ctx context.Context) ([]store.UserSecuritySettings, error)
	SetRequireNewDeviceApproval(ctx context.Context, userID string, on bool, now time.Time) error
	FlagUserForReset(ctx context.Context, userID, reason string, now time.Time) error
	ClearUserResetFlag(ctx context.Context, userID string, now time.Time) error
	CreateSignInAlertToken(ctx context.Context, t store.SignInAlertToken) error
	ConsumeSignInAlertToken(ctx context.Context, id string, now time.Time) (store.SignInAlertToken, error)
	PruneSignInAlertTokens(ctx context.Context, cutoff time.Time) error
	ListTokenHygieneNotices(ctx context.Context) ([]store.TokenHygieneNotice, error)
	SaveTokenHygieneNotice(ctx context.Context, n store.TokenHygieneNotice) error
	MarkTokenHygieneDisabled(ctx context.Context, tokenID string, now time.Time) error
	DeleteTokenHygieneNotice(ctx context.Context, tokenID string) error
	RememberBrowser(ctx context.Context, userID, fingerprint string, now time.Time) (bool, bool, error)
	ForgetBrowser(ctx context.Context, userID, fingerprint string) error
	PruneKnownBrowsers(ctx context.Context, cutoff time.Time) error
}

SecurityStore is the store surface the security center needs.

type SelfUpgradeLauncher ¶ added in v0.2.0

type SelfUpgradeLauncher func(ctx context.Context, args []string) error

SelfUpgradeLauncher starts the host command. Tests replace it.

type SelfUpgradeStore ¶ added in v0.2.0

type SelfUpgradeStore interface {
	UpsertSelfUpgradeAttempt(ctx context.Context, a store.SelfUpgradeAttempt) error
	ListSelfUpgradeAttempts(ctx context.Context, limit int) ([]store.SelfUpgradeAttempt, error)
}

SelfUpgradeStore is what the self-upgrade routes persist and read.

type ServerProfileStore ¶

type ServerProfileStore interface {
	GetServerProfile(ctx context.Context) (store.ServerProfileSetting, error)
	SetServerProfile(ctx context.Context, profile, actor string, now time.Time) error
	CountEnabledPlugins(ctx context.Context) (int, error)
}

ServerProfileStore persists the server profile and reads what a move could cost; *store.DB satisfies it.

type ServiceVolumeBackupHistoryStore ¶

type ServiceVolumeBackupHistoryStore interface {
	ListServiceVolumeBackupHistory(ctx context.Context, serviceName, volumeName string, limit int, before *time.Time) ([]store.BackupHistory, error)
}

ServiceVolumeBackupHistoryStore is the store surface the volume backup history handler needs.

type ServiceVolumeBackupRunner ¶

type ServiceVolumeBackupRunner interface {
	RunVolumeBackup(ctx context.Context, historyID, serviceName, volumeName, dockerVolumeName, targetID, sqlitePath string) error
}

ServiceVolumeBackupRunner is the surface the volume backup trigger needs from backup.Runner.

type ServiceVolumeBackupScheduleStore ¶

type ServiceVolumeBackupScheduleStore interface {
	SetServiceVolumeBackupSchedule(ctx context.Context, serviceName, volumeName, targetID, schedule string, retain, retainDays int, sqlitePath string) error
	GetServiceVolumeBackupSchedule(ctx context.Context, serviceName, volumeName string) (store.ServiceVolumeBackupConfig, error)
}

ServiceVolumeBackupScheduleStore is the store surface for volume backup schedules, kept in service_volume_backups.

type ServiceVolumeRestoreHistoryStore ¶

type ServiceVolumeRestoreHistoryStore interface {
	ListServiceVolumeRestoreHistory(ctx context.Context, serviceName, volumeName string) ([]store.RestoreHistory, error)
}

ServiceVolumeRestoreHistoryStore is the store surface the volume restore history handler needs, the volume counterpart of RestoreHistoryStore (restore.go).

type ServiceVolumeRestoreRunner ¶

type ServiceVolumeRestoreRunner interface {
	RunVolumeRestore(ctx context.Context, historyID, serviceName, volumeName, dockerVolumeName, backupHistoryID string) error
}

ServiceVolumeRestoreRunner is the volume counterpart of RestoreRunner; *backup.RestoreRunner satisfies it structurally.

type SessionLinkTokenStore ¶ added in v0.2.0

type SessionLinkTokenStore interface {
	SaveSessionLinkToken(ctx context.Context, t store.SessionLinkToken) error
	GetSessionLinkTokenByHash(ctx context.Context, hash string) (*store.SessionLinkToken, error)
	ClaimSessionLinkToken(ctx context.Context, id string) error
}

SessionLinkTokenStore is the store surface the session-link flow needs: always set, part of the core Store interface, same shape as PasswordResetTokenStore above.

type SetupGuideStore ¶ added in v0.2.0

type SetupGuideStore interface {
	GetSetupGuideState(ctx context.Context) (store.SetupGuideState, error)
	SetSetupGuideHidden(ctx context.Context, hidden bool, by string) error
	SetSetupGuideOverride(ctx context.Context, stepID, state, by string) error
	ResetSetupGuide(ctx context.Context) error
}

SetupGuideStore persists the Get started hub's dismissal and step overrides.

type SleepActivity ¶

type SleepActivity interface {
	Snapshot(name string) (appsleep.Snapshot, bool)
}

SleepActivity is the scheduler's latest view of each app's traffic.

type SplitTestStore ¶

type SplitTestStore interface {
	CreateSplitTest(ctx context.Context, t store.SplitTest) error
	GetRunningSplitTest(ctx context.Context, app string) (store.SplitTest, bool, error)
	GetLatestSplitTest(ctx context.Context, app string) (store.SplitTest, bool, error)
	ListRunningSplitTests(ctx context.Context) ([]store.SplitTest, error)
	UpdateSplitTestVariants(ctx context.Context, id string, vs []store.SplitVariant) error
	EndSplitTest(ctx context.Context, id, reason string) error
	AddSplitStats(ctx context.Context, testID string, counts map[string]uint64, at time.Time) error
	ListSplitStats(ctx context.Context, testID string) ([]store.SplitStat, error)
	ListDeployURLs(ctx context.Context, appName string) ([]store.DeployURL, error)
	ListBranchDeploysByApp(ctx context.Context, appName string) ([]store.BranchDeploy, error)
}

SplitTestStore is the store surface split testing needs. The store passed to NewRouter may or may not implement it; routes answer 404 when it does not.

type StaleSecretCounter ¶ added in v0.2.0

type StaleSecretCounter interface {
	CountStaleSecrets(ctx context.Context, cutoff time.Time) (int, error)
}

StaleSecretCounter is the surface GET /api/v1/system/doctor's stale_secrets check needs: count every secret-backed value (per-app and every secret-marked shared-env row alike) last set or rotated before cutoff. *store.DB satisfies this via CountStaleSecrets (internal/store/secret_rotation.go).

type StandaloneSafety ¶ added in v0.2.0

type StandaloneSafety struct {
	// ControlPorts are this platform's own listeners on this server.
	ControlPorts []standalone.ControlPort
	// IngressPorts are the ports the embedded ingress listens on.
	IngressPorts []int
}

StandaloneSafety is what the API needs to refuse dangerous standalone targets.

type Statement ¶

type Statement struct {
	Effect   Effect   `json:"Effect"`
	Action   []string `json:"Action"`
	Resource []string `json:"Resource"`
}

Statement is one Allow/Deny rule inside a Document: Action holds ability strings (abilities.go's AbilityRead etc.) or "*", Resource holds resource identifiers ("app:myapp", "database:main") or "*". Both are lists so one statement can cover several actions or resources at once, matching how a real IAM statement reads.

type StaticSiteStore ¶

type StaticSiteStore interface {
	ListStaticSites(ctx context.Context) ([]store.StaticSite, error)
}

StaticSiteStore is the store surface handleListStaticSites needs. *store.DB satisfies this structurally, the same consumer-defined interface convention every other Store sub-interface in this package follows (see CertStore, DatabaseStore).

type StatusPageDB ¶ added in v0.2.0

type StatusPageDB interface {
	StatusPageStore
	statuspage.Store
}

StatusPageDB is everything the status page needs from the database.

type StatusPageStore ¶ added in v0.2.0

type StatusPageStore interface {
	GetStatusPageSettings(ctx context.Context) (store.StatusPageSettings, error)
	SaveStatusPageSettings(ctx context.Context, s store.StatusPageSettings) error
	ListStatusComponents(ctx context.Context) ([]store.StatusComponent, error)
	GetStatusComponent(ctx context.Context, id string) (store.StatusComponent, error)
	SaveStatusComponent(ctx context.Context, c store.StatusComponent) error
	DeleteStatusComponent(ctx context.Context, id string) error
	SaveStatusIncident(ctx context.Context, i store.StatusIncident) error
	GetStatusIncident(ctx context.Context, id string) (store.StatusIncident, error)
	ListStatusIncidents(ctx context.Context, limit int) ([]store.StatusIncident, error)
	DeleteStatusIncident(ctx context.Context, id string) error
	AddStatusIncidentUpdate(ctx context.Context, u store.StatusIncidentUpdate) error
	ListStatusIncidentUpdates(ctx context.Context) ([]store.StatusIncidentUpdate, error)
}

StatusPageStore is the persistence surface of the status page handlers. *store.DB satisfies it.

type StatusPageViewer ¶ added in v0.2.0

type StatusPageViewer interface {
	View(ctx context.Context) (statuspage.View, error)
	PreviewView(ctx context.Context) (statuspage.View, error)
	Enabled(ctx context.Context) (bool, error)
	Invalidate()
}

StatusPageViewer builds the public view. *statuspage.Service satisfies it.

type StorageDeps ¶ added in v0.2.0

type StorageDeps struct {
	Options     StorageOptionsStore
	Archive     LogArchiveStore
	Clients     ObjectClientResolver
	Archiver    LogArchiver
	ArchiveRoot string

	// Policy enables per-class defaults, usage and quota reporting; nil answers 501 for defaults and omits usage.
	Policy StoragePolicyStore

	// BuildCache and BuildCacheSettings enable /api/v1/build-cache; nil answers 501.
	BuildCache         BuildCacheService
	BuildCacheSettings BuildCacheSettingsStore

	// Buckets enables /api/v1/storage/buckets; nil answers 501. BucketSweeper runs lifecycle rules on demand.
	Buckets       BucketRowStore
	BucketSweeper BucketSweepService
}

StorageDeps groups what the storage destination and log archive routes need.

type StorageOptionsStore ¶ added in v0.2.0

type StorageOptionsStore interface {
	SaveStorageOptions(ctx context.Context, o store.StorageOptions) error
	GetStorageOptions(ctx context.Context, targetID string) (store.StorageOptions, bool, error)
	ListStorageOptions(ctx context.Context) (map[string]store.StorageOptions, error)
}

StorageOptionsStore persists per-destination options.

type StoragePolicyStore ¶

type StoragePolicyStore interface {
	SetStorageDefault(ctx context.Context, dataClass, targetID, updatedAt string) error
	ClearStorageDefault(ctx context.Context, dataClass string) error
	ListStorageDefaults(ctx context.Context) ([]store.StorageDefault, error)
	StorageUsageByTarget(ctx context.Context) (map[string]store.StorageUsage, error)
}

StoragePolicyStore persists per-class default destinations and reports how much backup data each destination holds.

type Store ¶

type Store interface {
	AppStore
	AppGroupLister
	AppComposeStore
	CustomTemplateStore
	DeployStore
	DeployAttemptStore
	ProbeAttemptStore
	DatabaseStore
	AuthStore
	TokenStore
	InstanceStore
	NodeStore
	CertStore
	StaticSiteStore
	BackupTargetStore
	RegistryCredentialStore
	NetworkShareStore
	FirewallRuleStore
	AppStreamStore
	BackupHistoryStore
	BackupVerificationStore
	RestoreHistoryStore
	BaseBackupHistoryStore
	PITRRestoreHistoryStore
	MajorUpgradeStore
	ServiceVolumeBackupHistoryStore
	ServiceVolumeBackupScheduleStore
	ServiceVolumeRestoreHistoryStore
	CloneRestoreHistoryStore
	VolumeCloneRestoreHistoryStore
	AppVolumeMoveStore
	ProjectStore
	OrganizationStore
	EnvironmentStore
	IngressSettingsStore
	UpdateSettingsStore
	DomainStore
	DomainBasicAuthStore
	DomainMaintenanceStore
	DomainTLSCertStore
	DomainWAFStore
	DomainAuthGateStore
	DomainRedirectStore
	DomainErrorPagesStore
	DomainSearchVisibilityStore
	DomainTrafficPolicyStore
	CachePurgeStore
	EdgeFirewallStore
	GitSourceStore
	AppScheduleStore
	AppGitHubActionsStore
	CIOIDCTrustStore
	ImageAutoUpdateStore
	BuildHookStore
	AppSleepStore
	DataImportStore
	MigrationHubStore
	MigrationVerifyStore
	MigrationChecklistStore
	AppImportStore
	LoginCodeStore
	SecurityStore
	ExternalDatabaseStore
	CanaryStore
	DatabaseQueryStore
	PreviewEnvironmentStore
	BranchDeployStore
	GitHubAppStore
	GitConnectionsStore
	OAuthSettingsStore
	OAuthIdentityStore
	EmailSettingsStore
	EmailProviderStore
	TrafficExportStore
	ObservabilityStore
	CloudflareTunnelStore
	RegistryStore
	CloudflareDNSStore
	Route53DNSStore
	GoogleCloudDNSStore
	NodeProvisionStore
	NodeProviderConnectionStore
	PackageRegistryStore
	SSHNodeProvisionStore
	VaultSettingsStore
	SessionLinkTokenStore
	InviteStore
	PushSubscriptions
	AuditStore
	ScheduledTaskStore
	FeatureFlagStore
	TagStore
	AppIntegrationStore
	OnboardingStore
	WebhookDeliveryStore
	PolicyStore
	HookRunStore
	DeployApprovalStore
	AIChatStore
	RoleStore
	AIControlStore
}

Store is the full surface NewRouter needs. *store.DB satisfies it structurally, same pattern internal/reconcile/application.ServiceStore already established for this codebase.

type SupplyChainService ¶ added in v0.2.0

type SupplyChainService interface {
	Config() supplychain.Config
	Settings(ctx context.Context, app string) (supplychain.Settings, error)
	SaveSettings(ctx context.Context, app string, patch supplychain.SettingsPatch) (supplychain.Settings, error)
	ArmOverride(ctx context.Context, app, reason string) (supplychain.Settings, error)
	Get(ctx context.Context, app, attemptID string) (supplychain.Record, error)
	OpenSBOM(ctx context.Context, app, attemptID string) ([]byte, supplychain.Record, error)
	ScanNow(ctx context.Context, app, attemptID string) (supplychain.Record, error)
	Lookup(ctx context.Context, ids []string) (map[string]supplychain.Record, error)
	DeleteApp(ctx context.Context, app string) error
}

SupplyChainService is the SBOM and scan surface; *supplychain.Service satisfies it.

type TagStore ¶ added in v0.2.0

type TagStore interface {
	SaveTag(ctx context.Context, t store.Tag) error
	GetTag(ctx context.Context, id string) (store.Tag, error)
	GetTagByName(ctx context.Context, name string) (store.Tag, error)
	ListTags(ctx context.Context) ([]store.Tag, error)
	DeleteTag(ctx context.Context, id string) error
	AttachAppTag(ctx context.Context, tagID, appName string) error
	DetachAppTag(ctx context.Context, tagID, appName string) error
	ListTagsForApp(ctx context.Context, appName string) ([]store.Tag, error)
	ListTagsForApps(ctx context.Context, appNames []string) (map[string][]store.Tag, error)
	ListAppNamesByTag(ctx context.Context, tagID string) ([]string, error)
}

TagStore is the store surface the tag handlers need, mirroring FeatureFlagStore's own shape for a different child resource.

type TelemetryQuerier ¶

type TelemetryQuerier interface {
	QueryMetrics(ctx context.Context, resourceID, metric string, from, to time.Time) ([]telemetry.Sample, error)
	QueryLogs(ctx context.Context, resourceID string, from, to time.Time, query string) ([]telemetry.LogEntry, error)
	// LatestByMetric backs handleAppResourceUsage
	// (app_resource_usage.go): the dashboard-wide "what is every app
	// doing right now" ranking, one query per metric rather than one
	// query per app.
	LatestByMetric(ctx context.Context, metric string) ([]telemetry.Sample, error)
}

TelemetryQuerier is the surface the metrics and logs query handlers need. *telemetry.Federator satisfies this structurally: today it fans out to exactly one source (this node's own local store), the same single-node-now shape already established for the reconcile agent transport, so Phase 3's real multi-node federation slots in here without this package changing.

type TelemetryStore ¶

type TelemetryStore interface {
	FileBytes(ctx context.Context) (int64, error)
	Compact(ctx context.Context) error
}

TelemetryStore is the metrics database surface the health page reads and compacts.

type TokenStore ¶

type TokenStore interface {
	SaveAPIToken(ctx context.Context, t store.APIToken) error
	GetAPITokenByHash(ctx context.Context, hash string) (*store.APIToken, error)
	GetAPITokenByID(ctx context.Context, id string) (*store.APIToken, error)
	ListAPITokens(ctx context.Context) ([]store.APIToken, error)
	RevokeAPIToken(ctx context.Context, id string) error
	TouchAPITokenLastUsed(ctx context.Context, id string) error
}

TokenStore is the store surface the API-token handlers and the ability-aware auth middleware need.

type TraceStore ¶

type TraceStore interface {
	WriteSpans(ctx context.Context, spans []telemetry.Span) error
	ListTraces(ctx context.Context, f telemetry.TraceFilter) ([]telemetry.TraceSummary, error)
	GetTrace(ctx context.Context, resourceID, traceID string) ([]telemetry.Span, error)
}

TraceStore is the span storage the trace routes need.

type TrafficExportSecrets ¶

type TrafficExportSecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
	DeleteAll(ctx context.Context, serviceName string) error
}

TrafficExportSecrets is the part of internal/secrets.Manager the handlers need. Resolve results never reach a response.

type TrafficExportStore ¶

type TrafficExportStore interface {
	ListTrafficExportSinks(ctx context.Context) ([]store.TrafficExportSink, error)
	GetTrafficExportSink(ctx context.Context, id string) (store.TrafficExportSink, error)
	UpsertTrafficExportSink(ctx context.Context, s store.TrafficExportSink) error
	DeleteTrafficExportSink(ctx context.Context, id string) error
}

TrafficExportStore is the sink surface the traffic export handlers need; *store.DB satisfies it.

type TrafficExporter ¶

type TrafficExporter interface {
	Reload(ctx context.Context) error
	Status() []trafficexport.SinkStatus
	Test(ctx context.Context, spec trafficexport.SinkSpec) trafficexport.TestResult
}

TrafficExporter is the running export service: reload after a config write, live status, one synthetic delivery.

type TrialKeeper ¶

type TrialKeeper interface {
	KeepTrialApp(ctx context.Context, name string) (store.TrialKeep, error)
}

TrialKeeper makes a trial deployment permanent. *store.DB satisfies it.

type TrustRootProbe ¶

type TrustRootProbe interface {
	State() string
	Warm()
}

TrustRootProbe reports the Sigstore trust root state without blocking and can start a background refresh.

type UpdateSettingsStore ¶ added in v0.2.0

type UpdateSettingsStore interface {
	GetUpdateSettings(ctx context.Context) (store.UpdateSettings, error)
	UpdateUpdateSettings(ctx context.Context, s store.UpdateSettings) error
}

UpdateSettingsStore is the store surface the update settings handlers need. *store.DB satisfies this structurally, the same consumer-defined interface convention IngressSettingsStore already establishes.

type UpgradeHistoryStore ¶ added in v0.2.0

type UpgradeHistoryStore interface {
	ListUpgradeHistory(ctx context.Context, limit int) ([]store.UpgradeHistoryEntry, error)
	AcknowledgeUpgrade(ctx context.Context, id, byType, byID, byName string, now time.Time) (e store.UpgradeHistoryEntry, changed bool, err error)
	ListNodeAgentVersionChanges(ctx context.Context, limit int) ([]store.NodeAgentVersionChange, error)
}

UpgradeHistoryStore is what the upgrade history routes need. ListUnacknowledgedUpgrades is the query the attention center consumes.

type UpgradeScheduleStore ¶ added in v0.2.0

type UpgradeScheduleStore interface {
	upgradesched.Store
	UpdateUpgradePolicy(ctx context.Context, p store.UpgradePolicy) error
}

UpgradeScheduleStore is the persistence behind scheduled and automatic upgrades. *store.DB satisfies it.

type UserCounter ¶ added in v0.2.0

type UserCounter interface {
	CountUsers(ctx context.Context) (int, error)
}

UserCounter is the store surface EnsureSetupToken needs.

type VaultSecrets ¶ added in v0.2.0

type VaultSecrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	DeleteAll(ctx context.Context, serviceName string) error
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
	DeleteValue(ctx context.Context, serviceName, envKey string) error
}

VaultSecrets is the surface the Vault settings handlers need from internal/secrets.Manager: set the credential (PUT), check whether one exists (GET's has_credential, and PUT's "was a credential already set" check for the omitted-credential case), and clear it (DELETE). *secrets.Manager satisfies this structurally, the same "narrow, consumer-defined interface" shape CloudflareTunnelSecrets already establishes.

type VaultSettingsStore ¶ added in v0.2.0

type VaultSettingsStore interface {
	GetVaultSettings(ctx context.Context) (store.VaultSettings, error)
	UpdateVaultSettings(ctx context.Context, s store.VaultSettings) error
	SetVaultCredentialRotation(ctx context.Context, rotatedAt, previousExpiresAt time.Time) error
}

VaultSettingsStore is the store surface GET/PUT/DELETE /api/v1/settings/vault need: the single platform-wide row, always present, the same shape CloudflareTunnelStore has for its own row.

type VolumeCloneRestoreHistoryStore ¶

type VolumeCloneRestoreHistoryStore interface {
	ListVolumeCloneRestores(ctx context.Context, serviceName, volumeName string) ([]store.VolumeCloneRestore, error)
}

VolumeCloneRestoreHistoryStore is the store surface the volume clone-restore history handler needs, the app service volume counterpart of CloneRestoreHistoryStore (database_clone_restore.go).

type VolumeCloneRestoreRunner ¶

type VolumeCloneRestoreRunner interface {
	RunVolumeCloneRestore(ctx context.Context, historyID, sourceServiceName, sourceVolumeName, newVolumeName, backupHistoryID string) error
}

VolumeCloneRestoreRunner is the surface the volume clone-restore handler needs, satisfied by *backup.VolumeCloneRestoreRunner.

type WALShipStatusSource ¶ added in v0.2.0

type WALShipStatusSource interface {
	WALShipStatus(databaseName string) (backup.WALShipStatus, bool)
}

WALShipStatusSource reports the last WAL shipping outcome per database.

type WebhookDeliveryStore ¶

type WebhookDeliveryStore interface {
	SaveWebhookDelivery(ctx context.Context, d store.WebhookDelivery) error
	GetWebhookDelivery(ctx context.Context, id string) (*store.WebhookDelivery, error)
	ListWebhookDeliveries(ctx context.Context, serviceName string, limit int, before *time.Time) ([]store.WebhookDelivery, error)
	// DeleteWebhookDeliveriesOlderThan backs the retention sweep
	// (webhook_delivery_retention.go), the same age-based deletion
	// AuditStore.DeleteAuditEntriesOlderThan already provides for audit_log.
	DeleteWebhookDeliveriesOlderThan(ctx context.Context, cutoff time.Time) (int64, error)
	// PruneFailedWebhookDeliveries caps unsigned deliveries per app so
	// junk requests cannot grow the table between retention sweeps.
	PruneFailedWebhookDeliveries(ctx context.Context, serviceName string, keep int) (int64, error)
}

WebhookDeliveryStore is the store surface real inbound webhook delivery history needs: row-per-delivery CRUD backing GET /api/v1/apps/{name}/webhook-deliveries and its replay endpoint. *store.DB satisfies this structurally.

Source Files ¶

Jump to

Keyboard shortcuts

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