Require approval to run actions for fork pull request (#22803)
Currently, Gitea will run actions automatically which are triggered by fork pull request. It's a security risk, people can create a PR and modify the workflow yamls to execute a malicious script. So we should require approval for first-time contributors, which is the default strategy of a public repo on GitHub, see [Approving workflow runs from public forks](https://docs.github.com/en/actions/managing-workflow-runs/approving-workflow-runs-from-public-forks). Current strategy: - don't need approval if it's not a fork PR; - always need approval if the user is restricted; - don't need approval if the user can write; - don't need approval if the user has been approved before; - otherwise, need approval. https://user-images.githubusercontent.com/9418365/217207121-badf50a8-826c-4425-bef1-d82d1979bc81.mov GitHub has an option for that, you can see that at `/<owner>/<repo>/settings/actions`, and we can support that later. <img width="835" alt="image" src="https://user-images.githubusercontent.com/9418365/217199990-2967e68b-e693-4e59-8186-ab33a1314a16.png"> --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
parent
a6175b01d9
commit
edf98a2dc3
10 changed files with 154 additions and 16 deletions
|
@ -32,11 +32,13 @@ type ActionRun struct {
|
|||
OwnerID int64 `xorm:"index"`
|
||||
WorkflowID string `xorm:"index"` // the name of workflow file
|
||||
Index int64 `xorm:"index unique(repo_index)"` // a unique number for each run of a repository
|
||||
TriggerUserID int64
|
||||
TriggerUser *user_model.User `xorm:"-"`
|
||||
TriggerUserID int64 `xorm:"index"`
|
||||
TriggerUser *user_model.User `xorm:"-"`
|
||||
Ref string
|
||||
CommitSHA string
|
||||
IsForkPullRequest bool
|
||||
NeedApproval bool // may need approval if it's a fork pull request
|
||||
ApprovedBy int64 `xorm:"index"` // who approved
|
||||
Event webhook_module.HookEventType
|
||||
EventPayload string `xorm:"LONGTEXT"`
|
||||
Status Status `xorm:"index"`
|
||||
|
@ -164,10 +166,6 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
|
|||
}
|
||||
run.Index = index
|
||||
|
||||
if run.Status.IsUnknown() {
|
||||
run.Status = StatusWaiting
|
||||
}
|
||||
|
||||
if err := db.Insert(ctx, run); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -191,7 +189,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
|
|||
job.EraseNeeds()
|
||||
payload, _ := v.Marshal()
|
||||
status := StatusWaiting
|
||||
if len(needs) > 0 {
|
||||
if len(needs) > 0 || run.NeedApproval {
|
||||
status = StatusBlocked
|
||||
}
|
||||
runJobs = append(runJobs, &ActionRunJob{
|
||||
|
|
|
@ -68,6 +68,8 @@ type FindRunOptions struct {
|
|||
OwnerID int64
|
||||
IsClosed util.OptionalBool
|
||||
WorkflowFileName string
|
||||
TriggerUserID int64
|
||||
Approved bool // not util.OptionalBool, it works only when it's true
|
||||
}
|
||||
|
||||
func (opts FindRunOptions) toConds() builder.Cond {
|
||||
|
@ -89,6 +91,12 @@ func (opts FindRunOptions) toConds() builder.Cond {
|
|||
if opts.WorkflowFileName != "" {
|
||||
cond = cond.And(builder.Eq{"workflow_id": opts.WorkflowFileName})
|
||||
}
|
||||
if opts.TriggerUserID > 0 {
|
||||
cond = cond.And(builder.Eq{"trigger_user_id": opts.TriggerUserID})
|
||||
}
|
||||
if opts.Approved {
|
||||
cond = cond.And(builder.Gt{"approved_by": 0})
|
||||
}
|
||||
return cond
|
||||
}
|
||||
|
||||
|
|
|
@ -82,6 +82,10 @@ func (s Status) IsRunning() bool {
|
|||
return s == StatusRunning
|
||||
}
|
||||
|
||||
func (s Status) IsBlocked() bool {
|
||||
return s == StatusBlocked
|
||||
}
|
||||
|
||||
// In returns whether s is one of the given statuses
|
||||
func (s Status) In(statuses ...Status) bool {
|
||||
for _, v := range statuses {
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"code.gitea.io/gitea/models/migrations/v1_17"
|
||||
"code.gitea.io/gitea/models/migrations/v1_18"
|
||||
"code.gitea.io/gitea/models/migrations/v1_19"
|
||||
"code.gitea.io/gitea/models/migrations/v1_20"
|
||||
"code.gitea.io/gitea/models/migrations/v1_6"
|
||||
"code.gitea.io/gitea/models/migrations/v1_7"
|
||||
"code.gitea.io/gitea/models/migrations/v1_8"
|
||||
|
@ -463,6 +464,9 @@ var migrations = []Migration{
|
|||
NewMigration("Add exclusive label", v1_19.AddExclusiveLabel),
|
||||
|
||||
// Gitea 1.19.0 ends at v244
|
||||
|
||||
// v244 -> v245
|
||||
NewMigration("Add NeedApproval to actions tables", v1_20.AddNeedApprovalToActionRun),
|
||||
}
|
||||
|
||||
// GetCurrentDBVersion returns the current db version
|
||||
|
|
22
models/migrations/v1_20/v244.go
Normal file
22
models/migrations/v1_20/v244.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_20 //nolint
|
||||
|
||||
import (
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func AddNeedApprovalToActionRun(x *xorm.Engine) error {
|
||||
/*
|
||||
New index: TriggerUserID
|
||||
New fields: NeedApproval, ApprovedBy
|
||||
*/
|
||||
type ActionRun struct {
|
||||
TriggerUserID int64 `xorm:"index"`
|
||||
NeedApproval bool // may need approval if it's a fork pull request
|
||||
ApprovedBy int64 `xorm:"index"` // who approved
|
||||
}
|
||||
|
||||
return x.Sync(new(ActionRun))
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue