diff --git a/.gitignore b/.gitignore
index 040dfe79..64f4c728 100644
--- a/.gitignore
+++ b/.gitignore
@@ -245,3 +245,4 @@ my-codeql-db/**
codeql-linux64.zip
backend/main
**.out
+docs/plans/supply_chain_security_implementation.md.backup
diff --git a/backend/test_output.txt b/backend/test_output.txt
index 120e28ad..3cde71d3 100644
--- a/backend/test_output.txt
+++ b/backend/test_output.txt
@@ -1,3 +1,45 @@
-ok github.com/Wikid82/charon/backend/cmd/api (cached) coverage: 0.0% of statements
-ok github.com/Wikid82/charon/backend/cmd/seed (cached) coverage: 63.2% of statements
+=== RUN TestResetPasswordCommand_Succeeds
+time="2026-01-10T03:00:26Z" level=info msg="SQLite database connected with WAL mode enabled" journal_mode=wal
+time="2026-01-10T03:00:26Z" level=info msg="SQLite database integrity check passed"
+--- PASS: TestResetPasswordCommand_Succeeds (0.15s)
+=== RUN TestMigrateCommand_Succeeds
+time="2026-01-10T03:00:27Z" level=info msg="SQLite database connected with WAL mode enabled" journal_mode=wal
+time="2026-01-10T03:00:27Z" level=info msg="SQLite database integrity check passed"
+time="2026-01-10T03:00:27Z" level=info msg="SQLite database connected with WAL mode enabled" journal_mode=wal
+time="2026-01-10T03:00:27Z" level=info msg="SQLite database integrity check passed"
+--- PASS: TestMigrateCommand_Succeeds (0.08s)
+=== RUN TestStartupVerification_MissingTables
+time="2026-01-10T03:00:27Z" level=info msg="SQLite database connected with WAL mode enabled" journal_mode=wal
+time="2026-01-10T03:00:27Z" level=info msg="SQLite database integrity check passed"
+time="2026-01-10T03:00:27Z" level=info msg="SQLite database connected with WAL mode enabled" journal_mode=wal
+time="2026-01-10T03:00:27Z" level=info msg="SQLite database integrity check passed"
+ main_test.go:171: Missing table for model *models.SecurityConfig
+ main_test.go:171: Missing table for model *models.SecurityDecision
+ main_test.go:171: Missing table for model *models.SecurityAudit
+ main_test.go:171: Missing table for model *models.SecurityRuleSet
+ main_test.go:171: Missing table for model *models.CrowdsecPresetEvent
+ main_test.go:171: Missing table for model *models.CrowdsecConsoleEnrollment
+--- PASS: TestStartupVerification_MissingTables (0.05s)
+PASS
+coverage: 0.0% of statements
+ok github.com/Wikid82/charon/backend/cmd/api 0.310s coverage: 0.0% of statements
+=== RUN TestSeedMain_Smoke
+{"level":"info","msg":"✓ Database migrated successfully","time":"2026-01-10T03:00:27Z"}
+{"level":"info","msg":"✓ Created remote server: Local Docker Registry (localhost:5000)","server":"Local Docker Registry","time":"2026-01-10T03:00:27Z"}
+{"level":"info","msg":"✓ Created remote server: Development API Server (192.168.1.100:8080)","server":"Development API Server","time":"2026-01-10T03:00:27Z"}
+{"level":"info","msg":"✓ Created remote server: Staging Web App (staging.internal:3000)","server":"Staging Web App","time":"2026-01-10T03:00:27Z"}
+{"level":"info","msg":"✓ Created remote server: Database Admin (localhost:8081)","server":"Database Admin","time":"2026-01-10T03:00:27Z"}
+{"host":"app.local.dev","level":"info","msg":"✓ Created proxy host: app.local.dev -\u003e http://localhost:3000","time":"2026-01-10T03:00:27Z"}
+{"host":"api.local.dev","level":"info","msg":"✓ Created proxy host: api.local.dev -\u003e http://192.168.1.100:8080","time":"2026-01-10T03:00:27Z"}
+{"host":"docker.local.dev","level":"info","msg":"✓ Created proxy host: docker.local.dev -\u003e http://localhost:5000","time":"2026-01-10T03:00:27Z"}
+{"level":"info","msg":"✓ Created setting: app_name = Charon","setting":"app_name","time":"2026-01-10T03:00:27Z"}
+{"level":"info","msg":"✓ Created setting: default_scheme = http","setting":"default_scheme","time":"2026-01-10T03:00:27Z"}
+{"level":"info","msg":"✓ Created setting: enable_ssl_by_default = false","setting":"enable_ssl_by_default","time":"2026-01-10T03:00:27Z"}
+{"level":"info","msg":"✓ Created default user: admin@localhost","time":"2026-01-10T03:00:27Z","user":"admin@localhost"}
+{"level":"info","msg":"\n✓ Database seeding completed successfully!","time":"2026-01-10T03:00:27Z"}
+{"level":"info","msg":" You can now start the application and see sample data.","time":"2026-01-10T03:00:27Z"}
+--- PASS: TestSeedMain_Smoke (0.31s)
+PASS
+coverage: 63.2% of statements
+ok github.com/Wikid82/charon/backend/cmd/seed 0.322s coverage: 63.2% of statements
? github.com/Wikid82/charon/backend/integration [no test files]
diff --git a/backend/test_output_qa.txt b/backend/test_output_qa.txt
new file mode 100644
index 00000000..d6fd3486
--- /dev/null
+++ b/backend/test_output_qa.txt
@@ -0,0 +1,14134 @@
+=== RUN TestResetPasswordCommand_Succeeds
+time="2026-01-10T02:16:43Z" level=info msg="SQLite database connected with WAL mode enabled" journal_mode=wal
+time="2026-01-10T02:16:43Z" level=info msg="SQLite database integrity check passed"
+--- PASS: TestResetPasswordCommand_Succeeds (1.99s)
+=== RUN TestMigrateCommand_Succeeds
+time="2026-01-10T02:16:44Z" level=info msg="SQLite database connected with WAL mode enabled" journal_mode=wal
+time="2026-01-10T02:16:44Z" level=info msg="SQLite database integrity check passed"
+time="2026-01-10T02:16:46Z" level=info msg="SQLite database connected with WAL mode enabled" journal_mode=wal
+time="2026-01-10T02:16:46Z" level=info msg="SQLite database integrity check passed"
+--- PASS: TestMigrateCommand_Succeeds (1.27s)
+=== RUN TestStartupVerification_MissingTables
+time="2026-01-10T02:16:46Z" level=info msg="SQLite database connected with WAL mode enabled" journal_mode=wal
+time="2026-01-10T02:16:46Z" level=info msg="SQLite database integrity check passed"
+time="2026-01-10T02:16:46Z" level=info msg="SQLite database connected with WAL mode enabled" journal_mode=wal
+time="2026-01-10T02:16:46Z" level=info msg="SQLite database integrity check passed"
+ main_test.go:171: Missing table for model *models.SecurityConfig
+ main_test.go:171: Missing table for model *models.SecurityDecision
+ main_test.go:171: Missing table for model *models.SecurityAudit
+ main_test.go:171: Missing table for model *models.SecurityRuleSet
+ main_test.go:171: Missing table for model *models.CrowdsecPresetEvent
+ main_test.go:171: Missing table for model *models.CrowdsecConsoleEnrollment
+--- PASS: TestStartupVerification_MissingTables (0.06s)
+PASS
+coverage: 0.0% of statements
+ok github.com/Wikid82/charon/backend/cmd/api (cached) coverage: 0.0% of statements
+=== RUN TestSeedMain_Smoke
+{"level":"info","msg":"✓ Database migrated successfully","time":"2026-01-10T02:16:43Z"}
+{"level":"info","msg":"✓ Created remote server: Local Docker Registry (localhost:5000)","server":"Local Docker Registry","time":"2026-01-10T02:16:43Z"}
+{"level":"info","msg":"✓ Created remote server: Development API Server (192.168.1.100:8080)","server":"Development API Server","time":"2026-01-10T02:16:43Z"}
+{"level":"info","msg":"✓ Created remote server: Staging Web App (staging.internal:3000)","server":"Staging Web App","time":"2026-01-10T02:16:43Z"}
+{"level":"info","msg":"✓ Created remote server: Database Admin (localhost:8081)","server":"Database Admin","time":"2026-01-10T02:16:43Z"}
+{"host":"app.local.dev","level":"info","msg":"✓ Created proxy host: app.local.dev -\u003e http://localhost:3000","time":"2026-01-10T02:16:43Z"}
+{"host":"api.local.dev","level":"info","msg":"✓ Created proxy host: api.local.dev -\u003e http://192.168.1.100:8080","time":"2026-01-10T02:16:43Z"}
+{"host":"docker.local.dev","level":"info","msg":"✓ Created proxy host: docker.local.dev -\u003e http://localhost:5000","time":"2026-01-10T02:16:43Z"}
+{"level":"info","msg":"✓ Created setting: app_name = Charon","setting":"app_name","time":"2026-01-10T02:16:43Z"}
+{"level":"info","msg":"✓ Created setting: default_scheme = http","setting":"default_scheme","time":"2026-01-10T02:16:43Z"}
+{"level":"info","msg":"✓ Created setting: enable_ssl_by_default = false","setting":"enable_ssl_by_default","time":"2026-01-10T02:16:43Z"}
+{"level":"info","msg":"✓ Created default user: admin@localhost","time":"2026-01-10T02:16:43Z","user":"admin@localhost"}
+{"level":"info","msg":"\n✓ Database seeding completed successfully!","time":"2026-01-10T02:16:43Z"}
+{"level":"info","msg":" You can now start the application and see sample data.","time":"2026-01-10T02:16:43Z"}
+--- PASS: TestSeedMain_Smoke (0.28s)
+PASS
+coverage: 63.2% of statements
+ok github.com/Wikid82/charon/backend/cmd/seed (cached) coverage: 63.2% of statements
+? github.com/Wikid82/charon/backend/integration [no test files]
+=== RUN TestAccessListHandler_SetGeoIPService
+--- PASS: TestAccessListHandler_SetGeoIPService (0.01s)
+=== RUN TestAccessListHandler_SetGeoIPService_Nil
+--- PASS: TestAccessListHandler_SetGeoIPService_Nil (0.01s)
+=== RUN TestAccessListHandler_Get_InvalidID
+--- PASS: TestAccessListHandler_Get_InvalidID (0.03s)
+=== RUN TestAccessListHandler_Update_InvalidID
+--- PASS: TestAccessListHandler_Update_InvalidID (0.02s)
+=== RUN TestAccessListHandler_Update_InvalidJSON
+--- PASS: TestAccessListHandler_Update_InvalidJSON (0.02s)
+=== RUN TestAccessListHandler_Delete_InvalidID
+--- PASS: TestAccessListHandler_Delete_InvalidID (0.02s)
+=== RUN TestAccessListHandler_TestIP_InvalidID
+--- PASS: TestAccessListHandler_TestIP_InvalidID (0.02s)
+=== RUN TestAccessListHandler_TestIP_MissingIPAddress
+--- PASS: TestAccessListHandler_TestIP_MissingIPAddress (0.02s)
+=== RUN TestAccessListHandler_List_DBError
+
+2026/01/10 02:17:36 [31;1m/projects/Charon/backend/internal/services/access_list_service.go:129 [35;1mno such table: access_lists
+[0m[33m[1.585ms] [34;1m[rows:0][0m SELECT * FROM `access_lists` ORDER BY updated_at desc
+--- PASS: TestAccessListHandler_List_DBError (0.00s)
+=== RUN TestAccessListHandler_Get_DBError
+
+2026/01/10 02:17:36 [31;1m/projects/Charon/backend/internal/services/access_list_service.go:105 [35;1mno such table: access_lists
+[0m[33m[2.493ms] [34;1m[rows:0][0m SELECT * FROM `access_lists` WHERE `access_lists`.`id` = 1 ORDER BY `access_lists`.`id` LIMIT 1
+--- PASS: TestAccessListHandler_Get_DBError (0.00s)
+=== RUN TestAccessListHandler_Delete_InternalError
+
+2026/01/10 02:17:36 [31;1m/projects/Charon/backend/internal/services/access_list_service.go:162 [35;1mno such table: proxy_hosts
+[0m[33m[10.015ms] [34;1m[rows:0][0m SELECT count(*) FROM `proxy_hosts` WHERE access_list_id = 1
+--- PASS: TestAccessListHandler_Delete_InternalError (0.01s)
+=== RUN TestAccessListHandler_Update_InvalidType
+--- PASS: TestAccessListHandler_Update_InvalidType (0.03s)
+=== RUN TestAccessListHandler_Create_InvalidJSON
+--- PASS: TestAccessListHandler_Create_InvalidJSON (0.04s)
+=== RUN TestAccessListHandler_TestIP_Blacklist
+--- PASS: TestAccessListHandler_TestIP_Blacklist (0.03s)
+=== RUN TestAccessListHandler_TestIP_GeoWhitelist
+--- PASS: TestAccessListHandler_TestIP_GeoWhitelist (0.03s)
+=== RUN TestAccessListHandler_TestIP_LocalNetworkOnly
+--- PASS: TestAccessListHandler_TestIP_LocalNetworkOnly (0.02s)
+=== RUN TestAccessListHandler_TestIP_InternalError
+
+2026/01/10 02:17:36 [31;1m/projects/Charon/backend/internal/services/access_list_service.go:105 [35;1mno such table: access_lists
+[0m[33m[0.993ms] [34;1m[rows:0][0m SELECT * FROM `access_lists` WHERE `access_lists`.`id` = 1 ORDER BY `access_lists`.`id` LIMIT 1
+--- PASS: TestAccessListHandler_TestIP_InternalError (0.00s)
+=== RUN TestAccessListHandler_Create
+=== RUN TestAccessListHandler_Create/create_whitelist_successfully
+=== RUN TestAccessListHandler_Create/create_geo_whitelist_successfully
+=== RUN TestAccessListHandler_Create/create_local_network_only
+=== RUN TestAccessListHandler_Create/fail_with_invalid_type
+=== RUN TestAccessListHandler_Create/fail_with_missing_name
+--- PASS: TestAccessListHandler_Create (0.02s)
+ --- PASS: TestAccessListHandler_Create/create_whitelist_successfully (0.00s)
+ --- PASS: TestAccessListHandler_Create/create_geo_whitelist_successfully (0.00s)
+ --- PASS: TestAccessListHandler_Create/create_local_network_only (0.00s)
+ --- PASS: TestAccessListHandler_Create/fail_with_invalid_type (0.00s)
+ --- PASS: TestAccessListHandler_Create/fail_with_missing_name (0.00s)
+=== RUN TestAccessListHandler_List
+--- PASS: TestAccessListHandler_List (0.02s)
+=== RUN TestAccessListHandler_Get
+=== RUN TestAccessListHandler_Get/get_existing_ACL
+=== RUN TestAccessListHandler_Get/get_non-existent_ACL
+
+2026/01/10 02:17:36 [31;1m/projects/Charon/backend/internal/services/access_list_service.go:105 [35;1mrecord not found
+[0m[33m[0.120ms] [34;1m[rows:0][0m SELECT * FROM `access_lists` WHERE `access_lists`.`id` = 9999 ORDER BY `access_lists`.`id` LIMIT 1
+--- PASS: TestAccessListHandler_Get (0.02s)
+ --- PASS: TestAccessListHandler_Get/get_existing_ACL (0.00s)
+ --- PASS: TestAccessListHandler_Get/get_non-existent_ACL (0.00s)
+=== RUN TestAccessListHandler_Update
+=== RUN TestAccessListHandler_Update/update_successfully
+=== RUN TestAccessListHandler_Update/update_non-existent_ACL
+
+2026/01/10 02:17:36 [31;1m/projects/Charon/backend/internal/services/access_list_service.go:105 [35;1mrecord not found
+[0m[33m[0.098ms] [34;1m[rows:0][0m SELECT * FROM `access_lists` WHERE `access_lists`.`id` = 9999 ORDER BY `access_lists`.`id` LIMIT 1
+--- PASS: TestAccessListHandler_Update (0.03s)
+ --- PASS: TestAccessListHandler_Update/update_successfully (0.00s)
+ --- PASS: TestAccessListHandler_Update/update_non-existent_ACL (0.00s)
+=== RUN TestAccessListHandler_Delete
+=== RUN TestAccessListHandler_Delete/delete_successfully
+=== RUN TestAccessListHandler_Delete/fail_to_delete_ACL_in_use
+=== RUN TestAccessListHandler_Delete/delete_non-existent_ACL
+--- PASS: TestAccessListHandler_Delete (0.05s)
+ --- PASS: TestAccessListHandler_Delete/delete_successfully (0.00s)
+ --- PASS: TestAccessListHandler_Delete/fail_to_delete_ACL_in_use (0.00s)
+ --- PASS: TestAccessListHandler_Delete/delete_non-existent_ACL (0.00s)
+=== RUN TestAccessListHandler_TestIP
+=== RUN TestAccessListHandler_TestIP/test_IP_in_whitelist
+=== RUN TestAccessListHandler_TestIP/test_IP_not_in_whitelist
+=== RUN TestAccessListHandler_TestIP/test_invalid_IP
+=== RUN TestAccessListHandler_TestIP/test_non-existent_ACL
+
+2026/01/10 02:17:36 [31;1m/projects/Charon/backend/internal/services/access_list_service.go:105 [35;1mrecord not found
+[0m[33m[0.074ms] [34;1m[rows:0][0m SELECT * FROM `access_lists` WHERE `access_lists`.`id` = 9999 ORDER BY `access_lists`.`id` LIMIT 1
+--- PASS: TestAccessListHandler_TestIP (0.04s)
+ --- PASS: TestAccessListHandler_TestIP/test_IP_in_whitelist (0.00s)
+ --- PASS: TestAccessListHandler_TestIP/test_IP_not_in_whitelist (0.00s)
+ --- PASS: TestAccessListHandler_TestIP/test_invalid_IP (0.00s)
+ --- PASS: TestAccessListHandler_TestIP/test_non-existent_ACL (0.00s)
+=== RUN TestAccessListHandler_GetTemplates
+--- PASS: TestAccessListHandler_GetTemplates (0.02s)
+=== RUN TestImportHandler_Commit_InvalidJSON
+--- PASS: TestImportHandler_Commit_InvalidJSON (0.03s)
+=== RUN TestImportHandler_Commit_InvalidSessionUUID
+--- PASS: TestImportHandler_Commit_InvalidSessionUUID (0.03s)
+=== RUN TestImportHandler_Commit_SessionNotFound
+--- PASS: TestImportHandler_Commit_SessionNotFound (0.05s)
+=== RUN TestRemoteServerHandler_TestConnection_Unreachable
+--- PASS: TestRemoteServerHandler_TestConnection_Unreachable (5.01s)
+=== RUN TestSecurityHandler_GetConfig_InternalError
+--- PASS: TestSecurityHandler_GetConfig_InternalError (0.01s)
+=== RUN TestSecurityHandler_UpdateConfig_ApplyCaddyError
+--- PASS: TestSecurityHandler_UpdateConfig_ApplyCaddyError (0.01s)
+=== RUN TestSecurityHandler_GenerateBreakGlass_Error
+--- PASS: TestSecurityHandler_GenerateBreakGlass_Error (0.75s)
+=== RUN TestSecurityHandler_ListDecisions_Error
+--- PASS: TestSecurityHandler_ListDecisions_Error (0.01s)
+=== RUN TestSecurityHandler_ListRuleSets_Error
+--- PASS: TestSecurityHandler_ListRuleSets_Error (0.01s)
+=== RUN TestSecurityHandler_UpsertRuleSet_Error
+--- PASS: TestSecurityHandler_UpsertRuleSet_Error (0.01s)
+=== RUN TestSecurityHandler_CreateDecision_LogError
+--- PASS: TestSecurityHandler_CreateDecision_LogError (0.01s)
+=== RUN TestSecurityHandler_DeleteRuleSet_Error
+--- PASS: TestSecurityHandler_DeleteRuleSet_Error (0.01s)
+=== RUN TestCrowdsec_ImportConfig_EmptyUpload
+--- PASS: TestCrowdsec_ImportConfig_EmptyUpload (0.00s)
+=== RUN TestBackupHandler_List_DBError
+time="2026-01-10T02:17:42Z" level=info msg="Backup service cron scheduler stopped"
+--- PASS: TestBackupHandler_List_DBError (0.00s)
+=== RUN TestImportHandler_UploadMulti_InvalidJSON
+--- PASS: TestImportHandler_UploadMulti_InvalidJSON (0.02s)
+=== RUN TestImportHandler_UploadMulti_MissingCaddyfile
+--- PASS: TestImportHandler_UploadMulti_MissingCaddyfile (0.01s)
+=== RUN TestImportHandler_UploadMulti_EmptyContent
+--- PASS: TestImportHandler_UploadMulti_EmptyContent (0.02s)
+=== RUN TestImportHandler_UploadMulti_PathTraversal
+--- PASS: TestImportHandler_UploadMulti_PathTraversal (0.02s)
+=== RUN TestLogsHandler_Download_PathTraversal
+--- PASS: TestLogsHandler_Download_PathTraversal (0.00s)
+=== RUN TestLogsHandler_Download_NotFound
+--- PASS: TestLogsHandler_Download_NotFound (0.00s)
+=== RUN TestLogsHandler_Download_Success
+--- PASS: TestLogsHandler_Download_Success (0.01s)
+=== RUN TestImportHandler_Upload_InvalidJSON
+time="2026-01-10T02:17:42Z" level=error msg="Import Upload: failed to bind JSON" error="invalid character 'o' in literal null (expecting 'u')"
+--- PASS: TestImportHandler_Upload_InvalidJSON (0.02s)
+=== RUN TestImportHandler_Upload_EmptyContent
+time="2026-01-10T02:17:42Z" level=error msg="Import Upload: failed to bind JSON" error="Key: 'Content' Error:Field validation for 'Content' failed on the 'required' tag"
+--- PASS: TestImportHandler_Upload_EmptyContent (0.02s)
+=== RUN TestBackupHandler_List_ServiceError
+--- PASS: TestBackupHandler_List_ServiceError (0.00s)
+=== RUN TestBackupHandler_Delete_PathTraversal
+time="2026-01-10T02:17:42Z" level=info msg="Backup service cron scheduler stopped"
+--- PASS: TestBackupHandler_Delete_PathTraversal (0.00s)
+=== RUN TestBackupHandler_Delete_InternalError2
+time="2026-01-10T02:17:42Z" level=info msg="Backup service cron scheduler stopped"
+--- PASS: TestBackupHandler_Delete_InternalError2 (0.00s)
+=== RUN TestRemoteServerHandler_TestConnection_NotFound2
+--- PASS: TestRemoteServerHandler_TestConnection_NotFound2 (0.00s)
+=== RUN TestRemoteServerHandler_TestConnectionCustom_Unreachable2
+--- PASS: TestRemoteServerHandler_TestConnectionCustom_Unreachable2 (5.01s)
+=== RUN TestAuthHandler_Register_InvalidJSON
+--- PASS: TestAuthHandler_Register_InvalidJSON (0.02s)
+=== RUN TestHealthHandler_Basic
+--- PASS: TestHealthHandler_Basic (0.00s)
+=== RUN TestBackupHandler_Create_Error
+time="2026-01-10T02:17:47Z" level=error msg="Failed to create backup" action=create_backup error="database file not found: /tmp/TestBackupHandler_Create_Error62628796/001/data/charon.db"
+time="2026-01-10T02:17:47Z" level=info msg="Backup service cron scheduler stopped"
+--- PASS: TestBackupHandler_Create_Error (0.00s)
+=== RUN TestSettingsHandler_GetSettings_Error
+--- PASS: TestSettingsHandler_GetSettings_Error (0.00s)
+=== RUN TestSettingsHandler_UpdateSetting_InvalidJSON
+--- PASS: TestSettingsHandler_UpdateSetting_InvalidJSON (0.00s)
+=== RUN TestRemoteServerHandler_TestConnection_Reachable
+--- PASS: TestRemoteServerHandler_TestConnection_Reachable (0.01s)
+=== RUN TestRemoteServerHandler_TestConnection_EmptyHost
+--- PASS: TestRemoteServerHandler_TestConnection_EmptyHost (0.00s)
+=== RUN TestImportHandler_UploadMulti_ValidCaddyfile
+time="2026-01-10T02:17:47Z" level=error msg="Import UploadMulti: import failed" error="caddy adapt failed: exec: \"caddy\": executable file not found in $PATH (output: )" mainCaddyfile=Caddyfile preview="example.com { reverse_proxy localhost:8080 }"
+--- PASS: TestImportHandler_UploadMulti_ValidCaddyfile (0.02s)
+=== RUN TestImportHandler_UploadMulti_SubdirFile
+time="2026-01-10T02:17:47Z" level=error msg="Import UploadMulti: import failed" error="caddy adapt failed: exec: \"caddy\": executable file not found in $PATH (output: )" mainCaddyfile=Caddyfile preview="import sites/*"
+--- PASS: TestImportHandler_UploadMulti_SubdirFile (0.02s)
+=== RUN Test_getLocalIP_Additional
+ additional_handlers_test.go:29: getLocalIP returned: 217.15.170.144
+--- PASS: Test_getLocalIP_Additional (0.00s)
+=== RUN TestFeatureFlagsHandler_GetFlags_FromShortEnv
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/api/handlers/feature_flags_handler.go:48 [35;1mrecord not found
+[0m[33m[0.064ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/api/handlers/feature_flags_handler.go:48 [35;1mrecord not found
+[0m[33m[0.056ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.uptime.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/api/handlers/feature_flags_handler.go:48 [35;1mrecord not found
+[0m[33m[0.094ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.crowdsec.console_enrollment" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestFeatureFlagsHandler_GetFlags_FromShortEnv (0.00s)
+=== RUN TestFeatureFlagsHandler_UpdateFlags_UnknownFlag
+--- PASS: TestFeatureFlagsHandler_UpdateFlags_UnknownFlag (0.00s)
+=== RUN TestDomainHandler_List_Additional
+--- PASS: TestDomainHandler_List_Additional (0.00s)
+=== RUN TestDomainHandler_List_Empty_Additional
+--- PASS: TestDomainHandler_List_Empty_Additional (0.00s)
+=== RUN TestDomainHandler_Create_Additional
+--- PASS: TestDomainHandler_Create_Additional (0.00s)
+=== RUN TestDomainHandler_Create_MissingName_Additional
+--- PASS: TestDomainHandler_Create_MissingName_Additional (0.00s)
+=== RUN TestDomainHandler_Delete_Additional
+--- PASS: TestDomainHandler_Delete_Additional (0.00s)
+=== RUN TestDomainHandler_Delete_NotFound_Additional
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/api/handlers/domain_handler.go:73 [35;1mrecord not found
+[0m[33m[0.094ms] [34;1m[rows:0][0m SELECT * FROM `domains` WHERE uuid = "nonexistent" AND `domains`.`deleted_at` IS NULL ORDER BY `domains`.`id` LIMIT 1
+--- PASS: TestDomainHandler_Delete_NotFound_Additional (0.00s)
+=== RUN TestNotificationHandler_List_Additional
+--- PASS: TestNotificationHandler_List_Additional (0.00s)
+=== RUN TestNotificationHandler_MarkAsRead_Additional
+--- PASS: TestNotificationHandler_MarkAsRead_Additional (0.00s)
+=== RUN TestNotificationHandler_MarkAllAsRead_Additional
+--- PASS: TestNotificationHandler_MarkAllAsRead_Additional (0.00s)
+=== RUN TestCrowdsecExec_NewDefaultCrowdsecExecutor
+--- PASS: TestCrowdsecExec_NewDefaultCrowdsecExecutor (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_isCrowdSecProcess
+--- PASS: TestDefaultCrowdsecExecutor_isCrowdSecProcess (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_pidFile
+--- PASS: TestDefaultCrowdsecExecutor_pidFile (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_Status
+--- PASS: TestDefaultCrowdsecExecutor_Status (0.00s)
+=== RUN Test_isSafePathUnderBase_Additional
+=== RUN Test_isSafePathUnderBase_Additional/valid_relative_path_under_base
+=== RUN Test_isSafePathUnderBase_Additional/valid_relative_path_with_subdir
+=== RUN Test_isSafePathUnderBase_Additional/path_traversal_attempt
+=== RUN Test_isSafePathUnderBase_Additional/empty_path
+--- PASS: Test_isSafePathUnderBase_Additional (0.00s)
+ --- PASS: Test_isSafePathUnderBase_Additional/valid_relative_path_under_base (0.00s)
+ --- PASS: Test_isSafePathUnderBase_Additional/valid_relative_path_with_subdir (0.00s)
+ --- PASS: Test_isSafePathUnderBase_Additional/path_traversal_attempt (0.00s)
+ --- PASS: Test_isSafePathUnderBase_Additional/empty_path (0.00s)
+=== RUN TestAuditLogHandler_List
+=== RUN TestAuditLogHandler_List/List_all_audit_logs
+=== RUN TestAuditLogHandler_List/Filter_by_actor
+=== RUN TestAuditLogHandler_List/Filter_by_action
+=== RUN TestAuditLogHandler_List/Filter_by_event_category
+=== RUN TestAuditLogHandler_List/Pagination_-_page_1,_limit_1
+--- PASS: TestAuditLogHandler_List (0.01s)
+ --- PASS: TestAuditLogHandler_List/List_all_audit_logs (0.00s)
+ --- PASS: TestAuditLogHandler_List/Filter_by_actor (0.00s)
+ --- PASS: TestAuditLogHandler_List/Filter_by_action (0.00s)
+ --- PASS: TestAuditLogHandler_List/Filter_by_event_category (0.00s)
+ --- PASS: TestAuditLogHandler_List/Pagination_-_page_1,_limit_1 (0.00s)
+=== RUN TestAuditLogHandler_Get
+=== RUN TestAuditLogHandler_Get/Get_existing_audit_log
+=== RUN TestAuditLogHandler_Get/Get_non-existent_audit_log
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/services/security_service.go:321 [35;1mrecord not found
+[0m[33m[0.092ms] [34;1m[rows:0][0m SELECT * FROM `security_audits` WHERE uuid = "non-existent-uuid" ORDER BY `security_audits`.`id` LIMIT 1
+=== RUN TestAuditLogHandler_Get/Get_with_empty_UUID
+--- PASS: TestAuditLogHandler_Get (0.00s)
+ --- PASS: TestAuditLogHandler_Get/Get_existing_audit_log (0.00s)
+ --- PASS: TestAuditLogHandler_Get/Get_non-existent_audit_log (0.00s)
+ --- PASS: TestAuditLogHandler_Get/Get_with_empty_UUID (0.00s)
+=== RUN TestAuditLogHandler_ListByProvider
+=== RUN TestAuditLogHandler_ListByProvider/List_audit_logs_for_provider
+=== RUN TestAuditLogHandler_ListByProvider/List_audit_logs_for_non-existent_provider
+=== RUN TestAuditLogHandler_ListByProvider/Invalid_provider_ID
+--- PASS: TestAuditLogHandler_ListByProvider (0.00s)
+ --- PASS: TestAuditLogHandler_ListByProvider/List_audit_logs_for_provider (0.00s)
+ --- PASS: TestAuditLogHandler_ListByProvider/List_audit_logs_for_non-existent_provider (0.00s)
+ --- PASS: TestAuditLogHandler_ListByProvider/Invalid_provider_ID (0.00s)
+=== RUN TestAuditLogHandler_ListWithDateFilters
+=== RUN TestAuditLogHandler_ListWithDateFilters/Filter_by_start_date
+=== RUN TestAuditLogHandler_ListWithDateFilters/Filter_by_end_date
+=== RUN TestAuditLogHandler_ListWithDateFilters/Filter_by_date_range
+--- PASS: TestAuditLogHandler_ListWithDateFilters (0.01s)
+ --- PASS: TestAuditLogHandler_ListWithDateFilters/Filter_by_start_date (0.00s)
+ --- PASS: TestAuditLogHandler_ListWithDateFilters/Filter_by_end_date (0.00s)
+ --- PASS: TestAuditLogHandler_ListWithDateFilters/Filter_by_date_range (0.00s)
+=== RUN TestAuditLogHandler_ServiceErrors
+=== RUN TestAuditLogHandler_ServiceErrors/List_fails_when_database_unavailable
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/services/security_service.go:305 [35;1msql: database is closed
+[0m[33m[0.026ms] [34;1m[rows:0][0m SELECT count(*) FROM `security_audits`
+=== RUN TestAuditLogHandler_ServiceErrors/ListByProvider_fails_when_database_unavailable
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/services/security_service.go:339 [35;1msql: database is closed
+[0m[33m[0.039ms] [34;1m[rows:0][0m SELECT count(*) FROM `security_audits` WHERE event_category = "dns_provider" AND resource_id = 123
+=== RUN TestAuditLogHandler_ServiceErrors/Get_fails_when_database_unavailable
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/services/security_service.go:321 [35;1msql: database is closed
+[0m[33m[0.041ms] [34;1m[rows:0][0m SELECT * FROM `security_audits` WHERE uuid = "some-uuid" ORDER BY `security_audits`.`id` LIMIT 1
+--- PASS: TestAuditLogHandler_ServiceErrors (0.00s)
+ --- PASS: TestAuditLogHandler_ServiceErrors/List_fails_when_database_unavailable (0.00s)
+ --- PASS: TestAuditLogHandler_ServiceErrors/ListByProvider_fails_when_database_unavailable (0.00s)
+ --- PASS: TestAuditLogHandler_ServiceErrors/Get_fails_when_database_unavailable (0.00s)
+=== RUN TestAuditLogHandler_List_PaginationBoundaryEdgeCases
+=== RUN TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Negative_page_defaults_to_1
+=== RUN TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Zero_page_defaults_to_1
+=== RUN TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Negative_limit_defaults_to_50
+=== RUN TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Zero_limit_defaults_to_50
+=== RUN TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Limit_over_100_defaults_to_50
+=== RUN TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Non-numeric_page_ignored
+=== RUN TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Non-numeric_limit_ignored
+--- PASS: TestAuditLogHandler_List_PaginationBoundaryEdgeCases (0.01s)
+ --- PASS: TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Negative_page_defaults_to_1 (0.00s)
+ --- PASS: TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Zero_page_defaults_to_1 (0.00s)
+ --- PASS: TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Negative_limit_defaults_to_50 (0.00s)
+ --- PASS: TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Zero_limit_defaults_to_50 (0.00s)
+ --- PASS: TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Limit_over_100_defaults_to_50 (0.00s)
+ --- PASS: TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Non-numeric_page_ignored (0.00s)
+ --- PASS: TestAuditLogHandler_List_PaginationBoundaryEdgeCases/Non-numeric_limit_ignored (0.00s)
+=== RUN TestAuditLogHandler_ListByProvider_PaginationBoundaryEdgeCases
+=== RUN TestAuditLogHandler_ListByProvider_PaginationBoundaryEdgeCases/Negative_page_defaults_to_1
+=== RUN TestAuditLogHandler_ListByProvider_PaginationBoundaryEdgeCases/Zero_limit_defaults_to_50
+=== RUN TestAuditLogHandler_ListByProvider_PaginationBoundaryEdgeCases/Limit_over_100_defaults_to_50
+--- PASS: TestAuditLogHandler_ListByProvider_PaginationBoundaryEdgeCases (0.01s)
+ --- PASS: TestAuditLogHandler_ListByProvider_PaginationBoundaryEdgeCases/Negative_page_defaults_to_1 (0.00s)
+ --- PASS: TestAuditLogHandler_ListByProvider_PaginationBoundaryEdgeCases/Zero_limit_defaults_to_50 (0.00s)
+ --- PASS: TestAuditLogHandler_ListByProvider_PaginationBoundaryEdgeCases/Limit_over_100_defaults_to_50 (0.00s)
+=== RUN TestAuditLogHandler_List_InvalidDateFormats
+=== RUN TestAuditLogHandler_List_InvalidDateFormats/Invalid_start_date_format
+=== RUN TestAuditLogHandler_List_InvalidDateFormats/Invalid_end_date_format
+=== RUN TestAuditLogHandler_List_InvalidDateFormats/Both_dates_invalid
+--- PASS: TestAuditLogHandler_List_InvalidDateFormats (0.01s)
+ --- PASS: TestAuditLogHandler_List_InvalidDateFormats/Invalid_start_date_format (0.00s)
+ --- PASS: TestAuditLogHandler_List_InvalidDateFormats/Invalid_end_date_format (0.00s)
+ --- PASS: TestAuditLogHandler_List_InvalidDateFormats/Both_dates_invalid (0.00s)
+=== RUN TestAuditLogHandler_Get_InternalError
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/services/security_service.go:321 [35;1msql: database is closed
+[0m[33m[0.033ms] [34;1m[rows:0][0m SELECT * FROM `security_audits` WHERE uuid = "test-uuid" ORDER BY `security_audits`.`id` LIMIT 1
+--- PASS: TestAuditLogHandler_Get_InternalError (0.00s)
+=== RUN TestAuthHandler_Login
+=== PAUSE TestAuthHandler_Login
+=== RUN TestSetSecureCookie_HTTPS_Strict
+--- PASS: TestSetSecureCookie_HTTPS_Strict (0.00s)
+=== RUN TestSetSecureCookie_HTTP_Lax
+=== PAUSE TestSetSecureCookie_HTTP_Lax
+=== RUN TestAuthHandler_Login_Errors
+=== PAUSE TestAuthHandler_Login_Errors
+=== RUN TestAuthHandler_Register
+=== PAUSE TestAuthHandler_Register
+=== RUN TestAuthHandler_Register_Duplicate
+=== PAUSE TestAuthHandler_Register_Duplicate
+=== RUN TestAuthHandler_Logout
+=== PAUSE TestAuthHandler_Logout
+=== RUN TestAuthHandler_Me
+=== PAUSE TestAuthHandler_Me
+=== RUN TestAuthHandler_Me_NotFound
+=== PAUSE TestAuthHandler_Me_NotFound
+=== RUN TestAuthHandler_ChangePassword
+=== PAUSE TestAuthHandler_ChangePassword
+=== RUN TestAuthHandler_ChangePassword_WrongOld
+=== PAUSE TestAuthHandler_ChangePassword_WrongOld
+=== RUN TestAuthHandler_ChangePassword_Errors
+=== PAUSE TestAuthHandler_ChangePassword_Errors
+=== RUN TestNewAuthHandlerWithDB
+=== PAUSE TestNewAuthHandlerWithDB
+=== RUN TestAuthHandler_Verify_NoCookie
+=== PAUSE TestAuthHandler_Verify_NoCookie
+=== RUN TestAuthHandler_Verify_InvalidToken
+=== PAUSE TestAuthHandler_Verify_InvalidToken
+=== RUN TestAuthHandler_Verify_ValidToken
+=== PAUSE TestAuthHandler_Verify_ValidToken
+=== RUN TestAuthHandler_Verify_BearerToken
+=== PAUSE TestAuthHandler_Verify_BearerToken
+=== RUN TestAuthHandler_Verify_DisabledUser
+=== PAUSE TestAuthHandler_Verify_DisabledUser
+=== RUN TestAuthHandler_Verify_ForwardAuthDenied
+=== PAUSE TestAuthHandler_Verify_ForwardAuthDenied
+=== RUN TestAuthHandler_VerifyStatus_NotAuthenticated
+=== PAUSE TestAuthHandler_VerifyStatus_NotAuthenticated
+=== RUN TestAuthHandler_VerifyStatus_InvalidToken
+=== PAUSE TestAuthHandler_VerifyStatus_InvalidToken
+=== RUN TestAuthHandler_VerifyStatus_Authenticated
+=== PAUSE TestAuthHandler_VerifyStatus_Authenticated
+=== RUN TestAuthHandler_VerifyStatus_DisabledUser
+=== PAUSE TestAuthHandler_VerifyStatus_DisabledUser
+=== RUN TestAuthHandler_GetAccessibleHosts_Unauthorized
+=== PAUSE TestAuthHandler_GetAccessibleHosts_Unauthorized
+=== RUN TestAuthHandler_GetAccessibleHosts_AllowAll
+=== PAUSE TestAuthHandler_GetAccessibleHosts_AllowAll
+=== RUN TestAuthHandler_GetAccessibleHosts_DenyAll
+=== PAUSE TestAuthHandler_GetAccessibleHosts_DenyAll
+=== RUN TestAuthHandler_GetAccessibleHosts_PermittedHosts
+=== PAUSE TestAuthHandler_GetAccessibleHosts_PermittedHosts
+=== RUN TestAuthHandler_GetAccessibleHosts_UserNotFound
+=== PAUSE TestAuthHandler_GetAccessibleHosts_UserNotFound
+=== RUN TestAuthHandler_CheckHostAccess_Unauthorized
+=== PAUSE TestAuthHandler_CheckHostAccess_Unauthorized
+=== RUN TestAuthHandler_CheckHostAccess_InvalidHostID
+=== PAUSE TestAuthHandler_CheckHostAccess_InvalidHostID
+=== RUN TestAuthHandler_CheckHostAccess_Allowed
+=== PAUSE TestAuthHandler_CheckHostAccess_Allowed
+=== RUN TestAuthHandler_CheckHostAccess_Denied
+=== PAUSE TestAuthHandler_CheckHostAccess_Denied
+=== RUN TestBackupHandlerSanitizesFilename
+--- PASS: TestBackupHandlerSanitizesFilename (0.00s)
+=== RUN TestBackupLifecycle
+--- PASS: TestBackupLifecycle (0.01s)
+=== RUN TestBackupHandler_Errors
+--- PASS: TestBackupHandler_Errors (0.00s)
+=== RUN TestBackupHandler_List_Success
+--- PASS: TestBackupHandler_List_Success (0.00s)
+=== RUN TestBackupHandler_Create_Success
+--- PASS: TestBackupHandler_Create_Success (0.00s)
+=== RUN TestBackupHandler_Download_Success
+--- PASS: TestBackupHandler_Download_Success (0.00s)
+=== RUN TestBackupHandler_PathTraversal
+--- PASS: TestBackupHandler_PathTraversal (0.00s)
+=== RUN TestBackupHandler_Download_InvalidPath
+--- PASS: TestBackupHandler_Download_InvalidPath (0.00s)
+=== RUN TestBackupHandler_Create_ServiceError
+--- PASS: TestBackupHandler_Create_ServiceError (0.00s)
+=== RUN TestBackupHandler_Delete_InternalError
+--- PASS: TestBackupHandler_Delete_InternalError (0.00s)
+=== RUN TestBackupHandler_Restore_InternalError
+--- PASS: TestBackupHandler_Restore_InternalError (0.00s)
+=== RUN TestCerberusLogsHandler_NewHandler
+=== PAUSE TestCerberusLogsHandler_NewHandler
+=== RUN TestCerberusLogsHandler_SuccessfulConnection
+=== PAUSE TestCerberusLogsHandler_SuccessfulConnection
+=== RUN TestCerberusLogsHandler_ReceiveLogEntries
+=== PAUSE TestCerberusLogsHandler_ReceiveLogEntries
+=== RUN TestCerberusLogsHandler_SourceFilter
+=== PAUSE TestCerberusLogsHandler_SourceFilter
+=== RUN TestCerberusLogsHandler_BlockedOnlyFilter
+=== PAUSE TestCerberusLogsHandler_BlockedOnlyFilter
+=== RUN TestCerberusLogsHandler_IPFilter
+=== PAUSE TestCerberusLogsHandler_IPFilter
+=== RUN TestCerberusLogsHandler_ClientDisconnect
+=== PAUSE TestCerberusLogsHandler_ClientDisconnect
+=== RUN TestCerberusLogsHandler_MultipleClients
+=== PAUSE TestCerberusLogsHandler_MultipleClients
+=== RUN TestCerberusLogsHandler_UpgradeFailure
+=== PAUSE TestCerberusLogsHandler_UpgradeFailure
+=== RUN TestCertificateHandler_List_DBError
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/services/certificate_service.go:198 [35;1mno such table: ssl_certificates
+[0m[33m[3.273ms] [34;1m[rows:0][0m SELECT * FROM `ssl_certificates` WHERE provider LIKE "letsencrypt%"
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/services/certificate_service.go:226 [35;1mno such table: ssl_certificates
+[0m[33m[0.033ms] [34;1m[rows:0][0m SELECT * FROM `ssl_certificates`
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/services/certificate_service.go:226 [35;1mno such table: ssl_certificates
+[0m[33m[0.032ms] [34;1m[rows:0][0m SELECT * FROM `ssl_certificates`
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/services/certificate_service.go:198 [35;1mno such table: ssl_certificates
+[0m[33m[0.044ms] [34;1m[rows:0][0m SELECT * FROM `ssl_certificates` WHERE provider LIKE "letsencrypt%"
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/services/certificate_service.go:226 [35;1mno such table: ssl_certificates
+[0m[33m[0.031ms] [34;1m[rows:0][0m SELECT * FROM `ssl_certificates`
+--- PASS: TestCertificateHandler_List_DBError (0.00s)
+=== RUN TestCertificateHandler_Delete_InvalidID
+--- PASS: TestCertificateHandler_Delete_InvalidID (0.02s)
+=== RUN TestCertificateHandler_Delete_NotFound
+
+2026/01/10 02:17:47 [31;1m/projects/Charon/backend/internal/services/certificate_service.go:410 [35;1mrecord not found
+[0m[33m[0.076ms] [34;1m[rows:0][0m SELECT * FROM `ssl_certificates` WHERE `ssl_certificates`.`id` = 9999 ORDER BY `ssl_certificates`.`id` LIMIT 1
+--- PASS: TestCertificateHandler_Delete_NotFound (0.01s)
+=== RUN TestCertificateHandler_Delete_NoBackupService
+--- PASS: TestCertificateHandler_Delete_NoBackupService (0.21s)
+=== RUN TestCertificateHandler_Delete_CheckUsageDBError
+
+2026/01/10 02:17:48 [31;1m/projects/Charon/backend/internal/services/certificate_service.go:392 [35;1mno such table: proxy_hosts
+[0m[33m[6.492ms] [34;1m[rows:0][0m SELECT count(*) FROM `proxy_hosts` WHERE certificate_id = 1
+
+2026/01/10 02:17:48 [31;1m/projects/Charon/backend/internal/services/certificate_service.go:232 [35;1mno such table: proxy_hosts
+[0m[33m[5.901ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts`
+--- PASS: TestCertificateHandler_Delete_CheckUsageDBError (0.01s)
+=== RUN TestCertificateHandler_List_WithCertificates
+--- PASS: TestCertificateHandler_List_WithCertificates (0.01s)
+=== RUN TestCertificateHandler_Delete_ZeroID
+--- PASS: TestCertificateHandler_Delete_ZeroID (0.02s)
+=== RUN TestCertificateHandler_Delete_RequiresAuth
+--- PASS: TestCertificateHandler_Delete_RequiresAuth (0.01s)
+=== RUN TestCertificateHandler_List_RequiresAuth
+--- PASS: TestCertificateHandler_List_RequiresAuth (0.01s)
+=== RUN TestCertificateHandler_Upload_RequiresAuth
+--- PASS: TestCertificateHandler_Upload_RequiresAuth (0.02s)
+=== RUN TestCertificateHandler_Delete_DiskSpaceCheck
+--- PASS: TestCertificateHandler_Delete_DiskSpaceCheck (0.01s)
+=== RUN TestCertificateHandler_Delete_NotificationRateLimiting
+--- PASS: TestCertificateHandler_Delete_NotificationRateLimiting (0.02s)
+=== RUN TestDeleteCertificate_InUse
+--- PASS: TestDeleteCertificate_InUse (0.02s)
+=== RUN TestDeleteCertificate_CreatesBackup
+
+2026/01/10 02:17:48 [31;1m/projects/Charon/backend/internal/api/handlers/certificate_handler_test.go:134 [35;1mrecord not found
+[0m[33m[0.090ms] [34;1m[rows:0][0m SELECT * FROM `ssl_certificates` WHERE `ssl_certificates`.`id` = 1 ORDER BY `ssl_certificates`.`id` LIMIT 1
+--- PASS: TestDeleteCertificate_CreatesBackup (0.01s)
+=== RUN TestDeleteCertificate_BackupFailure
+--- PASS: TestDeleteCertificate_BackupFailure (0.02s)
+=== RUN TestDeleteCertificate_InUse_NoBackup
+--- PASS: TestDeleteCertificate_InUse_NoBackup (0.01s)
+=== RUN TestCertificateHandler_List
+--- PASS: TestCertificateHandler_List (0.01s)
+=== RUN TestCertificateHandler_Upload_MissingName
+--- PASS: TestCertificateHandler_Upload_MissingName (0.01s)
+=== RUN TestCertificateHandler_Upload_MissingCertFile
+--- PASS: TestCertificateHandler_Upload_MissingCertFile (0.02s)
+=== RUN TestCertificateHandler_Upload_MissingKeyFile
+--- PASS: TestCertificateHandler_Upload_MissingKeyFile (0.02s)
+=== RUN TestCertificateHandler_Upload_Success
+--- PASS: TestCertificateHandler_Upload_Success (0.05s)
+=== RUN TestDeleteCertificate_InvalidID
+--- PASS: TestDeleteCertificate_InvalidID (0.01s)
+=== RUN TestDeleteCertificate_ZeroID
+--- PASS: TestDeleteCertificate_ZeroID (0.02s)
+=== RUN TestDeleteCertificate_LowDiskSpace
+--- PASS: TestDeleteCertificate_LowDiskSpace (0.02s)
+=== RUN TestDeleteCertificate_DiskSpaceCheckError
+
+2026/01/10 02:17:48 [31;1m/projects/Charon/backend/internal/services/certificate_service.go:198 [35;1mdatabase table is locked: ssl_certificates
+[0m[33m[0.359ms] [34;1m[rows:0][0m SELECT * FROM `ssl_certificates` WHERE provider LIKE "letsencrypt%"
+--- PASS: TestDeleteCertificate_DiskSpaceCheckError (0.02s)
+=== RUN TestDeleteCertificate_UsageCheckError
+
+2026/01/10 02:17:48 [31;1m/projects/Charon/backend/internal/services/certificate_service.go:392 [35;1mno such table: proxy_hosts
+[0m[33m[8.346ms] [34;1m[rows:0][0m SELECT count(*) FROM `proxy_hosts` WHERE certificate_id = 1
+
+2026/01/10 02:17:48 [31;1m/projects/Charon/backend/internal/services/certificate_service.go:232 [35;1mno such table: proxy_hosts
+[0m[33m[7.932ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts`
+--- PASS: TestDeleteCertificate_UsageCheckError (0.01s)
+=== RUN TestDeleteCertificate_NotificationRateLimit
+--- PASS: TestDeleteCertificate_NotificationRateLimit (0.12s)
+=== RUN TestSafeIntToUint
+=== RUN TestSafeIntToUint/ValidPositive
+=== RUN TestSafeIntToUint/Zero
+=== RUN TestSafeIntToUint/Negative
+--- PASS: TestSafeIntToUint (0.00s)
+ --- PASS: TestSafeIntToUint/ValidPositive (0.00s)
+ --- PASS: TestSafeIntToUint/Zero (0.00s)
+ --- PASS: TestSafeIntToUint/Negative (0.00s)
+=== RUN TestSafeFloat64ToUint
+=== RUN TestSafeFloat64ToUint/ValidPositive
+=== RUN TestSafeFloat64ToUint/Zero
+=== RUN TestSafeFloat64ToUint/Negative
+=== RUN TestSafeFloat64ToUint/NotInteger
+--- PASS: TestSafeFloat64ToUint (0.00s)
+ --- PASS: TestSafeFloat64ToUint/ValidPositive (0.00s)
+ --- PASS: TestSafeFloat64ToUint/Zero (0.00s)
+ --- PASS: TestSafeFloat64ToUint/Negative (0.00s)
+ --- PASS: TestSafeFloat64ToUint/NotInteger (0.00s)
+=== RUN Test_ttlRemainingSeconds
+=== RUN Test_ttlRemainingSeconds/zero_retrievedAt_returns_nil
+=== RUN Test_ttlRemainingSeconds/zero_ttl_returns_nil
+=== RUN Test_ttlRemainingSeconds/negative_ttl_returns_nil
+=== RUN Test_ttlRemainingSeconds/expired_ttl_returns_zero
+=== RUN Test_ttlRemainingSeconds/valid_remaining_time_returns_positive
+--- PASS: Test_ttlRemainingSeconds (0.00s)
+ --- PASS: Test_ttlRemainingSeconds/zero_retrievedAt_returns_nil (0.00s)
+ --- PASS: Test_ttlRemainingSeconds/zero_ttl_returns_nil (0.00s)
+ --- PASS: Test_ttlRemainingSeconds/negative_ttl_returns_nil (0.00s)
+ --- PASS: Test_ttlRemainingSeconds/expired_ttl_returns_zero (0.00s)
+ --- PASS: Test_ttlRemainingSeconds/valid_remaining_time_returns_positive (0.00s)
+=== RUN Test_mapCrowdsecStatus
+=== RUN Test_mapCrowdsecStatus/deadline_exceeded_returns_gateway_timeout
+=== RUN Test_mapCrowdsecStatus/context_canceled_returns_gateway_timeout
+=== RUN Test_mapCrowdsecStatus/other_error_returns_default_code
+=== RUN Test_mapCrowdsecStatus/other_error_returns_bad_request_default
+--- PASS: Test_mapCrowdsecStatus (0.00s)
+ --- PASS: Test_mapCrowdsecStatus/deadline_exceeded_returns_gateway_timeout (0.00s)
+ --- PASS: Test_mapCrowdsecStatus/context_canceled_returns_gateway_timeout (0.00s)
+ --- PASS: Test_mapCrowdsecStatus/other_error_returns_default_code (0.00s)
+ --- PASS: Test_mapCrowdsecStatus/other_error_returns_bad_request_default (0.00s)
+=== RUN Test_actorFromContext
+=== RUN Test_actorFromContext/with_userID_in_context
+=== RUN Test_actorFromContext/without_userID_in_context
+=== RUN Test_actorFromContext/with_string_userID
+--- PASS: Test_actorFromContext (0.00s)
+ --- PASS: Test_actorFromContext/with_userID_in_context (0.00s)
+ --- PASS: Test_actorFromContext/without_userID_in_context (0.00s)
+ --- PASS: Test_actorFromContext/with_string_userID (0.00s)
+=== RUN Test_hubEndpoints
+=== RUN Test_hubEndpoints/nil_Hub_returns_nil
+--- PASS: Test_hubEndpoints (0.00s)
+ --- PASS: Test_hubEndpoints/nil_Hub_returns_nil (0.00s)
+=== RUN TestRealCommandExecutor_Execute
+=== RUN TestRealCommandExecutor_Execute/successful_command
+=== RUN TestRealCommandExecutor_Execute/failed_command
+=== RUN TestRealCommandExecutor_Execute/context_cancellation
+--- PASS: TestRealCommandExecutor_Execute (0.00s)
+ --- PASS: TestRealCommandExecutor_Execute/successful_command (0.00s)
+ --- PASS: TestRealCommandExecutor_Execute/failed_command (0.00s)
+ --- PASS: TestRealCommandExecutor_Execute/context_cancellation (0.00s)
+=== RUN Test_isCerberusEnabled
+=== RUN Test_isCerberusEnabled/returns_true_when_no_setting_exists_(default)
+=== RUN Test_isCerberusEnabled/enabled_when_setting_is_true
+=== RUN Test_isCerberusEnabled/disabled_when_setting_is_false
+--- PASS: Test_isCerberusEnabled (0.00s)
+ --- PASS: Test_isCerberusEnabled/returns_true_when_no_setting_exists_(default) (0.00s)
+ --- PASS: Test_isCerberusEnabled/enabled_when_setting_is_true (0.00s)
+ --- PASS: Test_isCerberusEnabled/disabled_when_setting_is_false (0.00s)
+=== RUN Test_isConsoleEnrollmentEnabled
+=== RUN Test_isConsoleEnrollmentEnabled/disabled_when_no_setting_exists
+=== RUN Test_isConsoleEnrollmentEnabled/enabled_when_setting_is_true
+=== RUN Test_isConsoleEnrollmentEnabled/disabled_when_setting_is_false
+--- PASS: Test_isConsoleEnrollmentEnabled (0.00s)
+ --- PASS: Test_isConsoleEnrollmentEnabled/disabled_when_no_setting_exists (0.00s)
+ --- PASS: Test_isConsoleEnrollmentEnabled/enabled_when_setting_is_true (0.00s)
+ --- PASS: Test_isConsoleEnrollmentEnabled/disabled_when_setting_is_false (0.00s)
+=== RUN TestCrowdsecHandler_ExportConfig
+--- PASS: TestCrowdsecHandler_ExportConfig (0.01s)
+=== RUN TestCrowdsecHandler_CheckLAPIHealth
+--- PASS: TestCrowdsecHandler_CheckLAPIHealth (0.00s)
+=== RUN TestCrowdsecHandler_ConsoleStatus
+--- PASS: TestCrowdsecHandler_ConsoleStatus (0.01s)
+=== RUN TestCrowdsecHandler_ConsoleEnroll_Disabled
+--- PASS: TestCrowdsecHandler_ConsoleEnroll_Disabled (0.00s)
+=== RUN TestCrowdsecHandler_DeleteConsoleEnrollment
+--- PASS: TestCrowdsecHandler_DeleteConsoleEnrollment (0.00s)
+=== RUN TestCrowdsecHandler_BanIP
+--- PASS: TestCrowdsecHandler_BanIP (0.01s)
+=== RUN TestCrowdsecHandler_UnbanIP
+--- PASS: TestCrowdsecHandler_UnbanIP (0.00s)
+=== RUN TestCrowdsecHandler_UpdateAcquisitionConfig
+--- PASS: TestCrowdsecHandler_UpdateAcquisitionConfig (0.01s)
+=== RUN Test_safeIntToUint
+=== RUN Test_safeIntToUint/positive_int
+=== RUN Test_safeIntToUint/zero
+=== RUN Test_safeIntToUint/negative_int
+=== RUN Test_safeIntToUint/large_positive
+--- PASS: Test_safeIntToUint (0.00s)
+ --- PASS: Test_safeIntToUint/positive_int (0.00s)
+ --- PASS: Test_safeIntToUint/zero (0.00s)
+ --- PASS: Test_safeIntToUint/negative_int (0.00s)
+ --- PASS: Test_safeIntToUint/large_positive (0.00s)
+=== RUN Test_safeFloat64ToUint
+=== RUN Test_safeFloat64ToUint/positive_integer_float
+=== RUN Test_safeFloat64ToUint/zero
+=== RUN Test_safeFloat64ToUint/negative_float
+=== RUN Test_safeFloat64ToUint/fractional_float
+--- PASS: Test_safeFloat64ToUint (0.00s)
+ --- PASS: Test_safeFloat64ToUint/positive_integer_float (0.00s)
+ --- PASS: Test_safeFloat64ToUint/zero (0.00s)
+ --- PASS: Test_safeFloat64ToUint/negative_float (0.00s)
+ --- PASS: Test_safeFloat64ToUint/fractional_float (0.00s)
+=== RUN TestBackupHandlerQuick
+--- PASS: TestBackupHandlerQuick (0.00s)
+=== RUN TestListPresetsShowsCachedStatus
+--- PASS: TestListPresetsShowsCachedStatus (1.13s)
+=== RUN TestCacheKeyPersistence
+--- PASS: TestCacheKeyPersistence (0.00s)
+=== RUN TestUpdateAcquisitionConfigMissingContent
+--- PASS: TestUpdateAcquisitionConfigMissingContent (0.00s)
+=== RUN TestUpdateAcquisitionConfigInvalidJSON
+--- PASS: TestUpdateAcquisitionConfigInvalidJSON (0.00s)
+=== RUN TestGetLAPIDecisionsWithIPFilter
+--- PASS: TestGetLAPIDecisionsWithIPFilter (0.00s)
+=== RUN TestGetLAPIDecisionsWithScopeFilter
+--- PASS: TestGetLAPIDecisionsWithScopeFilter (0.00s)
+=== RUN TestGetLAPIDecisionsWithTypeFilter
+--- PASS: TestGetLAPIDecisionsWithTypeFilter (0.00s)
+=== RUN TestGetLAPIDecisionsWithMultipleFilters
+--- PASS: TestGetLAPIDecisionsWithMultipleFilters (0.00s)
+=== RUN TestUpdateAcquisitionConfigSuccess
+--- PASS: TestUpdateAcquisitionConfigSuccess (0.00s)
+=== RUN TestRegisterBouncerScriptPathError
+--- PASS: TestRegisterBouncerScriptPathError (0.00s)
+=== RUN TestGetLAPIDecisionsEmptyResponse
+--- PASS: TestGetLAPIDecisionsEmptyResponse (0.00s)
+=== RUN TestGetLAPIDecisionsIPQueryParam
+--- PASS: TestGetLAPIDecisionsIPQueryParam (0.00s)
+=== RUN TestGetLAPIDecisionsScopeParam
+--- PASS: TestGetLAPIDecisionsScopeParam (0.00s)
+=== RUN TestGetLAPIDecisionsTypeParam
+--- PASS: TestGetLAPIDecisionsTypeParam (0.00s)
+=== RUN TestGetLAPIDecisionsCombinedParams
+--- PASS: TestGetLAPIDecisionsCombinedParams (0.01s)
+=== RUN TestCheckLAPIHealthRequest
+--- PASS: TestCheckLAPIHealthRequest (0.00s)
+=== RUN TestGetLAPIKeyLookup
+--- PASS: TestGetLAPIKeyLookup (0.00s)
+=== RUN TestGetLAPIKeyEmpty
+--- PASS: TestGetLAPIKeyEmpty (0.00s)
+=== RUN TestGetLAPIKeyAlternative
+--- PASS: TestGetLAPIKeyAlternative (0.00s)
+=== RUN TestStatusRequest
+--- PASS: TestStatusRequest (0.00s)
+=== RUN TestRegisterBouncerFlow
+--- PASS: TestRegisterBouncerFlow (0.00s)
+=== RUN TestRegisterBouncerExecutionFailure
+--- PASS: TestRegisterBouncerExecutionFailure (0.00s)
+=== RUN TestGetAcquisitionConfigNotPresent
+--- PASS: TestGetAcquisitionConfigNotPresent (0.00s)
+=== RUN TestListDecisions_Success
+--- PASS: TestListDecisions_Success (0.00s)
+=== RUN TestListDecisions_EmptyList
+--- PASS: TestListDecisions_EmptyList (0.00s)
+=== RUN TestListDecisions_CscliError
+--- PASS: TestListDecisions_CscliError (0.00s)
+=== RUN TestListDecisions_InvalidJSON
+--- PASS: TestListDecisions_InvalidJSON (0.00s)
+=== RUN TestBanIP_Success
+--- PASS: TestBanIP_Success (0.00s)
+=== RUN TestBanIP_DefaultDuration
+--- PASS: TestBanIP_DefaultDuration (0.00s)
+=== RUN TestBanIP_MissingIP
+--- PASS: TestBanIP_MissingIP (0.00s)
+=== RUN TestBanIP_EmptyIP
+--- PASS: TestBanIP_EmptyIP (0.00s)
+=== RUN TestBanIP_CscliError
+--- PASS: TestBanIP_CscliError (0.00s)
+=== RUN TestUnbanIP_Success
+--- PASS: TestUnbanIP_Success (0.01s)
+=== RUN TestUnbanIP_CscliError
+--- PASS: TestUnbanIP_CscliError (0.00s)
+=== RUN TestListDecisions_MultipleDecisions
+--- PASS: TestListDecisions_MultipleDecisions (0.00s)
+=== RUN TestBanIP_InvalidJSON
+--- PASS: TestBanIP_InvalidJSON (0.00s)
+=== RUN TestDefaultCrowdsecExecutorPidFile
+--- PASS: TestDefaultCrowdsecExecutorPidFile (0.00s)
+=== RUN TestDefaultCrowdsecExecutorStartStatusStop
+--- PASS: TestDefaultCrowdsecExecutorStartStatusStop (0.20s)
+=== RUN TestDefaultCrowdsecExecutor_Status_NoPidFile
+--- PASS: TestDefaultCrowdsecExecutor_Status_NoPidFile (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_Status_InvalidPid
+--- PASS: TestDefaultCrowdsecExecutor_Status_InvalidPid (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_Status_NonExistentProcess
+--- PASS: TestDefaultCrowdsecExecutor_Status_NonExistentProcess (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_Stop_NoPidFile
+--- PASS: TestDefaultCrowdsecExecutor_Stop_NoPidFile (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_Stop_InvalidPid
+--- PASS: TestDefaultCrowdsecExecutor_Stop_InvalidPid (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_Stop_NonExistentProcess
+--- PASS: TestDefaultCrowdsecExecutor_Stop_NonExistentProcess (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_Stop_Idempotent
+--- PASS: TestDefaultCrowdsecExecutor_Stop_Idempotent (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_Start_InvalidBinary
+--- PASS: TestDefaultCrowdsecExecutor_Start_InvalidBinary (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_isCrowdSecProcess_ValidProcess
+--- PASS: TestDefaultCrowdsecExecutor_isCrowdSecProcess_ValidProcess (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_isCrowdSecProcess_DifferentProcess
+--- PASS: TestDefaultCrowdsecExecutor_isCrowdSecProcess_DifferentProcess (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_isCrowdSecProcess_NonExistentProcess
+--- PASS: TestDefaultCrowdsecExecutor_isCrowdSecProcess_NonExistentProcess (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_isCrowdSecProcess_EmptyCmdline
+--- PASS: TestDefaultCrowdsecExecutor_isCrowdSecProcess_EmptyCmdline (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_Status_PIDReuse_DifferentProcess
+--- PASS: TestDefaultCrowdsecExecutor_Status_PIDReuse_DifferentProcess (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_Status_PIDReuse_IsCrowdSec
+--- PASS: TestDefaultCrowdsecExecutor_Status_PIDReuse_IsCrowdSec (0.00s)
+=== RUN TestDefaultCrowdsecExecutor_Stop_SignalError
+--- PASS: TestDefaultCrowdsecExecutor_Stop_SignalError (0.00s)
+=== RUN TestTTLRemainingSeconds
+=== RUN TestTTLRemainingSeconds/zero_retrieved_time
+=== RUN TestTTLRemainingSeconds/zero_ttl
+=== RUN TestTTLRemainingSeconds/expired_ttl
+=== RUN TestTTLRemainingSeconds/valid_ttl
+--- PASS: TestTTLRemainingSeconds (0.00s)
+ --- PASS: TestTTLRemainingSeconds/zero_retrieved_time (0.00s)
+ --- PASS: TestTTLRemainingSeconds/zero_ttl (0.00s)
+ --- PASS: TestTTLRemainingSeconds/expired_ttl (0.00s)
+ --- PASS: TestTTLRemainingSeconds/valid_ttl (0.00s)
+=== RUN TestMapCrowdsecStatus
+=== RUN TestMapCrowdsecStatus/no_error
+=== RUN TestMapCrowdsecStatus/generic_error
+--- PASS: TestMapCrowdsecStatus (0.00s)
+ --- PASS: TestMapCrowdsecStatus/no_error (0.00s)
+ --- PASS: TestMapCrowdsecStatus/generic_error (0.00s)
+=== RUN TestIsConsoleEnrollmentEnabled
+=== RUN TestIsConsoleEnrollmentEnabled/enabled_via_env
+=== RUN TestIsConsoleEnrollmentEnabled/disabled_via_env
+=== RUN TestIsConsoleEnrollmentEnabled/default_when_not_set
+--- PASS: TestIsConsoleEnrollmentEnabled (0.00s)
+ --- PASS: TestIsConsoleEnrollmentEnabled/enabled_via_env (0.00s)
+ --- PASS: TestIsConsoleEnrollmentEnabled/disabled_via_env (0.00s)
+ --- PASS: TestIsConsoleEnrollmentEnabled/default_when_not_set (0.00s)
+=== RUN TestActorFromContext
+=== RUN TestActorFromContext/with_userID
+=== RUN TestActorFromContext/without_userID
+--- PASS: TestActorFromContext (0.00s)
+ --- PASS: TestActorFromContext/with_userID (0.00s)
+ --- PASS: TestActorFromContext/without_userID (0.00s)
+=== RUN TestHubEndpoints
+--- PASS: TestHubEndpoints (0.00s)
+=== RUN TestGetCachedPreset
+--- PASS: TestGetCachedPreset (0.00s)
+=== RUN TestGetCachedPreset_NotFound
+--- PASS: TestGetCachedPreset_NotFound (0.00s)
+=== RUN TestGetLAPIDecisions
+--- PASS: TestGetLAPIDecisions (0.01s)
+=== RUN TestCheckLAPIHealth
+--- PASS: TestCheckLAPIHealth (0.00s)
+=== RUN TestListDecisions
+--- PASS: TestListDecisions (0.00s)
+=== RUN TestBanIP
+--- PASS: TestBanIP (0.00s)
+=== RUN TestUnbanIP
+--- PASS: TestUnbanIP (0.00s)
+=== RUN TestGetAcquisitionConfig
+--- PASS: TestGetAcquisitionConfig (0.00s)
+=== RUN TestUpdateAcquisitionConfig
+--- PASS: TestUpdateAcquisitionConfig (0.00s)
+=== RUN TestGetLAPIKey
+--- PASS: TestGetLAPIKey (0.00s)
+=== RUN TestCrowdsec_Start_Error
+--- PASS: TestCrowdsec_Start_Error (0.00s)
+=== RUN TestCrowdsec_Stop_Error
+--- PASS: TestCrowdsec_Stop_Error (0.00s)
+=== RUN TestCrowdsec_Status_Error
+--- PASS: TestCrowdsec_Status_Error (0.00s)
+=== RUN TestCrowdsec_ReadFile_MissingPath
+--- PASS: TestCrowdsec_ReadFile_MissingPath (0.00s)
+=== RUN TestCrowdsec_ReadFile_PathTraversal
+--- PASS: TestCrowdsec_ReadFile_PathTraversal (0.00s)
+=== RUN TestCrowdsec_ReadFile_NotFound
+--- PASS: TestCrowdsec_ReadFile_NotFound (0.01s)
+=== RUN TestCrowdsec_WriteFile_InvalidPayload
+--- PASS: TestCrowdsec_WriteFile_InvalidPayload (0.00s)
+=== RUN TestCrowdsec_WriteFile_MissingPath
+--- PASS: TestCrowdsec_WriteFile_MissingPath (0.01s)
+=== RUN TestCrowdsec_WriteFile_PathTraversal
+--- PASS: TestCrowdsec_WriteFile_PathTraversal (0.00s)
+=== RUN TestCrowdsec_ExportConfig_NotFound
+--- PASS: TestCrowdsec_ExportConfig_NotFound (0.00s)
+=== RUN TestCrowdsec_ListFiles_EmptyDir
+--- PASS: TestCrowdsec_ListFiles_EmptyDir (0.00s)
+=== RUN TestCrowdsec_ListFiles_NonExistent
+--- PASS: TestCrowdsec_ListFiles_NonExistent (0.00s)
+=== RUN TestCrowdsec_ImportConfig_NoFile
+--- PASS: TestCrowdsec_ImportConfig_NoFile (0.00s)
+=== RUN TestCrowdsec_ReadFile_NestedPath
+--- PASS: TestCrowdsec_ReadFile_NestedPath (0.01s)
+=== RUN TestCrowdsec_WriteFile_Success
+--- PASS: TestCrowdsec_WriteFile_Success (0.00s)
+=== RUN TestCrowdsec_ListPresets_Disabled
+--- PASS: TestCrowdsec_ListPresets_Disabled (0.00s)
+=== RUN TestCrowdsec_ListPresets_Success
+--- PASS: TestCrowdsec_ListPresets_Success (0.92s)
+=== RUN TestCrowdsec_PullPreset_Validation
+--- PASS: TestCrowdsec_PullPreset_Validation (0.01s)
+=== RUN TestCrowdsec_ApplyPreset_Validation
+--- PASS: TestCrowdsec_ApplyPreset_Validation (0.00s)
+=== RUN TestCrowdsecEndpoints
+=== PAUSE TestCrowdsecEndpoints
+=== RUN TestImportConfig
+=== PAUSE TestImportConfig
+=== RUN TestImportCreatesBackup
+=== PAUSE TestImportCreatesBackup
+=== RUN TestExportConfig
+=== PAUSE TestExportConfig
+=== RUN TestListAndReadFile
+=== PAUSE TestListAndReadFile
+=== RUN TestExportConfigStreamsArchive
+=== PAUSE TestExportConfigStreamsArchive
+=== RUN TestWriteFileCreatesBackup
+=== PAUSE TestWriteFileCreatesBackup
+=== RUN TestListPresetsCerberusDisabled
+--- PASS: TestListPresetsCerberusDisabled (0.00s)
+=== RUN TestReadFileInvalidPath
+=== PAUSE TestReadFileInvalidPath
+=== RUN TestWriteFileInvalidPath
+=== PAUSE TestWriteFileInvalidPath
+=== RUN TestWriteFileMissingPath
+=== PAUSE TestWriteFileMissingPath
+=== RUN TestWriteFileInvalidPayload
+=== PAUSE TestWriteFileInvalidPayload
+=== RUN TestImportConfigRequiresFile
+=== PAUSE TestImportConfigRequiresFile
+=== RUN TestImportConfigRejectsEmptyUpload
+=== PAUSE TestImportConfigRejectsEmptyUpload
+=== RUN TestListFilesMissingDir
+=== PAUSE TestListFilesMissingDir
+=== RUN TestListFilesReturnsEntries
+=== PAUSE TestListFilesReturnsEntries
+=== RUN TestIsCerberusEnabledFromDB
+=== PAUSE TestIsCerberusEnabledFromDB
+=== RUN TestIsCerberusEnabledInvalidEnv
+--- PASS: TestIsCerberusEnabledInvalidEnv (0.00s)
+=== RUN TestIsCerberusEnabledLegacyEnv
+--- PASS: TestIsCerberusEnabledLegacyEnv (0.00s)
+=== RUN TestConsoleEnrollDisabled
+--- PASS: TestConsoleEnrollDisabled (0.00s)
+=== RUN TestConsoleEnrollServiceUnavailable
+--- PASS: TestConsoleEnrollServiceUnavailable (0.00s)
+=== RUN TestConsoleEnrollInvalidPayload
+--- PASS: TestConsoleEnrollInvalidPayload (0.01s)
+=== RUN TestConsoleEnrollSuccess
+--- PASS: TestConsoleEnrollSuccess (0.01s)
+=== RUN TestConsoleEnrollMissingAgentName
+--- PASS: TestConsoleEnrollMissingAgentName (0.01s)
+=== RUN TestConsoleStatusDisabled
+--- PASS: TestConsoleStatusDisabled (0.00s)
+=== RUN TestConsoleStatusServiceUnavailable
+--- PASS: TestConsoleStatusServiceUnavailable (0.00s)
+=== RUN TestConsoleStatusSuccess
+--- PASS: TestConsoleStatusSuccess (0.01s)
+=== RUN TestConsoleStatusAfterEnroll
+--- PASS: TestConsoleStatusAfterEnroll (0.01s)
+=== RUN TestIsConsoleEnrollmentEnabledFromDB
+=== PAUSE TestIsConsoleEnrollmentEnabledFromDB
+=== RUN TestIsConsoleEnrollmentDisabledFromDB
+=== PAUSE TestIsConsoleEnrollmentDisabledFromDB
+=== RUN TestIsConsoleEnrollmentEnabledFromEnv
+--- PASS: TestIsConsoleEnrollmentEnabledFromEnv (0.00s)
+=== RUN TestIsConsoleEnrollmentDisabledFromEnv
+--- PASS: TestIsConsoleEnrollmentDisabledFromEnv (0.00s)
+=== RUN TestIsConsoleEnrollmentInvalidEnv
+--- PASS: TestIsConsoleEnrollmentInvalidEnv (0.00s)
+=== RUN TestIsConsoleEnrollmentDefaultDisabled
+--- PASS: TestIsConsoleEnrollmentDefaultDisabled (0.00s)
+=== RUN TestIsConsoleEnrollmentDBTrueVariants
+=== RUN TestIsConsoleEnrollmentDBTrueVariants/true
+=== RUN TestIsConsoleEnrollmentDBTrueVariants/TRUE
+=== RUN TestIsConsoleEnrollmentDBTrueVariants/True
+=== RUN TestIsConsoleEnrollmentDBTrueVariants/1
+=== RUN TestIsConsoleEnrollmentDBTrueVariants/yes
+=== RUN TestIsConsoleEnrollmentDBTrueVariants/YES
+=== RUN TestIsConsoleEnrollmentDBTrueVariants/false
+=== RUN TestIsConsoleEnrollmentDBTrueVariants/FALSE
+=== RUN TestIsConsoleEnrollmentDBTrueVariants/0
+=== RUN TestIsConsoleEnrollmentDBTrueVariants/no
+--- PASS: TestIsConsoleEnrollmentDBTrueVariants (0.04s)
+ --- PASS: TestIsConsoleEnrollmentDBTrueVariants/true (0.00s)
+ --- PASS: TestIsConsoleEnrollmentDBTrueVariants/TRUE (0.01s)
+ --- PASS: TestIsConsoleEnrollmentDBTrueVariants/True (0.01s)
+ --- PASS: TestIsConsoleEnrollmentDBTrueVariants/1 (0.00s)
+ --- PASS: TestIsConsoleEnrollmentDBTrueVariants/yes (0.00s)
+ --- PASS: TestIsConsoleEnrollmentDBTrueVariants/YES (0.00s)
+ --- PASS: TestIsConsoleEnrollmentDBTrueVariants/false (0.00s)
+ --- PASS: TestIsConsoleEnrollmentDBTrueVariants/FALSE (0.00s)
+ --- PASS: TestIsConsoleEnrollmentDBTrueVariants/0 (0.00s)
+ --- PASS: TestIsConsoleEnrollmentDBTrueVariants/no (0.00s)
+=== RUN TestRegisterBouncerScriptNotFound
+=== PAUSE TestRegisterBouncerScriptNotFound
+=== RUN TestRegisterBouncerSuccess
+=== PAUSE TestRegisterBouncerSuccess
+=== RUN TestRegisterBouncerExecutionError
+=== PAUSE TestRegisterBouncerExecutionError
+=== RUN TestGetAcquisitionConfigNotFound
+=== PAUSE TestGetAcquisitionConfigNotFound
+=== RUN TestGetAcquisitionConfigSuccess
+=== PAUSE TestGetAcquisitionConfigSuccess
+=== RUN TestDeleteConsoleEnrollmentDisabled
+--- PASS: TestDeleteConsoleEnrollmentDisabled (0.00s)
+=== RUN TestDeleteConsoleEnrollmentServiceUnavailable
+--- PASS: TestDeleteConsoleEnrollmentServiceUnavailable (0.00s)
+=== RUN TestDeleteConsoleEnrollmentSuccess
+--- PASS: TestDeleteConsoleEnrollmentSuccess (0.00s)
+=== RUN TestDeleteConsoleEnrollmentNoRecordSuccess
+--- PASS: TestDeleteConsoleEnrollmentNoRecordSuccess (0.00s)
+=== RUN TestDeleteConsoleEnrollmentThenReenroll
+--- PASS: TestDeleteConsoleEnrollmentThenReenroll (0.01s)
+=== RUN TestCrowdsecStart_LAPINotReadyTimeout
+=== PAUSE TestCrowdsecStart_LAPINotReadyTimeout
+=== RUN TestCrowdsecHandler_Status_Error
+=== PAUSE TestCrowdsecHandler_Status_Error
+=== RUN TestCrowdsecHandler_Start_ExecutorError
+=== PAUSE TestCrowdsecHandler_Start_ExecutorError
+=== RUN TestCrowdsecHandler_ExportConfig_DirNotFound
+=== PAUSE TestCrowdsecHandler_ExportConfig_DirNotFound
+=== RUN TestCrowdsecHandler_ReadFile_NotFound
+=== PAUSE TestCrowdsecHandler_ReadFile_NotFound
+=== RUN TestCrowdsecHandler_ReadFile_MissingPath
+=== PAUSE TestCrowdsecHandler_ReadFile_MissingPath
+=== RUN TestCrowdsecHandler_ListDecisions_Success
+=== PAUSE TestCrowdsecHandler_ListDecisions_Success
+=== RUN TestCrowdsecHandler_ListDecisions_Empty
+=== PAUSE TestCrowdsecHandler_ListDecisions_Empty
+=== RUN TestCrowdsecHandler_ListDecisions_CscliError
+=== PAUSE TestCrowdsecHandler_ListDecisions_CscliError
+=== RUN TestCrowdsecHandler_ListDecisions_InvalidJSON
+=== PAUSE TestCrowdsecHandler_ListDecisions_InvalidJSON
+=== RUN TestCrowdsecHandler_BanIP_Success
+=== PAUSE TestCrowdsecHandler_BanIP_Success
+=== RUN TestCrowdsecHandler_BanIP_MissingIP
+=== PAUSE TestCrowdsecHandler_BanIP_MissingIP
+=== RUN TestCrowdsecHandler_BanIP_EmptyIP
+=== PAUSE TestCrowdsecHandler_BanIP_EmptyIP
+=== RUN TestCrowdsecHandler_BanIP_DefaultDuration
+=== PAUSE TestCrowdsecHandler_BanIP_DefaultDuration
+=== RUN TestCrowdsecHandler_UnbanIP_Success
+=== PAUSE TestCrowdsecHandler_UnbanIP_Success
+=== RUN TestCrowdsecHandler_UnbanIP_Error
+=== PAUSE TestCrowdsecHandler_UnbanIP_Error
+=== RUN TestCrowdsecHandler_BanIP_ExecutionError
+=== PAUSE TestCrowdsecHandler_BanIP_ExecutionError
+=== RUN TestCrowdsecHandler_CheckLAPIHealth_InvalidURL
+=== PAUSE TestCrowdsecHandler_CheckLAPIHealth_InvalidURL
+=== RUN TestCrowdsecHandler_GetLAPIDecisions_Fallback
+=== PAUSE TestCrowdsecHandler_GetLAPIDecisions_Fallback
+=== RUN TestCrowdsecHandler_PullPreset_CerberusDisabled
+--- PASS: TestCrowdsecHandler_PullPreset_CerberusDisabled (0.00s)
+=== RUN TestCrowdsecHandler_PullPreset_InvalidPayload
+--- PASS: TestCrowdsecHandler_PullPreset_InvalidPayload (0.00s)
+=== RUN TestCrowdsecHandler_PullPreset_EmptySlug
+--- PASS: TestCrowdsecHandler_PullPreset_EmptySlug (0.00s)
+=== RUN TestCrowdsecHandler_PullPreset_HubUnavailable
+--- PASS: TestCrowdsecHandler_PullPreset_HubUnavailable (0.00s)
+=== RUN TestCrowdsecHandler_ApplyPreset_CerberusDisabled
+--- PASS: TestCrowdsecHandler_ApplyPreset_CerberusDisabled (0.00s)
+=== RUN TestCrowdsecHandler_ApplyPreset_InvalidPayload
+--- PASS: TestCrowdsecHandler_ApplyPreset_InvalidPayload (0.01s)
+=== RUN TestCrowdsecHandler_ApplyPreset_EmptySlug
+--- PASS: TestCrowdsecHandler_ApplyPreset_EmptySlug (0.00s)
+=== RUN TestCrowdsecHandler_ApplyPreset_HubUnavailable
+--- PASS: TestCrowdsecHandler_ApplyPreset_HubUnavailable (0.00s)
+=== RUN TestCrowdsecHandler_UpdateAcquisitionConfig_MissingContent
+=== PAUSE TestCrowdsecHandler_UpdateAcquisitionConfig_MissingContent
+=== RUN TestCrowdsecHandler_UpdateAcquisitionConfig_InvalidJSON
+=== PAUSE TestCrowdsecHandler_UpdateAcquisitionConfig_InvalidJSON
+=== RUN TestCrowdsecHandler_ListDecisions_WithConfigYaml
+=== PAUSE TestCrowdsecHandler_ListDecisions_WithConfigYaml
+=== RUN TestCrowdsecHandler_BanIP_WithConfigYaml
+=== PAUSE TestCrowdsecHandler_BanIP_WithConfigYaml
+=== RUN TestCrowdsecHandler_UnbanIP_WithConfigYaml
+=== PAUSE TestCrowdsecHandler_UnbanIP_WithConfigYaml
+=== RUN TestCrowdsecHandler_Status_LAPIReady
+=== PAUSE TestCrowdsecHandler_Status_LAPIReady
+=== RUN TestCrowdsecHandler_Status_LAPINotReady
+=== PAUSE TestCrowdsecHandler_Status_LAPINotReady
+=== RUN TestCrowdsecHandler_ListDecisions_WithCreatedAt
+=== PAUSE TestCrowdsecHandler_ListDecisions_WithCreatedAt
+=== RUN TestCrowdsecHandler_HubEndpoints
+=== PAUSE TestCrowdsecHandler_HubEndpoints
+=== RUN TestCrowdsecHandler_ConsoleEnroll_ProgressConflict
+--- PASS: TestCrowdsecHandler_ConsoleEnroll_ProgressConflict (0.01s)
+=== RUN TestCrowdsecHandler_GetCachedPreset_CerberusDisabled
+--- PASS: TestCrowdsecHandler_GetCachedPreset_CerberusDisabled (0.00s)
+=== RUN TestCrowdsecHandler_GetCachedPreset_HubUnavailable
+--- PASS: TestCrowdsecHandler_GetCachedPreset_HubUnavailable (0.00s)
+=== RUN TestCrowdsecHandler_GetCachedPreset_EmptySlug
+--- PASS: TestCrowdsecHandler_GetCachedPreset_EmptySlug (0.00s)
+=== RUN TestGetLAPIDecisions_FallbackToCscli
+--- PASS: TestGetLAPIDecisions_FallbackToCscli (0.00s)
+=== RUN TestGetLAPIDecisions_EmptyResponse
+--- PASS: TestGetLAPIDecisions_EmptyResponse (0.00s)
+=== RUN TestCheckLAPIHealth_Handler
+--- PASS: TestCheckLAPIHealth_Handler (0.00s)
+=== RUN TestGetLAPIKey_FromEnv
+--- PASS: TestGetLAPIKey_FromEnv (0.00s)
+=== RUN TestGetLAPIKey_Empty
+--- PASS: TestGetLAPIKey_Empty (0.00s)
+=== RUN TestListPresetsIncludesCacheAndIndex
+--- PASS: TestListPresetsIncludesCacheAndIndex (0.01s)
+=== RUN TestPullPresetHandlerSuccess
+--- PASS: TestPullPresetHandlerSuccess (0.01s)
+=== RUN TestApplyPresetHandlerAudits
+--- PASS: TestApplyPresetHandlerAudits (0.02s)
+=== RUN TestPullPresetHandlerHubError
+--- PASS: TestPullPresetHandlerHubError (0.00s)
+=== RUN TestPullPresetHandlerTimeout
+--- PASS: TestPullPresetHandlerTimeout (0.00s)
+=== RUN TestGetCachedPresetNotFound
+--- PASS: TestGetCachedPresetNotFound (0.00s)
+=== RUN TestGetCachedPresetServiceUnavailable
+--- PASS: TestGetCachedPresetServiceUnavailable (0.00s)
+=== RUN TestApplyPresetHandlerBackupFailure
+--- PASS: TestApplyPresetHandlerBackupFailure (0.00s)
+=== RUN TestListPresetsMergesCuratedAndHub
+--- PASS: TestListPresetsMergesCuratedAndHub (0.01s)
+=== RUN TestGetCachedPresetSuccess
+--- PASS: TestGetCachedPresetSuccess (0.00s)
+=== RUN TestGetCachedPresetSlugRequired
+--- PASS: TestGetCachedPresetSlugRequired (0.00s)
+=== RUN TestGetCachedPresetPreviewError
+--- PASS: TestGetCachedPresetPreviewError (0.00s)
+=== RUN TestPullCuratedPresetSkipsHub
+--- PASS: TestPullCuratedPresetSkipsHub (0.00s)
+=== RUN TestApplyCuratedPresetSkipsHub
+--- PASS: TestApplyCuratedPresetSkipsHub (0.00s)
+=== RUN TestPullThenApplyIntegration
+ crowdsec_pull_apply_integration_test.go:67: User pulls preset
+ crowdsec_pull_apply_integration_test.go:83: Pull succeeded, cache_key: test/preset-1768011471
+ crowdsec_pull_apply_integration_test.go:90: Cache verified, slug: test/preset
+ crowdsec_pull_apply_integration_test.go:93: User applies preset
+ crowdsec_pull_apply_integration_test.go:109: Apply succeeded, backup: /tmp/TestPullThenApplyIntegration893046683/002.backup.20260110-021751
+--- PASS: TestPullThenApplyIntegration (0.01s)
+=== RUN TestApplyWithoutPullReturnsProperError
+ crowdsec_pull_apply_integration_test.go:138: User tries to apply preset without pulling first
+ crowdsec_pull_apply_integration_test.go:154: Proper error message returned: Preset cache missing or expired. Pull the preset again, then retry apply.
+--- PASS: TestApplyWithoutPullReturnsProperError (0.01s)
+=== RUN TestApplyRollbackWhenCacheMissingAndRepullFails
+--- PASS: TestApplyRollbackWhenCacheMissingAndRepullFails (0.01s)
+=== RUN TestStartSyncsSettingsTable
+--- PASS: TestStartSyncsSettingsTable (60.13s)
+=== RUN TestStopSyncsSettingsTable
+--- PASS: TestStopSyncsSettingsTable (60.13s)
+=== RUN TestStartAndStopStateConsistency
+--- PASS: TestStartAndStopStateConsistency (180.39s)
+=== RUN TestExistingSettingIsUpdated
+--- PASS: TestExistingSettingIsUpdated (60.13s)
+=== RUN TestStartFailureRevertsSettings
+--- PASS: TestStartFailureRevertsSettings (0.01s)
+=== RUN TestStatusResponseFormat
+--- PASS: TestStatusResponseFormat (0.01s)
+=== RUN TestCrowdsecHandler_Stop_Success
+--- PASS: TestCrowdsecHandler_Stop_Success (0.01s)
+=== RUN TestCrowdsecHandler_Stop_Error
+--- PASS: TestCrowdsecHandler_Stop_Error (0.00s)
+=== RUN TestCrowdsecHandler_Stop_NoSecurityConfig
+--- PASS: TestCrowdsecHandler_Stop_NoSecurityConfig (0.00s)
+=== RUN TestGetLAPIDecisions_WithMockServer
+--- PASS: TestGetLAPIDecisions_WithMockServer (0.01s)
+=== RUN TestGetLAPIDecisions_Unauthorized
+--- PASS: TestGetLAPIDecisions_Unauthorized (0.01s)
+=== RUN TestGetLAPIDecisions_NullResponse
+--- PASS: TestGetLAPIDecisions_NullResponse (0.00s)
+=== RUN TestGetLAPIDecisions_NonJSONContentType
+--- PASS: TestGetLAPIDecisions_NonJSONContentType (0.01s)
+=== RUN TestCheckLAPIHealth_WithMockServer
+--- PASS: TestCheckLAPIHealth_WithMockServer (0.00s)
+=== RUN TestCheckLAPIHealth_FallbackToDecisions
+--- PASS: TestCheckLAPIHealth_FallbackToDecisions (0.01s)
+=== RUN TestGetLAPIKey_AllEnvVars
+=== RUN TestGetLAPIKey_AllEnvVars/CROWDSEC_API_KEY
+=== RUN TestGetLAPIKey_AllEnvVars/CROWDSEC_BOUNCER_API_KEY
+=== RUN TestGetLAPIKey_AllEnvVars/CERBERUS_SECURITY_CROWDSEC_API_KEY
+=== RUN TestGetLAPIKey_AllEnvVars/CHARON_SECURITY_CROWDSEC_API_KEY
+=== RUN TestGetLAPIKey_AllEnvVars/CPM_SECURITY_CROWDSEC_API_KEY
+--- PASS: TestGetLAPIKey_AllEnvVars (0.00s)
+ --- PASS: TestGetLAPIKey_AllEnvVars/CROWDSEC_API_KEY (0.00s)
+ --- PASS: TestGetLAPIKey_AllEnvVars/CROWDSEC_BOUNCER_API_KEY (0.00s)
+ --- PASS: TestGetLAPIKey_AllEnvVars/CERBERUS_SECURITY_CROWDSEC_API_KEY (0.00s)
+ --- PASS: TestGetLAPIKey_AllEnvVars/CHARON_SECURITY_CROWDSEC_API_KEY (0.00s)
+ --- PASS: TestGetLAPIKey_AllEnvVars/CPM_SECURITY_CROWDSEC_API_KEY (0.00s)
+=== RUN TestDBHealthHandler_Check_Healthy
+--- PASS: TestDBHealthHandler_Check_Healthy (0.00s)
+=== RUN TestDBHealthHandler_Check_WithBackupService
+--- PASS: TestDBHealthHandler_Check_WithBackupService (0.00s)
+=== RUN TestDBHealthHandler_Check_WALMode
+--- PASS: TestDBHealthHandler_Check_WALMode (0.01s)
+=== RUN TestDBHealthHandler_ResponseJSONTags
+--- PASS: TestDBHealthHandler_ResponseJSONTags (0.00s)
+=== RUN TestNewDBHealthHandler
+--- PASS: TestNewDBHealthHandler (0.00s)
+=== RUN TestDBHealthHandler_Check_CorruptedDatabase
+
+2026/01/10 02:23:52 [31;1m/projects/Charon/backend/internal/database/database.go:57 [35;1mdatabase disk image is malformed
+[0m[33m[0.125ms] [34;1m[rows:1][0m PRAGMA quick_check
+
+2026/01/10 02:23:52 [31;1m/projects/Charon/backend/internal/database/errors.go:63 [35;1mdatabase disk image is malformed
+[0m[33m[0.092ms] [34;1m[rows:1][0m PRAGMA quick_check
+--- PASS: TestDBHealthHandler_Check_CorruptedDatabase (0.01s)
+=== RUN TestDBHealthHandler_Check_BackupServiceError
+--- PASS: TestDBHealthHandler_Check_BackupServiceError (0.00s)
+=== RUN TestDBHealthHandler_Check_BackupTimeZero
+--- PASS: TestDBHealthHandler_Check_BackupTimeZero (0.00s)
+=== RUN TestNewDNSDetectionHandler
+--- PASS: TestNewDNSDetectionHandler (0.00s)
+=== RUN TestDetect_Success
+=== RUN TestDetect_Success/successful_detection_without_configured_provider
+=== RUN TestDetect_Success/successful_detection_with_configured_provider
+=== RUN TestDetect_Success/detection_not_found
+--- PASS: TestDetect_Success (0.00s)
+ --- PASS: TestDetect_Success/successful_detection_without_configured_provider (0.00s)
+ --- PASS: TestDetect_Success/successful_detection_with_configured_provider (0.00s)
+ --- PASS: TestDetect_Success/detection_not_found (0.00s)
+=== RUN TestDetect_ValidationErrors
+=== RUN TestDetect_ValidationErrors/missing_domain
+=== RUN TestDetect_ValidationErrors/invalid_JSON
+--- PASS: TestDetect_ValidationErrors (0.00s)
+ --- PASS: TestDetect_ValidationErrors/missing_domain (0.00s)
+ --- PASS: TestDetect_ValidationErrors/invalid_JSON (0.00s)
+=== RUN TestDetect_ServiceError
+--- PASS: TestDetect_ServiceError (0.00s)
+=== RUN TestGetPatterns
+--- PASS: TestGetPatterns (0.00s)
+=== RUN TestDetect_WildcardDomain
+--- PASS: TestDetect_WildcardDomain (0.00s)
+=== RUN TestDetect_LowConfidence
+--- PASS: TestDetect_LowConfidence (0.00s)
+=== RUN TestDetect_DNSLookupError
+--- PASS: TestDetect_DNSLookupError (0.00s)
+=== RUN TestDetectRequest_Binding
+=== RUN TestDetectRequest_Binding/valid_request
+=== RUN TestDetectRequest_Binding/missing_domain
+=== RUN TestDetectRequest_Binding/empty_domain
+=== RUN TestDetectRequest_Binding/invalid_JSON
+--- PASS: TestDetectRequest_Binding (0.00s)
+ --- PASS: TestDetectRequest_Binding/valid_request (0.00s)
+ --- PASS: TestDetectRequest_Binding/missing_domain (0.00s)
+ --- PASS: TestDetectRequest_Binding/empty_domain (0.00s)
+ --- PASS: TestDetectRequest_Binding/invalid_JSON (0.00s)
+=== RUN TestDNSProviderHandler_List
+=== RUN TestDNSProviderHandler_List/success
+=== RUN TestDNSProviderHandler_List/service_error
+--- PASS: TestDNSProviderHandler_List (0.00s)
+ --- PASS: TestDNSProviderHandler_List/success (0.00s)
+ --- PASS: TestDNSProviderHandler_List/service_error (0.00s)
+=== RUN TestDNSProviderHandler_Get
+=== RUN TestDNSProviderHandler_Get/success
+=== RUN TestDNSProviderHandler_Get/not_found
+=== RUN TestDNSProviderHandler_Get/invalid_id
+--- PASS: TestDNSProviderHandler_Get (0.00s)
+ --- PASS: TestDNSProviderHandler_Get/success (0.00s)
+ --- PASS: TestDNSProviderHandler_Get/not_found (0.00s)
+ --- PASS: TestDNSProviderHandler_Get/invalid_id (0.00s)
+=== RUN TestDNSProviderHandler_Create
+=== RUN TestDNSProviderHandler_Create/success
+=== RUN TestDNSProviderHandler_Create/validation_error
+=== RUN TestDNSProviderHandler_Create/invalid_provider_type
+=== RUN TestDNSProviderHandler_Create/invalid_credentials
+--- PASS: TestDNSProviderHandler_Create (0.00s)
+ --- PASS: TestDNSProviderHandler_Create/success (0.00s)
+ --- PASS: TestDNSProviderHandler_Create/validation_error (0.00s)
+ --- PASS: TestDNSProviderHandler_Create/invalid_provider_type (0.00s)
+ --- PASS: TestDNSProviderHandler_Create/invalid_credentials (0.00s)
+=== RUN TestDNSProviderHandler_Update
+=== RUN TestDNSProviderHandler_Update/success
+=== RUN TestDNSProviderHandler_Update/not_found
+--- PASS: TestDNSProviderHandler_Update (0.00s)
+ --- PASS: TestDNSProviderHandler_Update/success (0.00s)
+ --- PASS: TestDNSProviderHandler_Update/not_found (0.00s)
+=== RUN TestDNSProviderHandler_Delete
+=== RUN TestDNSProviderHandler_Delete/success
+=== RUN TestDNSProviderHandler_Delete/not_found
+--- PASS: TestDNSProviderHandler_Delete (0.00s)
+ --- PASS: TestDNSProviderHandler_Delete/success (0.00s)
+ --- PASS: TestDNSProviderHandler_Delete/not_found (0.00s)
+=== RUN TestDNSProviderHandler_Test
+=== RUN TestDNSProviderHandler_Test/success
+=== RUN TestDNSProviderHandler_Test/not_found
+--- PASS: TestDNSProviderHandler_Test (0.00s)
+ --- PASS: TestDNSProviderHandler_Test/success (0.00s)
+ --- PASS: TestDNSProviderHandler_Test/not_found (0.00s)
+=== RUN TestDNSProviderHandler_TestCredentials
+=== RUN TestDNSProviderHandler_TestCredentials/success
+=== RUN TestDNSProviderHandler_TestCredentials/validation_error
+--- PASS: TestDNSProviderHandler_TestCredentials (0.00s)
+ --- PASS: TestDNSProviderHandler_TestCredentials/success (0.00s)
+ --- PASS: TestDNSProviderHandler_TestCredentials/validation_error (0.00s)
+=== RUN TestDNSProviderHandler_GetTypes
+--- PASS: TestDNSProviderHandler_GetTypes (0.00s)
+=== RUN TestDNSProviderHandler_CredentialsNeverExposed
+=== RUN TestDNSProviderHandler_CredentialsNeverExposed/Get_endpoint
+=== RUN TestDNSProviderHandler_CredentialsNeverExposed/List_endpoint
+--- PASS: TestDNSProviderHandler_CredentialsNeverExposed (0.00s)
+ --- PASS: TestDNSProviderHandler_CredentialsNeverExposed/Get_endpoint (0.00s)
+ --- PASS: TestDNSProviderHandler_CredentialsNeverExposed/List_endpoint (0.00s)
+=== RUN TestDNSProviderHandler_UpdateInvalidID
+--- PASS: TestDNSProviderHandler_UpdateInvalidID (0.00s)
+=== RUN TestDNSProviderHandler_DeleteInvalidID
+--- PASS: TestDNSProviderHandler_DeleteInvalidID (0.00s)
+=== RUN TestDNSProviderHandler_TestInvalidID
+--- PASS: TestDNSProviderHandler_TestInvalidID (0.00s)
+=== RUN TestDNSProviderHandler_CreateEncryptionFailure
+--- PASS: TestDNSProviderHandler_CreateEncryptionFailure (0.00s)
+=== RUN TestDNSProviderHandler_UpdateEncryptionFailure
+--- PASS: TestDNSProviderHandler_UpdateEncryptionFailure (0.00s)
+=== RUN TestDNSProviderHandler_GetServiceError
+--- PASS: TestDNSProviderHandler_GetServiceError (0.00s)
+=== RUN TestDNSProviderHandler_DeleteServiceError
+--- PASS: TestDNSProviderHandler_DeleteServiceError (0.00s)
+=== RUN TestDNSProviderHandler_TestServiceError
+--- PASS: TestDNSProviderHandler_TestServiceError (0.00s)
+=== RUN TestDNSProviderHandler_TestCredentialsServiceError
+--- PASS: TestDNSProviderHandler_TestCredentialsServiceError (0.00s)
+=== RUN TestDNSProviderHandler_UpdateInvalidCredentials
+--- PASS: TestDNSProviderHandler_UpdateInvalidCredentials (0.00s)
+=== RUN TestDNSProviderHandler_UpdateBindJSONError
+--- PASS: TestDNSProviderHandler_UpdateBindJSONError (0.00s)
+=== RUN TestDNSProviderHandler_UpdateGenericError
+--- PASS: TestDNSProviderHandler_UpdateGenericError (0.00s)
+=== RUN TestDNSProviderHandler_CreateGenericError
+--- PASS: TestDNSProviderHandler_CreateGenericError (0.00s)
+=== RUN TestDockerHandler_ListContainers_InvalidHostRejected
+--- PASS: TestDockerHandler_ListContainers_InvalidHostRejected (0.00s)
+=== RUN TestDockerHandler_ListContainers_DockerUnavailableMappedTo503
+--- PASS: TestDockerHandler_ListContainers_DockerUnavailableMappedTo503 (0.00s)
+=== RUN TestDockerHandler_ListContainers_ServerIDResolvesToTCPHost
+--- PASS: TestDockerHandler_ListContainers_ServerIDResolvesToTCPHost (0.00s)
+=== RUN TestDockerHandler_ListContainers_ServerIDNotFoundReturns404
+--- PASS: TestDockerHandler_ListContainers_ServerIDNotFoundReturns404 (0.00s)
+=== RUN TestDockerHandler_ListContainers_Local
+--- PASS: TestDockerHandler_ListContainers_Local (0.00s)
+=== RUN TestDockerHandler_ListContainers_RemoteServerSuccess
+--- PASS: TestDockerHandler_ListContainers_RemoteServerSuccess (0.00s)
+=== RUN TestDockerHandler_ListContainers_RemoteServerNotFound
+--- PASS: TestDockerHandler_ListContainers_RemoteServerNotFound (0.00s)
+=== RUN TestDockerHandler_ListContainers_InvalidHost
+=== RUN TestDockerHandler_ListContainers_InvalidHost/arbitrary_IP
+=== RUN TestDockerHandler_ListContainers_InvalidHost/tcp_URL
+=== RUN TestDockerHandler_ListContainers_InvalidHost/unix_socket
+=== RUN TestDockerHandler_ListContainers_InvalidHost/http_URL
+--- PASS: TestDockerHandler_ListContainers_InvalidHost (0.00s)
+ --- PASS: TestDockerHandler_ListContainers_InvalidHost/arbitrary_IP (0.00s)
+ --- PASS: TestDockerHandler_ListContainers_InvalidHost/tcp_URL (0.00s)
+ --- PASS: TestDockerHandler_ListContainers_InvalidHost/unix_socket (0.00s)
+ --- PASS: TestDockerHandler_ListContainers_InvalidHost/http_URL (0.00s)
+=== RUN TestDockerHandler_ListContainers_DockerUnavailable
+=== RUN TestDockerHandler_ListContainers_DockerUnavailable/daemon_not_running
+=== RUN TestDockerHandler_ListContainers_DockerUnavailable/socket_permission_denied
+=== RUN TestDockerHandler_ListContainers_DockerUnavailable/socket_not_found
+--- PASS: TestDockerHandler_ListContainers_DockerUnavailable (0.00s)
+ --- PASS: TestDockerHandler_ListContainers_DockerUnavailable/daemon_not_running (0.00s)
+ --- PASS: TestDockerHandler_ListContainers_DockerUnavailable/socket_permission_denied (0.00s)
+ --- PASS: TestDockerHandler_ListContainers_DockerUnavailable/socket_not_found (0.00s)
+=== RUN TestDockerHandler_ListContainers_GenericError
+=== RUN TestDockerHandler_ListContainers_GenericError/API_error
+=== RUN TestDockerHandler_ListContainers_GenericError/context_cancelled
+=== RUN TestDockerHandler_ListContainers_GenericError/unknown_error
+--- PASS: TestDockerHandler_ListContainers_GenericError (0.00s)
+ --- PASS: TestDockerHandler_ListContainers_GenericError/API_error (0.00s)
+ --- PASS: TestDockerHandler_ListContainers_GenericError/context_cancelled (0.00s)
+ --- PASS: TestDockerHandler_ListContainers_GenericError/unknown_error (0.00s)
+=== RUN TestDomainLifecycle
+--- PASS: TestDomainLifecycle (0.01s)
+=== RUN TestDomainErrors
+--- PASS: TestDomainErrors (0.01s)
+=== RUN TestDomainDelete_NotFound
+
+2026/01/10 02:23:52 [31;1m/projects/Charon/backend/internal/api/handlers/domain_handler.go:73 [35;1mrecord not found
+[0m[33m[0.094ms] [34;1m[rows:0][0m SELECT * FROM `domains` WHERE uuid = "nonexistent-uuid" AND `domains`.`deleted_at` IS NULL ORDER BY `domains`.`id` LIMIT 1
+--- PASS: TestDomainDelete_NotFound (0.01s)
+=== RUN TestDomainCreate_Duplicate
+
+2026/01/10 02:23:52 [31;1m/projects/Charon/backend/internal/api/handlers/domain_handler.go:49 [35;1mUNIQUE constraint failed: domains.name
+[0m[33m[0.211ms] [34;1m[rows:0][0m INSERT INTO `domains` (`uuid`,`name`,`created_at`,`updated_at`,`deleted_at`) VALUES ("072e12ad-e893-484b-809c-c89d1c1a1dd5","duplicate.com","2026-01-10 02:23:52.233","2026-01-10 02:23:52.233",NULL) RETURNING `id`
+--- PASS: TestDomainCreate_Duplicate (0.01s)
+=== RUN TestDomainList_Empty
+--- PASS: TestDomainList_Empty (0.01s)
+=== RUN TestDomainCreate_LongName
+--- PASS: TestDomainCreate_LongName (0.01s)
+=== RUN TestEncryptionHandler_GetStatus
+=== RUN TestEncryptionHandler_GetStatus/admin_can_get_status
+=== RUN TestEncryptionHandler_GetStatus/non-admin_cannot_get_status
+=== RUN TestEncryptionHandler_GetStatus/status_shows_next_key_when_configured
+=== RUN TestEncryptionHandler_GetStatus/status_error_when_database_unavailable
+
+2026/01/10 02:23:52 [31;1m/projects/Charon/backend/internal/crypto/rotation_service.go:272 [35;1msql: database is closed
+[0m[33m[0.041ms] [34;1m[rows:0][0m SELECT `key_version` FROM `dns_providers`
+--- PASS: TestEncryptionHandler_GetStatus (0.04s)
+ --- PASS: TestEncryptionHandler_GetStatus/admin_can_get_status (0.00s)
+ --- PASS: TestEncryptionHandler_GetStatus/non-admin_cannot_get_status (0.00s)
+ --- PASS: TestEncryptionHandler_GetStatus/status_shows_next_key_when_configured (0.00s)
+ --- PASS: TestEncryptionHandler_GetStatus/status_error_when_database_unavailable (0.00s)
+=== RUN TestEncryptionHandler_Rotate
+=== RUN TestEncryptionHandler_Rotate/admin_can_trigger_rotation
+=== RUN TestEncryptionHandler_Rotate/non-admin_cannot_trigger_rotation
+=== RUN TestEncryptionHandler_Rotate/rotation_fails_without_next_key
+--- PASS: TestEncryptionHandler_Rotate (0.06s)
+ --- PASS: TestEncryptionHandler_Rotate/admin_can_trigger_rotation (0.02s)
+ --- PASS: TestEncryptionHandler_Rotate/non-admin_cannot_trigger_rotation (0.00s)
+ --- PASS: TestEncryptionHandler_Rotate/rotation_fails_without_next_key (0.00s)
+=== RUN TestEncryptionHandler_GetHistory
+=== RUN TestEncryptionHandler_GetHistory/admin_can_get_history
+=== RUN TestEncryptionHandler_GetHistory/non-admin_cannot_get_history
+=== RUN TestEncryptionHandler_GetHistory/supports_pagination
+=== RUN TestEncryptionHandler_GetHistory/history_error_when_service_fails
+
+2026/01/10 02:23:52 [31;1m/projects/Charon/backend/internal/services/security_service.go:305 [35;1msql: database is closed
+[0m[33m[0.049ms] [34;1m[rows:0][0m SELECT count(*) FROM `security_audits` WHERE event_category = "encryption"
+--- PASS: TestEncryptionHandler_GetHistory (0.07s)
+ --- PASS: TestEncryptionHandler_GetHistory/admin_can_get_history (0.00s)
+ --- PASS: TestEncryptionHandler_GetHistory/non-admin_cannot_get_history (0.00s)
+ --- PASS: TestEncryptionHandler_GetHistory/supports_pagination (0.00s)
+ --- PASS: TestEncryptionHandler_GetHistory/history_error_when_service_fails (0.03s)
+=== RUN TestEncryptionHandler_Validate
+=== RUN TestEncryptionHandler_Validate/admin_can_validate_keys
+=== RUN TestEncryptionHandler_Validate/non-admin_cannot_validate_keys
+=== RUN TestEncryptionHandler_Validate/validation_fails_with_invalid_key_configuration
+--- PASS: TestEncryptionHandler_Validate (0.05s)
+ --- PASS: TestEncryptionHandler_Validate/admin_can_validate_keys (0.01s)
+ --- PASS: TestEncryptionHandler_Validate/non-admin_cannot_validate_keys (0.00s)
+ --- PASS: TestEncryptionHandler_Validate/validation_fails_with_invalid_key_configuration (0.00s)
+=== RUN TestEncryptionHandler_IntegrationFlow
+=== RUN TestEncryptionHandler_IntegrationFlow/complete_rotation_workflow
+--- PASS: TestEncryptionHandler_IntegrationFlow (0.10s)
+ --- PASS: TestEncryptionHandler_IntegrationFlow/complete_rotation_workflow (0.06s)
+=== RUN TestEncryptionHandler_HelperFunctions
+=== RUN TestEncryptionHandler_HelperFunctions/isAdmin_with_invalid_role_type
+=== RUN TestEncryptionHandler_HelperFunctions/getActorFromGinContext_with_string_user_id
+=== RUN TestEncryptionHandler_HelperFunctions/getActorFromGinContext_with_uint_user_id
+=== RUN TestEncryptionHandler_HelperFunctions/getActorFromGinContext_without_user_id_returns_system
+--- PASS: TestEncryptionHandler_HelperFunctions (0.00s)
+ --- PASS: TestEncryptionHandler_HelperFunctions/isAdmin_with_invalid_role_type (0.00s)
+ --- PASS: TestEncryptionHandler_HelperFunctions/getActorFromGinContext_with_string_user_id (0.00s)
+ --- PASS: TestEncryptionHandler_HelperFunctions/getActorFromGinContext_with_uint_user_id (0.00s)
+ --- PASS: TestEncryptionHandler_HelperFunctions/getActorFromGinContext_without_user_id_returns_system (0.00s)
+=== RUN TestEncryptionHandler_RefreshKey_RotatesCredentials
+--- PASS: TestEncryptionHandler_RefreshKey_RotatesCredentials (0.06s)
+=== RUN TestEncryptionHandler_RefreshKey_FailsWithoutProvider
+--- PASS: TestEncryptionHandler_RefreshKey_FailsWithoutProvider (0.03s)
+=== RUN TestEncryptionHandler_RefreshKey_InvalidOldKey
+Failed to rotate provider 1 (Test Provider): failed to decrypt credentials: failed to decrypt with version 1 or any fallback version
+--- PASS: TestEncryptionHandler_RefreshKey_InvalidOldKey (0.06s)
+=== RUN TestEncryptionHandler_GetActorFromGinContext_InvalidType
+--- PASS: TestEncryptionHandler_GetActorFromGinContext_InvalidType (0.00s)
+=== RUN TestEncryptionHandler_RotateWithPartialFailures
+Failed to rotate provider 2 (Invalid Provider): failed to decrypt credentials: failed to decrypt with version 1 or any fallback version
+--- PASS: TestEncryptionHandler_RotateWithPartialFailures (0.05s)
+=== RUN TestEncryptionHandler_isAdmin_NoRoleSet
+--- PASS: TestEncryptionHandler_isAdmin_NoRoleSet (0.00s)
+=== RUN TestEncryptionHandler_isAdmin_NonAdminRole
+--- PASS: TestEncryptionHandler_isAdmin_NonAdminRole (0.00s)
+=== RUN TestFeatureFlagsHandler_GetFlags_DBPrecedence
+--- PASS: TestFeatureFlagsHandler_GetFlags_DBPrecedence (0.00s)
+=== RUN TestFeatureFlagsHandler_GetFlags_EnvFallback
+--- PASS: TestFeatureFlagsHandler_GetFlags_EnvFallback (0.00s)
+=== RUN TestFeatureFlagsHandler_GetFlags_EnvShortForm
+--- PASS: TestFeatureFlagsHandler_GetFlags_EnvShortForm (0.00s)
+=== RUN TestFeatureFlagsHandler_GetFlags_EnvNumeric
+--- PASS: TestFeatureFlagsHandler_GetFlags_EnvNumeric (0.00s)
+=== RUN TestFeatureFlagsHandler_GetFlags_DefaultTrue
+--- PASS: TestFeatureFlagsHandler_GetFlags_DefaultTrue (0.00s)
+=== RUN TestFeatureFlagsHandler_GetFlags_AllDefaultFlagsPresent
+--- PASS: TestFeatureFlagsHandler_GetFlags_AllDefaultFlagsPresent (0.00s)
+=== RUN TestFeatureFlagsHandler_UpdateFlags_Success
+--- PASS: TestFeatureFlagsHandler_UpdateFlags_Success (0.00s)
+=== RUN TestFeatureFlagsHandler_UpdateFlags_Upsert
+--- PASS: TestFeatureFlagsHandler_UpdateFlags_Upsert (0.00s)
+=== RUN TestFeatureFlagsHandler_UpdateFlags_InvalidJSON
+--- PASS: TestFeatureFlagsHandler_UpdateFlags_InvalidJSON (0.00s)
+=== RUN TestFeatureFlagsHandler_UpdateFlags_OnlyAllowedKeys
+--- PASS: TestFeatureFlagsHandler_UpdateFlags_OnlyAllowedKeys (0.00s)
+=== RUN TestFeatureFlagsHandler_UpdateFlags_EmptyPayload
+--- PASS: TestFeatureFlagsHandler_UpdateFlags_EmptyPayload (0.00s)
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants/lowercase_true
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants/uppercase_TRUE
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants/mixed_case_True
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants/numeric_1
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants/yes
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants/YES_uppercase
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants/lowercase_false
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants/numeric_0
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants/no
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants/empty_string
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants/random_string
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants/whitespace_padded_true
+=== RUN TestFeatureFlagsHandler_GetFlags_DBValueVariants/whitespace_padded_false
+--- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants (0.04s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants/lowercase_true (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants/uppercase_TRUE (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants/mixed_case_True (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants/numeric_1 (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants/yes (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants/YES_uppercase (0.01s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants/lowercase_false (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants/numeric_0 (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants/no (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants/empty_string (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants/random_string (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants/whitespace_padded_true (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_DBValueVariants/whitespace_padded_false (0.00s)
+=== RUN TestFeatureFlagsHandler_GetFlags_EnvValueVariants
+=== RUN TestFeatureFlagsHandler_GetFlags_EnvValueVariants/true_string
+=== RUN TestFeatureFlagsHandler_GetFlags_EnvValueVariants/TRUE_uppercase
+=== RUN TestFeatureFlagsHandler_GetFlags_EnvValueVariants/1_numeric
+=== RUN TestFeatureFlagsHandler_GetFlags_EnvValueVariants/false_string
+=== RUN TestFeatureFlagsHandler_GetFlags_EnvValueVariants/FALSE_uppercase
+=== RUN TestFeatureFlagsHandler_GetFlags_EnvValueVariants/0_numeric
+=== RUN TestFeatureFlagsHandler_GetFlags_EnvValueVariants/invalid_value_defaults_to_numeric_check
+--- PASS: TestFeatureFlagsHandler_GetFlags_EnvValueVariants (0.03s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_EnvValueVariants/true_string (0.01s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_EnvValueVariants/TRUE_uppercase (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_EnvValueVariants/1_numeric (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_EnvValueVariants/false_string (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_EnvValueVariants/FALSE_uppercase (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_EnvValueVariants/0_numeric (0.00s)
+ --- PASS: TestFeatureFlagsHandler_GetFlags_EnvValueVariants/invalid_value_defaults_to_numeric_check (0.00s)
+=== RUN TestFeatureFlagsHandler_UpdateFlags_BoolValues
+=== RUN TestFeatureFlagsHandler_UpdateFlags_BoolValues/true
+=== RUN TestFeatureFlagsHandler_UpdateFlags_BoolValues/false
+--- PASS: TestFeatureFlagsHandler_UpdateFlags_BoolValues (0.00s)
+ --- PASS: TestFeatureFlagsHandler_UpdateFlags_BoolValues/true (0.00s)
+ --- PASS: TestFeatureFlagsHandler_UpdateFlags_BoolValues/false (0.00s)
+=== RUN TestFeatureFlagsHandler_NewFeatureFlagsHandler
+--- PASS: TestFeatureFlagsHandler_NewFeatureFlagsHandler (0.00s)
+=== RUN TestFeatureFlags_GetAndUpdate
+--- PASS: TestFeatureFlags_GetAndUpdate (0.00s)
+=== RUN TestFeatureFlags_EnvFallback
+--- PASS: TestFeatureFlags_EnvFallback (0.00s)
+=== RUN TestHealthHandler
+--- PASS: TestHealthHandler (0.00s)
+=== RUN TestGetLocalIP
+ health_handler_test.go:36: getLocalIP returned: "217.15.170.144"
+--- PASS: TestGetLocalIP (0.00s)
+=== RUN TestIsSafePathUnderBase
+--- PASS: TestIsSafePathUnderBase (0.00s)
+=== RUN TestImportUploadSanitizesFilename
+--- PASS: TestImportUploadSanitizesFilename (0.00s)
+=== RUN TestLogsHandler_Read_FilterBySearch
+--- PASS: TestLogsHandler_Read_FilterBySearch (0.00s)
+=== RUN TestLogsHandler_Read_FilterByHost
+--- PASS: TestLogsHandler_Read_FilterByHost (0.00s)
+=== RUN TestLogsHandler_Read_FilterByLevel
+--- PASS: TestLogsHandler_Read_FilterByLevel (0.00s)
+=== RUN TestLogsHandler_Read_FilterByStatus
+--- PASS: TestLogsHandler_Read_FilterByStatus (0.00s)
+=== RUN TestLogsHandler_Read_SortAsc
+--- PASS: TestLogsHandler_Read_SortAsc (0.00s)
+=== RUN TestLogsHandler_List_DirectoryIsFile
+--- PASS: TestLogsHandler_List_DirectoryIsFile (0.00s)
+=== RUN TestLogsHandler_Download_TempFileError
+--- PASS: TestLogsHandler_Download_TempFileError (0.00s)
+=== RUN TestLogsLifecycle
+--- PASS: TestLogsLifecycle (0.00s)
+=== RUN TestLogsHandler_PathTraversal
+--- PASS: TestLogsHandler_PathTraversal (0.00s)
+=== RUN TestLogsWebSocketHandler_SuccessfulConnection
+--- PASS: TestLogsWebSocketHandler_SuccessfulConnection (0.00s)
+=== RUN TestLogsWebSocketHandler_ReceiveLogEntries
+--- PASS: TestLogsWebSocketHandler_ReceiveLogEntries (0.00s)
+=== RUN TestLogsWebSocketHandler_LevelFilter
+--- PASS: TestLogsWebSocketHandler_LevelFilter (0.15s)
+=== RUN TestLogsWebSocketHandler_SourceFilter
+--- PASS: TestLogsWebSocketHandler_SourceFilter (0.00s)
+=== RUN TestLogsWebSocketHandler_CombinedFilters
+--- PASS: TestLogsWebSocketHandler_CombinedFilters (0.00s)
+=== RUN TestLogsWebSocketHandler_CaseInsensitiveFilters
+--- PASS: TestLogsWebSocketHandler_CaseInsensitiveFilters (0.00s)
+=== RUN TestLogsWebSocketHandler_UpgradeFailure
+--- PASS: TestLogsWebSocketHandler_UpgradeFailure (0.00s)
+=== RUN TestLogsWebSocketHandler_ClientDisconnect
+--- PASS: TestLogsWebSocketHandler_ClientDisconnect (0.02s)
+=== RUN TestLogsWebSocketHandler_ChannelClosed
+--- PASS: TestLogsWebSocketHandler_ChannelClosed (0.00s)
+=== RUN TestLogsWebSocketHandler_MultipleConnections
+--- PASS: TestLogsWebSocketHandler_MultipleConnections (0.01s)
+=== RUN TestLogsWebSocketHandler_HighVolumeLogging
+--- PASS: TestLogsWebSocketHandler_HighVolumeLogging (0.04s)
+=== RUN TestLogsWebSocketHandler_EmptyLogFields
+--- PASS: TestLogsWebSocketHandler_EmptyLogFields (0.02s)
+=== RUN TestLogsWebSocketHandler_SubscriberIDUniqueness
+--- PASS: TestLogsWebSocketHandler_SubscriberIDUniqueness (0.02s)
+=== RUN TestLogsWebSocketHandler_WithRealLogger
+--- PASS: TestLogsWebSocketHandler_WithRealLogger (0.00s)
+=== RUN TestLogsWebSocketHandler_ConnectionLifecycle
+--- PASS: TestLogsWebSocketHandler_ConnectionLifecycle (0.02s)
+=== RUN TestDomainHandler_List_Error
+--- PASS: TestDomainHandler_List_Error (0.00s)
+=== RUN TestDomainHandler_Create_InvalidJSON
+--- PASS: TestDomainHandler_Create_InvalidJSON (0.00s)
+=== RUN TestDomainHandler_Create_DBError
+--- PASS: TestDomainHandler_Create_DBError (0.00s)
+=== RUN TestDomainHandler_Delete_Error
+--- PASS: TestDomainHandler_Delete_Error (0.00s)
+=== RUN TestRemoteServerHandler_List_Error
+--- PASS: TestRemoteServerHandler_List_Error (0.00s)
+=== RUN TestRemoteServerHandler_List_EnabledOnly
+--- PASS: TestRemoteServerHandler_List_EnabledOnly (0.00s)
+=== RUN TestRemoteServerHandler_Update_NotFound
+--- PASS: TestRemoteServerHandler_Update_NotFound (0.00s)
+=== RUN TestRemoteServerHandler_Update_InvalidJSON
+--- PASS: TestRemoteServerHandler_Update_InvalidJSON (0.00s)
+=== RUN TestRemoteServerHandler_TestConnection_NotFound
+--- PASS: TestRemoteServerHandler_TestConnection_NotFound (0.00s)
+=== RUN TestRemoteServerHandler_TestConnectionCustom_InvalidJSON
+--- PASS: TestRemoteServerHandler_TestConnectionCustom_InvalidJSON (0.00s)
+=== RUN TestRemoteServerHandler_TestConnectionCustom_Unreachable
+--- PASS: TestRemoteServerHandler_TestConnectionCustom_Unreachable (5.00s)
+=== RUN TestUptimeHandler_List_Error
+--- PASS: TestUptimeHandler_List_Error (0.02s)
+=== RUN TestUptimeHandler_GetHistory_Error
+--- PASS: TestUptimeHandler_GetHistory_Error (0.02s)
+=== RUN TestUptimeHandler_Update_InvalidJSON
+--- PASS: TestUptimeHandler_Update_InvalidJSON (0.02s)
+=== RUN TestUptimeHandler_Sync_Error
+--- PASS: TestUptimeHandler_Sync_Error (0.02s)
+=== RUN TestUptimeHandler_Delete_Error
+--- PASS: TestUptimeHandler_Delete_Error (0.02s)
+=== RUN TestUptimeHandler_CheckMonitor_NotFound
+--- PASS: TestUptimeHandler_CheckMonitor_NotFound (0.02s)
+=== RUN TestNotificationHandler_List_Error
+--- PASS: TestNotificationHandler_List_Error (0.01s)
+=== RUN TestNotificationHandler_List_UnreadOnly
+--- PASS: TestNotificationHandler_List_UnreadOnly (0.01s)
+=== RUN TestNotificationHandler_MarkAsRead_Error
+--- PASS: TestNotificationHandler_MarkAsRead_Error (0.01s)
+=== RUN TestNotificationHandler_MarkAllAsRead_Error
+--- PASS: TestNotificationHandler_MarkAllAsRead_Error (0.01s)
+=== RUN TestNotificationProviderHandler_List_Error
+--- PASS: TestNotificationProviderHandler_List_Error (0.01s)
+=== RUN TestNotificationProviderHandler_Create_InvalidJSON
+--- PASS: TestNotificationProviderHandler_Create_InvalidJSON (0.01s)
+=== RUN TestNotificationProviderHandler_Create_DBError
+--- PASS: TestNotificationProviderHandler_Create_DBError (0.01s)
+=== RUN TestNotificationProviderHandler_Create_InvalidTemplate
+--- PASS: TestNotificationProviderHandler_Create_InvalidTemplate (0.01s)
+=== RUN TestNotificationProviderHandler_Update_InvalidJSON
+--- PASS: TestNotificationProviderHandler_Update_InvalidJSON (0.01s)
+=== RUN TestNotificationProviderHandler_Update_InvalidTemplate
+--- PASS: TestNotificationProviderHandler_Update_InvalidTemplate (0.01s)
+=== RUN TestNotificationProviderHandler_Update_DBError
+--- PASS: TestNotificationProviderHandler_Update_DBError (0.00s)
+=== RUN TestNotificationProviderHandler_Delete_Error
+--- PASS: TestNotificationProviderHandler_Delete_Error (0.01s)
+=== RUN TestNotificationProviderHandler_Test_InvalidJSON
+--- PASS: TestNotificationProviderHandler_Test_InvalidJSON (0.00s)
+=== RUN TestNotificationProviderHandler_Templates
+--- PASS: TestNotificationProviderHandler_Templates (0.00s)
+=== RUN TestNotificationProviderHandler_Preview_InvalidJSON
+--- PASS: TestNotificationProviderHandler_Preview_InvalidJSON (0.00s)
+=== RUN TestNotificationProviderHandler_Preview_WithData
+--- PASS: TestNotificationProviderHandler_Preview_WithData (0.01s)
+=== RUN TestNotificationProviderHandler_Preview_InvalidTemplate
+--- PASS: TestNotificationProviderHandler_Preview_InvalidTemplate (0.01s)
+=== RUN TestNotificationTemplateHandler_List_Error
+--- PASS: TestNotificationTemplateHandler_List_Error (0.01s)
+=== RUN TestNotificationTemplateHandler_Create_BadJSON
+--- PASS: TestNotificationTemplateHandler_Create_BadJSON (0.00s)
+=== RUN TestNotificationTemplateHandler_Create_DBError
+--- PASS: TestNotificationTemplateHandler_Create_DBError (0.01s)
+=== RUN TestNotificationTemplateHandler_Update_BadJSON
+--- PASS: TestNotificationTemplateHandler_Update_BadJSON (0.01s)
+=== RUN TestNotificationTemplateHandler_Update_DBError
+--- PASS: TestNotificationTemplateHandler_Update_DBError (0.01s)
+=== RUN TestNotificationTemplateHandler_Delete_Error
+--- PASS: TestNotificationTemplateHandler_Delete_Error (0.01s)
+=== RUN TestNotificationTemplateHandler_Preview_BadJSON
+--- PASS: TestNotificationTemplateHandler_Preview_BadJSON (0.01s)
+=== RUN TestNotificationTemplateHandler_Preview_TemplateNotFound
+--- PASS: TestNotificationTemplateHandler_Preview_TemplateNotFound (0.01s)
+=== RUN TestNotificationTemplateHandler_Preview_WithStoredTemplate
+--- PASS: TestNotificationTemplateHandler_Preview_WithStoredTemplate (0.01s)
+=== RUN TestNotificationTemplateHandler_Preview_InvalidTemplate
+--- PASS: TestNotificationTemplateHandler_Preview_InvalidTemplate (0.01s)
+=== RUN TestNotificationTemplateHandler_CRUDAndPreview
+--- PASS: TestNotificationTemplateHandler_CRUDAndPreview (0.01s)
+=== RUN TestNotificationTemplateHandler_Create_InvalidJSON
+--- PASS: TestNotificationTemplateHandler_Create_InvalidJSON (0.00s)
+=== RUN TestNotificationTemplateHandler_Update_InvalidJSON
+--- PASS: TestNotificationTemplateHandler_Update_InvalidJSON (0.00s)
+=== RUN TestNotificationTemplateHandler_Preview_InvalidJSON
+--- PASS: TestNotificationTemplateHandler_Preview_InvalidJSON (0.00s)
+=== RUN TestPerf_GetStatus_AssertThreshold
+ perf_assert_test.go:107: GetStatus avg=0.386ms p95=0.520ms max=2.700ms
+--- PASS: TestPerf_GetStatus_AssertThreshold (0.20s)
+=== RUN TestPerf_GetStatus_Parallel_AssertThreshold
+ perf_assert_test.go:150: GetStatus Parallel avg=0.584ms p95=1.505ms max=4.662ms
+--- PASS: TestPerf_GetStatus_Parallel_AssertThreshold (0.14s)
+=== RUN TestPerf_ListDecisions_AssertThreshold
+ perf_assert_test.go:179: ListDecisions avg=2.203ms p95=2.787ms max=6.314ms
+--- PASS: TestPerf_ListDecisions_AssertThreshold (0.68s)
+=== RUN TestPluginHandler_NewPluginHandler
+--- PASS: TestPluginHandler_NewPluginHandler (0.00s)
+=== RUN TestPluginHandler_ListPlugins
+--- PASS: TestPluginHandler_ListPlugins (0.06s)
+=== RUN TestPluginHandler_GetPlugin_InvalidID
+--- PASS: TestPluginHandler_GetPlugin_InvalidID (0.00s)
+=== RUN TestPluginHandler_GetPlugin_NotFound
+--- PASS: TestPluginHandler_GetPlugin_NotFound (0.00s)
+=== RUN TestPluginHandler_GetPlugin_Success
+--- PASS: TestPluginHandler_GetPlugin_Success (0.00s)
+=== RUN TestPluginHandler_EnablePlugin_InvalidID
+--- PASS: TestPluginHandler_EnablePlugin_InvalidID (0.00s)
+=== RUN TestPluginHandler_EnablePlugin_NotFound
+--- PASS: TestPluginHandler_EnablePlugin_NotFound (0.00s)
+=== RUN TestPluginHandler_EnablePlugin_AlreadyEnabled
+--- PASS: TestPluginHandler_EnablePlugin_AlreadyEnabled (0.00s)
+=== RUN TestPluginHandler_EnablePlugin_Success
+--- PASS: TestPluginHandler_EnablePlugin_Success (0.00s)
+=== RUN TestPluginHandler_DisablePlugin_InvalidID
+--- PASS: TestPluginHandler_DisablePlugin_InvalidID (0.00s)
+=== RUN TestPluginHandler_DisablePlugin_NotFound
+--- PASS: TestPluginHandler_DisablePlugin_NotFound (0.00s)
+=== RUN TestPluginHandler_DisablePlugin_AlreadyDisabled
+--- PASS: TestPluginHandler_DisablePlugin_AlreadyDisabled (0.00s)
+=== RUN TestPluginHandler_DisablePlugin_InUse
+--- PASS: TestPluginHandler_DisablePlugin_InUse (0.00s)
+=== RUN TestPluginHandler_DisablePlugin_Success
+--- PASS: TestPluginHandler_DisablePlugin_Success (0.00s)
+=== RUN TestPluginHandler_ReloadPlugins_Success
+--- PASS: TestPluginHandler_ReloadPlugins_Success (0.00s)
+=== RUN TestPluginHandler_ListPlugins_WithBuiltInProviders
+--- PASS: TestPluginHandler_ListPlugins_WithBuiltInProviders (0.00s)
+=== RUN TestPluginHandler_ListPlugins_ExternalLoadedPlugin
+--- PASS: TestPluginHandler_ListPlugins_ExternalLoadedPlugin (0.01s)
+=== RUN TestPluginHandler_GetPlugin_WithProvider
+--- PASS: TestPluginHandler_GetPlugin_WithProvider (0.00s)
+=== RUN TestPluginHandler_EnablePlugin_WithLoadError
+--- PASS: TestPluginHandler_EnablePlugin_WithLoadError (0.00s)
+=== RUN TestPluginHandler_DisablePlugin_WithUnloadError
+--- PASS: TestPluginHandler_DisablePlugin_WithUnloadError (0.01s)
+=== RUN TestPluginHandler_DisablePlugin_MultipleProviders
+--- PASS: TestPluginHandler_DisablePlugin_MultipleProviders (0.00s)
+=== RUN TestPluginHandler_ReloadPlugins_WithErrors
+--- PASS: TestPluginHandler_ReloadPlugins_WithErrors (0.00s)
+=== RUN TestPluginHandler_ListPlugins_FailedPluginWithLoadedAt
+--- PASS: TestPluginHandler_ListPlugins_FailedPluginWithLoadedAt (0.00s)
+=== RUN TestPluginHandler_GetPlugin_WithLoadedAt
+--- PASS: TestPluginHandler_GetPlugin_WithLoadedAt (0.01s)
+=== RUN TestPluginHandler_Count
+ plugin_handler_test.go:851: Total plugin handler tests: Aim for 15-20 tests
+--- PASS: TestPluginHandler_Count (0.00s)
+=== RUN TestPluginHandler_EnablePlugin_DBUpdateError
+--- PASS: TestPluginHandler_EnablePlugin_DBUpdateError (0.00s)
+=== RUN TestPluginHandler_DisablePlugin_DBUpdateError
+--- PASS: TestPluginHandler_DisablePlugin_DBUpdateError (0.00s)
+=== RUN TestPluginHandler_GetPlugin_DBInternalError
+--- PASS: TestPluginHandler_GetPlugin_DBInternalError (0.00s)
+=== RUN TestPluginHandler_EnablePlugin_FirstDBLookupError
+--- PASS: TestPluginHandler_EnablePlugin_FirstDBLookupError (0.00s)
+=== RUN TestPluginHandler_DisablePlugin_FirstDBLookupError
+--- PASS: TestPluginHandler_DisablePlugin_FirstDBLookupError (0.00s)
+=== RUN TestPluginHandler_EnablePlugin_DatabaseUpdateError
+--- PASS: TestPluginHandler_EnablePlugin_DatabaseUpdateError (0.00s)
+=== RUN TestPluginHandler_DisablePlugin_DatabaseUpdateError
+--- PASS: TestPluginHandler_DisablePlugin_DatabaseUpdateError (0.00s)
+=== RUN TestPluginHandler_GetPlugin_DatabaseError
+--- PASS: TestPluginHandler_GetPlugin_DatabaseError (0.00s)
+=== RUN TestPluginHandler_EnablePlugin_DatabaseFirstError
+--- PASS: TestPluginHandler_EnablePlugin_DatabaseFirstError (0.00s)
+=== RUN TestPluginHandler_DisablePlugin_DatabaseFirstError
+--- PASS: TestPluginHandler_DisablePlugin_DatabaseFirstError (0.00s)
+=== RUN TestEncryptionHandler_Validate_NonAdminAccess
+--- PASS: TestEncryptionHandler_Validate_NonAdminAccess (0.03s)
+=== RUN TestEncryptionHandler_GetHistory_PaginationBoundary
+--- PASS: TestEncryptionHandler_GetHistory_PaginationBoundary (0.03s)
+=== RUN TestEncryptionHandler_GetStatus_VersionInfo
+--- PASS: TestEncryptionHandler_GetStatus_VersionInfo (0.03s)
+=== RUN TestSettingsHandler_TestPublicURL_RoleNotExists
+--- PASS: TestSettingsHandler_TestPublicURL_RoleNotExists (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_InvalidURLFormat
+--- PASS: TestSettingsHandler_TestPublicURL_InvalidURLFormat (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_PrivateIPBlocked_Coverage
+--- PASS: TestSettingsHandler_TestPublicURL_PrivateIPBlocked_Coverage (0.00s)
+=== RUN TestSettingsHandler_ValidatePublicURL_WithTrailingSlash
+--- PASS: TestSettingsHandler_ValidatePublicURL_WithTrailingSlash (0.00s)
+=== RUN TestSettingsHandler_ValidatePublicURL_MissingScheme
+--- PASS: TestSettingsHandler_ValidatePublicURL_MissingScheme (0.00s)
+=== RUN TestAuditLogHandler_List_PaginationEdgeCases
+
+2026/01/10 02:23:59 [31;1m/projects/Charon/backend/internal/api/handlers/pr_coverage_test.go:408 [35;1mUNIQUE constraint failed: security_audits.uuid
+[0m[33m[0.315ms] [34;1m[rows:0][0m INSERT INTO `security_audits` (`uuid`,`actor`,`action`,`event_category`,`resource_id`,`resource_uuid`,`details`,`ip_address`,`user_agent`,`created_at`) VALUES ("","user1","action_1","test",NULL,"","{}","","","2026-01-10 02:23:59.873") RETURNING `id`
+
+2026/01/10 02:23:59 [31;1m/projects/Charon/backend/internal/api/handlers/pr_coverage_test.go:408 [35;1mUNIQUE constraint failed: security_audits.uuid
+[0m[33m[0.249ms] [34;1m[rows:0][0m INSERT INTO `security_audits` (`uuid`,`actor`,`action`,`event_category`,`resource_id`,`resource_uuid`,`details`,`ip_address`,`user_agent`,`created_at`) VALUES ("","user1","action_2","test",NULL,"","{}","","","2026-01-10 02:23:59.873") RETURNING `id`
+
+2026/01/10 02:23:59 [31;1m/projects/Charon/backend/internal/api/handlers/pr_coverage_test.go:408 [35;1mUNIQUE constraint failed: security_audits.uuid
+[0m[33m[0.385ms] [34;1m[rows:0][0m INSERT INTO `security_audits` (`uuid`,`actor`,`action`,`event_category`,`resource_id`,`resource_uuid`,`details`,`ip_address`,`user_agent`,`created_at`) VALUES ("","user1","action_3","test",NULL,"","{}","","","2026-01-10 02:23:59.873") RETURNING `id`
+
+2026/01/10 02:23:59 [31;1m/projects/Charon/backend/internal/api/handlers/pr_coverage_test.go:408 [35;1mUNIQUE constraint failed: security_audits.uuid
+[0m[33m[0.424ms] [34;1m[rows:0][0m INSERT INTO `security_audits` (`uuid`,`actor`,`action`,`event_category`,`resource_id`,`resource_uuid`,`details`,`ip_address`,`user_agent`,`created_at`) VALUES ("","user1","action_4","test",NULL,"","{}","","","2026-01-10 02:23:59.874") RETURNING `id`
+
+2026/01/10 02:23:59 [31;1m/projects/Charon/backend/internal/api/handlers/pr_coverage_test.go:408 [35;1mUNIQUE constraint failed: security_audits.uuid
+[0m[33m[0.194ms] [34;1m[rows:0][0m INSERT INTO `security_audits` (`uuid`,`actor`,`action`,`event_category`,`resource_id`,`resource_uuid`,`details`,`ip_address`,`user_agent`,`created_at`) VALUES ("","user1","action_5","test",NULL,"","{}","","","2026-01-10 02:23:59.875") RETURNING `id`
+
+2026/01/10 02:23:59 [31;1m/projects/Charon/backend/internal/api/handlers/pr_coverage_test.go:408 [35;1mUNIQUE constraint failed: security_audits.uuid
+[0m[33m[0.239ms] [34;1m[rows:0][0m INSERT INTO `security_audits` (`uuid`,`actor`,`action`,`event_category`,`resource_id`,`resource_uuid`,`details`,`ip_address`,`user_agent`,`created_at`) VALUES ("","user1","action_6","test",NULL,"","{}","","","2026-01-10 02:23:59.875") RETURNING `id`
+
+2026/01/10 02:23:59 [31;1m/projects/Charon/backend/internal/api/handlers/pr_coverage_test.go:408 [35;1mUNIQUE constraint failed: security_audits.uuid
+[0m[33m[0.169ms] [34;1m[rows:0][0m INSERT INTO `security_audits` (`uuid`,`actor`,`action`,`event_category`,`resource_id`,`resource_uuid`,`details`,`ip_address`,`user_agent`,`created_at`) VALUES ("","user1","action_7","test",NULL,"","{}","","","2026-01-10 02:23:59.875") RETURNING `id`
+
+2026/01/10 02:23:59 [31;1m/projects/Charon/backend/internal/api/handlers/pr_coverage_test.go:408 [35;1mUNIQUE constraint failed: security_audits.uuid
+[0m[33m[0.214ms] [34;1m[rows:0][0m INSERT INTO `security_audits` (`uuid`,`actor`,`action`,`event_category`,`resource_id`,`resource_uuid`,`details`,`ip_address`,`user_agent`,`created_at`) VALUES ("","user1","action_8","test",NULL,"","{}","","","2026-01-10 02:23:59.875") RETURNING `id`
+
+2026/01/10 02:23:59 [31;1m/projects/Charon/backend/internal/api/handlers/pr_coverage_test.go:408 [35;1mUNIQUE constraint failed: security_audits.uuid
+[0m[33m[0.157ms] [34;1m[rows:0][0m INSERT INTO `security_audits` (`uuid`,`actor`,`action`,`event_category`,`resource_id`,`resource_uuid`,`details`,`ip_address`,`user_agent`,`created_at`) VALUES ("","user1","action_9","test",NULL,"","{}","","","2026-01-10 02:23:59.876") RETURNING `id`
+--- PASS: TestAuditLogHandler_List_PaginationEdgeCases (0.04s)
+=== RUN TestAuditLogHandler_List_CategoryFilter
+
+2026/01/10 02:23:59 [31;1m/projects/Charon/backend/internal/api/handlers/pr_coverage_test.go:447 [35;1mUNIQUE constraint failed: security_audits.uuid
+[0m[33m[0.321ms] [34;1m[rows:0][0m INSERT INTO `security_audits` (`uuid`,`actor`,`action`,`event_category`,`resource_id`,`resource_uuid`,`details`,`ip_address`,`user_agent`,`created_at`) VALUES ("","user2","action2","security",NULL,"","{}","","","2026-01-10 02:23:59.909") RETURNING `id`
+--- PASS: TestAuditLogHandler_List_CategoryFilter (0.03s)
+=== RUN TestAuditLogHandler_ListByProvider_DatabaseError
+
+2026/01/10 02:23:59 [31;1m/projects/Charon/backend/internal/services/security_service.go:339 [35;1msql: database is closed
+[0m[33m[0.025ms] [34;1m[rows:0][0m SELECT count(*) FROM `security_audits` WHERE event_category = "dns_provider" AND resource_id = 1
+--- PASS: TestAuditLogHandler_ListByProvider_DatabaseError (0.03s)
+=== RUN TestAuditLogHandler_ListByProvider_InvalidProviderID
+--- PASS: TestAuditLogHandler_ListByProvider_InvalidProviderID (0.03s)
+=== RUN TestGetActorFromGinContext_InvalidUserIDType
+--- PASS: TestGetActorFromGinContext_InvalidUserIDType (0.00s)
+=== RUN TestIsAdmin_NonAdminRole
+--- PASS: TestIsAdmin_NonAdminRole (0.00s)
+=== RUN TestCredentialHandler_Update_InvalidProviderType
+--- PASS: TestCredentialHandler_Update_InvalidProviderType (0.01s)
+=== RUN TestCredentialHandler_List_DatabaseClosed
+
+2026/01/10 02:23:59 [31;1m/projects/Charon/backend/internal/services/credential_service.go:86 [35;1msql: database is closed
+[0m[33m[0.032ms] [34;1m[rows:0][0m SELECT * FROM `dns_providers` WHERE `dns_providers`.`id` = 1 ORDER BY `dns_providers`.`id` LIMIT 1
+--- PASS: TestCredentialHandler_List_DatabaseClosed (0.00s)
+=== RUN TestSettingsHandler_MaskPasswordForTestFunction
+=== RUN TestSettingsHandler_MaskPasswordForTestFunction/empty_string
+=== RUN TestSettingsHandler_MaskPasswordForTestFunction/non-empty_password
+=== RUN TestSettingsHandler_MaskPasswordForTestFunction/already_masked
+=== RUN TestSettingsHandler_MaskPasswordForTestFunction/single_char
+--- PASS: TestSettingsHandler_MaskPasswordForTestFunction (0.00s)
+ --- PASS: TestSettingsHandler_MaskPasswordForTestFunction/empty_string (0.00s)
+ --- PASS: TestSettingsHandler_MaskPasswordForTestFunction/non-empty_password (0.00s)
+ --- PASS: TestSettingsHandler_MaskPasswordForTestFunction/already_masked (0.00s)
+ --- PASS: TestSettingsHandler_MaskPasswordForTestFunction/single_char (0.00s)
+=== RUN TestCredentialHandler_Update_NotFoundError
+
+2026/01/10 02:23:59 [31;1m/projects/Charon/backend/internal/services/credential_service.go:111 [35;1mrecord not found
+[0m[33m[0.132ms] [34;1m[rows:0][0m SELECT * FROM `dns_provider_credentials` WHERE id = 9999 AND dns_provider_id = 1 ORDER BY `dns_provider_credentials`.`id` LIMIT 1
+--- PASS: TestCredentialHandler_Update_NotFoundError (0.01s)
+=== RUN TestCredentialHandler_Update_MalformedJSON
+--- PASS: TestCredentialHandler_Update_MalformedJSON (0.01s)
+=== RUN TestCredentialHandler_Update_BadCredentialID
+--- PASS: TestCredentialHandler_Update_BadCredentialID (0.00s)
+=== RUN TestCredentialHandler_Delete_NotFoundError
+
+2026/01/10 02:24:00 [31;1m/projects/Charon/backend/internal/services/credential_service.go:111 [35;1mrecord not found
+[0m[33m[0.118ms] [34;1m[rows:0][0m SELECT * FROM `dns_provider_credentials` WHERE id = 9999 AND dns_provider_id = 1 ORDER BY `dns_provider_credentials`.`id` LIMIT 1
+--- PASS: TestCredentialHandler_Delete_NotFoundError (0.01s)
+=== RUN TestCredentialHandler_Delete_BadCredentialID
+--- PASS: TestCredentialHandler_Delete_BadCredentialID (0.02s)
+=== RUN TestCredentialHandler_Test_BadCredentialID
+--- PASS: TestCredentialHandler_Test_BadCredentialID (0.01s)
+=== RUN TestCredentialHandler_EnableMultiCredentials_BadProviderID
+--- PASS: TestCredentialHandler_EnableMultiCredentials_BadProviderID (0.01s)
+=== RUN TestEncryptionHandler_Validate_AdminSuccess
+--- PASS: TestEncryptionHandler_Validate_AdminSuccess (0.09s)
+=== RUN TestBulkUpdateSecurityHeaders_Success
+--- PASS: TestBulkUpdateSecurityHeaders_Success (0.03s)
+=== RUN TestBulkUpdateSecurityHeaders_RemoveProfile
+--- PASS: TestBulkUpdateSecurityHeaders_RemoveProfile (0.02s)
+=== RUN TestBulkUpdateSecurityHeaders_InvalidProfileID
+
+2026/01/10 02:24:00 [31;1m/projects/Charon/backend/internal/api/handlers/proxy_host_handler.go:615 [35;1mrecord not found
+[0m[33m[0.101ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE `security_header_profiles`.`id` = 99999 ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestBulkUpdateSecurityHeaders_InvalidProfileID (0.02s)
+=== RUN TestBulkUpdateSecurityHeaders_EmptyUUIDs
+--- PASS: TestBulkUpdateSecurityHeaders_EmptyUUIDs (0.02s)
+=== RUN TestBulkUpdateSecurityHeaders_PartialFailure
+
+2026/01/10 02:24:00 [31;1m/projects/Charon/backend/internal/api/handlers/proxy_host_handler.go:638 [35;1mrecord not found
+[0m[33m[0.138ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts` WHERE uuid = "non-existent-uuid" ORDER BY `proxy_hosts`.`id` LIMIT 1
+--- PASS: TestBulkUpdateSecurityHeaders_PartialFailure (0.03s)
+=== RUN TestBulkUpdateSecurityHeaders_TransactionRollback
+
+2026/01/10 02:24:00 [31;1m/projects/Charon/backend/internal/api/handlers/proxy_host_handler.go:638 [35;1mrecord not found
+[0m[33m[0.144ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts` WHERE uuid = "invalid-uuid-1" ORDER BY `proxy_hosts`.`id` LIMIT 1
+
+2026/01/10 02:24:00 [31;1m/projects/Charon/backend/internal/api/handlers/proxy_host_handler.go:638 [35;1mrecord not found
+[0m[33m[0.137ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts` WHERE uuid = "invalid-uuid-2" ORDER BY `proxy_hosts`.`id` LIMIT 1
+--- PASS: TestBulkUpdateSecurityHeaders_TransactionRollback (0.03s)
+=== RUN TestBulkUpdateSecurityHeaders_InvalidJSON
+--- PASS: TestBulkUpdateSecurityHeaders_InvalidJSON (0.02s)
+=== RUN TestBulkUpdateSecurityHeaders_MixedProfileStates
+--- PASS: TestBulkUpdateSecurityHeaders_MixedProfileStates (0.04s)
+=== RUN TestBulkUpdateSecurityHeaders_SingleHost
+--- PASS: TestBulkUpdateSecurityHeaders_SingleHost (0.02s)
+=== RUN TestProxyHostLifecycle
+=== PAUSE TestProxyHostLifecycle
+=== RUN TestProxyHostDelete_WithUptimeCleanup
+=== PAUSE TestProxyHostDelete_WithUptimeCleanup
+=== RUN TestProxyHostErrors
+=== PAUSE TestProxyHostErrors
+=== RUN TestProxyHostValidation
+=== PAUSE TestProxyHostValidation
+=== RUN TestProxyHostCreate_AdvancedConfig_InvalidJSON
+=== PAUSE TestProxyHostCreate_AdvancedConfig_InvalidJSON
+=== RUN TestProxyHostCreate_AdvancedConfig_Normalization
+=== PAUSE TestProxyHostCreate_AdvancedConfig_Normalization
+=== RUN TestProxyHostUpdate_CertificateID_Null
+=== PAUSE TestProxyHostUpdate_CertificateID_Null
+=== RUN TestProxyHostConnection
+=== PAUSE TestProxyHostConnection
+=== RUN TestProxyHostHandler_List_Error
+=== PAUSE TestProxyHostHandler_List_Error
+=== RUN TestProxyHostWithCaddyIntegration
+=== PAUSE TestProxyHostWithCaddyIntegration
+=== RUN TestProxyHostHandler_BulkUpdateACL_Success
+=== PAUSE TestProxyHostHandler_BulkUpdateACL_Success
+=== RUN TestProxyHostHandler_BulkUpdateACL_RemoveACL
+=== PAUSE TestProxyHostHandler_BulkUpdateACL_RemoveACL
+=== RUN TestProxyHostHandler_BulkUpdateACL_PartialFailure
+=== PAUSE TestProxyHostHandler_BulkUpdateACL_PartialFailure
+=== RUN TestProxyHostHandler_BulkUpdateACL_EmptyUUIDs
+=== PAUSE TestProxyHostHandler_BulkUpdateACL_EmptyUUIDs
+=== RUN TestProxyHostHandler_BulkUpdateACL_InvalidJSON
+=== PAUSE TestProxyHostHandler_BulkUpdateACL_InvalidJSON
+=== RUN TestProxyHostUpdate_AdvancedConfig_ClearAndBackup
+=== PAUSE TestProxyHostUpdate_AdvancedConfig_ClearAndBackup
+=== RUN TestProxyHostUpdate_AdvancedConfig_InvalidJSON
+=== PAUSE TestProxyHostUpdate_AdvancedConfig_InvalidJSON
+=== RUN TestProxyHostUpdate_SetCertificateID
+=== PAUSE TestProxyHostUpdate_SetCertificateID
+=== RUN TestProxyHostUpdate_AdvancedConfig_SetBackup
+=== PAUSE TestProxyHostUpdate_AdvancedConfig_SetBackup
+=== RUN TestProxyHostUpdate_ForwardPort_StringValue
+=== PAUSE TestProxyHostUpdate_ForwardPort_StringValue
+=== RUN TestProxyHostUpdate_Locations_InvalidPayload
+=== PAUSE TestProxyHostUpdate_Locations_InvalidPayload
+=== RUN TestProxyHostUpdate_SetBooleansAndApplication
+=== PAUSE TestProxyHostUpdate_SetBooleansAndApplication
+=== RUN TestProxyHostUpdate_Locations_Replace
+=== PAUSE TestProxyHostUpdate_Locations_Replace
+=== RUN TestProxyHostCreate_WithCertificateAndLocations
+=== PAUSE TestProxyHostCreate_WithCertificateAndLocations
+=== RUN TestProxyHostCreate_WithSecurityHeaderProfile
+=== PAUSE TestProxyHostCreate_WithSecurityHeaderProfile
+=== RUN TestProxyHostUpdate_AssignSecurityHeaderProfile
+=== PAUSE TestProxyHostUpdate_AssignSecurityHeaderProfile
+=== RUN TestProxyHostUpdate_ChangeSecurityHeaderProfile
+=== PAUSE TestProxyHostUpdate_ChangeSecurityHeaderProfile
+=== RUN TestProxyHostUpdate_RemoveSecurityHeaderProfile
+=== PAUSE TestProxyHostUpdate_RemoveSecurityHeaderProfile
+=== RUN TestProxyHostUpdate_InvalidSecurityHeaderProfileID
+=== PAUSE TestProxyHostUpdate_InvalidSecurityHeaderProfileID
+=== RUN TestProxyHostUpdate_SecurityHeaderProfile_StrictToBasic
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfile_StrictToBasic
+=== RUN TestProxyHostUpdate_SecurityHeaderProfile_ToNone
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfile_ToNone
+=== RUN TestProxyHostUpdate_SecurityHeaderProfile_FromNoneToValid
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfile_FromNoneToValid
+=== RUN TestProxyHostUpdate_SecurityHeaderProfile_InvalidString
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfile_InvalidString
+=== RUN TestProxyHostUpdate_SecurityHeaderProfile_InvalidFloat
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfile_InvalidFloat
+=== RUN TestProxyHostUpdate_SecurityHeaderProfile_ValidString
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfile_ValidString
+=== RUN TestProxyHostUpdate_SecurityHeaderProfile_UnsupportedType
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfile_UnsupportedType
+=== RUN TestUpdate_EnableStandardHeaders
+=== PAUSE TestUpdate_EnableStandardHeaders
+=== RUN TestUpdate_ForwardAuthEnabled
+=== PAUSE TestUpdate_ForwardAuthEnabled
+=== RUN TestUpdate_WAFDisabled
+=== PAUSE TestUpdate_WAFDisabled
+=== RUN TestUpdate_IntegrationCaddyConfig
+=== PAUSE TestUpdate_IntegrationCaddyConfig
+=== RUN TestUpdate_ExistingHostsBackwardCompatibility
+=== PAUSE TestUpdate_ExistingHostsBackwardCompatibility
+=== RUN TestProxyHostHandler_BulkUpdateSecurityHeaders_Success
+=== PAUSE TestProxyHostHandler_BulkUpdateSecurityHeaders_Success
+=== RUN TestProxyHostHandler_BulkUpdateSecurityHeaders_RemoveProfile
+=== PAUSE TestProxyHostHandler_BulkUpdateSecurityHeaders_RemoveProfile
+=== RUN TestProxyHostHandler_BulkUpdateSecurityHeaders_PartialFailure
+=== PAUSE TestProxyHostHandler_BulkUpdateSecurityHeaders_PartialFailure
+=== RUN TestProxyHostHandler_BulkUpdateSecurityHeaders_EmptyUUIDs
+=== PAUSE TestProxyHostHandler_BulkUpdateSecurityHeaders_EmptyUUIDs
+=== RUN TestProxyHostHandler_BulkUpdateSecurityHeaders_InvalidJSON
+=== PAUSE TestProxyHostHandler_BulkUpdateSecurityHeaders_InvalidJSON
+=== RUN TestProxyHostHandler_BulkUpdateSecurityHeaders_ProfileNotFound
+=== PAUSE TestProxyHostHandler_BulkUpdateSecurityHeaders_ProfileNotFound
+=== RUN TestProxyHostHandler_BulkUpdateSecurityHeaders_AllFail
+=== PAUSE TestProxyHostHandler_BulkUpdateSecurityHeaders_AllFail
+=== RUN TestProxyHostUpdate_NegativeIntCertificateID
+=== PAUSE TestProxyHostUpdate_NegativeIntCertificateID
+=== RUN TestProxyHostUpdate_AccessListID_StringValue
+=== PAUSE TestProxyHostUpdate_AccessListID_StringValue
+=== RUN TestProxyHostUpdate_AccessListID_IntValue
+=== PAUSE TestProxyHostUpdate_AccessListID_IntValue
+=== RUN TestProxyHostUpdate_CertificateID_IntValue
+=== PAUSE TestProxyHostUpdate_CertificateID_IntValue
+=== RUN TestProxyHostUpdate_CertificateID_StringValue
+=== PAUSE TestProxyHostUpdate_CertificateID_StringValue
+=== RUN TestProxyHostUpdate_EnableStandardHeaders_Null
+=== PAUSE TestProxyHostUpdate_EnableStandardHeaders_Null
+=== RUN TestProxyHostUpdate_EnableStandardHeaders_True
+=== PAUSE TestProxyHostUpdate_EnableStandardHeaders_True
+=== RUN TestProxyHostUpdate_EnableStandardHeaders_False
+=== PAUSE TestProxyHostUpdate_EnableStandardHeaders_False
+=== RUN TestProxyHostUpdate_ForwardAuthEnabled
+=== PAUSE TestProxyHostUpdate_ForwardAuthEnabled
+=== RUN TestProxyHostUpdate_WAFDisabled
+=== PAUSE TestProxyHostUpdate_WAFDisabled
+=== RUN TestProxyHostUpdate_SecurityHeaderProfileID_NegativeFloat
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfileID_NegativeFloat
+=== RUN TestProxyHostUpdate_SecurityHeaderProfileID_NegativeInt
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfileID_NegativeInt
+=== RUN TestProxyHostUpdate_SecurityHeaderProfileID_InvalidString
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfileID_InvalidString
+=== RUN TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType
+=== RUN TestProxyHostUpdate_SecurityHeaderProfileID_ValidAssignment
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfileID_ValidAssignment
+=== RUN TestProxyHostUpdate_SecurityHeaderProfileID_SetToNull
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfileID_SetToNull
+=== RUN TestBulkUpdateSecurityHeaders_DBError_NonNotFound
+=== PAUSE TestBulkUpdateSecurityHeaders_DBError_NonNotFound
+=== RUN TestSanitizeForLog
+--- PASS: TestSanitizeForLog (0.00s)
+=== RUN TestSecurityHandler_GetGeoIPStatus_NotInitialized
+--- PASS: TestSecurityHandler_GetGeoIPStatus_NotInitialized (0.00s)
+=== RUN TestSecurityHandler_GetGeoIPStatus_Initialized_NotLoaded
+--- PASS: TestSecurityHandler_GetGeoIPStatus_Initialized_NotLoaded (0.00s)
+=== RUN TestSecurityHandler_ReloadGeoIP_NotInitialized
+--- PASS: TestSecurityHandler_ReloadGeoIP_NotInitialized (0.00s)
+=== RUN TestSecurityHandler_ReloadGeoIP_LoadError
+time="2026-01-10T02:24:00Z" level=error msg="Failed to reload GeoIP database" error="open : no such file or directory"
+--- PASS: TestSecurityHandler_ReloadGeoIP_LoadError (0.00s)
+=== RUN TestSecurityHandler_LookupGeoIP_MissingIPAddress
+--- PASS: TestSecurityHandler_LookupGeoIP_MissingIPAddress (0.00s)
+=== RUN TestSecurityHandler_LookupGeoIP_ServiceUnavailable
+--- PASS: TestSecurityHandler_LookupGeoIP_ServiceUnavailable (0.00s)
+=== RUN TestSecurityHandler_GetConfigAndUpdateConfig
+
+2026/01/10 02:24:00 [31;1m/projects/Charon/backend/internal/services/security_service.go:70 [35;1mrecord not found
+[0m[33m[0.082ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:00 [31;1m/projects/Charon/backend/internal/services/security_service.go:106 [35;1mrecord not found
+[0m[33m[0.107ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+--- PASS: TestSecurityHandler_GetConfigAndUpdateConfig (0.00s)
+=== RUN TestSecurityHandler_GetStatus_SQLInjection
+--- PASS: TestSecurityHandler_GetStatus_SQLInjection (0.03s)
+=== RUN TestSecurityHandler_CreateDecision_SQLInjection
+=== RUN TestSecurityHandler_CreateDecision_SQLInjection/payload_0
+=== RUN TestSecurityHandler_CreateDecision_SQLInjection/payload_1
+=== RUN TestSecurityHandler_CreateDecision_SQLInjection/payload_2
+=== RUN TestSecurityHandler_CreateDecision_SQLInjection/payload_3
+--- PASS: TestSecurityHandler_CreateDecision_SQLInjection (0.02s)
+ --- PASS: TestSecurityHandler_CreateDecision_SQLInjection/payload_0 (0.00s)
+ --- PASS: TestSecurityHandler_CreateDecision_SQLInjection/payload_1 (0.00s)
+ --- PASS: TestSecurityHandler_CreateDecision_SQLInjection/payload_2 (0.00s)
+ --- PASS: TestSecurityHandler_CreateDecision_SQLInjection/payload_3 (0.00s)
+=== RUN TestSecurityHandler_UpsertRuleSet_MassivePayload
+--- PASS: TestSecurityHandler_UpsertRuleSet_MassivePayload (0.57s)
+=== RUN TestSecurityHandler_UpsertRuleSet_EmptyName
+--- PASS: TestSecurityHandler_UpsertRuleSet_EmptyName (0.01s)
+=== RUN TestSecurityHandler_CreateDecision_EmptyFields
+=== RUN TestSecurityHandler_CreateDecision_EmptyFields/empty_ip
+=== RUN TestSecurityHandler_CreateDecision_EmptyFields/empty_action
+=== RUN TestSecurityHandler_CreateDecision_EmptyFields/both_empty
+=== RUN TestSecurityHandler_CreateDecision_EmptyFields/valid
+--- PASS: TestSecurityHandler_CreateDecision_EmptyFields (0.02s)
+ --- PASS: TestSecurityHandler_CreateDecision_EmptyFields/empty_ip (0.00s)
+ --- PASS: TestSecurityHandler_CreateDecision_EmptyFields/empty_action (0.00s)
+ --- PASS: TestSecurityHandler_CreateDecision_EmptyFields/both_empty (0.00s)
+ --- PASS: TestSecurityHandler_CreateDecision_EmptyFields/valid (0.00s)
+=== RUN TestSecurityHandler_GetStatus_SettingsOverride
+--- PASS: TestSecurityHandler_GetStatus_SettingsOverride (0.02s)
+=== RUN TestSecurityHandler_GetStatus_DisabledViaSettings
+--- PASS: TestSecurityHandler_GetStatus_DisabledViaSettings (0.02s)
+=== RUN TestSecurityAudit_DeleteRuleSet_InvalidID
+=== RUN TestSecurityAudit_DeleteRuleSet_InvalidID/empty_id
+=== RUN TestSecurityAudit_DeleteRuleSet_InvalidID/non_numeric
+=== RUN TestSecurityAudit_DeleteRuleSet_InvalidID/negative
+=== RUN TestSecurityAudit_DeleteRuleSet_InvalidID/sql_injection
+=== RUN TestSecurityAudit_DeleteRuleSet_InvalidID/not_found
+--- PASS: TestSecurityAudit_DeleteRuleSet_InvalidID (0.02s)
+ --- PASS: TestSecurityAudit_DeleteRuleSet_InvalidID/empty_id (0.00s)
+ --- PASS: TestSecurityAudit_DeleteRuleSet_InvalidID/non_numeric (0.00s)
+ --- PASS: TestSecurityAudit_DeleteRuleSet_InvalidID/negative (0.00s)
+ --- PASS: TestSecurityAudit_DeleteRuleSet_InvalidID/sql_injection (0.00s)
+ --- PASS: TestSecurityAudit_DeleteRuleSet_InvalidID/not_found (0.00s)
+=== RUN TestSecurityHandler_UpsertRuleSet_XSSInContent
+--- PASS: TestSecurityHandler_UpsertRuleSet_XSSInContent (0.03s)
+=== RUN TestSecurityHandler_UpdateConfig_RateLimitBounds
+=== RUN TestSecurityHandler_UpdateConfig_RateLimitBounds/valid_limits
+=== RUN TestSecurityHandler_UpdateConfig_RateLimitBounds/zero_requests
+=== RUN TestSecurityHandler_UpdateConfig_RateLimitBounds/negative_burst
+=== RUN TestSecurityHandler_UpdateConfig_RateLimitBounds/huge_values
+--- PASS: TestSecurityHandler_UpdateConfig_RateLimitBounds (0.02s)
+ --- PASS: TestSecurityHandler_UpdateConfig_RateLimitBounds/valid_limits (0.00s)
+ --- PASS: TestSecurityHandler_UpdateConfig_RateLimitBounds/zero_requests (0.00s)
+ --- PASS: TestSecurityHandler_UpdateConfig_RateLimitBounds/negative_burst (0.00s)
+ --- PASS: TestSecurityHandler_UpdateConfig_RateLimitBounds/huge_values (0.00s)
+=== RUN TestSecurityHandler_GetStatus_NilDB
+--- PASS: TestSecurityHandler_GetStatus_NilDB (0.00s)
+=== RUN TestSecurityHandler_Enable_WithoutWhitelist
+--- PASS: TestSecurityHandler_Enable_WithoutWhitelist (0.01s)
+=== RUN TestSecurityHandler_Disable_RequiresToken
+--- PASS: TestSecurityHandler_Disable_RequiresToken (0.03s)
+=== RUN TestSecurityHandler_GetStatus_CrowdSecModeValidation
+=== RUN TestSecurityHandler_GetStatus_CrowdSecModeValidation/mode_remote
+=== RUN TestSecurityHandler_GetStatus_CrowdSecModeValidation/mode_external
+=== RUN TestSecurityHandler_GetStatus_CrowdSecModeValidation/mode_cloud
+=== RUN TestSecurityHandler_GetStatus_CrowdSecModeValidation/mode_api
+=== RUN TestSecurityHandler_GetStatus_CrowdSecModeValidation/mode_../../../etc/passwd
+--- PASS: TestSecurityHandler_GetStatus_CrowdSecModeValidation (0.03s)
+ --- PASS: TestSecurityHandler_GetStatus_CrowdSecModeValidation/mode_remote (0.01s)
+ --- PASS: TestSecurityHandler_GetStatus_CrowdSecModeValidation/mode_external (0.00s)
+ --- PASS: TestSecurityHandler_GetStatus_CrowdSecModeValidation/mode_cloud (0.00s)
+ --- PASS: TestSecurityHandler_GetStatus_CrowdSecModeValidation/mode_api (0.00s)
+ --- PASS: TestSecurityHandler_GetStatus_CrowdSecModeValidation/mode_../../../etc/passwd (0.00s)
+=== RUN TestSecurityHandler_GetStatus_Clean
+--- PASS: TestSecurityHandler_GetStatus_Clean (0.00s)
+=== RUN TestSecurityHandler_Cerberus_DBOverride
+--- PASS: TestSecurityHandler_Cerberus_DBOverride (0.01s)
+=== RUN TestSecurityHandler_ACL_DBOverride
+--- PASS: TestSecurityHandler_ACL_DBOverride (0.02s)
+=== RUN TestSecurityHandler_GenerateBreakGlass_ReturnsToken
+--- PASS: TestSecurityHandler_GenerateBreakGlass_ReturnsToken (1.09s)
+=== RUN TestSecurityHandler_ACL_DisabledWhenCerberusOff
+--- PASS: TestSecurityHandler_ACL_DisabledWhenCerberusOff (0.01s)
+=== RUN TestSecurityHandler_CrowdSec_Mode_DBOverride
+--- PASS: TestSecurityHandler_CrowdSec_Mode_DBOverride (0.01s)
+=== RUN TestSecurityHandler_CrowdSec_ExternalMappedToDisabled_DBOverride
+--- PASS: TestSecurityHandler_CrowdSec_ExternalMappedToDisabled_DBOverride (0.01s)
+=== RUN TestSecurityHandler_ExternalModeMappedToDisabled
+--- PASS: TestSecurityHandler_ExternalModeMappedToDisabled (0.00s)
+=== RUN TestSecurityHandler_Enable_Disable_WithAdminWhitelistAndToken
+--- PASS: TestSecurityHandler_Enable_Disable_WithAdminWhitelistAndToken (1.52s)
+=== RUN TestSecurityHandler_UpdateConfig_Success
+--- PASS: TestSecurityHandler_UpdateConfig_Success (0.02s)
+=== RUN TestSecurityHandler_UpdateConfig_DefaultName
+--- PASS: TestSecurityHandler_UpdateConfig_DefaultName (0.02s)
+=== RUN TestSecurityHandler_UpdateConfig_InvalidPayload
+--- PASS: TestSecurityHandler_UpdateConfig_InvalidPayload (0.01s)
+=== RUN TestSecurityHandler_GetConfig_Success
+--- PASS: TestSecurityHandler_GetConfig_Success (0.01s)
+=== RUN TestSecurityHandler_GetConfig_NotFound
+--- PASS: TestSecurityHandler_GetConfig_NotFound (0.01s)
+=== RUN TestSecurityHandler_ListDecisions_Success
+--- PASS: TestSecurityHandler_ListDecisions_Success (0.01s)
+=== RUN TestSecurityHandler_ListDecisions_WithLimit
+--- PASS: TestSecurityHandler_ListDecisions_WithLimit (0.01s)
+=== RUN TestSecurityHandler_CreateDecision_Success
+--- PASS: TestSecurityHandler_CreateDecision_Success (0.01s)
+=== RUN TestSecurityHandler_CreateDecision_MissingIP
+--- PASS: TestSecurityHandler_CreateDecision_MissingIP (0.01s)
+=== RUN TestSecurityHandler_CreateDecision_MissingAction
+--- PASS: TestSecurityHandler_CreateDecision_MissingAction (0.01s)
+=== RUN TestSecurityHandler_CreateDecision_InvalidPayload
+--- PASS: TestSecurityHandler_CreateDecision_InvalidPayload (0.01s)
+=== RUN TestSecurityHandler_ListRuleSets_Success
+--- PASS: TestSecurityHandler_ListRuleSets_Success (0.01s)
+=== RUN TestSecurityHandler_UpsertRuleSet_Success
+--- PASS: TestSecurityHandler_UpsertRuleSet_Success (0.01s)
+=== RUN TestSecurityHandler_UpsertRuleSet_MissingName
+--- PASS: TestSecurityHandler_UpsertRuleSet_MissingName (0.00s)
+=== RUN TestSecurityHandler_UpsertRuleSet_InvalidPayload
+--- PASS: TestSecurityHandler_UpsertRuleSet_InvalidPayload (0.01s)
+=== RUN TestSecurityHandler_DeleteRuleSet_Success
+--- PASS: TestSecurityHandler_DeleteRuleSet_Success (0.01s)
+=== RUN TestSecurityHandler_DeleteRuleSet_NotFound
+--- PASS: TestSecurityHandler_DeleteRuleSet_NotFound (0.01s)
+=== RUN TestSecurityHandler_DeleteRuleSet_InvalidID
+--- PASS: TestSecurityHandler_DeleteRuleSet_InvalidID (0.01s)
+=== RUN TestSecurityHandler_DeleteRuleSet_EmptyID
+--- PASS: TestSecurityHandler_DeleteRuleSet_EmptyID (0.00s)
+=== RUN TestSecurityHandler_Enable_NoConfigNoWhitelist
+--- PASS: TestSecurityHandler_Enable_NoConfigNoWhitelist (0.01s)
+=== RUN TestSecurityHandler_Enable_WithWhitelist
+--- PASS: TestSecurityHandler_Enable_WithWhitelist (0.01s)
+=== RUN TestSecurityHandler_Enable_IPNotInWhitelist
+--- PASS: TestSecurityHandler_Enable_IPNotInWhitelist (0.01s)
+=== RUN TestSecurityHandler_Enable_WithValidBreakGlassToken
+--- PASS: TestSecurityHandler_Enable_WithValidBreakGlassToken (1.51s)
+=== RUN TestSecurityHandler_Enable_WithInvalidBreakGlassToken
+--- PASS: TestSecurityHandler_Enable_WithInvalidBreakGlassToken (0.01s)
+=== RUN TestSecurityHandler_Disable_FromLocalhost
+--- PASS: TestSecurityHandler_Disable_FromLocalhost (0.01s)
+=== RUN TestSecurityHandler_Disable_FromRemoteWithToken
+--- PASS: TestSecurityHandler_Disable_FromRemoteWithToken (1.49s)
+=== RUN TestSecurityHandler_Disable_FromRemoteNoToken
+--- PASS: TestSecurityHandler_Disable_FromRemoteNoToken (0.01s)
+=== RUN TestSecurityHandler_Disable_FromRemoteInvalidToken
+--- PASS: TestSecurityHandler_Disable_FromRemoteInvalidToken (0.01s)
+=== RUN TestSecurityHandler_GenerateBreakGlass_NoConfig
+--- PASS: TestSecurityHandler_GenerateBreakGlass_NoConfig (0.79s)
+=== RUN TestSecurityHandler_Disable_FromIPv6Localhost
+--- PASS: TestSecurityHandler_Disable_FromIPv6Localhost (0.01s)
+=== RUN TestSecurityHandler_Enable_WithCIDRWhitelist
+--- PASS: TestSecurityHandler_Enable_WithCIDRWhitelist (0.01s)
+=== RUN TestSecurityHandler_Enable_WithExactIPWhitelist
+--- PASS: TestSecurityHandler_Enable_WithExactIPWhitelist (0.01s)
+=== RUN TestSecurityHandler_GetStatus_Fixed
+=== RUN TestSecurityHandler_GetStatus_Fixed/All_Disabled
+=== RUN TestSecurityHandler_GetStatus_Fixed/All_Enabled
+--- PASS: TestSecurityHandler_GetStatus_Fixed (0.00s)
+ --- PASS: TestSecurityHandler_GetStatus_Fixed/All_Disabled (0.00s)
+ --- PASS: TestSecurityHandler_GetStatus_Fixed/All_Enabled (0.00s)
+=== RUN TestSecurityHandler_CreateAndListDecisionAndRulesets
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/services/security_service.go:366 [35;1mrecord not found
+[0m[33m[0.186ms] [34;1m[rows:0][0m SELECT * FROM `security_rule_sets` WHERE name = "owasp-crs" ORDER BY `security_rule_sets`.`id` LIMIT 1
+--- PASS: TestSecurityHandler_CreateAndListDecisionAndRulesets (0.27s)
+=== RUN TestSecurityHandler_UpsertDeleteTriggersApplyConfig
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/services/security_service.go:251 [35;1mattempt to write a readonly database
+[0m[33m[0.701ms] [34;1m[rows:0][0m INSERT INTO `security_audits` (`uuid`,`actor`,`action`,`event_category`,`resource_id`,`resource_uuid`,`details`,`ip_address`,`user_agent`,`created_at`) VALUES ("6418b3c6-0b2e-46da-8fee-112ba3795600","192.0.2.1","delete_ruleset","",NULL,"","1","","","2026-01-10 02:24:08.191") RETURNING `id`
+Failed to write audit log: attempt to write a readonly database
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/services/security_service.go:366 [35;1mrecord not found
+[0m[33m[0.101ms] [34;1m[rows:0][0m SELECT * FROM `security_rule_sets` WHERE name = "owasp-crs" ORDER BY `security_rule_sets`.`id` LIMIT 1
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/caddy/manager.go:90 [35;1mno such table: dns_providers
+[0m[33m[0.044ms] [34;1m[rows:0][0m SELECT * FROM `dns_providers` WHERE enabled = true
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/caddy/manager.go:239 [35;1mrecord not found
+[0m[33m[0.706ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.acme_email" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/caddy/manager.go:246 [35;1mrecord not found
+[0m[33m[0.083ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.ssl_provider" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/caddy/manager.go:627 [35;1mrecord not found
+[0m[33m[0.094ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/caddy/manager.go:629 [35;1mrecord not found
+[0m[33m[0.097ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/caddy/manager.go:634 [35;1mrecord not found
+[0m[33m[0.067ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.acl.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/caddy/manager.go:90 [35;1mno such table: dns_providers
+[0m[33m[0.106ms] [34;1m[rows:0][0m SELECT * FROM `dns_providers` WHERE enabled = true
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/caddy/manager.go:239 [35;1mrecord not found
+[0m[33m[0.098ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.acme_email" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/caddy/manager.go:246 [35;1mrecord not found
+[0m[33m[0.102ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.ssl_provider" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/caddy/manager.go:627 [35;1mrecord not found
+[0m[33m[0.065ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/caddy/manager.go:629 [35;1mrecord not found
+[0m[33m[0.065ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/caddy/manager.go:634 [35;1mrecord not found
+[0m[33m[0.059ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.acl.enabled" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestSecurityHandler_UpsertDeleteTriggersApplyConfig (0.04s)
+=== RUN TestSecurityHandler_GetStatus_RespectsSettingsTable
+=== RUN TestSecurityHandler_GetStatus_RespectsSettingsTable/WAF_enabled_via_settings_overrides_disabled_config
+=== RUN TestSecurityHandler_GetStatus_RespectsSettingsTable/Rate_Limit_enabled_via_settings_overrides_disabled_config
+=== RUN TestSecurityHandler_GetStatus_RespectsSettingsTable/CrowdSec_enabled_via_settings_overrides_disabled_config
+=== RUN TestSecurityHandler_GetStatus_RespectsSettingsTable/All_modules_enabled_via_settings
+=== RUN TestSecurityHandler_GetStatus_RespectsSettingsTable/WAF_disabled_via_settings_overrides_enabled_config
+=== RUN TestSecurityHandler_GetStatus_RespectsSettingsTable/No_settings_-_falls_back_to_config_(enabled)
+--- PASS: TestSecurityHandler_GetStatus_RespectsSettingsTable (0.04s)
+ --- PASS: TestSecurityHandler_GetStatus_RespectsSettingsTable/WAF_enabled_via_settings_overrides_disabled_config (0.01s)
+ --- PASS: TestSecurityHandler_GetStatus_RespectsSettingsTable/Rate_Limit_enabled_via_settings_overrides_disabled_config (0.01s)
+ --- PASS: TestSecurityHandler_GetStatus_RespectsSettingsTable/CrowdSec_enabled_via_settings_overrides_disabled_config (0.01s)
+ --- PASS: TestSecurityHandler_GetStatus_RespectsSettingsTable/All_modules_enabled_via_settings (0.01s)
+ --- PASS: TestSecurityHandler_GetStatus_RespectsSettingsTable/WAF_disabled_via_settings_overrides_enabled_config (0.01s)
+ --- PASS: TestSecurityHandler_GetStatus_RespectsSettingsTable/No_settings_-_falls_back_to_config_(enabled) (0.01s)
+=== RUN TestSecurityHandler_GetStatus_WAFModeFromSettings
+--- PASS: TestSecurityHandler_GetStatus_WAFModeFromSettings (0.01s)
+=== RUN TestSecurityHandler_GetStatus_RateLimitModeFromSettings
+--- PASS: TestSecurityHandler_GetStatus_RateLimitModeFromSettings (0.01s)
+=== RUN TestSecurityHandler_GetWAFExclusions_Empty
+--- PASS: TestSecurityHandler_GetWAFExclusions_Empty (0.01s)
+=== RUN TestSecurityHandler_GetWAFExclusions_WithExclusions
+--- PASS: TestSecurityHandler_GetWAFExclusions_WithExclusions (0.01s)
+=== RUN TestSecurityHandler_GetWAFExclusions_InvalidJSON
+time="2026-01-10T02:24:08Z" level=warning msg="Failed to parse WAF exclusions" error="invalid character 'i' looking for beginning of value"
+--- PASS: TestSecurityHandler_GetWAFExclusions_InvalidJSON (0.01s)
+=== RUN TestSecurityHandler_AddWAFExclusion_Success
+--- PASS: TestSecurityHandler_AddWAFExclusion_Success (0.02s)
+=== RUN TestSecurityHandler_AddWAFExclusion_WithTarget
+--- PASS: TestSecurityHandler_AddWAFExclusion_WithTarget (0.01s)
+=== RUN TestSecurityHandler_AddWAFExclusion_ToExistingConfig
+--- PASS: TestSecurityHandler_AddWAFExclusion_ToExistingConfig (0.02s)
+=== RUN TestSecurityHandler_AddWAFExclusion_Duplicate
+--- PASS: TestSecurityHandler_AddWAFExclusion_Duplicate (0.01s)
+=== RUN TestSecurityHandler_AddWAFExclusion_DuplicateWithDifferentTarget
+--- PASS: TestSecurityHandler_AddWAFExclusion_DuplicateWithDifferentTarget (0.02s)
+=== RUN TestSecurityHandler_AddWAFExclusion_MissingRuleID
+--- PASS: TestSecurityHandler_AddWAFExclusion_MissingRuleID (0.01s)
+=== RUN TestSecurityHandler_AddWAFExclusion_InvalidRuleID
+--- PASS: TestSecurityHandler_AddWAFExclusion_InvalidRuleID (0.01s)
+=== RUN TestSecurityHandler_AddWAFExclusion_NegativeRuleID
+--- PASS: TestSecurityHandler_AddWAFExclusion_NegativeRuleID (0.01s)
+=== RUN TestSecurityHandler_AddWAFExclusion_InvalidPayload
+--- PASS: TestSecurityHandler_AddWAFExclusion_InvalidPayload (0.01s)
+=== RUN TestSecurityHandler_DeleteWAFExclusion_Success
+--- PASS: TestSecurityHandler_DeleteWAFExclusion_Success (0.01s)
+=== RUN TestSecurityHandler_DeleteWAFExclusion_WithTarget
+--- PASS: TestSecurityHandler_DeleteWAFExclusion_WithTarget (0.02s)
+=== RUN TestSecurityHandler_DeleteWAFExclusion_NotFound
+--- PASS: TestSecurityHandler_DeleteWAFExclusion_NotFound (0.01s)
+=== RUN TestSecurityHandler_DeleteWAFExclusion_NoConfig
+--- PASS: TestSecurityHandler_DeleteWAFExclusion_NoConfig (0.01s)
+=== RUN TestSecurityHandler_DeleteWAFExclusion_InvalidRuleID
+--- PASS: TestSecurityHandler_DeleteWAFExclusion_InvalidRuleID (0.01s)
+=== RUN TestSecurityHandler_DeleteWAFExclusion_ZeroRuleID
+--- PASS: TestSecurityHandler_DeleteWAFExclusion_ZeroRuleID (0.01s)
+=== RUN TestSecurityHandler_DeleteWAFExclusion_NegativeRuleID
+--- PASS: TestSecurityHandler_DeleteWAFExclusion_NegativeRuleID (0.01s)
+=== RUN TestSecurityHandler_WAFExclusion_FullWorkflow
+--- PASS: TestSecurityHandler_WAFExclusion_FullWorkflow (0.01s)
+=== RUN TestProxyHost_WAFDisabled_DefaultFalse
+--- PASS: TestProxyHost_WAFDisabled_DefaultFalse (0.02s)
+=== RUN TestProxyHost_WAFDisabled_SetTrue
+--- PASS: TestProxyHost_WAFDisabled_SetTrue (0.02s)
+=== RUN TestSecurityConfig_WAFParanoiaLevel_Default
+--- PASS: TestSecurityConfig_WAFParanoiaLevel_Default (0.01s)
+=== RUN TestSecurityConfig_WAFParanoiaLevel_CustomValue
+--- PASS: TestSecurityConfig_WAFParanoiaLevel_CustomValue (0.01s)
+=== RUN TestSecurityConfig_WAFExclusions_Empty
+--- PASS: TestSecurityConfig_WAFExclusions_Empty (0.01s)
+=== RUN TestSecurityConfig_WAFExclusions_JSONArray
+--- PASS: TestSecurityConfig_WAFExclusions_JSONArray (0.01s)
+=== RUN TestListProfiles
+--- PASS: TestListProfiles (0.01s)
+=== RUN TestGetProfile_ByID
+--- PASS: TestGetProfile_ByID (0.02s)
+=== RUN TestGetProfile_ByUUID
+--- PASS: TestGetProfile_ByUUID (0.01s)
+=== RUN TestGetProfile_NotFound
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:72 [35;1mrecord not found
+[0m[33m[0.131ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE `security_header_profiles`.`id` = 99999 ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestGetProfile_NotFound (0.01s)
+=== RUN TestCreateProfile
+--- PASS: TestCreateProfile (0.01s)
+=== RUN TestCreateProfile_MissingName
+--- PASS: TestCreateProfile_MissingName (0.01s)
+=== RUN TestUpdateProfile
+--- PASS: TestUpdateProfile (0.01s)
+=== RUN TestUpdateProfile_CannotModifyPreset
+--- PASS: TestUpdateProfile_CannotModifyPreset (0.01s)
+=== RUN TestDeleteProfile
+--- PASS: TestDeleteProfile (0.01s)
+=== RUN TestDeleteProfile_CannotDeletePreset
+--- PASS: TestDeleteProfile_CannotDeletePreset (0.02s)
+=== RUN TestDeleteProfile_InUse
+--- PASS: TestDeleteProfile_InUse (0.01s)
+=== RUN TestGetPresets
+--- PASS: TestGetPresets (0.01s)
+=== RUN TestApplyPreset
+--- PASS: TestApplyPreset (0.02s)
+=== RUN TestApplyPreset_InvalidType
+--- PASS: TestApplyPreset_InvalidType (0.01s)
+=== RUN TestCalculateScore
+--- PASS: TestCalculateScore (0.01s)
+=== RUN TestValidateCSP_Valid
+--- PASS: TestValidateCSP_Valid (0.01s)
+=== RUN TestValidateCSP_Invalid
+--- PASS: TestValidateCSP_Invalid (0.01s)
+=== RUN TestValidateCSP_UnsafeDirectives
+--- PASS: TestValidateCSP_UnsafeDirectives (0.01s)
+=== RUN TestBuildCSP
+--- PASS: TestBuildCSP (0.01s)
+=== RUN TestListProfiles_DBError
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:56 [35;1msql: database is closed
+[0m[33m[0.032ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` ORDER BY is_preset DESC, name ASC
+--- PASS: TestListProfiles_DBError (0.01s)
+=== RUN TestGetProfile_UUID_NotFound
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:82 [35;1mrecord not found
+[0m[33m[0.115ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE uuid = "non-existent-uuid-12345" ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestGetProfile_UUID_NotFound (0.01s)
+=== RUN TestGetProfile_ID_DBError
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:72 [35;1msql: database is closed
+[0m[33m[0.050ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE `security_header_profiles`.`id` = 1 ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestGetProfile_ID_DBError (0.01s)
+=== RUN TestGetProfile_UUID_DBError
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:82 [35;1msql: database is closed
+[0m[33m[0.038ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE uuid = "some-uuid-format" ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestGetProfile_UUID_DBError (0.01s)
+=== RUN TestCreateProfile_InvalidJSON
+--- PASS: TestCreateProfile_InvalidJSON (0.01s)
+=== RUN TestCreateProfile_DBError
+--- PASS: TestCreateProfile_DBError (0.02s)
+=== RUN TestUpdateProfile_InvalidID
+--- PASS: TestUpdateProfile_InvalidID (0.01s)
+=== RUN TestUpdateProfile_NotFound
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:136 [35;1mrecord not found
+[0m[33m[0.141ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE `security_header_profiles`.`id` = 99999 ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestUpdateProfile_NotFound (0.01s)
+=== RUN TestUpdateProfile_InvalidJSON
+--- PASS: TestUpdateProfile_InvalidJSON (0.01s)
+=== RUN TestUpdateProfile_DBError
+
+2026/01/10 02:24:08 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:136 [35;1msql: database is closed
+[0m[33m[0.037ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE `security_header_profiles`.`id` = 1 ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestUpdateProfile_DBError (0.02s)
+=== RUN TestUpdateProfile_LookupDBError
+
+2026/01/10 02:24:09 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:136 [35;1msql: database is closed
+[0m[33m[0.041ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE `security_header_profiles`.`id` = 1 ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestUpdateProfile_LookupDBError (0.01s)
+=== RUN TestDeleteProfile_InvalidID
+--- PASS: TestDeleteProfile_InvalidID (0.01s)
+=== RUN TestDeleteProfile_NotFound
+
+2026/01/10 02:24:09 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:183 [35;1mrecord not found
+[0m[33m[0.119ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE `security_header_profiles`.`id` = 99999 ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestDeleteProfile_NotFound (0.01s)
+=== RUN TestDeleteProfile_LookupDBError
+
+2026/01/10 02:24:09 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:183 [35;1msql: database is closed
+[0m[33m[0.055ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE `security_header_profiles`.`id` = 1 ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestDeleteProfile_LookupDBError (0.02s)
+=== RUN TestDeleteProfile_CountDBError
+
+2026/01/10 02:24:09 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:200 [35;1mno such table: proxy_hosts
+[0m[33m[4.018ms] [34;1m[rows:0][0m SELECT count(*) FROM `proxy_hosts` WHERE security_header_profile_id = 1
+--- PASS: TestDeleteProfile_CountDBError (0.01s)
+=== RUN TestDeleteProfile_DeleteDBError
+
+2026/01/10 02:24:09 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:183 [35;1msql: database is closed
+[0m[33m[0.063ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE `security_header_profiles`.`id` = 1 ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestDeleteProfile_DeleteDBError (0.01s)
+=== RUN TestApplyPreset_InvalidJSON
+--- PASS: TestApplyPreset_InvalidJSON (0.01s)
+=== RUN TestCalculateScore_InvalidJSON
+--- PASS: TestCalculateScore_InvalidJSON (0.02s)
+=== RUN TestValidateCSP_InvalidJSON
+--- PASS: TestValidateCSP_InvalidJSON (0.01s)
+=== RUN TestValidateCSP_EmptyCSP
+--- PASS: TestValidateCSP_EmptyCSP (0.01s)
+=== RUN TestValidateCSP_UnknownDirective
+--- PASS: TestValidateCSP_UnknownDirective (0.01s)
+=== RUN TestBuildCSP_InvalidJSON
+--- PASS: TestBuildCSP_InvalidJSON (0.02s)
+=== RUN TestGetProfile_UUID_DBError_NonNotFound
+
+2026/01/10 02:24:09 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:82 [35;1msql: database is closed
+[0m[33m[0.042ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE uuid = "550e8400-e29b-41d4-a716-446655440000" ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestGetProfile_UUID_DBError_NonNotFound (0.01s)
+=== RUN TestUpdateProfile_SaveError
+
+2026/01/10 02:24:09 [31;1m/projects/Charon/backend/internal/api/handlers/security_headers_handler.go:136 [35;1msql: database is closed
+[0m[33m[0.039ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE `security_header_profiles`.`id` = 1 ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestUpdateProfile_SaveError (0.01s)
+=== RUN TestNewSecurityNotificationHandler
+=== PAUSE TestNewSecurityNotificationHandler
+=== RUN TestSecurityNotificationHandler_GetSettings_Success
+=== PAUSE TestSecurityNotificationHandler_GetSettings_Success
+=== RUN TestSecurityNotificationHandler_GetSettings_ServiceError
+=== PAUSE TestSecurityNotificationHandler_GetSettings_ServiceError
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidJSON
+=== PAUSE TestSecurityNotificationHandler_UpdateSettings_InvalidJSON
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidMinLogLevel
+=== PAUSE TestSecurityNotificationHandler_UpdateSettings_InvalidMinLogLevel
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF
+=== PAUSE TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF
+=== RUN TestSecurityNotificationHandler_UpdateSettings_PrivateIPWebhook
+=== PAUSE TestSecurityNotificationHandler_UpdateSettings_PrivateIPWebhook
+=== RUN TestSecurityNotificationHandler_UpdateSettings_ServiceError
+=== PAUSE TestSecurityNotificationHandler_UpdateSettings_ServiceError
+=== RUN TestSecurityNotificationHandler_UpdateSettings_Success
+=== PAUSE TestSecurityNotificationHandler_UpdateSettings_Success
+=== RUN TestSecurityNotificationHandler_UpdateSettings_EmptyWebhookURL
+=== PAUSE TestSecurityNotificationHandler_UpdateSettings_EmptyWebhookURL
+=== RUN TestSecurityHandler_Priority_SettingsOverSecurityConfig
+=== RUN TestSecurityHandler_Priority_SettingsOverSecurityConfig/Settings_table_overrides_SecurityConfig_DB
+=== RUN TestSecurityHandler_Priority_SettingsOverSecurityConfig/SecurityConfig_DB_overrides_static_config
+=== RUN TestSecurityHandler_Priority_SettingsOverSecurityConfig/Static_config_used_when_no_DB_overrides
+--- PASS: TestSecurityHandler_Priority_SettingsOverSecurityConfig (0.04s)
+ --- PASS: TestSecurityHandler_Priority_SettingsOverSecurityConfig/Settings_table_overrides_SecurityConfig_DB (0.01s)
+ --- PASS: TestSecurityHandler_Priority_SettingsOverSecurityConfig/SecurityConfig_DB_overrides_static_config (0.01s)
+ --- PASS: TestSecurityHandler_Priority_SettingsOverSecurityConfig/Static_config_used_when_no_DB_overrides (0.01s)
+=== RUN TestSecurityHandler_Priority_AllModules
+--- PASS: TestSecurityHandler_Priority_AllModules (0.01s)
+=== RUN TestSecurityHandler_GetRateLimitPresets
+--- PASS: TestSecurityHandler_GetRateLimitPresets (0.00s)
+=== RUN TestSecurityHandler_GetRateLimitPresets_StandardPreset
+--- PASS: TestSecurityHandler_GetRateLimitPresets_StandardPreset (0.00s)
+=== RUN TestSecurityHandler_GetRateLimitPresets_LoginPreset
+--- PASS: TestSecurityHandler_GetRateLimitPresets_LoginPreset (0.00s)
+=== RUN TestGetClientIPHeadersAndRemoteAddr
+--- PASS: TestGetClientIPHeadersAndRemoteAddr (0.00s)
+=== RUN TestGetMyIPHandler
+=== RUN TestGetMyIPHandler/with_CF_header
+=== RUN TestGetMyIPHandler/with_X-Forwarded-For_header
+=== RUN TestGetMyIPHandler/with_X-Real-IP_header
+=== RUN TestGetMyIPHandler/direct_connection
+--- PASS: TestGetMyIPHandler (0.00s)
+ --- PASS: TestGetMyIPHandler/with_CF_header (0.00s)
+ --- PASS: TestGetMyIPHandler/with_X-Forwarded-For_header (0.00s)
+ --- PASS: TestGetMyIPHandler/with_X-Real-IP_header (0.00s)
+ --- PASS: TestGetMyIPHandler/direct_connection (0.00s)
+=== RUN TestWaitForCondition_PassesImmediately
+--- PASS: TestWaitForCondition_PassesImmediately (0.00s)
+=== RUN TestWaitForCondition_PassesAfterIterations
+--- PASS: TestWaitForCondition_PassesAfterIterations (0.02s)
+=== RUN TestWaitForConditionWithInterval_PassesImmediately
+--- PASS: TestWaitForConditionWithInterval_PassesImmediately (0.00s)
+=== RUN TestWaitForConditionWithInterval_CustomInterval
+--- PASS: TestWaitForConditionWithInterval_CustomInterval (0.06s)
+=== RUN TestWaitForCondition_Timeout
+--- PASS: TestWaitForCondition_Timeout (0.03s)
+=== RUN TestWaitForConditionWithInterval_Timeout
+--- PASS: TestWaitForConditionWithInterval_Timeout (0.06s)
+=== RUN TestWaitForCondition_ZeroTimeout
+--- PASS: TestWaitForCondition_ZeroTimeout (0.00s)
+=== RUN TestGetTemplateDB
+--- PASS: TestGetTemplateDB (0.00s)
+=== RUN TestGetTemplateDB_HasTables
+--- PASS: TestGetTemplateDB_HasTables (0.00s)
+=== RUN TestOpenTestDB
+--- PASS: TestOpenTestDB (0.00s)
+=== RUN TestOpenTestDB_Uniqueness
+--- PASS: TestOpenTestDB_Uniqueness (0.00s)
+=== RUN TestOpenTestDBWithMigrations
+--- PASS: TestOpenTestDBWithMigrations (0.00s)
+=== RUN TestOpenTestDBWithMigrations_CanInsertData
+--- PASS: TestOpenTestDBWithMigrations_CanInsertData (0.02s)
+=== RUN TestOpenTestDBWithMigrations_MultipleModels
+--- PASS: TestOpenTestDBWithMigrations_MultipleModels (0.01s)
+=== RUN TestOpenTestDBWithMigrations_FallbackPath
+--- PASS: TestOpenTestDBWithMigrations_FallbackPath (0.01s)
+=== RUN TestOpenTestDB_ParallelSafety
+=== PAUSE TestOpenTestDB_ParallelSafety
+=== RUN TestOpenTestDBWithMigrations_ParallelSafety
+=== RUN TestOpenTestDBWithMigrations_ParallelSafety/parallel-migrations-0
+=== RUN TestOpenTestDBWithMigrations_ParallelSafety/parallel-migrations-1
+=== RUN TestOpenTestDBWithMigrations_ParallelSafety/parallel-migrations-2
+--- PASS: TestOpenTestDBWithMigrations_ParallelSafety (0.02s)
+ --- PASS: TestOpenTestDBWithMigrations_ParallelSafety/parallel-migrations-0 (0.01s)
+ --- PASS: TestOpenTestDBWithMigrations_ParallelSafety/parallel-migrations-1 (0.01s)
+ --- PASS: TestOpenTestDBWithMigrations_ParallelSafety/parallel-migrations-2 (0.01s)
+=== RUN TestUpdateHandler_Check
+--- PASS: TestUpdateHandler_Check (0.00s)
+=== RUN TestUserHandler_GetSetupStatus_Error
+--- PASS: TestUserHandler_GetSetupStatus_Error (0.02s)
+=== RUN TestUserHandler_Setup_CheckStatusError
+--- PASS: TestUserHandler_Setup_CheckStatusError (0.02s)
+=== RUN TestUserHandler_Setup_AlreadyCompleted
+--- PASS: TestUserHandler_Setup_AlreadyCompleted (0.74s)
+=== RUN TestUserHandler_Setup_InvalidJSON
+--- PASS: TestUserHandler_Setup_InvalidJSON (0.02s)
+=== RUN TestUserHandler_RegenerateAPIKey_Unauthorized
+--- PASS: TestUserHandler_RegenerateAPIKey_Unauthorized (0.02s)
+=== RUN TestUserHandler_RegenerateAPIKey_DBError
+--- PASS: TestUserHandler_RegenerateAPIKey_DBError (0.02s)
+=== RUN TestUserHandler_GetProfile_Unauthorized
+--- PASS: TestUserHandler_GetProfile_Unauthorized (0.02s)
+=== RUN TestUserHandler_GetProfile_NotFound
+--- PASS: TestUserHandler_GetProfile_NotFound (0.02s)
+=== RUN TestUserHandler_UpdateProfile_Unauthorized
+--- PASS: TestUserHandler_UpdateProfile_Unauthorized (0.01s)
+=== RUN TestUserHandler_UpdateProfile_InvalidJSON
+--- PASS: TestUserHandler_UpdateProfile_InvalidJSON (0.02s)
+=== RUN TestUserHandler_UpdateProfile_UserNotFound
+--- PASS: TestUserHandler_UpdateProfile_UserNotFound (0.02s)
+=== RUN TestUserHandler_UpdateProfile_EmailConflict
+--- PASS: TestUserHandler_UpdateProfile_EmailConflict (1.48s)
+=== RUN TestUserHandler_UpdateProfile_EmailChangeNoPassword
+--- PASS: TestUserHandler_UpdateProfile_EmailChangeNoPassword (0.75s)
+=== RUN TestUserHandler_UpdateProfile_WrongPassword
+--- PASS: TestUserHandler_UpdateProfile_WrongPassword (1.47s)
+=== RUN TestUserHandler_GetSetupStatus
+--- PASS: TestUserHandler_GetSetupStatus (0.02s)
+=== RUN TestUserHandler_Setup
+--- PASS: TestUserHandler_Setup (0.74s)
+=== RUN TestUserHandler_Setup_DBError
+--- PASS: TestUserHandler_Setup_DBError (0.00s)
+=== RUN TestUserHandler_RegenerateAPIKey
+--- PASS: TestUserHandler_RegenerateAPIKey (0.01s)
+=== RUN TestUserHandler_GetProfile
+--- PASS: TestUserHandler_GetProfile (0.02s)
+=== RUN TestUserHandler_RegisterRoutes
+--- PASS: TestUserHandler_RegisterRoutes (0.01s)
+=== RUN TestUserHandler_Errors
+
+2026/01/10 02:24:14 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:171 [35;1mrecord not found
+[0m[33m[0.103ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE `users`.`id` = 99999 ORDER BY `users`.`id` LIMIT 1
+
+2026/01/10 02:24:14 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:154 [35;1mno such table: users
+[0m[33m[0.155ms] [34;1m[rows:0][0m UPDATE `users` SET `api_key`="e55dd8a0-c3ca-4679-a77b-509d128435d1",`updated_at`="2026-01-10 02:24:14.927" WHERE id = 99999
+--- PASS: TestUserHandler_Errors (0.02s)
+=== RUN TestUserHandler_UpdateProfile
+=== RUN TestUserHandler_UpdateProfile/Success_Name_Only
+=== RUN TestUserHandler_UpdateProfile/Success_Email_Change
+=== RUN TestUserHandler_UpdateProfile/Fail_Email_Change_No_Password
+=== RUN TestUserHandler_UpdateProfile/Fail_Email_Change_Wrong_Password
+=== RUN TestUserHandler_UpdateProfile/Fail_Email_In_Use
+--- PASS: TestUserHandler_UpdateProfile (2.36s)
+ --- PASS: TestUserHandler_UpdateProfile/Success_Name_Only (0.00s)
+ --- PASS: TestUserHandler_UpdateProfile/Success_Email_Change (0.77s)
+ --- PASS: TestUserHandler_UpdateProfile/Fail_Email_Change_No_Password (0.00s)
+ --- PASS: TestUserHandler_UpdateProfile/Fail_Email_Change_Wrong_Password (0.73s)
+ --- PASS: TestUserHandler_UpdateProfile/Fail_Email_In_Use (0.00s)
+=== RUN TestUserHandler_UpdateProfile_Errors
+
+2026/01/10 02:24:17 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:207 [35;1mrecord not found
+[0m[33m[0.135ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE `users`.`id` = 999 ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestUserHandler_UpdateProfile_Errors (0.01s)
+=== RUN TestUserHandler_ListUsers_NonAdmin
+--- PASS: TestUserHandler_ListUsers_NonAdmin (0.02s)
+=== RUN TestUserHandler_ListUsers_Admin
+--- PASS: TestUserHandler_ListUsers_Admin (0.01s)
+=== RUN TestUserHandler_CreateUser_NonAdmin
+--- PASS: TestUserHandler_CreateUser_NonAdmin (0.01s)
+=== RUN TestUserHandler_CreateUser_Admin
+--- PASS: TestUserHandler_CreateUser_Admin (0.73s)
+=== RUN TestUserHandler_CreateUser_InvalidJSON
+--- PASS: TestUserHandler_CreateUser_InvalidJSON (0.01s)
+=== RUN TestUserHandler_CreateUser_DuplicateEmail
+--- PASS: TestUserHandler_CreateUser_DuplicateEmail (0.01s)
+=== RUN TestUserHandler_CreateUser_WithPermittedHosts
+--- PASS: TestUserHandler_CreateUser_WithPermittedHosts (0.73s)
+=== RUN TestUserHandler_GetUser_NonAdmin
+--- PASS: TestUserHandler_GetUser_NonAdmin (0.01s)
+=== RUN TestUserHandler_GetUser_InvalidID
+--- PASS: TestUserHandler_GetUser_InvalidID (0.02s)
+=== RUN TestUserHandler_GetUser_NotFound
+
+2026/01/10 02:24:18 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:571 [35;1mrecord not found
+[0m[33m[0.080ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE `users`.`id` = 999 ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestUserHandler_GetUser_NotFound (0.02s)
+=== RUN TestUserHandler_GetUser_Success
+--- PASS: TestUserHandler_GetUser_Success (0.01s)
+=== RUN TestUserHandler_UpdateUser_NonAdmin
+--- PASS: TestUserHandler_UpdateUser_NonAdmin (0.02s)
+=== RUN TestUserHandler_UpdateUser_InvalidID
+--- PASS: TestUserHandler_UpdateUser_InvalidID (0.01s)
+=== RUN TestUserHandler_UpdateUser_InvalidJSON
+--- PASS: TestUserHandler_UpdateUser_InvalidJSON (0.01s)
+=== RUN TestUserHandler_UpdateUser_NotFound
+
+2026/01/10 02:24:18 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:623 [35;1mrecord not found
+[0m[33m[0.103ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE `users`.`id` = 999 ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestUserHandler_UpdateUser_NotFound (0.02s)
+=== RUN TestUserHandler_UpdateUser_Success
+--- PASS: TestUserHandler_UpdateUser_Success (0.02s)
+=== RUN TestUserHandler_DeleteUser_NonAdmin
+--- PASS: TestUserHandler_DeleteUser_NonAdmin (0.01s)
+=== RUN TestUserHandler_DeleteUser_InvalidID
+--- PASS: TestUserHandler_DeleteUser_InvalidID (0.02s)
+=== RUN TestUserHandler_DeleteUser_NotFound
+
+2026/01/10 02:24:19 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:693 [35;1mrecord not found
+[0m[33m[0.096ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE `users`.`id` = 999 ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestUserHandler_DeleteUser_NotFound (0.02s)
+=== RUN TestUserHandler_DeleteUser_Success
+--- PASS: TestUserHandler_DeleteUser_Success (0.02s)
+=== RUN TestUserHandler_DeleteUser_CannotDeleteSelf
+--- PASS: TestUserHandler_DeleteUser_CannotDeleteSelf (0.02s)
+=== RUN TestUserHandler_UpdateUserPermissions_NonAdmin
+--- PASS: TestUserHandler_UpdateUserPermissions_NonAdmin (0.01s)
+=== RUN TestUserHandler_UpdateUserPermissions_InvalidID
+--- PASS: TestUserHandler_UpdateUserPermissions_InvalidID (0.02s)
+=== RUN TestUserHandler_UpdateUserPermissions_InvalidJSON
+--- PASS: TestUserHandler_UpdateUserPermissions_InvalidJSON (0.01s)
+=== RUN TestUserHandler_UpdateUserPermissions_NotFound
+
+2026/01/10 02:24:19 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:734 [35;1mrecord not found
+[0m[33m[0.079ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE `users`.`id` = 999 ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestUserHandler_UpdateUserPermissions_NotFound (0.01s)
+=== RUN TestUserHandler_UpdateUserPermissions_Success
+--- PASS: TestUserHandler_UpdateUserPermissions_Success (0.02s)
+=== RUN TestUserHandler_ValidateInvite_MissingToken
+--- PASS: TestUserHandler_ValidateInvite_MissingToken (0.01s)
+=== RUN TestUserHandler_ValidateInvite_InvalidToken
+
+2026/01/10 02:24:19 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:783 [35;1mrecord not found
+[0m[33m[0.091ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE invite_token = "invalidtoken" ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestUserHandler_ValidateInvite_InvalidToken (0.01s)
+=== RUN TestUserHandler_ValidateInvite_ExpiredToken
+--- PASS: TestUserHandler_ValidateInvite_ExpiredToken (0.02s)
+=== RUN TestUserHandler_ValidateInvite_AlreadyAccepted
+--- PASS: TestUserHandler_ValidateInvite_AlreadyAccepted (0.01s)
+=== RUN TestUserHandler_ValidateInvite_Success
+--- PASS: TestUserHandler_ValidateInvite_Success (0.02s)
+=== RUN TestUserHandler_AcceptInvite_InvalidJSON
+--- PASS: TestUserHandler_AcceptInvite_InvalidJSON (0.02s)
+=== RUN TestUserHandler_AcceptInvite_InvalidToken
+
+2026/01/10 02:24:19 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:822 [35;1mrecord not found
+[0m[33m[0.115ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE invite_token = "invalidtoken" ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestUserHandler_AcceptInvite_InvalidToken (0.02s)
+=== RUN TestUserHandler_AcceptInvite_Success
+--- PASS: TestUserHandler_AcceptInvite_Success (0.78s)
+=== RUN TestGenerateSecureToken
+--- PASS: TestGenerateSecureToken (0.00s)
+=== RUN TestUserHandler_InviteUser_NonAdmin
+--- PASS: TestUserHandler_InviteUser_NonAdmin (0.02s)
+=== RUN TestUserHandler_InviteUser_InvalidJSON
+--- PASS: TestUserHandler_InviteUser_InvalidJSON (0.02s)
+=== RUN TestUserHandler_InviteUser_DuplicateEmail
+--- PASS: TestUserHandler_InviteUser_DuplicateEmail (0.02s)
+=== RUN TestUserHandler_InviteUser_Success
+
+2026/01/10 02:24:20 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:422 [35;1mrecord not found
+[0m[33m[0.088ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE email = "newinvite@example.com" ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestUserHandler_InviteUser_Success (0.02s)
+=== RUN TestUserHandler_InviteUser_WithPermittedHosts
+
+2026/01/10 02:24:20 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:422 [35;1mrecord not found
+[0m[33m[0.098ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE email = "invitee-perms@example.com" ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestUserHandler_InviteUser_WithPermittedHosts (0.02s)
+=== RUN TestUserHandler_InviteUser_WithSMTPConfigured
+
+2026/01/10 02:24:20 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:422 [35;1mrecord not found
+[0m[33m[0.107ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE email = "smtp-test@example.com" ORDER BY `users`.`id` LIMIT 1
+
+2026/01/10 02:24:20 [31;1m/projects/Charon/backend/internal/utils/url.go:17 [35;1mrecord not found
+[0m[33m[0.081ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "app.public_url" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestUserHandler_InviteUser_WithSMTPConfigured (0.03s)
+=== RUN TestUserHandler_InviteUser_WithSMTPConfigured_DefaultAppName
+
+2026/01/10 02:24:20 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:422 [35;1mrecord not found
+[0m[33m[0.117ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE email = "smtp-test-default@example.com" ORDER BY `users`.`id` LIMIT 1
+
+2026/01/10 02:24:20 [31;1m/projects/Charon/backend/internal/utils/url.go:17 [35;1mrecord not found
+[0m[33m[0.087ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "app.public_url" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:20 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:549 [35;1mrecord not found
+[0m[33m[0.075ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "app_name" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestUserHandler_InviteUser_WithSMTPConfigured_DefaultAppName (0.02s)
+=== RUN TestUserHandler_AcceptInvite_ExpiredToken
+--- PASS: TestUserHandler_AcceptInvite_ExpiredToken (0.02s)
+=== RUN TestUserHandler_AcceptInvite_AlreadyAccepted
+--- PASS: TestUserHandler_AcceptInvite_AlreadyAccepted (0.02s)
+=== RUN TestUserHandler_PreviewInviteURL_NonAdmin
+--- PASS: TestUserHandler_PreviewInviteURL_NonAdmin (0.01s)
+=== RUN TestUserHandler_PreviewInviteURL_InvalidJSON
+--- PASS: TestUserHandler_PreviewInviteURL_InvalidJSON (0.01s)
+=== RUN TestUserHandler_PreviewInviteURL_Success_Unconfigured
+
+2026/01/10 02:24:20 [31;1m/projects/Charon/backend/internal/utils/url.go:17 [35;1mrecord not found
+[0m[33m[0.102ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "app.public_url" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:20 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:529 [35;1mrecord not found
+[0m[33m[0.069ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "app.public_url" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestUserHandler_PreviewInviteURL_Success_Unconfigured (0.02s)
+=== RUN TestUserHandler_PreviewInviteURL_Success_Configured
+--- PASS: TestUserHandler_PreviewInviteURL_Success_Configured (0.02s)
+=== RUN TestGetAppName_Default
+
+2026/01/10 02:24:20 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:549 [35;1mrecord not found
+[0m[33m[0.093ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "app_name" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestGetAppName_Default (0.01s)
+=== RUN TestGetAppName_FromSettings
+--- PASS: TestGetAppName_FromSettings (0.02s)
+=== RUN TestGetAppName_EmptyValue
+--- PASS: TestGetAppName_EmptyValue (0.01s)
+=== RUN TestUserHandler_UpdateUser_EmailConflict
+--- PASS: TestUserHandler_UpdateUser_EmailConflict (0.02s)
+=== RUN TestUserHandler_CreateUser_EmailNormalization
+--- PASS: TestUserHandler_CreateUser_EmailNormalization (0.74s)
+=== RUN TestUserHandler_InviteUser_EmailNormalization
+
+2026/01/10 02:24:21 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:422 [35;1mrecord not found
+[0m[33m[0.102ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE email = "invite@example.com" ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestUserHandler_InviteUser_EmailNormalization (0.02s)
+=== RUN TestUserHandler_CreateUser_DefaultPermissionMode
+--- PASS: TestUserHandler_CreateUser_DefaultPermissionMode (0.76s)
+=== RUN TestUserHandler_InviteUser_DefaultPermissionMode
+
+2026/01/10 02:24:21 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:422 [35;1mrecord not found
+[0m[33m[0.081ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE email = "defaultinvite@example.com" ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestUserHandler_InviteUser_DefaultPermissionMode (0.02s)
+=== RUN TestUserHandler_CreateUser_DefaultRole
+--- PASS: TestUserHandler_CreateUser_DefaultRole (0.81s)
+=== RUN TestUserHandler_InviteUser_DefaultRole
+
+2026/01/10 02:24:22 [31;1m/projects/Charon/backend/internal/api/handlers/user_handler.go:422 [35;1mrecord not found
+[0m[33m[0.104ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE email = "defaultroleinvite@example.com" ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestUserHandler_InviteUser_DefaultRole (0.02s)
+=== RUN TestUserHandler_CreateUser_EmptyPermittedHosts
+--- PASS: TestUserHandler_CreateUser_EmptyPermittedHosts (0.75s)
+=== RUN TestUserHandler_CreateUser_NonExistentPermittedHosts
+--- PASS: TestUserHandler_CreateUser_NonExistentPermittedHosts (0.71s)
+=== RUN TestUserLoginAfterEmailChange
+--- PASS: TestUserLoginAfterEmailChange (3.64s)
+=== RUN TestWebSocketStatusHandler_GetConnections
+--- PASS: TestWebSocketStatusHandler_GetConnections (0.00s)
+=== RUN TestWebSocketStatusHandler_GetConnectionsEmpty
+--- PASS: TestWebSocketStatusHandler_GetConnectionsEmpty (0.00s)
+=== RUN TestWebSocketStatusHandler_GetStats
+--- PASS: TestWebSocketStatusHandler_GetStats (0.00s)
+=== RUN TestWebSocketStatusHandler_GetStatsEmpty
+--- PASS: TestWebSocketStatusHandler_GetStatsEmpty (0.00s)
+=== RUN TestCredentialHandler_Create
+--- PASS: TestCredentialHandler_Create (0.01s)
+=== RUN TestCredentialHandler_Create_InvalidProviderID
+--- PASS: TestCredentialHandler_Create_InvalidProviderID (0.01s)
+=== RUN TestCredentialHandler_List
+--- PASS: TestCredentialHandler_List (0.06s)
+=== RUN TestCredentialHandler_Get
+--- PASS: TestCredentialHandler_Get (0.01s)
+=== RUN TestCredentialHandler_Get_NotFound
+
+2026/01/10 02:24:27 [31;1m/projects/Charon/backend/internal/services/credential_service.go:111 [35;1mrecord not found
+[0m[33m[0.111ms] [34;1m[rows:0][0m SELECT * FROM `dns_provider_credentials` WHERE id = 9999 AND dns_provider_id = 1 ORDER BY `dns_provider_credentials`.`id` LIMIT 1
+--- PASS: TestCredentialHandler_Get_NotFound (0.01s)
+=== RUN TestCredentialHandler_Update
+--- PASS: TestCredentialHandler_Update (0.02s)
+=== RUN TestCredentialHandler_Delete
+
+2026/01/10 02:24:27 [31;1m/projects/Charon/backend/internal/services/credential_service.go:349 [35;1mdatabase table is locked
+[0m[33m[0.198ms] [34;1m[rows:0][0m DELETE FROM `dns_provider_credentials` WHERE `dns_provider_credentials`.`id` = 1
+ credential_handler_test.go:271:
+ Error Trace: /projects/Charon/backend/internal/api/handlers/credential_handler_test.go:271
+ Error: Not equal:
+ expected: 204
+ actual : 500
+ Test: TestCredentialHandler_Delete
+ credential_handler_test.go:275:
+ Error Trace: /projects/Charon/backend/internal/api/handlers/credential_handler_test.go:275
+ Error: Expected error with "credential not found" in chain but got nil.
+ Test: TestCredentialHandler_Delete
+--- FAIL: TestCredentialHandler_Delete (0.01s)
+=== RUN TestCredentialHandler_Test
+
+2026/01/10 02:24:27 [31;1m/projects/Charon/backend/internal/services/credential_service.go:431 [35;1mdatabase table is locked
+[0m[33m[0.284ms] [34;1m[rows:0][0m UPDATE `dns_provider_credentials` SET `uuid`="f40f619f-7684-4790-b783-ac5e44294763",`dns_provider_id`=1,`label`="Test",`zone_filter`="",`enabled`=true,`credentials_encrypted`="NBrnkSpfbFdR/MjU6p0DHJ+vnHw83TDcFg9uM543VBlnMlK1Sdw/IvMOMEVHGmAumg==",`key_version`=1,`propagation_timeout`=120,`polling_interval`=5,`last_used_at`=NULL,`success_count`=1,`failure_count`=0,`last_error`="",`created_at`="2026-01-10 02:24:27.934",`updated_at`="2026-01-10 02:24:27.935" WHERE `id` = 1
+--- PASS: TestCredentialHandler_Test (0.01s)
+=== RUN TestCredentialHandler_EnableMultiCredentials
+--- PASS: TestCredentialHandler_EnableMultiCredentials (0.01s)
+=== RUN TestCredentialHandler_List_InvalidProviderID
+--- PASS: TestCredentialHandler_List_InvalidProviderID (0.01s)
+=== RUN TestCredentialHandler_List_ProviderNotFound
+
+2026/01/10 02:24:27 [31;1m/projects/Charon/backend/internal/services/credential_service.go:86 [35;1mrecord not found
+[0m[33m[0.095ms] [34;1m[rows:0][0m SELECT * FROM `dns_providers` WHERE `dns_providers`.`id` = 9999 ORDER BY `dns_providers`.`id` LIMIT 1
+--- PASS: TestCredentialHandler_List_ProviderNotFound (0.01s)
+=== RUN TestCredentialHandler_List_MultiCredentialNotEnabled
+--- PASS: TestCredentialHandler_List_MultiCredentialNotEnabled (0.00s)
+=== RUN TestCredentialHandler_Create_ProviderNotFound
+
+2026/01/10 02:24:27 [31;1m/projects/Charon/backend/internal/services/credential_service.go:127 [35;1mrecord not found
+[0m[33m[0.098ms] [34;1m[rows:0][0m SELECT * FROM `dns_providers` WHERE `dns_providers`.`id` = 9999 ORDER BY `dns_providers`.`id` LIMIT 1
+--- PASS: TestCredentialHandler_Create_ProviderNotFound (0.01s)
+=== RUN TestCredentialHandler_Create_MultiCredentialNotEnabled
+--- PASS: TestCredentialHandler_Create_MultiCredentialNotEnabled (0.01s)
+=== RUN TestCredentialHandler_Create_InvalidJSON
+--- PASS: TestCredentialHandler_Create_InvalidJSON (0.00s)
+=== RUN TestCredentialHandler_Create_MissingRequiredFields
+--- PASS: TestCredentialHandler_Create_MissingRequiredFields (0.01s)
+=== RUN TestCredentialHandler_Create_InvalidProviderType
+--- PASS: TestCredentialHandler_Create_InvalidProviderType (0.01s)
+=== RUN TestCredentialHandler_Get_InvalidProviderID
+--- PASS: TestCredentialHandler_Get_InvalidProviderID (0.01s)
+=== RUN TestCredentialHandler_Get_InvalidCredentialID
+--- PASS: TestCredentialHandler_Get_InvalidCredentialID (0.00s)
+=== RUN TestCredentialHandler_Update_InvalidProviderID
+--- PASS: TestCredentialHandler_Update_InvalidProviderID (0.01s)
+=== RUN TestCredentialHandler_Update_InvalidCredentialID
+--- PASS: TestCredentialHandler_Update_InvalidCredentialID (0.01s)
+=== RUN TestCredentialHandler_Update_NotFound
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/credential_service.go:111 [35;1mrecord not found
+[0m[33m[0.103ms] [34;1m[rows:0][0m SELECT * FROM `dns_provider_credentials` WHERE id = 9999 AND dns_provider_id = 1 ORDER BY `dns_provider_credentials`.`id` LIMIT 1
+--- PASS: TestCredentialHandler_Update_NotFound (0.01s)
+=== RUN TestCredentialHandler_Update_InvalidJSON
+--- PASS: TestCredentialHandler_Update_InvalidJSON (0.01s)
+=== RUN TestCredentialHandler_Delete_InvalidProviderID
+--- PASS: TestCredentialHandler_Delete_InvalidProviderID (0.00s)
+=== RUN TestCredentialHandler_Delete_InvalidCredentialID
+--- PASS: TestCredentialHandler_Delete_InvalidCredentialID (0.00s)
+=== RUN TestCredentialHandler_Delete_NotFound
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/credential_service.go:111 [35;1mrecord not found
+[0m[33m[0.136ms] [34;1m[rows:0][0m SELECT * FROM `dns_provider_credentials` WHERE id = 9999 AND dns_provider_id = 1 ORDER BY `dns_provider_credentials`.`id` LIMIT 1
+--- PASS: TestCredentialHandler_Delete_NotFound (0.00s)
+=== RUN TestCredentialHandler_Test_InvalidProviderID
+--- PASS: TestCredentialHandler_Test_InvalidProviderID (0.00s)
+=== RUN TestCredentialHandler_Test_InvalidCredentialID
+--- PASS: TestCredentialHandler_Test_InvalidCredentialID (0.00s)
+=== RUN TestCredentialHandler_Test_NotFound
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/credential_service.go:111 [35;1mrecord not found
+[0m[33m[0.094ms] [34;1m[rows:0][0m SELECT * FROM `dns_provider_credentials` WHERE id = 9999 AND dns_provider_id = 1 ORDER BY `dns_provider_credentials`.`id` LIMIT 1
+--- PASS: TestCredentialHandler_Test_NotFound (0.01s)
+=== RUN TestCredentialHandler_EnableMultiCredentials_InvalidProviderID
+--- PASS: TestCredentialHandler_EnableMultiCredentials_InvalidProviderID (0.00s)
+=== RUN TestCredentialHandler_EnableMultiCredentials_ProviderNotFound
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/credential_service.go:555 [35;1mrecord not found
+[0m[33m[0.115ms] [34;1m[rows:0][0m SELECT * FROM `dns_providers` WHERE `dns_providers`.`id` = 9999 ORDER BY `dns_providers`.`id` LIMIT 1
+--- PASS: TestCredentialHandler_EnableMultiCredentials_ProviderNotFound (0.01s)
+=== RUN TestCredentialHandler_Create_EncryptionError
+--- PASS: TestCredentialHandler_Create_EncryptionError (0.01s)
+=== RUN TestCredentialHandler_Update_EncryptionError
+--- PASS: TestCredentialHandler_Update_EncryptionError (0.02s)
+=== RUN TestCredentialHandler_Update_InvalidProviderType
+--- PASS: TestCredentialHandler_Update_InvalidProviderType (0.02s)
+=== RUN TestCredentialHandler_Update_InvalidCredentials
+--- PASS: TestCredentialHandler_Update_InvalidCredentials (0.02s)
+=== RUN TestCredentialHandler_Create_EmptyLabel
+--- PASS: TestCredentialHandler_Create_EmptyLabel (0.01s)
+=== RUN TestCredentialHandler_Update_WithZoneFilter
+--- PASS: TestCredentialHandler_Update_WithZoneFilter (0.02s)
+=== RUN TestCredentialHandler_Delete_ProviderNotFound
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/credential_service.go:111 [35;1mrecord not found
+[0m[33m[0.109ms] [34;1m[rows:0][0m SELECT * FROM `dns_provider_credentials` WHERE id = 1 AND dns_provider_id = 9999 ORDER BY `dns_provider_credentials`.`id` LIMIT 1
+--- PASS: TestCredentialHandler_Delete_ProviderNotFound (0.01s)
+=== RUN TestCredentialHandler_Test_ProviderNotFound
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/credential_service.go:111 [35;1mrecord not found
+[0m[33m[0.088ms] [34;1m[rows:0][0m SELECT * FROM `dns_provider_credentials` WHERE id = 1 AND dns_provider_id = 9999 ORDER BY `dns_provider_credentials`.`id` LIMIT 1
+--- PASS: TestCredentialHandler_Test_ProviderNotFound (0.01s)
+=== RUN TestRemoteServerHandler_List
+=== PAUSE TestRemoteServerHandler_List
+=== RUN TestRemoteServerHandler_Create
+=== PAUSE TestRemoteServerHandler_Create
+=== RUN TestRemoteServerHandler_TestConnection
+=== PAUSE TestRemoteServerHandler_TestConnection
+=== RUN TestRemoteServerHandler_Get
+=== PAUSE TestRemoteServerHandler_Get
+=== RUN TestRemoteServerHandler_Update
+=== PAUSE TestRemoteServerHandler_Update
+=== RUN TestRemoteServerHandler_Delete
+=== PAUSE TestRemoteServerHandler_Delete
+=== RUN TestProxyHostHandler_List
+=== PAUSE TestProxyHostHandler_List
+=== RUN TestProxyHostHandler_Create
+=== PAUSE TestProxyHostHandler_Create
+=== RUN TestProxyHostHandler_PartialUpdate_DoesNotWipeFields
+=== PAUSE TestProxyHostHandler_PartialUpdate_DoesNotWipeFields
+=== RUN TestHealthHandler
+=== PAUSE TestHealthHandler
+=== RUN TestRemoteServerHandler_Errors
+=== PAUSE TestRemoteServerHandler_Errors
+=== RUN TestImportHandler_GetStatus
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:60 [35;1mrecord not found
+[0m[33m[0.180ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE status IN ("pending","reviewing") ORDER BY created_at DESC,`import_sessions`.`id` LIMIT 1
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:60 [35;1mrecord not found
+[0m[33m[0.101ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE status IN ("pending","reviewing") ORDER BY created_at DESC,`import_sessions`.`id` LIMIT 1
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:70 [35;1mrecord not found
+[0m[33m[0.077ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE source_file = "/tmp/TestImportHandler_GetStatus2696916650/001/mounted.caddyfile" AND status = "committed" ORDER BY committed_at DESC,`import_sessions`.`id` LIMIT 1
+--- PASS: TestImportHandler_GetStatus (0.02s)
+=== RUN TestImportHandler_GetPreview
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:122 [35;1mrecord not found
+[0m[33m[0.193ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE status IN ("pending","reviewing") ORDER BY created_at DESC,`import_sessions`.`id` LIMIT 1
+--- PASS: TestImportHandler_GetPreview (0.02s)
+=== RUN TestImportHandler_Cancel
+--- PASS: TestImportHandler_Cancel (0.01s)
+=== RUN TestImportHandler_Commit
+--- PASS: TestImportHandler_Commit (0.01s)
+=== RUN TestImportHandler_Upload
+--- PASS: TestImportHandler_Upload (0.02s)
+=== RUN TestImportHandler_GetPreview_WithContent
+--- PASS: TestImportHandler_GetPreview_WithContent (0.02s)
+=== RUN TestImportHandler_Commit_Errors
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:583 [35;1mrecord not found
+[0m[33m[0.080ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE uuid = "non-existent" AND status = "reviewing" ORDER BY `import_sessions`.`id` LIMIT 1
+--- PASS: TestImportHandler_Commit_Errors (0.01s)
+=== RUN TestImportHandler_Cancel_Errors
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:734 [35;1mrecord not found
+[0m[33m[0.123ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE uuid = "non-existent" ORDER BY `import_sessions`.`id` LIMIT 1
+--- PASS: TestImportHandler_Cancel_Errors (0.01s)
+=== RUN TestCheckMountedImport
+--- PASS: TestCheckMountedImport (0.01s)
+=== RUN TestImportHandler_Upload_Failure
+--- PASS: TestImportHandler_Upload_Failure (0.02s)
+=== RUN TestImportHandler_Upload_Conflict
+--- PASS: TestImportHandler_Upload_Conflict (0.02s)
+=== RUN TestImportHandler_GetPreview_BackupContent
+--- PASS: TestImportHandler_GetPreview_BackupContent (0.02s)
+=== RUN TestImportHandler_RegisterRoutes
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:60 [35;1mrecord not found
+[0m[33m[0.152ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE status IN ("pending","reviewing") ORDER BY created_at DESC,`import_sessions`.`id` LIMIT 1
+--- PASS: TestImportHandler_RegisterRoutes (0.02s)
+=== RUN TestImportHandler_GetPreview_TransientMount
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:122 [35;1mrecord not found
+[0m[33m[0.162ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE status IN ("pending","reviewing") ORDER BY created_at DESC,`import_sessions`.`id` LIMIT 1
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:167 [35;1mrecord not found
+[0m[33m[0.074ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE source_file = "/tmp/TestImportHandler_GetPreview_TransientMount3200069616/001/mounted.caddyfile" AND status = "committed" ORDER BY committed_at DESC,`import_sessions`.`id` LIMIT 1
+--- PASS: TestImportHandler_GetPreview_TransientMount (0.02s)
+=== RUN TestImportHandler_Commit_TransientUpload
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:583 [35;1mrecord not found
+[0m[33m[0.101ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE uuid = "07b56185-d75c-46c0-8e2d-ece5943f0c14" AND status = "reviewing" ORDER BY `import_sessions`.`id` LIMIT 1
+--- PASS: TestImportHandler_Commit_TransientUpload (0.02s)
+=== RUN TestImportHandler_Commit_TransientMount
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:583 [35;1mrecord not found
+[0m[33m[0.112ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE uuid = "7b3daafe-be1a-4222-a08f-4b5b10b631e8" AND status = "reviewing" ORDER BY `import_sessions`.`id` LIMIT 1
+--- PASS: TestImportHandler_Commit_TransientMount (0.02s)
+=== RUN TestImportHandler_Cancel_TransientUpload
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:734 [35;1mrecord not found
+[0m[33m[0.108ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE uuid = "49cca609-8bee-4ea1-bb1f-0381031e0894" ORDER BY `import_sessions`.`id` LIMIT 1
+--- PASS: TestImportHandler_Cancel_TransientUpload (0.03s)
+=== RUN TestImportHandler_Errors
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:583 [35;1mrecord not found
+[0m[33m[0.156ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE uuid = "non-existent" AND status = "reviewing" ORDER BY `import_sessions`.`id` LIMIT 1
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/import_handler.go:734 [35;1mrecord not found
+[0m[33m[0.063ms] [34;1m[rows:0][0m SELECT * FROM `import_sessions` WHERE uuid = "non-existent" ORDER BY `import_sessions`.`id` LIMIT 1
+--- PASS: TestImportHandler_Errors (0.01s)
+=== RUN TestImportHandler_DetectImports
+=== RUN TestImportHandler_DetectImports/no_imports
+=== RUN TestImportHandler_DetectImports/single_import
+=== RUN TestImportHandler_DetectImports/multiple_imports
+=== RUN TestImportHandler_DetectImports/import_with_comment
+--- PASS: TestImportHandler_DetectImports (0.02s)
+ --- PASS: TestImportHandler_DetectImports/no_imports (0.00s)
+ --- PASS: TestImportHandler_DetectImports/single_import (0.00s)
+ --- PASS: TestImportHandler_DetectImports/multiple_imports (0.00s)
+ --- PASS: TestImportHandler_DetectImports/import_with_comment (0.00s)
+=== RUN TestImportHandler_DetectImports_InvalidJSON
+--- PASS: TestImportHandler_DetectImports_InvalidJSON (0.01s)
+=== RUN TestImportHandler_UploadMulti
+=== RUN TestImportHandler_UploadMulti/single_Caddyfile
+=== RUN TestImportHandler_UploadMulti/Caddyfile_with_site_files
+=== RUN TestImportHandler_UploadMulti/missing_Caddyfile
+=== RUN TestImportHandler_UploadMulti/path_traversal_in_filename
+=== RUN TestImportHandler_UploadMulti/empty_file_content
+--- PASS: TestImportHandler_UploadMulti (0.03s)
+ --- PASS: TestImportHandler_UploadMulti/single_Caddyfile (0.00s)
+ --- PASS: TestImportHandler_UploadMulti/Caddyfile_with_site_files (0.00s)
+ --- PASS: TestImportHandler_UploadMulti/missing_Caddyfile (0.00s)
+ --- PASS: TestImportHandler_UploadMulti/path_traversal_in_filename (0.00s)
+ --- PASS: TestImportHandler_UploadMulti/empty_file_content (0.00s)
+=== RUN TestNotificationHandler_List
+--- PASS: TestNotificationHandler_List (0.01s)
+=== RUN TestNotificationHandler_MarkAsRead
+--- PASS: TestNotificationHandler_MarkAsRead (0.01s)
+=== RUN TestNotificationHandler_MarkAllAsRead
+--- PASS: TestNotificationHandler_MarkAllAsRead (0.01s)
+=== RUN TestNotificationHandler_MarkAllAsRead_Error
+--- PASS: TestNotificationHandler_MarkAllAsRead_Error (0.01s)
+=== RUN TestNotificationHandler_DBError
+--- PASS: TestNotificationHandler_DBError (0.01s)
+=== RUN TestNotificationProviderHandler_CRUD
+[GIN] 2026/01/10 - 02:24:28 | 201 | 455.583µs | | POST "/api/v1/notifications/providers"
+[GIN] 2026/01/10 - 02:24:28 | 200 | 237.03µs | | GET "/api/v1/notifications/providers"
+[GIN] 2026/01/10 - 02:24:28 | 200 | 395.081µs | | PUT "/api/v1/notifications/providers/19f9ccc0-a4f6-421b-9541-c556bdee06d9"
+[GIN] 2026/01/10 - 02:24:28 | 200 | 153.631µs | | DELETE "/api/v1/notifications/providers/19f9ccc0-a4f6-421b-9541-c556bdee06d9"
+--- PASS: TestNotificationProviderHandler_CRUD (0.01s)
+=== RUN TestNotificationProviderHandler_Templates
+[GIN] 2026/01/10 - 02:24:28 | 200 | 84.391µs | | GET "/api/v1/notifications/templates"
+--- PASS: TestNotificationProviderHandler_Templates (0.01s)
+=== RUN TestNotificationProviderHandler_Test
+[GIN] 2026/01/10 - 02:24:28 | 400 | 535.722µs | | POST "/api/v1/notifications/providers/test"
+--- PASS: TestNotificationProviderHandler_Test (0.00s)
+=== RUN TestNotificationProviderHandler_Errors
+[GIN] 2026/01/10 - 02:24:28 | 400 | 38.21µs | | POST "/api/v1/notifications/providers"
+[GIN] 2026/01/10 - 02:24:28 | 400 | 20.67µs | | PUT "/api/v1/notifications/providers/123"
+[GIN] 2026/01/10 - 02:24:28 | 400 | 19.43µs | | POST "/api/v1/notifications/providers/test"
+--- PASS: TestNotificationProviderHandler_Errors (0.00s)
+=== RUN TestNotificationProviderHandler_InvalidCustomTemplate_Rejects
+[GIN] 2026/01/10 - 02:24:28 | 400 | 203.791µs | | POST "/api/v1/notifications/providers"
+[GIN] 2026/01/10 - 02:24:28 | 201 | 416.732µs | | POST "/api/v1/notifications/providers"
+[GIN] 2026/01/10 - 02:24:28 | 400 | 137.501µs | | PUT "/api/v1/notifications/providers/c3d48686-6348-4440-8417-eaec4cd16093"
+--- PASS: TestNotificationProviderHandler_InvalidCustomTemplate_Rejects (0.01s)
+=== RUN TestNotificationProviderHandler_Preview
+[GIN] 2026/01/10 - 02:24:28 | 200 | 415.902µs | | POST "/api/v1/notifications/providers/preview"
+[GIN] 2026/01/10 - 02:24:28 | 400 | 248.891µs | | POST "/api/v1/notifications/providers/preview"
+--- PASS: TestNotificationProviderHandler_Preview (0.00s)
+=== RUN TestRemoteServerHandler_TestConnectionCustom
+[GIN] 2026/01/10 - 02:24:28 | 200 | 1.952616ms | | POST "/api/v1/remote-servers/test"
+--- PASS: TestRemoteServerHandler_TestConnectionCustom (0.03s)
+=== RUN TestRemoteServerHandler_FullCRUD
+[GIN] 2026/01/10 - 02:24:28 | 201 | 1.055584ms | | POST "/api/v1/remote-servers"
+[GIN] 2026/01/10 - 02:24:28 | 200 | 274.871µs | | GET "/api/v1/remote-servers"
+[GIN] 2026/01/10 - 02:24:28 | 200 | 233.741µs | | GET "/api/v1/remote-servers/5a619327-d8de-4d58-917a-f6d159264bbc"
+[GIN] 2026/01/10 - 02:24:28 | 200 | 675.653µs | | PUT "/api/v1/remote-servers/5a619327-d8de-4d58-917a-f6d159264bbc"
+[GIN] 2026/01/10 - 02:24:28 | 204 | 504.062µs | | DELETE "/api/v1/remote-servers/5a619327-d8de-4d58-917a-f6d159264bbc"
+[GIN] 2026/01/10 - 02:24:28 | 400 | 32.881µs | | POST "/api/v1/remote-servers"
+[GIN] 2026/01/10 - 02:24:28 | 404 | 131.18µs | | PUT "/api/v1/remote-servers/non-existent-uuid"
+[GIN] 2026/01/10 - 02:24:28 | 404 | 113.17µs | | DELETE "/api/v1/remote-servers/non-existent-uuid"
+--- PASS: TestRemoteServerHandler_FullCRUD (0.03s)
+=== RUN TestSettingsHandler_GetSettings
+--- PASS: TestSettingsHandler_GetSettings (0.00s)
+=== RUN TestSettingsHandler_GetSettings_DatabaseError
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/settings_handler.go:30 [35;1msql: database is closed
+[0m[33m[0.026ms] [34;1m[rows:0][0m SELECT * FROM `settings`
+--- PASS: TestSettingsHandler_GetSettings_DatabaseError (0.00s)
+=== RUN TestSettingsHandler_UpdateSettings
+--- PASS: TestSettingsHandler_UpdateSettings (0.00s)
+=== RUN TestSettingsHandler_UpdateSetting_DatabaseError
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/api/handlers/settings_handler.go:72 [35;1msql: database is closed
+[0m[33m[0.026ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE `settings`.`key` = "test_key" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestSettingsHandler_UpdateSetting_DatabaseError (0.00s)
+=== RUN TestSettingsHandler_Errors
+--- PASS: TestSettingsHandler_Errors (0.00s)
+=== RUN TestSettingsHandler_GetSMTPConfig
+--- PASS: TestSettingsHandler_GetSMTPConfig (0.00s)
+=== RUN TestSettingsHandler_GetSMTPConfig_Empty
+--- PASS: TestSettingsHandler_GetSMTPConfig_Empty (0.01s)
+=== RUN TestSettingsHandler_GetSMTPConfig_DatabaseError
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/mail_service.go:91 [35;1msql: database is closed
+[0m[33m[0.019ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE category = "smtp"
+--- PASS: TestSettingsHandler_GetSMTPConfig_DatabaseError (0.00s)
+=== RUN TestSettingsHandler_UpdateSMTPConfig_NonAdmin
+--- PASS: TestSettingsHandler_UpdateSMTPConfig_NonAdmin (0.00s)
+=== RUN TestSettingsHandler_UpdateSMTPConfig_InvalidJSON
+--- PASS: TestSettingsHandler_UpdateSMTPConfig_InvalidJSON (0.00s)
+=== RUN TestSettingsHandler_UpdateSMTPConfig_Success
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/mail_service.go:142 [35;1mrecord not found
+[0m[33m[0.047ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "smtp_host" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/mail_service.go:142 [35;1mrecord not found
+[0m[33m[0.078ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "smtp_port" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/mail_service.go:142 [35;1mrecord not found
+[0m[33m[0.104ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "smtp_username" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/mail_service.go:142 [35;1mrecord not found
+[0m[33m[0.069ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "smtp_password" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/mail_service.go:142 [35;1mrecord not found
+[0m[33m[0.054ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "smtp_from_address" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/mail_service.go:142 [35;1mrecord not found
+[0m[33m[0.080ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "smtp_encryption" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestSettingsHandler_UpdateSMTPConfig_Success (0.00s)
+=== RUN TestSettingsHandler_UpdateSMTPConfig_KeepExistingPassword
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/mail_service.go:142 [35;1mrecord not found
+[0m[33m[0.066ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "smtp_username" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestSettingsHandler_UpdateSMTPConfig_KeepExistingPassword (0.00s)
+=== RUN TestSettingsHandler_TestSMTPConfig_NonAdmin
+--- PASS: TestSettingsHandler_TestSMTPConfig_NonAdmin (0.00s)
+=== RUN TestSettingsHandler_TestSMTPConfig_NotConfigured
+--- PASS: TestSettingsHandler_TestSMTPConfig_NotConfigured (0.00s)
+=== RUN TestSettingsHandler_TestSMTPConfig_Success
+--- PASS: TestSettingsHandler_TestSMTPConfig_Success (0.00s)
+=== RUN TestSettingsHandler_SendTestEmail_NonAdmin
+--- PASS: TestSettingsHandler_SendTestEmail_NonAdmin (0.00s)
+=== RUN TestSettingsHandler_SendTestEmail_InvalidJSON
+--- PASS: TestSettingsHandler_SendTestEmail_InvalidJSON (0.00s)
+=== RUN TestSettingsHandler_SendTestEmail_NotConfigured
+--- PASS: TestSettingsHandler_SendTestEmail_NotConfigured (0.00s)
+=== RUN TestSettingsHandler_SendTestEmail_Success
+--- PASS: TestSettingsHandler_SendTestEmail_Success (0.00s)
+=== RUN TestMaskPassword
+--- PASS: TestMaskPassword (0.00s)
+=== RUN TestSettingsHandler_ValidatePublicURL_NonAdmin
+--- PASS: TestSettingsHandler_ValidatePublicURL_NonAdmin (0.00s)
+=== RUN TestSettingsHandler_ValidatePublicURL_InvalidFormat
+=== RUN TestSettingsHandler_ValidatePublicURL_InvalidFormat/Missing_scheme
+=== RUN TestSettingsHandler_ValidatePublicURL_InvalidFormat/Invalid_scheme
+=== RUN TestSettingsHandler_ValidatePublicURL_InvalidFormat/URL_with_path
+--- PASS: TestSettingsHandler_ValidatePublicURL_InvalidFormat (0.00s)
+ --- PASS: TestSettingsHandler_ValidatePublicURL_InvalidFormat/Missing_scheme (0.00s)
+ --- PASS: TestSettingsHandler_ValidatePublicURL_InvalidFormat/Invalid_scheme (0.00s)
+ --- PASS: TestSettingsHandler_ValidatePublicURL_InvalidFormat/URL_with_path (0.00s)
+=== RUN TestSettingsHandler_ValidatePublicURL_Success
+=== RUN TestSettingsHandler_ValidatePublicURL_Success/HTTPS_URL
+=== RUN TestSettingsHandler_ValidatePublicURL_Success/HTTP_URL
+=== RUN TestSettingsHandler_ValidatePublicURL_Success/URL_with_port
+=== RUN TestSettingsHandler_ValidatePublicURL_Success/URL_with_trailing_slash
+--- PASS: TestSettingsHandler_ValidatePublicURL_Success (0.00s)
+ --- PASS: TestSettingsHandler_ValidatePublicURL_Success/HTTPS_URL (0.00s)
+ --- PASS: TestSettingsHandler_ValidatePublicURL_Success/HTTP_URL (0.00s)
+ --- PASS: TestSettingsHandler_ValidatePublicURL_Success/URL_with_port (0.00s)
+ --- PASS: TestSettingsHandler_ValidatePublicURL_Success/URL_with_trailing_slash (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_NonAdmin
+--- PASS: TestSettingsHandler_TestPublicURL_NonAdmin (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_NoRole
+--- PASS: TestSettingsHandler_TestPublicURL_NoRole (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_InvalidJSON
+--- PASS: TestSettingsHandler_TestPublicURL_InvalidJSON (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_InvalidURL
+--- PASS: TestSettingsHandler_TestPublicURL_InvalidURL (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_PrivateIPBlocked
+=== RUN TestSettingsHandler_TestPublicURL_PrivateIPBlocked/localhost
+=== RUN TestSettingsHandler_TestPublicURL_PrivateIPBlocked/127.0.0.1
+=== RUN TestSettingsHandler_TestPublicURL_PrivateIPBlocked/Private_10.x
+=== RUN TestSettingsHandler_TestPublicURL_PrivateIPBlocked/Private_192.168.x
+=== RUN TestSettingsHandler_TestPublicURL_PrivateIPBlocked/AWS_metadata
+--- PASS: TestSettingsHandler_TestPublicURL_PrivateIPBlocked (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_PrivateIPBlocked/localhost (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_PrivateIPBlocked/127.0.0.1 (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_PrivateIPBlocked/Private_10.x (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_PrivateIPBlocked/Private_192.168.x (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_PrivateIPBlocked/AWS_metadata (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_Success
+2026/01/10 02:24:28 [SECURITY AUDIT] {"timestamp":"2026-01-10T02:24:28Z","action":"url_connectivity_test","host":"example.com","request_id":"test-1768011868760076519","result":"allowed","resolved_ips":null,"blocked_reason":"","user_id":"system","source_ip":""}
+--- PASS: TestSettingsHandler_TestPublicURL_Success (0.08s)
+=== RUN TestSettingsHandler_TestPublicURL_DNSFailure
+--- PASS: TestSettingsHandler_TestPublicURL_DNSFailure (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_ConnectivityError
+--- PASS: TestSettingsHandler_TestPublicURL_ConnectivityError (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_SSRFProtection
+=== RUN TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_RFC_1918_-_10.x
+=== RUN TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_RFC_1918_-_192.168.x
+=== RUN TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_RFC_1918_-_172.16.x
+=== RUN TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_localhost
+=== RUN TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_127.0.0.1
+=== RUN TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_cloud_metadata
+=== RUN TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_link-local
+--- PASS: TestSettingsHandler_TestPublicURL_SSRFProtection (0.01s)
+ --- PASS: TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_RFC_1918_-_10.x (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_RFC_1918_-_192.168.x (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_RFC_1918_-_172.16.x (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_localhost (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_127.0.0.1 (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_cloud_metadata (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_SSRFProtection/blocks_link-local (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_EmbeddedCredentials
+--- PASS: TestSettingsHandler_TestPublicURL_EmbeddedCredentials (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_EmptyURL
+=== RUN TestSettingsHandler_TestPublicURL_EmptyURL/empty_string
+=== RUN TestSettingsHandler_TestPublicURL_EmptyURL/missing_field
+--- PASS: TestSettingsHandler_TestPublicURL_EmptyURL (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_EmptyURL/empty_string (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_EmptyURL/missing_field (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_InvalidScheme
+=== RUN TestSettingsHandler_TestPublicURL_InvalidScheme/ftp_scheme
+=== RUN TestSettingsHandler_TestPublicURL_InvalidScheme/file_scheme
+=== RUN TestSettingsHandler_TestPublicURL_InvalidScheme/javascript_scheme
+--- PASS: TestSettingsHandler_TestPublicURL_InvalidScheme (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_InvalidScheme/ftp_scheme (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_InvalidScheme/file_scheme (0.00s)
+ --- PASS: TestSettingsHandler_TestPublicURL_InvalidScheme/javascript_scheme (0.00s)
+=== RUN TestSettingsHandler_ValidatePublicURL_InvalidJSON
+--- PASS: TestSettingsHandler_ValidatePublicURL_InvalidJSON (0.00s)
+=== RUN TestSettingsHandler_ValidatePublicURL_URLWithWarning
+--- PASS: TestSettingsHandler_ValidatePublicURL_URLWithWarning (0.00s)
+=== RUN TestSettingsHandler_UpdateSMTPConfig_DatabaseError
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/mail_service.go:91 [35;1msql: database is closed
+[0m[33m[0.037ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE category = "smtp"
+
+2026/01/10 02:24:28 [31;1m/projects/Charon/backend/internal/services/mail_service.go:142 [35;1msql: database is closed
+[0m[33m[0.026ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "smtp_host" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestSettingsHandler_UpdateSMTPConfig_DatabaseError (0.00s)
+=== RUN TestSettingsHandler_TestPublicURL_IPv6LocalhostBlocked
+--- PASS: TestSettingsHandler_TestPublicURL_IPv6LocalhostBlocked (0.00s)
+=== RUN TestUptimeHandler_List
+[GIN] 2026/01/10 - 02:24:28 | 200 | 437.171µs | | GET "/api/v1/uptime"
+--- PASS: TestUptimeHandler_List (0.03s)
+=== RUN TestUptimeHandler_GetHistory
+[GIN] 2026/01/10 - 02:24:28 | 200 | 266.771µs | | GET "/api/v1/uptime/monitor-1/history"
+--- PASS: TestUptimeHandler_GetHistory (0.02s)
+=== RUN TestUptimeHandler_CheckMonitor
+[GIN] 2026/01/10 - 02:24:28 | 200 | 272.301µs | | POST "/api/v1/uptime/check-mon-1/check"
+--- PASS: TestUptimeHandler_CheckMonitor (0.03s)
+=== RUN TestUptimeHandler_CheckMonitor_NotFound
+[GIN] 2026/01/10 - 02:24:28 | 404 | 286.201µs | | POST "/api/v1/uptime/nonexistent/check"
+--- PASS: TestUptimeHandler_CheckMonitor_NotFound (0.02s)
+=== RUN TestUptimeHandler_Update
+=== RUN TestUptimeHandler_Update/success
+[GIN] 2026/01/10 - 02:24:28 | 200 | 589.321µs | | PUT "/api/v1/uptime/monitor-update"
+=== RUN TestUptimeHandler_Update/invalid_json
+[GIN] 2026/01/10 - 02:24:29 | 400 | 159.921µs | | PUT "/api/v1/uptime/monitor-1"
+=== RUN TestUptimeHandler_Update/not_found
+[GIN] 2026/01/10 - 02:24:29 | 500 | 239.771µs | | PUT "/api/v1/uptime/nonexistent"
+--- PASS: TestUptimeHandler_Update (0.08s)
+ --- PASS: TestUptimeHandler_Update/success (0.03s)
+ --- PASS: TestUptimeHandler_Update/invalid_json (0.02s)
+ --- PASS: TestUptimeHandler_Update/not_found (0.02s)
+=== RUN TestUptimeHandler_DeleteAndSync
+=== RUN TestUptimeHandler_DeleteAndSync/delete_monitor
+[GIN] 2026/01/10 - 02:24:29 | 200 | 455.851µs | | DELETE "/api/v1/uptime/mon-delete"
+=== RUN TestUptimeHandler_DeleteAndSync/sync_creates_monitor_for_proxy_host
+[GIN] 2026/01/10 - 02:24:29 | 200 | 1.287745ms | | POST "/api/v1/uptime/sync"
+=== RUN TestUptimeHandler_DeleteAndSync/update_enabled_via_PUT
+[GIN] 2026/01/10 - 02:24:29 | 200 | 564.043µs | | PUT "/api/v1/uptime/mon-enable"
+--- PASS: TestUptimeHandler_DeleteAndSync (0.07s)
+ --- PASS: TestUptimeHandler_DeleteAndSync/delete_monitor (0.02s)
+ --- PASS: TestUptimeHandler_DeleteAndSync/sync_creates_monitor_for_proxy_host (0.02s)
+ --- PASS: TestUptimeHandler_DeleteAndSync/update_enabled_via_PUT (0.02s)
+=== RUN TestUptimeHandler_Sync_Success
+[GIN] 2026/01/10 - 02:24:29 | 200 | 265.551µs | | POST "/api/v1/uptime/sync"
+--- PASS: TestUptimeHandler_Sync_Success (0.03s)
+=== RUN TestUptimeHandler_Delete_Error
+[GIN] 2026/01/10 - 02:24:29 | 500 | 178.732µs | | DELETE "/api/v1/uptime/nonexistent"
+--- PASS: TestUptimeHandler_Delete_Error (0.02s)
+=== RUN TestUptimeHandler_List_Error
+[GIN] 2026/01/10 - 02:24:29 | 500 | 230.432µs | | GET "/api/v1/uptime"
+--- PASS: TestUptimeHandler_List_Error (0.02s)
+=== RUN TestUptimeHandler_GetHistory_Error
+[GIN] 2026/01/10 - 02:24:29 | 500 | 175.441µs | | GET "/api/v1/uptime/monitor-1/history"
+--- PASS: TestUptimeHandler_GetHistory_Error (0.02s)
+=== CONT TestAuthHandler_Login
+=== CONT TestCrowdsecHandler_Status_LAPINotReady
+=== CONT TestExportConfigStreamsArchive
+=== CONT TestProxyHostHandler_BulkUpdateSecurityHeaders_RemoveProfile
+--- PASS: TestExportConfigStreamsArchive (0.02s)
+=== CONT TestExportConfig
+--- PASS: TestCrowdsecHandler_Status_LAPINotReady (0.03s)
+=== CONT TestImportCreatesBackup
+--- PASS: TestExportConfig (0.01s)
+=== CONT TestListAndReadFile
+--- PASS: TestImportCreatesBackup (0.01s)
+=== CONT TestRemoteServerHandler_Errors
+--- PASS: TestListAndReadFile (0.00s)
+=== CONT TestHealthHandler
+--- PASS: TestHealthHandler (0.00s)
+=== CONT TestProxyHostHandler_PartialUpdate_DoesNotWipeFields
+--- PASS: TestProxyHostHandler_BulkUpdateSecurityHeaders_RemoveProfile (0.07s)
+--- PASS: TestRemoteServerHandler_Errors (0.04s)
+=== CONT TestProxyHostHandler_Create
+=== CONT TestProxyHostHandler_List
+--- PASS: TestProxyHostHandler_PartialUpdate_DoesNotWipeFields (0.06s)
+=== CONT TestRemoteServerHandler_Update
+--- PASS: TestProxyHostHandler_Create (0.03s)
+=== CONT TestRemoteServerHandler_Get
+--- PASS: TestProxyHostHandler_List (0.05s)
+=== CONT TestRemoteServerHandler_TestConnection
+--- PASS: TestRemoteServerHandler_Update (0.03s)
+=== CONT TestRemoteServerHandler_Create
+--- PASS: TestRemoteServerHandler_Get (0.03s)
+=== CONT TestRemoteServerHandler_Delete
+--- PASS: TestRemoteServerHandler_TestConnection (0.03s)
+=== CONT TestOpenTestDB_ParallelSafety
+=== RUN TestOpenTestDB_ParallelSafety/parallel-0
+=== PAUSE TestOpenTestDB_ParallelSafety/parallel-0
+=== RUN TestOpenTestDB_ParallelSafety/parallel-1
+=== PAUSE TestOpenTestDB_ParallelSafety/parallel-1
+=== RUN TestOpenTestDB_ParallelSafety/parallel-2
+=== PAUSE TestOpenTestDB_ParallelSafety/parallel-2
+=== RUN TestOpenTestDB_ParallelSafety/parallel-3
+=== PAUSE TestOpenTestDB_ParallelSafety/parallel-3
+=== RUN TestOpenTestDB_ParallelSafety/parallel-4
+=== PAUSE TestOpenTestDB_ParallelSafety/parallel-4
+=== CONT TestRemoteServerHandler_List
+--- PASS: TestRemoteServerHandler_Create (0.04s)
+=== CONT TestSecurityNotificationHandler_UpdateSettings_Success
+--- PASS: TestSecurityNotificationHandler_UpdateSettings_Success (0.00s)
+--- PASS: TestRemoteServerHandler_Delete (0.03s)
+=== CONT TestSecurityNotificationHandler_UpdateSettings_ServiceError
+--- PASS: TestSecurityNotificationHandler_UpdateSettings_ServiceError (0.00s)
+=== CONT TestSecurityNotificationHandler_UpdateSettings_EmptyWebhookURL
+--- PASS: TestSecurityNotificationHandler_UpdateSettings_EmptyWebhookURL (0.00s)
+=== CONT TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/AWS_Metadata
+=== CONT TestSecurityNotificationHandler_UpdateSettings_InvalidMinLogLevel
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidMinLogLevel/trace
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/GCP_Metadata
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidMinLogLevel/critical
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidMinLogLevel/fatal
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidMinLogLevel/unknown
+--- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidMinLogLevel (0.00s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidMinLogLevel/trace (0.00s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidMinLogLevel/critical (0.00s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidMinLogLevel/fatal (0.00s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidMinLogLevel/unknown (0.00s)
+=== CONT TestSecurityNotificationHandler_UpdateSettings_PrivateIPWebhook
+=== RUN TestSecurityNotificationHandler_UpdateSettings_PrivateIPWebhook/http://127.0.0.1/hook
+=== RUN TestSecurityNotificationHandler_UpdateSettings_PrivateIPWebhook/http://localhost/webhook
+=== RUN TestSecurityNotificationHandler_UpdateSettings_PrivateIPWebhook/http://[::1]/api
+--- PASS: TestSecurityNotificationHandler_UpdateSettings_PrivateIPWebhook (0.00s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_PrivateIPWebhook/http://127.0.0.1/hook (0.00s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_PrivateIPWebhook/http://localhost/webhook (0.00s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_PrivateIPWebhook/http://[::1]/api (0.00s)
+=== CONT TestSecurityNotificationHandler_GetSettings_ServiceError
+--- PASS: TestSecurityNotificationHandler_GetSettings_ServiceError (0.00s)
+=== CONT TestSecurityNotificationHandler_GetSettings_Success
+--- PASS: TestSecurityNotificationHandler_GetSettings_Success (0.00s)
+=== CONT TestSecurityNotificationHandler_UpdateSettings_InvalidJSON
+--- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidJSON (0.00s)
+=== CONT TestBulkUpdateSecurityHeaders_DBError_NonNotFound
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/Azure_Metadata
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/Private_IP_10.x
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/Private_IP_172.16.x
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/Private_IP_192.168.x
+=== RUN TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/Link-local
+--- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF (0.01s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/AWS_Metadata (0.00s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/GCP_Metadata (0.01s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/Azure_Metadata (0.00s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/Private_IP_10.x (0.00s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/Private_IP_172.16.x (0.00s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/Private_IP_192.168.x (0.00s)
+ --- PASS: TestSecurityNotificationHandler_UpdateSettings_InvalidWebhookURL_SSRF/Link-local (0.00s)
+=== CONT TestProxyHostUpdate_SecurityHeaderProfileID_SetToNull
+--- PASS: TestRemoteServerHandler_List (0.03s)
+=== CONT TestNewSecurityNotificationHandler
+--- PASS: TestNewSecurityNotificationHandler (0.00s)
+=== CONT TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/api/handlers/proxy_host_handler.go:615 [35;1msql: database is closed
+[0m[33m[0.029ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE `security_header_profiles`.`id` = 1 ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestBulkUpdateSecurityHeaders_DBError_NonNotFound (0.02s)
+=== CONT TestProxyHostUpdate_SecurityHeaderProfileID_InvalidString
+=== RUN TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/boolean_true
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/boolean_true
+=== RUN TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/boolean_false
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/boolean_false
+=== RUN TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/array
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/array
+=== RUN TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/object
+=== PAUSE TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/object
+=== CONT TestProxyHostUpdate_SecurityHeaderProfileID_ValidAssignment
+--- PASS: TestProxyHostUpdate_SecurityHeaderProfileID_SetToNull (0.05s)
+=== CONT TestProxyHostUpdate_SecurityHeaderProfileID_NegativeFloat
+--- PASS: TestProxyHostUpdate_SecurityHeaderProfileID_InvalidString (0.04s)
+=== CONT TestProxyHostUpdate_SecurityHeaderProfileID_NegativeInt
+--- PASS: TestProxyHostUpdate_SecurityHeaderProfileID_NegativeFloat (0.02s)
+=== CONT TestProxyHostUpdate_ForwardAuthEnabled
+=== RUN TestProxyHostUpdate_SecurityHeaderProfileID_ValidAssignment/as_float64
+=== RUN TestProxyHostUpdate_SecurityHeaderProfileID_ValidAssignment/as_string
+--- PASS: TestProxyHostUpdate_SecurityHeaderProfileID_NegativeInt (0.03s)
+=== CONT TestProxyHostUpdate_EnableStandardHeaders_False
+--- PASS: TestProxyHostUpdate_SecurityHeaderProfileID_ValidAssignment (0.05s)
+ --- PASS: TestProxyHostUpdate_SecurityHeaderProfileID_ValidAssignment/as_float64 (0.00s)
+ --- PASS: TestProxyHostUpdate_SecurityHeaderProfileID_ValidAssignment/as_string (0.01s)
+=== CONT TestProxyHostUpdate_WAFDisabled
+--- PASS: TestProxyHostUpdate_ForwardAuthEnabled (0.04s)
+=== CONT TestProxyHostUpdate_EnableStandardHeaders_True
+--- PASS: TestProxyHostUpdate_WAFDisabled (0.03s)
+=== CONT TestProxyHostUpdate_CertificateID_StringValue
+--- PASS: TestProxyHostUpdate_EnableStandardHeaders_False (0.03s)
+=== CONT TestProxyHostUpdate_EnableStandardHeaders_Null
+--- PASS: TestProxyHostUpdate_EnableStandardHeaders_True (0.02s)
+=== CONT TestProxyHostUpdate_CertificateID_IntValue
+--- PASS: TestProxyHostUpdate_EnableStandardHeaders_Null (0.03s)
+=== CONT TestProxyHostUpdate_AccessListID_IntValue
+--- PASS: TestProxyHostUpdate_CertificateID_StringValue (0.03s)
+=== CONT TestProxyHostUpdate_NegativeIntCertificateID
+--- PASS: TestProxyHostUpdate_CertificateID_IntValue (0.03s)
+=== CONT TestProxyHostHandler_BulkUpdateSecurityHeaders_AllFail
+--- PASS: TestProxyHostUpdate_NegativeIntCertificateID (0.02s)
+=== CONT TestProxyHostHandler_BulkUpdateSecurityHeaders_ProfileNotFound
+--- PASS: TestProxyHostUpdate_AccessListID_IntValue (0.04s)
+=== CONT TestProxyHostUpdate_AccessListID_StringValue
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/api/handlers/proxy_host_handler.go:615 [35;1mrecord not found
+[0m[33m[0.111ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE `security_header_profiles`.`id` = 99999 ORDER BY `security_header_profiles`.`id` LIMIT 1
+--- PASS: TestProxyHostHandler_BulkUpdateSecurityHeaders_ProfileNotFound (0.04s)
+=== CONT TestProxyHostHandler_BulkUpdateSecurityHeaders_EmptyUUIDs
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/api/handlers/proxy_host_handler.go:638 [35;1mrecord not found
+[0m[33m[0.104ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts` WHERE uuid = "8c5c2bdf-0760-4ddb-9980-c72c43b5fe33" ORDER BY `proxy_hosts`.`id` LIMIT 1
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/api/handlers/proxy_host_handler.go:638 [35;1mrecord not found
+[0m[33m[0.100ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts` WHERE uuid = "ea888497-0fec-4c2e-a9ba-9017bc322ac3" ORDER BY `proxy_hosts`.`id` LIMIT 1
+--- PASS: TestProxyHostHandler_BulkUpdateSecurityHeaders_AllFail (0.05s)
+=== CONT TestProxyHostHandler_BulkUpdateSecurityHeaders_InvalidJSON
+--- PASS: TestProxyHostUpdate_AccessListID_StringValue (0.04s)
+=== CONT TestProxyHostHandler_BulkUpdateSecurityHeaders_PartialFailure
+--- PASS: TestProxyHostHandler_BulkUpdateSecurityHeaders_EmptyUUIDs (0.03s)
+=== CONT TestUpdate_ExistingHostsBackwardCompatibility
+--- PASS: TestProxyHostHandler_BulkUpdateSecurityHeaders_InvalidJSON (0.03s)
+=== CONT TestUpdate_IntegrationCaddyConfig
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/api/handlers/proxy_host_handler.go:638 [35;1mrecord not found
+[0m[33m[0.170ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts` WHERE uuid = "d6bdf056-cc3d-4ff3-bc3f-ce1e4dde3499" ORDER BY `proxy_hosts`.`id` LIMIT 1
+--- PASS: TestProxyHostHandler_BulkUpdateSecurityHeaders_PartialFailure (0.06s)
+=== CONT TestUpdate_WAFDisabled
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/caddy/manager.go:239 [35;1mrecord not found
+[0m[33m[0.069ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.acme_email" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/caddy/manager.go:246 [35;1mrecord not found
+[0m[33m[0.114ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.ssl_provider" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/caddy/manager.go:598 [35;1mno such table: security_configs
+[0m[33m[2.830ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/caddy/manager.go:627 [35;1mrecord not found
+[0m[33m[0.088ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/caddy/manager.go:629 [35;1mrecord not found
+[0m[33m[0.079ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/caddy/manager.go:634 [35;1mrecord not found
+[0m[33m[0.076ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.acl.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/caddy/manager.go:285 [35;1mno such table: security_configs
+[0m[33m[0.037ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/caddy/manager.go:295 [35;1mno such table: security_rule_sets
+[0m[33m[1.014ms] [34;1m[rows:0][0m SELECT * FROM `security_rule_sets`
+
+2026/01/10 02:24:29 [31;1m/projects/Charon/backend/internal/caddy/manager.go:302 [35;1mno such table: security_decisions
+[0m[33m[3.027ms] [34;1m[rows:0][0m SELECT * FROM `security_decisions` ORDER BY created_at desc
+--- PASS: TestUpdate_WAFDisabled (0.04s)
+=== CONT TestProxyHostHandler_BulkUpdateSecurityHeaders_Success
+--- PASS: TestUpdate_IntegrationCaddyConfig (0.08s)
+=== CONT TestUpdate_ForwardAuthEnabled
+--- PASS: TestUpdate_ForwardAuthEnabled (0.04s)
+=== CONT TestUpdate_EnableStandardHeaders
+--- PASS: TestUpdate_ExistingHostsBackwardCompatibility (0.14s)
+=== CONT TestProxyHostUpdate_SecurityHeaderProfile_UnsupportedType
+--- PASS: TestProxyHostHandler_BulkUpdateSecurityHeaders_Success (0.07s)
+=== CONT TestProxyHostUpdate_SecurityHeaderProfile_InvalidFloat
+--- PASS: TestUpdate_EnableStandardHeaders (0.06s)
+=== CONT TestProxyHostUpdate_SecurityHeaderProfile_InvalidString
+--- PASS: TestProxyHostUpdate_SecurityHeaderProfile_InvalidFloat (0.04s)
+=== CONT TestProxyHostUpdate_SecurityHeaderProfile_ValidString
+--- PASS: TestProxyHostUpdate_SecurityHeaderProfile_UnsupportedType (0.07s)
+=== CONT TestProxyHostUpdate_SecurityHeaderProfile_FromNoneToValid
+--- PASS: TestProxyHostUpdate_SecurityHeaderProfile_InvalidString (0.03s)
+=== CONT TestProxyHostUpdate_SecurityHeaderProfile_ToNone
+--- PASS: TestProxyHostUpdate_SecurityHeaderProfile_ValidString (0.05s)
+=== CONT TestProxyHostUpdate_InvalidSecurityHeaderProfileID
+--- PASS: TestProxyHostUpdate_SecurityHeaderProfile_FromNoneToValid (0.05s)
+=== CONT TestProxyHostUpdate_RemoveSecurityHeaderProfile
+--- PASS: TestProxyHostUpdate_SecurityHeaderProfile_ToNone (0.05s)
+=== CONT TestProxyHostUpdate_SecurityHeaderProfile_StrictToBasic
+--- PASS: TestProxyHostUpdate_InvalidSecurityHeaderProfileID (0.10s)
+=== CONT TestProxyHostUpdate_AssignSecurityHeaderProfile
+--- PASS: TestProxyHostUpdate_RemoveSecurityHeaderProfile (0.10s)
+=== CONT TestProxyHostUpdate_ChangeSecurityHeaderProfile
+--- PASS: TestProxyHostUpdate_SecurityHeaderProfile_StrictToBasic (0.10s)
+=== CONT TestProxyHostCreate_WithCertificateAndLocations
+--- PASS: TestProxyHostUpdate_AssignSecurityHeaderProfile (0.04s)
+=== CONT TestProxyHostCreate_WithSecurityHeaderProfile
+--- PASS: TestProxyHostCreate_WithCertificateAndLocations (0.03s)
+=== CONT TestProxyHostUpdate_SetBooleansAndApplication
+--- PASS: TestProxyHostCreate_WithSecurityHeaderProfile (0.04s)
+=== CONT TestProxyHostUpdate_Locations_InvalidPayload
+--- PASS: TestProxyHostUpdate_ChangeSecurityHeaderProfile (0.06s)
+=== CONT TestProxyHostUpdate_Locations_Replace
+--- PASS: TestProxyHostUpdate_SetBooleansAndApplication (0.04s)
+=== CONT TestProxyHostUpdate_ForwardPort_StringValue
+--- PASS: TestProxyHostUpdate_Locations_InvalidPayload (0.02s)
+=== CONT TestProxyHostUpdate_AdvancedConfig_SetBackup
+--- PASS: TestProxyHostUpdate_ForwardPort_StringValue (0.03s)
+=== CONT TestProxyHostUpdate_SetCertificateID
+--- PASS: TestProxyHostUpdate_Locations_Replace (0.05s)
+=== CONT TestProxyHostUpdate_AdvancedConfig_InvalidJSON
+--- PASS: TestProxyHostUpdate_AdvancedConfig_SetBackup (0.03s)
+=== CONT TestProxyHostUpdate_AdvancedConfig_ClearAndBackup
+--- PASS: TestProxyHostUpdate_SetCertificateID (0.03s)
+=== CONT TestProxyHostHandler_BulkUpdateACL_EmptyUUIDs
+--- PASS: TestProxyHostUpdate_AdvancedConfig_InvalidJSON (0.03s)
+=== CONT TestProxyHostHandler_BulkUpdateACL_PartialFailure
+--- PASS: TestProxyHostUpdate_AdvancedConfig_ClearAndBackup (0.03s)
+=== CONT TestProxyHostHandler_BulkUpdateACL_InvalidJSON
+--- PASS: TestProxyHostHandler_BulkUpdateACL_InvalidJSON (0.03s)
+=== CONT TestProxyHostHandler_BulkUpdateACL_Success
+--- PASS: TestProxyHostHandler_BulkUpdateACL_EmptyUUIDs (0.04s)
+=== CONT TestProxyHostWithCaddyIntegration
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/services/proxyhost_service.go:117 [35;1mrecord not found
+[0m[33m[0.088ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts` WHERE uuid = "07e9e0fb-b069-425f-a470-33bdf2cf6e2e" ORDER BY `proxy_hosts`.`id` LIMIT 1
+--- PASS: TestProxyHostHandler_BulkUpdateACL_PartialFailure (0.03s)
+=== CONT TestProxyHostHandler_BulkUpdateACL_RemoveACL
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:239 [35;1mrecord not found
+[0m[33m[0.061ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.acme_email" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:246 [35;1mrecord not found
+[0m[33m[0.061ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.ssl_provider" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:598 [35;1mno such table: security_configs
+[0m[33m[1.273ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:627 [35;1mrecord not found
+[0m[33m[0.126ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:629 [35;1mrecord not found
+[0m[33m[0.092ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:634 [35;1mrecord not found
+[0m[33m[0.104ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.acl.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:285 [35;1mno such table: security_configs
+[0m[33m[0.033ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:295 [35;1mno such table: security_rule_sets
+[0m[33m[0.826ms] [34;1m[rows:0][0m SELECT * FROM `security_rule_sets`
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:302 [35;1mno such table: security_decisions
+[0m[33m[0.760ms] [34;1m[rows:0][0m SELECT * FROM `security_decisions` ORDER BY created_at desc
+--- PASS: TestProxyHostHandler_BulkUpdateACL_Success (0.03s)
+=== CONT TestProxyHostConnection
+--- PASS: TestProxyHostHandler_BulkUpdateACL_RemoveACL (0.04s)
+=== CONT TestProxyHostHandler_List_Error
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/services/notification_service.go:96 [35;1mno such table: notification_providers
+[0m[33m[1.014ms] [34;1m[rows:0][0m SELECT * FROM `notification_providers` WHERE enabled = true
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:239 [35;1mrecord not found
+[0m[33m[0.059ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.acme_email" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:246 [35;1mrecord not found
+[0m[33m[0.118ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.ssl_provider" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:598 [35;1mno such table: security_configs
+[0m[33m[0.039ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:627 [35;1mrecord not found
+[0m[33m[0.311ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:629 [35;1mrecord not found
+[0m[33m[0.097ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:634 [35;1mrecord not found
+[0m[33m[0.093ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.acl.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:285 [35;1mno such table: security_configs
+[0m[33m[0.039ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:295 [35;1mno such table: security_rule_sets
+[0m[33m[0.037ms] [34;1m[rows:0][0m SELECT * FROM `security_rule_sets`
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:302 [35;1mno such table: security_decisions
+[0m[33m[0.040ms] [34;1m[rows:0][0m SELECT * FROM `security_decisions` ORDER BY created_at desc
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:239 [35;1mrecord not found
+[0m[33m[0.069ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.acme_email" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:246 [35;1mrecord not found
+[0m[33m[0.124ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.ssl_provider" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:598 [35;1mno such table: security_configs
+[0m[33m[0.064ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:627 [35;1mrecord not found
+[0m[33m[0.095ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:629 [35;1mrecord not found
+[0m[33m[0.131ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:634 [35;1mrecord not found
+[0m[33m[0.095ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.acl.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:285 [35;1mno such table: security_configs
+[0m[33m[0.039ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:295 [35;1mno such table: security_rule_sets
+[0m[33m[0.032ms] [34;1m[rows:0][0m SELECT * FROM `security_rule_sets`
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:302 [35;1mno such table: security_decisions
+[0m[33m[0.058ms] [34;1m[rows:0][0m SELECT * FROM `security_decisions` ORDER BY created_at desc
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/services/notification_service.go:96 [35;1mno such table: notification_providers
+[0m[33m[0.069ms] [34;1m[rows:0][0m SELECT * FROM `notification_providers` WHERE enabled = true
+--- PASS: TestProxyHostWithCaddyIntegration (0.06s)
+=== CONT TestProxyHostCreate_AdvancedConfig_Normalization
+--- PASS: TestProxyHostConnection (0.03s)
+=== CONT TestProxyHostUpdate_CertificateID_Null
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/services/proxyhost_service.go:126 [35;1msql: database is closed
+[0m[33m[0.031ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts` ORDER BY updated_at desc
+--- PASS: TestProxyHostHandler_List_Error (0.02s)
+=== CONT TestProxyHostValidation
+--- PASS: TestProxyHostUpdate_CertificateID_Null (0.04s)
+=== CONT TestProxyHostCreate_AdvancedConfig_InvalidJSON
+--- PASS: TestProxyHostCreate_AdvancedConfig_Normalization (0.04s)
+=== CONT TestProxyHostDelete_WithUptimeCleanup
+--- PASS: TestProxyHostValidation (0.05s)
+=== CONT TestProxyHostLifecycle
+--- PASS: TestProxyHostCreate_AdvancedConfig_InvalidJSON (0.02s)
+=== CONT TestCrowdsecHandler_HubEndpoints
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/services/notification_service.go:96 [35;1mno such table: notification_providers
+[0m[33m[3.430ms] [34;1m[rows:0][0m SELECT * FROM `notification_providers` WHERE enabled = true
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/api/handlers/proxy_host_handler_test.go:143 [35;1mrecord not found
+[0m[33m[0.133ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts` WHERE uuid = "ph-delete-1" ORDER BY `proxy_hosts`.`id` LIMIT 1
+--- PASS: TestProxyHostDelete_WithUptimeCleanup (0.03s)
+=== CONT TestProxyHostErrors
+--- PASS: TestCrowdsecHandler_HubEndpoints (0.01s)
+=== CONT TestCrowdsecHandler_Status_LAPIReady
+--- PASS: TestCrowdsecHandler_Status_LAPIReady (0.01s)
+=== CONT TestCrowdsecHandler_ListDecisions_WithCreatedAt
+--- PASS: TestCrowdsecHandler_ListDecisions_WithCreatedAt (0.01s)
+=== CONT TestCrowdsecHandler_BanIP_WithConfigYaml
+--- PASS: TestCrowdsecHandler_BanIP_WithConfigYaml (0.00s)
+=== CONT TestCrowdsecHandler_UnbanIP_WithConfigYaml
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/services/proxyhost_service.go:117 [35;1mrecord not found
+[0m[33m[0.108ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts` WHERE uuid = "baa89836-1f8a-4d50-9840-30e46e95211b" ORDER BY `proxy_hosts`.`id` LIMIT 1
+--- PASS: TestProxyHostLifecycle (0.03s)
+=== CONT TestCrowdsecHandler_UpdateAcquisitionConfig_InvalidJSON
+--- PASS: TestCrowdsecHandler_UnbanIP_WithConfigYaml (0.01s)
+=== CONT TestCrowdsecHandler_UpdateAcquisitionConfig_MissingContent
+--- PASS: TestCrowdsecHandler_UpdateAcquisitionConfig_InvalidJSON (0.00s)
+=== CONT TestCrowdsecHandler_ListDecisions_WithConfigYaml
+--- PASS: TestCrowdsecHandler_UpdateAcquisitionConfig_MissingContent (0.00s)
+=== CONT TestCrowdsecHandler_CheckLAPIHealth_InvalidURL
+--- PASS: TestCrowdsecHandler_ListDecisions_WithConfigYaml (0.01s)
+=== CONT TestCrowdsecHandler_BanIP_ExecutionError
+--- PASS: TestCrowdsecHandler_BanIP_ExecutionError (0.11s)
+=== CONT TestCrowdsecHandler_GetLAPIDecisions_Fallback
+--- PASS: TestCrowdsecHandler_CheckLAPIHealth_InvalidURL (0.12s)
+=== CONT TestCrowdsecHandler_UnbanIP_Error
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:239 [35;1mrecord not found
+[0m[33m[0.094ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.acme_email" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:246 [35;1mrecord not found
+[0m[33m[0.068ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.ssl_provider" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:598 [35;1mno such table: security_configs
+[0m[33m[1.028ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:627 [35;1mrecord not found
+[0m[33m[0.068ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:629 [35;1mrecord not found
+[0m[33m[0.075ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:634 [35;1mrecord not found
+[0m[33m[0.069ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.acl.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:285 [35;1mno such table: security_configs
+[0m[33m[0.025ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:295 [35;1mno such table: security_rule_sets
+[0m[33m[3.112ms] [34;1m[rows:0][0m SELECT * FROM `security_rule_sets`
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:302 [35;1mno such table: security_decisions
+[0m[33m[0.784ms] [34;1m[rows:0][0m SELECT * FROM `security_decisions` ORDER BY created_at desc
+--- PASS: TestCrowdsecHandler_UnbanIP_Error (0.01s)
+=== CONT TestCrowdsecHandler_BanIP_DefaultDuration
+--- PASS: TestCrowdsecHandler_GetLAPIDecisions_Fallback (0.02s)
+=== CONT TestCrowdsecHandler_UnbanIP_Success
+--- PASS: TestCrowdsecHandler_BanIP_DefaultDuration (0.01s)
+=== CONT TestCrowdsecHandler_BanIP_EmptyIP
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/services/proxyhost_service.go:117 [35;1mrecord not found
+[0m[33m[0.123ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts` WHERE uuid = "non-existent-uuid" ORDER BY `proxy_hosts`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/services/proxyhost_service.go:117 [35;1mrecord not found
+[0m[33m[0.119ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts` WHERE uuid = "non-existent-uuid" ORDER BY `proxy_hosts`.`id` LIMIT 1
+--- PASS: TestCrowdsecHandler_UnbanIP_Success (0.01s)
+=== CONT TestCrowdsecHandler_BanIP_MissingIP
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:239 [35;1mrecord not found
+[0m[33m[0.092ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.acme_email" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:246 [35;1mrecord not found
+[0m[33m[0.105ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.ssl_provider" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:598 [35;1mno such table: security_configs
+[0m[33m[0.086ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:627 [35;1mrecord not found
+[0m[33m[0.084ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:629 [35;1mrecord not found
+[0m[33m[0.093ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:634 [35;1mrecord not found
+[0m[33m[0.092ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.acl.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:285 [35;1mno such table: security_configs
+[0m[33m[0.045ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:295 [35;1mno such table: security_rule_sets
+[0m[33m[0.081ms] [34;1m[rows:0][0m SELECT * FROM `security_rule_sets`
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:302 [35;1mno such table: security_decisions
+[0m[33m[0.037ms] [34;1m[rows:0][0m SELECT * FROM `security_decisions` ORDER BY created_at desc
+--- PASS: TestCrowdsecHandler_BanIP_EmptyIP (0.01s)
+=== CONT TestCrowdsecHandler_ListDecisions_InvalidJSON
+--- PASS: TestCrowdsecHandler_BanIP_MissingIP (0.01s)
+=== CONT TestCrowdsecHandler_BanIP_Success
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/services/proxyhost_service.go:117 [35;1mrecord not found
+[0m[33m[0.159ms] [34;1m[rows:0][0m SELECT * FROM `proxy_hosts` WHERE uuid = "non-existent-uuid" ORDER BY `proxy_hosts`.`id` LIMIT 1
+--- PASS: TestCrowdsecHandler_ListDecisions_InvalidJSON (0.01s)
+=== CONT TestCrowdsecHandler_ListDecisions_Empty
+=== CONT TestCrowdsecHandler_ListDecisions_Success
+--- PASS: TestCrowdsecHandler_ListDecisions_Empty (0.01s)
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:239 [35;1mrecord not found
+[0m[33m[0.740ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.acme_email" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:246 [35;1mrecord not found
+[0m[33m[0.082ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "caddy.ssl_provider" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestCrowdsecHandler_BanIP_Success (0.01s)
+=== CONT TestCrowdsecHandler_ReadFile_MissingPath
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:598 [35;1mno such table: security_configs
+[0m[33m[0.082ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:627 [35;1mrecord not found
+[0m[33m[0.076ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:629 [35;1mrecord not found
+[0m[33m[0.104ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:634 [35;1mrecord not found
+[0m[33m[0.110ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.acl.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:285 [35;1mno such table: security_configs
+[0m[33m[0.057ms] [34;1m[rows:0][0m SELECT * FROM `security_configs` WHERE name = "default" ORDER BY `security_configs`.`id` LIMIT 1
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:295 [35;1mno such table: security_rule_sets
+[0m[33m[0.063ms] [34;1m[rows:0][0m SELECT * FROM `security_rule_sets`
+
+2026/01/10 02:24:30 [31;1m/projects/Charon/backend/internal/caddy/manager.go:302 [35;1mno such table: security_decisions
+[0m[33m[0.069ms] [34;1m[rows:0][0m SELECT * FROM `security_decisions` ORDER BY created_at desc
+--- PASS: TestCrowdsecHandler_ListDecisions_Success (0.01s)
+=== CONT TestCrowdsecHandler_ListDecisions_CscliError
+--- PASS: TestCrowdsecHandler_ReadFile_MissingPath (0.01s)
+--- PASS: TestCrowdsecHandler_ListDecisions_CscliError (0.00s)
+=== CONT TestCrowdsecHandler_Start_ExecutorError
+=== CONT TestCrowdsecHandler_ExportConfig_DirNotFound
+--- PASS: TestCrowdsecHandler_ExportConfig_DirNotFound (0.01s)
+=== CONT TestCrowdsecHandler_ReadFile_NotFound
+--- PASS: TestProxyHostErrors (0.20s)
+=== CONT TestCrowdsecStart_LAPINotReadyTimeout
+--- PASS: TestCrowdsecHandler_ReadFile_NotFound (0.00s)
+=== CONT TestCrowdsecHandler_Status_Error
+--- PASS: TestCrowdsecHandler_Start_ExecutorError (0.01s)
+=== CONT TestGetAcquisitionConfigNotFound
+--- PASS: TestGetAcquisitionConfigNotFound (0.00s)
+=== CONT TestRegisterBouncerExecutionError
+--- PASS: TestCrowdsecHandler_Status_Error (0.00s)
+=== CONT TestGetAcquisitionConfigSuccess
+--- PASS: TestRegisterBouncerExecutionError (0.00s)
+=== CONT TestRegisterBouncerScriptNotFound
+--- PASS: TestGetAcquisitionConfigSuccess (0.00s)
+=== CONT TestRegisterBouncerSuccess
+--- PASS: TestRegisterBouncerSuccess (0.00s)
+=== CONT TestIsConsoleEnrollmentDisabledFromDB
+--- PASS: TestRegisterBouncerScriptNotFound (0.00s)
+=== CONT TestIsConsoleEnrollmentEnabledFromDB
+--- PASS: TestIsConsoleEnrollmentDisabledFromDB (0.01s)
+=== CONT TestIsCerberusEnabledFromDB
+--- PASS: TestIsConsoleEnrollmentEnabledFromDB (0.01s)
+=== CONT TestListFilesMissingDir
+--- PASS: TestListFilesMissingDir (0.00s)
+=== CONT TestImportConfigRejectsEmptyUpload
+=== CONT TestListFilesReturnsEntries
+--- PASS: TestImportConfigRejectsEmptyUpload (0.00s)
+=== CONT TestWriteFileInvalidPayload
+--- PASS: TestWriteFileInvalidPayload (0.00s)
+=== CONT TestCrowdsecEndpoints
+--- PASS: TestIsCerberusEnabledFromDB (0.00s)
+--- PASS: TestListFilesReturnsEntries (0.00s)
+=== CONT TestCerberusLogsHandler_UpgradeFailure
+--- PASS: TestCerberusLogsHandler_UpgradeFailure (0.00s)
+=== CONT TestCerberusLogsHandler_MultipleClients
+--- PASS: TestCerberusLogsHandler_MultipleClients (0.40s)
+=== CONT TestImportConfig
+--- PASS: TestImportConfig (0.00s)
+=== CONT TestCerberusLogsHandler_ClientDisconnect
+--- PASS: TestCerberusLogsHandler_ClientDisconnect (0.10s)
+=== CONT TestCerberusLogsHandler_IPFilter
+--- PASS: TestAuthHandler_Login (1.84s)
+=== CONT TestCerberusLogsHandler_SourceFilter
+--- PASS: TestCerberusLogsHandler_IPFilter (0.30s)
+=== CONT TestCerberusLogsHandler_BlockedOnlyFilter
+=== CONT TestCerberusLogsHandler_ReceiveLogEntries
+--- PASS: TestCerberusLogsHandler_SourceFilter (0.30s)
+--- PASS: TestCerberusLogsHandler_BlockedOnlyFilter (0.30s)
+=== CONT TestCerberusLogsHandler_NewHandler
+--- PASS: TestCerberusLogsHandler_NewHandler (0.00s)
+=== CONT TestAuthHandler_CheckHostAccess_Denied
+--- PASS: TestAuthHandler_CheckHostAccess_Denied (0.02s)
+=== CONT TestAuthHandler_CheckHostAccess_Allowed
+--- PASS: TestCerberusLogsHandler_ReceiveLogEntries (0.30s)
+=== CONT TestCerberusLogsHandler_SuccessfulConnection
+--- PASS: TestCerberusLogsHandler_SuccessfulConnection (0.00s)
+=== CONT TestAuthHandler_CheckHostAccess_Unauthorized
+--- PASS: TestAuthHandler_CheckHostAccess_Allowed (0.02s)
+=== CONT TestWriteFileMissingPath
+--- PASS: TestWriteFileMissingPath (0.00s)
+=== CONT TestImportConfigRequiresFile
+--- PASS: TestImportConfigRequiresFile (0.00s)
+=== CONT TestWriteFileInvalidPath
+--- PASS: TestWriteFileInvalidPath (0.00s)
+=== CONT TestReadFileInvalidPath
+--- PASS: TestReadFileInvalidPath (0.00s)
+=== CONT TestWriteFileCreatesBackup
+--- PASS: TestAuthHandler_CheckHostAccess_Unauthorized (0.02s)
+=== CONT TestAuthHandler_GetAccessibleHosts_UserNotFound
+--- PASS: TestWriteFileCreatesBackup (0.00s)
+=== CONT TestAuthHandler_GetAccessibleHosts_PermittedHosts
+
+2026/01/10 02:24:31 [31;1m/projects/Charon/backend/internal/api/handlers/auth_handler.go:334 [35;1mrecord not found
+[0m[33m[0.106ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE `users`.`id` = 99999 ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestAuthHandler_GetAccessibleHosts_UserNotFound (0.02s)
+=== CONT TestAuthHandler_GetAccessibleHosts_DenyAll
+--- PASS: TestAuthHandler_GetAccessibleHosts_PermittedHosts (0.03s)
+=== CONT TestAuthHandler_GetAccessibleHosts_AllowAll
+--- PASS: TestAuthHandler_GetAccessibleHosts_DenyAll (0.02s)
+=== CONT TestAuthHandler_GetAccessibleHosts_Unauthorized
+--- PASS: TestAuthHandler_GetAccessibleHosts_AllowAll (0.02s)
+=== CONT TestAuthHandler_VerifyStatus_DisabledUser
+--- PASS: TestAuthHandler_GetAccessibleHosts_Unauthorized (0.02s)
+=== CONT TestAuthHandler_VerifyStatus_Authenticated
+--- PASS: TestAuthHandler_VerifyStatus_Authenticated (0.73s)
+=== CONT TestAuthHandler_VerifyStatus_InvalidToken
+--- PASS: TestAuthHandler_VerifyStatus_DisabledUser (0.75s)
+=== CONT TestAuthHandler_CheckHostAccess_InvalidHostID
+--- PASS: TestAuthHandler_VerifyStatus_InvalidToken (0.02s)
+=== CONT TestAuthHandler_VerifyStatus_NotAuthenticated
+--- PASS: TestAuthHandler_CheckHostAccess_InvalidHostID (0.02s)
+=== CONT TestAuthHandler_Verify_ForwardAuthDenied
+--- PASS: TestAuthHandler_VerifyStatus_NotAuthenticated (0.03s)
+=== CONT TestAuthHandler_Verify_DisabledUser
+--- PASS: TestAuthHandler_Verify_ForwardAuthDenied (0.75s)
+=== CONT TestAuthHandler_Verify_ValidToken
+--- PASS: TestAuthHandler_Verify_DisabledUser (0.77s)
+=== CONT TestAuthHandler_Verify_InvalidToken
+--- PASS: TestAuthHandler_Verify_InvalidToken (0.02s)
+=== CONT TestAuthHandler_Verify_BearerToken
+--- PASS: TestAuthHandler_Verify_ValidToken (0.75s)
+=== CONT TestNewAuthHandlerWithDB
+--- PASS: TestNewAuthHandlerWithDB (0.01s)
+=== CONT TestAuthHandler_Verify_NoCookie
+--- PASS: TestAuthHandler_Verify_NoCookie (0.02s)
+=== CONT TestAuthHandler_ChangePassword_Errors
+--- PASS: TestAuthHandler_ChangePassword_Errors (0.02s)
+=== CONT TestAuthHandler_ChangePassword_WrongOld
+--- PASS: TestAuthHandler_Verify_BearerToken (0.75s)
+=== CONT TestAuthHandler_ChangePassword
+--- PASS: TestAuthHandler_ChangePassword_WrongOld (1.71s)
+=== CONT TestAuthHandler_Me
+--- PASS: TestAuthHandler_Me (0.03s)
+=== CONT TestAuthHandler_Me_NotFound
+
+2026/01/10 02:24:35 [31;1m/projects/Charon/backend/internal/services/auth_service.go:147 [35;1mrecord not found
+[0m[33m[0.110ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE `users`.`id` = 999 ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestAuthHandler_Me_NotFound (0.02s)
+=== CONT TestAuthHandler_Logout
+--- PASS: TestAuthHandler_Logout (0.02s)
+=== CONT TestAuthHandler_Register
+--- PASS: TestAuthHandler_Register (0.78s)
+=== CONT TestAuthHandler_Login_Errors
+
+2026/01/10 02:24:36 [31;1m/projects/Charon/backend/internal/services/auth_service.go:64 [35;1mrecord not found
+[0m[33m[0.126ms] [34;1m[rows:0][0m SELECT * FROM `users` WHERE email = "nonexistent@example.com" ORDER BY `users`.`id` LIMIT 1
+--- PASS: TestAuthHandler_Login_Errors (0.02s)
+=== CONT TestAuthHandler_Register_Duplicate
+--- PASS: TestAuthHandler_ChangePassword (3.20s)
+=== CONT TestSetSecureCookie_HTTP_Lax
+--- PASS: TestSetSecureCookie_HTTP_Lax (0.00s)
+=== CONT TestOpenTestDB_ParallelSafety/parallel-3
+=== CONT TestOpenTestDB_ParallelSafety/parallel-4
+=== CONT TestOpenTestDB_ParallelSafety/parallel-2
+=== CONT TestOpenTestDB_ParallelSafety/parallel-1
+=== CONT TestOpenTestDB_ParallelSafety/parallel-0
+--- PASS: TestOpenTestDB_ParallelSafety (0.00s)
+ --- PASS: TestOpenTestDB_ParallelSafety/parallel-3 (0.00s)
+ --- PASS: TestOpenTestDB_ParallelSafety/parallel-4 (0.00s)
+ --- PASS: TestOpenTestDB_ParallelSafety/parallel-2 (0.00s)
+ --- PASS: TestOpenTestDB_ParallelSafety/parallel-1 (0.00s)
+ --- PASS: TestOpenTestDB_ParallelSafety/parallel-0 (0.00s)
+=== CONT TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/boolean_false
+=== CONT TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/array
+=== CONT TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/object
+=== CONT TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/boolean_true
+--- PASS: TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType (0.04s)
+ --- PASS: TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/boolean_false (0.00s)
+ --- PASS: TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/array (0.00s)
+ --- PASS: TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/object (0.00s)
+ --- PASS: TestProxyHostUpdate_SecurityHeaderProfileID_UnsupportedType/boolean_true (0.00s)
+
+2026/01/10 02:24:37 [31;1m/projects/Charon/backend/internal/services/auth_service.go:54 [35;1mUNIQUE constraint failed: users.email
+[0m[33m[0.517ms] [34;1m[rows:0][0m INSERT INTO `users` (`uuid`,`email`,`api_key`,`password_hash`,`name`,`role`,`enabled`,`failed_login_attempts`,`locked_until`,`last_login`,`invite_token`,`invite_expires`,`invited_at`,`invited_by`,`invite_status`,`permission_mode`,`created_at`,`updated_at`) VALUES ("6fce0af7-2cd7-43c4-bd3c-4b55b59b90f9","dup@example.com","a727f701-f3cc-478a-b4ce-b0e4725a470f","$2a$10$wfJbDIjJM9wSS4ZzXClUTe1qVO5jZMtW9QpArDQ09rMPsAnaa/S5S","Dup User","user",true,0,NULL,NULL,"",NULL,NULL,NULL,"","allow_all","2026-01-10 02:24:36.614","2026-01-10 02:24:36.614") RETURNING `id`
+--- PASS: TestAuthHandler_Register_Duplicate (0.76s)
+--- PASS: TestCrowdsecStart_LAPINotReadyTimeout (60.12s)
+--- PASS: TestCrowdsecEndpoints (60.14s)
+FAIL
+coverage: 86.9% of statements
+FAIL github.com/Wikid82/charon/backend/internal/api/handlers 474.816s
+=== RUN TestAuthMiddleware_MissingHeader
+--- PASS: TestAuthMiddleware_MissingHeader (0.00s)
+=== RUN TestRequireRole_Success
+--- PASS: TestRequireRole_Success (0.00s)
+=== RUN TestRequireRole_Forbidden
+--- PASS: TestRequireRole_Forbidden (0.00s)
+=== RUN TestAuthMiddleware_Cookie
+--- PASS: TestAuthMiddleware_Cookie (1.22s)
+=== RUN TestAuthMiddleware_ValidToken
+--- PASS: TestAuthMiddleware_ValidToken (0.85s)
+=== RUN TestAuthMiddleware_PrefersAuthorizationHeader
+--- PASS: TestAuthMiddleware_PrefersAuthorizationHeader (0.82s)
+=== RUN TestAuthMiddleware_InvalidToken
+--- PASS: TestAuthMiddleware_InvalidToken (0.03s)
+=== RUN TestRequireRole_MissingRoleInContext
+--- PASS: TestRequireRole_MissingRoleInContext (0.00s)
+=== RUN TestAuthMiddleware_QueryParamFallback
+--- PASS: TestAuthMiddleware_QueryParamFallback (0.87s)
+=== RUN TestAuthMiddleware_PrefersCookieOverQueryParam
+--- PASS: TestAuthMiddleware_PrefersCookieOverQueryParam (1.64s)
+=== RUN TestRecoveryLogsStacktraceVerbose
+--- PASS: TestRecoveryLogsStacktraceVerbose (0.00s)
+=== RUN TestRecoveryLogsBriefWhenNotVerbose
+--- PASS: TestRecoveryLogsBriefWhenNotVerbose (0.00s)
+=== RUN TestRecoveryDoesNotLogSensitiveHeaders
+--- PASS: TestRecoveryDoesNotLogSensitiveHeaders (0.00s)
+=== RUN TestRecoveryTruncatesLongPanicMessage
+--- PASS: TestRecoveryTruncatesLongPanicMessage (0.00s)
+=== RUN TestRecoveryNoPanicNormalFlow
+--- PASS: TestRecoveryNoPanicNormalFlow (0.00s)
+=== RUN TestRecoveryPanicWithNilValue
+--- PASS: TestRecoveryPanicWithNilValue (0.00s)
+=== RUN TestRequestIDAddsHeaderAndLogger
+--- PASS: TestRequestIDAddsHeaderAndLogger (0.00s)
+=== RUN TestRequestLoggerSanitizesPath
+--- PASS: TestRequestLoggerSanitizesPath (0.00s)
+=== RUN TestRequestLoggerIncludesRequestID
+--- PASS: TestRequestLoggerIncludesRequestID (0.00s)
+=== RUN TestSanitizeHeaders
+=== RUN TestSanitizeHeaders/nil_headers
+=== RUN TestSanitizeHeaders/redacts_sensitive_headers
+=== RUN TestSanitizeHeaders/sanitizes_and_truncates_values
+--- PASS: TestSanitizeHeaders (0.00s)
+ --- PASS: TestSanitizeHeaders/nil_headers (0.00s)
+ --- PASS: TestSanitizeHeaders/redacts_sensitive_headers (0.00s)
+ --- PASS: TestSanitizeHeaders/sanitizes_and_truncates_values (0.00s)
+=== RUN TestSanitizePath
+--- PASS: TestSanitizePath (0.00s)
+=== RUN TestSecurityHeaders
+=== RUN TestSecurityHeaders/production_mode_sets_HSTS
+=== RUN TestSecurityHeaders/development_mode_skips_HSTS
+=== RUN TestSecurityHeaders/sets_X-Frame-Options
+=== RUN TestSecurityHeaders/sets_X-Content-Type-Options
+=== RUN TestSecurityHeaders/sets_X-XSS-Protection
+=== RUN TestSecurityHeaders/sets_Referrer-Policy
+=== RUN TestSecurityHeaders/sets_Content-Security-Policy
+=== RUN TestSecurityHeaders/development_mode_CSP_allows_unsafe-eval
+=== RUN TestSecurityHeaders/sets_Permissions-Policy
+=== RUN TestSecurityHeaders/sets_Cross-Origin-Opener-Policy_in_production
+=== RUN TestSecurityHeaders/skips_Cross-Origin-Opener-Policy_in_development
+=== RUN TestSecurityHeaders/sets_Cross-Origin-Resource-Policy
+--- PASS: TestSecurityHeaders (0.00s)
+ --- PASS: TestSecurityHeaders/production_mode_sets_HSTS (0.00s)
+ --- PASS: TestSecurityHeaders/development_mode_skips_HSTS (0.00s)
+ --- PASS: TestSecurityHeaders/sets_X-Frame-Options (0.00s)
+ --- PASS: TestSecurityHeaders/sets_X-Content-Type-Options (0.00s)
+ --- PASS: TestSecurityHeaders/sets_X-XSS-Protection (0.00s)
+ --- PASS: TestSecurityHeaders/sets_Referrer-Policy (0.00s)
+ --- PASS: TestSecurityHeaders/sets_Content-Security-Policy (0.00s)
+ --- PASS: TestSecurityHeaders/development_mode_CSP_allows_unsafe-eval (0.00s)
+ --- PASS: TestSecurityHeaders/sets_Permissions-Policy (0.00s)
+ --- PASS: TestSecurityHeaders/sets_Cross-Origin-Opener-Policy_in_production (0.00s)
+ --- PASS: TestSecurityHeaders/skips_Cross-Origin-Opener-Policy_in_development (0.00s)
+ --- PASS: TestSecurityHeaders/sets_Cross-Origin-Resource-Policy (0.00s)
+=== RUN TestSecurityHeadersCustomCSP
+--- PASS: TestSecurityHeadersCustomCSP (0.00s)
+=== RUN TestDefaultSecurityHeadersConfig
+--- PASS: TestDefaultSecurityHeadersConfig (0.00s)
+=== RUN TestSecurityHeaders_COOP_DevelopmentMode
+--- PASS: TestSecurityHeaders_COOP_DevelopmentMode (0.00s)
+=== RUN TestSecurityHeaders_COOP_ProductionMode
+--- PASS: TestSecurityHeaders_COOP_ProductionMode (0.00s)
+=== RUN TestBuildCSP
+=== RUN TestBuildCSP/production_CSP
+=== RUN TestBuildCSP/development_CSP
+--- PASS: TestBuildCSP (0.00s)
+ --- PASS: TestBuildCSP/production_CSP (0.00s)
+ --- PASS: TestBuildCSP/development_CSP (0.00s)
+=== RUN TestBuildPermissionsPolicy
+--- PASS: TestBuildPermissionsPolicy (0.00s)
+PASS
+coverage: 99.1% of statements
+ok github.com/Wikid82/charon/backend/internal/api/middleware (cached) coverage: 99.1% of statements
+=== RUN TestRegister
+time="2026-01-10T02:16:51Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:51Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:51Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+
+2026/01/10 02:16:51 [31;1m/projects/Charon/backend/internal/services/security_headers_service.go:116 [35;1mrecord not found
+[0m[33m[0.131ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE uuid = "preset-basic" ORDER BY `security_header_profiles`.`id` LIMIT 1
+
+2026/01/10 02:16:51 [31;1m/projects/Charon/backend/internal/services/security_headers_service.go:116 [35;1mrecord not found
+[0m[33m[0.138ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE uuid = "preset-api-friendly" ORDER BY `security_header_profiles`.`id` LIMIT 1
+
+2026/01/10 02:16:51 [31;1m/projects/Charon/backend/internal/services/security_headers_service.go:116 [35;1mrecord not found
+[0m[33m[0.123ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE uuid = "preset-strict" ORDER BY `security_header_profiles`.`id` LIMIT 1
+
+2026/01/10 02:16:51 [31;1m/projects/Charon/backend/internal/services/security_headers_service.go:116 [35;1mrecord not found
+[0m[33m[0.164ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE uuid = "preset-paranoid" ORDER BY `security_header_profiles`.`id` LIMIT 1
+time="2026-01-10T02:16:51Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:51Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:51Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+--- PASS: TestRegister (0.13s)
+=== RUN TestRegister_WithDevelopmentEnvironment
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:51Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:51Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:51Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:51Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:51Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:51Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+--- PASS: TestRegister_WithDevelopmentEnvironment (0.48s)
+=== RUN TestRegister_WithProductionEnvironment
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:51Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:51Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:51Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:51Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:51Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:51Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+--- PASS: TestRegister_WithProductionEnvironment (0.31s)
+=== RUN TestRegister_AutoMigrateFailure
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: disk sync complete" count=0
+
+2026/01/10 02:16:51 [31;1m/projects/Charon/backend/internal/api/routes/routes.go:42 [35;1msql: database is closed
+[0m[33m[0.005ms] [34;1m[rows:0][0m CREATE TABLE `ssl_certificates` (`id` integer PRIMARY KEY AUTOINCREMENT,`uuid` text,`name` text,`provider` text,`domains` text,`certificate` text,`private_key` text,`expires_at` datetime,`auto_renew` numeric DEFAULT false,`created_at` datetime,`updated_at` datetime)
+--- PASS: TestRegister_AutoMigrateFailure (0.04s)
+=== RUN TestRegisterImportHandler
+--- PASS: TestRegisterImportHandler (0.00s)
+=== RUN TestRegister_RoutesRegistration
+time="2026-01-10T02:16:52Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:52Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:52Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:52Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:52Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:52Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegister_RoutesRegistration (0.27s)
+=== RUN TestRegister_ProxyHostsRequireAuth
+time="2026-01-10T02:16:52Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:52Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:52Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:52Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:52Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:52Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+
+2026/01/10 02:16:52 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.099ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:52 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.062ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegister_ProxyHostsRequireAuth (0.17s)
+=== RUN TestRegister_DNSProviders_NotRegisteredWhenEncryptionKeyMissing
+time="2026-01-10T02:16:52Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:52Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:52Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:52Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:52Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:52Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+--- PASS: TestRegister_DNSProviders_NotRegisteredWhenEncryptionKeyMissing (0.15s)
+=== RUN TestRegister_DNSProviders_NotRegisteredWhenEncryptionKeyInvalid
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:52Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:52Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:52Z" level=error msg="Failed to initialize encryption service - DNS provider features will be unavailable" error="invalid base64 key: illegal base64 data at input byte 3"
+time="2026-01-10T02:16:52Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:52Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:52Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+--- PASS: TestRegister_DNSProviders_NotRegisteredWhenEncryptionKeyInvalid (0.18s)
+=== RUN TestRegister_DNSProviders_RegisteredWhenEncryptionKeyValid
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:52Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:52Z" level=info msg="Backup service cron scheduler started"
+Warning: RotationService initialization failed, using basic encryption: CHARON_ENCRYPTION_KEY is required
+Warning: RotationService initialization failed, using basic encryption: CHARON_ENCRYPTION_KEY is required
+time="2026-01-10T02:16:52Z" level=warning msg="Failed to initialize rotation service - key rotation features will be unavailable" error="CHARON_ENCRYPTION_KEY is required"
+time="2026-01-10T02:16:52Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:52Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:52Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+--- PASS: TestRegister_DNSProviders_RegisteredWhenEncryptionKeyValid (0.19s)
+=== RUN TestRegister_AllRoutesRegistered
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:52Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:53Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:53Z" level=info msg="Backup service cron scheduler started"
+Warning: RotationService initialization failed, using basic encryption: CHARON_ENCRYPTION_KEY is required
+Warning: RotationService initialization failed, using basic encryption: CHARON_ENCRYPTION_KEY is required
+time="2026-01-10T02:16:53Z" level=warning msg="Failed to initialize rotation service - key rotation features will be unavailable" error="CHARON_ENCRYPTION_KEY is required"
+time="2026-01-10T02:16:53Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:53Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:53Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegister_AllRoutesRegistered (0.17s)
+=== RUN TestRegister_MiddlewareApplied
+time="2026-01-10T02:16:53Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:53Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:53Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:53Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:53Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:53Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegister_MiddlewareApplied (0.18s)
+=== RUN TestRegister_AuthenticatedRoutes
+time="2026-01-10T02:16:53Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:53Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:53Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:53Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:53Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:53Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+=== RUN TestRegister_AuthenticatedRoutes/GET_/api/v1/backups
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.172ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.086ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+=== RUN TestRegister_AuthenticatedRoutes/POST_/api/v1/backups
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.269ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.094ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+=== RUN TestRegister_AuthenticatedRoutes/GET_/api/v1/logs
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.110ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: disk sync complete" count=0
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.531ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+=== RUN TestRegister_AuthenticatedRoutes/GET_/api/v1/settings
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.170ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.098ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+=== RUN TestRegister_AuthenticatedRoutes/GET_/api/v1/notifications
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.137ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.080ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+=== RUN TestRegister_AuthenticatedRoutes/GET_/api/v1/users
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.089ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.059ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+=== RUN TestRegister_AuthenticatedRoutes/GET_/api/v1/auth/me
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.094ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.076ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+=== RUN TestRegister_AuthenticatedRoutes/POST_/api/v1/auth/logout
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.086ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.067ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+=== RUN TestRegister_AuthenticatedRoutes/GET_/api/v1/uptime/monitors
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.104ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.062ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestRegister_AuthenticatedRoutes (0.20s)
+ --- PASS: TestRegister_AuthenticatedRoutes/GET_/api/v1/backups (0.00s)
+ --- PASS: TestRegister_AuthenticatedRoutes/POST_/api/v1/backups (0.00s)
+ --- PASS: TestRegister_AuthenticatedRoutes/GET_/api/v1/logs (0.00s)
+ --- PASS: TestRegister_AuthenticatedRoutes/GET_/api/v1/settings (0.00s)
+ --- PASS: TestRegister_AuthenticatedRoutes/GET_/api/v1/notifications (0.00s)
+ --- PASS: TestRegister_AuthenticatedRoutes/GET_/api/v1/users (0.00s)
+ --- PASS: TestRegister_AuthenticatedRoutes/GET_/api/v1/auth/me (0.00s)
+ --- PASS: TestRegister_AuthenticatedRoutes/POST_/api/v1/auth/logout (0.00s)
+ --- PASS: TestRegister_AuthenticatedRoutes/GET_/api/v1/uptime/monitors (0.00s)
+=== RUN TestRegister_AdminRoutes
+time="2026-01-10T02:16:53Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:53Z" level=info msg="Backup service cron scheduler started"
+Warning: RotationService initialization failed, using basic encryption: CHARON_ENCRYPTION_KEY is required
+Warning: RotationService initialization failed, using basic encryption: CHARON_ENCRYPTION_KEY is required
+time="2026-01-10T02:16:53Z" level=warning msg="Failed to initialize rotation service - key rotation features will be unavailable" error="CHARON_ENCRYPTION_KEY is required"
+time="2026-01-10T02:16:53Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:53Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:53Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.190ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.096ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.086ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: disk sync complete" count=0
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.120ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestRegister_AdminRoutes (0.17s)
+=== RUN TestRegister_PublicRoutes
+time="2026-01-10T02:16:53Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:53Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:53Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:53Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:53Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:53Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+=== RUN TestRegister_PublicRoutes/GET_/api/v1/health
+=== RUN TestRegister_PublicRoutes/GET_/metrics
+=== RUN TestRegister_PublicRoutes/GET_/api/v1/setup
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.312ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.098ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+=== RUN TestRegister_PublicRoutes/GET_/api/v1/auth/status
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.188ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+
+2026/01/10 02:16:53 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.359ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestRegister_PublicRoutes (0.20s)
+ --- PASS: TestRegister_PublicRoutes/GET_/api/v1/health (0.00s)
+ --- PASS: TestRegister_PublicRoutes/GET_/metrics (0.00s)
+ --- PASS: TestRegister_PublicRoutes/GET_/api/v1/setup (0.00s)
+ --- PASS: TestRegister_PublicRoutes/GET_/api/v1/auth/status (0.00s)
+=== RUN TestRegister_HealthEndpoint
+time="2026-01-10T02:16:53Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:54Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:54Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:54Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:54Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:54Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:54Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+--- PASS: TestRegister_HealthEndpoint (0.21s)
+=== RUN TestRegister_MetricsEndpoint
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:54Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:54Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:54Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:54Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:54Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:54Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegister_MetricsEndpoint (0.19s)
+=== RUN TestRegister_DBHealthEndpoint
+time="2026-01-10T02:16:54Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:54Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:54Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:54Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:54Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:54Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegister_DBHealthEndpoint (0.18s)
+=== RUN TestRegister_LoginEndpoint
+time="2026-01-10T02:16:54Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:54Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:54Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:54Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:54Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:54Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+
+2026/01/10 02:16:54 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.237ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: disk sync complete" count=0
+
+2026/01/10 02:16:54 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.640ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestRegister_LoginEndpoint (0.21s)
+=== RUN TestRegister_SetupEndpoint
+time="2026-01-10T02:16:54Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:54Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:54Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:54Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:54Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:54Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+
+2026/01/10 02:16:54 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.124ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:54 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.149ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestRegister_SetupEndpoint (0.22s)
+time="2026-01-10T02:16:54Z" level=info msg="CertificateService: disk sync complete" count=0
+=== RUN TestRegister_WithEncryptionRoutes
+time="2026-01-10T02:16:55Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:55Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:55Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:55Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:55Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+--- PASS: TestRegister_WithEncryptionRoutes (0.21s)
+=== RUN TestRegister_UptimeCheckEndpoint
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:55Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:55Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:55Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:55Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:55Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:55Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+
+2026/01/10 02:16:55 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.092ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:55 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.494ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegister_UptimeCheckEndpoint (0.17s)
+=== RUN TestRegister_CrowdSecRoutes
+time="2026-01-10T02:16:55Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:55Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:55Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:55Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:55Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:55Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+--- PASS: TestRegister_CrowdSecRoutes (0.19s)
+=== RUN TestRegister_SecurityRoutes
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:55Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:55Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:55Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:55Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:55Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:55Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+--- PASS: TestRegister_SecurityRoutes (0.18s)
+=== RUN TestRegister_AccessListRoutes
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:55Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:55Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:55Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:55Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:55Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:55Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+--- PASS: TestRegister_AccessListRoutes (0.17s)
+=== RUN TestRegister_CertificateRoutes
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:55Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:55Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:55Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:55Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:55Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:55Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+--- PASS: TestRegister_CertificateRoutes (0.17s)
+=== RUN TestRegister_NilHandlers
+time="2026-01-10T02:16:55Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:56Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:56Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:56Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:56Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:56Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:56Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegister_NilHandlers (0.20s)
+=== RUN TestRegister_MiddlewareOrder
+time="2026-01-10T02:16:56Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:56Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:56Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:56Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:56Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:56Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+--- PASS: TestRegister_MiddlewareOrder (0.17s)
+=== RUN TestRegister_GzipCompression
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:56Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:56Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:56Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:56Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:56Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:56Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegister_GzipCompression (0.20s)
+=== RUN TestRegister_CerberusMiddleware
+time="2026-01-10T02:16:56Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:56Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:56Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:56Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:56Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:56Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+--- PASS: TestRegister_CerberusMiddleware (0.17s)
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+=== RUN TestRegister_FeatureFlagsEndpoint
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:56Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:56Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:56Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:56Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:56Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:56Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+
+2026/01/10 02:16:56 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.094ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:56 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.074ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestRegister_FeatureFlagsEndpoint (0.23s)
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:56Z" level=info msg="CertificateService: disk sync complete" count=0
+=== RUN TestRegister_WebSocketRoutes
+time="2026-01-10T02:16:57Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:57Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:57Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:57Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:57Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:57Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+--- PASS: TestRegister_WebSocketRoutes (0.19s)
+=== RUN TestRegister_NotificationRoutes
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:57Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:57Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:57Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:57Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:57Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:57Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+--- PASS: TestRegister_NotificationRoutes (0.18s)
+=== RUN TestRegister_DomainRoutes
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:57Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:57Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:57Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:57Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:57Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:57Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegister_DomainRoutes (0.20s)
+=== RUN TestRegister_VerifyAuthEndpoint
+time="2026-01-10T02:16:57Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:57Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:57Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:57Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:57Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:57Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+
+2026/01/10 02:16:57 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:57 [35;1mrecord not found
+[0m[33m[0.165ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "feature.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+
+2026/01/10 02:16:57 [31;1m/projects/Charon/backend/internal/cerberus/cerberus.go:61 [35;1mrecord not found
+[0m[33m[0.115ms] [34;1m[rows:0][0m SELECT * FROM `settings` WHERE key = "security.cerberus.enabled" ORDER BY `settings`.`id` LIMIT 1
+--- PASS: TestRegister_VerifyAuthEndpoint (0.21s)
+=== RUN TestRegister_SMTPRoutes
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:57Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:57Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:57Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:57Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:57Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:57Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+--- PASS: TestRegister_SMTPRoutes (0.23s)
+=== RUN TestRegisterImportHandler_RoutesExist
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:57Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegisterImportHandler_RoutesExist (0.00s)
+=== RUN TestRegister_EncryptionRoutesWithValidKey
+time="2026-01-10T02:16:58Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:58Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:58Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:58Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:58Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:58Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:58Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:58Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegister_EncryptionRoutesWithValidKey (0.26s)
+=== RUN TestRegister_WAFExclusionRoutes
+time="2026-01-10T02:16:58Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:58Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:58Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:58Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:58Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:58Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+--- PASS: TestRegister_WAFExclusionRoutes (0.18s)
+=== RUN TestRegister_BreakGlassRoute
+time="2026-01-10T02:16:58Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:58Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:58Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:58Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:58Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:58Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:58Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:58Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:58Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:58Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:58Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:58Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegister_BreakGlassRoute (0.20s)
+=== RUN TestRegister_RateLimitPresetsRoute
+time="2026-01-10T02:16:58Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:58Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:58Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:58Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:58Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:58Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=/data
+time="2026-01-10T02:16:58Z" level=info msg="CertificateService: scanning cert directory" certRoot=/data/certificates
+time="2026-01-10T02:16:58Z" level=info msg="CertificateService: cert directory does not exist" certRoot=/data/certificates
+time="2026-01-10T02:16:58Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestRegister_RateLimitPresetsRoute (0.16s)
+=== RUN TestRegisterImportHandler
+--- PASS: TestRegisterImportHandler (0.02s)
+PASS
+coverage: 87.1% of statements
+ok github.com/Wikid82/charon/backend/internal/api/routes (cached) coverage: 87.1% of statements
+=== RUN TestIntegration_WAF_BlockAndMonitor
+time="2026-01-10T02:16:51Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:51Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:51Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+
+2026/01/10 02:16:51 [31;1m/projects/Charon/backend/internal/services/security_headers_service.go:116 [35;1mrecord not found
+[0m[33m[0.091ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE uuid = "preset-basic" ORDER BY `security_header_profiles`.`id` LIMIT 1
+
+2026/01/10 02:16:51 [31;1m/projects/Charon/backend/internal/services/security_headers_service.go:116 [35;1mrecord not found
+[0m[33m[0.134ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE uuid = "preset-api-friendly" ORDER BY `security_header_profiles`.`id` LIMIT 1
+
+2026/01/10 02:16:51 [31;1m/projects/Charon/backend/internal/services/security_headers_service.go:116 [35;1mrecord not found
+[0m[33m[0.127ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE uuid = "preset-strict" ORDER BY `security_header_profiles`.`id` LIMIT 1
+
+2026/01/10 02:16:51 [31;1m/projects/Charon/backend/internal/services/security_headers_service.go:116 [35;1mrecord not found
+[0m[33m[0.094ms] [34;1m[rows:0][0m SELECT * FROM `security_header_profiles` WHERE uuid = "preset-paranoid" ORDER BY `security_header_profiles`.`id` LIMIT 1
+time="2026-01-10T02:16:51Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:51Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:51Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=data/caddy/data
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: scanning cert directory" certRoot=data/caddy/data/certificates
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: cert directory does not exist" certRoot=data/caddy/data/certificates
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: disk sync complete" count=0
+time="2026-01-10T02:16:51Z" level=info msg="Cleaning up invalid Let's Encrypt certificate associations..."
+time="2026-01-10T02:16:51Z" level=info msg="Backup service cron scheduler started"
+time="2026-01-10T02:16:51Z" level=warning msg="CHARON_ENCRYPTION_KEY not set - DNS provider and plugin features will be unavailable"
+time="2026-01-10T02:16:51Z" level=info msg="GeoIP database not found - geo-blocking features will be unavailable" path=/app/data/geoip/GeoLite2-Country.mmdb
+time="2026-01-10T02:16:51Z" level=info msg="LogWatcher started" path=/var/log/caddy/access.log
+time="2026-01-10T02:16:51Z" level=info msg="Using Caddy data directory for certificates scan" caddy_data_dir=data/caddy/data
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: scanning cert directory" certRoot=data/caddy/data/certificates
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: cert directory does not exist" certRoot=data/caddy/data/certificates
+time="2026-01-10T02:16:51Z" level=info msg="CertificateService: disk sync complete" count=0
+--- PASS: TestIntegration_WAF_BlockAndMonitor (0.55s)
+=== RUN TestInviteToken_MustBeUnguessable
+--- PASS: TestInviteToken_MustBeUnguessable (1.00s)
+=== RUN TestInviteToken_ExpiredCannotBeUsed
+--- PASS: TestInviteToken_ExpiredCannotBeUsed (0.84s)
+=== RUN TestInviteToken_CannotBeReused
+--- PASS: TestInviteToken_CannotBeReused (1.67s)
+=== RUN TestInviteUser_EmailValidation
+=== RUN TestInviteUser_EmailValidation/empty_email
+=== RUN TestInviteUser_EmailValidation/invalid_email_no_@
+=== RUN TestInviteUser_EmailValidation/invalid_email_no_domain
+=== RUN TestInviteUser_EmailValidation/sql_injection_attempt
+=== RUN TestInviteUser_EmailValidation/script_injection
+=== RUN TestInviteUser_EmailValidation/valid_email
+--- PASS: TestInviteUser_EmailValidation (0.83s)
+ --- PASS: TestInviteUser_EmailValidation/empty_email (0.00s)
+ --- PASS: TestInviteUser_EmailValidation/invalid_email_no_@ (0.00s)
+ --- PASS: TestInviteUser_EmailValidation/invalid_email_no_domain (0.00s)
+ --- PASS: TestInviteUser_EmailValidation/sql_injection_attempt (0.00s)
+ --- PASS: TestInviteUser_EmailValidation/script_injection (0.00s)
+ --- PASS: TestInviteUser_EmailValidation/valid_email (0.00s)
+=== RUN TestAcceptInvite_PasswordValidation
+=== RUN TestAcceptInvite_PasswordValidation/empty_password
+=== RUN TestAcceptInvite_PasswordValidation/too_short
+=== RUN TestAcceptInvite_PasswordValidation/7_chars
+=== RUN TestAcceptInvite_PasswordValidation/8_chars_valid
+--- PASS: TestAcceptInvite_PasswordValidation (1.71s)
+ --- PASS: TestAcceptInvite_PasswordValidation/empty_password (0.00s)
+ --- PASS: TestAcceptInvite_PasswordValidation/too_short (0.00s)
+ --- PASS: TestAcceptInvite_PasswordValidation/7_chars (0.00s)
+ --- PASS: TestAcceptInvite_PasswordValidation/8_chars_valid (0.85s)
+=== RUN TestUserEndpoints_RequireAdmin
+=== RUN TestUserEndpoints_RequireAdmin/GET_/api/users
+=== RUN TestUserEndpoints_RequireAdmin/POST_/api/users
+=== RUN TestUserEndpoints_RequireAdmin/POST_/api/users/invite
+=== RUN TestUserEndpoints_RequireAdmin/GET_/api/users/1
+=== RUN TestUserEndpoints_RequireAdmin/PUT_/api/users/1
+=== RUN TestUserEndpoints_RequireAdmin/DELETE_/api/users/1
+=== RUN TestUserEndpoints_RequireAdmin/PUT_/api/users/1/permissions
+--- PASS: TestUserEndpoints_RequireAdmin (0.91s)
+ --- PASS: TestUserEndpoints_RequireAdmin/GET_/api/users (0.00s)
+ --- PASS: TestUserEndpoints_RequireAdmin/POST_/api/users (0.00s)
+ --- PASS: TestUserEndpoints_RequireAdmin/POST_/api/users/invite (0.00s)
+ --- PASS: TestUserEndpoints_RequireAdmin/GET_/api/users/1 (0.00s)
+ --- PASS: TestUserEndpoints_RequireAdmin/PUT_/api/users/1 (0.00s)
+ --- PASS: TestUserEndpoints_RequireAdmin/DELETE_/api/users/1 (0.00s)
+ --- PASS: TestUserEndpoints_RequireAdmin/PUT_/api/users/1/permissions (0.00s)
+=== RUN TestSMTPEndpoints_RequireAdmin
+=== RUN TestSMTPEndpoints_RequireAdmin/POST_/api/settings/smtp
+=== RUN TestSMTPEndpoints_RequireAdmin/POST_/api/settings/smtp/test
+=== RUN TestSMTPEndpoints_RequireAdmin/POST_/api/settings/smtp/test-email
+--- PASS: TestSMTPEndpoints_RequireAdmin (0.82s)
+ --- PASS: TestSMTPEndpoints_RequireAdmin/POST_/api/settings/smtp (0.00s)
+ --- PASS: TestSMTPEndpoints_RequireAdmin/POST_/api/settings/smtp/test (0.00s)
+ --- PASS: TestSMTPEndpoints_RequireAdmin/POST_/api/settings/smtp/test-email (0.00s)
+=== RUN TestSMTPConfig_PasswordMasked
+--- PASS: TestSMTPConfig_PasswordMasked (0.78s)
+=== RUN TestSMTPConfig_PortValidation
+=== RUN TestSMTPConfig_PortValidation/port_0_invalid
+=== RUN TestSMTPConfig_PortValidation/port_-1_invalid
+=== RUN TestSMTPConfig_PortValidation/port_65536_invalid
+=== RUN TestSMTPConfig_PortValidation/port_587_valid
+=== RUN TestSMTPConfig_PortValidation/port_465_valid
+=== RUN TestSMTPConfig_PortValidation/port_25_valid
+--- PASS: TestSMTPConfig_PortValidation (0.99s)
+ --- PASS: TestSMTPConfig_PortValidation/port_0_invalid (0.00s)
+ --- PASS: TestSMTPConfig_PortValidation/port_-1_invalid (0.00s)
+ --- PASS: TestSMTPConfig_PortValidation/port_65536_invalid (0.00s)
+ --- PASS: TestSMTPConfig_PortValidation/port_587_valid (0.01s)
+ --- PASS: TestSMTPConfig_PortValidation/port_465_valid (0.00s)
+ --- PASS: TestSMTPConfig_PortValidation/port_25_valid (0.00s)
+=== RUN TestSMTPConfig_EncryptionValidation
+=== RUN TestSMTPConfig_EncryptionValidation/empty_encryption_invalid
+=== RUN TestSMTPConfig_EncryptionValidation/invalid_encryption
+=== RUN TestSMTPConfig_EncryptionValidation/tls_lowercase_valid
+=== RUN TestSMTPConfig_EncryptionValidation/starttls_valid
+=== RUN TestSMTPConfig_EncryptionValidation/none_valid
+--- PASS: TestSMTPConfig_EncryptionValidation (2.40s)
+ --- PASS: TestSMTPConfig_EncryptionValidation/empty_encryption_invalid (0.00s)
+ --- PASS: TestSMTPConfig_EncryptionValidation/invalid_encryption (0.00s)
+ --- PASS: TestSMTPConfig_EncryptionValidation/tls_lowercase_valid (0.00s)
+ --- PASS: TestSMTPConfig_EncryptionValidation/starttls_valid (0.00s)
+ --- PASS: TestSMTPConfig_EncryptionValidation/none_valid (0.00s)
+=== RUN TestInviteUser_DuplicateEmailBlocked
+--- PASS: TestInviteUser_DuplicateEmailBlocked (0.93s)
+=== RUN TestInviteUser_EmailCaseInsensitive
+--- PASS: TestInviteUser_EmailCaseInsensitive (0.82s)
+=== RUN TestDeleteUser_CannotDeleteSelf
+--- PASS: TestDeleteUser_CannotDeleteSelf (0.83s)
+=== RUN TestUpdatePermissions_ValidModes
+=== RUN TestUpdatePermissions_ValidModes/allow_all_valid
+=== RUN TestUpdatePermissions_ValidModes/deny_all_valid
+=== RUN TestUpdatePermissions_ValidModes/invalid_mode
+=== RUN TestUpdatePermissions_ValidModes/empty_mode
+--- PASS: TestUpdatePermissions_ValidModes (0.85s)
+ --- PASS: TestUpdatePermissions_ValidModes/allow_all_valid (0.00s)
+ --- PASS: TestUpdatePermissions_ValidModes/deny_all_valid (0.00s)
+ --- PASS: TestUpdatePermissions_ValidModes/invalid_mode (0.00s)
+ --- PASS: TestUpdatePermissions_ValidModes/empty_mode (0.00s)
+=== RUN TestPublicEndpoints_NoAuthRequired
+--- PASS: TestPublicEndpoints_NoAuthRequired (0.81s)
+PASS
+coverage: [no statements]
+ok github.com/Wikid82/charon/backend/internal/api/tests (cached) coverage: [no statements]
+=== RUN TestClient_Load_Success
+--- PASS: TestClient_Load_Success (0.01s)
+=== RUN TestClient_Load_Failure
+--- PASS: TestClient_Load_Failure (0.01s)
+=== RUN TestClient_GetConfig_Success
+--- PASS: TestClient_GetConfig_Success (0.00s)
+=== RUN TestClient_Ping_Success
+--- PASS: TestClient_Ping_Success (0.00s)
+=== RUN TestClient_Ping_Unreachable
+--- PASS: TestClient_Ping_Unreachable (0.00s)
+=== RUN TestClient_Load_CreateRequestFailure
+--- PASS: TestClient_Load_CreateRequestFailure (0.00s)
+=== RUN TestClient_Ping_CreateRequestFailure
+--- PASS: TestClient_Ping_CreateRequestFailure (0.00s)
+=== RUN TestClient_GetConfig_Failure
+--- PASS: TestClient_GetConfig_Failure (0.00s)
+=== RUN TestClient_GetConfig_InvalidJSON
+--- PASS: TestClient_GetConfig_InvalidJSON (0.00s)
+=== RUN TestClient_Ping_Failure
+--- PASS: TestClient_Ping_Failure (0.00s)
+=== RUN TestClient_RequestCreationErrors
+--- PASS: TestClient_RequestCreationErrors (0.00s)
+=== RUN TestClient_NetworkErrors
+--- PASS: TestClient_NetworkErrors (0.00s)
+=== RUN TestClient_Load_MarshalFailure
+--- PASS: TestClient_Load_MarshalFailure (0.00s)
+=== RUN TestClient_Ping_TransportError
+--- PASS: TestClient_Ping_TransportError (0.00s)
+=== RUN TestClient_GetConfig_BaseURLNil_ReturnsError
+--- PASS: TestClient_GetConfig_BaseURLNil_ReturnsError (0.00s)
+=== RUN TestClient_RequestCreationErrors_FromInvalidResolvedURL
+--- PASS: TestClient_RequestCreationErrors_FromInvalidResolvedURL (0.00s)
+=== RUN TestBuildACLHandler_GeoBlacklist
+--- PASS: TestBuildACLHandler_GeoBlacklist (0.00s)
+=== RUN TestBuildACLHandler_UnknownTypeReturnsNil
+--- PASS: TestBuildACLHandler_UnknownTypeReturnsNil (0.00s)
+=== RUN TestBuildACLHandler_GeoWhitelist
+--- PASS: TestBuildACLHandler_GeoWhitelist (0.00s)
+=== RUN TestBuildACLHandler_LocalNetwork
+--- PASS: TestBuildACLHandler_LocalNetwork (0.00s)
+=== RUN TestBuildACLHandler_IPRules
+--- PASS: TestBuildACLHandler_IPRules (0.00s)
+=== RUN TestBuildACLHandler_InvalidIPJSON
+--- PASS: TestBuildACLHandler_InvalidIPJSON (0.00s)
+=== RUN TestBuildACLHandler_NoIPRulesReturnsNil
+--- PASS: TestBuildACLHandler_NoIPRulesReturnsNil (0.00s)
+=== RUN TestBuildACLHandler_Whitelist
+--- PASS: TestBuildACLHandler_Whitelist (0.00s)
+=== RUN TestBuildCrowdSecHandler_Disabled
+--- PASS: TestBuildCrowdSecHandler_Disabled (0.00s)
+=== RUN TestBuildCrowdSecHandler_EnabledWithoutConfig
+--- PASS: TestBuildCrowdSecHandler_EnabledWithoutConfig (0.00s)
+=== RUN TestBuildCrowdSecHandler_EnabledWithEmptyAPIURL
+--- PASS: TestBuildCrowdSecHandler_EnabledWithEmptyAPIURL (0.00s)
+=== RUN TestBuildCrowdSecHandler_EnabledWithCustomAPIURL
+--- PASS: TestBuildCrowdSecHandler_EnabledWithCustomAPIURL (0.00s)
+=== RUN TestBuildCrowdSecHandler_JSONFormat
+--- PASS: TestBuildCrowdSecHandler_JSONFormat (0.00s)
+=== RUN TestBuildCrowdSecHandler_WithHost
+--- PASS: TestBuildCrowdSecHandler_WithHost (0.00s)
+=== RUN TestGenerateConfig_WithCrowdSec
+--- PASS: TestGenerateConfig_WithCrowdSec (0.00s)
+=== RUN TestGenerateConfig_CrowdSecDisabled
+--- PASS: TestGenerateConfig_CrowdSecDisabled (0.00s)
+=== RUN TestGenerateConfig_CatchAllFrontend
+--- PASS: TestGenerateConfig_CatchAllFrontend (0.00s)
+=== RUN TestGenerateConfig_AdvancedInvalidJSON
+time="2026-01-10T02:16:57Z" level=warning msg="Failed to parse advanced_config for host" error="invalid character 'i' looking for beginning of object key string" host=adv1
+--- PASS: TestGenerateConfig_AdvancedInvalidJSON (0.00s)
+=== RUN TestGenerateConfig_AdvancedArrayHandler
+--- PASS: TestGenerateConfig_AdvancedArrayHandler (0.00s)
+=== RUN TestGenerateConfig_LowercaseDomains
+--- PASS: TestGenerateConfig_LowercaseDomains (0.00s)
+=== RUN TestGenerateConfig_AdvancedObjectHandler
+--- PASS: TestGenerateConfig_AdvancedObjectHandler (0.00s)
+=== RUN TestGenerateConfig_AdvancedHeadersStringToArray
+--- PASS: TestGenerateConfig_AdvancedHeadersStringToArray (0.00s)
+=== RUN TestGenerateConfig_ACLWhitelistIncluded
+--- PASS: TestGenerateConfig_ACLWhitelistIncluded (0.00s)
+=== RUN TestGenerateConfig_SkipsEmptyDomainEntries
+--- PASS: TestGenerateConfig_SkipsEmptyDomainEntries (0.00s)
+=== RUN TestGenerateConfig_AdvancedNoHandlerKey
+time="2026-01-10T02:16:57Z" level=warning msg="advanced_config for host is not a handler object" host=adv3
+--- PASS: TestGenerateConfig_AdvancedNoHandlerKey (0.00s)
+=== RUN TestGenerateConfig_AdvancedUnexpectedJSONStructure
+time="2026-01-10T02:16:57Z" level=warning msg="advanced_config for host has unexpected JSON structure" host=adv4
+--- PASS: TestGenerateConfig_AdvancedUnexpectedJSONStructure (0.00s)
+=== RUN TestBuildACLHandler_UnknownIPTypeReturnsNil
+--- PASS: TestBuildACLHandler_UnknownIPTypeReturnsNil (0.00s)
+=== RUN TestGenerateConfig_SecurityPipeline_Order
+--- PASS: TestGenerateConfig_SecurityPipeline_Order (0.00s)
+=== RUN TestGenerateConfig_SecurityPipeline_OmitWhenDisabled
+--- PASS: TestGenerateConfig_SecurityPipeline_OmitWhenDisabled (0.00s)
+=== RUN TestGetAccessLogPath
+=== RUN TestGetAccessLogPath/CrowdSecEnabled_UsesStandardPath
+=== RUN TestGetAccessLogPath/Production_UsesStandardPath
+=== RUN TestGetAccessLogPath/Development_UsesRelativePath
+=== RUN TestGetAccessLogPath/NoEnv_CrowdSecEnabled_UsesStandardPath
+--- PASS: TestGetAccessLogPath (0.00s)
+ --- PASS: TestGetAccessLogPath/CrowdSecEnabled_UsesStandardPath (0.00s)
+ --- PASS: TestGetAccessLogPath/Production_UsesStandardPath (0.00s)
+ --- PASS: TestGetAccessLogPath/Development_UsesRelativePath (0.00s)
+ --- PASS: TestGetAccessLogPath/NoEnv_CrowdSecEnabled_UsesStandardPath (0.00s)
+=== RUN TestGenerateConfig_LoggingConfigured
+--- PASS: TestGenerateConfig_LoggingConfigured (0.00s)
+=== RUN TestGenerateConfig_ZerosslAndBothProviders
+--- PASS: TestGenerateConfig_ZerosslAndBothProviders (0.00s)
+=== RUN TestGenerateConfig_SecurityPipeline_Order_Locations
+--- PASS: TestGenerateConfig_SecurityPipeline_Order_Locations (0.00s)
+=== RUN TestGenerateConfig_ACLLogWarning
+--- PASS: TestGenerateConfig_ACLLogWarning (0.00s)
+=== RUN TestGenerateConfig_ACLHandlerIncluded
+--- PASS: TestGenerateConfig_ACLHandlerIncluded (0.00s)
+=== RUN TestGenerateConfig_DecisionsBlockWithAdminExclusion
+ config_generate_additional_test.go:147: handles: [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "body": "Access denied: Blocked by security decision",
+ "handler": "static_response",
+ "status_code": 403
+ }
+ ],
+ "match": [
+ {
+ "remote_ip": {
+ "ranges": [
+ "1.2.3.4"
+ ]
+ }
+ },
+ {
+ "not": [
+ {
+ "remote_ip": {
+ "ranges": [
+ "10.0.0.1/32"
+ ]
+ }
+ }
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ },
+ {
+ "flush_interval": -1,
+ "handler": "reverse_proxy",
+ "headers": {
+ "request": {
+ "set": {
+ "X-Forwarded-Host": [
+ "{http.request.host}"
+ ],
+ "X-Forwarded-Port": [
+ "{http.request.port}"
+ ],
+ "X-Forwarded-Proto": [
+ "{http.request.scheme}"
+ ],
+ "X-Real-IP": [
+ "{http.request.remote.host}"
+ ]
+ }
+ }
+ },
+ "upstreams": [
+ {
+ "dial": "app:8080"
+ }
+ ]
+ }
+ ]
+--- PASS: TestGenerateConfig_DecisionsBlockWithAdminExclusion (0.00s)
+=== RUN TestGenerateConfig_WAFModeAndRulesetReference
+--- PASS: TestGenerateConfig_WAFModeAndRulesetReference (0.00s)
+=== RUN TestGenerateConfig_WAFModeDisabledSkipsHandler
+--- PASS: TestGenerateConfig_WAFModeDisabledSkipsHandler (0.00s)
+=== RUN TestGenerateConfig_WAFSelectedSetsContentAndMode
+--- PASS: TestGenerateConfig_WAFSelectedSetsContentAndMode (0.00s)
+=== RUN TestGenerateConfig_DecisionAdminPartsEmpty
+--- PASS: TestGenerateConfig_DecisionAdminPartsEmpty (0.00s)
+=== RUN TestNormalizeHeaderOps_PreserveStringArray
+--- PASS: TestNormalizeHeaderOps_PreserveStringArray (0.00s)
+=== RUN TestGenerateConfig_WAFUsesRuleSet
+--- PASS: TestGenerateConfig_WAFUsesRuleSet (0.00s)
+=== RUN TestGenerateConfig_WAFUsesRuleSetFromAdvancedConfig
+--- PASS: TestGenerateConfig_WAFUsesRuleSetFromAdvancedConfig (0.00s)
+=== RUN TestGenerateConfig_WAFUsesRuleSetFromAdvancedConfig_Array
+--- PASS: TestGenerateConfig_WAFUsesRuleSetFromAdvancedConfig_Array (0.00s)
+=== RUN TestGenerateConfig_WAFUsesRulesetFromSecCfgFallback
+--- PASS: TestGenerateConfig_WAFUsesRulesetFromSecCfgFallback (0.00s)
+=== RUN TestGenerateConfig_RateLimitFromSecCfg
+--- PASS: TestGenerateConfig_RateLimitFromSecCfg (0.00s)
+=== RUN TestGenerateConfig_CrowdSecHandlerFromSecCfg
+--- PASS: TestGenerateConfig_CrowdSecHandlerFromSecCfg (0.00s)
+=== RUN TestGenerateConfig_EmptyHostsAndNoFrontend
+--- PASS: TestGenerateConfig_EmptyHostsAndNoFrontend (0.00s)
+=== RUN TestGenerateConfig_SkipsInvalidCustomCert
+--- PASS: TestGenerateConfig_SkipsInvalidCustomCert (0.00s)
+=== RUN TestGenerateConfig_SkipsDuplicateDomains
+--- PASS: TestGenerateConfig_SkipsDuplicateDomains (0.00s)
+=== RUN TestGenerateConfig_LoadPEMSetsTLSWhenNoACME
+--- PASS: TestGenerateConfig_LoadPEMSetsTLSWhenNoACME (0.00s)
+=== RUN TestGenerateConfig_DefaultAcmeStaging
+--- PASS: TestGenerateConfig_DefaultAcmeStaging (0.00s)
+=== RUN TestGenerateConfig_ACLHandlerBuildError
+--- PASS: TestGenerateConfig_ACLHandlerBuildError (0.00s)
+=== RUN TestGenerateConfig_SkipHostDomainEmptyAndDisabled
+--- PASS: TestGenerateConfig_SkipHostDomainEmptyAndDisabled (0.00s)
+=== RUN TestGenerateConfig_CustomCertsAndTLS
+--- PASS: TestGenerateConfig_CustomCertsAndTLS (0.00s)
+=== RUN TestGenerateConfig_DNSChallenge_LetsEncrypt_StagingCAAndPropagationTimeout
+--- PASS: TestGenerateConfig_DNSChallenge_LetsEncrypt_StagingCAAndPropagationTimeout (0.00s)
+=== RUN TestGenerateConfig_DNSChallenge_ZeroSSL_IssuerShape
+--- PASS: TestGenerateConfig_DNSChallenge_ZeroSSL_IssuerShape (0.00s)
+=== RUN TestGenerateConfig_DNSChallenge_SkipsPolicyWhenProviderConfigMissing
+--- PASS: TestGenerateConfig_DNSChallenge_SkipsPolicyWhenProviderConfigMissing (0.00s)
+=== RUN TestGenerateConfig_HTTPChallenge_ExcludesIPDomains
+--- PASS: TestGenerateConfig_HTTPChallenge_ExcludesIPDomains (0.00s)
+=== RUN TestGetCrowdSecAPIKey_EnvPriority
+--- PASS: TestGetCrowdSecAPIKey_EnvPriority (0.00s)
+=== RUN TestHasWildcard_TrueFalse
+--- PASS: TestHasWildcard_TrueFalse (0.00s)
+=== RUN TestGenerateConfig_MultiCredential_ZoneSpecificPolicies
+--- PASS: TestGenerateConfig_MultiCredential_ZoneSpecificPolicies (0.00s)
+=== RUN TestGenerateConfig_MultiCredential_ZeroSSL_Issuer
+--- PASS: TestGenerateConfig_MultiCredential_ZeroSSL_Issuer (0.00s)
+=== RUN TestGenerateConfig_MultiCredential_BothIssuers
+--- PASS: TestGenerateConfig_MultiCredential_BothIssuers (0.00s)
+=== RUN TestGenerateConfig_MultiCredential_ACMEStaging
+--- PASS: TestGenerateConfig_MultiCredential_ACMEStaging (0.00s)
+=== RUN TestGenerateConfig_MultiCredential_NoMatchingDomains
+--- PASS: TestGenerateConfig_MultiCredential_NoMatchingDomains (0.00s)
+=== RUN TestGenerateConfig_MultiCredential_ProviderTypeNotFound
+--- PASS: TestGenerateConfig_MultiCredential_ProviderTypeNotFound (0.00s)
+=== RUN TestGenerateConfig_MultiCredential_SupportsMultiCredential_UsesZoneConfigAndStagingBothIssuers
+--- PASS: TestGenerateConfig_MultiCredential_SupportsMultiCredential_UsesZoneConfigAndStagingBothIssuers (0.00s)
+=== RUN TestGenerateConfig_DNSChallenge_SingleCredential_BothIssuers_ACMEStaging
+--- PASS: TestGenerateConfig_DNSChallenge_SingleCredential_BothIssuers_ACMEStaging (0.00s)
+=== RUN TestGenerateConfig_DNSChallenge_SingleCredential_ProviderTypeNotFound_SkipsPolicy
+--- PASS: TestGenerateConfig_DNSChallenge_SingleCredential_ProviderTypeNotFound_SkipsPolicy (0.00s)
+=== RUN TestGenerateConfig_DefaultPolicy_LetsEncrypt_StagingCA
+--- PASS: TestGenerateConfig_DefaultPolicy_LetsEncrypt_StagingCA (0.00s)
+=== RUN TestGenerateConfig_DefaultPolicy_ZeroSSL_Issuer
+--- PASS: TestGenerateConfig_DefaultPolicy_ZeroSSL_Issuer (0.00s)
+=== RUN TestGenerateConfig_DefaultPolicy_BothIssuers_StagingCA
+--- PASS: TestGenerateConfig_DefaultPolicy_BothIssuers_StagingCA (0.00s)
+=== RUN TestGenerateConfig_IPSubjects_InitializesTLSAppAndAutomation
+--- PASS: TestGenerateConfig_IPSubjects_InitializesTLSAppAndAutomation (0.00s)
+=== RUN TestGetAccessLogPath_DockerEnv_UsesCrowdSecPath
+--- PASS: TestGetAccessLogPath_DockerEnv_UsesCrowdSecPath (0.00s)
+=== RUN TestBuildSecurityHeadersHandler_AllEnabled
+--- PASS: TestBuildSecurityHeadersHandler_AllEnabled (0.00s)
+=== RUN TestBuildSecurityHeadersHandler_HSTSOnly
+--- PASS: TestBuildSecurityHeadersHandler_HSTSOnly (0.00s)
+=== RUN TestBuildSecurityHeadersHandler_CSPOnly
+--- PASS: TestBuildSecurityHeadersHandler_CSPOnly (0.00s)
+=== RUN TestBuildSecurityHeadersHandler_CSPReportOnly
+--- PASS: TestBuildSecurityHeadersHandler_CSPReportOnly (0.00s)
+=== RUN TestBuildSecurityHeadersHandler_NoProfile
+--- PASS: TestBuildSecurityHeadersHandler_NoProfile (0.00s)
+=== RUN TestBuildSecurityHeadersHandler_Disabled
+--- PASS: TestBuildSecurityHeadersHandler_Disabled (0.00s)
+=== RUN TestBuildSecurityHeadersHandler_NilHost
+--- PASS: TestBuildSecurityHeadersHandler_NilHost (0.00s)
+=== RUN TestBuildCSPString
+=== RUN TestBuildCSPString/simple_CSP
+=== RUN TestBuildCSPString/multiple_directives
+=== RUN TestBuildCSPString/empty_string
+=== RUN TestBuildCSPString/invalid_JSON
+--- PASS: TestBuildCSPString (0.00s)
+ --- PASS: TestBuildCSPString/simple_CSP (0.00s)
+ --- PASS: TestBuildCSPString/multiple_directives (0.00s)
+ --- PASS: TestBuildCSPString/empty_string (0.00s)
+ --- PASS: TestBuildCSPString/invalid_JSON (0.00s)
+=== RUN TestBuildPermissionsPolicyString
+=== RUN TestBuildPermissionsPolicyString/single_feature_no_allowlist
+=== RUN TestBuildPermissionsPolicyString/single_feature_with_self
+=== RUN TestBuildPermissionsPolicyString/multiple_features
+=== RUN TestBuildPermissionsPolicyString/empty_string
+=== RUN TestBuildPermissionsPolicyString/invalid_JSON
+--- PASS: TestBuildPermissionsPolicyString (0.00s)
+ --- PASS: TestBuildPermissionsPolicyString/single_feature_no_allowlist (0.00s)
+ --- PASS: TestBuildPermissionsPolicyString/single_feature_with_self (0.00s)
+ --- PASS: TestBuildPermissionsPolicyString/multiple_features (0.00s)
+ --- PASS: TestBuildPermissionsPolicyString/empty_string (0.00s)
+ --- PASS: TestBuildPermissionsPolicyString/invalid_JSON (0.00s)
+=== RUN TestGetDefaultSecurityHeaderProfile
+--- PASS: TestGetDefaultSecurityHeaderProfile (0.00s)
+=== RUN TestBuildSecurityHeadersHandler_PermissionsPolicy
+--- PASS: TestBuildSecurityHeadersHandler_PermissionsPolicy (0.00s)
+=== RUN TestBuildSecurityHeadersHandler_InvalidCSPJSON
+--- PASS: TestBuildSecurityHeadersHandler_InvalidCSPJSON (0.00s)
+=== RUN TestBuildSecurityHeadersHandler_InvalidPermissionsJSON
+--- PASS: TestBuildSecurityHeadersHandler_InvalidPermissionsJSON (0.00s)
+=== RUN TestBuildSecurityHeadersHandler_APIFriendlyPreset
+--- PASS: TestBuildSecurityHeadersHandler_APIFriendlyPreset (0.00s)
+=== RUN TestGenerateConfig_Empty
+--- PASS: TestGenerateConfig_Empty (0.00s)
+=== RUN TestGenerateConfig_SingleHost
+--- PASS: TestGenerateConfig_SingleHost (0.00s)
+=== RUN TestGenerateConfig_MultipleHosts
+--- PASS: TestGenerateConfig_MultipleHosts (0.00s)
+=== RUN TestGenerateConfig_WebSocketEnabled
+--- PASS: TestGenerateConfig_WebSocketEnabled (0.00s)
+=== RUN TestGenerateConfig_EmptyDomain
+--- PASS: TestGenerateConfig_EmptyDomain (0.00s)
+=== RUN TestGenerateConfig_Logging
+--- PASS: TestGenerateConfig_Logging (0.00s)
+=== RUN TestGenerateConfig_IPHostsSkipAutoHTTPS
+--- PASS: TestGenerateConfig_IPHostsSkipAutoHTTPS (0.00s)
+=== RUN TestGenerateConfig_Advanced
+--- PASS: TestGenerateConfig_Advanced (0.00s)
+=== RUN TestGenerateConfig_ACMEStaging
+--- PASS: TestGenerateConfig_ACMEStaging (0.00s)
+=== RUN TestBuildACLHandler_WhitelistAndBlacklistAdminMerge
+--- PASS: TestBuildACLHandler_WhitelistAndBlacklistAdminMerge (0.00s)
+=== RUN TestBuildACLHandler_GeoAndLocalNetwork
+--- PASS: TestBuildACLHandler_GeoAndLocalNetwork (0.00s)
+=== RUN TestBuildACLHandler_AdminWhitelistParsing
+--- PASS: TestBuildACLHandler_AdminWhitelistParsing (0.00s)
+=== RUN TestBuildRateLimitHandler_Disabled
+--- PASS: TestBuildRateLimitHandler_Disabled (0.00s)
+=== RUN TestBuildRateLimitHandler_InvalidValues
+--- PASS: TestBuildRateLimitHandler_InvalidValues (0.00s)
+=== RUN TestBuildRateLimitHandler_ValidConfig
+--- PASS: TestBuildRateLimitHandler_ValidConfig (0.00s)
+=== RUN TestBuildRateLimitHandler_JSONFormat
+--- PASS: TestBuildRateLimitHandler_JSONFormat (0.00s)
+=== RUN TestGenerateConfig_WithRateLimiting
+--- PASS: TestGenerateConfig_WithRateLimiting (0.00s)
+=== RUN TestBuildRateLimitHandler_UsesBurst
+--- PASS: TestBuildRateLimitHandler_UsesBurst (0.00s)
+=== RUN TestBuildRateLimitHandler_DefaultBurst
+--- PASS: TestBuildRateLimitHandler_DefaultBurst (0.00s)
+=== RUN TestGetAccessLogPath_CrowdSecEnabled
+--- PASS: TestGetAccessLogPath_CrowdSecEnabled (0.00s)
+=== RUN TestGetAccessLogPath_DockerEnv
+--- PASS: TestGetAccessLogPath_DockerEnv (0.00s)
+=== RUN TestGetAccessLogPath_Development
+--- PASS: TestGetAccessLogPath_Development (0.00s)
+=== RUN TestBuildPermissionsPolicyString_EmptyAllowlist
+--- PASS: TestBuildPermissionsPolicyString_EmptyAllowlist (0.00s)
+=== RUN TestBuildPermissionsPolicyString_SelfAndStar
+--- PASS: TestBuildPermissionsPolicyString_SelfAndStar (0.00s)
+=== RUN TestBuildPermissionsPolicyString_DomainValues
+--- PASS: TestBuildPermissionsPolicyString_DomainValues (0.00s)
+=== RUN TestBuildPermissionsPolicyString_Mixed
+--- PASS: TestBuildPermissionsPolicyString_Mixed (0.00s)
+=== RUN TestBuildPermissionsPolicyString_InvalidJSON
+--- PASS: TestBuildPermissionsPolicyString_InvalidJSON (0.00s)
+=== RUN TestBuildCSPString_EmptyDirective
+--- PASS: TestBuildCSPString_EmptyDirective (0.00s)
+=== RUN TestBuildCSPString_InvalidJSON
+--- PASS: TestBuildCSPString_InvalidJSON (0.00s)
+=== RUN TestBuildSecurityHeadersHandler_CompleteProfile
+--- PASS: TestBuildSecurityHeadersHandler_CompleteProfile (0.00s)
+=== RUN TestGenerateConfig_SSLProviderZeroSSL
+--- PASS: TestGenerateConfig_SSLProviderZeroSSL (0.00s)
+=== RUN TestGenerateConfig_SSLProviderBoth
+--- PASS: TestGenerateConfig_SSLProviderBoth (0.00s)
+=== RUN TestGenerateConfig_DuplicateDomains
+--- PASS: TestGenerateConfig_DuplicateDomains (0.00s)
+=== RUN TestGenerateConfig_WithCrowdSecApp
+--- PASS: TestGenerateConfig_WithCrowdSecApp (0.00s)
+=== RUN TestGenerateConfig_CrowdSecHandlerAdded
+--- PASS: TestGenerateConfig_CrowdSecHandlerAdded (0.00s)
+=== RUN TestGenerateConfig_WithSecurityDecisions
+--- PASS: TestGenerateConfig_WithSecurityDecisions (0.00s)
+=== RUN TestBuildRateLimitHandler_BypassList
+--- PASS: TestBuildRateLimitHandler_BypassList (0.00s)
+=== RUN TestBuildRateLimitHandler_BypassList_PlainIPs
+--- PASS: TestBuildRateLimitHandler_BypassList_PlainIPs (0.00s)
+=== RUN TestBuildRateLimitHandler_BypassList_InvalidEntries
+--- PASS: TestBuildRateLimitHandler_BypassList_InvalidEntries (0.00s)
+=== RUN TestBuildRateLimitHandler_BypassList_Empty
+--- PASS: TestBuildRateLimitHandler_BypassList_Empty (0.00s)
+=== RUN TestBuildRateLimitHandler_BypassList_AllInvalid
+--- PASS: TestBuildRateLimitHandler_BypassList_AllInvalid (0.00s)
+=== RUN TestParseBypassCIDRs
+=== RUN TestParseBypassCIDRs/empty
+=== RUN TestParseBypassCIDRs/single_cidr
+=== RUN TestParseBypassCIDRs/multiple_cidrs
+=== RUN TestParseBypassCIDRs/plain_ipv4
+=== RUN TestParseBypassCIDRs/plain_ipv6
+=== RUN TestParseBypassCIDRs/mixed
+=== RUN TestParseBypassCIDRs/with_spaces
+=== RUN TestParseBypassCIDRs/all_invalid
+--- PASS: TestParseBypassCIDRs (0.00s)
+ --- PASS: TestParseBypassCIDRs/empty (0.00s)
+ --- PASS: TestParseBypassCIDRs/single_cidr (0.00s)
+ --- PASS: TestParseBypassCIDRs/multiple_cidrs (0.00s)
+ --- PASS: TestParseBypassCIDRs/plain_ipv4 (0.00s)
+ --- PASS: TestParseBypassCIDRs/plain_ipv6 (0.00s)
+ --- PASS: TestParseBypassCIDRs/mixed (0.00s)
+ --- PASS: TestParseBypassCIDRs/with_spaces (0.00s)
+ --- PASS: TestParseBypassCIDRs/all_invalid (0.00s)
+=== RUN TestBuildWAFHandler_ParanoiaLevel
+=== RUN TestBuildWAFHandler_ParanoiaLevel/level_1_default
+=== RUN TestBuildWAFHandler_ParanoiaLevel/level_1_explicit
+=== RUN TestBuildWAFHandler_ParanoiaLevel/level_2
+=== RUN TestBuildWAFHandler_ParanoiaLevel/level_3
+=== RUN TestBuildWAFHandler_ParanoiaLevel/level_4_max
+=== RUN TestBuildWAFHandler_ParanoiaLevel/level_invalid_high
+=== RUN TestBuildWAFHandler_ParanoiaLevel/level_invalid_neg
+--- PASS: TestBuildWAFHandler_ParanoiaLevel (0.00s)
+ --- PASS: TestBuildWAFHandler_ParanoiaLevel/level_1_default (0.00s)
+ --- PASS: TestBuildWAFHandler_ParanoiaLevel/level_1_explicit (0.00s)
+ --- PASS: TestBuildWAFHandler_ParanoiaLevel/level_2 (0.00s)
+ --- PASS: TestBuildWAFHandler_ParanoiaLevel/level_3 (0.00s)
+ --- PASS: TestBuildWAFHandler_ParanoiaLevel/level_4_max (0.00s)
+ --- PASS: TestBuildWAFHandler_ParanoiaLevel/level_invalid_high (0.00s)
+ --- PASS: TestBuildWAFHandler_ParanoiaLevel/level_invalid_neg (0.00s)
+=== RUN TestBuildWAFHandler_Exclusions
+--- PASS: TestBuildWAFHandler_Exclusions (0.00s)
+=== RUN TestBuildWAFHandler_ExclusionsWithTarget
+--- PASS: TestBuildWAFHandler_ExclusionsWithTarget (0.00s)
+=== RUN TestBuildWAFHandler_PerHostDisabled
+--- PASS: TestBuildWAFHandler_PerHostDisabled (0.00s)
+=== RUN TestBuildWAFHandler_MonitorMode
+--- PASS: TestBuildWAFHandler_MonitorMode (0.00s)
+=== RUN TestBuildWAFHandler_GlobalDisabled
+--- PASS: TestBuildWAFHandler_GlobalDisabled (0.00s)
+=== RUN TestBuildWAFHandler_NoRuleset
+--- PASS: TestBuildWAFHandler_NoRuleset (0.00s)
+=== RUN TestParseWAFExclusions
+=== RUN TestParseWAFExclusions/empty
+=== RUN TestParseWAFExclusions/single_exclusion
+=== RUN TestParseWAFExclusions/multiple_exclusions
+=== RUN TestParseWAFExclusions/invalid_json
+--- PASS: TestParseWAFExclusions (0.00s)
+ --- PASS: TestParseWAFExclusions/empty (0.00s)
+ --- PASS: TestParseWAFExclusions/single_exclusion (0.00s)
+ --- PASS: TestParseWAFExclusions/multiple_exclusions (0.00s)
+ --- PASS: TestParseWAFExclusions/invalid_json (0.00s)
+=== RUN TestGenerateConfig_WithWAFPerHostDisabled
+--- PASS: TestGenerateConfig_WithWAFPerHostDisabled (0.00s)
+=== RUN TestGenerateConfig_WithDisabledHost
+--- PASS: TestGenerateConfig_WithDisabledHost (0.00s)
+=== RUN TestGenerateConfig_WithFrontendDir
+--- PASS: TestGenerateConfig_WithFrontendDir (0.00s)
+=== RUN TestGenerateConfig_CustomCertificate
+--- PASS: TestGenerateConfig_CustomCertificate (0.00s)
+=== RUN TestGenerateConfig_CustomCertificateMissingData
+--- PASS: TestGenerateConfig_CustomCertificateMissingData (0.00s)
+=== RUN TestGenerateConfig_LetsEncryptCertificateNotLoaded
+--- PASS: TestGenerateConfig_LetsEncryptCertificateNotLoaded (0.00s)
+=== RUN TestGenerateConfig_NormalizeAdvancedConfig
+--- PASS: TestGenerateConfig_NormalizeAdvancedConfig (0.00s)
+=== RUN TestGenerateConfig_NoACMEEmailNoTLS
+--- PASS: TestGenerateConfig_NoACMEEmailNoTLS (0.00s)
+=== RUN TestGenerateConfig_SecurityDecisionsWithAdminWhitelist
+--- PASS: TestGenerateConfig_SecurityDecisionsWithAdminWhitelist (0.00s)
+=== RUN TestBuildSecurityHeadersHandler_DefaultProfile
+--- PASS: TestBuildSecurityHeadersHandler_DefaultProfile (0.00s)
+=== RUN TestHasWildcard
+=== RUN TestHasWildcard/no_wildcard
+=== RUN TestHasWildcard/with_wildcard
+=== RUN TestHasWildcard/only_wildcard
+=== RUN TestHasWildcard/empty
+--- PASS: TestHasWildcard (0.00s)
+ --- PASS: TestHasWildcard/no_wildcard (0.00s)
+ --- PASS: TestHasWildcard/with_wildcard (0.00s)
+ --- PASS: TestHasWildcard/only_wildcard (0.00s)
+ --- PASS: TestHasWildcard/empty (0.00s)
+=== RUN TestDedupeDomains
+=== RUN TestDedupeDomains/no_dupes
+=== RUN TestDedupeDomains/with_dupes
+=== RUN TestDedupeDomains/all_dupes
+=== RUN TestDedupeDomains/empty
+--- PASS: TestDedupeDomains (0.00s)
+ --- PASS: TestDedupeDomains/no_dupes (0.00s)
+ --- PASS: TestDedupeDomains/with_dupes (0.00s)
+ --- PASS: TestDedupeDomains/all_dupes (0.00s)
+ --- PASS: TestDedupeDomains/empty (0.00s)
+=== RUN TestNormalizeAdvancedConfig_NestedRoutes
+--- PASS: TestNormalizeAdvancedConfig_NestedRoutes (0.00s)
+=== RUN TestNormalizeAdvancedConfig_ArrayInput
+--- PASS: TestNormalizeAdvancedConfig_ArrayInput (0.00s)
+=== RUN TestGetCrowdSecAPIKey
+--- PASS: TestGetCrowdSecAPIKey (0.00s)
+=== RUN TestBuildWAFHandler_PathTraversalAttack
+=== RUN TestBuildWAFHandler_PathTraversalAttack/Path_traversal_in_ruleset_name
+=== RUN TestBuildWAFHandler_PathTraversalAttack/Null_byte_injection
+=== RUN TestBuildWAFHandler_PathTraversalAttack/URL_encoded_traversal
+--- PASS: TestBuildWAFHandler_PathTraversalAttack (0.00s)
+ --- PASS: TestBuildWAFHandler_PathTraversalAttack/Path_traversal_in_ruleset_name (0.00s)
+ --- PASS: TestBuildWAFHandler_PathTraversalAttack/Null_byte_injection (0.00s)
+ --- PASS: TestBuildWAFHandler_PathTraversalAttack/URL_encoded_traversal (0.00s)
+=== RUN TestBuildWAFHandler_SQLInjectionInRulesetName
+=== RUN TestBuildWAFHandler_SQLInjectionInRulesetName/';_DROP_TABLE_rulesets;_--
+=== RUN TestBuildWAFHandler_SQLInjectionInRulesetName/1'_OR_'1'='1
+=== RUN TestBuildWAFHandler_SQLInjectionInRulesetName/UNION_SELECT_*_FROM_users--
+=== RUN TestBuildWAFHandler_SQLInjectionInRulesetName/admin'/*
+--- PASS: TestBuildWAFHandler_SQLInjectionInRulesetName (0.00s)
+ --- PASS: TestBuildWAFHandler_SQLInjectionInRulesetName/';_DROP_TABLE_rulesets;_-- (0.00s)
+ --- PASS: TestBuildWAFHandler_SQLInjectionInRulesetName/1'_OR_'1'='1 (0.00s)
+ --- PASS: TestBuildWAFHandler_SQLInjectionInRulesetName/UNION_SELECT_*_FROM_users-- (0.00s)
+ --- PASS: TestBuildWAFHandler_SQLInjectionInRulesetName/admin'/* (0.00s)
+=== RUN TestBuildWAFHandler_XSSInAdvancedConfig
+=== RUN TestBuildWAFHandler_XSSInAdvancedConfig/{"ruleset_name":""}
+=== RUN TestBuildWAFHandler_XSSInAdvancedConfig/{"ruleset_name":""}
+=== RUN TestBuildWAFHandler_XSSInAdvancedConfig/{"ruleset_name":"javascript:alert(1)"}
+=== RUN TestBuildWAFHandler_XSSInAdvancedConfig/{"ruleset_name":"