diff --git a/pkg/workflow/action_cache.go b/pkg/workflow/action_cache.go index 6ebed0e0e1..8cc48beaa8 100644 --- a/pkg/workflow/action_cache.go +++ b/pkg/workflow/action_cache.go @@ -177,6 +177,18 @@ func (c *ActionCache) Get(repo, version string) (string, bool) { return entry.SHA, true } +// FindEntryBySHA finds a cache entry with the given repo and SHA +// Returns the entry and true if found, or empty entry and false if not found +func (c *ActionCache) FindEntryBySHA(repo, sha string) (ActionCacheEntry, bool) { + for key, entry := range c.Entries { + if entry.Repo == repo && entry.SHA == sha { + actionCacheLog.Printf("Found cache entry for %s with SHA %s: %s", repo, sha[:8], key) + return entry, true + } + } + return ActionCacheEntry{}, false +} + // Set stores a new cache entry func (c *ActionCache) Set(repo, version, sha string) { key := repo + "@" + version diff --git a/pkg/workflow/action_cache_test.go b/pkg/workflow/action_cache_test.go index 0adfe8669e..701aede1f8 100644 --- a/pkg/workflow/action_cache_test.go +++ b/pkg/workflow/action_cache_test.go @@ -504,3 +504,42 @@ func TestActionCacheDirtyFlag(t *testing.T) { t.Fatalf("Failed to save dirty cache after modification: %v", err) } } + +// TestActionCacheFindEntryBySHA tests finding cache entries by SHA +func TestActionCacheFindEntryBySHA(t *testing.T) { + tmpDir := testutil.TempDir(t, "test-*") + cache := NewActionCache(tmpDir) + + // Add entries with same SHA + cache.Set("actions/github-script", "v8", "ed597411d8f924073f98dfc5c65a23a2325f34cd") + cache.Set("actions/github-script", "v8.0.0", "ed597411d8f924073f98dfc5c65a23a2325f34cd") + + // Find entry by SHA + entry, found := cache.FindEntryBySHA("actions/github-script", "ed597411d8f924073f98dfc5c65a23a2325f34cd") + if !found { + t.Fatal("Expected to find entry by SHA") + } + + // Should find one of the entries (either v8 or v8.0.0) + if entry.Repo != "actions/github-script" { + t.Errorf("Expected repo 'actions/github-script', got '%s'", entry.Repo) + } + if entry.SHA != "ed597411d8f924073f98dfc5c65a23a2325f34cd" { + t.Errorf("Expected SHA to match") + } + if entry.Version != "v8" && entry.Version != "v8.0.0" { + t.Errorf("Expected version 'v8' or 'v8.0.0', got '%s'", entry.Version) + } + + // Test not found case + _, found = cache.FindEntryBySHA("actions/unknown", "unknown-sha") + if found { + t.Error("Expected not to find entry with unknown SHA") + } + + // Test different repo with same SHA + _, found = cache.FindEntryBySHA("actions/checkout", "ed597411d8f924073f98dfc5c65a23a2325f34cd") + if found { + t.Error("Expected not to find entry for different repo") + } +} diff --git a/pkg/workflow/action_pins.go b/pkg/workflow/action_pins.go index 647cc96609..8af55d1e8c 100644 --- a/pkg/workflow/action_pins.go +++ b/pkg/workflow/action_pins.go @@ -155,19 +155,28 @@ func GetActionPinWithData(actionRepo, version string, data *WorkflowData) (strin actionPinsLog.Printf("Dynamic resolution succeeded: %s@%s → %s", actionRepo, version, sha) // Check if there are other cache entries with the same SHA + // If found, use the existing version to maintain consistency + canonicalVersion := version if data.ActionCache != nil { actionPinsLog.Printf("Checking cache for other versions with same SHA %s", sha[:8]) for key, entry := range data.ActionCache.Entries { if entry.Repo == actionRepo && entry.SHA == sha && entry.Version != version { actionPinsLog.Printf("Found cache entry with same SHA: %s (version=%s) vs requested version=%s", key, entry.Version, version) + // Use the existing version to prevent version comment switching + // This ensures all workflows use the same canonical version for a given SHA + if isMorePreciseVersion(entry.Version, version) { + canonicalVersion = entry.Version + actionPinsLog.Printf("Using existing more precise version %s instead of requested %s", + entry.Version, version) + } } } } // Successfully resolved - cache will be saved at end of compilation actionPinsLog.Printf("Successfully resolved action pin (cache marked dirty, will save at end)") - result := actionRepo + "@" + sha + " # " + version + result := actionRepo + "@" + sha + " # " + canonicalVersion actionPinsLog.Printf("Returning pinned reference: %s", result) return result, nil }