package config import ( "os" "path/filepath" "testing" "time" ) func TestLoadValidConfig(t *testing.T) { content := ` log_level = "debug" [ssh] listen_addr = ":3333" host_key_path = "/tmp/test_key" [auth] accept_after = 5 credential_ttl = "1h" [[auth.static_credentials]] username = "root" password = "toor" ` path := writeTemp(t, content) cfg, err := Load(path) if err != nil { t.Fatalf("unexpected error: %v", err) } if cfg.LogLevel != "debug" { t.Errorf("log_level = %q, want %q", cfg.LogLevel, "debug") } if cfg.SSH.ListenAddr != ":3333" { t.Errorf("listen_addr = %q, want %q", cfg.SSH.ListenAddr, ":3333") } if cfg.SSH.HostKeyPath != "/tmp/test_key" { t.Errorf("host_key_path = %q, want %q", cfg.SSH.HostKeyPath, "/tmp/test_key") } if cfg.Auth.AcceptAfter != 5 { t.Errorf("accept_after = %d, want %d", cfg.Auth.AcceptAfter, 5) } if cfg.Auth.CredentialTTLDuration != time.Hour { t.Errorf("credential_ttl_duration = %v, want %v", cfg.Auth.CredentialTTLDuration, time.Hour) } if len(cfg.Auth.StaticCredentials) != 1 { t.Fatalf("static_credentials len = %d, want 1", len(cfg.Auth.StaticCredentials)) } if cfg.Auth.StaticCredentials[0].Username != "root" { t.Errorf("username = %q, want %q", cfg.Auth.StaticCredentials[0].Username, "root") } } func TestLoadDefaults(t *testing.T) { path := writeTemp(t, "") cfg, err := Load(path) if err != nil { t.Fatalf("unexpected error: %v", err) } if cfg.SSH.ListenAddr != ":2222" { t.Errorf("default listen_addr = %q, want %q", cfg.SSH.ListenAddr, ":2222") } if cfg.SSH.HostKeyPath != "oubliette_host_key" { t.Errorf("default host_key_path = %q, want %q", cfg.SSH.HostKeyPath, "oubliette_host_key") } if cfg.Auth.AcceptAfter != 10 { t.Errorf("default accept_after = %d, want %d", cfg.Auth.AcceptAfter, 10) } if cfg.Auth.CredentialTTLDuration != 24*time.Hour { t.Errorf("default credential_ttl = %v, want %v", cfg.Auth.CredentialTTLDuration, 24*time.Hour) } if cfg.LogLevel != "info" { t.Errorf("default log_level = %q, want %q", cfg.LogLevel, "info") } if cfg.Storage.DBPath != "oubliette.db" { t.Errorf("default db_path = %q, want %q", cfg.Storage.DBPath, "oubliette.db") } if cfg.Storage.RetentionDays != 90 { t.Errorf("default retention_days = %d, want %d", cfg.Storage.RetentionDays, 90) } if cfg.Storage.RetentionIntervalDuration != time.Hour { t.Errorf("default retention_interval = %v, want %v", cfg.Storage.RetentionIntervalDuration, time.Hour) } } func TestLoadInvalidTTL(t *testing.T) { content := ` [auth] credential_ttl = "notaduration" ` path := writeTemp(t, content) _, err := Load(path) if err == nil { t.Fatal("expected error for invalid credential_ttl") } } func TestLoadNegativeTTL(t *testing.T) { content := ` [auth] credential_ttl = "-1h" ` path := writeTemp(t, content) _, err := Load(path) if err == nil { t.Fatal("expected error for negative credential_ttl") } } func TestLoadInvalidStaticCredential(t *testing.T) { content := ` [[auth.static_credentials]] username = "" password = "test" ` path := writeTemp(t, content) _, err := Load(path) if err == nil { t.Fatal("expected error for empty username") } } func TestLoadInvalidRetentionInterval(t *testing.T) { content := ` [storage] retention_interval = "notaduration" ` path := writeTemp(t, content) _, err := Load(path) if err == nil { t.Fatal("expected error for invalid retention_interval") } } func TestLoadInvalidRetentionDays(t *testing.T) { content := ` [storage] retention_days = -1 ` path := writeTemp(t, content) _, err := Load(path) if err == nil { t.Fatal("expected error for negative retention_days") } } func TestLoadStorageConfig(t *testing.T) { content := ` [storage] db_path = "/tmp/test.db" retention_days = 30 retention_interval = "2h" ` path := writeTemp(t, content) cfg, err := Load(path) if err != nil { t.Fatalf("unexpected error: %v", err) } if cfg.Storage.DBPath != "/tmp/test.db" { t.Errorf("db_path = %q, want %q", cfg.Storage.DBPath, "/tmp/test.db") } if cfg.Storage.RetentionDays != 30 { t.Errorf("retention_days = %d, want 30", cfg.Storage.RetentionDays) } if cfg.Storage.RetentionIntervalDuration != 2*time.Hour { t.Errorf("retention_interval = %v, want 2h", cfg.Storage.RetentionIntervalDuration) } } func TestLoadShellDefaults(t *testing.T) { path := writeTemp(t, "") cfg, err := Load(path) if err != nil { t.Fatalf("unexpected error: %v", err) } if cfg.Shell.Hostname != "ubuntu-server" { t.Errorf("default hostname = %q, want %q", cfg.Shell.Hostname, "ubuntu-server") } if cfg.Shell.Banner == "" { t.Error("default banner should not be empty") } if cfg.Shell.FakeUser != "" { t.Errorf("default fake_user = %q, want empty", cfg.Shell.FakeUser) } } func TestLoadShellConfig(t *testing.T) { content := ` [shell] hostname = "myhost" banner = "Custom banner\r\n" fake_user = "admin" [shell.bash] custom_key = "value" ` path := writeTemp(t, content) cfg, err := Load(path) if err != nil { t.Fatalf("unexpected error: %v", err) } if cfg.Shell.Hostname != "myhost" { t.Errorf("hostname = %q, want %q", cfg.Shell.Hostname, "myhost") } if cfg.Shell.Banner != "Custom banner\r\n" { t.Errorf("banner = %q, want %q", cfg.Shell.Banner, "Custom banner\r\n") } if cfg.Shell.FakeUser != "admin" { t.Errorf("fake_user = %q, want %q", cfg.Shell.FakeUser, "admin") } if cfg.Shell.Shells == nil { t.Fatal("Shells map should not be nil") } bashCfg, ok := cfg.Shell.Shells["bash"] if !ok { t.Fatal("Shells[\"bash\"] not found") } if bashCfg["custom_key"] != "value" { t.Errorf("Shells[\"bash\"][\"custom_key\"] = %v, want %q", bashCfg["custom_key"], "value") } } func TestLoadWebDefaults(t *testing.T) { path := writeTemp(t, "") cfg, err := Load(path) if err != nil { t.Fatalf("unexpected error: %v", err) } if cfg.Web.Enabled { t.Error("web should be disabled by default") } if cfg.Web.ListenAddr != ":8080" { t.Errorf("default web listen_addr = %q, want %q", cfg.Web.ListenAddr, ":8080") } } func TestLoadWebConfig(t *testing.T) { content := ` [web] enabled = true listen_addr = ":9090" ` path := writeTemp(t, content) cfg, err := Load(path) if err != nil { t.Fatalf("unexpected error: %v", err) } if !cfg.Web.Enabled { t.Error("web should be enabled") } if cfg.Web.ListenAddr != ":9090" { t.Errorf("web listen_addr = %q, want %q", cfg.Web.ListenAddr, ":9090") } } func TestLoadCredentialWithShell(t *testing.T) { content := ` [[auth.static_credentials]] username = "samsung" password = "fridge" shell = "fridge" [[auth.static_credentials]] username = "root" password = "toor" ` path := writeTemp(t, content) cfg, err := Load(path) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(cfg.Auth.StaticCredentials) != 2 { t.Fatalf("static_credentials len = %d, want 2", len(cfg.Auth.StaticCredentials)) } if cfg.Auth.StaticCredentials[0].Shell != "fridge" { t.Errorf("cred[0].Shell = %q, want %q", cfg.Auth.StaticCredentials[0].Shell, "fridge") } if cfg.Auth.StaticCredentials[1].Shell != "" { t.Errorf("cred[1].Shell = %q, want empty", cfg.Auth.StaticCredentials[1].Shell) } } func TestLoadMetricsToken(t *testing.T) { content := ` [web] enabled = true metrics_token = "my-secret-token" ` path := writeTemp(t, content) cfg, err := Load(path) if err != nil { t.Fatalf("unexpected error: %v", err) } if cfg.Web.MetricsToken != "my-secret-token" { t.Errorf("metrics_token = %q, want %q", cfg.Web.MetricsToken, "my-secret-token") } } func TestLoadMissingFile(t *testing.T) { _, err := Load("/nonexistent/path/config.toml") if err == nil { t.Fatal("expected error for missing file") } } func TestLoadInvalidTOML(t *testing.T) { path := writeTemp(t, "{{{{invalid toml") _, err := Load(path) if err == nil { t.Fatal("expected error for invalid TOML") } } func TestLoadUsernameRoutes(t *testing.T) { content := ` [shell] hostname = "myhost" [shell.username_routes] postgres = "psql" admin = "bash" [shell.bash] custom_key = "value" ` path := writeTemp(t, content) cfg, err := Load(path) if err != nil { t.Fatalf("unexpected error: %v", err) } if cfg.Shell.UsernameRoutes == nil { t.Fatal("UsernameRoutes should not be nil") } if cfg.Shell.UsernameRoutes["postgres"] != "psql" { t.Errorf("UsernameRoutes[\"postgres\"] = %q, want %q", cfg.Shell.UsernameRoutes["postgres"], "psql") } if cfg.Shell.UsernameRoutes["admin"] != "bash" { t.Errorf("UsernameRoutes[\"admin\"] = %q, want %q", cfg.Shell.UsernameRoutes["admin"], "bash") } // username_routes should NOT appear in the Shells map. if _, ok := cfg.Shell.Shells["username_routes"]; ok { t.Error("username_routes should not appear in Shells map") } // bash should still appear in Shells map. if _, ok := cfg.Shell.Shells["bash"]; !ok { t.Error("Shells[\"bash\"] should still be present") } } func writeTemp(t *testing.T, content string) string { t.Helper() path := filepath.Join(t.TempDir(), "config.toml") if err := os.WriteFile(path, []byte(content), 0644); err != nil { t.Fatalf("writing temp config: %v", err) } return path }