Artifact 20568bea6ae883d7bf5f9a382b55f2bc01b0296d5f732edcc117e13cd9ff461f:
- File
signing.go
— part of check-in
[451d368554]
at
2026-10-24 13:16:26
on branch main
— feat(horizon): bind each seed to its horizon and sign seeds apart
Every seed an origin mints now carries T +horizon-seed <C> <rule> (draft-fossil-horizon-00 §5.2.1), inside the signed bytes. The card is not counted as a tag in force, Mint never derives a horizon-seed row into a seed, and Apply skips the card.
Before a clone holds a seed, signed or not, it checks the seed against its store cone (§5.2.4). The seed must carry exactly one binding card naming the store's C and rule, and its D must be no earlier than the held seed's. A seed that fails is refused as a wrongly signed one and the clone falls back to the content horizon. A deepen discards the held seed first, so the floor restarts at the new C. A held seed that is no longer bound is discarded when it is next applied.
Seeds are signed with their own horizon-seed-command and are no longer signed by clearsign and pgp-command. SSH seed signatures use the fossil-horizon-seed namespace. clearsign.Key.Verify now takes the namespace, and check-in verification keeps fossilscm.
Adds 9 conformance cases and flips HZ-5.2-8, HZ-5.2-11, HZ-5.2-12 and HZ-5.2-13 to covered. The zit interop gate moves to zit 0.7.1, whose seeds are byte-identical with ours. (user: [email protected], size: 2704) [annotate] [blame] [check-ins using] [more...]
package libfossil import "github.com/danmestas/go-libfossil/internal/clearsign" // SettingClearsign names the boolean repository setting, read as fossil reads // one, that signs every check-in a commit or a branch creation stores, as // fossil and zit sign them. Off by default. It signs no horizon seed: see // SettingHorizonSeedCommand. The signed text is the // artifact, so a signed check-in's name is the hash of the signed bytes; a // signer that fails abandons the commit. CommitOpts.NoSign and // CheckoutCommitOpts.NoSign store one check-in unsigned, as fossil's // --nosign does, and fossil's legacy omitsign setting turns signing off. const SettingClearsign = clearsign.SettingClearsign // SettingPGPCommand names the signing command, as fossil names it. Unset, it // is fossil's default, "gpg --clearsign -o ", run as COMMAND OUTFILE INFILE. // A command whose name starts with "ssh" is run as COMMAND INFILE and writes // a detached INFILE.sig, which is wrapped in fossil's SSH envelope; to sign // with an SSH key, set it to // // ssh-keygen -q -Y sign -n fossilscm -f ~/.ssh/id_ed25519 // // The namespace must be fossilscm for a clone to verify the signature. The // command runs through the shell, so ~ and environment variables expand. const SettingPGPCommand = clearsign.SettingPGPCommand // SettingHorizonSeedKey names the setting holding the public key a clone // verifies its origin's structural horizon seeds with // (draft-fossil-horizon-00 §5.2.4): an SSH public key line, verified in // process, or the fingerprint of an OpenPGP key in the user's gpg keyring, // verified by gpg. With a key set, a seed that is unsigned or not signed by // that key is discarded and the clone falls back to the content horizon; // unset, an unsigned seed is accepted. An SSH signature must carry the // namespace fossil-horizon-seed. CloneOpts.SeedKey sets it when the clone is // made. It is the clone's own: an origin never sends it. const SettingHorizonSeedKey = clearsign.SettingSeedKey // SettingHorizonSeedCommand names the command an origin signs the // structural horizon seeds it mints with (draft-fossil-horizon-00 §5.2.4), // configured apart from SettingClearsign and SettingPGPCommand: unset or // off, seeds go out unsigned even when check-ins are signed. It follows // pgp-command's contract, and an SSH signer must sign in the namespace // fossil-horizon-seed, never fossilscm, so that a check-in's signature // cannot stand in for a seed's: // // ssh-keygen -q -Y sign -n fossil-horizon-seed -f ~/.ssh/id_ed25519 // // An origin whose command signs in another namespace serves no seed: the // request fails. const SettingHorizonSeedCommand = clearsign.SettingSeedCommand