Addresses MS-LEAD secrev REQUEST CHANGES on #806.
S1 (CRITICAL — REQ 2 defeated by provider switches + cloud creds): the env sweep
did not neutralize AWS Bedrock / GCP Vertex routing. CLAUDE_CODE_USE_BEDROCK /
CLAUDE_CODE_USE_VERTEX are routing switches whose mere presence makes Claude Code
talk to the real Anthropic API via the ambient cloud credential chain, bypassing
ANTHROPIC_BASE_URL (the loopback proxy) entirely — and the cloud credentials
(AWS_SECRET_ACCESS_KEY, AWS_BEARER_TOKEN_BEDROCK, GOOGLE_APPLICATION_CREDENTIALS,
…) passed straight through.
- buildClaudexEnv now force-deletes the routing switches by exact name
(CLAUDEX_FORCED_UNSET_ENV) regardless of value — a name pattern is the wrong
model for a boolean switch.
- CLAUDEX_CREDENTIAL_ENV_RE extended to the cloud-cred families (^AWS_,
^GOOGLE_APPLICATION_CREDENTIALS, ^GOOGLE_CLOUD_, ^GCP_) and the mid-string
_KEY$ / _SECRET gap (STRIPE_SECRET_KEY, SSH_PRIVATE_KEY, AWS_SECRET_ACCESS_KEY).
- Doc-comment updated to match reality.
S2 (HIGH — fail-open contradicts documented fail-closed): defaultCanonicalizeIntended
and defaultIsSymlink swallowed ANY fs error. Now they distinguish ENOENT
(genuinely absent → safe to continue) from every other errno (ELOOP, EACCES,
ENOTDIR, …) which rethrows and fails CLOSED.
Tests (TDD red-first, 4 new specs red before the fix): Bedrock/Vertex switches +
AWS/GCP creds swept while the loopback proxy stays the only route; mid-string
_KEY/_SECRET closed; real-FS ELOOP (canonicalize) and ENOTDIR (isSymlink) fail
closed; injected EACCES not swallowed.
New-module coverage 100% stmts/lines, 93.75% branch. Full mosaic suite 1169 green;
typecheck / lint / format:check green. No --no-verify.
Refs #790
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Second and final PR for `mosaic [yolo] claudex` — runs GPT models inside the
Claude Code harness via claude-code-proxy (ChatGPT-subscription OAuth). Builds
on the PR-1 preflight/lifecycle library (#793).
New `claudex.ts` (pure / dependency-injected composition):
- resolveClaudexConfigDir / assertIsolatedConfigDir — the isolated
CLAUDE_CONFIG_DIR seam. HARD REQ 1 (provable isolation): canonicalizes both
sides, rejects `~/.claude` and any descendant, ensures the dir 0700, then
re-checks post-create and rejects a symlinked target (TOCTOU). Ambient
CLAUDE_CONFIG_DIR is never inherited. Fails closed on any uncertainty.
- buildClaudexEnv — HARD REQ 2 (zero token leakage): strips the entire
credential-bearing env family (ANTHROPIC_*, *_TOKEN, *_API_KEY, *_SECRET,
CLAUDE_CODE_OAUTH*) and hands Claude Code only ANTHROPIC_AUTH_TOKEN=unused.
Never reads the proxy credential file. Returns a fresh object (no mutation).
- resolveClaudexModels — P3 tier map: primary→gpt-5.6-sol,
small/fast→gpt-5.6-luna; operator env values win.
- buildClaudexBanner / buildClaudexContractNote — P4 EXPERIMENTAL classification
(no token material by construction).
- runClaudexProxyGate — preflight → device reauth (only when needed) → ensure a
trusted-live listener → re-preflight; surfaces non-sensitive problems only.
- launchClaudex — fail-closed DI orchestration: preflight → gate → compose env →
exec; never reaches exec on a gate failure or guard throw. Proxy endpoint
imported from claudex-proxy.ts (single source of truth).
launch.ts wiring:
- execRuntime gains an env parameter.
- `claudex` + `yolo claudex` commander dispatch (keeps the #454 arg-slice fix);
claudexHandler is an injectable seam for the wiring tests.
- launchClaudexProduction glue assembles the real harness adapter.
Tests: 45 claudex specs + 5 launch wiring specs, TDD red-first. New-module
coverage 99% stmts/lines, 93% branch (≥85% gate). Full mosaic suite 1164 green;
typecheck / lint / format:check green.
Refs #790
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>