Add a policy-enforced setting wrapper and use it for request access
What does this MR do and why?
Summary
This change introduces a new UI component called PolicyEnforcedSetting that visually communicates when a project setting is controlled by a security policy. When a policy is in enforce mode, the setting becomes disabled and a lock icon appears with a popover explaining which policy controls it. When in warn mode, the setting remains editable but a warning message appears below it explaining the non-compliance, along with the policy author's message when there is one. In audit mode (or when no policy applies), the setting looks and behaves completely normally.
The first setting to use this new component is the "Users can request access" checkbox on the project permissions page. The feature is gated behind a feature flag (policy_store_setting_enforcement) scoped to the project's root group, so it has no visible effect until explicitly enabled. No backend lookup ships here: the panel exposes a requestAccessEnforcements prop that nothing fills yet, so the data source is decided by the follow-up once the policy preview design (https://gitlab.com/gitlab-org/architecture/govern/design-doc/-/merge_requests/29) settles. Accessibility is also considered — screen readers will announce the policy restriction alongside the disabled state of the control.
References
- Work item: https://gitlab.com/gitlab-org/gitlab/-/work_items/631256
- First MR of the plan, posted on the work item: https://gitlab.com/gitlab-org/gitlab/-/work_items/631256#note_3924775112
- Feature flag rollout issue: #631790
- Parent epic: https://gitlab.com/groups/gitlab-org/-/work_items/23462
Screenshots or screen recordings
| Before | After |
|---|---|
| No visible change on any page until a policy row is supplied. The validation steps below show how to produce the enforce and warn states. |
No visible change on any page until a policy row is supplied. The validation steps below show how to produce the enforce and warn states. |
How to set up and validate locally
-
Enable the flag for the project's root group in a Rails console.
project = Project.find_by_full_path('flightjs/Flight') Feature.enable(:policy_store_setting_enforcement, project.root_ancestor) -
Mock an enforced state. No policy lookup exists yet. Temporarily edit the
requestAccessEnforcementsprop default inapp/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue. Replacedefault: () => []with the following. Vite reloads the page on save.default: () => [ { mode: 'enforce', policy: { name: 'Lock request access', webPath: '/groups/flightjs/-/security/policy_store/1' }, message: null }, ], -
Open the project's General settings and expand "Visibility, project features, permissions". The project visibility must be Internal or Public, because the checkbox is hidden for Private projects.
-
Expect the "Users can request access" checkbox to be disabled. Expect a lock icon beside it. Hovering or focusing the icon opens a popover titled "Setting managed by policy". The popover link points at the policy path. In the accessibility tree, the checkbox has
aria-describedbypointing at the hidden description text. -
Switch the mock row to warn. Set
mode: 'warn'andmessage: 'Disable request access before the audit.'. Reload the page. Expect the checkbox to be enabled again, with no lock icon. Expect a notice below it that reads "This setting does not comply with the policy Lock request access." followed by the message. -
Set
mode: 'audit'and reload. Expect the checkbox to be unchanged, with no notice. -
Disable the flag with
Feature.disable(:policy_store_setting_enforcement, project.root_ancestor). Reload with the enforce row still mocked. Expect the checkbox to be unchanged. Revert the prop default afterwards. -
Alternatively, run
yarn storybookand openvue_shared/settings/policy_enforced_settingto see every mode without a GDK project.
Verification
- Plan and progress: https://gitlab.com/gitlab-org/gitlab/-/work_items/631256#note_3924775112
- Local: Jest green across the touched spec files; RSpec for the controller example; ESLint, Prettier and RuboCop clean on the changed lines.
- Adversarial review before the first push:
pass with findings. Fixed: unknown-mode rows outranking an enforce row, anullprop crashing the wrapper, fragile link placeholders, audit policies and duplicates in the popover, a doubly announced description, markup changes with the flag off, and a weak panel spec. Left as is: the popover link is not keyboard reachable, matching the existing popovers in the same folder, and the "Also governed by" list uses a plain comma join.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

