modules/git: Recognize SSH signed tags too

Just like commits, tags can be signed with either an OpenPGP, or with an
SSH key. While the latter is supported already, SSH-signed tags have not
been. This patch teaches the git module to recognize and handle
SSH-signed tags too.

This will stop the signatures appearing in release notes, but are
currently unused otherwise.

Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu>
This commit is contained in:
Gergely Nagy 2024-02-28 12:52:21 +01:00 committed by oliverpool
parent a334c7ca17
commit 26ed995290
3 changed files with 71 additions and 10 deletions

View file

@ -185,10 +185,15 @@ func parseTagRef(ref map[string]string) (tag *Tag, err error) {
tag.Tagger = parseSignatureFromCommitLine(ref["creator"])
tag.Message = ref["contents"]
// strip PGP signature if present in contents field
// strip the signature if present in contents field
pgpStart := strings.Index(tag.Message, beginpgp)
if pgpStart >= 0 {
tag.Message = tag.Message[0:pgpStart]
} else {
sshStart := strings.Index(tag.Message, beginssh)
if sshStart >= 0 {
tag.Message = tag.Message[0:sshStart]
}
}
// annotated tag with GPG signature

View file

@ -14,6 +14,8 @@ import (
const (
beginpgp = "\n-----BEGIN PGP SIGNATURE-----\n"
endpgp = "\n-----END PGP SIGNATURE-----"
beginssh = "\n-----BEGIN SSH SIGNATURE-----\n"
endssh = "\n-----END SSH SIGNATURE-----"
)
// Tag represents a Git tag.
@ -71,17 +73,36 @@ l:
break l
}
}
idx := strings.LastIndex(tag.Message, beginpgp)
if idx > 0 {
endSigIdx := strings.Index(tag.Message[idx:], endpgp)
if endSigIdx > 0 {
tag.Signature = &CommitGPGSignature{
Signature: tag.Message[idx+1 : idx+endSigIdx+len(endpgp)],
Payload: string(data[:bytes.LastIndex(data, []byte(beginpgp))+1]),
}
tag.Message = tag.Message[:idx+1]
extractTagSignature := func(signatureBeginMark, signatureEndMark string) (bool, *CommitGPGSignature, string) {
idx := strings.LastIndex(tag.Message, signatureBeginMark)
if idx == -1 {
return false, nil, ""
}
endSigIdx := strings.Index(tag.Message[idx:], signatureEndMark)
if endSigIdx == -1 {
return false, nil, ""
}
return true, &CommitGPGSignature{
Signature: tag.Message[idx+1 : idx+endSigIdx+len(signatureEndMark)],
Payload: string(data[:bytes.LastIndex(data, []byte(signatureBeginMark))+1]),
}, tag.Message[:idx+1]
}
// Try to find an OpenPGP signature
found, sig, message := extractTagSignature(beginpgp, endpgp)
if !found {
// If not found, try an SSH one
found, sig, message = extractTagSignature(beginssh, endssh)
}
// If either is found, update the tag Signature and Message
if found {
tag.Signature = sig
tag.Message = message
}
return tag, nil
}

View file

@ -46,6 +46,41 @@ ono`), tag: Tag{
Message: "test message\no\n\nono",
Signature: nil,
}},
{data: []byte(`object d8d1fdb5b20eaca882e34ee510eb55941a242b24
type commit
tag v0
tagger Jane Doe <jane.doe@example.com> 1709146405 +0100
v0
-----BEGIN SSH SIGNATURE-----
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgvD4pK7baygXxoWoVoKjVEc/xZh
6w+1FUn5hypFqJXNAAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
AAAAQKFeTnxi9ssRqSg+sJcmjAgpgoPq1k5SXm306+mJmkPwvhim8f9Gz6uy1AddPmXaD7
5LVB3fV2GmmFDKGB+wCAo=
-----END SSH SIGNATURE-----
`), tag: Tag{
Name: "",
ID: Sha1ObjectFormat.EmptyObjectID(),
Object: &Sha1Hash{0xd8, 0xd1, 0xfd, 0xb5, 0xb2, 0x0e, 0xac, 0xa8, 0x82, 0xe3, 0x4e, 0xe5, 0x10, 0xeb, 0x55, 0x94, 0x1a, 0x24, 0x2b, 0x24},
Type: "commit",
Tagger: &Signature{Name: "Jane Doe", Email: "jane.doe@example.com", When: time.Unix(1709146405, 0)},
Message: "v0\n",
Signature: &CommitGPGSignature{
Signature: `-----BEGIN SSH SIGNATURE-----
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgvD4pK7baygXxoWoVoKjVEc/xZh
6w+1FUn5hypFqJXNAAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
AAAAQKFeTnxi9ssRqSg+sJcmjAgpgoPq1k5SXm306+mJmkPwvhim8f9Gz6uy1AddPmXaD7
5LVB3fV2GmmFDKGB+wCAo=
-----END SSH SIGNATURE-----`,
Payload: `object d8d1fdb5b20eaca882e34ee510eb55941a242b24
type commit
tag v0
tagger Jane Doe <jane.doe@example.com> 1709146405 +0100
v0
`,
},
}},
}
for _, test := range testData {