from datetime import UTC, datetime from decimal import Decimal import pytest from app.core.exceptions import AppException from app.domains.asset.models import AssetLocation, AssetLocationAdmin from app.identity.person_models import IdentityPerson from app.intelligence.access import project_snapshot, resolve_access_plan from app.intelligence.models import IntelligenceSnapshot from app.intelligence.provider_registry import BUSINESS_AUDIENCE_KEY def _person(index: int) -> IdentityPerson: return IdentityPerson( source_system="test", hris_person_id=f"access-{index}", work_email=f"access-{index}@example.test", employment_status="active", ) @pytest.mark.asyncio async def test_access_plan_enforces_role_dimensions_scope_and_cost_boundary(db_session): user = _person(1) location = AssetLocation(code="ACCESSRGN", name="Access Region") db_session.add_all([user, location]) await db_session.flush() db_session.add( AssetLocationAdmin(location_id=location.id, person_id=user.id), ) await db_session.commit() hr = await resolve_access_plan(db_session, person_id=user.id, role_names=["hr"]) assert [row.dimension for row in hr.dimensions] == ["people_org", "lifecycle"] assert all(row.subject.audience_key == BUSINESS_AUDIENCE_KEY for row in hr.dimensions) assert hr.can_view_paid_cost is False assert hr.can_manage_recommendations is False regional = await resolve_access_plan( db_session, person_id=user.id, role_names=["asset_admin"], ) assert [row.dimension for row in regional.dimensions] == ["assets"] assert regional.dimensions[0].subject.subject_type == "domain" assert regional.dimensions[0].subject.audience_key.startswith("asset_region:") finance = await resolve_access_plan( db_session, person_id=user.id, role_names=["finance", "asset_admin"], ) assert [row.dimension for row in finance.dimensions] == [ "assets", "software_api", "cloud_network", "cost_efficiency", ] assert all(row.subject.subject_type == "platform" for row in finance.dimensions) assert finance.can_view_paid_cost is True cloud = await resolve_access_plan( db_session, person_id=user.id, role_names=["cloud_admin"], ) assert [row.dimension for row in cloud.dimensions] == [ "cloud_network", "cost_efficiency", ] assert cloud.can_view_paid_cost is True asset_global = await resolve_access_plan( db_session, person_id=user.id, role_names=["asset_global_admin"], ) assert [row.dimension for row in asset_global.dimensions] == ["assets"] assert asset_global.dimensions[0].subject.subject_type == "platform" auditor = await resolve_access_plan( db_session, person_id=user.id, role_names=["security_auditor"], ) assert [row.dimension for row in auditor.dimensions] == ["security_compliance"] management = await resolve_access_plan( db_session, person_id=user.id, role_names=["management"], ) assert len(management.dimensions) == 8 assert management.can_view_paid_cost is False assert management.can_manage_recommendations is False global_admin = await resolve_access_plan( db_session, person_id=user.id, role_names=["it_admin"], ) assert global_admin.can_manage_recommendations is True assert global_admin.can_force_generate is True with pytest.raises(AppException) as exc_info: await resolve_access_plan(db_session, person_id=user.id, role_names=["employee"]) assert exc_info.value.status_code == 403 @pytest.mark.asyncio async def test_asset_admin_without_active_location_scope_is_denied(db_session): user = _person(2) inactive_location = AssetLocation( code="INACTIVERGN", name="Inactive Access Region", is_active=False, ) db_session.add_all([user, inactive_location]) await db_session.flush() db_session.add( AssetLocationAdmin(location_id=inactive_location.id, person_id=user.id), ) await db_session.commit() with pytest.raises(AppException, match="active Intelligence data scope"): await resolve_access_plan(db_session, person_id=user.id, role_names=["asset_admin"]) def test_snapshot_projection_strips_other_domains_and_raw_reference_map(): now = datetime(2026, 8, 16, tzinfo=UTC) snapshot = IntelligenceSnapshot( subject_type="platform", subject_id="platform", audience_key=BUSINESS_AUDIENCE_KEY, score_version="2026.08.1", facts_hash="a" * 64, overall_score=Decimal("85"), confidence_score=Decimal("90"), grade="healthy", dimensions=[ { "key": "people_org", "score": 90, "confidence": 80, "weight": 0.1, "metrics": [{"key": "people.org_coverage", "evidence_refs": ["person_01"]}], }, { "key": "cloud_network", "score": 70, "confidence": 100, "weight": 0.15, "metrics": [{"key": "cloud.sync_freshness", "evidence_refs": ["scope_01"]}], }, ], aggregate_facts={ "people_org": {"active_count": 500}, "cloud_network": {"scope_count": 20}, }, reference_map={ "person_01": {"kind": "person", "object_id": "private-person-id"}, "scope_01": {"kind": "cloud_scope", "object_id": "private-scope-id"}, }, data_as_of=now, created_at=now, ) projected = project_snapshot(snapshot, dimensions=["people_org"]) assert [row["key"] for row in projected.public["dimensions"]] == ["people_org"] assert projected.public["confidence_score"] == "80.00" assert projected.public["aggregate_facts"] == { "people_org": {"active_count": 500}, } assert "reference_map" not in projected.public assert "private-person-id" not in str(projected.public) assert projected.local_reference_map == { "person_01": {"kind": "person", "object_id": "private-person-id"}, } combined = project_snapshot( snapshot, dimensions=["cloud_network", "people_org"], ) assert [row["key"] for row in combined.public["dimensions"]] == [ "people_org", "cloud_network", ] with pytest.raises(ValueError, match="does not contain"): project_snapshot(snapshot, dimensions=["lifecycle"])