zonegit

module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Apr 26, 2026 License: Apache-2.0

README

zonegit

CI Go Reference Go Report Card Release License

Git semantics for authoritative DNS.

zonegit is a content-addressed, version-controlled object model for authoritative DNS zones. Every change is an immutable commit; the live zone is just a pointer to the latest commit on a branch. That single inversion gives you log, diff, blame, time-travel reads, and branch-based rollout — operations that today's authoritative DNS servers (BIND, Knot, PowerDNS, Route 53) don't expose at all.

Status

v0.1 — public preview. Single zone, single process, no replication. The on-disk format and public Go API are not yet stable; expect breakage between minor versions until v1.

Demo

The repo ships with an end-to-end demo that builds both binaries, imports a real zonefile, serves it on 127.0.0.1:15353, mutates a record, and shows the change reflected live — without a reload, an SOA bump, or restarting the daemon.

make demo

Below is roughly what you should see.

1. Initialise a repo and import a zonefile
$ zonegit --repo ./.zonegit init foo.com.
initialised zonegit repo at ./.zonegit (zone: foo.com.)

$ cat foo.com.zone
$ORIGIN foo.com.
$TTL 300
@   IN SOA ns1.foo.com. admin.foo.com. 1 7200 3600 1209600 300
    IN NS  ns1.foo.com.
ns1 IN A   10.0.0.1
api IN A   1.2.3.4
www IN CNAME api.foo.com.

$ zonegit --repo ./.zonegit --zone foo.com. import foo.com.zone -m "initial import"
[main 4f1c2a9] initial import
 5 RRsets imported
2. Serve it, query it
$ zonegitd --repo ./.zonegit --zone foo.com. --listen 127.0.0.1:15353 &

$ dig @127.0.0.1 -p 15353 +short api.foo.com. A
1.2.3.4

$ dig @127.0.0.1 -p 15353 +short www.foo.com. A
api.foo.com.
1.2.3.4
3. Change a record. The daemon picks it up on the next packet.
$ zonegit --repo ./.zonegit --zone foo.com. \
    set api.foo.com. A 300 9.9.9.9 -m "failover to DR site"
[main 7c2af3b] failover to DR site

$ dig @127.0.0.1 -p 15353 +short api.foo.com. A
9.9.9.9

No reload, no SOA dance, no daemon restart. The server reopens its read-only Badger handle per query and sees the new HEAD.

4. Inspect the history
$ zonegit --repo ./.zonegit log
commit 7c2af3b  Chandan Kumar  2026-04-25 22:13  failover to DR site
commit 4f1c2a9  Chandan Kumar  2026-04-25 22:08  initial import

$ zonegit --repo ./.zonegit diff HEAD~1 HEAD
~ api  A   1.2.3.4 -> 9.9.9.9

$ zonegit --repo ./.zonegit blame api.foo.com. A
api.foo.com. A  9.9.9.9   <- 7c2af3b  Chandan Kumar  "failover to DR site"
5. Time-travel
$ zonegit --repo ./.zonegit show api.foo.com. A HEAD~1
api.foo.com. 300 IN A 1.2.3.4

That last query — "what did this name resolve to N commits ago?" — is the one that no DNS tool shipping today can answer.

Install

Pre-built binaries

Download the latest release for your platform from the releases page.

From source

Requires Go 1.23+.

go install github.com/ckumar392/zonegit/cmd/zonegit@latest
go install github.com/ckumar392/zonegit/cmd/zonegitd@latest

Or clone and build:

git clone https://github.com/ckumar392/zonegit.git
cd zonegit
make build      # produces ./bin/zonegit and ./bin/zonegitd

How it works

zonegit models a zone as a Merkle DAG of immutable objects:

Object What it holds
Blob One canonicalised RRset (one (name, type) coordinate).
Tree A directory of labels mapping to subtrees and RRset blobs.
Commit A snapshot of the zone tree, with parent links and metadata.
Tag / Ref Named pointers into the commit graph.

Names with identical content hash to identical blobs, so equivalent zones share storage. Subtree hashes mean diff skips unchanged branches in O(changes), not O(zone size). Commits chain by parent hash, so the history is verifiable end-to-end.

The full design is in docs/OBJECT_MODEL.md.

Repository layout

cmd/
  zonegit/      CLI entry point
  zonegitd/     Authoritative DNS server entry point
pkg/
  store/        Storage interface + Badger and in-memory backends
  object/       Blob / Tree / Commit / Tag, canonical encoding, hashing
  zone/         Bridge between miekg/dns RRs and the object model
  refs/         Branches, HEAD, reflog, atomic compare-and-swap
  history/      log, diff, blame
  merge/        Three-way RRset merge (v1+)
  resolve/      DNS query path
  repo/         Public Go API
docs/           Design documentation
scripts/        Development helpers

Build and test

make build       # build both binaries into ./bin
make test        # unit tests
make test-race   # tests with the race detector
make lint        # golangci-lint (or go vet as a fallback)
make demo        # end-to-end demo
make help        # list all targets

Documentation

Contributing

Contributions are welcome. See CONTRIBUTING.md for the development setup, the change-proposal process, and the good first issue list. Released versions are tracked in CHANGELOG.md.

License

Licensed under the Apache License, Version 2.0.

Directories

Path Synopsis
cmd
zonegit command
zonegitd command
Command zonegitd is a minimal authoritative DNS responder backed by a zonegit repository.
Command zonegitd is a minimal authoritative DNS responder backed by a zonegit repository.
pkg
history
Package history provides read-only views over the commit DAG: log (commits in parent order), diff (RRset changes between trees), blame (who last touched a specific RRset), and walk-at (point-in-time).
Package history provides read-only views over the commit DAG: log (commits in parent order), diff (RRset changes between trees), blame (who last touched a specific RRset), and walk-at (point-in-time).
merge
Package merge implements 3-way RRset merge for the v1 `zonegit merge` operation.
Package merge implements 3-way RRset merge for the v1 `zonegit merge` operation.
object
Package object defines the four immutable content-addressable object kinds that constitute a zonegit repository: Blob, Tree, Commit, Tag.
Package object defines the four immutable content-addressable object kinds that constitute a zonegit repository: Blob, Tree, Commit, Tag.
repo
Package repo is the public Go API of zonegit.
Package repo is the public Go API of zonegit.
resolve
Package resolve is the DNS query path.
Package resolve is the DNS query path.
store
Package store defines the only persistence seam in zonegit.
Package store defines the only persistence seam in zonegit.
store/memstore
Package memstore is an in-memory implementation of store.Storage used for tests, demos, and embedded scenarios where durability is not required.
Package memstore is an in-memory implementation of store.Storage used for tests, demos, and embedded scenarios where durability is not required.
zone
Package zone bridges miekg/dns RR types and pkg/object Blob payloads.
Package zone bridges miekg/dns RR types and pkg/object Blob payloads.

Jump to

Keyboard shortcuts

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