Skip to content

Thread context.Context through all ResolveSHA call sites#32295

Merged
pelikhan merged 7 commits into
mainfrom
copilot/context-propagation-fix
May 15, 2026
Merged

Thread context.Context through all ResolveSHA call sites#32295
pelikhan merged 7 commits into
mainfrom
copilot/context-propagation-fix

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 15, 2026

Enhancement

5 production call sites hardcoded context.Background() when calling ActionResolver.ResolveSHA(), making it impossible for callers to inject timeouts or cancel hung gh api network calls. This threads ctx end-to-end from cobra cmd.Context() down to every ResolveSHA invocation.

pkg/workflow/ — core fixes

  • action_sha_checker.go: CheckActionSHAUpdates(ctx, actions, resolver)
  • action_reference.go: ResolveSetupActionReference(ctx, ...) / resolveSetupActionRef(ctx, ...)
  • maintenance_workflow.go: resolveActionRef(ctx, ...), generateInstallCLISteps(ctx, ...), GenerateMaintenanceWorkflow(ctx, ...)
  • lock_validation.go: ValidateActionSHAsInLockFile(ctx, ...)
  • central_slash_command_workflow.go, maintenance_workflow_yaml.go, side_repo_maintenance.go: corresponding generator functions take ctx
  • compiler_types.go: added ctx context.Context field to Compiler with WithContext option and SetContext method; defaults to context.Background() in NewCompiler()

pkg/cli/ — call chain propagation

  • copilot_setup.go: all 7 internal functions (getActionRef, ensureCopilotSetupSteps, upgradeCopilotSetupSteps, etc.) take ctx
  • compile pipeline: CompileWorkflowWithValidation, CompileWorkflowDataWithValidation, compileWorkflowFile, compileSingleFile, compileAllWorkflowFiles, watchAndCompileWorkflows, and orchestrator functions all take ctx
  • add_command.go: AddResolvedWorkflows, addWorkflows, addWorkflowsWithTracking, addWorkflowWithTracking take ctx; fetchAllRemoteDependencies updated to use ctx
  • enable.go: EnableWorkflowsByNames / DisableWorkflowsByNames take ctx
  • init.go: InitOptions gains Ctx context.Context; InitRepository falls back to context.Background() if nil
  • upgrade_command.go, update_workflows.go, update_actions.go: call sites updated

cmd/gh-aw/main.go — boundary

Cobra RunE handlers pass cmd.Context() (signal-aware) instead of context.Background().

Before / After

// Before
func CheckActionSHAUpdates(actions []ActionUsage, resolver *ActionResolver) []ActionUpdateCheck {
    latestSHA, err := resolver.ResolveSHA(context.Background(), action.Repo, action.Version)

// After
func CheckActionSHAUpdates(ctx context.Context, actions []ActionUsage, resolver *ActionResolver) []ActionUpdateCheck {
    latestSHA, err := resolver.ResolveSHA(ctx, action.Repo, action.Version)

context.Background() now only appears at top-level CLI entry points and in tests.

Copilot AI and others added 3 commits May 15, 2026 05:38
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…ll chains

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…ction name strings

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix context propagation in ResolveSHA call sites Thread context.Context through all ResolveSHA call sites May 15, 2026
Copilot AI requested a review from pelikhan May 15, 2026 06:14
@pelikhan pelikhan marked this pull request as ready for review May 15, 2026 11:44
Copilot AI review requested due to automatic review settings May 15, 2026 11:44
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 threads context.Context through SHA resolution and related compile/add/init/update flows so gh api calls can be canceled or timed out by callers.

Changes:

  • Adds context parameters to workflow SHA resolution helpers, maintenance workflow generation, compile orchestration, add/update/init/enable paths, and CLI command boundaries.
  • Adds compiler context storage via WithContext / SetContext.
  • Updates many tests and one generated workflow lock file to match the new APIs/output.
Show a summary per file
File Description
pkg/workflow/side_repo_maintenance.go Passes context through side-repo maintenance generation.
pkg/workflow/maintenance_workflow.go Adds context to maintenance workflow and setup CLI action resolution.
pkg/workflow/maintenance_workflow_yaml.go Passes context into generated maintenance YAML action references.
pkg/workflow/maintenance_workflow_test.go Updates tests for context-aware maintenance APIs.
pkg/workflow/lock_validation.go Adds context to action SHA validation.
pkg/workflow/compiler_types.go Adds compiler context field and setters/options.
pkg/workflow/compiler_custom_actions_test.go Updates setup action reference tests.
pkg/workflow/central_slash_command_workflow.go Adds context to centralized slash-command generation.
pkg/workflow/central_slash_command_workflow_test.go Updates centralized workflow tests.
pkg/workflow/action_sha_validation_test.go Updates lock SHA validation test call.
pkg/workflow/action_sha_checker.go Passes context to ResolveSHA.
pkg/workflow/action_sha_checker_test.go Updates SHA checker test call.
pkg/workflow/action_reference.go Adds context to setup action reference resolution.
pkg/workflow/action_reference_test.go Updates setup action reference tests.
pkg/cli/upgrade_command.go Threads context through upgrade compilation/setup paths.
pkg/cli/update_workflows.go Passes context during workflow recompilation.
pkg/cli/update_command_test.go Updates compile-with-refresh test calls.
pkg/cli/update_actions.go Passes context during action update recompilation.
pkg/cli/init.go Adds InitOptions.Ctx and threads context into setup/maintenance.
pkg/cli/init_test.go Updates maintenance helper test call.
pkg/cli/init_mcp_test.go Updates Copilot setup helper calls.
pkg/cli/init_command.go Passes Cobra command context into init.
pkg/cli/file_tracker_test.go Updates tracking compile helper tests.
pkg/cli/error_formatting_test.go Updates compile validation test call.
pkg/cli/enable.go Adds context to enable/disable workflow flows.
pkg/cli/copilot_setup.go Threads context through Copilot setup action resolution.
pkg/cli/copilot_setup_test.go Updates Copilot setup tests for context APIs.
pkg/cli/compile_workflow_processor.go Passes context into workflow-data compilation.
pkg/cli/compile_watch.go Threads context into watch-mode compile calls.
pkg/cli/compile_validation.go Adds context to compile validation and SHA validation.
pkg/cli/compile_update_discussion_test.go Updates compile validation test call.
pkg/cli/compile_security_benchmark_test.go Updates benchmark compile calls.
pkg/cli/compile_post_processing.go Passes context into post-processing workflow generation.
pkg/cli/compile_pipeline.go Threads context through compile pipeline stages.
pkg/cli/compile_orchestrator.go Sets compiler context and passes it through orchestration.
pkg/cli/compile_guard_policy_test.go Updates guard policy compile tests.
pkg/cli/compile_file_operations.go Adds context to single/all/dependency compile helpers.
pkg/cli/commands_file_watching_test.go Updates watch/file compile helper tests.
pkg/cli/add_workflow_pr.go Passes context through PR-based workflow addition.
pkg/cli/add_workflow_compilation.go Adds context to add-time compile helpers.
pkg/cli/add_interactive_git.go Passes interactive context into add flow.
pkg/cli/add_gitattributes_test.go Updates add workflow helper tests.
pkg/cli/add_command.go Threads context through resolved workflow addition and dependencies.
pkg/cli/add_command_test.go Updates add command helper tests.
cmd/gh-aw/main.go Passes Cobra command context to enable/disable commands.
.github/workflows/linter-miner.lock.yml Regenerates the linter-miner workflow lock output.

Copilot's findings

Tip

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

Comments suppressed due to low confidence (1)

pkg/cli/compile_validation.go:110

  • This signature change is not applied consistently: pkg/cli/compile_command_test.go still calls CompileWorkflowDataWithValidation without the new context argument, so the package tests will not compile. Also apply ctx to the compiler before CompileWorkflowData so SHA resolution during data compilation observes caller cancellation.
func CompileWorkflowDataWithValidation(ctx context.Context, compiler *workflow.Compiler, workflowData *workflow.WorkflowData, filePath string, verbose bool, runZizmorPerFile bool, runPoutinePerFile bool, runActionlintPerFile bool, strict bool, validateActionSHAs bool) error {
  • Files reviewed: 46/46 changed files
  • Comments generated: 7


// Compiler handles converting markdown workflows to GitHub Actions YAML
type Compiler struct {
ctx context.Context // Context for network operations (e.g. SHA resolution); defaults to context.Background()

// ValidateActionSHAsInLockFile validates action SHAs in a lock file and emits warnings
func ValidateActionSHAsInLockFile(lockFilePath string, cache *ActionCache, verbose bool) error {
func ValidateActionSHAsInLockFile(ctx context.Context, lockFilePath string, cache *ActionCache, verbose bool) error {
// repoSlug is the owner/repo slug used to determine the default branch for the push
// trigger; pass an empty string to fall back to "main".
func GenerateMaintenanceWorkflow(workflowDataList []*WorkflowData, workflowDir string, version string, actionMode ActionMode, actionTag string, verbose bool, repoConfig *RepoConfig, repoSlug string) error {
func GenerateMaintenanceWorkflow(ctx context.Context, workflowDataList []*WorkflowData, workflowDir string, version string, actionMode ActionMode, actionTag string, verbose bool, repoConfig *RepoConfig, repoSlug string) error {
Comment thread pkg/cli/enable.go

// EnableWorkflowsByNames enables workflows by specific names, or all if no names provided
func EnableWorkflowsByNames(workflowNames []string, repoOverride string) error {
func EnableWorkflowsByNames(ctx context.Context, workflowNames []string, repoOverride string) error {
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@v0.72.1
uses: ./actions/setup

// CompileWorkflowWithValidation compiles a workflow with always-on YAML validation for CLI usage
func CompileWorkflowWithValidation(compiler *workflow.Compiler, filePath string, verbose bool, runZizmorPerFile bool, runPoutinePerFile bool, runActionlintPerFile bool, strict bool, validateActionSHAs bool) error {
func CompileWorkflowWithValidation(ctx context.Context, compiler *workflow.Compiler, filePath string, verbose bool, runZizmorPerFile bool, runPoutinePerFile bool, runActionlintPerFile bool, strict bool, validateActionSHAs bool) error {
// This is a convenience wrapper around compileWorkflowWithRefresh.
func compileWorkflow(filePath string, verbose bool, quiet bool, engineOverride string) error {
return compileWorkflowWithRefresh(filePath, verbose, quiet, engineOverride, false)
func compileWorkflow(ctx context.Context, filePath string, verbose bool, quiet bool, engineOverride string) error {
@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: N/A

i️ No new test functions were added or modified in this PR. All test file changes are purely mechanical — threading context.Background() through existing function call sites to match the updated signatures in production code.

Summary

Metric Value
Test files changed 18
New test functions added 0
New test functions analyzed 0
Coding-guideline violations 0
Newly added test files missing build tags 0

Nature of Test Changes

All 18 modified test files follow an identical mechanical pattern:

  1. Added "context" import where needed
  2. Prepended context.Background() as the first argument to calls such as ensureCopilotSetupSteps(...), GenerateMaintenanceWorkflow(...), upgradeSetupCliVersionInContent(...), buildMaintenanceWorkflowYAML(...), etc.
  3. Updated error message strings to mention context.Background() for clarity (e.g., "ensureCopilotSetupSteps(context.Background()) error = ...")

These are signature-adaptation changes required by the production code refactoring — no behavioral changes to test logic.


Verdict

Check passed. No new or substantively modified test functions were found — 0% of new tests are implementation tests (threshold: 30%). The existing test suite continues to enforce the same behavioral contracts as before.


References: §25916052602

🧪 Test quality analysis by Test Quality Sentinel · ● 7.9M ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

✅ Test Quality Sentinel: N/A score (no new test functions). Test quality is acceptable — 0% of new tests are implementation tests (threshold: 30%). All 18 test file changes are purely mechanical context threading with no behavioral changes.

@github-actions
Copy link
Copy Markdown
Contributor

Commit pushed: 8af12a1

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · ● 5.7M

@github-actions
Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (313 new lines across pkg/workflow/ and pkg/cli/, exceeding the 100-line threshold) but does not have a linked Architecture Decision Record (ADR).

AI has analyzed the PR diff and generated a draft ADR to help you get started:

📄 Draft ADR: docs/adr/32295-thread-context-through-resolvesha-call-chains.md

The draft has been committed to this PR branch.

What to do next

  1. Review the draft ADR committed to your branch — it was generated from the PR diff and may have gaps the AI couldn't infer.
  2. Complete the missing sections — refine the Context, double-check that the listed alternatives are the ones you actually weighed, and verify the Consequences match your real trade-offs.
  3. Commit the finalized ADR to docs/adr/ on this branch (replace the draft, don't add a second file).
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-32295: Thread context.Context Through ResolveSHA Call Chains

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 32295-thread-context-through-resolvesha-call-chains.md for PR #32295).

References:

🔒 This PR cannot merge until an ADR is linked in the PR body.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · ● 5.7M ·

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot merge main and review all comments

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /zoom-out and /tdd — this is a pure refactor that threads context.Context through a call chain, with architectural implications worth examining.

Key Themes

1. Split context ownership (important)
CompileWorkflowWithValidation now takes a ctx parameter and passes it to ValidateActionSHAsInLockFile, but compiler.CompileWorkflow (line 46) uses compiler.ctx — a different context stored in the struct. Callers who inject a timeout context into CompileWorkflowWithValidation will only get partial cancellation coverage. See inline comment.

2. context.Context as a struct field (Go anti-pattern)
The Go team explicitly discourages storing Context in structs. A long-lived Compiler reused across multiple compiles is a good example of why — each compile call may warrant a different deadline. The cleaner path is to pass ctx per-call through the public compile entry points and remove c.ctx / WithContext / SetContext. See inline comment.

3. Missing cancellation test
All test call sites pass context.Background(). There is no test that verifies a cancelled context is actually propagated and honoured. The PR's stated value — "making it impossible for callers to inject timeouts or cancel hung gh api network calls" — is unverified. See inline comment.

Positive Highlights

  • ✅ Clean, mechanical refactor with no logic changes — easy to review
  • ✅ Consistent call-site updates across all 5 production sites
  • ✅ Good PR description explains the motivation clearly
  • WithContext functional option follows the established CompilerOption pattern

Verdict

The threading is mechanically correct and the goal is valuable. The split-context issue is the most actionable — it means the PR solves the stated problem only partially as-is. Flagging as COMMENT since the issues are architectural observations rather than blockers, but the split-context concern is worth resolving before this ships.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · ● 17.6M

// Use the compiler's shared action cache to benefit from cached resolutions
actionCache := compiler.GetSharedActionCache()
if err := workflow.ValidateActionSHAsInLockFile(lockFile, actionCache, verbose); err != nil {
if err := workflow.ValidateActionSHAsInLockFile(ctx, lockFile, actionCache, verbose); err != nil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/zoom-out] Split context ownership: CompileWorkflowWithValidation receives ctx and passes it to ValidateActionSHAsInLockFile (line 77), but line 46's compiler.CompileWorkflow(filePath) uses compiler.ctx internally — a different context. A caller who does:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
CompileWorkflowWithValidation(ctx, compiler, filePath, ...)

will time out SHA validation but not the compile step (which uses compiler.ctx = context.Background() by default).

To eliminate this inconsistency, either:

  • Drop the ctx parameter from CompileWorkflowWithValidation entirely and call compiler.SetContext(ctx) at the call site before invoking this function, so a single context governs everything, or
  • Forward ctx to the compiler at the top of the function: compiler.SetContext(ctx)


// Compiler handles converting markdown workflows to GitHub Actions YAML
type Compiler struct {
ctx context.Context // Context for network operations (e.g. SHA resolution); defaults to context.Background()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/zoom-out] Storing context.Context as a struct field is explicitly discouraged by the Go team ([context docs]((pkg.go.dev/redacted) "Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it."

This approach forces callers to think about per-operation context vs per-compiler-instance context, and leads to the split-ownership issue noted in compile_validation.go. A long-lived Compiler may be reused across multiple compile calls with different deadlines/cancellation scopes.

Consider removing c.ctx and requiring callers to pass ctx directly to each compile entry point. The existing WithContext / SetContext API can be removed once the context is passed per-call instead.


// Check for updates
checks := CheckActionSHAUpdates(actions, resolver)
checks := CheckActionSHAUpdates(context.Background(), actions, resolver)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] The entire motivation of this PR is to allow callers to inject timeouts/cancellation into ResolveSHA calls. But every test site simply passes context.Background(). There is no test that verifies the context is actually honoured.

Consider adding a test that cancels the context and verifies the operation respects it:

t.Run("respects cancelled context", func(t *testing.T) {
    ctx, cancel := context.WithCancel(context.Background())
    cancel() // cancel immediately

    checks := CheckActionSHAUpdates(ctx, actions, resolver)

    // All checks should fail or be skipped — not hang indefinitely
    for _, c := range checks {
        assert.False(t, c.UpdateAvailable, "should not resolve SHAs with cancelled context")
    }
})

Without this, the refactor is correct by inspection but not by evidence.

Copilot AI and others added 2 commits May 15, 2026 12:24
…gation-fix

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…integration test call sites

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 15, 2026

@copilot merge main and review all comments

Done. Merged origin/main (resolved the linter-miner.lock.yml conflict by taking main's version) and addressed all reviewer comments:

  • WorkflowData.PinContext() — added Ctx context.Context field to WorkflowData, populated it from c.ctx in compiler_orchestrator_workflow.go and compiler_string_api.go, and threaded it into the returned actionpins.PinContext so action-pinning SHA resolution is cancellable end-to-end.
  • compile_validation.go — added compiler.SetContext(ctx) before each CompileWorkflow/CompileWorkflowData call; replaced the two remaining context.Background() literals in the runActionlintOnFiles calls with ctx.
  • Integration test call sites — updated action_sha_checker_integration_test.go, side_repo_maintenance_integration_test.go, fuzzy_matching_integration_test.go, compile_command_test.go, and commands_compile_workflow_test.go to pass context.Background() at the new first parameter position.

All tests pass (go test ./pkg/workflow/... ./pkg/cli/...). Commit: fix: address PR review comments - thread ctx into PinContext and fix integration test call sites.

@pelikhan pelikhan merged commit 857531f into main May 15, 2026
@pelikhan pelikhan deleted the copilot/context-propagation-fix branch May 15, 2026 12:45
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.

context.Background() hard-coded in 5 ResolveSHA call sites blocks ctx propagation

3 participants