package middleware import ( "net/http" "net/http/httptest" "testing" "veza-backend-api/internal/models" "veza-backend-api/internal/services" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/lib/pq" "go.uber.org/zap" ) func TestRequireAPIKeyScope_PassthroughWithoutAPIKey(t *testing.T) { svc := services.NewAPIKeyService(nil, zap.NewNop()) router := gin.New() router.Use(RequireAPIKeyScope(svc)) router.GET("/test", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"ok": true}) }) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/test", nil) router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("expected 200, got %d", w.Code) } } func TestRequireAPIKeyScope_AllowsReadScopeOnGET(t *testing.T) { svc := services.NewAPIKeyService(nil, zap.NewNop()) apiKey := &models.APIKey{ ID: uuid.New(), UserID: uuid.New(), Name: "test", Scopes: pq.StringArray{"read"}, } router := gin.New() router.Use(func(c *gin.Context) { c.Set("api_key", apiKey) c.Next() }) router.Use(RequireAPIKeyScope(svc)) router.GET("/test", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"ok": true}) }) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/test", nil) router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("expected 200, got %d", w.Code) } } func TestRequireAPIKeyScope_DeniesWriteWithReadOnlyScope(t *testing.T) { svc := services.NewAPIKeyService(nil, zap.NewNop()) apiKey := &models.APIKey{ ID: uuid.New(), UserID: uuid.New(), Name: "test", Scopes: pq.StringArray{"read"}, } router := gin.New() router.Use(func(c *gin.Context) { c.Set("api_key", apiKey) c.Next() }) router.Use(RequireAPIKeyScope(svc)) router.POST("/test", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"ok": true}) }) w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/test", nil) router.ServeHTTP(w, req) if w.Code != http.StatusForbidden { t.Errorf("expected 403, got %d", w.Code) } } func TestRequireAPIKeyScope_AllowsWriteWithWriteScope(t *testing.T) { svc := services.NewAPIKeyService(nil, zap.NewNop()) apiKey := &models.APIKey{ ID: uuid.New(), UserID: uuid.New(), Name: "test", Scopes: pq.StringArray{"read", "write"}, } router := gin.New() router.Use(func(c *gin.Context) { c.Set("api_key", apiKey) c.Next() }) router.Use(RequireAPIKeyScope(svc)) router.POST("/test", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"ok": true}) }) w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/test", nil) router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("expected 200, got %d", w.Code) } } func TestRequireAPIKeyScope_AdminScopeAllowsAll(t *testing.T) { svc := services.NewAPIKeyService(nil, zap.NewNop()) apiKey := &models.APIKey{ ID: uuid.New(), UserID: uuid.New(), Name: "test", Scopes: pq.StringArray{"admin"}, } router := gin.New() router.Use(func(c *gin.Context) { c.Set("api_key", apiKey) c.Next() }) router.Use(RequireAPIKeyScope(svc)) router.DELETE("/test", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"ok": true}) }) w := httptest.NewRecorder() req, _ := http.NewRequest("DELETE", "/test", nil) router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("expected 200, got %d (admin should have write access)", w.Code) } }