Skip to content

Commit 48e5a74

Browse files
authored
Support pull_request_target event (#25229)
Fix #25088 This PR adds the support for [`pull_request_target`](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target) workflow trigger. `pull_request_target` is similar to `pull_request`, but the workflow triggered by the `pull_request_target` event runs in the context of the base branch of the pull request rather than the head branch. Since the workflow from the base is considered trusted, it can access the secrets and doesn't need approvals to run.
1 parent e409e14 commit 48e5a74

File tree

10 files changed

+286
-63
lines changed

10 files changed

+286
-63
lines changed

models/actions/run.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ type ActionRun struct {
3636
TriggerUser *user_model.User `xorm:"-"`
3737
Ref string
3838
CommitSHA string
39-
IsForkPullRequest bool // If this is triggered by a PR from a forked repository or an untrusted user, we need to check if it is approved and limit permissions when running the workflow.
40-
NeedApproval bool // may need approval if it's a fork pull request
41-
ApprovedBy int64 `xorm:"index"` // who approved
42-
Event webhook_module.HookEventType
43-
EventPayload string `xorm:"LONGTEXT"`
44-
Status Status `xorm:"index"`
39+
IsForkPullRequest bool // If this is triggered by a PR from a forked repository or an untrusted user, we need to check if it is approved and limit permissions when running the workflow.
40+
NeedApproval bool // may need approval if it's a fork pull request
41+
ApprovedBy int64 `xorm:"index"` // who approved
42+
Event webhook_module.HookEventType // the webhook event that causes the workflow to run
43+
EventPayload string `xorm:"LONGTEXT"`
44+
TriggerEvent string // the trigger event defined in the `on` configuration of the triggered workflow
45+
Status Status `xorm:"index"`
4546
Started timeutil.TimeStamp
4647
Stopped timeutil.TimeStamp
4748
Created timeutil.TimeStamp `xorm:"created"`

models/migrations/migrations.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,9 +503,10 @@ var migrations = []Migration{
503503

504504
// v260 -> v261
505505
NewMigration("Drop custom_labels column of action_runner table", v1_21.DropCustomLabelsColumnOfActionRunner),
506-
507506
// v261 -> v262
508507
NewMigration("Add variable table", v1_21.CreateVariableTable),
508+
// v262 -> v263
509+
NewMigration("Add TriggerEvent to action_run table", v1_21.AddTriggerEventToActionRun),
509510
}
510511

511512
// GetCurrentDBVersion returns the current db version

models/migrations/v1_21/v262.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_21 //nolint
5+
6+
import (
7+
"xorm.io/xorm"
8+
)
9+
10+
func AddTriggerEventToActionRun(x *xorm.Engine) error {
11+
type ActionRun struct {
12+
TriggerEvent string
13+
}
14+
15+
return x.Sync(new(ActionRun))
16+
}

modules/actions/github.go

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,33 @@ import (
88
)
99

1010
const (
11-
githubEventPullRequest = "pull_request"
12-
githubEventPullRequestTarget = "pull_request_target"
13-
githubEventPullRequestReviewComment = "pull_request_review_comment"
14-
githubEventPullRequestReview = "pull_request_review"
15-
githubEventRegistryPackage = "registry_package"
16-
githubEventCreate = "create"
17-
githubEventDelete = "delete"
18-
githubEventFork = "fork"
19-
githubEventPush = "push"
20-
githubEventIssues = "issues"
21-
githubEventIssueComment = "issue_comment"
22-
githubEventRelease = "release"
23-
githubEventPullRequestComment = "pull_request_comment"
24-
githubEventGollum = "gollum"
11+
GithubEventPullRequest = "pull_request"
12+
GithubEventPullRequestTarget = "pull_request_target"
13+
GithubEventPullRequestReviewComment = "pull_request_review_comment"
14+
GithubEventPullRequestReview = "pull_request_review"
15+
GithubEventRegistryPackage = "registry_package"
16+
GithubEventCreate = "create"
17+
GithubEventDelete = "delete"
18+
GithubEventFork = "fork"
19+
GithubEventPush = "push"
20+
GithubEventIssues = "issues"
21+
GithubEventIssueComment = "issue_comment"
22+
GithubEventRelease = "release"
23+
GithubEventPullRequestComment = "pull_request_comment"
24+
GithubEventGollum = "gollum"
2525
)
2626

2727
// canGithubEventMatch check if the input Github event can match any Gitea event.
2828
func canGithubEventMatch(eventName string, triggedEvent webhook_module.HookEventType) bool {
2929
switch eventName {
30-
case githubEventRegistryPackage:
30+
case GithubEventRegistryPackage:
3131
return triggedEvent == webhook_module.HookEventPackage
3232

3333
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#gollum
34-
case githubEventGollum:
34+
case GithubEventGollum:
3535
return triggedEvent == webhook_module.HookEventWiki
3636

37-
case githubEventIssues:
37+
case GithubEventIssues:
3838
switch triggedEvent {
3939
case webhook_module.HookEventIssues,
4040
webhook_module.HookEventIssueAssign,
@@ -46,7 +46,7 @@ func canGithubEventMatch(eventName string, triggedEvent webhook_module.HookEvent
4646
return false
4747
}
4848

49-
case githubEventPullRequest, githubEventPullRequestTarget:
49+
case GithubEventPullRequest, GithubEventPullRequestTarget:
5050
switch triggedEvent {
5151
case webhook_module.HookEventPullRequest,
5252
webhook_module.HookEventPullRequestSync,
@@ -58,7 +58,7 @@ func canGithubEventMatch(eventName string, triggedEvent webhook_module.HookEvent
5858
return false
5959
}
6060

61-
case githubEventPullRequestReview:
61+
case GithubEventPullRequestReview:
6262
switch triggedEvent {
6363
case webhook_module.HookEventPullRequestReviewApproved,
6464
webhook_module.HookEventPullRequestReviewComment,

modules/actions/github_test.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,85 +21,85 @@ func TestCanGithubEventMatch(t *testing.T) {
2121
// registry_package event
2222
{
2323
"registry_package matches",
24-
githubEventRegistryPackage,
24+
GithubEventRegistryPackage,
2525
webhook_module.HookEventPackage,
2626
true,
2727
},
2828
{
2929
"registry_package cannot match",
30-
githubEventRegistryPackage,
30+
GithubEventRegistryPackage,
3131
webhook_module.HookEventPush,
3232
false,
3333
},
3434
// issues event
3535
{
3636
"issue matches",
37-
githubEventIssues,
37+
GithubEventIssues,
3838
webhook_module.HookEventIssueLabel,
3939
true,
4040
},
4141
{
4242
"issue cannot match",
43-
githubEventIssues,
43+
GithubEventIssues,
4444
webhook_module.HookEventIssueComment,
4545
false,
4646
},
4747
// issue_comment event
4848
{
4949
"issue_comment matches",
50-
githubEventIssueComment,
50+
GithubEventIssueComment,
5151
webhook_module.HookEventIssueComment,
5252
true,
5353
},
5454
{
5555
"issue_comment cannot match",
56-
githubEventIssueComment,
56+
GithubEventIssueComment,
5757
webhook_module.HookEventIssues,
5858
false,
5959
},
6060
// pull_request event
6161
{
6262
"pull_request matches",
63-
githubEventPullRequest,
63+
GithubEventPullRequest,
6464
webhook_module.HookEventPullRequestSync,
6565
true,
6666
},
6767
{
6868
"pull_request cannot match",
69-
githubEventPullRequest,
69+
GithubEventPullRequest,
7070
webhook_module.HookEventPullRequestComment,
7171
false,
7272
},
7373
// pull_request_target event
7474
{
7575
"pull_request_target matches",
76-
githubEventPullRequest,
76+
GithubEventPullRequest,
7777
webhook_module.HookEventPullRequest,
7878
true,
7979
},
8080
{
8181
"pull_request_target cannot match",
82-
githubEventPullRequest,
82+
GithubEventPullRequest,
8383
webhook_module.HookEventPullRequestComment,
8484
false,
8585
},
8686
// pull_request_review event
8787
{
8888
"pull_request_review matches",
89-
githubEventPullRequestReview,
89+
GithubEventPullRequestReview,
9090
webhook_module.HookEventPullRequestReviewComment,
9191
true,
9292
},
9393
{
9494
"pull_request_review cannot match",
95-
githubEventPullRequestReview,
95+
GithubEventPullRequestReview,
9696
webhook_module.HookEventPullRequestComment,
9797
false,
9898
},
9999
// other events
100100
{
101101
"create event",
102-
githubEventCreate,
102+
GithubEventCreate,
103103
webhook_module.HookEventCreate,
104104
true,
105105
},

modules/actions/workflows.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ import (
2020
"gopkg.in/yaml.v3"
2121
)
2222

23+
type DetectedWorkflow struct {
24+
EntryName string
25+
TriggerEvent string
26+
Commit *git.Commit
27+
Ref string
28+
Content []byte
29+
}
30+
2331
func init() {
2432
model.OnDecodeNodeError = func(node yaml.Node, out interface{}, err error) {
2533
// Log the error instead of panic or fatal.
@@ -89,13 +97,13 @@ func GetEventsFromContent(content []byte) ([]*jobparser.Event, error) {
8997
return events, nil
9098
}
9199

92-
func DetectWorkflows(commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader) (map[string][]byte, error) {
100+
func DetectWorkflows(commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader) ([]*DetectedWorkflow, error) {
93101
entries, err := ListWorkflows(commit)
94102
if err != nil {
95103
return nil, err
96104
}
97105

98-
workflows := make(map[string][]byte, len(entries))
106+
workflows := make([]*DetectedWorkflow, 0, len(entries))
99107
for _, entry := range entries {
100108
content, err := GetContentFromEntry(entry)
101109
if err != nil {
@@ -109,7 +117,13 @@ func DetectWorkflows(commit *git.Commit, triggedEvent webhook_module.HookEventTy
109117
for _, evt := range events {
110118
log.Trace("detect workflow %q for event %#v matching %q", entry.Name(), evt, triggedEvent)
111119
if detectMatched(commit, triggedEvent, payload, evt) {
112-
workflows[entry.Name()] = content
120+
dwf := &DetectedWorkflow{
121+
EntryName: entry.Name(),
122+
TriggerEvent: evt.Name,
123+
Commit: commit,
124+
Content: content,
125+
}
126+
workflows = append(workflows, dwf)
113127
}
114128
}
115129
}

modules/actions/workflows_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,77 +23,77 @@ func TestDetectMatched(t *testing.T) {
2323
expected bool
2424
}{
2525
{
26-
desc: "HookEventCreate(create) matches githubEventCreate(create)",
26+
desc: "HookEventCreate(create) matches GithubEventCreate(create)",
2727
triggedEvent: webhook_module.HookEventCreate,
2828
payload: nil,
2929
yamlOn: "on: create",
3030
expected: true,
3131
},
3232
{
33-
desc: "HookEventIssues(issues) `opened` action matches githubEventIssues(issues)",
33+
desc: "HookEventIssues(issues) `opened` action matches GithubEventIssues(issues)",
3434
triggedEvent: webhook_module.HookEventIssues,
3535
payload: &api.IssuePayload{Action: api.HookIssueOpened},
3636
yamlOn: "on: issues",
3737
expected: true,
3838
},
3939
{
40-
desc: "HookEventIssues(issues) `milestoned` action matches githubEventIssues(issues)",
40+
desc: "HookEventIssues(issues) `milestoned` action matches GithubEventIssues(issues)",
4141
triggedEvent: webhook_module.HookEventIssues,
4242
payload: &api.IssuePayload{Action: api.HookIssueMilestoned},
4343
yamlOn: "on: issues",
4444
expected: true,
4545
},
4646
{
47-
desc: "HookEventPullRequestSync(pull_request_sync) matches githubEventPullRequest(pull_request)",
47+
desc: "HookEventPullRequestSync(pull_request_sync) matches GithubEventPullRequest(pull_request)",
4848
triggedEvent: webhook_module.HookEventPullRequestSync,
4949
payload: &api.PullRequestPayload{Action: api.HookIssueSynchronized},
5050
yamlOn: "on: pull_request",
5151
expected: true,
5252
},
5353
{
54-
desc: "HookEventPullRequest(pull_request) `label_updated` action doesn't match githubEventPullRequest(pull_request) with no activity type",
54+
desc: "HookEventPullRequest(pull_request) `label_updated` action doesn't match GithubEventPullRequest(pull_request) with no activity type",
5555
triggedEvent: webhook_module.HookEventPullRequest,
5656
payload: &api.PullRequestPayload{Action: api.HookIssueLabelUpdated},
5757
yamlOn: "on: pull_request",
5858
expected: false,
5959
},
6060
{
61-
desc: "HookEventPullRequest(pull_request) `label_updated` action matches githubEventPullRequest(pull_request) with `label` activity type",
61+
desc: "HookEventPullRequest(pull_request) `label_updated` action matches GithubEventPullRequest(pull_request) with `label` activity type",
6262
triggedEvent: webhook_module.HookEventPullRequest,
6363
payload: &api.PullRequestPayload{Action: api.HookIssueLabelUpdated},
6464
yamlOn: "on:\n pull_request:\n types: [labeled]",
6565
expected: true,
6666
},
6767
{
68-
desc: "HookEventPullRequestReviewComment(pull_request_review_comment) matches githubEventPullRequestReviewComment(pull_request_review_comment)",
68+
desc: "HookEventPullRequestReviewComment(pull_request_review_comment) matches GithubEventPullRequestReviewComment(pull_request_review_comment)",
6969
triggedEvent: webhook_module.HookEventPullRequestReviewComment,
7070
payload: &api.PullRequestPayload{Action: api.HookIssueReviewed},
7171
yamlOn: "on:\n pull_request_review_comment:\n types: [created]",
7272
expected: true,
7373
},
7474
{
75-
desc: "HookEventPullRequestReviewRejected(pull_request_review_rejected) doesn't match githubEventPullRequestReview(pull_request_review) with `dismissed` activity type (we don't support `dismissed` at present)",
75+
desc: "HookEventPullRequestReviewRejected(pull_request_review_rejected) doesn't match GithubEventPullRequestReview(pull_request_review) with `dismissed` activity type (we don't support `dismissed` at present)",
7676
triggedEvent: webhook_module.HookEventPullRequestReviewRejected,
7777
payload: &api.PullRequestPayload{Action: api.HookIssueReviewed},
7878
yamlOn: "on:\n pull_request_review:\n types: [dismissed]",
7979
expected: false,
8080
},
8181
{
82-
desc: "HookEventRelease(release) `published` action matches githubEventRelease(release) with `published` activity type",
82+
desc: "HookEventRelease(release) `published` action matches GithubEventRelease(release) with `published` activity type",
8383
triggedEvent: webhook_module.HookEventRelease,
8484
payload: &api.ReleasePayload{Action: api.HookReleasePublished},
8585
yamlOn: "on:\n release:\n types: [published]",
8686
expected: true,
8787
},
8888
{
89-
desc: "HookEventPackage(package) `created` action doesn't match githubEventRegistryPackage(registry_package) with `updated` activity type",
89+
desc: "HookEventPackage(package) `created` action doesn't match GithubEventRegistryPackage(registry_package) with `updated` activity type",
9090
triggedEvent: webhook_module.HookEventPackage,
9191
payload: &api.PackagePayload{Action: api.HookPackageCreated},
9292
yamlOn: "on:\n registry_package:\n types: [updated]",
9393
expected: false,
9494
},
9595
{
96-
desc: "HookEventWiki(wiki) matches githubEventGollum(gollum)",
96+
desc: "HookEventWiki(wiki) matches GithubEventGollum(gollum)",
9797
triggedEvent: webhook_module.HookEventWiki,
9898
payload: nil,
9999
yamlOn: "on: gollum",

routers/api/actions/runner/utils.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
actions_model "code.gitea.io/gitea/models/actions"
1111
secret_model "code.gitea.io/gitea/models/secret"
12+
actions_module "code.gitea.io/gitea/modules/actions"
1213
"code.gitea.io/gitea/modules/git"
1314
"code.gitea.io/gitea/modules/json"
1415
"code.gitea.io/gitea/modules/log"
@@ -54,8 +55,10 @@ func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv
5455

5556
func getSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) map[string]string {
5657
secrets := map[string]string{}
57-
if task.Job.Run.IsForkPullRequest {
58+
if task.Job.Run.IsForkPullRequest && task.Job.Run.TriggerEvent != actions_module.GithubEventPullRequestTarget {
5859
// ignore secrets for fork pull request
60+
// for the tasks triggered by pull_request_target event, they could access the secrets because they will run in the context of the base branch
61+
// see the documentation: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
5962
return secrets
6063
}
6164

@@ -116,6 +119,14 @@ func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
116119
event := map[string]interface{}{}
117120
_ = json.Unmarshal([]byte(t.Job.Run.EventPayload), &event)
118121

122+
// TriggerEvent is added in https://github.com/go-gitea/gitea/pull/25229
123+
// This fallback is for the old ActionRun that doesn't have the TriggerEvent field
124+
// and should be removed in 1.22
125+
eventName := t.Job.Run.TriggerEvent
126+
if eventName == "" {
127+
eventName = t.Job.Run.Event.Event()
128+
}
129+
119130
baseRef := ""
120131
headRef := ""
121132
if pullPayload, err := t.Job.Run.GetPullRequestEventPayload(); err == nil && pullPayload.PullRequest != nil && pullPayload.PullRequest.Base != nil && pullPayload.PullRequest.Head != nil {
@@ -137,7 +148,7 @@ func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
137148
"base_ref": baseRef, // string, The base_ref or target branch of the pull request in a workflow run. This property is only available when the event that triggers a workflow run is either pull_request or pull_request_target.
138149
"env": "", // string, Path on the runner to the file that sets environment variables from workflow commands. This file is unique to the current step and is a different file for each step in a job. For more information, see "Workflow commands for GitHub Actions."
139150
"event": event, // object, The full event webhook payload. You can access individual properties of the event using this context. This object is identical to the webhook payload of the event that triggered the workflow run, and is different for each event. The webhooks for each GitHub Actions event is linked in "Events that trigger workflows." For example, for a workflow run triggered by the push event, this object contains the contents of the push webhook payload.
140-
"event_name": t.Job.Run.Event.Event(), // string, The name of the event that triggered the workflow run.
151+
"event_name": eventName, // string, The name of the event that triggered the workflow run.
141152
"event_path": "", // string, The path to the file on the runner that contains the full event webhook payload.
142153
"graphql_url": "", // string, The URL of the GitHub GraphQL API.
143154
"head_ref": headRef, // string, The head_ref or source branch of the pull request in a workflow run. This property is only available when the event that triggers a workflow run is either pull_request or pull_request_target.

0 commit comments

Comments
 (0)