From 1280de570485ac5dfe8c644564990d8175c8f043 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sun, 13 Sep 2026 00:26:20 +0800 Subject: [PATCH] chore: fix system users (#39299) --- cmd/audit.go | 2 +- models/user/user.go | 2 +- models/user/user_system.go | 37 ++++++------------- routers/private/internal_repo.go | 2 +- routers/web/auth/oauth.go | 4 +- routers/web/auth/oauth_signin_sync.go | 2 +- services/auth/reverseproxy.go | 2 +- .../auth/source/ldap/source_authenticate.go | 2 +- services/auth/source/ldap/source_sync.go | 2 +- .../auth/source/pam/source_authenticate.go | 2 +- .../auth/source/smtp/source_authenticate.go | 2 +- services/auth/source/source_group_sync.go | 2 +- services/auth/sspi.go | 2 +- services/lfs/server.go | 2 +- 14 files changed, 26 insertions(+), 39 deletions(-) diff --git a/cmd/audit.go b/cmd/audit.go index 23ac1f68c77..7ccad812bfc 100644 --- a/cmd/audit.go +++ b/cmd/audit.go @@ -13,5 +13,5 @@ import ( func cliAuditContext(ctx context.Context) context.Context { ctx = audit.WithOrigin(ctx, audit_model.OriginCLI) - return audit.WithDoer(ctx, user_model.NewCLIUser()) + return audit.WithDoer(ctx, user_model.NewCliUser()) } diff --git a/models/user/user.go b/models/user/user.go index 77da0fcdf2f..09358e7093c 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -580,7 +580,7 @@ var globalVars = sync.OnceValue(func() *globalVarsStruct { emailRegexp: regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"), } - userFuncs := []func() *User{NewGhostUser, NewActionsUser, NewDeployKeyUser} + userFuncs := []func() *User{NewGhostUser, NewActionsUser, NewDeployKeyUser, NewCliUser, NewAuthSourceUser} ret.systemUserNewFuncs = map[int64]func() *User{} ret.systemUserNameIdMap = map[string]int64{} for _, fn := range userFuncs { diff --git a/models/user/user_system.go b/models/user/user_system.go index 14304eb1174..7e1b49d265e 100644 --- a/models/user/user_system.go +++ b/models/user/user_system.go @@ -47,8 +47,10 @@ func newSystemUser(id int64, name, fullName string) *User { } const ( - ActionsUserID int64 = -2 - DeployKeyUserID int64 = -3 + ActionsUserID int64 = -2 + DeployKeyUserID int64 = -3 + CliUserID int64 = -4 + AuthSourceUserID int64 = -5 ) // NewActionsUser creates and returns a fake user for running the actions. @@ -90,30 +92,14 @@ func NewDeployKeyUserWithKeyID(id int64) *User { return u } -const ( - CLIUserID int64 = -4 - CLIUserName = "CLI" -) - -func NewCLIUser() *User { - return &User{ - ID: CLIUserID, - Name: CLIUserName, - LowerName: strings.ToLower(CLIUserName), - } +func NewCliUser() *User { + // for audit log only + return newSystemUser(CliUserID, "(gitea-cli)", "Gitea CLI") } -const ( - AuthenticationSourceUserID int64 = -5 - AuthenticationSourceUserName = "AuthenticationSource" -) - -func NewAuthenticationSourceUser() *User { - return &User{ - ID: AuthenticationSourceUserID, - Name: AuthenticationSourceUserName, - LowerName: strings.ToLower(AuthenticationSourceUserName), - } +func NewAuthSourceUser() *User { + // for audit log only + return newSystemUser(AuthSourceUserID, "(gitea-auth-source)", "Gitea Auth Source") } func GetSystemUserByName(name string) *User { @@ -125,7 +111,7 @@ func GetSystemUserByName(name string) *User { return nil } -func GetDoerUser(ctx context.Context, id int64, extDoerData string) (u *User, _ error) { +func GetDoerPermissionUser(ctx context.Context, id int64, extDoerData string) (u *User, _ error) { if id > 0 { return GetUserByID(ctx, id) } @@ -137,6 +123,7 @@ func GetDoerUser(ctx context.Context, id int64, extDoerData string) (u *User, _ u = NewDeployKeyUser() u.ExtDoerData = &extDoerDeployKey{} default: + // other system users are not real doers for the permission system return nil, ErrUserNotExist{UID: id} } return u, u.ExtDoerData.DecodeFromString(extDoerData) diff --git a/routers/private/internal_repo.go b/routers/private/internal_repo.go index 98bcae51d1d..d68c47325b2 100644 --- a/routers/private/internal_repo.go +++ b/routers/private/internal_repo.go @@ -45,7 +45,7 @@ func loadRepository(ctx *gitea_context.PrivateContext, ownerName, repoName strin } func loadContextDoerPermission(ctx *gitea_context.PrivateContext, userID int64, extDoerData string) bool { - doer, err := user.GetDoerUser(ctx, userID, extDoerData) + doer, err := user.GetDoerPermissionUser(ctx, userID, extDoerData) if err != nil { ctx.PrivateInternalErrorf("Failed to get user: %d, error: %v", userID, err) return false diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 0b3aeb865b4..0192aa1bd50 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -420,7 +420,7 @@ func handleOAuth2SignIn(ctx *context.Context, authSource *auth.Source, u *user_m // Register last login opts.SetLastLogin = true - if err := user_service.UpdateUser(audit.WithDoer(ctx, user_model.NewAuthenticationSourceUser()), u, opts); err != nil { + if err := user_service.UpdateUser(audit.WithDoer(ctx, user_model.NewAuthSourceUser()), u, opts); err != nil { ctx.ServerError("UpdateUser", err) return } @@ -449,7 +449,7 @@ func handleOAuth2SignIn(ctx *context.Context, authSource *auth.Source, u *user_m } if opts.IsActive.Has() || opts.IsAdmin.Has() || opts.IsRestricted.Has() { - if err := user_service.UpdateUser(audit.WithDoer(ctx, user_model.NewAuthenticationSourceUser()), u, opts); err != nil { + if err := user_service.UpdateUser(audit.WithDoer(ctx, user_model.NewAuthSourceUser()), u, opts); err != nil { ctx.ServerError("UpdateUser", err) return } diff --git a/routers/web/auth/oauth_signin_sync.go b/routers/web/auth/oauth_signin_sync.go index fcb84a7694c..0642b939005 100644 --- a/routers/web/auth/oauth_signin_sync.go +++ b/routers/web/auth/oauth_signin_sync.go @@ -55,7 +55,7 @@ func oauth2SignInSync(ctx *context.Context, authSourceID int64, u *user_model.Us // sync user flags (admin/restricted) isAdmin, isRestricted := getUserAdminAndRestrictedFromGroupClaims(oauth2Source, &gothUser) if isAdmin.Has() || isRestricted.Has() { - if err = user_service.UpdateUser(audit.WithDoer(ctx, user_model.NewAuthenticationSourceUser()), u, &user_service.UpdateOptions{IsAdmin: isAdmin, IsRestricted: isRestricted}); err != nil { + if err = user_service.UpdateUser(audit.WithDoer(ctx, user_model.NewAuthSourceUser()), u, &user_service.UpdateOptions{IsAdmin: isAdmin, IsRestricted: isRestricted}); err != nil { log.Error("Unable to sync OAuth2 user admin or restricted status %s: %v", gothUser.Provider, err) } } diff --git a/services/auth/reverseproxy.go b/services/auth/reverseproxy.go index e05f3b933f2..1cf3142285f 100644 --- a/services/auth/reverseproxy.go +++ b/services/auth/reverseproxy.go @@ -173,7 +173,7 @@ func (r *ReverseProxy) newUser(req *http.Request) *user_model.User { return nil } - audit.RecordAs(req.Context(), user_model.NewAuthenticationSourceUser(), audit_model.UserCreate, user) + audit.RecordAs(req.Context(), user_model.NewAuthSourceUser(), audit_model.UserCreate, user) return user } diff --git a/services/auth/source/ldap/source_authenticate.go b/services/auth/source/ldap/source_authenticate.go index 90977c88bcf..fe735d192f0 100644 --- a/services/auth/source/ldap/source_authenticate.go +++ b/services/auth/source/ldap/source_authenticate.go @@ -23,7 +23,7 @@ import ( // Authenticate queries if login/password is valid against the LDAP directory pool, // and create a local user if success when enabled. func (source *Source) Authenticate(ctx context.Context, user *user_model.User, userName, password string) (*user_model.User, error) { - ctx = audit.WithDoer(ctx, user_model.NewAuthenticationSourceUser()) + ctx = audit.WithDoer(ctx, user_model.NewAuthSourceUser()) loginName := userName if user != nil { diff --git a/services/auth/source/ldap/source_sync.go b/services/auth/source/ldap/source_sync.go index fe4f5a11231..98af9eb6e9f 100644 --- a/services/auth/source/ldap/source_sync.go +++ b/services/auth/source/ldap/source_sync.go @@ -28,7 +28,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error { // everything this sync changes is attributed to the authentication source, // not to a signed-in user - ctx = audit.WithDoer(ctx, user_model.NewAuthenticationSourceUser()) + ctx = audit.WithDoer(ctx, user_model.NewAuthSourceUser()) isAttributeSSHPublicKeySet := strings.TrimSpace(source.AttributeSSHPublicKey) != "" var sshKeysNeedUpdate bool diff --git a/services/auth/source/pam/source_authenticate.go b/services/auth/source/pam/source_authenticate.go index c359349da72..4c21b5cd387 100644 --- a/services/auth/source/pam/source_authenticate.go +++ b/services/auth/source/pam/source_authenticate.go @@ -68,7 +68,7 @@ func (source *Source) Authenticate(ctx context.Context, user *user_model.User, u return user, err } - audit.RecordAs(ctx, user_model.NewAuthenticationSourceUser(), audit_model.UserCreate, user) + audit.RecordAs(ctx, user_model.NewAuthSourceUser(), audit_model.UserCreate, user) return user, nil } diff --git a/services/auth/source/smtp/source_authenticate.go b/services/auth/source/smtp/source_authenticate.go index b58ce53984f..e306691eac9 100644 --- a/services/auth/source/smtp/source_authenticate.go +++ b/services/auth/source/smtp/source_authenticate.go @@ -85,7 +85,7 @@ func (source *Source) Authenticate(ctx context.Context, user *user_model.User, u return user, err } - audit.RecordAs(ctx, user_model.NewAuthenticationSourceUser(), audit_model.UserCreate, user) + audit.RecordAs(ctx, user_model.NewAuthSourceUser(), audit_model.UserCreate, user) return user, nil } diff --git a/services/auth/source/source_group_sync.go b/services/auth/source/source_group_sync.go index d8784de6b79..fd25ec29f49 100644 --- a/services/auth/source/source_group_sync.go +++ b/services/auth/source/source_group_sync.go @@ -33,7 +33,7 @@ func SyncGroupsToTeams(ctx context.Context, user *user_model.User, sourceUserGro // SyncGroupsToTeamsCached maps authentication source groups to organization and team memberships func SyncGroupsToTeamsCached(ctx context.Context, user *user_model.User, sourceUserGroups container.Set[string], sourceGroupTeamMapping map[string]map[string][]string, performRemoval bool, orgCache map[string]*organization.Organization, teamCache map[string]*organization.Team) error { // team membership changes here come from the authentication source mapping - ctx = audit.WithDoer(ctx, user_model.NewAuthenticationSourceUser()) + ctx = audit.WithDoer(ctx, user_model.NewAuthSourceUser()) membershipsToAdd, membershipsToRemove := resolveMappedMemberships(sourceUserGroups, sourceGroupTeamMapping) diff --git a/services/auth/sspi.go b/services/auth/sspi.go index 3d495c0441b..eee92c931c5 100644 --- a/services/auth/sspi.go +++ b/services/auth/sspi.go @@ -173,7 +173,7 @@ func (s *SSPI) newUser(ctx context.Context, username string, cfg *sspi.Source) ( return nil, err } - audit.RecordAs(ctx, user_model.NewAuthenticationSourceUser(), audit_model.UserCreate, user) + audit.RecordAs(ctx, user_model.NewAuthSourceUser(), audit_model.UserCreate, user) return user, nil } diff --git a/services/lfs/server.go b/services/lfs/server.go index ccca2297eea..6d5df20b123 100644 --- a/services/lfs/server.go +++ b/services/lfs/server.go @@ -598,7 +598,7 @@ func handleLFSToken(ctx stdCtx.Context, tokenSHA string, target *repo_model.Repo return nil, errors.New("invalid token claim") } - u, err := user_model.GetDoerUser(ctx, claims.UserID, claims.UserExtDoerData) + u, err := user_model.GetDoerPermissionUser(ctx, claims.UserID, claims.UserExtDoerData) if err != nil { log.Error("Unable to GetDoerUser[%d]: Error: %v", claims.UserID, err) return nil, err