control

package
v0.0.0-...-9ac6046 Latest Latest
Warning

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

Go to latest
Published: Jul 26, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package control owns the Phase 4 control-plane model: owners, apps, deploys, auth metadata, and deploy pointers. It deliberately avoids transport and database choices so HTTP handlers and persistence can be layered on later.

Index

Constants

View Source
const AutoClaimOwnerHandle = "autoclaim"

AutoClaimOwnerHandle is the internal owner used for deployments accepted without an interactive user claim. Its apps are exposed publicly by bare app name even though they remain grouped under this owner for storage and policy.

View Source
const DeployClaimTTL = 5 * time.Minute

DeployClaimTTL is the default lifetime of an unclaimed deploy before it is garbage-collected. Operators can override it per-store with WithDeployClaimTTL.

Variables

View Source
var (
	ErrInvalid   = errors.New("control: invalid input")
	ErrNotFound  = errors.New("control: not found")
	ErrConflict  = errors.New("control: conflict")
	ErrSuspended = errors.New("control: suspended")
	ErrQuota     = errors.New("control: quota exceeded")
)

Functions

func ValidateDigest

func ValidateDigest(label, digest string) error

ValidateDigest validates a SHA-256 digest supplied at an API boundary.

func ValidateEgressHost

func ValidateEgressHost(host string) (string, error)

ValidateEgressHost normalizes and validates an egress allowlist entry. It accepts a public DNS hostname (optionally with a leading dot for the subdomain-wildcard form) and rejects IP literals, single-label/internal names, and anything carrying a scheme, port, or path. This is the add-time half of the SSRF defense; the runner additionally blocks non-public resolved IPs at dial time to stop DNS rebinding.

func ValidateName

func ValidateName(name string) error

ValidateName accepts the namespace-safe handles used for owners and apps.

Types

type App

type App struct {
	ID             string
	OwnerID        string
	Name           string
	ActiveDeployID string
	// Suspended is an operator kill switch: when true, the app does not resolve
	// to a runnable session.
	Suspended bool
	CreatedAt time.Time
}

App is the durable namespace record for <owner>/<name>.

type AppInput

type AppInput struct {
	OwnerID string
	Name    string
}

type Artifact

type Artifact struct {
	ID            string
	Digest        string
	SizeBytes     int64
	ABIVersion    uint8
	BuildMetadata map[string]string
	CreatedAt     time.Time
}

Artifact describes a content-addressed WASM artifact produced by build workers. The control plane stores metadata only, never raw source or WASM.

type ArtifactInput

type ArtifactInput struct {
	Digest        string
	SizeBytes     int64
	ABIVersion    uint8
	BuildMetadata map[string]string
}

type AuthIdentity

type AuthIdentity struct {
	Provider  AuthProvider
	Subject   string
	OwnerID   string
	CreatedAt time.Time
}

AuthIdentity binds an external verified identity to a Plumtree owner.

type AuthProvider

type AuthProvider string
const (
	ProviderShoo AuthProvider = "shoo"
)

type BlobStore

type BlobStore interface {
	Put(id string, data []byte) error
	Get(id string) ([]byte, bool)
	Delete(id string)
	// contains filtered or unexported methods
}

BlobStore holds artifact bytes (compiled WASM). It is separated from the metadata store so large binaries need not live inside the JSON state file: a durable, filesystem-backed store keeps them on disk, while the default in-memory store embeds them in the snapshot for the all-in-one dev process.

type CIToken

type CIToken struct {
	ID        string
	OwnerID   string
	Name      string
	TokenHash string
	Scopes    []TokenScope
	CreatedAt time.Time
	RevokedAt *time.Time
}

CIToken is metadata for an owner-scoped automation token.

type CITokenInput

type CITokenInput struct {
	OwnerID   string
	Name      string
	TokenHash string
	Scopes    []TokenScope
}

type Deploy

type Deploy struct {
	ID               string
	AppID            string
	AppName          string
	AppType          string
	ArtifactID       string
	SourceDigest     string
	CreatedByOwnerID string
	ClaimTokenHash   string
	CreatedAt        time.Time
	ClaimExpiresAt   *time.Time
	ClaimedAt        *time.Time
}

Deploy is an immutable release record for an app.

type DeployClaimInput

type DeployClaimInput struct {
	AppName        string
	AppType        string
	ArtifactID     string
	SourceDigest   string
	ClaimTokenHash string
}

type DeployInput

type DeployInput struct {
	AppID            string
	ArtifactID       string
	SourceDigest     string
	CreatedByOwnerID string
}

type DeployedApp

type DeployedApp struct {
	App   App
	Owner Owner
}

DeployedApp pairs an active app with its namespace owner for server-level administrative listings.

type IdentityInput

type IdentityInput struct {
	Provider AuthProvider
	Subject  string
}

type Option

type Option func(*Store)

func WithAnonymousPreview

func WithAnonymousPreview(enabled bool) Option

WithAnonymousPreview enables anonymous preview run: any deploy is runnable by id at "preview-<deployID>" in the tightest sandbox (no owner capabilities). It is gated because it lets unclaimed code run; enable it only with deploy rate limiting in place.

func WithBlobDir

func WithBlobDir(dir string) Option

WithBlobDir stores compiled WASM artifacts as files under dir instead of inside the JSON state file — durable artifact storage that keeps large binaries out of the metadata snapshot. The directory is created on first use.

func WithClock

func WithClock(now func() time.Time) Option

WithClock lets tests provide deterministic timestamps.

func WithDefaultMaxApps

func WithDefaultMaxApps(n int) Option

WithDefaultMaxApps caps how many apps a single owner may create, applied to any owner without an explicit MaxApps quota. 0 leaves owners uncapped.

func WithDeployClaimTTL

func WithDeployClaimTTL(d time.Duration) Option

WithDeployClaimTTL sets how long an unclaimed deploy survives before it is garbage-collected. Non-positive values keep the default (DeployClaimTTL).

func WithMaxDeployClaimsPerHour

func WithMaxDeployClaimsPerHour(n int) Option

WithMaxDeployClaimsPerHour caps how many new deploy claims may be created across the platform in any rolling hour — the primary control against anonymous-deploy flooding (deploy is gated harder than run). 0 disables it.

func WithMaxSessionsPerAppPerDay

func WithMaxSessionsPerAppPerDay(n int) Option

WithMaxSessionsPerAppPerDay caps how many sessions a single app may start in any rolling 24-hour window, a platform-wide abuse/DDoS control. 0 disables it.

func WithPreviousSnapshotEncryptionKey

func WithPreviousSnapshotEncryptionKey(key []byte) Option

WithPreviousSnapshotEncryptionKey permits a one-time startup migration from a snapshot wrapped by the previous KEK. New writes always use the current key configured by WithSnapshotEncryptionKey.

func WithSnapshotEncryptionKey

func WithSnapshotEncryptionKey(key []byte) Option

WithSnapshotEncryptionKey enables envelope encryption for the durable state snapshot. The 32-byte KEK must come from a managed secret store or a file mounted outside the state volume.

type Owner

type Owner struct {
	ID            string
	Handle        string
	HandleClaimed bool
	// Internal distinguishes reserved platform namespaces from user-owned
	// handles. Internal owners cannot be created or claimed through public flows.
	Internal bool
	// Suspended is an operator kill switch: when true, none of the owner's apps
	// resolve to a runnable session.
	Suspended bool
	CreatedAt time.Time
}

Owner is an authenticated Plumtree namespace owner.

type Quotas

type Quotas struct {
	MaxApps          int
	MaxDeploysPerApp int
	MaxSecretsPerApp int
	MaxSessions      int
}

Quotas are owner-level abuse and cost limits. Zero values mean "unset" in this in-memory implementation.

type SSHKey

type SSHKey struct {
	ID          string
	OwnerID     string
	Name        string
	PublicKey   string
	Fingerprint string
	CreatedAt   time.Time
}

SSHKey is login metadata for owner authentication.

type SSHKeyInput

type SSHKeyInput struct {
	OwnerID     string
	Name        string
	PublicKey   string
	Fingerprint string
}

type SecretInput

type SecretInput struct {
	AppID string
	Key   string
	Value []byte
}

type SecretMetadata

type SecretMetadata struct {
	AppID     string
	Key       string
	Version   int
	CreatedAt time.Time
	UpdatedAt time.Time
}

SecretMetadata records the existence/version of a server-side app secret. Secret values are intentionally outside this package.

type Session

type Session struct {
	ID        string
	AppID     string
	DeployID  string
	StartedAt time.Time
	EndedAt   *time.Time
	// Log is the guest's captured stdout/stderr for the session, size-capped by
	// the runner. LogTruncated reports that output exceeded the cap and the tail
	// was dropped.
	Log          string
	LogTruncated bool
}

Session records a runner session selected by the gateway/control plane.

type Store

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

Store is a concurrency-safe control-plane repository. It is in-memory by default; OpenStore enables local JSON snapshot persistence. A SQL implementation can satisfy the same behavior later.

func NewStore

func NewStore(opts ...Option) *Store

func OpenStore

func OpenStore(snapshotPath string, opts ...Option) (*Store, error)

OpenStore returns a store backed by snapshotPath. A missing path starts empty; subsequent durable mutations atomically rewrite the snapshot file.

func (*Store) ActivateDeploy

func (s *Store) ActivateDeploy(appID, deployID string) (App, error)

ActivateDeploy moves an app's active deploy pointer after proving the deploy belongs to the same app. Deploy records themselves remain immutable.

func (*Store) AddEgressHost

func (s *Store) AddEgressHost(appID, host string) ([]string, error)

AddEgressHost adds host to the app's allowlist if absent. It returns the updated allowlist.

func (*Store) AnonymousPreviewEnabled

func (s *Store) AnonymousPreviewEnabled() bool

AnonymousPreviewEnabled reports whether anonymous preview run is on, so the API can advertise the preview handle to the deploy client.

func (*Store) AppDailyConnections

func (s *Store) AppDailyConnections(appID string) (used, cap int)

AppDailyConnections reports how many sessions the app started in the trailing 24h window and the configured per-app daily cap. A cap of 0 means unlimited.

func (*Store) AuthenticateCIToken

func (s *Store) AuthenticateCIToken(tokenHash string) (CIToken, Owner, error)

AuthenticateCIToken resolves an active (non-revoked) CI token by its hash and returns the token with its owner. Revoked and unknown hashes both report ErrNotFound so callers cannot distinguish them.

func (*Store) AuthorizeDeployClaimUpdate

func (s *Store) AuthorizeDeployClaimUpdate(deployID, appName, sourceDigest, claimTokenHash string) error

AuthorizeDeployClaimUpdate validates an update and its claim proof without requiring an artifact, so callers can reject it before invoking a builder.

func (*Store) ClaimDeploy

func (s *Store) ClaimDeploy(deployID, claimTokenHash, ownerID string) (App, Deploy, string, error)

func (*Store) ClaimOwnerHandle

func (s *Store) ClaimOwnerHandle(ownerID, handle string) (Owner, error)

func (*Store) CreateApp

func (s *Store) CreateApp(in AppInput) (App, error)

func (*Store) CreateArtifact

func (s *Store) CreateArtifact(in ArtifactInput) (Artifact, error)

func (*Store) CreateCIToken

func (s *Store) CreateCIToken(in CITokenInput) (CIToken, error)

func (*Store) CreateDeploy

func (s *Store) CreateDeploy(in DeployInput) (Deploy, error)

func (*Store) CreateDeployClaim

func (s *Store) CreateDeployClaim(in DeployClaimInput) (Deploy, error)

func (*Store) CreateDeployClaimWithArtifact

func (s *Store) CreateDeployClaimWithArtifact(reservation uint64, artifactIn ArtifactInput, wasm []byte, deployIn DeployClaimInput) (Artifact, Deploy, error)

CreateDeployClaimWithArtifact commits artifact metadata, bytes, and the new deploy claim as one store operation. reservation must have been obtained before building with ReserveDeployClaimQuota.

func (*Store) CreateOwner

func (s *Store) CreateOwner(handle string) (Owner, error)

func (*Store) DeleteExpiredDeployClaims

func (s *Store) DeleteExpiredDeployClaims() (int, error)

func (*Store) DeleteSecret

func (s *Store) DeleteSecret(appID, key string) error

DeleteSecret removes a secret (metadata and value). Deleting a missing secret reports ErrNotFound.

func (*Store) DeployClaimTTL

func (s *Store) DeployClaimTTL() time.Duration

DeployClaimTTL returns the configured unclaimed-deploy lifetime, so callers (e.g. cleanup schedulers) stay consistent with the store's expiry policy.

func (*Store) EgressAllowlist

func (s *Store) EgressAllowlist(appID string) []string

EgressAllowlist returns the app's outbound-HTTP host allowlist (a copy).

func (*Store) EndSession

func (s *Store) EndSession(id string) (Session, error)

func (*Store) EnsureApp

func (s *Store) EnsureApp(in AppInput) (App, error)

func (*Store) EnsureAutoClaimOwner

func (s *Store) EnsureAutoClaimOwner() (Owner, error)

EnsureAutoClaimOwner returns the reserved internal owner used for trusted automatic claims. A pre-existing public owner with the reserved handle is rejected instead of receiving deployments intended for the platform owner.

func (*Store) EnsureOwner

func (s *Store) EnsureOwner(handle string) (Owner, error)

func (*Store) EnsureOwnerForIdentity

func (s *Store) EnsureOwnerForIdentity(in IdentityInput) (Owner, AuthIdentity, error)

func (*Store) FindOwner

func (s *Store) FindOwner(handle string) (Owner, error)

func (*Store) GetArtifact

func (s *Store) GetArtifact(id string) (Artifact, error)

func (*Store) GetCIToken

func (s *Store) GetCIToken(id string) (CIToken, error)

func (*Store) GetDeploy

func (s *Store) GetDeploy(id string) (Deploy, error)

func (*Store) GetOwner

func (s *Store) GetOwner(id string) (Owner, error)

func (*Store) InspectDeployClaim

func (s *Store) InspectDeployClaim(deployID, claimTokenHash string) (Deploy, App, Owner, Artifact, error)

func (*Store) ListApps

func (s *Store) ListApps(ownerID string) ([]App, error)

func (*Store) ListCITokens

func (s *Store) ListCITokens(ownerID string) ([]CIToken, error)

ListCITokens returns an owner's CI tokens (active and revoked) ordered by ID.

func (*Store) ListDeployedApps

func (s *Store) ListDeployedApps() []DeployedApp

ListDeployedApps returns all claimed apps with an active deploy, ordered by their owner/app handle.

func (*Store) ListSSHKeys

func (s *Store) ListSSHKeys(ownerID string) ([]SSHKey, error)

ListSSHKeys returns an owner's registered SSH keys ordered by ID.

func (*Store) ListSecrets

func (s *Store) ListSecrets(appID string) []SecretMetadata

ListSecrets returns the value-free metadata for an app's secrets, sorted by key. Values are never returned.

func (*Store) ListSessionsForApp

func (s *Store) ListSessionsForApp(appID string) ([]Session, error)

func (*Store) LoadSnapshot

func (s *Store) LoadSnapshot(path string) error

LoadSnapshot replaces the current store contents with the snapshot at path. Missing files are treated as an empty store.

func (*Store) PutArtifactBytes

func (s *Store) PutArtifactBytes(artifactID string, wasm []byte) error

func (*Store) RecordSessionLog

func (s *Store) RecordSessionLog(id, log string, truncated bool) (Session, error)

RecordSessionLog stores the guest's captured output for a session. truncated reports that the runner dropped output past its size cap. It is safe to call after EndSession.

func (*Store) RegisterSSHKey

func (s *Store) RegisterSSHKey(in SSHKeyInput) (SSHKey, error)

func (*Store) RegisterSuspensionListener

func (s *Store) RegisterSuspensionListener(listener SuspensionListener) func()

RegisterSuspensionListener adds one suspension destination. The returned function unregisters it and is safe to call more than once.

func (*Store) RemoveEgressHost

func (s *Store) RemoveEgressHost(appID, host string) ([]string, error)

RemoveEgressHost drops host from the app's allowlist. Removing an absent host is not an error.

func (*Store) ReserveDeployClaimQuota

func (s *Store) ReserveDeployClaimQuota() (uint64, func(), error)

ReserveDeployClaimQuota reserves capacity in the rolling deploy-claim rate limit before expensive build work starts. The returned release function is idempotent; a successful CreateDeployClaimWithArtifact consumes the ticket.

func (*Store) ResolveActiveDeploy

func (s *Store) ResolveActiveDeploy(ownerHandle, appName string) (App, Deploy, Artifact, error)

func (*Store) ResolveRunnable

func (s *Store) ResolveRunnable(handle string) (App, Deploy, Artifact, []byte, error)

func (*Store) ResolveSSHKey

func (s *Store) ResolveSSHKey(fingerprint string) (SSHKey, Owner, error)

ResolveSSHKey resolves a proved SSH public-key fingerprint to its registered key and owner. Callers must only use this after the SSH transport has verified a signature made by the corresponding private key.

func (*Store) RevokeCIToken

func (s *Store) RevokeCIToken(ownerID, id string) (CIToken, error)

RevokeCIToken marks an owner's CI token revoked. It is idempotent and fails with ErrNotFound if the token is unknown or owned by someone else.

func (*Store) RevokeSSHKey

func (s *Store) RevokeSSHKey(ownerID, id string) error

RevokeSSHKey removes one of an owner's registered SSH keys. A key owned by someone else is reported as not found so ownership cannot be probed.

func (*Store) SecretsForApp

func (s *Store) SecretsForApp(appID string) map[string]string

SecretsForApp returns the app's secret keys and values, for injection into a claimed app's runtime as the Env capability. This is the only method that exposes values, and it stays inside the platform (never reaches an HTTP response).

func (*Store) SetAppSuspended

func (s *Store) SetAppSuspended(appID string, suspended bool) (App, error)

SetAppSuspended toggles the app-level kill switch.

func (*Store) SetDeploySuspended

func (s *Store) SetDeploySuspended(deployID string, suspended bool) error

SetDeploySuspended toggles the deploy-level kill switch. The deploy record is unchanged; suspension is tracked separately so deploy records stay immutable.

func (*Store) SetOwnerSuspended

func (s *Store) SetOwnerSuspended(ownerID string, suspended bool) (Owner, error)

SetOwnerSuspended toggles the owner-level kill switch. While suspended, none of the owner's apps resolve to a runnable session.

func (*Store) StartSession

func (s *Store) StartSession(appID, deployID string) (Session, error)

func (*Store) Subscribe

func (s *Store) Subscribe() (<-chan struct{}, func())

Subscribe registers a listener for runtime-state changes. The returned channel receives a coalesced signal whenever sessions change; the caller re-reads the store to get the new state. The cancel func unregisters and must be called when the listener goes away.

func (*Store) UpdateDeployClaim

func (s *Store) UpdateDeployClaim(deployID string, in DeployClaimInput) (App, Deploy, bool, error)

func (*Store) UpdateDeployClaimWithArtifact

func (s *Store) UpdateDeployClaimWithArtifact(deployID string, artifactIn ArtifactInput, wasm []byte, deployIn DeployClaimInput) (Artifact, App, Deploy, bool, error)

UpdateDeployClaimWithArtifact authenticates again under the commit lock and switches the deploy to a newly-created artifact atomically.

func (*Store) UpsertSecret

func (s *Store) UpsertSecret(in SecretInput) (SecretMetadata, error)

type SuspensionEvent

type SuspensionEvent struct {
	Scope SuspensionScope `json:"scope"`
	ID    string          `json:"id"`
}

type SuspensionListener

type SuspensionListener func(SuspensionEvent) error

SuspensionListener acknowledges an event by returning nil only after all matching sessions under its responsibility have stopped.

type SuspensionScope

type SuspensionScope string
const (
	SuspensionOwner  SuspensionScope = "owner"
	SuspensionApp    SuspensionScope = "app"
	SuspensionDeploy SuspensionScope = "deploy"
)

type TokenScope

type TokenScope string

TokenScope limits CI token use. Tokens are stored by hash only.

const (
	ScopeDeploy  TokenScope = "deploy"
	ScopeInspect TokenScope = "inspect"
	ScopeLogs    TokenScope = "logs"
	ScopeSecrets TokenScope = "secrets"
)

func ParseScope

func ParseScope(raw string) (TokenScope, error)

ParseScope validates and normalizes a raw CI token scope string.

Jump to

Keyboard shortcuts

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