identity v3 WIP#1576
Draft
MichaelMure wants to merge 1 commit into
Draft
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR is an “identity v3” work-in-progress that migrates identity signing and key representation away from embedded OpenPGP keys toward a pluggable signer model (GPG subprocess or SSH agent/SSHSIG) and W3C DID-style publicKeyMultibase public keys. It updates repository commit signing/verification and adjusts tests accordingly.
Changes:
- Introduces a
repository.Signerabstraction with SSH-agent-based SSHSIG signing and gpg-subprocess signing, plus SSHSIG verification helpers. - Updates commit signing APIs and commit signature payload representation (
[]byteinstead ofio.Reader) across repo implementations and tests. - Bumps identity format to v3 and changes key serialization to store
publicKeyMultibase(with legacy v2 key migration support).
Reviewed changes
Copilot reviewed 19 out of 20 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
repository/signer.go |
Adds Signer interface, SSH agent SSHSIG signing, GPG signing, and SSHSIG parsing/verification. |
repository/repo.go |
Switches signed commit API from OpenPGP entity to Signer; changes Commit fields to []byte. |
repository/gogit.go |
Implements new signing flow for go-git repo; re-encodes commit without signature to rebuild signed payload bytes. |
repository/mock_repo.go |
Updates mock repo signing to use Signer; returns signed payload/signature as []byte. |
repository/common.go |
Removes OpenPGP de-armoring helper no longer needed with armored signatures stored directly. |
repository/repo_testing.go |
Updates signature tests to use SSHSIG with an in-process SSH agent keyring. |
entity/dag/operation_pack.go |
Signs commits via Identity.Signer(); verifies SSHSIG or PGP armored detached signatures depending on signature type. |
entity/dag/operation_pack_test.go |
Updates signing test to use injected SSH-agent-backed signer. |
entities/identity/version.go |
Bumps identity version format to 3; changes key JSON handling; adds legacy v2 key migration path. |
entities/identity/key.go |
Reworks key model to publicKeyMultibase + origin (ssh/gpg) and signer construction. |
entities/identity/multibase.go / *_test.go |
Adds multibase encode/decode helpers and tests. |
entities/identity/interface.go / identity.go / stubs/tests |
Replaces SigningKey with Signer() and updates call sites and tests. |
go.mod / go.sum |
Adds/updates dependencies (including multibase/varint; also introduces several seemingly unused auth/web deps). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+474
to
485
| // Signer returns a Signer for the first available signing key. | ||
| // Returns nil, nil if the identity has no keys. | ||
| func (i *Identity) Signer() (repository.Signer, error) { | ||
| for _, key := range i.Keys() { | ||
| s, err := key.Signer() | ||
| if err != nil { | ||
| return nil, err | ||
| continue | ||
| } | ||
| return key, nil | ||
| return s, nil | ||
| } | ||
| return nil, nil | ||
| } |
Comment on lines
+286
to
+292
| multibase, err := pgpPubKeyToMultibase(entities[0]) | ||
| if err != nil { | ||
| return err | ||
| return nil, err | ||
| } | ||
|
|
||
| return repo.Keyring().Set(repository.Item{ | ||
| Key: k.public.KeyIdString(), | ||
| Data: buf.Bytes(), | ||
| }) | ||
| // pgpEntity is intentionally empty: v2 only stored the bare public key, not | ||
| // the full entity needed for signing. | ||
| return &Key{publicKeyMultibase: multibase, origin: KeyOriginGPG}, nil |
Comment on lines
+283
to
+293
| if repository.IsSSHSignature(commit.Signature) { | ||
| var sshPubKeys []ssh.PublicKey | ||
| for _, key := range keys { | ||
| pub, err := key.SSHPublicKey() | ||
| if err == nil { | ||
| sshPubKeys = append(sshPubKeys, pub) | ||
| } | ||
| } | ||
| if err := repository.VerifySSHSIG(sshPubKeys, commit.SignedData, commit.Signature); err != nil { | ||
| return nil, fmt.Errorf("signature failure: %v", err) | ||
| } |
Comment on lines
+79
to
+87
| func (g *GPGSigner) Sign(payload []byte) ([]byte, error) { | ||
| cmd := exec.Command("gpg", "--armor", "--detach-sign", "-u", g.fingerprint) | ||
| cmd.Stdin = bytes.NewReader(payload) | ||
| out, err := cmd.Output() | ||
| if err != nil { | ||
| return nil, fmt.Errorf("gpg sign: %w", err) | ||
| } | ||
| return out, nil | ||
| } |
Comment on lines
+208
to
+216
| var blob blobFields | ||
| if err := ssh.Unmarshal(raw, &blob); err != nil { | ||
| return nil, "", nil, fmt.Errorf("unmarshal SSHSIG: %w", err) | ||
| } | ||
|
|
||
| pubKey, err = ssh.ParsePublicKey(blob.PublicKey) | ||
| if err != nil { | ||
| return nil, "", nil, fmt.Errorf("parse SSHSIG public key: %w", err) | ||
| } |
Comment on lines
14
to
+25
| github.com/fatih/color v1.17.0 | ||
| github.com/go-git/go-billy/v5 v5.6.2 | ||
| github.com/go-git/go-git/v5 v5.16.5 | ||
| github.com/golang-jwt/jwt/v5 v5.3.1 | ||
| github.com/gorilla/mux v1.8.1 | ||
| github.com/gorilla/websocket v1.5.3 | ||
| github.com/hashicorp/golang-lru/v2 v2.0.7 | ||
| github.com/icrowley/fake v0.0.0-20240710202011-f797eb4a99c0 | ||
| github.com/markbates/goth v1.82.0 | ||
| github.com/mattn/go-isatty v0.0.20 | ||
| github.com/multiformats/go-multibase v0.2.0 | ||
| github.com/multiformats/go-varint v0.0.7 |
Comment on lines
+62
to
+66
| signedData := sshsigSignedData(sshsigNamespace, payload) | ||
| sig, err := ag.Sign(s.pubKey, signedData) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("SSH agent sign: %w", err) | ||
| } |
Comment on lines
+23
to
+26
| func pubkeyMultibaseEncode(code uint64, keyBytes []byte) string { | ||
| payload := append(varint.ToUvarint(code), keyBytes...) | ||
| s, _ := mbase.Encode(mbase.Base58BTC, payload) | ||
| return s |
Comment on lines
+17
to
23
| github.com/golang-jwt/jwt/v5 v5.3.1 | ||
| github.com/gorilla/mux v1.8.1 | ||
| github.com/gorilla/websocket v1.5.3 | ||
| github.com/hashicorp/golang-lru/v2 v2.0.7 | ||
| github.com/icrowley/fake v0.0.0-20240710202011-f797eb4a99c0 | ||
| github.com/markbates/goth v1.82.0 | ||
| github.com/mattn/go-isatty v0.0.20 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.