Help us shape the future of Go! Take the 2026 Go Developer Survey

gitops-reverser

module
v0.55.0 Latest Latest
Warning

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

Go to latest
Published: Oct 27, 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 is a Kubernetes operator that turns cluster activity into clean YAML commits.

GitOps keeps the desired state of a cluster in Git, so every change has to arrive as a commit. That requires everyone who makes a change to know Git, YAML, and the layout of your repo. With GitOps Reverser they use the Kubernetes API instead: kubectl, a GUI, a CI job, or an AI agent over MCP. It commits the result within seconds, and Flux or Argo CD keeps deploying from the repo. The operator is deterministic, with no AI at runtime.

Quick start · Documentation

Inspect an example commit. Its named Kubernetes actor comes from optional audit attribution; the default uses a configured Git identity.

Why GitOps Reverser

Use it to:

  • Let people change the cluster without learning Git. A GUI, a CI job, or an MCP agent works through the Kubernetes API, under its RBAC and admission control, and the change still lands in Git with the rest of your history.
  • Bring an existing cluster into Git. A new target commits the selected resources already in the cluster, then follows their changes.
  • Keep Git in step with live edits. A kubectl fix made during an incident becomes a commit instead of drift.

What sets it apart:

  • Your files keep their shape. An update edits the existing YAML document in place: key order, comments, and untouched documents in multi-document files survive. In a supported Kustomize layout it edits the source manifest, not the rendered output. See what it can write.
  • Authors are established, never asserted. With audit attribution, a commit names the identity the API server authenticated, and no field lets anyone type a name in. It needs kube-apiserver flags, so managed control planes that hide them cannot use it. See attribution.
  • A commit can say why. Changes are grouped into commit windows, and a CommitRequest lets the person making a change explain why it was necessary. See commit windows.

How it works

  1. Watch the Kubernetes API for the types each GitTarget claims, the single source of object state.
  2. Sanitize the change, stripping status, managedFields, and runtime metadata, 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.

A GitTarget names a folder on a Git branch, and a WatchRule or ClusterWatchRule says what to capture into it. A few more custom resources hold the repo, its credentials, and the source cluster. By default it watches its own cluster, and one operator can serve several source clusters, repos, branches, and folders. See Configuration.

What it can write
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, image/replica declarations, and configMapGenerator input files; 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

Local Kustomize bases and overlays work, with the base kept read-only. A configMapGenerator with disableNameSuffixHash: true is writable: a ConfigMap edit lands in the file, .env line or literal it came from, and deleting the ConfigMap removes its generator entry. secretGenerator, hash-suffixed generators, components, and remote bases are unsupported; such a folder is refused with Stalled=True before anything is written. See the supported subset.

Watch the resources that express your intent, such as a HelmRelease rather than the workloads it renders: the operator cannot tell authored resources from generated ones. See choosing what to capture.

Commit windows

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.

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

The picture shows the commit-window example running on top of the quick start.

Bi-directional GitOps with Flux and Argo CD

GitOps Reverser writes commits; Flux or Argo CD deploys them. Others can push to the same branch: the operator replays its writes on top of their commits, so history stays linear with no merge commits. If both touch the same resource, the API wins (API-first publication).

Quick start

Follow the installation walkthrough to capture ConfigMaps from a demo namespace into a disposable repo. You need a Kubernetes cluster, kubectl, Helm 3, and Git write access. Redis, audit delivery and cert-manager are optional: they come in with named commit authors.

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 repo. Then edit the ConfigMap and inspect the next diff. The walkthrough includes status checks, troubleshooting, and cleanup.

Features

  • 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.
  • Secrets never reach Git in plaintext. Resources classified as sensitive are encrypted with SOPS and age before commit, or the write is rejected. The operator creates the encryption configuration and can generate a missing age key. See SOPS and age.
  • Inspect a repo before you point at it. manifest-analyzer --mode scan-repo classifies every candidate folder under a repo root, read-only and with no cluster. See cmd/manifest-analyzer/.
  • The operational basics. SSH-signed commits and custom commit message templates. Conditions follow the kstatus convention, so kubectl wait works on every resource (status conditions). Metrics are on a standard /metrics endpoint, with an optional ServiceMonitor and example queries.

Adopting it

Try it with your existing repo

Start with a scratch branch containing your existing manifests, with nothing 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 Flux or Argo CD deploys the folder you write, read bi-directional GitOps with Flux and Argo CD first.

Limits before 1.0

It is pre-1.0: the CRDs are v1alpha3, so the configuration surface can change between releases; docs/UPGRADING.md carries each migration.

  • 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 repo.
  • Availability: it runs one replica, with no standby failover: the chart rejects replicaCount > 1 rather than let two instances write the same repo.
  • Versions: the test suites run against Kubernetes 1.37, at the API level with envtest and end-to-end on k3s. Other versions may work but are not in the matrix.

The road to 1.0 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, and our engineers work with your team 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, or reach out on LinkedIn. Install attempts, Git output shape, and CRD ergonomics are the most useful reports at this stage. Contributions are welcome; see CONTRIBUTING.md.

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
apidocwidth command
Command apidocwidth checks that every line of an API doc comment fits in 76 characters after the "// " prefix.
Command apidocwidth checks that every line of an API doc comment fits in 76 characters after the "// " prefix.
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
applier
Package applier delivers apply requests: what GitOps Reverser sends the object that applies a GitTarget's folder back to its source cluster (its applier) when the branch worker has decided a commit is safe to apply.
Package applier delivers apply requests: what GitOps Reverser sends the object that applies a GitTarget's folder back to its source cluster (its applier) when the branch worker has decided a commit is safe to apply.
applier/argosim
Package argosim is the API server's field ownership of an Argo CD Application's automated sync switch, spec.syncPolicy.automated.enabled, for tests of code that holds it.
Package argosim is the API server's field ownership of an Argo CD Application's automated sync switch, spec.syncPolicy.automated.enabled, for tests of code that holds it.
applier/fluxsim
Package fluxsim is a fake source cluster running kustomize-controller and source-controller, for tests of code that drives Flux.
Package fluxsim is a fake source cluster running kustomize-controller and source-controller, for tests of code that drives Flux.
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 admission decisions for the objects that lend something: a GitProvider's credential (spec.allowedGitBranches), a GitBranch (spec.allowedGitTargets), and a KubeProvider's cluster connection (spec.allowedGitTargets, spec.allowedApplierClaims).
Package authz holds the admission decisions for the objects that lend something: a GitProvider's credential (spec.allowedGitBranches), a GitBranch (spec.allowedGitTargets), and a KubeProvider's cluster connection (spec.allowedGitTargets, spec.allowedApplierClaims).
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.
repourl
Package repourl decides whether two spellings of a Git repository URL name the same repository.
Package repourl decides whether two spellings of a Git repository URL name the same repository.
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.
mutationlab/tools/lab-certs command
Command lab-certs issues the mutation-capture lab's certificates before its cluster exists: one CA, a serving certificate for the lab's Service, and a client certificate for the API server, which it writes into the audit webhook kubeconfig the cluster is created with.
Command lab-certs issues the mutation-capture lab's certificates before its cluster exists: one CA, a serving certificate for the lab's Service, and a client certificate for the API server, which it writes into the audit webhook kubeconfig the cluster is created with.
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