spec

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Jul 25, 2026 License: Apache-2.0 Imports: 32 Imported by: 0

Documentation

Overview

Package spec parses, validates, and manipulates Deployah spec files.

It loads YAML specs, resolves environments and env files, applies schema defaults, substitutes variables, and validates against embedded JSON schemas.

Loading and saving

  • Load: read a spec, resolve an environment, substitute variables
  • Save: write a spec to YAML

Validation

Defaults

Index

Examples

Constants

View Source
const (
	// CurrentManifestVersion is the manifest apiVersion written by the init
	// command and expected by the current resolver. Bump this when a new
	// schema version is added alongside a new schema directory.
	CurrentManifestVersion = "v1-alpha.2"

	// DefaultSpecPath is the default path for the Deployah spec file
	DefaultSpecPath = "deployah.yaml"

	// DefaultEnvFile is the default environment file name
	DefaultEnvFile = ".env"

	// DefaultConfigFile is the default configuration file name
	DefaultConfigFile = "config.yaml"

	// DeployahConfigDir is the default directory for Deployah-specific files
	DeployahConfigDir = ".deployah"

	// EnvFilePrefix is the prefix for environment-specific files
	EnvFilePrefix = ".env."

	// ConfigFilePrefix is the prefix for environment-specific config files
	ConfigFilePrefix = "config."

	// ConfigFileSuffix is the suffix for configuration files
	ConfigFileSuffix = ".yaml"
)

File and Path Constants

View Source
const (
	// EnvVarPrefix is the prefix for Deployah-specific environment variables
	EnvVarPrefix = "DPY_VAR_"

	// LogLevelEnvVar is the environment variable for log level override
	LogLevelEnvVar = "DPY_LOG_LEVEL"
)

Environment Variables

View Source
const (
	// MaxComponentNameLength is the maximum allowed length for component names
	MaxComponentNameLength = 63

	// MaxProjectNameLength is the maximum allowed length for project names
	MaxProjectNameLength = 63

	// MaxEnvironmentNameLength is the maximum allowed length for environment names
	MaxEnvironmentNameLength = 63

	// ComponentNamePattern is the regex pattern for valid component names
	ComponentNamePattern = "^[a-zA-Z0-9_-]+$"

	// ProjectNamePattern is the regex pattern for valid project names
	ProjectNamePattern = "^[a-zA-Z0-9_-]+$"

	// EnvironmentNamePattern is the regex pattern for valid environment names
	EnvironmentNamePattern = "^[a-zA-Z0-9_-]+$"
)

Validation Constants

View Source
const (
	// PlaceholderName is the placeholder used in templates for name substitution
	PlaceholderName = "{name}"

	// ComponentsPrefix is the prefix for component paths in schemas
	ComponentsPrefix = "components."

	// EnvironmentsPrefix is the prefix for environment paths in schemas
	EnvironmentsPrefix = "environments."

	// ArrayItemIndexTemplate is the template for array item indices in schema paths
	ArrayItemIndexTemplate = "[0]"

	// EnvFileSuffix is the suffix to remove from environment names during cleanup
	EnvFileSuffix = "/*"
)

Spec Processing

View Source
const (
	// DefaultStartupProbePeriod is how often (in seconds) the startup probe
	// checks the container port during the startup window.
	DefaultStartupProbePeriod = 5

	// DefaultStartupProbeFailureThreshold is how many consecutive failures
	// before the container is killed during startup.
	// Budget: 36 * 5s = 180s (3 minutes).
	DefaultStartupProbeFailureThreshold = 36

	// DefaultStartupProbeTimeout is the per-request timeout in seconds for
	// the startup probe.
	DefaultStartupProbeTimeout = 3

	// DefaultReadinessProbePeriod is how often (in seconds) the readiness
	// probe checks whether the container can receive traffic.
	DefaultReadinessProbePeriod = 5

	// DefaultReadinessProbeFailureThreshold is how many consecutive failures
	// before the container is removed from service endpoints.
	// Detection window: 3 * 5s = 15s.
	DefaultReadinessProbeFailureThreshold = 3

	// DefaultReadinessProbeTimeout is the per-request timeout in seconds for
	// the readiness probe.
	DefaultReadinessProbeTimeout = 3

	// DefaultLivenessProbePeriod is how often (in seconds) the alive probe
	// checks whether the container is responsive.
	DefaultLivenessProbePeriod = 10

	// DefaultLivenessProbeTimeout is the per-request timeout in seconds for
	// the alive probe.
	DefaultLivenessProbeTimeout = 3

	// DefaultLivenessRestartAfterSec is the default restart-after window
	// in seconds (used as a numeric fallback in probe generation).
	DefaultLivenessRestartAfterSec = 60

	// DefaultLivenessInterval is the default value for health.alive.interval
	// when the field is omitted.
	DefaultLivenessInterval = "10s"

	// DefaultLivenessRestartAfter is the default value for
	// health.alive.restartAfter when the field is omitted.
	DefaultLivenessRestartAfter = "60s"
)

Health Check Probe Timing

These constants define the Kubernetes probe parameters used when building startup, readiness, and liveness probes from the spec health fields. They are named constants so that the product behavior (e.g. how quickly a pod is removed from rotation) can be reviewed and changed in one place.

View Source
const (
	// DefaultResourcePreset is the default resource preset when none is specified
	DefaultResourcePreset = "small"

	// MinCPUMillicores is the minimum CPU allocation in millicores
	MinCPUMillicores = 10

	// MaxCPUMillicores is the maximum CPU allocation in millicores
	MaxCPUMillicores = 16000

	// MinMemoryMB is the minimum memory allocation in megabytes
	MinMemoryMB = 16

	// MaxMemoryMB is the maximum memory allocation in megabytes
	MaxMemoryMB = 32768
)

Resource Management

View Source
const (
	// LabelPrefix is the prefix for all Deployah-managed labels
	LabelPrefix = "deployah.dev"

	// LabelProject is the label key for project identification
	LabelProject = LabelPrefix + "/project"

	// LabelEnvironment is the label key for environment identification
	LabelEnvironment = LabelPrefix + "/environment"

	// LabelManagedBy is the label key indicating management by Deployah
	LabelManagedBy = LabelPrefix + "/managed-by"

	// LabelVersion is the label key for API version tracking
	LabelVersion = LabelPrefix + "/version"

	// LabelComponent is the label key for component identification
	LabelComponent = LabelPrefix + "/component"

	// ManagedByValue is the value used for the managed-by label
	ManagedByValue = "deployah"

	// AnnotationSource is the annotation key recording which Deployah layer
	// produced a managed object (spec, manifests, or crds).
	AnnotationSource = LabelPrefix + "/source"

	// AnnotationProject is the annotation key for project identification on
	// Deployah-managed objects. Same string as LabelProject; used as an
	// annotation so CRDs (which carry no environment label) still identify
	// the owning project.
	AnnotationProject = LabelProject

	// SourceSpec is the AnnotationSource value for chart-generated objects.
	SourceSpec = "spec"

	// SourceManifests is the AnnotationSource value for .deployah/manifests.
	SourceManifests = "manifests"

	// SourceCRDs is the AnnotationSource value for .deployah/crds.
	SourceCRDs = "crds"

	// ManifestsDir is the subdirectory under DeployahConfigDir for extra
	// Kubernetes manifests.
	ManifestsDir = "manifests"

	// CRDsDir is the subdirectory under DeployahConfigDir for CRDs.
	CRDsDir = "crds"
)

Kubernetes Labels

View Source
const (
	ErrCodePlatformNotFound            = "PLATFORM_NOT_FOUND"
	ErrCodePlatformEnvNotFound         = "PLATFORM_ENV_NOT_FOUND"
	ErrCodeDomainGap                   = "DOMAIN_GAP"
	ErrCodeFQDNCollision               = "FQDN_COLLISION"
	ErrCodeInvalidDNS                  = "INVALID_DNS"
	ErrCodeStaticWildcardSubdomain     = "STATIC_WILDCARD_SUBDOMAIN"
	ErrCodeContextMismatch             = "CONTEXT_MISMATCH"
	ErrCodeHostnameChanged             = "HOSTNAME_CHANGED"
	ErrCodeProfileNotFound             = "PROFILE_NOT_FOUND"
	ErrCodeProfileDomainNotAllowed     = "PROFILE_DOMAIN_NOT_ALLOWED"
	ErrCodeProfileStorageClassNotFound = "PROFILE_STORAGE_CLASS_NOT_FOUND"
	ErrCodeProfileResourceExceeded     = "PROFILE_RESOURCE_EXCEEDED"
	ErrCodeProfileOptOutBlocked        = "PROFILE_OPT_OUT_BLOCKED"
)

Resolution error codes for use in the resolution report and JSON output.

View Source
const CurrentPlatformVersion = "platform/v1-alpha.1"

CurrentPlatformVersion is the platform apiVersion written by scaffold helpers (init, cluster up). It is always the last entry in SupportedPlatformVersions. Bump SupportedPlatformVersions first, then this constant follows automatically at compile time.

View Source
const DefaultPlatformPath = "deployah.platform.yaml"

DefaultPlatformPath is the default filename for the platform configuration file, looked up relative to the manifest.

View Source
const DefaultProfileName = "default"

DefaultProfileName is the profile name that is automatically prepended when a component omits the profiles field.

View Source
const PlatformEnvVar = "DEPLOYAH_PLATFORM_FILE"

PlatformEnvVar is the environment variable that overrides platform file lookup. When set and the file does not exist, the error is surfaced immediately; the same-directory fallback is NOT tried.

Variables

View Source
var MatchEnvKey = matchEnvKey

MatchEnvKey is the exported form of matchEnvKey.

View Source
var ResourcePresetMappings = map[ResourcePreset]map[string]Resources{
	ResourcePresetNano: {
		"requests": {
			CPU:              MustQuantity("100m"),
			Memory:           MustQuantity("128Mi"),
			EphemeralStorage: MustQuantity("50Mi"),
		},
		"limits": {
			CPU:              MustQuantity("150m"),
			Memory:           MustQuantity("192Mi"),
			EphemeralStorage: MustQuantity("2Gi"),
		},
	},
	ResourcePresetMicro: {
		"requests": {
			CPU:              MustQuantity("250m"),
			Memory:           MustQuantity("256Mi"),
			EphemeralStorage: MustQuantity("50Mi"),
		},
		"limits": {
			CPU:              MustQuantity("375m"),
			Memory:           MustQuantity("384Mi"),
			EphemeralStorage: MustQuantity("2Gi"),
		},
	},
	ResourcePresetSmall: {
		"requests": {
			CPU:              MustQuantity("500m"),
			Memory:           MustQuantity("512Mi"),
			EphemeralStorage: MustQuantity("50Mi"),
		},
		"limits": {
			CPU:              MustQuantity("750m"),
			Memory:           MustQuantity("768Mi"),
			EphemeralStorage: MustQuantity("2Gi"),
		},
	},
	ResourcePresetMedium: {
		"requests": {
			CPU:              MustQuantity("500m"),
			Memory:           MustQuantity("1024Mi"),
			EphemeralStorage: MustQuantity("50Mi"),
		},
		"limits": {
			CPU:              MustQuantity("750m"),
			Memory:           MustQuantity("1536Mi"),
			EphemeralStorage: MustQuantity("2Gi"),
		},
	},
	ResourcePresetLarge: {
		"requests": {
			CPU:              MustQuantity("1000m"),
			Memory:           MustQuantity("2048Mi"),
			EphemeralStorage: MustQuantity("50Mi"),
		},
		"limits": {
			CPU:              MustQuantity("1500m"),
			Memory:           MustQuantity("3072Mi"),
			EphemeralStorage: MustQuantity("2Gi"),
		},
	},
	ResourcePresetXLarge: {
		"requests": {
			CPU:              MustQuantity("1000m"),
			Memory:           MustQuantity("3072Mi"),
			EphemeralStorage: MustQuantity("50Mi"),
		},
		"limits": {
			CPU:              MustQuantity("3000m"),
			Memory:           MustQuantity("6144Mi"),
			EphemeralStorage: MustQuantity("2Gi"),
		},
	},
	ResourcePreset2XLarge: {
		"requests": {
			CPU:              MustQuantity("1000m"),
			Memory:           MustQuantity("3072Mi"),
			EphemeralStorage: MustQuantity("50Mi"),
		},
		"limits": {
			CPU:              MustQuantity("6000m"),
			Memory:           MustQuantity("12288Mi"),
			EphemeralStorage: MustQuantity("2Gi"),
		},
	},
}

ResourcePresetMappings defines the resource specifications for each preset

View Source
var SupportedPlatformVersions = []string{"platform/v1-alpha.1"}

SupportedPlatformVersions lists platform schema versions that are compatible with the current manifest API.

Functions

func ClearSchemaCache

func ClearSchemaCache()

ClearSchemaCache clears all cached schemas and patterns. Call it between tests that mutate schema caches, or to release memory in long-running processes.

func CoerceSetValue added in v0.4.0

func CoerceSetValue(kv string, obj map[string]any, version string) error

CoerceSetValue upgrades the string leaf strvals.ParseIntoString stored in obj to a properly typed Go value (int64, float64, or bool) by consulting the manifest schema's declared type for the dotted key path in kv.

func CrossCheckPlatformReferences added in v0.4.0

func CrossCheckPlatformReferences(appSpec *Spec, platform *PlatformConfig) (problems, warnings []string)

CrossCheckPlatformReferences checks spec references against the platform file without picking an environment. It returns problems (expose.domain keys defined in no platform environment, unknown profile names) and warnings (environment names unknown to the registry). Domains containing ${VAR} tokens are skipped.

func DeclaredEnvironments added in v0.5.0

func DeclaredEnvironments(environments map[string]Environment, platform *PlatformConfig) []string

DeclaredEnvironments returns the sorted registry of environment names that may be deployed to. The platform config owns the registry when present; otherwise the spec's environments map is used.

func FillSpecWithDefaults

func FillSpecWithDefaults(spec *Spec, version string) error

FillSpecWithDefaults fills spec with defaults from the JSON schemas for version, in this order: apply spec schema defaults to components, resolve resource presets to concrete values, merge spec and environment defaults, then apply the merged defaults to environments with placeholder substitution. spec is updated in place. It returns an error if schema loading, default extraction, or application fails.

Example

ExampleFillSpecWithDefaults applies schema defaults to a minimal manifest.

package main

import (
	"fmt"
	"log"

	"deployah.dev/deployah/internal/spec"
)

func main() {
	m := &spec.Spec{
		APIVersion: "v1-alpha.2",
		Project:    "demo",
		Components: map[string]spec.Component{
			"web": {Image: "nginx:latest"},
		},
	}
	if err := spec.FillSpecWithDefaults(m, "v1-alpha.2"); err != nil {
		log.Fatal(err)
	}
	fmt.Println(m.Components["web"].Port)
}
Output:
8080

func IsSupportedPlatformVersion added in v0.4.0

func IsSupportedPlatformVersion(apiVersion string) bool

IsSupportedPlatformVersion reports whether the given platform apiVersion (e.g. "platform/v1-alpha.1") is supported by the current version of Deployah.

func MissingPlatformEnvironments added in v0.4.0

func MissingPlatformEnvironments(platform *PlatformConfig, envNames []string) []string

MissingPlatformEnvironments returns the subset of envNames that have no entry in platform.Environments, sorted for stable output. platform may be nil, which reports every name as missing.

func MustQuantity added in v0.4.0

func MustQuantity(s string) *resource.Quantity

MustQuantity parses s as a Kubernetes quantity pointer. Panics on invalid input; use only for compile-time constants such as resource presets.

func ParseDuration

func ParseDuration(s string) (int, error)

ParseDuration converts a deployah duration string into whole seconds.

It delegates to time.ParseDuration, so it accepts the same syntax (e.g. "10s", "2m", "1h"). The JSON Schema pattern on health.alive fields already constrains values to positive integer seconds, minutes, or hours, so sub-second units and float values are rejected before they reach this function.

Zero and negative durations are rejected.

func PlatformEnvContext added in v0.4.0

func PlatformEnvContext(platform *PlatformConfig, envName string) string

PlatformEnvContext returns the Kubernetes context for the given environment from the platform config, or empty string if not found.

func Resolve added in v0.4.0

func Resolve(
	appSpec *Spec,
	platform *PlatformConfig,
	env EnvIdentity,
	substReport SubstitutionReport,
) (*ResolvedSpec, *ResolutionReport, error)

Resolve processes all components in spec at once for env, combining them with the platform configuration. It returns a ResolvedSpec containing per-component resolved values and a ResolutionReport with field provenance.

The platform parameter may be nil only when no component uses an expose block (offline manifest-only validation). When any component uses expose and platform is nil, Resolve returns a hard error.

substReport identifies which expose.subdomain fields were produced by envsubst; the wildcard static-subdomain warning does not fire for those.

func ResolveForDisplay added in v0.4.0

func ResolveForDisplay(
	appSpec *Spec,
	platform *PlatformConfig,
	env EnvIdentity,
	substReport SubstitutionReport,
) (*ResolvedSpec, *ResolutionReport, error)

ResolveForDisplay is like Resolve but never returns a hard error for missing platform file. Instead it marks the report with PLATFORM_NOT_FOUND and returns partial results. Used by the resolve command in offline mode.

func ResolveProfileNames added in v0.4.0

func ResolveProfileNames(componentProfiles []string, platformProfiles map[string]PlatformProfile) ([]string, error)

ResolveProfileNames decides which profile names apply to a component.

Rules:

  • nil componentProfiles (field omitted): apply ["default"] when the platform defines that profile; otherwise no profiles.
  • empty componentProfiles (profiles: []): opt-out. Error when a default profile exists; otherwise return an empty list.
  • non-empty list: require a platform profiles map; prepend default when defined (and not already listed).

func SanitizeProjectName added in v0.4.0

func SanitizeProjectName(s string) string

SanitizeProjectName rewrites s to satisfy ValidateProjectName's pattern (the result may still be too short; callers should check that separately).

func Save

func Save(spec *Spec, path string) error

Save writes the spec to a YAML file at the specified path.

func ScaffoldPlatformFile added in v0.4.0

func ScaffoldPlatformFile(path, ingressIP string, envNames []string) (created bool, err error)

ScaffoldPlatformFile writes a deployah.platform.yaml at path registering the given environment names. "local" gets a full entry (kind-deployah context, nip.io domain, self-signed TLS); every other name gets an empty entry with no context, meaning deploys to it follow the kubeconfig current-context until one is set.

func SchemaTypesAtPath added in v0.4.0

func SchemaTypesAtPath(version string, path []string) ([]string, bool)

SchemaTypesAtPath resolves the JSON Schema types declared for a dotted field path into the compiled manifest schema, e.g. path []string{"components", "web", "port"} resolves to []string{"integer"}. A false result means "unknown, don't guess" rather than an error.

func SentinelSubstituteRaw added in v0.4.0

func SentinelSubstituteRaw(data []byte) []byte

SentinelSubstituteRaw replaces ${VAR} tokens in raw YAML bytes with format-valid sentinel values so JSON schema format assertions still catch literal typos in fields like subdomain or hostname. Only scalar string values that consist entirely of a single ${VAR} expression are replaced; mixed strings (e.g., "prefix-${VAR}") are left as-is because they are likely already valid enough for schema validation.

This is intentionally a simple text-level approach (not a YAML AST walk) because sentinel substitution is only needed for offline validate mode where no env context is available. It is not used during normal deploy flows.

func SubstituteVariables

func SubstituteVariables(data []byte, env *Environment) ([]byte, error)

SubstituteVariables substitutes variables in spec data using the provided environment. Variable precedence is lowest to highest: environment definition, env file, then OS environment variables. Substitution uses the envsubst syntax.

func ValidateAPIVersion

func ValidateAPIVersion(specObj map[string]any) (string, error)

ValidateAPIVersion checks the spec apiVersion field for presence, type, and validity. Returns the apiVersion string if valid, or an error otherwise.

func ValidateComponentAutoscaling

func ValidateComponentAutoscaling(component Component) error

ValidateComponentAutoscaling validates a component's autoscaling configuration.

func ValidateComponentEnvironmentFilter added in v0.4.0

func ValidateComponentEnvironmentFilter(component Component) error

ValidateComponentEnvironmentFilter rejects unsupported "/*" suffixes in a component's environments filter: matching is prefix-based, so a plain name already covers its wildcard instances.

func ValidateComponentExpose added in v0.4.0

func ValidateComponentExpose(component Component) error

ValidateComponentExpose rejects an expose block combining apex with a subdomain.

func ValidateComponentHealth

func ValidateComponentHealth(component Component) error

ValidateComponentHealth validates the health check configuration of a component. Health checks are only supported for role: service components.

func ValidateComponentName

func ValidateComponentName(name string) error

ValidateComponentName validates a component name against the JSON schema pattern

func ValidateComponentProfiles added in v0.4.0

func ValidateComponentProfiles(component Component) error

ValidateComponentProfiles checks that profile names in the component are non-empty strings. Platform lookup happens during resolve.

func ValidateComponentResources

func ValidateComponentResources(component Component) error

ValidateComponentResources validates a component's resource configuration. A component can have either: 1. Explicit resources (resources field with actual values) 2. Resource preset (resourcePreset field) 3. Neither (will use defaults) It cannot have both resources and resourcePreset, or an empty resources object.

func ValidateEnvName

func ValidateEnvName(name string) error

ValidateEnvName validates an environment name against the JSON schema pattern

func ValidateEnvVarName

func ValidateEnvVarName(name string) error

ValidateEnvVarName validates an environment variable name against the JSON schema pattern.

func ValidateEnvironments

func ValidateEnvironments(specObj map[string]any, version string) error

ValidateEnvironments validates environments YAML against the provided JSON schema file. version should be the version of the schema (e.g., "v1-alpha.2"). This is a strict validation: unknown fields are not allowed.

func ValidateHostname

func ValidateHostname(hostname string) error

ValidateHostname validates a hostname against the JSON schema pattern

func ValidatePort

func ValidatePort(portStr string) error

ValidatePort validates that the port is a number between 1024 and 65535.

func ValidateProfileAgainstComponent added in v0.4.0

func ValidateProfileAgainstComponent(
	compName string,
	comp Component,
	merged PlatformProfile,
	platformEnv *PlatformEnvironment,
	domainKey string,
) error

ValidateProfileAgainstComponent checks domain, storage class, and resource ceiling constraints from the merged profile against the component and target environment.

func ValidateProjectName

func ValidateProjectName(name string) error

ValidateProjectName validates a project name against the JSON schema pattern

func ValidateSpec

func ValidateSpec(specObj map[string]any, version string) error

ValidateSpec validates spec YAML against the provided JSON schema. version should be the version of the schema (e.g., "v1-alpha.2"). This is a strict validation: unknown fields are not allowed.

func ValidateSpecComponents

func ValidateSpecComponents(spec *Spec) error

ValidateSpecComponents validates all components in a spec.

Types

type Autoscaling

type Autoscaling struct {
	Enabled     bool     `json:"enabled,omitempty" yaml:"enabled,omitempty"`
	MinReplicas int      `json:"minReplicas,omitempty" yaml:"minReplicas,omitempty"`
	MaxReplicas int      `json:"maxReplicas,omitempty" yaml:"maxReplicas,omitempty"`
	Metrics     []Metric `json:"metrics,omitempty" yaml:"metrics,omitempty"`
}

Autoscaling defines the autoscaling settings for the component.

type Component

type Component struct {
	// Role selects the default deployment strategy for the component.
	Role ComponentRole `json:"role,omitempty" yaml:"role,omitempty"`
	// EnvFile is the path to a component-specific dotenv file.
	EnvFile string `json:"envFile,omitempty" yaml:"envFile,omitempty"`
	// ConfigFile is the path to a component-specific config file.
	ConfigFile string `json:"configFile,omitempty" yaml:"configFile,omitempty"`
	// Environments limits the component to the named environments.
	Environments []string `json:"environments,omitempty" yaml:"environments,omitempty"`
	// Kind selects stateless or stateful deployment behavior.
	Kind ComponentKind `json:"kind,omitempty" yaml:"kind,omitempty"`
	// Image is the container image reference.
	Image string `json:"image" yaml:"image"`
	// Command overrides the container entrypoint.
	Command []string `json:"command,omitempty" yaml:"command,omitempty"`
	// Args overrides the container command arguments.
	Args []string `json:"args,omitempty" yaml:"args,omitempty"`
	// Port is the primary container port for services.
	Port int `json:"port,omitempty" yaml:"port,omitempty"`
	// Autoscaling configures horizontal pod autoscaling.
	Autoscaling *Autoscaling `json:"autoscaling,omitempty" yaml:"autoscaling,omitempty"`
	// Resources sets explicit CPU, memory, and storage requests and limits.
	Resources Resources `json:"resources" yaml:"resources,omitempty"`
	// ResourcePreset selects a named resource profile when Resources is empty.
	ResourcePreset ResourcePreset `json:"resourcePreset,omitempty" yaml:"resourcePreset,omitempty"`
	// Expose exposes the component via an ingress rule resolved against the
	// platform domain configuration. Replaces the former ingress block.
	Expose *Expose `json:"expose,omitempty" yaml:"expose,omitempty"`
	// Profiles lists platform-defined deployment profile names. Multiple
	// profiles are merged left to right. Requires a profiles section in the
	// platform file.
	Profiles []string `json:"profiles,omitempty" yaml:"profiles,omitempty"`
	// Env sets static environment variables for the container.
	Env map[string]string `json:"env,omitempty" yaml:"env,omitempty"`
	// Health configures ready and alive checks for the component.
	Health *Health `json:"health,omitempty" yaml:"health,omitempty"`
}

Component defines a deployable unit in the project.

func (Component) ListensOnPort added in v0.4.0

func (c Component) ListensOnPort() bool

ListensOnPort reports whether the component has a service role and a configured port, i.e. whether it should get a container port, an ingress rule, or a health probe.

type ComponentKind

type ComponentKind string

ComponentKind specifies the kind of the component.

const (
	// ComponentKindStateless runs replicas that do not require stable storage.
	ComponentKindStateless ComponentKind = "stateless"
	// ComponentKindStateful runs replicas that require stable storage.
	ComponentKindStateful ComponentKind = "stateful"
)

type ComponentRole

type ComponentRole string

ComponentRole defines the role of a component and its default deployment strategy.

const (
	// ComponentRoleService runs a long-lived HTTP or network service.
	ComponentRoleService ComponentRole = "service"
	// ComponentRoleWorker runs background or queue-processing workloads.
	ComponentRoleWorker ComponentRole = "worker"
	// ComponentRoleJob runs a finite batch or one-off task.
	ComponentRoleJob ComponentRole = "job"
)

func (ComponentRole) IsService added in v0.4.0

func (r ComponentRole) IsService() bool

IsService reports whether r is the "service" role, the only role that listens on a port or gets exposed via an ingress rule. Worker and job components run without inbound traffic.

type DefaultValues

type DefaultValues map[string]any

DefaultValues represents default values extracted from a JSON schema. Map keys are dot-notation paths to fields; values are defaults to apply.

Examples of keys:

  • "components.[^[a-zA-Z0-9_-]+$].role" -> "service" (pattern-based component default)
  • "components.web.port" -> 8080 (specific component default)
  • "environments.[0].envFile" -> ".env.{name}" (environment template with placeholder)
  • "environments.production.configFile" -> "config.production.yaml" (specific environment)

func GetDefaultValues

func GetDefaultValues(version string, schemaType schema.SchemaType) (DefaultValues, error)

GetDefaultValues returns all default values declared by the schema for version and schemaType, keyed by dot-notation path. It is the main entry point for schema-based defaults.

type EnvIdentity added in v0.4.0

type EnvIdentity struct {
	// Original is the raw environment name as supplied by the caller.
	Original string
	// MapKey is the key used for map lookups: split on the first "/" and take
	// the prefix. For "review/pr-123" MapKey is "review". For "production" it
	// equals Original.
	MapKey string
	// K8sSafe is a Kubernetes-safe version of Original: "/" replaced with "-",
	// truncated to 53 characters. When truncation changes the string a 4-char
	// hex hash of Original is appended (after truncating to 49 chars) to keep
	// uniqueness. Safe for Helm release name suffixes and label values.
	K8sSafe string
}

EnvIdentity is the canonical identity for an environment name. A single NormalizeEnv call is the only entry point. All subsystems (manifest lookup, platform lookup, component.Environments filter, release name generation, cache keys, and explain output) use fields from the same EnvIdentity.

func NormalizeEnv added in v0.4.0

func NormalizeEnv(name string) EnvIdentity

NormalizeEnv returns the canonical identity for an environment name. It handles the slash-prefix pattern used by wildcard environments (e.g. "review/pr-42" has MapKey "review").

type Environment

type Environment struct {
	// EnvFile is the path to a dotenv file for this environment.
	EnvFile string `json:"envFile,omitempty" yaml:"envFile,omitempty"`
	// ConfigFile is the path to an environment-specific config file.
	ConfigFile string `json:"configFile,omitempty" yaml:"configFile,omitempty"`
	// Variables holds inline key-value overrides for this environment.
	Variables map[string]string `json:"variables,omitempty" yaml:"variables,omitempty"`
}

Environment defines developer-controlled settings for a deployment target. Context is platform-owned and lives in deployah.platform.yaml.

func ResolveEnvironment

func ResolveEnvironment(environments map[string]Environment, platform *PlatformConfig, desiredEnvironment string) (string, *Environment, error)

ResolveEnvironment selects the target environment and returns its name and developer-owned overrides. Which names are valid (the registry) is owned by the platform config when one exists; the spec's environments map supplies optional per-environment overrides (envFile, variables) and acts as the registry only when there is no platform config.

When desiredEnvironment is empty:

  • Empty registry: returns a synthetic default environment.
  • One registry entry: selects it automatically.
  • Two or more: returns an error listing the registry names.

When desiredEnvironment is set it must match the registry via [matchEnvKey]; with an empty registry any name is accepted as-is.

type Expose added in v0.4.0

type Expose struct {
	// Domain is the domain key referencing an entry in the platform
	// environment's domains map. When empty, the environment's only domain
	// is used, or the one marked default in the platform file.
	Domain string `json:"domain,omitempty" yaml:"domain,omitempty"`
	// Subdomain is a DNS label prepended to the platform baseDomain to form
	// the FQDN. When nil the component name is used. Mutually exclusive
	// with Apex.
	Subdomain *string `json:"subdomain,omitempty" yaml:"subdomain,omitempty"`
	// Apex exposes the component at the baseDomain itself. Mutually
	// exclusive with Subdomain.
	Apex bool `json:"apex,omitempty" yaml:"apex,omitempty"`
	// contains filtered or unexported fields
}

Expose declares that a component should be accessible via an ingress rule. The resolved hostname and TLS settings come from the platform configuration referenced by Domain. In YAML the field also accepts a boolean shorthand: `expose: true` equals an empty object (all defaults) and `expose: false` equals omitting the block.

func (Expose) MarshalJSON added in v0.4.0

func (e Expose) MarshalJSON() ([]byte, error)

MarshalJSON emits `true` for the zero value so generated specs keep the shorthand form, and `false` for a disabled block.

func (*Expose) UnmarshalJSON added in v0.4.0

func (e *Expose) UnmarshalJSON(data []byte) error

UnmarshalJSON accepts the boolean shorthand alongside the object form.

type Health

type Health struct {
	// Ready controls the readiness check. Provide a path to upgrade from TCP
	// to HTTP. Set to false to disable readiness and startup checks entirely.
	Ready *HealthReady `json:"ready,omitempty" yaml:"ready,omitempty"`
	// Alive controls the alive check. Provide a path to upgrade from TCP to
	// HTTP. Set to false to disable the alive check entirely.
	Alive *HealthAlive `json:"alive,omitempty" yaml:"alive,omitempty"`
}

Health configures HTTP health checks for a service component. When omitted, TCP checks on the component port run automatically.

type HealthAlive

type HealthAlive struct {
	// Disabled is true when the developer set alive: false.
	Disabled bool `json:"-" yaml:"-"`
	// Path is the HTTP endpoint that must return 2xx for the pod to be
	// considered alive. Must start with /. Check only internal process
	// state here, not external dependencies.
	Path string `json:"path,omitempty" yaml:"path,omitempty"`
	// Interval is how often to check the endpoint (e.g. "10s", "1m").
	// Defaults to "10s" when omitted.
	Interval string `json:"interval,omitempty" yaml:"interval,omitempty"`
	// RestartAfter is how long the endpoint must fail continuously before
	// the pod is restarted (e.g. "60s", "2m"). Defaults to "60s" when
	// omitted. The effective window rounds up to the nearest multiple of
	// Interval.
	RestartAfter string `json:"restartAfter,omitempty" yaml:"restartAfter,omitempty"`
}

HealthAlive configures the alive check for a service component. It accepts either false (to disable) or an object with a path and optional timing.

When Alive is nil (field absent), a TCP alive check on the component port runs automatically.

func (*HealthAlive) UnmarshalJSON

func (a *HealthAlive) UnmarshalJSON(data []byte) error

UnmarshalJSON handles both false and object forms:

alive: false                           -> HealthAlive{Disabled: true}
alive: {path: /livez, interval: 10s}  -> HealthAlive{Path: "/livez", ...}

type HealthReady

type HealthReady struct {
	// Disabled is true when the developer set ready: false.
	Disabled bool `json:"-" yaml:"-"`
	// Path is the HTTP endpoint that must return 2xx for the component to
	// receive traffic. Must start with /.
	Path string `json:"path,omitempty" yaml:"path,omitempty"`
}

HealthReady configures the readiness check for a service component. It accepts either false (to disable) or an object with a path.

When Ready is nil (field absent), a TCP readiness check on the component port runs automatically.

func (*HealthReady) UnmarshalJSON

func (r *HealthReady) UnmarshalJSON(data []byte) error

UnmarshalJSON handles both false and object forms:

ready: false         -> HealthReady{Disabled: true}
ready: {path: /h}   -> HealthReady{Path: "/h"}

type Metric

type Metric struct {
	Type   MetricType `json:"type" yaml:"type"`
	Target int        `json:"target" yaml:"target"`
}

Metric defines a metric used to trigger autoscaling.

type MetricType

type MetricType string

MetricType specifies the type of metric to monitor.

const (
	// MetricTypeCPU scales on CPU utilization.
	MetricTypeCPU MetricType = "cpu"
	// MetricTypeMemory scales on memory utilization.
	MetricTypeMemory MetricType = "memory"
)

type PlatformConfig added in v0.4.0

type PlatformConfig struct {
	// APIVersion is the platform schema version, e.g. "platform/v1-alpha.1".
	APIVersion string `json:"apiVersion" yaml:"apiVersion"`
	// Profiles maps logical profile names to deployment policy. Profiles are
	// org-wide (root-level), not per-environment. A profile named "default" is
	// prepended automatically when a component omits profiles.
	Profiles map[string]PlatformProfile `json:"profiles,omitempty" yaml:"profiles,omitempty"`
	// Environments is a map of environment names to their platform
	// configuration. Wildcard matching (prefix-split on "/") is applied by
	// [matchEnvKey].
	Environments map[string]PlatformEnvironment `json:"environments" yaml:"environments"`
}

PlatformConfig is the top-level structure of the platform file (deployah.platform.yaml). It is platform-owned and not subject to envsubst.

func LoadPlatform added in v0.4.0

func LoadPlatform(path string) (*PlatformConfig, error)

LoadPlatform reads and validates the platform configuration file at path. The file is never subject to envsubst. LoadPlatform performs:

  1. YAML parse into a raw map for schema validation
  2. Schema validation against the embedded platform schema
  3. Internal-consistency checks (TLS mode fields, domain references)
  4. Unmarshal into PlatformConfig

On success it returns the parsed platform config. On error it returns a nil config and a descriptive error.

type PlatformDomain added in v0.4.0

type PlatformDomain struct {
	// BaseDomain is the DNS apex for this domain, e.g. "example.com".
	BaseDomain string `json:"baseDomain" yaml:"baseDomain"`
	// Default marks this domain as the one used when a component's expose
	// block names no domain. At most one per environment.
	Default bool `json:"default,omitempty" yaml:"default,omitempty"`
	// TLS holds the TLS mode and associated parameters.
	TLS *PlatformTLS `json:"tls,omitempty" yaml:"tls,omitempty"`
}

PlatformDomain holds the base domain and TLS configuration for a logical domain key.

type PlatformEnvironment added in v0.4.0

type PlatformEnvironment struct {
	// Context is the Kubernetes context to use for this environment.
	Context string `json:"context,omitempty" yaml:"context,omitempty"`
	// Domains is a map of logical domain names to their configuration.
	// Developers reference domain keys in expose.domain.
	Domains map[string]PlatformDomain `json:"domains,omitempty" yaml:"domains,omitempty"`
	// StorageClasses maps logical names to Kubernetes storage classes.
	StorageClasses map[string]PlatformStorageClass `json:"storageClasses,omitempty" yaml:"storageClasses,omitempty"`
	// AllowStaticSubdomain suppresses the wildcard static-subdomain warning
	// for this environment key when set to true.
	AllowStaticSubdomain bool `json:"allowStaticSubdomain,omitempty" yaml:"allowStaticSubdomain,omitempty"`
}

PlatformEnvironment holds platform-controlled settings for one environment.

func LocalPlatformEnvironment added in v0.4.0

func LocalPlatformEnvironment(ingressIP string) PlatformEnvironment

LocalPlatformEnvironment returns a PlatformEnvironment configured for local development: kind-deployah context, nip.io base domain using ingressIP, and selfSigned TLS. Pass the host IP at which the Ingress controller is reachable (typically localkube.DefaultIngressIP).

type PlatformProfile added in v0.4.0

type PlatformProfile struct {
	// NodeSelector is Kubernetes nodeSelector labels for pod placement.
	NodeSelector map[string]string `json:"nodeSelector,omitempty" yaml:"nodeSelector,omitempty"`
	// Tolerations are Kubernetes tolerations for pod scheduling.
	Tolerations []corev1.Toleration `json:"tolerations,omitempty" yaml:"tolerations,omitempty"`
	// PodLabels are additional labels applied to pods.
	PodLabels map[string]string `json:"podLabels,omitempty" yaml:"podLabels,omitempty"`
	// PodAnnotations are additional annotations applied to pods.
	PodAnnotations map[string]string `json:"podAnnotations,omitempty" yaml:"podAnnotations,omitempty"`
	// SecurityContext is a Kubernetes PodSecurityContext (pod-level).
	SecurityContext *corev1.PodSecurityContext `json:"securityContext,omitempty" yaml:"securityContext,omitempty"`
	// ContainerSecurityContext is a Kubernetes SecurityContext applied to
	// all containers.
	ContainerSecurityContext *corev1.SecurityContext `json:"containerSecurityContext,omitempty" yaml:"containerSecurityContext,omitempty"`
	// StorageClass is a logical storage class key from the target
	// environment's storageClasses map.
	StorageClass string `json:"storageClass,omitempty" yaml:"storageClass,omitempty"`
	// AllowedDomains restricts which domain keys a component may expose on.
	// nil means no constraint. A non-nil empty list means deny-all (no domain
	// is allowed). Multiple profiles intersect. Neither JSON nor YAML uses
	// omitempty, so deny-all serializes as [] rather than becoming nil.
	AllowedDomains []string `json:"allowedDomains" yaml:"allowedDomains"`
	// MaxResources is a ceiling on component resource requests.
	MaxResources *ProfileMaxResources `json:"maxResources,omitempty" yaml:"maxResources,omitempty"`
}

PlatformProfile is a named deployment policy applied to components that select it. Multiple profiles merge left to right.

func MergeProfiles added in v0.4.0

func MergeProfiles(names []string, profiles map[string]PlatformProfile) (PlatformProfile, error)

MergeProfiles looks up names in profiles and merges them left to right.

Merge rules:

  • maps (nodeSelector, podLabels, podAnnotations): deep merge, last wins
  • security contexts: field overlay; non-nil overlay pointers win, including false *bool values that mergo would skip
  • arrays (tolerations): concatenate and deduplicate identical entries
  • scalars (storageClass): last non-empty wins
  • allowedDomains: intersection of explicit lists; omitted means no constraint
  • maxResources: minimum (strictest) ceiling per resource

type PlatformStorageClass added in v0.4.0

type PlatformStorageClass struct {
	// ClassName is the actual Kubernetes storage class name.
	ClassName string `json:"className" yaml:"className"`
}

PlatformStorageClass maps a logical name to a Kubernetes storage class.

type PlatformTLS added in v0.4.0

type PlatformTLS struct {
	// Mode is the TLS provisioning strategy.
	Mode TLSMode `json:"mode" yaml:"mode"`
	// Issuer is the cert-manager ClusterIssuer or Issuer name.
	// Required when Mode is [TLSModeCertManager].
	Issuer string `json:"issuer,omitempty" yaml:"issuer,omitempty"`
	// SecretName is the pre-existing Kubernetes TLS secret name.
	// Required when Mode is [TLSModeSecretName].
	SecretName string `json:"secretName,omitempty" yaml:"secretName,omitempty"`
}

PlatformTLS holds explicit TLS configuration for a domain.

type ProfileMaxResources added in v0.4.0

type ProfileMaxResources struct {
	// CPU is the maximum CPU request (Kubernetes quantity).
	CPU *resource.Quantity `json:"cpu,omitempty" yaml:"cpu,omitempty"`
	// Memory is the maximum memory request (Kubernetes quantity).
	Memory *resource.Quantity `json:"memory,omitempty" yaml:"memory,omitempty"`
}

ProfileMaxResources caps component resource requests.

type ResolutionError added in v0.4.0

type ResolutionError struct {
	Code    string
	Message string
}

ResolutionError is a resolution error that carries a machine-readable code.

func (*ResolutionError) Error added in v0.4.0

func (e *ResolutionError) Error() string

Error returns the resolution error message.

type ResolutionReport added in v0.4.0

type ResolutionReport struct {
	// Env is the environment identity used for this resolution.
	Env EnvIdentity
	// Fields is the ordered list of resolved field provenance entries.
	Fields []ResolvedField
	// Warnings is the list of non-fatal warnings emitted during resolution.
	Warnings []string
	// ErrorCode is set when resolution produced a hard error.
	ErrorCode string
	// ErrorMessage is the human-readable error message when ErrorCode is set.
	ErrorMessage string
}

ResolutionReport holds the provenance of each resolved field, enabling the resolve command and deploy --explain to trace where each value came from.

type ResolvedComponent added in v0.4.0

type ResolvedComponent struct {
	// FQDN is the fully qualified domain name resolved for this component.
	// Empty when the component has no expose block.
	FQDN string
	// TLSMode is the TLS provisioning strategy resolved from the platform.
	// Empty when the component has no TLS configuration.
	TLSMode TLSMode
	// TLSIssuer is the cert-manager issuer name (certManager mode only).
	TLSIssuer string
	// TLSSecretName is the pre-existing TLS secret name (secretName mode only).
	TLSSecretName string
	// TLSCertPEM and TLSKeyPEM hold a materialized self-signed certificate
	// (selfSigned mode only), filled in by
	// [k8s.MaterializeSelfSignedTLS] before rendering. Never written into
	// the deployah.resolved chart values block: only fqdn/tlsMode are.
	TLSCertPEM []byte
	TLSKeyPEM  []byte
	// StorageClass is the Kubernetes storage class name resolved from the
	// platform profile's storageClass reference. Empty when no profile sets
	// a storage class.
	StorageClass string
	// Profiles is the ordered list of profile names applied after default
	// prepend. Empty when no profiles apply.
	Profiles []string
	// MergedProfile is the left-to-right merge of Profiles. Nil when no
	// profiles apply.
	MergedProfile *PlatformProfile
	// DomainKey is the logical domain key used for expose resolution.
	// Empty when the component has no expose block.
	DomainKey string
}

ResolvedComponent holds the platform-resolved values for a single component.

type ResolvedField added in v0.4.0

type ResolvedField struct {
	// Component is the component name this field belongs to, or empty for
	// top-level fields.
	Component string
	// Path is the spec path, e.g. "expose.host".
	Path string
	// Value is the resolved value as a string.
	Value string
	// Source is a human-readable description of where the value came from,
	// e.g. "platform environments.production.domains.public.baseDomain".
	Source string
}

ResolvedField holds provenance for a single resolved value.

type ResolvedSpec added in v0.4.0

type ResolvedSpec struct {
	// Spec is the application manifest with defaults applied.
	Spec *Spec
	// Env is the canonical environment identity used for this resolution.
	Env EnvIdentity
	// KubeContext is the Kubernetes context resolved from the platform file.
	// Empty when no platform file was loaded.
	KubeContext string
	// Components holds the per-component resolved data.
	Components map[string]ResolvedComponent
	// Warnings is the list of non-fatal resolution warnings.
	Warnings []string
}

ResolvedSpec is the load+platform+resolution result for one environment; primary input to [MapSpecToChartValues], the hostname guard, and cache keys.

Its deployah.resolved block, written to Helm chart values, has this contract:

deployah:
  resolved:
    schemaVersion: "1"
    components:
      <name>:
        fqdn: api.example.com
        tlsMode: certManager
        storageClass: ""

type ResourcePreset

type ResourcePreset string

ResourcePreset specifies the resource preset for the component.

const (
	// ResourcePresetNano is the smallest resource preset.
	ResourcePresetNano ResourcePreset = "nano"
	// ResourcePresetMicro is a very small resource preset.
	ResourcePresetMicro ResourcePreset = "micro"
	// ResourcePresetSmall is a small resource preset.
	ResourcePresetSmall ResourcePreset = "small"
	// ResourcePresetMedium is a medium resource preset.
	ResourcePresetMedium ResourcePreset = "medium"
	// ResourcePresetLarge is a large resource preset.
	ResourcePresetLarge ResourcePreset = "large"
	// ResourcePresetXLarge is an extra-large resource preset.
	ResourcePresetXLarge ResourcePreset = "xlarge"
	// ResourcePreset2XLarge is a double extra-large resource preset.
	ResourcePreset2XLarge ResourcePreset = "2xlarge"
)

type Resources

type Resources struct {
	CPU              *resource.Quantity `json:"cpu,omitempty" yaml:"cpu,omitempty"`
	Memory           *resource.Quantity `json:"memory,omitempty" yaml:"memory,omitempty"`
	EphemeralStorage *resource.Quantity `json:"ephemeralStorage,omitempty" yaml:"ephemeralStorage,omitempty"`
}

Resources defines the resource requests and limits for the component.

func (Resources) ResourcesPresent added in v0.4.0

func (r Resources) ResourcesPresent() bool

ResourcesPresent reports whether any resource field pointer is non-nil (including an explicit zero quantity).

func (Resources) ResourcesSet added in v0.4.0

func (r Resources) ResourcesSet() bool

ResourcesSet reports whether r has any non-zero resource request.

type Spec

type Spec struct {
	// APIVersion is the schema version of the spec (e.g., "v1-alpha.2").
	APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
	// Project is the project name.
	Project string `json:"project" yaml:"project"`
	// Environments is a map of environment names to their definitions.
	// The map key is the environment name (e.g. "production", "staging").
	// Context is platform-owned and lives in deployah.platform.yaml.
	Environments map[string]Environment `json:"environments,omitempty" yaml:"environments,omitempty"`
	// Components is a map of component names to their configuration.
	Components map[string]Component `json:"components" yaml:"components"`
}

Spec defines the structure of the project spec.

func CreateSpecWithDefaults

func CreateSpecWithDefaults(projectName, version string) (*Spec, error)

CreateSpecWithDefaults creates a minimal Spec for projectName and fills it with the defaults declared by version's schema.

func Load

func Load(ctx context.Context, path, desiredEnv string, platform *PlatformConfig) (*Spec, error)

Load reads and parses the spec YAML file at the given path, resolves the environment (using desiredEnv or default resolution rules), substitutes variables according to precedence, validates the spec, and applies defaults.

platform supplies the environment registry for ResolveEnvironment; pass nil when no platform file exists. This function performs the load pipeline without platform resolution; for ResolvedSpec see Resolve.

Example

ExampleLoad reads a manifest file from disk.

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"deployah.dev/deployah/internal/spec"
)

func main() {
	const yamlDoc = `apiVersion: v1-alpha.2
project: demo
environments:
  default: {}
components:
  web:
    image: nginx:latest
    resources:
      cpu: 500m
      memory: 512Mi
`
	f, err := os.CreateTemp("", "example-*.yaml")
	if err != nil {
		log.Fatal(err)
	}
	path := f.Name()
	if _, err = f.WriteString(yamlDoc); err != nil {
		if rmErr := os.Remove(path); rmErr != nil {
			log.Print(rmErr)
		}
		log.Fatal(err)
	}
	if err = f.Close(); err != nil {
		if rmErr := os.Remove(path); rmErr != nil {
			log.Print(rmErr)
		}
		log.Fatal(err)
	}

	m, err := spec.Load(context.Background(), path, "", nil)
	if err != nil {
		if rmErr := os.Remove(path); rmErr != nil {
			log.Print(rmErr)
		}
		log.Fatal(err)
	}
	defer func() {
		if rmErr := os.Remove(path); rmErr != nil {
			log.Print(rmErr)
		}
	}()
	fmt.Println(m.Project)
}
Output:
demo

func ParseManifest added in v0.4.0

func ParseManifest(path string) (*Spec, string, error)

ParseManifest reads and partially validates the spec YAML file: validates the API version and environments section, then unmarshals the raw struct without applying envsubst or defaults. It returns the raw spec and version. Used by [Session.ResolvedSpec] as the first step of the full pipeline.

func (*Spec) EnvironmentNames

func (m *Spec) EnvironmentNames() []string

EnvironmentNames returns the sorted list of environment names defined in the spec. Returns an empty slice when no environments are defined.

type SubstitutionReport added in v0.4.0

type SubstitutionReport struct {
	// DynamicSubdomains maps component names to true when the component's
	// expose.subdomain field contained a ${VAR} token before substitution.
	DynamicSubdomains map[string]bool
}

SubstitutionReport records which component fields were produced by envsubst variable expansion. Consumers (e.g. the resolver) use this to distinguish user-supplied literals from dynamically expanded values.

func PrescanSubstitutionReport added in v0.4.0

func PrescanSubstitutionReport(rawSpec *Spec) SubstitutionReport

PrescanSubstitutionReport inspects the raw (pre-envsubst) spec for ${VAR} tokens in expose.subdomain fields and returns a SubstitutionReport. Call it after ParseManifest and before envsubst so the resolver can distinguish static from dynamic subdomains (the wildcard static-subdomain warning does not fire for dynamically expanded values).

type TLSMode added in v0.4.0

type TLSMode string

TLSMode specifies the TLS provisioning strategy for a domain.

const (
	// TLSModeSelfSigned uses a chart-managed self-signed certificate with a
	// stable secret name. The chart performs a lookup-before-create so the
	// certificate is not regenerated on every deploy.
	TLSModeSelfSigned TLSMode = "selfSigned"
	// TLSModeSecretName uses a pre-existing Kubernetes TLS secret. The secret
	// must exist in the deployment namespace.
	TLSModeSecretName TLSMode = "secretName"
	// TLSModeCertManager provisions a certificate via cert-manager. A
	// pre-flight check verifies that the cert-manager.io/v1 API group exists
	// and that the referenced ClusterIssuer or Issuer object is present.
	TLSModeCertManager TLSMode = "certManager"
)

Directories

Path Synopsis
Package schema embeds versioned JSON schemas for manifest, environment, and platform validation.
Package schema embeds versioned JSON schemas for manifest, environment, and platform validation.

Jump to

Keyboard shortcuts

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