Skip to content

Prevent session creation when API keys are not configured #626

Description

@jeremyeder

Problem

Users can create sessions that immediately get stuck in PendingFailed 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:

  1. Frontend (components/frontend/src/components/create-session-dialog.tsx) — validates form fields (model, temperature, etc.) but does NOT check whether API keys exist
  2. Backend (components/backend/handlers/sessions.go:524-730) — creates the AgenticSession CR immediately without checking for secrets
  3. Operator (components/operator/internal/handlers/sessions.go:637-687) — checks for ambient-runner-secrets during 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

  1. Without API key configured: "Create Session" button disabled, warning shown with link to Settings
  2. After configuring API key in Settings: "Create Session" button enabled, session starts normally
  3. With Vertex AI enabled: no warning, creation allowed (cluster-level credentials)
  4. Direct API call without key: returns 412 Precondition Failed with actionable error message

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ambient-code:auto-fixAmber agent: automated low-risk fixes (formatting, linting)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions