Skip to content

fix: pass owner/repo to gh run download for cross-repo audit#18603

Merged
pelikhan merged 5 commits intomainfrom
copilot/fix-gh-aw-audit-artifact-download
Feb 27, 2026
Merged

fix: pass owner/repo to gh run download for cross-repo audit#18603
pelikhan merged 5 commits intomainfrom
copilot/fix-gh-aw-audit-artifact-download

Conversation

Copy link
Contributor

Copilot AI commented Feb 27, 2026

  • Add owner, repo, hostname parameters to downloadRunArtifacts() and downloadWorkflowRunLogs()
  • Update call in audit.go to pass owner, repo, hostname to downloadRunArtifacts()
  • Update logs_orchestrator.go to thread repoOverride through downloadRunArtifactsConcurrent
  • Update unit test calls in audit_test.go and logs_parallel_test.go
  • Fix integration test calls in logs_orchestrator_test.go (add missing repoOverride arg)
  • Fix hostname handling in downloadRunArtifacts to use HOST/owner/repo for GHES
Original prompt

This section details on the original issue you should resolve

<issue_title>bug: gh aw audit fails to download artifacts for cross-repo run URLs</issue_title>
<issue_description>## Summary

gh aw audit correctly parses owner/repo from a cross-repo GitHub Actions URL but fails to pass -R owner/repo to gh run download, causing a 404 when auditing runs from a different repository.

Steps to Reproduce

# From inside the gh-aw repo, audit a run from gh-aw-firewall
gh aw audit https://github.com/github/gh-aw-firewall/actions/runs/22467849591 -v

Expected

Artifacts download successfully from github/gh-aw-firewall.

Actual

ℹ Run: Smoke Copilot (Status: completed, Conclusion: success)
ℹ Executing: gh run download 22467849591 --dir .github/aw/logs/run-22467849591
🔍 error fetching artifacts: HTTP 404: Not Found (https://api.github.com/repos/github/gh-aw/actions/runs/22467849591/artifacts?per_page=100)

The metadata API call correctly uses github/gh-aw-firewall, but gh run download defaults to the current directory's repo (github/gh-aw).

Root Cause

In pkg/cli/audit.go:200, downloadRunArtifacts is called with only (runID, runOutputDir, verbose) — the owner, repo, and hostname parameters from AuditWorkflowRun are not forwarded.

In pkg/cli/logs_download.go:512, the gh run download command is built without -R:

cmd := workflow.ExecGH("run", "download", strconv.FormatInt(runID, 10), "--dir", outputDir)

Suggested Fix

  1. Add owner, repo (and optionally hostname for GHES) parameters to downloadRunArtifacts()
  2. When owner/repo are non-empty, append -R owner/repo to the gh run download command
  3. Same fix may be needed for downloadWorkflowRunLogs() if it has the same pattern

Workaround

Download artifacts manually with the -R flag:

gh run download 22467849591 -R github/gh-aw-firewall --dir /tmp/audit-output
```</issue_description>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>

🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Copilot AI and others added 2 commits February 27, 2026 01:19
…kflowRunLogs for cross-repo support

Co-authored-by: Mossaka <5447827+Mossaka@users.noreply.github.com>
…e, use consistent fmt.Sprintf

Co-authored-by: Mossaka <5447827+Mossaka@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix artifact download failure in gh aw audit fix: pass owner/repo to gh run download for cross-repo audit Feb 27, 2026
@Mossaka Mossaka marked this pull request as ready for review February 27, 2026 01:46
Copilot AI review requested due to automatic review settings February 27, 2026 01:46
Copy link
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 cross-repo workflow run auditing/log download failures by ensuring the correct repository (and host where applicable) is used when downloading artifacts and workflow run logs.

Changes:

  • Extend artifact/log download helpers to accept owner, repo, and hostname, and use explicit repo-scoped API endpoints/CLI flags.
  • Thread owner/repo/hostname from AuditWorkflowRun into artifact download, and thread repoOverride through concurrent downloads for gh aw logs --repo.
  • Update unit tests to match updated function signatures.

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
pkg/cli/logs_download.go Adds repo/host-aware endpoint construction for run logs and adds repo override support for gh run download.
pkg/cli/audit.go Forwards parsed owner/repo/hostname into artifact download for cross-repo audits.
pkg/cli/logs_orchestrator.go Threads repoOverride into concurrent artifact download and parses it for owner/repo.
pkg/cli/logs_parallel_test.go Updates calls to downloadRunArtifactsConcurrent for the new signature.
pkg/cli/audit_test.go Updates call to downloadRunArtifacts for the new signature.
Comments suppressed due to low confidence (2)

pkg/cli/logs_download.go:518

  • New behavior is introduced here (adding repo override flags to the gh run download invocation), but there’s no unit test that asserts the constructed gh arguments/behavior for cross-repo (and host) inputs. Consider extracting arg construction into a small pure helper and adding tests for owner/repo and hostname cases so regressions are caught without needing network/gh CLI access.
	// Build gh run download command with optional repo override for cross-repo support
	ghArgs := []string{"run", "download", strconv.FormatInt(runID, 10), "--dir", outputDir}
	if owner != "" && repo != "" {
		ghArgs = append(ghArgs, "-R", owner+"/"+repo)
	}

pkg/cli/logs_orchestrator.go:552

  • repoOverride is documented as [HOST/]owner/repo, but this parsing uses SplitN(repoOverride, "/", 2). For values like ghe.example.com/owner/repo, this will set dlOwner to the host and dlRepo to owner/repo, which later produces an invalid repo string and breaks cross-host downloads. Parse 2- vs 3-segment forms explicitly (host/owner/repo) and thread the host through (or avoid splitting entirely by passing the full repoOverride to gh run download --repo).
	// Parse repoOverride into owner/repo once for cross-repo artifact download
	var dlOwner, dlRepo string
	if repoOverride != "" {
		parts := strings.SplitN(repoOverride, "/", 2)
		if len(parts) == 2 {
			dlOwner = parts[0]
			dlRepo = parts[1]
		}
	}

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

Comment on lines 514 to 517
// Build gh run download command with optional repo override for cross-repo support
ghArgs := []string{"run", "download", strconv.FormatInt(runID, 10), "--dir", outputDir}
if owner != "" && repo != "" {
ghArgs = append(ghArgs, "-R", owner+"/"+repo)
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

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

downloadRunArtifacts now accepts hostname, but the gh run download command it builds never uses it. This means auditing/downloading artifacts for GHES or other non-default hosts will still try to use the default host and can fail. Include the hostname in the gh invocation (or use --repo with [HOST/]owner/repo) when hostname is set and not github.com.

This issue also appears on line 514 of the same file.

Suggested change
// Build gh run download command with optional repo override for cross-repo support
ghArgs := []string{"run", "download", strconv.FormatInt(runID, 10), "--dir", outputDir}
if owner != "" && repo != "" {
ghArgs = append(ghArgs, "-R", owner+"/"+repo)
// Build gh run download command with optional repo/hostname override for cross-repo and multi-host support
ghArgs := []string{"run", "download", strconv.FormatInt(runID, 10), "--dir", outputDir}
if owner != "" && repo != "" {
// When a non-default hostname is provided, qualify the repo with the host: HOST/owner/repo
if hostname != "" && hostname != "github.com" {
ghArgs = append(ghArgs, "-R", hostname+"/"+owner+"/"+repo)
} else {
ghArgs = append(ghArgs, "-R", owner+"/"+repo)
}
} else if hostname != "" && hostname != "github.com" {
// If we don't have an explicit owner/repo but do have a non-default host, ensure gh targets that host
ghArgs = append(ghArgs, "--hostname", hostname)

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in f091cc6. downloadRunArtifacts now uses HOST/owner/repo format for -R when a non-default hostname is provided, matching the gh CLI's [HOST/]owner/repo convention.

Comment on lines 507 to 509
// downloadRunArtifactsConcurrent downloads artifacts for multiple workflow runs concurrently
func downloadRunArtifactsConcurrent(ctx context.Context, runs []WorkflowRun, outputDir string, verbose bool, maxRuns int) []DownloadResult {
func downloadRunArtifactsConcurrent(ctx context.Context, runs []WorkflowRun, outputDir string, verbose bool, maxRuns int, repoOverride string) []DownloadResult {
logsOrchestratorLog.Printf("Starting concurrent artifact download: runs=%d, outputDir=%s, maxRuns=%d", len(runs), outputDir, maxRuns)
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

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

This function signature change requires updating all call sites. There are still callers using the old 5-arg form under the integration build tag (e.g., pkg/cli/logs_orchestrator_test.go:22,41,74,...), which will fail to compile when integration tests are built. Update those call sites to pass the new repoOverride argument.

This issue also appears on line 544 of the same file.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in f091cc6. All 14 call sites in logs_orchestrator_test.go (integration build tag) now pass the repoOverride argument. Verified with go build -tags integration ./pkg/cli/.

@Mossaka
Copy link
Collaborator

Mossaka commented Feb 27, 2026

@copilot investigate integration test failures in this PR.

…signature and add GHES hostname support to gh run download

Co-authored-by: Mossaka <5447827+Mossaka@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 27, 2026

@copilot investigate integration test failures in this PR.

The integration test failures were caused by the downloadRunArtifactsConcurrent signature change — all 14 call sites in logs_orchestrator_test.go were missing the new repoOverride string parameter. Also fixed the hostname not being forwarded to gh run download for GHES. Both fixed in f091cc6.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts
    • Triggering command: /usr/bin/gh gh run download 1 --dir test-logs/run-1 (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts
    • Triggering command: /usr/bin/gh gh run download 12345 --dir test-logs/run-12345 (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts
    • Triggering command: /usr/bin/gh gh run download 12346 --dir test-logs/run-12346 (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts
    • Triggering command: /usr/bin/gh gh run download 2 --dir test-logs/run-2 (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts
    • Triggering command: /usr/bin/gh gh run download 3 --dir test-logs/run-3 (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts
    • Triggering command: /usr/bin/gh gh run download 4 --dir test-logs/run-4 (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts
    • Triggering command: /usr/bin/gh gh run download 5 --dir test-logs/run-5 (http block)

If you need me to access, download, or install something from one of these locations, you can either:

@pelikhan pelikhan merged commit a5b22ba into main Feb 27, 2026
77 checks passed
@pelikhan pelikhan deleted the copilot/fix-gh-aw-audit-artifact-download branch February 27, 2026 03:29
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.

bug: gh aw audit fails to download artifacts for cross-repo run URLs

4 participants