Documentation
¶
Overview ¶
Package appcontract owns AppTown's native .apptown/app.yaml declaration, parsing, validation, and preparation of independent execution inputs.
Parse accepts source bytes; callers own file and repository lookup. Prepare accepts already-resolved service connections; callers own provisioning, image selection, scoped secret delivery, health rendering, and execution. This package has no runtime collaborators or persistence dependencies. App-part replicas may explicitly declare 1 (also the omitted/null default); larger counts are refused during parsing, before any runtime effects.
Index ¶
- Constants
- Variables
- func CheckSpecPath(path string) error
- func FormatMemory(b int64) string
- func MergeEnv(base, override map[string]string) map[string]string
- func ParseCPU(v any) (float64, error)
- func ParseDataCheck(line string) (path string, expect int, err error)
- func ParseHealthDuration(s string) (time.Duration, error)
- func ParseMemory(s string) (int64, error)
- func ParseMemoryV1(s string) (int64, error)
- func ParseSizeName(value any) (string, error)
- func ReleaseIdentity(part, revision string) string
- func ReservedEnvName(name string) string
- func WireEnv(version int, owner string, env, values map[string]string) (map[string]string, error)
- func WiresFrom(version int, env map[string]string) map[string][]string
- func WithoutNeedRefs(version int, v string) string
- type Contract
- func (c *Contract) CheckNeedSizes() error
- func (c *Contract) Disposable(need string) bool
- func (c *Contract) ForProfile(name string) *Contract
- func (c *Contract) NeedRefs() []NeedRef
- func (c *Contract) PartResources() map[string]Resources
- func (c *Contract) ProfileNames() []string
- func (c *Contract) PublicPart() *Part
- func (c *Contract) PublicRelease(revision string) string
- func (c *Contract) WithResources(over map[string]Resources) *Contract
- type Health
- type InitContainer
- type MemoryDefault
- type NeedRef
- type NeedSize
- type Part
- type Plan
- type Probe
- type ProfileChoice
- type ProfilePart
- type Resources
- type StaticBuild
Constants ¶
const BrowserEnvVar = "APPTOWN_BROWSER_ENV"
BrowserEnvVar carries a static part's browser-safe values. AppTown alone sets it; a contract or secret that names it is refused, so nothing can replace what the page is given.
const DefaultProfile = "default"
DefaultProfile is the base: the parts as `app:` declares them.
const MinMemoryBytes = 32 << 20
MinMemoryBytes is the smallest memory a part may declare: below it a container cannot start reliably.
const PreviewProfile = "preview"
PreviewProfile is the profile a preview uses when a file declares it.
const ReleaseEnvVar = "APPTOWN_RELEASE"
ReleaseEnvVar carries a static part's release identity (ReleaseIdentity); its file server answers it at ReleasePath, so a target whose front door AppTown can only reach from outside (App Platform) can witness that the part it deployed, in this release, is what answers. The AppTown sets it.
const ReleasePath = "/_apptown/release"
ReleasePath is where a static site's file server answers ReleaseEnvVar.
const ReservedEnvPrefix = "APPTOWN_"
ReservedEnvPrefix begins the names AppTown keeps for itself: a variable AppTown adds in a 1.x release starts with it, so no app that followed the contract already uses that name.
const TrustEnvVar = trust.EnvVar
TrustEnvVar carries the extra certificate authorities an app's own containers trust, as the script that installs them (internal/trust), which the app's image runs at start. AppTown sets it.
Variables ¶
var AppTownSetEnv = []string{"PORT", "APPTOWN_ORIGINS", "DATA_DIR", ReleaseEnvVar, BrowserEnvVar, TrustEnvVar}
AppTownSetEnv are the environment names AppTown alone sets on a part. An app that set one would win over AppTown's value on one target and lose on another, so the contract refuses it in a part's or a profile's environment (the contract reference, "The environment an app gets").
var JSONSchema []byte
JSONSchema is the JSON Schema for .apptown/app.yaml, served to models and editors. It describes the structure the parser accepts; rules a schema cannot express (exactly one public part, needs in the catalog) stay in Parse. A test holds its properties to the parser's own document types.
Functions ¶
func CheckSpecPath ¶
CheckSpecPath refuses a secrets.spec path that is absolute or leaves the project's tree: the declaration is read from the app's own source.
func FormatMemory ¶
FormatMemory writes bytes as app.yaml does: Gi when whole, else Mi.
func MergeEnv ¶
MergeEnv is a new environment: base, with override's values taking precedence. Neither input is changed, so a part's declared environment stays as written.
func ParseCPU ¶
ParseCPU reads a cpu as app.yaml writes it: a positive number of CPUs ("0.5", "2"), or Kubernetes millicores ("500m").
func ParseDataCheck ¶
ParseDataCheck reads one rehearsal data check: "GET <path>", answered 200, or "GET <path> expect <status>". It is the GET line of the probe grammar (internal/check), and only that: a data check asks one path.
func ParseHealthDuration ¶
ParseHealthDuration accepts Go duration strings ("90s", "10s", "3s"); a plain integer would be ambiguous, so require a unit.
func ParseMemory ¶
ParseMemory reads a memory as the current contract writes it, in Kubernetes binary units: a whole number of mebibytes or gibibytes, "512Mi", "1Gi". A bare "512M" is refused, not guessed: version 1 read it as MiB, Kubernetes and Score read it as decimal megabytes.
func ParseMemoryV1 ¶
ParseMemoryV1 reads a memory as a version-1 contract or a pack default writes it: "Mi"/"Gi", or "M"/"G" meaning the same (MiB, GiB).
func ParseSizeName ¶
ParseSizeName reads a size selector without coercing numbers or booleans.
func ReleaseIdentity ¶
ReleaseIdentity is what a static part's file server is told to answer: the part by name and the revision its release was cut from.
func ReservedEnvName ¶
ReservedEnvName says why an app may not set name in a part's environment or declare it as a secret, or "" when it may: AppTown sets it on every part (AppTownSetEnv), or it starts with ReservedEnvPrefix.
func WireEnv ¶
WireEnv is env with each need reference replaced by the value the need gives (values: the need variables the target has resolved, by name) and each $${needs. written as ${needs.. Version-1 environments are returned unchanged. A reference to a variable the target did not give is an error naming it: every target gives every need's documented variables.
func WiresFrom ¶
WiresFrom says which of values' keys env's references read, so a target can deliver a wired value with the care its source needs (a credential stays a secret).
func WithoutNeedRefs ¶
WithoutNeedRefs is v with its need references removed and each escaped one written as the literal it delivers: what is left is what the app wrote literally, for a target that must check literal text (App Platform rewrites any ${…} it delivers).
Types ¶
type Contract ¶
type Contract struct {
Needs []string
NeedParams map[string]map[string]string
// NeedSizes are catalogue size selections; Command is filled only by execution resolution.
NeedSizes map[string]NeedSize
// Version is the contract's shape version: 1 (or none written) or 2
// (parse.go, currentContractVersion).
Version int
// NeedResources is the most each need's service may use, by need;
// a need that declares nothing is absent (no limit). It is not a
// parameter: the catalogue never sees it.
NeedResources map[string]Resources
// Parts is the canonical declaration; exactly one is public.
Parts []Part
// Init are ordered run-to-completion containers (migrations, asset builds)
// that must succeed BEFORE the app parts start. app.yaml-only.
Init []InitContainer
// Secrets metadata: the declaration file's path
// (default secretspec.toml) and which generated secrets are stable per
// project rather than per deployment. The declaration itself is read
// from the tree at boot (secretspec.go); values never live here.
SecretSpecPath string
SecretGenerate map[string]string
// RehearsalChecks are the app's declared data checks, each "GET <path>"
// or "GET <path> expect <status>": paths it answers without its own
// sign-in that read its database. A restore rehearsal asks them after
// readiness and the front page (design/subsystems/deployment.md,
// "Restore rehearsals").
RehearsalChecks []string
// Profiles are the declared profiles by name, each part's or need's
// changes by its name (resources.go); a need's are its resources alone.
// The base, default, is the declaration itself.
Profiles map[string]map[string]ProfilePart
}
Contract is the canonical declaration parsed from .apptown/app.yaml. Callers retain it as source intent and use Prepare for mutable execution inputs.
func Parse ¶
Parse parses .apptown/app.yaml into the internal contract. Errors name the offending field and are written for a human or an agent to fix.
func (*Contract) CheckNeedSizes ¶
CheckNeedSizes refuses competing source declarations. Applied operator cap overrides are separate recorded decisions, not source declarations.
func (*Contract) Disposable ¶
Disposable says the app declared need's data not worth keeping (`redis: {disposable: true}`, a cache): it is never copied, starts empty, and reads as disposable rather than as a gap in its protection.
func (*Contract) ForProfile ¶
ForProfile is the contract under profile name: each part's resources replaced field by field and its environment merged key by key by what the profile declares for it. A name app.yaml does not declare, default among them, is the base unchanged. It performs no I/O and changes nothing of c.
func (*Contract) NeedRefs ¶
NeedRefs lists the contract's wiring references in a stable order: none for a version-1 contract.
func (*Contract) PartResources ¶
PartResources is each part's and each need's resources, by name: one map, since a name is one or the other.
func (*Contract) ProfileNames ¶
ProfileNames are the profiles app.yaml declares, sorted; the base (default) is not among them.
func (*Contract) PublicPart ¶
PublicPart returns the declared front door, or nil if none is present. The returned part belongs to the declaration; use Prepare before modifying it.
func (*Contract) PublicRelease ¶
PublicRelease is the release identity c's front door answers when it is served from revision: the public part's, when that part is a static site (its file server answers ReleasePath), and "" otherwise, or when there is no revision, whose release is not witnessed. Every target that runs a release sets and witnesses this one value.
type Health ¶
type Health struct {
Readiness *Probe `yaml:"readiness" json:"readiness,omitempty"`
Liveness *Probe `yaml:"liveness" json:"liveness,omitempty"`
}
Health is the per-part `health:` block.
type InitContainer ¶
type InitContainer struct {
Name string
Build string
Image string
Command []string
Env map[string]string
}
InitContainer runs once to completion before the app parts (ECS: an essential:false container the app parts dependsOn with condition SUCCESS).
type MemoryDefault ¶
type MemoryDefault struct {
Memory string `json:"memory,omitempty" yaml:"memory,omitempty"`
}
MemoryDefault is a positive memory fallback supplied by adopted content. Unlimited memory is an operator decision, never a content default.
func (MemoryDefault) Bytes ¶
func (d MemoryDefault) Bytes() (int64, error)
func (*MemoryDefault) UnmarshalJSON ¶
func (d *MemoryDefault) UnmarshalJSON(raw []byte) error
func (*MemoryDefault) UnmarshalYAML ¶
func (d *MemoryDefault) UnmarshalYAML(n *yaml.Node) error
type NeedRef ¶
type NeedRef struct {
Part, Key, Need, Var string
}
NeedRef is one wiring reference: Part's environment Key names Need's Var. Part is a part's name, "init-<name>" for an init step, or "<profile>/<part>" for a profile's environment.
type NeedSize ¶
NeedSize selects a catalogue-owned container configuration. Source YAML sets only Name; Command is resolved by the dependency owner or restored from the generation's applied record, never supplied through the app contract YAML.
type Part ¶
type Part struct {
Name string
Build string // build context (compose `build:`)
Image string // pushed ref (compose `image:`)
Static string // client-only: serve this committed folder
// StaticBuild is a static site built first: its output folder is
// served as Static is. Exactly one of Build, Image, Static, StaticBuild.
StaticBuild *StaticBuild
Command []string // compose `command:`
Port int // container port (from compose `ports:`)
Env map[string]string // compose `environment:`
DataDir string // AppTown: a named volume that survives redeploys
Health string // LEGACY healthcheck shell command; exit 0 = healthy
Intent *Health // structured per-part health intent (design/subsystems/healthchecks.md); nil = none declared
Public bool // the front door the preview/deploy URL points at
// Resources is the most the part may use; zero fields are no limit.
Resources Resources
// ServesStatic marks a static part after its files are packed into the
// file-server image (Static is cleared then): it is still a static site,
// and AppTown still gives its page browser values.
ServesStatic bool
}
Part is one app-owned container from .apptown/app.yaml's `app:` map. Compose conventions for the run mechanics; Public marks the front door (exactly one).
type Plan ¶
type Plan struct {
Parts []Part
Init []InitContainer
}
Plan holds one execution's private inputs. Runtime owners select images and apply scoped secrets to this plan without changing the source declaration.
func Prepare ¶
Prepare copies a declaration into an independent execution plan. Resolved service connections override each consumer's own environment; public-only values never flow into workers or init containers. It performs no I/O.
func PrepareWired ¶
PrepareWired is Prepare after each part's and init step's need references are replaced with the values connections gives (WireEnv), the path every container target takes so wiring is the same everywhere.
func (*Plan) PublicOnly ¶
PublicOnly is the plan with its public part and init steps alone: what a restore rehearsal runs, so workers and schedulers stay off.
func (*Plan) PublicPart ¶
PublicPart returns the plan's mutable front door, or nil if none is present.
type Probe ¶
type Probe struct {
// exactly one target:
HTTP string `yaml:"http" json:"http,omitempty"` // a path, e.g. /healthz
TCP int `yaml:"tcp" json:"tcp,omitempty"` // a port (0 = infer from the part)
Exec []any `yaml:"exec" json:"exec,omitempty"` // a command run INSIDE the container
// readiness only:
RequestContext string `yaml:"requestContext" json:"requestContext,omitempty"` // frontDoor | direct
Expect int `yaml:"expect" json:"expect,omitempty"` // HTTP status (default 200)
ChecksDeps bool `yaml:"checksDeps" json:"checksDeps,omitempty"` // ASSERTION (metadata, not proven)
// execution policy (design §4.1):
StartupGrace string `yaml:"startupGrace" json:"startupGrace,omitempty"` // e.g. 90s (a FLOOR)
Period string `yaml:"period" json:"period,omitempty"`
Timeout string `yaml:"timeout" json:"timeout,omitempty"`
FailureThreshold int `yaml:"failureThreshold" json:"failureThreshold,omitempty"`
SuccessThreshold int `yaml:"successThreshold" json:"successThreshold,omitempty"`
// contains filtered or unexported fields
}
Probe is one liveness or readiness probe's intent.
type ProfileChoice ¶
type ProfileChoice string
ProfileChoice is how a deployment's profile was chosen.
const ( ProfileChosen ProfileChoice = "chosen" // an explicit choice for the deployment ProfilePreview ProfileChoice = "preview" // a preview, and a file declares preview ProfileBase ProfileChoice = "default" // nothing else applies )
func DeploymentProfile ¶
func DeploymentProfile(chosen, deployment string, declared map[string]bool) (string, ProfileChoice)
DeploymentProfile is the one profile a deployment uses, whichever file declares it: the explicit choice when app.yaml or secretspec.toml declares it; otherwise, for the preview deployment, preview when either declares it; otherwise default. Each file then applies the name when it declares it and its own base when it does not.
type ProfilePart ¶
type ProfilePart struct {
Size string `json:"size,omitempty"`
Resources Resources `json:"resources,omitzero"`
Env map[string]string `json:"env,omitempty"`
}
ProfilePart is one profile's change to one part.
type Resources ¶
type Resources struct {
MemoryBytes int64 `json:"memoryBytes,omitempty"` // swap included
CPUs float64 `json:"cpus,omitempty"`
}
Resources is the most a part may use. Zero in a field is no limit of that kind in a declaration or historical applied record. Fresh container execution supplies defaults separately; zero is never proof a running container is capped.
func (Resources) MemoryWords ¶
MemoryWords is the memory as app.yaml writes it, or "no limit".
type StaticBuild ¶
type StaticBuild struct {
Context, Target, Output string
}
StaticBuild declares a static site AppTown builds before serving it: the Dockerfile in Context is built to its Target stage (the last when empty), and the folder Output inside that stage's files is the site.