diff --git a/api/v1alpha1/task_types.go b/api/v1alpha1/task_types.go index dfce1d83..33c6bd90 100644 --- a/api/v1alpha1/task_types.go +++ b/api/v1alpha1/task_types.go @@ -13,6 +13,9 @@ const ( CredentialTypeAPIKey CredentialType = "api-key" // CredentialTypeOAuth uses OAuth for authentication. CredentialTypeOAuth CredentialType = "oauth" + // CredentialTypeNone disables built-in credential injection. + // Users supply their own credentials via PodOverrides.Env. + CredentialTypeNone CredentialType = "none" ) // TaskPhase represents the current phase of a Task. @@ -39,12 +42,14 @@ type SecretReference struct { // Credentials defines how to authenticate with the AI agent. type Credentials struct { - // Type specifies the credential type (api-key or oauth). - // +kubebuilder:validation:Enum=api-key;oauth + // Type specifies the credential type. + // +kubebuilder:validation:Enum=api-key;oauth;none Type CredentialType `json:"type"` // SecretRef references the Secret containing credentials. - SecretRef SecretReference `json:"secretRef"` + // Required for api-key and oauth types. Not used with none. + // +optional + SecretRef *SecretReference `json:"secretRef,omitempty"` } // PodOverrides defines optional overrides for the agent pod. @@ -69,6 +74,12 @@ type PodOverrides struct { // NodeSelector constrains agent pods to nodes matching the given labels. // +optional NodeSelector map[string]string `json:"nodeSelector,omitempty"` + + // ServiceAccountName sets the pod's service account. + // Use with workload identity systems such as IRSA on EKS, GKE + // Workload Identity, or Azure Workload Identity. + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` } // TaskSpec defines the desired state of Task. @@ -84,6 +95,7 @@ type TaskSpec struct { // Credentials specifies how to authenticate with the agent. // +kubebuilder:validation:Required + // +kubebuilder:validation:XValidation:rule="self.type == 'none' || has(self.secretRef)",message="secretRef is required for api-key and oauth credential types" Credentials Credentials `json:"credentials"` // Model optionally overrides the default model. diff --git a/api/v1alpha1/taskspawner_types.go b/api/v1alpha1/taskspawner_types.go index d35020e6..f4dd0e7d 100644 --- a/api/v1alpha1/taskspawner_types.go +++ b/api/v1alpha1/taskspawner_types.go @@ -304,6 +304,7 @@ type TaskTemplate struct { // Credentials specifies how to authenticate with the agent. // +kubebuilder:validation:Required + // +kubebuilder:validation:XValidation:rule="self.type == 'none' || has(self.secretRef)",message="secretRef is required for api-key and oauth credential types" Credentials Credentials `json:"credentials"` // Model optionally overrides the default model. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 69bc880b..83ace025 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -151,7 +151,11 @@ func (in *AgentDefinition) DeepCopy() *AgentDefinition { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Credentials) DeepCopyInto(out *Credentials) { *out = *in - out.SecretRef = in.SecretRef + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(SecretReference) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Credentials. @@ -703,7 +707,7 @@ func (in *TaskSpawnerStatus) DeepCopy() *TaskSpawnerStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TaskSpec) DeepCopyInto(out *TaskSpec) { *out = *in - out.Credentials = in.Credentials + in.Credentials.DeepCopyInto(&out.Credentials) if in.WorkspaceRef != nil { in, out := &in.WorkspaceRef, &out.WorkspaceRef *out = new(WorkspaceReference) @@ -779,7 +783,7 @@ func (in *TaskStatus) DeepCopy() *TaskStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TaskTemplate) DeepCopyInto(out *TaskTemplate) { *out = *in - out.Credentials = in.Credentials + in.Credentials.DeepCopyInto(&out.Credentials) if in.WorkspaceRef != nil { in, out := &in.WorkspaceRef, &out.WorkspaceRef *out = new(WorkspaceReference) diff --git a/cmd/kelos-spawner/main_test.go b/cmd/kelos-spawner/main_test.go index 0cec6029..5b4cb21f 100644 --- a/cmd/kelos-spawner/main_test.go +++ b/cmd/kelos-spawner/main_test.go @@ -77,7 +77,7 @@ func newTaskSpawner(name, namespace string, maxConcurrency *int32) *kelosv1alpha Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "creds"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "creds"}, }, WorkspaceRef: &kelosv1alpha1.WorkspaceReference{Name: "test-ws"}, }, @@ -100,7 +100,7 @@ func newTask(name, namespace, spawnerName string, phase kelosv1alpha1.TaskPhase) Prompt: "test", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "creds"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "creds"}, }, }, Status: kelosv1alpha1.TaskStatus{ @@ -212,7 +212,7 @@ func TestBuildSource_Jira(t *testing.T) { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "creds"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "creds"}, }, }, }, @@ -1186,7 +1186,7 @@ func newCompletedTask(name, namespace, spawnerName string, phase kelosv1alpha1.T Prompt: "test", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "creds"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "creds"}, }, }, Status: kelosv1alpha1.TaskStatus{ @@ -1520,7 +1520,7 @@ func TestRunCycleWithSource_PropagatesUpstreamRepo(t *testing.T) { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, }, @@ -1563,7 +1563,7 @@ func TestRunCycleWithSource_ExplicitUpstreamRepoTakesPrecedence(t *testing.T) { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, UpstreamRepo: "explicit-org/explicit-repo", }, @@ -1843,7 +1843,7 @@ func TestRunReportingCycle_ReportsForAnnotatedTasks(t *testing.T) { Prompt: "test", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "creds"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "creds"}, }, }, Status: kelosv1alpha1.TaskStatus{ @@ -1904,7 +1904,7 @@ func TestRunReportingCycle_SkipsTasksWithoutReporting(t *testing.T) { Prompt: "test", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "creds"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "creds"}, }, }, Status: kelosv1alpha1.TaskStatus{ diff --git a/examples/09-bedrock-credentials/README.md b/examples/09-bedrock-credentials/README.md new file mode 100644 index 00000000..e51f0402 --- /dev/null +++ b/examples/09-bedrock-credentials/README.md @@ -0,0 +1,52 @@ +# Bedrock Credentials + +This example demonstrates running a Claude Code task using AWS Bedrock instead of the Anthropic API directly. It uses the `none` credential type with `podOverrides` to inject provider-specific environment variables. + +## Prerequisites + +- AWS account with Bedrock access enabled for Claude models +- AWS IAM credentials with `bedrock:InvokeModel`, `bedrock:InvokeModelWithResponseStream`, and `bedrock:ListInferenceProfiles` permissions + +## Option 1: Static Credentials (Secret) + +1. Create the Secret with your AWS credentials: + + ```bash + kubectl create secret generic bedrock-credentials \ + --from-literal=AWS_ACCESS_KEY_ID= \ + --from-literal=AWS_SECRET_ACCESS_KEY= \ + --from-literal=AWS_REGION=us-east-1 + ``` + +2. Create the Task: + + ```bash + kubectl apply -f task.yaml + ``` + +## Option 2: IAM Roles for Service Accounts (IRSA) + +On EKS, you can use IRSA instead of static credentials. The AWS SDK automatically picks up credentials from the projected service account token — no Secret needed. + +### Prerequisites + +1. Create an IAM role with Bedrock permissions +2. Create a Kubernetes ServiceAccount annotated with the IAM role: + + ```bash + kubectl create serviceaccount bedrock-agent-sa + kubectl annotate serviceaccount bedrock-agent-sa \ + eks.amazonaws.com/role-arn=arn:aws:iam::123456789012:role/bedrock-agent-role + ``` + +3. Create the Task: + + ```bash + kubectl apply -f task-irsa.yaml + ``` + +## How it works + +The `none` credential type tells Kelos not to inject any built-in credentials. Instead, you supply provider-specific env vars via `podOverrides.env` and optionally set `podOverrides.serviceAccountName` for workload identity. + +This pattern works for any provider (Bedrock, Vertex AI, Azure OpenAI, etc.) — just change the environment variables. diff --git a/examples/09-bedrock-credentials/secret.yaml b/examples/09-bedrock-credentials/secret.yaml new file mode 100644 index 00000000..020b0abb --- /dev/null +++ b/examples/09-bedrock-credentials/secret.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Secret +metadata: + name: bedrock-credentials +type: Opaque +stringData: + # TODO: Replace with your AWS credentials + AWS_ACCESS_KEY_ID: "AKIAIOSFODNN7EXAMPLE" + AWS_SECRET_ACCESS_KEY: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + AWS_REGION: "us-east-1" + # Optional: uncomment if using temporary credentials (e.g. STS AssumeRole) + # AWS_SESSION_TOKEN: "your-session-token" + # Optional: uncomment to use a custom Bedrock endpoint + # ANTHROPIC_BEDROCK_BASE_URL: "https://bedrock-runtime.us-east-1.amazonaws.com" diff --git a/examples/09-bedrock-credentials/task-irsa.yaml b/examples/09-bedrock-credentials/task-irsa.yaml new file mode 100644 index 00000000..868a6293 --- /dev/null +++ b/examples/09-bedrock-credentials/task-irsa.yaml @@ -0,0 +1,16 @@ +apiVersion: kelos.dev/v1alpha1 +kind: Task +metadata: + name: bedrock-irsa-task +spec: + type: claude-code + prompt: "Write a Python script that prints the first 20 Fibonacci numbers." + credentials: + type: none + podOverrides: + serviceAccountName: bedrock-agent-sa + env: + - name: CLAUDE_CODE_USE_BEDROCK + value: "1" + - name: AWS_REGION + value: us-east-1 diff --git a/examples/09-bedrock-credentials/task.yaml b/examples/09-bedrock-credentials/task.yaml new file mode 100644 index 00000000..06fbc8f5 --- /dev/null +++ b/examples/09-bedrock-credentials/task.yaml @@ -0,0 +1,28 @@ +apiVersion: kelos.dev/v1alpha1 +kind: Task +metadata: + name: bedrock-task +spec: + type: claude-code + prompt: "Write a Python script that prints the first 20 Fibonacci numbers." + credentials: + type: none + podOverrides: + env: + - name: CLAUDE_CODE_USE_BEDROCK + value: "1" + - name: AWS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: bedrock-credentials + key: AWS_ACCESS_KEY_ID + - name: AWS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: bedrock-credentials + key: AWS_SECRET_ACCESS_KEY + - name: AWS_REGION + valueFrom: + secretKeyRef: + name: bedrock-credentials + key: AWS_REGION diff --git a/internal/cli/dryrun_test.go b/internal/cli/dryrun_test.go index 77c43749..74747e84 100644 --- a/internal/cli/dryrun_test.go +++ b/internal/cli/dryrun_test.go @@ -828,6 +828,141 @@ func TestRunCommand_DryRun_CodexOAuthToken_FileRef(t *testing.T) { } } +func TestRunCommand_DryRun_NoneCredentialType(t *testing.T) { + dir := t.TempDir() + cfgPath := filepath.Join(dir, "config.yaml") + if err := os.WriteFile(cfgPath, []byte(""), 0o644); err != nil { + t.Fatal(err) + } + + cmd := NewRootCommand() + cmd.SetArgs([]string{ + "run", + "--config", cfgPath, + "--dry-run", + "--prompt", "hello", + "--name", "none-cred-task", + "--namespace", "test-ns", + "--credential-type", "none", + }) + + old := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + if err := cmd.Execute(); err != nil { + w.Close() + os.Stdout = old + t.Fatalf("unexpected error: %v", err) + } + + w.Close() + os.Stdout = old + var out bytes.Buffer + out.ReadFrom(r) + output := out.String() + + if !strings.Contains(output, "kind: Task") { + t.Errorf("expected 'kind: Task' in output, got:\n%s", output) + } + if !strings.Contains(output, "type: none") { + t.Errorf("expected credential 'type: none' in output, got:\n%s", output) + } + // none credential type should not produce a secretRef. + if strings.Contains(output, "secretRef") { + t.Errorf("none credential type should not include secretRef, got:\n%s", output) + } +} + +func TestRunCommand_DryRun_NoneCredentialType_WithEnv(t *testing.T) { + dir := t.TempDir() + cfgPath := filepath.Join(dir, "config.yaml") + if err := os.WriteFile(cfgPath, []byte(""), 0o644); err != nil { + t.Fatal(err) + } + + cmd := NewRootCommand() + cmd.SetArgs([]string{ + "run", + "--config", cfgPath, + "--dry-run", + "--prompt", "hello", + "--name", "none-env-task", + "--namespace", "test-ns", + "--credential-type", "none", + "--env", "CLAUDE_CODE_USE_BEDROCK=1", + "--env", "AWS_REGION=us-east-1", + }) + + old := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + if err := cmd.Execute(); err != nil { + w.Close() + os.Stdout = old + t.Fatalf("unexpected error: %v", err) + } + + w.Close() + os.Stdout = old + var out bytes.Buffer + out.ReadFrom(r) + output := out.String() + + if !strings.Contains(output, "type: none") { + t.Errorf("expected credential 'type: none' in output, got:\n%s", output) + } + if !strings.Contains(output, "CLAUDE_CODE_USE_BEDROCK") { + t.Errorf("expected CLAUDE_CODE_USE_BEDROCK env var in output, got:\n%s", output) + } + if !strings.Contains(output, "AWS_REGION") { + t.Errorf("expected AWS_REGION env var in output, got:\n%s", output) + } +} + +func TestRunCommand_DryRun_NoneCredentialType_ConfigFile(t *testing.T) { + dir := t.TempDir() + cfgPath := filepath.Join(dir, "config.yaml") + cfg := "credentialType: none\n" + if err := os.WriteFile(cfgPath, []byte(cfg), 0o644); err != nil { + t.Fatal(err) + } + + cmd := NewRootCommand() + cmd.SetArgs([]string{ + "run", + "--config", cfgPath, + "--dry-run", + "--prompt", "hello", + "--name", "none-cfg-task", + "--namespace", "test-ns", + }) + + old := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + if err := cmd.Execute(); err != nil { + w.Close() + os.Stdout = old + t.Fatalf("unexpected error: %v", err) + } + + w.Close() + os.Stdout = old + var out bytes.Buffer + out.ReadFrom(r) + output := out.String() + + if !strings.Contains(output, "type: none") { + t.Errorf("expected credential 'type: none' in output, got:\n%s", output) + } + if strings.Contains(output, "secretRef") { + t.Errorf("none credential type should not include secretRef, got:\n%s", output) + } +} + func TestResolveContent(t *testing.T) { t.Run("empty", func(t *testing.T) { got, err := resolveContent("") diff --git a/internal/cli/printer.go b/internal/cli/printer.go index e20c90fd..930e1192 100644 --- a/internal/cli/printer.go +++ b/internal/cli/printer.go @@ -64,7 +64,9 @@ func printTaskDetail(w io.Writer, t *kelosv1alpha1.Task) { printField(w, "Type", t.Spec.Type) printField(w, "Phase", string(t.Status.Phase)) printField(w, "Prompt", t.Spec.Prompt) - printField(w, "Secret", t.Spec.Credentials.SecretRef.Name) + if t.Spec.Credentials.SecretRef != nil { + printField(w, "Secret", t.Spec.Credentials.SecretRef.Name) + } printField(w, "Credential Type", string(t.Spec.Credentials.Type)) if t.Spec.Model != "" { printField(w, "Model", t.Spec.Model) diff --git a/internal/cli/printer_test.go b/internal/cli/printer_test.go index 80330601..e74ec1b6 100644 --- a/internal/cli/printer_test.go +++ b/internal/cli/printer_test.go @@ -739,7 +739,7 @@ func TestPrintTaskDetail(t *testing.T) { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, Model: "claude-sonnet-4-20250514", Image: "custom-image:latest", @@ -993,7 +993,7 @@ func TestPrintTaskDetailMinimal(t *testing.T) { Prompt: "Do something", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "secret"}, }, }, Status: kelosv1alpha1.TaskStatus{ diff --git a/internal/cli/run.go b/internal/cli/run.go index c85a7aa3..86983431 100644 --- a/internal/cli/run.go +++ b/internal/cli/run.go @@ -79,8 +79,15 @@ func newRunCommand(cfg *ClientConfig) *cobra.Command { // Auto-create secret from token if no explicit secret is set. if secret == "" && cfg.Config != nil { - if cfg.Config.OAuthToken != "" && cfg.Config.APIKey != "" { - return fmt.Errorf("config file must specify either oauthToken or apiKey, not both") + sources := 0 + if cfg.Config.OAuthToken != "" { + sources++ + } + if cfg.Config.APIKey != "" { + sources++ + } + if sources > 1 { + return fmt.Errorf("config file must specify only one of oauthToken or apiKey") } if token := cfg.Config.OAuthToken; token != "" { resolved, err := resolveContent(token) @@ -111,7 +118,7 @@ func newRunCommand(cfg *ClientConfig) *cobra.Command { } } - if secret == "" { + if secret == "" && credentialType != "none" { return fmt.Errorf("no credentials configured (set oauthToken/apiKey in config file, or use --secret flag)") } @@ -193,22 +200,24 @@ func newRunCommand(cfg *ClientConfig) *cobra.Command { name = "task-" + rand.String(5) } + creds := kelosv1alpha1.Credentials{ + Type: kelosv1alpha1.CredentialType(credentialType), + } + if secret != "" { + creds.SecretRef = &kelosv1alpha1.SecretReference{Name: secret} + } + task := &kelosv1alpha1.Task{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: ns, }, Spec: kelosv1alpha1.TaskSpec{ - Type: agentType, - Prompt: prompt, - Credentials: kelosv1alpha1.Credentials{ - Type: kelosv1alpha1.CredentialType(credentialType), - SecretRef: kelosv1alpha1.SecretReference{ - Name: secret, - }, - }, - Model: model, - Image: image, + Type: agentType, + Prompt: prompt, + Credentials: creds, + Model: model, + Image: image, }, } @@ -288,7 +297,7 @@ func newRunCommand(cfg *ClientConfig) *cobra.Command { cmd.Flags().StringVarP(&prompt, "prompt", "p", "", "task prompt (required)") cmd.Flags().StringVarP(&agentType, "type", "t", "claude-code", "agent type (claude-code, codex, gemini, opencode, cursor)") cmd.Flags().StringVar(&secret, "secret", "", "secret name with credentials (overrides oauthToken/apiKey in config)") - cmd.Flags().StringVar(&credentialType, "credential-type", "api-key", "credential type (api-key, oauth)") + cmd.Flags().StringVar(&credentialType, "credential-type", "api-key", "credential type (api-key, oauth, none)") cmd.Flags().StringVar(&model, "model", "", "model override") cmd.Flags().StringVar(&image, "image", "", "custom agent image (must implement agent image interface)") cmd.Flags().StringVar(&name, "name", "", "task name (auto-generated if omitted)") @@ -304,7 +313,7 @@ func newRunCommand(cfg *ClientConfig) *cobra.Command { cmd.MarkFlagRequired("prompt") - _ = cmd.RegisterFlagCompletionFunc("credential-type", cobra.FixedCompletions([]string{"api-key", "oauth"}, cobra.ShellCompDirectiveNoFileComp)) + _ = cmd.RegisterFlagCompletionFunc("credential-type", cobra.FixedCompletions([]string{"api-key", "oauth", "none"}, cobra.ShellCompDirectiveNoFileComp)) _ = cmd.RegisterFlagCompletionFunc("type", cobra.FixedCompletions([]string{"claude-code", "codex", "gemini", "opencode", "cursor"}, cobra.ShellCompDirectiveNoFileComp)) return cmd diff --git a/internal/controller/job_builder.go b/internal/controller/job_builder.go index 57517c1a..5c3fc7cc 100644 --- a/internal/controller/job_builder.go +++ b/internal/controller/job_builder.go @@ -168,6 +168,53 @@ func oauthEnvVar(agentType string) string { } } +// credentialEnvVars returns the environment variables to inject for the given +// credentials and agent type. This centralises all credential-type-specific +// logic so that new providers (e.g. Vertex) only need to add a case here. +func credentialEnvVars(creds kelosv1alpha1.Credentials, agentType string) []corev1.EnvVar { + secretName := "" + if creds.SecretRef != nil { + secretName = creds.SecretRef.Name + } + + secretEnvRef := func(key string, optional bool) corev1.EnvVar { + sel := &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{Name: secretName}, + Key: key, + } + if optional { + sel.Optional = ptr(true) + } + return corev1.EnvVar{ + Name: key, + ValueFrom: &corev1.EnvVarSource{SecretKeyRef: sel}, + } + } + + switch creds.Type { + case kelosv1alpha1.CredentialTypeAPIKey: + keyName := apiKeyEnvVar(agentType) + return []corev1.EnvVar{secretEnvRef(keyName, false)} + + case kelosv1alpha1.CredentialTypeOAuth: + tokenName := oauthEnvVar(agentType) + return []corev1.EnvVar{secretEnvRef(tokenName, false)} + + case kelosv1alpha1.CredentialTypeNone: + // No built-in credential injection; users supply their own + // credentials via PodOverrides.Env. + return nil + + default: + return nil + } +} + +// ptr returns a pointer to the given value. +func ptr[T any](v T) *T { + return &v +} + func effectiveWorkspaceRemotes(workspace *kelosv1alpha1.WorkspaceSpec) []kelosv1alpha1.GitRemote { if workspace == nil { return nil @@ -224,34 +271,8 @@ func (b *JobBuilder) buildAgentJob(task *kelosv1alpha1.Task, workspace *kelosv1a }) } - switch task.Spec.Credentials.Type { - case kelosv1alpha1.CredentialTypeAPIKey: - keyName := apiKeyEnvVar(task.Spec.Type) - envVars = append(envVars, corev1.EnvVar{ - Name: keyName, - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: task.Spec.Credentials.SecretRef.Name, - }, - Key: keyName, - }, - }, - }) - case kelosv1alpha1.CredentialTypeOAuth: - tokenName := oauthEnvVar(task.Spec.Type) - envVars = append(envVars, corev1.EnvVar{ - Name: tokenName, - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: task.Spec.Credentials.SecretRef.Name, - }, - Key: tokenName, - }, - }, - }) - } + credEnvVars := credentialEnvVars(task.Spec.Credentials, task.Spec.Type) + envVars = append(envVars, credEnvVars...) var workspaceEnvVars []corev1.EnvVar var isEnterprise bool @@ -546,6 +567,7 @@ func (b *JobBuilder) buildAgentJob(task *kelosv1alpha1.Task, workspace *kelosv1a // Apply PodOverrides before constructing the Job so all overrides // are reflected in the final spec. + var serviceAccountName string var activeDeadlineSeconds *int64 var nodeSelector map[string]string @@ -575,6 +597,10 @@ func (b *JobBuilder) buildAgentJob(task *kelosv1alpha1.Task, workspace *kelosv1a if po.NodeSelector != nil { nodeSelector = po.NodeSelector } + + if po.ServiceAccountName != "" { + serviceAccountName = po.ServiceAccountName + } } // PodFailurePolicy ensures only pod disruptions (e.g. node scale-down, @@ -626,12 +652,13 @@ func (b *JobBuilder) buildAgentJob(task *kelosv1alpha1.Task, workspace *kelosv1a }, }, Spec: corev1.PodSpec{ - RestartPolicy: corev1.RestartPolicyNever, - SecurityContext: podSecurityContext, - InitContainers: initContainers, - Volumes: volumes, - Containers: []corev1.Container{mainContainer}, - NodeSelector: nodeSelector, + RestartPolicy: corev1.RestartPolicyNever, + SecurityContext: podSecurityContext, + ServiceAccountName: serviceAccountName, + InitContainers: initContainers, + Volumes: volumes, + Containers: []corev1.Container{mainContainer}, + NodeSelector: nodeSelector, }, }, }, diff --git a/internal/controller/job_builder_test.go b/internal/controller/job_builder_test.go index 6729441d..69e5b783 100644 --- a/internal/controller/job_builder_test.go +++ b/internal/controller/job_builder_test.go @@ -25,7 +25,7 @@ func TestBuildClaudeCodeJob_DefaultImage(t *testing.T) { Prompt: "Hello world", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, Model: "claude-sonnet-4-20250514", }, @@ -80,7 +80,7 @@ func TestBuildClaudeCodeJob_CustomImage(t *testing.T) { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, Model: "my-model", Image: "my-custom-agent:latest", @@ -136,7 +136,7 @@ func TestBuildClaudeCodeJob_NoModel(t *testing.T) { Prompt: "Hello", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -168,7 +168,7 @@ func TestBuildClaudeCodeJob_WorkspaceWithRef(t *testing.T) { Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -235,7 +235,7 @@ func TestBuildClaudeCodeJob_WorkspaceWithInjectedFiles(t *testing.T) { Prompt: "Inject plugin files", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -307,7 +307,7 @@ func TestBuildClaudeCodeJob_WorkspaceWithInjectedFilesInvalidPath(t *testing.T) Prompt: "Inject plugin files", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -343,7 +343,7 @@ func TestBuildClaudeCodeJob_CustomImageWithWorkspace(t *testing.T) { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, Image: "my-agent:v1", Model: "gpt-4", @@ -425,7 +425,7 @@ func TestBuildClaudeCodeJob_WorkspaceWithSecretRefPersistsCredentialHelper(t *te Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -483,7 +483,7 @@ func TestBuildClaudeCodeJob_EnterpriseWorkspaceSetsGHHostAndEnterpriseToken(t *t Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -562,7 +562,7 @@ func TestBuildClaudeCodeJob_GithubComWorkspaceUsesGHToken(t *testing.T) { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -615,7 +615,7 @@ func TestBuildCodexJob_DefaultImage(t *testing.T) { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "openai-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "openai-secret"}, }, Model: "gpt-4.1", }, @@ -699,7 +699,7 @@ func TestBuildCodexJob_CustomImage(t *testing.T) { Prompt: "Refactor the module", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "openai-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "openai-secret"}, }, Image: "my-codex:v2", }, @@ -735,7 +735,7 @@ func TestBuildCodexJob_WithWorkspace(t *testing.T) { Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "openai-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "openai-secret"}, }, Model: "gpt-4.1", }, @@ -810,7 +810,7 @@ func TestBuildCodexJob_OAuthCredentials(t *testing.T) { Prompt: "Review the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "codex-oauth"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "codex-oauth"}, }, }, } @@ -862,7 +862,7 @@ func TestBuildGeminiJob_DefaultImage(t *testing.T) { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "gemini-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "gemini-secret"}, }, Model: "gemini-2.5-pro", }, @@ -949,7 +949,7 @@ func TestBuildGeminiJob_CustomImage(t *testing.T) { Prompt: "Refactor the module", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "gemini-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "gemini-secret"}, }, Image: "my-gemini:v2", }, @@ -985,7 +985,7 @@ func TestBuildGeminiJob_WithWorkspace(t *testing.T) { Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "gemini-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "gemini-secret"}, }, Model: "gemini-2.5-pro", }, @@ -1063,7 +1063,7 @@ func TestBuildGeminiJob_OAuthCredentials(t *testing.T) { Prompt: "Review the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "gemini-oauth"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "gemini-oauth"}, }, }, } @@ -1115,7 +1115,7 @@ func TestBuildOpenCodeJob_DefaultImage(t *testing.T) { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "opencode-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "opencode-secret"}, }, Model: "anthropic/claude-sonnet-4-20250514", }, @@ -1205,7 +1205,7 @@ func TestBuildOpenCodeJob_CustomImage(t *testing.T) { Prompt: "Refactor the module", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "opencode-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "opencode-secret"}, }, Image: "my-opencode:v2", }, @@ -1241,7 +1241,7 @@ func TestBuildOpenCodeJob_WithWorkspace(t *testing.T) { Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "opencode-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "opencode-secret"}, }, Model: "anthropic/claude-sonnet-4-20250514", }, @@ -1322,7 +1322,7 @@ func TestBuildOpenCodeJob_OAuthCredentials(t *testing.T) { Prompt: "Review the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "opencode-oauth"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "opencode-oauth"}, }, }, } @@ -1377,7 +1377,7 @@ func TestBuildCursorJob_DefaultImage(t *testing.T) { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "cursor-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "cursor-secret"}, }, Model: "claude-sonnet-4-20250514", }, @@ -1461,7 +1461,7 @@ func TestBuildCursorJob_CustomImage(t *testing.T) { Prompt: "Refactor the module", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "cursor-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "cursor-secret"}, }, Image: "my-cursor:v2", }, @@ -1495,7 +1495,7 @@ func TestBuildCursorJob_OAuthCredentials(t *testing.T) { Prompt: "Review the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "cursor-oauth"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "cursor-oauth"}, }, }, } @@ -1555,7 +1555,7 @@ func TestBuildClaudeCodeJob_UnsupportedType(t *testing.T) { Prompt: "Hello", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -1580,7 +1580,7 @@ func TestBuildJob_PodOverridesResources(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, PodOverrides: &kelosv1alpha1.PodOverrides{ Resources: &corev1.ResourceRequirements{ @@ -1634,7 +1634,7 @@ func TestBuildJob_PodOverridesActiveDeadlineSeconds(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, PodOverrides: &kelosv1alpha1.PodOverrides{ ActiveDeadlineSeconds: int64Ptr(1800), @@ -1667,7 +1667,7 @@ func TestBuildJob_PodOverridesEnv(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, Model: "claude-sonnet-4-20250514", PodOverrides: &kelosv1alpha1.PodOverrides{ @@ -1718,7 +1718,7 @@ func TestBuildJob_PodOverridesEnvBuiltinPrecedence(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, Model: "claude-sonnet-4-20250514", PodOverrides: &kelosv1alpha1.PodOverrides{ @@ -1765,7 +1765,7 @@ func TestBuildJob_PodOverridesNodeSelector(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, PodOverrides: &kelosv1alpha1.PodOverrides{ NodeSelector: map[string]string{ @@ -1805,7 +1805,7 @@ func TestBuildJob_PodOverridesAllFields(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "openai-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "openai-secret"}, }, PodOverrides: &kelosv1alpha1.PodOverrides{ Resources: &corev1.ResourceRequirements{ @@ -1871,7 +1871,7 @@ func TestBuildJob_NoPodOverrides(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -1911,7 +1911,7 @@ func TestBuildJob_AgentConfigAgentsMD(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -1962,7 +1962,7 @@ func TestBuildJob_AgentConfigPlugins(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2067,7 +2067,7 @@ func TestBuildJob_AgentConfigFull(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2126,7 +2126,7 @@ func TestBuildJob_AgentConfigSkills(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2235,7 +2235,7 @@ func TestBuildJob_AgentConfigSkillsWithPlugins(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2294,7 +2294,7 @@ func TestBuildJob_AgentConfigSkillsEmptySource(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2326,7 +2326,7 @@ func TestBuildJob_AgentConfigWithWorkspace(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2387,7 +2387,7 @@ func TestBuildJob_AgentConfigWithoutWorkspace(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2437,7 +2437,7 @@ func TestBuildJob_AgentConfigCodex(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2506,7 +2506,7 @@ func TestBuildJob_AgentConfigGemini(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2572,7 +2572,7 @@ func TestBuildJob_AgentConfigOpenCode(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2641,7 +2641,7 @@ func TestBuildJob_AgentConfigPluginNamePathTraversal(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2715,7 +2715,7 @@ func TestBuildJob_BranchSetupInitContainer(t *testing.T) { Branch: "feature-x", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2798,7 +2798,7 @@ func TestBuildJob_BranchSetupWithSecretRefUsesCredentialHelper(t *testing.T) { Branch: "feature-y", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2857,7 +2857,7 @@ func TestBuildJob_BranchWithoutWorkspaceNoInitContainer(t *testing.T) { Branch: "feature-z", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2898,7 +2898,7 @@ func TestBuildJob_BranchEnvDoesNotMutateWorkspaceEnvVars(t *testing.T) { Branch: "feature-w", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2952,7 +2952,7 @@ func TestBuildJob_KelosAgentTypeAlwaysSet(t *testing.T) { Prompt: "Hello", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -2991,7 +2991,7 @@ func TestBuildJob_AgentConfigMCPServers(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3098,7 +3098,7 @@ func TestBuildJob_AgentConfigMCPServersWithHTTPHeaders(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3161,7 +3161,7 @@ func TestBuildJob_AgentConfigMCPServersWithPluginsAndAgentsMD(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3230,7 +3230,7 @@ func TestBuildJob_AgentConfigMCPServersCodex(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "openai-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "openai-secret"}, }, }, } @@ -3274,7 +3274,7 @@ func TestBuildJob_AgentConfigMCPServersGemini(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "gemini-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "gemini-secret"}, }, }, } @@ -3318,7 +3318,7 @@ func TestBuildJob_AgentConfigMCPServersEmptyName(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3354,7 +3354,7 @@ func TestBuildJob_AgentConfigMCPServersDuplicateName(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3399,7 +3399,7 @@ func TestBuildJob_AgentConfigMCPServerNamePathTraversal(t *testing.T) { Prompt: "Fix issue", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3431,7 +3431,7 @@ func TestBuildJob_KelosBaseBranchSetWhenWorkspaceRefPresent(t *testing.T) { Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3473,7 +3473,7 @@ func TestBuildJob_KelosBaseBranchAbsentWhenRefEmpty(t *testing.T) { Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3507,7 +3507,7 @@ func TestBuildJob_KelosBaseBranchAbsentWithoutWorkspace(t *testing.T) { Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3537,7 +3537,7 @@ func TestBuildJob_WorkspaceWithOneRemote(t *testing.T) { Prompt: "Work on feature", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3588,7 +3588,7 @@ func TestBuildJob_WorkspaceWithMultipleRemotes(t *testing.T) { Prompt: "Work on feature", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3639,7 +3639,7 @@ func TestBuildJob_WorkspaceWithNoRemotesNoRemoteSetupContainer(t *testing.T) { Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3674,7 +3674,7 @@ func TestBuildJob_RemoteSetupOrderingWithBranchSetup(t *testing.T) { Branch: "feature-x", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3730,7 +3730,7 @@ func TestBuildJob_RemoteSetupQuotesShellMetacharacters(t *testing.T) { Prompt: "Do work", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3777,7 +3777,7 @@ func TestBuildJob_WorkspaceWithUpstreamRemoteInjectsEnv(t *testing.T) { Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3823,7 +3823,7 @@ func TestBuildJob_WorkspaceWithNonUpstreamRemoteNoEnv(t *testing.T) { Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3861,7 +3861,7 @@ func TestBuildJob_WorkspaceWithInvalidUpstreamRemoteNoEnv(t *testing.T) { Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3902,7 +3902,7 @@ func TestBuildJob_TaskSpawnerLabelInjectsEnv(t *testing.T) { Prompt: "Hello", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3939,7 +3939,7 @@ func TestBuildJob_NoTaskSpawnerLabelNoEnv(t *testing.T) { Prompt: "Hello", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -3969,7 +3969,7 @@ func TestBuildJob_PodFailurePolicy(t *testing.T) { Prompt: "Hello", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -4033,7 +4033,7 @@ func TestBuildJob_GHConfigDirNotSetWithoutSecretRef(t *testing.T) { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -4067,7 +4067,7 @@ func TestBuildJob_CustomImageGetsGHConfigDir(t *testing.T) { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, Image: "my-custom-agent:latest", }, @@ -4116,7 +4116,7 @@ func TestBuildJob_CredentialHelperClearsInheritedHelpers(t *testing.T) { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, }, } @@ -4168,7 +4168,7 @@ func TestBuildJob_UpstreamRepoSpecOverridesRemote(t *testing.T) { Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, UpstreamRepo: "override-org/override-repo", }, @@ -4215,7 +4215,7 @@ func TestBuildJob_UpstreamRepoSpecWithoutRemote(t *testing.T) { Prompt: "Fix the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "my-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "my-secret"}, }, UpstreamRepo: "upstream-org/upstream-repo", }, @@ -4246,3 +4246,113 @@ func TestBuildJob_UpstreamRepoSpecWithoutRemote(t *testing.T) { t.Error("Expected KELOS_UPSTREAM_REPO env var on main container") } } + +func TestBuildJob_NoneCredentials(t *testing.T) { + builder := NewJobBuilder() + task := &kelosv1alpha1.Task{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-none-creds", + Namespace: "default", + }, + Spec: kelosv1alpha1.TaskSpec{ + Type: AgentTypeClaudeCode, + Prompt: "Fix the bug", + Credentials: kelosv1alpha1.Credentials{ + Type: kelosv1alpha1.CredentialTypeNone, + }, + PodOverrides: &kelosv1alpha1.PodOverrides{ + Env: []corev1.EnvVar{ + {Name: "CLAUDE_CODE_USE_BEDROCK", Value: "1"}, + {Name: "AWS_REGION", Value: "us-east-1"}, + }, + }, + }, + } + + job, err := builder.Build(task, nil, nil, task.Spec.Prompt) + if err != nil { + t.Fatalf("Build() returned error: %v", err) + } + + container := job.Spec.Template.Spec.Containers[0] + + // Collect env vars by name for easier assertions. + envMap := make(map[string]corev1.EnvVar) + for _, env := range container.Env { + envMap[env.Name] = env + } + + // User-supplied env vars from PodOverrides should be present. + if env, ok := envMap["CLAUDE_CODE_USE_BEDROCK"]; !ok { + t.Error("Expected CLAUDE_CODE_USE_BEDROCK env var from PodOverrides") + } else if env.Value != "1" { + t.Errorf("CLAUDE_CODE_USE_BEDROCK = %q, want %q", env.Value, "1") + } + + if env, ok := envMap["AWS_REGION"]; !ok { + t.Error("Expected AWS_REGION env var from PodOverrides") + } else if env.Value != "us-east-1" { + t.Errorf("AWS_REGION = %q, want %q", env.Value, "us-east-1") + } + + // No built-in credential env vars should be set. + if _, ok := envMap["ANTHROPIC_API_KEY"]; ok { + t.Error("ANTHROPIC_API_KEY should not be set for none credential type") + } + if _, ok := envMap["CLAUDE_CODE_OAUTH_TOKEN"]; ok { + t.Error("CLAUDE_CODE_OAUTH_TOKEN should not be set for none credential type") + } +} + +func TestBuildJob_NoneCredentials_ServiceAccountName(t *testing.T) { + builder := NewJobBuilder() + task := &kelosv1alpha1.Task{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-none-sa", + Namespace: "default", + }, + Spec: kelosv1alpha1.TaskSpec{ + Type: AgentTypeClaudeCode, + Prompt: "Fix the bug", + Credentials: kelosv1alpha1.Credentials{ + Type: kelosv1alpha1.CredentialTypeNone, + }, + PodOverrides: &kelosv1alpha1.PodOverrides{ + ServiceAccountName: "bedrock-agent-sa", + Env: []corev1.EnvVar{ + {Name: "CLAUDE_CODE_USE_BEDROCK", Value: "1"}, + {Name: "AWS_REGION", Value: "us-west-2"}, + }, + }, + }, + } + + job, err := builder.Build(task, nil, nil, task.Spec.Prompt) + if err != nil { + t.Fatalf("Build() returned error: %v", err) + } + + // ServiceAccountName should be set on the pod spec from PodOverrides. + if job.Spec.Template.Spec.ServiceAccountName != "bedrock-agent-sa" { + t.Errorf("ServiceAccountName = %q, want %q", job.Spec.Template.Spec.ServiceAccountName, "bedrock-agent-sa") + } + + container := job.Spec.Template.Spec.Containers[0] + envMap := make(map[string]corev1.EnvVar) + for _, env := range container.Env { + envMap[env.Name] = env + } + + // User-supplied env vars should be present. + if env, ok := envMap["CLAUDE_CODE_USE_BEDROCK"]; !ok { + t.Error("Expected CLAUDE_CODE_USE_BEDROCK env var") + } else if env.Value != "1" { + t.Errorf("CLAUDE_CODE_USE_BEDROCK = %q, want %q", env.Value, "1") + } + + if env, ok := envMap["AWS_REGION"]; !ok { + t.Error("Expected AWS_REGION env var") + } else if env.Value != "us-west-2" { + t.Errorf("AWS_REGION = %q, want %q", env.Value, "us-west-2") + } +} diff --git a/internal/controller/task_controller_test.go b/internal/controller/task_controller_test.go index d4895345..a1323e9f 100644 --- a/internal/controller/task_controller_test.go +++ b/internal/controller/task_controller_test.go @@ -607,7 +607,7 @@ func TestUpdateStatusRefreshesPodName(t *testing.T) { Prompt: "test", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "creds", }, }, @@ -663,7 +663,7 @@ func TestUpdateStatusClearsStalePodNameWhenNoLivePodsRemain(t *testing.T) { Prompt: "test", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "creds", }, }, diff --git a/internal/controller/taskspawner_deployment_builder_test.go b/internal/controller/taskspawner_deployment_builder_test.go index c17ae3eb..ca7e4e73 100644 --- a/internal/controller/taskspawner_deployment_builder_test.go +++ b/internal/controller/taskspawner_deployment_builder_test.go @@ -1483,7 +1483,7 @@ func TestBuildCronJob_BasicSchedule(t *testing.T) { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "creds"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "creds"}, }, }, }, @@ -1611,7 +1611,7 @@ func TestIsCronBased(t *testing.T) { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "creds"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "creds"}, }, }, }, diff --git a/internal/manifests/install-crd.yaml b/internal/manifests/install-crd.yaml index 9cff7acd..af40d00d 100644 --- a/internal/manifests/install-crd.yaml +++ b/internal/manifests/install-crd.yaml @@ -304,7 +304,9 @@ spec: description: Credentials specifies how to authenticate with the agent. properties: secretRef: - description: SecretRef references the Secret containing credentials. + description: |- + SecretRef references the Secret containing credentials. + Required for api-key and oauth types. Not used with none. properties: name: description: Name is the name of the secret. @@ -313,15 +315,19 @@ spec: - name type: object type: - description: Type specifies the credential type (api-key or oauth). + description: Type specifies the credential type. enum: - api-key - oauth + - none type: string required: - - secretRef - type type: object + x-kubernetes-validations: + - message: secretRef is required for api-key and oauth credential + types + rule: self.type == 'none' || has(self.secretRef) dependsOn: description: DependsOn lists Task names that must succeed before this Task starts. @@ -575,6 +581,12 @@ spec: More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object + serviceAccountName: + description: |- + ServiceAccountName sets the pod's service account. + Use with workload identity systems such as IRSA on EKS, GKE + Workload Identity, or Azure Workload Identity. + type: string type: object prompt: description: Prompt is the task prompt to send to the agent. @@ -791,7 +803,9 @@ spec: agent. properties: secretRef: - description: SecretRef references the Secret containing credentials. + description: |- + SecretRef references the Secret containing credentials. + Required for api-key and oauth types. Not used with none. properties: name: description: Name is the name of the secret. @@ -800,16 +814,19 @@ spec: - name type: object type: - description: Type specifies the credential type (api-key or - oauth). + description: Type specifies the credential type. enum: - api-key - oauth + - none type: string required: - - secretRef - type type: object + x-kubernetes-validations: + - message: secretRef is required for api-key and oauth credential + types + rule: self.type == 'none' || has(self.secretRef) dependsOn: description: DependsOn lists Task names that spawned Tasks depend on. @@ -1064,6 +1081,12 @@ spec: More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object + serviceAccountName: + description: |- + ServiceAccountName sets the pod's service account. + Use with workload identity systems such as IRSA on EKS, GKE + Workload Identity, or Azure Workload Identity. + type: string type: object promptTemplate: description: |- diff --git a/internal/reporting/watcher_test.go b/internal/reporting/watcher_test.go index 9605af04..4c6b471f 100644 --- a/internal/reporting/watcher_test.go +++ b/internal/reporting/watcher_test.go @@ -107,7 +107,7 @@ func newTaskWithAnnotations(name, namespace string, phase kelosv1alpha1.TaskPhas Prompt: "test", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "creds"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "creds"}, }, }, Status: kelosv1alpha1.TaskStatus{ @@ -555,7 +555,7 @@ func TestReportTaskStatus_NilAnnotations(t *testing.T) { Prompt: "test", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "creds"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "creds"}, }, }, Status: kelosv1alpha1.TaskStatus{ diff --git a/test/e2e/opencode_test.go b/test/e2e/opencode_test.go index e8b92d13..05285dd3 100644 --- a/test/e2e/opencode_test.go +++ b/test/e2e/opencode_test.go @@ -31,7 +31,7 @@ var _ = Describe("OpenCode Task", func() { Prompt: "Print 'Hello from OpenCode e2e test' to stdout", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "opencode-credentials"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "opencode-credentials"}, }, }, }) diff --git a/test/e2e/skills_test.go b/test/e2e/skills_test.go index 11f09145..0adbf507 100644 --- a/test/e2e/skills_test.go +++ b/test/e2e/skills_test.go @@ -81,7 +81,7 @@ var _ = Describe("Task with skills.sh AgentConfig", func() { Prompt: "Print 'Hello from skills.sh e2e test' to stdout", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "claude-credentials"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "claude-credentials"}, }, AgentConfigRef: &kelosv1alpha1.AgentConfigReference{ Name: "skills-ac", diff --git a/test/e2e/task_test.go b/test/e2e/task_test.go index 360d1e5d..920eaece 100644 --- a/test/e2e/task_test.go +++ b/test/e2e/task_test.go @@ -37,7 +37,7 @@ func describeAgentTests(cfg agentTestConfig) { Prompt: "Print 'Hello from Kelos e2e test' to stdout", Credentials: kelosv1alpha1.Credentials{ Type: cfg.CredentialType, - SecretRef: kelosv1alpha1.SecretReference{Name: cfg.SecretName}, + SecretRef: &kelosv1alpha1.SecretReference{Name: cfg.SecretName}, }, }, }) @@ -92,7 +92,7 @@ func describeAgentTests(cfg agentTestConfig) { Prompt: "Create a file called 'test.txt' with the content 'hello' in the current directory and print 'done'", Credentials: kelosv1alpha1.Credentials{ Type: cfg.CredentialType, - SecretRef: kelosv1alpha1.SecretReference{Name: cfg.SecretName}, + SecretRef: &kelosv1alpha1.SecretReference{Name: cfg.SecretName}, }, WorkspaceRef: &kelosv1alpha1.WorkspaceReference{Name: "e2e-workspace"}, }, @@ -153,7 +153,7 @@ func describeAgentTests(cfg agentTestConfig) { Prompt: "Print 'hello' to stdout", Credentials: kelosv1alpha1.Credentials{ Type: cfg.CredentialType, - SecretRef: kelosv1alpha1.SecretReference{Name: cfg.SecretName}, + SecretRef: &kelosv1alpha1.SecretReference{Name: cfg.SecretName}, }, WorkspaceRef: &kelosv1alpha1.WorkspaceReference{Name: "e2e-outputs-workspace"}, }, @@ -225,7 +225,7 @@ func describeAgentTests(cfg agentTestConfig) { Prompt: "Print 'Task A done' to stdout", Credentials: kelosv1alpha1.Credentials{ Type: cfg.CredentialType, - SecretRef: kelosv1alpha1.SecretReference{Name: cfg.SecretName}, + SecretRef: &kelosv1alpha1.SecretReference{Name: cfg.SecretName}, }, }, }) @@ -242,7 +242,7 @@ func describeAgentTests(cfg agentTestConfig) { DependsOn: []string{"dep-chain-a"}, Credentials: kelosv1alpha1.Credentials{ Type: cfg.CredentialType, - SecretRef: kelosv1alpha1.SecretReference{Name: cfg.SecretName}, + SecretRef: &kelosv1alpha1.SecretReference{Name: cfg.SecretName}, }, }, }) @@ -288,7 +288,7 @@ func describeAgentTests(cfg agentTestConfig) { Prompt: "Print 'Hello' to stdout", Credentials: kelosv1alpha1.Credentials{ Type: cfg.CredentialType, - SecretRef: kelosv1alpha1.SecretReference{Name: cfg.SecretName}, + SecretRef: &kelosv1alpha1.SecretReference{Name: cfg.SecretName}, }, }, }) @@ -336,7 +336,7 @@ var _ = Describe("Task with make available", func() { Prompt: "Run 'make --version' and print the output", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "claude-credentials"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "claude-credentials"}, }, }, }) @@ -400,7 +400,7 @@ var _ = Describe("Task with workspace and secretRef", func() { Prompt: "Run 'gh auth status' and print the output", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "claude-credentials"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "claude-credentials"}, }, WorkspaceRef: &kelosv1alpha1.WorkspaceReference{Name: "e2e-github-workspace"}, }, diff --git a/test/e2e/taskspawner_test.go b/test/e2e/taskspawner_test.go index 471b963c..d1e12020 100644 --- a/test/e2e/taskspawner_test.go +++ b/test/e2e/taskspawner_test.go @@ -63,7 +63,7 @@ var _ = Describe("TaskSpawner", func() { }, Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "claude-credentials"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "claude-credentials"}, }, PromptTemplate: "Fix: {{.Title}}\n{{.Body}}", }, @@ -112,7 +112,7 @@ var _ = Describe("TaskSpawner", func() { }, Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "claude-credentials"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "claude-credentials"}, }, }, PollInterval: "5m", @@ -174,7 +174,7 @@ var _ = Describe("Cron TaskSpawner", func() { Model: testModel, Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "claude-credentials"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "claude-credentials"}, }, PromptTemplate: "Cron triggered at {{.Time}} (schedule: {{.Schedule}}). Print 'Hello from cron'", }, @@ -212,7 +212,7 @@ var _ = Describe("Cron TaskSpawner", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{Name: "claude-credentials"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "claude-credentials"}, }, }, PollInterval: "5m", diff --git a/test/integration/cli_test.go b/test/integration/cli_test.go index ed610eca..41d9faed 100644 --- a/test/integration/cli_test.go +++ b/test/integration/cli_test.go @@ -198,7 +198,7 @@ var _ = Describe("CLI Delete All Commands", func() { Prompt: "test", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, @@ -289,7 +289,7 @@ var _ = Describe("CLI Delete All Commands", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, @@ -379,7 +379,7 @@ var _ = Describe("CLI Delete TaskSpawner Command", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, @@ -427,7 +427,7 @@ var _ = Describe("CLI Delete TaskSpawner Command", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, @@ -475,7 +475,7 @@ var _ = Describe("CLI Delete TaskSpawner Command", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, @@ -543,7 +543,7 @@ var _ = Describe("CLI Suspend/Resume Commands", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, @@ -589,7 +589,7 @@ var _ = Describe("CLI Suspend/Resume Commands", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, @@ -635,7 +635,7 @@ var _ = Describe("CLI Suspend/Resume Commands", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, @@ -679,7 +679,7 @@ var _ = Describe("CLI Suspend/Resume Commands", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, @@ -717,7 +717,7 @@ var _ = Describe("CLI Suspend/Resume Commands", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, @@ -770,7 +770,7 @@ var _ = Describe("CLI Suspend/Resume Commands", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, diff --git a/test/integration/completion_test.go b/test/integration/completion_test.go index 99e295a8..05d9c7e4 100644 --- a/test/integration/completion_test.go +++ b/test/integration/completion_test.go @@ -68,7 +68,7 @@ var _ = Describe("Completion", func() { Prompt: "test", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, @@ -106,7 +106,7 @@ var _ = Describe("Completion", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, @@ -143,7 +143,7 @@ var _ = Describe("Completion", func() { Prompt: "test", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "test-secret", }, }, diff --git a/test/integration/install_test.go b/test/integration/install_test.go index 61ad178b..aa32ede3 100644 --- a/test/integration/install_test.go +++ b/test/integration/install_test.go @@ -241,7 +241,7 @@ var _ = Describe("Install/Uninstall", Ordered, func() { Prompt: "test prompt", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "fake-secret"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "fake-secret"}, }, }, } diff --git a/test/integration/metrics_test.go b/test/integration/metrics_test.go index d53755ec..64da1b10 100644 --- a/test/integration/metrics_test.go +++ b/test/integration/metrics_test.go @@ -91,7 +91,7 @@ func createAndCompleteTask(nsName, taskName, spawner, model string) *kelosv1alph Prompt: fmt.Sprintf("Test task %s", taskName), Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, diff --git a/test/integration/task_test.go b/test/integration/task_test.go index ef339816..642996d7 100644 --- a/test/integration/task_test.go +++ b/test/integration/task_test.go @@ -79,7 +79,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Create a hello world program", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -234,7 +234,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Create a hello world program", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-oauth", }, }, @@ -339,7 +339,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Resolve MCP headersFrom", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, AgentConfigRef: &kelosv1alpha1.AgentConfigReference{Name: "mcp-headers-from-config"}, }, @@ -445,7 +445,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Resolve MCP envFrom", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, AgentConfigRef: &kelosv1alpha1.AgentConfigReference{Name: "mcp-env-from-config"}, }, @@ -534,7 +534,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Fail on missing MCP secret", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, AgentConfigRef: &kelosv1alpha1.AgentConfigReference{Name: "mcp-missing-secret-config"}, }, @@ -629,7 +629,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Prefer MCP secret values", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, AgentConfigRef: &kelosv1alpha1.AgentConfigReference{Name: "mcp-precedence-config"}, }, @@ -711,7 +711,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -834,7 +834,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Create a PR", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -953,7 +953,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Review the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -1030,7 +1030,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Create a hello world program", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -1112,7 +1112,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Create a hello world program", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -1183,7 +1183,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Create a hello world program", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -1274,7 +1274,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -1386,7 +1386,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -1481,7 +1481,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "codex-api-key", }, }, @@ -1590,7 +1590,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Refactor the module", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "codex-api-key", }, }, @@ -1674,7 +1674,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Review the code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "codex-oauth-secret", }, }, @@ -1739,7 +1739,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "opencode-api-key", }, }, @@ -1835,7 +1835,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -1958,7 +1958,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Fix the bug", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -2048,7 +2048,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Test events", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -2164,7 +2164,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Test failure event", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -2248,7 +2248,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Do something", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, }, } @@ -2266,7 +2266,7 @@ var _ = Describe("Task Controller", func() { DependsOn: []string{"task-a"}, Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, }, } @@ -2364,7 +2364,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Do something", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, }, } @@ -2382,7 +2382,7 @@ var _ = Describe("Task Controller", func() { DependsOn: []string{"dep-task-a"}, Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, }, } @@ -2467,7 +2467,7 @@ var _ = Describe("Task Controller", func() { Branch: "feature-1", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, }, } @@ -2510,7 +2510,7 @@ var _ = Describe("Task Controller", func() { Branch: "feature-1", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, }, } @@ -2597,7 +2597,7 @@ var _ = Describe("Task Controller", func() { Branch: "feature-x", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, WorkspaceRef: &kelosv1alpha1.WorkspaceReference{ Name: "test-workspace", @@ -2714,7 +2714,7 @@ var _ = Describe("Task Controller", func() { Branch: "feature-1", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, WorkspaceRef: &kelosv1alpha1.WorkspaceReference{Name: "workspace-a"}, }, @@ -2758,7 +2758,7 @@ var _ = Describe("Task Controller", func() { Branch: "feature-1", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, WorkspaceRef: &kelosv1alpha1.WorkspaceReference{Name: "workspace-b"}, }, @@ -2808,7 +2808,7 @@ var _ = Describe("Task Controller", func() { DependsOn: []string{"cycle-task-b"}, Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, }, } @@ -2826,7 +2826,7 @@ var _ = Describe("Task Controller", func() { DependsOn: []string{"cycle-task-a"}, Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, }, } @@ -2878,7 +2878,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Generate outputs", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, }, } @@ -2929,7 +2929,7 @@ var _ = Describe("Task Controller", func() { DependsOn: []string{"tmpl-task-a"}, Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, }, } @@ -2980,7 +2980,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Generate results", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, }, } @@ -3035,7 +3035,7 @@ var _ = Describe("Task Controller", func() { DependsOn: []string{"results-task-a"}, Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, }, } @@ -3103,7 +3103,7 @@ var _ = Describe("Task Controller", func() { Branch: "kelos-task-42", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, WorkspaceRef: &kelosv1alpha1.WorkspaceReference{Name: "test-workspace"}, }, @@ -3125,7 +3125,7 @@ var _ = Describe("Task Controller", func() { Branch: "kelos-task-99", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, WorkspaceRef: &kelosv1alpha1.WorkspaceReference{Name: "test-workspace"}, }, @@ -3252,7 +3252,7 @@ var _ = Describe("Task Controller", func() { Branch: "kelos-task-42", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, WorkspaceRef: &kelosv1alpha1.WorkspaceReference{Name: "lock-workspace"}, }, @@ -3298,7 +3298,7 @@ var _ = Describe("Task Controller", func() { Branch: "kelos-task-42", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, + SecretRef: &kelosv1alpha1.SecretReference{Name: "anthropic-api-key"}, }, WorkspaceRef: &kelosv1alpha1.WorkspaceReference{Name: "lock-workspace"}, }, @@ -3372,7 +3372,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Original prompt", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, @@ -3454,7 +3454,7 @@ var _ = Describe("Task Controller", func() { Prompt: "Work on feature", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeAPIKey, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "anthropic-api-key", }, }, diff --git a/test/integration/taskspawner_test.go b/test/integration/taskspawner_test.go index 7489aa85..84eed323 100644 --- a/test/integration/taskspawner_test.go +++ b/test/integration/taskspawner_test.go @@ -66,7 +66,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -199,7 +199,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -265,7 +265,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -335,7 +335,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -428,7 +428,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -485,7 +485,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -578,7 +578,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -658,7 +658,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -801,7 +801,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -924,7 +924,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -1005,7 +1005,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -1115,7 +1115,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -1188,7 +1188,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -1309,7 +1309,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -1388,7 +1388,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -1465,7 +1465,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -1547,7 +1547,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -1685,7 +1685,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -1831,7 +1831,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -1921,7 +1921,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -1996,7 +1996,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -2067,7 +2067,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -2144,7 +2144,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -2222,7 +2222,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -2279,7 +2279,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -2341,7 +2341,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, }, @@ -2418,7 +2418,7 @@ var _ = Describe("TaskSpawner Controller", func() { Type: "claude-code", Credentials: kelosv1alpha1.Credentials{ Type: kelosv1alpha1.CredentialTypeOAuth, - SecretRef: kelosv1alpha1.SecretReference{ + SecretRef: &kelosv1alpha1.SecretReference{ Name: "claude-credentials", }, },