use iam_service::application::services::{ AuthService, AuthorizationService, RoleService, TenantService, }; use iam_service::models::{CreateRoleRequest, CreateTenantRequest, CreateUserRequest}; use sqlx::PgPool; use uuid::Uuid; #[tokio::test] async fn role_permission_grant_and_wildcard_match() -> Result<(), Box> { let database_url = match std::env::var("DATABASE_URL") { Ok(v) if !v.trim().is_empty() => v, _ => return Ok(()), }; let pool = PgPool::connect(&database_url).await?; let tenant_service = TenantService::new(pool.clone()); let role_service = RoleService::new(pool.clone()); let authz_service = AuthorizationService::new(pool.clone()); let auth_service = AuthService::new(pool.clone(), "unused".to_string()); let tenant = tenant_service .create_tenant(CreateTenantRequest { name: format!("rp-{}", Uuid::new_v4()), config: None, }) .await?; let admin = auth_service .register( tenant.id, CreateUserRequest { email: format!("admin-{}@example.com", Uuid::new_v4()), password: "Password12345".to_string(), }, ) .await?; let user = auth_service .register( tenant.id, CreateUserRequest { email: format!("user-{}@example.com", Uuid::new_v4()), password: "Password12345".to_string(), }, ) .await?; let _ = sqlx::query( r#" INSERT INTO permissions (code, description, resource, action) VALUES ('cms:article:create', 'Create article', 'article', 'create'), ('cms:*:*', 'CMS wildcard', '*', '*') ON CONFLICT (code) DO NOTHING "#, ) .execute(&pool) .await?; tenant_service .set_enabled_apps(tenant.id, vec!["cms".to_string()], None, admin.id) .await?; let role = role_service .create_role( tenant.id, CreateRoleRequest { name: "ContentAdmin".into(), description: None, }, admin.id, ) .await?; role_service .grant_permissions_to_role(tenant.id, role.id, vec!["cms:*:*".to_string()], admin.id) .await?; role_service .grant_role_to_users(tenant.id, role.id, vec![user.id], admin.id) .await?; authz_service .require_permission(tenant.id, user.id, "cms:article:create") .await?; Ok(()) }