blueprint

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2026 License: MPL-2.0 Imports: 25 Imported by: 0

Documentation

Overview

Package blueprint provides blueprint loading, facet processing, composition, and writing for the Windsor CLI.

The config_block_order file orders config blocks for evaluation by their inter-block reference dependencies. The order built up by mergeFacetScopeIntoGlobal reflects facet processing order, which does not necessarily match evaluation order: a block that references another block must be evaluated after the block it references, regardless of which facet wrote which first. Topological sort of the block dependency graph produces an order where every block evaluates after the blocks it depends on.

The expr_helpers file provides shared expression AST utilities for the blueprint package. It provides parsing and walking of expr-lang expressions (${...}), dotted path extraction, and detection of derived-from-block references used for config merge semantics.

The ExplainResolver provides blueprint value provenance resolution for the windsor explain command. It resolves a dotted path against the composed blueprint and produces a trace showing the value and which facets contributed to it, enabling users to understand where values originate and how composition affected them.

The YAMLNodeResolver provides YAML AST utilities for resolving line numbers from facet files. It navigates goccy/go-yaml parsed trees to locate specific nodes by structural path (map key, named sequence item, sequence index, or entry value match), enabling precise provenance line number resolution during blueprint composition and explain.

Index

Constants

This section is empty.

Variables

View Source
var DefaultBlueprint = blueprintv1alpha1.Blueprint{
	Kind:       "Blueprint",
	ApiVersion: "blueprints.windsorcli.dev/v1alpha1",
	Metadata: blueprintv1alpha1.Metadata{
		Name:        "default",
		Description: "A default blueprint",
	},
	Sources:             []blueprintv1alpha1.Source{},
	TerraformComponents: []blueprintv1alpha1.TerraformComponent{},
	Kustomizations:      []blueprintv1alpha1.Kustomization{},
}

DefaultBlueprint provides the base blueprint structure used when no blueprint exists.

View Source
var ErrBlueprintInvalid = errors.New("invalid blueprint")

ErrBlueprintInvalid is the sentinel returned by blueprint validation when the composed blueprint violates a structural invariant. Callers use errors.Is to detect this class of failure and present the wrapped message to the operator without scary "Error:" framing — the run is rejected, but the cause is a blueprint authoring mistake the operator can fix, not an internal exception.

Functions

func EvaluateWithOrigins added in v0.9.0

func EvaluateWithOrigins(eval evaluator.ExpressionEvaluator, keyPath string, value any, origins map[string]string, scope map[string]any, evaluateDeferred bool) (any, error)

EvaluateWithOrigins evaluates a single input value using per-sub-key origin paths stored in origins (dot-separated keys such as "config.db.host"). When a direct origin exists for keyPath the entire value is evaluated against that path. When sub-key origins exist the value is walked recursively so each leaf resolves against its originating facet.

func IsDowngrade added in v0.9.0

func IsDowngrade(previousURL, targetURL string) bool

IsDowngrade reports whether targetURL pins an older stable semver than previousURL for the same OCI repository. It returns false when either URL is not a parseable OCI reference, when the two reference different repositories (a re-source is not an ordered version change), or when either tag is not a semver (a branch, mutable tag, or commit is not ordered) — in those cases a regression cannot be asserted, so the caller must not treat the change as a downgrade.

func MergeScopeMaps added in v0.9.0

func MergeScopeMaps(globalScope map[string]any, overlay map[string]any) map[string]any

MergeScopeMaps deep-merges two scope maps (e.g. from multiple loaders or scope plus context values). When the same block name exists in both, block bodies are deep-merged recursively (maps by key, lists/scalars replaced at that path). Returns a new map; does not mutate inputs.

func OrdinalFromBasename added in v0.9.0

func OrdinalFromBasename(basename string) int

OrdinalFromBasename returns the default ordinal for a facet file given only its basename (e.g. "config-cluster.yaml", "provider-base.yaml"). Used by OrdinalFromFacetPath and by tests.

func OrdinalFromFacetPath added in v0.9.0

func OrdinalFromFacetPath(path string) int

OrdinalFromFacetPath returns the default ordinal for a facet based on its file path. The basename of the path is used to match prefix rules. When the facet does not set ordinal explicitly, the loader uses this to assign a default so that facet processing order is deterministic (config first, then provider/platform base, then provider/platform, then options, then addons). Higher ordinal means higher precedence when merging. Rules: config-* 100; provider-* or platform-* with "-base" in name 199; provider-* or platform-* 200; option-* or options-* 300; addon-* or addons-* 400; no match 0.

func RenderForDisplay added in v0.9.0

func RenderForDisplay(resource any, raw bool, deferredPaths map[string]bool) any

RenderForDisplay returns a copy of resource ready for CLI output: composed-blueprint fields not meant for display (Messages, resolved separately by GenerateResolved for bootstrap/up to print) are cleared, and unless raw is true, deferred values named in deferredPaths are rewritten to a placeholder. Unsupported resource types pass through unchanged.

func ValidateComposedBlueprint added in v0.9.0

func ValidateComposedBlueprint(blueprint *blueprintv1alpha1.Blueprint) error

ValidateComposedBlueprint rejects composed blueprints whose Backend field names a component that does not exist. Nil and empty-Backend blueprints are accepted. Failures wrap ErrBlueprintInvalid.

Types

type BaseBlueprintComposer added in v0.9.0

type BaseBlueprintComposer struct {
	// contains filtered or unexported fields
}

BaseBlueprintComposer provides the default implementation of the BlueprintComposer interface.

func NewBlueprintComposer added in v0.9.0

func NewBlueprintComposer(rt *runtime.Runtime) *BaseBlueprintComposer

NewBlueprintComposer creates a new BlueprintComposer that merges multiple blueprints into one. The runtime provides access to configuration and context. Optional overrides allow setting common substitutions that will be applied to all kustomizations in the composed blueprint.

func (*BaseBlueprintComposer) Compose added in v0.9.0

func (c *BaseBlueprintComposer) Compose(loaders []BlueprintLoader, initLoaderNames []string, userBlueprintPath string, configScope map[string]any) (*blueprintv1alpha1.Blueprint, error)

Compose merges blueprints from multiple loaders into a single unified blueprint. Blueprints are merged in order: sources (in the order they appear in the user's Sources array, filtered by install:true) → user blueprint as final overlay. The actual merging of individual components and kustomizations is delegated to Blueprint.StrategicMerge. After merging, Compose ensures all source loaders' source names are present in the result's Sources array so components can resolve references (e.g. source: "core"). The "template" source is only included when the local template directory exists. Missing sources are added from the loader's blueprint or as minimal entries; for OCI loaders without a matching source entry, URL and Ref are taken from any OCI source in the loader's blueprint. When configScope is non-nil, it is used when evaluating user blueprint terraform inputs so config-block refs resolve.

func (*BaseBlueprintComposer) SetCommonSubstitutions added in v0.9.0

func (c *BaseBlueprintComposer) SetCommonSubstitutions(substitutions map[string]string)

SetCommonSubstitutions configures substitution values that will be added to all kustomizations during composition. These typically include context-wide values like cluster name, domain, or environment that should be available to every kustomization's postBuild substitution.

func (*BaseBlueprintComposer) SetExcludedFacets added in v0.9.0

func (c *BaseBlueprintComposer) SetExcludedFacets(excluded []ExcludedFacet)

SetExcludedFacets provides the facets dropped by a false when: during facet processing, so validateDependencies can attribute a dangling dependency to the excluded facet that would have provided it and name the condition that excluded it.

type BaseBlueprintHandler

type BaseBlueprintHandler struct {
	// contains filtered or unexported fields
}

BaseBlueprintHandler provides the default implementation of the BlueprintHandler interface. It orchestrates the pipeline: Load → Process → Compose → Write.

func NewBlueprintHandler

func NewBlueprintHandler(rt *runtime.Runtime, artifactBuilder artifact.Artifact, opts ...*BaseBlueprintHandler) *BaseBlueprintHandler

NewBlueprintHandler creates a new BlueprintHandler with the provided runtime and artifact builder. It initializes the internal processor, composer, and writer components with sensible defaults. Optional overrides can be passed to replace any of the internal components for testing or custom behavior. Panics if runtime or artifactBuilder are nil.

func (*BaseBlueprintHandler) Explain added in v0.9.0

func (h *BaseBlueprintHandler) Explain(pathStr string) (*ExplainTrace, error)

Explain delegates to the trace collector if set, otherwise returns an error. The handler method exists only to satisfy the BlueprintHandler interface.

func (*BaseBlueprintHandler) Generate

Generate returns the fully composed blueprint after all sources and user blueprint have been merged. This is a simple accessor method that returns the composedBlueprint field. The blueprint is already fully processed and composed by LoadBlueprint(). Input expressions and substitutions remain in their raw form and are evaluated later by their respective consumers.

func (*BaseBlueprintHandler) GenerateResolved added in v0.9.0

func (h *BaseBlueprintHandler) GenerateResolved() (*blueprintv1alpha1.Blueprint, error)

GenerateResolved returns a deep copy of the composed blueprint with deferred substitutions resolved. This is the JIT entry point for consumers that need fully evaluated values (e.g. the provisioner writing ConfigMaps to the cluster). The copy ensures the base composedBlueprint is never mutated, so subsequent Generate() or GenerateResolved() calls start from the original deferred expressions. Callers that only display the blueprint (e.g. windsor show) should use Generate() instead to preserve deferred placeholders.

Returns an error when a deferred substitution cannot be resolved (e.g. terraform_output() references a missing key, or terraform itself errors during the lookup), named by the offending substitution path (e.g. "kustomize.dns.substitutions.external_dns_tenant_id") so operators see the failure at blueprint-resolution time rather than via a downstream pod crashloop. An unresolved expression must never reach a ConfigMap: raw `${...}` source text left in place would be treated as a literal config value by downstream Helm renders.

func (*BaseBlueprintHandler) GetDeclaredSources added in v0.9.0

func (h *BaseBlueprintHandler) GetDeclaredSources() ([]blueprintv1alpha1.Source, error)

GetDeclaredSources loads only the context's blueprint.yaml (the user blueprint) and returns its declared sources, without loading remote source content or composing. It is the cheap pre-flight read upgrade uses to evaluate a --source change before pulling or composing anything, so a refused downgrade never triggers a registry round-trip. Returns an empty slice when no blueprint.yaml or no sources are declared.

func (*BaseBlueprintHandler) GetDeferredPaths added in v0.9.0

func (h *BaseBlueprintHandler) GetDeferredPaths() map[string]bool

GetDeferredPaths returns composed paths whose values were deferred during expression evaluation.

func (*BaseBlueprintHandler) GetLocalTemplateData

func (h *BaseBlueprintHandler) GetLocalTemplateData() (map[string][]byte, error)

GetLocalTemplateData returns all files collected from the template blueprint's directory. This includes blueprint.yaml, schema.yaml, features, and any other template files. The data is used by the artifact builder when pushing local templates to an OCI registry. Returns nil if no template loader exists (e.g., when loading from OCI without a local _template).

func (*BaseBlueprintHandler) GetTerraformComponents

func (h *BaseBlueprintHandler) GetTerraformComponents() []blueprintv1alpha1.TerraformComponent

GetTerraformComponents returns a copy of the composed blueprint's terraform components with Source and FullPath resolved for each component. Source names are expanded to full OCI or Git URLs based on the Sources array. Components with a Name or Source are placed in the Windsor scratch path (contexts/<context>/terraform/), while local components without a source are placed in the project's terraform directory.

func (*BaseBlueprintHandler) LoadBlueprint

func (h *BaseBlueprintHandler) LoadBlueprint(blueprintURL ...string) error

LoadBlueprint orchestrates the complete blueprint loading pipeline. It loads the user blueprint first, then loads all sources from the user's sources array (including "name: template" for local _template). Sources are loaded recursively to discover nested sources. Finally, it processes facets for all source blueprints and composes them into a single unified blueprint, applying the user blueprint as the final override layer. The blueprintURL parameter stores URLs that should be added to sources during initialization. These URLs are loaded first so their metadata names can be used.

func (*BaseBlueprintHandler) RetargetSource added in v0.9.0

func (h *BaseBlueprintHandler) RetargetSource(name, url string) (string, error)

RetargetSource repoints an already-declared source to a new tagged OCI URL and returns the source's previous URL for diff reporting. The new URL must include a version tag, validated via OCI parsing; the tag is carried in the URL (the canonical source form), so any prior ref fields are cleared. It errors when the source name is not declared, since adding or removing a source is a structural edit to blueprint.yaml rather than a retarget. RetargetSource mutates the composed blueprint in memory only; call Write to persist.

func (*BaseBlueprintHandler) SetSkipValidation added in v0.9.0

func (h *BaseBlueprintHandler) SetSkipValidation(skip bool)

SetSkipValidation toggles structural-invariant validation in LoadBlueprint. Default is false (validate). Teardown commands (destroy, down, env) call this with true so an operator with a deployed-but-misordered blueprint can still tear down or inspect — without this escape hatch, the validator would block the only commands that could resolve the situation. Write/deploy commands (init, bootstrap, up, apply, plan) leave it false so structural mistakes surface at the moment they are introduced. (show tolerates validation failure via a separate mechanism in getBlueprint that captures the error and continues, rather than skipping validation outright.) Provisioner's destroy paths iterate components independent of blueprint position (Blueprint.BackendComponentID + symmetric-destroy), so skipping validation does not produce a wrong destroy order.

func (*BaseBlueprintHandler) SetTraceCollector added in v0.9.0

func (h *BaseBlueprintHandler) SetTraceCollector(tc TraceCollector)

SetTraceCollector enables opt-in trace collection for the explain command. When set, the collector is propagated to the processor at the start of composition so expression scope references and nested paths are recorded during facet processing. Pass nil to disable.

func (*BaseBlueprintHandler) UpgradeSourcesToLatest added in v0.9.0

func (h *BaseBlueprintHandler) UpgradeSourcesToLatest() ([]SourceUpgrade, error)

UpgradeSourcesToLatest moves each remote OCI source pinned to a semver to the highest stable tag this CLI is compatible with (see artifact.ResolveCompatibleTag), mutating the composed blueprint in memory (call Write to persist) and returning the changes for reporting. Sources that are not OCI, not semver-pinned, or already at the latest compatible tag are left untouched. All tags are resolved before any source is mutated, so a registry failure mid-resolution leaves the in-memory blueprint untouched.

func (*BaseBlueprintHandler) Write

func (h *BaseBlueprintHandler) Write(overwrite ...bool) error

Write persists the blueprint to blueprint.yaml in the config root directory. It always writes the referential form (metadata, repository, sources only). If overwrite is true, an existing file is replaced; if false or omitted, the file is only written if it does not already exist, preserving user modifications.

type BaseBlueprintLoader added in v0.9.0

type BaseBlueprintLoader struct {
	// contains filtered or unexported fields
}

BaseBlueprintLoader provides the default implementation of the BlueprintLoader interface.

func NewBlueprintLoader added in v0.9.0

func NewBlueprintLoader(rt *runtime.Runtime, artifactBuilder artifact.Artifact) *BaseBlueprintLoader

NewBlueprintLoader creates a new BlueprintLoader. The sourceName and sourceURL are provided when calling Load(), not during construction. The artifactBuilder is required for OCI sources but may be nil for local sources.

func (*BaseBlueprintLoader) GetBlueprint added in v0.9.0

func (l *BaseBlueprintLoader) GetBlueprint() *blueprintv1alpha1.Blueprint

GetBlueprint returns the loaded blueprint, which may be nil if loading failed or the source does not contain a blueprint. The blueprint is modified during facet processing as components from evaluated facets are appended to it.

func (*BaseBlueprintLoader) GetBlueprintPath added in v0.9.0

func (l *BaseBlueprintLoader) GetBlueprintPath() string

GetBlueprintPath returns the absolute path to the main blueprint file (e.g. blueprint.yaml) for this source. For the user blueprint this is the config root blueprint; for template/OCI sources it is empty. Used when resolving relative paths in expressions (e.g. yaml(), file()).

func (*BaseBlueprintLoader) GetFacets added in v0.9.0

func (l *BaseBlueprintLoader) GetFacets() []blueprintv1alpha1.Facet

GetFacets returns all Facet definitions loaded from this source's facets directory. Facets are YAML files in the facets/ subdirectory that define conditional terraform components and kustomizations. Returns an empty slice if no facets were found.

func (*BaseBlueprintLoader) GetSourceName added in v0.9.0

func (l *BaseBlueprintLoader) GetSourceName() string

GetSourceName returns the identifier for this loader, used in error messages and to track which source a blueprint came from during composition. Common values are "primary", "user", or the name specified in a blueprint's sources array.

func (*BaseBlueprintLoader) GetTemplateData added in v0.9.0

func (l *BaseBlueprintLoader) GetTemplateData() map[string][]byte

GetTemplateData returns a map of relative file paths to their contents for all files collected from this source. This data is used when building OCI artifacts from local templates, allowing the complete template to be pushed to a registry.

func (*BaseBlueprintLoader) Load added in v0.9.0

func (l *BaseBlueprintLoader) Load(sourceName, sourceURL string) error

Load loads the blueprint from the specified source. The sourceName identifies this loader (e.g., "user", "template", or a source name from the sources array). The sourceURL specifies an OCI artifact URL to pull; if empty, the loader will use local filesystem paths based on sourceName. For "user", it loads from config root. For other names, it loads from _template.

type BaseBlueprintProcessor added in v0.9.0

type BaseBlueprintProcessor struct {
	// contains filtered or unexported fields
}

BaseBlueprintProcessor provides the default implementation of the BlueprintProcessor interface.

func NewBlueprintProcessor added in v0.9.0

func NewBlueprintProcessor(rt *runtime.Runtime) *BaseBlueprintProcessor

NewBlueprintProcessor creates a new BlueprintProcessor using the runtime's expression evaluator. The evaluator is used to evaluate 'when' conditions on facets and components. Optional overrides allow replacing the evaluator for testing. The processor is stateless and can be shared across multiple concurrent facet processing operations. The evaluator must be provided either via the runtime or as an override.

func (*BaseBlueprintProcessor) GetDeferredPaths added in v0.9.0

func (p *BaseBlueprintProcessor) GetDeferredPaths() map[string]bool

GetDeferredPaths returns a copy of deferred composed paths discovered during the last ProcessFacets call.

func (*BaseBlueprintProcessor) GetExcludedFacets added in v0.9.0

func (p *BaseBlueprintProcessor) GetExcludedFacets() []ExcludedFacet

GetExcludedFacets returns a copy of the facets excluded by a false when: across every ProcessFacets call since the last reset. Read after the per-source passes complete so the set is stable.

func (*BaseBlueprintProcessor) ProcessFacets added in v0.9.0

func (p *BaseBlueprintProcessor) ProcessFacets(target *blueprintv1alpha1.Blueprint, facets []blueprintv1alpha1.Facet, sourceName ...string) (map[string]any, error)

ProcessFacets iterates facets, evaluating each facet's 'when' against config data. Facets with true (or unset) conditions contribute their terraform components, kustomizations, and config blocks to target. Components in facets may have 'when' for granular control. Facets are sorted by ordinal (asc), then by metadata.name (tiebreak). Higher ordinal means higher precedence when merging. Config blocks, terraform components, and kustomizations are merged by ordinal (higher wins), then by strategy precedence (remove > replace > merge) when ordinals match. Config block expressions are evaluated once per round after all same-name blocks are merged, so expressions see the final merged value for each block. If sourceName is set, it updates Source on components lacking it. The target blueprint is modified in place. Returns: evaluated config scope and block order for the loader. Runtime ConfigHandler context values are merged over facet-derived scope so 'when' or component expressions use the actual config. An active facet contributes its config blocks (not its components) even while its requires are unmet, so facets with mutually dependent config and requires resolve across rounds; a facet still unsatisfied when the loop settles fails composition, so a permanently-blocked facet never leaks config into a successful blueprint.

func (*BaseBlueprintProcessor) ProcessGlobally added in v0.9.0

func (p *BaseBlueprintProcessor) ProcessGlobally(sources []SourceFacetSet) (map[string]any, error)

ProcessGlobally resolves config and facet inclusion once across every source's facets, then emits each source's included components into its own target blueprint. Facets are ranked by a depth-adjusted ordinal so a deeper source's config wins over a shallower one's for the same key, while derivations resolve against the final merged scope and an upstream facet's when: sees a downstream source's config. Returns the resolved global scope.

func (*BaseBlueprintProcessor) ResetExcludedFacets added in v0.9.0

func (p *BaseBlueprintProcessor) ResetExcludedFacets()

ResetExcludedFacets clears the accumulated excluded-facet record. Callers invoke it once before a composition's per-source ProcessFacets pass, so the set reflects only that composition. ProcessFacets appends across sources rather than resetting, letting a multi-source compose accumulate one set.

func (*BaseBlueprintProcessor) SetExtraScope added in v0.9.0

func (p *BaseBlueprintProcessor) SetExtraScope(scope map[string]any)

SetExtraScope sets additional scope values that are merged over context values during facet processing.

func (*BaseBlueprintProcessor) SetTraceCollector added in v0.9.0

func (p *BaseBlueprintProcessor) SetTraceCollector(tc TraceCollector)

SetTraceCollector sets the trace collector for recording per-key contributions and config blocks during composition. When non-nil, all contributions are recorded into the collector. Set to nil to disable trace collection.

type BaseBlueprintWriter added in v0.9.0

type BaseBlueprintWriter struct {
	// contains filtered or unexported fields
}

BaseBlueprintWriter provides the default implementation of the BlueprintWriter interface.

func NewBlueprintWriter added in v0.9.0

func NewBlueprintWriter(rt *runtime.Runtime) *BaseBlueprintWriter

NewBlueprintWriter creates a new BlueprintWriter that persists blueprints to the filesystem. The runtime provides the config root path where blueprint.yaml will be written. Optional overrides allow replacing the shims for testing file system operations.

func (*BaseBlueprintWriter) Write added in v0.9.0

func (w *BaseBlueprintWriter) Write(blueprint *blueprintv1alpha1.Blueprint, overwrite bool, initBlueprintURLs ...string) error

Write serializes the blueprint to YAML and saves it to blueprint.yaml in the config root. It always writes the referential form: metadata, repository, and sources only (no terraform/kustomize expansion). Components come from referenced blueprint sources; run "windsor show blueprint" to see the fully rendered blueprint. If overwrite is false and the file exists, the write is skipped to preserve user modifications. The initBlueprintURLs parameter contains blueprint URLs to add as sources when initializing.

type BlueprintComposer added in v0.9.0

type BlueprintComposer interface {
	Compose(loaders []BlueprintLoader, initLoaderNames []string, userBlueprintPath string, configScope map[string]any) (*blueprintv1alpha1.Blueprint, error)
}

BlueprintComposer combines processed blueprints from multiple loaders into a final composed blueprint. It applies the composition algorithm: Sources (in order) → Template (if not in sources) → User overlay.

type BlueprintHandler

type BlueprintHandler interface {
	LoadBlueprint(blueprintURL ...string) error
	SetSkipValidation(skip bool)
	Write(overwrite ...bool) error
	RetargetSource(name, url string) (string, error)
	UpgradeSourcesToLatest() ([]SourceUpgrade, error)
	GetDeclaredSources() ([]blueprintv1alpha1.Source, error)
	GetTerraformComponents() []blueprintv1alpha1.TerraformComponent
	GetLocalTemplateData() (map[string][]byte, error)
	Generate() *blueprintv1alpha1.Blueprint
	GenerateResolved() (*blueprintv1alpha1.Blueprint, error)
	Explain(path string) (*ExplainTrace, error)
	GetDeferredPaths() map[string]bool
}

BlueprintHandler manages the lifecycle of infrastructure blueprints. It orchestrates loading, processing, composing, and writing blueprints.

type BlueprintLoader added in v0.9.0

type BlueprintLoader interface {
	Load(sourceName, sourceURL string) error
	GetBlueprint() *blueprintv1alpha1.Blueprint
	GetFacets() []blueprintv1alpha1.Facet
	GetTemplateData() map[string][]byte
	GetSourceName() string
}

BlueprintLoader holds individual blueprint state in-memory through the processing lifecycle. One BlueprintLoader is created per blueprint source (primary, each OCI source, user).

type BlueprintProcessor added in v0.9.0

type BlueprintProcessor interface {
	ProcessFacets(target *blueprintv1alpha1.Blueprint, facets []blueprintv1alpha1.Facet, sourceName ...string) (scope map[string]any, err error)
	ProcessGlobally(sources []SourceFacetSet) (map[string]any, error)
}

BlueprintProcessor evaluates when: conditions on facets, terraform components, and kustomizations. It determines inclusion/exclusion based on boolean condition results. The processor is stateless and shared across all loaders. ProcessFacets returns the evaluated config scope for the loader so callers can merge scopes from multiple loaders (e.g. for user overlay and final terraform input evaluation).

type BlueprintWriter added in v0.9.0

type BlueprintWriter interface {
	Write(blueprint *blueprintv1alpha1.Blueprint, overwrite bool, initBlueprintURLs ...string) error
}

BlueprintWriter writes the final composed blueprint to contexts/<context>/blueprint.yaml.

type ConfigBlockRecord added in v0.9.0

type ConfigBlockRecord struct {
	FacetPath   string
	Line        int
	RawValue    any
	ScopeRefs   []string
	NestedPaths []string
	NestedRefs  map[string][]string
}

ConfigBlockRecord records a config block value for scope reference resolution. ScopeRefs and NestedPaths are pre-extracted during recording so query-time AST parsing is not needed. NestedRefs maps each nested expression path to its pre-extracted scope variable references.

type CrdInstallLayer added in v0.9.0

type CrdInstallLayer struct {
	Source string
	Refs   []string
}

CrdInstallLayer is a CRD kustomization the provisioner will synthesize: a source (empty for the default/project source) and the references it owns. Derived from the composed blueprint by CrdLayers.

func CrdLayers added in v0.9.0

CrdLayers returns the CRD kustomization layers a composed blueprint implies: the default/project layer (empty source) from bp.Crds, then one per install source that vendors CRDs, alphabetically by name. The composer wires the stack to these names and the provisioner materializes them, so both must agree on the set — they share this single derivation.

type DefaultTraceCollector added in v0.9.0

type DefaultTraceCollector struct {
	// contains filtered or unexported fields
}

DefaultTraceCollector is the standard TraceCollector implementation backed by in-memory maps. Contributions and config blocks are recorded during composition (Phase 1). After composition, Finalize stores the composed blueprint, scope, and template root. GetTrace performs lazy resolution on demand.

func NewTraceCollector added in v0.9.0

func NewTraceCollector() *DefaultTraceCollector

NewTraceCollector creates a new DefaultTraceCollector with initialized storage.

func (*DefaultTraceCollector) Finalize added in v0.9.0

func (c *DefaultTraceCollector) Finalize(bp *blueprintv1alpha1.Blueprint, scope map[string]any, templateRoot string)

Finalize stores the composed blueprint, scope, and template root for lazy trace resolution. Called once after all facet processing and scope merging completes.

func (*DefaultTraceCollector) GetTrace added in v0.9.0

func (c *DefaultTraceCollector) GetTrace(pathStr string) (*ExplainTrace, error)

GetTrace resolves a dotted blueprint path and returns a trace with the composed value, contributions sorted by ordinal, effective marking, and scope reference resolution.

func (*DefaultTraceCollector) RecordConfigBlock added in v0.9.0

func (c *DefaultTraceCollector) RecordConfigBlock(configPath string, record ConfigBlockRecord)

RecordConfigBlock stores a config block value and pre-extracts scope references, nested expression paths, and per-path refs from the raw value. No child entries are created; getConfigBlockWithRecord's fallback logic resolves lines via YAML AST. Thread-safe.

func (*DefaultTraceCollector) RecordContribution added in v0.9.0

func (c *DefaultTraceCollector) RecordContribution(composedPath string, tc TraceContribution)

RecordContribution stores a per-key contribution from a facet and pre-extracts scope references from the raw value expression. Called from the processor during composition for each terraform input, kustomize substitution, and kustomize components list. Thread-safe.

type ExcludedFacet added in v0.9.0

type ExcludedFacet struct {
	Name     string   // facet metadata name
	When     string   // the when: expression that evaluated false
	Provides []string // terraform component IDs and kustomization names (including flux tiers) it declares
}

ExcludedFacet records a facet dropped from composition by a false when: condition, along with the component and kustomization names it would have contributed. Dependency validation joins a dangling dependency name against these so it can name the excluded facet and the condition that excluded it, rather than only reporting the unresolvable edge.

type ExplainContribution added in v0.9.0

type ExplainContribution struct {
	SourceName    string
	FacetPath     string
	AbsFacetPath  string
	Line          int
	Ordinal       int
	Strategy      string
	Expression    string
	HasValue      bool
	Effective     bool
	ScopeRefs     []ExplainScopeRef
	RawComponents []string
	// contains filtered or unexported fields
}

ExplainContribution describes one source that contributed to the value (facet file, source name, etc.). AbsFacetPath is the absolute filesystem path for clickable terminal references; FacetPath is the shortened display form. Line is the 1-based line number of the specific key (or the component definition if the key is not locatable). Effective is true when this contribution produced the final composed value; false means it was overridden by a higher-ordinal facet.

type ExplainPath added in v0.9.0

type ExplainPath struct {
	Kind    ExplainPathKind
	Segment string
	Key     string
}

ExplainPath is a parsed explain path identifying a single value in the composed blueprint.

func ParseExplainPath added in v0.9.0

func ParseExplainPath(path string) (ExplainPath, error)

ParseExplainPath parses a path string into an ExplainPath. Supported forms:

  • terraform.<componentID>.inputs.<key>
  • kustomize.<name>.substitutions.<key>
  • configMaps.<name>.<key>

Returns an error if the path is malformed or empty.

func (ExplainPath) String added in v0.9.0

func (p ExplainPath) String() string

String returns the canonical path string (e.g. terraform.cluster.inputs.domain_name).

type ExplainPathKind added in v0.9.0

type ExplainPathKind int

ExplainPathKind identifies the type of blueprint path being explained.

const (
	ExplainPathKindTerraformInput ExplainPathKind = iota
	ExplainPathKindKustomizeSubstitution
	ExplainPathKindKustomizeComponents
	ExplainPathKindConfigMap
	ExplainPathKindSubstitution
)

type ExplainScopeRef added in v0.9.0

type ExplainScopeRef struct {
	Name   string
	Status string
	Source string
	Line   int
	Nested []ExplainScopeRef
}

ExplainScopeRef describes a scope variable referenced in an expression, its resolution status, and the source location of the config block that defines it (if applicable). Nested holds refs for expressions or map keys that contain expressions, recursively until origins.

type ExplainTrace added in v0.9.0

type ExplainTrace struct {
	Path          string
	Value         string
	Contributions []ExplainContribution
}

ExplainTrace holds the result of explaining a path: the value and its contributions.

type MockBlueprintHandler

type MockBlueprintHandler struct {
	LoadBlueprintFunc          func(...string) error
	SetSkipValidationFunc      func(skip bool)
	WriteFunc                  func(overwrite ...bool) error
	RetargetSourceFunc         func(name, url string) (string, error)
	UpgradeSourcesToLatestFunc func() ([]SourceUpgrade, error)
	GetDeclaredSourcesFunc     func() ([]blueprintv1alpha1.Source, error)
	GetTerraformComponentsFunc func() []blueprintv1alpha1.TerraformComponent
	GetLocalTemplateDataFunc   func() (map[string][]byte, error)
	GenerateFunc               func() *blueprintv1alpha1.Blueprint
	GenerateResolvedFunc       func() (*blueprintv1alpha1.Blueprint, error)
	ExplainFunc                func(string) (*ExplainTrace, error)
	GetDeferredPathsFunc       func() map[string]bool
	// contains filtered or unexported fields
}

MockBlueprintHandler is a mock implementation of BlueprintHandler interface for testing.

func NewMockBlueprintHandler

func NewMockBlueprintHandler() *MockBlueprintHandler

NewMockBlueprintHandler creates a new instance of MockBlueprintHandler.

func (*MockBlueprintHandler) Explain added in v0.9.0

func (m *MockBlueprintHandler) Explain(path string) (*ExplainTrace, error)

Explain calls the mock ExplainFunc if set, otherwise returns nil.

func (*MockBlueprintHandler) Generate

Generate calls the mock GenerateFunc if set, otherwise returns nil.

func (*MockBlueprintHandler) GenerateResolved added in v0.9.0

func (m *MockBlueprintHandler) GenerateResolved() (*blueprintv1alpha1.Blueprint, error)

GenerateResolved calls the mock GenerateResolvedFunc if set, otherwise falls back to Generate.

func (*MockBlueprintHandler) GetDeclaredSources added in v0.9.0

func (m *MockBlueprintHandler) GetDeclaredSources() ([]blueprintv1alpha1.Source, error)

GetDeclaredSources calls the mock GetDeclaredSourcesFunc if set, otherwise returns nil.

func (*MockBlueprintHandler) GetDeferredPaths added in v0.9.0

func (m *MockBlueprintHandler) GetDeferredPaths() map[string]bool

GetDeferredPaths calls the mock GetDeferredPathsFunc if set, otherwise returns nil.

func (*MockBlueprintHandler) GetLocalTemplateData

func (m *MockBlueprintHandler) GetLocalTemplateData() (map[string][]byte, error)

GetLocalTemplateData calls the mock GetLocalTemplateDataFunc if set, otherwise returns empty map.

func (*MockBlueprintHandler) GetTerraformComponents

func (m *MockBlueprintHandler) GetTerraformComponents() []blueprintv1alpha1.TerraformComponent

GetTerraformComponents calls the mock GetTerraformComponentsFunc if set, otherwise returns empty slice.

func (*MockBlueprintHandler) LoadBlueprint

func (m *MockBlueprintHandler) LoadBlueprint(blueprintURL ...string) error

LoadBlueprint calls the mock LoadBlueprintFunc if set, otherwise returns nil.

func (*MockBlueprintHandler) RetargetSource added in v0.9.0

func (m *MockBlueprintHandler) RetargetSource(name, url string) (string, error)

RetargetSource calls the mock RetargetSourceFunc if set, otherwise returns an empty previous URL.

func (*MockBlueprintHandler) SetSkipValidation added in v0.9.0

func (m *MockBlueprintHandler) SetSkipValidation(skip bool)

SetSkipValidation calls the mock SetSkipValidationFunc if set, otherwise records the flag on the mock so tests can assert prepareProject toggled it.

func (*MockBlueprintHandler) SkipValidation added in v0.9.0

func (m *MockBlueprintHandler) SkipValidation() bool

SkipValidation reports the recorded skip flag (only meaningful when SetSkipValidationFunc is not set). Test-only accessor.

func (*MockBlueprintHandler) UpgradeSourcesToLatest added in v0.9.0

func (m *MockBlueprintHandler) UpgradeSourcesToLatest() ([]SourceUpgrade, error)

UpgradeSourcesToLatest calls the mock UpgradeSourcesToLatestFunc if set, otherwise returns nil.

func (*MockBlueprintHandler) Write

func (m *MockBlueprintHandler) Write(overwrite ...bool) error

Write calls the mock WriteFunc if set, otherwise returns nil.

type RequirementsError added in v0.9.0

type RequirementsError struct {
	Message string
}

RequirementsError signals that one or more required facet inputs are not set. It carries the formatted operator-facing message produced by formatRequirementsError. Pipeline callers that would otherwise wrap blueprint errors with internal context (project's "failed to load blueprint data", handler's "failed to compose blueprint" and "failed to process facets for 'X'") detect this type via errors.As and pass it through unwrapped, so the operator sees the prose alone instead of a chain of internal frame names.

func (*RequirementsError) Error added in v0.9.0

func (e *RequirementsError) Error() string

type Shims

type Shims struct {
	Stat          func(string) (os.FileInfo, error)
	ReadFile      func(string) ([]byte, error)
	ReadDir       func(string) ([]os.DirEntry, error)
	WriteFile     func(string, []byte, os.FileMode) error
	MkdirAll      func(string, os.FileMode) error
	Walk          func(string, filepath.WalkFunc) error
	YamlMarshal   func(any) ([]byte, error)
	YamlUnmarshal func([]byte, any) error
	FilepathBase  func(string) string
}

Shims provides testable wrappers around external dependencies for the blueprint package. This enables dependency injection and mocking in unit tests while maintaining clean separation between business logic and external system interactions.

func NewShims

func NewShims() *Shims

NewShims creates a new Shims instance with default implementations that delegate to the actual system functions and libraries.

type SourceFacetSet added in v0.9.0

type SourceFacetSet struct {
	Name   string
	Depth  int
	Target *blueprintv1alpha1.Blueprint
	Facets []blueprintv1alpha1.Facet
}

SourceFacetSet is one source's contribution to global composition: its name, its dependency depth (deeper/referencing sources override shallower ones), the blueprint to emit its components into, and its facets.

type SourceUpgrade added in v0.9.0

type SourceUpgrade struct {
	Name string
	From string
	To   string
}

SourceUpgrade records one source moved to a newer version by UpgradeSourcesToLatest.

type TraceCollector added in v0.9.0

type TraceCollector interface {
	RecordContribution(composedPath string, tc TraceContribution)
	RecordConfigBlock(configPath string, record ConfigBlockRecord)
	Finalize(bp *blueprintv1alpha1.Blueprint, scope map[string]any, templateRoot string)
	GetTrace(pathStr string) (*ExplainTrace, error)
}

TraceCollector records per-key contributions and config blocks during blueprint composition, then provides trace queries after finalization. Implementations are set on the processor before composition begins and are only active when the explain command is running.

type TraceContribution added in v0.9.0

type TraceContribution struct {
	FacetPath     string
	SourceName    string
	Ordinal       int
	Strategy      string
	Line          int
	RawValue      any
	RawComponents []string
	ScopeRefs     []string
}

TraceContribution records a single per-key contribution from a facet during composition. Recorded at the per-key level (e.g. "terraform.networking.inputs.domain_name") with all metadata resolved at record time so no retroactive YAML reparsing is needed. ScopeRefs are pre-extracted from expressions during recording.

Jump to

Keyboard shortcuts

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