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 =
Filesystem path for config.
Rails.root.join('config/analytics/data_domains.yml').freeze
Class Method Summary collapse
-
.allowed_objects_for(account:) ⇒ Set<String>?
Returns nil for admins/executive_managers (unrestricted) or a Set of allowed object names.
-
.config ⇒ Hash
Parsed data_domains.yml config.
-
.domain_descriptions_for(account:) ⇒ Hash{String => String}
Returns a human-friendly hash of domain name => description for the user's domains.
-
.domains_for(account:) ⇒ Array<String>
Returns an array of domain names the user has access to.
- .reset_config! ⇒ void
-
.tool_service_descriptions_for(account:) ⇒ Hash{String => String}
Returns a hash of tool service key => description for the user's allowed services.
-
.tool_services_for(account:) ⇒ Array<String>
Returns an array of tool service keys the user can access.
Class Method Details
.allowed_objects_for(account:) ⇒ Set<String>?
Returns nil for admins/executive_managers (unrestricted) or a Set of allowed object names.
32 33 34 35 36 37 |
# File 'app/services/assistant/data_domain_policy.rb', line 32 def allowed_objects_for(account:) return nil if unrestricted_access?(account) domain_names = domains_for(account: account) resolve_objects(domain_names) end |
.config ⇒ Hash
Returns parsed data_domains.yml config.
123 124 125 126 127 128 129 |
# File 'app/services/assistant/data_domain_policy.rb', line 123 def config if Rails.env.local? load_config # Always re-read in dev/test for fast iteration else @config ||= load_config end end |
.domain_descriptions_for(account:) ⇒ Hash{String => String}
Returns a human-friendly hash of domain name => description for the user's domains.
68 69 70 71 72 73 74 75 76 |
# File 'app/services/assistant/data_domain_policy.rb', line 68 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:) ⇒ Array<String>
Returns an array of domain names the user has access to.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'app/services/assistant/data_domain_policy.rb', line 43 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! ⇒ void
This method returns an undefined value.
145 146 147 |
# File 'app/services/assistant/data_domain_policy.rb', line 145 def reset_config! @config = nil end |
.tool_service_descriptions_for(account:) ⇒ Hash{String => String}
Returns a hash of tool service key => description for the user's allowed services.
110 111 112 113 114 115 116 117 118 |
# File 'app/services/assistant/data_domain_policy.rb', line 110 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:) ⇒ Array<String>
Returns an array of tool service keys the user can access.
Admins get all tool services. Others are resolved from their roles.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'app/services/assistant/data_domain_policy.rb', line 85 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 elsif account.is_manager? # No explicit mapping — use fallback Array(config.fetch('default_manager_tool_services', [])) else Array(config.fetch('default_employee_tool_services', [])) end end |