mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-11 08:38:24 +00:00
* fix(vertex): report an unreadable credentials file as a read failure Tell a path apart from inline JSON by shape, not os.path.exists(). Fixes #40166 * test(vertex): narrow pytest.raises to the expected message * fix(vertex): log the credentials path instead of returning it to the caller * refactor(vertex): log the credential source decision where it is made * fix(vertex): handle paths open() rejects with a bare ValueError * fix(vertex): redact the credentials path before it reaches the log * test(vertex): cover the brace fallback and non-text credentials file * test(vertex): exclude the unreachable exhaustiveness guard from coverage * refactor(vertex): read the failure's fields off the matched object CodeQL's py/uninitialized-local-variable does not follow keyword capture patterns in a match statement and reported `path` and `reason` as possibly unbound. Narrowing on the class and reading the attributes says the same thing without a suppression. * fix(vertex): accept a read-only mapping in extract_aws_params * fix(vertex): keep encoded credentials out of the log and cover the legacy route * fix(vertex): give one message for every credentials file failure and pick file or JSON by shape in Rust * fix(vertex): read a `{`-named key file in Rust, name base64 there, and give one message when Google auth rejects a credentials file * fix(vertex): read an unreadable `{`-named key file as a file, cap key file reads, and drop storage advice from the file message * test(vertex): integration cells for credentials file and inline value failures * test(vertex): drive the Rust messages cell through Vertex Claude --------- Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
114 lines
3.8 KiB
Rust
114 lines
3.8 KiB
Rust
use std::collections::BTreeMap;
|
|
|
|
use litellm_auth_gcp::{
|
|
VertexConfig,
|
|
constants::{GOOGLE_APPLICATION_CREDENTIALS_ENV, VERTEX_LOCATION_ENV},
|
|
get_vertex_ai_location, get_vertex_ai_project, get_vertex_ai_project_from_credentials,
|
|
};
|
|
use litellm_auth_types::VertexParams;
|
|
use rstest::rstest;
|
|
use serde_json::{Value, json};
|
|
|
|
fn config(value: Value) -> VertexConfig {
|
|
VertexConfig::from_sourced_optional_params(value.as_object().unwrap(), &BTreeMap::new())
|
|
.unwrap()
|
|
}
|
|
|
|
#[rstest]
|
|
fn config_is_typed_and_secrets_are_redacted() {
|
|
let config = config(json!({
|
|
"vertex_credentials":{"private_key":"secret-key"},
|
|
"vertex_project":"project-1",
|
|
"vertex_location":"europe-west4"
|
|
}));
|
|
assert_eq!(config.project_id(), Some("project-1"));
|
|
assert_eq!(config.location(), Some("europe-west4"));
|
|
assert!(!format!("{config:?}").contains("secret-key"));
|
|
assert!(
|
|
VertexConfig::from_sourced_optional_params(
|
|
json!({"vertex_credentials":true}).as_object().unwrap(),
|
|
&BTreeMap::new()
|
|
)
|
|
.is_err()
|
|
);
|
|
}
|
|
|
|
#[rstest]
|
|
fn project_and_location_prefer_input_then_environment() {
|
|
let configured =
|
|
config(json!({"vertex_project":"input-project","vertex_location":"input-location"}));
|
|
let env = |name: &str| Some(format!("env-{name}"));
|
|
assert_eq!(
|
|
get_vertex_ai_project(&configured, &env).as_deref(),
|
|
Some("input-project")
|
|
);
|
|
assert_eq!(
|
|
get_vertex_ai_location(&configured, &env).as_deref(),
|
|
Some("input-location")
|
|
);
|
|
let empty = VertexConfig::default();
|
|
assert_eq!(
|
|
get_vertex_ai_project(&empty, &|_| Some("env-project".into())).as_deref(),
|
|
Some("env-project")
|
|
);
|
|
assert_eq!(
|
|
get_vertex_ai_location(&empty, &|name| (name == VERTEX_LOCATION_ENV)
|
|
.then(|| "fallback-location".into()))
|
|
.as_deref(),
|
|
Some("fallback-location")
|
|
);
|
|
}
|
|
|
|
#[rstest]
|
|
fn project_is_read_from_the_credentials_that_would_authenticate() {
|
|
let key = tempfile::NamedTempFile::new().unwrap();
|
|
std::fs::write(key.path(), r#"{"project_id":"file-project"}"#).unwrap();
|
|
let path = key.path().to_str().unwrap().to_string();
|
|
let inline = VertexConfig::from_params(&VertexParams {
|
|
vertex_credentials: Some(r#"{"project_id":"inline-project"}"#.into()),
|
|
..VertexParams::default()
|
|
});
|
|
assert_eq!(
|
|
get_vertex_ai_project_from_credentials(&inline, &|_| None).as_deref(),
|
|
Some("inline-project")
|
|
);
|
|
let from_file = VertexConfig::from_params(&VertexParams {
|
|
vertex_credentials: Some(path.clone()),
|
|
..VertexParams::default()
|
|
});
|
|
assert_eq!(
|
|
get_vertex_ai_project_from_credentials(&from_file, &|_| None).as_deref(),
|
|
Some("file-project")
|
|
);
|
|
let empty = VertexConfig::default();
|
|
assert_eq!(
|
|
get_vertex_ai_project_from_credentials(&empty, &|name| (name
|
|
== GOOGLE_APPLICATION_CREDENTIALS_ENV)
|
|
.then(|| path.clone()))
|
|
.as_deref(),
|
|
Some("file-project")
|
|
);
|
|
assert_eq!(
|
|
get_vertex_ai_project_from_credentials(&empty, &|_| None),
|
|
None
|
|
);
|
|
}
|
|
|
|
#[rstest]
|
|
fn project_is_read_from_a_relative_key_file_named_like_json() {
|
|
let key = tempfile::Builder::new()
|
|
.prefix("{vertex")
|
|
.suffix(".json")
|
|
.tempfile_in(".")
|
|
.unwrap();
|
|
std::fs::write(key.path(), r#"{"project_id":"file-project"}"#).unwrap();
|
|
let relative_name = key.path().file_name().unwrap().to_str().unwrap();
|
|
let from_file = VertexConfig::from_params(&VertexParams {
|
|
vertex_credentials: Some(relative_name.into()),
|
|
..VertexParams::default()
|
|
});
|
|
assert_eq!(
|
|
get_vertex_ai_project_from_credentials(&from_file, &|_| None).as_deref(),
|
|
Some("file-project")
|
|
);
|
|
}
|