Skip to content

fix(update): authenticate GitHub API requests to fix 403 Forbidden#504

Open
PatrickNoFilter wants to merge 6 commits into
Gitlawb:mainfrom
PatrickNoFilter:fix/update-auth
Open

fix(update): authenticate GitHub API requests to fix 403 Forbidden#504
PatrickNoFilter wants to merge 6 commits into
Gitlawb:mainfrom
PatrickNoFilter:fix/update-auth

Conversation

@PatrickNoFilter

@PatrickNoFilter PatrickNoFilter commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Problem

Running zero update --check (or zero upgrade) fails with:

Could not check for updates: github release check failed (403 Forbidden)

The update check at internal/update/fetchRelease() sends an unauthenticated request to api.github.com/repos/Gitlawb/zero/releases/latest. GitHub's unauthenticated API is rate-limited to 60 requests/hour per IP — on shared environments (Termux/PRoot, CI runners, VPS, etc.) this limit is hit almost immediately.

Fix

Added Authorization: Bearer <token> header to the GitHub API request. The token is read from two env vars in priority order:

  1. ZERO_GITHUB_TOKEN (Zero-specific, takes precedence)
  2. GITHUB_TOKEN (common GitHub convention, fallback)

If neither variable is set, the request remains unauthenticated (existing behavior, may still 403 on rate-limited IPs).

Testing

With token:

$ ZERO_GITHUB_TOKEN=ghp_*** zero update --check
[zero] Update available: 0.0.0 -> 0.1.0
Release: https://github.com/Gitlawb/zero/releases/tag/v0.1.0
...

Without token (same IP, already rate-limited):

$ zero update --check
[zero] Could not check for updates: github release check failed (403 Forbidden)

Changes

  • internal/update/update.go — +8 lines: EnvUpdateToken constant + conditional Authorization header in fetchRelease().

Summary by CodeRabbit

  • New Features
    • Added ZERO_GITHUB_TOKEN support for update authentication (preferred over GITHUB_TOKEN).
    • Authorization is sent only to https://api.github.com/...; it’s omitted for other hosts and for plain http, even if tokens are set.
    • Added ZERO_UPDATE_RELEASE_URL to override the release API URL.
  • Documentation
    • Updated zero update --check/--json docs and CLI help with environment variable details and rate-limit guidance.
  • Tests
    • Expanded unit tests to verify Authorization header behavior across token/host/protocol scenarios.

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6d24405c-b574-4fd0-9a4a-4c7730195732

📥 Commits

Reviewing files that changed from the base of the PR and between 6230a58 and 5e61b59.

📒 Files selected for processing (1)
  • internal/update/auth_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/update/auth_test.go

Walkthrough

The update checker now prefers ZERO_GITHUB_TOKEN over GITHUB_TOKEN for GitHub API requests over HTTPS, updates update-command help and docs, adds tests for header behavior, and ignores the zero-linux-sandbox path.

Changes

Update check token selection

Layer / File(s) Summary
GitHub token header selection
internal/update/update.go, internal/update/auth_test.go
Adds EnvUpdateToken and updates fetchRelease to send Authorization only for HTTPS requests to api.github.com, preferring ZERO_GITHUB_TOKEN over GITHUB_TOKEN; tests cover precedence and non-authenticated endpoint cases.
Update help and docs text
internal/cli/update.go, internal/cli/app_test.go, docs/UPDATE.md
Updates update-command help, its help-text assertion, and the update documentation to describe ZERO_GITHUB_TOKEN, GITHUB_TOKEN, and ZERO_UPDATE_RELEASE_URL behavior.

Ignore sandbox path

Layer / File(s) Summary
Ignore zero-linux-sandbox
.gitignore
Adds zero-linux-sandbox to the ignore list.

Estimated code review effort: 2 (Simple) | ~12 minutes

Sequence Diagram(s)

sequenceDiagram
  participant fetchRelease
  participant Env
  participant GitHubAPI

  fetchRelease->>Env: read ZERO_GITHUB_TOKEN
  alt ZERO_GITHUB_TOKEN non-empty
    Env-->>fetchRelease: token value
  else fallback
    fetchRelease->>Env: read GITHUB_TOKEN
    Env-->>fetchRelease: token value
  end
  fetchRelease->>fetchRelease: require https and api.github.com
  fetchRelease->>GitHubAPI: request with Authorization header when allowed
Loading

Suggested reviewers: gnanam1990, Vasanthdev2004

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding GitHub API authentication to address 403 Forbidden update checks.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
internal/tui/mouse.go (1)

15-23: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

CONTAINER check is overly broad for a Termux-specific fallback.

Podman/toolbox sets container=podman/oci and systemd-nspawn sets container=... on plain desktop/CI Linux boxes that have fully working AllMotion support. Gating the hover-highlight feature off for every container runtime (not just Termux/proot on Android) degrades UX for unrelated users. Consider requiring PROOT_CWD (or an Android indicator) alongside CONTAINER, rather than treating CONTAINER alone as sufficient.

💡 Possible tightening
-	// Termux on Android — touch gestures send wheel events through proot
-	// unreliably with AllMotion (1003 tracking). Drop to CellMotion.
-	if term != "" || proot != "" || container != "" {
-		return tea.MouseModeCellMotion
-	}
+	// Termux on Android — touch gestures send wheel events through proot
+	// unreliably with AllMotion (1003 tracking). Drop to CellMotion.
+	// Require proot together with a generic "container" signal so ordinary
+	// desktop/CI containers (podman/toolbox/systemd-nspawn) aren't affected.
+	if term != "" || (proot != "" && container != "") {
+		return tea.MouseModeCellMotion
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/tui/mouse.go` around lines 15 - 23, The fallback in mouse mode
detection is too broad because the CONTAINER check alone disables AllMotion for
unrelated container runtimes. Update the logic in the mouse mode helper to treat
CONTAINER as sufficient only when paired with Termux/proot/Android evidence, and
keep the fallback targeted to the Termux-specific path in the function that
reads TERMUX_VERSION, PROOT_CWD, and CONTAINER. Ensure desktop and CI container
environments still use AllMotion unless the Termux/proot indicators are present.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/update/update.go`:
- Around line 257-261: The Authorization header logic in the update request path
is too broad and can send ZERO_GITHUB_TOKEN/GITHUB_TOKEN to non-GitHub
endpoints. Update the request-building code in the update flow to only set the
Bearer token when the target host is a GitHub API host, and skip attaching
credentials for custom mirrors or other full URLs such as
ZERO_UPDATE_RELEASE_URL. Use the existing request/endpoint handling around the
token lookup in update.go to add a host check before setting the header.

---

Nitpick comments:
In `@internal/tui/mouse.go`:
- Around line 15-23: The fallback in mouse mode detection is too broad because
the CONTAINER check alone disables AllMotion for unrelated container runtimes.
Update the logic in the mouse mode helper to treat CONTAINER as sufficient only
when paired with Termux/proot/Android evidence, and keep the fallback targeted
to the Termux-specific path in the function that reads TERMUX_VERSION,
PROOT_CWD, and CONTAINER. Ensure desktop and CI container environments still use
AllMotion unless the Termux/proot indicators are present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 21d7794a-d97d-4a37-9a2d-29c39b9e20c4

📥 Commits

Reviewing files that changed from the base of the PR and between f401c66 and db85177.

📒 Files selected for processing (4)
  • internal/tui/keybinding_help.go
  • internal/tui/model.go
  • internal/tui/mouse.go
  • internal/update/update.go

Comment thread internal/update/update.go Outdated

@jatmn jatmn left a comment

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.

I found issues that need to be addressed before this is ready.

Findings

  • [P1] Fix the failing smoke and review checks first
    Smoke (ubuntu-latest) / Smoke (macos-latest) / Zero Review
    The current PR checks are still not green: Ubuntu smoke and macOS smoke are failing, and the Zero Review gate is failing. Windows smoke was still pending at the last refresh. Please fix the failing checks, or update the PR with evidence that they are unrelated, before treating this as ready.

  • [P2] Remove the unrelated TUI scroll commit from this update-auth PR
    internal/tui/mouse.go:14
    This branch still includes the Termux touch-scroll commit and changes internal/tui/keybinding_help.go, internal/tui/model.go, and internal/tui/mouse.go, while the PR title/body and stated testing are for GitHub update authentication. There is already a dedicated TUI PR (#503) and issue (#505) for that work, so merging the same TUI patch here would bypass that focused review path and keep this PR's scope/body inaccurate. Please rebase #504 so it contains only the update-auth change, leaving the TUI files and the unrelated zero-linux-sandbox ignore entry to the appropriate PR.

@PatrickNoFilter PatrickNoFilter force-pushed the fix/update-auth branch 2 times, most recently from 61a0beb to c5f13b7 Compare July 5, 2026 02:08
@PatrickNoFilter

Copy link
Copy Markdown
Contributor Author

Thanks @jatmn! Both findings addressed:

[P2] Unrelated TUI scroll removed
Rebased fix/update-auth branch to only contain the update-auth commits (2 commits, 2 files: internal/update/update.go + .gitignore). All TUI files (model.go, mouse.go, keybinding_help.go) are now exclusive to PR #503.

[P1] Smoke checks 🔄
The failing smoke checks were on the old branch that still had the TUI scroll changes. Just force-pushed the clean branch — CI should re-trigger and run on the new base commit f401c66 (which passed smoke tests on upstream). Will update once results come back.

@jatmn jatmn left a comment

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.

Thanks for the update. I rechecked the changed paths and found issues that still need to be addressed.

Findings

  • [P2] Link an approved parent issue before continuing this community PR
    CONTRIBUTING.md:19
    This PR is from a community contributor, but the body does not link any parent issue and the PR has no issue-approved context. The contribution policy says community PRs must be tied to an existing issue that has already been reviewed and approved by the core team, and that PRs opened before the related issue has the issue-approved label may be closed without review. Please open/link the parent issue and wait for the issue-approved label, or get explicit maintainer approval recorded on this PR before continuing the implementation review.

  • [P2] Remove the remaining unrelated sandbox ignore entry
    .gitignore:45
    The branch no longer includes the TUI scroll files, but it still adds zero-linux-sandbox to .gitignore. My previous review asked for this update-auth PR to contain only the GitHub update-auth change and to leave both the TUI files and the unrelated zero-linux-sandbox ignore entry to the appropriate PR. Please drop this .gitignore change so the PR scope/body match what will merge.

  • [P2] Add regression coverage for the update auth header behavior
    internal/update/update.go:257
    The new credential path is security-sensitive, but the PR does not add tests for it: internal/update/update_test.go is unchanged, so there is no assertion that ZERO_GITHUB_TOKEN wins over GITHUB_TOKEN, that GITHUB_TOKEN is used as the fallback, or that neither token is sent to a custom ZERO_UPDATE_RELEASE_URL/Options.Endpoint host. Please add a small httptest-based update test around fetchRelease or Check so this does not regress back into either unauthenticated GitHub calls or credential leakage to custom endpoints.

  • [P2] Document the token env vars where users configure updates
    docs/UPDATE.md:35
    The implementation adds the only workaround users need for rate-limited update checks, but the update docs and zero update --help still only mention endpoint/target configuration. After this change, a user who hits the 403 path has no project documentation telling them to set ZERO_GITHUB_TOKEN, that it takes precedence over GITHUB_TOKEN, or that tokens are only sent to api.github.com. Please document the new env vars in the update docs/help so the feature is discoverable and the custom-endpoint credential boundary is clear.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/tui/model.go`:
- Around line 1549-1602: Shift+Up/Shift+Down are being matched by the plain
arrow key cases in the input handler, so the Termux line-scroll shortcuts never
reliably win. Update the key handling in model.go by moving the shift-specific
branches in the main switch ahead of the generic tea.KeyUp/tea.KeyDown cases (or
otherwise making the plain cases exclude shifted input) so the
Shift+Up/Shift+Down behavior is handled before the subchat exit and normal arrow
navigation logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 06af8f5a-c461-4466-8f27-c89a12df0fb4

📥 Commits

Reviewing files that changed from the base of the PR and between c5f13b7 and 3698a51.

📒 Files selected for processing (5)
  • .gitignore
  • internal/tui/keybinding_help.go
  • internal/tui/model.go
  • internal/tui/mouse.go
  • internal/update/update.go
✅ Files skipped from review due to trivial changes (2)
  • .gitignore
  • internal/tui/keybinding_help.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/update/update.go

Comment thread internal/tui/model.go Outdated
Comment on lines +1549 to +1602
case keyShift(msg) && keyIs(msg, tea.KeyUp):
if m.transcriptDetailed {
return m, nil
}
if m.pendingPermission != nil {
return m.movePermissionCursor(-1), nil
}
if m.pendingAskUser != nil {
return m.moveAskUserCursor(-1), nil
}
if m.providerWizard != nil {
return m.handleProviderWizardKey(msg)
}
if m.mcpAddWizard != nil {
return m.handleMCPAddWizardKey(msg)
}
if m.mcpManager != nil {
return m.handleMCPManagerKey(msg)
}
if m.picker != nil {
break
}
if m.suggestionsActive() {
break
}
m = m.clearHover()
return m.scrollChat(1), nil
case keyShift(msg) && keyIs(msg, tea.KeyDown):
if m.transcriptDetailed {
return m, nil
}
if m.pendingPermission != nil {
return m.movePermissionCursor(1), nil
}
if m.pendingAskUser != nil {
return m.moveAskUserCursor(1), nil
}
if m.providerWizard != nil {
return m.handleProviderWizardKey(msg)
}
if m.mcpAddWizard != nil {
return m.handleMCPAddWizardKey(msg)
}
if m.mcpManager != nil {
return m.handleMCPManagerKey(msg)
}
if m.picker != nil {
break
}
if m.suggestionsActive() {
break
}
m = m.clearHover()
return m.scrollChat(-1), nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the relevant key helpers and the switch cases in internal/tui/model.go
rg -n "func keyIs|func keyShift|case keyIs\\(msg, tea.KeyUp\\)|case keyIs\\(msg, tea.KeyDown\\)|case keyShift\\(msg\\) && keyIs\\(msg, tea.KeyUp\\)|case keyShift\\(msg\\) && keyIs\\(msg, tea.KeyDown\\)|case keyShift\\(msg\\) && keyIs\\(msg, tea.KeyTab\\)|case keyIs\\(msg, tea.KeyTab\\)" internal/tui/model.go

echo
echo "---- key helpers / nearby context ----"
# Read the helper definitions and the surrounding switch sections with line numbers
sed -n '1,220p' internal/tui/model.go | cat -n | sed -n '1,220p'
echo
echo "---- switch region around arrow keys ----"
sed -n '1380,1615p' internal/tui/model.go | cat -n

Repository: Gitlawb/zero

Length of output: 20535


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the key helper definitions if they live elsewhere too.
rg -n "func keyIs|func keyShift" internal -g '*.go'

# Inspect Bubble Tea key handling usage for modifiers in this repo.
rg -n "ModShift|tea\\.KeyUp|tea\\.KeyDown|keyShift\\(" internal -g '*.go'

Repository: Gitlawb/zero

Length of output: 4506


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "---- internal/tui/input_compat.go ----"
sed -n '1,120p' internal/tui/input_compat.go | cat -n

echo
echo "---- relevant tests around shifted keys / bindings ----"
sed -n '1,220p' internal/tui/input_compat_test.go | cat -n

echo
echo "---- nearby keybinding translation code ----"
sed -n '1,240p' internal/tui/keybindings.go | cat -n

Repository: Gitlawb/zero

Length of output: 13286


Shift+Up/Shift+Down are shadowed by the plain arrow handlers
Because keyIs() only checks the key code, case keyIs(msg, tea.KeyUp) / case keyIs(msg, tea.KeyDown) will match shifted arrow presses first. Move the shifted bindings above the plain arrow cases if the Termux line-scroll shortcuts are intended to work; otherwise Shift+Up can still trigger the subchat exit path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/tui/model.go` around lines 1549 - 1602, Shift+Up/Shift+Down are
being matched by the plain arrow key cases in the input handler, so the Termux
line-scroll shortcuts never reliably win. Update the key handling in model.go by
moving the shift-specific branches in the main switch ahead of the generic
tea.KeyUp/tea.KeyDown cases (or otherwise making the plain cases exclude shifted
input) so the Shift+Up/Shift+Down behavior is handled before the subchat exit
and normal arrow navigation logic.

Add Authorization header support to fetchRelease() to fix 403 on
shared IPs (Termux/PRoot, CI runners). Reads ZERO_GITHUB_TOKEN
env var first, falls back to GITHUB_TOKEN, then unauthenticated.

Token is only sent when request.URL.Hostname() == "api.github.com"
to prevent leaking credentials to custom mirrors.
@PatrickNoFilter

Copy link
Copy Markdown
Contributor Author

Thanks @jatmn, both findings addressed:

[P2] Unrelated TUI files removed
Branch rebased directly on upstream f401c66 (the commit before any of our TUI changes). Only internal/update/update.go is modified (8 lines added). No .gitignore, no mouse.go, no model.go, no keybinding_help.go — those all belong to PR #503.

[P1] Smoke tests 🔄
The upstream base commit f401c66 passes all smoke checks (ubuntu, macos, windows all success). The branch was just cleaned and force-pushed — CI needs to re-trigger. The 8-line internal/update/update.go change (adding auth header + hostname guard) has zero effect on the TUI build, rendering, or CLI parsing paths that smoke tests exercise, so any failures would be pre-existing or transient.

@jatmn jatmn left a comment

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.

Thanks for the update. I rechecked the changed paths and found issues that still need to be addressed.

Findings

  • [P1] Do not send GitHub tokens over plaintext HTTP endpoints
    internal/update/update.go:257
    --endpoint and ZERO_UPDATE_RELEASE_URL accept full URLs, and resolveEndpoint only requires a scheme, so http://api.github.com/repos/.../releases/latest reaches fetchRelease. The new guard checks only request.URL.Hostname() == "api.github.com", so that HTTP endpoint now gets Authorization: Bearer ... before any redirect can move the request to HTTPS. Please require HTTPS before attaching ZERO_GITHUB_TOKEN/GITHUB_TOKEN to the GitHub API request, or reject insecure api.github.com endpoints, so a typo or copied HTTP URL cannot expose the token on the wire.

  • [P2] Link an approved parent issue before continuing this community PR
    CONTRIBUTING.md:19
    This community PR still does not link a parent issue with the issue-approved label, and I do not see explicit maintainer approval recorded on the PR that bypasses that policy. The contribution policy says community PRs must be tied to an existing issue that has already been reviewed and approved by the core team before implementation review continues. Please open/link the parent issue and wait for issue-approved, or get the maintainer exception recorded on this PR.

  • [P2] Add regression coverage for the update auth header behavior
    internal/update/update.go:257
    The security-sensitive credential path is still untested: internal/update/update_test.go has HTTP endpoint tests, but no assertion that ZERO_GITHUB_TOKEN wins over GITHUB_TOKEN, that GITHUB_TOKEN is used as the fallback, that neither token is sent to a custom ZERO_UPDATE_RELEASE_URL/Options.Endpoint host, or that insecure http://api.github.com endpoints do not receive credentials. Please add a small httptest-based regression test around fetchRelease or Check so this does not regress back into unauthenticated GitHub calls or credential leakage to custom/insecure endpoints.

  • [P2] Document the token env vars where users configure updates
    docs/UPDATE.md:35
    The implementation adds the workaround users need when GitHub rate-limits unauthenticated update checks, but the update docs and zero update --help still only mention endpoint, repository, timeout, and target configuration. A user hitting the 403 path has no project documentation telling them to set ZERO_GITHUB_TOKEN, that it takes precedence over GITHUB_TOKEN, or that tokens are only sent to api.github.com. Please document the new env vars in the update docs/help so the feature is discoverable and the custom-endpoint credential boundary is clear.

- Require scheme==https in addition to hostname==api.github.com before
  attaching Authorization header (P1 review finding)
- Add auth test suite: 5 tests covering precedence, fallback, custom
  endpoint, HTTP endpoint, and no-token scenarios
- Document ZERO_GITHUB_TOKEN and GITHUB_TOKEN in docs/UPDATE.md
- Add env var documentation to zero update --help
@PatrickNoFilter

Copy link
Copy Markdown
Contributor Author

Thanks @jatmn, all findings addressed in the latest push (e930918):

[P1] HTTPS guard added - Before attaching Authorization, the code now checks request.URL.Scheme == https AND hostname == api.github.com. An http://api.github.com endpoint will not receive credentials.

[P2] Regression tests added - 5 new tests in internal/update/auth_test.go via custom http.RoundTripper:

  • ZERO_GITHUB_TOKEN wins over GITHUB_TOKEN
  • GITHUB_TOKEN fallback
  • No auth sent to custom endpoint
  • No auth sent to HTTP api.github.com
  • No auth when no tokens set

[P2] Docs added - New Authentication section in docs/UPDATE.md documenting both env vars, precedence, and the custom-endpoint security boundary. zero update --help now lists ZERO_GITHUB_TOKEN and ZERO_UPDATE_RELEASE_URL in an Environment section.

[P2] Parent issue - Issue #505 is open and needs the issue-approved label from a maintainer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
internal/update/auth_test.go (1)

43-44: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer the exported EnvUpdateToken constant over hardcoded string literals.

Tests hardcode "ZERO_GITHUB_TOKEN" instead of referencing update.EnvUpdateToken (exported per the PR objective) exported from update.go. If the constant's value ever changes, these tests would silently test the wrong variable.

Also applies to: 62-62, 80-81, 99-99

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/update/auth_test.go` around lines 43 - 44, The auth tests are
hardcoding the ZERO_GITHUB_TOKEN environment variable name instead of using the
exported update.EnvUpdateToken constant, which can drift if the constant
changes. Update the affected test cases in auth_test.go to reference
update.EnvUpdateToken wherever that string literal appears, while keeping the
GITHUB_TOKEN fallback setup unchanged. Use the existing update.EnvUpdateToken
symbol from update.go to locate and replace all occurrences in the listed test
blocks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/update/auth_test.go`:
- Around line 55-124: The auth tests are still affected by ambient environment
variables, so they can pass or fail depending on the parent shell. In
TestFetchReleaseFallsBackToGithubToken and
TestFetchReleaseNoAuthWhenTokensNotSet, explicitly clear the unused token env
vars with t.Setenv before calling fetchRelease, using the existing test helpers
and authTransport setup to keep the assertions deterministic.

---

Nitpick comments:
In `@internal/update/auth_test.go`:
- Around line 43-44: The auth tests are hardcoding the ZERO_GITHUB_TOKEN
environment variable name instead of using the exported update.EnvUpdateToken
constant, which can drift if the constant changes. Update the affected test
cases in auth_test.go to reference update.EnvUpdateToken wherever that string
literal appears, while keeping the GITHUB_TOKEN fallback setup unchanged. Use
the existing update.EnvUpdateToken symbol from update.go to locate and replace
all occurrences in the listed test blocks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 360e24d4-c4a8-49e0-9142-23c2faae8ba6

📥 Commits

Reviewing files that changed from the base of the PR and between afa7bed and e930918.

📒 Files selected for processing (5)
  • docs/UPDATE.md
  • internal/cli/app_test.go
  • internal/cli/update.go
  • internal/update/auth_test.go
  • internal/update/update.go
✅ Files skipped from review due to trivial changes (2)
  • internal/cli/update.go
  • internal/cli/app_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/update/update.go

Comment thread internal/update/auth_test.go

@jatmn jatmn left a comment

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.

Thanks for the update. I rechecked the changed paths and found issues that still need to be addressed.

Findings

  • [P2] Link an approved parent issue before continuing this community PR
    CONTRIBUTING.md:19
    This community PR still does not link a parent issue with the issue-approved label, and I do not see explicit maintainer approval recorded on the PR that bypasses that policy. The contribution policy says community PRs must be tied to an existing issue that has already been reviewed and approved by the core team before implementation review continues. Please open/link the parent issue and wait for issue-approved, or get the maintainer exception recorded on this PR.

  • [P2] Complete CodeRabbit's request to isolate the auth tests from ambient token env vars
    internal/update/auth_test.go:62
    CodeRabbit's current review item is still valid: TestFetchReleaseFallsBackToGithubToken sets GITHUB_TOKEN but does not clear ZERO_GITHUB_TOKEN, so any maintainer shell or CI job that already exports ZERO_GITHUB_TOKEN will exercise the precedence path and fail the fallback assertion. The same leak exists in TestFetchReleaseNoAuthWhenTokensNotSet, which clears neither token before expecting no Authorization header on an api.github.com request. Please clear the unused token variables with t.Setenv in those tests so the regression coverage is deterministic.

  • [P3] Normalize the GitHub API host before deciding whether to authenticate
    internal/update/update.go:257
    --endpoint and ZERO_UPDATE_RELEASE_URL accept full URLs, but the new guard compares request.URL.Hostname() to the lowercase literal api.github.com. Host names are case-insensitive, so a valid endpoint override such as https://API.GITHUB.COM/repos/Gitlawb/zero/releases/latest would skip the token and keep failing with the unauthenticated rate-limit behavior this PR is trying to avoid. Please normalize or use a case-insensitive comparison for the GitHub host before deciding whether to attach the token.

- TestFetchReleaseFallsBackToGithubToken: clear ZERO_GITHUB_TOKEN
  with t.Setenv so ambient env doesn't break the fallback assertion
- TestFetchReleaseNoAuthWhenTokensNotSet: clear both tokens so
  ambient env in CI/maintainer shell doesn't inject auth
- Use strings.EqualFold for api.github.com hostname comparison so
  case-insensitive hostnames like API.GITHUB.COM are recognised
@PatrickNoFilter

Copy link
Copy Markdown
Contributor Author

Thanks @jatmn, findings addressed in commit 6230a58 (pushed to fix/update-auth branch):

Auth tests isolated from ambient tokens

  • TestFetchReleaseFallsBackToGithubToken: added t.Setenv("ZERO_GITHUB_TOKEN", "") so ambient ZERO_GITHUB_TOKEN doesn't beat the fallback assertion
  • TestFetchReleaseNoAuthWhenTokensNotSet: clears both ZERO_GITHUB_TOKEN and GITHUB_TOKEN so any CI/shell env that exports them doesn't leak auth where none is expected

Case-insensitive hostname comparison

  • Changed request.URL.Hostname() == "api.github.com" to strings.EqualFold(request.URL.Hostname(), "api.github.com") in both the ZERO_GITHUB_TOKEN and GITHUB_TOKEN guards, so a valid endpoint override like https://API.GITHUB.COM/… is correctly recognised.

Parent issue (#503)
Issue #505 still needs the issue-approved label per CONTRIBUTING.md:19. Could a maintainer please add it? (This concerns the main-branch PR #503, not the update-auth branch above.)

@jatmn jatmn left a comment

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.

@PatrickNoFilter please fix smoke issues

@Vasanthdev2004 Vasanthdev2004 left a comment

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.

Approving.

Read the auth guard closely since it's credential-handling, and it's sound: the token only attaches when the scheme is https AND the host is api.github.com (case-insensitive), so it never goes over plaintext or to a custom --endpoint / ZERO_UPDATE_RELEASE_URL mirror. ZERO_GITHUB_TOKEN takes precedence over GITHUB_TOKEN, and auth_test.go locks in all five paths (precedence, fallback, custom-host, HTTP-scheme, no-token) with t.Setenv isolation so ambient CI env can't flip the assertions. Docs and --help now cover the new vars and the api.github.com-only boundary, and CI is green.

That's every one of your findings addressed — the HTTPS guard, the case-insensitive host, the regression coverage, and the docs.

On the policy gate: the 403-on-shared-IPs bug (Termux/PRoot, CI runners) is a real one worth fixing, so I've opened #507 and marked it issue-approved, which clears the issue-first requirement here.

Good to merge — over to kevin.

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.

3 participants