governance

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Apr 4, 2026 License: AGPL-3.0, AGPL-3.0-only Imports: 11 Imported by: 0

Documentation

Overview

Package governance implements the StageFreight governance engine: preset resolution, two-file config merge, governance reconciliation, capability detection, and execution gating.

Index

Constants

This section is empty.

Variables

View Source
var CanonicalKeyOrder = []string{
	"version",
	"vars",
	"sources",
	"policies",
	"builds",
	"targets",
	"badges",
	"narrator",
	"lint",
	"security",
	"dependency",
	"docs",
	"commit",
	"release",
	"lifecycle",
	"gitops",
	"docker",
	"glossary",
	"presentation",
	"tag",
	"manifest",
}

CanonicalKeyOrder defines the fixed top-level key order for rendered YAML. Prevents noisy diffs and unstable commits.

Functions

func DeepMerge

func DeepMerge(base, override map[string]any) map[string]any

DeepMerge merges two maps. Override (second arg) wins on conflict. Objects: deep merge. Scalars: override replaces. Lists: override replaces.

func ExplainTrace

func ExplainTrace(trace MergeTrace) string

ExplainTrace returns a detailed per-entry trace for debugging.

func FetchFile

func FetchFile(repoURL, ref, path string) ([]byte, error)

FetchFile fetches a single file from a git repo at a specific ref. Used as the AssetFetcher for governance distribution.

func LoadGovernance

func LoadGovernance(source GovernanceSource) (*GovernanceConfig, PresetLoader, error)

LoadGovernance loads governance config and returns a preset loader. When source.LocalPath is set (CI mode), uses the local checkout directly. Otherwise, fetches the policy repo at the pinned ref. Ref must be pinned (tag or commit SHA) unless AllowFloating is true.

func RenderEffective

func RenderEffective(config map[string]any) ([]byte, error)

RenderEffective returns config as YAML with canonical key ordering. Used by `config render` for display.

func RenderGated

func RenderGated(plan ExecutionPlan) string

RenderGated returns the execution plan as human-readable output (after gating).

func RenderPlanView

func RenderPlanView(w io.Writer, data PlanViewData)

RenderPlanView writes the structured plan view to w.

func RenderSealedConfig

func RenderSealedConfig(seal SealMeta, config map[string]any) ([]byte, error)

RenderSealedConfig produces a sealed .stagefreight.yml for a satellite repo. The seal is a human-facing warning header with provenance — not governance state. Uses canonical key ordering for deterministic, diff-stable output.

func ValidatePreset

func ValidatePreset(content []byte) (string, map[string]any, error)

ValidatePreset checks that a preset file declares exactly one top-level key. Returns hard error on violation.

func ValidateRef

func ValidateRef(ref string, allowFloating bool) error

ValidateRef checks pinning rules. Pinned tag or commit SHA: always allowed. Branch ref: only if allowFloating is true. Empty: hard error.

Types

type AssetFetcher

type AssetFetcher func(repoURL, ref, path string) ([]byte, error)

AssetFetcher fetches a file from a repo at a specific ref.

type CapabilityResult

type CapabilityResult struct {
	Domain     string // e.g., "build.docker", "build.binary", "package.helm"
	Detected   bool
	Confidence string   // "high", "medium", "low"
	Evidence   []string // filesystem signals that supported detection
}

CapabilityResult records whether a specific capability was detected.

type Cluster

type Cluster struct {
	ID      string         `yaml:"id"`
	Targets ClusterTargets `yaml:"targets"`
	Config  map[string]any `yaml:"stagefreight"` // raw StageFreight config
}

Cluster assigns lifecycle doctrine to a group of repos. The StageFreight block is normal StageFreight config — same grammar. Assets (CI skeletons, settings files, etc.) are declared inside the stagefreight config as assets: entries — no separate skeleton construct.

type ClusterTargets

type ClusterTargets struct {
	Repos  []string      `yaml:"repos,omitempty"`  // shorthand: flat list, inherited forge
	Groups []TargetGroup `yaml:"groups,omitempty"` // explicit: per-group forge identity
}

ClusterTargets identifies which repos belong to this cluster. Two forms:

  • Flat: targets.repos (string list, inherits governance sources.primary forge)
  • Grouped: targets.groups (each group declares its own forge source)

func (ClusterTargets) AllRepos

func (ct ClusterTargets) AllRepos() []ResolvedRepo

AllRepos flattens both forms into a unified list for iteration. Flat repos get empty ForgeURL (inherit from governance sources.primary). Group repos get the group's declared forge URL.

func (ClusterTargets) ValidateTargets

func (ct ClusterTargets) ValidateTargets() error

ValidateTargets checks that group forge URLs are base URLs only (no path). Prevents ambiguity between forge base URL and full repo URL.

type CommitResult

type CommitResult struct {
	Repo    string
	Status  string // "committed", "unchanged", "dry-run", "skipped-identical", "error"
	SHA     string // commit SHA if committed
	Message string
	Drifted bool // true if managed file was drifted before replacement
	Error   error
}

CommitResult records what happened for each repo during distribution.

func CommitDistribution

func CommitDistribution(plans []DistributionPlan, forge ForgeClient, sourceIdentity, sourceRef string, dryRun bool) ([]CommitResult, error)

CommitDistribution executes distribution plans by committing to target repos. Per-repo failure does NOT stop the run. Aggregates results. Idempotent: skips repos where all files are unchanged. Returns error if ANY repo failed.

type DetectionReport

type DetectionReport struct {
	Capabilities []CapabilityResult
}

DetectionReport is the output of capability discovery.

func DetectCapabilities

func DetectCapabilities(repoRoot string) DetectionReport

DetectCapabilities scans the repo filesystem for evidence of each capability domain. Independent per capability. No global winner. No config mutation.

type DistributedFile

type DistributedFile struct {
	Path    string // e.g., ".stagefreight/stagefreight-managed.yml"
	Content []byte
	Action  string // "create", "replace", "unchanged", "delete"
	Drifted bool   // true if existing file differs from governance intent
}

DistributedFile is a single file to write/update in a target repo.

type DistributionPlan

type DistributionPlan struct {
	Repo  string // "org/repo"
	Files []DistributedFile
}

DistributionPlan describes what files to write to a target repo.

func PlanDistribution

func PlanDistribution(
	gov *GovernanceConfig,
	presetLoader PresetLoader,
	assetFetcher AssetFetcher,
	forgeReader ForgeReader,
	presetSource PresetSourceInfo,
	sourceIdentity string,
) ([]DistributionPlan, error)

func (DistributionPlan) HasChanges

func (p DistributionPlan) HasChanges() bool

HasChanges returns true if this plan has any files that need writing.

type EnabledFeature

type EnabledFeature struct {
	Domain string
	Reason string // "config enabled + capability detected"
}

EnabledFeature is a feature that passed both config and capability gates.

type ExecutionPlan

type ExecutionPlan struct {
	Enabled []EnabledFeature
	Skipped []SkippedFeature
}

ExecutionPlan is the gated output — what will actually run. Produced by GateExecution. Does NOT modify config.

func GateExecution

func GateExecution(config map[string]any, detection DetectionReport) ExecutionPlan

GateExecution combines merged config + detected capabilities into a runnable plan. Does NOT modify config. Produces ExecutionPlan only.

type FileCommit

type FileCommit struct {
	Path    string
	Content []byte
	Action  string // "create", "update"
}

FileCommit is a single file change within a commit.

type ForgeClient

type ForgeClient interface {
	ForgeReader

	// CommitFiles commits multiple file changes to a repo's default branch.
	// Returns commit SHA on success.
	CommitFiles(repo, branch, message string, files []FileCommit) (string, error)

	// DefaultBranch returns the default branch name for a repo.
	DefaultBranch(repo string) (string, error)
}

ForgeClient abstracts forge API for file commits. Extends ForgeReader with write capability.

type ForgeReader

type ForgeReader interface {
	GetFileContent(repo, path, ref string) ([]byte, error)
}

ForgeReader reads current file content from a remote repo. Used to detect drift and determine create vs update actions.

type GovernanceConfig

type GovernanceConfig struct {
	Clusters []Cluster `yaml:"clusters"`
}

GovernanceConfig is the parsed clusters.yml from the policy repo.

type GovernanceSource

type GovernanceSource struct {
	RepoURL       string `yaml:"repo_url"`       // policy repo URL
	Ref           string `yaml:"ref"`            // pinned tag or commit SHA (required)
	Path          string `yaml:"path"`           // path to governance config within repo
	AllowFloating bool   `yaml:"allow_floating"` // if true, branch refs allowed (dev/unsafe)
	LocalPath     string `yaml:"-"`              // if set, use local checkout instead of cloning
}

GovernanceSource declares where governance inputs come from. Declared in .stagefreight.yml under governance.source.

type MergeEntry

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

func ResolvePresets(raw map[string]any, loader PresetLoader, sourceRef, sourcePath string, depth int, seen map[string]bool) (map[string]any, []MergeEntry, error)

ResolvePresets walks a config map, finds all preset: references, loads the preset files, validates the single-key invariant, and merges. Recursive: presets may reference other presets (depth-first resolution). sourceRef is the repo identity (e.g., "PrPlanIT/MaintenancePolicy@v1.0.0"). sourcePath is the current file being processed (e.g., "preset/docker-targets.yml"). Returns the resolved config + provenance entries.

type MergeTrace

type MergeTrace struct {
	Entries []MergeEntry
}

MergeTrace records how each config value was resolved.

type PlanViewConfig

type PlanViewConfig struct {
	Mode    string // "dry-run" or "apply"
	Source  string // e.g. "PrPlanIT/MaintenancePolicy"
	Ref     string // e.g. "dba5d2a" or "v1.0.0"
	Verbose bool   // expand preset-cache files individually
}

PlanViewConfig controls what the plan view renders.

type PlanViewData

type PlanViewData struct {
	Config   PlanViewConfig
	Clusters []Cluster
	Plans    map[string]DistributionPlan // keyed by repo
	Results  map[string]CommitResult     // keyed by repo (nil for dry-run)
}

PlanViewData holds everything needed to render a plan view.

type PresetLoader

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

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

type PresetRef

type PresetRef struct {
	Path string
}

PresetRef is a reference to an external preset fragment. Appears as preset: "path" within any config section.

type PresetSourceInfo

type PresetSourceInfo struct {
	Provider    string // "gitlab", "github", "gitea"
	ForgeURL    string // HTTPS base URL (e.g., "https://gitlab.prplanit.com")
	ProjectID   string // "org/repo" or "org/group/repo"
	Ref         string // pinned ref
	CachePolicy string // "authoritative" or "advisory"
}

PlanDistribution computes what files need to change for each governed repo. Pure planning — does NOT write anything. Reads current state from forge to detect drift and determine actions. PresetSourceInfo holds the forge coordinates for preset resolution. Injected into satellite .stagefreight.yml so repos can resolve presets independently.

type ResolvedPreset

type ResolvedPreset struct {
	Path        string         // source path within policy repo
	TopLevelKey string         // the single top-level key this preset declares
	Content     map[string]any // parsed YAML content under that key
}

ResolvedPreset is a loaded and validated preset fragment.

type ResolvedRepo

type ResolvedRepo struct {
	ID       string // "org/repo" project identifier on the resolved forge
	ForgeURL string // forge base URL from group, or "" (inherit from governance sources.primary)
}

ResolvedRepo is a repo with its forge context resolved.

type SealMeta

type SealMeta struct {
	SourceRepo string // e.g., "https://gitlab.prplanit.com/PrPlanIT/MaintenancePolicy"
	SourceRef  string // e.g., "v1.0.0" or commit SHA
	ClusterID  string // e.g., "docker-services"
}

SealMeta holds provenance info for the generated header.

type SkippedFeature

type SkippedFeature struct {
	Domain string
	Reason string // "capability not detected" or "config disabled"
}

SkippedFeature is a feature that was gated out.

type TargetGroup

type TargetGroup struct {
	ID      string             `yaml:"id,omitempty"`
	Sources *TargetGroupSource `yaml:"sources,omitempty"` // nil = inherit governance sources.primary
	Repos   []string           `yaml:"repos"`             // project IDs on this forge
}

TargetGroup is a cohort of repos on the same forge.

type TargetGroupPrimary

type TargetGroupPrimary struct {
	URL string `yaml:"url"` // forge base URL (e.g., "https://github.com")
}

TargetGroupPrimary holds the forge base URL for a target group.

type TargetGroupSource

type TargetGroupSource struct {
	Primary TargetGroupPrimary `yaml:"primary"`
}

TargetGroupSource declares forge identity using standard sources schema.

Jump to

Keyboard shortcuts

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