Skip to content

Changelog

All notable changes to kardinal-promoter are documented here. Format follows Keep a Changelog. Versioning follows Semantic Versioning.


Unreleased

UI accessibility compliance, DX polish, keyboard shortcuts

Added

  • kardinal-agent standalone binary — separate binary for spoke-cluster distributed mode (cmd/kardinal-agent/); runs only the PromotionStep reconciler for a specific shard, without Bundle, Pipeline, PolicyGate, UI, or webhook components. Required flag: --shard. Defaults to ports :8085/:8086 to avoid collision with the controller. (#886)
  • kubectl get printer columns on Bundle and PromotionStep CRDskubectl get bundle now shows Type, Pipeline, Phase, Age; kubectl get promotionstep (shortname: ps) now shows Pipeline, Env, Bundle, State, Age. No more kubectl describe to find which pipeline a step belongs to. (#903)
  • WaitingForMerge timeoutenvironment.waitForMergeTimeout on Pipeline environments (e.g. waitForMergeTimeout: "24h") causes a PromotionStep stuck waiting for a PR reviewer to transition to Failed after the configured duration. No timeout by default (no behavior change for existing pipelines). Closes production-blocker: abandoned PR reviews no longer stall pipelines indefinitely. (#906)
  • Shell completionkardinal completion bash|zsh|fish|powershell (#731)
  • Color output for kardinal explain--color flag, auto-detected TTY; Pass=green, Block=red, Pending=yellow (#730)
  • Dark/light mode — system-aware theme with manual toggle in the embedded UI (#734)
  • Prometheus metricskardinal_bundles_total{phase}, kardinal_steps_total{type,result}, kardinal_gate_evaluations_total{result}, kardinal_pr_duration_seconds histogram emitted from reconcilers (#726)
  • kardinal validate — validate Pipeline and PolicyGate YAML files offline; checks CEL syntax and schema (#713)
  • kardinal status — show controller health, CRD versions, and resource summary (#715)
  • Improved explain errorkardinal explain <pipeline> --env <bogus> now lists available environments (#717)
  • Improved circular dependency error — cycle path displayed in full (#711)
  • --dry-run for kardinal create bundle — print what would be created without submitting; useful for CI validation (#741)
  • URL routing in embedded UI — selecting a pipeline, node, or bundle diff panel updates the URL hash fragment; page reload and back/forward navigation restore selection (#742)
  • Keyboard shortcuts in embedded UI? opens help panel, r refreshes, Esc closes panels (#750)
  • Error boundaries on async UI components — DAGView, PipelineList, NodeDetail, BundleTimeline show a user-friendly message + Retry on render error (#755)
  • WCAG 2.1 AA accessibility enforcement — axe-core Playwright check in E2E test suite (Journey 009); all structural violations resolved (#756, #759, #760)
  • Copy-to-clipboard on pipeline names and bundle hashes — click to copy pipeline name, bundle name, or commit SHA in the embedded UI (#764)
  • Stale data indicator escalation — red + pulse animation when dashboard data is >30s old; screen reader announcement via aria-live (#767)
  • Skeleton loading states — NodeDetail step details, BundleTimeline chips, and PolicyGatesPanel now show animated shimmer placeholders instead of blank panels while data loads (#784)
  • / keyboard shortcut to focus pipeline search — pressing / anywhere (except when an input is focused) moves keyboard focus to the pipeline filter input; Esc inside the filter clears and blurs; / listed in the ? shortcut help modal (#800)
  • Responsive layout at 1280px — Journey 010 Playwright test formalizes the no-overflow guarantee at 1280×800 viewport (#806)
  • Virtual scrolling for pipeline list@tanstack/react-virtual used for flat lists exceeding 50 entries; multi-namespace grouped display falls back to normal rendering (#817)
  • Full adapter demo coverage — examples, unit tests, and docs/demo-validation.md for all 5 health adapters: resource, argocd, flux, argoRollouts, flagger (#821)
  • kardinal delete bundle <name> — new CLI command to explicitly delete a Bundle by name, cancelling any in-progress promotion (#851)

Changed

  • UI CSS theme tokens — migrated 206 hardcoded hex color values to CSS custom properties (--color-* tokens); consistent theming across dark/light mode (#738)
  • UI WCAG color contrast — all theme colors now meet WCAG 2.1 AA 4.5:1 minimum contrast ratio in both dark and light modes (#760)
  • krocodile upgraded to 3376810 — correctness fix: propagation trigger on self-state refresh. Without this, UAT PromotionStep was never created after test reached Verified. Also includes NodeState sync guard and ForEach typed binding (#789)
  • krocodile upgraded to d6cbc54 — additive forEach incremental diff optimization (O(K) vs O(N) rehash), WatchManager canonical Kind caching fix. No breaking changes (#803)

Fixed

  • Demo Validate nightly workflow — missing issues: write permission caused GraphQL: Resource not accessible by integration (addComment) on every scheduled run; fixed and improved to post to the current daily report issue instead of hard-coded #1 (#801)
  • UAT never starting after test Verified — krocodile Path 2 (self-state refresh) now correctly marks dependents as propagationTriggered; UAT PromotionStep is created once test PS writes status.state=Verified (#789)
  • AbortedByAlarm / RollingBack cycling — PromotionStep reconciler now handles AbortedByAlarm and RollingBack as explicit terminal/managed cases, preventing fall-through to default which incorrectly reset state to Pending (#789)

v0.8.1 — 2026-04-17

Security release: supply chain hardening — trivy, cosign, SBOM, SLSA, krocodile scan


v0.8.0 — 2026-04-17

Audit log, SCM circuit breaker, Bundle Watch node, Graph-first cleanup, DX improvements


v0.7.0 — 2026-04-17

WatchKind O(1) health checks, krocodile 81c5a03 upgrade, reactive PromotionStep reconciler, graph-first cleanup

Added

  • WatchKind health nodeshealth.labelSelector on Pipeline environments switches from Watch (O(n) full list per event) to WatchKind (O(1) incremental cache). Requires krocodile 745998f+ (#652)
  • Kargo migration guide — concept mapping, side-by-side Pipeline vs Kargo YAML, 7-step migration walkthrough in docs/guides/ (#640)
  • Operations runbook expanded — PolicyGate debugging, SCM failure modes, RBAC issues, krocodile restarts, performance tuning added (#639)
  • Bundle image diff in NodeDetail — UI compares the current bundle's image against the previous bundle for that environment; closes a Kargo parity gap (#638)
  • Per-step progress observabilityPromotionStep.status.steps[] exposes each step with individual state, start time, and duration (#630)
  • kardinal get pipelines --watch — real-time promotion progress with live table refresh (#629)
  • PrometheusRule CRD — 6 pre-built alerting rules in Helm chart: promotion stuck, high rollback rate, policy gate blocked, SCM errors (#621)
  • UI: conditions summary and reason — NodeDetail shows Kubernetes Conditions table with reason column; improved empty-state onboarding (#529, #530)
  • UI: Kubernetes events stream — timestamped event history per PromotionStep in NodeDetail (#560)
  • UI: cross-environment error aggregation — groups PromotionStep failures by type across environments; shows affected count (#564)
  • krocodile upgraded to 745998f — Decorator bootstrap primitive, Definition compile-time type inference, forEach array format support, DAG finalizer guard for non-resource nodes (#614)

Fixed

  • Bundle reconciler watches Pipeline changes — Graph is regenerated when Pipeline spec changes (new environments, updated policyNamespaces, changed git config). Previously Pipeline changes were invisible to in-flight Bundles (#634)
  • Subscription deduplication under HA — uses label selector (kardinal.io/source-digest) instead of status field comparison; safe under concurrent reconciles and multiple controller replicas (#636)
  • CEL documentation accuracy — corrected false claims about pkg/cel/NewCELEnvironment() (does not exist) and schedule.* (map variable, not CEL library function) in design docs and code comments (#631)
  • Shell completion — bash, zsh, fish, and PowerShell completion scripts via kardinal completion <shell> (#606)
  • kardinal doctor — pre-flight cluster health check: validates CRD installation, krocodile, RBAC, and GitHub token before first use (#607)
  • Graceful shutdown — controller drains in-flight reconcile loops on SIGTERM; no promotion steps interrupted by pod restarts (#605)
  • PodDisruptionBudget + topology spread — minAvailable: 1 PDB and topologySpreadConstraints in Helm chart for HA deployments (#598)
  • krocodile bundled in Helm chart — single helm install now installs both kardinal-promoter and the krocodile Graph controller; no separate hack/install-krocodile.sh step needed (#590)
  • Library-based git operations — replaced exec.Command("git") with go-git library (#517). Controller no longer requires a git binary. Improves portability (distroless images) and performance.
  • Controller /tmp mount — emptyDir volume added for git-clone with readOnlyRootFilesystem: true (#609)
  • policy simulate now searches all namespaces — org-level gates in platform-policies were never found
  • pkg/cel standalone CEL evaluator eliminated — evaluation moved inline to PolicyGate reconciler
  • Rollback PR title and body now include rollback notice and the kardinal/rollback label

v0.6.0 — 2026-04-14

Live-cluster validation infrastructure, J7 multi-tenant self-service, OCI/Git source watchers, pipeline deployment metrics

Added

  • Multi-tenant self-service (J7) — ApplicationSet + Pipeline template bootstrap; team onboarding via Git directory; org PolicyGates automatically inherited (#489)
  • OCI + Git source watchersOCIWatcher and GitWatcher Subscription reconcilers poll registries and Git branches, creating Bundles on new images/commits (#491, #493)
  • Pipeline deployment metricsPipeline.status.deploymentMetrics aggregated by PipelineReconciler: rolloutsLast30Days, p50CommitToProdMinutes, p90CommitToProdMinutes, autoRollbackRate (#498)
  • changewindow.isAllowed() / changewindow.isBlocked() CEL functions — named-argument helpers for ChangeWindow gates (#506)
  • krocodile upgraded to 948ad6c — DNS-1123 node ID validation, drift timers (30 min), propagation hash includes propagateWhen state
  • Cardinal logo — added across docs site, UI sidebar, and README

Fixed

  • kardinal-promoter controller image rebuilt correctly when Graph CR is deleted externally (#490)
  • PDCA live-cluster validation workflow: fixed pipeline name mismatch, missing platform-policies namespace, missing controller install step (#514)
  • CI: enforce_admins: true on branch protection; 8 required status checks; concurrency guards on Docs and E2E workflows (#513)

v0.5.0 — 2026-04-13

Pipeline Expressiveness (K-Series), Enterprise UI Control Plane, krocodile upgrade

Added

  • K-01: Contiguous healthy soakbake.minutes + bake.policy: reset-on-alarm on environment spec; BakeElapsedMinutes and BakeResets tracked in PromotionStep status
  • K-02: Pre-deploy gate typewhen: pre-deploy on PolicyGate spec; blocks PromotionStep in Waiting state before git-clone starts
  • K-03: Auto-rollback with ABORT vs ROLLBACK distinctiononHealthFailure: rollback | abort | none per environment
  • K-04: ChangeWindow CRD — blackout and recurring allowed-hours windows; changewindow["name"] CEL function evaluates to true when the window is active/blocking
  • K-05: Bundle.status.metrics — commitToFirstStageMinutes, commitToProductionMinutes, bakeResets, operatorInterventions; kardinal metrics CLI command
  • K-06: Wave topologywave: N field on environment spec; Wave N automatically depends on all Wave N-1 stages
  • K-07: Integration test step — built-in integration-test step runs a Kubernetes Job as part of the promotion sequence
  • K-08: PR review gatebundle.pr["staging"].isApproved and .approvalCount in CEL context via PRStatus CRD
  • K-09: kardinal override with audit record — emergency gate override with mandatory reason + time limit; override record in Bundle status and PR evidence body
  • K-10: Cross-stage history CELupstream.<env>.soakMinutes, .recentSuccessCount, .recentFailureCount, .lastPromotedAt in gate expressions
  • UI control plane — all 7 UI issues shipped (#462–#468): fleet health dashboard, pipeline ops view, per-stage bake countdown, in-UI actions (pause/resume/rollback/override), release metrics bar, bundle timeline, policy gate detail panel

Fixed

  • krocodile upgraded to 948ad6c — DNS-1123 node ID validation, drift timers, propagation hash improvements
  • changewindow.isAllowed() / changewindow.isBlocked() CEL helpers added alongside the map-style access

v0.4.0 — 2026-04-12

Distributed Mode, Argo Rollouts delegation, graph purity, K-series features

Added

  • Distributed mode--shard flag routes PromotionSteps to matching shard agents; supports multi-cluster deployments where each spoke cluster runs its own agent
  • Argo Rollouts delivery delegationdelivery.delegate: argo-rollouts in Pipeline env spec hands off rollout progression to an existing Rollout resource
  • GitLab + Forgejo/Gitea SCM providersscm.provider: gitlab and scm.provider: forgejo in Pipeline spec
  • PRStatus CRD — makes PR merge/close signal observable by the Graph (eliminates 6 GitHub API call paths from the reconciler hot path)
  • RollbackPolicy CRD — auto-rollback threshold comparison moved to dedicated reconciler
  • Graph purity milestone — all 41 krocodile-independent logic leaks eliminated (see docs/design/11-graph-purity-tech-debt.md)
  • K-01–K-11 — all Pipeline Expressiveness features (see v0.5.0 above for full list; initial implementation in this release)

Fixed

  • Pause enforcement via bundle.status.paused (eliminates in-memory pause state)
  • Step cleanup on pipeline deletion no longer leaves orphaned PromotionSteps
  • PolicyGate re-evaluation after TTL now fires correctly when graph resumes

v0.3.0 — 2026-04-12

Observability: embedded UI, PR evidence, GitHub Actions

Added

  • Embedded React UI — promotion DAG visualization with 6-state health chips, CEL expression display, live polling with staleness indicator, blocked-gate banner
  • PR evidence body — structured markdown in every prod PR: image digest, CI run link, gate results, upstream soak time
  • kardinal diffkardinal diff <bundle-a> <bundle-b> shows artifact delta
  • kardinal approve — approve a Bundle bypassing upstream gate requirements
  • kardinal metrics — DORA-style promotion metrics (deployment frequency, lead time, fail rate)
  • kardinal refresh / dashboard / logs — operational CLI commands
  • History commandkardinal history <pipeline> shows previous promotions

Fixed

  • DAG graph deduplicates gate nodes (was showing duplicate PolicyGate cards)
  • Pipeline phase uses status.phase not condition reason for display
  • Explain command deduplicates gate output when multiple instances match

v0.2.1 — 2026-04-12

Graph Purity: all krocodile-independent logic leaks eliminated

Added

  • PRStatus CRD — replaces in-reconciler GitHub API polling for PR state
  • RollbackPolicy CRD — moves auto-rollback threshold logic out of PromotionStepReconciler
  • ScheduleClock CRD — writes status.tick on a configurable interval to drive time-based policy gate re-evaluation via real Kubernetes watch events; replaces the ctrl.Result{RequeueAfter} timer loop pattern

Fixed

  • time.Now() calls moved outside reconciler hot paths into CRD status writes
  • Cross-CRD status mutations eliminated — each reconciler writes only to its own CRD
  • exec.Command() in reconciler replaced with library call

v0.2.0 — 2026-04-11

Workshop 1 Complete — first end-to-end validated release

Milestone

kardinal-promoter now executes the AWS Platform Engineering on EKS workshop end-to-end on a live kind cluster.

Added

  • MetricCheck CRD — Prometheus-backed policy gates: block promotions when error rate > threshold
  • Custom promotion steps — HTTP webhook steps for extensible promotion workflows
  • Auto-rollback — configurable failure threshold triggers rollback PR after N consecutive health failures
  • Pause/resumekardinal pause/resume <pipeline> halts in-flight promotions
  • Policy simulatekardinal policy simulate evaluates gates without creating a Bundle
  • Policy testkardinal policy test validates CEL syntax offline
  • Policy list — lists active PolicyGates scoped to a pipeline/environment
  • Promote commandkardinal promote creates a Bundle from the last verified image
  • Config Bundle type — promotes Git commit SHAs through the same pipeline as image Bundles
  • Rendered manifests steppre-render strategy generates environment-specific YAML

Fixed

  • kind E2E infrastructure (make setup-e2e-env) sets up krocodile + ArgoCD + test/uat/prod namespaces
  • kardinal get pipelines shows per-environment status columns
  • kardinal explain shows active PolicyGates with CEL expression and current value

v0.1.0 — 2026-04-11

Foundation: CRDs, Controller, Graph Integration, PolicyGate

Added

  • Go module scaffold — directory layout, Makefile, CI pipeline (build/lint/test/vet)
  • CRD types — Pipeline, Bundle, PolicyGate, PromotionStep (kubebuilder markers, deep copy, validation)
  • Controller manager — BundleReconciler, PipelineReconciler, PromotionStepReconciler, PolicyGateReconciler
  • Helm chart — controller deployment, RBAC, CRDs packaged for OCI registry
  • Graph integration — kro Graph builder and translator: Pipeline → Graph spec
  • PolicyGate CEL evaluator!schedule.isWeekend, upstream.uat.soakMinutes >= 30, kro CEL library
  • SCM provider — GitHub: push branch, open PR, detect merge, post comments
  • Health adapters — Kubernetes Deployment readiness, ArgoCD Application sync, Flux Kustomization
  • Steps engine — kustomize-set-image, helm-set-image, git-commit, open-pr, wait-for-merge, health-check
  • CLI foundationkardinal get pipelines/bundles/steps, kardinal explain, kardinal rollback, kardinal version, kardinal init
  • Embedded React UI — scaffolded with Vite + React 19, embedded via go:embed