Skip to content

[WIP] Add fallback to unauthenticated REST API call#3957

Closed
Copilot wants to merge 7 commits intomainfrom
copilot/fallback-rest-api-call
Closed

[WIP] Add fallback to unauthenticated REST API call#3957
Copilot wants to merge 7 commits intomainfrom
copilot/fallback-rest-api-call

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Nov 14, 2025

Task: Add REST API Fallback for GitHub API Calls ✅

Add fallback to unauthenticated REST API calls when GitHub token is not available.

Completed ✅

  • Explore repository structure
  • Identify files using gh api command
  • Understand current authentication behavior
  • Review existing tests
  • Add REST API fallback helper function
  • Update ExecGH wrapper with fallback capability
  • Add HTTP client for direct REST API calls
  • Update action_resolver.go to use fallback
  • Add comprehensive tests for fallback behavior
  • Fix auth error detection to check combined output
  • Fix failing test after merge with main
  • Specialize function signature for gh api commands only
  • Verify all changes work correctly

Implementation Summary

Core Changes:

  1. pkg/workflow/gh_helper.go - Added REST API fallback functions:

    • ExecGHAPIWithRESTFallback(apiPath, jqFilter) - Specialized for gh api commands
    • callGitHubRESTAPI() - Makes unauthenticated HTTP GET requests
    • applyJQFilter() - Simple jq-style JSON field extraction
  2. pkg/workflow/action_resolver.go - Updated to use REST fallback:

    • Modified resolveFromGitHub() to call ExecGHAPIWithRESTFallback()
    • Logs when REST API fallback is used
  3. Test Coverage:

    • Unit tests for jq filtering (7 test cases)
    • Unit tests for specialized API function (2 test cases)
    • Integration tests for real API calls (3 test cases)
    • All tests pass ✅

How It Works

  1. Try gh CLI First: Calls gh api <path> with optional --jq filter
  2. Detect Auth Failure: Checks for:
    • Exit code 4 (gh CLI auth error)
    • "GH_TOKEN" in output (gh CLI's auth message)
    • "authentication", "HTTP 401", "HTTP 403", "unauthorized" in output/stderr
  3. Fallback to REST API: Makes direct HTTP GET to api.github.com
  4. Apply jq Filter: Extracts specified JSON fields if provided
  5. Return Result: Returns output with flag indicating source (gh CLI or REST)

Function Signature

// Specialized for gh api commands only
ExecGHAPIWithRESTFallback(apiPath, jqFilter string) ([]byte, bool, error)

// Usage
output, fromREST, err := ExecGHAPIWithRESTFallback("/repos/actions/checkout/git/ref/tags/v4", ".object.sha")

The specialized signature makes it clear this function is only for GitHub API calls, removing the need for runtime validation of command type.

Limitations

  • Only supports GET requests (POST/PUT/DELETE require authentication)
  • Only simple jq filters (e.g., .object.sha, .name.nested.field)
  • Integration tests blocked by DNS proxy in sandboxed environments
  • Logs download not implemented (requires binary data + HTTP redirect handling)

Testing Notes

  • Unit tests: ✅ All pass
  • Build: ✅ Succeeds
  • Integration tests: Skip in restricted environments (DNS monitoring proxy)
  • Will work in normal environments with internet access to api.github.com
Original prompt

The codepath that attempts to execute "gh api" (through the exec helper) should fallback to an unauthenticated REST api call if the github token is not available.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 3 commits November 14, 2025 13:36
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
- Add ExecGHWithRESTFallback function that attempts gh CLI first, then falls back to direct REST API calls
- Implement callGitHubRESTAPI for unauthenticated GitHub API requests
- Implement applyJQFilter for basic jq-style field extraction
- Update action_resolver.go to use REST API fallback when resolving action SHAs
- Add comprehensive unit tests for jq filtering and fallback logic
- Add integration tests (skip in restricted environments)
- All existing tests continue to pass

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
- Change cmd.Output() to cmd.CombinedOutput() to capture gh CLI messages
- Check both combined output and stderr for authentication error indicators
- Add check for "GH_TOKEN" string in output (gh CLI's auth error message)
- Fix error return to use exitErr instead of err for consistency
- All unit tests pass

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

@copilot keep working

After merge with main, action_pins.json now contains 20 entries instead of 18. Updated TestGetActionPinsSorting to reflect the current count.

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

Copilot AI commented Nov 14, 2025

@copilot keep working

Fixed failing test after merge with main. All unit tests now pass ✅ (commit 14bee46)

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/actions/ai-inference/git/ref/tags/v1
    • Triggering command: /tmp/go-build1898445436/b307/cli.test -test.testlogfile=/tmp/go-build1898445436/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/08c6903cd8c0fde910a37f88322edcfb5dd907a8
    • Triggering command: /tmp/go-build1898445436/b329/workflow.test -test.testlogfile=/tmp/go-build1898445436/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build1485327318/b329/workflow.test -test.testlogfile=/tmp/go-build1485327318/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build3266486215/b329/workflow.test -test.testlogfile=/tmp/go-build3266486215/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v4
    • Triggering command: /tmp/go-build1898445436/b329/workflow.test -test.testlogfile=/tmp/go-build1898445436/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build1485327318/b329/workflow.test -test.testlogfile=/tmp/go-build1485327318/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build3266486215/b329/workflow.test -test.testlogfile=/tmp/go-build3266486215/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v5
    • Triggering command: /tmp/go-build1898445436/b329/workflow.test -test.testlogfile=/tmp/go-build1898445436/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build1898445436/b307/cli.test -test.testlogfile=/tmp/go-build1898445436/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build1485327318/b329/workflow.test -test.testlogfile=/tmp/go-build1485327318/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/complex/git/ref/tags/v1
    • Triggering command: /tmp/go-build1898445436/b329/workflow.test -test.testlogfile=/tmp/go-build1898445436/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build1485327318/b329/workflow.test -test.testlogfile=/tmp/go-build1485327318/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build3266486215/b329/workflow.test -test.testlogfile=/tmp/go-build3266486215/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/download-artifact/git/ref/tags/v6
    • Triggering command: /tmp/go-build1898445436/b307/cli.test -test.testlogfile=/tmp/go-build1898445436/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v8
    • Triggering command: /tmp/go-build1898445436/b307/cli.test -test.testlogfile=/tmp/go-build1898445436/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/d35c59abb061a4a6fb18e82ac0862c26744d6ab5
    • Triggering command: /tmp/go-build1898445436/b329/workflow.test -test.testlogfile=/tmp/go-build1898445436/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build1485327318/b329/workflow.test -test.testlogfile=/tmp/go-build1485327318/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build3266486215/b329/workflow.test -test.testlogfile=/tmp/go-build3266486215/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v5
    • Triggering command: /tmp/go-build1898445436/b307/cli.test -test.testlogfile=/tmp/go-build1898445436/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/2028fbc5c25fe9cf00d9f06a71cc4710d4507903
    • Triggering command: /tmp/go-build1898445436/b329/workflow.test -test.testlogfile=/tmp/go-build1898445436/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build1485327318/b329/workflow.test -test.testlogfile=/tmp/go-build1485327318/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build3266486215/b329/workflow.test -test.testlogfile=/tmp/go-build3266486215/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v6
    • Triggering command: /tmp/go-build1898445436/b307/cli.test -test.testlogfile=/tmp/go-build1898445436/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/setup-python/git/ref/tags/a26af69be951a213d495a4c3e4e4022e16d87065
    • Triggering command: /tmp/go-build1898445436/b329/workflow.test -test.testlogfile=/tmp/go-build1898445436/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build1485327318/b329/workflow.test -test.testlogfile=/tmp/go-build1485327318/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build3266486215/b329/workflow.test -test.testlogfile=/tmp/go-build3266486215/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/330a01c490aca151604b8cf639adc76d48f6c5d4
    • Triggering command: /tmp/go-build1898445436/b329/workflow.test -test.testlogfile=/tmp/go-build1898445436/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build1485327318/b329/workflow.test -test.testlogfile=/tmp/go-build1485327318/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build3266486215/b329/workflow.test -test.testlogfile=/tmp/go-build3266486215/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4
    • Triggering command: /tmp/go-build1898445436/b307/cli.test -test.testlogfile=/tmp/go-build1898445436/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v5
    • Triggering command: /tmp/go-build1898445436/b307/cli.test -test.testlogfile=/tmp/go-build1898445436/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/super-linter/super-linter/git/ref/tags/v8.2.1
    • Triggering command: /tmp/go-build1898445436/b307/cli.test -test.testlogfile=/tmp/go-build1898445436/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)

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

// Usage:
//
// output, fromREST, err := ExecGHWithRESTFallback("api", "/repos/actions/checkout/git/ref/tags/v4", "--jq", ".object.sha")
func ExecGHWithRESTFallback(args ...string) ([]byte, bool, error) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@copilot this helper only applies to gh api so specialize it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Specialized function for gh api commands only. Renamed to ExecGHAPIWithRESTFallback(apiPath, jqFilter) with explicit parameters instead of generic args. (commit 6d148ce)

Renamed to ExecGHAPIWithRESTFallback with specialized signature:
- Removed generic args parameter
- Now requires apiPath and jqFilter as explicit parameters
- Function signature makes it clear this is only for API calls
- Updated all usages in action_resolver.go and tests
- Removed obsolete tests for non-API commands
- All unit tests pass ✅

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

Copilot AI commented Nov 14, 2025

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

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/actions/ai-inference/git/ref/tags/v1
    • Triggering command: /tmp/go-build3107175252/b307/cli.test -test.testlogfile=/tmp/go-build3107175252/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/checkout
    • Triggering command: /tmp/go-build2056899332/b001/workflow.test -test.testlogfile=/tmp/go-build2056899332/b001/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=10s -test.run=TestExecGH|TestApplyJQ (http block)
    • Triggering command: /tmp/go-build3107175252/b329/workflow.test -test.testlogfile=/tmp/go-build3107175252/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/08c6903cd8c0fde910a37f88322edcfb5dd907a8
    • Triggering command: /tmp/go-build3107175252/b329/workflow.test -test.testlogfile=/tmp/go-build3107175252/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v4
    • Triggering command: /tmp/go-build3107175252/b329/workflow.test -test.testlogfile=/tmp/go-build3107175252/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v5
    • Triggering command: /tmp/go-build3107175252/b329/workflow.test -test.testlogfile=/tmp/go-build3107175252/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
    • Triggering command: /tmp/go-build3107175252/b307/cli.test -test.testlogfile=/tmp/go-build3107175252/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/complex/git/ref/tags/v1
    • Triggering command: /tmp/go-build3107175252/b329/workflow.test -test.testlogfile=/tmp/go-build3107175252/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/download-artifact/git/ref/tags/v6
    • Triggering command: /tmp/go-build3107175252/b307/cli.test -test.testlogfile=/tmp/go-build3107175252/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v8
    • Triggering command: /tmp/go-build3107175252/b307/cli.test -test.testlogfile=/tmp/go-build3107175252/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/d35c59abb061a4a6fb18e82ac0862c26744d6ab5
    • Triggering command: /tmp/go-build3107175252/b329/workflow.test -test.testlogfile=/tmp/go-build3107175252/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v5
    • Triggering command: /tmp/go-build3107175252/b307/cli.test -test.testlogfile=/tmp/go-build3107175252/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/2028fbc5c25fe9cf00d9f06a71cc4710d4507903
    • Triggering command: /tmp/go-build3107175252/b329/workflow.test -test.testlogfile=/tmp/go-build3107175252/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v6
    • Triggering command: /tmp/go-build3107175252/b307/cli.test -test.testlogfile=/tmp/go-build3107175252/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/setup-python/git/ref/tags/a26af69be951a213d495a4c3e4e4022e16d87065
    • Triggering command: /tmp/go-build3107175252/b329/workflow.test -test.testlogfile=/tmp/go-build3107175252/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/330a01c490aca151604b8cf639adc76d48f6c5d4
    • Triggering command: /tmp/go-build3107175252/b329/workflow.test -test.testlogfile=/tmp/go-build3107175252/b329/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4
    • Triggering command: /tmp/go-build3107175252/b307/cli.test -test.testlogfile=/tmp/go-build3107175252/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v5
    • Triggering command: /tmp/go-build3107175252/b307/cli.test -test.testlogfile=/tmp/go-build3107175252/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)
  • https://api.github.com/repos/super-linter/super-linter/git/ref/tags/v8.2.1
    • Triggering command: /tmp/go-build3107175252/b307/cli.test -test.testlogfile=/tmp/go-build3107175252/b307/testlog.txt -test.paniconexit0 -test.v=true -test.timeout=3m0s (http block)

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

Copilot AI requested a review from pelikhan November 14, 2025 16:46
@pelikhan pelikhan closed this Nov 14, 2025
@pelikhan pelikhan deleted the copilot/fallback-rest-api-call branch November 19, 2025 00:33
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