Feat v0.6.3 dead code sweep (#38)
All checks were successful
CI/CD / detect-changes (push) Successful in 4s
CI/CD / test-frontend (push) Successful in 6s
CI/CD / test-sqlite (push) Successful in 2m46s
CI/CD / test-go-pg (push) Successful in 2m47s
CI/CD / build-and-deploy (push) Successful in 26s

Co-authored-by: Jeffrey Smith <jasafpro@gmail.com>
Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #38.
This commit is contained in:
2026-03-31 12:37:47 +00:00
committed by xcaliber
parent a887b4c78b
commit 3d4228f868
130 changed files with 522 additions and 1215 deletions

View File

@@ -36,7 +36,6 @@ import (
sqliteStore "switchboard-core/store/sqlite"
)
// v0.33.0: Embedded OpenAPI spec and Swagger UI for /api/docs.
//
//go:embed static/openapi.yaml
var openapiSpec []byte
@@ -59,13 +58,10 @@ func main() {
// ── Server startup ──────────────────────
cfg := config.Load()
// v0.33.0: Structured logging — must be first so all subsequent
// Structured logging — must be first so all subsequent
// log output goes through slog.
logging.Init(cfg.LogFormat, cfg.LogLevel)
// v0.29.1: Config-file provider types (Ollama, LiteLLM, vLLM, etc.)
var stores store.Stores
uekCache := crypto.NewUEKCache()
var keyResolver *crypto.KeyResolver
@@ -109,7 +105,6 @@ func main() {
stores = postgres.NewStores(database.DB)
}
// v0.33.0: Start Prometheus DB pool collector
metrics.StartDBCollector(database.DB, 15*time.Second)
// Bootstrap admin from env (K8s secret) — upserts on every restart
@@ -161,23 +156,18 @@ func main() {
sandbox.New(sandbox.DefaultConfig()),
stores,
)
// v0.38.1: connections module — extension connection resolution
starlarkRunner.SetConnectionResolver(handlers.NewConnectionResolverAdapter(stores, keyResolver))
// v0.29.2: db module — extension namespaced table access
starlarkRunner.SetDB(database.DB, database.IsPostgres())
// v0.38.0: disk-based script loading + load() support
if cfg.StoragePath != "" {
starlarkRunner.SetPackagesDir(cfg.StoragePath + "/packages")
}
// v0.5.0: realtime module — extension publish to WebSocket channels
starlarkRunner.SetBus(bus)
// v0.38.5: allow extensions to reach private IPs (self-hosted Gitea, etc.)
if os.Getenv("EXT_ALLOW_PRIVATE_IPS") == "true" {
starlarkRunner.SetAllowPrivateIPs(true)
log.Printf(" ⚠️ Extension SSRF protection relaxed: private IPs allowed")
}
// ── Bundled Packages (v0.3.8) ───────────────
// ── Bundled Packages ───────────────
// Auto-install bundled .pkg archives on first run.
// Skipped if SKIP_BUNDLED_PACKAGES=true or packages already exist.
if !cfg.SkipBundledPackages && stores.Packages != nil {
@@ -188,7 +178,7 @@ func main() {
handlers.InstallBundledPackages(cfg.BundledPackagesDir, bundledPkgDir, cfg.BundledPackages, stores, starlarkRunner)
}
// ── Trigger Engine (v0.2.2) ─────────────────
// ── Trigger Engine ─────────────────
triggerEngine := triggers.New(stores, starlarkRunner, bus)
if err := triggerEngine.Start(context.Background()); err != nil {
log.Printf(" ⚠️ Trigger engine start: %v", err)
@@ -210,7 +200,7 @@ func main() {
// ── WebSocket Hub ─────────────────────────
hub := events.NewHub(bus, middleware.GetAllowedOrigins(cfg))
// ── Cluster Registry (v0.6.0) ────────────
// ── Cluster Registry ────────────
// PG-backed node self-registration + heartbeat. No-op on SQLite.
var clusterReg *cluster.Registry
if database.IsPostgres() && stores.Cluster != nil {
@@ -231,10 +221,10 @@ func main() {
}
}
// ── WebSocket Ticket Store (v0.32.0: PG-backed for cross-pod) ─────
// ── WebSocket Ticket Store ─────
ticketAdapter := &events.TicketValidatorAdapter{Store: stores.Tickets}
// ── Notification Service (v0.20.0) ───────
// ── Notification Service ───────
var notifSvc *notifications.Service
if stores.Notifications != nil {
notifSvc = notifications.NewService(stores.Notifications, hub).
@@ -277,7 +267,6 @@ func main() {
c.JSON(200, info)
})
// v0.32.0: Kubernetes probe endpoints
// Liveness: process is alive and serving (no dependency checks).
base.GET("/healthz/live", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
@@ -299,10 +288,8 @@ func main() {
c.JSON(200, gin.H{"status": "ok"})
})
// v0.33.0: Prometheus metrics endpoint (no auth — Prometheus scrapes directly)
base.GET("/metrics", gin.WrapH(promhttp.Handler()))
// v0.33.0: OpenAPI spec + Swagger UI (no auth — documentation)
base.GET("/api/docs", func(c *gin.Context) {
c.Data(http.StatusOK, "text/html; charset=utf-8", swaggerHTML)
})
@@ -311,7 +298,6 @@ func main() {
patched := bytes.Replace(openapiSpec, []byte("${VERSION}"), []byte(Version), 1)
c.Data(http.StatusOK, "application/yaml", patched)
})
// v0.6.2: Dynamic OpenAPI spec with extension routes merged in
base.GET("/api/docs/openapi.json", func(c *gin.Context) {
spec, err := handlers.BuildOpenAPISpec(stores, openapiSpec, Version)
if err != nil {
@@ -401,7 +387,7 @@ func main() {
extH := handlers.NewExtensionHandler(stores)
api.GET("/extensions/:id/assets/*path", extH.ServeExtensionAsset)
// ── Webhook Inbound (v0.2.2) ──────────────
// ── Webhook Inbound ──────────────
// Public routes — HMAC-verified in handler, no auth middleware.
api.POST("/hooks/:package_id/:slug", triggerEngine.HandleWebhook)
api.GET("/hooks/:package_id/:slug", triggerEngine.HandleWebhook)
@@ -409,7 +395,7 @@ func main() {
// ── Workflow Engine (shared by public + protected routes) ──
wfEngine := workflow.NewEngine(stores, bus, starlarkRunner)
// ── Public Workflow Entry (v0.3.3) ─────
// ── Public Workflow Entry ─────
publicWfH := handlers.NewWorkflowPublicHandler(wfEngine, stores)
publicWf := api.Group("/public/workflows")
publicWf.Use(authLimiter.Limit())
@@ -419,7 +405,7 @@ func main() {
publicWf.POST("/advance/:token", publicWfH.AdvancePublic)
}
// ── Workflow Scanner (v0.3.3) ──────────
// ── Workflow Scanner ──────────
wfScanner := workflow.NewScanner(stores, bus)
wfScanner.Start()
defer wfScanner.Stop()
@@ -429,7 +415,7 @@ func main() {
protected.Use(middleware.Auth(cfg, stores.Users, userCache))
protected.Use(middleware.ValidatePathParams())
{
// ── WebSocket Ticket (v0.28.8) ───────────
// ── WebSocket Ticket ───────────
// Issue a single-use ticket for WebSocket auth.
// Client fetches this, then connects with ?ticket=<opaque>.
protected.POST("/ws/ticket", func(c *gin.Context) {
@@ -442,15 +428,15 @@ func main() {
c.JSON(http.StatusOK, gin.H{"ticket": ticket})
})
// Presence (v0.23.1)
// Presence
presence := handlers.NewPresenceHandler(stores)
protected.POST("/presence/heartbeat", presence.Heartbeat)
protected.GET("/presence", presence.Query)
// User search (v0.23.2 — DM user picker)
// User search
protected.GET("/users/search", presence.SearchUsers)
// Workflows (v0.26.1 — team-owned staged processes)
// Workflows
wfH := handlers.NewWorkflowHandler(stores)
protected.GET("/workflows", wfH.List)
protected.POST("/workflows", middleware.RequirePermission(auth.PermWorkflowCreate, stores), wfH.Create)
@@ -466,7 +452,7 @@ func main() {
protected.POST("/workflows/:id/clone", middleware.RequirePermission(auth.PermWorkflowCreate, stores), wfH.Clone)
protected.GET("/workflows/:id/versions/:version", wfH.GetVersion)
// Workflow instances + assignments (v0.3.2)
// Workflow instances + assignments
wfInstH := handlers.NewWorkflowInstanceHandler(wfEngine, stores)
protected.POST("/workflows/:id/instances", middleware.RequirePermission(auth.PermWorkflowSubmit, stores), wfInstH.Start)
protected.GET("/workflows/:id/instances", wfInstH.ListInstances)
@@ -481,16 +467,16 @@ func main() {
protected.POST("/assignments/:id/cancel", middleware.RequirePermission(auth.PermWorkflowCreate, stores), wfAssignH.Cancel)
protected.GET("/assignments/mine", wfAssignH.ListMine)
// Workflow signoffs (v0.3.4)
// Workflow signoffs
wfSignoffH := handlers.NewWorkflowSignoffHandler(wfEngine, stores)
protected.POST("/instances/:iid/signoffs", wfSignoffH.Submit)
protected.GET("/instances/:iid/signoffs", wfSignoffH.List)
// Surface discovery (v0.25.0, v0.28.7: unified packages)
// Surface discovery
pkgH := handlers.NewPackageHandler(stores)
protected.GET("/surfaces", pkgH.ListEnabledSurfaces)
// User package management (v0.30.0)
// User package management
userPkgDir := ""
if cfg.StoragePath != "" {
userPkgDir = cfg.StoragePath + "/packages"
@@ -500,11 +486,11 @@ func main() {
protected.POST("/packages/install", userPkgH.InstallPersonalPackage)
protected.DELETE("/packages/:id", userPkgH.DeletePersonalPackage)
// Connection Type Discovery (v0.38.4)
// Connection Type Discovery
connTypeH := handlers.NewConnectionTypeHandler(stores)
protected.GET("/connection-types", connTypeH.ListConnectionTypes)
// Extension Connections (personal scope — v0.38.1)
// Extension Connections (personal scope
connH := handlers.NewConnectionHandler(stores, keyResolver)
protected.GET("/connections", connH.ListConnections)
protected.POST("/connections", connH.CreateConnection)
@@ -521,21 +507,21 @@ func main() {
protected.GET("/settings", settings.GetSettings)
protected.PUT("/settings", settings.UpdateSettings)
// Documentation (v0.6.1)
// Documentation
docsDir := findDocsDir()
docsH := handlers.NewDocsHandler(docsDir)
protected.GET("/docs", docsH.ListDocs)
protected.GET("/docs/:name", docsH.GetDoc)
// Permission bootstrap (v0.37.1) — self-service resolved permissions
// Permission bootstrap — self-service resolved permissions
permH := handlers.NewProfilePermissionsHandler(stores)
protected.GET("/profile/permissions", permH.GetMyPermissions)
// Boot payload (v0.37.15) — single-call SDK bootstrap
// Boot payload — single-call SDK bootstrap
bootH := handlers.NewProfileBootstrapHandler(stores)
protected.GET("/profile/bootstrap", bootH.GetBootstrap)
// Notifications (v0.20.0)
// Notifications
notifH := handlers.NewNotificationHandler(stores, hub)
protected.GET("/notifications", notifH.List)
protected.GET("/notifications/unread-count", notifH.UnreadCount)
@@ -543,12 +529,12 @@ func main() {
protected.POST("/notifications/mark-all-read", notifH.MarkAllRead)
protected.DELETE("/notifications/:id", notifH.Delete)
// Notification preferences (v0.20.0 Phase 3)
// Notification preferences
protected.GET("/notifications/preferences", notifH.ListPreferences)
protected.PUT("/notifications/preferences/:type", notifH.SetPreference)
protected.DELETE("/notifications/preferences/:type", notifH.DeletePreference)
// ── Scheduled Tasks — User (v0.2.2) ────
// ── Scheduled Tasks — User ────
userSchedH := handlers.NewScheduleHandler(stores, triggerEngine)
protected.GET("/schedules", userSchedH.ListMySchedules)
protected.POST("/schedules", userSchedH.CreateSchedule)
@@ -562,7 +548,7 @@ func main() {
teams := handlers.NewTeamHandler(stores, keyResolver)
protected.GET("/teams/mine", teams.MyTeams)
// Groups (user: my groups — v0.16.0)
// Groups (user: my groups
groupH := handlers.NewGroupHandler(stores)
protected.GET("/groups/mine", groupH.MyGroups)
@@ -580,18 +566,18 @@ func main() {
// Team groups (team admins manage team-scoped groups)
teamScoped.GET("/groups", groupH.ListTeamGroups)
// Team connections (v0.38.1)
// Team connections
teamScoped.GET("/connections", teams.ListTeamConnections)
teamScoped.POST("/connections", teams.CreateTeamConnection)
teamScoped.PUT("/connections/:id", teams.UpdateTeamConnection)
teamScoped.DELETE("/connections/:id", teams.DeleteTeamConnection)
// Team package management (v0.30.0)
// Team package management
teamPkgH := handlers.NewUserPackageHandler(stores, userPkgDir)
teamScoped.POST("/packages/install", teamPkgH.InstallTeamPackage)
teamScoped.DELETE("/packages/:id", teamPkgH.DeleteTeamPackage)
// Team package settings — cascade overrides (v0.2.0)
// Team package settings — cascade overrides
teamPkgSettingsH := handlers.NewTeamPackageSettingsHandler(stores)
teamScoped.GET("/packages/:id/settings", teamPkgSettingsH.GetTeamPackageSettings)
teamScoped.PUT("/packages/:id/settings", teamPkgSettingsH.UpdateTeamPackageSettings)
@@ -601,7 +587,7 @@ func main() {
teamScoped.GET("/audit", teams.ListTeamAuditLog)
teamScoped.GET("/audit/actions", teams.ListTeamAuditActions)
// Team workflows — self-service (v0.31.2)
// Team workflows — self-service
teamWfH := handlers.NewWorkflowHandler(stores)
teamScoped.GET("/workflows", teamWfH.ListTeamWorkflows)
teamScoped.POST("/workflows", teamWfH.CreateTeamWorkflow)
@@ -619,7 +605,7 @@ func main() {
teamScoped.GET("/workflows/available", teamWfH.ListGlobalWorkflows)
teamScoped.GET("/workflows/:id/versions/:version", teamWfH.GetTeamWorkflowVersion)
// Team workflow instances + assignments (v0.3.2)
// Team workflow instances + assignments
teamWfInstH := handlers.NewWorkflowInstanceHandler(wfEngine, stores)
teamScoped.POST("/workflows/:id/instances", teamWfInstH.Start)
teamScoped.GET("/workflows/:id/instances", teamWfInstH.ListInstances)
@@ -630,7 +616,7 @@ func main() {
teamWfAssignH := handlers.NewWorkflowAssignmentHandler(wfEngine, stores)
teamScoped.GET("/assignments", teamWfAssignH.ListByTeam)
// Team workflow signoffs (v0.3.4)
// Team workflow signoffs
teamWfSignoffH := handlers.NewWorkflowSignoffHandler(wfEngine, stores)
teamScoped.POST("/instances/:iid/signoffs", teamWfSignoffH.Submit)
teamScoped.GET("/instances/:iid/signoffs", teamWfSignoffH.List)
@@ -674,7 +660,7 @@ func main() {
// Stats
admin.GET("/stats", adm.GetStats)
// Global Connections (v0.38.1)
// Global Connections
admin.GET("/connections", adm.ListGlobalConnections)
admin.POST("/connections", adm.CreateGlobalConnection)
admin.PUT("/connections/:id", adm.UpdateGlobalConnection)
@@ -692,7 +678,7 @@ func main() {
admin.PUT("/teams/:id/members/:memberId", teamAdm.UpdateMember)
admin.DELETE("/teams/:id/members/:memberId", teamAdm.RemoveMember)
// Admin broadcast (v0.28.6)
// Admin broadcast
adminNotifH := handlers.NewNotificationHandler(stores, hub)
admin.POST("/notifications/broadcast", adminNotifH.Broadcast)
@@ -700,7 +686,7 @@ func main() {
admin.GET("/audit", adm.ListAuditLog)
admin.GET("/audit/actions", adm.ListAuditActions)
// Groups (admin — v0.16.0)
// Groups (admin
groupAdm := handlers.NewGroupHandler(stores)
admin.GET("/groups", groupAdm.ListGroups)
admin.POST("/groups", groupAdm.CreateGroup)
@@ -711,11 +697,11 @@ func main() {
admin.POST("/groups/:id/members", groupAdm.AddMember)
admin.DELETE("/groups/:id/members/:userId", groupAdm.RemoveMember)
// Permissions (v0.24.2)
// Permissions
admin.GET("/permissions", groupAdm.ListPermissions)
admin.GET("/users/:id/permissions", groupAdm.GetUserPermissions)
// Resource Grants (admin — v0.16.0)
// Resource Grants (admin
admin.GET("/grants/:type/:id", groupAdm.GetResourceGrant)
admin.PUT("/grants/:type/:id", groupAdm.SetResourceGrant)
@@ -728,7 +714,7 @@ func main() {
// Vault
admin.GET("/vault/status", adm.VaultStatus)
// Email / SMTP test (v0.20.0 Phase 3)
// Email / SMTP test
emailAdm := handlers.NewAdminEmailHandler(stores)
admin.POST("/notifications/test-email", emailAdm.TestEmail)
@@ -739,7 +725,7 @@ func main() {
admin.PUT("/extensions/:id", extAdm.AdminUpdateExtension)
admin.DELETE("/extensions/:id", extAdm.AdminUninstallExtension)
// Extension permissions (admin — v0.29.0)
// Extension permissions (admin
extPermH := handlers.NewExtPermHandler(stores)
admin.GET("/extensions/:id/permissions", extPermH.ListPackagePermissions)
admin.GET("/extensions/:id/review", extPermH.ReviewPackage)
@@ -747,21 +733,21 @@ func main() {
admin.POST("/extensions/:id/permissions/:perm/revoke", extPermH.RevokePermission)
admin.POST("/extensions/:id/permissions/grant-all", extPermH.GrantAllPermissions)
// Extension secrets (admin — v0.29.0 CS3)
// Extension secrets (admin
extSecH := handlers.NewExtSecretsHandler(stores)
admin.GET("/extensions/:id/secrets", extSecH.GetSecrets)
admin.PUT("/extensions/:id/secrets", extSecH.SetSecrets)
admin.DELETE("/extensions/:id/secrets", extSecH.DeleteSecrets)
// Package lifecycle management (v0.28.7 — replaces surfaces + extensions admin)
// Package lifecycle management
packagesDir := ""
if cfg.StoragePath != "" {
packagesDir = cfg.StoragePath + "/packages"
}
pkgAdm := handlers.NewPackageHandler(stores, packagesDir)
pkgAdm.SetSandbox(sandbox.New(sandbox.DefaultConfig())) // v0.30.0: schema migrations
pkgAdm.SetSandbox(sandbox.New(sandbox.DefaultConfig()))
// Package registry — must be registered before /packages/:id (v0.30.0)
// Package registry — must be registered before /packages/:id
registryH := handlers.NewRegistryHandler(stores, packagesDir, pkgAdm)
admin.GET("/packages/registry", registryH.BrowseRegistry)
admin.POST("/packages/registry/install", registryH.InstallFromRegistry)
@@ -772,20 +758,20 @@ func main() {
admin.PUT("/packages/:id/enable", pkgAdm.EnablePackage)
admin.PUT("/packages/:id/disable", pkgAdm.DisablePackage)
admin.DELETE("/packages/:id", pkgAdm.DeletePackage)
admin.GET("/packages/:id/settings", pkgAdm.GetPackageSettings) // v0.30.0
admin.PUT("/packages/:id/settings", pkgAdm.UpdatePackageSettings) // v0.30.0
admin.GET("/packages/:id/dependencies", pkgAdm.ListDependencies) // v0.38.2
admin.GET("/packages/:id/consumers", pkgAdm.ListConsumers) // v0.38.2
admin.POST("/packages/:id/test-tool", pkgAdm.TestTool) // v0.38.2
admin.POST("/packages/:id/update", pkgAdm.UpdatePackage) // v0.5.4
admin.GET("/packages/:id/export", pkgAdm.ExportPackage) // v0.5.4
admin.GET("/dependencies", pkgAdm.ListAllDependencies) // v0.38.2
admin.GET("/packages/:id/settings", pkgAdm.GetPackageSettings)
admin.PUT("/packages/:id/settings", pkgAdm.UpdatePackageSettings)
admin.GET("/packages/:id/dependencies", pkgAdm.ListDependencies)
admin.GET("/packages/:id/consumers", pkgAdm.ListConsumers)
admin.POST("/packages/:id/test-tool", pkgAdm.TestTool)
admin.POST("/packages/:id/update", pkgAdm.UpdatePackage)
admin.GET("/packages/:id/export", pkgAdm.ExportPackage)
admin.GET("/dependencies", pkgAdm.ListAllDependencies)
// Workflow package export (v0.30.2)
// Workflow package export
wfPkgH := handlers.NewWorkflowPackageHandler(stores)
admin.GET("/workflows/:id/export", wfPkgH.ExportWorkflowPackage)
// ── Triggers (v0.2.2) ─────────────────
// ── Triggers ─────────────────
trigH := handlers.NewTriggerHandler(stores, triggerEngine)
admin.GET("/triggers", trigH.ListTriggers)
admin.GET("/triggers/:id", trigH.GetTrigger)
@@ -795,20 +781,20 @@ func main() {
admin.GET("/triggers/:id/logs", trigH.ListTriggerLogs)
admin.GET("/packages/:id/triggers", trigH.ListPackageTriggers)
// ── Scheduled Tasks — Admin (v0.2.2) ──
// ── Scheduled Tasks — Admin ──
schedH := handlers.NewScheduleHandler(stores, triggerEngine)
admin.GET("/schedules", schedH.AdminListSchedules)
admin.PUT("/schedules/:id/enable", schedH.AdminEnableSchedule)
admin.PUT("/schedules/:id/disable", schedH.AdminDisableSchedule)
admin.DELETE("/schedules/:id", schedH.AdminDeleteSchedule)
// ── Cluster (v0.6.0) ─────────────────
// ── Cluster ─────────────────
if stores.Cluster != nil {
clusterH := handlers.NewClusterHandler(stores)
admin.GET("/cluster", clusterH.ListNodes)
}
// ── Backup/Restore (v0.6.1) ─────────
// ── Backup/Restore ─────────
backupH := handlers.NewBackupHandler(stores, packagesDir, cfg.StoragePath)
admin.POST("/backup", backupH.CreateBackup)
admin.GET("/backups", backupH.ListBackups)
@@ -828,9 +814,7 @@ func main() {
}
// ── Page Routes ──────────────────────────
// v0.27.0: Extension surface static assets (JS, CSS, images).
// Served without auth — same rationale as extension assets (script tags can't send headers).
// v0.28.7: on-disk path moved to /data/packages/, URL stays /surfaces/:id/ for stability.
// In split deployment, nginx serves these from /data/packages/ directly.
if cfg.StoragePath != "" {
packagesStaticDir := cfg.StoragePath + "/packages"
@@ -850,13 +834,12 @@ func main() {
pages.SetVersion(Version)
pageEngine := pages.New(cfg, stores)
// Root redirect → configurable default surface (v0.2.1)
// Root redirect → configurable default surface
base.GET("/", pageEngine.DefaultSurfaceRedirect())
// Login page — no auth required
base.GET("/login", pageEngine.RenderLogin())
// v0.25.0: Surface routes generated from manifest registry.
// Replaces manual per-surface route blocks.
pageEngine.RegisterPageRoutes(base, pages.PageRouteMiddleware{
Authenticated: middleware.AuthOrRedirect(cfg, stores.Users, userCache),
@@ -864,10 +847,9 @@ func main() {
middleware.AuthOrRedirect(cfg, stores.Users, userCache),
middleware.RequireAdminPage(stores),
},
Session: middleware.AuthOrRedirect(cfg, stores.Users, userCache), // TODO: session middleware for workflow visitors (v0.2.0)
Session: middleware.AuthOrRedirect(cfg, stores.Users, userCache), // TODO: session middleware for workflow visitors
})
// v0.29.1: Extension API routes — Starlark packages serve JSON endpoints.
// Mounted at /s/:slug/api/* with JWT auth (returns 401, not redirect).
{
extAPIH := handlers.NewExtAPIHandler(stores, starlarkRunner)