Pascal THUET
5601830ba3
harden: bound HTTP reads and enforce strict redirects ( #3140 )
...
* harden: bound HTTP reads and enforce strict redirects
Add a shared _download_security module (read_response_limited,
is_https_or_localhost_http, size constants) and route the GitHub release
and Azure DevOps token network reads through bounded reads so an oversized
response can't exhaust memory.
Add a strict_redirects mode to authentication.open_url: the redirect handler
now rejects any redirect whose target isn't HTTPS (or HTTP to localhost),
composing with the existing per-hop redirect_validator and auth-stripping.
The Azure DevOps token POST is routed through that handler so a 307/308
cannot forward the client_secret body to a non-HTTPS host.
Assisted-by: Codex (model: GPT-5, autonomous)
* test: align HTTP fakes with bounded reads
Assisted-by: Codex (model: GPT-5, autonomous)
* fix: tolerate invalid token response encoding
Assisted-by: Codex (model: GPT-5, autonomous)
* test: align GHES fakes with bounded reads
Assisted-by: Codex (model: GPT-5, autonomous)
* test: reuse shared upgrade HTTP response helper
Assisted-by: Codex (model: GPT-5, autonomous)
* fix: include rejected redirect target in error
Assisted-by: Codex (model: GPT-5, autonomous)
* fix: enforce strict redirects by default
Assisted-by: Codex (model: GPT-5, autonomous)
* fix: close redirect credential and SSRF gaps
Assisted-by: Codex (model: GPT-5, autonomous)
2026-07-22 11:08:32 -05:00
Ali jawwad
41c5dfc3a1
fix(auth): Azure DevOps az-CLI token acquisition returns None on undecodable output ( #3527 )
...
_acquire_via_az_cli runs 'az account get-access-token' with text=True, so
subprocess.run decodes stdout with the locale encoding and raises
UnicodeDecodeError (a ValueError sibling, NOT a JSONDecodeError) when the output
can't be decoded. That escaped the except (OSError, TimeoutExpired,
JSONDecodeError, KeyError) tuple and crashed a helper whose contract is to
return str | None. Add UnicodeDecodeError to the tuple.
Test patches subprocess.run to raise UnicodeDecodeError and asserts resolve_token
returns None (fails before: the error propagated).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-17 13:51:51 -05:00
Copilot
f0998348be
feat: Config-driven opt-in authentication registry with multi-platform support ( #2393 )
...
* Initial plan
* feat: add authentication provider registry (GitHub + Azure DevOps)
Agent-Logs-Url: https://github.com/github/spec-kit/sessions/da7ecfd0-e1c9-48dc-b692-27be0879e976
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com >
* feat: add try-each-provider HTTP helper and wire all catalog fetches through auth registry
- Add authentication/http.py with open_url() that tries each configured
provider in registry order, falling through on 401/403 to the next,
and finally to unauthenticated
- Add build_request() for one-shot request construction
- Add configured_providers() to registry __init__
- Remove api_base_url() from AuthProvider ABC (unused)
- Remove hosts attribute from providers (no host matching)
- Replace _github_http.py usage in ExtensionCatalog and PresetCatalog
- Wire IntegrationCatalog and WorkflowCatalog through open_url (were unauthenticated)
- Wire _fetch_latest_release_tag() through open_url
- Wire all inline --from-url downloads through open_url
- Fix unused stub variable flagged by code-quality bot
- 49 auth tests (positive + negative), 1805 total tests passing
* fix: address review — fix stale docstrings, restore Accept header, add extra_headers to open_url
- Fix _open_url() docstrings in extensions.py and presets.py that
incorrectly claimed redirect stripping behavior
- Add extra_headers parameter to open_url() so callers can pass
additional headers (e.g. Accept) that persist across retries
- Restore Accept: application/vnd.github+json header in
_fetch_latest_release_tag() via extra_headers
* feat: config-driven opt-in auth via ~/.specify/auth.json
Security-first redesign: no credentials are sent unless the user
explicitly creates ~/.specify/auth.json mapping hosts to providers.
- Add authentication/config.py: loads and validates auth.json with
host-to-provider mappings, supports token/token_env/azure-ad/azure-cli
- Refactor AuthProvider ABC: auth_headers(token, scheme) + resolve_token(entry)
- Refactor GitHubAuth: bearer scheme only, token from config entry
- Refactor AzureDevOpsAuth: 4 schemes (basic-pat, bearer, azure-cli, azure-ad)
with dynamic token acquisition for azure-cli and azure-ad
- Rewrite authentication/http.py: host matching, redirect stripping,
provider fallthrough on 401/403, unauthenticated fallback
- Add docs/reference/authentication.md with full reference and template
- 1823 tests passing (67 auth-specific)
* fix: address review — unused imports, host normalization, provider+scheme validation, security hardening
- Remove unused imports (os, field, Any) in config.py
- Normalize hosts during load (strip + lowercase)
- Validate token/token_env are non-empty strings during load
- Validate provider+scheme compatibility during load
- Fix extra_headers order: auth headers applied last, cannot be overridden
- Remove unused 'tried' variable in http.py
- Warn (once) on malformed auth.json instead of silent fallback
- URL-encode OAuth2 client credentials body in azure_devops.py
- Update 403 message to mention auth.json configuration
- Fix registry leak in test_register_duplicate (try/finally)
- Fix import style consistency in test_authentication.py
- Add azure-cli and azure-ad token acquisition tests (mock subprocess/urlopen)
- Add autouse fixture to isolate upgrade tests from real auth.json
- 1829 tests passing
* fix: reject unknown providers, validate azure-ad fields, strip Authorization from extra_headers
- Reject unknown provider keys during auth.json load with clear error message
- Validate azure-ad tenant_id/client_id/client_secret_env as non-empty strings
- Strip Authorization from extra_headers in both build_request and open_url
to prevent accidental or intentional bypass of provider-configured auth
- Add tests for unknown provider and incompatible scheme validation
- 1831 tests passing
* fix: extract shared auth test helpers, global config isolation, align docstring
- Move _inject_github_config / make_github_auth_entry to tests/auth_helpers.py
to eliminate duplication across test_extensions, test_presets, test_upgrade
- Move auth config isolation fixture to global conftest.py (autouse) so ALL
tests are isolated from ~/.specify/auth.json, not just test_upgrade
- Align load_auth_config docstring with actual behavior: ValueError may be
caught by higher-level HTTP helpers that warn and continue unauthenticated
- 1831 tests passing
* fix: preserve auth header across multi-hop redirect chains
- Read Authorization from both headers and unredirected_hdrs in
_StripAuthOnRedirect to survive multi-hop chains within allowed hosts
- Add test_multi_hop_redirect_within_hosts_preserves_auth
- 1832 tests passing
* fix: use resolved config path in warning/error messages and patch build_opener in no-network test
Agent-Logs-Url: https://github.com/github/spec-kit/sessions/86df9557-54f1-4fe4-a25f-9501cb2356cf
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com >
* fix: assert full resolved config path in rate-limit output test
Agent-Logs-Url: https://github.com/github/spec-kit/sessions/86df9557-54f1-4fe4-a25f-9501cb2356cf
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com >
* fix: close HTTPError on 401/403, remove _VALID_AUTH_SCHEMES, catch TimeoutExpired, skip POSIX test on Windows, remove unused import
Agent-Logs-Url: https://github.com/github/spec-kit/sessions/a1e29737-dd6e-4287-96c1-509e0c96fb21
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com >
* fix: use stable ~/.specify/auth.json in rate-limit message, skip POSIX permission check on Windows
Agent-Logs-Url: https://github.com/github/spec-kit/sessions/4636bcdb-87ae-45d6-9545-a40e4effd617
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com >
* fix: validate host patterns, cache auth config per-process
Agent-Logs-Url: https://github.com/github/spec-kit/sessions/889b58a7-7f8c-47e2-8056-931ebcc671cc
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com >
* fix: clarify _is_valid_host_pattern docstring, clean up test sentinel type
Agent-Logs-Url: https://github.com/github/spec-kit/sessions/889b58a7-7f8c-47e2-8056-931ebcc671cc
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com >
* fix: improve _is_valid_host_pattern docstring and test observability
Agent-Logs-Url: https://github.com/github/spec-kit/sessions/889b58a7-7f8c-47e2-8056-931ebcc671cc
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com >
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com >
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com >
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com >
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com >
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com >
2026-05-07 12:51:20 -05:00