Documentation
¶
Overview ¶
Package transform - ast.go implements Go template AST analysis for fast mode. Instead of sentinel rendering (O(N+1) renders), it parses template files once to find .Values.* references and matches rendered field values against known Helm values to produce FieldMappings in a single render pass.
Package transform - engine.go orchestrates the full transformation pipeline that converts parsed Kubernetes resources and Helm values into a KRO ResourceGraphDefinition.
Package transform - fieldpath.go provides utilities for navigating and mutating nested map[string]interface{} structures using dot-separated field paths with optional array index notation (e.g., "spec.containers[0].image").
Package transform implements the core transformation pipeline that converts parsed Kubernetes resources and Helm values into KRO-compatible artifacts.
Package transform - jsonschema.go provides utilities to extract type information from a Helm chart's values.schema.json, enriching the schema beyond what Go runtime types can infer from values.yaml alone.
Package transform - params.go defines parameter mapping types and CEL expression generation for sentinel-based parameter detection.
Package transform - readyconditions.go provides loading and merging of user-supplied custom readiness conditions from a YAML file. The file format maps Kubernetes resource kinds to readiness expressions:
Deployment:
- "${self.status.availableReplicas == self.spec.replicas}"
Service:
- "${self.spec.clusterIP != \"\"}"
Job:
- "${self.status.succeeded > 0}"
Package transform - schema.go implements schema extraction from Helm values.
Package transform - sentinel.go implements sentinel value injection and diffing for parameter detection. It replaces Helm values with unique markers, re-renders, and diffs resources to determine which fields are controlled by which values.
Index ¶
- Constants
- func AnalyzeTemplates(templateFiles map[string]string) (map[string]bool, error)
- func ApplyFieldMappings(resources []*k8s.Resource, resourceIDs map[*k8s.Resource]string, ...)
- func ApplySchemaOverrides(fields []*SchemaField, overrides map[string]SchemaOverride)
- func AssignResourceIDs(resources []*k8s.Resource, overrides map[string]string) (map[*k8s.Resource]string, error)
- func BatchSentinelizeIndependent(values map[string]interface{}) []map[string]interface{}
- func BuildCELExpression(mapping FieldMapping, sentinelRendered string) string
- func BuildInterpolatedCELFromSentinel(sentinelRendered string) string
- func BuildSimpleSchema(fields []*SchemaField) map[string]interface{}
- func CompoundIncludeWhen(conditions []IncludeCondition) string
- func ExtractSentinelsFromString(s string) []string
- func IncludeWhenExpression(path ...string) string
- func Interpolate(parts ...string) string
- func LoadCustomReadyConditions(path string) (map[string][]string, error)
- func MapToSimpleSchemaType(jsonSchemaType string) string
- func ResolveReadyWhen(gvk schema.GroupVersionKind, custom map[string][]string) []string
- func ResourceRef(resourceID string, path ...string) string
- func ResourceRefWithOptional(resourceID string, segments ...PathSegment) string
- func SchemaRef(path ...string) string
- func SelfRef(path ...string) string
- func SentinelForString(path string) string
- func SentinelizeAll(values map[string]interface{}) map[string]interface{}
- func ToCamelCase(s string) string
- func ToPascalCase(s string) string
- func ValidateExpression(expr string) error
- type CycleError
- type DependencyGraph
- func (g *DependencyGraph) AddEdge(source, target string)
- func (g *DependencyGraph) AddNode(id string, r *k8s.Resource)
- func (g *DependencyGraph) DependenciesOf(id string) []string
- func (g *DependencyGraph) DetectCycles() [][]string
- func (g *DependencyGraph) EdgeCount() int
- func (g *DependencyGraph) Nodes() []string
- func (g *DependencyGraph) Resource(id string) *k8s.Resource
- func (g *DependencyGraph) TopologicalSort() ([]string, error)
- type Engine
- type EngineConfig
- type FieldMapping
- func DiffAllResources(baseline []*k8s.Resource, sentinelRendered []*k8s.Resource, ...) []FieldMapping
- func MatchFieldsByValue(resources []*k8s.Resource, resourceIDs map[*k8s.Resource]string, ...) []FieldMapping
- func ParallelDiffAllResources(baseline []*k8s.Resource, sentinelRendered []*k8s.Resource, ...) []FieldMapping
- type IncludeCondition
- type JSONSchemaInfo
- type JSONSchemaResolver
- type MatchType
- type ParallelDiffConfig
- type PathSegment
- type ReadyWhenCondition
- type Result
- type SchemaExtractor
- type SchemaField
- type SchemaOverride
- type StatusField
- type TransformerOutput
- type TransformerRegistry
Constants ¶
const SentinelPrefix = "__CHART2KRO_SENTINEL_"
SentinelPrefix is the prefix used for string sentinel values.
const SentinelSuffix = "__"
SentinelSuffix is the suffix used for string sentinel values.
Variables ¶
This section is empty.
Functions ¶
func AnalyzeTemplates ¶
AnalyzeTemplates parses Go template files and extracts all .Values.* paths referenced in template actions. This returns the set of referenced value paths without requiring sentinel rendering.
templateFiles is a map of template filename to template content (e.g., from chart.Chart.Templates). Only files with .yaml/.yml/.tpl extensions are parsed.
func ApplyFieldMappings ¶
func ApplyFieldMappings( resources []*k8s.Resource, resourceIDs map[*k8s.Resource]string, mappings []FieldMapping, )
ApplyFieldMappings applies field mappings to resource templates, replacing hardcoded values with CEL expressions (e.g., ${schema.spec.replicaCount}). For substring matches (string interpolation), it uses the full sentinel-rendered value to produce a composite CEL expression.
func ApplySchemaOverrides ¶
func ApplySchemaOverrides(fields []*SchemaField, overrides map[string]SchemaOverride)
ApplySchemaOverrides mutates the extracted schema fields in-place, replacing inferred types and defaults with user-specified overrides.
func AssignResourceIDs ¶
func AssignResourceIDs(resources []*k8s.Resource, overrides map[string]string) (map[*k8s.Resource]string, error)
AssignResourceIDs assigns stable, human-readable IDs to each resource. When multiple resources share the same kind, a disambiguating name segment is appended (e.g., "service-main", "service-headless"). The overrides map allows manual ID assignment by qualified name ("Kind/name"). Returns an error if two resources would receive the same ID after sanitization.
func BatchSentinelizeIndependent ¶
BatchSentinelizeIndependent analyses the values tree and groups structurally independent leaf values that can be sentinelized together in a single rendering pass.
Values are independent when they reside under different top-level keys. This is a conservative heuristic that avoids sentinel collision while allowing batching of unrelated subtrees.
This utility is useful as a fallback strategy when full sentinelization via SentinelizeAll causes template rendering failures. By batching into smaller groups, each render pass handles fewer sentinel values, reducing the chance of template type-mismatch errors.
The current pipeline uses SentinelizeAll for single-pass rendering, which is optimal for most charts. Use this function when implementing custom multi-pass sentinel strategies for very large or complex charts.
func BuildCELExpression ¶
func BuildCELExpression(mapping FieldMapping, sentinelRendered string) string
BuildCELExpression generates a CEL expression for a field mapping. For exact matches: ${schema.spec.<path>} For substring matches: "${schema.spec.<path1>}...<literal>...${schema.spec.<path2>}"
func BuildInterpolatedCELFromSentinel ¶
BuildInterpolatedCELFromSentinel parses a sentinel-rendered string with one or more sentinels embedded, and produces a CEL interpolation expression.
func BuildSimpleSchema ¶
func BuildSimpleSchema(fields []*SchemaField) map[string]interface{}
BuildSimpleSchema converts a list of SchemaFields into a map[string]interface{} suitable for YAML serialization, using KRO SimpleSchema syntax.
func CompoundIncludeWhen ¶
func CompoundIncludeWhen(conditions []IncludeCondition) string
CompoundIncludeWhen generates a compound CEL expression from multiple conditions. Conditions are joined with "&&" and enclosed in a single ${...} expression.
Examples:
[{Path: "a"}] → "${schema.spec.a}"
[{Path: "a"}, {Path: "b"}] → "${schema.spec.a && schema.spec.b}"
[{Path: "a", Operator: "!=", Value: "\"\""}] → "${schema.spec.a != \"\"}"
func ExtractSentinelsFromString ¶
ExtractSentinelsFromString extracts all sentinel paths from a string that may contain multiple interpolated sentinels.
func IncludeWhenExpression ¶
IncludeWhenExpression generates a conditional inclusion expression. e.g., IncludeWhenExpression("spec", "monitoring", "enabled") => "${schema.spec.monitoring.enabled}".
func Interpolate ¶
Interpolate wraps multiple expressions in a string interpolation. e.g., Interpolate("${schema.spec.image}", ":", "${schema.spec.tag}") => "${schema.spec.image}:${schema.spec.tag}".
func LoadCustomReadyConditions ¶
LoadCustomReadyConditions reads a YAML file containing custom readiness conditions keyed by Kind name. Returns a map of Kind → raw CEL condition strings. The caller can use ResolveReadyWhen to apply these overrides.
func MapToSimpleSchemaType ¶
MapToSimpleSchemaType converts a JSON Schema type string to a KRO SimpleSchema type string. JSON Schema "integer" maps to "integer", "number" to "number", "boolean" to "boolean", and everything else (including "string") to "string".
func ResolveReadyWhen ¶
func ResolveReadyWhen(gvk schema.GroupVersionKind, custom map[string][]string) []string
ResolveReadyWhen returns readiness conditions for a resource GVK. Custom conditions take precedence over defaults when the Kind matches.
func ResourceRef ¶
ResourceRef generates a CEL expression referencing another resource's field. e.g., ResourceRef("deployment", "status", "availableReplicas") => "${deployment.status.availableReplicas}".
func ResourceRefWithOptional ¶
func ResourceRefWithOptional(resourceID string, segments ...PathSegment) string
ResourceRefWithOptional generates a CEL expression using optional "?" accessors for potentially absent status fields. e.g., ResourceRefWithOptional("svc", PathSegment{"status", false}, PathSegment{"loadBalancer", false},
PathSegment{"ingress[0]", true}, PathSegment{"hostname", true})
=> "${svc.status.loadBalancer.?ingress[0].?hostname}"
func SchemaRef ¶
SchemaRef generates a CEL expression referencing a schema field. e.g., SchemaRef("spec", "replicas") => "${schema.spec.replicas}". Returns an error-indicative string if path is empty.
func SelfRef ¶
SelfRef generates a CEL expression referencing the resource's own field. e.g., SelfRef("status", "availableReplicas") => "${self.status.availableReplicas}".
func SentinelForString ¶
SentinelForString returns the sentinel string for a given path.
func SentinelizeAll ¶
SentinelizeAll creates a deep copy of values with ALL leaf values replaced by their sentinel equivalents. This enables detecting multi-value string interpolation patterns (e.g., "${image.repo}:${image.tag}") in a single render.
func ToCamelCase ¶
ToCamelCase converts a dot-separated or hyphenated path to camelCase.
func ToPascalCase ¶
ToPascalCase converts a string to PascalCase.
func ValidateExpression ¶ added in v0.0.2
ValidateExpression checks that a KRO CEL expression string has balanced ${...} delimiters and is non-empty. It does NOT compile or type-check the inner CEL — that is KRO's responsibility at apply time.
Types ¶
type CycleError ¶
type CycleError struct {
Cycles [][]string
}
CycleError is returned when the dependency graph contains cycles.
func (*CycleError) Error ¶
func (e *CycleError) Error() string
type DependencyGraph ¶
type DependencyGraph struct {
// contains filtered or unexported fields
}
DependencyGraph represents the DAG of resource dependencies.
func BuildDependencyGraph ¶
func BuildDependencyGraph(resources map[*k8s.Resource]string) *DependencyGraph
BuildDependencyGraph analyzes resources and constructs a dependency graph. It detects label selector matches, name references, SA references, and volume refs.
func NewDependencyGraph ¶
func NewDependencyGraph() *DependencyGraph
NewDependencyGraph creates an empty dependency graph.
func (*DependencyGraph) AddEdge ¶
func (g *DependencyGraph) AddEdge(source, target string)
AddEdge adds a dependency: source depends on target. Both source and target must be registered nodes.
func (*DependencyGraph) AddNode ¶
func (g *DependencyGraph) AddNode(id string, r *k8s.Resource)
AddNode adds a resource to the graph.
func (*DependencyGraph) DependenciesOf ¶
func (g *DependencyGraph) DependenciesOf(id string) []string
DependenciesOf returns the IDs that the given node depends on.
func (*DependencyGraph) DetectCycles ¶
func (g *DependencyGraph) DetectCycles() [][]string
DetectCycles returns all unique cycles in the graph using DFS. Cycles are deduplicated by normalizing: each cycle is rotated so that its lexicographically smallest node comes first, then stored as a canonical string key to avoid reporting the same cycle from different starting points.
func (*DependencyGraph) EdgeCount ¶ added in v0.0.2
func (g *DependencyGraph) EdgeCount() int
EdgeCount returns the total number of dependency edges in the graph.
func (*DependencyGraph) Nodes ¶
func (g *DependencyGraph) Nodes() []string
Nodes returns all node IDs.
func (*DependencyGraph) Resource ¶
func (g *DependencyGraph) Resource(id string) *k8s.Resource
Resource returns the resource for the given ID.
func (*DependencyGraph) TopologicalSort ¶
func (g *DependencyGraph) TopologicalSort() ([]string, error)
TopologicalSort returns the nodes in topological order using Kahn's algorithm. Ties are broken alphabetically for deterministic output. Returns an error if the graph contains a cycle.
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine orchestrates the full transformation pipeline.
func NewEngine ¶
func NewEngine(config EngineConfig) *Engine
NewEngine creates a new transformation engine.
func (*Engine) Transform ¶
func (e *Engine) Transform( ctx context.Context, resources []*k8s.Resource, values map[string]interface{}, ) (*Result, error)
Transform runs the full transformation pipeline: 1. Assign resource IDs 2. Apply field mappings to resource templates (CEL expression injection) 3. Extract schema from values (with optional pruning) 4. Build dependency graph 5. Generate status projections via transformer registry
type EngineConfig ¶
type EngineConfig struct {
// IncludeAllValues includes all values in the schema, even unreferenced ones.
IncludeAllValues bool
// FlatSchema uses flat camelCase field names instead of nested objects.
FlatSchema bool
// ResourceIDOverrides allows manual ID assignment by qualified name.
ResourceIDOverrides map[string]string
// FieldMappings are pre-computed sentinel-based parameter mappings.
// When non-nil, the engine applies these to resource templates,
// replacing hardcoded values with CEL expressions.
FieldMappings []FieldMapping
// ReferencedPaths is the set of Helm value paths detected as referenced.
// When non-nil and IncludeAllValues is false, only these paths are
// included in the schema.
ReferencedPaths map[string]bool
// JSONSchemaBytes is the raw values.schema.json from the chart.
// When non-nil, enriches schema type inference with explicit JSON Schema types.
JSONSchemaBytes []byte
// SchemaOverrides override inferred schema field types and defaults.
// Keys are dotted Helm value paths (e.g., "replicaCount", "image.tag").
SchemaOverrides map[string]SchemaOverride
// TransformerRegistry is an optional pluggable transformer registry.
// When non-nil, the engine dispatches per-resource transformation
// through the registry to produce readiness conditions and status
// projections. When nil, DefaultStatusProjections is used.
TransformerRegistry TransformerRegistry
}
EngineConfig configures the transformation engine.
type FieldMapping ¶
type FieldMapping struct {
// ValuesPath is the dot-separated Helm values path (e.g., "image.tag").
ValuesPath string
// ResourceID is the ID of the affected resource.
ResourceID string
// FieldPath is the dot-separated field path within the resource
// (e.g., "spec.template.spec.containers[0].image").
FieldPath string
// MatchType indicates how the sentinel was found.
MatchType MatchType
// SentinelRendered holds the sentinel-rendered field value for substring matches.
// Used by BuildCELExpression to produce interpolated CEL expressions.
SentinelRendered string
}
FieldMapping represents a mapping from a Helm values path to affected resource fields.
func DiffAllResources ¶
func DiffAllResources( baseline []*k8s.Resource, sentinelRendered []*k8s.Resource, resourceIDs map[*k8s.Resource]string, ) []FieldMapping
DiffAllResources compares baseline resources against full-sentinel-rendered resources to detect all field mappings in a single pass. Resources are matched by GVK+name identity rather than positional index, making the diff robust against structural changes caused by sentinel values (e.g., conditional blocks).
func MatchFieldsByValue ¶
func MatchFieldsByValue( resources []*k8s.Resource, resourceIDs map[*k8s.Resource]string, values map[string]interface{}, referencedPaths map[string]bool, ) []FieldMapping
MatchFieldsByValue walks rendered resources and matches field values against known Helm values to produce FieldMappings without sentinel rendering. This is the field-mapping phase for fast mode.
It flattens Helm values to a map of path→value, then walks each resource's fields. If a field value matches a known value exactly, a FieldMapping with MatchExact is created. If a field value contains known string values as substrings, a FieldMapping with MatchSubstring is created.
Only paths present in referencedPaths (from AST analysis) are considered.
func ParallelDiffAllResources ¶
func ParallelDiffAllResources( baseline []*k8s.Resource, sentinelRendered []*k8s.Resource, resourceIDs map[*k8s.Resource]string, cfg ParallelDiffConfig, ) []FieldMapping
ParallelDiffAllResources is the concurrent version of DiffAllResources. It distributes resource diffing across a bounded worker pool and collects results without data races.
type IncludeCondition ¶
type IncludeCondition struct {
// Path is the dot-separated Helm values path (e.g., "monitoring.enabled").
Path string
// Operator is the comparison operator (defaults to implicit truthiness if empty).
Operator string
// Value is the comparison value (e.g., "\"\""). Empty for truthiness checks.
Value string
}
IncludeCondition represents a single condition for compound includeWhen.
type JSONSchemaInfo ¶
type JSONSchemaInfo struct {
// Type is the JSON Schema type (string, integer, number, boolean, array, object).
Type string
// Format is an optional format hint (e.g., "int64", "email", "uri").
Format string
// Description is the human-readable description from the schema.
Description string
// Enum lists allowed values, if specified.
Enum []interface{}
// Minimum is the minimum numeric value, if specified.
Minimum *float64
// Maximum is the maximum numeric value, if specified.
Maximum *float64
}
JSONSchemaInfo holds type metadata extracted from a JSON Schema property.
type JSONSchemaResolver ¶
type JSONSchemaResolver struct {
// contains filtered or unexported fields
}
JSONSchemaResolver resolves type information from a parsed values.schema.json. The resolver walks the JSON Schema tree to find type, format, enum, and description metadata for a given dot-separated Helm values path.
func NewJSONSchemaResolver ¶
func NewJSONSchemaResolver(schemaBytes []byte) (*JSONSchemaResolver, error)
NewJSONSchemaResolver parses raw values.schema.json bytes and returns a resolver. Returns nil (no error) when schemaBytes is empty, allowing callers to skip JSON Schema enrichment without branching.
func (*JSONSchemaResolver) Resolve ¶
func (r *JSONSchemaResolver) Resolve(path string) *JSONSchemaInfo
Resolve looks up a dot-separated Helm values path in the JSON Schema and returns the type info. Returns nil when the path is not found.
type ParallelDiffConfig ¶
type ParallelDiffConfig struct {
// Workers is the maximum number of goroutines.
// Defaults to GOMAXPROCS if zero.
Workers int
}
ParallelDiffConfig controls parallel sentinel diff behaviour.
type PathSegment ¶
type PathSegment struct {
// Name is the field name (e.g., "status", "loadBalancer", "ingress[0]").
Name string
// Optional marks this segment with a "?" accessor for potentially absent fields.
Optional bool
}
PathSegment represents a segment in a resource reference path, with an optional flag indicating the field may be absent.
type ReadyWhenCondition ¶
type ReadyWhenCondition struct {
// Key is the status field path to check.
Key string
// Operator is the comparison operator (==, !=, >, <, etc.).
Operator string
// Value is the expected value (can be another field reference or literal).
Value string
}
ReadyWhenCondition represents a readiness condition for a KRO resource.
func DefaultReadyWhen ¶
func DefaultReadyWhen(gvk schema.GroupVersionKind) []ReadyWhenCondition
DefaultReadyWhen returns default readiness conditions for a given GVK.
func (ReadyWhenCondition) String ¶
func (c ReadyWhenCondition) String() string
String returns the CEL expression for a readiness condition.
type Result ¶
type Result struct {
// Resources is the list of parsed Kubernetes resources.
Resources []*k8s.Resource
// ResourceIDs maps each resource to its assigned ID.
ResourceIDs map[*k8s.Resource]string
// SchemaFields are the extracted schema fields.
SchemaFields []*SchemaField
// StatusFields are the generated status projections.
StatusFields []StatusField
// DependencyGraph is the constructed dependency graph.
DependencyGraph *DependencyGraph
// FieldMappings are the detected parameter mappings.
FieldMappings []FieldMapping
}
Result holds all artifacts produced by the transformation pipeline.
type SchemaExtractor ¶
type SchemaExtractor struct {
// IncludeAll includes all values even if not referenced in templates.
IncludeAll bool
// FlatMode uses flat camelCase field names instead of nested objects.
FlatMode bool
// JSONSchema is an optional resolver for values.schema.json type info.
// When non-nil, it enriches inferred types with explicit JSON Schema types.
JSONSchema *JSONSchemaResolver
}
SchemaExtractor extracts KRO SimpleSchema from Helm values.
func NewSchemaExtractor ¶
func NewSchemaExtractor(includeAll, flatMode bool, jsonSchema *JSONSchemaResolver) *SchemaExtractor
NewSchemaExtractor creates a SchemaExtractor with the given options.
func (*SchemaExtractor) Extract ¶
func (e *SchemaExtractor) Extract(values map[string]interface{}, referencedPaths map[string]bool) []*SchemaField
Extract walks the values tree and produces a list of SchemaFields. referencedPaths is the set of Helm value paths actually used in templates. If nil or IncludeAll is set, all values are included.
type SchemaField ¶
type SchemaField struct {
// Name is the field name (camelCase).
Name string
// Path is the dot-separated Helm values path (e.g., "image.repository").
Path string
// Type is the KRO SimpleSchema type (string, integer, number, boolean).
Type string
// Default is the default value as a string (e.g., "\"nginx\"", "3", "true").
Default string
// Children holds nested fields for object types.
Children []*SchemaField
}
SchemaField represents a single field in the KRO SimpleSchema.
func (*SchemaField) IsObject ¶
func (f *SchemaField) IsObject() bool
IsObject returns true if this field has children (nested object).
func (*SchemaField) SimpleSchemaString ¶
func (f *SchemaField) SimpleSchemaString() string
SimpleSchemaString returns the KRO SimpleSchema representation. e.g., "string | default=\"nginx\"" or "integer | default=3".
type SchemaOverride ¶
type SchemaOverride struct {
// Type overrides the inferred type (string, integer, number, boolean).
Type string
// Default overrides the default value.
Default string
}
SchemaOverride allows overriding the inferred type and default of a schema field.
type StatusField ¶
type StatusField struct {
// Name is the name of the field in the RGD status.
Name string
// CELExpression is the CEL expression to extract the value.
CELExpression string
}
StatusField represents a field to project from a resource's status.
func DefaultStatusProjections ¶
func DefaultStatusProjections(gvk schema.GroupVersionKind, resourceID string) []StatusField
DefaultStatusProjections returns default status fields to project for a given GVK. Fields that may be absent on newly created resources use optional "?" accessors.
type TransformerOutput ¶
type TransformerOutput struct {
// ReadyWhen are the readiness conditions (raw CEL-style strings).
ReadyWhen []string
// StatusFields are the status projections for this resource.
StatusFields []StatusField
// IncludeWhen is an optional conditional inclusion CEL expression.
IncludeWhen string
}
TransformerOutput holds the results from a transformer's per-resource transformation. This is the engine-facing type that decouples the engine from the transformer package.
type TransformerRegistry ¶
type TransformerRegistry interface {
// TransformResource applies the matching transformer to a resource.
TransformResource(
ctx context.Context,
resource *k8s.Resource,
resourceID string,
fieldMappings []FieldMapping,
values map[string]interface{},
) (*TransformerOutput, error)
}
TransformerRegistry is the interface the engine uses to dispatch per-resource transformation. The concrete implementation lives in internal/transform/transformer to avoid circular imports.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package transformer defines the Transformer interface and Registry for per-resource-kind transformation logic.
|
Package transformer defines the Transformer interface and Registry for per-resource-kind transformation logic. |