TenantAtlas/specs/135-canonical-tenant-context-resolution/contracts/context-resolution-matrix.yaml
2026-03-11 22:22:22 +01:00

121 lines
4.2 KiB
YAML

version: 1
feature: 135-canonical-tenant-context-resolution
title: Canonical Tenant Context Resolution Matrix
type: internal-behavior-contract
canonical_rules:
tenant_panel:
source_of_truth: Filament::getTenant()
fallback_behavior: none
notes:
- Tenant-panel-native routes keep panel semantics.
- Remembered admin tenant state must not override tenant-panel context.
workspace_admin:
source_of_truth: App\Support\OperateHub\OperateHubShell::activeEntitledTenant
priority_order:
- entitled_filament_tenant
- entitled_remembered_workspace_tenant
- none
no_context_outcome_by_surface:
operations_monitoring_index: workspace_scoped_all_tenants_state_with_no_tenant_default_filter_and_no_tenant_only_kpis
tenantless_operation_run_detail: render_only_if_workspace_scope_and_tenant_entitlement_still_pass_otherwise_not_found
admin_entra_group_list_and_view: not_found
admin_entra_group_global_search: no_results_for_tenant_owned_records
request_states:
remembered_only:
filament_tenant: null
remembered_tenant: entitled
resolved_source: remembered
filament_only:
filament_tenant: entitled
remembered_tenant: null
resolved_source: filament
conflict:
filament_tenant: entitled
remembered_tenant: entitled_and_different
resolved_source: filament
no_context:
filament_tenant: null_or_not_entitled
remembered_tenant: null_or_not_entitled
resolved_source: none
surfaces:
- name: operations_monitoring_index
route: /admin/operations
panel: admin
expectations:
- header_scope_label_matches_resolved_tenant
- kpi_cards_match_resolved_tenant
- table_query_matches_resolved_tenant
- filter_defaults_match_resolved_tenant
- no_context_renders_workspace_scoped_all_tenants_state
- no_context_clears_tenant_default_filters
- no_context_hides_tenant_only_kpi_behavior
- name: tenantless_operation_run_detail
route: /admin/operations/{run}
panel: admin
expectations:
- authorization_uses_workspace_and_tenant_entitlement
- detail_visibility_is_not_broader_than_index_scope
- navigation_labels_use_same_resolved_tenant_as_admin_shell
- no_context_renders_only_when_workspace_scope_and_tenant_entitlement_still_pass
- no_context_otherwise_returns_not_found
- name: operation_run_filters
route: /admin/operations with persisted table filters
panel: admin
expectations:
- tenant_filter_options_do_not_exceed_list_scope
- tenant_filter_default_uses_resolved_tenant
- persisted_tenant_sensitive_values_are_revalidated_per_request
- name: entra_group_list_and_view
route: /admin/.../groups and /admin/.../groups/{record}
panel: mixed
expectations:
- tenant_panel_routes_use_panel_native_tenant
- admin_sensitive_access_paths_use_explicit_scope_rule
- direct_record_resolution_matches_list_scope
- admin_no_context_returns_not_found
- out_of_scope_access_returns_not_found
- name: entra_group_global_search
route: global-search
panel: mixed
expectations:
- search_results_follow_same_scope_as_list_and_detail
- non_members_receive_no_hints
- admin_no_context_returns_no_tenant_owned_results
- resource_search_is_disabled_if_scope_parity_cannot_be_guaranteed
- name: alert_delivery_reference_pattern
route: /admin/alert-deliveries
panel: admin
expectations:
- existing_admin_query_and_filter_alignment_is_preserved
- resource_remains_non_regression_reference
authorization_contract:
non_member_or_out_of_scope:
response: not_found
member_missing_capability:
response: forbidden
guardrail:
purpose: prevent_new_admin_panel_raw_panel_native_tenant_reads
forbidden_patterns:
- Filament::getTenant()
- Tenant::current()
enforced_in:
- app/Filament/Pages/Monitoring
- app/Filament/Pages/Operations
- app/Filament/Resources
- app/Filament/Widgets/Operations
allowed_exceptions:
- app/Filament/Pages/ChooseTenant.php
- app/Http/Controllers/SelectTenantController.php
- app/Support/Middleware/EnsureFilamentTenantSelected.php
- app/Filament/Resources/EntraGroupResource.php