Skip to content

fix: harden GitHub Action version resolution#3

Closed
qartik wants to merge 9 commits into
mainfrom
codex-fix-same-major-action-updates
Closed

fix: harden GitHub Action version resolution#3
qartik wants to merge 9 commits into
mainfrom
codex-fix-same-major-action-updates

Conversation

@qartik

@qartik qartik commented May 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • keep moving action refs at their published precision, including major-moving tags like v3 and minor-moving tags like v3.4
  • upgrade exact action refs to the latest eligible stable release without treating semver-equivalent representations as upgrades
  • resolve each workflow action reference independently instead of reusing one repo-level result across mixed refs
  • reduce resolver edge cases and API pressure by modeling per-major candidates explicitly and short-circuiting cooldown checks once a higher-priority eligible target is found
  • strengthen the resolver with targeted regressions, reference-model checks, and property-based tests

Details

actupdate now resolves action tags through an explicit per-major candidate model instead of a sequence of ad hoc helper interactions. For each published major, the resolver distinguishes moving major tags such as v6, moving minor tags such as v6.2, and exact tags such as v6.2.1, then applies one consistent selection policy across upgrade, cooldown, and unchanged paths.

This makes the tool behave correctly for cases such as:

  • exact same-major upgrades like v3.0 to v3.3
  • preserving moving minor refs like v3.4 instead of rewriting them to v3.4.1
  • mixed workflow refs from the same repository without cross-contaminating results
  • fallback from blocked moving tags to eligible exact tags when appropriate
  • newer majors that publish only a moving tag
  • semver-equivalent exact tags such as v3.0 and v3.0.0 without treating them as upgrades

Validation

  • go test ./...
  • targeted resolver and CLI regressions for mixed refs, cooldown fallback, moving-only majors, moving minor preservation, and semver-equivalent tags
  • generated reference-model checks over many candidate-state combinations
  • property-based tests for resolver invariants using testing/quick

@qartik qartik marked this pull request as ready for review May 22, 2026 21:38
@qartik qartik requested a review from Copilot May 22, 2026 21:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates actupdate’s resolver and CLI so exact semver action refs (e.g. @v3.0) can be upgraded to newer eligible tags within the same major (e.g. @v3.3), and ensures per-repo resolutions aren’t incorrectly reused across different refs during a single scan.

Changes:

  • Add ResolveLatestStable to resolve upgrades within the current major and still prefer moving major tags when a newer major is eligible.
  • Update the CLI scan/report flow to resolve per ref (removing the repo-level resolution reuse that caused incorrect behavior).
  • Add regression tests covering mixed refs for the same repo (e.g. pypa/cibuildwheel@v3.3 and @v3.0) and same-major upgrade behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
README.md Updates documentation to describe “latest eligible stable version” behavior and moving-tag preference rules.
internal/github/client.go Introduces ResolveLatestStable and same-major exact-tag upgrade detection logic.
internal/github/client_test.go Adds unit tests for same-major upgrades and behavior with moving tags.
cmd/actupdate/main.go Switches CLI resolution to ResolveLatestStable and removes repo-wide resolution caching across refs.
cmd/actupdate/main_test.go Adds CLI regression test for mixed refs from the same repo in one workflow file.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/github/client.go Outdated
Comment thread internal/github/client.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comment thread internal/github/client.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comment thread internal/github/client.go Outdated
Comment thread internal/github/client.go Outdated
@qartik qartik changed the title fix: upgrade exact action tags within current major fix: harden action version resolution policy May 22, 2026
@qartik qartik changed the title fix: harden action version resolution policy fix: make action version resolution robust May 22, 2026
@qartik qartik requested a review from Copilot May 22, 2026 23:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Comment thread internal/github/client.go
Comment thread internal/github/client.go Outdated
Comment thread internal/github/client_test.go
@qartik qartik changed the title fix: make action version resolution robust fix: harden GitHub Action version resolution May 22, 2026
@qartik qartik requested a review from Copilot May 22, 2026 23:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comment thread internal/github/client.go Outdated
Comment thread internal/github/client.go

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Comment thread internal/github/client.go
Comment on lines +353 to +359
if candidates[i].HasMovingMinor {
eligible, err := c.tagEligible(ctx, repo, candidates[i].MovingMinor.Original, cutoff)
if err != nil {
return false, err
}
candidates[i].MovingMinorEligible = eligible
if eligible && !candidates[i].HasMovingMajor {
Comment thread README.md
Comment on lines +82 to +83
- When a newer major exists, moving major tags such as `v6` are preferred over
exact tags such as `v6.2.1`
Comment on lines +645 to +690
func candidateFromState(major, state int) (majorCandidates, bool) {
candidate := majorCandidates{Major: major}
switch state {
case 0:
return majorCandidates{}, false
case 1:
candidate.MovingMajor = mustParseStableVersion(nil, fmt.Sprintf("v%d", major))
candidate.HasMovingMajor = true
candidate.MovingMajorEligible = true
case 2:
candidate.MovingMajor = mustParseStableVersion(nil, fmt.Sprintf("v%d", major))
candidate.HasMovingMajor = true
case 3:
candidate.Exact = mustParseStableVersion(nil, fmt.Sprintf("v%d.2.0", major))
candidate.HasExact = true
candidate.ExactEligible = true
case 4:
candidate.Exact = mustParseStableVersion(nil, fmt.Sprintf("v%d.2.0", major))
candidate.HasExact = true
case 5:
candidate.MovingMajor = mustParseStableVersion(nil, fmt.Sprintf("v%d", major))
candidate.HasMovingMajor = true
candidate.MovingMajorEligible = true
candidate.Exact = mustParseStableVersion(nil, fmt.Sprintf("v%d.2.0", major))
candidate.HasExact = true
candidate.ExactEligible = true
case 6:
candidate.MovingMajor = mustParseStableVersion(nil, fmt.Sprintf("v%d", major))
candidate.HasMovingMajor = true
candidate.Exact = mustParseStableVersion(nil, fmt.Sprintf("v%d.2.0", major))
candidate.HasExact = true
candidate.ExactEligible = true
case 7:
candidate.MovingMajor = mustParseStableVersion(nil, fmt.Sprintf("v%d", major))
candidate.HasMovingMajor = true
candidate.Exact = mustParseStableVersion(nil, fmt.Sprintf("v%d.2.0", major))
candidate.HasExact = true
case 8:
candidate.MovingMajor = mustParseStableVersion(nil, fmt.Sprintf("v%d", major))
candidate.HasMovingMajor = true
candidate.MovingMajorEligible = true
candidate.Exact = mustParseStableVersion(nil, fmt.Sprintf("v%d.2.0", major))
candidate.HasExact = true
default:
panic(fmt.Sprintf("unknown state %d", state))
}
Comment on lines +885 to +890
func (s policyScenario) currentVersion() actionspec.StableVersion {
if s.CurrentKind {
return mustParseStableVersion(nil, fmt.Sprintf("v%d.1.0", s.CurrentMajor))
}
return mustParseStableVersion(nil, fmt.Sprintf("v%d", s.CurrentMajor))
}
}
}

func TestResolveLatestStableTreatsEquivalentExactTagsAsUnchanged(t *testing.T) {
@qartik

qartik commented May 23, 2026

Copy link
Copy Markdown
Owner Author

@qartik qartik closed this May 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants