Artifact 998ae1acd6940037e8c2f61ec8a73eeea7596e5f5c24c69290ed83d8ac9af05f:
- File
internal/horizon/seed/noverifier_test.go
— part of check-in
[a87790f468]
at
2026-10-26 12:45:46
on branch main
— feat(sshverify): make in-process SSH signature verification opt-in
internal/clearsign keeps the SSH envelope, SSHSIG parsing, namespace, hash and SHA-1 checks, none of which need cryptography, and hands the key parse and signature check to an SSHVerifier that the new public package sshverify registers from init. The library therefore no longer links golang.org/x/crypto/ssh and the ECDSA, P-256, Ed25519 and RSA code it pulls in; html-artifact-publisher's TinyGo engine drops from 1,347,569 to 1,093,647 bytes gzipped (3,777,936 to 3,208,411 raw).
Without the verifier nothing is accepted unchecked: a well-formed SSH signature is ErrSSHVerifierUnavailable, which wraps ErrCannotVerify, so a seed under an SSH horizon-seed-key is refused, the held one is kept, and the sync or rebuild fails naming the package to import. Malformed signatures are still bad. The cli package (and so cmd/libfossil) and examples/tinygo import sshverify; a go list guard keeps x/crypto/ssh out of the root and db closures. (user: [email protected], size: 2215) [annotate] [blame] [check-ins using] [more...]
//go:build !js && !windows package seed_test import ( "context" "errors" "testing" "github.com/danmestas/go-libfossil/db" "github.com/danmestas/go-libfossil/internal/clearsign" "github.com/danmestas/go-libfossil/internal/clearsign/signtest" "github.com/danmestas/go-libfossil/internal/hash" "github.com/danmestas/go-libfossil/internal/horizon/seed" ) // TestSSHSeedKeyWithoutVerifierFailsClosed: this test binary links no SSH // verifier. A clone with an SSH horizon-seed-key refuses a seed signed by // that very key, as one it could not judge: it is never held, and one held // before is neither applied nor discarded. With no key, the unsigned seed // is taken as before. func TestSSHSeedKeyWithoutVerifierFailsClosed(t *testing.T) { w := newWorld(t) clone := w.lacking(w.k(w.c3)) _, data := w.mint(w.c3, "origin") command, pub := signtest.SSHKey(t, "ed25519", clearsign.SeedNamespace) signer := &clearsign.Signer{Command: command, Namespace: clearsign.SeedNamespace} signed, err := signer.Sign(context.Background(), data) if err != nil { t.Fatal(err) } name := hash.SHA3(signed) if err := clone.SetConfig(clearsign.SettingSeedKey, pub); err != nil { t.Fatal(err) } verify, err := seed.VerifierFor(clone.DB()) if err != nil || verify == nil { t.Fatalf("VerifierFor = %v, %v; want a verifier for the configured key", verify, err) } err = hold(t, clone, name, signed, verify) if !errors.Is(err, clearsign.ErrSSHVerifierUnavailable) || errors.Is(err, seed.ErrProvenance) { t.Fatalf("Hold with no SSH verifier = %v, want ErrSSHVerifierUnavailable", err) } if held, _ := seed.Held(clone.DB()); held != nil { t.Fatal("a seed no verifier judged was held") } if err := hold(t, clone, name, signed, nil); err != nil { t.Fatal(err) } err = clone.WithTx(func(tx *db.Tx) error { applied, err := seed.Apply(tx, verify) if applied { t.Error("Apply with no SSH verifier applied the seed") } return err }) if !errors.Is(err, clearsign.ErrSSHVerifierUnavailable) { t.Fatalf("Apply with no SSH verifier = %v, want ErrSSHVerifierUnavailable", err) } if held, _ := seed.Held(clone.DB()); held == nil { t.Error("a held seed was discarded for want of a verifier") } }