Skip to content

fix: gh aw logs MCP tool fails with 'unable to find git executable in PATH' in agent sandbox#26347

Closed
Copilot wants to merge 6 commits intomainfrom
copilot/fix-git-executable-path-error
Closed

fix: gh aw logs MCP tool fails with 'unable to find git executable in PATH' in agent sandbox#26347
Copilot wants to merge 6 commits intomainfrom
copilot/fix-git-executable-path-error

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 15, 2026

The gh aw logs MCP tool is unusable in agent sandbox environments (e.g. audit-workflows) because gh run list tries to detect the current repo via git remote, but git is not in PATH inside the agent container.

Changes

  • pkg/cli/logs_orchestrator.go: Extracts a applyRepoOverrideFallback helper that, when repoOverride is empty, falls back to GITHUB_REPOSITORY (always set in GitHub Actions). This single assignment propagates through the entire call chain:
    • listWorkflowRunsWithPagination → adds --repo to gh run list
    • downloadRunArtifactsConcurrent → adds --repo to gh run download and artifact API calls
func applyRepoOverrideFallback(repoOverride string) string {
    if repoOverride != "" {
        return repoOverride
    }
    if githubRepo := os.Getenv("GITHUB_REPOSITORY"); githubRepo != "" {
        return githubRepo
    }
    return repoOverride
}

The fallback only activates when no explicit --repo flag is given. gh api calls using {owner}/{repo} template placeholders (fetchJobStatuses, fetchJobDetails) may fail if git is unavailable and GH_REPO is not set externally, but these calls are already non-fatal and return nil on error.

  • pkg/cli/logs_repo_fallback_test.go: Unit tests for applyRepoOverrideFallback covering explicit override passthrough, GITHUB_REPOSITORY fallback, and no env vars present.

[!WARNING]

Copilot AI and others added 2 commits April 15, 2026 02:26
…o avoid git dependency

When the gh aw logs MCP tool is called in agent sandbox environments where git
is not installed (e.g., audit-workflows agent container), gh run list and gh run
download fail with 'unable to find git executable in PATH' because the gh CLI
cannot determine the current repository without git.

Fix: at the start of DownloadWorkflowLogs, when no explicit --repo override is
specified, fall back to the GITHUB_REPOSITORY environment variable. This value is:
- propagated as opts.RepoOverride to listWorkflowRunsWithPagination (adds --repo
  to gh run list)
- propagated as repoOverride to downloadRunArtifactsConcurrent (adds --repo to
  gh run download)
- set as GH_REPO env var so gh api calls with {owner}/{repo} template placeholders
  (fetchJobStatuses, fetchJobDetails) can resolve the repository without git

Closes #<issue number>

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/2e2c77ee-7608-4732-a446-2f379ec61ce0

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix MCP tool error due to missing git executable in PATH fix: gh aw logs MCP tool fails with 'unable to find git executable in PATH' in agent sandbox Apr 15, 2026
Copilot AI requested a review from pelikhan April 15, 2026 02:40
@pelikhan pelikhan marked this pull request as ready for review April 15, 2026 02:58
Copilot AI review requested due to automatic review settings April 15, 2026 02:58
@github-actions github-actions bot mentioned this pull request Apr 15, 2026
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

Fixes gh aw logs failures in agent sandbox environments where git isn’t available by ensuring gh commands have an explicit repository context.

Changes:

  • Add a fallback in DownloadWorkflowLogs to use GITHUB_REPOSITORY when --repo isn’t provided, and set GH_REPO (if unset) for gh api template paths.
  • Add a repo-level .mcp.json MCP server configuration for gh aw mcp-server.
Show a summary per file
File Description
pkg/cli/logs_orchestrator.go Derives repo context from GITHUB_REPOSITORY when repoOverride is empty; sets GH_REPO to support gh api template placeholders without git.
.mcp.json Adds MCP server config pointing to gh aw mcp-server.

Copilot's findings

Tip

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

  • Files reviewed: 2/2 changed files
  • Comments generated: 3

Comment thread pkg/cli/logs_orchestrator.go Outdated
Comment on lines +56 to +61
if os.Getenv("GH_REPO") == "" {
if err := os.Setenv("GH_REPO", repoOverride); err != nil {
// Non-fatal: the primary listing and download paths use explicit --repo flags.
// Only gh api calls using {owner}/{repo} template placeholders (e.g. job status
// queries) will be unable to resolve the repository context.
logsOrchestratorLog.Printf("Failed to set GH_REPO env var (gh api {owner}/{repo} template calls may fail to resolve repo context): %v", err)
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

This code mutates the process environment by setting GH_REPO. Since DownloadWorkflowLogs is exported and used from unit tests, leaving GH_REPO set for the remainder of the process can create cross-test contamination and unexpected behavior in later commands. Consider capturing the prior GH_REPO value (via os.LookupEnv) and restoring/unsetting it with a defer so the env change is scoped to this invocation while still affecting all gh subprocesses spawned within the function.

Suggested change
if os.Getenv("GH_REPO") == "" {
if err := os.Setenv("GH_REPO", repoOverride); err != nil {
// Non-fatal: the primary listing and download paths use explicit --repo flags.
// Only gh api calls using {owner}/{repo} template placeholders (e.g. job status
// queries) will be unable to resolve the repository context.
logsOrchestratorLog.Printf("Failed to set GH_REPO env var (gh api {owner}/{repo} template calls may fail to resolve repo context): %v", err)
if _, ghRepoWasSet := os.LookupEnv("GH_REPO"); !ghRepoWasSet {
if err := os.Setenv("GH_REPO", repoOverride); err != nil {
// Non-fatal: the primary listing and download paths use explicit --repo flags.
// Only gh api calls using {owner}/{repo} template placeholders (e.g. job status
// queries) will be unable to resolve the repository context.
logsOrchestratorLog.Printf("Failed to set GH_REPO env var (gh api {owner}/{repo} template calls may fail to resolve repo context): %v", err)
} else {
defer func() {
if err := os.Unsetenv("GH_REPO"); err != nil {
logsOrchestratorLog.Printf("Failed to restore GH_REPO env var after temporary override: %v", err)
}
}()

Copilot uses AI. Check for mistakes.
Comment on lines 44 to +66
// DownloadWorkflowLogs downloads and analyzes workflow logs with metrics
func DownloadWorkflowLogs(ctx context.Context, workflowName string, count int, startDate, endDate, outputDir, engine, ref string, beforeRunID, afterRunID int64, repoOverride string, verbose bool, toolGraph bool, noStaged bool, firewallOnly bool, noFirewall bool, parse bool, jsonOutput bool, timeout int, summaryFile string, safeOutputType string, filteredIntegrity bool, train bool, format string, artifactSets []string) error {
// When no explicit repo override is given, fall back to GITHUB_REPOSITORY so that
// `gh run list` and `gh run download` can operate without a git checkout.
// This is needed in agent sandbox environments (e.g., the audit-workflows agent)
// where git is not installed but GITHUB_REPOSITORY is set by GitHub Actions.
// We also set GH_REPO so that `gh api` calls using {owner}/{repo} template
// placeholders (e.g., fetchJobStatuses, fetchJobDetails) resolve correctly.
if repoOverride == "" {
if githubRepo := os.Getenv("GITHUB_REPOSITORY"); githubRepo != "" {
repoOverride = githubRepo
logsOrchestratorLog.Printf("Using GITHUB_REPOSITORY env var as repo override: %s", repoOverride)
if os.Getenv("GH_REPO") == "" {
if err := os.Setenv("GH_REPO", repoOverride); err != nil {
// Non-fatal: the primary listing and download paths use explicit --repo flags.
// Only gh api calls using {owner}/{repo} template placeholders (e.g. job status
// queries) will be unable to resolve the repository context.
logsOrchestratorLog.Printf("Failed to set GH_REPO env var (gh api {owner}/{repo} template calls may fail to resolve repo context): %v", err)
}
}
}
}

Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

The new GITHUB_REPOSITORY→repoOverride/GH_REPO fallback is a key behavior change but isn’t covered by tests. Suggest extracting the fallback logic into a small helper and adding a unit test that verifies: (1) repoOverride is populated from GITHUB_REPOSITORY when empty, (2) pre-existing GH_REPO is respected, and (3) GH_REPO is set when absent.

Suggested change
// DownloadWorkflowLogs downloads and analyzes workflow logs with metrics
func DownloadWorkflowLogs(ctx context.Context, workflowName string, count int, startDate, endDate, outputDir, engine, ref string, beforeRunID, afterRunID int64, repoOverride string, verbose bool, toolGraph bool, noStaged bool, firewallOnly bool, noFirewall bool, parse bool, jsonOutput bool, timeout int, summaryFile string, safeOutputType string, filteredIntegrity bool, train bool, format string, artifactSets []string) error {
// When no explicit repo override is given, fall back to GITHUB_REPOSITORY so that
// `gh run list` and `gh run download` can operate without a git checkout.
// This is needed in agent sandbox environments (e.g., the audit-workflows agent)
// where git is not installed but GITHUB_REPOSITORY is set by GitHub Actions.
// We also set GH_REPO so that `gh api` calls using {owner}/{repo} template
// placeholders (e.g., fetchJobStatuses, fetchJobDetails) resolve correctly.
if repoOverride == "" {
if githubRepo := os.Getenv("GITHUB_REPOSITORY"); githubRepo != "" {
repoOverride = githubRepo
logsOrchestratorLog.Printf("Using GITHUB_REPOSITORY env var as repo override: %s", repoOverride)
if os.Getenv("GH_REPO") == "" {
if err := os.Setenv("GH_REPO", repoOverride); err != nil {
// Non-fatal: the primary listing and download paths use explicit --repo flags.
// Only gh api calls using {owner}/{repo} template placeholders (e.g. job status
// queries) will be unable to resolve the repository context.
logsOrchestratorLog.Printf("Failed to set GH_REPO env var (gh api {owner}/{repo} template calls may fail to resolve repo context): %v", err)
}
}
}
}
// applyRepoOverrideFallback populates repoOverride from GITHUB_REPOSITORY when unset
// and ensures GH_REPO is available for gh api {owner}/{repo} template expansion.
func applyRepoOverrideFallback(repoOverride string) string {
if repoOverride != "" {
return repoOverride
}
githubRepo := os.Getenv("GITHUB_REPOSITORY")
if githubRepo == "" {
return repoOverride
}
repoOverride = githubRepo
logsOrchestratorLog.Printf("Using GITHUB_REPOSITORY env var as repo override: %s", repoOverride)
if os.Getenv("GH_REPO") == "" {
if err := os.Setenv("GH_REPO", repoOverride); err != nil {
// Non-fatal: the primary listing and download paths use explicit --repo flags.
// Only gh api calls using {owner}/{repo} template placeholders (e.g. job status
// queries) will be unable to resolve the repository context.
logsOrchestratorLog.Printf("Failed to set GH_REPO env var (gh api {owner}/{repo} template calls may fail to resolve repo context): %v", err)
}
}
return repoOverride
}
// DownloadWorkflowLogs downloads and analyzes workflow logs with metrics
func DownloadWorkflowLogs(ctx context.Context, workflowName string, count int, startDate, endDate, outputDir, engine, ref string, beforeRunID, afterRunID int64, repoOverride string, verbose bool, toolGraph bool, noStaged bool, firewallOnly bool, noFirewall bool, parse bool, jsonOutput bool, timeout int, summaryFile string, safeOutputType string, filteredIntegrity bool, train bool, format string, artifactSets []string) error {
repoOverride = applyRepoOverrideFallback(repoOverride)

Copilot uses AI. Check for mistakes.
Comment thread .mcp.json Outdated
Comment on lines +1 to +8
{
"servers": {
"github-agentic-workflows": {
"command": "gh",
"args": ["aw", "mcp-server"]
}
}
}
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

This PR adds a new top-level .mcp.json file, but the PR description only mentions changes to pkg/cli/logs_orchestrator.go. Please update the PR description to mention .mcp.json, or drop the file from this PR if it’s unrelated to the reported gh aw logs sandbox failure.

Copilot uses AI. Check for mistakes.
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review comments

…h defer, add tests, remove .mcp.json

- Extract GITHUB_REPOSITORY fallback into applyRepoOverrideFallback helper
  for easier testing and cleaner DownloadWorkflowLogs function
- Use defer to unset GH_REPO when the function returns, preventing cross-test
  contamination in unit tests and across sequential CLI invocations
- Use os.LookupEnv to detect pre-existing GH_REPO (never overwrite it)
- Add TestApplyRepoOverrideFallback covering all four scenarios:
  explicit override, GITHUB_REPOSITORY fallback + cleanup, pre-existing GH_REPO
  respected, and no env vars present
- Remove unrelated .mcp.json file from the PR

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/231e43cf-03b9-4cd9-8605-752ef9f39035

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

Copilot AI commented Apr 15, 2026

@copilot review comments

Addressed all three review comments in commit 5004613:

  1. Extracted applyRepoOverrideFallback helper — the fallback logic lives in its own function, making DownloadWorkflowLogs cleaner and the logic independently testable.

  2. Scoped GH_REPO with defer — used os.LookupEnv to detect whether GH_REPO was already set (never overwrite), and defer os.Unsetenv to clean it up on function return, preventing cross-test contamination.

  3. Added unit tests (TestApplyRepoOverrideFallback) covering all four scenarios: explicit override passthrough, GITHUB_REPOSITORY fallback + cleanup, pre-existing GH_REPO respected, and no env vars present. All pass.

  4. Removed .mcp.json — it was unrelated to this fix.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot do not set env, fail if needed

Copilot AI and others added 2 commits April 15, 2026 03:33
Per review feedback, do not set environment variables; let gh api {owner}/{repo}
calls fail gracefully (they already return nil on error). Simplify:
- applyRepoOverrideFallback returns string only (no cleanup func)
- DownloadWorkflowLogs uses a simple assignment, no defer cleanup
- Update tests to match — remove GH_REPO behaviour coverage

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/12bca3e1-ec6b-4574-ada9-24b948ab4e3c

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/12bca3e1-ec6b-4574-ada9-24b948ab4e3c

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

Copilot AI commented Apr 15, 2026

@copilot do not set env, fail if needed

Done in e016b3a. applyRepoOverrideFallback now only reads GITHUB_REPOSITORY and returns the fallback string — no environment variables are set. If gh api {owner}/{repo} calls fail because git isn't available, they already return nil (non-fatal), so no change in observable behaviour for those paths.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review comments

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 15, 2026

@copilot review comments

Code review ran clean — the only finding was about .mcp.json which was a stale staged file in the validation environment, not in the committed diff. The file is confirmed deleted from the branch. No other issues found.

@pelikhan pelikhan closed this Apr 15, 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.

audit-workflows: gh aw logs MCP tool fails with 'unable to find git executable in PATH'

3 participants