From 3ee0abcda02acd70f3c375636c2348831f9b9820 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Jul 2026 06:28:38 +0000 Subject: [PATCH 1/4] Initial plan From dbb63fee3085fbc8b04778ae2ff89d95d8b779b8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Jul 2026 06:47:23 +0000 Subject: [PATCH 2/4] fix: address targeted custom lint findings in workflow and parser paths Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/logs_rate_limit.go | 13 +++--- pkg/parser/remote_download_file.go | 41 +++++++++++++------ pkg/workflow/action_cache.go | 12 +++--- .../compiler_orchestrator_frontmatter.go | 4 +- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/pkg/cli/logs_rate_limit.go b/pkg/cli/logs_rate_limit.go index 81e1deae5cf..bb398c57c82 100644 --- a/pkg/cli/logs_rate_limit.go +++ b/pkg/cli/logs_rate_limit.go @@ -77,12 +77,13 @@ func fetchRateLimit() (rateLimitResource, error) { // If ctx is cancelled before the timer expires, it stops the timer and returns // ctx.Err() so callers can propagate cancellation immediately. func sleepWithContext(ctx context.Context, d time.Duration) error { - if ctx == nil { - ctx = context.Background() + var done <-chan struct{} + if ctx != nil { + done = ctx.Done() } select { - case <-ctx.Done(): - return ctx.Err() + case <-done: + return context.Cause(ctx) default: } @@ -91,8 +92,8 @@ func sleepWithContext(ctx context.Context, d time.Duration) error { select { case <-timer.C: return nil - case <-ctx.Done(): - return ctx.Err() + case <-done: + return context.Cause(ctx) } } diff --git a/pkg/parser/remote_download_file.go b/pkg/parser/remote_download_file.go index ad00a23a6f3..585f17bf2d7 100644 --- a/pkg/parser/remote_download_file.go +++ b/pkg/parser/remote_download_file.go @@ -210,7 +210,15 @@ func resolveRemoteSymlinks(ctx context.Context, client *api.RESTClient, owner, r for i := 1; i < len(parts); i++ { dirPath := strings.Join(parts[:i], "/") - resolvedPath, found, err := resolveRemoteSymlinkComponent(ctx, client, owner, repo, filePath, ref, parts, i, dirPath) + resolvedPath, found, err := resolveRemoteSymlinkComponent(ctx, client, remoteSymlinkComponentParams{ + owner: owner, + repo: repo, + filePath: filePath, + ref: ref, + parts: parts, + index: i, + dirPath: dirPath, + }) if err != nil { return "", err } @@ -223,39 +231,46 @@ func resolveRemoteSymlinks(ctx context.Context, client *api.RESTClient, owner, r return "", fmt.Errorf("no symlinks found in path: %s", filePath) } +type remoteSymlinkComponentParams struct { + owner string + repo string + filePath string + ref string + parts []string + index int + dirPath string +} + func resolveRemoteSymlinkComponent( ctx context.Context, client *api.RESTClient, - owner, repo, filePath, ref string, - parts []string, - index int, - dirPath string, + params remoteSymlinkComponentParams, ) (string, bool, error) { - target, isSymlink, err := checkRemoteSymlink(ctx, client, owner, repo, dirPath, ref) + target, isSymlink, err := checkRemoteSymlink(ctx, client, params.owner, params.repo, params.dirPath, params.ref) if err != nil { if errorutil.IsNotFoundError(err) { - remoteLog.Printf("Path component %s returned 404, skipping", dirPath) + remoteLog.Printf("Path component %s returned 404, skipping", params.dirPath) return "", false, nil } - return "", false, fmt.Errorf("failed to check path component %s for symlinks: %w", dirPath, err) + return "", false, fmt.Errorf("failed to check path component %s for symlinks: %w", params.dirPath, err) } if !isSymlink { return "", false, nil } parentDir := "" - if index > 1 { - parentDir = strings.Join(parts[:index-1], "/") + if params.index > 1 { + parentDir = strings.Join(params.parts[:params.index-1], "/") } - resolvedBase, err := resolveAndValidateRemoteSymlinkBase(parentDir, target, dirPath) + resolvedBase, err := resolveAndValidateRemoteSymlinkBase(parentDir, target, params.dirPath) if err != nil { return "", false, err } - remaining := strings.Join(parts[index:], "/") + remaining := strings.Join(params.parts[params.index:], "/") resolvedPath := pathpkg.Clean(pathpkg.Join(resolvedBase, remaining)) if resolvedPath == "" || resolvedPath == "." || pathpkg.IsAbs(resolvedPath) || strings.HasPrefix(resolvedPath, "..") { return "", false, fmt.Errorf("resolved symlink path escapes repository root: %s", resolvedPath) } - remoteLog.Printf("Resolved symlink in remote path: %s -> %s (full: %s -> %s)", dirPath, target, filePath, resolvedPath) + remoteLog.Printf("Resolved symlink in remote path: %s -> %s (full: %s -> %s)", params.dirPath, target, params.filePath, resolvedPath) return resolvedPath, true, nil } diff --git a/pkg/workflow/action_cache.go b/pkg/workflow/action_cache.go index a77311ec3ee..f82a8a53234 100644 --- a/pkg/workflow/action_cache.go +++ b/pkg/workflow/action_cache.go @@ -272,7 +272,7 @@ func (c *ActionCache) marshalSorted() ([]byte, error) { // Manually construct JSON with sorted keys var result []byte - result = append(result, []byte("{\n \"entries\": {\n")...) + result = append(result, "{\n \"entries\": {\n"...) for i, key := range keys { entry := c.Entries[key] @@ -284,7 +284,7 @@ func (c *ActionCache) marshalSorted() ([]byte, error) { } // Add the key and entry - result = append(result, []byte(" \""+key+"\": ")...) + result = append(result, " \""+key+"\": "...) result = append(result, entryJSON...) // Add comma if not the last entry @@ -294,27 +294,27 @@ func (c *ActionCache) marshalSorted() ([]byte, error) { result = append(result, '\n') } - result = append(result, []byte(" }")...) + result = append(result, " }"...) // Add containers section if non-empty if len(c.ContainerPins) > 0 { pinKeys := sliceutil.SortedKeys(c.ContainerPins) - result = append(result, []byte(",\n \"containers\": {\n")...) + result = append(result, ",\n \"containers\": {\n"...) for i, k := range pinKeys { pin := c.ContainerPins[k] pinJSON, err := json.MarshalIndent(pin, " ", " ") if err != nil { return nil, err } - result = append(result, []byte(" \""+k+"\": ")...) + result = append(result, " \""+k+"\": "...) result = append(result, pinJSON...) if i < len(pinKeys)-1 { result = append(result, ',') } result = append(result, '\n') } - result = append(result, []byte(" }")...) + result = append(result, " }"...) } result = append(result, '\n', '}') diff --git a/pkg/workflow/compiler_orchestrator_frontmatter.go b/pkg/workflow/compiler_orchestrator_frontmatter.go index a3af25f0e6b..8ce1aeddef7 100644 --- a/pkg/workflow/compiler_orchestrator_frontmatter.go +++ b/pkg/workflow/compiler_orchestrator_frontmatter.go @@ -84,8 +84,8 @@ func (c *Compiler) parseFrontmatterSection(markdownPath string) (*frontmatterPar content, err := os.ReadFile(cleanPath) if err != nil { orchestratorFrontmatterLog.Printf("Failed to read file: %s, error: %v", cleanPath, err) - // Intentionally not wrapping to avoid exposing internal path details - return nil, fmt.Errorf("failed to read file: %v", err) //nolint:errorlint // intentionally not wrapping to avoid exposing os.PathError + // Keep the user-facing message while avoiding exposure of os.PathError internals. + return nil, fmt.Errorf("failed to read file: %w", errors.New(err.Error())) } contentString := string(content) From efdf30a63d9aef0e4d035592d2c1fb04e11a47a5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Jul 2026 06:58:45 +0000 Subject: [PATCH 3/4] fix: complete targeted lint-monster cleanup for issue #43923 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/logs_rate_limit.go | 13 +++++++++++-- pkg/workflow/compiler_orchestrator_frontmatter.go | 10 +++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/pkg/cli/logs_rate_limit.go b/pkg/cli/logs_rate_limit.go index bb398c57c82..433b629274e 100644 --- a/pkg/cli/logs_rate_limit.go +++ b/pkg/cli/logs_rate_limit.go @@ -26,6 +26,13 @@ import ( var logsRateLimitLog = logger.New("cli:logs_rate_limit") var fetchRateLimitFunc = fetchRateLimit +func contextCause(ctx context.Context) error { + if ctx == nil { + return nil + } + return context.Cause(ctx) +} + // rateLimitResponse models the JSON returned by `gh api rate_limit`. // Only the "core" resource bucket is used because log downloads and // workflow-run listing both draw from the core quota. @@ -81,9 +88,11 @@ func sleepWithContext(ctx context.Context, d time.Duration) error { if ctx != nil { done = ctx.Done() } + // When ctx is nil, done remains nil. A nil channel is never selected, which + // intentionally makes cancellation checks a no-op and preserves prior behavior. select { case <-done: - return context.Cause(ctx) + return contextCause(ctx) default: } @@ -93,7 +102,7 @@ func sleepWithContext(ctx context.Context, d time.Duration) error { case <-timer.C: return nil case <-done: - return context.Cause(ctx) + return contextCause(ctx) } } diff --git a/pkg/workflow/compiler_orchestrator_frontmatter.go b/pkg/workflow/compiler_orchestrator_frontmatter.go index 8ce1aeddef7..c420e6ecc37 100644 --- a/pkg/workflow/compiler_orchestrator_frontmatter.go +++ b/pkg/workflow/compiler_orchestrator_frontmatter.go @@ -29,6 +29,14 @@ type frontmatterParseResult struct { redirectTarget string } +type frontmatterReadError struct { + message string +} + +func (e frontmatterReadError) Error() string { + return e.message +} + func (c *Compiler) validateEngineBeforeSchema( cleanPath string, content []byte, @@ -85,7 +93,7 @@ func (c *Compiler) parseFrontmatterSection(markdownPath string) (*frontmatterPar if err != nil { orchestratorFrontmatterLog.Printf("Failed to read file: %s, error: %v", cleanPath, err) // Keep the user-facing message while avoiding exposure of os.PathError internals. - return nil, fmt.Errorf("failed to read file: %w", errors.New(err.Error())) + return nil, fmt.Errorf("failed to read file: %w", frontmatterReadError{message: err.Error()}) } contentString := string(content) From 6b00cf94051c44c16944f333eba0e80251befcc9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Jul 2026 08:33:27 +0000 Subject: [PATCH 4/4] docs: fix sleepWithContext comment to reflect context.Cause(ctx) return Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com> --- pkg/cli/logs_rate_limit.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/cli/logs_rate_limit.go b/pkg/cli/logs_rate_limit.go index 433b629274e..5abd45c6475 100644 --- a/pkg/cli/logs_rate_limit.go +++ b/pkg/cli/logs_rate_limit.go @@ -82,7 +82,8 @@ func fetchRateLimit() (rateLimitResource, error) { // sleepWithContext pauses for duration d and returns nil when the timer fires. // If ctx is cancelled before the timer expires, it stops the timer and returns -// ctx.Err() so callers can propagate cancellation immediately. +// context.Cause(ctx) so callers can propagate cancellation (and any wrapped +// cause) immediately. func sleepWithContext(ctx context.Context, d time.Duration) error { var done <-chan struct{} if ctx != nil {