Documentation
¶
Overview ¶
Package definition is the mooring.yaml definition file (plan §7.7): the declarative source of truth for an app's Mooring-managed surface. It is a SECOND front-end onto the same reconciler/§5.6 validator the dashboard drives — a new front door, never a new trust path. Nothing in it reaches `docker compose` unvalidated.
Mooring OWNS the runtime: the operator declares a multi-service STACK here and Mooring GENERATES the compose (and, for build services, the Dockerfile). There is no way to supply a raw compose/Dockerfile — `compose.source` is generated-only. `services` is a map keyed by name; per-service `env` is a map of literals/secret references (compose-familiar).
Index ¶
- Constants
- Variables
- func Canonical(d *Definition) ([]byte, error)
- func CanonicalHost(h *Host) ([]byte, error)
- func ComposeBytes(d *Definition) ([]byte, error)
- func Kind(raw []byte) (string, error)
- func ManagedCertDir(service, hostname string) string
- func ManagedConfigPath(service string, i int) string
- func ManagedSecretPath(service, name string) string
- func PeekMetadata(raw []byte) (slug, name string)
- func Validate(d *Definition, runDir string, env compose.Env, protectedPaths []string) error
- type AckSet
- type AppRegistration
- type AppSource
- type Binding
- type Build
- type CertBinding
- type Compose
- type ConfigFile
- type DefaultScaling
- type Defaults
- type Definition
- type Edge
- type EnvValue
- type Git
- type Host
- type HostSpec
- type L4Route
- type Metadata
- type NofileLimit
- type OpsInterface
- type Orchestration
- type OrderEdge
- type Plan
- type Port
- type Route
- type Scaling
- type ScalingMetric
- type ScheduledTask
- type Secret
- type SelfHealing
- type Service
- type Setup
- type Spec
- type Store
- func (s *Store) CommitForVersion(slug string, id int64) (string, error)
- func (s *Store) Current(slug string) (*Definition, error)
- func (s *Store) DeleteApp(ctx context.Context, slug string) error
- func (s *Store) DeleteVersion(ctx context.Context, slug string, id int64) error
- func (s *Store) List(slug string) ([]VersionMeta, error)
- func (s *Store) SaveCanonical(ctx context.Context, d *Definition, note, commit string) (int64, error)
- func (s *Store) Version(slug string, id int64) (*Definition, error)
- type Ulimits
- type VersionMeta
- type Volume
- type Widening
Constants ¶
const APIVersion = "mooring/v1"
APIVersion is the ONLY accepted envelope version — exact-match, fail-closed.
const SourceGenerated = "generated"
SourceGenerated is the only accepted compose source.
Variables ¶
var ErrNotDeletable = errors.New("version not found, or it is the current live version (which cannot be deleted)")
ErrNotDeletable means a version delete targeted a non-existent id or the current live version (the latest row, which cannot be deleted). It maps to a 400 (a raw DB error maps to a 500).
var ErrTampered = errors.New("definition HMAC mismatch (tampered)")
ErrTampered means a stored definition's HMAC did not verify (changed outside Mooring). It is never loaded — fail-closed.
Functions ¶
func Canonical ¶
func Canonical(d *Definition) ([]byte, error)
Canonical re-marshals a definition to canonical YAML (stable field order from the struct) — what is written back to canonical.yaml on every successful apply, so the stored form is always Mooring's typed render, never the operator's raw bytes.
func CanonicalHost ¶
Canonical re-marshals a host definition to canonical YAML.
func ComposeBytes ¶
func ComposeBytes(d *Definition) ([]byte, error)
ComposeBytes returns the compose document this definition would deploy: ALWAYS generated from the typed services — Mooring owns the compose. There is no raw (repo_path/inline) source.
func Kind ¶
Kind peeks the `kind` field for dispatch (App vs Host). It is a loose read used ONLY to choose the typed parser — the real Parse/ParseHost then re-does the full hardened, parser-differential-resistant validation, so a mis-peek can't bypass it.
func ManagedCertDir ¶
ManagedCertDir is the run-dir-relative directory a cert binding is synced into (tls.crt + tls.key) and bind-mounted from. service + hostname are schema-validated.
func ManagedConfigPath ¶
ManagedConfigPath / ManagedSecretPath are the run-dir-relative paths where Mooring materializes a service's config file / secret file (and the compose bind source). Kept here so reconcile (which emits the mount) and the deploy (which writes the content) always agree. The service name, secret name, and index are schema-validated, so the path is traversal-free.
func ManagedSecretPath ¶
func PeekMetadata ¶
PeekMetadata leniently reads metadata.slug + metadata.name from a mooring file — just enough to label a multi-file repo's chooser (which file → which app). It does NOT validate the document; the slug it returns is re-checked by gitstore.Save (the real gate) before any app is created, and the full hardened Parse runs at deploy.
Types ¶
type AppRegistration ¶
type AppRegistration struct {
Slug string `yaml:"slug"`
Source AppSource `yaml:"source"`
Enabled bool `yaml:"enabled"`
}
AppRegistration is one entry in the registry — the ONLY place the set of apps on the box is enumerated. Registering does NOT deploy.
type AppSource ¶
type AppSource struct {
Repo string `yaml:"repo,omitempty"`
Ref string `yaml:"ref,omitempty"`
Path string `yaml:"path,omitempty"`
Managed bool `yaml:"managed,omitempty"`
}
AppSource is a oneOf: a repo (+ref), a local path, or managed-in-place.
type Binding ¶
Binding resolves one {{hm.KEY}} token in a config-file template. Exactly one form: a scalar literal, or a single-key mapping selecting a source —
- { secret: NAME } the encrypted secret value (marks the file secret-bearing)
- { env: NAME } the SAME service's env value (literal or secret-backed)
- { app: FIELD } a safe app field (currently only `slug`)
- { cert: HOSTNAME.field } a path to a SAME-service cert binding's tls.crt|key|ca
This is the superset of the legacy dashboard binding sources, so the dashboard's config-file editor can express the full capability with nothing lost.
func (Binding) MarshalYAML ¶
MarshalYAML renders the canonical form: the single source mapping for a reference, else the scalar literal — so Canonical round-trips back through UnmarshalYAML.
type Build ¶
type Build struct {
Language string `yaml:"language,omitempty"`
Version string `yaml:"version,omitempty"`
Dir string `yaml:"dir,omitempty"` // repo-relative subdir to build from (default ".")
Base string `yaml:"base,omitempty"` // generic only
Install string `yaml:"install,omitempty"`
BuildCmd string `yaml:"build,omitempty"`
Start []string `yaml:"start,omitempty"`
Env map[string]string `yaml:"env,omitempty"`
Packages []string `yaml:"packages,omitempty"`
Output string `yaml:"output,omitempty"` // build output dir to ship (e.g. static: "dist")
Nonroot *bool `yaml:"run_as_nonroot,omitempty"`
}
Build is the declarative build spec — Mooring GENERATES the Dockerfile from it.
type CertBinding ¶
type CertBinding struct {
Hostname string `yaml:"hostname"`
Subdomain string `yaml:"subdomain,omitempty"` // XOR hostname: expands to <subdomain>.<namespace apex>
BaseDomain string `yaml:"base_domain,omitempty"` // per-item namespace NAME override (only with subdomain)
Mount string `yaml:"mount"`
CA string `yaml:"ca,omitempty"` // "" = default issuer; else a named CA from config.yaml edge.cas
}
CertBinding syncs a managed edge cert into a service. The edge issues AND renews the leaf; Mooring copies it into the service's mount and recreates the service at deploy AND autonomously on renewal (a background watcher re-syncs + recreates the affected service when the edge renews the leaf), so a renewed cert is picked up without a manual redeploy.
type Compose ¶
type Compose struct {
Source string `yaml:"source,omitempty"`
Services map[string]Service `yaml:"services,omitempty"`
Path string `yaml:"path,omitempty"`
Inline string `yaml:"inline,omitempty"`
}
Compose is GENERATED-ONLY: Mooring owns the compose. `source` defaults to and may only be "generated". The legacy `repo_path`/`inline` sources are rejected; Path and Inline are retained ONLY so a stale definition gets a clear, guiding rejection.
type ConfigFile ¶
type ConfigFile struct {
Repo string `yaml:"repo,omitempty"`
Template string `yaml:"template,omitempty"`
Mount string `yaml:"mount"`
Bindings map[string]Binding `yaml:"bindings,omitempty"`
}
ConfigFile is an app config file Mooring renders + bind-mounts read-only into a service. Content is a repo path (git cat-file @ pinned commit) XOR inline template. Bindings is the explicit allowlist of {{hm.KEY}} tokens the file may resolve; the app's own ${…} survive byte-identical.
type DefaultScaling ¶
DefaultScaling is the host-default scaling envelope (a ceiling, projectable).
type Defaults ¶
type Defaults struct {
Scaling *DefaultScaling `yaml:"scaling,omitempty"`
SelfHealing *bool `yaml:"self_healing,omitempty"` // enable/disable the supervisor
AutoDeploy *bool `yaml:"auto_deploy,omitempty"` // default git auto-deploy (widening → ack)
}
Defaults is the global base layer projected BENEATH each app's spec (resolved before §5.6). It carries ONLY the Tier-3 subset of knobs — never edge.routes or git.ref (which don't exist here by construction) and never a Tier-1 field. A default may TIGHTEN a posture but never silently WIDEN one (see posture.go).
POSTURE-SENSITIVE: every field here must be handled by PostureWidenings() in posture.go. TestDefaultsFieldsAllPostureChecked enforces this — adding a field without a widening check fails that test, so the predicate stays closed.
type Definition ¶
type Definition struct {
APIVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
Metadata Metadata `yaml:"metadata"`
Spec Spec `yaml:"spec"`
}
Definition is the whole mooring.yaml document (kind: App).
func Parse ¶
func Parse(raw []byte) (*Definition, error)
Parse turns mooring.yaml bytes into a validated, typed App Definition. It is the parser-differential-resistant chokepoint (plan §7.7):
- reject YAML anchors, aliases, and merge keys (<<) — they let one parser see a different document than another, smuggling a key past validation;
- reject duplicate keys (last-wins ambiguity);
- reject a SECOND YAML document;
- reject unknown keys (KnownFields — additionalProperties:false everywhere);
- reject any Tier-1 security field (the 3-tier boundary, §7.8);
- exact apiVersion + kind + immutable-slug shape, fail-closed.
type Edge ¶
type Edge struct {
// BaseDomain names which operator-declared namespace (config.yaml edge.base_domains[].name)
// this app's `subdomain:` shorthands expand under. "" = the default (edge.base_domain). It
// is a NAME referencing operator config, never an apex the app can invent — an undeclared
// name fails the deploy (the name lives in config.yaml, not this repo). A route/cert_binding
// may override it per-item.
BaseDomain string `yaml:"base_domain,omitempty"`
Routes []Route `yaml:"routes,omitempty"`
L4Routes []L4Route `yaml:"l4_routes,omitempty"`
}
Edge is the Layer-1 route input (§6).
type EnvValue ¶
EnvValue is a per-service env var: a literal value XOR a `{secret: NAME}` reference. A scalar is a literal; a mapping must be exactly `{ secret: NAME }`.
func (EnvValue) MarshalYAML ¶
MarshalYAML renders the canonical form: a `{secret: NAME}` mapping for a reference, else the scalar literal — so Canonical round-trips back through UnmarshalYAML.
type Git ¶
type Git struct {
Repo string `yaml:"repo"`
Ref string `yaml:"ref"`
AutoDeploy bool `yaml:"auto_deploy"`
}
Git is the repo-path / auto-pull config (§7.6). AutoDeploy defaults false.
type Host ¶
type Host struct {
APIVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
Spec HostSpec `yaml:"spec"`
}
Host is the whole host.yaml document.
type HostSpec ¶
type HostSpec struct {
Apps []AppRegistration `yaml:"apps,omitempty"`
Defaults *Defaults `yaml:"defaults,omitempty"`
Orchestration *Orchestration `yaml:"orchestration,omitempty"`
}
HostSpec is the server-wide surface.
type L4Route ¶
type L4Route struct {
Listen int `yaml:"listen"` // the host port the L4 LB binds
Protocol string `yaml:"protocol"` // tcp | udp
Service string `yaml:"service"` // selector → the service whose replicas receive traffic
Port int `yaml:"port"` // the service's internal container port
TLS string `yaml:"tls,omitempty"` // "" | passthrough (terminate not yet supported)
LB string `yaml:"lb,omitempty"` // "" (round_robin) | least_conn | hash_client_ip
}
L4Route is one managed Layer-4 (TCP/UDP) listener: a fixed public port the L4 load balancer owns, forwarded to a service's INTERNAL replica pool. Service/Port are selectors (never a literal dial target). Use it for non-HTTP stream services (DNS 53, DoT 853, MQTTS 8883). TLS is passthrough only for now (the app terminates with a cert_binding); `terminate` is reserved for a later phase.
type Metadata ¶
type Metadata struct {
Slug string `yaml:"slug"`
}
Metadata carries the immutable app slug.
type NofileLimit ¶ added in v0.4.2
NofileLimit is a soft/hard open-file-descriptor limit (compose `ulimits.nofile`).
type OpsInterface ¶
type OpsInterface struct {
Enabled bool `yaml:"enabled"`
BaseURL string `yaml:"base_url,omitempty"`
SecretHeader string `yaml:"secret_header,omitempty"`
Secret string `yaml:"secret,omitempty"` // reference to a declared secret NAME (value resolved at deploy); never the value
Mode string `yaml:"mode,omitempty"` // auto | rich | basic
BasePath string `yaml:"base_path,omitempty"`
Adapter string `yaml:"adapter,omitempty"`
}
OpsInterface is the app's optional ops endpoint (§4): Mooring probes it for RICH health/queues. Everything here is operator config EXCEPT the shared-secret VALUE — that stays encrypted (set the value in the dashboard, or declare a secret and point `secret` at it; the value never lives in this file). base_url is the in-cluster endpoint (origin only, never loopback); base_path is the relative prefix.
type Orchestration ¶
type Orchestration struct {
DeployOrder []OrderEdge `yaml:"deploy_order,omitempty"`
SetupOrder []string `yaml:"setup_order,omitempty"`
}
Orchestration sequences multi-app deploys/setup under one operator-initiated run.
func (*Orchestration) DeploySequence ¶
func (o *Orchestration) DeploySequence() ([]string, error)
DeploySequence returns a valid deploy order (a topological sort of the partial order: an app appears only after every app it waits on). A cycle is an error.
type Plan ¶
type Plan struct {
NewApp bool
Changes []string // changed field paths (the file is never secret-bearing, so nothing to mask)
}
Plan is the diff between the live canonical (current) and a desired definition.
func DiffPlan ¶
func DiffPlan(current, desired *Definition) (Plan, error)
DiffPlan computes the field-level changes from current to desired. current may be nil (a brand-new app).
type Port ¶
type Port struct {
Internal int `yaml:"internal"`
Publish bool `yaml:"publish"`
Public bool `yaml:"public"`
Protocol string `yaml:"protocol,omitempty"` // "" (=tcp) | "tcp" | "udp"
Published int `yaml:"published,omitempty"` // host port (default = internal); maps host→container so a non-root container can bind a privileged host port
}
Port is one container port. Internal is the in-container port; Publish maps it to the host (loopback by default, all interfaces only when Public).
type Route ¶
type Route struct {
Hostname string `yaml:"hostname"`
Subdomain string `yaml:"subdomain,omitempty"` // XOR hostname: expands to <subdomain>.<namespace apex>
BaseDomain string `yaml:"base_domain,omitempty"` // per-item namespace NAME override (only with subdomain)
Service string `yaml:"service"`
Port int `yaml:"port"`
PathPrefix string `yaml:"path_prefix"`
HSTS bool `yaml:"hsts"`
SecurityHeaders bool `yaml:"security_headers"`
RedirectHTTP bool `yaml:"redirect_http"`
UpstreamScheme string `yaml:"upstream_scheme,omitempty"` // "" (=http) | http | https — how the edge dials the upstream
CA string `yaml:"ca,omitempty"` // "" = default issuer; else a named CA from config.yaml edge.cas
}
Route is one managed edge vhost. Upstream is a SELECTOR — "service:port".
type Scaling ¶
type Scaling struct {
Service string `yaml:"service"`
Enabled bool `yaml:"enabled"`
Min int `yaml:"min"`
Max int `yaml:"max"`
UpCPUPct float64 `yaml:"up_cpu_pct"`
DownCPUPct float64 `yaml:"down_cpu_pct"`
UpMemPct float64 `yaml:"up_mem_pct"`
DownMemPct float64 `yaml:"down_mem_pct"`
PerReplicaMemMiB int `yaml:"per_replica_mem_mib"`
PerReplicaCPUMilli int `yaml:"per_replica_cpu_milli"`
BreachForSecs int `yaml:"breach_for_secs,omitempty"` // sustain window before acting (default 60)
CooldownUpSecs int `yaml:"cooldown_up_secs,omitempty"` // min seconds between scale-ups (default 60)
CooldownDownSecs int `yaml:"cooldown_down_secs,omitempty"` // min seconds between scale-downs (default 300; >= up)
// Metrics are OPTIONAL custom scaling signals in ADDITION to CPU/mem. Each reads a per-service
// number from a source and scales UP when the value is at/above `up`, permits DOWN below `down`
// (up>down is the dead band). Two sources: "ops" (queue depth from the app's own ops interface)
// and "edge" (latency / request-rate MEASURED by Mooring's edge — for an I/O-bound service whose
// CPU/mem stay low under load). For a service-TOTAL like queue depth or req/s the value is divided
// by the running replica count, so setting `up` to the desired per-replica target gives
// target-tracking through the same engine.
Metrics []ScalingMetric `yaml:"metrics,omitempty"`
}
Scaling is the opt-in auto-scaling policy (§8A) for one service.
type ScalingMetric ¶ added in v0.10.0
type ScalingMetric struct {
Name string `yaml:"name"` // signal name / display label (unique within the service)
Source string `yaml:"source"` // "ops" (app's ops interface) | "edge" (Mooring-measured at the edge)
// Select picks which value to read.
// source: ops → "" = the BACKLOG (sum of pending counters across every queue, EXCLUDING
// cumulative lifetime totals like completed/failed so a monotonic counter can't
// cause a runaway). A name sums the counters of a queue OR counter called that.
// source: edge → "p95_latency_ms" (service p95 request latency; absolute) or "req_per_sec"
// (request rate, tracked per replica). Measured by the edge — the app can't fake it.
Select string `yaml:"select,omitempty"`
Up float64 `yaml:"up"` // scale up when the (per-replica, for totals) value is >= this
Down float64 `yaml:"down"` // permit scale-down when the value is < this
}
ScalingMetric is one custom autoscaling signal (see Scaling.Metrics).
type ScheduledTask ¶ added in v0.6.0
type ScheduledTask struct {
Name string `yaml:"name"`
Service string `yaml:"service"`
Every string `yaml:"every"` // interval (e.g. "24h", "15m"); floored at 1m
}
ScheduledTask runs one declared service's command on a fixed interval. The service's `command:` IS the job; the service is generated into the compose but profiled so `up` never starts it — Mooring runs `docker compose run --rm --no-deps <service>` each tick (a fresh one-shot container that self-removes; never an exec into a running container).
type SelfHealing ¶
type SelfHealing struct {
SustainTicks int `yaml:"sustain_ticks,omitempty"` // failing ticks before the first remediation (anti-flap)
AttemptCap int `yaml:"attempt_cap,omitempty"` // remediations per window before the circuit opens
StabilizeTicks int `yaml:"stabilize_ticks,omitempty"` // healthy ticks required to declare RECOVERED
OOMStrikeCap int `yaml:"oom_strike_cap,omitempty"` // OOM-classified failures before short-circuiting the ladder
WindowSeconds int `yaml:"window_seconds,omitempty"` // attempt-window length; attempts reset after it elapses
BackoffBaseSecs int `yaml:"backoff_base_secs,omitempty"` // exponential backoff base between attempts
BackoffMaxSecs int `yaml:"backoff_max_secs,omitempty"` // backoff ceiling
RedeployEnabled bool `yaml:"redeploy_enabled,omitempty"` // rung-3 redeploy (≥1 GB host AND opt-in here)
}
SelfHealing tunes this app's self-healing supervisor (§8.5). Mooring supervises every service with a conservative built-in default; this block overrides the ladder tunables for ONE app. Omitted fields keep the built-in default; an omitted block leaves the app on the default entirely. All durations are in seconds.
type Service ¶
type Service struct {
Image string `yaml:"image,omitempty"` // image XOR build
Build *Build `yaml:"build,omitempty"`
Ports []Port `yaml:"ports,omitempty"`
Volumes []Volume `yaml:"volumes,omitempty"`
Env map[string]EnvValue `yaml:"env,omitempty"` // KEY: literal | {secret: NAME}
SecretFiles []string `yaml:"secret_files,omitempty"`
ConfigFiles []ConfigFile `yaml:"config_files,omitempty"`
CertBindings []CertBinding `yaml:"cert_bindings,omitempty"`
Command []string `yaml:"command,omitempty"`
Healthcheck []string `yaml:"healthcheck,omitempty"`
Restart string `yaml:"restart,omitempty"`
DependsOn []string `yaml:"depends_on,omitempty"`
OpsInterface *OpsInterface `yaml:"ops_interface,omitempty"` // per-service ops endpoint (§4); probed for RICH health/queues/metrics
// MemLimit sets a cgroup memory cap per replica (e.g. "768m", "1g"). It also makes the
// autoscaler's up_mem_pct/down_mem_pct per-service: docker reports it as the container's
// mem limit, so the trigger measures RSS against THIS budget, not the host's total RAM.
// MemReservation is the optional soft reservation. Both empty → unbounded (host RAM), as today.
MemLimit string `yaml:"mem_limit,omitempty"`
MemReservation string `yaml:"mem_reservation,omitempty"`
// StopGracePeriod widens the SIGTERM→SIGKILL window on stop (scale-down / redeploy)
// from docker's 10s default, so the app can drain long in-flight requests, e.g. "60s",
// "1m30s". Empty = docker default. Pairs with the app's graceful-shutdown hooks.
StopGracePeriod string `yaml:"stop_grace_period,omitempty"`
// Ulimits sets per-container resource limits (currently only `nofile`, the open
// file-descriptor cap). Raise it for services that hold many concurrent sockets
// beyond the docker daemon default of 1024 (e.g. an MQTT broker whose
// max_connections is otherwise clamped to the fd limit). nil = daemon default.
Ulimits *Ulimits `yaml:"ulimits,omitempty"`
}
Service is one service in the generated stack (the map key is its name). A service is `image` (pull) XOR `build` (Mooring generates the Dockerfile).
type Setup ¶
type Setup struct {
Script string `yaml:"script"`
Trigger string `yaml:"trigger"`
Produces []string `yaml:"produces,omitempty"`
}
Setup is the per-app setup script (Mode 3), declared here and synced into the setup store; the portal is a read-only view + the gated Run (no literal paste).
type Spec ¶
type Spec struct {
Compose Compose `yaml:"compose"`
Secrets []Secret `yaml:"secrets,omitempty"`
Edge Edge `yaml:"edge"`
Scaling []Scaling `yaml:"scaling,omitempty"` // one policy per service (auto-scale several services in one app)
SelfHealing *SelfHealing `yaml:"self_healing,omitempty"`
OpsInterface *OpsInterface `yaml:"ops_interface,omitempty"`
// ScheduledTasks run a declared service's command on an interval (cron jobs). The
// referenced service becomes SCHEDULED-ONLY: it is generated into the compose but not
// started by `up` (a profile) — Mooring runs it as a fresh one-shot `compose run --rm`
// container on each tick. No exec into a running container; no shell.
ScheduledTasks []ScheduledTask `yaml:"scheduled_tasks,omitempty"`
Git *Git `yaml:"git,omitempty"`
Setup *Setup `yaml:"setup,omitempty"`
}
Spec is the managed surface. Each field projects onto an existing artifact.
func (*Spec) ScheduledServiceSet ¶ added in v0.6.0
ScheduledServiceSet returns the set of service names that are scheduled-only (referenced by a scheduled_task) — the generator profiles these so `up` never starts them.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store persists applied canonical definitions (the history; the latest per slug is the live canonical). Every read RE-PARSES + RE-VALIDATES the stored YAML through the full pipeline (re-derive, never a verbatim replay), and the per-row HMAC is defence-in-depth so a DB tamper that still parses is caught.
func (*Store) CommitForVersion ¶ added in v0.6.0
CommitForVersion returns the git sha a specific version was deployed from, scoped to the slug (so a cross-app id can never resolve). The commit is HMAC-VERIFIED against the row (a DB tamper that repoints it surfaces ErrTampered — the rollback path must not deploy an unverified sha, since it skips the git-ref staged cross-check). Empty string means the version has no recorded commit (a dashboard edit) and is not a rollback target. sql.ErrNoRows if the (slug, id) pair does not exist.
func (*Store) Current ¶
func (s *Store) Current(slug string) (*Definition, error)
Current returns the live canonical definition for a slug (the latest version), HMAC-verified and RE-PARSED. No version yet → (nil, nil).
func (*Store) DeleteApp ¶
DeleteApp removes ALL canonical-definition versions for a slug (the whole history). Used by the app-delete teardown.
func (*Store) DeleteVersion ¶ added in v0.6.0
DeleteVersion removes ONE past version from the history (trimming the rollback list). It REFUSES to delete the latest version — that row is the live canonical, and losing it would orphan the app's current shape. Returns an error if the id is the latest or unknown. Note: this only frees the (tiny) history row; disk from superseded build images is reclaimed by the image-prune path, not here.
func (*Store) List ¶
func (s *Store) List(slug string) ([]VersionMeta, error)
List returns a slug's version history, newest first.
func (*Store) SaveCanonical ¶
func (s *Store) SaveCanonical(ctx context.Context, d *Definition, note, commit string) (int64, error)
SaveCanonical re-marshals an already-validated definition to canonical YAML and records it as a new version (which becomes the live canonical). Returns its id. commit is the git sha this version was deployed from ("" for dashboard edits).
type Ulimits ¶ added in v0.4.2
type Ulimits struct {
Nofile *NofileLimit `yaml:"nofile,omitempty"`
}
Ulimits is the per-service ulimit block. Only `nofile` (max open file descriptors) is supported — the knob that gates concurrent connection count.
type VersionMeta ¶
VersionMeta is one history row (no content). Commit is the git sha this version was deployed from ("" for dashboard-originated versions, which are not rollback targets).
type Volume ¶
type Volume struct {
Name string `yaml:"name"`
Source string `yaml:"source"`
Target string `yaml:"target"`
ReadOnly bool `yaml:"read_only"`
}
Volume is a named volume XOR a run_dir-confined bind.
type Widening ¶
Widening is one posture-widening a default would apply to an app (needs an ack).
func PostureWidenings ¶
PostureWidenings returns every posture-widening the given host defaults would apply (empty = the defaults only tighten / are neutral, applicable without acknowledgement). edge.routes and git.ref cannot appear in Defaults at all (not in the struct), so they need no check here.
func UnackedWidenings ¶
UnackedWidenings returns the posture-widenings NOT covered by acks — a non-empty result must BLOCK the apply (the host default would silently widen an app's posture). This is how "defaults never silently widen" is enforced.