Skip to content

Commit da5ce5c

Browse files
Instance signing rule pubkey should allow all public keys, not just GPG (#35357)
Instance signing rule `pubkey` is described as "Only sign if the user has a public key", however if the user only has SSH public keys, this check will fail, as it only checks for GPG keys. Changed the `pubkey` checks to call a helper `userHasPubkeys` which sequentially checks for GPG, then SSH keys. Related #34341 --------- Co-authored-by: wxiaoguang <[email protected]>
1 parent c4fbccc commit da5ce5c

File tree

2 files changed

+70
-20
lines changed

2 files changed

+70
-20
lines changed

services/asymkey/sign.go

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,29 @@ func signingModeFromStrings(modeStrings []string) []signingMode {
6969
return returnable
7070
}
7171

72+
func userHasPubkeysGPG(ctx context.Context, userID int64) (bool, error) {
73+
return db.Exist[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
74+
OwnerID: userID,
75+
IncludeSubKeys: true,
76+
}.ToConds())
77+
}
78+
79+
func userHasPubkeysSSH(ctx context.Context, userID int64) (bool, error) {
80+
return db.Exist[asymkey_model.PublicKey](ctx, asymkey_model.FindPublicKeyOptions{
81+
OwnerID: userID,
82+
NotKeytype: asymkey_model.KeyTypePrincipal,
83+
}.ToConds())
84+
}
85+
86+
// userHasPubkeys checks if a user has any public keys (GPG or SSH)
87+
func userHasPubkeys(ctx context.Context, userID int64) (bool, error) {
88+
has, err := userHasPubkeysGPG(ctx, userID)
89+
if has || err != nil {
90+
return has, err
91+
}
92+
return userHasPubkeysSSH(ctx, userID)
93+
}
94+
7295
// ErrWontSign explains the first reason why a commit would not be signed
7396
// There may be other reasons - this is just the first reason found
7497
type ErrWontSign struct {
@@ -170,14 +193,11 @@ Loop:
170193
case always:
171194
break Loop
172195
case pubkey:
173-
keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
174-
OwnerID: u.ID,
175-
IncludeSubKeys: true,
176-
})
196+
hasKeys, err := userHasPubkeys(ctx, u.ID)
177197
if err != nil {
178198
return false, nil, nil, err
179199
}
180-
if len(keys) == 0 {
200+
if !hasKeys {
181201
return false, nil, nil, &ErrWontSign{pubkey}
182202
}
183203
case twofa:
@@ -210,14 +230,11 @@ Loop:
210230
case always:
211231
break Loop
212232
case pubkey:
213-
keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
214-
OwnerID: u.ID,
215-
IncludeSubKeys: true,
216-
})
233+
hasKeys, err := userHasPubkeys(ctx, u.ID)
217234
if err != nil {
218235
return false, nil, nil, err
219236
}
220-
if len(keys) == 0 {
237+
if !hasKeys {
221238
return false, nil, nil, &ErrWontSign{pubkey}
222239
}
223240
case twofa:
@@ -266,14 +283,11 @@ Loop:
266283
case always:
267284
break Loop
268285
case pubkey:
269-
keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
270-
OwnerID: u.ID,
271-
IncludeSubKeys: true,
272-
})
286+
hasKeys, err := userHasPubkeys(ctx, u.ID)
273287
if err != nil {
274288
return false, nil, nil, err
275289
}
276-
if len(keys) == 0 {
290+
if !hasKeys {
277291
return false, nil, nil, &ErrWontSign{pubkey}
278292
}
279293
case twofa:
@@ -337,14 +351,11 @@ Loop:
337351
case always:
338352
break Loop
339353
case pubkey:
340-
keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
341-
OwnerID: u.ID,
342-
IncludeSubKeys: true,
343-
})
354+
hasKeys, err := userHasPubkeys(ctx, u.ID)
344355
if err != nil {
345356
return false, nil, nil, err
346357
}
347-
if len(keys) == 0 {
358+
if !hasKeys {
348359
return false, nil, nil, &ErrWontSign{pubkey}
349360
}
350361
case twofa:

services/asymkey/sign_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package asymkey
5+
6+
import (
7+
"testing"
8+
9+
"code.gitea.io/gitea/models/unittest"
10+
11+
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
func TestUserHasPubkeys(t *testing.T) {
16+
assert.NoError(t, unittest.PrepareTestDatabase())
17+
test := func(t *testing.T, userID int64, expectedHasGPG, expectedHasSSH bool) {
18+
ctx := t.Context()
19+
hasGPG, err := userHasPubkeysGPG(ctx, userID)
20+
require.NoError(t, err)
21+
hasSSH, err := userHasPubkeysSSH(ctx, userID)
22+
require.NoError(t, err)
23+
hasPubkeys, err := userHasPubkeys(ctx, userID)
24+
require.NoError(t, err)
25+
assert.Equal(t, expectedHasGPG, hasGPG)
26+
assert.Equal(t, expectedHasSSH, hasSSH)
27+
assert.Equal(t, expectedHasGPG || expectedHasSSH, hasPubkeys)
28+
}
29+
30+
t.Run("AllowUserWithGPGKey", func(t *testing.T) {
31+
test(t, 36, true, false) // has gpg
32+
})
33+
t.Run("AllowUserWithSSHKey", func(t *testing.T) {
34+
test(t, 2, false, true) // has ssh
35+
})
36+
t.Run("DenyUserWithNoKeys", func(t *testing.T) {
37+
test(t, 1, false, false) // no pubkey
38+
})
39+
}

0 commit comments

Comments
 (0)