Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,14 @@ Retry logic for GitHub API rate limiting: 10 attempts with linear additive backo

`AuthHeaderCache` provides thread-safe per-origin auth header caching (modeled after `RateLimitCoordinator`). `get_origin()` normalizes URL variants (GitHub web/raw/API, GitLab web/API) to a single cache key. A single instance is created in `main()` and shared across both the validation phase (`FileValidator`) and all download functions, so auth discovered during validation is reused during downloads. The first request per origin probes unauthenticated; on auth resolution, subsequent requests for the same origin skip the probe. `resolve_and_cache()` uses double-checked locking for thread safety. `_fetch_url_core()` (DRY refactor of the former near-duplicate `fetch_url_with_auth`/`fetch_url_bytes_with_auth`) implements auth resolution priority: explicit `auth_headers` param > `auth_cache` hit > unauthenticated probe with cache population. GitHub API transport headers (`Accept: application/vnd.github.raw+json`, `X-GitHub-Api-Version`) are managed independently from cached auth headers via `github_api_headers` dict and `_build_request()` helper in `_fetch_url_core()`, applied to every `Request` construction in `_do_fetch()` when `'api.github.com' in url`.

**Lazy-auth invariant (validation + download parity):** Both `FileValidator.validate_remote_url` and `_fetch_url_core._do_fetch` MUST honor the "try unauthenticated first; escalate to authentication only on HTTP 401, 403, or 404" contract. Non-auth failures (SSL, DNS, 5xx, timeout, 416 Range Not Satisfiable) MUST NOT trigger auth prompts. Successful unauthenticated probes cache a `None` sentinel in `AuthHeaderCache` for downstream consumers. When `auth_cache` is available, route escalation through `AuthHeaderCache.resolve_and_cache(url)` (double-checked locking) to serialize prompts across parallel validation threads. Helper functions `_check_with_head` and `_check_with_range` return `tuple[bool, int | None]` where the second element is the HTTP status code (or `None` for non-HTTP failures) used to gate the escalation decision.

**Authentication SRP:** `get_auth_headers(url, auth_param)` is a thin orchestrator that delegates to `resolve_credentials(url, auth_param)` (pure, non-interactive -- reads CLI param + env vars only) and then escalates to `prompt_for_credentials(url, tokens_checked=[...])` (interactive, guarded by `sys.stdin.isatty()`). The split is transparent to existing callers (`get_auth_headers` preserves its original signature and behavior), but enables non-interactive callers to opt into credential resolution without risking user prompts. The interactive prompt uses the wording `Authentication required for {url}` (both the `warning(...)` on interactive terminals and the `info(...)` fallback on non-interactive terminals emit this URL-qualified message); the earlier `Private {RepoType} repository detected but no authentication found` wording has been removed.

**Repository type classification (`detect_repo_type`):** Uses hostname-based matching via `urllib.parse.urlparse`. GitHub Pages URLs (hostname ending in `.github.io`) are explicitly classified as `None` (not `'github'`) because GitHub Pages sites are static HTTP hosts with no repository auth model. `github.com`, `raw.githubusercontent.com`, and `api.github.com` are classified as `'github'`. GitLab classification uses both hostname substring (`'gitlab' in host`) and the API path marker (`/api/v4/projects/`).

**GitHub 404 disambiguation (UX polish):** When a GitHub URL returns HTTP 404 during validation, before escalating to an auth prompt, the validator probes `GET https://api.github.com/repos/{owner}/{repo}` unauthenticated. If the repo endpoint returns 200, the original 404 is classified as a **genuine missing file** (typo) and the auth prompt is skipped (returns failure directly). If the repo endpoint returns 404 (private-hidden or nonexistent -- GitHub does not distinguish), the validator conservatively escalates to the auth prompt. Rate-limiting or network errors from the repo probe also trigger conservative escalation. The `/contents/{path}` endpoint intentionally cannot distinguish private-hidden from missing, which is why `/repos/{owner}/{repo}` is used instead.

### Hooks Configuration Structure

Hooks support four types matching the official Claude Code hooks specification:
Expand Down
2 changes: 2 additions & 0 deletions docs/environment-configuration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -1533,6 +1533,8 @@ Authentication is resolved in this order (highest priority first):
- GitLab web URLs (`/-/raw/`) are automatically converted to API format
- GitHub raw URLs are automatically converted to API URLs
- Public access is attempted first; authentication is applied only on 401/403/404 responses
- GitHub Pages URLs (`*.github.io`) are never treated as repository URLs -- no auth prompt is issued for them even on 404 responses
- For GitHub 404 responses, the setup script probes `api.github.com/repos/{owner}/{repo}` unauthenticated to distinguish missing files in public repositories (no auth prompt) from private or nonexistent repositories (auth prompt)

### Automatic Auto-Update Management

Expand Down
Loading
Loading