feat(auth/gcp): add credentials-service REST client#1149
Open
wolo-lab wants to merge 10 commits into
Open
Conversation
wolo-lab
force-pushed
the
wolo/auth-core
branch
4 times, most recently
from
July 12, 2026 21:26
0136d03 to
d70c44e
Compare
wolo-lab
force-pushed
the
wolo/auth-gcp-client
branch
from
July 16, 2026 11:57
6d59920 to
e49269e
Compare
wolo-lab
marked this pull request as ready for review
July 17, 2026 15:51
Add a hand-rolled REST client for the Google Cloud Agent Identity and IAM
Connector credential services. Given a resource name it routes to the right
service, retrieves an end-user credential, polls while the service reports a
non-interactive pending state, and maps the {header, token} result to an
auth.Credential (bearer or header API key), or to auth.ErrConsentRequired when
interactive consent is required.
No generated Go clients exist for these preview services (verified: no such
module on pkg.go.dev) and the surface is a single RPC, so this is hand-rolled
over net/http, authenticating calls with Application Default Credentials
(cloud-platform). No new module dependencies.
This is the transport layer only; the CredentialProvider that resolves the
acting user from the invocation context is a later step (it needs a shared
agent.FromContext helper).
- Add ErrConsentRejected / ErrPollTimeout sentinels (errors.Is-able) and wrap the rejection/timeout returns with them. - Add a context-cancellation-during-poll test (no hang; surfaces context.Canceled). - Move test helpers below the tests; use t.Context() in tests. - Fix the URIConsentRequired initialism. - Note the X-GOOG-API-KEY mirror as a follow-up TODO (needs an additive AdditionalHeaders field on auth.APIKeyCredential; non-breaking).
The auth core package redesigned Credential from a struct into an interface (BearerCredential/APIKeyCredential/OAuth2Credential), so the client no longer compiled against its base. Port the mapping accordingly, and apply the remaining review feedback on the connector. - mapCredential returns auth.Credential: auth.BearerCredential for an "Authorization: Bearer" header, auth.APIKeyCredential otherwise. RetrieveCredential's return type changes from *auth.Credential to auth.Credential. - Connector: a done operation carrying no credential now returns an error instead of being treated as pending and polled to the timeout; drop the unused consentPending metadata field. - Test ErrPollTimeout and the connector done-without-credential path.
Custom (non-bearer) headers now also set X-Goog-Api-Key alongside the service's own header, matching adk-python's credential mapping. Model the IAM Connector metadata consent_pending status explicitly (per the v1alpha RetrieveCredentialsMetadata status oneof) instead of relying on the unknown-status fall-through, and add a test for the connector consent_rejected path (a real proto field that adk-python's connector provider omits).
The wire responses emulated the services' result oneof with nullable-pointer
structs and mapped them to a retrieveResult inline in each retrieve* method.
Move that mapping into result() methods on agentIdentityResponse and
connectorOperation, so transport (doPost) is separated from interpretation
(now a pure, unit-testable step), and extract the duplicated {token, header}
success shape into a shared credentialPayload type. No behavior change.
Replace the retrieveResult struct + retrieveStatus enum (a fat struct whose valid fields depended on the status) with a sealed outcome sum type (credOutcome / pendingOutcome / consentOutcome / rejectedOutcome), so each arm carries only its own fields and RetrieveCredential type-switches on it. The per-service result() methods now return outcome. No behavior change.
Fold the eleven near-identical TestRetrieveAgentIdentity*/TestRetrieveConnector* scenario tests (plus the done-without-credential case) into a single table-driven TestRetrieveCredential, and make TestRetrieveValidatesRequest table-driven too. The routing, HTTP-error, mapCredential, cancellation, and poll-timeout tests stay separate (distinct setup/timing). No coverage change.
Trim four slightly wordy comments (outcome, credentialPayload, the connector pending fall-through, and the TestRetrieveCredential doc) down to the essential "why" after the outcome/table-driven refactors. No code changes; the remaining comments were verified accurate and already terse.
adk-go overwhelmingly constructs objects with config structs (runner, agent, llmagent, agenttool, skilltoolset, mcptoolset, agentregistry, gemini, ...); only apigee and telemetry use functional options. Replace the Option/With* API with a Config struct and NewClient(ctx, *Config) — a nil cfg or any zero field uses defaults — matching the gemini/agenttool nil-config precedent and the go-expert-review / adk-go-review "config structs" convention. No behavior change.
wolo-lab
force-pushed
the
wolo/auth-gcp-client
branch
from
July 17, 2026 22:09
034ee34 to
c300cef
Compare
- Reject an oversized response body instead of feeding json.Unmarshal silently truncated bytes; cap error-body text so a large gateway page doesn't bloat the returned error. - Trim trailing slashes on endpoint overrides so a configured "host/" can't produce a "//v1/..." path. - Send Accept: application/json and include the operation error code in the connector failure message (which could be empty before). - Remove the unused connectorRequest.ForceRefresh field; use errors.New for the constant validation errors. - Add a NewClient test covering defaults and trailing-slash trimming.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
ADK-go's auth subsystem needs to fetch end-user credentials from Google Cloud's
Agent Identity and IAM Connector credential services. There are no generated Go
client libraries for these (preview) services, and adk-go currently has no transport for them at all — while
adk-python already talks to these services.
Summary
auth/gcp, a hand-rolled REST client overnet/http(no new moduledependencies) for the Agent Identity and IAM Connector credential services.
Client.RetrieveCredential(ctx, Request)takes a resource name, routes it tothe right service (IAM Connector when the resource matches
projects/*/locations/*/connectors/*, Agent Identity otherwise — same splitas adk-python), retrieves an end-user credential, and maps the
{header, token}result to an*auth.Credential(bearer token or header APIkey).
pendingstate (bounded by
WithPollTimeout), and surfaces interactive consent as aconsent-required error (
auth.ErrConsentRequired).scope) unless a custom
*http.Clientis supplied viaWithHTTPClient;endpoints are overridable via
WithAgentIdentityEndpoint/WithConnectorEndpoint(used by tests).CredentialProviderthat resolves the acting userfrom the invocation context is a later step (it needs a shared
agent.FromContexthelper).