mirror of
https://github.com/Dvorinka/Primora.git
synced 2026-10-28 15:51:23 +00:00
feat: phase 4 integrations — connectors, rybbit analytics, webhooks
- core.integrations (migration 00005) with AES-256-GCM-encrypted credentials (PRIMORA_ENCRYPTION_KEY, hex/base64, dev fallback); has_credentials serialization only — secrets never leave the server - /projects/:id/integrations list/create/delete/test; health check hits the stored base URL with a 5s timeout and records status - Rybbit connector: GET …/integrations/:id/analytics proxies /api/organizations + /api/sites/* server-side into a normalized shape - core.webhooks + core.webhook_deliveries; CRUD, deliveries, test, and POST …/deploy-markers. Events: issue.created (new fingerprint on ingest), deploy.marker, webhook.test. X-Primora-Signature HMAC-SHA256 over the raw body; in-process dispatcher, 3 attempts, quadratic backoff, 10s timeout, pending-scan on boot - HTTPS enforced for public targets; HTTP allowed for loopback/private/ self-hosted sinks - Integrations page (connectors + webhooks tabs, inline analytics, delivery log, secret-shown-once), demo-mode stubs - 12 new primora_* MCP tools - workspace 0.4.0 Authored By: TDvorak <[email protected]>
This commit is contained in:
1 parent
8cfddf9184
commit
e25eb92339
82 files changed
+5710
-61
No files matched your search
@@ -24,17 +24,19 @@ import (
|
||||
"github.com/tdvorak/primora/apps/backend/internal/middleware"
|
||||
"github.com/tdvorak/primora/apps/backend/internal/observability"
|
||||
"github.com/tdvorak/primora/apps/backend/internal/repositories"
|
||||
"github.com/tdvorak/primora/apps/backend/internal/secrets"
|
||||
"github.com/tdvorak/primora/apps/backend/internal/services"
|
||||
"github.com/tdvorak/primora/apps/backend/internal/storage"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
Config config.Config
|
||||
Router *gin.Engine
|
||||
Logger *slog.Logger
|
||||
DB *pgxpool.Pool
|
||||
Redis *redis.Client
|
||||
DBX *dbx.Client
|
||||
Config config.Config
|
||||
Router *gin.Engine
|
||||
Logger *slog.Logger
|
||||
DB *pgxpool.Pool
|
||||
Redis *redis.Client
|
||||
DBX *dbx.Client
|
||||
Platform *services.PlatformService
|
||||
}
|
||||
|
||||
func Bootstrap(ctx context.Context) (*App, error) {
|
||||
@@ -82,20 +84,27 @@ func Bootstrap(ctx context.Context) (*App, error) {
|
||||
}
|
||||
dbxClient := dbx.NewClient(logger, cfg.DBXDataDir)
|
||||
repo := repositories.NewCoreRepository(dbPool)
|
||||
platform := services.NewPlatformService(repo, store, services.NewMailer(cfg), os.Getenv("VITE_APP_URL"), dbxClient, firstPartyDBSeeds(cfg))
|
||||
encryptor, err := secrets.NewEncryptor(cfg.EncryptionKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("encryption key: %w", err)
|
||||
}
|
||||
platform := services.NewPlatformService(repo, store, services.NewMailer(cfg), os.Getenv("VITE_APP_URL"), dbxClient, firstPartyDBSeeds(cfg), encryptor, logger)
|
||||
|
||||
if cfg.Env == "production" {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
if cfg.Env != "production" && os.Getenv("PRIMORA_ENCRYPTION_KEY") == "" {
|
||||
logger.Warn("PRIMORA_ENCRYPTION_KEY unset — using the built-in development key")
|
||||
}
|
||||
router := gin.New()
|
||||
router.Use(gin.Recovery())
|
||||
router.Use(middleware.RequestID())
|
||||
router.Use(middleware.Logger(logger))
|
||||
|
||||
|
||||
metrics := observability.NewMetrics()
|
||||
router.Use(middleware.Metrics(metrics))
|
||||
router.Use(middleware.Compression())
|
||||
|
||||
|
||||
// CORS configuration - update AllowedOrigins for production
|
||||
corsOrigins := []string{cfg.PublicURL}
|
||||
if cfg.Env == "development" {
|
||||
@@ -104,7 +113,7 @@ func Bootstrap(ctx context.Context) (*App, error) {
|
||||
router.Use(middleware.CORS(middleware.CORSConfig{
|
||||
AllowedOrigins: corsOrigins,
|
||||
}))
|
||||
|
||||
|
||||
router.Use(middleware.AuthMiddleware{
|
||||
Queries: repo,
|
||||
Logger: logger,
|
||||
@@ -149,12 +158,13 @@ func Bootstrap(ctx context.Context) (*App, error) {
|
||||
handler.Register(router)
|
||||
|
||||
return &App{
|
||||
Config: cfg,
|
||||
Router: router,
|
||||
Logger: logger,
|
||||
DB: dbPool,
|
||||
Redis: redisClient,
|
||||
DBX: dbxClient,
|
||||
Config: cfg,
|
||||
Router: router,
|
||||
Logger: logger,
|
||||
DB: dbPool,
|
||||
Redis: redisClient,
|
||||
DBX: dbxClient,
|
||||
Platform: platform,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -196,6 +206,9 @@ func firstPartyDBSeeds(cfg config.Config) []services.ManagedDBSeed {
|
||||
}
|
||||
|
||||
func (a *App) Close() error {
|
||||
if a.Platform != nil {
|
||||
a.Platform.Close()
|
||||
}
|
||||
if a.DBX != nil {
|
||||
a.DBX.Close()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user