GitVote is an experimental protocol and CLI for public, signed governance votes transported through Git.
Voters sign ballots with Ed25519 identity keys. An election manifest fixes the eligible voter keys, choices, voting window, and administrator identity. A fresh clone can validate every signature and reproduce the tally without trusting Git usernames, email addresses, or hosting accounts.
GitVote is under active development and MUST NOT yet be used for consequential elections. It does not provide secret ballots, anonymity, coercion resistance, or guaranteed admission of submitted ballots. See the protocol and threat model.
Implemented
- Secure Ed25519 identity generation
- Administrator-signed election manifests
- Voter-signed ballots bound to one manifest
- Eligible-key, choice, duplicate, filename, and signature validation
- Diff-aware validation of proposed base and head Git commits
- Deterministic tallying of validated ballots
- Strict JSON schemas that reject unknown fields
Signed deterministic result files are the next protocol feature.
Build
GitVote currently requires Rust 1.86 or newer.
cargo build --release ./target/release/gitvote --help
Commands
Generate an identity key:
gitvote keygen --output voter.key
The key file contains private key material, is created with mode 0600 on Unix,
and must not be committed. The command prints the public key and key ID that an
administrator places in election.json.
Sign an election manifest:
gitvote sign-manifest --key administrator.key
Cast a signed ballot and commit it:
gitvote cast --choice yes --key voter.key
Use --no-commit to write the ballot without invoking Git.
Validate and tally accepted ballots:
gitvote validate gitvote tally
Validate a proposed ballot change without trusting the working tree:
gitvote validate-pr --base <target-commit> --head <proposed-commit>
This requires exactly one newly added canonical ballot file, rejects every other tree change, validates the base manifest and accepted ballots, and checks the new ballot's eligibility and signature.
Paths default to election.json and votes/; each command exposes overrides in
its --help output.
Development
cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
cargo test --all-targetsReleases
GitVote software releases use UTC DateVer in the Cargo-compatible form
YYYYMMDD.0.N. The final component starts at zero and increments for multiple
releases on the same day. Protocol versions have their own independent DateVer.
make version make release
make release must start from a clean main. It creates a release branch,
updates Cargo.toml and Cargo.lock, runs the complete lint suite, packages the
crate, merges and tags the release, pushes it, and publishes it to crates.io.
Run git fetch --tags origin first so the automatic sequence sees every
existing release tag. Use VERSION=YYYYMMDD.0.N to select an explicit version.
License
MIT