The signed release ledger
Gitfence's signed release ledger: what is public (signatures, digests, the hash chain) and the full release record Enterprise and self-hosted customers receive.
Short answer: Every Gitfence release is signed and linked into a hash chain. The public releases page shows the proof: version, date, signature, the digests of the files we shipped, and the chain hash. Enterprise and self-hosted customers also receive the full release record.
What is public
For each release, /releases/ shows:
- the version and release date, and that the entry is signed by Gitfence (Ed25519);
- the SHA-256 digests of the container image, the executables and the release's
SHA256SUMSfile, so you can check that what you run is what we shipped (how); - the release's chain hash, and the published head of the chain;
- how many automated checks passed;
- the SHA-256 of the full release record, so the record a customer receives can be checked against the public chain.
Nothing else is public: no list of changes, no test results, no dependency list and no audit findings.
What Enterprise and self-hosted customers receive
The full release record covers:
Changes: a plain-language changelog and the list of changes since the previous release, by category (security, feature, fix, dependency). There are no file paths and no source code.
Who made each change, and review: each change names the person who made it, and the record states who reviewed and approved the release.
Evidence: test totals, including the security property tests by name; the dependency changes since the previous release, with licenses; and the vulnerability scan of the image.
Automated checks, run at release time:
- Outbound network: every host the code can contact, checked against a reviewed list. The release fails on anything new.
- No telemetry: no analytics or phone-home code in the self-hosted build.
- Dependency licenses: every shipped package's license, with copyleft flagged.
- Secret scan of the release.
- Static analysis (SAST) with semgrep.
- Hidden code never served: the results of the security property tests.
- Known vulnerabilities: the scan of the container image, with the release's signed VEX statements. A release passes 'Known vulnerabilities' when no critical or high finding is fixable or not covered by a signed VEX statement. Medium and low are published but don't fail it.
Each check has a pass or fail result and a short summary.
Admins of Enterprise organizations find it in the app under Settings → Releases, where they can also download it for a procurement team. Self-hosted releases include it in the release bundle as release-record-<version>.json, next to the public entry ledger-<version>.json. A self-hosted admin imports newer releases on the About this version page, without connecting the installation to us.
The hash chain
Each entry includes the hash of the entry before it. Changing, removing or reordering any past entry breaks every later link, and the head of the chain is published on the releases page. Compare it with the value you saw before: if they disagree, the history was rewritten.
The chain was started again on 29 October 2026, when the public entries changed to the format described here; 1.0.0-rc1 is its first entry.
Verify
On a release page, choose Verify. Your browser checks the entry's Ed25519 signature with WebCrypto, then fetches the published index from this site and checks the entry's place in the chain. Verify a file does the same for a file you downloaded. You can also upload an entry or a release record to the app's /verify page.
To check from the command line, save the release public key as ledger-key.pem:
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEA3Ks7lmpahkeD6B8CJNcLCTMdmjk8zEdiZd45R3VrwCo=
-----END PUBLIC KEY-----
Download the entry from its release page, then, with jq and OpenSSL 3:
jq -cjS 'del(.signature)' 1.0.0-rc1.json > body.json
jq -r '.signature.value' 1.0.0-rc1.json | base64 -d > sig.bin
openssl pkeyutl -verify -pubin -inkey ledger-key.pem -rawin -in body.json -sigfile sig.bin
jq -cjS . 1.0.0-rc1.json | sha256sum
The third command must print Signature Verified Successfully. The last one prints the entry's chain hash: for the latest release it equals the head on /releases/, and the next release's entry names it as previous.
Check a release record
The record carries the same kind of signature, so the same three commands verify it. Then check that it is the record the public chain committed to:
jq -cjS . release-record-1.0.0-rc1.json | sha256sum
jq -r '.record.sha256' 1.0.0-rc1.json
The two values must be equal. If they are not, the record is not the one Gitfence published for that release.
Related guides
- Encryption at restHow Gitfence encrypts code at rest, what the recovery key opens, what locked means and what is not covered.
- Self-hostingInstall Gitfence on your servers with docker compose: sizing, your GitHub App, the offline license, encryption and Vault keys, Fenced CI, backups, upgrades.
- Offboarding and exit packsEnd a person's access, revoke tokens and agents, and download a signed exit pack with agreements, access history and exposure receipts.