-
Notifications
You must be signed in to change notification settings - Fork 55
Description
Problem
Users can create sessions that immediately get stuck in Pending → Failed because required secrets (ambient-runner-secrets with ANTHROPIC_API_KEY) are missing. The operator catches this during reconciliation and sets SecretsReady=False with reason RunnerSecretMissing, but by then the user has already created a broken session and is staring at a "Pending" status with no actionable guidance.
The validation happens too late — at the operator level during pod provisioning — instead of at session creation time.
Expected Behavior
- Users cannot create a session unless the required API key is configured for the workspace
- The "Create Session" button is disabled with a clear message when prerequisites are missing
- The UI guides users to the Settings page to configure their API key first
Root Cause
The session creation flow has no pre-flight validation:
- Frontend (
components/frontend/src/components/create-session-dialog.tsx) — validates form fields (model, temperature, etc.) but does NOT check whether API keys exist - Backend (
components/backend/handlers/sessions.go:524-730) — creates theAgenticSessionCR immediately without checking for secrets - Operator (
components/operator/internal/handlers/sessions.go:637-687) — checks forambient-runner-secretsduring reconciliation, fails the session if missing
The integrations status endpoint (GET /api/auth/integrations/status) does not report API key configuration status, so the frontend has no way to know.
Implementation Plan
1. Backend — Add pre-flight check endpoint
File: components/backend/handlers/secrets.go
Add a new handler:
// GetRunnerSecretsStatus handles GET /api/projects/:projectName/runner-secrets/status
// Returns whether required runner secrets are configured (without exposing values).
func GetRunnerSecretsStatus(c *gin.Context) {
projectName := c.Param("projectName")
k8sClient, _ := GetK8sClientsForRequest(c)
// ...
secret, err := k8sClient.CoreV1().Secrets(projectName).Get(ctx, "ambient-runner-secrets", ...)
vertexEnabled := os.Getenv("CLAUDE_CODE_USE_VERTEX") == "1"
response := gin.H{
"configured": false,
"vertexEnabled": vertexEnabled,
}
if vertexEnabled {
// Check for ambient-vertex secret in operator namespace instead
response["configured"] = true // Vertex keys are cluster-level, not per-workspace
} else if secret != nil {
_, hasKey := secret.Data["ANTHROPIC_API_KEY"]
response["configured"] = hasKey && len(secret.Data["ANTHROPIC_API_KEY"]) > 0
}
c.JSON(http.StatusOK, response)
}File: components/backend/routes.go
Add route:
projectGroup.GET("/runner-secrets/status", handlers.GetRunnerSecretsStatus)2. Frontend — Add proxy route
File: components/frontend/src/app/api/projects/[name]/runner-secrets/status/route.ts
Standard GET proxy following existing pattern.
3. Frontend — Add API function and query hook
File: components/frontend/src/services/api/secrets.ts (or wherever runner-secrets API lives)
export type RunnerSecretsStatus = {
configured: boolean;
vertexEnabled: boolean;
};
export async function getRunnerSecretsStatus(projectName: string): Promise<RunnerSecretsStatus> {
return apiClient.get<RunnerSecretsStatus>(`/projects/${projectName}/runner-secrets/status`);
}Add a useRunnerSecretsStatus(projectName) query hook.
4. Frontend — Gate session creation in dialog
File: components/frontend/src/components/create-session-dialog.tsx
- Call
useRunnerSecretsStatus(projectName) - If
!status.configured && !status.vertexEnabled:- Show a warning banner at the top of the dialog: "An Anthropic API key is required to create sessions. Configure it in workspace Settings."
- Include a link/button to navigate to the Settings page
- Disable the "Create" submit button
- If
status.vertexEnabled, no API key warning needed (Vertex uses cluster-level credentials)
5. Backend — Optional: reject at CreateSession handler
File: components/backend/handlers/sessions.go
As defense-in-depth, add a check in CreateSession() before creating the CR:
// Check runner secrets before creating session
vertexEnabled := os.Getenv("CLAUDE_CODE_USE_VERTEX") == "1"
if !vertexEnabled {
_, err := k8sClient.CoreV1().Secrets(projectName).Get(ctx, "ambient-runner-secrets", metav1.GetOptions{})
if err != nil {
c.JSON(http.StatusPreconditionFailed, gin.H{
"error": "ANTHROPIC_API_KEY not configured. Go to workspace Settings to add it.",
"code": "MISSING_API_KEY",
})
return
}
}This ensures the API also rejects session creation even if the frontend check is bypassed.
Files to Create/Modify
| File | Action |
|---|---|
components/backend/handlers/secrets.go |
Add GetRunnerSecretsStatus handler |
components/backend/routes.go |
Add GET /runner-secrets/status route |
components/backend/handlers/sessions.go |
Add pre-creation secret check in CreateSession |
components/frontend/src/app/api/projects/[name]/runner-secrets/status/route.ts |
Create proxy route |
components/frontend/src/services/api/secrets.ts |
Add getRunnerSecretsStatus() function |
components/frontend/src/services/queries/use-secrets.ts |
Add useRunnerSecretsStatus() hook |
components/frontend/src/components/create-session-dialog.tsx |
Gate creation on API key status |
Verification
- Without API key configured: "Create Session" button disabled, warning shown with link to Settings
- After configuring API key in Settings: "Create Session" button enabled, session starts normally
- With Vertex AI enabled: no warning, creation allowed (cluster-level credentials)
- Direct API call without key: returns 412 Precondition Failed with actionable error message