mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-07-14 07:57:26 +02:00
Add files via upload
This commit is contained in:
@@ -6,6 +6,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cyberstrike-ai/internal/mcp"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -19,6 +21,184 @@ func newRBACTestDB(t *testing.T) *DB {
|
||||
return db
|
||||
}
|
||||
|
||||
func TestRBACToolExecutionOwnershipAccess(t *testing.T) {
|
||||
db := newRBACTestDB(t)
|
||||
for _, exec := range []*mcp.ToolExecution{
|
||||
{ID: "exec-u1", ToolName: "one", Status: "completed", StartTime: time.Now(), OwnerUserID: "u1"},
|
||||
{ID: "exec-u2", ToolName: "two", Status: "completed", StartTime: time.Now(), OwnerUserID: "u2"},
|
||||
{ID: "exec-legacy", ToolName: "legacy", Status: "completed", StartTime: time.Now()},
|
||||
} {
|
||||
if err := db.SaveToolExecution(exec); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
access := RBACListAccess{UserID: "u1", Scope: RBACScopeAssigned}
|
||||
rows, err := db.LoadToolExecutionListPageForAccess(0, 20, "", "", access)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(rows) != 1 || rows[0].ID != "exec-u1" {
|
||||
t.Fatalf("rows = %#v, want only exec-u1", rows)
|
||||
}
|
||||
summary, err := db.LoadToolStatsSummaryForAccess(10, access)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if summary.Summary.TotalCalls != 1 || summary.Summary.ToolCount != 1 || len(summary.TopTools) != 1 || summary.TopTools[0].ToolName != "one" {
|
||||
t.Fatalf("scoped summary = %#v", summary)
|
||||
}
|
||||
if !db.UserCanAccessToolExecution("u1", RBACScopeAssigned, "exec-u1") {
|
||||
t.Fatal("owner could not access execution")
|
||||
}
|
||||
if db.UserCanAccessToolExecution("u1", RBACScopeAssigned, "exec-u2") {
|
||||
t.Fatal("foreign execution was accessible")
|
||||
}
|
||||
if db.UserCanAccessToolExecution("u1", RBACScopeAssigned, "exec-legacy") {
|
||||
t.Fatal("ownerless legacy execution did not fail closed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRBACGroupAndUploadOwnership(t *testing.T) {
|
||||
db := newRBACTestDB(t)
|
||||
group1, err := db.CreateGroup("u1 group", "", "u1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
group2, err := db.CreateGroup("u2 group", "", "u2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
groups, err := db.ListGroupsForAccess("u1", RBACScopeAssigned)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(groups) != 1 || groups[0].ID != group1.ID {
|
||||
t.Fatalf("groups = %#v, want only %s (not %s)", groups, group1.ID, group2.ID)
|
||||
}
|
||||
if db.UserCanAccessGroup("u1", RBACScopeAssigned, group2.ID) {
|
||||
t.Fatal("foreign group was accessible")
|
||||
}
|
||||
|
||||
conversation, err := db.CreateConversation("upload", ConversationCreateMeta{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.UpsertChatUploadArtifact("2026-07-10/"+conversation.ID+"/a.txt", conversation.ID, "u1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if conv, owner, ok := db.GetChatUploadArtifact("2026-07-10/" + conversation.ID + "/a.txt"); !ok || conv != conversation.ID || owner != "u1" {
|
||||
t.Fatalf("artifact = conv=%q owner=%q ok=%v", conv, owner, ok)
|
||||
}
|
||||
if err := db.RenameChatUploadArtifactPath("2026-07-10/"+conversation.ID+"/a.txt", "2026-07-10/"+conversation.ID+"/b.txt"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, _, ok := db.GetChatUploadArtifact("2026-07-10/" + conversation.ID + "/b.txt"); !ok {
|
||||
t.Fatal("renamed artifact metadata missing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSystemRoleBootstrapDoesNotLeakManagementReadPermissions(t *testing.T) {
|
||||
db := newRBACTestDB(t)
|
||||
catalog := map[string]string{
|
||||
"auth:self": "self", "project:read": "projects", "project:write": "project writes",
|
||||
"agent:local-execute": "local tools",
|
||||
"rbac:read": "rbac", "config:read": "config", "audit:read": "audit", "terminal:execute": "terminal",
|
||||
"mcp:execute": "invoke", "mcp:write": "manage", "mcp:external:execute": "external invoke",
|
||||
"workflow:execute": "run", "workflow:write": "manage definitions", "knowledge:write": "manage knowledge",
|
||||
}
|
||||
if err := db.BootstrapRBAC("hash", catalog); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
viewer, err := db.CreateRBACUser("viewer-policy", "Viewer", "hash", true, []string{RBACSystemRoleViewer})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
viewerAccess, err := db.ResolveRBACAccess(viewer.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !viewerAccess.Permissions["project:read"] || viewerAccess.Permissions["rbac:read"] || viewerAccess.Permissions["config:read"] || viewerAccess.Permissions["audit:read"] {
|
||||
t.Fatalf("unexpected viewer permissions: %#v", viewerAccess.Permissions)
|
||||
}
|
||||
auditor, err := db.CreateRBACUser("auditor-policy", "Auditor", "hash", true, []string{RBACSystemRoleAuditor})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
auditorAccess, err := db.ResolveRBACAccess(auditor.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !auditorAccess.Permissions["audit:read"] || auditorAccess.Permissions["config:read"] || auditorAccess.Permissions["rbac:read"] {
|
||||
t.Fatalf("unexpected auditor permissions: %#v", auditorAccess.Permissions)
|
||||
}
|
||||
operator, err := db.CreateRBACUser("operator-policy", "Operator", "hash", true, []string{RBACSystemRoleOperator})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
operatorAccess, err := db.ResolveRBACAccess(operator.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !operatorAccess.Permissions["mcp:execute"] || operatorAccess.Permissions["mcp:write"] || operatorAccess.Permissions["mcp:external:execute"] {
|
||||
t.Fatalf("unexpected operator MCP permissions: %#v", operatorAccess.Permissions)
|
||||
}
|
||||
if !operatorAccess.Permissions["workflow:execute"] || operatorAccess.Permissions["workflow:write"] || operatorAccess.Permissions["knowledge:write"] {
|
||||
t.Fatalf("operator received global definition mutation permissions: %#v", operatorAccess.Permissions)
|
||||
}
|
||||
if !operatorAccess.Permissions["agent:local-execute"] {
|
||||
t.Fatalf("operator is missing explicit local tool permission: %#v", operatorAccess.Permissions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermissionScopeDoesNotWidenAcrossUnrelatedRoles(t *testing.T) {
|
||||
db := newRBACTestDB(t)
|
||||
catalog := map[string]string{"auth:self": "self", "project:read": "read", "project:write": "write", "audit:read": "audit"}
|
||||
if err := db.BootstrapRBAC("hash", catalog); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ownWrite, err := db.UpsertRBACRole("", "own-writer", "", RBACScopeOwn, []string{"project:write"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
user, err := db.CreateRBACUser("mixed-scope", "Mixed", "hash", true, []string{RBACSystemRoleAuditor, ownWrite.ID})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
access, err := db.ResolveRBACAccess(user.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if access.Scope != RBACScopeAll {
|
||||
t.Fatalf("compatibility scope = %q, want all", access.Scope)
|
||||
}
|
||||
if got := access.PermissionScopes["project:read"]; got != RBACScopeAll {
|
||||
t.Fatalf("project:read scope = %q, want all", got)
|
||||
}
|
||||
if got := access.PermissionScopes["project:write"]; got != RBACScopeOwn {
|
||||
t.Fatalf("project:write scope widened to %q, want own", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoleRejectsUnknownPermission(t *testing.T) {
|
||||
db := newRBACTestDB(t)
|
||||
if err := db.BootstrapRBAC("hash", map[string]string{"auth:self": "self"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := db.UpsertRBACRole("", "future-role", "", RBACScopeAssigned, []string{"future:permission"}); err == nil {
|
||||
t.Fatal("unknown permission was persisted")
|
||||
}
|
||||
if _, err := db.Exec(`INSERT INTO rbac_permissions (key, description, created_at) VALUES ('stale:permission', '', ?)`, time.Now()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.BootstrapRBAC("hash", map[string]string{"auth:self": "self"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var count int
|
||||
if err := db.QueryRow(`SELECT COUNT(*) FROM rbac_permissions WHERE key = 'stale:permission'`).Scan(&count); err != nil || count != 0 {
|
||||
t.Fatalf("stale permission survived bootstrap: count=%d err=%v", count, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRBACProjectAndConversationListAccess(t *testing.T) {
|
||||
db := newRBACTestDB(t)
|
||||
p1, _ := db.CreateProject(&Project{Name: "visible"})
|
||||
|
||||
Reference in New Issue
Block a user