Repository: nektos/act (language: go)

Issue:
`--use-new-action-cache` doesn't handle `HEAD`
### Bug report info

```plain text
act version:            4ca35d2
GOOS:                   darwin
GOARCH:                 arm64
NumCPU:                 10
Docker host:            DOCKER_HOST environment variable is not set
Sockets found:
	/var/run/docker.sock
Config files:           
	/Users/jsoref/.actrc:
		#-P ubuntu-latest=node:12.20.1-buster-slim
		#-P ubuntu-20.04=node:12.20.1-buster-slim
		#-P ubuntu-18.04=node:12.20.1-buster-slim
		-P ubuntu-latest=catthehacker/ubuntu:act-latest
		-P ubuntu-22.04=catthehacker/ubuntu:act-22.04
		-P ubuntu-20.04=catthehacker/ubuntu:act-20.04
		-P ubuntu-18.04=catthehacker/ubuntu:act-18.04
		-P ubuntu-16.04=catthehacker/ubuntu:act-16.04
		-P self-hosted=catthehacker/ubuntu:act-latest
		-P ubuntu-latest-4cpu=ubuntu:act-latest
		-P ubuntu-latest-8cpu=ubuntu:act-latest
Build info:
	Go version:            go1.21.6
	Module path:           command-line-arguments
	Main version:          
	Main path:             
	Main checksum:         
	Build settings:
		-buildmode:           exe
		-compiler:            gc
		-ldflags:             -X main.version=4ca35d2
		DefaultGODEBUG:       panicnil=1
		CGO_ENABLED:          1
		CGO_CFLAGS:           
		CGO_CPPFLAGS:         
		CGO_CXXFLAGS:         
		CGO_LDFLAGS:          
		GOARCH:               arm64
		GOOS:                 darwin
Docker Engine:
	Engine version:        23.0.6
	Engine runtime:        runc
	Cgroup version:        1
	Cgroup driver:         cgroupfs
	Storage driver:        overlay2
	Registry URI:          https://index.docker.io/v1/
	OS:                    Alpine Linux v3.18
	OS type:               linux
	OS version:            3.18.5
	OS arch:               aarch64
	OS kernel:             6.1.64-0-virt
	OS CPU:                2
	OS memory:             1973 MB
	Security options:
		name=seccomp,profile=builtin
```


### Command used with act

```sh
~/code/nektos/act/dist/local/act --use-new-action-cache -s ACTIONS_STEP_DEBUG=true
```


### Describe issue

Error: failed to fetch "https://github.com/check-spelling-sandbox/sub-actions-0" version "HEAD": couldn't find remote ref "HEAD"

### Link to GitHub repository

https://github.com/check-spelling-sandbox/sub-actions-0/blob/a346debe23919e80d1b24a059027c0e898117763/.github/workflows/test.yml

### Workflow content

```yml
on: push

jobs:
    test:
        runs-on: ubuntu-latest
        steps:
        - name: checkout
          uses: actions/checkout@v4
        - name: test local
          uses: ./test
        - name: test public
          uses: check-spelling-sandbox/sub-actions-0/test@HEAD
```


### Relevant log output

```sh
jsoref@jsoref-mbp sub-actions-0 % ~/code/nektos/act/dist/local/act --use-new-action-cache -s ACTIONS_STEP_DEBUG=true -v
WARN  ⚠ You are using Apple M-series chip and you have not specified container architecture, you might encounter issues while running act. If so, try running it with '--container-architecture linux/amd64'. ⚠
DEBU[0000] Loading environment from /var/folders/r3/n29fz25x72x191fdv6mhhr3m0000gp/T/tmp.OgpfaaBnyw/sub-actions-0/.env
DEBU[0000] Loading action inputs from /var/folders/r3/n29fz25x72x191fdv6mhhr3m0000gp/T/tmp.OgpfaaBnyw/sub-actions-0/.input
DEBU[0000] Loading secrets from /var/folders/r3/n29fz25x72x191fdv6mhhr3m0000gp/T/tmp.OgpfaaBnyw/sub-actions-0/.secrets
DEBU[0000] Loading vars from /var/folders/r3/n29fz25x72x191fdv6mhhr3m0000gp/T/tmp.OgpfaaBnyw/sub-actions-0/.vars
DEBU[0000] Evaluated matrix inclusions: map[]
DEBU[0000] Loading workflows from '/var/folders/r3/n29fz25x72x191fdv6mhhr3m0000gp/T/tmp.OgpfaaBnyw/sub-actions-0/.github/workflows'
DEBU[0000] Loading workflows recursively
DEBU[0000] Found workflow 'test.yml' in '/var/folders/r3/n29fz25x72x191fdv6mhhr3m0000gp/T/tmp.OgpfaaBnyw/sub-actions-0/.github/workflows/test.yml'
DEBU[0000] Reading workflow '/var/folders/r3/n29fz25x72x191fdv6mhhr3m0000gp/T/tmp.OgpfaaBnyw/sub-actions-0/.github/workflows/test.yml'
DEBU[0000] Preparing plan with all jobs
DEBU[0000] Using the only detected workflow event: push
DEBU[0000] Planning jobs for event: push
DEBU[0000] Conditional GET for notices etag=dc91bad3-e1dd-4d9d-8dd5-5b630fc490a7
DEBU[0000] gc: 2024-02-05 15:27:43.600916 -0500 EST m=+0.016884126  module=artifactcache
DEBU[0000] Plan Stages: [0x140003a0390]
DEBU[0000] Stages Runs: [test]
DEBU[0000] Job.Name: test
DEBU[0000] Job.RawNeeds: {0 0    <nil> []    0 0}
DEBU[0000] Job.RawRunsOn: {8 0 !!str ubuntu-latest  <nil> []    5 18}
DEBU[0000] Job.Env: {0 0    <nil> []    0 0}
DEBU[0000] Job.If: {0 0  success()  <nil> []    0 0}
DEBU[0000] Job.Steps: checkout
DEBU[0000] Job.Steps: test local
DEBU[0000] Job.Steps: test public
DEBU[0000] Job.TimeoutMinutes:
DEBU[0000] Job.Services: map[]
DEBU[0000] Job.Strategy: <nil>
DEBU[0000] Job.RawContainer: {0 0    <nil> []    0 0}
DEBU[0000] Job.Defaults.Run.Shell:
DEBU[0000] Job.Defaults.Run.WorkingDirectory:
DEBU[0000] Job.Outputs: map[]
DEBU[0000] Job.Uses:
DEBU[0000] Job.With: map[]
DEBU[0000] Job.Result:
DEBU[0000] Empty Strategy, matrixes=[map[]]
DEBU[0000] Job Matrices: [map[]]
DEBU[0000] Runner Matrices: map[]
DEBU[0000] Final matrix after applying user inclusions '[map[]]'
DEBU[0000] Loading revision from git directory
DEBU[0000] Found revision: a346debe23919e80d1b24a059027c0e898117763
DEBU[0000] HEAD points to 'a346debe23919e80d1b24a059027c0e898117763'
DEBU[0000] using github ref: refs/heads/main
DEBU[0000] Found revision: a346debe23919e80d1b24a059027c0e898117763
DEBU[0000] Detected CPUs: 10
[test.yml/test] [DEBUG] evaluating expression 'success()'
[test.yml/test] [DEBUG] expression 'success()' evaluated to '***'
[test.yml/test] 🚀  Start image=catthehacker/ubuntu:act-latest
INFO[0000] Parallel tasks (0) below minimum, setting to 1
[test.yml/test]   🐳  docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=***
[test.yml/test] [DEBUG]   🐳  docker pull catthehacker/ubuntu:act-latest
[test.yml/test] [DEBUG] pulling image 'docker.io/catthehacker/ubuntu:act-latest' ()
DEBU[0000] Saving notices etag=dc91bad3-e1dd-4d9d-8dd5-5b630fc490a7
DEBU[0000] No new notices
[test.yml/test] [DEBUG] Pulling from catthehacker/ubuntu :: act-latest
[test.yml/test] [DEBUG] Digest: sha256:fa1bac54a63b8f2d338d5b3e2beb326bb70904d993e26f1c5804a97d0013de8c ::
[test.yml/test] [DEBUG] Status: Image is up to date for catthehacker/ubuntu:act-latest ::
INFO[0008] Parallel tasks (0) below minimum, setting to 1
[test.yml/test]   🐳  docker create image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[test.yml/test] [DEBUG] Common container.Config ==> &{Hostname: Domainname: User: AttachStdin:false AttachStdout:false AttachStderr:false ExposedPorts:map[] Tty:*** OpenStdin:false StdinOnce:false Env:[RUNNER_TOOL_CACHE=/opt/hostedtoolcache RUNNER_OS=Linux RUNNER_ARCH=ARM64 RUNNER_TEMP=/tmp LANG=C.UTF-8] Cmd:[] Healthcheck:<nil> ArgsEscaped:false Image:catthehacker/ubuntu:act-latest Volumes:map[] WorkingDir:/var/folders/r3/n29fz25x72x191fdv6mhhr3m0000gp/T/tmp.OgpfaaBnyw/sub-actions-0 Entrypoint:[] NetworkDisabled:false MacAddress: OnBuild:[] Labels:map[] StopSignal: StopTimeout:<nil> Shell:[]}
[test.yml/test] [DEBUG] Common container.HostConfig ==> &{Binds:[/var/run/docker.sock:/var/run/docker.sock] ContainerIDFile: LogConfig:{Type: Config:map[]} NetworkMode:host PortBindings:map[] RestartPolicy:{Name: MaximumRetryCount:0} AutoRemove:false VolumeDriver: VolumesFrom:[] ConsoleSize:[0 0] Annotations:map[] CapAdd:[] CapDrop:[] CgroupnsMode: DNS:[] DNSOptions:[] DNSSearch:[] ExtraHosts:[] GroupAdd:[] IpcMode: Cgroup: Links:[] OomScoreAdj:0 PidMode: Privileged:false PublishAllPorts:false ReadonlyRootfs:false SecurityOpt:[] StorageOpt:map[] Tmpfs:map[] UTSMode: UsernsMode: ShmSize:0 Sysctls:map[] Runtime: Isolation: Resources:{CPUShares:0 Memory:0 NanoCPUs:0 CgroupParent: BlkioWeight:0 BlkioWeightDevice:[] BlkioDeviceReadBps:[] BlkioDeviceWriteBps:[] BlkioDeviceReadIOps:[] BlkioDeviceWriteIOps:[] CPUPeriod:0 CPUQuota:0 CPURealtimePeriod:0 CPURealtimeRuntime:0 CpusetCpus: CpusetMems: Devices:[] DeviceCgroupRules:[] DeviceRequests:[] KernelMemory:0 KernelMemoryTCP:0 MemoryReservation:0 MemorySwap:0 MemorySwappiness:<nil> OomKillDisable:<nil> PidsLimit:<nil> Ulimits:[] CPUCount:0 CPUPercent:0 IOMaximumIOps:0 IOMaximumBandwidth:0} Mounts:[{Type:volume Source:act-toolcache Target:/toolcache ReadOnly:false Consistency: BindOptions:<nil> VolumeOptions:<nil> TmpfsOptions:<nil> ClusterOptions:<nil>} {Type:volume Source:act-test-yml-test-1022155a5276c1a9bd474715a469356fa6538d4315e857809c6e7a523bcb2644-env Target:/var/run/act ReadOnly:false Consistency: BindOptions:<nil> VolumeOptions:<nil> TmpfsOptions:<nil> ClusterOptions:<nil>} {Type:volume Source:act-test-yml-test-1022155a5276c1a9bd474715a469356fa6538d4315e857809c6e7a523bcb2644 Target:/var/folders/r3/n29fz25x72x191fdv6mhhr3m0000gp/T/tmp.OgpfaaBnyw/sub-actions-0 ReadOnly:false Consistency: BindOptions:<nil> VolumeOptions:<nil> TmpfsOptions:<nil> ClusterOptions:<nil>}] MaskedPaths:[] ReadonlyPaths:[] Init:<nil>}
[test.yml/test] [DEBUG] input.NetworkAliases ==> [test]
[test.yml/test] [DEBUG] Created container name=act-test-yml-test-1022155a5276c1a9bd474715a469356fa6538d4315e857809c6e7a523bcb2644 id=ae6c60e496b6a98298ae9e3dbf72f384582101d8388c8a6da17e8cacf1543feb from image catthehacker/ubuntu:act-latest (platform: )
[test.yml/test] [DEBUG] ENV ==> [RUNNER_TOOL_CACHE=/opt/hostedtoolcache RUNNER_OS=Linux RUNNER_ARCH=ARM64 RUNNER_TEMP=/tmp LANG=C.UTF-8]
[test.yml/test]   🐳  docker run image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[test.yml/test] [DEBUG] Starting container: ae6c60e496b6a98298ae9e3dbf72f384582101d8388c8a6da17e8cacf1543feb
[test.yml/test] [DEBUG] Started container: ae6c60e496b6a98298ae9e3dbf72f384582101d8388c8a6da17e8cacf1543feb
[test.yml/test] [DEBUG] Writing entry to tarball workflow/event.json len:2
[test.yml/test] [DEBUG] Writing entry to tarball workflow/envs.txt len:0
[test.yml/test] [DEBUG] Extracting content to '/var/run/act/'
[test.yml/test] [DEBUG] Loading revision from git directory
[test.yml/test] [DEBUG] Found revision: a346debe23919e80d1b24a059027c0e898117763
[test.yml/test] [DEBUG] HEAD points to 'a346debe23919e80d1b24a059027c0e898117763'
[test.yml/test] [DEBUG] using github ref: refs/heads/main
[test.yml/test] [DEBUG] Found revision: a346debe23919e80d1b24a059027c0e898117763
[test.yml/test] [DEBUG] Loading revision from git directory
[test.yml/test] [DEBUG] Found revision: a346debe23919e80d1b24a059027c0e898117763
[test.yml/test] [DEBUG] HEAD points to 'a346debe23919e80d1b24a059027c0e898117763'
[test.yml/test] [DEBUG] using github ref: refs/heads/main
[test.yml/test] [DEBUG] Found revision: a346debe23919e80d1b24a059027c0e898117763
[test.yml/test] [DEBUG] Skipping local actions/checkout because workdir was already copied
[test.yml/test] [DEBUG] skip pre step for 'checkout': no action model available
[test.yml/test] [DEBUG] Loading revision from git directory
[test.yml/test] [DEBUG] Found revision: a346debe23919e80d1b24a059027c0e898117763
[test.yml/test] [DEBUG] HEAD points to 'a346debe23919e80d1b24a059027c0e898117763'
[test.yml/test] [DEBUG] using github ref: refs/heads/main
[test.yml/test] [DEBUG] Found revision: a346debe23919e80d1b24a059027c0e898117763
[test.yml/test] [DEBUG] skipping post step for 'test public'; step was not executed
[test.yml/test] [DEBUG] skipping post step for 'test local'; step was not executed
[test.yml/test] [DEBUG] skipping post step for 'checkout'; step was not executed
[test.yml/test] Cleaning up container for job test
[test.yml/test] [DEBUG] Removed container: ae6c60e496b6a98298ae9e3dbf72f384582101d8388c8a6da17e8cacf1543feb
[test.yml/test] [DEBUG]   🐳  docker volume rm act-test-yml-test-1022155a5276c1a9bd474715a469356fa6538d4315e857809c6e7a523bcb2644
[test.yml/test] [DEBUG]   🐳  docker volume rm act-test-yml-test-1022155a5276c1a9bd474715a469356fa6538d4315e857809c6e7a523bcb2644-env
[test.yml/test] 🏁  Job succeeded
[test.yml/test] [DEBUG] Loading revision from git directory
[test.yml/test] [DEBUG] Found revision: a346debe23919e80d1b24a059027c0e898117763
[test.yml/test] [DEBUG] HEAD points to 'a346debe23919e80d1b24a059027c0e898117763'
[test.yml/test] [DEBUG] using github ref: refs/heads/main
[test.yml/test] [DEBUG] Found revision: a346debe23919e80d1b24a059027c0e898117763
Error: failed to fetch "https://github.com/check-spelling-sandbox/sub-actions-0" version "HEAD": couldn't find remote ref "HEAD"
jsoref@jsoref-mbp sub-actions-0 %
```


### Additional information

_No response_


Discussion / hints:
Thank you for pointing this out.

Seems like I did error prone over engineering in the fetch refspec, because old code had complicated refspec.
- short sha is not supported by GHA, same applies to fetch shortsha:branchname
- everything can be fetched with ref:branchname would fix `HEAD` fetch

Fix patch:
diff --git a/pkg/runner/action_cache.go b/pkg/runner/action_cache.go
index da4e651ce62..1099d78f99a 100644
--- a/pkg/runner/action_cache.go
+++ b/pkg/runner/action_cache.go
@@ -6,7 +6,6 @@ import (
 	"crypto/rand"
 	"encoding/hex"
 	"errors"
-	"fmt"
 	"io"
 	"io/fs"
 	"path"
@@ -43,17 +42,7 @@ func (c GoGitActionCache) Fetch(ctx context.Context, cacheDir, url, ref, token s
 		return "", err
 	}
 	branchName := hex.EncodeToString(tmpBranch)
-	var refSpec config.RefSpec
-	spec := config.RefSpec(ref + ":" + branchName)
-	tagOrSha := false
-	if spec.IsExactSHA1() {
-		refSpec = spec
-	} else if strings.HasPrefix(ref, "refs/") {
-		refSpec = config.RefSpec(ref + ":refs/heads/" + branchName)
-	} else {
-		tagOrSha = true
-		refSpec = config.RefSpec("refs/*/" + ref + ":refs/heads/*/" + branchName)
-	}
+
 	var auth transport.AuthMethod
 	if token != "" {
 		auth = &http.BasicAuth{
@@ -71,35 +60,17 @@ func (c GoGitActionCache) Fetch(ctx context.Context, cacheDir, url, ref, token s
 		return "", err
 	}
 	defer func() {
-		if refs, err := gogitrepo.References(); err == nil {
-			_ = refs.ForEach(func(r *plumbing.Reference) error {
-				if strings.Contains(r.Name().String(), branchName) {
-					return gogitrepo.DeleteBranch(r.Name().String())
-				}
-				return nil
-			})
-		}
+		_ = gogitrepo.DeleteBranch(branchName)
 	}()
 	if err := remote.FetchContext(ctx, &git.FetchOptions{
 		RefSpecs: []config.RefSpec{
-			refSpec,
+			config.RefSpec(ref + ":" + branchName),
 		},
 		Auth:  auth,
 		Force: true,
 	}); err != nil {
-		if tagOrSha && errors.Is(err, git.NoErrAlreadyUpToDate) {
-			return "", fmt.Errorf("couldn't find remote ref \"%s\"", ref)
-		}
 		return "", err
 	}
-	if tagOrSha {
-		for _, prefix := range []string{"refs/heads/tags/", "refs/heads/heads/"} {
-			hash, err := gogitrepo.ResolveRevision(plumbing.Revision(prefix + branchName))
-			if err == nil {
-				return hash.String(), nil
-			}
-		}
-	}
 	hash, err := gogitrepo.ResolveRevision(plumbing.Revision(branchName))
 	if err != nil {
 		return "", err


Test patch:
diff --git a/pkg/runner/action_cache_test.go b/pkg/runner/action_cache_test.go
index e222cfb9c01..58fac5bd979 100644
--- a/pkg/runner/action_cache_test.go
+++ b/pkg/runner/action_cache_test.go
@@ -18,20 +18,60 @@ func TestActionCache(t *testing.T) {
 		Path: os.TempDir(),
 	}
 	ctx := context.Background()
-	sha, err := cache.Fetch(ctx, "christopherhx/script", "https://github.com/christopherhx/script", "main", "")
-	a.NoError(err)
-	a.NotEmpty(sha)
-	atar, err := cache.GetTarArchive(ctx, "christopherhx/script", sha, "node_modules")
-	a.NoError(err)
-	a.NotEmpty(atar)
-	mytar := tar.NewReader(atar)
-	th, err := mytar.Next()
-	a.NoError(err)
-	a.NotEqual(0, th.Size)
-	buf := &bytes.Buffer{}
-	// G110: Potential DoS vulnerability via decompression bomb (gosec)
-	_, err = io.Copy(buf, mytar)
-	a.NoError(err)
-	str := buf.String()
-	a.NotEmpty(str)
+	cacheDir := "nektos/act-test-actions"
+	repo := "https://github.com/nektos/act-test-actions"
+	refs := []struct {
+		Name     string
+		CacheDir string
+		Repo     string
+		Ref      string
+	}{
+		{
+			Name:     "Fetch Branch Name",
+			CacheDir: cacheDir,
+			Repo:     repo,
+			Ref:      "main",
+		},
+		{
+			Name:     "Fetch Branch Name Absolutely",
+			CacheDir: cacheDir,
+			Repo:     repo,
+			Ref:      "refs/heads/main",
+		},
+		{
+			Name:     "Fetch HEAD",
+			CacheDir: cacheDir,
+			Repo:     repo,
+			Ref:      "HEAD",
+		},
+		{
+			Name:     "Fetch Sha",
+			CacheDir: cacheDir,
+			Repo:     repo,
+			Ref:      "de984ca37e4df4cb9fd9256435a3b82c4a2662b1",
+		},
+	}
+	for _, c := range refs {
+		t.Run(c.Name, func(t *testing.T) {
+			sha, err := cache.Fetch(ctx, c.CacheDir, c.Repo, c.Ref, "")
+			if !a.NoError(err) || !a.NotEmpty(sha) {
+				return
+			}
+			atar, err := cache.GetTarArchive(ctx, c.CacheDir, sha, "js")
+			if !a.NoError(err) || !a.NotEmpty(atar) {
+				return
+			}
+			mytar := tar.NewReader(atar)
+			th, err := mytar.Next()
+			if !a.NoError(err) || !a.NotEqual(0, th.Size) {
+				return
+			}
+			buf := &bytes.Buffer{}
+			// G110: Potential DoS vulnerability via decompression bomb (gosec)
+			_, err = io.Copy(buf, mytar)
+			a.NoError(err)
+			str := buf.String()
+			a.NotEmpty(str)
+		})
+	}
 }