diff --git a/pkg/runner/action.go b/pkg/runner/action.go index 94d9cfc..f871653 100644 --- a/pkg/runner/action.go +++ b/pkg/runner/action.go @@ -472,7 +472,7 @@ func runPreStep(step actionStep) common.Executor { var actionPath string if _, ok := step.(*stepActionRemote); ok { actionPath = newRemoteAction(stepModel.Uses).Path - actionDir = fmt.Sprintf("%s/%s", rc.ActionCacheDir(), strings.ReplaceAll(stepModel.Uses, "/", "-")) + actionDir = fmt.Sprintf("%s/%s", rc.ActionCacheDir(), safeFilename(stepModel.Uses)) } else { actionDir = filepath.Join(rc.Config.Workdir, stepModel.Uses) actionPath = "" @@ -563,7 +563,7 @@ func runPostStep(step actionStep) common.Executor { var actionPath string if _, ok := step.(*stepActionRemote); ok { actionPath = newRemoteAction(stepModel.Uses).Path - actionDir = fmt.Sprintf("%s/%s", rc.ActionCacheDir(), strings.ReplaceAll(stepModel.Uses, "/", "-")) + actionDir = fmt.Sprintf("%s/%s", rc.ActionCacheDir(), safeFilename(stepModel.Uses)) } else { actionDir = filepath.Join(rc.Config.Workdir, stepModel.Uses) actionPath = "" diff --git a/pkg/runner/reusable_workflow.go b/pkg/runner/reusable_workflow.go index a5687f9..1ffa22b 100644 --- a/pkg/runner/reusable_workflow.go +++ b/pkg/runner/reusable_workflow.go @@ -8,7 +8,6 @@ import ( "os" "path" "regexp" - "strings" "sync" "github.com/nektos/act/pkg/common" @@ -29,7 +28,7 @@ func newRemoteReusableWorkflowExecutor(rc *RunContext) common.Executor { } remoteReusableWorkflow.URL = rc.Config.GitHubInstance - workflowDir := fmt.Sprintf("%s/%s", rc.ActionCacheDir(), strings.ReplaceAll(uses, "/", "-")) + workflowDir := fmt.Sprintf("%s/%s", rc.ActionCacheDir(), safeFilename(uses)) return common.NewPipelineExecutor( newMutexExecutor(cloneIfRequired(rc, *remoteReusableWorkflow, workflowDir)), diff --git a/pkg/runner/step_action_remote.go b/pkg/runner/step_action_remote.go index 1783486..029ed5c 100644 --- a/pkg/runner/step_action_remote.go +++ b/pkg/runner/step_action_remote.go @@ -11,11 +11,11 @@ import ( "regexp" "strings" + gogit "github.com/go-git/go-git/v5" + "github.com/nektos/act/pkg/common" "github.com/nektos/act/pkg/common/git" "github.com/nektos/act/pkg/model" - - gogit "github.com/go-git/go-git/v5" ) type stepActionRemote struct { @@ -62,7 +62,7 @@ func (sar *stepActionRemote) prepareActionExecutor() common.Executor { } } - actionDir := fmt.Sprintf("%s/%s", sar.RunContext.ActionCacheDir(), strings.ReplaceAll(sar.Step.Uses, "/", "-")) + actionDir := fmt.Sprintf("%s/%s", sar.RunContext.ActionCacheDir(), safeFilename(sar.Step.Uses)) gitClone := stepActionRemoteNewCloneExecutor(git.NewGitCloneExecutorInput{ URL: sar.remoteAction.CloneURL(), Ref: sar.remoteAction.Ref, @@ -122,7 +122,7 @@ func (sar *stepActionRemote) main() common.Executor { return sar.RunContext.JobContainer.CopyDir(copyToPath, sar.RunContext.Config.Workdir+string(filepath.Separator)+".", sar.RunContext.Config.UseGitIgnore)(ctx) } - actionDir := fmt.Sprintf("%s/%s", sar.RunContext.ActionCacheDir(), strings.ReplaceAll(sar.Step.Uses, "/", "-")) + actionDir := fmt.Sprintf("%s/%s", sar.RunContext.ActionCacheDir(), safeFilename(sar.Step.Uses)) return sar.runAction(sar, actionDir, sar.remoteAction)(ctx) }), @@ -181,7 +181,7 @@ func (sar *stepActionRemote) getActionModel() *model.Action { func (sar *stepActionRemote) getCompositeRunContext(ctx context.Context) *RunContext { if sar.compositeRunContext == nil { - actionDir := fmt.Sprintf("%s/%s", sar.RunContext.ActionCacheDir(), strings.ReplaceAll(sar.Step.Uses, "/", "-")) + actionDir := fmt.Sprintf("%s/%s", sar.RunContext.ActionCacheDir(), safeFilename(sar.Step.Uses)) actionLocation := path.Join(actionDir, sar.remoteAction.Path) _, containerActionDir := getContainerActionPaths(sar.getStepModel(), actionLocation, sar.RunContext) @@ -243,3 +243,17 @@ func newRemoteAction(action string) *remoteAction { URL: "github.com", } } + +func safeFilename(s string) string { + return strings.NewReplacer( + `<`, "-", + `>`, "-", + `:`, "-", + `"`, "-", + `/`, "-", + `\`, "-", + `|`, "-", + `?`, "-", + `*`, "-", + ).Replace(s) +} diff --git a/pkg/runner/step_action_remote_test.go b/pkg/runner/step_action_remote_test.go index 23d6554..dfc49d2 100644 --- a/pkg/runner/step_action_remote_test.go +++ b/pkg/runner/step_action_remote_test.go @@ -8,13 +8,13 @@ import ( "strings" "testing" - "github.com/nektos/act/pkg/common" - "github.com/nektos/act/pkg/common/git" - "github.com/nektos/act/pkg/model" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "gopkg.in/yaml.v3" + + "github.com/nektos/act/pkg/common" + "github.com/nektos/act/pkg/common/git" + "github.com/nektos/act/pkg/model" ) type stepActionRemoteMocks struct { @@ -615,3 +615,24 @@ func TestStepActionRemotePost(t *testing.T) { }) } } + +func Test_safeFilename(t *testing.T) { + tests := []struct { + s string + want string + }{ + { + s: "https://test.com/test/", + want: "https---test.com-test-", + }, + { + s: `<>:"/\|?*`, + want: "---------", + }, + } + for _, tt := range tests { + t.Run(tt.s, func(t *testing.T) { + assert.Equalf(t, tt.want, safeFilename(tt.s), "safeFilename(%v)", tt.s) + }) + } +}