Add files via upload

This commit is contained in:
公明
2026-07-13 16:10:07 +08:00
committed by GitHub
parent a497c4bfcd
commit 8a3229aa5a
4 changed files with 150 additions and 15 deletions
+91
View File
@@ -2,7 +2,10 @@ package handler
import (
"bytes"
"cyberstrike-ai/internal/audit"
"cyberstrike-ai/internal/config"
"cyberstrike-ai/internal/database"
"cyberstrike-ai/internal/security"
"encoding/json"
"net/http"
"net/http/httptest"
@@ -69,6 +72,40 @@ func TestRBACAssignResourceBatchIsAtomicAndLegacyCompatible(t *testing.T) {
}
}
func TestRBACAssignResourceAutoDetectsActualType(t *testing.T) {
gin.SetMode(gin.TestMode)
db, err := database.NewDB(filepath.Join(t.TempDir(), "rbac-auto-detect.db"), zap.NewNop())
if err != nil {
t.Fatal(err)
}
defer db.Close()
user, err := db.CreateRBACUser("auto-member", "Auto Member", "hash", true, nil)
if err != nil {
t.Fatal(err)
}
project, err := db.CreateProject(&database.Project{Name: "auto-project"})
if err != nil {
t.Fatal(err)
}
h := NewRBACHandler(db, zap.NewNop())
router := gin.New()
router.POST("/api/rbac/resource-assignments", h.AssignResource)
response := performRBACJSONRequest(t, router, map[string]interface{}{
"user_id": user.ID, "resource_type": "conversation", "resource_ids": []string{project.ID}, "auto_detect": true,
})
if response.Code != http.StatusOK {
t.Fatalf("auto-detect status = %d, body = %s", response.Code, response.Body.String())
}
rows, err := db.ListRBACResourceAssignments(user.ID)
if err != nil {
t.Fatal(err)
}
if len(rows) != 1 || rows[0].ResourceType != "project" || rows[0].ResourceID != project.ID {
t.Fatalf("auto-detected assignments = %#v, want project/%s", rows, project.ID)
}
}
func TestRBACAssignableResourcesArePaged(t *testing.T) {
gin.SetMode(gin.TestMode)
db, err := database.NewDB(filepath.Join(t.TempDir(), "rbac-picker.db"), zap.NewNop())
@@ -104,6 +141,60 @@ func TestRBACAssignableResourcesArePaged(t *testing.T) {
}
}
func TestRBACDeleteResourceAssignmentAuditsTargetResource(t *testing.T) {
gin.SetMode(gin.TestMode)
db, err := database.NewDB(filepath.Join(t.TempDir(), "rbac-revoke-audit.db"), zap.NewNop())
if err != nil {
t.Fatal(err)
}
defer db.Close()
user, err := db.CreateRBACUser("audit-member", "Audit Member", "hash", true, nil)
if err != nil {
t.Fatal(err)
}
project, err := db.CreateProject(&database.Project{Name: "audit-project"})
if err != nil {
t.Fatal(err)
}
if _, err := db.AssignResourcesToUser(user.ID, "project", []string{project.ID}); err != nil {
t.Fatal(err)
}
assignments, err := db.ListRBACResourceAssignments(user.ID)
if err != nil || len(assignments) != 1 {
t.Fatalf("assignments = %#v, err = %v", assignments, err)
}
h := NewRBACHandler(db, zap.NewNop())
h.SetAudit(audit.NewService(db, &config.Config{}, zap.NewNop()))
router := gin.New()
router.Use(func(c *gin.Context) {
c.Set(security.ContextUsernameKey, "operator-user")
c.Next()
})
router.DELETE("/api/rbac/resource-assignments/:id", h.DeleteResourceAssignment)
request := httptest.NewRequest(http.MethodDelete, "/api/rbac/resource-assignments/"+assignments[0].ID, nil)
recorder := httptest.NewRecorder()
router.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Fatalf("status = %d, body = %s", recorder.Code, recorder.Body.String())
}
logs, err := db.ListAuditLogs(database.ListAuditLogsFilter{Category: "rbac", RelatedUserID: user.ID, Limit: 10})
if err != nil {
t.Fatal(err)
}
if len(logs) != 1 {
t.Fatalf("audit logs = %#v, want one member-related revoke", logs)
}
log := logs[0]
if log.Action != "delete_resource_assignment" || log.Actor != "operator-user" || log.ResourceType != "project" || log.ResourceID != project.ID {
t.Fatalf("audit log = %#v", log)
}
if log.Detail["user_id"] != user.ID || log.Detail["assignment_id"] != assignments[0].ID {
t.Fatalf("audit detail = %#v", log.Detail)
}
}
func performRBACJSONRequest(t *testing.T, router http.Handler, payload map[string]interface{}) *httptest.ResponseRecorder {
t.Helper()
body, err := json.Marshal(payload)