Redefine the meaning of column is_active to make Actions Registration Token generation easier (#27143)

Partially Fix #25041

This PR redefined the meaning of column `is_active` in table
`action_runner_token`.
Before this PR, `is_active` means whether it has been used by any
runner. If it's true, other runner cannot use it to register again.

In this PR, `is_active` means whether it's validated to be used to
register runner. And if it's true, then it can be used to register
runners until it become false. When creating a new `is_active` register
token, any previous tokens will be set `is_active` to false.
This commit is contained in:
Lunny Xiao 2023-09-27 13:37:48 +08:00 committed by GitHub
parent ee27b94b2c
commit 3b2da7e4ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 26 additions and 16 deletions

View file

@ -22,7 +22,7 @@ type ActionRunnerToken struct {
Owner *user_model.User `xorm:"-"` Owner *user_model.User `xorm:"-"`
RepoID int64 `xorm:"index"` // repo level runner, if orgid also is zero, then it's a global RepoID int64 `xorm:"index"` // repo level runner, if orgid also is zero, then it's a global
Repo *repo_model.Repository `xorm:"-"` Repo *repo_model.Repository `xorm:"-"`
IsActive bool IsActive bool // true means it can be used
Created timeutil.TimeStamp `xorm:"created"` Created timeutil.TimeStamp `xorm:"created"`
Updated timeutil.TimeStamp `xorm:"updated"` Updated timeutil.TimeStamp `xorm:"updated"`
@ -57,7 +57,7 @@ func UpdateRunnerToken(ctx context.Context, r *ActionRunnerToken, cols ...string
return err return err
} }
// NewRunnerToken creates a new runner token // NewRunnerToken creates a new active runner token and invalidate all old tokens
func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
token, err := util.CryptoRandomString(40) token, err := util.CryptoRandomString(40)
if err != nil { if err != nil {
@ -66,17 +66,27 @@ func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerTo
runnerToken := &ActionRunnerToken{ runnerToken := &ActionRunnerToken{
OwnerID: ownerID, OwnerID: ownerID,
RepoID: repoID, RepoID: repoID,
IsActive: false, IsActive: true,
Token: token, Token: token,
} }
_, err = db.GetEngine(ctx).Insert(runnerToken)
return runnerToken, err return runnerToken, db.WithTx(ctx, func(ctx context.Context) error {
if _, err := db.GetEngine(ctx).Where("owner_id =? AND repo_id = ?", ownerID, repoID).Cols("is_active").Update(&ActionRunnerToken{
IsActive: false,
}); err != nil {
return err
} }
// GetUnactivatedRunnerToken returns a unactivated runner token _, err = db.GetEngine(ctx).Insert(runnerToken)
func GetUnactivatedRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { return err
})
}
// GetLastestRunnerToken returns the latest runner token
func GetLastestRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
var runnerToken ActionRunnerToken var runnerToken ActionRunnerToken
has, err := db.GetEngine(ctx).Where("owner_id=? AND repo_id=? AND is_active=?", ownerID, repoID, false).OrderBy("id DESC").Get(&runnerToken) has, err := db.GetEngine(ctx).Where("owner_id=? AND repo_id=?", ownerID, repoID).
OrderBy("id DESC").Get(&runnerToken)
if err != nil { if err != nil {
return nil, err return nil, err
} else if !has { } else if !has {

View file

@ -47,11 +47,11 @@ func (s *Service) Register(
runnerToken, err := actions_model.GetRunnerToken(ctx, req.Msg.Token) runnerToken, err := actions_model.GetRunnerToken(ctx, req.Msg.Token)
if err != nil { if err != nil {
return nil, errors.New("runner token not found") return nil, errors.New("runner registration token not found")
} }
if runnerToken.IsActive { if !runnerToken.IsActive {
return nil, errors.New("runner token has already been activated") return nil, errors.New("runner registration token has been invalidated, please use the latest one")
} }
labels := req.Msg.Labels labels := req.Msg.Labels

View file

@ -41,8 +41,8 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) {
}) })
} }
token, err := actions_model.GetUnactivatedRunnerToken(ctx, owner, repo) token, err := actions_model.GetLastestRunnerToken(ctx, owner, repo)
if errors.Is(err, util.ErrNotExist) { if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) {
token, err = actions_model.NewRunnerToken(ctx, owner, repo) token, err = actions_model.NewRunnerToken(ctx, owner, repo)
if err != nil { if err != nil {
err := fmt.Sprintf("error while creating runner token: %v", err) err := fmt.Sprintf("error while creating runner token: %v", err)

View file

@ -35,15 +35,15 @@ func RunnersList(ctx *context.Context, opts actions_model.FindRunnerOptions) {
// ownid=0,repo_id=0,means this token is used for global // ownid=0,repo_id=0,means this token is used for global
var token *actions_model.ActionRunnerToken var token *actions_model.ActionRunnerToken
token, err = actions_model.GetUnactivatedRunnerToken(ctx, opts.OwnerID, opts.RepoID) token, err = actions_model.GetLastestRunnerToken(ctx, opts.OwnerID, opts.RepoID)
if errors.Is(err, util.ErrNotExist) { if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) {
token, err = actions_model.NewRunnerToken(ctx, opts.OwnerID, opts.RepoID) token, err = actions_model.NewRunnerToken(ctx, opts.OwnerID, opts.RepoID)
if err != nil { if err != nil {
ctx.ServerError("CreateRunnerToken", err) ctx.ServerError("CreateRunnerToken", err)
return return
} }
} else if err != nil { } else if err != nil {
ctx.ServerError("GetUnactivatedRunnerToken", err) ctx.ServerError("GetLastestRunnerToken", err)
return return
} }