Help us shape the future of Go! Take the 2026 Go Developer Survey

config

package
v0.12.0 Latest Latest
Warning

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

Go to latest
Published: Sep 12, 2026 License: AGPL-3.0, AGPL-3.0-only Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const (
	OriginNarrate    = "narrate"
	OriginDeps       = "deps"
	OriginGovernance = "governance"
)

Commit origins — the StageFreight path that authored a commit, and the git-native provenance trailer each carries. Both are our own trailers (they read like Signed-off-by, fire no forge CI-skip matcher, and are not forge-recognized so they trigger no avatar attribution). The verb is the whole signal — no parenthetical — and it lines up with the CI decision:

narrate → Generated-By: StageFreight   generation (docs/badges from code); no build
                                        impact → the CI rules SKIP its branch push.
deps    → Updated-By: StageFreight      an update to existing dependencies; changes what
                                        the image ships → it still BUILDS (rebuild + republish).
govern  → Governed-By: StageFreight     policy distributed from a control repo; changes the
                                        config the repo builds UNDER → it must BUILD, or the
                                        satellite never runs under the policy just given to
                                        it. Distinct from Updated-By so `git log --grep` can
                                        separate a reconcile from a dependency bump; no
                                        behaviour keys on either, both are provenance.

A manual `stagefreight commit` or a human commit carries no trailer — SF-authorship is already inferable from the commit author, and it builds by default. `Co-authored-by` is deliberately NOT used: it's a forge-recognized attribution trailer, reserved for the day StageFreight authors real code, not an automated docs/deps pass.

View Source
const (
	// GeneratedByTrailer marks a narrate commit (generated docs/badges); the CI rules key
	// on it to skip the branch pipeline, since regenerating would only re-emit it (the loop).
	GeneratedByTrailer = "Generated-By: StageFreight"
	// UpdatedByTrailer marks a deps commit (updated dependencies); provenance only — the CI
	// does NOT skip on it, because the image must rebuild to ship the update.
	UpdatedByTrailer = "Updated-By: StageFreight"
	// GovernedByTrailer marks a governance reconcile (policy distributed from a control
	// repo); provenance only, and likewise NOT skipped — the satellite must build under the
	// config it was just given.
	GovernedByTrailer = "Governed-By: StageFreight"
)
View Source
const (
	ModeImage      = "image"
	ModeGitops     = "gitops"
	ModeDocker     = "docker"
	ModeGovernance = "governance"
)

Lifecycle mode identifiers — the CANONICAL set. A mode selects phase-BODY behavior (build vs reconcile) and which mode-specific config block applies; it never gates a phase — the five phases (audition/perform/review/publish/narrate) run for every mode. These constants and the lifecycleModes table below are the single source of truth: dispatch sites and the validator read them instead of hardcoding `case "gitops"` literals.

View Source
const (
	TrustKey      = "key"
	TrustOIDC     = "oidc"
	TrustKMS      = "kms"
	TrustHardware = "hardware"
)

Trust classes — the only valid `requires` values after normalization.

View Source
const (
	DefaultChangesLimit   = 20000
	DefaultChangelogLimit = 40000
)

Release-note fact bounds, in characters, when a target declares none.

View Source
const DefaultAnsibleImage = "docker.io/hlhd/ansible:latest"

DefaultAnsibleImage is the official execution image. Repos normally pin an explicit version tag; the bare default exists so local plan/lint work before the pin is chosen.

View Source
const ShippedNotificationSubject = "{project} {ref} — {status} in {duration}"

ShippedNotificationSubject is the default notification title — a freeform body like everything else. No {status_icon}: ntfy renders the notification's Tags emoji in front of the title already (white_check_mark / rotating_light), and two icons read as a stutter. The fact stays available for custom subjects. {duration} is elapsed from the run's first recorded state write.

Variables

View Source
var DefaultScribeStore = path.Join(paths.Root, paths.ScribeName)

DefaultScribeStore is the default directory for scribe-rendered file assets (badge SVGs, and any future rendered files). Named after the subsystem, consistent with .stagefreight/security, .stagefreight/deps, .stagefreight/manifests. Derived from paths so the durable allowlist (workspace) carves out this exact directory.

View Source
var SourceFetcher presetref.Fetcher

SourceFetcher is the injected remote-preset fetcher. It is nil by default — in that state a sourced preset ref resolves from the preset-cache only (offline), erroring on a miss. A network-capable entry point (the CLI) sets it at startup so tracked/pinned refs fetch live. This is a set-once startup seam, not a per-call mutable global.

Functions

func AssertNormalized added in v0.5.0

func AssertNormalized(cfg *Config) error

AssertNormalized verifies no unresolved {var:} templates remain in the config, and that no identity token ({org*}/{orgs.*}/{metadata.*}/{path.*}/{slug}) survived the identity pass outside the (opaque) governance payload — a survivor means a typo'd alias/field or a missing orgs/metadata declaration, and failing loudly here beats a malformed push ref or a forge 404 later. Hard failure — not a warning.

func BodyRefs added in v0.8.0

func BodyRefs(body string) []string

BodyRefs scans a body for {name} embed tokens (skipping {{…}} literal escapes) and returns the names in order of appearance. It mirrors the stencil engine's brace scan so validation (cycle detection) and rendering agree on what a body references.

func CIBranch added in v0.7.0

func CIBranch() string

CIBranch returns the current branch from the CI environment ("" if none).

func CIEvent added in v0.7.0

func CIEvent() string

CIEvent derives the current CI event in the canonical when.events vocabulary. Tag presence (CI_COMMIT_TAG / SF_CI_TAG) is the authoritative push-vs-tag signal: GitLab reports CI_PIPELINE_SOURCE=push even for tag pushes, and the dev channel synthesizes its tag locally (never exporting SF_CI_TAG), so a tag *string* is not a reliable event signal. Otherwise the raw forge source (SF_CI_EVENT) is mapped to the canonical vocabulary via NormalizeEvent, so gates authored once (events:[manual]) match on every forge despite their differing raw names.

func CIProvider added in v0.7.0

func CIProvider() string

CIProvider returns the current forge provider (github/gitlab/gitea/forgejo) from the CI environment ("" if none), for forge-scoped target eligibility.

func CITag added in v0.7.0

func CITag() string

CITag returns the current tag from the CI environment ("" if none).

func DeepMerge added in v0.6.0

func DeepMerge(base, override *yaml.Node) *yaml.Node

DeepMerge deep-merges override into base (both mapping nodes), override wins. Objects deep-merge (base order preserved, new keys appended); scalars/sequences replace. Non-mapping inputs: override replaces.

func EventMatches added in v0.7.0

func EventMatches(events []string, current string) bool

EventMatches reports whether the current CI event satisfies a target's when.events filter. It is the shared primitive for event-aware target routing (release targets, binary-archive gating). The current event is expected in the canonical vocabulary (see NormalizeEvent) — CIEvent normalizes at the env boundary, so this primitive never sees a raw forge source name.

Semantics:

  • An empty filter (no events: declared) means no filtering — always true.
  • An empty current event (unknown) also means no filtering — events are enforced only when the event is known, so non-CI/manual paths stay lenient.
  • Comparison is case-insensitive and trims surrounding whitespace.
  • A push-equivalent event (manual or schedule — see pushEquivalent) satisfies a "push" gate as well as its own literal gate name, so manual re-runs and scheduled auto-release pipelines distribute exactly what a push would. The relation is one-way: a plain "push" does NOT satisfy a manual-/schedule-only gate.

func ForgeLinkBase added in v0.5.0

func ForgeLinkBase(provider, baseURL, projectID, branch string) (string, error)

ForgeLinkBase constructs a page-link (blob) base URL from forge fields. Used for resolving relative links (e.g., LICENSE → blob URL).

func ForgeRawBase added in v0.5.0

func ForgeRawBase(provider, baseURL, projectID, branch string) (string, error)

ForgeRawBase constructs a raw content base URL from forge mirror fields. Handles GitLab subgroup paths (group/subgroup/project) correctly. All inputs are normalized to prevent double-slash artifacts.

func HostOf added in v0.9.0

func HostOf(raw string) string

HostOf extracts the lowercased hostname (no scheme, no port, no path, no userinfo) from a URL or bare host string, for EXACT host matching. "https://gitlab.example.com:443/o/r" and "gitlab.example.com" both normalize to "gitlab.example.com". Returns "" when the input has no resolvable host. This is the single host-identity primitive used to bind a git credential to the forge that owns the destination host.

func IdentitySubs added in v0.10.0

func IdentitySubs(cfg *Config) map[string]string

IdentitySubs builds the brace-delimited token → value map from config. Tokens are brace-delimited so none is a substring of another as a whole token (e.g. "{org}" never matches inside "{org.lower}"), making ReplaceAll order-independent. Only tokens the config can populate are added; a typo'd token has no entry, stays literal, and the normalization assertion rejects it loudly.

func IsShippedStencilID added in v0.8.0

func IsShippedStencilID(id string) bool

IsShippedStencilID reports whether id names a shipped default stencil (valid to announce or embed without a user declaration).

func LLMTaintedStencils added in v0.8.0

func LLMTaintedStencils(stencils OrderedStencils) map[string]bool

LLMTaintedStencils returns every stencil id whose output can carry AI text: the type: llm stencils plus any text stencil embedding a tainted stencil, transitively (fixpoint). AI output is DISPATCH-ONLY — stdout cards and notifications — never the committed record: scribe file regions reject these ids at validation (the determinism boundary).

func LoadWithReport added in v0.6.0

func LoadWithReport(path string) (*Config, ConfigReport, []MergeEntry, error)

LoadWithReport loads config and returns a ConfigReport with real provenance. It also returns the raw per-value merge entries so callers that want per-value provenance (e.g. `config resolve --verbose`) render from the SAME resolution — no second resolve. Entries are nil for an absent/preset-free config.

func MatchCondition

func MatchCondition(c Condition) bool

MatchCondition evaluates a Condition against the current CI environment. Returns true if all present fields match (AND logic). Empty condition = catch-all (always true).

func MatchConditionWith

func MatchConditionWith(c Condition, tag, branch string) bool

MatchConditionWith evaluates a Condition against explicit tag/branch values. Use this when you already have the values resolved (e.g., from git detection).

func MatchPatterns

func MatchPatterns(patterns []string, value string) bool

MatchPatterns evaluates a list of patterns against a value (OR logic). Any pattern matching means the value is allowed. Empty list = always allowed (no filter). Supports ! negation — a negated pattern excludes even if others include.

Evaluation: exclude patterns (!) are checked first. If any exclude matches, the value is rejected. Then include patterns are checked — if any matches, the value is allowed. If only exclude patterns exist and none matched, the value is allowed (exclude-only = allowlist by negation).

func MatchPatternsWithPolicy

func MatchPatternsWithPolicy(patterns []string, value string, policyMap map[string]string) bool

MatchPatternsWithPolicy resolves named patterns and evaluates them against a value. Convenience wrapper combining ResolvePatterns + MatchPatterns. (Name retained for backward compat with existing call sites.)

func MessageHasTrailer added in v0.9.0

func MessageHasTrailer(msg, trailer string) bool

MessageHasTrailer reports whether msg carries trailer as a whole line. A git trailer sits on its own line (and is the last line for SF's own commits, per commit.Plan.Message), so matching the full line — not a substring — prevents a commit whose PROSE merely mentions the trailer (e.g. one describing this very skip rule) from being mistaken for a generated commit. The CI-render layer anchors equivalently (GitLab `(?m)^…`, Actions `endsWith`).

func MigrateToLatest

func MigrateToLatest(data []byte) ([]byte, error)

MigrateToLatest takes raw YAML data and migrates it to the current schema version. Returns the migrated YAML bytes ready for writing.

Migration chain:

version 1 → current (no-op, already latest)

Future schema changes should add migration steps here (e.g., v1→v2). The old pre-version config was an unversioned alpha that never earned a schema number — it is not convertible and is not supported by this migration path.

func Normalize added in v0.5.0

func Normalize(cfg *Config) error

Normalize resolves all {var:...} templates throughout the entire config. Walks every string in the config graph recursively — structs, maps, slices, interfaces. No field enumeration. No partial coverage.

Called once after load+validate, before any consumer reads the config.

func NormalizeEvent added in v0.9.2

func NormalizeEvent(raw string) string

NormalizeEvent maps a forge's raw pipeline-source string to the canonical when.events vocabulary (see validEvents), so a config gate is written once in portable terms and matches on every forge. The raw source is CI_PIPELINE_SOURCE on GitLab, github.event_name on GitHub/Gitea/Forgejo, and Build.Reason on Azure — and the single "manual re-run" concept has five different raw names across them (web/api/trigger, workflow_dispatch, Manual), which all collapse to "manual". An unrecognized source passes through lowercased (lenient: it still matches a literally-named gate), and empty stays empty (the unknown-event lenience in EventMatches then applies).

func OriginTrailer added in v0.8.0

func OriginTrailer(origin string) string

OriginTrailer returns the provenance trailer for a StageFreight commit origin, or "" for a manual/human commit (no trailer). The commit layer writes it; the CI-render layer keys its skip rule on GeneratedByTrailer.

func ParseDuration added in v0.5.0

func ParseDuration(s string) (time.Duration, error)

ParseDuration parses a human duration like "7d", "72h", "30m". Extends time.ParseDuration with "d" (days) support.

func ParseForgeURL added in v0.5.0

func ParseForgeURL(rawURL string) (provider, baseURL, projectID string, err error)

ParseForgeURL detects forge provider from a full repository URL, extracts base URL and project ID. Examples:

"https://github.com/PrPlanIT/StageFreight"       → github, "https://github.com", "PrPlanIT/StageFreight"
"https://gitlab.prplanit.com/SoFMeRight/dungeon" → gitlab, "https://gitlab.prplanit.com", "SoFMeRight/dungeon"

func ParseSize added in v0.5.0

func ParseSize(s string) (int64, error)

ParseSize parses a human size like "15GB", "500MB", "100KB". Uses binary units (1 GB = 1024³ bytes).

func PrimaryDefaultBranch added in v0.6.0

func PrimaryDefaultBranch(cfg *Config) string

PrimaryDefaultBranch returns the default branch of the primary repo.

func PrimaryURL added in v0.6.0

func PrimaryURL(cfg *Config) string

PrimaryURL returns the full URL of the primary repo, or empty string. Thin wrapper over ResolvePrimary for call sites that only need the URL.

func PrimaryWorktree added in v0.6.0

func PrimaryWorktree(cfg *Config) string

PrimaryWorktree returns the worktree path of the primary repo, or ".".

func ResolveLinkBase added in v0.5.0

func ResolveLinkBase(cfg *Config) (string, error)

ResolveLinkBase resolves the page-link (blob) base URL for relative links. Uses the repo with publish-origin role, falling back to primary.

func ResolvePatterns

func ResolvePatterns(patterns []string, patternMap map[string]string) []string

ResolvePatterns resolves named tokens in a pattern list to their regex values from the provided name→regex map (e.g. matchers.branches or a flattened tag_sources map). It is the single resolver for the full when: pattern vocabulary: named policies, bare/`re:`-prefixed regex, and `!` negation. A "re:" prefix forces inline-regex interpretation, bypassing named-pattern lookup; bare patterns pass through unchanged; negation is preserved.

func ResolvePublishOrigin added in v0.5.0

func ResolvePublishOrigin(cfg *Config) (string, error)

ResolvePublishOrigin resolves the serving base URL for rendered artifacts. Uses the repo with publish-origin role, falling back to primary.

func SlugFromPrimary added in v0.10.0

func SlugFromPrimary(cfg *Config) string

SlugFromPrimary is the repo's name that coordinates default {repo} to: the LITERAL primary repo location's last segment. "" when no primary exists or its project is still templated (which cannot anchor a slug).

func TargetIsUnconditional added in v0.7.0

func TargetIsUnconditional(t TargetConfig) bool

TargetIsUnconditional reports whether a target declares no when: constraints at all (no events, branches, or git_tags) — i.e. it is eligible in every CI context. It exists so callers can ask this WITHOUT reading t.When.* directly: an emptiness probe is still an interpretation of target constraints, and per the eligibility-routing invariant there is exactly one interpreter (this package).

func TargetMatches added in v0.7.0

func TargetMatches(t TargetConfig, event, branch, tag, forge string, tagPolicies, branchPolicies map[string]string) bool

TargetMatches reports whether a target's when: conditions are satisfied — the bool view of TargetEligibility for call sites that don't narrate. See the TargetEligibility invariant: this is the single shared gating predicate; capabilities must not interpret when: themselves.

func TargetMatchesEnv added in v0.7.0

func TargetMatchesEnv(t TargetConfig, cfg *Config) bool

TargetMatchesEnv evaluates TargetMatches against the current CI environment, resolving policy maps from cfg. Convenience for contributors that gate on when:.

func ValidArchiveFormats added in v0.8.0

func ValidArchiveFormats() []string

ValidArchiveFormats returns the recognized binary-archive format values.

func ValidBuildKinds added in v0.8.0

func ValidBuildKinds() []string

ValidBuildKinds returns the recognized builds[].kind values.

func ValidBuilders added in v0.8.0

func ValidBuilders() []string

ValidBuilders returns the recognized builds[].builder values.

func ValidEvents added in v0.8.0

func ValidEvents() []string

ValidEvents returns the recognized targets[].when.events values.

func ValidLintLevels added in v0.8.0

func ValidLintLevels() []string

ValidLintLevels returns the recognized lint.level values.

func ValidManifestModes added in v0.8.0

func ValidManifestModes() []string

ValidManifestModes returns the recognized manifest.mode values.

func ValidOutputTypes added in v0.8.0

func ValidOutputTypes() []string

ValidOutputTypes returns the recognized builds[].outputs[].type values.

func ValidTargetKinds added in v0.8.0

func ValidTargetKinds() []string

ValidTargetKinds returns the recognized targets[].kind values.

func ValidTrustClasses added in v0.8.0

func ValidTrustClasses() []string

ValidTrustClasses returns the recognized signing.profiles[].requires values.

func Validate

func Validate(cfg *Config) (warnings []string, err error)

Validate checks structural invariants of a loaded v2 Config. Returns warnings (soft issues) and a hard error if the config is invalid.

func ValidateIdentityGraph added in v0.6.0

func ValidateIdentityGraph(forges []ForgeConfig, repos []RepoConfig, registries []RegistryConfig) []string

ValidateIdentityGraph checks structural invariants of forges, repos, and registries. Returns all errors found (not just the first).

func ValidatePreset added in v0.6.0

func ValidatePreset(content []byte) (string, *yaml.Node, error)

ValidatePreset parses a preset and enforces exactly one top-level key, returning that key and its value node.

func ValidateSigningConfig added in v0.7.0

func ValidateSigningConfig(c SigningConfig) []string

ValidateSigningConfig checks the operational signing block. auto_provision needs a state dir (nowhere to persist a Tier-0 identity otherwise — a silent ephemeral key would break continuity on every run).

func ValidateSigningProfiles added in v0.7.0

func ValidateSigningProfiles(profiles []SigningProfile) []string

ValidateSigningProfiles is the single validation layer for signing policy (Compile in src/sign never re-validates — it is total over validated config). Alias-tolerant (keyless/yubikey accepted; Normalize canonicalizes later).

func ValidateTargetRegistryRefs added in v0.6.0

func ValidateTargetRegistryRefs(targets []TargetConfig, registries []RegistryConfig) []string

ValidateTargetRegistryRefs checks that targets with registry: reference existing registries, and that registry + inline fields don't conflict.

func ValidateTargetRepoRefs added in v0.7.0

func ValidateTargetRepoRefs(targets []TargetConfig, repos []RepoConfig) []string

ValidateTargetRepoRefs checks that targets referencing a repo (kind: generic-package) resolve to a declared repos[] entry. Mirrors ValidateTargetRegistryRefs.

func ValidateTargetSigningProfileRefs added in v0.7.0

func ValidateTargetSigningProfileRefs(targets []TargetConfig, profiles []SigningProfile) []string

ValidateTargetSigningProfileRefs checks each target's signing_profile resolves. An empty reference is valid (→ the synthesized `legacy` profile); the reserved `legacy` id is always valid. Mirrors ValidateTargetRegistryRefs.

Types

type AgePruneRule added in v0.5.0

type AgePruneRule struct {
	OlderThan string `yaml:"older_than,omitempty"` // e.g. "72h"
}

AgePruneRule is a simple age-based prune rule.

type AnsibleConfig added in v0.9.0

type AnsibleConfig struct {
	Preset string `yaml:"preset,omitempty"`

	// Backend selects the host-convergence backend. Default: "ansible".
	Backend string `yaml:"backend"`

	// Image is the execution image the playbooks (and ansible-lint) run in —
	// the ansible runtime, collections, and connection deps are the image's
	// contract. Fully qualified, version-pinned reference.
	// Default: docker.io/hlhd/ansible (the official StageFreight ansible image).
	Image string `yaml:"image"`

	// Inventory is the repo-relative ansible inventory file.
	Inventory string `yaml:"inventory"`

	// SSH is the shared connection identity used by every play.
	SSH AnsibleSSH `yaml:"ssh"`

	// Playbooks is the play library: an order-preserving id → entry map.
	// Entries with converge: true run every perform reconcile, in declared
	// order; entries with converge: false are runbooks — lintable and
	// plannable, but only ever executed by an explicit `ansible run <id>`.
	Playbooks OrderedAnsiblePlaybooks `yaml:"playbooks"`
}

AnsibleConfig defines the ansible host-convergence subsystem: a library of declared playbooks executed inside a containerized ansible runtime. It is presence-gated (any converge playbook activates the perform-phase backend) and deliberately independent of lifecycle.mode — ansible runs alongside gitops/governance, never instead of them.

func DefaultAnsibleConfig added in v0.9.0

func DefaultAnsibleConfig() AnsibleConfig

DefaultAnsibleConfig returns sensible defaults for ansible configuration.

func (AnsibleConfig) ConvergePlaybooks added in v0.9.0

func (a AnsibleConfig) ConvergePlaybooks() []AnsiblePlaybook

ConvergePlaybooks returns the converge set in declared order.

func (AnsibleConfig) HasConvergePlaybooks added in v0.9.0

func (a AnsibleConfig) HasConvergePlaybooks() bool

HasConvergePlaybooks reports whether any play is declared converge: true — the presence gate for the perform-phase ansible subsystem.

func (AnsibleConfig) PlaybookByID added in v0.9.0

func (a AnsibleConfig) PlaybookByID(id string) (AnsiblePlaybook, bool)

PlaybookByID returns the declared play with the given id.

type AnsiblePlaybook added in v0.9.0

type AnsiblePlaybook struct {
	ID string `yaml:"-"`

	// Path is the repo-relative playbook file.
	Path string `yaml:"path"`

	// Groups are the inventory groups this play targets (rendered as --limit).
	Groups []string `yaml:"groups"`

	// Converge marks the play as desired-state: it runs on every perform
	// reconcile. False declares a runbook — a named human operation that CI
	// can never trigger.
	Converge bool `yaml:"converge"`

	// Required: failure is hard pipeline fail (default: true — a converge
	// mutates hosts, so a partial apply must never pass silently). Set false
	// for advisory plays: a failure is recorded and narrated but the phase
	// still exits clean.
	Required *bool `yaml:"required,omitempty"`
}

AnsiblePlaybook is one declared play in the library. The map key is its ID.

func (AnsiblePlaybook) IsRequired added in v0.9.0

func (p AnsiblePlaybook) IsRequired() bool

IsRequired reports whether this play's failure hard-fails the phase. Unset defaults to true.

type AnsibleSSH added in v0.9.0

type AnsibleSSH struct {
	// User is the remote login user on the managed hosts.
	User string `yaml:"user"`

	// Credentials is the env-prefix name the SSH key material is read from.
	Credentials string `yaml:"credentials"`

	// KnownHosts is the repo-relative known_hosts file holding the managed
	// hosts' public keys. Host-key verification is always strict; the file is
	// committed so host trust is auditable in git.
	KnownHosts string `yaml:"known_hosts"`
}

AnsibleSSH is the shared SSH connection identity for all plays. The private key is resolved from environment variables at runtime:

  • <PREFIX>_SSH_KEY: PEM private key material
  • <PREFIX>_SSH_KEY_B64: base64 of the PEM — the single-line form a forge MASKED variable can hold (mirrors the gitops <NAME>_CA_B64 convention)
  • <PREFIX>_SSH_KEY_PASSPHRASE: optional key passphrase

Credentials is uppercased with hyphens replaced by underscores to form the env prefix (the same convention as the gitops cluster CA).

func (AnsibleSSH) EnvPrefix added in v0.9.0

func (s AnsibleSSH) EnvPrefix() string

EnvPrefix derives the environment prefix for SSH credential resolution: uppercased, hyphens to underscores (e.g. "dungeon-nodes" → "DUNGEON_NODES").

type BadgeSpec

type BadgeSpec struct {
	Label    string  // left side text (badge name / alt text)
	Value    string  // right side text (supports templates)
	Color    string  // hex color or "auto"
	Output   string  // SVG file output path
	Font     string  // built-in font name override
	FontSize float64 // font size override
	FontFile string  // custom font file override
}

BadgeSpec is the reusable internal badge specification. Consumed by badge engine, CLI ad-hoc mode, release badge, and docker build badge. No YAML tags — this is an internal model, not a config surface.

type BranchBuildConfig added in v0.6.0

type BranchBuildConfig struct {
	// ID is the unique identifier. "default" is the catch-all entry and must
	// appear last in the BranchBuilds slice.
	ID string `yaml:"id"`

	// Match references a declared branch matcher name. Required for named
	// branch_builds entries. The "default" entry rejects Match — it catches
	// any branch that did not match a named entry.
	Match string `yaml:"match,omitempty"`

	// BaseFrom is the ordered fallback chain of tag_sources ids. The runtime
	// walks this list in order; for each source id, it scans tags for a match
	// and returns the first hit. Fallback advances only when a source yields
	// zero matches.
	//
	// Reads as "look in prerelease first; if nothing, look in stable":
	//   base_from: [prerelease, stable]
	//
	// It does NOT mean "prerelease beats stable by priority" — ordering is a
	// declared search path, not a ranking.
	BaseFrom []string `yaml:"base_from"`

	// Format is the version template for non-release commits.
	// Supported placeholders: {base}, {sha}, {branch}
	// e.g., "{base}-dev+{sha}"
	Format string `yaml:"format"`
}

BranchBuildConfig defines how dev versions are formatted for a branch.

type BranchesConfig added in v0.6.0

type BranchesConfig struct {
	// Default is the default branch name (e.g., "main"). Required for primary.
	Default string `yaml:"default,omitempty"`
}

BranchesConfig declares branch identity for a repo. Currently carries only Default; reserved for future additions like protected branches, release branches, etc. — those stay on the repo because they're topology, not versioning or promotion.

type BreakingConfig added in v0.5.0

type BreakingConfig struct {
	Aliases        []string `yaml:"aliases,omitempty"` // e.g., [b, break, bc]
	BangSuffix     bool     `yaml:"bang_suffix"`       // feat! syntax
	FooterKeys     []string `yaml:"footer_keys"`       // e.g., ["BREAKING CHANGE"]
	ForceHighlight bool     `yaml:"force_highlight"`
	PriorityBoost  int      `yaml:"priority_boost"`
}

BreakingConfig defines how breaking changes are detected and presented.

type BuildCacheConfig added in v0.5.0

type BuildCacheConfig struct {
	Preset string `yaml:"preset,omitempty"`

	// Mode selects which cache planes are active.
	// "": inactive — no cache flags emitted, no cleanup runs.
	// off: explicitly disabled.
	// local: bounded local buildkit cache only.
	// shared: registry-backed external cache only.
	// hybrid: both local and external.
	Mode string `yaml:"mode,omitempty"`

	// Builder configures the buildx builder lifecycle.
	// The engine owns creation, bootstrap, and narration — skeleton is transport only.
	Builder BuilderConfig `yaml:"builder,omitempty"`

	// Local configures the bounded local buildkit cache.
	Local LocalCacheConfig `yaml:"local,omitempty"`

	// External configures registry-backed shared cache.
	External ExternalCacheConfig `yaml:"external,omitempty"`

	// Cleanup is governance-owned host-hygiene policy — see HostCleanupConfig.
	Cleanup HostCleanupConfig `yaml:"cleanup,omitempty"`
}

BuildCacheConfig defines the three-layer build cache subsystem. Mode selects the active planes. Advanced config underneath only when needed.

func DefaultBuildCacheConfig added in v0.5.0

func DefaultBuildCacheConfig() BuildCacheConfig

DefaultBuildCacheConfig returns baseline defaults. Mode is empty (inactive) — cleanup and cache only execute when mode is explicitly set. Governance presets should override enforcement and thresholds per runner class.

func (BuildCacheConfig) IsActive added in v0.5.0

func (c BuildCacheConfig) IsActive() bool

IsActive returns true if any cache mode is enabled.

type BuildCachePrunePolicy added in v0.5.0

type BuildCachePrunePolicy struct {
	OlderThan   string `yaml:"older_than,omitempty"`   // e.g. "72h"
	KeepStorage string `yaml:"keep_storage,omitempty"` // e.g. "20GB"
}

BuildCachePrunePolicy defines build cache pruning rules.

type BuildConfig

type BuildConfig struct {
	// ID is the unique identifier for this build, referenced by targets.
	ID string `yaml:"id"`

	// Kind is the build type. Determines which fields are valid.
	// Supported: "docker", "binary", "command".
	//   - docker:  build an OCI image
	//   - binary:  build an executable via a language builder (opinionated inference)
	//   - command: run an arbitrary command in an image, capture typed outputs (the
	//              un-opinionated escape hatch; no inference). Prefer a `builder:` when
	//              one fits; reach for command only when none does.
	Kind string `yaml:"kind"`

	// SelectTags enables CLI filtering via --select.
	SelectTags []string `yaml:"select_tags,omitempty"`

	// Required means build failure is a hard pipeline fail. Default: true.
	Required *bool `yaml:"required,omitempty"`

	// BuildMode controls the build execution strategy.
	// Supported: "" (standard), "crucible" (self-proving rebuild).
	BuildMode string `yaml:"build_mode,omitempty"`

	// DependsOn lists the nodes that must complete before this build runs. Entries
	// are TYPED references: a bare id (or "build:<id>") is another BUILD; "scribe:<id>"
	// is a scribe content item that must be rendered first (a build baking scribe
	// output — e.g. a doc-site build consuming composed pages). Accepts a scalar or a
	// sequence; a bare id stays a build ref, so existing `depends_on: x` is unchanged.
	// Typed prefixes keep the build and scribe id spaces separate — no shared-uid rule.
	DependsOn StringOrList `yaml:"depends_on,omitempty"`

	// Dockerfile is the path to the Dockerfile. Default: auto-detect.
	Dockerfile string `yaml:"dockerfile,omitempty"`

	// Context is the Docker build context path. Default: "." (repo root).
	Context string `yaml:"context,omitempty"`

	// Target is the --target stage name for multi-stage builds.
	Target string `yaml:"target,omitempty"`

	// Platforms lists the target platforms. Default: [linux/{current_arch}].
	Platforms []string `yaml:"platforms,omitempty"`

	// BuildArgs are key-value pairs passed as --build-arg. Supports templates.
	BuildArgs map[string]string `yaml:"build_args,omitempty"`

	// Secrets are id → in-repo file path, passed as --secret id=<id>,src=<path>.
	// A build arg is baked into the image and readable from its history; a secret is
	// mounted for one RUN and leaves nothing behind. Use it for a credential, and for
	// an input a Dockerfile expects this way — upstream frappe_docker takes its app
	// list as a secret rather than a build arg, for instance.
	Secrets map[string]string `yaml:"secrets,omitempty"`

	// Cache holds build cache settings.
	Cache CacheConfig `yaml:"cache,omitempty"`

	// Stage recycles a binary build's output into this docker build's context before
	// buildx, so a copy-pre-built Dockerfile (COPY <name>) resolves — the compiled
	// binary is reused, not recompiled inside the image.
	Stage *StageConfig `yaml:"stage,omitempty"`

	// Builder is the toolchain that interprets the build.
	// Supported: "go", "rust", "node", "elixir", "dotnet", "c", "python", "jvm", "android"
	// (authoritative list: validBuilders in enums.go). Future: "zig". Empty defaults to "go".
	Builder string `yaml:"builder,omitempty"`

	// Command is the builder subcommand (binary: e.g. "build") or the full command
	// (kind: command). Accepts a scalar string or an argv sequence. Default: "build".
	Command CommandSpec `yaml:"command,omitempty"`

	// From is the source/input root or entry point.
	// e.g., "./src/cli" (Go package), "./src/main.rs" (Rust).
	From string `yaml:"from,omitempty"`

	// Output is the artifact name. Windows platforms auto-append ".exe".
	// Default: basename of From.
	Output string `yaml:"output,omitempty"`

	// Image is the container image a containerized build (builder: node, elixir) runs
	// inside (with the repo mounted). Command runs in it; Output is the produced
	// artifact (file or directory tree). Defaults per builder; override for the odd
	// case (e.g. electronuserland/builder:wine, or an elixir+node image for Phoenix).
	Image string `yaml:"image,omitempty"`

	// Args are ordered raw arguments passed directly to the selected builder.
	// For Go: raw args to "go build". For Rust: raw args to "cargo build".
	// Supports template variables: {version}, {sha}, {sha:N}, {date}.
	Args []string `yaml:"args,omitempty"`

	// Env are build environment variables. e.g., {"CGO_ENABLED": "0"}
	Env map[string]string `yaml:"env,omitempty"`

	// Compress enables UPX compression on the output binary. Default: false.
	Compress bool `yaml:"compress,omitempty"`

	// Crucible holds crucible-specific configuration for binary builds.
	Crucible *CrucibleConfig `yaml:"crucible,omitempty"`

	// Outputs declares what the command produced and each output's artifact class.
	Outputs []OutputSpec `yaml:"outputs,omitempty"`
}

BuildConfig defines a named build artifact. Each build has a unique ID (referenced by targets) and a kind that determines which fields are valid.

This is a discriminated union keyed by Kind — only fields relevant to the kind should be set. Validated at load time by v2 validation.

func (BuildConfig) BuildDeps added in v0.8.0

func (b BuildConfig) BuildDeps() []string

BuildDeps returns the BUILD ids this build depends on — the bare or "build:"- prefixed entries in depends_on, with the prefix stripped. Scribe deps are excluded.

func (BuildConfig) BuilderCommand added in v0.4.0

func (b BuildConfig) BuilderCommand() string

BuilderCommand returns the builder command, defaulting to "build".

func (BuildConfig) IsRequired added in v0.5.0

func (b BuildConfig) IsRequired() bool

IsRequired returns whether build failure is a hard pipeline fail. Default: true.

func (BuildConfig) OutputName added in v0.4.0

func (b BuildConfig) OutputName() string

OutputName returns the output artifact name, defaulting to basename of From.

func (BuildConfig) ScribeDeps added in v0.8.0

func (b BuildConfig) ScribeDeps() []string

ScribeDeps returns the scribe content ids this build consumes as inputs — the "scribe:"-prefixed entries in depends_on. These render before this build runs.

type BuilderConfig added in v0.5.0

type BuilderConfig struct {
	// Backend pins the build backend. Default: "" (auto-detect).
	// "buildkitd" → prefer persistent buildkitd, fail if unavailable.
	// "dind" → use DinD only, ignore buildkitd even if available.
	// "" → auto-detect: prefer buildkitd if available, fall back to DinD.
	Backend string `yaml:"backend,omitempty"`

	// Name is the buildx builder name. Default: "sf-builder".
	Name string `yaml:"name,omitempty"`

	// Driver is the buildx driver. Default: "docker-container".
	Driver string `yaml:"driver,omitempty"`

	// Context is the Docker context name for the builder endpoint. Default: "sf-context".
	Context string `yaml:"context,omitempty"`

	// Memory caps the builder container (e.g. "3g"), pinning memory-swap to the same
	// value so the builder cannot swap. Unset derives it from the runner: total RAM
	// minus a reserve that keeps the host alive — a build must never be able to
	// livelock its own machine. Only applies to a builder StageFreight creates
	// (docker-container driver); an external buildkitd owns its own limits.
	Memory string `yaml:"memory,omitempty"`
}

BuilderConfig declares the buildx builder identity. The engine creates/bootstraps/narrates — this is just the declaration.

func (BuilderConfig) BuilderDriver added in v0.5.0

func (b BuilderConfig) BuilderDriver() string

BuilderDriver returns the driver, defaulting to "docker-container".

func (BuilderConfig) BuilderName added in v0.5.0

func (b BuilderConfig) BuilderName() string

BuilderName returns the builder name, defaulting to "sf-builder".

func (BuilderConfig) ContextName added in v0.5.0

func (b BuilderConfig) ContextName() string

ContextName returns the Docker context name, defaulting to "sf-context".

type CIConfig added in v0.6.0

type CIConfig struct {
	// Image is the container image for all pipeline jobs.
	// Required — render refuses to emit without it.
	Image string `yaml:"image"`

	// Forge names the forge whose CI skeleton this repo runs on, and therefore which
	// pipeline file governance renders and distributes (gitlab → .gitlab-ci.yml,
	// github → .github/workflows/stagefreight.yml, …). More than one may be listed —
	// each writes its own file — for a repo genuinely wired to two CI systems.
	//
	// It is DECLARED, never inferred. The primary repo's forge is the obvious guess and
	// it is wrong often enough to matter: a repo can be authoritative on one forge and
	// run CI on another after replication — source on GitLab, Actions on the GitHub
	// mirror. Guessing there writes a skeleton for a forge that never runs it while the
	// one that does goes stale, surfacing as an unexplained "CI is stale" at audition.
	//
	// Empty means no CI file is rendered or distributed. That is deliberate: a repo that
	// has not said where its CI runs gets nothing, rather than something plausible.
	Forge []string `yaml:"forge,omitempty"`

	// Routing declares per-phase runner placement requirements.
	// The renderer lowers labels to forge-native primitives
	// (GitLab: tags, GitHub/Gitea/Forgejo: runs-on).
	Routing RoutingConfig `yaml:"routing,omitempty"`
}

CIConfig holds all pipeline-related configuration consumed by stagefreight ci render. One block, one concern.

type CacheConfig

type CacheConfig struct {
	Watch      []WatchRule `yaml:"watch"`
	AutoDetect *bool       `yaml:"auto_detect"`
}

CacheConfig holds build cache settings.

type ClusterConfig added in v0.5.0

type ClusterConfig struct {
	Name     string
	Endpoint string
	Exposure ExposureRules
}

ClusterConfig identifies a Kubernetes cluster and how to connect to it. Built from a GitOpsCluster via Connection(); it is an internal descriptor, not a YAML shape. CA trust is resolved from environment variables at runtime:

  • <NAME>_CA_FILE: path to CA certificate file
  • <NAME>_CA_B64: base64-encoded CA certificate PEM

Name is uppercased with hyphens replaced by underscores for the env prefix.

type CommandSpec added in v0.7.0

type CommandSpec string

CommandSpec is a build command that accepts either a scalar shell string (`command: "go build"`) or a sequence / argv list (`command: [go, build]`), normalized to a single string for `sh -c`. The sequence form is shell-quoted so args with spaces survive. Used by binary builders (a subcommand) and kind: command (the full command).

func (*CommandSpec) UnmarshalYAML added in v0.7.0

func (c *CommandSpec) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML accepts a scalar or a sequence of strings.

type CommitConfig

type CommitConfig struct {
	Preset       string `yaml:"preset,omitempty"`
	DefaultType  string `yaml:"default_type,omitempty"`
	DefaultScope string `yaml:"default_scope,omitempty"`
	SkipCI       bool   `yaml:"skip_ci,omitempty"`
	Push         bool   `yaml:"push,omitempty"`
	Conventional bool   `yaml:"conventional"`

	// Render controls commit rendering (default DefaultCommitPresentation; a
	// partial render: block overlays those defaults).
	Render  CommitPresentation `yaml:"render,omitempty"`
	Backend string             `yaml:"backend,omitempty"`
	Types   []CommitType       `yaml:"types,omitempty"`
}

CommitConfig holds configuration for the commit subsystem.

func DefaultCommitConfig

func DefaultCommitConfig() CommitConfig

DefaultCommitConfig returns sensible defaults for commit configuration.

type CommitPresentation added in v0.5.0

type CommitPresentation struct {
	PreserveRawSubject  bool `yaml:"preserve_raw_subject"`
	EnforceConventional bool `yaml:"enforce_conventional"`
}

CommitPresentation controls commit rendering (commit.render). Authoring-oriented: alias expansion and validation, NOT release-style uplift.

func DefaultCommitPresentation added in v0.8.0

func DefaultCommitPresentation() CommitPresentation

DefaultCommitPresentation is the default commit.render policy.

type CommitType

type CommitType struct {
	Key       string `yaml:"key"`
	Label     string `yaml:"label"`
	AliasFor  string `yaml:"alias_for,omitempty"`
	ForceBang bool   `yaml:"force_bang,omitempty"`
}

CommitType defines a recognized commit type for conventional commits.

type CompiledPatterns

type CompiledPatterns struct {
	Include []*regexp.Regexp
	Exclude []*regexp.Regexp
}

CompiledPatterns holds pre-compiled include and exclude regex patterns. Avoids repeated regex compilation during planning and matching.

func CompilePatterns

func CompilePatterns(patterns []string, policyMap map[string]string) (*CompiledPatterns, error)

CompilePatterns resolves pattern tokens against a policy map and compiles them into include/exclude regex groups. Discards warnings.

func CompilePatternsWithWarnings

func CompilePatternsWithWarnings(patterns []string, policyMap map[string]string) (*CompiledPatterns, []string, error)

CompilePatternsWithWarnings resolves pattern tokens against a policy map, compiles them into include/exclude regex groups, and returns any warnings (e.g., typo detection for unknown policy names).

func (*CompiledPatterns) Match

func (cp *CompiledPatterns) Match(value string) bool

Match evaluates the compiled patterns against a value. Exclude-first semantics: if any exclude matches, rejected. Empty include list with no excludes = pass (no constraints). Empty include list with only excludes = everything not excluded passes.

type Condition

type Condition struct {
	// Tag is a pattern matched against the git tag (CI_COMMIT_TAG).
	// Only evaluated when a tag is present. Prefix with ! to negate.
	Tag string `yaml:"tag,omitempty"`

	// Branch is a pattern matched against the git branch (CI_COMMIT_BRANCH).
	// Prefix with ! to negate.
	Branch string `yaml:"branch,omitempty"`
}

Condition is the universal conditional rule primitive used across StageFreight. Every feature that has tag/branch-sensitive behavior uses this same structure.

Pattern syntax (applies to Tag, Branch, and any future filter fields):

"^main$"             — regex match (default)
"!^feature/.*"       — negated regex (! prefix)
"main"               — literal match (no regex metacharacters)
"!develop"           — negated literal

Matching logic:

  • Tag: tested against CI_COMMIT_TAG / git tag. Only evaluated when a tag is present.
  • Branch: tested against CI_COMMIT_BRANCH / git branch.
  • Multiple fields set: AND — all present fields must match.
  • No fields set: catch-all (always matches).

Rules are always evaluated top-down, first match wins. CLI overrides take precedence.

type Config

type Config struct {
	// Version must be 1. The pre-version config was an unversioned alpha
	// that never earned a schema number — this is the first stable schema.
	Version int `yaml:"version"`

	// Vars is a user-defined template variable dictionary.
	// Referenced as {var:name} anywhere templates are resolved.
	Vars map[string]string `yaml:"vars,omitempty"`

	// Defaults is inert YAML anchor storage. StageFreight ignores this
	// section entirely — it exists for users to define &anchors.
	Defaults yaml.Node `yaml:"defaults,omitempty"`

	// Forges declares git hosts as an id→forge map (provider, URL, credentials).
	Forges OrderedForges `yaml:"forges,omitempty"`

	// Repos declares projects as an id→repo map. References forges by id. Has role.
	Repos OrderedRepos `yaml:"repos,omitempty"`

	// Registries declares OCI registry hosts as an id→registry map.
	Registries OrderedRegistries `yaml:"registries,omitempty"`

	// Orgs declares organization/owner identities as an id→org map (maintainer +
	// aliases). Identity only — no forge, no credentials. Feeds {org.*} and, through
	// surface default_paths, {path.*}. See docs/design/identity-model.md.
	Orgs OrderedOrgs `yaml:"orgs,omitempty"`

	// Metadata is this repo's identity/branding — the one block every consumer reads
	// (org ref, title, names, scoped description/readme, topics, license, …). Feeds
	// {metadata.*}. See docs/design/identity-model.md.
	Metadata MetadataConfig `yaml:"metadata,omitempty"`

	// SigningSetup is the signing block. Its Profiles field holds the named trust
	// profiles (generic primitives), referenced per-target by signing_profile: <id>.
	// "Releases require hardware" is project policy (the target's selection), never
	// encoded in the framework.
	SigningSetup SigningConfig `yaml:"signing,omitempty"`

	// Git is the git: cluster and the single source for ref interpretation: named
	// branch patterns (git.branches), tag patterns (git.tags), and versioning rules
	// (git.versioning). Consumers read cfg.Git.Branches / cfg.Git.Tags /
	// cfg.Git.Versioning.{BranchBuilds,NoLineage} directly — no translation layer.
	Git GitConfig `yaml:"git,omitempty"`

	// Builds defines named build artifacts as an id→build map.
	Builds OrderedBuilds `yaml:"builds"`

	// Targets defines distribution targets and side-effects. Declared under the
	// publish: key as an id→target map (execution order preserved).
	Targets OrderedTargets `yaml:"publish,omitempty"`

	// Lint holds lint-specific configuration (unchanged from v1).
	Lint LintConfig `yaml:"lint"`

	// Security holds security scanning configuration (unchanged from v1).
	Security SecurityConfig `yaml:"security"`

	// Commit holds configuration for the commit subsystem.
	Commit CommitConfig `yaml:"commit"`

	// Dependency holds configuration for the dependency update subsystem.
	Dependency DependencyConfig `yaml:"dependency"`

	// LLMs is the model endpoint library (llms:): id → { provider, url, model,
	// credentials }, referenced by type: llm stencils via llm: <id>.
	LLMs OrderedLLMs `yaml:"llms,omitempty"`

	// Stencils is the shared audience-text library: id → reusable markdown element
	// with {…} variable fill, embeddable as {id} anywhere SF composes text (scribe
	// file regions, narrate, release bodies). Presence-neutral (a shared library, not
	// a phase). Consumers differ only by destination.
	Stencils OrderedStencils `yaml:"stencils,omitempty"`

	// Scribe places rendered stencils into repository files and commits them: files:
	// (placement regions whose bodies reference stencils by {id}) + commit:.
	// Presence-enabled (files/commit gate the stage).
	Scribe ScribeConfig `yaml:"scribe"`

	// Notifications sends a message when a run finishes: id → { provider, on, subject,
	// body, … }. Flat, one entry per notification. subject/body accept {…} embeds; an
	// omitted body defaults to the run's apex summary. Dispatched by the narrate phase.
	Notifications OrderedNotifications `yaml:"notifications,omitempty"`

	// Narrate is the stdout storytelling surface: announces: lists stencil ids rendered
	// as structured-output cards at the end of the run (default: the built-in summary).
	Narrate NarrateConfig `yaml:"narrate,omitempty"`

	Test TestConfig `yaml:"test"`

	// Manifest holds configuration for the manifest subsystem.
	Manifest ManifestConfig `yaml:"manifest"`

	// Release holds configuration for the release subsystem.
	Release ReleaseConfig `yaml:"release"`

	// CI holds all pipeline-related configuration consumed by ci render.
	CI CIConfig `yaml:"ci"`

	// Lifecycle defines the repository lifecycle mode (image, gitops, governance).
	Lifecycle LifecycleConfig `yaml:"lifecycle"`

	// Governance declares the control repo's governance profiles. It is
	// PRESENCE-GATED, not mode-gated: the reconcile facet activates whenever
	// governance.profiles is non-empty (like the ansible/gitops subsystems), so a
	// control repo needs no lifecycle.mode: governance. A satellite instead carries
	// governance.source (a pointer at its policy repo).
	Governance GovernanceConfig `yaml:"governance"`

	// GitOps defines the gitops lifecycle target clusters, keyed by cluster name.
	GitOps OrderedClusters `yaml:"gitops,omitempty"`

	// Ansible defines the ansible host-convergence subsystem. Presence-gated
	// (any converge playbook activates it) and independent of lifecycle.mode.
	Ansible AnsibleConfig `yaml:"ansible"`

	// Docker defines configuration for the docker lifecycle mode.
	Docker DockerLifecycleConfig `yaml:"docker"`

	// BuildCache defines the build cache subsystem (local, shared, hybrid).
	BuildCache BuildCacheConfig `yaml:"build_cache"`

	// Glossary defines the repo's shared change-language model.
	// Consumed by commit authoring, tag planning, and release rendering.
	Glossary GlossaryConfig `yaml:"glossary"`

	// Tag holds workflow defaults for the tag planner.
	Tag TagConfig `yaml:"tagging"`

	// Toolchains defines operator control over external tool resolution.
	// Version pins, future retention policy, future trust settings.
	Toolchains ToolchainSection `yaml:"toolchains,omitempty"`
	// contains filtered or unexported fields
}

Config is the top-level StageFreight v2 configuration.

func Load

func Load(path string) (*Config, error)

Load reads configuration from a YAML file. If path is empty, it tries the default file. Returns sensible defaults if the file doesn't exist. Discards validation warnings; use LoadWithWarnings for full diagnostics.

func LoadOffline added in v0.11.0

func LoadOffline(path string) (*Config, error)

LoadOffline loads a config resolving sourced presets from the retained cache only, never the network.

For verifying a render against the cache that ships WITH it — governance checking a satellite's config before distributing it. Resolving live there would ask the wrong question (does the source answer right now) instead of the one that matters (is what we are about to hand over self-sufficient), and would fetch every reference once per governed repo.

func LoadWithWarnings

func LoadWithWarnings(path string) (*Config, []string, error)

LoadWithWarnings reads configuration from a YAML file and returns validation warnings alongside the config. Thin wrapper over loadResolved — the single preset-resolving construction path (invariants.md §1); every runtime caller funnels through it.

func (*Config) ApplyStencilStoreDefaults added in v0.8.0

func (c *Config) ApplyStencilStoreDefaults()

ApplyStencilStoreDefaults derives Output = {store}/{id}.svg for badge stencils that don't set an explicit output path, so a badge stencil needs no per-item output: line. An explicit output: wins. Store comes from scribe.store (default DefaultScribeStore) — badge SVGs are a scribe-placed asset.

func (*Config) DriftedPresets added in v0.11.0

func (c *Config) DriftedPresets() []presetref.Outcome

DriftedPresets returns the references whose source served content differing from what was retained. This is the REPORTING view: it answers whether policy content changed.

func (*Config) Mode added in v0.8.0

func (c *Config) Mode() LifecycleMode

Mode resolves this config's lifecycle mode for DISPATCH. An unknown mode falls back to the image fact-set — the same outcome the phase bodies' `default:` arm gives — because validation rejects unknown modes at load, so a dispatch-time lookup can safely treat anything unresolved as the build default.

func (*Config) PresetOutcomes added in v0.11.0

func (c *Config) PresetOutcomes() []presetref.Outcome

PresetOutcomes reports how each sourced preset reference resolved on this load. Empty when every reference was local, or when nothing was sourced.

func (*Config) RefreshedPresets added in v0.11.0

func (c *Config) RefreshedPresets() []presetref.Outcome

RefreshedPresets returns the references whose retained copy THIS run wrote — the set a satellite must carry back. Not the same question as DriftedPresets: a copy governance never seeded is written without differing from anything, and a pin mismatch the operator chose to resolve from the source is a write they asked for. Either way the run produced a retained copy, and one that is never committed leaves the tree dirty.

func (*Config) SetPresetOutcomes added in v0.11.0

func (c *Config) SetPresetOutcomes(o []presetref.Outcome)

SetPresetOutcomes records how sourced references resolved. The loader sets this on the config it builds; exported so a caller that resolves presets itself can hand the result on, and so the behaviour that depends on it is reachable from a test.

func (*Config) StencilsByID added in v0.8.0

func (c *Config) StencilsByID() map[string]StencilDef

StencilsByID is the Config-level convenience over the stencil library.

func (*Config) WorktreeOutputs added in v0.7.0

func (c *Config) WorktreeOutputs() []WorktreeOutput

WorktreeOutputs returns every build output opted into the working tree (outputs[].worktree) across all builds. The runner materializes these at the start of Narrate; Perform's archive trigger uses them to know which build trees must cross to Narrate as transport artifacts.

type ConfigReport added in v0.6.0

type ConfigReport struct {
	SourceFile   string         `json:"source_file"`
	Presets      []string       `json:"presets,omitempty"`
	Overrides    int            `json:"overrides,omitempty"`
	Sections     []SectionState `json:"sections,omitempty"`
	SyncTopology *SyncTopology  `json:"sync_topology,omitempty"`
	VarsApplied  int            `json:"vars_applied,omitempty"`
	Warnings     []string       `json:"warnings,omitempty"`
	Status       string         `json:"status"`       // "ok" | "partial" | "error"
	Completeness string         `json:"completeness"` // "complete" | "partial"
	Error        string         `json:"error,omitempty"`
}

ConfigReport is the result of loading and resolving configuration. Surfaces the "Explain" layer of the resolution pipeline.

type ContainerPrunePolicy added in v0.5.0

type ContainerPrunePolicy struct {
	Exited AgePruneRule `yaml:"exited,omitempty"`
}

ContainerPrunePolicy defines container pruning rules.

type CrucibleConfig added in v0.4.0

type CrucibleConfig struct {
	// ToolchainImage is the pinned container image for pass-2 verification.
	// e.g., "docker.io/library/golang:1.24-alpine"
	ToolchainImage string `yaml:"toolchain_image,omitempty"`
}

CrucibleConfig holds crucible-specific build configuration.

type DependencyCIConfig

type DependencyCIConfig struct {
	Handoff DependencyHandoff `yaml:"handoff"` // default: continue
}

DependencyCIConfig controls CI-level behavior when deps creates a commit.

type DependencyCommitConfig

type DependencyCommitConfig struct {
	Enabled   bool                      `yaml:"enabled"`
	Type      string                    `yaml:"type"`
	Message   string                    `yaml:"message"`
	Push      bool                      `yaml:"push"`
	SkipCI    bool                      `yaml:"skip_ci"`
	Promotion DependencyCommitPromotion `yaml:"promotion"` // "direct" or "mr"
	MR        DependencyMRConfig        `yaml:"mr"`
	RunFrom   RunFromConfig             `yaml:"run_from,omitempty"` // gate mutation to declared origin
}

DependencyCommitConfig controls auto-commit behavior for dependency updates.

type DependencyCommitPromotion added in v0.4.0

type DependencyCommitPromotion string

DependencyCommitPromotion controls how dependency commits reach the target branch.

const (
	PromotionDirect DependencyCommitPromotion = "direct" // push to current branch (existing behavior)
	PromotionMR     DependencyCommitPromotion = "mr"     // push to unique bot branch, open merge request
)

type DependencyConfig

type DependencyConfig struct {
	Preset  string                 `yaml:"preset,omitempty"`
	Enabled bool                   `yaml:"enabled"`
	Output  string                 `yaml:"output"`
	Scope   DependencyScopeConfig  `yaml:"scope"`
	Commit  DependencyCommitConfig `yaml:"commit"`
	CI      DependencyCIConfig     `yaml:"ci"`
	Ignore  []DependencyIgnore     `yaml:"ignore,omitempty"`

	// Remediate controls whether the update pass PATCHES eligible dependencies
	// (true, default — fix-forward) or only evaluates them without changing
	// anything (false). It is the module's remediation stage, orthogonal to
	// fail_on (the policy stage).
	Remediate *bool `yaml:"remediate,omitempty"`

	// Outdated gates on how far a dependency has fallen behind — an update-MAGNITUDE
	// policy, not a severity one. Vulnerability severity has exactly one authority,
	// security.fail_on; duplicating that vocabulary here made two places disagree
	// about the same question.
	Outdated OutdatedGate `yaml:"outdated,omitempty"`

	// Policy is the freshness SCOPE — which non-vulnerable dependencies to pursue:
	// "all" (default — every dep to its latest eligible) or "security" (only
	// vulnerable deps; leave everything else where it is). A known vulnerability is
	// a floor, remediated under EVERY policy — Policy only governs freshness of
	// NON-vulnerable deps. Empty defaults to "all" (today's audition behavior).
	Policy string `yaml:"policy,omitempty"`

	// MaxUpdate is the update-type CEILING — how far a dependency may move:
	// "major" (allow the ecosystem's own maximum), "minor" (n.x.n — lock the major,
	// allow minor+patch), or "patch" (n.n.x — lock major and minor, allow patch
	// only). Empty defaults to "major" — a NO-OP that imposes no ceiling beyond each
	// ecosystem's native compatibility model (cargo/docker still hold out-of-range
	// majors via their `^`/tag-line semantics; gomod/github-release/toolchain retain
	// their prior auto-apply). Setting "minor"/"patch" is an explicit opt-in to hold
	// majors (and minors). A security fix is applied even if it exceeds the ceiling
	// (remediation floor).
	MaxUpdate string `yaml:"max_update,omitempty"`

	// MinReleaseAge is the supply-chain COOLDOWN: a release younger than this is
	// not recommended (freshness) nor applied (deps) — dodging the window in which
	// a compromised or yanked release is briefly live. Accepts durations like
	// "3d", "72h". Owned here as a supply-chain policy; the freshness lint module
	// reads the SAME value so its recommendations match what deps will apply.
	// Empty falls back to lint.modules.freshness.options.min_release_age (its
	// historical home) for back-compat, then to disabled.
	MinReleaseAge string `yaml:"min_release_age,omitempty"`
}

DependencyConfig holds configuration for the dependency update subsystem.

func DefaultDependencyConfig

func DefaultDependencyConfig() DependencyConfig

DefaultDependencyConfig returns sensible defaults for dependency management.

func (DependencyConfig) EffectiveMaxUpdate added in v0.7.0

func (c DependencyConfig) EffectiveMaxUpdate() string

EffectiveMaxUpdate resolves the update-type ceiling, defaulting to "major" — a no-op that preserves each ecosystem's native behavior (holding majors is an explicit opt-in, never a silent default). Lowercased "major" | "minor" | "patch".

func (DependencyConfig) EffectivePolicy added in v0.7.0

func (c DependencyConfig) EffectivePolicy() string

EffectivePolicy resolves the freshness scope, defaulting to "all". Lowercased "all" | "security".

func (DependencyConfig) RemediateEnabled added in v0.7.0

func (c DependencyConfig) RemediateEnabled() bool

RemediateEnabled reports whether the update pass patches eligible dependencies. Default: true (fix-forward).

type DependencyHandoff

type DependencyHandoff string

DependencyHandoff controls what happens when dependency repair creates a new commit.

  • "continue" — advisory only, current pipeline continues regardless
  • "restart_pipeline" — request pipeline rerun on repaired revision; downstream shipping stops
  • "fail" — fail hard if repair was needed but couldn't be handed off
const (
	HandoffContinue        DependencyHandoff = "continue"
	HandoffRestartPipeline DependencyHandoff = "restart_pipeline"
	HandoffFail            DependencyHandoff = "fail"
)

type DependencyIgnore added in v0.7.0

type DependencyIgnore struct {
	ID     string `yaml:"id"`               // e.g. "GHSA-xxxx-yyyy-zzzz", "GO-2026-1234"
	Reason string `yaml:"reason,omitempty"` // why this risk is carried
	Until  string `yaml:"until,omitempty"`  // YYYY-MM-DD; past this date the ignore lapses
}

DependencyIgnore suppresses a specific security advisory from remediation — an accepted-risk or false-positive decision. Keyed by advisory ID (the same `ignore` term osv-scanner/Trivy/Grype/Dependabot use), with a required reason and an expiry after which it lapses and the advisory re-surfaces.

type DependencyMRConfig added in v0.4.0

type DependencyMRConfig struct {
	BranchPrefix string `yaml:"branch_prefix"` // default: "stagefreight/deps"
	TargetBranch string `yaml:"target_branch"` // default: "" (CI default branch)
}

DependencyMRConfig controls merge request creation for promotion: mr.

type DependencyScopeConfig

type DependencyScopeConfig struct {
	GoModules     bool `yaml:"go_modules"`
	DockerfileEnv bool `yaml:"dockerfile_env"` // umbrella for docker-image + github-release
}

DependencyScopeConfig controls which dependency ecosystems are managed.

func (DependencyScopeConfig) ScopeToEcosystems

func (s DependencyScopeConfig) ScopeToEcosystems() []string

ScopeToEcosystems converts scope booleans to ecosystem filter strings compatible with dependency.UpdateConfig.Ecosystems. Returns nil (all ecosystems) if all scopes are enabled.

type DetailRule

type DetailRule struct {
	Condition `yaml:",inline"`

	// Detail is the detail level to use when this rule matches.
	// Values: "none", "counts", "detailed", "full".
	Detail string `yaml:"detail"`
}

DetailRule is a conditional override for security detail level in release notes. Embeds Condition for standard tag/branch pattern matching.

type DockerDriftPolicy added in v0.5.0

type DockerDriftPolicy struct {
	Tier2Action               string `yaml:"tier2_action"`                // report | reconcile (default: report)
	OrphanAction              string `yaml:"orphan_action"`               // report | down | prune (default: report)
	OrphanThreshold           int    `yaml:"orphan_threshold"`            // block if more than N orphans (default: 5)
	PruneRequiresConfirmation bool   `yaml:"prune_requires_confirmation"` // require --force for prune (default: true)
}

DockerDriftPolicy configures drift detection behavior.

type DockerIaCConfig added in v0.5.0

type DockerIaCConfig struct {
	// Path is the IaC directory relative to repo root (default: "docker-compose").
	Path string `yaml:"path"`
}

DockerIaCConfig defines the IaC directory layout.

type DockerLifecycleConfig added in v0.5.0

type DockerLifecycleConfig struct {
	Preset string `yaml:"preset,omitempty"`

	// Backend selects the Docker execution engine (e.g. "compose").
	Backend string `yaml:"backend"`

	// Targets defines how reconciliation targets are resolved.
	Targets DockerTargetsConfig `yaml:"targets"`

	// IaC defines the Infrastructure as Code directory layout.
	IaC DockerIaCConfig `yaml:"iac"`

	// Secrets defines the secrets decryption provider.
	Secrets DockerSecretsConfig `yaml:"secrets"`

	// Drift defines drift detection and reconciliation policy.
	Drift DockerDriftPolicy `yaml:"drift"`
}

DockerLifecycleConfig defines configuration for the docker lifecycle mode. This is Docker lifecycle orchestration, not docker-compose wrapping.

func DefaultDockerLifecycleConfig added in v0.5.0

func DefaultDockerLifecycleConfig() DockerLifecycleConfig

DefaultDockerLifecycleConfig returns sensible defaults.

type DockerSecretsConfig added in v0.5.0

type DockerSecretsConfig struct {
	// Provider selects the secrets backend (e.g. "sops", "vault", "infisical").
	Provider string `yaml:"provider"`
}

DockerSecretsConfig defines the secrets provider.

type DockerTargetSelector added in v0.5.0

type DockerTargetSelector struct {
	Groups []string `yaml:"groups"`
}

DockerTargetSelector declares eligibility via existing inventory groups. Group-based initially. Richer selectors deferred until groups become insufficient.

type DockerTargetsConfig added in v0.5.0

type DockerTargetsConfig struct {
	// Source is the inventory adapter (e.g. "ansible").
	Source string `yaml:"source"`

	// Inventory is the path to the inventory file (relative to repo root).
	Inventory string `yaml:"inventory"`

	// Selector declares which hosts from inventory are eligible.
	Selector DockerTargetSelector `yaml:"selector"`
}

DockerTargetsConfig defines target resolution for Docker reconciliation.

type ExposureRule added in v0.5.0

type ExposureRule struct {
	Level        string   `yaml:"level"`     // internet | intranet | cluster
	Endpoints    []string `yaml:"endpoints"` // ip:port (highest precedence)
	Gateways     []string `yaml:"gateways"`
	CIDRs        []string `yaml:"cidrs"`
	Ports        []int    `yaml:"ports"`         // AND with CIDRs (empty = any port)
	ServiceTypes []string `yaml:"service_types"` // ClusterIP | NodePort | LoadBalancer
}

ExposureRule classifies endpoints into exposure levels. Match fields are AND within a rule (CIDR AND port if both specified).

type ExposureRules added in v0.5.0

type ExposureRules struct {
	Rules []ExposureRule `yaml:"rules"`
}

ExposureRules defines rule-based endpoint exposure classification. Rules are evaluated by precedence: endpoint > gateway > CIDR > service type. Conflicting equal-precedence rules → unknown. Never first-match-wins.

func (*ExposureRules) UnmarshalYAML added in v0.10.0

func (e *ExposureRules) UnmarshalYAML(n *yaml.Node) error

UnmarshalYAML accepts both the flat list form (exposure: [ -level: … ]) and the nested map form (exposure: {rules: [ … ]}). Rules is the only field, so the flat list is the canonical shape; the map form stays accepted for compatibility.

type ExternalCacheConfig added in v0.5.0

type ExternalCacheConfig struct {
	// Registry references a registries[].id. Its URL + default_path locate the cache.
	Registry string `yaml:"registry,omitempty"`

	// Path is appended to the registry URL: <registry-url>/<path>/<repo>/<branch>.
	Path string `yaml:"path,omitempty"`

	// Fallback is the read-only fallback branch ref (e.g. "default", "main").
	// Never written to unless current ref equals fallback.
	Fallback string `yaml:"fallback,omitempty"`

	// Mode is the BuildKit cache mode (e.g. "max", "min"). Default: "max".
	Mode string `yaml:"mode,omitempty"`

	// Retention defines when stale external cache refs are pruned.
	Retention ExternalRetention `yaml:"retention,omitempty"`
}

ExternalCacheConfig defines registry-backed shared cache. References a registries[].id directly — no publish-target indirection.

type ExternalRetention added in v0.5.0

type ExternalRetention struct {
	MaxRefs  int    `yaml:"max_refs,omitempty"`  // max branch cache refs per repo
	StaleAge string `yaml:"stale_age,omitempty"` // prune refs for dead/merged branches
}

ExternalRetention defines external cache ref lifecycle.

type FacetSpec added in v0.8.0

type FacetSpec struct {
	Scope  string   `yaml:"scope,omitempty"`  // "current" | "all" (exact expands here)
	Prune  bool     `yaml:"prune,omitempty"`  // delete target refs/releases absent on source
	Force  bool     `yaml:"force,omitempty"`  // refs only: overwrite a DIVERGED mirror ref (default off = keep-divergent)
	Drafts bool     `yaml:"drafts,omitempty"` // releases only: carry unpublished drafts
	Only   []string `yaml:"only,omitempty"`   // releases only: restrict to these tag-sources
	Match  string   `yaml:"match,omitempty"`  // glob filter on ref/tag name
	Assets string   `yaml:"assets,omitempty"` // releases only: "" | "true" | "false" | "link"
}

FacetSpec is the resolved replication spec for one facet. A nil *FacetSpec on SyncConfig means the facet is not synced.

func (*FacetSpec) IsAll added in v0.8.0

func (f *FacetSpec) IsAll() bool

IsAll reports scope: all — replicate every ref of the facet.

func (*FacetSpec) IsCurrent added in v0.8.0

func (f *FacetSpec) IsCurrent() bool

IsCurrent reports scope: current — replicate only the ref the current run addresses (incremental, never deletes).

func (*FacetSpec) Summary added in v0.8.0

func (f *FacetSpec) Summary() string

Summary renders a facet back to its canonical scope word plus any options, for the resolved/topology view. Empty for a nil (unsynced) facet.

type FileDef added in v0.8.0

type FileDef struct {
	ID       string    `yaml:"-"` // set from the files map key
	File     string    `yaml:"file"`
	LinkBase string    `yaml:"link_base,omitempty"`
	Between  [2]string `yaml:"between,omitempty"`
	Inline   bool      `yaml:"inline,omitempty"` // items sugar: render side-by-side
	Items    []string  `yaml:"items,omitempty"`  // stencil ids (+ "br"); sugar for a body
	Body     string    `yaml:"body,omitempty"`   // freeform markdown with {id} embeds
}

FileDef is one placement region (scribe.files[id]): a marked span in a file and the markdown placed into it. body: is freeform markdown with {id} stencil embeds (+ {#if}); items: is sugar for a body (a row of stencils, "br" for a row break, inline: for side-by-side). One or the other — body: wins when both are set.

type FilterConfig added in v0.5.0

type FilterConfig struct {
	Summary             SummaryFilter `yaml:"summary"`
	Trailers            TrailerFilter `yaml:"trailers"`
	NormalizeWhitespace bool          `yaml:"normalize_whitespace"`
}

FilterConfig defines sanitization rules for change summaries.

type ForgeConfig added in v0.6.0

type ForgeConfig struct {
	ID          string `yaml:"id"`                     // unique identifier (e.g., "prplanit-gitlab")
	Provider    string `yaml:"provider"`               // gitlab, github, gitea
	URL         string `yaml:"url"`                    // base URL (e.g., "https://gitlab.prplanit.com")
	Credentials string `yaml:"credentials,omitempty"`  // env var prefix for token resolution
	DefaultPath string `yaml:"default_path,omitempty"` // default project path template (e.g. "{org}/{repo}"), for {path.<id>}
}

ForgeConfig declares a git host. Declared once, referenced by repos. A forge is an identity — provider type, base URL, credentials.

func FindForgeByID added in v0.6.0

func FindForgeByID(forges []ForgeConfig, id string) *ForgeConfig

FindForgeByID returns the forge with the given id, or nil.

func ForgeForURL added in v0.9.0

func ForgeForURL(remoteURL string, forges []ForgeConfig, vars map[string]string) *ForgeConfig

ForgeForURL returns the configured forge whose host OWNS remoteURL's host, or nil when no configured forge matches. Matching is EXACT on the normalized hostname — never a prefix or substring compare — so a credential can only ever be selected for a host its forge actually claims. A forge URL's {var:...} placeholders resolve first. A nil result means "no configured forge owns this host": the caller must fall back to anonymous, so a token is never sent to an unclaimed host.

type Gate added in v0.7.0

type Gate string

Gate is the declarative lifecycle consequence of a test suite's failure.

It is a typed policy value, decoded once at the config boundary so internal comparisons never use raw string literals. v1 implements `perform` (default) and `advisory`; `publish` is reserved (see the test-subsystem plan) — the "build locally but deny distribution" tier arrives with the finer authorizePhase rail when a suite actually needs it.

const (
	// GatePerform: a failed suite fails the audition exit code, which withholds
	// the cistate artifact and halts perform + everything downstream (only narrate
	// runs) — identical to how a lint critical gates today. This is the default.
	GatePerform Gate = "perform"
	// GateAdvisory: the suite runs and reports, but never affects the audition exit
	// code, so the pipeline ships regardless.
	GateAdvisory Gate = "advisory"
	// GatePublish: reserved (v2) — build the artifact but deny distribution.
	GatePublish Gate = "publish"
)

type GitConfig added in v0.8.0

type GitConfig struct {
	// Branches maps a matcher name to a regex.
	Branches map[string]string `yaml:"branches,omitempty"`

	// Submodules requests that CI check out submodules. A pipeline that clones without
	// them leaves the submodule directory empty, and the build fails on a missing file
	// rather than on anything to do with the checkout — so this is declared, not guessed.
	Submodules bool `yaml:"submodules,omitempty"`
	// Tags maps a tag-source name to its pattern.
	Tags OrderedTagSources `yaml:"tags,omitempty"`
	// Versioning holds the derivation rules that consume the patterns above.
	Versioning GitVersioning `yaml:"versioning,omitempty"`
}

GitConfig is the git: cluster — how the engine interprets a ref into named branch/tag patterns and the versions they imply. It is the SINGLE source: consumers read cfg.Git.Branches / cfg.Git.Tags / cfg.Git.Versioning directly — no translation layer, no separate Matchers/Versioning types.

type GitOpsCluster added in v0.10.0

type GitOpsCluster struct {
	Name string `yaml:"-"` // from the map key

	Preset string `yaml:"preset,omitempty"`

	// Backend selects the GitOps reconciliation backend (e.g. "flux", "argo").
	Backend string `yaml:"backend"`

	// Endpoint is the cluster API server URL (e.g. https://host:6443).
	Endpoint string `yaml:"endpoint"`

	// Exposure classifies endpoint reachability (rule-based).
	Exposure ExposureRules `yaml:"exposure"`

	// OIDC defines authentication configuration for the cluster.
	OIDC OIDCConfig `yaml:"oidc"`
}

GitOpsCluster is one gitops target cluster, keyed by its name in the gitops: map.

func (GitOpsCluster) Connection added in v0.10.0

func (c GitOpsCluster) Connection() ClusterConfig

Connection returns the connection descriptor the k8s/gitops packages consume.

type GitVersioning added in v0.8.0

type GitVersioning struct {
	BranchBuilds OrderedBranchBuilds `yaml:"branch_builds,omitempty"`
	NoLineage    NoLineageConfig     `yaml:"no_lineage,omitempty"`
}

GitVersioning is git.versioning — branch_builds + no_lineage (tag patterns moved up to git.tags).

type GlossaryConfig added in v0.5.0

type GlossaryConfig struct {
	Preset   string                  `yaml:"preset,omitempty"`
	Types    map[string]GlossaryType `yaml:"types"`
	Breaking BreakingConfig          `yaml:"breaking"`
	Filters  FilterConfig            `yaml:"filters"`
	Rewrites RewriteConfig           `yaml:"rewrites"`
	Render   RenderConfig            `yaml:"render"`
}

GlossaryConfig defines the repo's shared change-language model. Consumed by commit authoring, tag planning, and release rendering.

func DefaultGlossaryConfig added in v0.5.0

func DefaultGlossaryConfig() GlossaryConfig

DefaultGlossaryConfig returns sensible defaults for the glossary.

type GlossaryType added in v0.5.0

type GlossaryType struct {
	Aliases        []string `yaml:"aliases,omitempty"`
	CanonicalAs    string   `yaml:"canonical_as,omitempty"` // normalize to this type (e.g., deps → chore)
	Priority       int      `yaml:"priority"`
	ReleaseVisible bool     `yaml:"release_visible"`
}

GlossaryType defines a single change type's semantics.

type GovernanceConfig added in v0.5.0

type GovernanceConfig struct {
	Profiles OrderedGovProfiles `yaml:"profiles"`
}

GovernanceConfig declares governance profiles for the control repo. Presence of profiles activates governance reconcile (presence-gated like ansible/gitops). Assets (CI skeletons, settings files, etc.) are declared inside each profile's stagefreight config as assets: entries — no separate skeleton construct.

type GovernanceProfile added in v0.10.0

type GovernanceProfile struct {
	ID          string         `yaml:"-"`                     // from the profiles: map key
	Repos       map[string]any `yaml:"repos,omitempty"`       // the location-anchored catalog (raw here)
	Config      map[string]any `yaml:"config,omitempty"`      // the profile's shared StageFreight config
	Credentials string         `yaml:"credentials,omitempty"` // env var prefix for the write token
}

GovernanceProfile is one profile (config-side view). Repos and Config are raw maps — config only checks presence; the governance package owns the rich catalog shape.

type HostCleanupConfig added in v0.5.0

type HostCleanupConfig struct {
	// Enabled controls whether cleanup runs. Independent of cache mode.
	Enabled bool `yaml:"enabled,omitempty"`

	// Enforcement controls what happens when cleanup cannot execute.
	// best_effort: continue + structured warning.
	// required: fail build immediately.
	Enforcement string `yaml:"enforcement,omitempty"`

	// Protect defines what is never pruned.
	Protect ProtectionPolicy `yaml:"protect,omitempty"`

	// Prune defines what is eligible for removal.
	Prune PrunePolicy `yaml:"prune,omitempty"`
}

HostCleanupConfig defines host hygiene — classification-first pruning. Not cache — residue cleanup. Object classes match DD-UI's operation types.

Governance-owned policy, currently INACTIVE: the legacy executor was removed with the standalone build pipeline. Retained pending a perform-phase consumer.

type IDMap added in v0.9.0

type IDMap interface {
	// contains filtered or unexported methods
}

IDMap is the marker every Ordered* id→entry map type implements — the compile-checked contract that the type is a Go slice DECODING as a YAML map keyed by entry id. Consumers that must know the YAML shape (the docs generator renders map form, never "- id:" list form) detect it through this interface instead of naming conventions.

type ImageProtection added in v0.5.0

type ImageProtection struct {
	Refs []string `yaml:"refs,omitempty"` // glob patterns
}

ImageProtection defines which images are protected from pruning.

type ImagePrunePolicy added in v0.5.0

type ImagePrunePolicy struct {
	Dangling     AgePruneRule `yaml:"dangling,omitempty"`
	Unreferenced AgePruneRule `yaml:"unreferenced,omitempty"`

	// Refs is the operator's scoped ADOPTION list: third-party image streams
	// (matched by the shared retention-grammar template syntax) that the operator
	// explicitly grants a lifecycle — e.g. a CI base image pulled into the dind.
	// Each entry carries its own retention rules (keep_last / max_age / …), the same
	// RetentionRef grammar used everywhere retention appears. Nothing outside this
	// list (or SF's own provenance) is ever image-pruned; this is an authorization,
	// not a confidence judgment.
	Refs []RetentionRef `yaml:"refs,omitempty"`
}

ImagePrunePolicy defines image pruning rules by class.

type KMSTrust added in v0.7.0

type KMSTrust struct {
	Ref string `yaml:"ref"`
}

KMSTrust is a LOGICAL key ref (e.g. "release-signing-key"), bound to a concrete URI only at render time — never a cosign URI, so policy stays provider-portable.

type KeyTrust added in v0.7.0

type KeyTrust struct {
	Ref string `yaml:"ref"`
}

KeyTrust is a key reference — "path" or "env:VAR". A reference, not a mechanism.

type LLMConfig added in v0.8.0

type LLMConfig struct {
	ID          string `yaml:"-"`                     // the map key ({llm: <id>} reference target)
	Provider    string `yaml:"provider"`              // ollama (openai | anthropic | claude-agent reserved)
	URL         string `yaml:"url,omitempty"`         // ollama: server base URL
	Model       string `yaml:"model,omitempty"`       // model name/tag
	Credentials string `yaml:"credentials,omitempty"` // env prefix for hosted providers
}

LLMConfig is one entry in the top-level llms: block — a model endpoint library, sibling of forges:/registries:. It earns library status because the alternative is endpoints and credentials leaking into stencils: (an AI stencil references a backend by id — `llm: local` — and stays pure composition). Provider is the engine axis: ollama ships first; openai/anthropic/claude-agent slot in behind the same shape (engine additions, zero reshape).

type Level

type Level string

Level controls how much of the codebase gets scanned.

const (
	LevelChanged Level = "changed"
	LevelFull    Level = "full"
)

type LifecycleConfig added in v0.5.0

type LifecycleConfig struct {
	// Preset references an external lifecycle fragment to inherit (the generic
	// preset: fragment-include mechanism — resolved and deep-merged before parse).
	Preset string `yaml:"preset,omitempty"`
	// Mode selects the phase graph. Empty defaults to image.
	//   image      — build → review → publish image pipeline (the default)
	//   docker     — read-only Docker plan/reconcile (dry-run)
	//   gitops     — validate + reconcile Flux manifests
	//   governance — governance control-repo reconcile
	Mode string `yaml:"mode"`
}

LifecycleConfig selects the repository lifecycle mode — the phase graph the pipeline runs. Mode is the single most significant orchestration choice: review and publish are image-only; the other modes mark them not_applicable.

type LifecycleMode added in v0.8.0

type LifecycleMode struct {
	// Name is the canonical (lowercased) mode identifier.
	Name string

	// PhaseReconcile reports whether the perform/audition/review/publish phase
	// BODIES reconcile for this mode instead of build/review/publish. True for
	// gitops+governance. False for image (build) and docker — docker reconciles
	// via the `docker`/`reconcile` CLI (RunLifecycle), not the CI phase bodies.
	PhaseReconcile bool

	// Backend returns the RunLifecycle backend name for this mode, or nil when the
	// mode has no RunLifecycle backend: image (builds via the CI pipeline) and
	// governance (dispatched by its own subsystem, executeGovernanceReconcile —
	// it never reaches RunLifecycle).
	Backend func(*Config) string
}

LifecycleMode is the fact-set for one mode.

func LookupMode added in v0.8.0

func LookupMode(raw string) (LifecycleMode, bool)

LookupMode canonicalizes a raw lifecycle.mode string (lowercased, trimmed) and resolves its fact-set. Empty ≡ image (the live default the phase bodies apply via their `default:` arm). ok=false for an unknown mode — the validator uses this to reject typos.

type LintCacheConfig added in v0.5.0

type LintCacheConfig struct {
	MaxAge  string `yaml:"max_age,omitempty"`  // evict entries not hit in this duration (e.g. "7d")
	MaxSize string `yaml:"max_size,omitempty"` // evict oldest entries when cache exceeds this (e.g. "100MB")
}

LintCacheConfig controls lint result cache lifecycle. Content-addressed caches grow monotonically — every file edit creates a new entry. Without eviction, cache grows unbounded.

type LintConfig

type LintConfig struct {
	Preset       string                  `yaml:"preset,omitempty"`
	Level        Level                   `yaml:"level"`
	CacheDir     string                  `yaml:"cache_dir"`
	TargetBranch string                  `yaml:"target_branch"`
	Exclude      []string                `yaml:"exclude"`
	Modules      map[string]ModuleConfig `yaml:"modules"`
	Provenance   ProvenanceConfig        `yaml:"provenance,omitempty"`
	Remediation  RemediationConfig       `yaml:"remediation,omitempty"`
	Cache        LintCacheConfig         `yaml:"cache,omitempty"`

	// FailOn is the DIAGNOSTIC-IMPORTANCE threshold at or above which a lint
	// finding blocks the build: "critical" | "warning" | "info" | "off". This is
	// lint's OWN ordered vocabulary (info < warning < critical) — deliberately NOT
	// the vulnerability severity scale; a lint warning and a CVSS High are
	// incomparable. Empty defaults to "critical" (today's behavior: only critical
	// findings block). Note this is a SECOND control axis on top of each module's
	// own severity: raising fail_on reclassifies lower-importance findings from
	// other lint modules as blocking too.
	FailOn string `yaml:"fail_on,omitempty"`
}

LintConfig holds lint-specific configuration.

func DefaultLintConfig

func DefaultLintConfig() LintConfig

DefaultLintConfig returns production defaults.

func (LintConfig) EffectiveFailOn added in v0.7.0

func (c LintConfig) EffectiveFailOn() string

EffectiveFailOn resolves the lint gate threshold, defaulting to "critical" (today's behavior). Returns a lowercased "critical" | "warning" | "info" | "off". The lint package maps this onto its Severity tiers.

type LocalCacheConfig added in v0.5.0

type LocalCacheConfig struct {
	Path      string         `yaml:"path,omitempty"` // override local cache root (default: /stagefreight/cache/buildkit)
	Retention LocalRetention `yaml:"retention,omitempty"`
}

LocalCacheConfig defines bounded local BuildKit cache. Default path: /stagefreight/cache/buildkit (persistent runtime root). Override via Path field for non-standard mounts.

type LocalRetention added in v0.5.0

type LocalRetention struct {
	MaxAge  string `yaml:"max_age,omitempty"`  // e.g. "7d"
	MaxSize string `yaml:"max_size,omitempty"` // e.g. "15GB"
}

LocalRetention defines what local cache is allowed to exist.

type ManifestConfig added in v0.3.2

type ManifestConfig struct {
	Preset string `yaml:"preset,omitempty"`

	// Enabled controls whether manifest generation is active (default: false).
	Enabled bool `yaml:"enabled"`

	// Mode controls where the manifest is stored.
	// ephemeral: temp location, use during run, discard after.
	// workspace: generate to .stagefreight/manifests/, don't auto-commit.
	// commit: generate and include in docs commit.
	// publish: generate and export as release asset / CI artifact.
	Mode string `yaml:"mode,omitempty"`

	// OutputDir is the output directory for manifest files.
	// Default: .stagefreight/manifests
	OutputDir string `yaml:"output_dir,omitempty"`
}

ManifestConfig holds configuration for the manifest subsystem.

func DefaultManifestConfig added in v0.3.2

func DefaultManifestConfig() ManifestConfig

DefaultManifestConfig returns sensible defaults for manifest generation.

type MatchResult added in v0.7.0

type MatchResult struct {
	Eligible bool
	Reason   string // why NOT eligible; empty when Eligible
}

MatchResult is the outcome of a target eligibility check: whether the target is eligible for the current CI context and, when it is not, a human-readable reason coupled to the decision. Narration reads Reason directly, so the explanation can never drift from the matcher logic that produced it.

func NotificationEligibility added in v0.8.0

func NotificationEligibility(when WhenConditions, outcome, event, branch, tag, forge string, tagPolicies, branchPolicies map[string]string) MatchResult

NotificationEligibility interprets a notification's when: — the SAME grammar as publish targets (events/branches/git_tags/forges, OR over condition-sets) plus the outcomes: dimension. Lives here, in the one when: interpreter, per the eligibility-routing invariant. outcome is the run's word: success | failure | warning (unknown matches only an empty outcomes:).

func TargetEligibility added in v0.7.0

func TargetEligibility(t TargetConfig, event, branch, tag, forge string, tagPolicies, branchPolicies map[string]string) MatchResult

TargetEligibility is the single authoritative interpretation of a target's when: conditions (events, then git_tags, then branches), returning the decision and — on rejection — the coupled reason.

INVARIANT: every capability (docker, binary archives, release, retention, sync, and every future distribution capability) MUST route its when: interpretation through TargetEligibility/TargetMatches. Capability code must NOT inspect t.When.Events / t.When.Branches / t.When.GitTags directly. A new eligibility dimension is added here, to the framework — never bolted onto a caller. (This is the engine that replaced the old per-capability gates.)

tagPolicies/branchPolicies resolve named patterns (versioning.tag_sources, matchers.branches); inline "re:" and "!" negation are handled by ResolvePatterns. Empty conditions never restrict.

type MergeEntry added in v0.6.0

type MergeEntry struct {
	Path         string // dot-path (e.g., "security.sbom")
	Source       string // "managed", "local", "preset:preset/security.yml"
	SourceRef    string // "PrPlanIT/MaintenancePolicy@v1.0.0" for presets
	Layer        int    // resolution depth (0=innermost preset, N=outermost, N+1=managed, N+2=local)
	Operation    string // "set", "override", "merge", "replace"
	Value        any
	Overridden   bool
	OverriddenBy string
}

MergeEntry records the provenance of a single config value.

func ResolvePresets added in v0.6.0

func ResolvePresets(root *yaml.Node, loader PresetLoader, sourceRef, sourcePath string, depth int, seen map[string]bool) (*yaml.Node, []MergeEntry, error)

ResolvePresets walks a config node, finds all preset:/presets: references, loads the preset files, validates the single-key invariant, and merges — order-preserving. Recursive: presets may reference other presets (depth-first). sourceRef is the repo identity; sourcePath is the current file. Returns the resolved node + provenance.

type MergeTrace added in v0.6.0

type MergeTrace struct {
	Entries []MergeEntry
}

MergeTrace records how each config value was resolved.

type MetadataConfig added in v0.10.0

type MetadataConfig struct {
	// Org references an orgs: entry by id (the repo's owner). May be derived from the
	// primary repo location instead of declared.
	Org string `yaml:"org,omitempty"`

	// Title is the human display name (e.g. "ARK Server"); defaults to the slug.
	Title string `yaml:"title,omitempty"`

	// Names overrides the repo's PATH name per surface (default = slug), e.g.
	// { dockerhub: arkserver, github: SteamCMD }.
	Names map[string]string `yaml:"names,omitempty"`

	// Description is scoped: the default may be a tiered StringOrList (fit-picked across
	// un-named surfaces); a named surface takes a single string.
	Description Scoped[StringOrList] `yaml:"description,omitempty"`

	// Readme is the source doc pushed to registry overviews / forge About, scoped:
	// a default path or per-surface paths. Defaults to the auto-detected README.
	Readme Scoped[string] `yaml:"readme,omitempty"`

	Topics   []string `yaml:"topics,omitempty"`
	License  string   `yaml:"license,omitempty"`
	Category string   `yaml:"category,omitempty"`

	// Website / DocsURL are optional and only for a genuinely SEPARATE site (product
	// page / hosted docs) — never the repo URL, which is a coordinate ({path.<forge>}).
	Website string `yaml:"website,omitempty"`
	DocsURL string `yaml:"docs_url,omitempty"`
	Icon    string `yaml:"icon,omitempty"`

	// Labels is the open forward-compat escape hatch (OCI-annotation style) for
	// metadata the schema does not model — funding, support/changelog URLs, deprecation.
	// It is NEVER a back door for a typed field above.
	Labels map[string]string `yaml:"labels,omitempty"`
}

MetadataConfig is the metadata: block — a repo's identity/branding, the one place every consumer reads. The load-bearing fields (org, license, names) feed coordinates/module/license; the rest is branding, distributed for free. Feeds the {metadata.*} facts. See docs/design/identity-model.md.

This is a single block (the CURRENT repo's identity). The governance catalog's per- repo entries reuse the same shape, keyed by id — that lands with the governance work.

type MirrorSync added in v0.8.0

type MirrorSync struct {
	MirrorID string `json:"mirror_id"`
	Forge    string `json:"forge"`
	Legacy   bool   `json:"legacy,omitempty"`
	Branches string `json:"branches,omitempty"`
	Tags     string `json:"tags,omitempty"`
	Releases string `json:"releases,omitempty"`
}

MirrorSync is one row of the replication topology: a mirror and the per-facet scope it replicates from the primary.

type ModuleConfig

type ModuleConfig struct {
	Enabled *bool
	Exclude []string
	Options map[string]any
}

ModuleConfig holds per-module overrides. Options are authored INLINE (module-specific keys sit directly under the module); the retired `options:` wrapper is gone. Enabled and Exclude are the two typed fields every module shares; any other key is a module-specific option collected into Options (the heterogeneous bag the lint engine reads wholesale).

func (ModuleConfig) MarshalYAML added in v0.8.0

func (m ModuleConfig) MarshalYAML() (any, error)

MarshalYAML re-flattens: enabled/exclude plus the option keys at the module's top level, so `config render` shows the inline shape rather than the internal struct.

func (*ModuleConfig) UnmarshalYAML added in v0.8.0

func (m *ModuleConfig) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML flattens the module surface: `enabled`/`exclude` become the typed fields, every other key is a module option → Options. A stray `options:` key is the retired wrapper and is rejected loudly (rather than silently nesting under Options["options"]).

type NarrateConfig added in v0.7.0

type NarrateConfig struct {
	Announces []string `yaml:"announces,omitempty"`
}

NarrateConfig is the narrate: block — the run's stdout storytelling surface. announces: lists stencil ids to render as structured-output cards at the end of the run (stdout is a target, not an endpoint). Omitted → the shipped default, [summary]. Any declared stencil id is announceable; the id "summary" resolves to the run's built-in modality story unless a user stencil shadows it (shadowing a shipped id is the override mechanism).

func (NarrateConfig) IsZero added in v0.7.0

func (n NarrateConfig) IsZero() bool

IsZero reports whether the narrate block carries no configuration.

type NetworkPrunePolicy added in v0.5.0

type NetworkPrunePolicy struct {
	Unused bool `yaml:"unused,omitempty"`
}

NetworkPrunePolicy defines network pruning rules.

type NoLineageConfig added in v0.6.0

type NoLineageConfig struct {
	// Mode controls the response to missing lineage.
	//   "error" (default): fail fast with explanation and suggested fix
	//   "explicit": use the provided version template
	Mode string `yaml:"mode,omitempty"`

	// Version is the template used when mode is "explicit".
	// Must contain {sha} or {time} — hardcoded versions are rejected.
	// e.g., "0.1.0-bootstrap+{sha}"
	Version string `yaml:"version,omitempty"`
}

NoLineageConfig defines behavior when no tag source yields a match along the branch rule's base_from search path.

type Notification added in v0.8.0

type Notification struct {
	ID       string `yaml:"-"`        // the map key
	Provider string `yaml:"provider"` // ntfy | webhook

	// Transport. Credentials follows the shipped env-prefix convention
	// (credentials: NTFY → NTFY_TOKEN, sent as Authorization: Bearer).
	URL         string `yaml:"url,omitempty"`
	Credentials string `yaml:"credentials,omitempty"`

	// Message — freeform stencil bodies.
	Subject string `yaml:"subject,omitempty"`
	Body    string `yaml:"body,omitempty"`

	// When gates dispatch: outcomes: (success | failure | warning) composing with
	// branches:/events:/git_tags: ("failures, but only on main"). Omitted = always.
	When WhenConditions `yaml:"when,omitempty"`

	// MaxLength hard-caps the rendered body in bytes (ntfy's default server limit
	// is 4096). Trimming happens at a line boundary and always preserves the
	// pipeline-link line so tap-through survives. 0 = no cap.
	MaxLength int `yaml:"max_length,omitempty"`

	// ntfy knobs — the full header vocabulary.
	Priority string       `yaml:"priority,omitempty"` // min|low|default|high|max
	Tags     StringOrList `yaml:"tags,omitempty"`     // emoji tags (comma-joined into the Tags header)
	Click    string       `yaml:"click,omitempty"`    // tap-through URL (stencil body; default {pipeline_url})
	Attach   string       `yaml:"attach,omitempty"`   // attachment URL
	Actions  string       `yaml:"actions,omitempty"`  // ntfy actions spec string
	Markdown bool         `yaml:"markdown,omitempty"` // render body as markdown
	Email    string       `yaml:"email,omitempty"`    // forward to email address
}

Notification is one entry in the top-level notifications: block — endpoint and message FUSED in each entry (deliberately no notifier library: the library pattern pays when actions fan many-to-few, and a notification is one-to-one — message and destination are the same thought; shared topic URLs are what vars: is for). subject/body/click are freeform stencil bodies (facts + {stencil} embeds); omitted, they default to the shipped subject and the run's arc body. Gating uses the ONE when: grammar (events/branches/git_tags) extended with the outcomes: dimension; omitted when: = always.

type OIDCConfig added in v0.5.0

type OIDCConfig struct {
	Audience string `yaml:"audience"`
}

OIDCConfig defines OIDC authentication for cluster access. Token is resolved from environment variable STAGEFREIGHT_OIDC at runtime.

type OIDCTrust added in v0.7.0

type OIDCTrust struct {
	Issuer   string `yaml:"issuer,omitempty"`
	Identity string `yaml:"identity,omitempty"`
}

OIDCTrust is the expected keyless signer identity (both optional).

type OrderedAnsiblePlaybooks added in v0.9.0

type OrderedAnsiblePlaybooks []AnsiblePlaybook

OrderedAnsiblePlaybooks is the playbooks: block — an id→playbook map (key becomes AnsiblePlaybook.ID), document order preserved.

func (*OrderedAnsiblePlaybooks) UnmarshalYAML added in v0.9.0

func (o *OrderedAnsiblePlaybooks) UnmarshalYAML(n *yaml.Node) error

type OrderedBranchBuilds added in v0.8.0

type OrderedBranchBuilds []BranchBuildConfig

OrderedBranchBuilds is git.versioning.branch_builds — an id→rule map (key becomes BranchBuildConfig.ID).

func (*OrderedBranchBuilds) UnmarshalYAML added in v0.8.0

func (o *OrderedBranchBuilds) UnmarshalYAML(n *yaml.Node) error

type OrderedBuilds added in v0.8.0

type OrderedBuilds []BuildConfig

OrderedBuilds is the builds: block — an id→build map (key becomes BuildConfig.ID).

func (*OrderedBuilds) UnmarshalYAML added in v0.8.0

func (o *OrderedBuilds) UnmarshalYAML(n *yaml.Node) error

type OrderedClusters added in v0.10.0

type OrderedClusters []GitOpsCluster

OrderedClusters is the gitops: block — a clusterName→cluster map (the map key becomes GitOpsCluster.Name). Mirrors the repos:/forges:/registries: keyed maps so the cluster is named by its key, not a nested name: field.

func (OrderedClusters) ByName added in v0.10.0

func (o OrderedClusters) ByName(name string) (GitOpsCluster, bool)

ByName returns the declared cluster with the given name.

func (OrderedClusters) Primary added in v0.10.0

func (o OrderedClusters) Primary() (GitOpsCluster, bool)

Primary returns the first declared cluster. The reconcile/scribe flows are single-cluster; the keyed map is for schema consistency + naming, not fan-out.

func (*OrderedClusters) UnmarshalYAML added in v0.10.0

func (o *OrderedClusters) UnmarshalYAML(n *yaml.Node) error

type OrderedFiles added in v0.8.0

type OrderedFiles []FileDef

OrderedFiles is the files: map — id → FileDef in document order.

func (*OrderedFiles) UnmarshalYAML added in v0.8.0

func (o *OrderedFiles) UnmarshalYAML(n *yaml.Node) error

type OrderedForges added in v0.8.0

type OrderedForges []ForgeConfig

OrderedForges is the forges: block — an id→forge map (key becomes ForgeConfig.ID).

func (*OrderedForges) UnmarshalYAML added in v0.8.0

func (o *OrderedForges) UnmarshalYAML(n *yaml.Node) error

type OrderedGovProfiles added in v0.10.0

type OrderedGovProfiles []GovernanceProfile

OrderedGovProfiles is the governance.profiles: block — an id→profile map (key becomes GovernanceProfile.ID). Config-side this is used only for the presence gate (len>0); the governance package re-parses the same block richly for distribution.

func (*OrderedGovProfiles) UnmarshalYAML added in v0.10.0

func (o *OrderedGovProfiles) UnmarshalYAML(n *yaml.Node) error

type OrderedLLMs added in v0.8.0

type OrderedLLMs []LLMConfig

OrderedLLMs is the llms: map — id → LLMConfig in document order.

func (OrderedLLMs) ByID added in v0.8.0

func (o OrderedLLMs) ByID() map[string]LLMConfig

ByID returns a lookup map of the llms library keyed by id.

func (*OrderedLLMs) UnmarshalYAML added in v0.8.0

func (o *OrderedLLMs) UnmarshalYAML(n *yaml.Node) error

type OrderedNotifications added in v0.8.0

type OrderedNotifications []Notification

OrderedNotifications is the notifications: map — id → Notification in document order.

func (OrderedNotifications) IsZero added in v0.8.0

func (o OrderedNotifications) IsZero() bool

IsZero reports whether no notifications are declared (the dispatch gate).

func (*OrderedNotifications) UnmarshalYAML added in v0.8.0

func (o *OrderedNotifications) UnmarshalYAML(n *yaml.Node) error

type OrderedOrgs added in v0.10.0

type OrderedOrgs []OrgConfig

OrderedOrgs is the orgs: block — an id→org map (the map key becomes OrgConfig.ID). An org is identity ONLY: a maintainer and an open aliases map (the name-forms used to build coordinates on different surfaces). It carries no forge and no credentials — each surface owns its own credential, and a governance write token is DERIVED, not declared here. That identity≠credentials split is a hard invariant; see docs/design/identity-model.md.

func (OrderedOrgs) ByID added in v0.10.0

func (o OrderedOrgs) ByID(id string) (OrgConfig, bool)

ByID returns the declared org with the given id.

func (*OrderedOrgs) UnmarshalYAML added in v0.10.0

func (o *OrderedOrgs) UnmarshalYAML(n *yaml.Node) error

type OrderedRegistries added in v0.8.0

type OrderedRegistries []RegistryConfig

OrderedRegistries is the registries: block — an id→registry map (key becomes RegistryConfig.ID).

func (*OrderedRegistries) UnmarshalYAML added in v0.8.0

func (o *OrderedRegistries) UnmarshalYAML(n *yaml.Node) error

type OrderedRepos added in v0.8.0

type OrderedRepos []RepoConfig

OrderedRepos is the repos: block — an id→repo map (key becomes RepoConfig.ID).

func (*OrderedRepos) UnmarshalYAML added in v0.8.0

func (o *OrderedRepos) UnmarshalYAML(n *yaml.Node) error

type OrderedSigningProfiles added in v0.8.0

type OrderedSigningProfiles []SigningProfile

OrderedSigningProfiles is signing.profiles — an id→profile map (key becomes SigningProfile.ID).

func (*OrderedSigningProfiles) UnmarshalYAML added in v0.8.0

func (o *OrderedSigningProfiles) UnmarshalYAML(n *yaml.Node) error

type OrderedStencils added in v0.8.0

type OrderedStencils []StencilDef

OrderedStencils is the top-level stencils: library — id → StencilDef, document order.

func (OrderedStencils) ByID added in v0.8.0

func (o OrderedStencils) ByID() map[string]StencilDef

ByID returns a lookup map of the stencil library keyed by id.

func (*OrderedStencils) UnmarshalYAML added in v0.8.0

func (o *OrderedStencils) UnmarshalYAML(n *yaml.Node) error

type OrderedTagSources added in v0.8.0

type OrderedTagSources []TagSourceConfig

OrderedTagSources is git.tags — an id→{pattern} map (key becomes TagSourceConfig.ID).

func (*OrderedTagSources) UnmarshalYAML added in v0.8.0

func (o *OrderedTagSources) UnmarshalYAML(n *yaml.Node) error

type OrderedTargets added in v0.8.0

type OrderedTargets []TargetConfig

OrderedTargets is the publish: block — the distribution targets as an id→target map (the map key becomes each target's ID). Backed by a slice so execution order (YAML map order) is preserved. This is the ONLY accepted shape.

func (*OrderedTargets) UnmarshalYAML added in v0.8.0

func (o *OrderedTargets) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML decodes the id→target map in document order, stamping each target's ID from its key (strict-decoded — see decodeIDMap).

type OrderedTestSuites added in v0.8.0

type OrderedTestSuites []TestSuite

OrderedTestSuites is the test.suites: block — an id→suite map (key becomes TestSuite.ID). The ONLY accepted shape; the retired list form is rejected at decode ("must be an id → entry map").

func (*OrderedTestSuites) UnmarshalYAML added in v0.8.0

func (o *OrderedTestSuites) UnmarshalYAML(n *yaml.Node) error

type OrgConfig added in v0.10.0

type OrgConfig struct {
	ID string `yaml:"-"` // from the map key

	// Maintainer is the "Name <email>" contact for this org's repos.
	Maintainer string `yaml:"maintainer,omitempty"`

	// Aliases is an OPEN map of name-forms used to build coordinates on different
	// surfaces — e.g. {handle: hlhd, lower: homelabhd, gitlab_group: "PrPlanIT/HomeLabHD"}.
	// A surface's default_path references one as {org.<alias>}. Common case is a single
	// entry; string→string only (a coordinate segment is always a scalar).
	Aliases map[string]string `yaml:"aliases,omitempty"`
}

OrgConfig is one organization/owner identity, keyed by its id in the orgs: map. Identity only — no forge, no credentials.

type OutdatedGate added in v0.10.0

type OutdatedGate struct {
	// At is the smallest magnitude that trips the gate: "major" | "minor" | "patch",
	// or "off". Empty defaults to "off" — no gate, so this is zero-change until a
	// project opts in.
	At string `yaml:"at,omitempty"`

	// Action is what a tripped gate does: "warn" (default) or "error". Warn is the
	// default deliberately: an available update is information, and a policy that
	// breaks a build the day upstream publishes is one operators disable entirely.
	Action string `yaml:"action,omitempty"`
}

OutdatedGate declares the update magnitude that trips the gate, and what tripping it does. Split in two because the threshold and the response are independent decisions: a fleet can surface every held major without any repo failing on it, then tighten to error per repo once the noise is understood.

func (OutdatedGate) EffectiveAction added in v0.10.0

func (g OutdatedGate) EffectiveAction() string

EffectiveAction resolves the response, defaulting to "warn" — reporting, never failing, unless the operator asks for a hard gate.

func (OutdatedGate) EffectiveAt added in v0.10.0

func (g OutdatedGate) EffectiveAt() string

EffectiveAt resolves the magnitude threshold, defaulting to "off".

type OutputSpec added in v0.7.0

type OutputSpec struct {
	Type     string        `yaml:"type"`
	Source   string        `yaml:"source"`
	Worktree *WorktreeSpec `yaml:"worktree,omitempty"`
}

OutputSpec declares one captured build output: what the command produced (Source, repo-relative) and its artifact class (Type ∈ tree | file | binary). Worktree opts the output into the git working tree during Narrate (so it can be committed or read by patches); absent, the output is a pure artifact (transported/published, never landed).

func (OutputSpec) LandsInWorktree added in v0.7.0

func (o OutputSpec) LandsInWorktree() bool

LandsInWorktree reports whether this output is materialized into the working tree.

func (OutputSpec) WorktreePath added in v0.7.0

func (o OutputSpec) WorktreePath() string

WorktreePath is where the output lands in the repo: its explicit worktree path, or its Source path when worktree is just `true`.

type PKCS11Trust added in v0.7.0

type PKCS11Trust struct {
	Ref string `yaml:"ref"`
}

PKCS11Trust selects the PKCS#11 transport for a `hardware` profile via a LOGICAL ref (e.g. "release"), bound to a concrete `pkcs11:` URI (module path + slot/object) only at render time via SF_PKCS11_<REF>. So a profile names "my signing token", never a machine-specific module path. Absent → the hardware class falls back to FIDO2 (cosign --sk). The renderer treats transport as an implementation detail; the class still means only "a non-exportable key in a signing device".

type PagesVersioning added in v0.7.0

type PagesVersioning struct {
	// Mode: "replace" (each release overwrites; the only mode implemented in P1) or
	// "keep" (every released version stays browsable — reserved for phase 2, rejected
	// in P1 rather than silently ignored).
	Mode string `yaml:"mode,omitempty"`
}

PagesVersioning controls how released versions of a static site are published.

type PhraseRewrite added in v0.5.0

type PhraseRewrite struct {
	From string `yaml:"from"`
	To   string `yaml:"to"`
}

PhraseRewrite replaces exact substrings.

type PolicyPresetLoader added in v0.11.0

type PolicyPresetLoader interface {
	LoadWithPolicy(path, onMismatch string) ([]byte, error)
}

PolicyPresetLoader is an optional PresetLoader capability: resolve a reference under the mismatch policy declared beside it. A loader without it resolves under the default, which is to stop.

type PresetLoader added in v0.6.0

type PresetLoader interface {
	Load(path string) ([]byte, error)
}

PresetLoader fetches preset content by path. Implementations: local filesystem, git repo checkout.

type ProducerCoords added in v0.8.0

type ProducerCoords struct {
	Provider string // github, gitlab, gitea, forgejo
	Host     string // github.com, gitlab.prplanit.com, ...
	Project  string // owner/name
	Module   string // host/owner/name (Go module path)
}

ProducerCoords are the repository coordinates a named-producer badge derives from the publish-origin repo (or an explicit repos: id override), so props like goreportcard / github-* stop restating {var:...} coordinates that already live in repos:.

func ResolveProducerCoords added in v0.8.0

func ResolveProducerCoords(cfg *Config, repoOverride string) (*ProducerCoords, error)

ResolveProducerCoords resolves the coordinates for a named producer. When repoOverride names a repos: entry, that repo's coordinates are used; otherwise the publish-origin repo (role publish-origin, falling back to primary). This is what lets a named producer be self-contained — no module:/repo: param restating coordinates already declared once in repos:.

type ProtectionPolicy added in v0.5.0

type ProtectionPolicy struct {
	Images  ImageProtection  `yaml:"images,omitempty"`
	Volumes VolumeProtection `yaml:"volumes,omitempty"`
}

ProtectionPolicy defines what host objects are never pruned.

type ProvenanceConfig added in v0.7.0

type ProvenanceConfig struct {
	Generated []string `yaml:"generated,omitempty"`
	Vendored  []string `yaml:"vendored,omitempty"`
}

ProvenanceConfig lets a project DECLARE file provenance that can't be inferred from bytes or paths (e.g. a build's CSS output). Declarations are the highest-confidence provenance signal — they outrank heuristics — because only the project knows its own build. Globs match the repo-relative path. Provenance only ever RELAXES authored-code hygiene (whitespace/line-endings/length); security and supply-chain checks ignore it.

type PrunePolicy added in v0.5.0

type PrunePolicy struct {
	Images     ImagePrunePolicy      `yaml:"images,omitempty"`
	BuildCache BuildCachePrunePolicy `yaml:"build_cache,omitempty"`
	Containers ContainerPrunePolicy  `yaml:"containers,omitempty"`
	Networks   NetworkPrunePolicy    `yaml:"networks,omitempty"`
}

PrunePolicy defines which host objects are eligible for removal.

type RegexRewrite added in v0.5.0

type RegexRewrite struct {
	Pattern string `yaml:"pattern"`
	Replace string `yaml:"replace"`
}

RegexRewrite replaces regex matches.

type RegistryConfig added in v0.6.0

type RegistryConfig struct {
	ID          string `yaml:"id"`                     // unique identifier (e.g., "dockerhub")
	Provider    string `yaml:"provider"`               // docker, harbor, ghcr, quay, gitea, generic
	URL         string `yaml:"url"`                    // registry URL (e.g., "docker.io")
	Credentials string `yaml:"credentials,omitempty"`  // env var prefix for token resolution
	DefaultPath string `yaml:"default_path,omitempty"` // default image path (e.g., "{var:org}/{var:repo}")
}

RegistryConfig declares an OCI registry host. Declared once, referenced by targets.

func FindRegistryByID added in v0.6.0

func FindRegistryByID(registries []RegistryConfig, id string) *RegistryConfig

FindRegistryByID returns the registry with the given id, or nil.

type ReleaseConfig

type ReleaseConfig struct {
	Preset   string `yaml:"preset,omitempty"`
	Enabled  bool   `yaml:"enabled"`
	Required *bool  `yaml:"required,omitempty"` // failure is hard pipeline fail (default: false)
	// Render controls release rendering (default DefaultReleasePresentation; a
	// partial render: block overlays those defaults).
	Render ReleasePresentation `yaml:"render,omitempty"`

	RunFrom RunFromConfig `yaml:"run_from,omitempty"` // gate mutation to declared origin
}

ReleaseConfig holds configuration for the release subsystem.

func DefaultReleaseConfig

func DefaultReleaseConfig() ReleaseConfig

DefaultReleaseConfig returns sensible defaults for release management.

func (ReleaseConfig) IsRequired added in v0.5.0

func (r ReleaseConfig) IsRequired() bool

IsRequired returns whether release failure is a hard pipeline fail. Default: false.

type ReleasePresentation added in v0.5.0

type ReleasePresentation struct {
	MaxEntries                int    `yaml:"max_entries"`
	GroupByType               bool   `yaml:"group_by_type"`
	Style                     string `yaml:"style"` // concise | explanatory | technical
	IncludeReleaseVisibleOnly bool   `yaml:"include_release_visible_only"`
}

ReleasePresentation controls release notes rendering (release.render).

func DefaultReleasePresentation added in v0.8.0

func DefaultReleasePresentation() ReleasePresentation

DefaultReleasePresentation is the default release.render policy.

type RemediationConfig added in v0.7.0

type RemediationConfig struct {
	TrailingWhitespace *bool `yaml:"trailing_whitespace,omitempty"` // default ON under --fix-safe
	FinalNewline       *bool `yaml:"final_newline,omitempty"`       // default ON under --fix-safe
}

RemediationConfig is the granular opt-in for `--fix-safe`. Each field is a *bool: nil means "use the safe default" (on for the conservative hygiene fixes), so the one-shot `--fix-safe` flow works out of the box while a project can still disable a category. Categories that are policy-dependent (line endings, tab/space) default OFF and must be turned on explicitly. Only authored files are ever mutated — generated/vendored/lock emit no hygiene findings, so they carry no fixes.

type RenderConfig added in v0.5.0

type RenderConfig struct {
	EmptyStrategy string `yaml:"empty_strategy"` // prompt | fail | allow_empty
}

RenderConfig controls glossary-level output defaults. Surface-specific max entries live in presentation config.

type RepoConfig added in v0.6.0

type RepoConfig struct {
	ID       string         `yaml:"id"`                 // unique identifier
	Forge    string         `yaml:"forge"`              // references forges[].id
	Project  string         `yaml:"project"`            // project path on the forge (e.g., "{var:gitlab_group}/{var:repo}")
	Roles    []string       `yaml:"roles,omitempty"`    // ["primary"] | ["mirror"] | ["mirror", "publish-origin"] | []
	Branches BranchesConfig `yaml:"branches,omitempty"` // branch identity (default, protected, etc.)
	Worktree string         `yaml:"worktree,omitempty"` // local working tree path (primary only)
	Ref      string         `yaml:"ref,omitempty"`      // pinned ref for non-primary repos (governance, presets)
	Sync     SyncConfig     `yaml:"sync,omitempty"`     // mirror sync domains
}

RepoConfig declares a project on a forge. References forge by id. Roles are explicit and composable:

  • "primary": exactly 1 required — authoritative source
  • "mirror": 0 to many — derivative copies
  • "publish-origin": 0 or 1 — where rendered artifacts are served from
  • empty: addressable, no special behavior

Forbidden combinations: primary + mirror (authoritative ≠ derivative). Allowed combinations: publish-origin + primary, publish-origin + mirror.

func FindRepoByID added in v0.6.0

func FindRepoByID(repos []RepoConfig, id string) *RepoConfig

FindRepoByID returns the repo with the given id, or nil.

func FindRepoWithRole added in v0.6.0

func FindRepoWithRole(repos []RepoConfig, role string) *RepoConfig

FindRepoWithRole returns the first repo that has the given role, or nil.

func MirrorRepos added in v0.6.0

func MirrorRepos(repos []RepoConfig) []RepoConfig

MirrorRepos returns all repos with the mirror role.

func (RepoConfig) HasRole added in v0.6.0

func (r RepoConfig) HasRole(role string) bool

HasRole returns true if the repo has the given role.

type ResolvedRegistry added in v0.6.0

type ResolvedRegistry struct {
	ID          string
	Provider    string // from registry
	URL         string // from registry
	Path        string // from registry default_path or target override
	Credentials string // from registry
}

ResolvedRegistry is a fully resolved registry target with all identity fields populated from the registry graph. Ready for buildx/push.

func ResolveRegistryByID added in v0.10.0

func ResolveRegistryByID(id string, registries []RegistryConfig, vars map[string]string) *ResolvedRegistry

ResolveRegistryByID resolves a registry from the graph by its config id alone, with {var:} templates expanded in URL and default_path. It is the addressing primitive for {registry.<id>...} template tokens: a registry is referenced only by the id it was given in registries:, never by a provider-literal shorthand (which cannot distinguish two registries of the same provider and picks one by luck). Returns nil for an unknown id.

func ResolveRegistryForTarget added in v0.6.0

func ResolveRegistryForTarget(target TargetConfig, registries []RegistryConfig, vars map[string]string) (*ResolvedRegistry, error)

ResolveRegistryForTarget resolves a target's registry identity from the registry graph. Path comes from target override or registry default_path.

type ResolvedRepo added in v0.6.0

type ResolvedRepo struct {
	ID            string
	Provider      string   // from forge
	BaseURL       string   // from forge
	Project       string   // from repo
	Credentials   string   // from forge
	Roles         []string // from repo (primary, mirror, publish-origin)
	DefaultBranch string   // flattened from repo.Branches.Default
	Worktree      string
	Ref           string
	Sync          SyncConfig
}

ResolvedRepo is a fully resolved repo with all identity fields populated from the forge + repo graph. Ready for forge client creation.

DefaultBranch is the flattened view of repo.Branches.Default — resolved once at load time so consumers don't need to know the nested shape.

func ResolveAllMirrors added in v0.6.0

func ResolveAllMirrors(repos []RepoConfig, forges []ForgeConfig, vars map[string]string) ([]*ResolvedRepo, error)

ResolveAllMirrors resolves all mirror repos against the forge graph.

func ResolvePrimary added in v0.6.0

func ResolvePrimary(repos []RepoConfig, forges []ForgeConfig, vars map[string]string) (*ResolvedRepo, error)

ResolvePrimary resolves the primary repo against the forge graph.

func ResolveRepo added in v0.6.0

func ResolveRepo(repo RepoConfig, forges []ForgeConfig, vars map[string]string) (*ResolvedRepo, error)

ResolveRepo resolves a repo entry against the forge graph. Returns error if the referenced forge doesn't exist.

func (ResolvedRepo) HasRole added in v0.6.0

func (r ResolvedRepo) HasRole(role string) bool

HasRole returns true if the resolved repo has the given role.

type ResolvedSigningProfile added in v0.7.0

type ResolvedSigningProfile struct {
	ID               string
	Class            string
	KeyRef           string
	KMSRef           string
	PKCS11Ref        string
	OIDCIssuer       string
	OIDCIdentity     string
	PhysicalPresence bool
	NonExportable    bool
	TransparencyLog  *bool // nil = use the class default
	Attestation      bool
	Enforce          bool // signing failure is fatal (orchestration policy, not trust)
	AllowFallback    bool // an unresolved explicit signer may fall back to Tier-0
}

ResolvedSigningProfile is the flattened, validated view consumed by the pure compiler (src/sign). Exactly one trust class; assurance keywords collapsed to booleans; logical refs carried verbatim (bound to keys/URIs only at render).

func ResolveSigningProfileByID added in v0.7.0

func ResolveSigningProfileByID(profiles []SigningProfile, id string) (*ResolvedSigningProfile, error)

ResolveSigningProfileByID resolves a profile by id for explicit signing flows (e.g. `stagefreight sign --profile <id>`). Unknown id → error; the reserved `legacy` id resolves to the synthesized default.

func ResolveSigningProfileForTarget added in v0.7.0

func ResolveSigningProfileForTarget(t TargetConfig, profiles []SigningProfile) (*ResolvedSigningProfile, error)

ResolveSigningProfileForTarget returns the resolved profile a target signs under. No signing_profile → the synthesized `legacy` profile (single path, never nil for a signable target). A set-but-unknown reference is an error. Mirrors ResolveRegistryForTarget.

func (*ResolvedSigningProfile) IsLegacyDefault added in v0.7.0

func (r *ResolvedSigningProfile) IsLegacyDefault() bool

IsLegacyDefault reports whether this is the synthesized implicit default profile (no explicit signing_profile on the target) — the always-on path that may fall to Tier-0 or silently skip, as opposed to an explicit profile that must resolve.

type RetentionPolicy

type RetentionPolicy struct {
	KeepLast     int            `yaml:"keep_last"`     // keep the N most recent tags per series (0/-1/unset = ∞)
	KeepDaily    int            `yaml:"keep_daily"`    // keep one per day for the last N days
	KeepWeekly   int            `yaml:"keep_weekly"`   // keep one per week for the last N weeks
	KeepMonthly  int            `yaml:"keep_monthly"`  // keep one per month for the last N months
	KeepYearly   int            `yaml:"keep_yearly"`   // keep one per year for the last N years
	KeepBranches int            `yaml:"keep_branches"` // keep the N most-recent identity groups per template (bounds retired branches; 0/unset = ∞)
	MaxAge       string         `yaml:"max_age"`       // keep items newer than this ("14d", "72h"); additive like keep_* — alone it means "only the recent survive"
	Identity     []string       `yaml:"identity"`      // extra identity vars beyond the {branch}/{env} defaults — partition tags into independent series
	Protect      []string       `yaml:"protect"`       // tag patterns that are never deleted, an explicit override
	Refs         []RetentionRef `yaml:"refs"`          // scoped overrides: a different policy for items matching a pattern (first match wins; unset fields inherit this default)
}

RetentionPolicy defines how many tags/releases to keep using time-bucketed rules. Policies are additive — a tag survives if ANY rule wants to keep it. This mirrors restic's forget policy.

func (RetentionPolicy) Active

func (r RetentionPolicy) Active() bool

Active returns true if any retention rule is configured. keep_last/buckets are active only when positive (0/-1/unset all mean ∞ / keep-all); keep_branches is a group-count bound that is likewise only active when positive. max_age and any scoped ref rule likewise activate the policy.

func (*RetentionPolicy) UnmarshalYAML

func (r *RetentionPolicy) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML implements custom unmarshaling so retention accepts both:

retention: 10          → RetentionPolicy{KeepLast: 10}
retention:
  keep_last: 3
  keep_daily: 7        → RetentionPolicy{KeepLast: 3, KeepDaily: 7}

type RetentionRef added in v0.10.0

type RetentionRef struct {
	Match       string `yaml:"match"` // pattern (same syntax as protect/templates)
	KeepLast    int    `yaml:"keep_last"`
	KeepDaily   int    `yaml:"keep_daily"`
	KeepWeekly  int    `yaml:"keep_weekly"`
	KeepMonthly int    `yaml:"keep_monthly"`
	KeepYearly  int    `yaml:"keep_yearly"`
	MaxAge      string `yaml:"max_age"`
}

RetentionRef is one scoped retention override: items matching Match are governed by this rule set instead of the default policy. Fields left unset inherit the default's value — a ref narrows or widens specific rules without restating the whole policy. The SAME grammar applies at every retention site (publish targets, toolchains, declared image eviction, releases, packages, mirrors) — one engine implements it.

type RewriteConfig added in v0.5.0

type RewriteConfig struct {
	Phrases []PhraseRewrite `yaml:"phrases,omitempty"`
	Regex   []RegexRewrite  `yaml:"regex,omitempty"`
}

RewriteConfig defines deterministic text transformations.

type RoutingConfig added in v0.6.0

type RoutingConfig struct {
	Default  RoutingSpec `yaml:"default,omitempty"`
	Audition RoutingSpec `yaml:"audition,omitempty"`
	Perform  RoutingSpec `yaml:"perform,omitempty"`
	Review   RoutingSpec `yaml:"review,omitempty"`
	Publish  RoutingSpec `yaml:"publish,omitempty"`
	Narrate  RoutingSpec `yaml:"narrate,omitempty"`
}

RoutingConfig declares runner placement per phase. Default applies to EVERY job; a per-phase field overrides it for that job. Empty ⇒ no constraint (any runner). This matters beyond consistency: GitLab's local runner cache is per-runner, so the build/toolchain caches StageFreight configures only actually persist across the pipeline when its phases land on the SAME runner — otherwise floating jobs re-provision toolchains every run. Set `default` to keep the whole pipeline on one runner.

func (RoutingConfig) For added in v0.7.0

func (r RoutingConfig) For(phase string) []string

For returns the runner labels for a phase: the per-phase override if set, else the Default. nil when neither is configured (the job is unconstrained).

type RoutingSpec added in v0.6.0

type RoutingSpec struct {
	Labels []string `yaml:"labels,omitempty"`
}

RoutingSpec declares runner placement labels for a single phase.

type RunFromConfig added in v0.6.0

type RunFromConfig struct {
	Allow    []string `yaml:"allow,omitempty"`    // permitted origins: "primary"
	Mismatch string   `yaml:"mismatch,omitempty"` // "read-only" (default), "exit", "ignore"
}

RunFromConfig gates mutation to declared execution origins. Attached to mutating surfaces (release, docs.commit, dependency.commit, targets).

func (RunFromConfig) IsActive added in v0.6.0

func (rf RunFromConfig) IsActive() bool

IsActive returns true if run_from has any allow rules configured.

type RunFromResult added in v0.6.0

type RunFromResult struct {
	Matched bool   // true if current context matches an allowed origin
	Mode    string // "read-only", "exit", "ignore", or "" (no restriction)
	Reason  string // human-readable explanation (empty when matched or unconfigured)
}

RunFromResult is the evaluated outcome of a run_from guard.

func EvaluateRunFrom added in v0.6.0

func EvaluateRunFrom(rf RunFromConfig, ciRepoURL, primaryURL string) RunFromResult

EvaluateRunFrom checks whether the current execution context is authorized to perform a mutation guarded by a run_from config.

ciRepoURL is the CI execution context (SF_CI_REPO_URL). primaryURL is sources.primary.url from config.

type ScannerCacheConfig added in v0.5.0

type ScannerCacheConfig struct {
	MaxSize string `yaml:"max_size,omitempty"` // e.g. "500MB" — full-clear when exceeded
	MaxAge  string `yaml:"max_age,omitempty"`  // e.g. "7d" — full-clear when oldest file exceeds age
}

ScannerCacheConfig is the cache policy for a single scanner. Any field set = persistent cache enabled for this tool. All fields empty = no StageFreight-managed persistence (tool defaults). Eviction is full-clear (opaque DBs, no granular eviction).

type ScannersConfig

type ScannersConfig struct {
	Trivy *bool `yaml:"trivy,omitempty"` // run Trivy image scan (default: true)
	Grype *bool `yaml:"grype,omitempty"` // run Grype image scan (default: true)
}

ScannersConfig controls which vulnerability scanners are enabled. Both default to true — scanners still require their binary in PATH. Uses *bool so omitting a key preserves the default instead of zeroing it.

func (ScannersConfig) GrypeEnabled

func (s ScannersConfig) GrypeEnabled() bool

GrypeEnabled returns whether Grype scanning is enabled (default: true).

func (ScannersConfig) TrivyEnabled

func (s ScannersConfig) TrivyEnabled() bool

TrivyEnabled returns whether Trivy scanning is enabled (default: true).

type Scoped added in v0.10.0

type Scoped[T any] struct {
	Default   T
	BySurface map[string]T
}

Scoped[T] is a value that is either an inferred DEFAULT (the common case) or scoped per surface — the same override idiom as `names`, for content values (description, readme). A plain value is the default used on every un-named surface; a map form

{ default: <T>, <surface>: <T>, … }

overrides specific surfaces. Resolution at surface S is BySurface[S] if present, else Default.

Disambiguation is by YAML shape: T here is always a scalar-or-list (StringOrList or string) — never itself a map — so a MappingNode can only mean the scoped form; anything else is the plain default. Note: only the DEFAULT of a Scoped[StringOrList] may be a tiered list; a named surface takes a single value (one endpoint, one value), enforced in validation rather than the type.

func (Scoped[T]) For added in v0.10.0

func (s Scoped[T]) For(surface string) T

For returns the value scoped to surface, or the default when the surface is un-named.

func (*Scoped[T]) UnmarshalYAML added in v0.10.0

func (s *Scoped[T]) UnmarshalYAML(n *yaml.Node) error

type ScribeCommit added in v0.8.0

type ScribeCommit struct {
	Type    string        `yaml:"type,omitempty"`
	Message string        `yaml:"message,omitempty"`
	Add     []string      `yaml:"add,omitempty"`
	Push    bool          `yaml:"push,omitempty"`
	SkipCI  bool          `yaml:"skip_ci,omitempty"`
	RunFrom RunFromConfig `yaml:"run_from,omitempty"`
}

ScribeCommit is scribe's auto-commit action.

func (ScribeCommit) IsZero added in v0.8.0

func (c ScribeCommit) IsZero() bool

IsZero reports whether the commit action is unset.

type ScribeConfig added in v0.8.0

type ScribeConfig struct {
	Store  string       `yaml:"store,omitempty"`  // dir for rendered file assets (default .stagefreight/scribe); path = {store}/{id}.svg
	Files  OrderedFiles `yaml:"files,omitempty"`  // id → placement region referencing stencils
	Commit ScribeCommit `yaml:"commit,omitempty"` // scribe's own auto-commit action
}

ScribeConfig is the scribe: block — place rendered stencils into repository files and commit them: files: (placement regions whose bodies reference stencils by {id}) + commit:. The reusable stencil library it draws from lives at the top-level stencils: block (Config.Stencils) — shared with narrate and release.

func (ScribeConfig) IsZero added in v0.8.0

func (s ScribeConfig) IsZero() bool

IsZero reports whether scribe declares nothing (the phase presence gate). Note it does NOT consider stencils: the library is presence-neutral (shared, may exist with no scribe placement), so only files/commit gate the scribe/narrate stage.

type SectionState added in v0.6.0

type SectionState struct {
	Name             string `json:"name"`
	Kind             string `json:"kind"` // "execution" | "capability" | "structural"
	Active           bool   `json:"active"`
	SourcePresent    bool   `json:"source_present"`
	Provenance       string `json:"provenance"`        // "manifest" | "preset" | "none"
	ResolutionStatus string `json:"resolution_status"` // "resolved" | "partial" | "none"
}

SectionState is the resolved state of one config domain section.

Provenance only applies when Active == true. When Active == false, Provenance MUST be "none" — inactive sections have no provenance because they do not exist in the runtime model.

type SecurityCacheConfig added in v0.5.0

type SecurityCacheConfig struct {
	Trivy ScannerCacheConfig `yaml:"trivy,omitempty"`
	Grype ScannerCacheConfig `yaml:"grype,omitempty"`
}

SecurityCacheConfig controls persistent vuln DB caching per scanner tool. These are opaque tool-managed directories — StageFreight hosts and bounds them, but does not manage their internal structure.

type SecurityConfig

type SecurityConfig struct {
	Preset         string         `yaml:"preset,omitempty"`
	Enabled        bool           `yaml:"enabled"`            // run vulnerability scanning (default: true)
	Required       *bool          `yaml:"required,omitempty"` // failure is hard pipeline fail (default: false)
	Scanners       ScannersConfig `yaml:"scanners"`           // per-scanner toggles
	SBOMEnabled    bool           `yaml:"sbom"`               // generate SBOM artifacts (default: true)
	FailOnCritical bool           `yaml:"fail_on_critical"`   // DEPRECATED: use fail_on. Alias — true → fail_on: critical.
	OutputDir      string         `yaml:"output"`             // directory for scan artifacts (default: .stagefreight/security)

	// FailOn is the severity threshold at or above which the scan fails the build:
	// "critical" | "high" | "medium" | "low" | "off". Empty falls back to the
	// deprecated fail_on_critical (true → "critical"), then to "off" — so the
	// default stays informational (no gate), exactly as today.
	FailOn string `yaml:"fail_on,omitempty"`

	// UnreachableVulns is the policy for vulnerabilities a reachability analyzer
	// proved are never called: "pass" (default — excused from the gate) or "fail"
	// (gated on severity regardless of reachability). Only vulns with a
	// proven-unreachable verdict are affected; everything else is "unknown" and
	// gates normally.
	UnreachableVulns string `yaml:"unreachable_vulns,omitempty"`

	// Exceptions are reviewed, on-record decisions to excuse specific advisories from the
	// fail_on gate — the human counterpart to the reachability excusal above. An excepted
	// finding STILL appears in the scan report (it is not hidden); the exception only stops
	// it from FAILING the build. Each carries a mandatory reason and an optional expiry: an
	// expired exception lapses (the advisory gates again and the lapse is surfaced), and one
	// with no expiry is a standing decision (reported as such). This does nothing unless
	// fail_on is set — with the gate off, everything is already informational.
	Exceptions []SecurityException `yaml:"exceptions,omitempty"`

	// ReleaseDetail is the default detail level for security info in release notes.
	// Values: "none", "counts", "detailed", "full" (default: "counts").
	ReleaseDetail string `yaml:"release_detail"`

	// ReleaseDetailRules are conditional overrides evaluated top-down (first match wins).
	// Uses the standard Condition primitive for tag/branch matching with ! negation.
	ReleaseDetailRules []DetailRule `yaml:"release_detail_rules"`

	// ReleaseDetailMaxRows bounds how many vulnerability rows the "full" detail level
	// writes into release notes; the rest are reported as a count. Unset = 100.
	//
	// "full" means complete within reason, not unbounded: a large image can carry
	// thousands of advisories, and every forge caps a release body — GitHub at 125k
	// characters, and it rejects an over-long body outright rather than trimming it. The
	// rows are written worst-first, so a bound keeps what a reader acts on and drops the
	// tail they scroll past. 0 disables the bound and restores the old behaviour.
	ReleaseDetailMaxRows *int `yaml:"release_detail_max_rows,omitempty"`

	// Cache controls persistent vulnerability DB caching per scanner.
	// Each tool's max_size triggers full-clear when exceeded (opaque DBs, no granular eviction).
	// Empty/omitted per tool = no StageFreight-managed persistence for that tool.
	Cache SecurityCacheConfig `yaml:"cache,omitempty"`

	// OverwhelmMessage is the message lines shown when >1000 vulns are found.
	// Defaults to ["…maybe start here:"] with the OverwhelmLink below.
	OverwhelmMessage []string `yaml:"overwhelm_message"`

	// OverwhelmLink is an optional URL appended after OverwhelmMessage.
	// Defaults to a Psychology Today anxiety page. Empty string disables.
	OverwhelmLink string `yaml:"overwhelm_link"`
}

SecurityConfig holds security scanning configuration.

func DefaultSecurityConfig

func DefaultSecurityConfig() SecurityConfig

DefaultSecurityConfig returns sensible defaults for security scanning.

func (SecurityConfig) EffectiveFailOn added in v0.7.0

func (s SecurityConfig) EffectiveFailOn() string

EffectiveFailOn resolves the severity threshold at or above which the security scan fails the build. Precedence: explicit fail_on > the deprecated fail_on_critical bool (true → "critical") > "off" — so with neither set the scan stays informational, exactly as it does today. Returns a lowercased "critical" | "high" | "medium" | "low" | "off".

func (SecurityConfig) IsRequired added in v0.5.0

func (s SecurityConfig) IsRequired() bool

IsRequired returns whether security failure is a hard pipeline fail. Default: false.

func (SecurityConfig) UnreachablePolicy added in v0.7.0

func (s SecurityConfig) UnreachablePolicy() string

UnreachablePolicy resolves how proven-unreachable vulnerabilities are gated: "pass" (default — excused) or "fail".

type SecurityException added in v0.9.1

type SecurityException struct {
	// ID is the advisory this excepts (CVE / GHSA), matched case-insensitively. Required.
	ID string `yaml:"id"`
	// Reason is why the advisory is accepted or not applicable. Required — there is no
	// anonymous excusal; the justification is the whole point of the record.
	Reason string `yaml:"reason"`
	// Expires optionally lapses the exception on a date (YYYY-MM-DD). Past its expiry the
	// advisory gates again and the lapse is surfaced. Omit for a standing decision (an
	// architectural fact), which is reported as a permanent exception.
	Expires string `yaml:"expires,omitempty"`
	// Package optionally scopes the exception to a single package name, so a later,
	// unrelated advisory that reuses the same ID against a different package still gates.
	Package string `yaml:"package,omitempty"`
}

SecurityException excuses one advisory from the fail_on gate on record. It never removes the finding from the report — it only marks it as a reviewed accepted-risk / not-applicable decision so it does not fail the build.

type SigningConfig added in v0.7.0

type SigningConfig struct {
	Enabled       *bool                  `yaml:"enabled,omitempty"`        // nil/true = signing allowed; false = all signing off
	AutoProvision bool                   `yaml:"auto_provision,omitempty"` // explicit consent to create/manage a Tier-0 identity
	StateDir      StateDir               `yaml:"state_dir,omitempty"`      // where persistent signing material lives
	Profiles      OrderedSigningProfiles `yaml:"profiles,omitempty"`       // id→profile map
}

SigningConfig is the OPERATIONAL signing block (`signing:`), distinct from the trust-profile list (`signing.profiles`). It governs whether StageFreight may sign at all, whether it may create/manage Tier-0 identity material on the operator's behalf, and where that material persists.

The two toggles are deliberately separate — collapsing them would let the system silently mint a trust identity nobody consented to:

  • enabled = "StageFreight may perform signing"
  • auto_provision = "StageFreight may create/manage a Tier-0 identity"

`auto_provision` defaults FALSE: with no config, StageFreight mints nothing and signs only with an explicit key/profile. Opinionated "always-on" defaults belong in a runner/distribution config (visible, editable, removable), never in core.

func (SigningConfig) SigningEnabled added in v0.7.0

func (c SigningConfig) SigningEnabled() bool

SigningEnabled reports whether signing may run. Default (unset) is true — signing is a first-class capability; `enabled: false` is the global kill switch.

type SigningProfile added in v0.7.0

type SigningProfile struct {
	ID       string       `yaml:"id"`
	Requires StringOrList `yaml:"requires"` // trust class(es); v1 enforces exactly one

	// Class reference blocks — at most one, matching the declared class.
	Key    *KeyTrust    `yaml:"key,omitempty"`
	OIDC   *OIDCTrust   `yaml:"oidc,omitempty"`
	KMS    *KMSTrust    `yaml:"kms,omitempty"`
	PKCS11 *PKCS11Trust `yaml:"pkcs11,omitempty"` // hardware transport selector (optional; absent = FIDO2 --sk)

	// Assurance properties (hardware-class ONLY; enforced in validation). The
	// value is the keyword "required" (absent = not required). The renderer later
	// selects a transport that satisfies them — they are never device names here.
	PhysicalPresence string `yaml:"physical_presence,omitempty"`
	NonExportable    string `yaml:"non_exportable,omitempty"`

	// TransparencyLog overrides the per-class default (on for oidc, off otherwise).
	TransparencyLog *bool `yaml:"transparency_log,omitempty"`

	// Attestation also emits a provenance attestation alongside the signature.
	Attestation bool `yaml:"attestation,omitempty"`

	// Enforce makes a signing failure fatal to the phase (default: best-effort —
	// warn + record a failed outcome, let the build proceed). An orchestration
	// policy, NOT a trust requirement — it never enters the SignPlan; Publish reads
	// it to decide block-vs-proceed (foundational invariant 4).
	Enforce bool `yaml:"enforce,omitempty"`

	// AllowFallback permits an explicitly-configured signer that fails to resolve to
	// fall back to the auto-provisioned Tier-0 identity. Default false: an explicit
	// trust expectation that is unmet fails LOUDLY, never silently downgrades.
	AllowFallback bool `yaml:"allow_fallback,omitempty"`
}

SigningProfile is a named, generic trust profile.

func FindSigningProfileByID added in v0.7.0

func FindSigningProfileByID(profiles []SigningProfile, id string) *SigningProfile

FindSigningProfileByID returns the profile with the given id, or nil.

func NormalizeSigning added in v0.7.0

func NormalizeSigning(profiles []SigningProfile) []SigningProfile

NormalizeSigning canonicalizes `requires` values (alias resolution) and synthesizes the implicit `legacy` profile, so a target with no signing_profile has a single, uniform compile path (never a parallel legacy branch). Idempotent.

type StageConfig added in v0.7.0

type StageConfig struct {
	From string `yaml:"from"`
	As   string `yaml:"as"`
}

StageConfig wires a binary build's output into a docker build's context. From names the binary build (its id); As is the destination path within the context, with {arch}/{os} placeholders substituted using Docker's naming (e.g. "app-{arch}" → "app-amd64") so a multi-arch copy-pre-built Dockerfile resolves per platform.

type StateDir added in v0.7.0

type StateDir struct {
	Type string `yaml:"type,omitempty"` // "volume" | "host_path"
	Name string `yaml:"name,omitempty"` // volume name (type: volume)
	Path string `yaml:"path,omitempty"` // absolute path (type: host_path)
}

StateDir locates the durable, operator-chosen home for persistent signing material — outside the build tree so it is never cleared, committed, or baked.

func (StateDir) Configured added in v0.7.0

func (s StateDir) Configured() bool

Configured reports whether a state dir is declared at all.

func (StateDir) Resolve added in v0.7.0

func (s StateDir) Resolve() (string, error)

Resolve maps the declared state dir to a filesystem path. Empty type → "" (not configured → no Tier-0 auto-provision).

type StencilDef added in v0.8.0

type StencilDef struct {
	ID string `yaml:"-"` // set from the stencils map key

	// SOURCE × RENDER.
	Type   string `yaml:"type,omitempty"`   // producer; empty = inline
	Render string `yaml:"render,omitempty"` // form: badge (default) | shield | image | table | list | kv | versions | raw

	// ── inline badge / shield areas ──
	Label      string `yaml:"label,omitempty"`     // left text (defaults to id); also props alt override
	Message    string `yaml:"message,omitempty"`   // right value (templates)
	Color      string `yaml:"color,omitempty"`     // hex or "auto"
	Font       string `yaml:"font,omitempty"`      // badge font override
	FontSize   int    `yaml:"font_size,omitempty"` // badge font size override
	Output     string `yaml:"output,omitempty"`    // SVG output path (badge generation)
	Link       string `yaml:"link,omitempty"`      // clickable URL
	LogoColor  string `yaml:"logo_color,omitempty"`
	LabelColor string `yaml:"label_color,omitempty"`
	Shield     string `yaml:"shield,omitempty"` // shields.io path (render: shield)

	// ── text (the dumb markdown stencil: facts + {id} stencil embeds, no logic) ──
	// llm shares body: — there it is the composed INPUT (inject {ci-detail} etc.
	// and write the ask inline; no separate prompt slot).
	Body string `yaml:"body,omitempty"`

	// ── llm (AI stencil: composed body × llms: backend → markdown) ──
	LLM string `yaml:"llm,omitempty"` // llms: entry id (the backend reference)

	// ── component ──
	Spec string `yaml:"spec,omitempty"`

	// ── include ──
	Path string `yaml:"path,omitempty"`

	// ── contents (build manifest) / ci (run-state producers) ──
	Build   string `yaml:"build,omitempty"`
	Source  string `yaml:"source,omitempty"`
	Section string `yaml:"section,omitempty"`
	// Limit caps a ci producer's rows (self-bounding: excess becomes "+K more").
	Limit int `yaml:"limit,omitempty"`
	// contents renderer form lives on the RENDER axis (render:), not a separate
	// renderer: key — one form vocabulary (badges|table|list|kv|versions).
	Columns    []string `yaml:"columns,omitempty"`
	OutputFile string   `yaml:"output_file,omitempty"`
	Wrap       string   `yaml:"wrap,omitempty"`
	Summary    string   `yaml:"summary,omitempty"`

	// ── named-producer coordinate override (props) ──
	Repo string `yaml:"repo,omitempty"` // repos: id whose coordinates the producer uses (default: publish-origin)

	// ── props (github-*, goreportcard, …) ──
	Params map[string]string `yaml:"params,omitempty"`
	Style  string            `yaml:"style,omitempty"`

	// ── k8s-inventory ──
	CatalogPath string `yaml:"catalog,omitempty"`
}

StencilDef is one entry in the top-level stencils: library — a named, reusable markdown element with variable fill, embeddable as {id} anywhere SF composes audience text (scribe file regions, narrate, release bodies). Its shape is SOURCE (type:) × RENDER (render:): an inline def (no type) renders a badge (default) or shield; a named producer (type: goreportcard, github-*, contents, include, text, component, k8s-inventory) renders through the matching module. The id (map key) is the {id} embed target and the default label.

func ShippedStencil added in v0.8.0

func ShippedStencil(id, modality string) (StencilDef, bool)

ShippedStencil returns SF's built-in stencil definition for id under the given lifecycle modality, if one exists. Callers must check user stencils FIRST — shadowing a shipped id is the override mechanism (redefine `changelog` with knobs — {type: ci, limit: 5} — and every {changelog} embed picks it up).

func (StencilDef) EffectiveKind added in v0.8.0

func (c StencilDef) EffectiveKind() string

EffectiveKind maps (Type, Render) to the render module used for this stencil. It is the discriminator the runtime dispatches on when resolving a {id} embed to markdown.

func (StencilDef) HasGeneration added in v0.8.0

func (c StencilDef) HasGeneration() bool

HasGeneration reports whether this stencil produces an SVG badge (an inline badge with an output path).

func (StencilDef) LabelOrID added in v0.8.0

func (c StencilDef) LabelOrID() string

LabelOrID returns the badge/alt label, defaulting to the stencil id.

func (StencilDef) ToBadgeSpec added in v0.8.0

func (c StencilDef) ToBadgeSpec() BadgeSpec

ToBadgeSpec extracts the SVG-generation fields.

type StringOrList added in v0.7.0

type StringOrList []string

StringOrList unmarshals a YAML scalar OR a sequence of strings into []string.

func (StringOrList) First added in v0.8.0

func (s StringOrList) First() string

First returns the first element, or "" if empty — for single-value consumers of a field that is now a list (e.g. a metadata description variant).

func (*StringOrList) UnmarshalYAML added in v0.7.0

func (s *StringOrList) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML accepts a bare scalar (coerced to a one-element list) or a sequence. Anything else is an error.

type SummaryFilter added in v0.5.0

type SummaryFilter struct {
	StripPhrases []string `yaml:"strip_phrases,omitempty"`
	StripRegex   []string `yaml:"strip_regex,omitempty"`
}

SummaryFilter strips content from commit subjects.

type SyncConfig added in v0.4.1

type SyncConfig struct {
	Branches *FacetSpec `yaml:"branches,omitempty"`
	Tags     *FacetSpec `yaml:"tags,omitempty"`
	Releases *FacetSpec `yaml:"releases,omitempty"`
	// contains filtered or unexported fields
}

SyncConfig is the per-facet replication spec on a mirror repo (repos.<id>.sync).

func (SyncConfig) Active added in v0.8.0

func (s SyncConfig) Active() bool

Active reports whether any facet is synced.

func (SyncConfig) IsLegacyForm added in v0.8.0

func (s SyncConfig) IsLegacyForm() bool

IsLegacyForm reports whether the sync block was written in the retired git/releases/docs bool form (translated on load).

func (SyncConfig) SyncsGit added in v0.8.0

func (s SyncConfig) SyncsGit() bool

SyncsGit reports whether this repo replicates git refs (branches or tags).

func (SyncConfig) SyncsReleases added in v0.8.0

func (s SyncConfig) SyncsReleases() bool

SyncsReleases reports whether this repo replicates releases.

func (*SyncConfig) UnmarshalYAML added in v0.8.0

func (s *SyncConfig) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML accepts the whole-hog scalar (sync: exact), the per-facet map, and the retired git/releases/docs bool form (translated with behavior preserved).

type SyncTopology added in v0.8.0

type SyncTopology struct {
	PrimaryID string       `json:"primary_id"`
	Mirrors   []MirrorSync `json:"mirrors,omitempty"`
}

SyncTopology is the replication topology: the primary source and each mirror's per-facet sync summary. It recovers the one-glance scannability that per-repo sync placement trades away (the resolved-view precedent).

func BuildSyncTopology added in v0.8.0

func BuildSyncTopology(cfg *Config) SyncTopology

BuildSyncTopology derives the replication topology from the resolved config.

type TagConfig added in v0.5.0

type TagConfig struct {
	Preset   string      `yaml:"preset,omitempty"`
	Defaults TagDefaults `yaml:"defaults"`
	Message  TagMessage  `yaml:"message"`

	// Render controls tag change-log rendering (default DefaultTagPresentation; a
	// partial render: block overlays those defaults).
	Render TagPresentation `yaml:"render,omitempty"`
}

TagConfig holds workflow defaults for the tag planner.

func DefaultTagConfig added in v0.5.0

func DefaultTagConfig() TagConfig

DefaultTagConfig returns sensible defaults.

type TagDefaults added in v0.5.0

type TagDefaults struct {
	Target          string `yaml:"target"`           // default ref to tag (default: HEAD)
	Preview         bool   `yaml:"preview"`          // show preview before creating
	RequireApproval bool   `yaml:"require_approval"` // require interactive approval
	Push            bool   `yaml:"push"`             // push after creation
}

TagDefaults controls default tag planning behavior.

type TagMessage added in v0.5.0

type TagMessage struct {
	Mode          string `yaml:"mode"`           // auto | prompt_if_missing | require_manual
	EmptyStrategy string `yaml:"empty_strategy"` // prompt | fail | allow_empty
}

TagMessage controls tag annotation message behavior.

type TagPresentation added in v0.5.0

type TagPresentation struct {
	MaxEntries                int    `yaml:"max_entries"`
	GroupByType               bool   `yaml:"group_by_type"`
	Style                     string `yaml:"style"` // concise | explanatory | technical
	IncludeReleaseVisibleOnly bool   `yaml:"include_release_visible_only"`
	CollapseSimilar           bool   `yaml:"collapse_similar"`
}

TagPresentation controls tag annotation rendering (tagging.render).

func DefaultTagPresentation added in v0.8.0

func DefaultTagPresentation() TagPresentation

DefaultTagPresentation is the default tagging.render policy.

type TagSourceConfig added in v0.6.0

type TagSourceConfig struct {
	// ID is the unique identifier (e.g. "stable", "prerelease").
	// Referenced by branch_builds[].base_from and target.when.git_tags.
	ID string `yaml:"id"`

	// Pattern is the regex that identifies tags belonging to this source.
	// e.g., "^v?\\d+\\.\\d+\\.\\d+$"
	Pattern string `yaml:"pattern"`
}

TagSourceConfig is a named tag pattern used for version lineage candidates.

type TargetCondition

type TargetCondition struct {
	// Branches lists branch filters. Each entry is a policy name or "re:<regex>".
	// Empty = no branch filtering.
	Branches []string `yaml:"branches,omitempty"`

	// GitTags lists git tag filters. Each entry is a policy name or "re:<regex>".
	// Empty = no tag filtering.
	GitTags []string `yaml:"git_tags,omitempty"`

	// Events lists CI event type filters.
	// Supported: push, tag, release, schedule, manual, pull_request, merge_request.
	// Empty = no event filtering.
	Events []string `yaml:"events,omitempty"`

	// Forges restricts this target to specific CI forges by provider name
	// (github, gitlab, gitea, forgejo). Empty = every forge. Use it when a
	// registry is reachable/credentialed on some forges but not others — e.g. a
	// private mirror that only resolves from the self-hosted GitLab runner, or a
	// ghcr push that only makes sense on GitHub Actions.
	Forges []string `yaml:"forges,omitempty"`

	// Outcomes gates on the RUN outcome (success | failure | warning) — the
	// notification dimension of the one when: grammar ("failures, but only on
	// main" composes with branches:/events:). Empty = every outcome. Only valid
	// on notifications: a publish target's when: is evaluated for eligibility
	// BEFORE an outcome exists, so outcomes: there is a validation error.
	Outcomes []string `yaml:"outcomes,omitempty"`
}

TargetCondition defines routing conditions for a target. All non-empty fields must match (AND logic).

type TargetConfig

type TargetConfig struct {
	// ID is the unique identifier for this target (logging, status, enable/disable).
	ID string `yaml:"id"`

	// Kind is the target type. Determines which fields are valid.
	Kind string `yaml:"kind"`

	// Build references a BuildConfig.ID. Required for kind: registry.
	Build string `yaml:"build,omitempty"`

	// When specifies routing conditions for this target: a single condition-set,
	// or a list of them (OR — the target fires if ANY matches). See WhenConditions.
	When WhenConditions `yaml:"when,omitempty"`

	// RunFrom gates mutation to declared execution origins.
	// e.g. ["primary"] — only mutate when running from sources.primary.
	// Empty = no restriction (backward compat).
	RunFrom RunFromConfig `yaml:"run_from,omitempty"`

	// SelectTags enables CLI filtering via --select.
	SelectTags []string `yaml:"select_tags,omitempty"`

	// Registry references registries[].id for registry/metadata targets. Accepts
	// a single id (registry: harbor) or a list (registry: [dockerhub, ghcr, harbor]) —
	// a list fans the target across registries: expandMultiRegistryTargets splits it
	// into one single-registry target per id at load, so resolution/execution always
	// sees exactly one registry. When set, URL/Provider/Path/Credentials resolve from
	// the registry entry. Path can still be overridden on the target.
	Registry StringOrList `yaml:"registry,omitempty"`

	// SigningProfile references a signing.profiles[].id — the trust profile this
	// target signs under. Empty = the synthesized `legacy` profile (key-signing,
	// inert unless a key resolves). Reference-by-id, same pattern as Registry.
	SigningProfile string `yaml:"signing_profile,omitempty"`

	// URL is the registry/forge hostname (kind: registry, metadata, release).
	URL string `yaml:"url,omitempty"`

	// Provider is the vendor type for auth and API behavior.
	// Registry: docker, ghcr, gitlab, jfrog, harbor, quay, gitea, generic.
	// Release: github, gitlab, gitea.
	// If omitted on registry, inferred from URL.
	Provider string `yaml:"provider,omitempty"`

	// Path is the image path within the registry (kind: registry).
	Path string `yaml:"path,omitempty"`

	// Credentials is the env var prefix for authentication.
	// Resolution: try {PREFIX}_TOKEN first, else {PREFIX}_USER + {PREFIX}_PASS.
	Credentials string `yaml:"credentials,omitempty"`

	// Description is the short project description/tagline. A scalar for kind:
	// registry; kind: metadata accepts a LIST of length-tiered variants
	// (the engine picks the longest that fits each destination's cap).
	Description StringOrList `yaml:"description,omitempty"`

	// Retention controls cleanup of old tags/releases.
	// Structured only in v2 (no scalar shorthand).
	Retention *RetentionPolicy `yaml:"retention,omitempty"`

	// Tags are tag templates resolved against version info (kind: registry).
	// e.g., ["{version}", "{major}.{minor}", "latest"]
	Tags []string `yaml:"tags,omitempty"`

	// NativeScan enables post-push vulnerability scanning via the registry's own built-in scanner.
	// Distinct from StageFreight's own scan pipeline (Trivy/Grype run by StageFreight itself).
	// Currently supported: Harbor (triggers Harbor's built-in Trivy after each push).
	// No-op for Docker Hub, GHCR, Quay, JFrog, and other providers.
	// Best-effort — scan failures warn but do not fail the build.
	// Push success does not imply scan success; results appear in the registry UI only.
	NativeScan bool `yaml:"native_scan,omitempty"`

	// Readme is the long markdown 'project page' body (registries only: Docker Hub Overview,
	// Harbor Info, JFrog README, Quay Description). On a forge the README is committed → N/A.
	Readme string `yaml:"readme,omitempty"`

	// Website is the project's external site URL (forges: GitHub, Gitea/Forgejo).
	Website string `yaml:"website,omitempty"`

	// Topics are discovery tags (forges: GitHub, GitLab, Gitea). Authored freely; the engine
	// normalizes to lowercase-hyphenated per destination and warns on any transform.
	Topics []string `yaml:"topics,omitempty"`

	// synced idempotently. Org-scoped logos (GitHub, Docker Hub) are out of scope.
	Logo string `yaml:"logo,omitempty"`

	// SpecFiles lists component spec file paths (kind: gitlab-component).
	SpecFiles []string `yaml:"spec_files,omitempty"`

	// Catalog enables GitLab Catalog registration (kind: gitlab-component).
	Catalog bool `yaml:"catalog,omitempty"`

	// Notes names the stencil (a type: text body in stencils:) that composes
	// this release's notes document (kind: release). An explicit reference —
	// different targets may name different stencils. Empty = SF's shipped
	// default body.
	Notes string `yaml:"notes,omitempty"`

	// Aliases are rolling git tag aliases (kind: release).
	// e.g., ["{version}", "{major}.{minor}", "latest"]
	// Named "aliases" to avoid collision with Tags (image tags) and git_tags (policy filters).
	Aliases []string `yaml:"aliases,omitempty"`

	// SecuritySummary attaches the security summary to this release; the summary's
	// location is security.output, so this is a yes/no toggle rather than a path.
	// RegistryLinks and CatalogLinks attach the published image and catalog links.
	//
	// Per target, with Notes and Limits, because all four describe what a release
	// CONTAINS, and each channel publishes a different document: a dev release cut on
	// every push and a stable one carry different evidence. Unset omits the content.
	SecuritySummary bool `yaml:"security_summary,omitempty"`
	RegistryLinks   bool `yaml:"registry_links,omitempty"`
	CatalogLinks    bool `yaml:"catalog_links,omitempty"`

	// Limits bound the release-note facts that grow with the repo, in characters
	// (kind: release). Keyed by fact name — changes, changelog — because the body is
	// composed from facts by a stencil, so there is no fixed set of sections to name:
	// a stencil may omit a fact, reorder them, or use one twice.
	//
	// Per target because verbosity is a property of the channel, not the project: a dev
	// release cut on every push wants a terse changelog where a stable one wants the
	// whole thing. Unset uses the engine default; 0 is unbounded.
	//
	// A bound stops between entries and never inside one, and states the remainder as a
	// count — every forge caps a release body, and an over-long one is rejected outright
	// rather than trimmed.
	Limits map[string]int `yaml:"limits,omitempty"`

	// Tag is the immutable identity pattern for a release channel (kind: release).
	// Distinct from Aliases (rolling): Tag names one immutable release per build, e.g.
	// "dev-{sha:8}". Resolved against version info like Aliases ({version}, {sha:8}, ...).
	// When the triggering event is not itself a ref (a branch push), the release runner
	// mints this tag so the channel release has a stable anchor. Empty = no channel tag.
	Tag string `yaml:"tag,omitempty"`

	// Type is the semantic release classification (kind: release):
	//
	//	type: latest        — the stable, "Latest" release (GitHub: make_latest=true)
	//	type: prerelease    — a pre-release (never Latest)
	//	type: unspecified   — explicit default/auto (declarative GitOps; same as omitting)
	//
	// Omitting the field is identical to "unspecified": the type is inferred from the
	// version (a semver prerelease suffix ⇒ prerelease) and the legacy `prerelease` flag.
	// Each forge lowers the intent to what it can express (GitHub: prerelease+make_latest;
	// Gitea: prerelease; GitLab: a plain release; Azure: n/a).
	Type string `yaml:"type,omitempty"`

	// Prerelease marks the forge release as a pre-release (kind: release). DEPRECATED:
	// prefer `type: prerelease`. Still honored when `type` is unset/unspecified.
	Prerelease bool `yaml:"prerelease,omitempty"`

	// ProjectID is the "owner/repo" or numeric ID for remote forge targets (kind: release).
	ProjectID string `yaml:"project_id,omitempty"`

	// Repos names the destination repos[].id for a kind: release target. The repo
	// with role primary is the canonical release (authored via the git remote); every
	// other named repo gets an authored copy (release + assets). Forge identity for
	// each is resolved from its repos[] entry. A repo reaches releases via a target's
	// repos: XOR its sync.releases facet — never both (config-time XOR).
	Repos StringOrList `yaml:"repos,omitempty"`

	// Archives references a binary-archive target ID (kind: release and generic-package).
	Archives string `yaml:"archives,omitempty"`

	// BinaryName overrides the binary name inside the archive (kind: binary-archive).
	// Auto-detected from referenced build if omitted.
	BinaryName string `yaml:"binary_name,omitempty"`

	// Format is the archive format: "tar.gz", "zip", "auto", or "binary" (kind:
	// binary-archive). "auto" picks zip for windows, tar.gz for everything else (default).
	// "binary" is a passthrough: the build's single-file output is carried as the
	// distributable as-is, NOT re-archived — for a build whose output is already packaged
	// (e.g. a kind: command build that emits its own tarball or a raw binary you want
	// uploaded unwrapped), so no double-archiving occurs.
	Format string `yaml:"format,omitempty"`

	// Name is the archive filename template (kind: binary-archive).
	// Supports: {id}, {version}, {os}, {arch}. e.g., "{id}-{version}-{os}-{arch}".
	Name string `yaml:"name,omitempty"`

	// Include lists extra files to bundle into the archive (kind: binary-archive).
	// e.g., ["README.md", "LICENSE"]
	Include []string `yaml:"include,omitempty"`

	// Checksums generates a SHA256SUMS file alongside archives (kind: binary-archive).
	Checksums bool `yaml:"checksums,omitempty"`

	// Repo references a repos[].id (kind: generic-package). The forge identity
	// (provider, url, project, credentials) is resolved from the repo; the package
	// is published to that forge's generic package registry.
	Repo string `yaml:"repo,omitempty"`

	// Package is the generic package name (kind: generic-package).
	// Defaults to the repo project's basename if empty.
	Package string `yaml:"package,omitempty"`

	// Version is the immutable package version pattern (kind: generic-package).
	// Resolved against version info like Aliases ({version}, {sha:8}, ...), e.g.
	// "dev-{sha:8}". Published once, never overwritten. Distinct from a release Tag
	// (a git ref): this names a package *version*, not a git tag. Required — every
	// rolling Alias must have an immutable Version behind it.
	Version string `yaml:"version,omitempty"`

	// Project is the Cloudflare Pages project name (provider: cloudflare). Default:
	// the target id. Cloudflare requires lowercase letters, digits, and hyphens,
	// 1–58 chars, no leading/trailing hyphen — validated at load. Ignored by the
	// github provider (which deploys to the gh-pages branch of the repo).
	Project string `yaml:"project,omitempty"`

	// Dir publishes a repo directory directly instead of a build's output tree
	// (kind: pages). Exactly one of Build or Dir must be set.
	Dir string `yaml:"dir,omitempty"`

	// Exclude drops matching paths from the publish workspace before deploy
	// (kind: pages). Globs, applied after extraction.
	Exclude []string `yaml:"exclude,omitempty"`

	// Domain is the custom domain(s) (kind: pages). Accepts a bare scalar or a list:
	//
	//	domain: precisionplanit.com
	//	domain: [precisionplanit.com, prplanit.com]
	//
	// Cloudflare attaches every listed domain to the project (each auto-wires DNS).
	// GitHub Pages serves a single custom domain, so a list is rejected at load; the
	// one entry is written as the CNAME.
	Domain StringOrList `yaml:"domain,omitempty"`

	// BasePath is the URL path the site is served under (kind: pages). Inferred per
	// provider (Cloudflare "/", GitHub project "/<repo>/") and fed into the build.
	BasePath string `yaml:"base_path,omitempty"`

	// Versioning controls multi-version publishing (kind: pages). P1 accepts only
	// mode: replace; mode: keep is reserved for phase 2 and rejected.
	Versioning *PagesVersioning `yaml:"versioning,omitempty"`
}

TargetConfig defines a distribution target or side-effect. Each target has a unique ID and a kind that determines which fields are valid.

This is a discriminated union keyed by Kind. Only fields relevant to the kind should be set — validated at load time.

Target kinds:

  • registry: Push image tags to a container registry (requires build reference)
  • metadata: Push project identity (description/readme/website/topics/logo) to registries + forge repos
  • gitlab-component: Publish to GitLab CI component catalog (standalone)
  • release: Create forge release + rolling git tags (standalone)
  • generic-package: Publish archives to a forge generic package registry (standalone)
  • pages: Deploy a static-site build's output to Cloudflare/GitHub Pages (build XOR dir)

func (TargetConfig) FactLimit added in v0.11.0

func (t TargetConfig) FactLimit(fact string, def int) int

FactLimit returns the character bound for a release-note fact on this target, falling back to the engine default when the target declares none.

type TestConfig added in v0.7.0

type TestConfig struct {
	Preset  string            `yaml:"preset,omitempty"`
	Enabled bool              `yaml:"enabled"`
	Auto    *bool             `yaml:"auto,omitempty"` // nil ⇒ true
	Suites  OrderedTestSuites `yaml:"suites,omitempty"`
}

TestConfig is the test subsystem. Auto-on by default: when Enabled and no suites are declared, a default suite is synthesized per builder from build metadata (unless Auto is explicitly false).

func DefaultTestConfig added in v0.7.0

func DefaultTestConfig() TestConfig

DefaultTestConfig is auto-on with no declared suites (synthesis derives the default suite from the configured builds).

func (TestConfig) AutoSynthesize added in v0.7.0

func (t TestConfig) AutoSynthesize() bool

AutoSynthesize reports whether a default suite should be synthesized from build metadata when the operator declared none. Defaults to true.

type TestSuite added in v0.7.0

type TestSuite struct {
	ID      string   `yaml:"id"`
	Tool    TestTool `yaml:"tool"`
	Gate    Gate     `yaml:"gate,omitempty"` // default: perform
	From    string   `yaml:"from,omitempty"` // module/crate dir when not at repo root (e.g. dd-ui's api/)
	Args    []string `yaml:"args,omitempty"` // raw passthrough escape hatch
	Command string   `yaml:"command,omitempty"`

	// ── Go (native `go test` flag projections) ──────────────────────────────
	Packages    []string `yaml:"packages,omitempty"`     // ./p/...   (default ./...)
	Tags        []string `yaml:"tags,omitempty"`         // -tags a,b
	Run         string   `yaml:"run,omitempty"`          // -run <regex>
	Timeout     string   `yaml:"timeout,omitempty"`      // -timeout <d>
	Race        *bool    `yaml:"race,omitempty"`         // -race
	Coverage    *bool    `yaml:"coverage,omitempty"`     // -coverprofile
	CoverageMin *float64 `yaml:"coverage_min,omitempty"` // gate: fail the suite if statement coverage < this %

	// ── Rust (native `cargo test` flag projections) ─────────────────────────
	Workspace *bool    `yaml:"workspace,omitempty"` // --workspace
	Features  []string `yaml:"features,omitempty"`  // --features a,b
	Tests     []string `yaml:"tests,omitempty"`     // --test <name>
	Release   *bool    `yaml:"release,omitempty"`   // --release
	Nextest   *bool    `yaml:"nextest,omitempty"`   // cargo nextest run

	// ── Python (native `pytest` flag projections) ───────────────────────────
	// Selection reuses the shared fields whose meaning is identical across
	// dialects: Packages → positional test paths, Run → -k <expr> (pytest's
	// keyword filter, the analogue of go's -run), Coverage/CoverageMin → --cov.
	Markers []string `yaml:"markers,omitempty"` // -m <marker>
}

TestSuite is one behavioral-verification suite. Typed fields are declarative projections of the native flag a developer already types (`-race`, `-tags`, `--workspace`, `--features`), so the YAML reads as the command. Fields are type-specific — Go and Rust have different selection spaces and are NOT forced through one shared vocabulary. `Args` is the explicit, intentionally-unsafe escape hatch (bypasses the typed guarantees); `Command` (with `type: script`) replaces the runner entirely.

func (TestSuite) EffectiveGate added in v0.7.0

func (s TestSuite) EffectiveGate() Gate

EffectiveGate returns the suite's gate, defaulting to perform (the strict, zero-wiring tier) when unset.

type TestTool added in v0.7.0

type TestTool string

TestTool is the test toolchain/dialect a suite uses — how its command is constructed, NOT where it runs (it is not a CI "runner"). `go`/`rust`/`python` are first-class typed (native-flag projection + builder-derived defaults); `script` is the intentionally-less-structured raw escape hatch. Future: `container`, `compose`.

const (
	TestToolGo     TestTool = "go"
	TestToolRust   TestTool = "rust"
	TestToolPython TestTool = "python"
	TestToolScript TestTool = "script"
)

type ToolConstraint added in v0.7.0

type ToolConstraint struct {
	Constraint string `yaml:"version,omitempty"`
}

ToolConstraint declares the acceptable version(s) for a single tool. The YAML key is `version` — the Cargo/Go convention — and its VALUE is a version requirement, not necessarily one exact version: "1.26.4" is exact, "1.26.x" is a line. It is pure operator INTENT. The machine-maintained RESOLUTION of that intent — the concrete version a wildcard locked to, plus its artifact digest — lives in .stagefreight/toolchains.lock, NOT here: the config is the Cargo.toml, the lock is the Cargo.lock. The Go field is named Constraint because the value is a requirement (the same reason Cargo models a `version` field as a VersionReq), even though the surface key is `version`.

func (*ToolConstraint) UnmarshalYAML added in v0.7.0

func (t *ToolConstraint) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML accepts two input forms and normalizes them to the internal Constraint — it answers only "what did the user write", performing no semantic validation:

go: 1.26.x               # scalar shorthand
go: {version: 1.26.x}    # explicit

type ToolchainConfig added in v0.6.0

type ToolchainConfig map[string]ToolConstraint

ToolchainConfig is the want: map inside the toolchains section (tool name → desired version constraint).

func (*ToolchainConfig) UnmarshalYAML added in v0.7.0

func (c *ToolchainConfig) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML decodes the tool→constraint mapping directly, naming the offending tool on a parse error. The tools block IS the map — the retired `desired:` wrapper is gone (a legacy `desired: …` key parses as a tool with no version and fails validation).

type ToolchainSection added in v0.10.0

type ToolchainSection struct {
	// Want is the tool→constraint map — the versions the operator WANTS (constraints, not
	// necessarily exact pins); the lock records what resolution GOT. Mirrors the internal
	// ToolchainDesired vocabulary. Authoritative, not a hint: a constraint that
	// fails to resolve fails the run, no fallback. Top-level in .stagefreight.yml
	// because toolchains are execution substrate (security scanning, signing, linting,
	// gitops), not CI-specific.
	Want ToolchainConfig `yaml:"want,omitempty"`

	// Retention governs how many resolved versions of each tool are RETAINED on the
	// runner (keep_last newest per tool; unset = engine default 2). The pinned
	// constraint's resolved version and the lock's resolution are always protected —
	// retention rotates superseded residue, never declared intent.
	Retention RetentionPolicy `yaml:"retention,omitempty"`
}

ToolchainSection is the toolchains: block — a wrapper pairing the tool→constraint map (want:) with the versions' lifecycle policy (retention:), following the keyed-map-plus-sibling-policy pattern (scribe: files+commit, governance: profiles). The map moved under want: in the wrapper flag-day: retention is POLICY about the installed versions, not a tool, so it must not live inside the tool namespace.

func (*ToolchainSection) UnmarshalYAML added in v0.10.0

func (s *ToolchainSection) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML decodes the toolchains section — the wrapper shape ONLY (clean-break flag-day, no legacy acceptance). The retired flat tool→constraint shape fails with a targeted migration hint naming the offending key, never a bare unknown-field error.

type TrailerFilter added in v0.5.0

type TrailerFilter struct {
	StripKeys []string `yaml:"strip_keys,omitempty"`
}

TrailerFilter strips commit trailers/footers.

type VolumeProtection added in v0.5.0

type VolumeProtection struct {
	Named *bool `yaml:"named,omitempty"` // protect all named volumes
}

VolumeProtection defines which volumes are protected from pruning.

type WatchRule

type WatchRule struct {
	Paths       []string `yaml:"paths"`
	Invalidates []string `yaml:"invalidates"`
}

WatchRule defines a cache-busting rule.

type WhenConditions added in v0.8.0

type WhenConditions []TargetCondition

WhenConditions is a target's routing gate: one condition-set, or a list of them combined with OR — the target fires if ANY condition matches. It accepts either a single condition map (when: { ... }) or a sequence of them (when: [ {...}, {...} ]). An empty/absent when: is unconditional (eligible in every context).

All when: interpretation flows through TargetEligibility (target_match.go); this type only models the shape.

func (*WhenConditions) UnmarshalYAML added in v0.8.0

func (w *WhenConditions) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML accepts a single condition map OR a sequence of condition maps.

type WorktreeOutput added in v0.7.0

type WorktreeOutput struct {
	BuildID string
	Output  OutputSpec
}

WorktreeOutput pairs a build with one of its outputs that lands in the working tree.

type WorktreeSpec added in v0.7.0

type WorktreeSpec struct {
	Set  bool   // whether worktree was present and truthy
	Path string // explicit landing path; empty means "land at the output's Source"
}

WorktreeSpec is an output's optional landing into the git working tree during Narrate. It accepts a bool or a path: `worktree: true` lands the output at its Source path; `worktree: <path>` lands it there instead (a clean rename); `worktree: false` / absent leaves it as a pure artifact. The runner materializes every landed output at the start of Narrate — before badges/patches/commit — so downstream config deals only in paths.

func (WorktreeSpec) MarshalYAML added in v0.7.0

func (w WorktreeSpec) MarshalYAML() (interface{}, error)

MarshalYAML renders back to the scalar form (`true`/`false` or the path) so `config render` stays clean.

func (*WorktreeSpec) UnmarshalYAML added in v0.7.0

func (w *WorktreeSpec) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML accepts either a bool (`true`/`false`) or a path string.

Jump to

Keyboard shortcuts

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