gitops-reverser

module
v0.51.0 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2026 License: Apache-2.0

README

CI OpenSSF Scorecard OpenSSF Best Practices Release codecov License Platforms Container Artifact Hub Open Issues

GitOps Reverser

GitOps Reverser watches selected Kubernetes resources and commits a clean YAML representation to Git. It strips status, managedFields, and runtime metadata. For supported layouts, it updates existing manifests in place, preserving comments and document structure.

Use it to capture live changes, bring an existing cluster into Git, or experiment with API-first workflows alongside Flux or Argo CD.

Quick start: install the operator and capture your first ConfigMap in Git.

It is pre-1.0: the CRDs are v1alpha3 and the configuration surface can still change between releases. Before you adopt it covers what to weigh.

Inspect an example commit. Named Kubernetes actors in Git history require optional audit attribution; the default uses a configured Git identity.

How it works

Changes reach the Kubernetes API however your users make them: kubectl, a GUI, a CI job, or an agent over MCP.

  1. Watch the Kubernetes API for the types each GitTarget claims, the single source of object state. A new target also reconciles all existing resources of those types into Git.
  2. Sanitize the change and compare it against what Git already holds.
  3. Write stable YAML to the target folder and push, grouping a burst of changes into one commit.

Custom resources configure it: GitProvider for repository and credentials, GitTarget for branch and folder, WatchRule or ClusterWatchRule for what to capture, and ClusterProvider for the source cluster, created as default on install. A rule selects whole resource collections, including their deletions; the GitTarget's prune mode decides whether a deletion removes the file from Git. See Configuration.

By default it watches its own cluster. Add more of each as you need them: one operator can serve several source clusters, repositories, branches, and folders.

Principles

  • Creates Git commits. The only output is Git commits that reflect the state of your cluster. Deploying is Flux's and Argo CD's job: run one alongside to bring changes from Git back into the cluster. See bi-directional usage.
  • API-first, not API-only. Most changes are assumed to arrive through the API, so that is what publishing is tuned for. Your changes end up in your remote Git repo within seconds. Other authors can push to the same branch, and that is handled without conflicts. If an API edit and a Git commit touch the same resource (which is rare!), then the API wins. See API-first publication for more depth.
  • Authors are established, never asserted. An attributed commit names the identity the API server authenticated for the change; everything else carries the configured Git identity, or an explicit unknown when attribution is on but cannot resolve. No field lets anyone type a name in. See attribution.
  • Resources classified as sensitive require encryption before commit. If encryption fails, or no encryptor is configured, the write is rejected. See SOPS and age.

Features

  • Capture existing resources and future changes. A new target captures the selected resources already in the cluster, then follows changes, including deletions under a deletion policy.
  • Mirror only the objects you label. A rule's objectSelector lets the API server choose which objects of a type are mirrored; an object that loses its label leaves the mirror like a deleted one. See selecting objects by label.
  • In-place edits keep the shape of your file. Updates preserve key order, comments, and untouched documents in multi-document files.
  • Inspect a repository before you point at it. manifest-analyzer --mode scan-repo classifies every candidate folder under a repository root, read-only and with no cluster. See cmd/manifest-analyzer/.
  • SOPS and age, set up on the fly. The operator creates the encryption configuration and can generate a missing age key in your chosen Kubernetes Secret. See SOPS and age.
  • Optional audit attribution identifies Kubernetes actors. Without it, commits carry the configured Git identity; when attribution cannot be resolved, they carry an explicit unknown author. See audit attribution.
  • Custom commit messages. Separate templates for live windows, reconciles, and save requests. See message templates.
  • SSH-signed commits. Configured through GitProvider.spec.commit.signing. See commit signing.
  • kubectl wait works on every resource. Conditions follow the kstatus convention, so Ready, Reconciling, and Stalled mean what GitOps tooling expects. See status conditions.
  • Metrics on a standard endpoint. Scrape /metrics with whatever you already run, or turn on the chart's ServiceMonitor. The docs carry example queries for the questions operators ask, and a named list of what is deliberately not instrumented. See interpreting metrics.

What it can write

Choose the resources to watch and the repository, branch, and folder to write into.

Your source in Git What you can do
Plain Kubernetes manifests Capture resources and update their existing YAML documents
Supported Kustomize layouts Update source manifests or image/replica declarations; add and remove resources
A Flux HelmRelease or Argo CD Application Capture the declaration, including chart versions and inline values
Helm templates or standalone values.yaml No writeback from rendered workloads

Kustomize support includes local bases and overlays, with the base kept read-only when targeting an overlay. Generators, components, remote bases, and several other transforms are unsupported: a folder that uses them is refused with Stalled=True and a reason, while the folder is still untouched. See the supported subset.

Select the resources that express your intent. For example, watch a HelmRelease to capture chart settings. The operator cannot automatically distinguish authored resources from controller-generated ones. See choosing what to capture.

Quick start

Follow the installation walkthrough to capture ConfigMaps from a demo namespace into a disposable repository. You need a Kubernetes cluster, kubectl, Helm 3, and Git write access. The walkthrough includes cert-manager setup; Redis and audit delivery are optional.

The demo captures a live change:

kubectl create configmap test-config --from-literal=key=value -n gitops-reverser-quickstart-demo

Inspect the commit under live-cluster/ in your repository. Then edit the ConfigMap and inspect the next diff. The walkthrough includes status checks, troubleshooting, and cleanup.

Batch changes into a commit

Changes for the same target and author share a commit window, and each window becomes one commit. When a window closes is yours to tune: its timers are set per GitTarget, and a CommitRequest can bring its own timers along with the commit message. This allows the person making a change to explain why the change was necessary.

Kubernetes resource changes flow through GitOps Reverser's commit window into Git

The picture shows the commit-window example running. It carries the manifests: a GitTarget with a window, a WatchRule selecting the two types, and a save request made after the changes or before them. It runs on top of the quickstart above.

Try it with your existing repo

Start with a scratch branch containing your existing manifests, with no reconciler deploying that branch. Select a small resource scope and one destination folder. Inspect the initial commits before making a live edit, then check which source files changed.

The operator pushes directly to the configured branch. If you later write to a branch that Flux or Argo CD deploys, read the bidirectional guide first. Live edits can be reverted by the reconciler, and replaying captured state can overwrite concurrent Git edits to the same object. Decide per folder which side is authoritative.

Before you adopt it

The CRDs are v1alpha3, so the configuration surface can change between releases; docs/UPGRADING.md carries each migration. Keep one GitProvider per repository, so that two of them never write the same paths.

  • Access: the chart defaults to cluster-wide read access, including Secrets. Review RBAC to restrict watched types and understand the remaining credential permissions.
  • History: batching can collapse intermediate edits. Unpublished work is held in memory and can be lost on restart; recovery captures current state. Git history is not a complete event log.
  • Deletes: the default mirrors observed delete events but retains documents absent from a reconnect snapshot. Choose a deletion policy that fits your repository.
  • Versions: tested against Kubernetes 1.37 at the API level (envtest) and 1.36 end-to-end (k3s, which has no stable 1.37 release yet). Other versions may work but are not in the matrix. Importing this repo as a Go module carries its own version floor; see docs/UPGRADING.md.

It runs one replica, with no standby failover: the chart rejects replicaCount > 1 rather than let two instances write the same repository. Ownership coordination and a durable worker queue are on the way to 1.0. The backlog is in docs/TODO.md, and longer-range directions in docs/future/.

Rather have it managed?

ConfigButler can run a small, secure, public-facing Kubernetes API for you: we operate GitOps Reverser and authorize your end users, with forward-deployed engineers to get you started. You keep a clean, self-owned Git repo where your users express their intent.

Documentation and feedback

Trying it with a real repo? Open an issue with the layout you tried, the diff you expected, and what happened. Install attempts, first-commit experience, audit delivery, Git output shape, and CRD ergonomics are the most useful reports at this stage. Contributions are welcome; see CONTRIBUTING.md.

Or connect on LinkedIn: feedback, questions, and ideas are all welcome.

Licensed under Apache 2.0.

Directories

Path Synopsis
api
v1alpha3
Package v1alpha3 contains API Schema definitions for the configbutler.ai v1alpha3 API group.
Package v1alpha3 contains API Schema definitions for the configbutler.ai v1alpha3 API group.
cmd
gitea-signing-debug command
gitea-signing-debug drives the full SSH-signed-commit flow against a live Gitea and reports Gitea's commit verification verdict at every stage.
gitea-signing-debug drives the full SSH-signed-commit flow against a live Gitea and reports Gitea's commit verification verdict at every stage.
manifest-analyzer command
manifest-analyzer is a standalone, read-only CLI that analyzes a folder of Kubernetes manifests.
manifest-analyzer is a standalone, read-only CLI that analyzes a folder of Kubernetes manifests.
mutation-capture-lab command
Command mutation-capture-lab is the mutation-capture lab binary: a minimal set of recorders (native watch, audit webhook, validating admission webhook) whose output is a versioned corpus of the exact structures Kubernetes emits.
Command mutation-capture-lab is the mutation-capture lab binary: a minimal set of recorders (native watch, audit webhook, validating admission webhook) whose output is a versioned corpus of the exact structures Kubernetes emits.
hack
crdfields command
Command crdfields renders the settings index in docs/configuration.md from the CRD schemas in config/crd/bases, so the table cannot drift from the API.
Command crdfields renders the settings index in docs/configuration.md from the CRD schemas in config/crd/bases, so the table cannot drift from the API.
doccheck command
Command doccheck verifies that every documentation reference in the repository resolves to a file that exists.
Command doccheck verifies that every documentation reference in the repository resolves to a file that exists.
internal
attribution
Package attribution holds the per-audit-route bookkeeping the attribution pipeline shares across its two halves: the audit ingress that PUBLISHES facts and the watch resolver that READS them.
Package attribution holds the per-audit-route bookkeeping the attribution pipeline shares across its two halves: the audit ingress that PUBLISHES facts and the watch resolver that READS them.
audit/outcome
Package outcome defines the single, bounded vocabulary for what the audit ingestion pipeline did with one event — its "outcome" — and records it on the gitopsreverser_audit_events_total counter.
Package outcome defines the single, bounded vocabulary for what the audit ingestion pipeline did with one event — its "outcome" — and records it on the gitopsreverser_audit_events_total counter.
auditutil
Package auditutil contains shared Kubernetes audit-event parsing helpers.
Package auditutil contains shared Kubernetes audit-event parsing helpers.
authz
Package authz holds the ClusterProvider namespace-admission decision.
Package authz holds the ClusterProvider namespace-admission decision.
controller
Package controller contains shared constants for all controllers.
Package controller contains shared constants for all controllers.
git
Package git provides Git repository operations and abstractions for the GitOps Reverser controller.
Package git provides Git repository operations and abstractions for the GitOps Reverser controller.
git/manifestedit
Package manifestedit is an isolated proof of concept for the manifest-inventory "file-agnostic placement" feature.
Package manifestedit is an isolated proof of concept for the manifest-inventory "file-agnostic placement" feature.
giteaclient
Package giteaclient is a small, focused Gitea REST client used by e2e tests and debug tools.
Package giteaclient is a small, focused Gitea REST client used by e2e tests and debug tools.
kubeconfig
Package kubeconfig resolves and safety-checks a source-cluster kubeconfig held in a Secret, shared by the watch data plane's SourceClusterResolver and the GitTarget controller's Validated gate so both apply exactly one contract: Flux's value→value.yaml key order, and a REJECT — not Flux's silent strip — of exec auth providers and insecure-skip-tls-verify.
Package kubeconfig resolves and safety-checks a source-cluster kubeconfig held in a Secret, shared by the watch data plane's SourceClusterResolver and the GitTarget controller's Validated gate so both apply exactly one contract: Flux's value→value.yaml key order, and a REJECT — not Flux's silent strip — of exec auth providers and insecure-skip-tls-verify.
layoutfixture
Package layoutfixture reads the expected-*-status.yaml fixtures under test/fixtures/layout-corpus.
Package layoutfixture reads the expected-*-status.yaml fixtures under test/fixtures/layout-corpus.
manifestanalyzer
Package manifestanalyzer is a runtime-independent analyzer for a folder of Kubernetes manifests.
Package manifestanalyzer is a runtime-independent analyzer for a folder of Kubernetes manifests.
manifestreport
Package manifestreport is the integration layer that drives the cluster-free manifestedit library against a real repository and cluster state.
Package manifestreport is the integration layer that drives the cluster-free manifestedit library against a real repository and cluster state.
mutationlab
Package mutationlab holds the mutation-capture lab: a small, separate application that records the exact structures Kubernetes exposes through native watches, audit webhooks, and validating admission webhooks, and commits those structures as a versioned corpus.
Package mutationlab holds the mutation-capture lab: a small, separate application that records the exact structures Kubernetes exposes through native watches, audit webhooks, and validating admission webhooks, and commits those structures as a versioned corpus.
mutationlab/corpus
Package corpus turns captured records into the browsable golden tree: one directory per scenario, one file per emitted moment, named so an ordered fan-out is self-describing (watch.deleted.cm-a.yaml, ...).
Package corpus turns captured records into the browsable golden tree: one directory per scenario, one file per emitted moment, named so an ordered fan-out is self-describing (watch.deleted.cm-a.yaml, ...).
mutationlab/labserver
Package labserver assembles the lab's HTTP surface: the read/clear records API and the health endpoint.
Package labserver assembles the lab's HTTP surface: the read/clear records API and the health endpoint.
mutationlab/normalize
Package normalize rewrites the volatile fields of captured Kubernetes payloads to stable, relational placeholders so the lab corpus changes only when behavior changes — never when a run merely produces fresh UIDs, resource versions, or timestamps.
Package normalize rewrites the volatile fields of captured Kubernetes payloads to stable, relational placeholders so the lab corpus changes only when behavior changes — never when a run merely produces fresh UIDs, resource versions, or timestamps.
mutationlab/recorder
Package recorder turns live Kubernetes observations — audit webhook posts, admission reviews, and native watch events — into mutationlab.Record values in the store.
Package recorder turns live Kubernetes observations — audit webhook posts, admission reviews, and native watch events — into mutationlab.Record values in the store.
mutationlab/store
Package store is the lab's in-memory record store.
Package store is the lab's in-memory record store.
rulestore
Package rulestore manages the in-memory cache of compiled WatchRule configurations.
Package rulestore manages the in-memory cache of compiled WatchRule configurations.
sanitize
Package sanitize removes server-generated fields from Kubernetes objects.
Package sanitize removes server-generated fields from Kubernetes objects.
ssh
Package ssh provides SSH authentication utilities for Git operations.
Package ssh provides SSH authentication utilities for Git operations.
telemetry
Package telemetry provides the OpenTelemetry-based metrics exporter for GitOps Reverser.
Package telemetry provides the OpenTelemetry-based metrics exporter for GitOps Reverser.
types
Package types provides common type definitions used across the GitOps Reverser.
Package types provides common type definitions used across the GitOps Reverser.
typeset
Package typeset is GitOps Reverser's single decision surface for "is this resource type followable, and if not, what is the one reason it is not?".
Package typeset is GitOps Reverser's single decision surface for "is this resource type followable, and if not, what is the one reason it is not?".
watch
Package watch drives the api-source-of-truth reconcile: it keeps the followability registry and the per-GitTarget watched-type tables fresh, and mirrors each watched type into Git from a long-lived Kubernetes watch per claimed (GitTarget, GVR, scope).
Package watch drives the api-source-of-truth reconcile: it keeps the followability registry and the per-GitTarget watched-type tables fresh, and mirrors each watched type into Git from a long-lived Kubernetes watch per claimed (GitTarget, GVR, scope).
yamlstyle
Package yamlstyle owns the one YAML serialization style this product writes to Git.
Package yamlstyle owns the one YAML serialization style this product writes to Git.
pkg
manifestanalyzer
Package manifestanalyzer is the public answer to two questions a tool built around GitOps Reverser needs to ask about a Git repository, without a cluster and without writing anything:
Package manifestanalyzer is the public answer to two questions a tool built around GitOps Reverser needs to ask about a Git repository, without a cluster and without writing anything:
test
e2e
Package e2e provides helper functions for end-to-end testing of the GitOps Reverser controller.
Package e2e provides helper functions for end-to-end testing of the GitOps Reverser controller.
e2e/tools/ginkgo-allure command
ginkgo-allure converts Ginkgo JSON reports into Allure result files.
ginkgo-allure converts Ginkgo JSON reports into Allure result files.
e2e/tools/spec-timings command
spec-timings reads a Ginkgo JSON report and prints a duration-sorted table of specs with each spec's share of the total wallclock.
spec-timings reads a Ginkgo JSON report and prints a duration-sorted table of specs with each spec's share of the total wallclock.
e2e/tools/ts command
ts prefixes each stdin line with the elapsed seconds since startup and the current wallclock, then writes it to stdout.
ts prefixes each stdin line with the elapsed seconds since startup and the current wallclock, then writes it to stdout.
loadtest command
SPDX-License-Identifier: Apache-2.0
SPDX-License-Identifier: Apache-2.0
mutationlab/e2e
Package e2e drives the mutation-capture lab against a live cluster: it runs each scenario, drains the lab's records API, and compares (or, with MUTATIONLAB_UPDATE=1, rewrites) the golden corpus.
Package e2e drives the mutation-capture lab against a live cluster: it runs each scenario, drains the lab's records API, and compares (or, with MUTATIONLAB_UPDATE=1, rewrites) the golden corpus.
utils
Package utils provides utility functions for e2e testing.
Package utils provides utility functions for e2e testing.

Jump to

Keyboard shortcuts

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