fix(workspace-server): provider-matched byok credential injection (internal#728 Bug 1) [BEHAVIOR-AFFECTING — CTO merge-go] #2000
@@ -67,8 +67,10 @@ func TestApplyPlatformManagedLLMEnv_ReProvisionUsesStoredModel(t *testing.T) {
|
||||
"CLAUDE_CODE_OAUTH_TOKEN": "RENO-OWN-OAUTH", // workspace_secrets origin
|
||||
"ANTHROPIC_BASE_URL": "https://api.moleculesai.app/api/v1/internal/llm/anthropic",
|
||||
}
|
||||
// payload.Model == "" — exactly the re-provision shape.
|
||||
res := applyPlatformManagedLLMEnv(ctx, envVars, wsID, "claude-code", "")
|
||||
// payload.Model == "" — exactly the re-provision shape. The oauth is
|
||||
// workspace_secrets-origin (NOT in globalKeys) → exempt from the #728
|
||||
// provider-matched strip regardless of provider match.
|
||||
res := applyPlatformManagedLLMEnv(ctx, envVars, wsID, "claude-code", "", nil)
|
||||
|
||||
if res.ResolvedMode != LLMBillingModeBYOK {
|
||||
t.Fatalf("re-provision with stored MODEL=opus must resolve byok, got %q (source=%s) — the #1994 divergence", res.ResolvedMode, res.Source)
|
||||
@@ -149,7 +151,7 @@ func TestApplyPlatformManagedLLMEnv_ReadProvisionParity(t *testing.T) {
|
||||
"MODEL": "opus",
|
||||
"CLAUDE_CODE_OAUTH_TOKEN": "RENO-OWN-OAUTH",
|
||||
}
|
||||
provRes := applyPlatformManagedLLMEnv(ctx, provEnv, wsID, "claude-code", "")
|
||||
provRes := applyPlatformManagedLLMEnv(ctx, provEnv, wsID, "claude-code", "", nil)
|
||||
if err := provMock.ExpectationsWereMet(); err != nil {
|
||||
t.Errorf("provision-path sqlmock expectations: %v", err)
|
||||
}
|
||||
@@ -179,7 +181,7 @@ func TestApplyPlatformManagedLLMEnv_DefaultPreservation(t *testing.T) {
|
||||
|
||||
// No MODEL anywhere, no auth env — nothing to derive.
|
||||
envVars := map[string]string{}
|
||||
res := applyPlatformManagedLLMEnv(ctx, envVars, wsID, "claude-code", "")
|
||||
res := applyPlatformManagedLLMEnv(ctx, envVars, wsID, "claude-code", "", nil)
|
||||
|
||||
if res.ResolvedMode != LLMBillingModePlatformManaged {
|
||||
t.Fatalf("no model + no cred must default platform_managed (CTO: default stays platform), got %q (source=%s)", res.ResolvedMode, res.Source)
|
||||
@@ -219,8 +221,13 @@ func TestApplyPlatformManagedLLMEnv_ByokGlobalScopeOAuthSurvives(t *testing.T) {
|
||||
"MODEL": "opus",
|
||||
"CLAUDE_CODE_OAUTH_TOKEN": "TENANT-OWN-GLOBAL-OAUTH",
|
||||
}
|
||||
// Provenance: the oauth is GLOBAL-origin (internal#728). It must STILL
|
||||
// survive — opus derives anthropic-oauth, whose auth_env IS
|
||||
// CLAUDE_CODE_OAUTH_TOKEN, so the provider-matched strip keeps it. This is
|
||||
// the PM/reno opus-byok regression guard against #728's strip.
|
||||
globalKeys := map[string]struct{}{"CLAUDE_CODE_OAUTH_TOKEN": {}}
|
||||
|
||||
res := applyPlatformManagedLLMEnv(ctx, envVars, wsID, "claude-code", "")
|
||||
res := applyPlatformManagedLLMEnv(ctx, envVars, wsID, "claude-code", "", globalKeys)
|
||||
|
||||
if res.ResolvedMode != LLMBillingModeBYOK {
|
||||
t.Fatalf("opus derives byok; got %q", res.ResolvedMode)
|
||||
@@ -255,3 +262,113 @@ func TestReProvisionPayloadOmitsModel(t *testing.T) {
|
||||
t.Fatalf("re-provision payload model expected empty (the #1994 trigger), got %q", p.Model)
|
||||
}
|
||||
}
|
||||
|
||||
// --- internal#728 Bug 1: provider-matched credential injection ---------------
|
||||
|
||||
// TestApplyPlatformManagedLLMEnv_MinimaxStripsStrayGlobalOAuth is the direct
|
||||
// repro of DevB (Dev Engineer B, MiniMax-M2.7, claude-code; live-confirmed
|
||||
// 2026-05-28). config.yaml correctly resolves provider=minimax, but the
|
||||
// container inherits the tenant-GLOBAL CLAUDE_CODE_OAUTH_TOKEN; the claude-code
|
||||
// runtime greedily prefers it (`llm-auth: detected oauth`) and routes
|
||||
// MiniMax-M2.7 → api.anthropic.com → `Claude Code returned an error result`.
|
||||
//
|
||||
// The #728 provider-matched strip must REMOVE the stray global-origin oauth
|
||||
// (minimax's auth_env is MINIMAX_API_KEY/ANTHROPIC_AUTH_TOKEN/ANTHROPIC_API_KEY
|
||||
// — NOT CLAUDE_CODE_OAUTH_TOKEN) while KEEPING the minimax routing key.
|
||||
//
|
||||
// Mutation (load-bearing): remove the stripNonMatchingGlobalOriginLLMCreds
|
||||
// call (revert to #1994's blanket keep) → the oauth survives → this test RED on
|
||||
// the oauth-absent assertion. Make the strip provider-UNAWARE (strip all
|
||||
// global bypass keys) → MINIMAX_API_KEY also vanishes → RED on the
|
||||
// minimax-routing assertion. Make it provenance-UNAWARE (strip by name
|
||||
// regardless of origin) → the workspace-origin exemption test below goes RED.
|
||||
func TestApplyPlatformManagedLLMEnv_MinimaxStripsStrayGlobalOAuth(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
const wsID = "22222222-3333-4444-5555-666666666666" // agents-team Dev Engineer B
|
||||
|
||||
mock := setupTestDB(t)
|
||||
expectOverrideQuery(mock, wsID, "")
|
||||
|
||||
// The container env on a re-provision: the MiniMax routing key + the stray
|
||||
// tenant-global oauth (both global_secrets origin) + the stored model.
|
||||
envVars := map[string]string{
|
||||
"MODEL": "MiniMax-M2.7",
|
||||
"MINIMAX_API_KEY": "MINIMAX-TENANT-KEY",
|
||||
"CLAUDE_CODE_OAUTH_TOKEN": "STRAY-TENANT-GLOBAL-OAUTH",
|
||||
}
|
||||
// Both creds are global_secrets origin (the tenant configured them at org
|
||||
// scope; no per-workspace override re-set them).
|
||||
globalKeys := map[string]struct{}{
|
||||
"MINIMAX_API_KEY": {},
|
||||
"CLAUDE_CODE_OAUTH_TOKEN": {},
|
||||
}
|
||||
|
||||
res := applyPlatformManagedLLMEnv(ctx, envVars, wsID, "claude-code", "", globalKeys)
|
||||
|
||||
if res.ResolvedMode != LLMBillingModeBYOK {
|
||||
t.Fatalf("MiniMax-M2.7 must derive minimax → byok, got %q (source=%s)", res.ResolvedMode, res.Source)
|
||||
}
|
||||
if res.Source != BillingModeSourceDerivedProvider {
|
||||
t.Errorf("source: got %q want derived_provider (MiniMax-M2.7 → minimax)", res.Source)
|
||||
}
|
||||
// THE FIX: the stray global oauth that does NOT match minimax's auth_env
|
||||
// must be gone, so the runtime cannot prefer it and mis-route to Anthropic.
|
||||
if v, present := envVars["CLAUDE_CODE_OAUTH_TOKEN"]; present {
|
||||
t.Errorf("stray global-origin CLAUDE_CODE_OAUTH_TOKEN must be STRIPPED for a minimax-resolving workspace (the DevB bug); still present=%q", v)
|
||||
}
|
||||
// The minimax routing key (IS in minimax's auth_env) must remain.
|
||||
if envVars["MINIMAX_API_KEY"] != "MINIMAX-TENANT-KEY" {
|
||||
t.Errorf("minimax routing key must SURVIVE (it matches the resolved provider's auth_env); got %q", envVars["MINIMAX_API_KEY"])
|
||||
}
|
||||
if !res.HasUsableLLMCred {
|
||||
t.Errorf("MINIMAX_API_KEY is a usable credential → HasUsableLLMCred must stay true (not failed-closed)")
|
||||
}
|
||||
if _, present := envVars["MOLECULE_LLM_USAGE_TOKEN"]; present {
|
||||
t.Errorf("byok must not inject the platform usage token")
|
||||
}
|
||||
if err := mock.ExpectationsWereMet(); err != nil {
|
||||
t.Errorf("sqlmock expectations: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestApplyPlatformManagedLLMEnv_WorkspaceOriginCredExemptFromStrip pins the
|
||||
// provenance guard: a CLAUDE_CODE_OAUTH_TOKEN the USER set via the canvas
|
||||
// Secrets tab (workspace_secrets origin → NOT in globalKeys) must NEVER be
|
||||
// stripped, even on a minimax-resolving workspace where it doesn't match the
|
||||
// derived provider's auth_env. The user authored it deliberately; the #728
|
||||
// strip is scoped to the inherited operator-store channel only.
|
||||
//
|
||||
// Mutation: drop the `if _, isBypass...; continue` / globalKeys gate (strip by
|
||||
// name regardless of origin) → the user's oauth vanishes → RED.
|
||||
func TestApplyPlatformManagedLLMEnv_WorkspaceOriginCredExemptFromStrip(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
const wsID = "33333333-4444-5555-6666-777777777777"
|
||||
|
||||
mock := setupTestDB(t)
|
||||
expectOverrideQuery(mock, wsID, "")
|
||||
|
||||
envVars := map[string]string{
|
||||
"MODEL": "MiniMax-M2.7",
|
||||
"MINIMAX_API_KEY": "MINIMAX-TENANT-KEY",
|
||||
"CLAUDE_CODE_OAUTH_TOKEN": "USER-AUTHORED-OAUTH",
|
||||
}
|
||||
// MINIMAX_API_KEY is global-origin; the oauth is WORKSPACE-origin (the user
|
||||
// re-set it via the Secrets tab, so loadWorkspaceSecrets cleared its
|
||||
// global-origin flag) → exempt.
|
||||
globalKeys := map[string]struct{}{"MINIMAX_API_KEY": {}}
|
||||
|
||||
res := applyPlatformManagedLLMEnv(ctx, envVars, wsID, "claude-code", "", globalKeys)
|
||||
|
||||
if res.ResolvedMode != LLMBillingModeBYOK {
|
||||
t.Fatalf("MiniMax-M2.7 derives byok; got %q", res.ResolvedMode)
|
||||
}
|
||||
if envVars["CLAUDE_CODE_OAUTH_TOKEN"] != "USER-AUTHORED-OAUTH" {
|
||||
t.Errorf("workspace-origin (user-authored) oauth must NOT be stripped even when it doesn't match the provider; got %q", envVars["CLAUDE_CODE_OAUTH_TOKEN"])
|
||||
}
|
||||
if envVars["MINIMAX_API_KEY"] != "MINIMAX-TENANT-KEY" {
|
||||
t.Errorf("matching minimax key must survive; got %q", envVars["MINIMAX_API_KEY"])
|
||||
}
|
||||
if err := mock.ExpectationsWereMet(); err != nil {
|
||||
t.Errorf("sqlmock expectations: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -900,7 +900,17 @@ type platformLLMEnvResult struct {
|
||||
Source BillingModeSource
|
||||
}
|
||||
|
||||
func applyPlatformManagedLLMEnv(ctx context.Context, envVars map[string]string, workspaceID, runtime, model string) platformLLMEnvResult {
|
||||
// globalKeys is the provenance side-channel from loadWorkspaceSecrets: the set
|
||||
// of env keys that originated from the operator-controlled global_secrets table
|
||||
// (a workspace_secrets row of the same name overrides and clears the flag). It
|
||||
// is consumed ONLY on the byok/disabled branch's provider-matched strip
|
||||
// (internal#728 Bug 1): a global-origin LLM bypass cred that does NOT match the
|
||||
// resolved provider's auth_env is stripped so a greedy runtime (claude-code
|
||||
// prefers CLAUDE_CODE_OAUTH_TOKEN) cannot route a non-anthropic model to the
|
||||
// wrong upstream. May be nil (no global-origin keys / unknown provenance) — a
|
||||
// nil set strips nothing, preserving the pre-#728 behavior for callers that do
|
||||
// not thread provenance.
|
||||
func applyPlatformManagedLLMEnv(ctx context.Context, envVars map[string]string, workspaceID, runtime, model string, globalKeys map[string]struct{}) platformLLMEnvResult {
|
||||
// internal#718 P2-B: the platform-vs-byok decision now DERIVES the provider
|
||||
// from (runtime, model) via the registry and keys off IsPlatform(derived) —
|
||||
// NOT a stored LLM_PROVIDER and NOT the org rung. This path already carries
|
||||
@@ -945,19 +955,43 @@ func applyPlatformManagedLLMEnv(ctx context.Context, envVars map[string]string,
|
||||
envVars["MOLECULE_LLM_BILLING_MODE_RESOLVED"] = res.ResolvedMode
|
||||
if res.ResolvedMode != LLMBillingModePlatformManaged {
|
||||
// byok or disabled — DO NOT force-route to CP, DO NOT override the
|
||||
// workspace's own ANTHROPIC_BASE_URL / OAuth token, and DO NOT strip
|
||||
// the tenant's own LLM credentials.
|
||||
// workspace's own ANTHROPIC_BASE_URL, and DO NOT strip the tenant's own
|
||||
// (provider-matching) LLM credentials.
|
||||
//
|
||||
// molecule-core#1994 (corrected model): `global_secrets` is the
|
||||
// TENANT's store, not the platform's. The tenant's own credential —
|
||||
// at global OR workspace scope — is exactly what byok runs on, direct.
|
||||
// We leave envVars untouched here and report whether a usable LLM
|
||||
// credential survived so the caller can fail closed when there is
|
||||
// genuinely none (no platform-managed-shaped key at any scope). The
|
||||
// platform's own credential is never in a tenant's global_secrets
|
||||
// The platform's own credential is never in a tenant's global_secrets
|
||||
// (guarded at the SetGlobal write boundary + the proxy token is
|
||||
// server-env-only), so leaving the tenant's globals in place cannot
|
||||
// re-open the platform-credit drain.
|
||||
//
|
||||
// internal#728 Bug 1 (provider-matched credential injection): #1994
|
||||
// removed the BLANKET strip, which was correct for the platform-key
|
||||
// co-mingling it targeted but left EVERY claude-code workspace
|
||||
// inheriting the tenant-global CLAUDE_CODE_OAUTH_TOKEN. A claude-code
|
||||
// runtime greedily prefers that oauth (`llm-auth: detected oauth` →
|
||||
// api.anthropic.com), so a workspace whose RESOLVED provider is NOT
|
||||
// anthropic-oauth (minimax, kimi-byok, …) routes its non-Anthropic
|
||||
// model to Anthropic and errors (`Claude Code returned an error
|
||||
// result`; DevB MiniMax-M2.7 live-confirmed 2026-05-28).
|
||||
//
|
||||
// The precise, provider-AWARE replacement for the over-removed strip:
|
||||
// keep ONLY the global-origin bypass creds whose env-var name is in the
|
||||
// RESOLVED provider's auth_env; strip the rest. This is NOT a return to
|
||||
// the blanket strip — it is keyed off the derived provider:
|
||||
// - minimax (auth_env: MINIMAX_API_KEY, ANTHROPIC_AUTH_TOKEN,
|
||||
// ANTHROPIC_API_KEY) → global-origin CLAUDE_CODE_OAUTH_TOKEN is
|
||||
// NOT a match → stripped (fixes DevB).
|
||||
// - anthropic-oauth (auth_env: CLAUDE_CODE_OAUTH_TOKEN) → the
|
||||
// global-origin oauth IS a match → kept (PM/reno opus byok NOT
|
||||
// regressed — the #1994 ByokGlobalScopeOAuthSurvives guard holds).
|
||||
// WORKSPACE-origin creds (the user explicitly set them via the canvas
|
||||
// Secrets tab → NOT in globalKeys) are NEVER stripped here, even when
|
||||
// they don't match: the user authored them deliberately (JRS kimi
|
||||
// workspace-key, reno's own oauth). Only the inherited operator-store
|
||||
// channel is provider-gated.
|
||||
stripNonMatchingGlobalOriginLLMCreds(envVars, globalKeys, runtime, effectiveModel, availableAuthEnv)
|
||||
return platformLLMEnvResult{
|
||||
ResolvedMode: res.ResolvedMode,
|
||||
HasUsableLLMCred: hasAnyPlatformManagedLLMKey(envVars),
|
||||
@@ -1028,6 +1062,66 @@ func hasAnyPlatformManagedLLMKey(envVars map[string]string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// stripNonMatchingGlobalOriginLLMCreds is the byok-branch provider-matched
|
||||
// credential injection (internal#728 Bug 1). It removes from envVars every
|
||||
// platform-managed LLM bypass key that:
|
||||
//
|
||||
// 1. originated from the operator-controlled global_secrets store
|
||||
// (present in globalKeys — a workspace_secrets row of the same name
|
||||
// overrides + clears the flag, so user-authored creds are exempt), AND
|
||||
// 2. is NOT in the RESOLVED provider's auth_env set.
|
||||
//
|
||||
// The motivating regression: #1994 dropped the blanket strip, so a claude-code
|
||||
// workspace resolving to `minimax` still inherited the tenant-global
|
||||
// CLAUDE_CODE_OAUTH_TOKEN; the runtime prefers that oauth and routes the
|
||||
// MiniMax model to api.anthropic.com → error. Keeping only the resolved
|
||||
// provider's own auth_env keys (minimax: MINIMAX_API_KEY/ANTHROPIC_AUTH_TOKEN/
|
||||
// ANTHROPIC_API_KEY — not the oauth) removes the stray oauth while preserving
|
||||
// anthropic-oauth's CLAUDE_CODE_OAUTH_TOKEN for an opus byok workspace.
|
||||
//
|
||||
// Fail-OPEN by design: if the provider cannot be derived (empty model /
|
||||
// unknown runtime / ambiguous) or the registry is unavailable, we strip
|
||||
// NOTHING — we never strip a credential we cannot prove is non-matching, so a
|
||||
// derive miss can never fail-close a legitimate byok workspace (mirrors the
|
||||
// resolver's own default-closed-to-platform contract: the worst case is we
|
||||
// keep a stray cred, never that we remove the only usable one). The earlier
|
||||
// internal#711 blanket strip's fail-direction (remove first) was the bug;
|
||||
// this strip's fail-direction is keep-first.
|
||||
func stripNonMatchingGlobalOriginLLMCreds(envVars map[string]string, globalKeys map[string]struct{}, runtime, model string, availableAuthEnv []string) {
|
||||
if len(globalKeys) == 0 {
|
||||
return // no operator-store-origin keys to consider — nothing to strip.
|
||||
}
|
||||
manifest, err := providerRegistry()
|
||||
if err != nil || manifest == nil {
|
||||
return // registry unavailable — fail open, strip nothing.
|
||||
}
|
||||
provider, dErr := manifest.DeriveProvider(runtime, model, availableAuthEnv)
|
||||
if dErr != nil {
|
||||
return // underivable provider — fail open, strip nothing.
|
||||
}
|
||||
// The resolved provider's accepted auth-env-var NAMES (case-insensitive
|
||||
// for parity with isPlatformManagedDirectLLMBypassKey, which upper-cases).
|
||||
keep := make(map[string]struct{}, len(provider.AuthEnv))
|
||||
for _, e := range provider.AuthEnv {
|
||||
keep[strings.ToUpper(strings.TrimSpace(e))] = struct{}{}
|
||||
}
|
||||
for key := range globalKeys {
|
||||
upper := strings.ToUpper(strings.TrimSpace(key))
|
||||
if _, isBypass := platformManagedDirectLLMBypassKeys[upper]; !isBypass {
|
||||
continue // not an LLM bypass cred (e.g. a non-LLM operator secret) — leave it.
|
||||
}
|
||||
if _, matches := keep[upper]; matches {
|
||||
continue // matches the resolved provider's auth_env — this is what byok runs on.
|
||||
}
|
||||
// Global-origin LLM bypass cred that does NOT match the resolved
|
||||
// provider — the stray that a greedy runtime would mis-prefer. Strip.
|
||||
if _, present := envVars[key]; present {
|
||||
log.Printf("workspace_provision: byok provider-matched strip — removing global-origin LLM cred %s (resolved provider=%s does not accept it)", key, provider.Name)
|
||||
delete(envVars, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runtimeUsesAnthropicNativeProxy(runtime string) bool {
|
||||
return strings.EqualFold(strings.TrimSpace(runtime), "claude-code")
|
||||
}
|
||||
|
||||
@@ -195,9 +195,16 @@ func (h *WorkspaceHandler) prepareProvisionContext(
|
||||
applyAgentGitHTTPCreds(envVars, payload.Role)
|
||||
// molecule-core#1994: per-workspace LLM billing-mode resolution + env wiring.
|
||||
// On platform_managed it forces the CP proxy usage token; on byok/disabled
|
||||
// it leaves the tenant's own creds (global OR workspace scope) untouched and
|
||||
// reports whether a usable LLM credential is present.
|
||||
llmRes := applyPlatformManagedLLMEnv(ctx, envVars, workspaceID, payload.Runtime, payload.Model)
|
||||
// it keeps the tenant's own provider-MATCHING creds (global OR workspace
|
||||
// scope) and reports whether a usable LLM credential is present.
|
||||
//
|
||||
// internal#728 Bug 1: globalSecretKeys (loadWorkspaceSecrets provenance)
|
||||
// lets the byok branch strip ONLY operator-store-origin LLM creds that do
|
||||
// NOT match the resolved provider's auth_env — so a non-anthropic-oauth
|
||||
// claude-code workspace no longer inherits the stray tenant-global
|
||||
// CLAUDE_CODE_OAUTH_TOKEN the runtime would greedily prefer. User-authored
|
||||
// workspace_secrets (provenance flag cleared) are exempt.
|
||||
llmRes := applyPlatformManagedLLMEnv(ctx, envVars, workspaceID, payload.Runtime, payload.Model, globalSecretKeys)
|
||||
// Fail closed for a BYOK workspace with no usable LLM credential at ANY
|
||||
// scope: do NOT start it credential-less. Mirror the "model+provider+
|
||||
// credential REQUIRED at create" spirit with an actionable error surfaced
|
||||
|
||||
@@ -968,7 +968,7 @@ func TestApplyPlatformManagedLLMEnv_NonClaudeRuntimeDefaultsOpenAIProxyWhenNoWor
|
||||
t.Setenv("MOLECULE_LLM_DEFAULT_MODEL", "moonshot/kimi-k2.6")
|
||||
|
||||
envVars := map[string]string{}
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, "", "codex", "")
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, "", "codex", "", nil)
|
||||
applyRuntimeModelEnv(envVars, "codex", "")
|
||||
|
||||
if got := envVars["OPENAI_BASE_URL"]; got != "https://api.example.test/api/v1/internal/llm/openai/v1" {
|
||||
@@ -998,7 +998,7 @@ func TestApplyPlatformManagedLLMEnv_StripsWorkspaceOpenAIKeyForClaudeCode(t *tes
|
||||
"OPENAI_BASE_URL": "https://api.openai.com/v1",
|
||||
"MODEL": "openai/gpt-5.5",
|
||||
}
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, "", "claude-code", "")
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, "", "claude-code", "", nil)
|
||||
|
||||
if _, ok := envVars["OPENAI_API_KEY"]; ok {
|
||||
t.Fatalf("OPENAI_API_KEY should be stripped for claude-code platform-managed mode")
|
||||
@@ -1024,7 +1024,7 @@ func TestApplyPlatformManagedLLMEnv_ClaudeCodeUsesAnthropicProxyOverOAuth(t *tes
|
||||
"CLAUDE_CODE_OAUTH_TOKEN": "user-oauth-token",
|
||||
"MODEL": "sonnet",
|
||||
}
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, "", "claude-code", "")
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, "", "claude-code", "", nil)
|
||||
|
||||
if _, ok := envVars["CLAUDE_CODE_OAUTH_TOKEN"]; ok {
|
||||
t.Fatalf("CLAUDE_CODE_OAUTH_TOKEN should be stripped in platform-managed mode")
|
||||
@@ -1047,7 +1047,7 @@ func TestApplyPlatformManagedLLMEnv_ClaudeCodeInjectsAnthropicProxyWhenNoWorkspa
|
||||
t.Setenv("MOLECULE_LLM_USAGE_TOKEN", "tenant-admin-token")
|
||||
|
||||
envVars := map[string]string{}
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, "", "claude-code", "minimax/MiniMax-M2.7")
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, "", "claude-code", "minimax/MiniMax-M2.7", nil)
|
||||
|
||||
if got := envVars["ANTHROPIC_BASE_URL"]; got != "https://api.example.test/api/v1/internal/llm/anthropic/v1" {
|
||||
t.Fatalf("ANTHROPIC_BASE_URL = %q", got)
|
||||
@@ -1070,7 +1070,7 @@ func TestApplyPlatformManagedLLMEnv_ClaudeCodeStripsVendorBYOK(t *testing.T) {
|
||||
"MINIMAX_API_KEY": "user-minimax-key",
|
||||
"MODEL": "MiniMax-M2.7",
|
||||
}
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, "", "claude-code", "")
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, "", "claude-code", "", nil)
|
||||
|
||||
if _, ok := envVars["MINIMAX_API_KEY"]; ok {
|
||||
t.Fatalf("MINIMAX_API_KEY should be stripped in platform-managed mode")
|
||||
@@ -1104,7 +1104,7 @@ func TestApplyPlatformManagedLLMEnv_NoopsOutsidePlatformManaged(t *testing.T) {
|
||||
t.Setenv("MOLECULE_LLM_USAGE_TOKEN", "tenant-admin-token")
|
||||
|
||||
envVars := map[string]string{}
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "kimi-for-coding")
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "kimi-for-coding", nil)
|
||||
|
||||
if res.ResolvedMode != LLMBillingModeBYOK {
|
||||
t.Fatalf("resolved mode = %q, want byok (derived from non-platform model)", res.ResolvedMode)
|
||||
@@ -1151,7 +1151,7 @@ func TestApplyPlatformManagedLLMEnv_ClaudeCodeByokKeepsOwnProviderEnv(t *testing
|
||||
"CLAUDE_CODE_OAUTH_TOKEN": "user-oauth-token",
|
||||
"MODEL": "sonnet",
|
||||
}
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "")
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "", nil)
|
||||
|
||||
// 1. OAuth token intact — not stripped.
|
||||
if got := envVars["CLAUDE_CODE_OAUTH_TOKEN"]; got != "user-oauth-token" {
|
||||
@@ -1213,7 +1213,7 @@ func TestApplyPlatformManagedLLMEnv_ByokGlobalScopeOAuthSurvivesAndRunsDirect(t
|
||||
"MODEL": "opus",
|
||||
}
|
||||
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "")
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "", nil)
|
||||
|
||||
// 1. The tenant's own global-scope oauth SURVIVES — byok runs on it.
|
||||
if envVars["CLAUDE_CODE_OAUTH_TOKEN"] != "TENANT-OWN-GLOBAL-OAUTH" {
|
||||
@@ -1266,7 +1266,7 @@ func TestApplyPlatformManagedLLMEnv_DERIVED_PlatformModelKeepsPlatformCreds(t *t
|
||||
t.Setenv("MOLECULE_LLM_USAGE_TOKEN", "tenant-admin-token")
|
||||
|
||||
envVars := map[string]string{}
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "anthropic/claude-opus-4-7")
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "anthropic/claude-opus-4-7", nil)
|
||||
|
||||
if res.ResolvedMode != LLMBillingModePlatformManaged {
|
||||
t.Fatalf("platform-derived model must resolve platform_managed, got %q (source=%s)", res.ResolvedMode, res.Source)
|
||||
@@ -1308,7 +1308,7 @@ func TestApplyPlatformManagedLLMEnv_DERIVED_ByokNoCredentialFailsClosed(t *testi
|
||||
// No LLM credential at all — neither global nor workspace scope.
|
||||
envVars := map[string]string{}
|
||||
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "kimi-for-coding")
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "kimi-for-coding", nil)
|
||||
|
||||
// 1. DERIVED byok (NOT the old platform_managed default).
|
||||
if res.ResolvedMode != LLMBillingModeBYOK {
|
||||
@@ -1346,7 +1346,7 @@ func TestApplyPlatformManagedLLMEnv_DERIVED_UnsetModelPlatformDefault(t *testing
|
||||
t.Setenv("MOLECULE_LLM_USAGE_TOKEN", "tenant-admin-token")
|
||||
|
||||
envVars := map[string]string{}
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "")
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "", nil)
|
||||
|
||||
if res.ResolvedMode != LLMBillingModePlatformManaged {
|
||||
t.Fatalf("unset model must default platform_managed, got %q (source=%s)", res.ResolvedMode, res.Source)
|
||||
@@ -1385,7 +1385,7 @@ func TestApplyPlatformManagedLLMEnv_ByokKeepsWorkspaceOwnOAuth(t *testing.T) {
|
||||
"MODEL": "opus",
|
||||
}
|
||||
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "")
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "", nil)
|
||||
|
||||
if got := envVars["CLAUDE_CODE_OAUTH_TOKEN"]; got != "CUSTOMER-OWN-OAUTH-TOKEN" {
|
||||
t.Fatalf("CLAUDE_CODE_OAUTH_TOKEN = %q, want the workspace's own token left intact", got)
|
||||
@@ -1425,7 +1425,7 @@ func TestApplyPlatformManagedLLMEnv_DisabledKeepsTenantGlobalNoProxy(t *testing.
|
||||
"CLAUDE_CODE_OAUTH_TOKEN": "TENANT-OWN-GLOBAL-OAUTH",
|
||||
}
|
||||
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "")
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "", nil)
|
||||
|
||||
// The tenant's own global cred survives (not stripped).
|
||||
if envVars["CLAUDE_CODE_OAUTH_TOKEN"] != "TENANT-OWN-GLOBAL-OAUTH" {
|
||||
@@ -1466,7 +1466,7 @@ func TestApplyPlatformManagedLLMEnv_PlatformManagedStillReceivesGlobalCreds(t *t
|
||||
"MODEL": "opus",
|
||||
}
|
||||
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "")
|
||||
res := applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "", nil)
|
||||
|
||||
// Platform-managed routes through the CP proxy: OAuth stripped, proxy creds forced.
|
||||
if _, ok := envVars["CLAUDE_CODE_OAUTH_TOKEN"]; ok {
|
||||
@@ -1507,7 +1507,7 @@ func TestApplyPlatformManagedLLMEnv_PlatformManagedStillEmitsResolvedMode(t *tes
|
||||
"CLAUDE_CODE_OAUTH_TOKEN": "user-oauth-token",
|
||||
"MODEL": "sonnet",
|
||||
}
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "")
|
||||
applyPlatformManagedLLMEnv(context.Background(), envVars, wsID, "claude-code", "", nil)
|
||||
|
||||
// OAuth stripped, proxy forced — unchanged platform_managed contract.
|
||||
if _, ok := envVars["CLAUDE_CODE_OAUTH_TOKEN"]; ok {
|
||||
|
||||
Reference in New Issue
Block a user