feat: add compliance modules 2-5 (dashboard, security templates, process manager, evidence collector)
All checks were successful
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 32s
CI/CD / test-python-backend-compliance (push) Successful in 34s
CI/CD / test-python-document-crawler (push) Successful in 23s
CI/CD / test-python-dsms-gateway (push) Successful in 21s
CI/CD / validate-canonical-controls (push) Successful in 11s
CI/CD / Deploy (push) Successful in 2s
All checks were successful
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 32s
CI/CD / test-python-backend-compliance (push) Successful in 34s
CI/CD / test-python-document-crawler (push) Successful in 23s
CI/CD / test-python-dsms-gateway (push) Successful in 21s
CI/CD / validate-canonical-controls (push) Successful in 11s
CI/CD / Deploy (push) Successful in 2s
Module 2: Extended Compliance Dashboard with roadmap, module-status, next-actions, snapshots, score-history Module 3: 7 German security document templates (IT-Sicherheitskonzept, Datenschutz, Backup, Logging, Incident-Response, Zugriff, Risikomanagement) Module 4: Compliance Process Manager with CRUD, complete/skip/seed, ~50 seed tasks, 3-tab UI Module 5: Evidence Collector Extended with automated checks, control-mapping, coverage report, 4-tab UI Also includes: canonical control library enhancements (verification method, categories, dedup), control generator improvements, RAG client extensions 52 tests pass, frontend builds clean. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/breakpilot/ai-compliance-sdk/internal/ucca"
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -157,3 +158,47 @@ func (h *RAGHandlers) CorpusVersionHistory(c *gin.Context) {
|
||||
"count": len(versions),
|
||||
})
|
||||
}
|
||||
|
||||
// HandleScrollChunks scrolls/lists all chunks in a Qdrant collection with pagination.
|
||||
// GET /sdk/v1/rag/scroll?collection=...&offset=...&limit=...
|
||||
func (h *RAGHandlers) HandleScrollChunks(c *gin.Context) {
|
||||
collection := c.Query("collection")
|
||||
if collection == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "query parameter 'collection' is required"})
|
||||
return
|
||||
}
|
||||
|
||||
if !AllowedCollections[collection] {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Unknown collection: " + collection})
|
||||
return
|
||||
}
|
||||
|
||||
// Parse limit (default 100, max 500)
|
||||
limit := 100
|
||||
if limitStr := c.Query("limit"); limitStr != "" {
|
||||
parsed, err := strconv.Atoi(limitStr)
|
||||
if err != nil || parsed < 1 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "limit must be a positive integer"})
|
||||
return
|
||||
}
|
||||
limit = parsed
|
||||
}
|
||||
if limit > 500 {
|
||||
limit = 500
|
||||
}
|
||||
|
||||
// Offset is optional (empty string = start from beginning)
|
||||
offset := c.Query("offset")
|
||||
|
||||
chunks, nextOffset, err := h.ragClient.ScrollChunks(c.Request.Context(), collection, offset, limit)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "scroll failed: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"chunks": chunks,
|
||||
"next_offset": nextOffset,
|
||||
"total": len(chunks),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -91,6 +91,72 @@ func TestSearch_WithCollectionParam_BindsCorrectly(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleScrollChunks_MissingCollection_Returns400(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
handler := &RAGHandlers{}
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request, _ = http.NewRequest("GET", "/sdk/v1/rag/scroll", nil)
|
||||
|
||||
handler.HandleScrollChunks(c)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("Expected 400, got %d", w.Code)
|
||||
}
|
||||
|
||||
var resp map[string]interface{}
|
||||
json.Unmarshal(w.Body.Bytes(), &resp)
|
||||
if resp["error"] == nil {
|
||||
t.Error("Expected error message in response")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleScrollChunks_InvalidCollection_Returns400(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
handler := &RAGHandlers{}
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request, _ = http.NewRequest("GET", "/sdk/v1/rag/scroll?collection=bp_evil_collection", nil)
|
||||
|
||||
handler.HandleScrollChunks(c)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("Expected 400, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleScrollChunks_InvalidLimit_Returns400(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
handler := &RAGHandlers{}
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request, _ = http.NewRequest("GET", "/sdk/v1/rag/scroll?collection=bp_compliance_ce&limit=abc", nil)
|
||||
|
||||
handler.HandleScrollChunks(c)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("Expected 400, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleScrollChunks_NegativeLimit_Returns400(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
handler := &RAGHandlers{}
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request, _ = http.NewRequest("GET", "/sdk/v1/rag/scroll?collection=bp_compliance_ce&limit=-5", nil)
|
||||
|
||||
handler.HandleScrollChunks(c)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("Expected 400, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearch_EmptyCollection_IsAllowed(t *testing.T) {
|
||||
// Empty collection should be allowed (falls back to default in the handler)
|
||||
body := `{"query":"test"}`
|
||||
|
||||
Reference in New Issue
Block a user