Module: Assistant::DataDomainPolicy
- Defined in:
- app/services/assistant/data_domain_policy.rb
Overview
Resolves a user's CanCanCan roles into analytics data domains, then
returns the set of database objects (views/tables) they may query
through the AI assistant.
Domain descriptions and role mappings live in config/analytics/data_domains.yml.
Object-to-domain assignments live in each db/comments/*.yml manifest (domain: field).
Two-layer security model:
Layer 1 — DataDomainPolicy (this module): object-level access ("can you query this table?")
Layer 2 — CommentManifest restricted flags: column-level redaction ("is this column redacted?")
Usage:
Assistant::DataDomainPolicy.allowed_objects_for(account: current_account)
=> Set["view_sales_facts", "orders", "items", ...] or nil (admin = unrestricted)
Assistant::DataDomainPolicy.domains_for(account: current_account)
=> ["sales", "workforce"]
Constant Summary collapse
- CONFIG_PATH =
Rails.root.join('config/analytics/data_domains.yml').freeze
Class Method Summary collapse
-
.allowed_objects_for(account:) ⇒ Object
Returns nil for admins/executive_managers (unrestricted) or a Set of allowed object names.
-
.config ⇒ Object
── Configuration loading ──────────────────────────────────────────.
-
.domain_descriptions_for(account:) ⇒ Object
Returns a human-friendly hash of domain name => description for the user's domains.
-
.domains_for(account:) ⇒ Object
Returns an array of domain names the user has access to.
- .reset_config! ⇒ Object
-
.tool_service_descriptions_for(account:) ⇒ Object
Returns a hash of tool service key => description for the user's allowed services.
-
.tool_services_for(account:) ⇒ Object
Returns an array of tool service keys the user can access.
Class Method Details
.allowed_objects_for(account:) ⇒ Object
Returns nil for admins/executive_managers (unrestricted) or a Set of allowed object names.
28 29 30 31 32 33 |
# File 'app/services/assistant/data_domain_policy.rb', line 28 def allowed_objects_for(account:) return nil if unrestricted_access?(account) domain_names = domains_for(account: account) resolve_objects(domain_names) end |
.config ⇒ Object
── Configuration loading ──────────────────────────────────────────
108 109 110 111 112 113 114 |
# File 'app/services/assistant/data_domain_policy.rb', line 108 def config if Rails.env.development? || Rails.env.test? load_config # Always re-read in dev/test for fast iteration else @config ||= load_config end end |
.domain_descriptions_for(account:) ⇒ Object
Returns a human-friendly hash of domain name => description for the user's domains.
58 59 60 61 62 63 64 65 66 |
# File 'app/services/assistant/data_domain_policy.rb', line 58 def domain_descriptions_for(account:) domain_names = domains_for(account: account) domains = config.fetch('domains', {}) domain_names.each_with_object({}) do |name, out| = domains[name] out[name] = ['description'] if end end |
.domains_for(account:) ⇒ Object
Returns an array of domain names the user has access to.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'app/services/assistant/data_domain_policy.rb', line 36 def domains_for(account:) return config.fetch('domains', {}).keys if unrestricted_access?(account) role_names = Array(account.inherited_role_names).map { |r| r.to_s.downcase } mappings = config.fetch('role_mappings', {}) # Collect domains from all the user's roles mapped = role_names.flat_map { |r| Array(mappings[r]) } if mapped.empty? # No explicit role mapping found — use fallback mapped = if account.is_manager? default_manager_domains else Array(config.fetch('default_employee', ['sales'])) end end mapped.uniq end |
.reset_config! ⇒ Object
128 129 130 |
# File 'app/services/assistant/data_domain_policy.rb', line 128 def reset_config! @config = nil end |
.tool_service_descriptions_for(account:) ⇒ Object
Returns a hash of tool service key => description for the user's allowed services.
96 97 98 99 100 101 102 103 104 |
# File 'app/services/assistant/data_domain_policy.rb', line 96 def tool_service_descriptions_for(account:) service_keys = tool_services_for(account: account) services = config.fetch('tool_services', {}) service_keys.each_with_object({}) do |key, out| = services[key] out[key] = ['description'] if end end |
.tool_services_for(account:) ⇒ Object
Returns an array of tool service keys the user can access.
Admins get all tool services. Others are resolved from their roles.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'app/services/assistant/data_domain_policy.rb', line 72 def tool_services_for(account:) all_services = config.fetch('tool_services', {}).keys return all_services if account.is_admin? role_names = Array(account.inherited_role_names).map { |r| r.to_s.downcase } mappings = config.fetch('tool_service_mappings', {}) # Collect services from all the user's roles mapped = role_names.flat_map { |r| Array(mappings[r]) if mappings.key?(r) }.compact.flatten if role_names.any? { |r| mappings.key?(r) } # At least one role has an explicit mapping (even if empty []) mapped.uniq else # No explicit mapping — use fallback if account.is_manager? Array(config.fetch('default_manager_tool_services', [])) else Array(config.fetch('default_employee_tool_services', [])) end end end |