Feat v0.7.7 api tokens ext permissions (#61)
All checks were successful
CI/CD / detect-changes (push) Successful in 4s
CI/CD / e2e-smoke (push) Has been skipped
CI/CD / test-frontend (push) Successful in 6s
CI/CD / test-runners (push) Has been skipped
CI/CD / test-go-pg (push) Successful in 2m48s
CI/CD / test-sqlite (push) Successful in 2m49s
CI/CD / build-and-deploy (push) Successful in 28s

Co-authored-by: Jeffrey Smith <jasafpro@gmail.com>
Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #61.
This commit is contained in:
2026-04-02 19:11:47 +00:00
committed by xcaliber
parent e02b13dc12
commit e4f0bdbd36
34 changed files with 1769 additions and 58 deletions

View File

@@ -115,6 +115,7 @@ func main() {
// Bootstrap admin from env (K8s secret) — upserts on every restart
handlers.BootstrapAdmin(cfg, stores, uekCache)
handlers.BootstrapPAT(cfg, stores)
// Seed additional users from env (dev/test only, skipped in production)
handlers.SeedUsers(cfg, stores, uekCache)
@@ -184,6 +185,10 @@ func main() {
handlers.InstallBundledPackages(cfg.BundledPackagesDir, bundledPkgDir, cfg.BundledPackages, stores, starlarkRunner)
}
// ── Register extension user permissions ─────
// Scan active packages on boot and populate the dynamic permission registry.
handlers.RegisterAllExtensionUserPermissions(stores)
// ── Trigger Engine ─────────────────
triggerEngine := triggers.New(stores, starlarkRunner, bus)
if err := triggerEngine.Start(context.Background()); err != nil {
@@ -342,7 +347,7 @@ func main() {
})
// WebSocket endpoint
base.GET("/ws", middleware.WsAuth(cfg, stores.Users, userCache, ticketAdapter), hub.HandleWebSocket)
base.GET("/ws", middleware.WsAuth(cfg, stores.Users, userCache, ticketAdapter, stores.APITokens), hub.HandleWebSocket)
// ── Auth routes (rate limited) ──────────────
authMode, err := auth.ParseMode(cfg.AuthMode)
@@ -448,12 +453,15 @@ func main() {
// Client SDK calls this on user interaction (debounced, max 1/min)
// to update last_activity_at for idle-timeout tracking.
activityGroup := api.Group("/auth")
activityGroup.Use(middleware.Auth(cfg, stores.Users, userCache))
activityGroup.Use(middleware.Auth(cfg, stores.Users, userCache, stores.APITokens))
activityGroup.POST("/activity", authH.Activity)
// ── Shared handler instances ──────────────
tokenH := handlers.NewAPITokenHandler(stores)
// ── Protected routes ────────────────────
protected := api.Group("")
protected.Use(middleware.Auth(cfg, stores.Users, userCache))
protected.Use(middleware.Auth(cfg, stores.Users, userCache, stores.APITokens))
protected.Use(middleware.ValidatePathParams())
{
// ── WebSocket Ticket ───────────
@@ -559,6 +567,11 @@ func main() {
permH := handlers.NewProfilePermissionsHandler(stores)
protected.GET("/profile/permissions", permH.GetMyPermissions)
// API Tokens (PATs)
protected.POST("/auth/tokens", tokenH.CreateToken)
protected.GET("/auth/tokens", tokenH.ListTokens)
protected.DELETE("/auth/tokens/:id", tokenH.RevokeToken)
// Boot payload — single-call SDK bootstrap
bootH := handlers.NewProfileBootstrapHandler(stores)
protected.GET("/profile/bootstrap", bootH.GetBootstrap)
@@ -680,7 +693,7 @@ func main() {
// ── Admin routes ────────────────────────
admin := api.Group("/admin")
admin.Use(middleware.Auth(cfg, stores.Users, userCache))
admin.Use(middleware.Auth(cfg, stores.Users, userCache, stores.APITokens))
admin.Use(middleware.RequireAdmin(stores))
admin.Use(middleware.ValidatePathParams())
{
@@ -696,6 +709,9 @@ func main() {
admin.POST("/users/:id/vault/reset", adm.ResetVault)
admin.DELETE("/users/:id", adm.DeleteUser)
// Admin API Tokens (create tokens for any user)
admin.POST("/tokens", tokenH.AdminCreateToken)
// Global settings
admin.GET("/settings", adm.ListGlobalSettings)
admin.GET("/settings/:key", adm.GetGlobalSetting)
@@ -910,7 +926,7 @@ func main() {
{
extAPIH := handlers.NewExtAPIHandler(stores, starlarkRunner)
extAPI := base.Group("/s/:slug/api")
extAPI.Use(middleware.Auth(cfg, stores.Users, userCache))
extAPI.Use(middleware.Auth(cfg, stores.Users, userCache, stores.APITokens))
extAPI.Any("/*path", extAPIH.Handle)
}