feat(rust): add Vertex auth base provider

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
This commit is contained in:
Devin AI 2026-07-19 02:17:05 +00:00
parent f2e340cf2b
commit e0f2e5ee11
5 changed files with 1013 additions and 22 deletions

654
litellm-rust/Cargo.lock generated
View file

@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "arc-swap"
version = "1.9.2"
@ -19,7 +28,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]
@ -313,7 +322,7 @@ checksum = "221eaa237ddf1ca79b60d1372aad77e47f9c0ea5b3ce5099da8c61d027dc77b3"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]
@ -478,6 +487,15 @@ dependencies = [
"hybrid-array",
]
[[package]]
name = "bs58"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
dependencies = [
"tinyvec",
]
[[package]]
name = "bumpalo"
version = "3.20.3"
@ -495,6 +513,9 @@ name = "bytes"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593"
dependencies = [
"serde",
]
[[package]]
name = "bytes-utils"
@ -530,6 +551,29 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chacha20"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81"
dependencies = [
"cfg-if",
"cpufeatures 0.3.0",
"rand_core 0.10.1",
]
[[package]]
name = "chrono"
version = "0.4.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
dependencies = [
"iana-time-zone",
"num-traits",
"serde",
"windows-link",
]
[[package]]
name = "cmake"
version = "0.1.58"
@ -545,6 +589,16 @@ version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
[[package]]
name = "combine"
version = "4.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
dependencies = [
"bytes",
"memchr",
]
[[package]]
name = "const-oid"
version = "0.10.2"
@ -613,6 +667,40 @@ dependencies = [
"cmov",
]
[[package]]
name = "darling"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
dependencies = [
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.118",
]
[[package]]
name = "darling_macro"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
dependencies = [
"darling_core",
"quote",
"syn 2.0.118",
]
[[package]]
name = "data-encoding"
version = "2.11.0"
@ -624,6 +712,9 @@ name = "deranged"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
dependencies = [
"serde_core",
]
[[package]]
name = "digest"
@ -655,7 +746,7 @@ checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]
@ -664,6 +755,12 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]]
name = "dyn-clone"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "either"
version = "1.16.0"
@ -676,6 +773,16 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.2",
]
[[package]]
name = "fastrand"
version = "2.4.1"
@ -709,6 +816,20 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]]
name = "futures"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.32"
@ -739,7 +860,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]
@ -816,6 +937,82 @@ dependencies = [
"cfg-if",
"libc",
"r-efi 6.0.0",
"rand_core 0.10.1",
]
[[package]]
name = "google-cloud-auth"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4595b69c95c727ac896a4f2f16d0cdaa6f547de0bc5d64dbe9201487fc3226d5"
dependencies = [
"async-trait",
"base64",
"bytes",
"chrono",
"google-cloud-gax",
"hex",
"hmac",
"http 1.4.2",
"reqwest 0.13.4",
"rustc_version",
"rustls 0.23.41",
"rustls-pki-types",
"serde",
"serde_json",
"sha2 0.11.0",
"thiserror 2.0.18",
"time",
"tokio",
"url",
]
[[package]]
name = "google-cloud-gax"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3103a4a9013f1aed573ca56e19a9680b0211643a99ea85caf524b397d6be8be3"
dependencies = [
"bytes",
"futures",
"google-cloud-rpc",
"google-cloud-wkt",
"http 1.4.2",
"pin-project",
"rand 0.10.2",
"serde",
"serde_json",
"thiserror 2.0.18",
"tokio",
]
[[package]]
name = "google-cloud-rpc"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2162c08a89118130979ba261080e960e44cdcb2d6e2ab8ca9b1da245285d353"
dependencies = [
"bytes",
"google-cloud-wkt",
"serde",
"serde_json",
"serde_with",
]
[[package]]
name = "google-cloud-wkt"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46df1fcc3ab69164af3f4199ed21f45b5dbc56d9f03211eb4fa20116d442364b"
dependencies = [
"base64",
"bytes",
"serde",
"serde_json",
"serde_with",
"thiserror 2.0.18",
"time",
"url",
]
[[package]]
@ -830,7 +1027,7 @@ dependencies = [
"futures-sink",
"futures-util",
"http 0.2.12",
"indexmap",
"indexmap 2.14.0",
"slab",
"tokio",
"tokio-util",
@ -849,13 +1046,19 @@ dependencies = [
"futures-core",
"futures-sink",
"http 1.4.2",
"indexmap",
"indexmap 2.14.0",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.17.1"
@ -1060,6 +1263,30 @@ dependencies = [
"tracing",
]
[[package]]
name = "iana-time-zone"
version = "0.1.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "icu_collections"
version = "2.2.0"
@ -1142,6 +1369,12 @@ dependencies = [
"zerovec",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "1.1.0"
@ -1163,6 +1396,17 @@ dependencies = [
"icu_properties",
]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
"serde",
]
[[package]]
name = "indexmap"
version = "2.14.0"
@ -1170,7 +1414,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown",
"hashbrown 0.17.1",
"serde",
"serde_core",
]
[[package]]
@ -1185,6 +1431,55 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "jni"
version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498"
dependencies = [
"cfg-if",
"combine",
"jni-macros",
"jni-sys",
"log",
"simd_cesu8",
"thiserror 2.0.18",
"walkdir",
"windows-link",
]
[[package]]
name = "jni-macros"
version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3"
dependencies = [
"proc-macro2",
"quote",
"rustc_version",
"simd_cesu8",
"syn 2.0.118",
]
[[package]]
name = "jni-sys"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2"
dependencies = [
"jni-sys-macros",
]
[[package]]
name = "jni-sys-macros"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
dependencies = [
"quote",
"syn 2.0.118",
]
[[package]]
name = "jobserver"
version = "0.1.35"
@ -1222,7 +1517,7 @@ dependencies = [
"futures-util",
"litellm-core",
"pyo3",
"reqwest",
"reqwest 0.12.28",
"serde",
"serde_json",
"sha2 0.10.9",
@ -1242,8 +1537,9 @@ dependencies = [
"aws-sigv4",
"aws-smithy-runtime-api",
"aws-types",
"google-cloud-auth",
"rand 0.8.6",
"reqwest",
"reqwest 0.12.28",
"serde",
"serde_json",
"sha2 0.10.9",
@ -1358,6 +1654,26 @@ version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "pin-project"
version = "1.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.118",
]
[[package]]
name = "pin-project-lite"
version = "0.2.17"
@ -1471,7 +1787,7 @@ dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]
@ -1483,7 +1799,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]
@ -1512,6 +1828,7 @@ version = "0.11.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e"
dependencies = [
"aws-lc-rs",
"bytes",
"getrandom 0.3.4",
"lru-slab",
@ -1583,6 +1900,17 @@ dependencies = [
"rand_core 0.9.5",
]
[[package]]
name = "rand"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
dependencies = [
"chacha20",
"getrandom 0.4.3",
"rand_core 0.10.1",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
@ -1621,6 +1949,32 @@ dependencies = [
"getrandom 0.3.4",
]
[[package]]
name = "rand_core"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "ref-cast"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216e8f773d7923bcba9ceb86a86c93cabb3903a11872fc3f138c49630e50b96d"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9283685feec7d69af75fb0e858d5e7378f33fe4fc699383b2916ab9273e03c"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.0",
]
[[package]]
name = "regex-lite"
version = "0.1.9"
@ -1670,6 +2024,44 @@ dependencies = [
"webpki-roots",
]
[[package]]
name = "reqwest"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
dependencies = [
"base64",
"bytes",
"futures-core",
"http 1.4.2",
"http-body 1.0.1",
"http-body-util",
"hyper 1.10.1",
"hyper-rustls 0.27.9",
"hyper-util",
"js-sys",
"log",
"percent-encoding",
"pin-project-lite",
"quinn",
"rustls 0.23.41",
"rustls-pki-types",
"rustls-platform-verifier",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper",
"tokio",
"tokio-rustls 0.26.4",
"tower",
"tower-http",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "ring"
version = "0.17.14"
@ -1718,6 +2110,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f"
dependencies = [
"aws-lc-rs",
"log",
"once_cell",
"ring",
"rustls-pki-types",
@ -1748,6 +2141,33 @@ dependencies = [
"zeroize",
]
[[package]]
name = "rustls-platform-verifier"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
dependencies = [
"core-foundation",
"core-foundation-sys",
"jni",
"log",
"once_cell",
"rustls 0.23.41",
"rustls-native-certs",
"rustls-platform-verifier-android",
"rustls-webpki 0.103.13",
"security-framework",
"security-framework-sys",
"webpki-root-certs",
"windows-sys 0.61.2",
]
[[package]]
name = "rustls-platform-verifier-android"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
[[package]]
name = "rustls-webpki"
version = "0.101.7"
@ -1782,6 +2202,15 @@ version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "schannel"
version = "0.1.29"
@ -1791,6 +2220,30 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "schemars"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
dependencies = [
"dyn-clone",
"ref-cast",
"serde",
"serde_json",
]
[[package]]
name = "schemars"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc"
dependencies = [
"dyn-clone",
"ref-cast",
"serde",
"serde_json",
]
[[package]]
name = "sct"
version = "0.7.1"
@ -1857,7 +2310,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]
@ -1896,6 +2349,38 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_with"
version = "3.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c"
dependencies = [
"base64",
"bs58",
"chrono",
"hex",
"indexmap 1.9.3",
"indexmap 2.14.0",
"schemars 0.9.0",
"schemars 1.2.1",
"serde_core",
"serde_json",
"serde_with_macros",
"time",
]
[[package]]
name = "serde_with_macros"
version = "3.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.118",
]
[[package]]
name = "sha1"
version = "0.10.6"
@ -1935,6 +2420,32 @@ version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
[[package]]
name = "signal-hook-registry"
version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
dependencies = [
"errno",
"libc",
]
[[package]]
name = "simd_cesu8"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520"
dependencies = [
"rustc_version",
"simdutf8",
]
[[package]]
name = "simdutf8"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
[[package]]
name = "slab"
version = "0.4.12"
@ -1973,6 +2484,12 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "subtle"
version = "2.6.1"
@ -1990,6 +2507,17 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "syn"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2fac314a64dc9a36e61a9eb4261a5e9bbfbc922b27e518af97bc32b926cf967"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "sync_wrapper"
version = "1.0.2"
@ -2007,7 +2535,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]
@ -2042,7 +2570,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]
@ -2053,7 +2581,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]
@ -2121,6 +2649,7 @@ dependencies = [
"libc",
"mio",
"pin-project-lite",
"signal-hook-registry",
"socket2 0.6.4",
"tokio-macros",
"windows-sys 0.61.2",
@ -2134,7 +2663,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]
@ -2252,7 +2781,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]
@ -2360,6 +2889,16 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "want"
version = "0.3.1"
@ -2426,7 +2965,7 @@ dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
"wasm-bindgen-shared",
]
@ -2472,6 +3011,15 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "webpki-root-certs"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "webpki-roots"
version = "1.0.8"
@ -2481,12 +3029,74 @@ dependencies = [
"rustls-pki-types",
]
[[package]]
name = "winapi-util"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "windows-core"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-implement"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.118",
]
[[package]]
name = "windows-interface"
version = "0.59.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.118",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
@ -2680,7 +3290,7 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
"synstructure",
]
@ -2701,7 +3311,7 @@ checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]
@ -2721,7 +3331,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
"synstructure",
]
@ -2761,7 +3371,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.118",
]
[[package]]

View file

@ -17,6 +17,7 @@ aws-sdk-sts = { version = "1.108.0", default-features = false, features = ["rust
aws-sigv4 = { version = "1.5.1", optional = true }
aws-types = { version = "1.4.0", optional = true }
aws-smithy-runtime-api = { version = "1.13.0", optional = true }
google-cloud-auth = { version = "=1.12.0", default-features = false, features = ["default-rustls-provider"], optional = true }
[features]
default = []
@ -28,6 +29,7 @@ bedrock-auth = [
"dep:aws-types",
"dep:aws-smithy-runtime-api",
]
vertex-auth = ["dep:google-cloud-auth"]
[dev-dependencies]
reqwest.workspace = true

View file

@ -0,0 +1,7 @@
pub const VERTEXAI_PROJECT: &str = "VERTEXAI_PROJECT";
pub const VERTEXAI_LOCATION: &str = "VERTEXAI_LOCATION";
pub const VERTEXAI_CREDENTIALS: &str = "VERTEXAI_CREDENTIALS";
pub const GOOGLE_APPLICATION_CREDENTIALS: &str = "GOOGLE_APPLICATION_CREDENTIALS";
pub const GOOGLE_CLOUD_PROJECT: &str = "GOOGLE_CLOUD_PROJECT";
pub const GOOGLE_CLOUD_QUOTA_PROJECT: &str = "GOOGLE_CLOUD_QUOTA_PROJECT";
pub const CLOUD_PLATFORM_SCOPE: &str = "https://www.googleapis.com/auth/cloud-platform";

View file

@ -1 +1,5 @@
#[cfg(feature = "vertex-auth")]
mod constants;
pub mod ocr;
#[cfg(feature = "vertex-auth")]
pub mod vertex_base;

View file

@ -0,0 +1,368 @@
//! User-directed exception: this base provider owns Google auth I/O for parity
//! with Python's `VertexBase`; the broader core purity guidance is reconciled
//! separately.
use std::env;
use std::fs;
use std::path::Path;
use std::sync::{Mutex, OnceLock};
use google_cloud_auth::credentials::external_account;
use google_cloud_auth::credentials::service_account;
use google_cloud_auth::credentials::user_account;
use google_cloud_auth::credentials::AccessTokenCredentials;
use serde_json::Value;
use sha2::{Digest, Sha256};
use crate::caching::in_memory_cache::InMemoryCache;
use crate::error::{CoreError, CoreResult};
use super::constants::{
CLOUD_PLATFORM_SCOPE, GOOGLE_APPLICATION_CREDENTIALS, GOOGLE_CLOUD_PROJECT,
GOOGLE_CLOUD_QUOTA_PROJECT, VERTEXAI_CREDENTIALS, VERTEXAI_LOCATION, VERTEXAI_PROJECT,
};
static VERTEX_CREDENTIALS_CACHE: OnceLock<Mutex<InMemoryCache<AccessTokenCredentials>>> =
OnceLock::new();
// google-cloud-auth owns async token caching and refresh; Python's single-flight machinery is intentionally not ported.
#[derive(Clone, Debug, PartialEq)]
pub enum VertexCredentialsInput {
Json(Value),
String(String),
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct VertexAuthConfig {
pub credentials: Option<VertexCredentialsInput>,
pub location: Option<String>,
pub project_id: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum VertexAuthSource {
AwsWorkloadIdentity,
ExecutableWorkloadIdentity,
IdentityPoolWorkloadIdentity,
AuthorizedUser,
ServiceAccount,
DefaultAdc,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct VertexToken {
pub access_token: String,
pub project_id: String,
}
impl VertexAuthConfig {
pub fn from_environment() -> Self {
Self {
credentials: non_empty_env(VERTEXAI_CREDENTIALS)
.or_else(|| non_empty_env(GOOGLE_APPLICATION_CREDENTIALS))
.map(VertexCredentialsInput::String),
location: non_empty_env(VERTEXAI_LOCATION),
project_id: non_empty_env(VERTEXAI_PROJECT)
.or_else(|| non_empty_env(GOOGLE_CLOUD_PROJECT)),
}
}
}
pub fn resolve_credentials_input(
credentials: Option<VertexCredentialsInput>,
) -> CoreResult<Option<Value>> {
let Some(credentials) = credentials else {
return Ok(None);
};
let value = match credentials {
VertexCredentialsInput::Json(value) => value,
VertexCredentialsInput::String(value) => {
if value.trim().is_empty() {
return Ok(None);
}
let path = Path::new(&value);
let json = if path.is_file() {
fs::read_to_string(path).map_err(|error| {
CoreError::Auth(format!("unable to read Vertex credentials file: {error}"))
})?
} else {
value
};
serde_json::from_str(&json).map_err(|error| {
CoreError::Auth(format!("invalid Vertex credentials JSON: {error}"))
})?
}
};
if value.is_object() {
Ok(Some(value))
} else {
Err(CoreError::InvalidType {
expected: "object",
actual: crate::error::json_type_name(&value),
})
}
}
pub fn classify_auth(credentials: Option<&Value>) -> VertexAuthSource {
let Some(credentials) = credentials else {
return VertexAuthSource::DefaultAdc;
};
let credential_type = credentials.get("type").and_then(Value::as_str);
if credential_type == Some("external_account") {
let source = credentials
.get("credential_source")
.and_then(Value::as_object);
let environment_id = source
.and_then(|source| source.get("environment_id"))
.and_then(Value::as_str)
.unwrap_or_default();
if environment_id.contains("aws") {
return VertexAuthSource::AwsWorkloadIdentity;
}
if source.is_some_and(|source| source.contains_key("executable")) {
return VertexAuthSource::ExecutableWorkloadIdentity;
}
return VertexAuthSource::IdentityPoolWorkloadIdentity;
}
if credential_type == Some("authorized_user") {
return VertexAuthSource::AuthorizedUser;
}
VertexAuthSource::ServiceAccount
}
pub async fn resolve_token(config: VertexAuthConfig) -> CoreResult<VertexToken> {
let credentials = resolve_credentials_input(config.credentials)?;
let source = classify_auth(credentials.as_ref());
let project_id = project_id(config.project_id, credentials.as_ref())?;
let cache_key = cache_key(credentials.as_ref(), &project_id);
let provider = cached_credentials(&cache_key)?;
let provider = match provider {
Some(provider) => provider,
None => {
let provider = build_credentials(source, credentials)?;
let access_token = provider.access_token().await.map_err(|error| {
CoreError::Auth(format!("Google token resolution failed: {error}"))
})?;
store_credentials(cache_key, provider.clone())?;
return Ok(VertexToken {
access_token: access_token.token,
project_id,
});
}
};
let access_token = provider
.access_token()
.await
.map_err(|error| CoreError::Auth(format!("Google token resolution failed: {error}")))?;
Ok(VertexToken {
access_token: access_token.token,
project_id,
})
}
fn build_credentials(
source: VertexAuthSource,
credentials: Option<Value>,
) -> CoreResult<AccessTokenCredentials> {
let scopes = [CLOUD_PLATFORM_SCOPE];
match source {
VertexAuthSource::DefaultAdc => google_cloud_auth::credentials::Builder::default()
.with_scopes(scopes)
.build_access_token_credentials()
.map_err(|error| CoreError::Auth(format!("Google ADC resolution failed: {error}"))),
VertexAuthSource::AwsWorkloadIdentity
| VertexAuthSource::ExecutableWorkloadIdentity
| VertexAuthSource::IdentityPoolWorkloadIdentity => {
let value = credentials.ok_or(CoreError::MissingField("credentials"))?;
external_account::Builder::new(value)
.with_scopes(scopes)
.build_access_token_credentials()
.map_err(|error| {
CoreError::Auth(format!(
"Google external account resolution failed: {error}"
))
})
}
VertexAuthSource::AuthorizedUser => {
let value = credentials.ok_or(CoreError::MissingField("credentials"))?;
user_account::Builder::new(value)
.with_scopes(scopes)
.build_access_token_credentials()
.map_err(|error| {
CoreError::Auth(format!("Google authorized-user resolution failed: {error}"))
})
}
VertexAuthSource::ServiceAccount => {
let value = credentials.ok_or(CoreError::MissingField("credentials"))?;
service_account::Builder::new(value)
.with_access_specifier(service_account::AccessSpecifier::from_scopes(scopes))
.build_access_token_credentials()
.map_err(|error| {
CoreError::Auth(format!("Google service-account resolution failed: {error}"))
})
}
}
}
fn project_id(explicit: Option<String>, credentials: Option<&Value>) -> CoreResult<String> {
let project_id = explicit
.filter(|value| !value.trim().is_empty())
.or_else(|| {
credentials.and_then(|value| {
value
.get("project_id")
.and_then(Value::as_str)
.map(str::to_owned)
})
})
.or_else(|| {
credentials.and_then(|value| {
value
.get("quota_project_id")
.and_then(Value::as_str)
.map(str::to_owned)
})
})
.or_else(|| non_empty_env(GOOGLE_CLOUD_PROJECT))
.or_else(|| non_empty_env(GOOGLE_CLOUD_QUOTA_PROJECT));
project_id.ok_or(CoreError::MissingField("project_id"))
}
fn cache_key(credentials: Option<&Value>, project_id: &str) -> String {
let mut hasher = Sha256::new();
if let Some(credentials) = credentials {
hasher.update(credentials.to_string());
}
hasher.update(project_id);
format!("{:x}", hasher.finalize())
}
fn cached_credentials(key: &str) -> CoreResult<Option<AccessTokenCredentials>> {
let cache = VERTEX_CREDENTIALS_CACHE.get_or_init(|| Mutex::new(InMemoryCache::default()));
let mut cache = cache
.lock()
.map_err(|_| CoreError::Auth("Vertex credential cache lock poisoned".to_string()))?;
Ok(cache.get_cache(key))
}
fn store_credentials(key: String, credentials: AccessTokenCredentials) -> CoreResult<()> {
let cache = VERTEX_CREDENTIALS_CACHE.get_or_init(|| Mutex::new(InMemoryCache::default()));
let mut cache = cache
.lock()
.map_err(|_| CoreError::Auth("Vertex credential cache lock poisoned".to_string()))?;
cache.set_cache(key, credentials, None);
Ok(())
}
fn non_empty_env(name: &str) -> Option<String> {
env::var(name).ok().filter(|value| !value.trim().is_empty())
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn classifier_preserves_external_account_dispatch_order() {
assert_eq!(
classify_auth(Some(&json!({
"type": "external_account",
"credential_source": {"environment_id": "aws1", "executable": {}}
}))),
VertexAuthSource::AwsWorkloadIdentity
);
assert_eq!(
classify_auth(Some(&json!({
"type": "external_account",
"credential_source": {"executable": {"command": "token"}}
}))),
VertexAuthSource::ExecutableWorkloadIdentity
);
assert_eq!(
classify_auth(Some(
&json!({"type": "external_account", "credential_source": {}})
)),
VertexAuthSource::IdentityPoolWorkloadIdentity
);
}
#[test]
fn classifier_covers_authorized_service_and_default_sources() {
assert_eq!(
classify_auth(Some(&json!({"type": "authorized_user"}))),
VertexAuthSource::AuthorizedUser
);
assert_eq!(
classify_auth(Some(&json!({"type": "service_account"}))),
VertexAuthSource::ServiceAccount
);
assert_eq!(
classify_auth(Some(&json!({"client_email": "test@example.com"}))),
VertexAuthSource::ServiceAccount
);
assert_eq!(classify_auth(None), VertexAuthSource::DefaultAdc);
}
#[test]
fn credential_input_reads_files_inline_json_and_objects() {
let path = std::env::temp_dir().join(format!("vertex-auth-{}.json", std::process::id()));
std::fs::write(&path, r#"{"type":"authorized_user"}"#).unwrap();
assert_eq!(
resolve_credentials_input(Some(VertexCredentialsInput::String(
path.to_string_lossy().into_owned()
)))
.unwrap(),
Some(json!({"type": "authorized_user"}))
);
std::fs::remove_file(path).unwrap();
assert_eq!(
resolve_credentials_input(Some(VertexCredentialsInput::String(
r#"{"type":"service_account"}"#.to_string()
)))
.unwrap(),
Some(json!({"type": "service_account"}))
);
assert_eq!(
resolve_credentials_input(Some(VertexCredentialsInput::Json(json!({
"type": "external_account"
}))))
.unwrap(),
Some(json!({"type": "external_account"}))
);
}
#[test]
fn credential_input_treats_empty_as_absent_and_rejects_invalid_json() {
assert_eq!(
resolve_credentials_input(Some(VertexCredentialsInput::String(" \n".to_string())))
.unwrap(),
None
);
assert!(matches!(
resolve_credentials_input(Some(VertexCredentialsInput::String("{".to_string()))),
Err(CoreError::Auth(_))
));
}
#[test]
fn project_id_explicit_value_wins_over_credential_and_environment() {
let credentials = json!({"project_id": "credential-project"});
assert_eq!(
project_id(Some("explicit-project".to_string()), Some(&credentials)).unwrap(),
"explicit-project"
);
assert_eq!(
project_id(None, Some(&credentials)).unwrap(),
"credential-project"
);
assert_eq!(
project_id(None, Some(&json!({"quota_project_id": "quota-project"}))).unwrap(),
"quota-project"
);
}
}