"""One fail-closed visibility contract for every resource-directory API.""" from __future__ import annotations from dataclasses import dataclass from typing import Any from sqlalchemy import and_, exists, false, func, or_, select, true, tuple_ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import aliased from app.core.rbac import ( AUDITOR_ROLE, CLOUD_ADMIN_ROLE, GLOBAL_ADMIN_ROLE, can_view_cloud_resources, get_subordinate_person_ids, has_role, ) from app.domains.cmdb.models import ( GRANT_STATUS_ACTIVE, SCOPE_TYPE_AZURE_RESOURCE_GROUP, CmdbCloudAccessGrant, CmdbCloudResource, CmdbCloudScope, CmdbResourceFinding, CmdbResourceGovernance, ) @dataclass(frozen=True) class DirectoryVisibility: full: bool person_ids: tuple[str, ...] = () scope_pairs: tuple[tuple[str, str], ...] = () resource_group_pairs: tuple[tuple[str, str], ...] = () singleton_integration_ids: tuple[str, ...] = () async def resolve_directory_visibility( db: AsyncSession, *, user_id: str, role_names: list[str], ) -> DirectoryVisibility: """Resolve full-reader or self/manager/grant/assignment visibility.""" if has_role(role_names, GLOBAL_ADMIN_ROLE, CLOUD_ADMIN_ROLE, AUDITOR_ROLE): return DirectoryVisibility(full=True) if not can_view_cloud_resources(role_names): return DirectoryVisibility(full=False) reports = await get_subordinate_person_ids(db, user_id) person_ids = tuple(dict.fromkeys([user_id, *reports])) accessible_scope_rows = (await db.execute(select( CmdbCloudScope.integration_id, CmdbCloudScope.external_id, CmdbCloudScope.scope_type, ).outerjoin( CmdbCloudAccessGrant, and_( CmdbCloudAccessGrant.scope_id == CmdbCloudScope.id, CmdbCloudAccessGrant.person_id.in_(person_ids), CmdbCloudAccessGrant.status == GRANT_STATUS_ACTIVE, ), ).where( CmdbCloudScope.deleted_at.is_(None), or_( CmdbCloudScope.owner_person_id.in_(person_ids), CmdbCloudAccessGrant.id.is_not(None), ), ).distinct())).all() scope_pairs: set[tuple[str, str]] = set() resource_group_pairs: set[tuple[str, str]] = set() for integration_id, external_id, scope_type in accessible_scope_rows: pair = (str(integration_id), str(external_id)) if scope_type == SCOPE_TYPE_AZURE_RESOURCE_GROUP: resource_group_pairs.add(pair) else: scope_pairs.add(pair) scope_counts = dict((str(integration_id), int(count)) for integration_id, count in ( await db.execute(select( CmdbCloudScope.integration_id, func.count(CmdbCloudScope.id), ).where( CmdbCloudScope.scope_type != SCOPE_TYPE_AZURE_RESOURCE_GROUP, CmdbCloudScope.deleted_at.is_(None), ).group_by(CmdbCloudScope.integration_id)) ).all()) singleton_integration_ids = tuple(sorted({ integration_id for integration_id, _external_id in scope_pairs if scope_counts.get(integration_id) == 1 })) return DirectoryVisibility( full=False, person_ids=person_ids, scope_pairs=tuple(sorted(scope_pairs)), resource_group_pairs=tuple(sorted(resource_group_pairs)), singleton_integration_ids=singleton_integration_ids, ) def directory_visibility_clause(vis: DirectoryVisibility) -> Any: if vis.full: return true() if not vis.person_ids: return false() terms: list[Any] = [CmdbCloudResource.owner_person_id.in_(vis.person_ids)] parent_resource = aliased(CmdbCloudResource) terms.append(exists(select(parent_resource.id).where( parent_resource.integration_id == CmdbCloudResource.integration_id, parent_resource.deleted_at.is_(None), parent_resource.resource_type == "domain", parent_resource.owner_person_id.in_(vis.person_ids), or_( and_( CmdbCloudResource.resource_type == "dns_record", parent_resource.provider_resource_id == CmdbCloudResource.normalized_metadata["zone_name"].as_string(), ), and_( CmdbCloudResource.resource_type == "cdn_domain", parent_resource.provider_resource_id == CmdbCloudResource.provider_resource_id, ), ), ).correlate(CmdbCloudResource))) if vis.scope_pairs: terms.append(tuple_( CmdbCloudResource.integration_id, CmdbCloudResource.scope_external_id, ).in_(vis.scope_pairs)) if vis.resource_group_pairs: terms.append(tuple_( CmdbCloudResource.integration_id, CmdbCloudResource.raw_metadata["resource_group"].as_string(), ).in_(vis.resource_group_pairs)) if vis.singleton_integration_ids: terms.append(and_( CmdbCloudResource.integration_id.in_(vis.singleton_integration_ids), or_( CmdbCloudResource.scope_external_id.is_(None), CmdbCloudResource.scope_external_id == "", ), )) terms.append(exists(select(CmdbResourceGovernance.id).where( CmdbResourceGovernance.resource_id == CmdbCloudResource.id, or_( CmdbResourceGovernance.business_owner_person_id.in_(vis.person_ids), CmdbResourceGovernance.technical_owner_person_id.in_(vis.person_ids), ), ).correlate(CmdbCloudResource))) terms.append(exists(select(CmdbResourceFinding.id).where( CmdbResourceFinding.resource_id == CmdbCloudResource.id, CmdbResourceFinding.assigned_to_person_id.in_(vis.person_ids), CmdbResourceFinding.status.in_(("open", "acknowledged")), ).correlate(CmdbCloudResource))) return or_(*terms) async def directory_resource_visible( db: AsyncSession, resource_id: str, vis: DirectoryVisibility, ) -> bool: value = await db.scalar(select(CmdbCloudResource.id).where( CmdbCloudResource.id == resource_id, directory_visibility_clause(vis), )) return value is not None