● zegit · proves
ZEGITFILE & config
Two files govern a repo: the ZEGITFILE (the governance contract) and .zegit/config.yaml (the validation pipeline). Both are written by zg init and are the source of the policy digest.
Documented from the implementation
Design documents describe a richer schema (roles, permissions, critical areas). This page documents the schema that zg init actually writes and zg and the gateway actually parse today.
ZEGITFILE
The governance contract: a tag_request block that controls release quorum, and an optional validation block that pins the validation pipeline. The shape below is modelled on zegit's own ZEGITFILE (which pins fourteen steps):
# ZEGITFILE — ZeGit Governance Contract
tag_request:
# Minimum number of distinct approvals before a tag can be created.
threshold: 1
# Roles permitted to approve a Tag Request.
approver_roles:
- owner
- maintainer
# When true, the AoV signed by the TR creator counts as one approval,
# enabling a solo-maintainer flow without a second identity. Default: false.
allow_aov_self_approval: false
# Tags governed by a Tag Request (globs, default ["v*"]). In git mode,
# `git tag <name>` opens a TR when the name matches; other tags are plain git.
release_tags:
- "v*"
# Validation scope — generated by `zg policy scope`. Once the policy is
# activated, the gateway rejects an AoV that did not run exactly this
# .zegit/config.yaml with every listed step required and passed.
validation:
config_digest: sha256:<hex digest of .zegit/config.yaml>
required_steps:
- fmt
- lint
- test
- build| Key | Type | Meaning |
|---|---|---|
tag_request.threshold | int | Distinct approvals needed to finalize a tag. |
tag_request.approver_roles | []string | Roles allowed to approve — owner, maintainer, developer. |
tag_request.allow_aov_self_approval | bool | Let the creator's own AoV count as one quorum vote (default false; zg init --solo writes true). |
tag_request.release_tags | []glob | Which tag names are release tags for the git-mode tag ceremony (default ["v*"]; ["*"] governs every tag). |
validation.config_digest | string | sha256 of the sanctioned .zegit/config.yaml. An AoV whose policy digest does not match is rejected on protected refs (ZG_ERR_AOV_SCOPE_MISMATCH). |
validation.required_steps | []string | Step ids every attestation must carry as required-and-passed (ZG_ERR_AOV_STEP_MISSING otherwise). |
Without a validation block the pin is advisory
zg validate prints a recommendation until the scope is pinned — a pipeline narrowed to fmt would still produce a valid ALLOW. Changing the pipeline afterwards is a policy change: re-run zg policy scope, commit, zg policy propose, owner approval.
The activated policy: refs/zegit/policy
The ZEGITFILE in the tree is the proposal source. What the gateway enforces is the policy activated at refs/zegit/policy — a signed statement carrying the same fields, proposed with zg policy propose, approved by owners, and activated once the owner quorum holds (two distinct owners; the first activation needs one). A repository with no activated policy refuses tag pushes. Organizations can additionally activate a baseline (zg policy propose --org): a floor on threshold, approver roles and self-approval that every repository may tighten but never loosen. A baseline never carries a validation scope — that pin is per repository.
.zegit/config.yaml
The validation pipeline that zg validate runs. Steps run in order; a required step exiting non-zero blocks the AoV.
version: 1
validate:
- id: lint
run: |
gofmt -l . | grep . && exit 1 || exit 0
required: true
- id: test
run: go test ./...
required: true| Key | Type | Meaning |
|---|---|---|
version | int | Schema version — must be 1. |
validate[].id | string | Step identifier (required). |
validate[].run | string | Shell to run (bash -c), required. |
validate[].required | bool | Whether a non-zero exit blocks. Defaults to true when omitted. |
The policy digest
Every AoV records a policy_ref.digest of the form sha256:<hex>, computed over the bytes of .zegit/config.yaml concatenated with ZEGITFILE (when present). An AoV without it is rejected on protected refs (ZG_ERR_AOV_MISSING_POLICY_DIGEST), and when the active policy pins a validation scope the gateway compares the digest against the committed files — which is how "policy cannot be weakened" becomes a cryptographic property rather than a process promise. Change either file and the digest changes, so a stale or hand-edited policy no longer matches.
Keep both files in version control. They are your governance — reviewed like code, and bound into every attestation.
Authoritative reference, generated from the component repos. Spot something stale? Tell us.