Skip to content

fix: support native macOS keyring credential lookup#18776

Open
pietrodn wants to merge 1 commit intoastral-sh:mainfrom
pietrodn:fix/native-auth-keychain-lookup
Open

fix: support native macOS keyring credential lookup#18776
pietrodn wants to merge 1 commit intoastral-sh:mainfrom
pietrodn:fix/native-auth-keychain-lookup

Conversation

@pietrodn
Copy link
Copy Markdown

@pietrodn pietrodn commented Mar 31, 2026

Relates to #12591 and #8810 (this comment).

Summary

When UV_PREVIEW_FEATURES=native-auth is set, uv auth login stores credentials in the macOS Keychain keyed by service name + username. But during uv sync, no username is available in the request URL — it's stored inside the keychain entry itself. fetch_native returned None immediately when username was None, silently skipping the keychain lookup. Plaintext credential lookup works fine, so the problem is specific to native-auth on macOS.

The fix adds find_credential_by_service to uv-keyring, using the macOS SecItemCopyMatching API to search by service name alone (no account/username required), returning the first matching credential. fetch_native now falls back to this search when no username is provided.

Test Plan

New unit test test_find_credential_by_service_without_account in uv-keyring:

cargo test -p uv-keyring --features native-auth --lib -- test_find_credential_by_service

All existing keyring tests pass:

cargo test -p uv-auth -- keyring        # 21 passed
cargo test -p uv-keyring --features native-auth --lib  # 22 passed

Here below I provide a manual test setup to validate the fix. It can be employed to verify the issue and the resolution even if an alternative approach is preferred.

Manual end-to-end reproduction with a local pypiserver

1. Set up a private Python index with basic auth

pip install pypiserver passlib htpasswd
mkdir -p /tmp/private-pypi/packages && cd /tmp/private-pypi
htpasswd -cb .htpasswd testuser testpass
pip download --no-deps --dest packages/ iniconfig==2.0.0
pypi-server run -p 8099 --authenticate list,update --passwords .htpasswd packages/ &

2. Create a test project

mkdir -p /tmp/uv-test-project && cd /tmp/uv-test-project
cat > pyproject.toml << 'EOF'
[project]
name = "test-project"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = ["iniconfig"]

[[tool.uv.index]]
name = "private"
url = "http://localhost:8099/simple/"
default = true
authenticate = "always"
EOF

3. Reproduce the bug (before fix)

UV_PREVIEW_FEATURES=native-auth \
  uv auth login http://localhost:8099 --username testuser --password testpass

# FAILS with "Missing credentials"
UV_PREVIEW_FEATURES=native-auth uv sync --no-cache

4. Verify the fix (after fix)

rm -f ~/.local/share/uv/credentials/credentials.toml
rm -rf .venv uv.lock

# SUCCEEDS — credentials are fetched from keychain
UV_PREVIEW_FEATURES=native-auth uv sync --no-cache

5. Verify plaintext credentials still work

security delete-generic-password -s "uv:http://localhost:8099" 2>/dev/null
rm -rf .venv uv.lock
uv auth login http://localhost:8099 --username testuser --password testpass
uv sync --no-cache

6. Cleanup

pkill -f "pypi-server"
security delete-generic-password -s "uv:http://localhost:8099" 2>/dev/null
rm -f ~/.local/share/uv/credentials/credentials.toml
rm -rf /tmp/private-pypi /tmp/uv-test-project

I used Claude Code to diagnose the bug and propose the fix. I reviewed all produced code manually and re-wrote the PR description in my own words, in compliance with the AI policy. Also, I tested the fix on a real-world private Python index. Let me know if something needs to be changed or if I am missing some critical context.

@pietrodn pietrodn force-pushed the fix/native-auth-keychain-lookup branch from 07c2e8b to aa0b141 Compare March 31, 2026 12:54
When `UV_PREVIEW_FEATURES=native-auth` is set, `uv auth login` stores
credentials in the macOS Keychain keyed by service name + username. But
during `uv sync`, no username is available in the request URL, because it is
stored inside the keychain entry itself. So, the lookup fails if the
username is not embedded in the index URL.

Fix by adding `find_credential_by_service` to uv-keyring, which searches
by service name alone (without an account/username), returning the first
matching credential.
The `fetch_native` method now falls back to this search when no username
is provided.
@pietrodn pietrodn force-pushed the fix/native-auth-keychain-lookup branch from aa0b141 to 9e384a5 Compare March 31, 2026 12:55
@zanieb zanieb self-assigned this Mar 31, 2026
@konstin konstin requested a review from zanieb March 31, 2026 13:59
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