mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-13 20:11:12 +00:00
8161479fde
For a `pull_request_target` (PRT) run, Gitea loads the top-level workflow from the trusted base branch, but any local reusable workflow it calls (`uses: ./...`) was read from the PR **head** commit, which the fork author controls. ## Fix **Record the source commit where the content is read.** `DetectedWorkflow` now carries a `SourceCommitSHA` filled in next to `Content`, so the PRT detection pass at the base commit records the base SHA automatically. **Defense in depth.** `loadReusableWorkflowSource` pins the PR base commit for a PRT run's local `uses: ./...` rather than trusting the stored SHA. This also covers runs recorded before this change, whose rows still hold the head SHA and would otherwise resolve from the fork on rerun. Existing run rows are not migrated. --------- Co-authored-by: Zettat <zettat123@gmail.com>
94 lines
3.0 KiB
Go
94 lines
3.0 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package actions
|
|
|
|
import (
|
|
"context"
|
|
|
|
"gitea.dev/modules/actions/jobparser"
|
|
"gitea.dev/modules/git"
|
|
"gitea.dev/modules/log"
|
|
"gitea.dev/modules/setting"
|
|
api "gitea.dev/modules/structs"
|
|
webhook_module "gitea.dev/modules/webhook"
|
|
)
|
|
|
|
// ListScopedWorkflows lists scoped workflow files (under SCOPED_WORKFLOW_DIRS) at the given commit.
|
|
func ListScopedWorkflows(ctx context.Context, gitRepo *git.Repository, commit *git.Commit) (string, git.Entries, error) {
|
|
return listWorkflowsInDirs(ctx, gitRepo, commit, setting.Actions.ScopedWorkflowDirs)
|
|
}
|
|
|
|
// ParsedScopedWorkflow is one scoped workflow's source-side parse result
|
|
type ParsedScopedWorkflow struct {
|
|
EntryName string
|
|
DisplayName string // the workflow `name:` or base file name
|
|
Content []byte // raw content of the workflow file
|
|
Events []*jobparser.Event // decoded `on:` events
|
|
}
|
|
|
|
// ParseScopedWorkflows lists and parses the scoped workflow files at sourceCommit (under SCOPED_WORKFLOW_DIRS).
|
|
func ParseScopedWorkflows(ctx context.Context, gitRepo *git.Repository, sourceCommit *git.Commit) ([]*ParsedScopedWorkflow, error) {
|
|
_, entries, err := ListScopedWorkflows(ctx, gitRepo, sourceCommit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
parsed := make([]*ParsedScopedWorkflow, 0, len(entries))
|
|
for _, entry := range entries {
|
|
content, err := GetContentFromEntry(ctx, gitRepo, entry)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// one workflow may have multiple events
|
|
events, err := GetEventsFromContent(content)
|
|
if err != nil {
|
|
log.Warn("ignore invalid scoped workflow %q: %v", entry.Name(), err)
|
|
continue
|
|
}
|
|
parsed = append(parsed, &ParsedScopedWorkflow{
|
|
EntryName: entry.Name(),
|
|
DisplayName: WorkflowDisplayName(entry.Name(), content),
|
|
Content: content,
|
|
Events: events,
|
|
})
|
|
}
|
|
return parsed, nil
|
|
}
|
|
|
|
// MatchScopedWorkflows evaluates already-parsed scoped workflows against one consuming event.
|
|
// It returns the workflows whose `on:` matches, and those that matched the event but were excluded by a branch/paths filter (filtered).
|
|
func MatchScopedWorkflows(
|
|
ctx context.Context,
|
|
parsed []*ParsedScopedWorkflow,
|
|
sourceCommitSHA string,
|
|
consumerGitRepo *git.Repository,
|
|
consumerCommit *git.Commit,
|
|
inputEvent webhook_module.HookEventType,
|
|
payload api.Payloader,
|
|
) (matched, filtered []*DetectedWorkflow) {
|
|
for _, p := range parsed {
|
|
for _, evt := range p.Events {
|
|
if evt.IsSchedule() {
|
|
// schedule is a non-target for scoped workflows
|
|
continue
|
|
}
|
|
dwf := &DetectedWorkflow{
|
|
EntryName: p.EntryName,
|
|
TriggerEvent: evt,
|
|
Content: p.Content,
|
|
SourceCommitSHA: sourceCommitSHA,
|
|
}
|
|
switch detectWorkflowMatch(ctx, consumerGitRepo, consumerCommit, inputEvent, payload, evt) {
|
|
case detectMatched:
|
|
matched = append(matched, dwf)
|
|
case detectFilteredOut:
|
|
filtered = append(filtered, dwf)
|
|
case detectNotApplicable:
|
|
}
|
|
}
|
|
}
|
|
return matched, filtered
|
|
}
|