GitOps Mode

GitOps mode writes the assembled haproxy.cfg to a git repository instead of posting to the Dataplane API. It is the right destination when configuration changes need to go through code review, when HAProxy is deployed by a pipeline rather than managed by hand, or when policy requires an auditable trail.

How it works

The canvas and draft are identical to live mode. What changes is the final step: instead of a Dataplane transaction, HAProxy UI assembles the canonical config into haproxy.cfg text, writes it, commits it, and pushes.

canonical draft → assemble.ts → haproxy.cfg text → write → commit → push

Reading works in the other direction: the current haproxy.cfg is parsed back into the canonical model, so the graph reflects what is actually in the repository.

Git operations

All git work is routed through Rust (git2), never through the webview:

Operation

Notes

Safety

clone

Initial clone into the working path

—

commit_and_push

Stage, commit and push the assembled config

Normal push

pull

Fetch and fast-forward

Fails rather than merge on divergence

rebase

Replay local commits on top of the remote

Use when behind

force_push

Rewrite the branch

--force-with-lease only — never bare --force. Requires an explicit UI confirmation step.

git_status

Drives the sync-state badge

Read-only

read_haproxy_cfg / write_text_file

Config file I/O

Scoped to the configured working path

Sync state

A background watcher polls git status and reports one of four states, so you always know whether your tree is still rebased on the remote:

State

Meaning

Action

clean

Working tree matches the remote

—

local-changes

Uncommitted or unpushed local edits

Apply to push

behind

The remote has moved ahead

Pull or rebase before pushing

diverged

Local and remote have both moved

Rebase. Force-push only with the explicit confirmation, and only when you are certain the remote commits are disposable.

The badge refetches every 60 seconds.

Authentication

  • SSH — keys are used via ssh-agent from the Rust side. No private key material is read into the webview.

  • HTTPS — credentials follow the same keychain path as Dataplane API tokens.

Instance configuration

A GitOps instance adds four fields on top of the standard instance fields: repository URL, branch, auth scheme, and the working path (clone destination on disk).

Round-trip fidelity

The parse and assemble halves are inverses, so a config that goes out through GitOps and comes back through the graph is byte-stable. This is tested directly — see Spec coverage gate.

The property that makes GitOps mode safe on a real config is that unmodelled directives survive. Sections the app does not understand — custom userlist, resolvers, peers, Lua loads — are preserved verbatim. A GitOps apply will not delete configuration the team wrote by hand just because there is no widget for it.

Practical notes

  • GitOps mode does not reload HAProxy. Something has to consume the commit — your pipeline, an Ansible run, a sidecar. If you want the Dataplane apply path as well, use both: GitOps for the audit trail, live apply for the running instance.

  • Commit and push are separate from the diff and validation steps, which still run. An invalid config fails locally before a commit is created.


Was this article helpful?