Files
gsc-ops-api/internal/router/router.go
Claude (gsc-ops-api init) 3847eb2036 Initial import — snapshot from admin host /srv/gosec/gsc-ops-api
This repo had no version control prior to this commit. The import is a
straight snapshot of the working tree at 2026-05-03; the deployed
binary on fihelvop01 was being rebuilt from this source via `make
build` + scp into place, with no upstream review path.

The snapshot already includes one in-flight fix made on 2026-05-03 to
internal/service/persona.go:GetSelfModel — the handler queried
`source` and `strength` columns plus an `is_active = true` filter on
persona.persona_commitments, none of which exist on that table (its
shape is session-bound commitments with `status`, `commitment_meta`,
etc.). The query returned a 500 every time SynapseHub bootstrapped a
persona's self-model, dropping the IdentityConstraints / Commitments /
ConscienceStandards layer from the assembled prompt. The patched
query reads existing columns only (commitment_text, commitment_type),
filters on `status='active'`, and synthesises Source="learned" /
Strength=1.0 to keep the SelfModel response shape stable for callers.

Verified live: `GET /api/v1/personas/70f7cfd9-.../self-model` now
returns 200 with `{identityConstraints:[],commitments:[],
conscienceStandards:[]}` instead of 500.

Future changes go through PRs against this repo — no more bin-only
deploys.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 20:06:02 +02:00

226 lines
8.3 KiB
Go

package router
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/recover"
"github.com/rs/zerolog"
"github.com/gosec/gsc-ops-api/internal/handler"
"github.com/gosec/gsc-ops-api/internal/middleware"
)
// Config holds all handler dependencies for route registration
type Config struct {
Logger zerolog.Logger
APIKeys []string
Health *handler.HealthHandler
LDAPUsers *handler.LDAPUserHandler
LDAPGroups *handler.LDAPGroupHandler
LDAPEntities *handler.LDAPEntityHandler
DNSZones *handler.DNSZoneHandler
DNSRecords *handler.DNSRecordHandler
DBTenants *handler.DBTenantHandler
DBUsers *handler.DBUserHandler
Certs *handler.CertHandler
PGP *handler.PGPHandler
CardDAV *handler.CardDAVHandler
PBX *handler.PBXHandler
VoiceAgent *handler.VoiceAgentHandler
PersonalAgent *handler.PersonalAgentHandler
Persona *handler.PersonaHandler
}
// Setup registers all routes on the Fiber app
func Setup(app *fiber.App, cfg *Config) {
// Global middleware
app.Use(recover.New())
app.Use(middleware.RequestID())
app.Use(middleware.Logging(cfg.Logger))
app.Use(middleware.JWTExtract())
// Health endpoints (no API key required)
app.Get("/health", cfg.Health.Liveness)
app.Get("/ready", cfg.Health.Readiness)
// API v1 routes (API key required)
api := app.Group("/api/v1", middleware.APIKey(cfg.APIKeys))
// LDAP Users
ldapUsers := api.Group("/ldap/users")
ldapUsers.Get("/", cfg.LDAPUsers.List)
ldapUsers.Get("/:uid", cfg.LDAPUsers.Get)
ldapUsers.Post("/", cfg.LDAPUsers.Create)
ldapUsers.Put("/:uid", cfg.LDAPUsers.Update)
ldapUsers.Delete("/:uid", cfg.LDAPUsers.Delete)
ldapUsers.Post("/:uid/password", cfg.LDAPUsers.ResetPassword)
ldapUsers.Get("/:uid/groups", cfg.LDAPUsers.ListGroups)
ldapUsers.Get("/:uid/services", cfg.LDAPUsers.ListServices)
ldapUsers.Get("/:uid/services/:domain", cfg.LDAPUsers.GetService)
// LDAP Groups
ldapGroups := api.Group("/ldap/groups")
ldapGroups.Get("/", cfg.LDAPGroups.List)
ldapGroups.Get("/:cn", cfg.LDAPGroups.Get)
ldapGroups.Post("/", cfg.LDAPGroups.Create)
ldapGroups.Put("/:cn", cfg.LDAPGroups.Update)
ldapGroups.Delete("/:cn", cfg.LDAPGroups.Delete)
ldapGroups.Get("/:cn/members", cfg.LDAPGroups.ListMembers)
ldapGroups.Post("/:cn/members", cfg.LDAPGroups.AddMembers)
ldapGroups.Delete("/:cn/members/:uid", cfg.LDAPGroups.RemoveMember)
// LDAP Entities (generic CRUD)
ldapEntities := api.Group("/ldap/entities")
ldapEntities.Get("/", cfg.LDAPEntities.ListTypes)
ldapEntities.Get("/:type", cfg.LDAPEntities.List)
ldapEntities.Post("/:type", cfg.LDAPEntities.Create)
ldapEntities.Get("/:type/:rdn", cfg.LDAPEntities.Get)
ldapEntities.Put("/:type/:rdn", cfg.LDAPEntities.Update)
ldapEntities.Delete("/:type/:rdn", cfg.LDAPEntities.Delete)
// DNS Zones
dnsZones := api.Group("/dns/zones")
dnsZones.Get("/", cfg.DNSZones.List)
dnsZones.Get("/:zoneId", cfg.DNSZones.Get)
dnsZones.Post("/", cfg.DNSZones.Create)
dnsZones.Put("/:zoneId", cfg.DNSZones.Update)
dnsZones.Delete("/:zoneId", cfg.DNSZones.Delete)
dnsZones.Post("/:zoneId/notify", cfg.DNSZones.Notify)
// DNS Records
dnsZones.Get("/:zoneId/records", cfg.DNSRecords.List)
dnsZones.Post("/:zoneId/records", cfg.DNSRecords.Create)
dnsZones.Put("/:zoneId/records", cfg.DNSRecords.Replace)
dnsZones.Delete("/:zoneId/records", cfg.DNSRecords.Delete)
// DNS Domains (orchestrated)
dnsDomains := api.Group("/dns/domains")
dnsDomains.Post("/setup", cfg.DNSRecords.DomainSetup)
dnsDomains.Post("/verify", cfg.DNSRecords.DomainVerify)
// DB Tenants
dbTenants := api.Group("/db/tenants")
dbTenants.Get("/", cfg.DBTenants.List)
dbTenants.Get("/:id", cfg.DBTenants.Get)
dbTenants.Post("/", cfg.DBTenants.Create)
dbTenants.Put("/:id", cfg.DBTenants.Update)
dbTenants.Delete("/:id", cfg.DBTenants.Delete)
// DB Users
dbUsers := api.Group("/db/users")
dbUsers.Get("/", cfg.DBUsers.List)
dbUsers.Get("/:id", cfg.DBUsers.Get)
dbUsers.Post("/", cfg.DBUsers.Create)
dbUsers.Put("/:id", cfg.DBUsers.Update)
dbUsers.Delete("/:id", cfg.DBUsers.Delete)
// Certificates
certs := api.Group("/certs")
certs.Get("/", cfg.Certs.List)
certs.Get("/:serialNumber", cfg.Certs.Get)
certs.Post("/request", cfg.Certs.Request)
certs.Post("/:serialNumber/renew", cfg.Certs.Renew)
certs.Post("/:serialNumber/revoke", cfg.Certs.Revoke)
// PGP Keys
pgp := api.Group("/pgp/keys")
pgp.Get("/", cfg.PGP.Search)
pgp.Get("/:keyId", cfg.PGP.Get)
pgp.Post("/", cfg.PGP.Upload)
pgp.Delete("/:keyId", cfg.PGP.Delete)
// PBX
if cfg.PBX != nil {
pbxTrunks := api.Group("/pbx/trunks")
pbxTrunks.Get("/", cfg.PBX.ListTrunks)
pbxTrunks.Post("/", cfg.PBX.CreateTrunk)
pbxTrunks.Get("/:id", cfg.PBX.GetTrunk)
pbxTrunks.Put("/:id", cfg.PBX.UpdateTrunk)
pbxTrunks.Delete("/:id", cfg.PBX.DeleteTrunk)
pbxTrunks.Post("/:id/activate", cfg.PBX.ActivateTrunk)
pbxTrunks.Post("/:id/deactivate", cfg.PBX.DeactivateTrunk)
pbxTrunks.Get("/:id/dids", cfg.PBX.ListTrunkDIDs)
pbxTrunks.Post("/:id/dids", cfg.PBX.CreateTrunkDID)
pbxTrunks.Delete("/:id/dids/:didId", cfg.PBX.DeleteTrunkDID)
pbxExts := api.Group("/pbx/extensions")
pbxExts.Get("/", cfg.PBX.ListExtensions)
pbxExts.Post("/", cfg.PBX.CreateExtension)
pbxExts.Get("/:id", cfg.PBX.GetExtension)
pbxExts.Put("/:id", cfg.PBX.UpdateExtension)
pbxExts.Delete("/:id", cfg.PBX.DeleteExtension)
pbxInbound := api.Group("/pbx/inbound-routes")
pbxInbound.Get("/", cfg.PBX.ListInboundRoutes)
pbxInbound.Post("/", cfg.PBX.CreateInboundRoute)
pbxInbound.Get("/:id", cfg.PBX.GetInboundRoute)
pbxInbound.Put("/:id", cfg.PBX.UpdateInboundRoute)
pbxInbound.Delete("/:id", cfg.PBX.DeleteInboundRoute)
pbxOutbound := api.Group("/pbx/outbound-routes")
pbxOutbound.Get("/", cfg.PBX.ListOutboundRoutes)
pbxOutbound.Post("/", cfg.PBX.CreateOutboundRoute)
pbxOutbound.Get("/:id", cfg.PBX.GetOutboundRoute)
pbxOutbound.Put("/:id", cfg.PBX.UpdateOutboundRoute)
pbxOutbound.Delete("/:id", cfg.PBX.DeleteOutboundRoute)
api.Get("/pbx/status", cfg.PBX.Status)
api.Post("/pbx/reload", cfg.PBX.Reload)
}
// Voice Agents
if cfg.VoiceAgent != nil {
voiceAgents := api.Group("/voice-agents")
voiceAgents.Get("/", cfg.VoiceAgent.ListConfigs)
voiceAgents.Post("/", cfg.VoiceAgent.CreateConfig)
voiceAgents.Get("/sessions/:sessionId", cfg.VoiceAgent.GetSession)
voiceAgents.Get("/:id", cfg.VoiceAgent.GetConfig)
voiceAgents.Put("/:id", cfg.VoiceAgent.UpdateConfig)
voiceAgents.Delete("/:id", cfg.VoiceAgent.DeleteConfig)
voiceAgents.Get("/:id/sessions", cfg.VoiceAgent.ListSessions)
}
// Personal Agents (user agent configs)
if cfg.PersonalAgent != nil {
agents := api.Group("/agents")
agents.Get("/me", cfg.PersonalAgent.GetMyConfig)
agents.Put("/me", cfg.PersonalAgent.UpsertMyConfig)
agents.Delete("/me", cfg.PersonalAgent.DeleteMyConfig)
}
// Personas
if cfg.Persona != nil {
personas := api.Group("/personas")
personas.Get("/", cfg.Persona.ListPersonas)
personas.Post("/", cfg.Persona.CreatePersona)
personas.Get("/:id", cfg.Persona.GetPersona)
personas.Put("/:id", cfg.Persona.UpdatePersona)
personas.Delete("/:id", cfg.Persona.DeletePersona)
personas.Get("/:id/self-model", cfg.Persona.GetSelfModel)
personas.Get("/:id/experiences", cfg.Persona.GetExperiences)
personas.Get("/:id/evaluations/:sessionId", cfg.Persona.GetEvaluations)
personas.Get("/:id/moral-pattern/:sessionId", cfg.Persona.GetMoralPattern)
}
// CardDAV
if cfg.CardDAV != nil {
cardDAVPrincipals := api.Group("/carddav/principals")
cardDAVPrincipals.Get("/", cfg.CardDAV.ListPrincipals)
cardDAVPrincipals.Get("/:username", cfg.CardDAV.GetPrincipal)
cardDAVPrincipals.Post("/", cfg.CardDAV.CreatePrincipal)
cardDAVPrincipals.Delete("/:username", cfg.CardDAV.DeletePrincipal)
cardDAVBooks := api.Group("/carddav/addressbooks")
cardDAVBooks.Get("/", cfg.CardDAV.ListAddressBooks)
cardDAVBooks.Get("/:id", cfg.CardDAV.GetAddressBook)
cardDAVBooks.Post("/", cfg.CardDAV.CreateAddressBook)
cardDAVBooks.Put("/:id", cfg.CardDAV.UpdateAddressBook)
cardDAVBooks.Delete("/:id", cfg.CardDAV.DeleteAddressBook)
cardDAVBooks.Get("/:id/contacts", cfg.CardDAV.ListContacts)
cardDAVBooks.Get("/:id/contacts/:uri", cfg.CardDAV.GetContact)
cardDAVBooks.Post("/:id/contacts", cfg.CardDAV.CreateContact)
cardDAVBooks.Put("/:id/contacts/:uri", cfg.CardDAV.UpdateContact)
cardDAVBooks.Delete("/:id/contacts/:uri", cfg.CardDAV.DeleteContact)
}
}