v0.9.0
π Highlights
Cluster-Scoped Instance CRDs (KREP-10)
RGDs can now generate cluster-scoped instance CRDs. Add scope: Cluster to your schema and kro produces a non-namespaced CRD. Namespaced child resources must explicitly declare metadata.namespace when the instance is cluster-scoped. The field defaults to Namespaced and is immutable after creation. Docs
includeWhen Can Reference Upstream Resources
includeWhen expressions are no longer limited to schema fields - they can now reference other resources in the graph. kro treats these references as real dependencies that participate in DAG construction and cycle detection. Docs.
Decorators - External Collections (KREP-008)
ExternalRef previously only supported name and namespace for scalar lookups. They now support full matchLabels and matchExpressions selectors, so a single externalRef can match multiple resources dynamically. Selector values accept CEL expressions. Docs
Reactive Watches on External References and Decorators (KREP-003)
kro now watches external references - both scalar and collections β and re-reconciles instances instantly when an external resource is created, updated, or deleted. (Docs)
omit() CEL Function ( CELOmitFunction)
A new CEL omit() function lets you conditionally remove fields from rendered templates. Use ${schema.spec.kmsKeyID != "" ? schema.spec.kmsKeyID : omit()} and the field is dropped entirely from the SSA payload - important for APIs that distinguish between field absence and an empty value. omit() is rejected on required metadata fields (name, namespace, apiVersion, kind). Alpha, default off. Docs
Instance Status Condition Events (InstanceConditionEvents)
kro can now emit Kubernetes Events when instance status conditions transition between reconciliation cycles. Events show the transition as "False β True: ResourcesReady" and are typed Normal for transitions to True, Warning for everything else. Visible via kubectl describe on any instance. Alpha, default off. Docs
CEL Libraries Enrichment
The CEL environment gained nine new capabilities:
- json:
json.marshal()andjson.unmarshal()for working with JSON payloads directly in expressions - maps:
map.merge()to combine two maps with second-map-wins semantics - lists:
lists.setAtIndex(),lists.insertAtIndex(),lists.removeAtIndex()for immutable list mutations; k8s Lists library forlists.concat()and friends - quantity: parse and manipulate Kubernetes Quantities (
"500m","2Gi") natively - bind:
cel.bind(varName, init, body)to name intermediate values and reduce repetition - comprehensions:
TwoVarComprehensions(transformMap,transformList) andsortByfor stable ordering by arbitrary expressions - random:
random.seededInt(min, max, seed)for deterministic integer generation from resource UIDs
Graph Revisions (KREP-013)
RGD specs are now versioned. Each spec change creates an immutable GraphRevision snapshot (kubectl get gr) that is compiled and validated independently before instances can use it. If a new spec breaks compilation, instances block with a clear status instead of failing silently β you see exactly which revision failed and why via kubectl describe gr. kro retains the last 5 revisions per RGD (configurable), giving you an audit trail of every spec change. More importantly, Graph Revisions lay the foundation for progressive rollouts and revision pinning in future releases. Docs. Docs
β¨ Features
- feat: implement KREP-10 - support cluster-scoped instance CRDs by @antcybersec in #1152
- feat: external ref watches and external ref collections by @jakobmoellerdev in #1079
- feat: support CEL expressions in LabelSelectors for external collections by @jakobmoellerdev in #1079
- feat: disable instance reconciliation when a kro.run/reconcile:"disabled" label is present by @NickKeller in #1062
- feat(cel): add omit() for conditional field omission in templates by @michaelhtm in #1139
- feat(events): Add events for instance status condition transition by @spattk in #1151
- feat(#510): implement standard Kubernetes feature gates via component-base by @jakobmoellerdev in #1172
- feat(helm): expose feature gates in chart values by @a-hilaly in #1187
- feat(graph): gate omit() behind CELOmitFunction feature flag by @a-hilaly in #1185
- feat(graph): reject omit() on required resource metadata fields by @michaelhtm in #1167
- feat: allow
includeWhento reference other resources by @a-hilaly in #1104 - feat(cel): add json.marshal and json.unmarshal CEL functions by @NicholasBlaskey in #1033
- feat(cel): add map library with merge functionality by @a-hilaly in #1068
- feat(cel): add index-mutation functions to the lists library by @pnz1990 in #1148
- feat(cel): add k8s Lists library support by @NicholasBlaskey in #1178
- feat(cel): add k8s Quantity library support by @NicholasBlaskey in #1177
- feat(cel): add cel.bind() support to default environment and AST inspector by @pnz1990 in #1145
- feat(cel): add support for
TwoVarComprehensionsin CEL environment by @jakobmoellerdev in #1136 - feat(cel/ast): improve loop variable scoping and support
sortBycomprehension by @jakobmoellerdev in #1136 - feat(cel): add deterministic seeded integer generation function by @a-hilaly in #1108
- feat(cel): add version support for the cel json library by @NicholasBlaskey in #1033
- feat(compat): detect default value changes as non-breaking in schema comparison by @michaelhtm in #1098
- feat(instance): block graph propagation on terminating managed resources by @a-hilaly in #1132
- feat(helm): add topologySpreadConstraints in deployment by @QuentinBtd in #1137
- feat: Add opt-in pprof profiling support via build tags by @a-hilaly in #922
- feat: make instance requeue interval configurable by @a-hilaly in #1184
- feat: expose leader election tuning flags in helm chart by @a-hilaly in #1205
- feat: add metrics for pkg/runtime by @NicholasBlaskey in #1053
- feat: Add RGD controller metrics by @NicholasBlaskey in #1063
- feat: Add instance controller metrics by @NicholasBlaskey in #1056
- feat(cel): add metrics for CEL cache hit/miss tracking by @a-hilaly in #1142
- feat: Add client-go and reflector metrics registration by @a-hilaly in #1143
- feat: Use expressive histogram buckets for controller reconciliation metrics by @a-hilaly in #1157
- feat: Implementation of Graph Revisions (KREP-013) by @a-hilaly in #1085
- feat: Watch owned
GraphRevisionsfrom the RGD controller by @a-hilaly in #1200 - feat: watch graph revisions by
spec.snapshot.namefor orphan adoption by @a-hilaly in #1206 - feat: Limit collection size to 1000 to protect cluster performance by @NicholasBlaskey in #1036
- feat: limit collection dimension to 5 by @michaelhtm in #1045
- feat: disable instance reconciliation with annotation instead of label by @michaelhtm in #1191
- feat: KREP-15 label/annotation migration to
internal.kro.run/prefix by @michaelhtm in #1094
π Bug Fixes
- fix: flaky validate RGD status test by @michaelhtm in #1034
- fix: flaky validate RGD status integration test by @Aman-Cool in #1041
- fix(docs): Wrong schema apiVersion definition in RGD chaining by @gagahsyuja in #1050
- fix: properly return error in simpleschema parsing when the marker does by @NickKeller in #1073
- fix: remove the rgd labels from managed resources by @jakobmoellerdev in #1075
- fix(applyset): preserve prune scope on UID conflicts and requeue retry by @a-hilaly in #1081
- fix: pass up expressive error by @fabianburth in #1078
- fix(runtime): schema-aware CEL value conversion by @jakobmoellerdev in #1080
- fix: show root cause error by @fabianburth in #1160
- fix(dynamic): skip parent instance events with unchanged generation by @jakobmoellerdev in #1173
- fix(metadata): skip instance-namespace label for cluster-scoped instances by @a-hilaly in #1175
- fix(docs): correct RGD conditions by @a-hilaly in #1181
- fix(collections): register collection watch for all expanded resources by @a-hilaly in #1182
- fix(cel): handle
oneOfstring|number schemas inUnstructuredToValby @a-hilaly in #1179 - fix: return a requeue error when waiting for readiness by @fabianburth in #1090
- fix: do not count requeue signals as handler errors in dynamic_controller_handler_errors_total by @Avr8 in #1059
- fix(cel): sort transformList result before comparison in TwoVar test by @a-hilaly in #1141
- fix: add instance state in progress case by @fabianburth in #1090
- fix(graph/resolver): expose schema resolver metrics on controller-runtime registry by @a-hilaly in #1113
- fix: ResourceGraphDefinition delete predicate handling by @a-hilaly in #1097
- fix(externalref): allow external collections to list across all namespaces by @a-hilaly in #1180
- fix: tighten cluster-scoped instance namespace validation by @a-hilaly in #1152
- fix: handle cluster-scoped instances in reconciliation and SSA patches by @a-hilaly in #1152
- fix(instance): surface graph resolution failures in conditions and metrics by @a-hilaly in #1201
- fix: get rid of cel build caches due to problems during stabilization by @jakobmoellerdev in #1195
- fix: missing dynamic controller registration, and wire up missing metrics by @jakobmoellerdev in #1146
β‘ Performance
- perf(graph): eliminate duplicate CEL type building during RGD construction by @jakobmoellerdev in #1116
- perf(cel): cache base declarations and environment with sync.Once by @jakobmoellerdev in #1119
- perf(cel): add caching for CEL compilation artifacts to optimize performance by @jakobmoellerdev in #1129
- perf: removes the lock convoy during large RGD bursts by @a-hilaly in #1192
- perf: Make string templates compile to concatenation by @NicholasBlaskey in #1131
- perf: use DefaultUnstructuredConverter to eliminate JSON round-trips in conditions by @spattk in #1204
π§ Refactoring
- refactor(cel): Move cel conversion functions to separate package by @NicholasBlaskey in #1043
- refactor(dag): use a heap-based topological sort by @a-hilaly in #1122
- refactor(api): move InstanceState and NodeState to api/v1alpha1 by @NicholasBlaskey in #1134
- refactor(runtime,instance): split large files and simplify state management by @jakobmoellerdev in #1165
- refactor(cel/ast): derive known functions from CEL environment by @a-hilaly in #1109
- refactor(apis): add condition prune mechanism for upgrades by @a-hilaly in #1198
- dynamiccontroller: retain parent informers for shared GVR watches by @a-hilaly in #1105
- dynamiccontroller: rollback provisional watches on failed reconciles by @a-hilaly in #1106
- commit watches on requeue signals, not just on success by @a-hilaly in #1158
π Documentation
- docs: document cluster-scoped instance support by @a-hilaly in #1162
- docs: expand external references to support collections with label selectors by @jakobmoellerdev in #1093
- docs: Add a page for feature gates by @a-hilaly in #1186
- docs(metrics): add stability notice for ALPHA metrics by @jakobmoellerdev in #1118
- docs(website): rewrite graph revisions page and add interactive diagrams by @a-hilaly in #1199
- docs: Update docs be explicitly clear about resources depending on
schema.specby @NickKeller in #1072 - docs: add "Building Abstractions with kro" guides by @a-hilaly in #1112
- docs: Fix formatting in the verify installation step by @KatharinaSick in #1188
- docs: Add AWS Accounts Factory example with nested RGDs by @tzahimizrahi in #1128
- Document escaping Bash '${VAR}' syntax for CEL by @mwarkentin in #1083
- website: overhaul overview docs with interactive resource graph diagrams by @a-hilaly in #1110
- website: add KREP roadmap page by @a-hilaly in #1133
- KREP-003: Decorators (Collection Watching) by @ellistarn in #738
- KREP-008: docs: add proposal for resource-backed includeWhen evaluation by @shivansh-source in #933
- KREP-10 for cluster-scoped instance CRDs by @antcybersec in #1030
- KREP-017 template field omission with
omit()by @a-hilaly in #1121
π§ͺ Testing
- test: harden pkg/runtime coverage by @a-hilaly in #1099
- test(instance): harden instance reconciler coverage by @a-hilaly in #1103
- test(rgd): harden rgd controller unit tests by @a-hilaly in #1102
- test(pkg/graph): harden unit tests for graph builder and friends by @a-hilaly in #1120
- test: verify externalref integration cases reconcile on watched updates by @a-hilaly in #1123
- test: integration test case, omit() removes field by @michaelhtm in #1168
- test: add webhook denial integration tests with ValidatingAdmissionPolicy by @NicholasBlaskey in #1154
- test: Add an upgrade test framework that validates kro upgrades don't break by @a-hilaly in #1197
- test: Add verify-codegen ci entrypoint by @a-hilaly in #1196
π§Ή Chores
- chore: bump controller-runtime to v0.23.1 by @NicholasBlaskey in #1046
- chore: bump cel-go to v0.27.0 by @NicholasBlaskey in #1047
- chore: implement annotation change predicate for rgd controller by @shabbskagalwala in #1155
- chore: Remove myself from NOTICE by @codesenju in #1082
- chore(deps): bump webpack by @dependabot in #1027
- chore(deps): bump the npm_and_yarn group across 2 directories with 4 updates by @dependabot in #1070
- chore(deps): bump the npm_and_yarn group across 1 directory with 2 updates by @dependabot in #1087
- chore(deps): bump @tootallnate/once by @dependabot in #1089
- chore(deps): bump dompurify by @dependabot in #1092
- build: group Dependabot npm and Go security updates by @a-hilaly in #1096
- docs(website): remove pre-v0.7.0 entries from versions.json by @a-hilaly in #1111
- add jakobmoellerdev to kro-maintainers by @jlbutler in #1020
- promote nicslatts to emeritus-kro-maintainers by @jlbutler in #1044
- add verify-codegen script by @a-hilaly in #1183
New Contributors
- @NicholasBlaskey made their first contribution in #1043
- @gagahsyuja made their first contribution in #1050
- @NickKeller made their first contribution in #1073
- @mwarkentin made their first contribution in #1083
- @shivansh-source made their first contribution in #933
- @QuentinBtd made their first contribution in #1137
- @Avr8 made their first contribution in #1059
- @pnz1990 made their first contribution in #1145
- @KatharinaSick made their first contribution in #1188
Full Changelog: v0.8.5...v0.9.0