[wip] single runtime handling
This commit is contained in:
@@ -9,6 +9,10 @@ use attune_common::{
|
||||
models::*,
|
||||
repositories::{
|
||||
action::{ActionRepository, CreateActionInput},
|
||||
identity::{
|
||||
CreatePermissionAssignmentInput, CreatePermissionSetInput,
|
||||
PermissionAssignmentRepository, PermissionSetRepository,
|
||||
},
|
||||
pack::{CreatePackInput, PackRepository},
|
||||
trigger::{CreateTriggerInput, TriggerRepository},
|
||||
workflow::{CreateWorkflowDefinitionInput, WorkflowDefinitionRepository},
|
||||
@@ -246,6 +250,47 @@ impl TestContext {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Create and authenticate a test user with identity + permission admin grants.
|
||||
pub async fn with_admin_auth(mut self) -> Result<Self> {
|
||||
let unique_id = uuid::Uuid::new_v4().to_string().replace("-", "")[..8].to_string();
|
||||
let login = format!("adminuser_{}", unique_id);
|
||||
let token = self.create_test_user(&login).await?;
|
||||
|
||||
let identity = attune_common::repositories::identity::IdentityRepository::find_by_login(
|
||||
&self.pool, &login,
|
||||
)
|
||||
.await?
|
||||
.ok_or_else(|| format!("Failed to find newly created identity '{}'", login))?;
|
||||
|
||||
let permset = PermissionSetRepository::create(
|
||||
&self.pool,
|
||||
CreatePermissionSetInput {
|
||||
r#ref: "core.admin".to_string(),
|
||||
pack: None,
|
||||
pack_ref: None,
|
||||
label: Some("Admin".to_string()),
|
||||
description: Some("Test admin permission set".to_string()),
|
||||
grants: json!([
|
||||
{"resource": "identities", "actions": ["read", "create", "update", "delete"]},
|
||||
{"resource": "permissions", "actions": ["read", "create", "update", "delete", "manage"]}
|
||||
]),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
PermissionAssignmentRepository::create(
|
||||
&self.pool,
|
||||
CreatePermissionAssignmentInput {
|
||||
identity: identity.id,
|
||||
permset: permset.id,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.token = Some(token);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Create a test user and return access token
|
||||
async fn create_test_user(&self, login: &str) -> Result<String> {
|
||||
// Register via API to get real token
|
||||
|
||||
178
crates/api/tests/permissions_api_tests.rs
Normal file
178
crates/api/tests/permissions_api_tests.rs
Normal file
@@ -0,0 +1,178 @@
|
||||
use axum::http::StatusCode;
|
||||
use helpers::*;
|
||||
use serde_json::json;
|
||||
|
||||
mod helpers;
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore = "integration test — requires database"]
|
||||
async fn test_identity_crud_and_permission_assignment_flow() {
|
||||
let ctx = TestContext::new()
|
||||
.await
|
||||
.expect("Failed to create test context")
|
||||
.with_admin_auth()
|
||||
.await
|
||||
.expect("Failed to create admin-authenticated test user");
|
||||
|
||||
let create_identity_response = ctx
|
||||
.post(
|
||||
"/api/v1/identities",
|
||||
json!({
|
||||
"login": "managed_user",
|
||||
"display_name": "Managed User",
|
||||
"password": "ManagedPass123!",
|
||||
"attributes": {
|
||||
"department": "platform"
|
||||
}
|
||||
}),
|
||||
ctx.token(),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create identity");
|
||||
|
||||
assert_eq!(create_identity_response.status(), StatusCode::CREATED);
|
||||
|
||||
let created_identity: serde_json::Value = create_identity_response
|
||||
.json()
|
||||
.await
|
||||
.expect("Failed to parse identity create response");
|
||||
let identity_id = created_identity["data"]["id"]
|
||||
.as_i64()
|
||||
.expect("Missing identity id");
|
||||
|
||||
let list_identities_response = ctx
|
||||
.get("/api/v1/identities", ctx.token())
|
||||
.await
|
||||
.expect("Failed to list identities");
|
||||
assert_eq!(list_identities_response.status(), StatusCode::OK);
|
||||
|
||||
let identities_body: serde_json::Value = list_identities_response
|
||||
.json()
|
||||
.await
|
||||
.expect("Failed to parse identities response");
|
||||
assert!(identities_body["data"]
|
||||
.as_array()
|
||||
.expect("Expected data array")
|
||||
.iter()
|
||||
.any(|item| item["login"] == "managed_user"));
|
||||
|
||||
let update_identity_response = ctx
|
||||
.put(
|
||||
&format!("/api/v1/identities/{}", identity_id),
|
||||
json!({
|
||||
"display_name": "Managed User Updated",
|
||||
"attributes": {
|
||||
"department": "security"
|
||||
}
|
||||
}),
|
||||
ctx.token(),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to update identity");
|
||||
assert_eq!(update_identity_response.status(), StatusCode::OK);
|
||||
|
||||
let get_identity_response = ctx
|
||||
.get(&format!("/api/v1/identities/{}", identity_id), ctx.token())
|
||||
.await
|
||||
.expect("Failed to get identity");
|
||||
assert_eq!(get_identity_response.status(), StatusCode::OK);
|
||||
|
||||
let identity_body: serde_json::Value = get_identity_response
|
||||
.json()
|
||||
.await
|
||||
.expect("Failed to parse get identity response");
|
||||
assert_eq!(
|
||||
identity_body["data"]["display_name"],
|
||||
"Managed User Updated"
|
||||
);
|
||||
assert_eq!(
|
||||
identity_body["data"]["attributes"]["department"],
|
||||
"security"
|
||||
);
|
||||
|
||||
let permission_sets_response = ctx
|
||||
.get("/api/v1/permissions/sets", ctx.token())
|
||||
.await
|
||||
.expect("Failed to list permission sets");
|
||||
assert_eq!(permission_sets_response.status(), StatusCode::OK);
|
||||
|
||||
let assignment_response = ctx
|
||||
.post(
|
||||
"/api/v1/permissions/assignments",
|
||||
json!({
|
||||
"identity_id": identity_id,
|
||||
"permission_set_ref": "core.admin"
|
||||
}),
|
||||
ctx.token(),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create permission assignment");
|
||||
assert_eq!(assignment_response.status(), StatusCode::CREATED);
|
||||
|
||||
let assignment_body: serde_json::Value = assignment_response
|
||||
.json()
|
||||
.await
|
||||
.expect("Failed to parse permission assignment response");
|
||||
let assignment_id = assignment_body["data"]["id"]
|
||||
.as_i64()
|
||||
.expect("Missing assignment id");
|
||||
assert_eq!(assignment_body["data"]["permission_set_ref"], "core.admin");
|
||||
|
||||
let list_assignments_response = ctx
|
||||
.get(
|
||||
&format!("/api/v1/identities/{}/permissions", identity_id),
|
||||
ctx.token(),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to list identity permissions");
|
||||
assert_eq!(list_assignments_response.status(), StatusCode::OK);
|
||||
|
||||
let assignments_body: serde_json::Value = list_assignments_response
|
||||
.json()
|
||||
.await
|
||||
.expect("Failed to parse identity permissions response");
|
||||
assert!(assignments_body
|
||||
.as_array()
|
||||
.expect("Expected array response")
|
||||
.iter()
|
||||
.any(|item| item["permission_set_ref"] == "core.admin"));
|
||||
|
||||
let delete_assignment_response = ctx
|
||||
.delete(
|
||||
&format!("/api/v1/permissions/assignments/{}", assignment_id),
|
||||
ctx.token(),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to delete assignment");
|
||||
assert_eq!(delete_assignment_response.status(), StatusCode::OK);
|
||||
|
||||
let delete_identity_response = ctx
|
||||
.delete(&format!("/api/v1/identities/{}", identity_id), ctx.token())
|
||||
.await
|
||||
.expect("Failed to delete identity");
|
||||
assert_eq!(delete_identity_response.status(), StatusCode::OK);
|
||||
|
||||
let missing_identity_response = ctx
|
||||
.get(&format!("/api/v1/identities/{}", identity_id), ctx.token())
|
||||
.await
|
||||
.expect("Failed to fetch deleted identity");
|
||||
assert_eq!(missing_identity_response.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore = "integration test — requires database"]
|
||||
async fn test_plain_authenticated_user_cannot_manage_identities() {
|
||||
let ctx = TestContext::new()
|
||||
.await
|
||||
.expect("Failed to create test context")
|
||||
.with_auth()
|
||||
.await
|
||||
.expect("Failed to authenticate plain test user");
|
||||
|
||||
let response = ctx
|
||||
.get("/api/v1/identities", ctx.token())
|
||||
.await
|
||||
.expect("Failed to call identities endpoint");
|
||||
|
||||
assert_eq!(response.status(), StatusCode::FORBIDDEN);
|
||||
}
|
||||
Reference in New Issue
Block a user