diff --git a/bin/install-latest.sh b/bin/install-latest.sh index 56da8437..47a3ed19 100755 --- a/bin/install-latest.sh +++ b/bin/install-latest.sh @@ -9,6 +9,12 @@ case "${ARCH}" in aarch64) ARCH="arm64" ;; esac +# GitHub API token: GITHUB_TOKEN env, else gh auth token. +GITHUB_TOKEN="${GITHUB_TOKEN:-}" +if [ -z "${GITHUB_TOKEN}" ] && command -v gh >/dev/null 2>&1; then + GITHUB_TOKEN="$(gh auth token 2>/dev/null || true)" +fi + # Fetch release metadata from GitHub API API_RESPONSE="$(curl -sf ${GITHUB_TOKEN:+-H "Authorization: token ${GITHUB_TOKEN}"} https://api.github.com/repos/brevdev/brev-cli/releases/latest)" || { echo "Error: Failed to fetch release info from GitHub API." >&2 diff --git a/pkg/cmd/agentskill/agentskill.go b/pkg/cmd/agentskill/agentskill.go index 4153ff8d..2496aa81 100644 --- a/pkg/cmd/agentskill/agentskill.go +++ b/pkg/cmd/agentskill/agentskill.go @@ -11,6 +11,7 @@ import ( "time" breverrors "github.com/brevdev/brev-cli/pkg/errors" + "github.com/brevdev/brev-cli/pkg/store" "github.com/brevdev/brev-cli/pkg/terminal" "github.com/spf13/cobra" ) @@ -58,6 +59,9 @@ func resolveCommitSHA(client *http.Client, ref string) (string, error) { return "", breverrors.WrapAndTrace(err) } req.Header.Set("Accept", "application/vnd.github.v3+json") + if token := store.GitHubAPIToken(); token != "" { + req.Header.Set("Authorization", "token "+token) + } resp, err := client.Do(req) //nolint:bodyclose // closed below if err != nil { diff --git a/pkg/store/release.go b/pkg/store/release.go index 657140a9..5e000902 100644 --- a/pkg/store/release.go +++ b/pkg/store/release.go @@ -1,6 +1,12 @@ package store import ( + "context" + "os" + "os/exec" + "strings" + "time" + breverrors "github.com/brevdev/brev-cli/pkg/errors" "github.com/go-resty/resty/v2" ) @@ -14,15 +20,36 @@ type GithubReleaseMetadata struct { } const ( - cliReleaseURL = "https://api.github.com/repos/brevdev/brev-cli/releases/latest" + cliReleaseURL = "https://api.github.com/repos/brevdev/brev-cli/releases/latest" + ghAuthTokenTimeout = 60 * time.Second ) +// GitHubAPIToken returns GITHUB_TOKEN from the environment, or "gh auth token" with a timeout. +func GitHubAPIToken() string { + if token := strings.TrimSpace(os.Getenv("GITHUB_TOKEN")); token != "" { + return token + } + + ctx, cancel := context.WithTimeout(context.Background(), ghAuthTokenTimeout) + defer cancel() + + out, err := exec.CommandContext(ctx, "gh", "auth", "token").Output() //nolint:gosec // intentional gh probe + if err != nil { + return "" + } + return strings.TrimSpace(string(out)) +} + func (n NoAuthHTTPStore) GetLatestReleaseMetadata() (*GithubReleaseMetadata, error) { var result GithubReleaseMetadata client := resty.New() + req := client.R().SetResult(&result) + if token := GitHubAPIToken(); token != "" { + req.SetHeader("Authorization", "token "+token) + } - res, err := client.R().SetResult(&result).Get(cliReleaseURL) + res, err := req.Get(cliReleaseURL) if err != nil { return nil, breverrors.WrapAndTrace(err) } diff --git a/scripts/install-agent-skill.sh b/scripts/install-agent-skill.sh index 247a64ca..648a1b4b 100755 --- a/scripts/install-agent-skill.sh +++ b/scripts/install-agent-skill.sh @@ -13,6 +13,12 @@ set -e +# GitHub API token: GITHUB_TOKEN env, else gh auth token. +GITHUB_TOKEN="${GITHUB_TOKEN:-}" +if [ -z "${GITHUB_TOKEN}" ] && command -v gh >/dev/null 2>&1; then + GITHUB_TOKEN="$(gh auth token 2>/dev/null || true)" +fi + # Configuration REPO="brevdev/brev-cli" BRANCH="main" @@ -116,7 +122,7 @@ done rm -rf "$TMPDIR" # Resolve commit SHA and write .version file -VERSION_RESPONSE=$(curl -fsSL "https://api.github.com/repos/$REPO/commits/$BRANCH" 2>&1) || true +VERSION_RESPONSE=$(curl -fsSL ${GITHUB_TOKEN:+-H "Authorization: token ${GITHUB_TOKEN}"} "https://api.github.com/repos/$REPO/commits/$BRANCH" 2>&1) || true if echo "$VERSION_RESPONSE" | grep -q "API rate limit exceeded"; then echo -e " ${YELLOW}⚠${NC} .version (skipped — GitHub API rate limit exceeded)" echo -e " ${YELLOW}If you are using a VPN, try turning it off and running this script again.${NC}"