@@ -71,6 +71,41 @@ import (
7171 "github.com/fluxcd/source-controller/internal/util"
7272)
7373
74+ const (
75+ // publicKeyPGPSuffix is the Secret data key suffix for PGP public keys.
76+ publicKeyPGPSuffix = ".asc"
77+ // publicKeySSHSuffix is the Secret data key suffix for SSH public keys.
78+ publicKeySSHSuffix = ".sshpub"
79+ )
80+
81+ // gitSigner abstracts the verification methods shared by git.Commit and git.Tag.
82+ type gitSigner interface {
83+ SignatureType () string
84+ VerifyPGP (keyRings ... string ) (string , error )
85+ VerifySSH (authorizedKeys ... string ) (string , error )
86+ }
87+
88+ // verifyGitObject dispatches signature verification based on the signature type
89+ // of the given git object. It returns the key identity (PGP key ID or SSH
90+ // fingerprint) on success, or an error if verification fails or the required
91+ // key type is missing from the Secret.
92+ func verifyGitObject (obj gitSigner , keyRings []string , authorizedKeys []string ) (string , error ) {
93+ switch obj .SignatureType () {
94+ case "openpgp" :
95+ if len (keyRings ) == 0 {
96+ return "" , fmt .Errorf ("PGP signature detected but no PGP public keys found in secret (keys with %s suffix)" , publicKeyPGPSuffix )
97+ }
98+ return obj .VerifyPGP (keyRings ... )
99+ case "ssh" :
100+ if len (authorizedKeys ) == 0 {
101+ return "" , fmt .Errorf ("SSH signature detected but no SSH public keys found in secret (keys with %s suffix)" , publicKeySSHSuffix )
102+ }
103+ return obj .VerifySSH (authorizedKeys ... )
104+ default :
105+ return "" , fmt .Errorf ("unsupported signature type: %s" , obj .SignatureType ())
106+ }
107+ }
108+
74109// gitRepositoryReadyCondition contains the information required to summarize a
75110// v1.GitRepository Ready Condition.
76111var gitRepositoryReadyCondition = summarize.Conditions {
@@ -1093,24 +1128,32 @@ func (r *GitRepositoryReconciler) verifySignature(ctx context.Context, obj *sour
10931128 return sreconcile .ResultSuccess , nil
10941129 }
10951130
1096- // Get secret with GPG data
1131+ // Get secret with public key data
10971132 publicKeySecret := types.NamespacedName {
10981133 Namespace : obj .Namespace ,
10991134 Name : obj .Spec .Verification .SecretRef .Name ,
11001135 }
11011136 secret := & corev1.Secret {}
11021137 if err := r .Client .Get (ctx , publicKeySecret , secret ); err != nil {
11031138 e := serror .NewGeneric (
1104- fmt .Errorf ("PGP public keys secret error: %w" , err ),
1139+ fmt .Errorf ("public keys secret error: %w" , err ),
11051140 "VerificationError" ,
11061141 )
11071142 conditions .MarkFalse (obj , sourcev1 .SourceVerifiedCondition , e .Reason , "%s" , e )
11081143 return sreconcile .ResultEmpty , e
11091144 }
11101145
11111146 var keyRings []string
1112- for _ , v := range secret .Data {
1113- keyRings = append (keyRings , string (v ))
1147+ var authorizedKeys []string
1148+ for k , v := range secret .Data {
1149+ if strings .HasSuffix (k , publicKeySSHSuffix ) {
1150+ authorizedKeys = append (authorizedKeys , string (v ))
1151+ } else if strings .HasSuffix (k , publicKeyPGPSuffix ) {
1152+ keyRings = append (keyRings , string (v ))
1153+ } else {
1154+ // Provide fallback to support previous undocumented behavior
1155+ keyRings = append (keyRings , string (v ))
1156+ }
11141157 }
11151158
11161159 var message strings.Builder
@@ -1140,38 +1183,34 @@ func (r *GitRepositoryReconciler) verifySignature(ctx context.Context, obj *sour
11401183 return sreconcile .ResultEmpty , err
11411184 }
11421185
1143- // Verify tag with GPG data from secret
1144- tagEntity , err := tag .Verify (keyRings ... )
1186+ entity , err := verifyGitObject (tag , keyRings , authorizedKeys )
11451187 if err != nil {
11461188 e := serror .NewGeneric (
11471189 fmt .Errorf ("signature verification of tag '%s' failed: %w" , tag .String (), err ),
11481190 "InvalidTagSignature" ,
11491191 )
11501192 conditions .MarkFalse (obj , sourcev1 .SourceVerifiedCondition , e .Reason , "%s" , e )
1151- // Return error in the hope the secret changes
11521193 return sreconcile .ResultEmpty , e
11531194 }
11541195
1155- message .WriteString (fmt .Sprintf ("verified signature of\n \t - tag '%s' with key '%s'" , tag .String (), tagEntity ))
1196+ message .WriteString (fmt .Sprintf ("verified signature of\n \t - tag '%s' with key '%s'" , tag .String (), entity ))
11561197 }
11571198
11581199 if obj .Spec .Verification .VerifyHEAD () {
1159- // Verify commit with GPG data from secret
1160- headEntity , err := commit .Verify (keyRings ... )
1200+ entity , err := verifyGitObject (& commit , keyRings , authorizedKeys )
11611201 if err != nil {
11621202 e := serror .NewGeneric (
11631203 fmt .Errorf ("signature verification of commit '%s' failed: %w" , commit .Hash .String (), err ),
11641204 "InvalidCommitSignature" ,
11651205 )
11661206 conditions .MarkFalse (obj , sourcev1 .SourceVerifiedCondition , e .Reason , "%s" , e )
1167- // Return error in the hope the secret changes
11681207 return sreconcile .ResultEmpty , e
11691208 }
11701209 // If we also verified the tag previously, then append to the message.
11711210 if message .Len () > 0 {
1172- message .WriteString (fmt .Sprintf ("\n \t - commit '%s' with key '%s'" , commit .Hash .String (), headEntity ))
1211+ message .WriteString (fmt .Sprintf ("\n \t - commit '%s' with key '%s'" , commit .Hash .String (), entity ))
11731212 } else {
1174- message .WriteString (fmt .Sprintf ("verified signature of\n \t - commit '%s' with key '%s'" , commit .Hash .String (), headEntity ))
1213+ message .WriteString (fmt .Sprintf ("verified signature of\n \t - commit '%s' with key '%s'" , commit .Hash .String (), entity ))
11751214 }
11761215 }
11771216
0 commit comments