Skip to content

Commit

Permalink
Hint about missing trusted publishing permission
Browse files Browse the repository at this point in the history
Fixes #8584
  • Loading branch information
konstin committed Oct 28, 2024
1 parent 572840d commit 35db7f9
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 4 deletions.
26 changes: 22 additions & 4 deletions crates/uv-publish/src/trusted_publishing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use reqwest_middleware::ClientWithMiddleware;
use serde::{Deserialize, Serialize};
use std::env;
use std::env::VarError;
use std::ffi::OsString;
use std::fmt::Display;
use thiserror::Error;
use tracing::{debug, trace};
Expand All @@ -13,8 +14,10 @@ use uv_static::EnvVars;

#[derive(Debug, Error)]
pub enum TrustedPublishingError {
#[error(transparent)]
Var(#[from] VarError),
#[error("Environment variable {0} not set, is the `id-token: write` permission missing?")]
MissingEnvVar(&'static str),
#[error("Environment variable {0} is not valid UTF-8: `{1:?}`")]
InvalidEnvVar(&'static str, OsString),
#[error(transparent)]
Url(#[from] url::ParseError),
#[error("Failed to fetch: `{0}`")]
Expand All @@ -29,6 +32,15 @@ pub enum TrustedPublishingError {
Pypi(StatusCode, String),
}

impl TrustedPublishingError {
fn from_var_err(env_var: &'static str, err: VarError) -> Self {
match err {
VarError::NotPresent => Self::MissingEnvVar(env_var),
VarError::NotUnicode(os_string) => Self::InvalidEnvVar(env_var, os_string),
}
}
}

#[derive(Deserialize)]
#[serde(transparent)]
pub struct TrustedPublishingToken(String);
Expand Down Expand Up @@ -75,7 +87,10 @@ pub(crate) async fn get_token(
client: &ClientWithMiddleware,
) -> Result<TrustedPublishingToken, TrustedPublishingError> {
// If this fails, we can skip the audience request.
let oidc_token_request_token = env::var(EnvVars::ACTIONS_ID_TOKEN_REQUEST_TOKEN)?;
let oidc_token_request_token =
env::var(EnvVars::ACTIONS_ID_TOKEN_REQUEST_TOKEN).map_err(|err| {
TrustedPublishingError::from_var_err(EnvVars::ACTIONS_ID_TOKEN_REQUEST_TOKEN, err)
})?;

// Request 1: Get the audience
let audience = get_audience(registry, client).await?;
Expand Down Expand Up @@ -125,7 +140,10 @@ async fn get_oidc_token(
oidc_token_request_token: &str,
client: &ClientWithMiddleware,
) -> Result<String, TrustedPublishingError> {
let mut oidc_token_url = Url::parse(&env::var(EnvVars::ACTIONS_ID_TOKEN_REQUEST_URL)?)?;
let oidc_token_url = env::var(EnvVars::ACTIONS_ID_TOKEN_REQUEST_URL).map_err(|err| {
TrustedPublishingError::from_var_err(EnvVars::ACTIONS_ID_TOKEN_REQUEST_URL, err)
})?;
let mut oidc_token_url = Url::parse(&oidc_token_url)?;
oidc_token_url
.query_pairs_mut()
.append_pair("audience", audience);
Expand Down
32 changes: 32 additions & 0 deletions crates/uv/tests/it/publish.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::common::{uv_snapshot, TestContext};
use uv_static::EnvVars;

#[test]
fn username_password_no_longer_supported() {
Expand Down Expand Up @@ -51,3 +52,34 @@ fn invalid_token() {
"###
);
}

#[test]
fn missing_trusted_publishing_permission() {
let context = TestContext::new("3.12");

uv_snapshot!(context.filters(), context.publish()
.arg("-u")
.arg("__token__")
.arg("-p")
.arg("dummy")
.arg("--publish-url")
.arg("https://test.pypi.org/legacy/")
.arg("--trusted-publishing")
.arg("always")
.arg("../../scripts/links/ok-1.0.0-py3-none-any.whl")
// Emulate CI
.env(EnvVars::GITHUB_ACTIONS, "true")
// Just to make sure
.env_remove(EnvVars::ACTIONS_ID_TOKEN_REQUEST_TOKEN), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
warning: `uv publish` is experimental and may change without warning
Publishing 1 file to https://test.pypi.org/legacy/
error: Failed to obtain token for trusted publishing
Caused by: Environment variable ACTIONS_ID_TOKEN_REQUEST_TOKEN not set, is the `id-token: write` permission missing?
"###
);
}

0 comments on commit 35db7f9

Please sign in to comment.