permission_forge 0.14.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (347) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2372 -0
  3. data/README.md +76 -25
  4. data/app/controllers/concerns/permission_forge/api/crud_actions.rb +3 -2
  5. data/app/controllers/concerns/permission_forge/api/input_shapes.rb +200 -0
  6. data/app/controllers/concerns/permission_forge/api/pagination.rb +12 -5
  7. data/app/controllers/concerns/permission_forge/api/response_renderer.rb +37 -1
  8. data/app/controllers/concerns/permission_forge/api_authentication.rb +13 -2
  9. data/app/controllers/concerns/permission_forge/cache_confirmation.rb +42 -11
  10. data/app/controllers/concerns/permission_forge/change_review.rb +42 -0
  11. data/app/controllers/concerns/permission_forge/copy_refusal.rb +39 -0
  12. data/app/controllers/concerns/permission_forge/param_shapes.rb +207 -7
  13. data/app/controllers/concerns/permission_forge/save_notice.rb +69 -0
  14. data/app/controllers/permission_forge/api/audit_events_controller.rb +1 -1
  15. data/app/controllers/permission_forge/api/base_controller.rb +163 -12
  16. data/app/controllers/permission_forge/api/dashboard_controller.rb +29 -4
  17. data/app/controllers/permission_forge/api/permission_set_group_users_controller.rb +5 -2
  18. data/app/controllers/permission_forge/api/permission_set_groups_controller.rb +5 -4
  19. data/app/controllers/permission_forge/api/permission_set_rules_controller.rb +7 -5
  20. data/app/controllers/permission_forge/api/permission_set_users_controller.rb +80 -19
  21. data/app/controllers/permission_forge/api/permission_sets_controller.rb +12 -6
  22. data/app/controllers/permission_forge/api/resource_actions_controller.rb +1 -1
  23. data/app/controllers/permission_forge/api/resource_fields_controller.rb +3 -4
  24. data/app/controllers/permission_forge/api/resources_controller.rb +26 -12
  25. data/app/controllers/permission_forge/api/unmatched_routes_controller.rb +20 -0
  26. data/app/controllers/permission_forge/application_controller.rb +39 -5
  27. data/app/controllers/permission_forge/assignments_controller.rb +36 -34
  28. data/app/controllers/permission_forge/bulk_assignments_controller.rb +8 -4
  29. data/app/controllers/permission_forge/field_lookups_controller.rb +1 -1
  30. data/app/controllers/permission_forge/maintenance_controller.rb +6 -2
  31. data/app/controllers/permission_forge/people_controller.rb +14 -14
  32. data/app/controllers/permission_forge/permission_set_editor.rb +20 -6
  33. data/app/controllers/permission_forge/permission_set_group_users_controller.rb +3 -1
  34. data/app/controllers/permission_forge/permission_set_groups_controller.rb +23 -9
  35. data/app/controllers/permission_forge/permission_set_rules_controller.rb +20 -10
  36. data/app/controllers/permission_forge/permission_sets_controller.rb +23 -24
  37. data/app/controllers/permission_forge/resource_actions_controller.rb +11 -6
  38. data/app/controllers/permission_forge/resource_fields_controller.rb +37 -19
  39. data/app/controllers/permission_forge/resources_controller.rb +12 -11
  40. data/app/frontend/permission_forge/pf_admin.css +99 -17
  41. data/app/frontend/permission_forge/pf_admin.js +36 -0
  42. data/app/helpers/permission_forge/application_helper.rb +22 -72
  43. data/app/helpers/permission_forge/audit_attribution_helper.rb +77 -0
  44. data/app/helpers/permission_forge/audit_helper.rb +57 -119
  45. data/app/helpers/permission_forge/audit_records_helper.rb +103 -0
  46. data/app/helpers/permission_forge/audit_sentences_helper.rb +56 -2
  47. data/app/helpers/permission_forge/badges_helper.rb +74 -17
  48. data/app/helpers/permission_forge/changes_helper.rb +24 -6
  49. data/app/helpers/permission_forge/conditions_helper.rb +119 -0
  50. data/app/helpers/permission_forge/labels_helper.rb +134 -0
  51. data/app/helpers/permission_forge/people_helper.rb +11 -19
  52. data/app/helpers/permission_forge/rule_problems_helper.rb +73 -0
  53. data/app/helpers/permission_forge/sentences_helper.rb +119 -98
  54. data/app/helpers/permission_forge/settings_helper.rb +2 -2
  55. data/app/helpers/permission_forge/ui_helper.rb +65 -4
  56. data/app/models/permission_forge/audit_event.rb +5 -1
  57. data/app/models/permission_forge/permission_set.rb +208 -18
  58. data/app/models/permission_forge/permission_set_group.rb +10 -4
  59. data/app/models/permission_forge/permission_set_group_user.rb +3 -1
  60. data/app/models/permission_forge/permission_set_rule.rb +254 -17
  61. data/app/models/permission_forge/permission_set_user.rb +38 -3
  62. data/app/models/permission_forge/resource.rb +18 -8
  63. data/app/models/permission_forge/resource_action.rb +15 -6
  64. data/app/models/permission_forge/resource_field.rb +97 -11
  65. data/app/views/permission_forge/assignments/confirm_destroy.html.erb +4 -4
  66. data/app/views/permission_forge/assignments/new.html.erb +10 -6
  67. data/app/views/permission_forge/audit_events/index.html.erb +1 -1
  68. data/app/views/permission_forge/audit_events/show.html.erb +16 -9
  69. data/app/views/permission_forge/bulk_assignments/confirm_revoke.html.erb +3 -3
  70. data/app/views/permission_forge/bulk_assignments/new.html.erb +3 -3
  71. data/app/views/permission_forge/field_lookups/show.html.erb +2 -2
  72. data/app/views/permission_forge/home/_broken_rules_card.html.erb +35 -0
  73. data/app/views/permission_forge/home/_conditions_card.html.erb +28 -0
  74. data/app/views/permission_forge/home/_ending_card.html.erb +11 -5
  75. data/app/views/permission_forge/home/_expired_card.html.erb +1 -1
  76. data/app/views/permission_forge/home/_mask_strategies_card.html.erb +27 -0
  77. data/app/views/permission_forge/home/_privacy_card.html.erb +21 -7
  78. data/app/views/permission_forge/home/_rules_card.html.erb +1 -1
  79. data/app/views/permission_forge/home/_secret_rules_card.html.erb +33 -0
  80. data/app/views/permission_forge/home/_stale_card.html.erb +7 -5
  81. data/app/views/permission_forge/home/_tidy_card.html.erb +1 -1
  82. data/app/views/permission_forge/home/index.html.erb +5 -6
  83. data/app/views/permission_forge/people/_access_tab.html.erb +26 -19
  84. data/app/views/permission_forge/people/_audit_tab.html.erb +8 -8
  85. data/app/views/permission_forge/people/_effective_field_source.html.erb +13 -7
  86. data/app/views/permission_forge/people/_effective_tab.html.erb +16 -15
  87. data/app/views/permission_forge/people/_effective_why.html.erb +20 -16
  88. data/app/views/permission_forge/people/_why_item.html.erb +1 -1
  89. data/app/views/permission_forge/people/confirm_remove_all.html.erb +3 -3
  90. data/app/views/permission_forge/people/erasure_preview.html.erb +1 -1
  91. data/app/views/permission_forge/permission_set_groups/confirm_destroy.html.erb +3 -3
  92. data/app/views/permission_forge/permission_set_groups/index.html.erb +3 -3
  93. data/app/views/permission_forge/permission_set_groups/show.html.erb +28 -19
  94. data/app/views/permission_forge/permission_set_rules/_builder.html.erb +35 -15
  95. data/app/views/permission_forge/permission_set_rules/_preview.html.erb +17 -0
  96. data/app/views/permission_forge/permission_set_rules/confirm_destroy.html.erb +3 -3
  97. data/app/views/permission_forge/permission_set_rules/preview.html.erb +12 -0
  98. data/app/views/permission_forge/permission_sets/_assignments_tab.html.erb +37 -22
  99. data/app/views/permission_forge/permission_sets/_audit_tab.html.erb +4 -4
  100. data/app/views/permission_forge/permission_sets/_condition_problems.html.erb +15 -0
  101. data/app/views/permission_forge/permission_sets/_conditions_tab.html.erb +14 -8
  102. data/app/views/permission_forge/permission_sets/_header.html.erb +6 -5
  103. data/app/views/permission_forge/permission_sets/_records_summary.html.erb +2 -2
  104. data/app/views/permission_forge/permission_sets/_resources_tab.html.erb +4 -4
  105. data/app/views/permission_forge/permission_sets/confirm_destroy.html.erb +4 -4
  106. data/app/views/permission_forge/permission_sets/confirm_switch_mode.html.erb +3 -3
  107. data/app/views/permission_forge/permission_sets/index.html.erb +6 -6
  108. data/app/views/permission_forge/permission_sets/new.html.erb +2 -2
  109. data/app/views/permission_forge/permission_sets/review.html.erb +13 -3
  110. data/app/views/permission_forge/permission_sets/show.html.erb +7 -5
  111. data/app/views/permission_forge/resource_actions/_across_sets.html.erb +7 -10
  112. data/app/views/permission_forge/resource_actions/_effect.html.erb +5 -5
  113. data/app/views/permission_forge/resource_actions/_form.html.erb +1 -1
  114. data/app/views/permission_forge/resource_actions/_managed_note.html.erb +5 -3
  115. data/app/views/permission_forge/resource_actions/confirm_destroy.html.erb +1 -1
  116. data/app/views/permission_forge/resource_actions/new.html.erb +1 -1
  117. data/app/views/permission_forge/resource_actions/show.html.erb +2 -2
  118. data/app/views/permission_forge/resource_fields/_explain.html.erb +19 -15
  119. data/app/views/permission_forge/resource_fields/show.html.erb +21 -12
  120. data/app/views/permission_forge/resources/_actions_tab.html.erb +4 -4
  121. data/app/views/permission_forge/resources/_fields_tab.html.erb +17 -9
  122. data/app/views/permission_forge/resources/_rules_tab.html.erb +9 -6
  123. data/app/views/permission_forge/resources/_sync.html.erb +8 -5
  124. data/app/views/permission_forge/resources/confirm_destroy.html.erb +3 -3
  125. data/app/views/permission_forge/resources/new.html.erb +3 -2
  126. data/app/views/permission_forge/resources/show.html.erb +6 -6
  127. data/app/views/permission_forge/settings/_row.html.erb +2 -2
  128. data/app/views/permission_forge/settings/show.html.erb +10 -1
  129. data/app/views/permission_forge/shared/_across_sets.html.erb +8 -9
  130. data/app/views/permission_forge/shared/_audit_events.html.erb +2 -2
  131. data/app/views/permission_forge/shared/_audit_footer.html.erb +13 -2
  132. data/app/views/permission_forge/shared/_crud_cell.html.erb +6 -6
  133. data/app/views/permission_forge/shared/_mode_banners.html.erb +1 -1
  134. data/app/views/permission_forge/shared/_savebar.html.erb +4 -2
  135. data/config/locales/permission_forge.en.yml +480 -69
  136. data/config/locales/permission_forge.mk.yml +499 -79
  137. data/config/locales/permission_forge.sq.yml +509 -80
  138. data/config/routes.rb +38 -23
  139. data/lib/generators/permission_forge/install/install_generator.rb +21 -0
  140. data/lib/generators/permission_forge/install/templates/initializer.rb.tt +35 -34
  141. data/lib/generators/permission_forge/install/templates/migration.rb.tt +5 -5
  142. data/lib/permission_forge/activation_conditions.rb +200 -0
  143. data/lib/permission_forge/admin/action_label.rb +33 -0
  144. data/lib/permission_forge/admin/action_rows.rb +3 -1
  145. data/lib/permission_forge/admin/actor_label.rb +52 -0
  146. data/lib/permission_forge/admin/attention_items.rb +152 -31
  147. data/lib/permission_forge/admin/audit_log.rb +4 -7
  148. data/lib/permission_forge/admin/audit_trail.rb +33 -17
  149. data/lib/permission_forge/admin/bulk_people_matcher.rb +32 -14
  150. data/lib/permission_forge/admin/chain_entries.rb +42 -0
  151. data/lib/permission_forge/admin/change_set.rb +12 -1
  152. data/lib/permission_forge/admin/change_set_parts/base.rb +5 -4
  153. data/lib/permission_forge/admin/change_set_parts/context.rb +3 -1
  154. data/lib/permission_forge/admin/change_set_parts/field_edit.rb +4 -1
  155. data/lib/permission_forge/admin/change_set_parts/field_levels.rb +1 -1
  156. data/lib/permission_forge/admin/change_set_parts/new_actions.rb +1 -1
  157. data/lib/permission_forge/admin/change_set_parts/new_fields.rb +38 -11
  158. data/lib/permission_forge/admin/change_set_parts/resource_edit.rb +17 -1
  159. data/lib/permission_forge/admin/change_set_parts/resource_flags.rb +1 -1
  160. data/lib/permission_forge/admin/change_set_parts/set_attrs.rb +4 -0
  161. data/lib/permission_forge/admin/change_set_parts/values.rb +10 -4
  162. data/lib/permission_forge/admin/column_fields.rb +22 -21
  163. data/lib/permission_forge/admin/conditions_form.rb +47 -15
  164. data/lib/permission_forge/admin/controller_catalog.rb +42 -14
  165. data/lib/permission_forge/admin/editable_lock.rb +83 -3
  166. data/lib/permission_forge/admin/effective_access.rb +147 -48
  167. data/lib/permission_forge/admin/effective_fields.rb +75 -67
  168. data/lib/permission_forge/admin/error_sentence.rb +47 -0
  169. data/lib/permission_forge/admin/expiry_presets.rb +17 -0
  170. data/lib/permission_forge/admin/exports/holdings.rb +6 -3
  171. data/lib/permission_forge/admin/field_across_sets.rb +7 -4
  172. data/lib/permission_forge/admin/field_chain.rb +109 -0
  173. data/lib/permission_forge/admin/field_detail.rb +24 -11
  174. data/lib/permission_forge/admin/field_label.rb +109 -0
  175. data/lib/permission_forge/admin/field_level.rb +4 -68
  176. data/lib/permission_forge/admin/field_provenance.rb +132 -0
  177. data/lib/permission_forge/admin/field_rows.rb +26 -11
  178. data/lib/permission_forge/admin/last_changes.rb +14 -0
  179. data/lib/permission_forge/admin/list_sentence.rb +32 -0
  180. data/lib/permission_forge/admin/mask_strategy_choices.rb +57 -0
  181. data/lib/permission_forge/admin/model_catalog.rb +83 -39
  182. data/lib/permission_forge/admin/model_label.rb +66 -0
  183. data/lib/permission_forge/admin/people_candidates.rb +21 -9
  184. data/lib/permission_forge/admin/people_directory.rb +23 -5
  185. data/lib/permission_forge/admin/permission_set_factory.rb +6 -15
  186. data/lib/permission_forge/admin/person_label.rb +105 -16
  187. data/lib/permission_forge/admin/prefill.rb +92 -0
  188. data/lib/permission_forge/admin/record_name.rb +45 -0
  189. data/lib/permission_forge/admin/rule_builder.rb +77 -3
  190. data/lib/permission_forge/admin/rule_form.rb +44 -10
  191. data/lib/permission_forge/admin/rule_form_input.rb +27 -11
  192. data/lib/permission_forge/admin/rule_notes.rb +43 -0
  193. data/lib/permission_forge/admin/rule_preview.rb +96 -0
  194. data/lib/permission_forge/admin/sensitive_columns.rb +10 -62
  195. data/lib/permission_forge/admin/settings_catalog.rb +64 -12
  196. data/lib/permission_forge/admin/state_label.rb +97 -0
  197. data/lib/permission_forge/admin_method_override.rb +44 -0
  198. data/lib/permission_forge/api/schema.rb +322 -0
  199. data/lib/permission_forge/api/serializers/base_serializer.rb +87 -1
  200. data/lib/permission_forge/api/serializers/permission_set_group_user_serializer.rb +1 -1
  201. data/lib/permission_forge/api/serializers/permission_set_rule_serializer.rb +1 -1
  202. data/lib/permission_forge/api/serializers/permission_set_serializer.rb +5 -2
  203. data/lib/permission_forge/api/serializers/permission_set_user_serializer.rb +1 -1
  204. data/lib/permission_forge/api/serializers/resource_action_serializer.rb +1 -1
  205. data/lib/permission_forge/api/serializers/resource_field_serializer.rb +1 -1
  206. data/lib/permission_forge/api/serializers/resource_serializer.rb +1 -1
  207. data/lib/permission_forge/api_authorizations.rb +59 -0
  208. data/lib/permission_forge/api_only_admin.rb +81 -0
  209. data/lib/permission_forge/audit/actor_codes.rb +32 -0
  210. data/lib/permission_forge/audit/actor_resolver.rb +1 -2
  211. data/lib/permission_forge/audit/boot_warnings.rb +29 -9
  212. data/lib/permission_forge/audit/event_catalog.rb +16 -6
  213. data/lib/permission_forge/audit/event_query.rb +3 -3
  214. data/lib/permission_forge/audit/reason_codes.rb +25 -0
  215. data/lib/permission_forge/audit/runtime.rb +9 -2
  216. data/lib/permission_forge/audit/settings_observer.rb +2 -2
  217. data/lib/permission_forge/audit/unmasked_without_user.rb +169 -0
  218. data/lib/permission_forge/audit.rb +24 -10
  219. data/lib/permission_forge/boot_checks.rb +180 -63
  220. data/lib/permission_forge/cache/base.rb +10 -0
  221. data/lib/permission_forge/cache/null_cache.rb +5 -0
  222. data/lib/permission_forge/cache/outcome.rb +119 -0
  223. data/lib/permission_forge/cache/rails_cache.rb +6 -0
  224. data/lib/permission_forge/cache/report.rb +150 -0
  225. data/lib/permission_forge/cache/user_keys.rb +8 -4
  226. data/lib/permission_forge/cache_warnings.rb +140 -0
  227. data/lib/permission_forge/concerns/auto_permission_scoping.rb +19 -2
  228. data/lib/permission_forge/concerns/has_tenant_scoping.rb +1 -1
  229. data/lib/permission_forge/concerns/has_uuid.rb +1 -1
  230. data/lib/permission_forge/concerns/keeps_copied_values.rb +48 -0
  231. data/lib/permission_forge/concerns/masked_attributes/alias_access.rb +12 -2
  232. data/lib/permission_forge/concerns/masked_attributes/virtual_readers.rb +6 -4
  233. data/lib/permission_forge/concerns/masked_attributes.rb +150 -34
  234. data/lib/permission_forge/concerns/normalizes_label.rb +78 -0
  235. data/lib/permission_forge/concerns/permission_cache_accessor.rb +3 -3
  236. data/lib/permission_forge/concerns/permission_scoped_findable.rb +121 -29
  237. data/lib/permission_forge/concerns/permissioned_user.rb +1 -1
  238. data/lib/permission_forge/concerns/records_audit_events.rb +13 -6
  239. data/lib/permission_forge/concerns/requires_name.rb +37 -0
  240. data/lib/permission_forge/concerns/validates_column_lengths.rb +24 -0
  241. data/lib/permission_forge/concerns/validates_dependency.rb +5 -2
  242. data/lib/permission_forge/concerns/validates_required_columns.rb +74 -0
  243. data/lib/permission_forge/conditional_sets.rb +13 -6
  244. data/lib/permission_forge/configuration/admin_ui_settings.rb +18 -4
  245. data/lib/permission_forge/configuration/audit_settings.rb +2 -1
  246. data/lib/permission_forge/configuration/controller_action_settings.rb +5 -4
  247. data/lib/permission_forge/configuration/masked_attributes_settings.rb +73 -19
  248. data/lib/permission_forge/configuration/presets.rb +20 -11
  249. data/lib/permission_forge/configuration/query_scoping_settings.rb +55 -0
  250. data/lib/permission_forge/configuration/strategy_values.rb +2 -1
  251. data/lib/permission_forge/configuration.rb +41 -18
  252. data/lib/permission_forge/controller_actions/managed_index.rb +8 -7
  253. data/lib/permission_forge/database_reach.rb +93 -0
  254. data/lib/permission_forge/deprecation.rb +1 -1
  255. data/lib/permission_forge/docs/api_samples.rb +250 -0
  256. data/lib/permission_forge/docs/configuration_reference.rb +172 -0
  257. data/lib/permission_forge/encrypted_attributes.rb +150 -0
  258. data/lib/permission_forge/engine.rb +46 -14
  259. data/lib/permission_forge/execution_state/restore.rb +74 -0
  260. data/lib/permission_forge/execution_state.rb +8 -1
  261. data/lib/permission_forge/field_level.rb +123 -0
  262. data/lib/permission_forge/field_names.rb +145 -0
  263. data/lib/permission_forge/field_variants.rb +96 -0
  264. data/lib/permission_forge/generated_text.rb +95 -0
  265. data/lib/permission_forge/inspection_filters.rb +83 -0
  266. data/lib/permission_forge/managed_fields.rb +66 -0
  267. data/lib/permission_forge/masked_models.rb +25 -19
  268. data/lib/permission_forge/masking_sync.rb +100 -25
  269. data/lib/permission_forge/model_bindings.rb +30 -19
  270. data/lib/permission_forge/model_lookup.rb +42 -0
  271. data/lib/permission_forge/operators/encrypted_alias.rb +67 -0
  272. data/lib/permission_forge/operators/registry.rb +6 -0
  273. data/lib/permission_forge/operators/rule_column.rb +242 -27
  274. data/lib/permission_forge/operators/rule_path.rb +179 -0
  275. data/lib/permission_forge/operators/rule_problem.rb +309 -0
  276. data/lib/permission_forge/operators/rule_sources.rb +96 -0
  277. data/lib/permission_forge/operators/value_casters/postgresql_types.rb +237 -0
  278. data/lib/permission_forge/operators/value_casters/temporal.rb +9 -20
  279. data/lib/permission_forge/operators/value_casters.rb +61 -13
  280. data/lib/permission_forge/operators/value_typing.rb +83 -7
  281. data/lib/permission_forge/query_scoping_warnings.rb +22 -17
  282. data/lib/permission_forge/rake_audit.rb +5 -4
  283. data/lib/permission_forge/rake_dry_run.rb +32 -0
  284. data/lib/permission_forge/rake_output.rb +189 -0
  285. data/lib/permission_forge/record_read_access.rb +51 -0
  286. data/lib/permission_forge/resource_chain.rb +14 -2
  287. data/lib/permission_forge/schema_read/ordered_types.rb +72 -0
  288. data/lib/permission_forge/schema_read.rb +335 -0
  289. data/lib/permission_forge/secret_columns.rb +49 -0
  290. data/lib/permission_forge/sensitive_columns.rb +114 -0
  291. data/lib/permission_forge/services/attribute_access_guard.rb +22 -14
  292. data/lib/permission_forge/services/bulk_permission_set_assignment.rb +16 -8
  293. data/lib/permission_forge/services/concerns/clonable.rb +9 -0
  294. data/lib/permission_forge/services/concerns/settles_cache.rb +58 -0
  295. data/lib/permission_forge/services/consent_withdrawal_handler.rb +37 -19
  296. data/lib/permission_forge/services/data_subject_erasure.rb +83 -45
  297. data/lib/permission_forge/services/expired_assignment_cleaner.rb +62 -25
  298. data/lib/permission_forge/services/extra_field_defaults.rb +1 -1
  299. data/lib/permission_forge/services/field_permission_merger.rb +44 -17
  300. data/lib/permission_forge/services/filters_response_attributes.rb +20 -5
  301. data/lib/permission_forge/services/gdpr_field_auditor/text_report.rb +33 -5
  302. data/lib/permission_forge/services/gdpr_field_auditor.rb +68 -48
  303. data/lib/permission_forge/services/host_key_guard.rb +8 -5
  304. data/lib/permission_forge/services/mask_value.rb +72 -11
  305. data/lib/permission_forge/services/permission_cache_clearer.rb +36 -15
  306. data/lib/permission_forge/services/permission_hash_builder.rb +48 -19
  307. data/lib/permission_forge/services/permission_rule_applier.rb +131 -68
  308. data/lib/permission_forge/services/permission_set_cloner.rb +32 -8
  309. data/lib/permission_forge/services/permission_set_condition_evaluator.rb +38 -36
  310. data/lib/permission_forge/services/permission_set_group_cloner.rb +2 -1
  311. data/lib/permission_forge/services/permits_attributes/result.rb +31 -0
  312. data/lib/permission_forge/services/permits_attributes.rb +48 -27
  313. data/lib/permission_forge/services/resource_field_generator/row_builder.rb +96 -0
  314. data/lib/permission_forge/services/resource_field_generator.rb +71 -42
  315. data/lib/permission_forge/services/resource_with_fields_builder.rb +2 -1
  316. data/lib/permission_forge/services/rls_operator_sql.rb +83 -24
  317. data/lib/permission_forge/services/rls_policy_generator.rb +83 -39
  318. data/lib/permission_forge/services/rls_read_access_sql.rb +131 -0
  319. data/lib/permission_forge/services/security_audit/action_check.rb +49 -5
  320. data/lib/permission_forge/services/security_audit/assignment_check.rb +2 -1
  321. data/lib/permission_forge/services/security_audit/audit_trail_check.rb +1 -3
  322. data/lib/permission_forge/services/security_audit/conditions_check.rb +92 -0
  323. data/lib/permission_forge/services/security_audit/config_check.rb +41 -18
  324. data/lib/permission_forge/services/security_audit/integrity_check.rb +71 -4
  325. data/lib/permission_forge/services/security_audit/masking_without_user.rb +66 -0
  326. data/lib/permission_forge/services/security_audit/personal_data_check.rb +7 -11
  327. data/lib/permission_forge/services/security_audit/rule_check.rb +180 -50
  328. data/lib/permission_forge/services/security_audit/text_report.rb +14 -2
  329. data/lib/permission_forge/services/security_audit/unmanaged_actions.rb +145 -0
  330. data/lib/permission_forge/services/security_audit/user_model_check.rb +4 -3
  331. data/lib/permission_forge/services/security_audit.rb +16 -4
  332. data/lib/permission_forge/services/stale_assignment_auditor.rb +8 -5
  333. data/lib/permission_forge/timestamp_fields.rb +60 -0
  334. data/lib/permission_forge/unique_conflict.rb +117 -0
  335. data/lib/permission_forge/version.rb +1 -1
  336. data/lib/permission_forge/virtual_fields/discovery.rb +2 -1
  337. data/lib/permission_forge/virtual_fields.rb +15 -5
  338. data/lib/permission_forge/warnings.rb +263 -0
  339. data/lib/permission_forge/web_request.rb +248 -0
  340. data/lib/permission_forge.rb +54 -0
  341. data/lib/tasks/permission_forge.rake +26 -6
  342. data/lib/tasks/permission_forge_audit_events.rake +8 -4
  343. data/lib/tasks/permission_forge_cache.rake +12 -12
  344. data/lib/tasks/permission_forge_docs.rake +48 -0
  345. data/lib/tasks/permission_forge_expiration.rake +11 -5
  346. data/lib/tasks/permission_forge_gdpr.rake +36 -20
  347. metadata +84 -1
@@ -3,14 +3,49 @@ en:
3
3
  permission_forge:
4
4
  api:
5
5
  errors:
6
+ action_authorization_missing: API changes need config.api_action_authorization;
7
+ they are refused while it is unset and config.api_require_authorization
8
+ is on
6
9
  action_not_authorized: Action not authorized
10
+ assignment_authorization_missing: API assignments need config.api_assignment_authorization;
11
+ they are refused while it is unset and config.api_require_authorization
12
+ is on
7
13
  assignment_not_authorized: Assignment not authorized
14
+ body_unreadable: The request body could not be read. Send valid JSON with
15
+ Content-Type application/json.
16
+ boolean_invalid: must be true or false
17
+ bulk_action_invalid: must be assign or revoke
18
+ expires_at_past: must be in the future
8
19
  field_generation_failed: Could not generate fields for this resource
20
+ field_value_shape: must be a string, a number, true or false; a list of them
21
+ (none with a comma) only for in, not_in and between
22
+ flag_shape: must be a string or null
9
23
  forbidden: Forbidden
24
+ hour_shape: must be a whole number from 0 to 23, or null
25
+ integer_shape: must be a whole number
26
+ ip_list_empty: has no entry; send null to clear the condition
27
+ ip_list_shape: must be a string or an array of strings (IP addresses or CIDR
28
+ ranges), or null
10
29
  not_editable: This record is not editable
11
30
  not_found: Record not found
31
+ not_iso8601_time: is not an ISO 8601 date or time
32
+ not_null: A required value is missing. Nothing was saved.
33
+ record_not_unique: Another request saved the same record a moment ago; it
34
+ already exists
35
+ resource_names_no_model: names no model this app can load
36
+ route_not_found: No API endpoint answers this path and method
37
+ section_missing: is missing, empty or not an object
38
+ stats_authorization_missing: GET /api/stats needs config.api_stats_authorization,
39
+ or config.api_stats_require_admin = false
12
40
  tenant_required: No tenant is set for this request. The admin API serves one
13
41
  tenant at a time.
42
+ text_shape: must be a string
43
+ unauthorized: Not authenticated
44
+ user_id_invalid: is not a user id
45
+ user_id_missing: is missing
46
+ user_ids_missing: must name at least one user
47
+ user_ids_not_list: must be a list of user ids
48
+ user_not_found: names nobody who can be assigned
14
49
  assignments:
15
50
  confirm_destroy:
16
51
  body: "%{name} will lose access to %{resources}, unless another Permission
@@ -32,6 +67,7 @@ en:
32
67
  expires: Expires
33
68
  filter_sets: Filter Permission Sets
34
69
  forever: with no end date
70
+ locked_hint: 'Managed by the system/API: holders can''t be added here.'
35
71
  muting_notice: "⊘ Muting. %{sets} takes access away from %{name}, whatever
36
72
  their other sets allow."
37
73
  no_sets: No Permission Sets match.
@@ -103,6 +139,7 @@ en:
103
139
  all_for_record: All events of this record
104
140
  all_for_set: All events of this Permission Set
105
141
  all_in_action: All events of this action
142
+ all_unknown_actor: All events with no known actor
106
143
  attribute: Attribute
107
144
  before: Before
108
145
  changes: Before and after
@@ -127,23 +164,30 @@ en:
127
164
  snapshot_destroyed: The record as it was when it was removed.
128
165
  source: Where
129
166
  title: Audit event %{event}
167
+ unknown_actor_html: No actor was named for this change (code run outside a
168
+ request, such as a runner or a job). Name one with %{method}.
130
169
  uuid: Event id
131
170
  value: Value
132
171
  what: What
133
172
  who: Who, where and why
134
173
  audit_log:
174
+ actor_codes:
175
+ api_client: API client
176
+ boot: Application start
135
177
  actor_named:
136
178
  api: "%{name} (API)"
137
179
  basic_auth: "%{name} (password prompt)"
138
- actor_types:
139
- api: API client
140
- basic_auth: Password prompt
141
- system: System
142
- unknown: Unknown
143
- user: Person
144
180
  boolean:
145
181
  'false': 'No'
146
182
  'true': 'Yes'
183
+ cache_scope:
184
+ own_process: 'The cached permissions were cleared only in the process that
185
+ ran it (an in-memory store): every other process kept theirs.'
186
+ server_process: 'The cached permissions were cleared in this server process
187
+ only (an in-memory store): the other web workers and the job processes kept
188
+ theirs.'
189
+ unconfirmed: 'The cache store lives in each process (an in-memory store):
190
+ the other processes keep their cached permissions either way.'
147
191
  categories:
148
192
  access: Access
149
193
  admin: Admin
@@ -172,6 +216,8 @@ en:
172
216
  page_of: Page %{page} of %{pages}
173
217
  pages_label: Pages
174
218
  person_id: 'Person #%{id}'
219
+ reason_codes:
220
+ expired: Its end date had passed
175
221
  reason_inline: 'Reason: %{reason}'
176
222
  refused:
177
223
  body: Reading the audit log is limited by the audit_log_authorization setting,
@@ -181,8 +227,17 @@ en:
181
227
  sentence_variants:
182
228
  assignment_revoked_expired: "%{actor} removed %{set} from %{person} after
183
229
  it expired on %{date}."
230
+ cache_cleared_unconfirmed: "%{actor} asked to clear the cached permissions
231
+ of every user, but the cache store did not confirm it: old permissions may
232
+ stay in use until the cache lifetime ends."
233
+ cache_settled_unconfirmed: 'The cached permissions of %{person} were to be
234
+ cleared after the change by %{actor}, but the cache store did not confirm
235
+ it: the old ones may stay in use until the cache lifetime ends.'
184
236
  field_access_limited: "%{actor} read %{record} with these fields hidden or
185
237
  masked: %{fields}."
238
+ permissions_invalidated_unconfirmed: 'The cached permissions of %{person}
239
+ were to be cleared, but the cache store did not confirm it: the old ones
240
+ may stay in use until the cache lifetime ends.'
186
241
  sentences:
187
242
  access:
188
243
  denied: "%{actor} was denied access to %{record}."
@@ -206,6 +261,8 @@ en:
206
261
  viewed: "%{actor} viewed audit records."
207
262
  cache:
208
263
  cleared: "%{actor} cleared the cached permissions of every user."
264
+ settled: The cached permissions of %{person} were cleared after the change
265
+ by %{actor}.
209
266
  cleanup:
210
267
  expired_assignments: "%{actor} removed expired assignments."
211
268
  consent:
@@ -218,6 +275,8 @@ en:
218
275
  access: "%{actor} read %{record}."
219
276
  sensitive_acknowledged: "%{actor} confirmed that the field %{record} in
220
277
  %{set} is meant to be readable unmasked."
278
+ unmasked_without_user: A field of %{model} was read unmasked in a web request
279
+ with nobody signed in.
221
280
  group_membership:
222
281
  added: "%{actor} added %{person} to %{group}."
223
282
  changed: "%{actor} changed %{person}'s membership of %{group}."
@@ -312,6 +371,9 @@ en:
312
371
  will_assign:
313
372
  one: "%{count} will be assigned"
314
373
  other: "%{count} will be assigned"
374
+ denials:
375
+ no_read_access: You do not have permission to read %{resource} records.
376
+ rule_default: You do not have permission to perform this action.
315
377
  errors:
316
378
  admin:
317
379
  action_format: Use lowercase letters, numbers and underscores, starting with
@@ -322,6 +384,9 @@ en:
322
384
  flag: Session flags can only contain letters, numbers, dots, colons, dashes
323
385
  and underscores.
324
386
  group_blank: Give the group a name.
387
+ hours_equal: The start and end hour must differ (a window from 9 to 9 is empty).
388
+ hours_incomplete: Choose both the start and the end hour.
389
+ hours_range: Choose hours between 00:00 and 23:00.
325
390
  ip: 'Line %{line}: “%{ip}” isn''t a valid IP address or CIDR range.'
326
391
  person: Choose a person first.
327
392
  resource_model: Pick a model from the list.
@@ -369,9 +434,40 @@ en:
369
434
  assigned:
370
435
  one: Assigned %{set} to %{count} person.
371
436
  other: Assigned %{set} to %{count} people.
437
+ assigned_cache_kept:
438
+ one: Assigned %{set} to %{count} person, but the cache store did not confirm
439
+ that their cached permissions were cleared. The old permissions may stay
440
+ in use until the cache lifetime ends.
441
+ other: Assigned %{set} to %{count} people, but the cache store did not confirm
442
+ that their cached permissions were cleared. The old permissions may stay
443
+ in use until the cache lifetime ends.
372
444
  revoked:
373
445
  one: Revoked %{set} from %{count} person.
374
446
  other: Revoked %{set} from %{count} people.
447
+ revoked_cache_kept:
448
+ one: Revoked %{set} from %{count} person, but the cache store did not confirm
449
+ that their cached permissions were cleared. The old permissions may stay
450
+ in use until the cache lifetime ends.
451
+ other: Revoked %{set} from %{count} people, but the cache store did not
452
+ confirm that their cached permissions were cleared. The old permissions
453
+ may stay in use until the cache lifetime ends.
454
+ cache_not_confirmed: 'The cache store did not confirm that the cached permissions
455
+ were cleared: the old permissions may stay in use until the cache lifetime
456
+ ends.'
457
+ cache_process_local: 'The cache store lives in this server process only (an
458
+ in-memory store): the other web workers and the job processes keep their cached
459
+ permissions until they restart or the entries expire.'
460
+ copy_refused:
461
+ kinds:
462
+ permission_set: Permission Set “%{name}”
463
+ permission_set_group: Permission Set Group “%{name}”
464
+ permission_set_rule: rule “%{name}”
465
+ record: a row
466
+ resource: Resource “%{name}”
467
+ resource_action: action “%{name}”
468
+ resource_field: field “%{name}”
469
+ message: "“%{name}” was not copied: %{record} holds what a new row cannot
470
+ (%{errors}). Correct it, then copy again."
375
471
  fields:
376
472
  acknowledged: Got it. “%{field}” won't be flagged in the privacy audit again.
377
473
  recommendation_applied: Applied the recommended mask to “%{field}”.
@@ -385,6 +481,7 @@ en:
385
481
  set_added: Moved “%{set}” into this group.
386
482
  set_removed: Removed “%{set}” from this group.
387
483
  updated: Group saved. No one's access changed.
484
+ invalid_param: "%{param} %{detail}. Nothing was changed."
388
485
  locked_widening: 'This Permission Set is locked: access can be removed or shortened,
389
486
  not given or extended.'
390
487
  locked_widening_muting: 'This Muting Permission Set is locked: holders can be
@@ -393,7 +490,17 @@ en:
393
490
  cleaned:
394
491
  one: Removed %{count} expired assignment.
395
492
  other: Removed %{count} expired assignments.
493
+ cleaned_cache_kept:
494
+ one: Removed %{count} expired assignment, but the cache store did not confirm
495
+ that the affected people's cached permissions were cleared. The old permissions
496
+ may stay in use until the cache lifetime ends.
497
+ other: Removed %{count} expired assignments, but the cache store did not
498
+ confirm that the affected people's cached permissions were cleared. The
499
+ old permissions may stay in use until the cache lifetime ends.
500
+ no_changes: No changes to save.
396
501
  not_editable: This record is not editable.
502
+ not_null: A required value was missing. Nothing was changed; the page shows
503
+ what is there now.
397
504
  people:
398
505
  cache_refresh_failed: Could not refresh %{name}'s cached permissions. The
399
506
  cache store did not confirm it, so the old permissions may stay in use until
@@ -438,23 +545,33 @@ en:
438
545
  duplicated_outside_group: 'Duplicated “%{name}”: resources, fields, actions
439
546
  and rules were copied. Assignments were not. The copy is not in “%{group}”,
440
547
  which is locked.'
441
- no_changes: No changes to save.
548
+ nothing_applied: 'Nothing to save: %{reasons}.'
442
549
  save_failed: 'Nothing was saved: %{errors}'
443
550
  saved:
444
551
  one: Saved %{count} change. It applies to %{people} now.
445
552
  other: Saved %{count} changes. They apply to %{people} now.
446
553
  switched_granting: "“%{name}” now grants access."
447
554
  switched_muting: "“%{name}” is now a Muting Permission Set."
555
+ record_not_unique: Another request saved the same thing a moment ago. Nothing
556
+ was changed; the page shows what is there now.
557
+ record_not_unique_detail: "%{detail} — another request saved it a moment ago.
558
+ Nothing was changed; the page shows what is there now."
448
559
  resources:
449
560
  added:
450
561
  one: Added %{resource} with %{count} field.
451
562
  other: Added %{resource} with %{count} fields.
563
+ added_muting: Added %{resource}. It takes away %{what}.
564
+ added_muting_nothing: 'Added %{resource}. It mutes nothing yet: choose below
565
+ what it takes away.'
452
566
  columns_added:
453
567
  one: Added %{count} column.
454
568
  other: Added %{count} columns.
455
569
  missing_removed:
456
570
  one: Removed %{count} field whose column no longer exists.
457
571
  other: Removed %{count} fields whose columns no longer exist.
572
+ muted_fields:
573
+ one: "%{count} field"
574
+ other: "%{count} fields"
458
575
  removed: Removed %{resource} from “%{set}”.
459
576
  rules:
460
577
  created: Added the rule “%{rule}”.
@@ -471,6 +588,28 @@ en:
471
588
  'off': Recording is switched off in the initializer (audit_events = false).
472
589
  No change is recorded.
473
590
  title: The audit log is not recording
591
+ broken_rules_card:
592
+ description: 'These record rules name a field, table, relationship or condition
593
+ that does not exist, or a value their field cannot hold. Each one matches
594
+ nothing: everyone it applies to is denied every record of the resource.'
595
+ fix: Fix rule
596
+ locked_fix_html: 'Locked (%{flag}): it is managed by the system or API that
597
+ created it, so fix the rule there (or unlock the set in code). A copy made
598
+ here would leave this rule as it is.'
599
+ open: Open rules
600
+ people:
601
+ one: "%{count} person has this set."
602
+ other: "%{count} people have this set."
603
+ rule: "“%{rule}” on %{resource} in “%{set}”"
604
+ title: Rules that match nothing
605
+ conditions_card:
606
+ description: These sets hold a condition that cannot be judged (an IP entry
607
+ that is no address, no entry at all, or a broken hour window).
608
+ open: Fix conditions
609
+ people:
610
+ one: "%{count} person has this set."
611
+ other: "%{count} people have this set."
612
+ title: Activation conditions nobody can judge
474
613
  ending_card:
475
614
  description: Assignments that end in the next 7 days.
476
615
  extend: Extend 30 days
@@ -515,8 +654,9 @@ en:
515
654
  people:
516
655
  one: "%{count} person has"
517
656
  other: "%{count} people have"
518
- search_placeholder: Look up a person by name or email to see what they can
519
- access, and why
657
+ search_help: Look up a person by name or email to see what they can access,
658
+ and why
659
+ search_placeholder: Name or email
520
660
  sets:
521
661
  one: "%{count} active Permission Set"
522
662
  other: "%{count} active Permission Sets"
@@ -525,10 +665,24 @@ en:
525
665
  one: "%{count} thing to review"
526
666
  other: "%{count} things to review"
527
667
  title: Needs attention
668
+ mask_strategies_card:
669
+ description: No built-in mask strategy and no custom strategy has these names,
670
+ so their values are masked fully until you pick a strategy or add the custom
671
+ one back.
672
+ field: "“%{field}” on %{resource} in “%{set}”"
673
+ fix: Fix field
674
+ people:
675
+ one: "%{count} person has this set."
676
+ other: "%{count} people have this set."
677
+ strategy_html: Strategy %{strategy}
678
+ title: Fields masked with an unknown strategy
528
679
  privacy_card:
680
+ by_name_note: Fields are flagged by column name, so some may not be personal
681
+ data (a company's name, for example).
529
682
  description: "%{unmasked}, %{unconfigured}."
530
683
  fix: Fix
531
684
  intended: This is intended
685
+ intended_note: If a field is fine unmasked, choose This is intended.
532
686
  per_set_note: Each line looks at one Permission Set on its own. A person who
533
687
  also holds another set that configures the field follows that set.
534
688
  show_all: Show all %{count}
@@ -542,6 +696,7 @@ en:
542
696
  unmasked:
543
697
  one: "%{count} sensitive field shown unmasked"
544
698
  other: "%{count} sensitive fields shown unmasked"
699
+ view: View field
545
700
  where: "%{resource} · Readable unmasked in “%{set}” · %{people}"
546
701
  where_turned_off: "%{resource} · Its setting in “%{set}” is turned off, so
547
702
  it passes through unmasked · %{people}"
@@ -565,6 +720,18 @@ en:
565
720
  the app uses find_by or permission_scoped. Other queries (where, all, associations)
566
721
  return every record.
567
722
  title: Record rules not applied everywhere
723
+ secret_rules_card:
724
+ column_html: Compares %{column}
725
+ description: These record rules compare a column that holds a secret. They
726
+ still apply, but who can see which record gives the secret away. Compare
727
+ another column, or remove the rule.
728
+ fix: Fix rule
729
+ open: Open rules
730
+ people:
731
+ one: "%{count} person has this set."
732
+ other: "%{count} people have this set."
733
+ rule: "“%{rule}” on %{resource} in “%{set}”"
734
+ title: Rules on secret columns
568
735
  stale_card:
569
736
  assigned: Assigned %{date} by %{by}
570
737
  description: Not reviewed in over %{days} days. Confirm these people still
@@ -658,21 +825,20 @@ en:
658
825
  one: " and %{count} more"
659
826
  other: " and %{count} more"
660
827
  from: from %{set}
828
+ masked_by: Masked by %{set}
661
829
  muted_by: Hidden by %{set}
662
830
  none: No set shows it
663
- unconfigured: Not configured · %{behaviour}
831
+ read_only_by: Limited to Read-only by %{set}
832
+ unconfigured: "%{state} · %{behaviour}"
664
833
  virtual: Virtual field, readable by default
665
834
  effective_tab:
666
835
  conditional: "%{sets} only count while their activation conditions are true.
667
836
  They're included here."
668
837
  fields_visible: "%{visible} of %{total} fields visible"
669
838
  grid_label: Effective access
670
- hidden_by_muting: Hidden by muting
671
839
  intro: What %{name} can do right now, with all sets combined. Select any cell
672
840
  to see why.
673
841
  legend: Legend
674
- legend_muted: Muted
675
- legend_none: Not given
676
842
  why: Why
677
843
  why_empty: Select a cell, field or action to see which Permission Set caused
678
844
  it.
@@ -681,10 +847,16 @@ en:
681
847
  action_granted: "%{set} permits this action."
682
848
  action_muted: "%{set} blocks this action."
683
849
  action_none: No Permission Set permits this action.
850
+ action_title: "%{action} · %{resource}"
851
+ field_base_unreadable: 'Hidden: it inherits from %{resource}, which doesn''t
852
+ allow Read.'
684
853
  field_capped: Shown as Read-only because Edit isn't allowed on this resource.
685
- field_from: "%{set} shows this field."
686
- field_muted: "%{set} hides or masks this field."
854
+ field_decided_by: 'Decided by %{resource}, which this inherits from: the strictest
855
+ setting along the inheritance wins.'
856
+ field_hidden_on: Hidden on %{resource}, which this inherits from.
687
857
  field_none: No Permission Set shows this field.
858
+ field_own_unreadable: Hidden because Read isn't allowed on this resource.
859
+ field_title: "%{resource} › %{field}"
688
860
  field_unconfigured: 'No set configures this column: %{behaviour}.'
689
861
  field_variant: Follows the setting of %{base}.
690
862
  field_virtual: Virtual field from the model, readable unless a set configures
@@ -692,6 +864,7 @@ en:
692
864
  flag_granted: "%{set} gives %{flag}."
693
865
  flag_muted: "%{set} mutes %{flag}."
694
866
  flag_none: No Permission Set gives %{flag}.
867
+ flag_title: "%{flag} %{resource}"
695
868
  no_rules: No record rules, so every record is shown.
696
869
  note_add_up: 'Permission Sets add up: one grant is enough.'
697
870
  note_fields: If several sets show a field, the most open setting wins.
@@ -754,7 +927,10 @@ en:
754
927
  tenant and clears their name from the audit log.
755
928
  title: Data subject erasure…
756
929
  refresh:
757
- desc: 'Rarely needed: changes already apply immediately.'
930
+ desc: 'Needed after a change from a console, runner or job when the cache
931
+ store is per process (an in-memory store): that process cleared only
932
+ its own entries, so this web process keeps serving the old permissions
933
+ until they expire.'
758
934
  title: Refresh cached permissions
759
935
  remove_all:
760
936
  desc: 'Offboarding: removes every assignment.'
@@ -827,10 +1003,12 @@ en:
827
1003
  field: Pick the field to check.
828
1004
  list: Add at least one value to the list.
829
1005
  name_blank: Give the rule a name.
1006
+ operator: Pick a condition from the list.
830
1007
  range: Enter both ends of the range.
831
1008
  value: Enter a value, or pick “the current user”.
832
1009
  field: Field to check
833
1010
  follow: Follow a relationship
1011
+ ignored_field: no field row (ignored_fields)
834
1012
  ignored_warning: View All is on for this resource, so record rules are ignored
835
1013
  until it's turned off.
836
1014
  include_nulls: Also show records where %{field} is empty
@@ -847,18 +1025,36 @@ en:
847
1025
  desc: Records without the related record are kept.
848
1026
  title: Also records without it
849
1027
  message: Blocked message
850
- message_placeholder: Shown when someone opens a record this rule hides.
1028
+ message_help: Shown when someone opens a record this rule hides.
1029
+ model_error: "%{field} %{message}"
851
1030
  model_missing: This model or relationship no longer exists in the app.
852
1031
  name: Rule name
853
1032
  name_placeholder: e.g. Own customers
1033
+ notes:
1034
+ secret_column:
1035
+ body_html: "%{column} holds a secret, so a new rule on it is refused.
1036
+ This rule still applies, but who can see which record gives the secret
1037
+ away: compare another column, or remove the rule."
1038
+ title: This rule compares a column that holds a secret
854
1039
  operator: Condition
855
1040
  optional: optional
1041
+ path_html: 'Relationship path: %{path}'
856
1042
  pick_field: Pick a field…
1043
+ pick_relationship: Pick a relationship…
857
1044
  preview: Preview
858
1045
  preview_empty: Pick a field to see the rule as a sentence.
1046
+ preview_refused: Will not save
1047
+ problem_fixes:
1048
+ field: Pick the field again to correct it.
1049
+ join: Choose how to combine again, under Advanced, to correct it.
1050
+ operator: Pick the condition again to correct it.
1051
+ path: Choose the relationship again to correct it.
1052
+ value: Enter a value this field can hold to correct it.
1053
+ problem_title: This rule matches nothing
859
1054
  relationship: Relationship
860
1055
  remove_step: Remove this relationship step
861
1056
  save: Save rule
1057
+ stored_field: "%{name} (as stored)"
862
1058
  this_field: this field
863
1059
  update_form: Update
864
1060
  confirm_destroy:
@@ -869,6 +1065,9 @@ en:
869
1065
  title: Edit rule for %{resource}
870
1066
  new:
871
1067
  title: New rule for %{resource}
1068
+ preview:
1069
+ back: Back to the rules
1070
+ title: Preview of a rule on %{resource}
872
1071
  value_input:
873
1072
  from: From
874
1073
  no_value: No value needed for this condition.
@@ -969,7 +1168,7 @@ en:
969
1168
  copy_name: "%{name} (copy)"
970
1169
  header:
971
1170
  description: Description
972
- description_placeholder: Add a description so others know when to use it
1171
+ description_placeholder: 'Add a description: when to use this set'
973
1172
  group: Group
974
1173
  name: Name
975
1174
  index:
@@ -1052,6 +1251,7 @@ en:
1052
1251
  body_nobody: Nobody has this set yet, so saving affects no one until you assign
1053
1252
  it.
1054
1253
  crumb: Review
1254
+ not_applied: 'Not applied:'
1055
1255
  save: Save changes
1056
1256
  title:
1057
1257
  one: Review %{count} change
@@ -1108,9 +1308,14 @@ en:
1108
1308
  suggestions, or type a key your code checks.
1109
1309
  permitted: Permitted
1110
1310
  managed_note:
1111
- body: As soon as one active Permission Set has a row for an action, only people
1112
- whose Permission Sets permit it can run it. Everyone else is refused.
1113
- title: Adding an action makes it managed for everyone
1311
+ body_allowed: As soon as one active Permission Set has a row for an action,
1312
+ only people whose Permission Sets permit it can run it. Everyone else is
1313
+ refused.
1314
+ body_blocked: Until an active Permission Set has a row for an action, nobody
1315
+ can run it. Once one has, the people whose Permission Sets permit it can
1316
+ run it; everyone else is still refused.
1317
+ title_allowed: Adding an action makes it managed for everyone
1318
+ title_blocked: Adding an action opens it to the people it is permitted to
1114
1319
  unmanaged_allowed: An action no Permission Set manages can be run by everyone.
1115
1320
  unmanaged_blocked: An action no Permission Set manages is blocked for everyone.
1116
1321
  new:
@@ -1133,9 +1338,17 @@ en:
1133
1338
  capped: It shows as Read-only because Edit isn't allowed on this resource.
1134
1339
  full_picture: See everything %{name} can access →
1135
1340
  granted: "%{name} sees it through %{sets}."
1136
- muted: "%{name} doesn't see it in full because %{sets} hides or masks it."
1341
+ hidden_by:
1342
+ one: "%{name} doesn't see it: %{sets} hides it."
1343
+ other: "%{name} doesn't see it: %{sets} hide it."
1344
+ masked_by:
1345
+ one: "%{name} sees it masked: %{sets} masks it."
1346
+ other: "%{name} sees it masked: %{sets} mask it."
1137
1347
  no_access: "%{name} can't read %{resources}."
1138
1348
  none: No set shows this field to %{name}.
1349
+ read_only_by:
1350
+ one: "%{name} can't edit it: %{sets} takes editing away."
1351
+ other: "%{name} can't edit it: %{sets} take editing away."
1139
1352
  unconfigured: No set configures this column, so the unconfigured-field setting
1140
1353
  decides for %{name}.
1141
1354
  virtual_default: "%{name} gets this virtual field by default, readable and
@@ -1156,6 +1369,7 @@ en:
1156
1369
  flags_muting_note: In muting sets these flags mean “remove”.
1157
1370
  impact: Saving applies to %{people} immediately.
1158
1371
  label: Label
1372
+ locked_impact: Locked, so nothing here can be saved.
1159
1373
  mask_strategy: Mask strategy
1160
1374
  muting_note: This is a Muting Permission Set. Choices here take access away.
1161
1375
  no_rules: No rules in this set filter on this field.
@@ -1164,14 +1378,20 @@ en:
1164
1378
  not_configured_implicit: 'No setting for this field in “%{set}”. It follows
1165
1379
  “Virtual fields without a setting”: with the current configuration it is
1166
1380
  readable and editable by default.'
1381
+ not_configured_muting: No setting for this column in “%{set}”, so this Muting
1382
+ Permission Set takes nothing away from it.
1167
1383
  pick_person: Pick a person…
1168
1384
  save: Save
1169
- sensitive: 'Matches privacy pattern “%{pattern}”. Recommended: Masked (%{strategy}).'
1385
+ sensitive: 'Matches privacy pattern “%{pattern}”, so it may be personal data.
1386
+ Recommended: Masked (%{strategy}).'
1170
1387
  turned_off: 'The setting for this field in “%{set}” is turned off, so it does
1171
1388
  not apply. With the current configuration the field is: %{behaviour}.'
1172
1389
  turned_off_implicit: 'The setting for this field in “%{set}” is turned off,
1173
1390
  so it does not apply. The field follows “Virtual fields without a setting”:
1174
1391
  with the current configuration it is readable and editable by default.'
1392
+ turned_off_muting: The setting for this field in “%{set}” is turned off, so
1393
+ this Muting Permission Set takes nothing away from it.
1394
+ unknown_strategy: "(unknown — masked fully until you pick one)"
1175
1395
  used_by_rules: Used by rules
1176
1396
  variants: 'Also applies to:'
1177
1397
  variants_muting: 'Muting this also mutes:'
@@ -1219,20 +1439,12 @@ en:
1219
1439
  filter_label: Filter fields
1220
1440
  filters:
1221
1441
  all: All
1222
- edit: Editable
1223
- hidden: Hidden
1224
- hide: Hidden
1225
- leave: Unchanged
1226
- mask: Force mask
1227
- masked: Masked
1228
- read: Read-only
1229
- sensitive: Sensitive
1230
- unconfigured: Not configured
1231
1442
  implicit_grant: Editable by default
1232
1443
  level: Access level
1233
1444
  level_aria: Access level for %{field}
1445
+ mutes_nothing: Mutes nothing
1234
1446
  no_match: No fields match.
1235
- not_configured: Not configured · %{behaviour}
1447
+ not_configured: "%{state} · %{behaviour}"
1236
1448
  read_off: Turn on Read for %{resource} to choose which fields people see.
1237
1449
  search: Search fields
1238
1450
  select_all: Select all shown fields
@@ -1253,14 +1465,15 @@ en:
1253
1465
  models: Models
1254
1466
  no_models: No models match.
1255
1467
  note: Fields will be created from the model's columns and virtual fields.
1256
- note_gdpr: Fields will be created from the model's columns and virtual fields.
1257
- Privacy defaults are on, so sensitive columns start Masked.
1468
+ note_gdpr: 'Fields will be created from the model''s columns and virtual fields.
1469
+ Privacy defaults are on, so sensitive columns start Masked, except with
1470
+ Full access: then they are only flagged Sensitive, for you to mask.'
1258
1471
  presets:
1259
1472
  block_changes:
1260
1473
  desc: Mutes Create, Edit, Delete and every action.
1261
1474
  title: Block all changes
1262
1475
  full:
1263
- desc: Read, create, edit and delete. All fields editable.
1476
+ desc: Read, create, edit and delete. All fields editable, none masked.
1264
1477
  title: Full access
1265
1478
  hide_sensitive:
1266
1479
  desc: Hides every column that looks like personal data.
@@ -1286,7 +1499,7 @@ en:
1286
1499
  all_queries: applies to all queries
1287
1500
  blocked_message: 'Blocked message: “%{message}”'
1288
1501
  empty: 'No rules yet, so records aren''t limited: people with this set see
1289
- every %{resources} they can read.'
1502
+ every %{resource} record they can read.'
1290
1503
  empty_muting: Muting Permission Sets don't add record rules.
1291
1504
  empty_view_all: No rules. View All is on, so every record is included anyway.
1292
1505
  filter_rule: Filter rule · %{applies}
@@ -1319,7 +1532,7 @@ en:
1319
1532
  modify_all_needs: Needs View All and Edit.
1320
1533
  muting_hint: Muted actions are removed from people with this set, whatever
1321
1534
  their other sets allow.
1322
- muting_note: Settings here take access away from %{set}'s people.
1535
+ muting_note: Settings here take access away from everyone who has “%{set}”.
1323
1536
  needs_read_hint: Edit and Delete need Read.
1324
1537
  record_scope: Record scope
1325
1538
  remove: Remove %{resource} from this set…
@@ -1338,7 +1551,8 @@ en:
1338
1551
  hide: Add all new as Hidden
1339
1552
  read: Add all new as Read-only
1340
1553
  gdpr_off: Privacy defaults are off.
1341
- gdpr_on: 'Privacy defaults are on: sensitive columns are added as Masked.'
1554
+ gdpr_on: 'Privacy defaults are on: sensitive columns are added as Masked,
1555
+ except with full access (then they are only flagged Sensitive).'
1342
1556
  ignored_count:
1343
1557
  one: "%{count} ignored"
1344
1558
  other: "%{count} ignored"
@@ -1351,6 +1565,9 @@ en:
1351
1565
  new_count:
1352
1566
  one: "%{count} new column not configured"
1353
1567
  other: "%{count} new columns not configured"
1568
+ new_count_muting:
1569
+ one: "%{count} column with no setting, so it mutes nothing"
1570
+ other: "%{count} columns with no setting, so they mute nothing"
1354
1571
  new_title: New columns, not configured
1355
1572
  none: None
1356
1573
  remove_missing: Remove missing fields
@@ -1433,6 +1650,9 @@ en:
1433
1650
  api_serializer_overrides:
1434
1651
  desc: Overrides for how records are written in API responses.
1435
1652
  name: Custom serializers
1653
+ api_stats_authorization:
1654
+ desc: Decides who may read usage statistics through the API.
1655
+ name: API stats check
1436
1656
  api_stats_require_admin:
1437
1657
  desc: Only admins can read usage statistics through the API.
1438
1658
  name: Stats only for admins
@@ -1549,7 +1769,8 @@ en:
1549
1769
  show them.
1550
1770
  name: Filter sensitive values from logs
1551
1771
  gdpr_defaults:
1552
- desc: Columns that look personal get masked by default when they're added.
1772
+ desc: Columns that look personal get masked by default when they're added,
1773
+ except when they're added with full access.
1553
1774
  name: Privacy defaults
1554
1775
  gdpr_field_patterns:
1555
1776
  desc: Column names matching a pattern are flagged sensitive and get this
@@ -1581,9 +1802,12 @@ en:
1581
1802
  them from the model.
1582
1803
  name: Mask virtual fields on models
1583
1804
  masked_attributes_nil_user_strategy:
1584
- desc: 'Whether masked models return their stored values or hidden ones when
1585
- there is no current user (jobs, mailers, the console). The user model
1586
- stays readable: sign-in reads it before anyone is signed in.'
1805
+ desc: 'What masked models return when there is no current user. bypass:
1806
+ the stored values everywhere (each read in a web request is logged and
1807
+ published as an audit event). hide_in_requests: hidden values in web requests
1808
+ (a public page, a controller that forgot sign-in), the stored values in
1809
+ jobs, rake tasks and the console. hide: hidden values everywhere. The
1810
+ user model stays readable: sign-in reads it before anyone is signed in.'
1587
1811
  name: Masked attributes with nobody signed in
1588
1812
  masked_write_protection:
1589
1813
  desc: Stops a masked value like “•••• 4821” from being saved back over the
@@ -1593,6 +1817,11 @@ en:
1593
1817
  desc: Whether rules are skipped, deny everything, or raise an error when
1594
1818
  there's no current user.
1595
1819
  name: Record rules with nobody signed in
1820
+ no_read_access_strategy:
1821
+ desc: 'What record lookups and queries return for a signed-in user whose
1822
+ Permission Sets do not grant Read on the resource: the rows the record
1823
+ rules allow (with no rule, every row), or none.'
1824
+ name: Records without read access
1596
1825
  omit_hidden_in_attributes_hash:
1597
1826
  desc: Hidden fields are removed from attribute hashes instead of being set
1598
1827
  to empty.
@@ -1628,6 +1857,10 @@ en:
1628
1857
  desc: Name of the variable that tells the database who the current user
1629
1858
  is.
1630
1859
  name: Database session variable
1860
+ rule_secret_column_patterns:
1861
+ desc: Record rules may not compare columns matching these patterns (password
1862
+ digests, tokens, encrypted_* columns). An empty list allows them.
1863
+ name: Secret column patterns
1631
1864
  snapshot_transactions:
1632
1865
  desc: 'Whether a database transaction keeps seeing the data as it was when
1633
1866
  it began. Permissions computed inside such a transaction are not cached.
@@ -1701,9 +1934,12 @@ en:
1701
1934
  gdpr_defaults: New sensitive columns start masked.
1702
1935
  http_basic_auth_enabled: Access to these screens is protected.
1703
1936
  masked_attributes_nil_user_strategy: Masked models hide their values when
1704
- nobody is signed in (the user model stays readable for sign-in).
1937
+ nobody is signed in, in web requests at least (the user model stays readable
1938
+ for sign-in).
1705
1939
  masked_write_protection: Masked values are never written back.
1706
1940
  nil_user_strategy: Code without a signed-in user sees no records.
1941
+ no_read_access_strategy: Signed-in users without Read on a resource see none
1942
+ of its records.
1707
1943
  preset: The :strict preset closes the settings that fail open by default.
1708
1944
  unconfigured_action_strategy: Controller actions nobody configured are blocked.
1709
1945
  risks:
@@ -1715,18 +1951,22 @@ en:
1715
1951
  the audit table is missing). With audit_events = true and no table, every
1716
1952
  change fails (under the default :raise strategy).
1717
1953
  audit_trail_enabled: No one is recorded as creating or editing records.
1954
+ auto_query_scoping: 'Record rules are in use, but they only apply to find_by
1955
+ and permission_scoped lookups: other queries return every record.'
1718
1956
  conditional_sets_strict_mode: Conditional sets are treated as active when
1719
1957
  request info is missing (fail-open).
1720
1958
  http_basic_auth_enabled: These screens are either locked (password prompt
1721
1959
  on, but no credentials) or unprotected (no password and no custom admin
1722
1960
  controller).
1723
1961
  masked_write_protection: Masked values can be saved back over real data.
1962
+ unconfigured_action_strategy: Controller actions nobody configured can be
1963
+ run by every signed-in user (an explicit opt-out from the :block default).
1724
1964
  unconfigured_field_strategy: Columns nobody configured are shown unmasked
1725
1965
  to anyone who can read the resource.
1726
1966
  row:
1727
1967
  changed: Changed
1728
- default: 'Default: %{value}'
1729
- docs: 'Configuration docs: %{key} ↗'
1968
+ default_html: 'Default: %{value}'
1969
+ docs_html: 'Configuration docs: %{key} ↗'
1730
1970
  how_to_change: How to change
1731
1971
  risk: Risk
1732
1972
  secure: Secure
@@ -1753,6 +1993,9 @@ en:
1753
1993
  record_rules: Record rules & query scoping
1754
1994
  show:
1755
1995
  api_disabled_html: API is disabled (%{key}).
1996
+ attention:
1997
+ one: Home lists %{count} item that needs attention.
1998
+ other: Home lists %{count} items that need attention.
1756
1999
  changed_count:
1757
2000
  one: "%{count} changed"
1758
2001
  other: "%{count} changed"
@@ -1763,12 +2006,16 @@ en:
1763
2006
  intro_html: Settings are defined in %{file}. Changes require a deploy/restart.
1764
2007
  This page shows the current values and how to change them.
1765
2008
  no_match: No settings match.
2009
+ open_home: Open Home
1766
2010
  read_only: Read-only
1767
2011
  search: Search settings
1768
2012
  section_meta: "%{settings} · %{changed}"
1769
2013
  secure_count:
1770
2014
  one: "%{count} security and privacy setting looks good."
1771
2015
  other: "%{count} security and privacy settings look good."
2016
+ secure_count_set:
2017
+ one: "%{count} security and privacy setting is set as recommended."
2018
+ other: "%{count} security and privacy settings are set as recommended."
1772
2019
  settings_count:
1773
2020
  one: "%{count} setting"
1774
2021
  other: "%{count} settings"
@@ -1802,18 +2049,17 @@ en:
1802
2049
  set: Set
1803
2050
  shared:
1804
2051
  across_sets:
1805
- muted_hidden: 'Muted: hidden'
1806
2052
  none: No Permission Set includes this resource.
1807
2053
  active: Active
1808
2054
  audit_footer:
1809
2055
  created: Created by %{created_by} · %{created_at}
1810
2056
  disabled: Created-by and edited-by aren't being recorded.
1811
2057
  edited: Last edited by %{updated_by} · %{updated_at}
2058
+ edited_at: Last edited %{updated_at}
1812
2059
  history: History
1813
2060
  crud_cell:
1814
2061
  allowed: Allowed
1815
2062
  muted: Muted
1816
- needs_read: Turn on Read first
1817
2063
  needs_read_short: Needs Read
1818
2064
  'no': 'No'
1819
2065
  unchanged: Unchanged
@@ -1875,8 +2121,6 @@ en:
1875
2121
  copied: Copied
1876
2122
  copy: Copy
1877
2123
  summary: Technical details
1878
- time_ago: "%{time} ago"
1879
- time_nil: "—"
1880
2124
  toasts:
1881
2125
  dismiss: Dismiss
1882
2126
  undo: Undo
@@ -1887,6 +2131,11 @@ en:
1887
2131
  user_select_prompt: Select a person...
1888
2132
  user_select_truncated: Showing only the first %{count} users. Configure user_list_resolver
1889
2133
  to narrow this list.
2134
+ support:
2135
+ array:
2136
+ last_word_connector: ", and "
2137
+ two_words_connector: " and "
2138
+ words_connector: ", "
1890
2139
  ui:
1891
2140
  actions: Actions
1892
2141
  apply: Apply
@@ -1897,7 +2146,14 @@ en:
1897
2146
  reviewed_by: Reviewed by %{who} on %{date}
1898
2147
  reviewed_on: Reviewed on %{date}
1899
2148
  audit:
1900
- system: System
2149
+ csv:
2150
+ created_at: Created at
2151
+ created_by: Created by
2152
+ edited_at: Last edited at
2153
+ edited_by: Last edited by
2154
+ record: Record
2155
+ type: Type
2156
+ where: Where
1901
2157
  types:
1902
2158
  action: Action
1903
2159
  assignment: Assignment
@@ -1915,18 +2171,19 @@ en:
1915
2171
  fail_open: Fail-open
1916
2172
  fail_open_long: 'Fail-open: active when request info is missing'
1917
2173
  fail_open_title: conditional_sets_strict_mode is off
1918
- locked: Locked
1919
2174
  muting: Muting
1920
- not_configured: Not configured
1921
2175
  'off': 'Off'
1922
2176
  sensitive: Sensitive
2177
+ unknown_mask_strategy: Unknown mask strategy — masked fully until fixed
1923
2178
  virtual: Virtual
1924
2179
  breadcrumb: Breadcrumb
1925
2180
  cancel: Cancel
1926
2181
  changes:
1927
2182
  action_managed_already: "(already managed; sets that permit it: %{sets})"
1928
- action_managed_first: "(this makes it managed: from now on only people whose
1929
- Permission Sets permit it can run it)"
2183
+ action_managed_first_allowed: "(this makes it managed: from now on only people
2184
+ whose Permission Sets permit it can run it)"
2185
+ action_managed_first_blocked: "(the first row for it: from now on the people
2186
+ whose Permission Sets permit it can run it; until now nobody could)"
1930
2187
  action_managed_later: "(takes effect once this set and this resource are on)"
1931
2188
  action_managed_nobody: "(already managed; no Permission Set permits it yet)"
1932
2189
  action_muted: "%{resource}: %{action} blocked"
@@ -1952,6 +2209,9 @@ en:
1952
2209
  flag_off_muting: "%{resource}: %{flag} no longer muted"
1953
2210
  flag_on: "%{resource}: %{flag} allowed"
1954
2211
  flag_on_muting: "%{resource}: %{flag} muted"
2212
+ not_applied_read: "%{resource}: %{flag} not turned on, because Read is off"
2213
+ not_applied_view_all_and_edit: "%{resource}: %{flag} not turned on, because
2214
+ it needs View All and Edit"
1955
2215
  resource_text: "%{resource}: %{attribute} changed"
1956
2216
  set_group: Moved to the group “%{group}”
1957
2217
  set_no_group: Removed from its group
@@ -1961,6 +2221,9 @@ en:
1961
2221
  close: Close
1962
2222
  conditions:
1963
2223
  always: Always active. No activation conditions.
2224
+ effect:
2225
+ granting: It never passes, so it grants nothing.
2226
+ muting: 'A Muting Permission Set: it applies to every request.'
1964
2227
  flag_generic: when %{flag} is set
1965
2228
  flags:
1966
2229
  marketing_consent: when marketing consent is given
@@ -1968,9 +2231,25 @@ en:
1968
2231
  sso_login: after company SSO sign-in
1969
2232
  from_ips: from %{ips}
1970
2233
  hours: between %{from} and %{to}
2234
+ hours_broken: between %{from} and %{to} (a window nobody can judge — fix it
2235
+ on the Conditions tab)
2236
+ hours_broken_here: between %{from} and %{to} (a window nobody can judge)
1971
2237
  hours_overnight: between %{from} and %{to} (overnight)
2238
+ ips_broken: from %{ips} (a list nobody can judge — fix it on the Conditions
2239
+ tab)
2240
+ ips_broken_here: from %{ips} (a list nobody can judge)
2241
+ no_hour: no hour
1972
2242
  only_works: Only works %{parts}.
1973
2243
  or: " or "
2244
+ problems:
2245
+ flag_unusable_html: The session flag %{flag} holds a control character,
2246
+ so no request can carry it.
2247
+ hours_equal: The start and end hour are the same, so the window is empty.
2248
+ hours_incomplete: Only one of the two hours is set.
2249
+ hours_range: An hour is outside 00:00–23:00.
2250
+ ip_empty: The IP list holds separators but no entry.
2251
+ ip_entry_html: "%{entry} is not an IP address or CIDR range."
2252
+ problems_title: These conditions cannot be judged
1974
2253
  dates:
1975
2254
  days_ago:
1976
2255
  one: "%{count} day ago"
@@ -2011,16 +2290,13 @@ en:
2011
2290
  read_access: Read
2012
2291
  view_all: View All
2013
2292
  keep: Keep
2014
- levels:
2015
- edit: Editable
2016
- hidden: Hidden
2017
- hide: Hide
2018
- leave: Unchanged
2019
- mask: Force mask
2020
- masked: Masked
2021
- muted: Muted
2022
- none: Not configured
2023
- read: Read-only
2293
+ level_sentences:
2294
+ edit: "%{set} shows this field and lets people edit it."
2295
+ hide: "%{set} hides this field."
2296
+ mask: "%{set} forces this field masked."
2297
+ masked: "%{set} shows this field masked (%{strategy})."
2298
+ no_edit: "%{set} stops people editing this field."
2299
+ read: "%{set} shows this field read-only."
2024
2300
  locked:
2025
2301
  title: 'Locked: managed by the system/API'
2026
2302
  mask_strategies:
@@ -2041,6 +2317,7 @@ en:
2041
2317
  nov: Nov
2042
2318
  oct: Oct
2043
2319
  sep: Sep
2320
+ needs_read_first: Turn on Read first
2044
2321
  next: Next
2045
2322
  no_group: Not in a group
2046
2323
  open_person: Open person
@@ -2068,48 +2345,182 @@ en:
2068
2345
  records: Records
2069
2346
  remove: Remove
2070
2347
  resource: Resource
2348
+ resource_plural:
2349
+ one: "%{name} record"
2350
+ other: "%{name} records"
2071
2351
  rules:
2072
2352
  and: and
2073
2353
  current_user: the current user
2354
+ matches_nothing: Matches nothing
2355
+ notes:
2356
+ secret_column: Secret column
2074
2357
  only_show: Only show
2075
2358
  or_empty: or %{field} is empty
2359
+ problems:
2360
+ empty_association: The relationship path has an empty step (two dots in
2361
+ a row, or a dot at the start)
2362
+ encrypted_column: "%{name} of %{model} is encrypted: the database holds
2363
+ its ciphertext, so a rule can only check whether it is empty"
2364
+ foreign_table_html: "%{name} is a table of another model: a filter rule
2365
+ compares %{model}'s own columns"
2366
+ missing_column_html: "%{name} is not a column of %{model}"
2367
+ pattern_on_non_text: "%{name} of %{model} is not text: a pattern condition
2368
+ (contains, starts with, ends with) cannot match it"
2369
+ unjoinable_association: "%{name} is a relationship of %{model} that a rule
2370
+ cannot follow"
2371
+ unjoinable_class_not_loadable: "%{name} is a relationship of %{model} whose
2372
+ model cannot be loaded"
2373
+ unjoinable_invalid_definition: "%{name} is a relationship of %{model} whose
2374
+ :through, :source or inverse_of names a relationship that is not there"
2375
+ unjoinable_polymorphic: "%{name} is a polymorphic relationship of %{model}:
2376
+ a rule cannot follow it"
2377
+ unjoinable_record_dependent_scope: "%{name} is a relationship of %{model}
2378
+ whose scope depends on the record: a rule cannot follow it"
2379
+ unknown_association_html: "%{name} is not a relationship of %{model}"
2380
+ unknown_join_type_html: "%{name} is not a way of joining this version knows"
2381
+ unknown_operator_html: "%{name} is not a condition this version knows"
2382
+ unknown_table_html: "%{name} is not a table of this database"
2383
+ unusable_value_html: "%{value} is not a value %{name} of %{model} can hold"
2076
2384
  where: where
2077
2385
  rules_count:
2078
2386
  one: Rules (%{count})
2079
2387
  other: Rules (%{count})
2080
2388
  rules_tab: Rules
2081
2389
  search: Search
2082
- search_people: Search by name or email
2390
+ search_people: Name or email
2083
2391
  setting: Setting
2084
2392
  states:
2085
- blocked: Blocked
2086
- granted: Allowed
2087
- none: 'No'
2393
+ actor:
2394
+ api: API client
2395
+ basic_auth: Password prompt
2396
+ system: System
2397
+ unknown: Unknown
2398
+ user: Person
2399
+ effective:
2400
+ blocked: Blocked
2401
+ granted: Allowed
2402
+ hidden_by_muting: Hidden by muting
2403
+ none: 'No'
2404
+ field_level:
2405
+ edit: Editable
2406
+ hidden: Hidden
2407
+ hide: Hide
2408
+ leave: Unchanged
2409
+ mask: Force mask
2410
+ masked: Masked
2411
+ none: Not configured
2412
+ read: Read-only
2413
+ lock:
2414
+ locked: Locked
2088
2415
  unconfigured:
2089
2416
  block: Blocked by default
2090
2417
  mask_all: Fully masked
2091
2418
  pass_through: Passes through unmasked
2092
2419
  warn: Passes through and is logged
2420
+ untitled:
2421
+ permission_set: Untitled Permission Set
2422
+ permission_set_group: Untitled Permission Set Group
2423
+ permission_set_rule: Untitled Rule
2093
2424
  view_all: View All
2094
2425
  validations:
2426
+ attributes:
2427
+ allowed_hours_end: End hour
2428
+ allowed_hours_start: Start hour
2429
+ allowed_ips: Allowed IPs
2430
+ create_access: Create
2431
+ delete_access: Delete
2432
+ description: Description
2433
+ edit_access: Edit
2434
+ expires_at: End date
2435
+ failure_message: Blocked message
2436
+ field_accessor_path: Relationship
2437
+ field_name: Field
2438
+ field_value: Value
2439
+ include_nulls: Include empty values
2440
+ is_active: Active
2441
+ is_editable: Editable
2442
+ is_muting: Muting
2443
+ is_permitted: Permitted
2444
+ join_type: Join
2445
+ label: Label
2446
+ mask_access: Mask
2447
+ mask_strategy: Mask strategy
2448
+ modify_all: Modify All
2449
+ name: Name
2450
+ operator: Condition
2451
+ permission_set_group: Permission Set Group
2452
+ read_access: Read
2453
+ requires_session_flag: Session flag
2454
+ user_id: Person
2455
+ uuid: UUID
2456
+ view_all: View All
2457
+ blank: can't be blank
2458
+ full_message: "%{attribute} %{message}"
2459
+ invalid: is invalid
2095
2460
  name_blank: can't be blank
2461
+ nul_byte: must not contain a NUL byte
2096
2462
  permission_set:
2463
+ flag_unusable: 'must not hold a control character (a newline, a tab): no request
2464
+ can carry such a flag'
2097
2465
  group_missing: must be an existing Permission Set Group
2466
+ hours_equal: must differ from the start hour (a window from an hour to the
2467
+ same hour is empty; leave both blank for no window)
2468
+ hours_incomplete: must be set together with the other hour (or both left blank)
2469
+ hours_range: must be between 0 and 23
2470
+ invalid_ip_entry: contains “%{entry}”, which is not an IP address or CIDR
2471
+ range
2472
+ name_taken: is already used by another Permission Set
2473
+ permission_set_group_user:
2474
+ taken: is already a member of this group
2098
2475
  permission_set_rule:
2099
2476
  between_requires_two_values: must contain exactly 2 comma-separated values
2100
2477
  for between operator
2478
+ empty_association: has an empty association name (two dots in a row, or a
2479
+ dot at the start)
2480
+ encrypted_column: 'names %{name}, an encrypted attribute of %{model}: the
2481
+ database holds its ciphertext, so a rule can only check whether it is empty
2482
+ (is_null, is_not_null)'
2101
2483
  field_value_required: is required for this operator
2484
+ foreign_table: 'names %{name}, a table that is not %{model}''s: a filter rule
2485
+ compares its own table. For a column of another table, use a join rule (a
2486
+ join type and the relationship path)'
2102
2487
  in_requires_values: must contain at least 1 comma-separated value
2103
2488
  invalid_field_name: must be a valid column name (letters, numbers, underscores,
2104
2489
  dots)
2105
2490
  invalid_join_type: is not a valid join type
2106
2491
  invalid_operator: is not a valid operator
2492
+ nul_byte: must not contain a NUL byte
2107
2493
  numeric_or_date_required: must be a numeric or date value for comparison operators
2494
+ pattern_on_non_text: 'matches text only, and %{model}.%{name} is a column
2495
+ of type %{type}: use a condition that compares values'
2496
+ secret_column: 'names a column that holds a secret (a password digest, a token,
2497
+ an encrypted_* column): a record rule never compares one'
2498
+ unjoinable_association: names %{association}, an association of %{model} that
2499
+ a rule cannot join
2500
+ unjoinable_class_not_loadable: names %{association}, an association of %{model}
2501
+ whose class cannot be loaded
2502
+ unjoinable_invalid_definition: names %{association}, an association of %{model}
2503
+ whose :through, :source or inverse_of names an association that is not there
2504
+ unjoinable_polymorphic: 'names %{association}, a polymorphic association of
2505
+ %{model}: a rule cannot join it'
2506
+ unjoinable_record_dependent_scope: 'names %{association}, an association of
2507
+ %{model} whose scope (or one along its :through) takes the record: a rule
2508
+ cannot join it'
2509
+ unknown_association: names %{association}, which is not an association of
2510
+ %{model}
2511
+ unknown_column: names %{name}, which is not a column of %{model}
2512
+ unknown_table: names %{name}, which is no table of this database
2513
+ unusable_value: is not a value %{model}.%{name} can hold
2108
2514
  value_not_expected: does not require a value for this operator
2109
2515
  value_required: must not be blank for this operator
2516
+ permission_set_user:
2517
+ taken: already holds this Permission Set
2518
+ requires: requires %{requires} to be enabled
2110
2519
  resource:
2111
2520
  invalid_name: must be a valid model class name (e.g. Customer or Admin::Report)
2521
+ name_taken: already exists in this permission set
2112
2522
  resource_field:
2113
2523
  invalid_mask_strategy: is not a valid mask strategy
2114
2524
  mask_strategy_required: must be present when mask access is enabled
2525
+ taken: has already been taken
2115
2526
  too_long: is too long (at most %{count} characters)