Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion cluster/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,37 @@ func New() *Manager {
}
}

// detectInClusterNamespace reads the namespace from the service account file
// that Kubernetes mounts into pods. Returns "default" if the file cannot be read.
func detectInClusterNamespace() string {
return readNamespaceFromFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
}

// readNamespaceFromFile reads the namespace from a file, with fallback to "default"
// This function is extracted to enable testing without filesystem dependencies
func readNamespaceFromFile(namespaceFile string) string {
// #nosec G304 - This is a well-known Kubernetes file path that is safe to read
data, err := os.ReadFile(namespaceFile)
if err != nil {
// If we can't read the file, fall back to "default"
slog.Debug("failed to read namespace from service account file, using default",
slog.String("file", namespaceFile),
slog.String("error", err.Error()),
)
return "default"
}

namespace := strings.TrimSpace(string(data))
if namespace == "" {
slog.Debug("namespace file was empty, using default",
slog.String("file", namespaceFile),
)
return "default"
}

return namespace
}

// LoadInClusterConfig loads the in-cluster Kubernetes configuration
// This is used when kai is running inside a Kubernetes pod
func (cm *Manager) LoadInClusterConfig(name string) error {
Expand Down Expand Up @@ -78,11 +109,14 @@ func (cm *Manager) LoadInClusterConfig(name string) error {
return fmt.Errorf("failed to connect to cluster: %w", err)
}

// Detect the actual namespace from the service account file
namespace := detectInClusterNamespace()

contextInfo := &kai.ContextInfo{
Name: name,
Cluster: "in-cluster",
User: "service-account",
Namespace: "default",
Namespace: namespace,
ServerURL: config.Host,
ConfigPath: "",
IsActive: true,
Expand All @@ -97,6 +131,7 @@ func (cm *Manager) LoadInClusterConfig(name string) error {
slog.Info("in-cluster config loaded",
slog.String("context", name),
slog.String("server", config.Host),
slog.String("namespace", namespace),
)

return nil
Expand Down
49 changes: 49 additions & 0 deletions cluster/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func TestExtendedClusterManager(t *testing.T) {

func TestInClusterConfig(t *testing.T) {
t.Run("LoadInClusterConfig", testLoadInClusterConfig)
t.Run("DetectInClusterNamespace", testDetectInClusterNamespace)
}

func testLoadInClusterConfig(t *testing.T) {
Expand Down Expand Up @@ -86,6 +87,54 @@ func testLoadInClusterConfig(t *testing.T) {
})
}

func testDetectInClusterNamespace(t *testing.T) {
t.Run("FileDoesNotExist", func(t *testing.T) {
// When the file doesn't exist (normal case outside cluster), should return "default"
namespace := readNamespaceFromFile("/nonexistent/path/namespace")
assert.Equal(t, "default", namespace)
})

t.Run("FileExistsWithNamespace", func(t *testing.T) {
// Create a temporary file that simulates the service account namespace file
tmpDir := t.TempDir()
namespaceFile := filepath.Join(tmpDir, "namespace")
err := os.WriteFile(namespaceFile, []byte("my-custom-namespace\n"), 0644)
require.NoError(t, err)

namespace := readNamespaceFromFile(namespaceFile)
assert.Equal(t, "my-custom-namespace", namespace)
})

t.Run("FileIsEmpty", func(t *testing.T) {
// Create a temporary empty file
tmpDir := t.TempDir()
namespaceFile := filepath.Join(tmpDir, "namespace")
err := os.WriteFile(namespaceFile, []byte(""), 0644)
require.NoError(t, err)

namespace := readNamespaceFromFile(namespaceFile)
assert.Equal(t, "default", namespace)
})

t.Run("FileWithWhitespace", func(t *testing.T) {
// Create a file with leading/trailing whitespace
tmpDir := t.TempDir()
namespaceFile := filepath.Join(tmpDir, "namespace")
err := os.WriteFile(namespaceFile, []byte(" production \n"), 0644)
require.NoError(t, err)

namespace := readNamespaceFromFile(namespaceFile)
assert.Equal(t, "production", namespace)
})

t.Run("DefaultFunctionBehavior", func(t *testing.T) {
// Test that detectInClusterNamespace calls readNamespaceFromFile with correct path
// Since the actual file won't exist in test environment, it should return "default"
namespace := detectInClusterNamespace()
assert.Equal(t, "default", namespace)
})
}

func testNewClusterManager(t *testing.T) {
cm := New()
assert.NotNil(t, cm)
Expand Down