@@ -3,22 +3,56 @@ package main
33import (
44 "context"
55 "encoding/json"
6- "log"
7- "net/http"
8- "time"
9-
106 "general/internal/db"
117 "general/internal/engine"
128 "general/internal/middleware"
9+ "log"
10+ "net/http"
11+ "os"
12+ "os/signal"
13+ "syscall"
14+ "time"
1315
1416 "github.com/google/uuid"
1517 "github.com/jackc/pgx/v5"
1618 "github.com/jackc/pgx/v5/pgtype"
1719)
1820
21+ type Config struct {
22+ DBHost string
23+ DBPort string
24+ DBUser string
25+ DBPassword string
26+ DBName string
27+ Port string
28+ JWTSecret string
29+ }
30+
31+ func loadConfig () * Config {
32+ return & Config {
33+ DBHost : getEnv ("DB_HOST" , "localhost" ),
34+ DBPort : getEnv ("DB_PORT" , "5433" ),
35+ DBUser : getEnv ("DB_USER" , "asguard" ),
36+ DBPassword : getEnv ("DB_PASSWORD" , "devpassword" ),
37+ DBName : getEnv ("DB_NAME" , "general_engine" ),
38+ Port : getEnv ("PORT" , "8083" ),
39+ JWTSecret : getEnv ("JWT_SECRET" , "" ),
40+ }
41+
42+ }
43+
44+ func getEnv (key , defaultValue string ) string {
45+ if value := os .Getenv (key ); value != "" {
46+ return value
47+ }
48+
49+ return defaultValue
50+ }
51+
1952func main () {
20- connString := "postgres://asguard:devpassword@localhost:5433/general_engine?sslmode=disable"
2153
54+ cfg := loadConfig ()
55+ connString := "postgres://" + cfg .DBUser + ":" + cfg .DBPassword + "@" + cfg .DBHost + ":" + cfg .DBPort + "/" + cfg .DBName + "?sslmode=disable"
2256 conn , err := pgx .Connect (context .Background (), connString )
2357 if err != nil {
2458 log .Fatalf ("Failed to connect to database: %v" , err )
@@ -68,12 +102,34 @@ func main() {
68102 }
69103 })
70104
71- // WRAP WITH MIDDLEWARE - This is the key line
72- handler := middleware .AuthMiddleware (mux )
105+ // WRAP WITH MIDDLEWARE
106+ handler := middleware .AuthMiddleware ([] byte ( cfg . JWTSecret ))( mux )
73107
74- port := "8083"
75- log .Printf ("General Validation Engine starting on port %s" , port )
76- log .Fatal (http .ListenAndServe (":" + port , handler )) // Use handler, not nil
108+ srv := & http.Server {
109+ Addr : ":" + cfg .Port ,
110+ Handler : handler ,
111+ }
112+
113+ quit := make (chan os.Signal , 1 )
114+ signal .Notify (quit , syscall .SIGINT , syscall .SIGTERM )
115+
116+ go func () {
117+ log .Printf ("General Validation Engine starting on port %s" , cfg .Port )
118+ if err := srv .ListenAndServe (); err != nil && err != http .ErrServerClosed {
119+ log .Fatalf ("listen: %s\n " , err )
120+ }
121+ }()
122+
123+ <- quit
124+ log .Println ("Shutting Down Server....." )
125+
126+ ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
127+ defer cancel ()
128+
129+ if err := srv .Shutdown (ctx ); err != nil {
130+ log .Fatalf ("Server shutdown failed: %v" , err )
131+ }
132+ log .Println ("Server shutdown successfully" )
77133}
78134
79135func healthHandler (w http.ResponseWriter , r * http.Request ) {
@@ -187,19 +243,25 @@ func createRuleHandler(queries *db.Queries, ruleEngine *engine.RuleEngine) http.
187243 }
188244
189245 // Validate required fields
190- if req .Name == "" || req .Context == "" || req .Action == "" {
191- http .Error (w , "Mising required fields" , http .StatusBadRequest )
246+ if req .Name == "" || req .Context == "" || req .Condition == "" || req . Action == "" {
247+ http .Error (w , "Missing required fields: name, context, condition, action " , http .StatusBadRequest )
192248 return
193249 }
194250
251+ //validate action type
195252 validActions := map [string ]bool {"allow" : true , "block" : true , "challenge" : true , "flag" : true , "score" : true }
196253 if ! validActions [req .Action ] {
197254 http .Error (w , "Invalid action. Must be: allow, block, challenge, flag, score" , http .StatusBadRequest )
198255 return
199256 }
200257
201- ctx := r .Context ()
258+ // validate CEL syntax
259+ if _ , err := ruleEngine .Evaluator .CompileRule (req .Condition ); err != nil {
260+ http .Error (w , "Invalid CEL syntax: " + err .Error (), http .StatusBadRequest )
261+ return
262+ }
202263
264+ ctx := r .Context ()
203265 // Extract tenant ID from JWT context (works with UUID strings and slugs alike)
204266 tenantIDStr := middleware .GetTenantID (ctx )
205267 if tenantIDStr == "" {
@@ -295,6 +357,11 @@ func updateRuleHandler(queries *db.Queries, ruleEngine *engine.RuleEngine, id st
295357 return
296358 }
297359
360+ if _ , err := ruleEngine .Evaluator .CompileRule (req .Condition ); err != nil {
361+ http .Error (w , "Invalid CEL syntax: " + err .Error (), http .StatusBadRequest )
362+ return
363+ }
364+
298365 ctx := r .Context ()
299366
300367 tenantIDStr := middleware .GetTenantID (ctx )
0 commit comments