Skip to main content
Glama
orneryd

M.I.M.I.R - Multi-agent Intelligent Memory & Insight Repository

by orneryd
config_test.go26.1 kB
// Package config tests for Neo4j-compatible configuration. package config import ( "os" "testing" "time" ) // TestLoadFromEnv_Defaults tests default values are loaded correctly. func TestLoadFromEnv_Defaults(t *testing.T) { // Clear any existing env vars clearEnvVars(t) cfg := LoadFromEnv() // Auth defaults - disabled by default for easy development if cfg.Auth.Enabled { t.Error("expected Auth.Enabled to be false by default") } if cfg.Auth.InitialUsername != "admin" { t.Errorf("expected username 'admin', got %q", cfg.Auth.InitialUsername) } if cfg.Auth.InitialPassword != "admin" { t.Errorf("expected password 'admin', got %q", cfg.Auth.InitialPassword) } if cfg.Auth.MinPasswordLength != 8 { t.Errorf("expected min password length 8, got %d", cfg.Auth.MinPasswordLength) } if cfg.Auth.TokenExpiry != 24*time.Hour { t.Errorf("expected token expiry 24h, got %v", cfg.Auth.TokenExpiry) } // Database defaults if cfg.Database.DataDir != "./data" { t.Errorf("expected data dir './data', got %q", cfg.Database.DataDir) } if cfg.Database.DefaultDatabase != "nornicdb" { t.Errorf("expected default db 'nornicdb', got %q", cfg.Database.DefaultDatabase) } if cfg.Database.ReadOnly { t.Error("expected ReadOnly to be false by default") } if cfg.Database.TransactionTimeout != 30*time.Second { t.Errorf("expected tx timeout 30s, got %v", cfg.Database.TransactionTimeout) } if cfg.Database.MaxConcurrentTransactions != 1000 { t.Errorf("expected max concurrent tx 1000, got %d", cfg.Database.MaxConcurrentTransactions) } // Server defaults - Bolt if !cfg.Server.BoltEnabled { t.Error("expected BoltEnabled to be true by default") } if cfg.Server.BoltPort != 7687 { t.Errorf("expected bolt port 7687, got %d", cfg.Server.BoltPort) } if cfg.Server.BoltAddress != "0.0.0.0" { t.Errorf("expected bolt address '0.0.0.0', got %q", cfg.Server.BoltAddress) } // Server defaults - HTTP if !cfg.Server.HTTPEnabled { t.Error("expected HTTPEnabled to be true by default") } if cfg.Server.HTTPPort != 7474 { t.Errorf("expected http port 7474, got %d", cfg.Server.HTTPPort) } if cfg.Server.HTTPSPort != 7473 { t.Errorf("expected https port 7473, got %d", cfg.Server.HTTPSPort) } // Memory defaults if !cfg.Memory.DecayEnabled { t.Error("expected DecayEnabled to be true by default") } if cfg.Memory.DecayInterval != time.Hour { t.Errorf("expected decay interval 1h, got %v", cfg.Memory.DecayInterval) } if cfg.Memory.ArchiveThreshold != 0.05 { t.Errorf("expected archive threshold 0.05, got %f", cfg.Memory.ArchiveThreshold) } if cfg.Memory.EmbeddingProvider != "ollama" { t.Errorf("expected embedding provider 'ollama', got %q", cfg.Memory.EmbeddingProvider) } if cfg.Memory.EmbeddingDimensions != 1024 { t.Errorf("expected embedding dimensions 1024, got %d", cfg.Memory.EmbeddingDimensions) } if !cfg.Memory.AutoLinksEnabled { t.Error("expected AutoLinksEnabled to be true by default") } // Compliance defaults if !cfg.Compliance.AuditEnabled { t.Error("expected AuditEnabled to be true by default") } if cfg.Compliance.AuditRetentionDays != 2555 { t.Errorf("expected audit retention 2555 days, got %d", cfg.Compliance.AuditRetentionDays) } if cfg.Compliance.RetentionEnabled { t.Error("expected RetentionEnabled to be false by default") } if !cfg.Compliance.AccessControlEnabled { t.Error("expected AccessControlEnabled to be true by default") } if cfg.Compliance.SessionTimeout != 30*time.Minute { t.Errorf("expected session timeout 30m, got %v", cfg.Compliance.SessionTimeout) } if cfg.Compliance.MaxFailedLogins != 5 { t.Errorf("expected max failed logins 5, got %d", cfg.Compliance.MaxFailedLogins) } if !cfg.Compliance.DataExportEnabled { t.Error("expected DataExportEnabled to be true by default") } if !cfg.Compliance.DataErasureEnabled { t.Error("expected DataErasureEnabled to be true by default") } if cfg.Compliance.AnonymizationMethod != "pseudonymization" { t.Errorf("expected anonymization method 'pseudonymization', got %q", cfg.Compliance.AnonymizationMethod) } // Logging defaults if cfg.Logging.Level != "INFO" { t.Errorf("expected log level 'INFO', got %q", cfg.Logging.Level) } if cfg.Logging.Format != "json" { t.Errorf("expected log format 'json', got %q", cfg.Logging.Format) } // Durability defaults - optimized for performance if cfg.Database.StrictDurability { t.Error("expected StrictDurability to be false by default") } if cfg.Database.WALSyncMode != "batch" { t.Errorf("expected WALSyncMode 'batch', got %q", cfg.Database.WALSyncMode) } if cfg.Database.WALSyncInterval != 100*time.Millisecond { t.Errorf("expected WALSyncInterval 100ms, got %v", cfg.Database.WALSyncInterval) } } // TestLoadFromEnv_DurabilitySettings tests durability configuration options. func TestLoadFromEnv_DurabilitySettings(t *testing.T) { t.Run("default_batch_mode", func(t *testing.T) { clearEnvVars(t) cfg := LoadFromEnv() if cfg.Database.WALSyncMode != "batch" { t.Errorf("expected default WALSyncMode 'batch', got %q", cfg.Database.WALSyncMode) } if cfg.Database.WALSyncInterval != 100*time.Millisecond { t.Errorf("expected default WALSyncInterval 100ms, got %v", cfg.Database.WALSyncInterval) } if cfg.Database.StrictDurability { t.Error("expected StrictDurability to be false by default") } }) t.Run("strict_durability_mode", func(t *testing.T) { clearEnvVars(t) os.Setenv("NORNICDB_STRICT_DURABILITY", "true") cfg := LoadFromEnv() if !cfg.Database.StrictDurability { t.Error("expected StrictDurability to be true") } if cfg.Database.WALSyncMode != "immediate" { t.Errorf("strict mode should set WALSyncMode to 'immediate', got %q", cfg.Database.WALSyncMode) } // WALSyncInterval is ignored in immediate mode, but we set it to 0 if cfg.Database.WALSyncInterval != 0 { t.Errorf("strict mode should set WALSyncInterval to 0, got %v", cfg.Database.WALSyncInterval) } }) t.Run("custom_wal_sync_mode", func(t *testing.T) { clearEnvVars(t) os.Setenv("NORNICDB_WAL_SYNC_MODE", "immediate") os.Setenv("NORNICDB_WAL_SYNC_INTERVAL", "50ms") cfg := LoadFromEnv() if cfg.Database.WALSyncMode != "immediate" { t.Errorf("expected WALSyncMode 'immediate', got %q", cfg.Database.WALSyncMode) } if cfg.Database.WALSyncInterval != 50*time.Millisecond { t.Errorf("expected WALSyncInterval 50ms, got %v", cfg.Database.WALSyncInterval) } }) t.Run("strict_overrides_custom", func(t *testing.T) { clearEnvVars(t) // Set custom values that should be overridden by strict mode os.Setenv("NORNICDB_WAL_SYNC_MODE", "none") os.Setenv("NORNICDB_WAL_SYNC_INTERVAL", "1s") os.Setenv("NORNICDB_STRICT_DURABILITY", "true") cfg := LoadFromEnv() // Strict mode should override custom settings if cfg.Database.WALSyncMode != "immediate" { t.Errorf("strict mode should override to 'immediate', got %q", cfg.Database.WALSyncMode) } if cfg.Database.WALSyncInterval != 0 { t.Errorf("strict mode should override to 0, got %v", cfg.Database.WALSyncInterval) } }) t.Run("none_sync_mode_for_testing", func(t *testing.T) { clearEnvVars(t) os.Setenv("NORNICDB_WAL_SYNC_MODE", "none") cfg := LoadFromEnv() if cfg.Database.WALSyncMode != "none" { t.Errorf("expected WALSyncMode 'none', got %q", cfg.Database.WALSyncMode) } }) } // TestLoadFromEnv_Neo4jAuth tests NEO4J_AUTH parsing. func TestLoadFromEnv_Neo4jAuth(t *testing.T) { tests := []struct { name string authEnv string wantEnabled bool wantUsername string wantPassword string }{ { name: "username/password format", authEnv: "admin/secretpass", wantEnabled: true, wantUsername: "admin", wantPassword: "secretpass", }, { name: "password with slash", authEnv: "neo4j/pass/word/with/slashes", wantEnabled: true, wantUsername: "neo4j", wantPassword: "pass/word/with/slashes", }, { name: "auth disabled", authEnv: "none", wantEnabled: false, wantUsername: "", wantPassword: "", }, { name: "password only (legacy)", authEnv: "simplepassword", wantEnabled: true, wantUsername: "admin", wantPassword: "simplepassword", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { clearEnvVars(t) os.Setenv("NEO4J_AUTH", tt.authEnv) cfg := LoadFromEnv() if cfg.Auth.Enabled != tt.wantEnabled { t.Errorf("expected Enabled=%v, got %v", tt.wantEnabled, cfg.Auth.Enabled) } if cfg.Auth.Enabled { if cfg.Auth.InitialUsername != tt.wantUsername { t.Errorf("expected username %q, got %q", tt.wantUsername, cfg.Auth.InitialUsername) } if cfg.Auth.InitialPassword != tt.wantPassword { t.Errorf("expected password %q, got %q", tt.wantPassword, cfg.Auth.InitialPassword) } } }) } } // TestLoadFromEnv_CustomValues tests custom env var values. func TestLoadFromEnv_CustomValues(t *testing.T) { clearEnvVars(t) // Set custom values os.Setenv("NEO4J_AUTH", "customuser/custompass") os.Setenv("NEO4J_dbms_directories_data", "/custom/data") os.Setenv("NEO4J_dbms_default__database", "mydb") os.Setenv("NEO4J_dbms_read__only", "true") os.Setenv("NEO4J_dbms_connector_bolt_listen__address_port", "7777") os.Setenv("NEO4J_dbms_connector_http_listen__address_port", "8080") os.Setenv("NORNICDB_MEMORY_DECAY_INTERVAL", "2h") os.Setenv("NORNICDB_EMBEDDING_PROVIDER", "openai") os.Setenv("NORNICDB_EMBEDDING_DIMENSIONS", "1536") os.Setenv("NORNICDB_AUDIT_RETENTION_DAYS", "365") os.Setenv("NORNICDB_SESSION_TIMEOUT", "1h") os.Setenv("NORNICDB_RETENTION_EXEMPT_ROLES", "admin, superuser, backup") cfg := LoadFromEnv() // Verify custom values if cfg.Auth.InitialUsername != "customuser" { t.Errorf("expected username 'customuser', got %q", cfg.Auth.InitialUsername) } if cfg.Database.DataDir != "/custom/data" { t.Errorf("expected data dir '/custom/data', got %q", cfg.Database.DataDir) } if cfg.Database.DefaultDatabase != "mydb" { t.Errorf("expected default db 'mydb', got %q", cfg.Database.DefaultDatabase) } if !cfg.Database.ReadOnly { t.Error("expected ReadOnly to be true") } if cfg.Server.BoltPort != 7777 { t.Errorf("expected bolt port 7777, got %d", cfg.Server.BoltPort) } if cfg.Server.HTTPPort != 8080 { t.Errorf("expected http port 8080, got %d", cfg.Server.HTTPPort) } if cfg.Memory.DecayInterval != 2*time.Hour { t.Errorf("expected decay interval 2h, got %v", cfg.Memory.DecayInterval) } if cfg.Memory.EmbeddingProvider != "openai" { t.Errorf("expected embedding provider 'openai', got %q", cfg.Memory.EmbeddingProvider) } if cfg.Memory.EmbeddingDimensions != 1536 { t.Errorf("expected embedding dimensions 1536, got %d", cfg.Memory.EmbeddingDimensions) } if cfg.Compliance.AuditRetentionDays != 365 { t.Errorf("expected audit retention 365, got %d", cfg.Compliance.AuditRetentionDays) } if cfg.Compliance.SessionTimeout != time.Hour { t.Errorf("expected session timeout 1h, got %v", cfg.Compliance.SessionTimeout) } // Check slice parsing expectedRoles := []string{"admin", "superuser", "backup"} if len(cfg.Compliance.RetentionExemptRoles) != len(expectedRoles) { t.Errorf("expected %d exempt roles, got %d", len(expectedRoles), len(cfg.Compliance.RetentionExemptRoles)) } else { for i, role := range expectedRoles { if cfg.Compliance.RetentionExemptRoles[i] != role { t.Errorf("expected role %q at index %d, got %q", role, i, cfg.Compliance.RetentionExemptRoles[i]) } } } } // TestLoadFromEnv_BoolParsing tests boolean env var parsing. func TestLoadFromEnv_BoolParsing(t *testing.T) { tests := []struct { envValue string want bool }{ {"true", true}, {"TRUE", true}, {"True", true}, {"1", true}, {"yes", true}, {"YES", true}, {"on", true}, {"ON", true}, {"false", false}, {"FALSE", false}, {"0", false}, {"no", false}, {"off", false}, {"", false}, // empty defaults to false for this test } for _, tt := range tests { t.Run("value="+tt.envValue, func(t *testing.T) { clearEnvVars(t) os.Setenv("NEO4J_dbms_read__only", tt.envValue) cfg := LoadFromEnv() if cfg.Database.ReadOnly != tt.want { t.Errorf("for value %q, expected ReadOnly=%v, got %v", tt.envValue, tt.want, cfg.Database.ReadOnly) } }) } } // TestLoadFromEnv_DurationParsing tests duration env var parsing. func TestLoadFromEnv_DurationParsing(t *testing.T) { tests := []struct { envValue string want time.Duration }{ {"30s", 30 * time.Second}, {"5m", 5 * time.Minute}, {"2h", 2 * time.Hour}, {"1h30m", 90 * time.Minute}, {"100", 100 * time.Second}, // numeric as seconds {"", 30 * time.Second}, // default } for _, tt := range tests { t.Run("value="+tt.envValue, func(t *testing.T) { clearEnvVars(t) if tt.envValue != "" { os.Setenv("NEO4J_dbms_transaction_timeout", tt.envValue) } cfg := LoadFromEnv() if cfg.Database.TransactionTimeout != tt.want { t.Errorf("for value %q, expected timeout=%v, got %v", tt.envValue, tt.want, cfg.Database.TransactionTimeout) } }) } } // TestConfig_Validate tests configuration validation. func TestConfig_Validate(t *testing.T) { tests := []struct { name string modify func(*Config) wantErr bool errMsg string }{ { name: "valid config with long password", modify: func(c *Config) { c.Auth.InitialPassword = "longenoughpassword" }, wantErr: false, }, { name: "auth enabled, no username", modify: func(c *Config) { c.Auth.Enabled = true c.Auth.InitialUsername = "" c.Auth.InitialPassword = "longenoughpassword" }, wantErr: true, errMsg: "no username", }, { name: "auth enabled, password too short", modify: func(c *Config) { c.Auth.Enabled = true c.Auth.InitialUsername = "admin" c.Auth.InitialPassword = "short" c.Auth.MinPasswordLength = 8 }, wantErr: true, errMsg: "at least 8 characters", }, { name: "auth disabled, short password OK", modify: func(c *Config) { c.Auth.Enabled = false c.Auth.InitialPassword = "x" }, wantErr: false, }, { name: "bolt enabled, invalid port", modify: func(c *Config) { c.Auth.InitialPassword = "longenoughpassword" c.Server.BoltEnabled = true c.Server.BoltPort = 0 }, wantErr: true, errMsg: "invalid bolt port", }, { name: "bolt enabled, negative port", modify: func(c *Config) { c.Auth.InitialPassword = "longenoughpassword" c.Server.BoltEnabled = true c.Server.BoltPort = -1 }, wantErr: true, errMsg: "invalid bolt port", }, { name: "bolt disabled, invalid port OK", modify: func(c *Config) { c.Auth.InitialPassword = "longenoughpassword" c.Server.BoltEnabled = false c.Server.BoltPort = 0 }, wantErr: false, }, { name: "http enabled, invalid port", modify: func(c *Config) { c.Auth.InitialPassword = "longenoughpassword" c.Server.HTTPEnabled = true c.Server.HTTPPort = -5 }, wantErr: true, errMsg: "invalid http port", }, { name: "invalid embedding dimensions", modify: func(c *Config) { c.Auth.InitialPassword = "longenoughpassword" c.Memory.EmbeddingDimensions = 0 }, wantErr: true, errMsg: "invalid embedding dimensions", }, { name: "negative embedding dimensions", modify: func(c *Config) { c.Auth.InitialPassword = "longenoughpassword" c.Memory.EmbeddingDimensions = -100 }, wantErr: true, errMsg: "invalid embedding dimensions", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { clearEnvVars(t) cfg := LoadFromEnv() tt.modify(cfg) err := cfg.Validate() if tt.wantErr { if err == nil { t.Error("expected error, got nil") } else if tt.errMsg != "" && !containsSubstring(err.Error(), tt.errMsg) { t.Errorf("expected error containing %q, got %q", tt.errMsg, err.Error()) } } else { if err != nil { t.Errorf("expected no error, got %v", err) } } }) } } // TestConfig_String tests safe string representation. func TestConfig_String(t *testing.T) { clearEnvVars(t) os.Setenv("NEO4J_AUTH", "admin/supersecretpassword") cfg := LoadFromEnv() str := cfg.String() // Should contain important info if !containsSubstring(str, "Auth: true") { t.Error("expected string to contain auth status") } if !containsSubstring(str, "7687") { t.Error("expected string to contain bolt port") } if !containsSubstring(str, "7474") { t.Error("expected string to contain http port") } if !containsSubstring(str, "./data") { t.Error("expected string to contain data dir") } // Should NOT contain secrets if containsSubstring(str, "supersecret") { t.Error("string should not contain password") } if containsSubstring(str, cfg.Auth.JWTSecret) { t.Error("string should not contain JWT secret") } } // TestGetEnvStringSlice tests string slice parsing. func TestGetEnvStringSlice(t *testing.T) { tests := []struct { name string envValue string defaultVal []string want []string }{ { name: "empty uses default", envValue: "", defaultVal: []string{"default"}, want: []string{"default"}, }, { name: "single value", envValue: "admin", defaultVal: []string{"default"}, want: []string{"admin"}, }, { name: "multiple values", envValue: "admin,user,guest", defaultVal: []string{"default"}, want: []string{"admin", "user", "guest"}, }, { name: "values with spaces", envValue: "admin, user , guest", defaultVal: []string{"default"}, want: []string{"admin", "user", "guest"}, }, { name: "empty parts ignored", envValue: "admin,,user,", defaultVal: []string{"default"}, want: []string{"admin", "user"}, }, { name: "only commas uses default", envValue: ",,,", defaultVal: []string{"default"}, want: []string{"default"}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { os.Setenv("TEST_SLICE", tt.envValue) defer os.Unsetenv("TEST_SLICE") got := getEnvStringSlice("TEST_SLICE", tt.defaultVal) if len(got) != len(tt.want) { t.Errorf("expected %d elements, got %d: %v", len(tt.want), len(got), got) return } for i, want := range tt.want { if got[i] != want { t.Errorf("element %d: expected %q, got %q", i, want, got[i]) } } }) } } // TestComplianceConfig_GDPR tests GDPR-specific compliance settings. func TestComplianceConfig_GDPR(t *testing.T) { clearEnvVars(t) // Enable GDPR-relevant features os.Setenv("NORNICDB_DATA_ERASURE_ENABLED", "true") os.Setenv("NORNICDB_DATA_EXPORT_ENABLED", "true") os.Setenv("NORNICDB_DATA_ACCESS_ENABLED", "true") os.Setenv("NORNICDB_CONSENT_REQUIRED", "true") os.Setenv("NORNICDB_ANONYMIZATION_ENABLED", "true") os.Setenv("NORNICDB_AUDIT_ENABLED", "true") cfg := LoadFromEnv() // GDPR Article 15-20: Data subject rights if !cfg.Compliance.DataErasureEnabled { t.Error("GDPR Art.17 Right to erasure should be enabled") } if !cfg.Compliance.DataExportEnabled { t.Error("GDPR Art.20 Data portability should be enabled") } if !cfg.Compliance.DataAccessEnabled { t.Error("GDPR Art.15 Right of access should be enabled") } // GDPR Article 7: Consent if !cfg.Compliance.ConsentRequired { t.Error("GDPR Art.7 Consent should be required") } // GDPR Recital 26: Anonymization if !cfg.Compliance.AnonymizationEnabled { t.Error("GDPR Recital 26 Anonymization should be enabled") } // GDPR Article 30: Records of processing if !cfg.Compliance.AuditEnabled { t.Error("GDPR Art.30 Audit logging should be enabled") } } // TestComplianceConfig_HIPAA tests HIPAA-specific compliance settings. func TestComplianceConfig_HIPAA(t *testing.T) { clearEnvVars(t) // HIPAA requires longer audit retention (6 years) os.Setenv("NORNICDB_AUDIT_RETENTION_DAYS", "2190") // 6 years os.Setenv("NORNICDB_ENCRYPTION_AT_REST", "true") os.Setenv("NORNICDB_ENCRYPTION_IN_TRANSIT", "true") os.Setenv("NORNICDB_ACCESS_CONTROL_ENABLED", "true") os.Setenv("NORNICDB_AUDIT_ENABLED", "true") cfg := LoadFromEnv() // HIPAA §164.530(j): Retain records for 6 years if cfg.Compliance.AuditRetentionDays < 2190 { t.Errorf("HIPAA requires 6 years audit retention, got %d days", cfg.Compliance.AuditRetentionDays) } // HIPAA §164.312(a)(2)(iv): Encryption if !cfg.Compliance.EncryptionAtRest { t.Error("HIPAA requires encryption at rest") } if !cfg.Compliance.EncryptionInTransit { t.Error("HIPAA requires encryption in transit") } // HIPAA §164.312(a): Access control if !cfg.Compliance.AccessControlEnabled { t.Error("HIPAA requires access control") } // HIPAA §164.312(b): Audit controls if !cfg.Compliance.AuditEnabled { t.Error("HIPAA requires audit controls") } } // TestComplianceConfig_FISMA tests FISMA-specific compliance settings. func TestComplianceConfig_FISMA(t *testing.T) { clearEnvVars(t) os.Setenv("NORNICDB_ACCESS_CONTROL_ENABLED", "true") os.Setenv("NORNICDB_AUDIT_ENABLED", "true") os.Setenv("NORNICDB_MAX_FAILED_LOGINS", "3") os.Setenv("NORNICDB_LOCKOUT_DURATION", "30m") os.Setenv("NORNICDB_SESSION_TIMEOUT", "15m") cfg := LoadFromEnv() // FISMA AC controls: Access Control if !cfg.Compliance.AccessControlEnabled { t.Error("FISMA AC controls require access control") } // FISMA AU controls: Audit if !cfg.Compliance.AuditEnabled { t.Error("FISMA AU controls require auditing") } // FISMA AC-7: Unsuccessful login attempts if cfg.Compliance.MaxFailedLogins > 5 { t.Errorf("FISMA recommends max 5 failed logins, got %d", cfg.Compliance.MaxFailedLogins) } // FISMA AC-12: Session termination if cfg.Compliance.SessionTimeout > 30*time.Minute { t.Errorf("FISMA recommends session timeout <= 30m, got %v", cfg.Compliance.SessionTimeout) } } // TestComplianceConfig_SOC2 tests SOC2-specific compliance settings. func TestComplianceConfig_SOC2(t *testing.T) { clearEnvVars(t) // SOC2 requires 7 years audit retention os.Setenv("NORNICDB_AUDIT_RETENTION_DAYS", "2555") // 7 years os.Setenv("NORNICDB_AUDIT_ENABLED", "true") os.Setenv("NORNICDB_BREACH_DETECTION_ENABLED", "true") cfg := LoadFromEnv() // SOC2: 7 year retention if cfg.Compliance.AuditRetentionDays < 2555 { t.Errorf("SOC2 requires 7 years audit retention, got %d days", cfg.Compliance.AuditRetentionDays) } // SOC2 CC7: System monitoring if !cfg.Compliance.AuditEnabled { t.Error("SOC2 CC7 requires audit logging") } // SOC2 CC7.4: Breach detection if !cfg.Compliance.BreachDetectionEnabled { t.Error("SOC2 CC7.4 requires breach detection") } } // TestGenerateDefaultSecret tests secret generation. func TestGenerateDefaultSecret(t *testing.T) { secret1 := generateDefaultSecret() secret2 := generateDefaultSecret() // Should be non-empty if len(secret1) < 20 { t.Errorf("expected secret length >= 20, got %d", len(secret1)) } // Should contain warning prefix if !containsSubstring(secret1, "CHANGE_ME") { t.Error("expected secret to contain CHANGE_ME warning") } // Different calls should produce different secrets (timestamp-based) // Note: This may occasionally fail if called within same nanosecond // In practice, this is extremely unlikely if secret1 == secret2 { t.Log("Warning: two consecutive secrets are identical (may happen rarely)") } } // Helper functions func clearEnvVars(t *testing.T) { t.Helper() envVars := []string{ "NEO4J_AUTH", "NEO4J_dbms_directories_data", "NEO4J_dbms_default__database", "NEO4J_dbms_read__only", "NEO4J_dbms_transaction_timeout", "NEO4J_dbms_transaction_concurrent_maximum", "NEO4J_dbms_connector_bolt_enabled", "NEO4J_dbms_connector_bolt_listen__address_port", "NEO4J_dbms_connector_bolt_listen__address", "NEO4J_dbms_connector_bolt_tls__level", "NEO4J_dbms_connector_http_enabled", "NEO4J_dbms_connector_http_listen__address_port", "NEO4J_dbms_connector_http_listen__address", "NEO4J_dbms_connector_https_enabled", "NEO4J_dbms_connector_https_listen__address_port", "NEO4J_dbms_logs_debug_level", "NEO4J_dbms_logs_query_enabled", "NEO4J_dbms_logs_query_threshold", "NEO4J_dbms_security_auth_minimum__password__length", "NORNICDB_AUTH_TOKEN_EXPIRY", "NORNICDB_AUTH_JWT_SECRET", "NORNICDB_MEMORY_DECAY_ENABLED", "NORNICDB_MEMORY_DECAY_INTERVAL", "NORNICDB_MEMORY_ARCHIVE_THRESHOLD", "NORNICDB_EMBEDDING_PROVIDER", "NORNICDB_EMBEDDING_MODEL", "NORNICDB_EMBEDDING_API_URL", "NORNICDB_EMBEDDING_DIMENSIONS", "NORNICDB_AUTO_LINKS_ENABLED", "NORNICDB_AUTO_LINKS_THRESHOLD", "NORNICDB_AUDIT_ENABLED", "NORNICDB_AUDIT_LOG_PATH", "NORNICDB_AUDIT_RETENTION_DAYS", "NORNICDB_RETENTION_ENABLED", "NORNICDB_RETENTION_POLICY_DAYS", "NORNICDB_RETENTION_AUTO_DELETE", "NORNICDB_RETENTION_EXEMPT_ROLES", "NORNICDB_ACCESS_CONTROL_ENABLED", "NORNICDB_SESSION_TIMEOUT", "NORNICDB_MAX_FAILED_LOGINS", "NORNICDB_LOCKOUT_DURATION", "NORNICDB_ENCRYPTION_AT_REST", "NORNICDB_ENCRYPTION_IN_TRANSIT", "NORNICDB_ENCRYPTION_KEY_PATH", "NORNICDB_DATA_EXPORT_ENABLED", "NORNICDB_DATA_ERASURE_ENABLED", "NORNICDB_DATA_ACCESS_ENABLED", "NORNICDB_ANONYMIZATION_ENABLED", "NORNICDB_ANONYMIZATION_METHOD", "NORNICDB_CONSENT_REQUIRED", "NORNICDB_CONSENT_VERSIONING", "NORNICDB_CONSENT_AUDIT_TRAIL", "NORNICDB_BREACH_DETECTION_ENABLED", "NORNICDB_BREACH_NOTIFY_EMAIL", "NORNICDB_BREACH_NOTIFY_WEBHOOK", "NORNICDB_LOG_FORMAT", "NORNICDB_LOG_OUTPUT", // Durability settings "NORNICDB_STRICT_DURABILITY", "NORNICDB_WAL_SYNC_MODE", "NORNICDB_WAL_SYNC_INTERVAL", } for _, v := range envVars { os.Unsetenv(v) } } func containsSubstring(s, substr string) bool { return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsSubstringHelper(s, substr)) } func containsSubstringHelper(s, substr string) bool { for i := 0; i <= len(s)-len(substr); i++ { if s[i:i+len(substr)] == substr { return true } } return false }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/orneryd/Mimir'

If you have feedback or need assistance with the MCP directory API, please join our Discord server