mod common; use axum::http::StatusCode; use common::*; // ═══════════════════════════════════════════════════════════════════ // Role listing // ═══════════════════════════════════════════════════════════════════ #[tokio::test] async fn list_roles_includes_system_roles() { let (app, pool) = build_test_app().await; let admin = admin_token(&app, &pool, "roleadmin").await; let (status, body) = send(&app, get("/api/v1/roles", &admin)).await; assert_eq!(status, StatusCode::OK); let roles = body.as_array().unwrap(); let ids: Vec<&str> = roles.iter().map(|r| r["id"].as_str().unwrap()).collect(); assert!(ids.contains(&"super_admin")); assert!(ids.contains(&"admin")); assert!(ids.contains(&"user")); } // ═══════════════════════════════════════════════════════════════════ // Role CRUD // ═══════════════════════════════════════════════════════════════════ #[tokio::test] async fn role_crud() { let (app, pool) = build_test_app().await; let admin = admin_token(&app, &pool, "rolecrud").await; // Create custom role let (status, body) = send( &app, post( "/api/v1/roles", &admin, serde_json::json!({ "id": "custom-role-1", "name": "Custom Role", "description": "A test role", "permissions": ["model:read", "relay:use"] }), ), ).await; assert_eq!(status, StatusCode::CREATED, "create role: {body}"); // Get let (status, body) = send(&app, get("/api/v1/roles/custom-role-1", &admin)).await; assert_eq!(status, StatusCode::OK); assert_eq!(body["name"], "Custom Role"); // Update let (status, body) = send( &app, put( "/api/v1/roles/custom-role-1", &admin, serde_json::json!({ "description": "Updated description" }), ), ).await; assert_eq!(status, StatusCode::OK); assert_eq!(body["description"], "Updated description"); // Delete custom role let (status, _) = send(&app, delete("/api/v1/roles/custom-role-1", &admin)).await; assert_eq!(status, StatusCode::OK); } // ═══════════════════════════════════════════════════════════════════ // System role protection // ═══════════════════════════════════════════════════════════════════ #[tokio::test] async fn cannot_delete_system_role() { let (app, pool) = build_test_app().await; let admin = admin_token(&app, &pool, "sysrole").await; let (status, _) = send(&app, delete("/api/v1/roles/super_admin", &admin)).await; assert_ne!(status, StatusCode::OK); } // ═══════════════════════════════════════════════════════════════════ // Role creation forbidden for regular user // ═══════════════════════════════════════════════════════════════════ #[tokio::test] async fn role_create_forbidden_for_user() { let (app, _pool) = build_test_app().await; let token = register_token(&app, "rolenouser").await; let (status, _) = send( &app, post( "/api/v1/roles", &token, serde_json::json!({ "id": "x", "name": "X", "permissions": [] }), ), ).await; assert_eq!(status, StatusCode::FORBIDDEN); } // ═══════════════════════════════════════════════════════════════════ // Permission templates // ═══════════════════════════════════════════════════════════════════ #[tokio::test] async fn permission_template_crud() { let (app, pool) = build_test_app().await; let admin = admin_token(&app, &pool, "tmpladmin").await; // Create template let (status, body) = send( &app, post( "/api/v1/permission-templates", &admin, serde_json::json!({ "name": "Read-Only Template", "description": "Only read access", "permissions": ["model:read", "config:read", "prompt:read"] }), ), ).await; assert_eq!(status, StatusCode::CREATED, "create template: {body}"); let tmpl_id = body["id"].as_str().unwrap(); // List templates let (status, list) = send(&app, get("/api/v1/permission-templates", &admin)).await; assert_eq!(status, StatusCode::OK); assert!(list.is_array()); // Get template let (status, _) = send(&app, get(&format!("/api/v1/permission-templates/{tmpl_id}"), &admin)).await; assert_eq!(status, StatusCode::OK); // Delete template let (status, _) = send(&app, delete(&format!("/api/v1/permission-templates/{tmpl_id}"), &admin)).await; assert_eq!(status, StatusCode::OK); } #[tokio::test] async fn apply_permission_template() { let (app, pool) = build_test_app().await; let admin = admin_token(&app, &pool, "applyadmin").await; // Create template let (_, tmpl_body) = send( &app, post( "/api/v1/permission-templates", &admin, serde_json::json!({ "name": "Apply Test", "permissions": ["model:read"] }), ), ).await; let tmpl_id = tmpl_body["id"].as_str().unwrap(); // Create a target user let (_, _, reg) = register(&app, "targetuser", "target@test.io", DEFAULT_PASSWORD).await; let target_id = reg["account"]["id"].as_str().unwrap(); // Apply template let (status, _) = send( &app, post( &format!("/api/v1/permission-templates/{tmpl_id}/apply"), &admin, serde_json::json!({ "account_ids": [target_id] }), ), ).await; assert_eq!(status, StatusCode::OK); }