Skip to content

Git-backed Versioning

With Git versioning on, every connection / environment / flow / template / secret-reference change is committed to a local git repository and (optionally) pushed to a remote. You get an audit trail, one-call config rollback, and branch-based staging.

The working tree where commits are written. Three hard requirements, each enforced at startup:

  • Owned by the service user. libgit2 refuses a working tree owned by a different OS user (its safe.directory equivalent). Running as zenvara, the repo must be owned by zenvara.
  • Writable under systemd hardening. With ProtectSystem=strict, the path must sit under a ReadWritePaths entry. The data dir (/var/lib/zenvara) already qualifies.
  • Outside Storage.Directory. A nested path logs an overlap warning — keep it in a sibling directory.
/etc/systemd/system/zenvara.service.d/git-versioning.conf
install -d -o zenvara -g zenvara /var/lib/zenvara-versions
[Service]
ReadWritePaths=/var/lib/zenvara-versions
# then: systemctl daemon-reload

libgit2 push/clone with an interactive account password trips server-side bot protection (e.g. Bitbucket’s CAPTCHA lockout) and will lock the account. Create an HTTP access token or a dedicated service account with repository write, and put those in Remote.Username / Remote.Password. Leave Remote.Url empty for local-only versioning.

Step 3 — Seed the repository before first start

Section titled “Step 3 — Seed the repository before first start”

Pre-create the working tree so the platform simply opens it:

Terminal window
cd /var/lib/zenvara-versions
sudo -u zenvara git init -b main .
sudo -u zenvara git -c [email protected] -c user.name=Zenvara \
commit --allow-empty -m "Initialize git-backed config versioning"
sudo -u zenvara git remote add origin https://git.example.com/scm/team/zenvara-config.git

If the remote already has a main branch with history, skip the manual init — the platform clones it on first start.

Terminal window
Git:
Enabled: true
LocalPath: "/var/lib/zenvara-versions" # owned by service user, outside Storage.Directory
ProductionBranch: main # the branch `live` resolves to
BaselineOnEnable: false # best-effort startup storage→git baseline
Remote:
Url: "https://git.example.com/scm/team/zenvara-config.git"
AutoPush: true
Username: "zenvara-ci" # service account or token owner
Password: "<http-access-token>" # NOT a personal account password
CommitIdentity:
Name: "Zenvara"

After systemctl restart zenvara, the log shows Opening existing git config repository at <LocalPath>. Verify end to end by editing any entity: a commit Update entity: <name> appears in the repo and, with AutoPush, lands on the remote.

A branch is a staging area for definition changes — edit safely, review the diff, promote. Give it a feature-style name for the change it carries (edi-rework), not a tier name. URLs carry the branch as a path segment: /api/v1/main/flows/... runs the production version, /api/v1/edi-rework/flows/... runs the version staged on the edi-rework branch. On git-disabled installs, the live alias resolves to the production branch so the same URLs work.

The loop is stage → diff → promote:

  1. Stage. Point edits at the branch by putting its name in the URL segment (Studio’s branch switcher does this for you). Production URLs keep serving the old definition.

  2. Diff. Review what the branch changed before anything ships — GET /api/v1/platform/branches/edi-rework/diff, the MCP resource branches:///edi-rework/diff, or the Studio Branches page.

  3. Promote. Merge the reviewed changes into production storage as a no-fast-forward merge:

    • Studio — the Branches page: select the branch, review, click Promote.
    • MCP — the promote-branch tool ({ "branch": "edi-rework", "preview": true } for a dry run).
    • RESTPOST /api/v1/platform/branches/promote with { "branch": "edi-rework", "preview": true|false }.

    Preview is a true dry run; conflicts abort the whole promotion; promotion requires the flow:promote release permission (admin-held by default — distinct from authoring). There is no zen CLI promote verb — promotion is a Studio / MCP / REST action.

With git versioning plus a shared remote, Git.Sync.Enabled: true makes an instance:

  1. fetch the remote,
  2. reverse-sync changed config into storage,
  3. invalidate caches.

Trigger it via PollInterval and/or the POST /api/v1/platform/git/sync HMAC webhook. The same remote keeps multiple instances in sync, with ConflictPolicy: manual | remote | local.