model

package
v0.1.66 Latest Latest
Warning

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

Go to latest
Published: Sep 8, 2026 License: AGPL-3.0 Imports: 5 Imported by: 0

Documentation

Overview

Package model contains Boxy's core domain data models.

Documentation pillars for this package: 1) What the thing is (definition) 2) Why it exists (the problem it solves) 3) When to use it (where it belongs in the system) 4) How to use it correctly (invariants and intended mutation points)

Design intent:

  • Keep these types "data-first": plain structs and small enums.
  • Prefer explicit domain types (PoolName, SandboxID, ResourceType) over raw strings when it prevents mixing up identifiers.
  • Keep behavior and side effects out of the model layer. Orchestrators, pool controllers, providers, agents, and storage adapters should depend on this package, not the other way around.

---

Provider

What:

  • A provider instance is an external system Boxy can provision resources on. Examples: a specific Docker engine, or a specific Hyper-V host.

Why:

  • Boxy must be able to route lifecycle operations (create/inspect/destroy) to the correct external system over time.

When to use: - Use ProviderRef on domain objects that need routing ("which provider owns this?"). - Use the runtime config layer (providersdk.Instance) for provider connection/config.

How to use correctly:

  • ProviderRef.Name must match a configured provider instance name.
  • Avoid using the word "provider" to mean both the code and the external system. In this repo:
  • provider instance = external configured target (providersdk.Instance)
  • ProviderRef = reference from core domain objects
  • driver/adapter = code that talks to a provider type

---

Pool

What: - Pool is a user-facing container of Resources.

Why:

  • Pools give Boxy a place to keep "ready-to-allocate" inventory, which is the foundation of preheating (min_ready) and fast sandbox allocation.

When to use:

  • Use Pool when you want the primary CLI/config noun to be something humans can name ("dev-docker", "win11-vms") and reason about as a bucket.
  • Use Pool inventory when you need to allocate a Resource into a Sandbox or decide whether to provision more inventory.

How to use correctly:

  • Pools should be homogeneous: all Resources in a Pool inventory should share the same ResourceType. (See ResourceCollection.)
  • Resources are single-use: once a Resource leaves a Pool for a Sandbox, it is not returned to any Pool.
  • The model layer does not replenish pools. A controller/reconciler should enforce preheat policy and perform lifecycle transitions.

---

Resource

What: - Resource is a tracked, provisioned instance (VM/container/share/etc).

Why:

  • Boxy needs a stable, backend-agnostic representation of "a thing that exists" so it can allocate it, track its lifecycle, and eventually clean it up.

When to use:

  • Use Resource for anything that can be allocated to a Sandbox and has a lifecycle state.

How to use correctly:

  • Resource.Type is intrinsic: a resource "is a VM" regardless of which pool or sandbox currently references it.
  • If you want homogeneous containers, enforce that at the container boundary (ResourceCollection.Add / Validate) rather than trying to infer a resource's kind from the container it happens to be in.

---

Sandbox

What: - Sandbox is a user-facing environment over 1..N resources, treated as "one thing".

Why:

  • Users want one handle they can name and destroy even when the environment contains multiple resources (VM + DB + share).
  • A sandbox can be as small as a single resource ("container sandbox") or as large as a full lab ("3 VM lab sandbox").

When to use: - Use Sandbox as the primary lifecycle object in the system.

How to use correctly:

  • Sandboxes should reference concrete allocated items; avoid hiding "what was allocated from where" since that is required for cleanup and troubleshooting.

Index

Constants

View Source
const LocalAdminUsername = "admin"

LocalAdminUsername is the fixed username of the single bootstrapped local administrator account (see LocalAdminAccount). Not configurable in v1 — there is exactly one local-admin account per daemon.

Variables

This section is empty.

Functions

This section is empty.

Types

type APIKey added in v0.1.34

type APIKey struct {
	ID        APIKeyID   `json:"id" yaml:"id"`
	Hash      string     `json:"hash" yaml:"hash"`
	Role      APIKeyRole `json:"role" yaml:"role"`
	Name      string     `json:"name,omitempty" yaml:"name,omitempty"`
	CreatedAt time.Time  `json:"created_at" yaml:"created_at"`
	ExpiresAt *time.Time `json:"expires_at,omitempty" yaml:"expires_at,omitempty"`
	RevokedAt *time.Time `json:"revoked_at,omitempty" yaml:"revoked_at,omitempty"`
	// Kind distinguishes an admin-issued service key from a self-service
	// personal key. Empty on every key created before this field existed
	// and on every key the existing admin-only POST /api/v1/api-keys
	// endpoint creates -- see EffectiveKind.
	Kind APIKeyKind `json:"kind,omitempty" yaml:"kind,omitempty"`
	// Subject identifies the human a personal key was minted for (an
	// "oidc:<sub>" identity, see auth.SessionPrincipal). Empty for
	// service keys, which have no such identity to record.
	Subject string `json:"subject,omitempty" yaml:"subject,omitempty"`
}

APIKey is the persisted metadata for an operator credential. The raw key is deliberately never part of this model; Hash is the only credential material stored by the daemon.

func (APIKey) EffectiveKind added in v0.1.53

func (k APIKey) EffectiveKind() APIKeyKind

EffectiveKind returns k.Kind, defaulting to APIKeyKindService for a pre-existing record that predates this field.

func (APIKey) Expired added in v0.1.34

func (k APIKey) Expired(now time.Time) bool

Expired reports whether the key has an expiry in the past.

func (APIKey) Revoked added in v0.1.34

func (k APIKey) Revoked() bool

Revoked reports whether the key has been explicitly revoked.

type APIKeyID added in v0.1.34

type APIKeyID string

APIKeyID identifies an operator API key record.

type APIKeyKind added in v0.1.53

type APIKeyKind string

APIKeyKind distinguishes an admin-issued, long-lived service credential from a self-service, short-lived personal one minted via OIDC login. An empty Kind on an existing persisted record means "service" -- see APIKey.EffectiveKind.

const (
	APIKeyKindService  APIKeyKind = "service"
	APIKeyKindPersonal APIKeyKind = "personal"
)

type APIKeyRole added in v0.1.34

type APIKeyRole string

APIKeyRole controls the operations available to an authenticated API key.

const (
	APIKeyRoleUser    APIKeyRole = "user"
	APIKeyRoleAuditor APIKeyRole = "auditor"
	APIKeyRoleAdmin   APIKeyRole = "admin"
)

func (APIKeyRole) Valid added in v0.1.34

func (r APIKeyRole) Valid() bool

Valid reports whether the role is one of Boxy's supported API-key roles.

type AgentIdentity

type AgentIdentity struct {
	AgentID    string    `json:"agent_id" yaml:"agent_id"`
	CertSerial string    `json:"cert_serial" yaml:"cert_serial"`
	IssuedAt   time.Time `json:"issued_at" yaml:"issued_at"`
}

AgentIdentity records which client certificate serial is currently associated with a registered agent, so an operator can revoke an agent by ID (`boxy agent revoke <id>`) even while it's disconnected — without this, the server would only learn an agent's cert serial while it has a live connection open.

type AgentIdentityID

type AgentIdentityID string

AgentIdentityID identifies a revoked-agent-identity record.

type AgentRegistrationToken

type AgentRegistrationToken struct {
	ID        AgentTokenID `json:"id" yaml:"id"`
	TokenHash string       `json:"token_hash" yaml:"token_hash"`
	CreatedAt time.Time    `json:"created_at" yaml:"created_at"`
	ExpiresAt time.Time    `json:"expires_at" yaml:"expires_at"`
	UsedAt    *time.Time   `json:"used_at,omitempty" yaml:"used_at,omitempty"`
	Label     string       `json:"label,omitempty" yaml:"label,omitempty"`
}

AgentRegistrationToken is a single-use, short-lived bootstrap credential minted by an operator (`boxy agent token create`) and consumed exactly once by `boxy agent serve --token ...` during initial registration. The raw token is never persisted — only its hash, so a store dump does not itself let someone impersonate an agent.

func (AgentRegistrationToken) Expired

func (t AgentRegistrationToken) Expired(now time.Time) bool

Expired reports whether this token's expiry has passed as of now.

func (AgentRegistrationToken) Used

func (t AgentRegistrationToken) Used() bool

Used reports whether this token has already been redeemed.

type AgentTokenID

type AgentTokenID string

AgentTokenID identifies a registration token record.

type Execution added in v0.1.60

type Execution struct {
	ID                 ExecutionID        `json:"id"`
	SandboxID          SandboxID          `json:"sandbox_id"`
	ResourceID         ResourceID         `json:"resource_id"`
	ActorID            string             `json:"actor_id,omitempty"`
	Status             ExecutionStatus    `json:"status"`
	InputKind          ExecutionInputKind `json:"input_kind"`
	RequestFingerprint string             `json:"request_fingerprint"`
	CreatedAt          time.Time          `json:"created_at"`
	StartedAt          *time.Time         `json:"started_at,omitempty"`
	FinishedAt         *time.Time         `json:"finished_at,omitempty"`
	DeadlineAt         time.Time          `json:"deadline_at"`
	ExitCode           *int               `json:"exit_code,omitempty"`
	Error              string             `json:"error,omitempty"`
	Truncated          bool               `json:"truncated,omitempty"`
	Chunks             []ExecutionChunk   `json:"chunks,omitempty"`
}

Execution is the durable, safe representation of a sandbox command. Deliberately absent are command arguments, script content, environment values, and credentials. The in-process worker retains those only until the provider call finishes.

type ExecutionChunk added in v0.1.60

type ExecutionChunk struct {
	Cursor  uint64 `json:"cursor"`
	Stream  string `json:"stream"`
	Data    []byte `json:"data"`
	Dropped bool   `json:"dropped,omitempty"`
}

ExecutionChunk is one immutable, cursor-addressable output chunk. Cursor values are assigned by the execution service and are not byte offsets; this guarantees reconnects only resume at chunk boundaries.

type ExecutionID added in v0.1.60

type ExecutionID string

ExecutionID identifies one accepted sandbox execution.

type ExecutionInputKind added in v0.1.60

type ExecutionInputKind string

ExecutionInputKind describes the source of an execution request without storing the request's sensitive or potentially large content.

const (
	ExecutionInputCommand     ExecutionInputKind = "command"
	ExecutionInputCommandText ExecutionInputKind = "command_text"
	ExecutionInputScript      ExecutionInputKind = "script"
	ExecutionInputStdin       ExecutionInputKind = "stdin"
)

type ExecutionStatus added in v0.1.60

type ExecutionStatus string

ExecutionStatus is the control-plane lifecycle of an execution.

const (
	ExecutionStatusPending     ExecutionStatus = "pending"
	ExecutionStatusRunning     ExecutionStatus = "running"
	ExecutionStatusSucceeded   ExecutionStatus = "succeeded"
	ExecutionStatusFailed      ExecutionStatus = "failed"
	ExecutionStatusCancelled   ExecutionStatus = "cancelled"
	ExecutionStatusInterrupted ExecutionStatus = "interrupted"
)

func (ExecutionStatus) IsTerminal added in v0.1.60

func (s ExecutionStatus) IsTerminal() bool

IsTerminal reports whether an execution will receive no more output.

type LocalAdminAccount added in v0.1.53

type LocalAdminAccount struct {
	Username     string    `json:"username" yaml:"username"`
	PasswordHash string    `json:"password_hash" yaml:"password_hash"`
	CreatedAt    time.Time `json:"created_at" yaml:"created_at"`
}

LocalAdminAccount is the daemon's single bootstrapped local administrator account, used to log into the web UI (SessionKindLocalAdmin) when no OIDC provider is configured, or as a break-glass login even when one is. Only PasswordHash is persisted; the raw bootstrap password is generated once, written to a restricted-permission file for one-time CLI retrieval, and never stored here — the same "hash persisted, raw value shown once" discipline as APIKey/api-key bootstrap.

type Pool

type Pool struct {
	Name PoolName `json:"name" yaml:"name"`

	// Template is the reusable desired resource shape used by this pool.
	Template string `json:"template,omitempty" yaml:"template,omitempty"`

	// Source and Packages are the resolved resource configuration carried by
	// this pool. They are optional for legacy inline pools.
	Source   string   `json:"source,omitempty" yaml:"source,omitempty"`
	Packages []string `json:"packages,omitempty" yaml:"packages,omitempty"`

	// Policies are pool-level behavioral controls (preheating, limits, etc).
	Policies PoolPolicies `json:"policies,omitempty" yaml:"policies,omitempty"`

	// Drain records desired drain state for unused pool inventory.
	Drain PoolDrainState `json:"drain,omitempty" yaml:"drain,omitempty"`

	// Configuration records where editable policy values came from. Static
	// provider, template, store, and secret definitions remain local-file owned.
	Configuration PoolConfigurationState `json:"configuration,omitempty" yaml:"configuration,omitempty"`

	// Inventory is the current contents of the pool.
	Inventory ResourceCollection `json:"inventory" yaml:"inventory"`
}

Pool is a user-facing container of resources.

func (Pool) EffectivelyDrained

func (p Pool) EffectivelyDrained() bool

EffectivelyDrained reports whether the pool should currently be drained.

type PoolConfigurationState added in v0.1.65

type PoolConfigurationState struct {
	Provenance    string    `json:"provenance,omitempty" yaml:"provenance,omitempty"`
	LocalRevision string    `json:"local_revision,omitempty" yaml:"local_revision,omitempty"`
	Pending       bool      `json:"pending,omitempty" yaml:"pending,omitempty"`
	UpdatedAt     time.Time `json:"updated_at,omitempty" yaml:"updated_at,omitempty"`
}

type PoolDebugPolicy added in v0.1.65

type PoolDebugPolicy struct {
	// RetainFailedResources keeps a resource's VM and rotated guest
	// credential running after admission (personalization or package
	// application) fails, instead of the default power-down-and-remove
	// teardown. A manual Retry against a retained resource re-admits it in
	// place -- reusing the same VM and credential -- rather than destroying
	// and recreating it from the template. Intended only for
	// troubleshooting: a retained failed resource still consumes pool
	// max_total capacity and can make the pool blocked exactly like any
	// other failed resource.
	RetainFailedResources bool `json:"retain_failed_resources,omitempty" yaml:"retain_failed_resources,omitempty"`
}

PoolDebugPolicy controls operator-opt-in troubleshooting behavior for a pool.

type PoolDrainState

type PoolDrainState struct {
	// ConfigDeclared is true when config declares the pool drained.
	ConfigDeclared bool `json:"config_declared,omitempty" yaml:"config_declared,omitempty"`

	// Operator is a persisted operator/debug override.
	Operator bool `json:"operator,omitempty" yaml:"operator,omitempty"`
}

PoolDrainState records whether a pool should destroy and avoid creating unused ready inventory.

func (PoolDrainState) Effective

func (d PoolDrainState) Effective() bool

Effective reports whether either config or operator state keeps the pool drained.

type PoolName

type PoolName string

PoolName is the stable, user-facing handle for a pool (the thing typed in CLI/config).

type PoolPolicies

type PoolPolicies struct {
	// Preheat controls keeping resources ready ahead of time.
	Preheat PreheatPolicy `json:"preheat,omitempty" yaml:"preheat,omitempty"`

	// Recycle controls periodic replacement of unused pool inventory.
	//
	// This does NOT mean resources are returned to the pool after sandbox use.
	// Resources remain single-use; recycle applies only to unused inventory.
	Recycle RecyclePolicy `json:"recycle,omitempty" yaml:"recycle,omitempty"`

	// Debug controls operator-opt-in troubleshooting behavior that trades
	// safety/cost for investigability. Debug settings are local-config-owned
	// only, like provider/template/store/secret definitions -- they are not
	// exposed through the pool Save-and-Apply web/API surface.
	Debug PoolDebugPolicy `json:"debug,omitempty" yaml:"debug,omitempty"`
}

PoolPolicies captures pool-level behavior without prescribing a specific CLI/API surface yet.

type PreheatPolicy

type PreheatPolicy struct {
	// MinReady is the number of ready units the pool should try to keep
	// available in the background. It is a soft preheat target, not a
	// second hard admission cap stacked on top of MaxTotal: failing to
	// reach MinReady alone never rejects an allocation request (see
	// #240) -- though a request can still fail for other reasons, e.g. a
	// drained pool or a provisioning error. A live allocation call may
	// still opportunistically top up toward MinReady in the background,
	// so a failure in that best-effort top-up can itself surface as an
	// error even when the request was already satisfiable -- see #249
	// for that residual gap.
	MinReady int `json:"min_ready,omitempty" yaml:"min_ready,omitempty"`

	// MaxTotal is the maximum total units that may exist for the pool.
	MaxTotal int `json:"max_total,omitempty" yaml:"max_total,omitempty"`
}

PreheatPolicy is the pool policy for keeping resources ready ahead of time.

type Profile

type Profile struct {
	Type ResourceType    `json:"type" yaml:"type"`
	Name ResourceProfile `json:"name" yaml:"name"`
}

Profile is a catalog entry defining an allowed (Type, Profile) pair.

This is intentionally minimal scaffolding. It exists to prevent "random strings at call sites" from becoming the de facto API.

func (Profile) Validate

func (p Profile) Validate() error

type ProfileRegistry

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

ProfileRegistry is a simple in-memory catalog of supported profiles.

It is Boxy-owned (not provider-owned): a profile name is a stable identifier that Boxy components can match on across pools and requests.

func NewProfileRegistry

func NewProfileRegistry(profiles []Profile) (*ProfileRegistry, error)

func (*ProfileRegistry) Has

type ProviderRef

type ProviderRef struct {
	Name string `json:"name" yaml:"name"`

	// AgentID is the specific agent instance (embedded or remote) that
	// provisioned this resource, stamped once at creation time. It is
	// deliberately distinct from Name (the provider type/instance): once
	// more than one agent can advertise the same provider type, any
	// lifecycle call on an existing resource (Destroy, Allocate) must
	// route back to this exact agent rather than re-resolving by type,
	// or it risks silently misrouting to a different agent that knows
	// nothing about the resource. See docs/adr/0005-remote-agent-transport-and-registration.md.
	AgentID string `json:"agent_id,omitempty" yaml:"agent_id,omitempty"`
}

ProviderRef identifies the provider instance that owns a resource.

This intentionally does not embed provider connection/config data. The canonical configured providers live in the runtime config (see providersdk.Instance).

For now, Name is the stable handle and must match a configured provider name. If/when renames become a real feature, introduce an immutable ID here.

type RecyclePolicy

type RecyclePolicy struct {
	// MaxAge is an optional upper bound on how long an unused resource may sit in
	// a pool before it should be recycled (destroy + replace).
	// Example values: "30m", "8h", "24h".
	MaxAge string `json:"max_age,omitempty" yaml:"max_age,omitempty"`
}

RecyclePolicy describes when unused resources should be destroyed and replaced.

type Resource

type Resource struct {
	ID ResourceID `json:"id,omitempty" yaml:"id,omitempty"`

	// Type is intrinsic to the resource, independent of which container holds it.
	Type ResourceType `json:"type,omitempty" yaml:"type,omitempty"`

	// Profile is a Boxy-defined variant identifier for this resource's Type.
	// Example: vm "win-2022", container "ubuntu-2204".
	Profile ResourceProfile `json:"profile,omitempty" yaml:"profile,omitempty"`

	// OriginPool is the immutable pool that originally provisioned this resource.
	// It is used for pool-level capacity accounting even after allocation removes
	// the resource from ready inventory.
	OriginPool PoolName `json:"origin_pool,omitempty" yaml:"origin_pool,omitempty"`

	// CurrentPool is the pool that currently owns this resource for inventory
	// and capacity accounting. Empty on legacy records means OriginPool.
	CurrentPool PoolName `json:"current_pool,omitempty" yaml:"current_pool,omitempty"`

	// PendingPool is set while a resource is being promoted into another pool.
	// It is cleared when promotion succeeds or the resource is quarantined.
	PendingPool PoolName `json:"pending_pool,omitempty" yaml:"pending_pool,omitempty"`

	// Provider identifies the external system instance this resource belongs to.
	Provider ProviderRef `json:"provider" yaml:"provider"`

	State ResourceState `json:"state,omitempty" yaml:"state,omitempty"`

	// Properties holds provider-specific data that Boxy core should not interpret.
	Properties map[string]any `json:"properties,omitempty" yaml:"properties,omitempty"`

	// AppliedPackages records successful resource-package applications. The
	// package engine uses the immutable reference and canonical input digest for
	// idempotency; this is not a guest drift detector.
	AppliedPackages []resourcepack.AppliedPackage `json:"applied_packages,omitempty" yaml:"applied_packages,omitempty"`

	CreatedAt time.Time `json:"created_at,omitempty" yaml:"created_at,omitempty"`
	UpdatedAt time.Time `json:"updated_at,omitempty" yaml:"updated_at,omitempty"`
}

Resource is a provisioned instance tracked by Boxy.

func (Resource) EffectivePool added in v0.1.54

func (r Resource) EffectivePool() PoolName

EffectivePool returns the current inventory owner, preserving compatibility with resources persisted before current ownership was introduced.

type ResourceCollection

type ResourceCollection struct {
	// ExpectedType is a constraint: all Resources must have Resource.Type == ExpectedType.
	ExpectedType ResourceType `json:"expected_type" yaml:"expected_type"`

	// ExpectedProfile is a constraint: all Resources must have Resource.Profile == ExpectedProfile.
	ExpectedProfile ResourceProfile `json:"expected_profile" yaml:"expected_profile"`

	Resources []Resource `json:"resources,omitempty" yaml:"resources,omitempty"`
}

ResourceCollection is a homogeneous container of resources.

func (*ResourceCollection) Add

func (c *ResourceCollection) Add(r Resource) error

Add appends r if it satisfies the collection invariant.

func (ResourceCollection) Validate

func (c ResourceCollection) Validate() error

Validate checks that the collection is internally consistent.

type ResourceID

type ResourceID string

ResourceID is a stable identifier for a resource tracked by Boxy.

type ResourceProfile

type ResourceProfile string

ResourceProfile is a Boxy-defined variant identifier for a ResourceType.

Think of it as the "pooling key" beyond the coarse ResourceType: - VM: "win-2022", "ubuntu-2204", "ubuntu-2204-devbox" - Container: "ubuntu-2204", "ubuntu-2204-lamp" - Share: "default", "smb-basic"

Profiles are type-dependent by design; "win-2022" only makes sense for vm.

const (
	// ResourceProfileDefault is the conventional "no special customization" profile.
	//
	// Using an explicit default keeps pools deterministic (no implicit meaning for "").
	ResourceProfileDefault ResourceProfile = "default"
)

type ResourceRequest

type ResourceRequest struct {
	Type     ResourceType    `json:"type" yaml:"type"`
	Profile  ResourceProfile `json:"profile" yaml:"profile"`
	Count    int             `json:"count" yaml:"count"`
	Packages []string        `json:"packages,omitempty" yaml:"packages,omitempty"`
}

ResourceRequest expresses demand for one or more resources matching a (Type, Profile) key.

This is intentionally small scaffolding: - It is not a full "spec" or "configuration". - It exists to make pooling/matching deterministic beyond coarse ResourceType.

Examples:

  • {Type: vm, Profile: "win-2022", Count: 3}
  • {Type: container, Profile: "ubuntu-2204", Count: 1}
  • {Type: share, Profile: "default", Count: 1}

func (ResourceRequest) Validate

func (r ResourceRequest) Validate() error

type ResourceState

type ResourceState string

ResourceState is the lifecycle state of a resource.

const (
	ResourceStateUnknown      ResourceState = "unknown"
	ResourceStateProvisioning ResourceState = "provisioning"
	ResourceStateReady        ResourceState = "ready"
	ResourceStateAllocated    ResourceState = "allocated"
	ResourceStateReleased     ResourceState = "released"
	// ResourceStateRecycling marks a resource being torn down by pool-level
	// max-age recycling (see RecyclePolicy) specifically, distinct from
	// ResourceStateDestroying (drain and explicit sandbox-triggered destroy).
	// It exists purely for observability: without it, a resource mid-teardown
	// looks identical to a healthy one (via the REST API, CLI, or persisted
	// state) until it suddenly disappears, which is indistinguishable from a
	// stalled/hung backend.
	ResourceStateRecycling  ResourceState = "recycling"
	ResourceStateDestroying ResourceState = "destroying"
	ResourceStatePromoting  ResourceState = "promoting"
	ResourceStateDestroyed  ResourceState = "destroyed"
	ResourceStateError      ResourceState = "error"
)

type ResourceTemplate added in v0.1.54

type ResourceTemplate struct {
	Name     string         `json:"name" yaml:"name"`
	Extends  string         `json:"extends,omitempty" yaml:"extends,omitempty"`
	Type     string         `json:"type,omitempty" yaml:"type,omitempty"`
	Provider string         `json:"provider,omitempty" yaml:"provider,omitempty"`
	Agent    string         `json:"agent,omitempty" yaml:"agent,omitempty"`
	Source   string         `json:"source,omitempty" yaml:"source,omitempty"`
	Config   map[string]any `json:"config,omitempty" yaml:"config,omitempty"`
	Packages []string       `json:"packages,omitempty" yaml:"packages,omitempty"`
}

ResourceTemplate is a reusable desired shape for a resource. It is kept separate from Pool because a template describes what should be built while a Pool describes how much inventory to maintain.

type ResourceType

type ResourceType string

ResourceType is the domain category of a resource (vm/container/share/etc).

const (
	ResourceTypeUnknown   ResourceType = "unknown"
	ResourceTypeVM        ResourceType = "vm"
	ResourceTypeContainer ResourceType = "container"
	ResourceTypeShare     ResourceType = "share"
	ResourceTypeNetwork   ResourceType = "network"
	ResourceTypeDB        ResourceType = "db"
)

type RevokedAgentIdentity

type RevokedAgentIdentity struct {
	ID         AgentIdentityID `json:"id" yaml:"id"`
	AgentID    string          `json:"agent_id" yaml:"agent_id"`
	CertSerial string          `json:"cert_serial" yaml:"cert_serial"`
	RevokedAt  time.Time       `json:"revoked_at" yaml:"revoked_at"`
	Reason     string          `json:"reason,omitempty" yaml:"reason,omitempty"`
}

RevokedAgentIdentity is a deny-list entry: once an agent's client certificate serial is revoked, the server must refuse new connections presenting that certificate, regardless of expiry, and tear down any live connection using it.

type Sandbox

type Sandbox struct {
	ID      SandboxID `json:"id" yaml:"id"`
	Name    string    `json:"name,omitempty" yaml:"name,omitempty"`
	OwnerID string    `json:"owner_id,omitempty" yaml:"owner_id,omitempty"`

	// Policies are sandbox-level behavioral controls (security, retention, etc).
	Policies SandboxPolicies `json:"policies,omitzero" yaml:"policies,omitempty"`

	// Status is the async lifecycle state of the sandbox request.
	Status SandboxStatus `json:"status,omitempty" yaml:"status,omitempty"`

	// Requests are the desired resources for this sandbox.
	Requests []ResourceRequest `json:"requests,omitempty" yaml:"requests,omitempty"`

	// Error is a human-readable failure detail when Status=failed.
	Error string `json:"error,omitempty" yaml:"error,omitempty"`

	// Resources are the resources that make up this sandbox.
	Resources []ResourceID `json:"resources,omitempty" yaml:"resources,omitempty"`

	// ExpiresAt is the absolute time this sandbox should be automatically
	// destroyed, computed from Policies.AutoDestroyAfter at creation time.
	// Nil means no automatic expiry.
	ExpiresAt *time.Time `json:"expires_at,omitempty" yaml:"expires_at,omitempty"`
}

Sandbox is a user-facing environment that contains 1..N resources.

This model is intentionally minimal. Orchestration state and richer composition semantics are layered on later.

type SandboxID

type SandboxID string

SandboxID is a stable identifier for a sandbox (user-facing handle).

type SandboxPolicies

type SandboxPolicies struct {
	// AutoDestroyAfter is an optional retention setting (e.g. "30m", "8h").
	// Empty means "no policy set here".
	AutoDestroyAfter string `json:"auto_destroy_after,omitempty" yaml:"auto_destroy_after,omitempty"`

	// SecurityProfile is an optional label for sandbox hardening posture.
	// Examples: "default", "lab", "pentest", "vdi".
	SecurityProfile string `json:"security_profile,omitempty" yaml:"security_profile,omitempty"`
}

SandboxPolicies captures sandbox-level behavior without prescribing a specific CLI/API surface yet.

type SandboxStatus

type SandboxStatus string

SandboxStatus is the lifecycle state of a sandbox request.

const (
	SandboxStatusPending      SandboxStatus = "pending"
	SandboxStatusProvisioning SandboxStatus = "provisioning"
	SandboxStatusReady        SandboxStatus = "ready"
	SandboxStatusDeleting     SandboxStatus = "deleting"
	SandboxStatusFailed       SandboxStatus = "failed"
)

func (SandboxStatus) IsTransient added in v0.1.44

func (s SandboxStatus) IsTransient() bool

IsTransient reports whether the sandbox is actively changing state (pending/provisioning/deleting) rather than settled into a terminal state (ready/failed). This is the single source of truth for that distinction — consumers such as the web dashboard's "in progress" badge styling should call this instead of hardcoding the transient status list, so a future lifecycle status only needs to be classified here once.

type Session added in v0.1.53

type Session struct {
	ID   SessionID   `json:"id" yaml:"id"`
	Hash string      `json:"hash" yaml:"hash"`
	Kind SessionKind `json:"kind" yaml:"kind"`
	// Subject identifies the principal within Kind: the local admin
	// account's username for SessionKindLocalAdmin, or the OIDC subject
	// claim for SessionKindOIDC.
	Subject   string     `json:"subject" yaml:"subject"`
	Role      APIKeyRole `json:"role" yaml:"role"`
	CreatedAt time.Time  `json:"created_at" yaml:"created_at"`
	ExpiresAt time.Time  `json:"expires_at" yaml:"expires_at"`
}

Session is a server-side web-UI login session. This is a browser-only concept, separate from and unaffected by the CLI/API bearer-key model in APIKey: a session authenticates a human at the dashboard, not a programmatic REST caller. Only Hash is persisted; the raw cookie value is generated once at login (see internal/auth) and never stored, matching how APIKey stores a hash rather than the raw key.

func (Session) Expired added in v0.1.53

func (s Session) Expired(now time.Time) bool

Expired reports whether the session's expiry has passed.

type SessionID added in v0.1.53

type SessionID string

SessionID identifies a persisted web-UI login session record.

type SessionKind added in v0.1.53

type SessionKind string

SessionKind identifies how a session's principal was established.

const (
	// SessionKindLocalAdmin is a session created by logging in with the
	// bootstrapped local admin account (see LocalAdminAccount).
	SessionKindLocalAdmin SessionKind = "local_admin"
	// SessionKindOIDC is a session created by a completed OIDC login.
	// Not produced anywhere yet; reserved for when OIDC support lands.
	SessionKindOIDC SessionKind = "oidc"
)

Jump to

Keyboard shortcuts

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