Skip to content

Commit 4aaea42

Browse files
committed
Pinning: exclude malformed workflows from commit
1 parent d6e3d1a commit 4aaea42

5 files changed

Lines changed: 56 additions & 1 deletion

File tree

cmd/gh-actions-lock/command_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,11 @@ func TestCheckCommand_LoadErrorFailsFixMode(t *testing.T) {
10561056
args := append(tt.args, workflowPath)
10571057
_, stderr, err := runCommandWithHTTP(t, reg, args...)
10581058
require.Error(t, err)
1059-
assert.Contains(t, err.Error(), "parsing workflow YAML")
1059+
if tt.name == "migration enabled" {
1060+
assert.Contains(t, err.Error(), "parsing workflow YAML")
1061+
} else {
1062+
require.ErrorIs(t, err, errSilent)
1063+
}
10601064
assert.NotContains(t, stderr, "All 1 workflow valid")
10611065
})
10621066
}

internal/pin/plan.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ type planResult struct {
134134
func planWorkflow(ctx context.Context, wr checks.WorkflowReport, opts PlanOptions, status func(string)) (planResult, error) {
135135
var entries []Entry
136136
var wplans []WorkflowPlan
137+
if wr.SkipCommit {
138+
return planResult{entries: verifiedEntries(wr.Inventory, wr.Path)}, nil
139+
}
137140
for _, finding := range wr.Findings {
138141
if finding.Category == checks.InvalidSelfRepositoryRef {
139142
return planResult{}, nil

internal/pin/plan_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,28 @@ func TestNarrowVerifiedEntries_StickyPrecision(t *testing.T) {
344344
assert.Empty(t, result.wplans[0].Rewrites)
345345
})
346346

347+
t.Run("SHA metadata repairs to branch", func(t *testing.T) {
348+
tagger, _ := newTagger(t)
349+
report := fastPathReport(sha)
350+
report.Inventory[0].Dep.Branch = "main"
351+
report.ActionRefs = []parserlock.ActionRef{{
352+
Owner: "actions",
353+
Repo: "checkout",
354+
Ref: sha,
355+
}}
356+
357+
result, err := planWorkflow(context.Background(), report, PlanOptions{Tagger: tagger}, func(string) {})
358+
require.NoError(t, err)
359+
360+
require.Len(t, result.entries, 1)
361+
assert.Equal(t, "main", result.entries[0].Ref)
362+
assert.Equal(t, sha, result.entries[0].AutoFixedRef)
363+
assert.Equal(t,
364+
map[string]string{"actions/checkout@" + sha: "actions/checkout@main"},
365+
result.wplans[0].Rewrites,
366+
)
367+
})
368+
347369
t.Run("repair preserves source NWO spelling", func(t *testing.T) {
348370
tagger, _ := newTagger(t)
349371
report := fastPathReport(sha)
@@ -474,6 +496,29 @@ func TestPlanRejectsRepairConflictingWithSymbolicEntry(t *testing.T) {
474496
require.ErrorContains(t, err, "conflicting planned target actions/checkout@v4.2.1")
475497
}
476498

499+
func TestPlanExcludesLoadFailuresFromCommit(t *testing.T) {
500+
const sha = "abc1230000000000000000000000000000000000"
501+
blocked := checks.WorkflowReport{
502+
Path: ".github/workflows/broken.yml",
503+
SkipCommit: true,
504+
Inventory: []checks.InventoryEntry{{
505+
Dep: dep.Dependency{NWO: "actions/checkout", Ref: "v4", SHA: sha},
506+
File: ".github/workflows/broken.yml",
507+
}},
508+
}
509+
valid := checks.WorkflowReport{Path: ".github/workflows/valid.yml"}
510+
511+
record, err := Plan(context.Background(), &checks.Report{
512+
Workflows: []checks.WorkflowReport{blocked, valid},
513+
}, PlanOptions{Pool: pinpool.New(2, nil)})
514+
require.NoError(t, err)
515+
516+
require.Len(t, record.Workflows, 1)
517+
assert.Equal(t, valid.Path, record.Workflows[0].Path)
518+
require.Len(t, record.Entries, 1)
519+
assert.Equal(t, blocked.Path, record.Entries[0].Workflows[0])
520+
}
521+
477522
func TestPlanWorkflow_SelfRepositoryDependencyIsNotRewrittenOnFastPath(t *testing.T) {
478523
const sha = "abc1230000000000000000000000000000000000"
479524

internal/pipeline/checks/finding.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ type InventoryEntry struct {
6363
type WorkflowReport struct {
6464
Path string
6565
Findings []Finding
66+
// SkipCommit prevents terminal parse failures from entering the write phase.
67+
SkipCommit bool
6668
// ActionRefs are all remote dependency roots attributed to the workflow,
6769
// including refs found inside in-repo `$/…` actions.
6870
ActionRefs []parserlock.ActionRef

internal/pipeline/diagnose.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ func precheckWorkflow(pw checks.ParsedWorkflow, store *lockfile.State) (checks.W
178178
wr := checks.WorkflowReport{Path: pw.Path}
179179

180180
if pw.LoadErr != nil {
181+
wr.SkipCommit = true
181182
wr.Findings = append(wr.Findings, checks.Finding{
182183
WorkflowPath: pw.Path,
183184
Category: checks.NotPinned,

0 commit comments

Comments
 (0)