@@ -180,6 +180,12 @@ func handleAgenticSessionEvent(obj *unstructured.Unstructured) error {
180180 // Continue - session cleanup is still successful
181181 }
182182
183+ // Cleanup Langfuse secret when session is stopped
184+ if err := deleteAmbientLangfuseSecret (deleteCtx , sessionNamespace ); err != nil {
185+ log .Printf ("Warning: Failed to cleanup ambient-admin-langfuse-secret from %s: %v" , sessionNamespace , err )
186+ // Continue - session cleanup is still successful
187+ }
188+
183189 return nil
184190 }
185191
@@ -290,6 +296,32 @@ func handleAgenticSessionEvent(obj *unstructured.Unstructured) error {
290296 log .Printf ("Vertex AI disabled (CLAUDE_CODE_USE_VERTEX=0), skipping %s secret copy" , types .AmbientVertexSecretName )
291297 }
292298
299+ // Check for Langfuse secret in the operator's namespace and copy it if enabled
300+ ambientLangfuseSecretCopied := false
301+ langfuseEnabled := os .Getenv ("LANGFUSE_ENABLED" ) != "" && os .Getenv ("LANGFUSE_ENABLED" ) != "0" && os .Getenv ("LANGFUSE_ENABLED" ) != "false"
302+
303+ if langfuseEnabled {
304+ if langfuseSecret , err := config .K8sClient .CoreV1 ().Secrets (operatorNamespace ).Get (context .TODO (), "ambient-admin-langfuse-secret" , v1.GetOptions {}); err == nil {
305+ // Secret exists in operator namespace, copy it to the session namespace
306+ log .Printf ("Found ambient-admin-langfuse-secret in %s, copying to %s" , operatorNamespace , sessionNamespace )
307+ // Create context with timeout for secret copy operation
308+ copyCtx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
309+ defer cancel ()
310+ if err := copySecretToNamespace (copyCtx , langfuseSecret , sessionNamespace , currentObj ); err != nil {
311+ return fmt .Errorf ("failed to copy Langfuse secret from %s to %s: %w" , operatorNamespace , sessionNamespace , err )
312+ }
313+ ambientLangfuseSecretCopied = true
314+ log .Printf ("Successfully copied Langfuse secret to %s" , sessionNamespace )
315+ } else if ! errors .IsNotFound (err ) {
316+ return fmt .Errorf ("failed to check for Langfuse secret in %s: %w" , operatorNamespace , err )
317+ } else {
318+ // Langfuse enabled but secret not found - log warning and continue without Langfuse
319+ log .Printf ("Warning: LANGFUSE_ENABLED is set but ambient-admin-langfuse-secret not found in namespace %s. Langfuse observability will be disabled for this session." , operatorNamespace )
320+ }
321+ } else {
322+ log .Printf ("Langfuse disabled, skipping secret copy" )
323+ }
324+
293325 // Create a Kubernetes Job for this AgenticSession
294326 jobName := fmt .Sprintf ("%s-job" , name )
295327
@@ -503,20 +535,54 @@ func handleAgenticSessionEvent(obj *unstructured.Unstructured) error {
503535 base = append (base , corev1.EnvVar {Name : "USER_NAME" , Value : userName })
504536 }
505537
506- // Platform-wide Langfuse observability configuration (injected from operator env)
507- // Uses explicit env vars instead of EnvFrom to prevent automatic exposure of future secret keys
508- // All LANGFUSE_* vars come from ambient-admin-langfuse-secret Secret (platform-admin managed)
509- if os .Getenv ("LANGFUSE_ENABLED" ) != "" {
510- base = append (base , corev1.EnvVar {Name : "LANGFUSE_ENABLED" , Value : os .Getenv ("LANGFUSE_ENABLED" )})
511- }
512- if os .Getenv ("LANGFUSE_HOST" ) != "" {
513- base = append (base , corev1.EnvVar {Name : "LANGFUSE_HOST" , Value : os .Getenv ("LANGFUSE_HOST" )})
514- }
515- if os .Getenv ("LANGFUSE_PUBLIC_KEY" ) != "" {
516- base = append (base , corev1.EnvVar {Name : "LANGFUSE_PUBLIC_KEY" , Value : os .Getenv ("LANGFUSE_PUBLIC_KEY" )})
517- }
518- if os .Getenv ("LANGFUSE_SECRET_KEY" ) != "" {
519- base = append (base , corev1.EnvVar {Name : "LANGFUSE_SECRET_KEY" , Value : os .Getenv ("LANGFUSE_SECRET_KEY" )})
538+ // Platform-wide Langfuse observability configuration
539+ // Uses secretKeyRef to prevent credential exposure in pod specs
540+ // Secret is copied to session namespace from operator namespace
541+ // All keys are optional to prevent pod startup failures if keys are missing
542+ if ambientLangfuseSecretCopied {
543+ base = append (base ,
544+ corev1.EnvVar {
545+ Name : "LANGFUSE_ENABLED" ,
546+ ValueFrom : & corev1.EnvVarSource {
547+ SecretKeyRef : & corev1.SecretKeySelector {
548+ LocalObjectReference : corev1.LocalObjectReference {Name : "ambient-admin-langfuse-secret" },
549+ Key : "LANGFUSE_ENABLED" ,
550+ Optional : boolPtr (true ),
551+ },
552+ },
553+ },
554+ corev1.EnvVar {
555+ Name : "LANGFUSE_HOST" ,
556+ ValueFrom : & corev1.EnvVarSource {
557+ SecretKeyRef : & corev1.SecretKeySelector {
558+ LocalObjectReference : corev1.LocalObjectReference {Name : "ambient-admin-langfuse-secret" },
559+ Key : "LANGFUSE_HOST" ,
560+ Optional : boolPtr (true ),
561+ },
562+ },
563+ },
564+ corev1.EnvVar {
565+ Name : "LANGFUSE_PUBLIC_KEY" ,
566+ ValueFrom : & corev1.EnvVarSource {
567+ SecretKeyRef : & corev1.SecretKeySelector {
568+ LocalObjectReference : corev1.LocalObjectReference {Name : "ambient-admin-langfuse-secret" },
569+ Key : "LANGFUSE_PUBLIC_KEY" ,
570+ Optional : boolPtr (true ),
571+ },
572+ },
573+ },
574+ corev1.EnvVar {
575+ Name : "LANGFUSE_SECRET_KEY" ,
576+ ValueFrom : & corev1.EnvVarSource {
577+ SecretKeyRef : & corev1.SecretKeySelector {
578+ LocalObjectReference : corev1.LocalObjectReference {Name : "ambient-admin-langfuse-secret" },
579+ Key : "LANGFUSE_SECRET_KEY" ,
580+ Optional : boolPtr (true ),
581+ },
582+ },
583+ },
584+ )
585+ log .Printf ("Langfuse env vars configured via secretKeyRef for session %s" , name )
520586 }
521587
522588 // Add Vertex AI configuration only if enabled
@@ -1127,6 +1193,12 @@ func deleteJobAndPerJobService(namespace, jobName, sessionName string) error {
11271193 // Don't return error - this is a non-critical cleanup step
11281194 }
11291195
1196+ // Delete the Langfuse secret if it was copied by the operator
1197+ if err := deleteAmbientLangfuseSecret (deleteCtx , namespace ); err != nil {
1198+ log .Printf ("Failed to delete ambient-admin-langfuse-secret from %s: %v" , namespace , err )
1199+ // Don't return error - this is a non-critical cleanup step
1200+ }
1201+
11301202 // NOTE: PVC is kept for all sessions and only deleted via garbage collection
11311203 // when the session CR is deleted. This allows sessions to be restarted.
11321204
@@ -1409,6 +1481,33 @@ func deleteAmbientVertexSecret(ctx context.Context, namespace string) error {
14091481 return nil
14101482}
14111483
1484+ // deleteAmbientLangfuseSecret deletes the ambient-admin-langfuse-secret from a namespace if it was copied
1485+ func deleteAmbientLangfuseSecret (ctx context.Context , namespace string ) error {
1486+ const langfuseSecretName = "ambient-admin-langfuse-secret"
1487+ secret , err := config .K8sClient .CoreV1 ().Secrets (namespace ).Get (ctx , langfuseSecretName , v1.GetOptions {})
1488+ if err != nil {
1489+ if errors .IsNotFound (err ) {
1490+ // Secret doesn't exist, nothing to do
1491+ return nil
1492+ }
1493+ return fmt .Errorf ("error checking for %s secret: %w" , langfuseSecretName , err )
1494+ }
1495+
1496+ // Check if this was a copied secret (has the annotation)
1497+ if _ , ok := secret .Annotations [types .CopiedFromAnnotation ]; ! ok {
1498+ log .Printf ("%s secret in namespace %s was not copied by operator, not deleting" , langfuseSecretName , namespace )
1499+ return nil
1500+ }
1501+
1502+ log .Printf ("Deleting copied %s secret from namespace %s" , langfuseSecretName , namespace )
1503+ err = config .K8sClient .CoreV1 ().Secrets (namespace ).Delete (ctx , langfuseSecretName , v1.DeleteOptions {})
1504+ if err != nil && ! errors .IsNotFound (err ) {
1505+ return fmt .Errorf ("failed to delete %s secret: %w" , langfuseSecretName , err )
1506+ }
1507+
1508+ return nil
1509+ }
1510+
14121511// Helper functions
14131512var (
14141513 boolPtr = func (b bool ) * bool { return & b }
0 commit comments