refactor(cloud): thread probe identity explicitly instead of pinning process env#56
Merged
sourcehawk merged 3 commits intoMay 30, 2026
Conversation
Provider.Identity and cloud.Probe now take the pinned identity and the subprocess env explicitly instead of reading process-global env. The gcp and aws Identity implementations validate the resolved identity against the threaded expected value, dropping their os.Getenv reads. cloud.Server carries ExpectedIdentity (read once from TRIAGENT_CLOUD_EXPECTED_IDENTITY in the serve subprocess) and builds the probe env via subprocessEnv(). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ProbeSource no longer mutates the launcher's process env (and its serializing mutex) to pin the per-provider expected identity. It now builds the subprocess credential env explicitly — base PATH/HOME plus the provider's declared config-dir passthrough names carried from os.Environ, with the source credential var overlaid — and threads the pinned identity into cloud.Probe. A test pins the no-mutation guarantee. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…erve cloudSourceEnv now sets the uniform TRIAGENT_CLOUD_EXPECTED_IDENTITY for both providers in addition to the per-provider credential env the CLI authenticates with (gcp impersonation target, aws assume-role profile), replacing the aws-only expected-role-ARN env. runCloud reads the uniform env once and threads it into cloud.Options.ExpectedIdentity. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Description
Towards #44
The launcher-side cloud identity probe pinned each provider's expected-identity env via process-global
os.Setenv(serialized behind a mutex) because the providers read that env throughos.Getenvin-process. Mutating process-global env from a request path is a concurrency footgun. This threads the pinned identity and the subprocess credential env explicitly instead, so concurrent probes for different sources never share state.It is an internal threading refactor: the profile schema (
CloudSource), theProbeSource(ctx, Source)signature, and all launcher behavior are unchanged. Theserve --kind=cloudsubprocess still authenticates from its injected env.Changes
Provider.Identityandcloud.Probetake the pinned identity (expected) and the subprocessenvexplicitly; the gcp and aws implementations validate the resolved identity againstexpectedinstead of reading their ownos.Getenv.ProbeSourceno longer mutates the launcher process env (and drops the serializing mutex). It builds the subprocess credential env explicitly — base PATH/HOME plus the provider's declared config-dir passthrough names carried fromos.Environ, with the source credential var overlaid — and threads the pinned identity intocloud.Probe.TRIAGENT_CLOUD_EXPECTED_IDENTITYenv carries the pinned identity for both providers, set bycloudSourceEnvalongside the per-provider credential env (gcp impersonation target, aws assume-role profile) and read once byrunCloudin the serve subprocess. The aws-only expected-role-ARN env is removed.Challenges
The serve subprocess and the launcher-side probe sit in different processes with different ambient env. The subprocess legitimately reads its injected credential env from
os.Environ(viaServer.subprocessEnv()), but the launcher process does not hold the pinned credential — which is why the old code mutated global env to fake it. The fix splits the env-building responsibility: the subprocess path keeps readingos.Environ, whileProbeSourceconstructs the credential env explicitly per source and passes it throughcloud.Probe, so neither path mutates shared state.Testing
make test-gois race-clean and green;make lintreports 0 issues. Added a test provingProbeSourceleaves the process env untouched (a sentinel,AWS_PROFILE, and the gcp impersonation env all read identically after probing both providers), asourceEnvForoverlay test (source credential overrides the operator's ambient value; undeclared env never crosses the boundary), and a nil-provider contract-error test onProbe. The provider identity tests now threadexpecteddirectly instead of setting env. The existingharness_security_test.gominimal-env guarantees forrun_cliare unaffected.🤖 Generated with Claude Code