mirror of https://github.com/astral-sh/uv
Add support for `HF_TOKEN` (#14797)
## Summary If `HF_TOKEN` is set, we'll automatically wire it up to authenticate requests when hitting private `huggingface.co` URLs in `uv run`. ## Test Plan An unauthenticated request: ``` > cargo run -- run https://huggingface.co/datasets/cmarsh/test/resolve/main/main.py File "/var/folders/nt/6gf2v7_s3k13zq_t3944rwz40000gn/T/mainYadr5M.py", line 1 Invalid username or password. ^^^^^^^^ SyntaxError: invalid syntax ``` An authenticated request: ``` > HF_TOKEN=hf_... cargo run run https://huggingface.co/datasets/cmarsh/test/resolve/main/main.py Hello from main.py! ```
This commit is contained in:
parent
7a56950bab
commit
a3ea1b69f2
|
|
@ -15,6 +15,7 @@ mod credentials;
|
||||||
mod index;
|
mod index;
|
||||||
mod keyring;
|
mod keyring;
|
||||||
mod middleware;
|
mod middleware;
|
||||||
|
mod providers;
|
||||||
mod realm;
|
mod realm;
|
||||||
|
|
||||||
// TODO(zanieb): Consider passing a cache explicitly throughout
|
// TODO(zanieb): Consider passing a cache explicitly throughout
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use reqwest::{Request, Response};
|
||||||
use reqwest_middleware::{Error, Middleware, Next};
|
use reqwest_middleware::{Error, Middleware, Next};
|
||||||
use tracing::{debug, trace, warn};
|
use tracing::{debug, trace, warn};
|
||||||
|
|
||||||
|
use crate::providers::HuggingFaceProvider;
|
||||||
use crate::{
|
use crate::{
|
||||||
CREDENTIALS_CACHE, CredentialsCache, KeyringProvider,
|
CREDENTIALS_CACHE, CredentialsCache, KeyringProvider,
|
||||||
cache::FetchUrl,
|
cache::FetchUrl,
|
||||||
|
|
@ -457,9 +458,8 @@ impl AuthMiddleware {
|
||||||
Some(credentials)
|
Some(credentials)
|
||||||
};
|
};
|
||||||
|
|
||||||
return self
|
self.complete_request(credentials, request, extensions, next, auth_policy)
|
||||||
.complete_request(credentials, request, extensions, next, auth_policy)
|
.await
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch credentials for a URL.
|
/// Fetch credentials for a URL.
|
||||||
|
|
@ -503,6 +503,13 @@ impl AuthMiddleware {
|
||||||
return credentials;
|
return credentials;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Support for known providers, like Hugging Face.
|
||||||
|
if let Some(credentials) = HuggingFaceProvider::credentials_for(url).map(Arc::new) {
|
||||||
|
debug!("Found Hugging Face credentials for {url}");
|
||||||
|
self.cache().fetches.done(key, Some(credentials.clone()));
|
||||||
|
return Some(credentials);
|
||||||
|
}
|
||||||
|
|
||||||
// Netrc support based on: <https://github.com/gribouille/netrc>.
|
// Netrc support based on: <https://github.com/gribouille/netrc>.
|
||||||
let credentials = if let Some(credentials) = self.netrc.get().and_then(|netrc| {
|
let credentials = if let Some(credentials) = self.netrc.get().and_then(|netrc| {
|
||||||
debug!("Checking netrc for credentials for {url}");
|
debug!("Checking netrc for credentials for {url}");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
use tracing::debug;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use uv_static::EnvVars;
|
||||||
|
|
||||||
|
use crate::Credentials;
|
||||||
|
use crate::realm::Realm;
|
||||||
|
|
||||||
|
/// The [`Realm`] for the Hugging Face platform.
|
||||||
|
static HUGGING_FACE_REALM: LazyLock<Realm> = LazyLock::new(|| {
|
||||||
|
let url = Url::parse("https://huggingface.co").expect("Failed to parse Hugging Face URL");
|
||||||
|
Realm::from(&url)
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The authentication token for the Hugging Face platform, if set.
|
||||||
|
static HUGGING_FACE_TOKEN: LazyLock<Option<Vec<u8>>> = LazyLock::new(|| {
|
||||||
|
// Extract the Hugging Face token from the environment variable, if it exists.
|
||||||
|
let hf_token = std::env::var(EnvVars::HF_TOKEN)
|
||||||
|
.ok()
|
||||||
|
.map(String::into_bytes)
|
||||||
|
.filter(|token| !token.is_empty())?;
|
||||||
|
|
||||||
|
if std::env::var_os(EnvVars::UV_NO_HF_TOKEN).is_some() {
|
||||||
|
debug!("Ignoring Hugging Face token from environment due to `UV_NO_HF_TOKEN`");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Found Hugging Face token in environment");
|
||||||
|
Some(hf_token)
|
||||||
|
});
|
||||||
|
|
||||||
|
/// A provider for authentication credentials for the Hugging Face platform.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub(crate) struct HuggingFaceProvider;
|
||||||
|
|
||||||
|
impl HuggingFaceProvider {
|
||||||
|
/// Returns the credentials for the Hugging Face platform, if available.
|
||||||
|
pub(crate) fn credentials_for(url: &Url) -> Option<Credentials> {
|
||||||
|
if Realm::from(url) == *HUGGING_FACE_REALM {
|
||||||
|
if let Some(token) = HUGGING_FACE_TOKEN.as_ref() {
|
||||||
|
return Some(Credentials::Bearer {
|
||||||
|
token: token.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -765,4 +765,11 @@ impl EnvVars {
|
||||||
|
|
||||||
/// Disable GitHub-specific requests that allow uv to skip `git fetch` in some circumstances.
|
/// Disable GitHub-specific requests that allow uv to skip `git fetch` in some circumstances.
|
||||||
pub const UV_NO_GITHUB_FAST_PATH: &'static str = "UV_NO_GITHUB_FAST_PATH";
|
pub const UV_NO_GITHUB_FAST_PATH: &'static str = "UV_NO_GITHUB_FAST_PATH";
|
||||||
|
|
||||||
|
/// Authentication token for Hugging Face requests. When set, uv will use this token
|
||||||
|
/// when making requests to `https://huggingface.co/` and any subdomains.
|
||||||
|
pub const HF_TOKEN: &'static str = "HF_TOKEN";
|
||||||
|
|
||||||
|
/// Disable Hugging Face authentication, even if `HF_TOKEN` is set.
|
||||||
|
pub const UV_NO_HF_TOKEN: &'static str = "UV_NO_HF_TOKEN";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -151,3 +151,18 @@ insecure.
|
||||||
|
|
||||||
Use `allow-insecure-host` with caution and only in trusted environments, as it can expose you to
|
Use `allow-insecure-host` with caution and only in trusted environments, as it can expose you to
|
||||||
security risks due to the lack of certificate verification.
|
security risks due to the lack of certificate verification.
|
||||||
|
|
||||||
|
## Hugging Face support
|
||||||
|
|
||||||
|
uv supports automatic authentication for the Hugging Face Hub. Specifically, if the `HF_TOKEN`
|
||||||
|
environment variable is set, uv will propagate it to requests to `huggingface.co`.
|
||||||
|
|
||||||
|
This is particularly useful for accessing private scripts in Hugging Face Datasets. For example, you
|
||||||
|
can run the following command to execute the script `main.py` script from a private dataset:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ HF_TOKEN=hf_... uv run https://huggingface.co/datasets/<user>/<name>/resolve/<branch>/main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
You can disable automatic Hugging Face authentication by setting the `UV_NO_HF_TOKEN=1` environment
|
||||||
|
variable.
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,10 @@ Ignore `.env` files when executing `uv run` commands.
|
||||||
|
|
||||||
Disable GitHub-specific requests that allow uv to skip `git fetch` in some circumstances.
|
Disable GitHub-specific requests that allow uv to skip `git fetch` in some circumstances.
|
||||||
|
|
||||||
|
### `UV_NO_HF_TOKEN`
|
||||||
|
|
||||||
|
Disable Hugging Face authentication, even if `HF_TOKEN` is set.
|
||||||
|
|
||||||
### `UV_NO_INSTALLER_METADATA`
|
### `UV_NO_INSTALLER_METADATA`
|
||||||
|
|
||||||
Skip writing `uv` installer metadata files (e.g., `INSTALLER`, `REQUESTED`, and `direct_url.json`) to site-packages `.dist-info` directories.
|
Skip writing `uv` installer metadata files (e.g., `INSTALLER`, `REQUESTED`, and `direct_url.json`) to site-packages `.dist-info` directories.
|
||||||
|
|
@ -528,6 +532,11 @@ See [force-color.org](https://force-color.org).
|
||||||
|
|
||||||
Used for trusted publishing via `uv publish`.
|
Used for trusted publishing via `uv publish`.
|
||||||
|
|
||||||
|
### `HF_TOKEN`
|
||||||
|
|
||||||
|
Authentication token for Hugging Face requests. When set, uv will use this token
|
||||||
|
when making requests to `https://huggingface.co/` and any subdomains.
|
||||||
|
|
||||||
### `HOME`
|
### `HOME`
|
||||||
|
|
||||||
The standard `HOME` env var.
|
The standard `HOME` env var.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue