Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
26eace7
Add `uv auth` commands (`login`, `logout`, and `token`) (#15539)
zanieb Aug 31, 2025
6f02ac2
Add preview warnings to `native-keyring` usage (#15555)
zanieb Aug 29, 2025
dbe5f93
Add support for credentials in URLs to `uv auth` (#15554)
zanieb Aug 28, 2025
a10c377
Only allow HTTPS services in login for now (#15559)
zanieb Aug 28, 2025
23fc93f
Update `uv auth` snapshots
zanieb Aug 28, 2025
5441e65
Update messaging for `uv auth` (#15573)
zanieb Aug 28, 2025
1b7bd8f
Remove unused dependencies from `uv auth` preview refactor (#15589)
zanieb Aug 30, 2025
a232aa4
Add a plain text backend for credential storage (#15588)
zanieb Aug 30, 2025
787346b
Strip the trailing `/simple` from index URLs provided to `uv auth log…
zanieb Aug 30, 2025
a62e141
Add the native keyring to the documentation (#15596)
zanieb Aug 30, 2025
712a0c0
Add test case for `uv auth login` in publish integration tests (#15592)
zanieb Aug 30, 2025
1bd10d2
Add documentation on the uv credential store and CLI (#15597)
zanieb Aug 30, 2025
13ff8eb
Respect `UV_CREDENTIALS_DIR` (#15598)
zanieb Aug 30, 2025
919c071
Add case for `uv auth login` in registry integration tests (#15593)
zanieb Aug 30, 2025
81bb26a
Misc. tweaks
charliermarsh Aug 30, 2025
caf5845
Use a dedicated wire type for credentials serialization (#15599)
charliermarsh Aug 31, 2025
d97a1e8
Add `uv auth dir` (#15600)
zanieb Aug 31, 2025
cc63c38
Lock the credentials store when reading or writing (#15610)
zanieb Sep 2, 2025
99499ff
Respect usernames when finding matching credentials in the plaintext …
zanieb Sep 2, 2025
d166487
Remove the native system store from the keyring providers (#15612)
zanieb Sep 2, 2025
e123f28
Allow storage of multiple usernames per service in the plaintext stor…
zanieb Sep 2, 2025
0184834
Run the `uv-keyring` tests serially (#15629)
zanieb Sep 2, 2025
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
11 changes: 11 additions & 0 deletions .config/nextest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,14 @@
# Mark tests that take longer than 10s as slow.
# Terminate after 120s as a stop-gap measure to terminate on deadlock.
slow-timeout = { period = "10s", terminate-after = 12 }

[test-groups]
serial = { max-threads = 1 }

[[profile.default.overrides]]
filter = 'test(native_auth)'
test-group = 'serial'

[[profile.default.overrides]]
filter = 'package(uv-keyring)'
test-group = 'serial'
40 changes: 35 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ jobs:
UV_HTTP_RETRIES: 5
run: |
cargo nextest run \
--features python-patch,keyring-tests,secret-service \
--features python-patch,native-auth,secret-service \
--workspace \
--status-level skip --failure-output immediate-final --no-fail-fast -j 20 --final-status-level slow

Expand Down Expand Up @@ -293,7 +293,7 @@ jobs:
run: |
cargo nextest run \
--no-default-features \
--features python,python-managed,pypi,git,performance,crates-io,keyring-tests,apple-native \
--features python,python-managed,pypi,git,performance,crates-io,native-auth,apple-native \
--workspace \
--status-level skip --failure-output immediate-final --no-fail-fast -j 12 --final-status-level slow

Expand Down Expand Up @@ -345,7 +345,7 @@ jobs:
run: |
cargo nextest run \
--no-default-features \
--features python,pypi,python-managed,keyring-tests,windows-native \
--features python,pypi,python-managed,native-auth,windows-native \
--workspace \
--status-level skip --failure-output immediate-final --no-fail-fast -j 20 --final-status-level slow

Expand Down Expand Up @@ -1779,8 +1779,32 @@ jobs:
echo "::add-mask::$UV_TEST_GCP_TOKEN"
echo "UV_TEST_GCP_TOKEN=$UV_TEST_GCP_TOKEN" >> $GITHUB_ENV

- name: "Run registry tests"
run: ./uv run -p "${PYTHON_VERSION}" scripts/registries-test.py --uv ./uv --color always --all
- name: "Run registry tests with environment variable backend"
run: ./uv run -p "${PYTHON_VERSION}" scripts/registries-test.py --uv ./uv --color always --all --auth-method env
env:
RUST_LOG: uv=debug
UV_TEST_ARTIFACTORY_TOKEN: ${{ secrets.UV_TEST_ARTIFACTORY_TOKEN }}
UV_TEST_ARTIFACTORY_URL: ${{ secrets.UV_TEST_ARTIFACTORY_URL }}
UV_TEST_ARTIFACTORY_USERNAME: ${{ secrets.UV_TEST_ARTIFACTORY_USERNAME }}
UV_TEST_AWS_URL: ${{ secrets.UV_TEST_AWS_URL }}
UV_TEST_AWS_USERNAME: aws
UV_TEST_AZURE_TOKEN: ${{ secrets.UV_TEST_AZURE_TOKEN }}
UV_TEST_AZURE_URL: ${{ secrets.UV_TEST_AZURE_URL }}
UV_TEST_AZURE_USERNAME: dummy
UV_TEST_CLOUDSMITH_TOKEN: ${{ secrets.UV_TEST_CLOUDSMITH_TOKEN }}
UV_TEST_CLOUDSMITH_URL: ${{ secrets.UV_TEST_CLOUDSMITH_URL }}
UV_TEST_CLOUDSMITH_USERNAME: ${{ secrets.UV_TEST_CLOUDSMITH_USERNAME }}
UV_TEST_GCP_URL: ${{ secrets.UV_TEST_GCP_URL }}
UV_TEST_GCP_USERNAME: oauth2accesstoken
UV_TEST_GEMFURY_TOKEN: ${{ secrets.UV_TEST_GEMFURY_TOKEN }}
UV_TEST_GEMFURY_URL: ${{ secrets.UV_TEST_GEMFURY_URL }}
UV_TEST_GEMFURY_USERNAME: ${{ secrets.UV_TEST_GEMFURY_USERNAME }}
UV_TEST_GITLAB_TOKEN: ${{ secrets.UV_TEST_GITLAB_TOKEN }}
UV_TEST_GITLAB_URL: ${{ secrets.UV_TEST_GITLAB_URL }}
UV_TEST_GITLAB_USERNAME: token

- name: "Run registry tests with text store backend"
run: ./uv run -p "${PYTHON_VERSION}" scripts/registries-test.py --uv ./uv --color always --all --auth-method text-store
env:
RUST_LOG: uv=debug
UV_TEST_ARTIFACTORY_TOKEN: ${{ secrets.UV_TEST_ARTIFACTORY_TOKEN }}
Expand Down Expand Up @@ -1865,6 +1889,12 @@ jobs:
env:
UV_TEST_PUBLISH_KEYRING: ${{ secrets.UV_TEST_PUBLISH_KEYRING }}

- name: "Add password to uv text store"
run: |
./uv auth login https://test.pypi.org/legacy/?astral-test-text-store --token ${UV_TEST_PUBLISH_TEXT_STORE}
env:
UV_TEST_PUBLISH_TEXT_STORE: ${{ secrets.UV_TEST_PUBLISH_TEXT_STORE }}

- name: "Publish test packages"
# `-p 3.12` prefers the python we just installed over the one locked in `.python_version`.
run: ./uv run -p "${PYTHON_VERSION}" scripts/publish/test_publish.py --uv ./uv all
Expand Down
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ uv-git-types = { path = "crates/uv-git-types" }
uv-globfilter = { path = "crates/uv-globfilter" }
uv-install-wheel = { path = "crates/uv-install-wheel", default-features = false }
uv-installer = { path = "crates/uv-installer" }
uv-keyring = { path = "crates/uv-keyring" }
uv-logging = { path = "crates/uv-logging" }
uv-macros = { path = "crates/uv-macros" }
uv-metadata = { path = "crates/uv-metadata" }
Expand Down
7 changes: 7 additions & 0 deletions crates/uv-auth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@ doctest = false
workspace = true

[dependencies]
uv-fs = { workspace = true }
uv-keyring = { workspace = true, features = ["apple-native", "secret-service", "windows-native"] }
uv-once-map = { workspace = true }
uv-preview = { workspace = true }
uv-redacted = { workspace = true }
uv-small-str = { workspace = true }
uv-static = { workspace = true }
uv-state = { workspace = true }
uv-warnings = { workspace = true }

anyhow = { workspace = true }
async-trait = { workspace = true }
base64 = { workspace = true }
fs-err = { workspace = true }
futures = { workspace = true }
http = { workspace = true }
percent-encoding = { workspace = true }
Expand All @@ -28,7 +33,9 @@ rust-netrc = { workspace = true }
rustc-hash = { workspace = true }
schemars = { workspace = true, optional = true }
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
tokio = { workspace = true }
toml = { workspace = true }
tracing = { workspace = true }
url = { workspace = true }

Expand Down
13 changes: 11 additions & 2 deletions crates/uv-auth/src/credentials.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use base64::prelude::BASE64_STANDARD;
use base64::read::DecoderReader;
use base64::write::EncoderWriter;
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::fmt;
use uv_redacted::DisplaySafeUrl;
Expand Down Expand Up @@ -28,7 +29,8 @@ pub enum Credentials {
},
}

#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Default)]
#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Default, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Username(Option<String>);

impl Username {
Expand Down Expand Up @@ -69,17 +71,24 @@ impl From<Option<String>> for Username {
}
}

#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Hash, Default)]
#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Hash, Default, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Password(String);

impl Password {
pub fn new(password: String) -> Self {
Self(password)
}

/// Return the [`Password`] as a string slice.
pub fn as_str(&self) -> &str {
self.0.as_str()
}

/// Convert the [`Password`] into its underlying [`String`].
pub fn into_string(self) -> String {
self.0
}
}

impl fmt::Debug for Password {
Expand Down
Loading
Loading