ee/app/policies/ee/project_policy.rb (985 lines of code) (raw):
# frozen_string_literal: true
module EE
module ProjectPolicy
extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
prepended do
include ReadonlyAbilities
include ::Gitlab::Utils::StrongMemoize
include Vulnerabilities::AdvancedVulnerabilityManagementPolicy
desc "User is a security policy bot on the project"
condition(:security_policy_bot) { user&.security_policy_bot? && team_member? }
with_scope :subject
condition(:repository_mirrors_enabled) { @subject.feature_available?(:repository_mirrors) }
with_scope :subject
condition(:iterations_available) { @subject.group&.licensed_feature_available?(:iterations) }
with_scope :subject
condition(:requirements_available) { @subject.feature_available?(:requirements) & access_allowed_to?(:requirements) }
with_scope :subject
condition(:quality_management_available) { @subject.feature_available?(:quality_management) }
condition(:compliance_framework_available) { @subject.feature_available?(:compliance_framework, @user) }
with_scope :subject
condition(:project_level_compliance_dashboard_enabled) do
in_group? && @subject.feature_available?(:project_level_compliance_dashboard)
end
with_scope :subject
condition(:project_level_compliance_adherence_report_enabled) do
in_group? && @subject.feature_available?(:project_level_compliance_adherence_report)
end
with_scope :subject
condition(:project_level_compliance_violations_report_enabled) do
in_group? && @subject.feature_available?(:project_level_compliance_violations_report)
end
with_scope :subject
condition(:project_epics_available) do
@subject.project_epics_enabled? && @subject.licensed_feature_available?(:epics)
end
with_scope :global
condition(:is_development) { Rails.env.development? }
with_scope :global
condition(:ai_available) do
::Feature.enabled?(:ai_global_switch, type: :ops)
end
with_scope :subject
condition(:generate_cube_query_enabled) do
::Feature.enabled?(:generate_cube_query, @subject) &&
::Gitlab::Llm::FeatureAuthorizer.new(
container: subject,
feature_name: :generate_cube_query,
user: @user
).allowed?
end
with_scope :global
condition(:locked_approvers_rules) do
!@user.can_admin_all_resources? &&
License.feature_available?(:admin_merge_request_approvers_rules) &&
::Gitlab::CurrentSettings.disable_overriding_approvers_per_merge_request
end
with_scope :subject
condition(:disable_invite_members_for_group) do
::Gitlab::Saas.feature_available?(:group_disable_invite_members) &&
@subject.group &&
@subject.group.root_ancestor.licensed_feature_available?(:disable_invite_members) &&
@subject.group.root_ancestor.disable_invite_members?
end
with_scope :global
condition(:disable_invite_members) do
License.feature_available?(:disable_invite_members) &&
::Gitlab::CurrentSettings.current_application_settings.disable_invite_members?
end
condition(:group_merge_request_approval_settings_enabled) do
@subject.feature_available?(:merge_request_approvers)
end
with_scope :global
condition(:locked_merge_request_author_setting) do
License.feature_available?(:admin_merge_request_approvers_rules) &&
::Gitlab::CurrentSettings.prevent_merge_requests_author_approval
end
with_scope :global
condition(:locked_merge_request_committer_setting) do
License.feature_available?(:admin_merge_request_approvers_rules) &&
::Gitlab::CurrentSettings.prevent_merge_requests_committers_approval
end
with_scope :subject
condition(:dora4_analytics_available) do
@subject.feature_available?(:dora4_analytics)
end
condition(:project_merge_request_analytics_available) do
@subject.feature_available?(:project_merge_request_analytics)
end
condition(:push_rules_available, scope: :subject) do
@subject.feature_available?(:push_rules)
end
condition(:commit_committer_check_available, scope: :subject) do
@subject.feature_available?(:commit_committer_check)
end
condition(:commit_committer_name_check_available, scope: :subject) do
@subject.feature_available?(:commit_committer_name_check)
end
condition(:reject_unsigned_commits_available, scope: :subject) do
@subject.feature_available?(:reject_unsigned_commits)
end
condition(:reject_non_dco_commits_available, scope: :subject) do
@subject.feature_available?(:reject_non_dco_commits)
end
condition(:security_orchestration_policies_enabled, scope: :subject) do
@subject.feature_available?(:security_orchestration_policies)
end
condition(:security_dashboard_enabled, scope: :subject) do
@subject.feature_available?(:security_dashboard)
end
condition(:security_scans_api_enabled, scope: :subject) do
# We check the service name to determine if the backend is globally available
# We use free_access? to check that the backend is globally availabile
security_scans_service.free_access? &&
@subject.licensed_feature_available?(:security_scans_api)
end
condition(:coverage_fuzzing_enabled, scope: :subject) do
@subject.feature_available?(:coverage_fuzzing)
end
condition(:on_demand_scans_enabled, scope: :subject) do
@subject.on_demand_dast_available?
end
condition(:license_scanning_enabled, scope: :subject) do
@subject.feature_available?(:license_scanning)
end
condition(:dependency_scanning_enabled, scope: :subject) do
@subject.feature_available?(:dependency_scanning)
end
condition(:code_review_analytics_enabled) do
@subject.feature_available?(:code_review_analytics, @user)
end
condition(:issue_analytics_enabled) do
@subject.feature_available?(:issues_analytics, @user)
end
condition(:combined_project_analytics_dashboards_enabled) do
@subject.feature_available?(:combined_project_analytics_dashboards, @user)
end
condition(:google_cloud_support_available, scope: :global) do
::Gitlab::Saas.feature_available?(:google_cloud_support)
end
condition(:status_page_available) do
@subject.feature_available?(:status_page, @user)
end
condition(:read_only, scope: :subject) do
@subject.root_namespace.read_only?
end
condition(:feature_flags_related_issues_disabled, scope: :subject) do
!@subject.feature_available?(:feature_flags_related_issues)
end
condition(:oncall_schedules_available, scope: :subject) do
::Gitlab::IncidentManagement.oncall_schedules_available?(@subject)
end
condition(:escalation_policies_available, scope: :subject) do
::Gitlab::IncidentManagement.escalation_policies_available?(@subject)
end
condition(:hidden, scope: :subject) do
@subject.hidden?
end
condition(:membership_locked_via_parent_group, scope: :subject) do
@subject.group && (
@subject.group.membership_lock? ||
::Gitlab::CurrentSettings.lock_memberships_to_ldap? ||
::Gitlab::CurrentSettings.lock_memberships_to_saml)
end
condition(:security_policy_project_available, scope: :subject) do
@subject.security_orchestration_policy_configuration.present?
end
condition(:can_commit_to_security_policy_project) do
security_orchestration_policy_configuration = @subject.security_orchestration_policy_configuration
next unless security_orchestration_policy_configuration
Ability.allowed?(@user, :developer_access, security_orchestration_policy_configuration.security_policy_management_project)
end
condition(:okrs_enabled, scope: :subject) do
@subject.okrs_mvc_feature_flag_enabled? && @subject.feature_available?(:okrs)
end
condition(:licensed_cycle_analytics_available, scope: :subject) do
@subject.feature_available?(:cycle_analytics_for_projects)
end
condition(:agent_registry_enabled, scope: :subject) do
::Feature.enabled?(:agent_registry, @subject) && @subject.licensed_feature_available?(:ai_agents)
end
condition(:user_banned_from_namespace) do
next unless @user.is_a?(User)
next if @user.can_admin_all_resources?
# Loading the namespace_bans association is intentional because it is going to
# be used in the banned_from_namespace? check below
next if @user.namespace_bans.to_a.empty?
groups = @subject.invited_groups + [@subject.group]
groups.compact!
next if groups.empty?
groups.any? do |group|
next unless group.root_ancestor.unique_project_download_limit_enabled?
@user.banned_from_namespace?(group.root_ancestor)
end
end
rule { membership_locked_via_parent_group }.policy do
prevent :import_project_members_from_another_project
prevent :invite_member
end
condition(:custom_roles_allowed) do
@subject.custom_roles_enabled?
end
MemberRole.all_customizable_project_permissions.each do |ability|
desc "Custom role on project that enables #{ability.to_s.tr('_', ' ')}"
condition("custom_role_enables_#{ability}".to_sym) do
custom_role_ability(@user, @subject).allowed?(ability)
end
end
MemberRole.all_customizable_admin_permission_keys.each do |ability|
desc "Admin custom role that enables #{ability.to_s.tr('_', ' ')}"
condition(:"admin_custom_role_enables_#{ability}", scope: :user) do
::Authz::CustomAbility.new(@user).allowed?(ability)
end
end
with_scope :subject
condition(:suggested_reviewers_available) do
@subject.can_suggest_reviewers?
end
condition(:summarize_new_merge_request_enabled) do
::Feature.enabled?(:add_ai_summary_for_new_mr, subject) &&
::Gitlab::Llm::FeatureAuthorizer.new(
container: subject,
feature_name: :summarize_new_merge_request,
user: @user,
licensed_feature: :summarize_new_merge_request
).allowed?
end
condition(:generate_description_enabled) do
::Gitlab::Llm::FeatureAuthorizer.new(
container: subject,
feature_name: :generate_description,
user: @user
).allowed?
end
condition(:summarize_notes_allowed) do
next false unless @user
::Gitlab::Llm::FeatureAuthorizer.new(
container: subject,
feature_name: :summarize_comments,
user: @user
).allowed?
end
with_scope :subject
condition(:target_branch_rules_available) { subject.licensed_feature_available?(:target_branch_rules) }
condition(:pages_multiple_versions_available) do
@subject.licensed_feature_available?(:pages_multiple_versions)
end
condition(:merge_requests_is_a_private_feature) do
project.project_feature&.private?(:merge_requests)
end
condition(:observability_enabled) do
::Feature.enabled?(:observability_features, @subject.root_namespace) &&
@subject.licensed_feature_available?(:observability)
end
# We are overriding the already defined condition in CE version
# to allow Guest users with member roles to access the merge requests.
condition(:merge_requests_disabled) do
!(access_allowed_to?(:merge_requests) ||
(merge_requests_is_a_private_feature? && custom_role_enables_admin_merge_request?))
end
rule { custom_role_enables_admin_cicd_variables }.policy do
enable :admin_cicd_variables
end
rule { custom_role_enables_admin_protected_environments }.policy do
enable :admin_protected_environments
end
rule { custom_role_enables_admin_push_rules }.policy do
enable :admin_push_rules
end
rule { custom_role_enables_manage_protected_tags }.policy do
enable :manage_protected_tags
end
rule { can?(:manage_protected_tags) }.policy do
enable :read_protected_tags
enable :create_protected_tags
enable :update_protected_tags
enable :destroy_protected_tags
end
rule { custom_role_enables_admin_integrations }.policy do
enable :admin_integrations
end
rule { custom_role_enables_admin_runners }.policy do
enable :admin_runner
enable :create_runner
end
rule { can?(:admin_runner) }.enable :read_runner
rule { custom_role_enables_read_runners }.policy do
enable :read_project_runners
enable :read_runner
end
rule { admin_custom_role_enables_read_admin_cicd }.policy do
enable :read_project_metadata
end
condition(:ci_cancellation_maintainers_only, scope: :subject) do
project.ci_cancellation_restriction.maintainers_only_allowed?
end
condition(:ci_cancellation_no_one, scope: :subject) do
project.ci_cancellation_restriction.no_one_allowed?
end
condition(:chat_allowed_for_parent_group, scope: :subject) do
next true unless ::Gitlab::Saas.feature_available?(:duo_chat_on_saas)
::Gitlab::Llm::StageCheck.available?(@subject.parent, :chat)
end
condition(:chat_available_for_user, scope: :user) do
Ability.allowed?(@user, :access_duo_chat)
end
condition(:duo_core_available_for_user, scope: :user) do
@user.any_root_namespace_with_duo_core_add_on?
end
condition(:duo_features_enabled, scope: :subject) { @subject.duo_features_enabled }
condition(:duo_core_features_enabled, scope: :subject) { @subject.namespace.duo_core_features_enabled? }
rule { visual_review_bot }.policy do
prevent_all
end
rule { license_block }.policy do
prevent :create_issue
prevent :create_merge_request_in
prevent :create_merge_request_from
prevent :push_code
end
rule { analytics_disabled }.policy do
prevent(:read_project_merge_request_analytics)
prevent(:read_code_review_analytics)
prevent(:read_issue_analytics)
end
rule { ~admin & (~is_gitlab_com & disable_invite_members) }.policy do
prevent :invite_project_members
end
rule { ~admin & disable_invite_members_for_group }.policy do
prevent :invite_project_members
end
rule { feature_flags_related_issues_disabled | repository_disabled }.policy do
prevent :admin_feature_flags_issue_links
end
rule { can?(:guest_access) & iterations_available }.enable :read_iteration
rule { can?(:reporter_access) }.policy do
enable :admin_issue_board
enable :read_product_analytics
end
rule { monitor_disabled }.policy do
prevent :read_incident_management_oncall_schedule
prevent :admin_incident_management_oncall_schedule
prevent :read_incident_management_escalation_policy
prevent :admin_incident_management_escalation_policy
end
rule { oncall_schedules_available & can?(:reporter_access) }.enable :read_incident_management_oncall_schedule
rule { escalation_policies_available & can?(:reporter_access) }.enable :read_incident_management_escalation_policy
rule { can?(:read_code) }.policy do
enable :read_path_locks
end
rule { can?(:developer_access) }.policy do
enable :admin_issue_board
enable :admin_feature_flags_issue_links
enable :read_project_audit_events
enable :create_workspace
enable :enable_continuous_vulnerability_scans
enable :read_project_security_exclusions
enable :read_security_settings
end
rule { can?(:push_code) }.policy do
enable :create_path_lock
end
rule { planner_or_reporter_access & iterations_available }.policy do
enable :create_iteration
enable :admin_iteration
end
rule { custom_roles_allowed & (guest | admin) }.policy do
enable :read_member_role
end
rule { can?(:read_project) & iterations_available }.enable :read_iteration
rule { security_orchestration_policies_enabled & can?(:developer_access) }.policy do
enable :read_security_orchestration_policies
end
rule { security_orchestration_policies_enabled & can?(:owner_access) }.policy do
enable :update_security_orchestration_policy_project
end
rule { security_orchestration_policies_enabled & can?(:reporter_access) }.policy do
enable :read_security_orchestration_policy_project
end
rule { security_orchestration_policies_enabled & auditor }.policy do
enable :read_security_orchestration_policies
end
rule { security_orchestration_policies_enabled & can?(:owner_access) & ~security_policy_project_available }.policy do
enable :modify_security_policy
end
rule { security_orchestration_policies_enabled & security_policy_project_available & can_commit_to_security_policy_project }.policy do
enable :modify_security_policy
end
rule { security_orchestration_policies_enabled & custom_role_enables_manage_security_policy_link }.policy do
enable :read_security_orchestration_policies
enable :read_security_orchestration_policy_project
enable :update_security_orchestration_policy_project
enable :access_security_and_compliance
end
rule { security_dashboard_enabled & can?(:developer_access) }.policy do
enable :read_security_resource
end
rule { security_scans_api_enabled & can?(:developer_access) }.policy do
enable :access_security_scans_api
end
rule { coverage_fuzzing_enabled & can?(:developer_access) }.policy do
enable :read_coverage_fuzzing
enable :create_coverage_fuzzing_corpus
end
rule { on_demand_scans_enabled & can?(:developer_access) }.policy do
enable :read_on_demand_dast_scan
enable :create_on_demand_dast_scan
enable :edit_on_demand_dast_scan
end
rule { on_demand_scans_enabled & security_policy_bot }.policy do
enable :read_on_demand_dast_scan
enable :create_on_demand_dast_scan
end
rule { security_dashboard_enabled & can?(:maintainer_access) }.policy do
enable :admin_security_testing
end
rule { custom_role_enables_admin_security_testing }.policy do
enable :admin_security_testing
end
rule { security_dashboard_enabled & can?(:admin_security_testing) }.policy do
enable :access_security_and_compliance
enable :read_security_configuration
enable :read_project_security_dashboard
enable :read_security_resource
# create scanner configuration
enable :push_code
enable :download_code
enable :read_merge_request
enable :create_merge_request_from
end
rule { secret_push_protection_available & can?(:admin_security_testing) }.policy do
enable :read_secret_push_protection_info
enable :enable_secret_push_protection
enable :read_project_security_exclusions
end
rule { container_scanning_for_registry_available & can?(:admin_security_testing) }.policy do
enable :enable_container_scanning_for_registry
end
rule { coverage_fuzzing_enabled & can?(:admin_security_testing) }.policy do
enable :read_coverage_fuzzing
enable :create_coverage_fuzzing_corpus
end
rule { security_scans_api_enabled & can?(:admin_security_testing) }.policy do
enable :access_security_scans_api
end
rule { on_demand_scans_enabled & can?(:admin_security_testing) }.policy do
enable :read_on_demand_dast_scan
enable :create_on_demand_dast_scan
enable :edit_on_demand_dast_scan
enable :read_project_runners # read runner tags when creating scan
enable :create_pipeline # run a scan
end
rule { security_dashboard_enabled & security_policy_bot }.policy do
enable :create_vulnerability_state_transition
end
# If licensed but not reporter+, prevent access
rule { can?(:read_merge_request) & can?(:read_issue) & licensed_cycle_analytics_available }.policy do
enable :read_cycle_analytics
end
# If licensed and reporter+, allow access
rule { ((reporter | admin)) & licensed_cycle_analytics_available }.policy do
enable :admin_value_stream
end
rule { can?(:read_merge_request) & can?(:read_pipeline) }.enable :read_merge_train
rule { can?(:read_security_resource) }.policy do
enable :read_project_security_dashboard
enable :create_vulnerability_export
enable :create_vulnerability_archive_export
enable :admin_vulnerability_issue_link
enable :admin_vulnerability_merge_request_link
enable :admin_vulnerability_external_issue_link
end
rule { can?(:read_security_resource) }.policy do
enable :read_vulnerability
end
rule { can?(:read_security_resource) & can?(:maintainer_access) }.policy do
enable :admin_vulnerability
end
rule { can?(:admin_vulnerability) }.policy do
enable :read_vulnerability
enable :create_vulnerability_feedback
enable :destroy_vulnerability_feedback
enable :update_vulnerability_feedback
enable :create_vulnerability_state_transition
end
rule { can?(:read_vulnerability) }.policy do
enable :read_vulnerability_feedback
enable :read_vulnerability_scanner
enable :read_vulnerability_representation_information
end
condition(:resolve_vulnerability_allowed) do
next false unless @user
::Gitlab::Llm::FeatureAuthorizer.new(
container: subject,
feature_name: :resolve_vulnerability,
user: @user
).allowed?
end
rule { can?(:read_security_resource) & resolve_vulnerability_allowed }.policy do
enable :resolve_vulnerability_with_ai
end
rule { security_and_compliance_disabled }.policy do
prevent :admin_vulnerability
prevent :read_vulnerability
end
rule { security_bot }.policy do
enable :push_code
enable :create_merge_request_from
enable :create_vulnerability_feedback
enable :admin_merge_request
end
rule { issues_disabled }.policy do
prevent :read_issue_analytics
end
rule { merge_requests_disabled }.policy do
prevent :read_project_merge_request_analytics
end
rule { issues_disabled & merge_requests_disabled }.policy do
prevent :read_iteration
prevent :create_iteration
prevent :update_iteration
prevent :admin_iteration
prevent :destroy_iteration
end
rule { repository_disabled }.policy do
prevent :read_code
end
rule { dependency_scanning_enabled & can?(:download_code) }.enable :read_dependency
rule { license_scanning_enabled & can?(:download_code) }.enable :read_licenses
rule { can?(:read_licenses) }.enable :read_software_license_policy
rule { repository_mirrors_enabled & ((mirror_available & can?(:admin_project)) | admin) }.enable :admin_mirror
rule { can?(:maintainer_access) }.policy do
enable :push_code_to_protected_branches
enable :admin_path_locks
enable :read_approvers
enable :update_approvers
enable :modify_approvers_rules
enable :modify_merge_request_author_setting
enable :modify_merge_request_committer_setting
enable :modify_product_analytics_settings
enable :admin_push_rules
enable :manage_deploy_tokens
enable :read_runner_usage
enable :manage_project_security_exclusions
enable :read_project_security_exclusions
enable :manage_security_settings
enable :read_vulnerability_statistics
end
rule { ~runner_performance_insights_available }.prevent :read_runner_usage
rule { ~clickhouse_main_database_available }.prevent :read_runner_usage
rule { license_scanning_enabled & can?(:maintainer_access) }.enable :admin_software_license_policy
rule { oncall_schedules_available & can?(:maintainer_access) }.enable :admin_incident_management_oncall_schedule
rule { escalation_policies_available & can?(:maintainer_access) }.enable :admin_incident_management_escalation_policy
rule { auditor }.policy do
enable :public_user_access
prevent :request_access
enable :read_build
enable :read_environment
enable :read_deployment
enable :read_pages
enable :read_project_audit_events
enable :read_cluster
enable :read_terraform_state
enable :read_project_merge_request_analytics
enable :read_approvers
enable :read_on_demand_dast_scan
enable :read_project_runners
enable :read_project_security_exclusions
enable :read_security_settings
end
rule { auditor & ~guest & private_project }.policy do
prevent :fork_project
prevent :create_merge_request_in
end
rule { auditor }.policy do
enable :access_security_and_compliance
end
rule { auditor & security_dashboard_enabled }.policy do
enable :read_security_resource
end
rule { auditor & oncall_schedules_available }.policy do
enable :read_incident_management_oncall_schedule
end
rule { auditor & escalation_policies_available }.policy do
enable :read_incident_management_escalation_policy
end
rule { auditor & ~monitor_disabled }.policy do
enable :read_alert_management_alert
end
rule { auditor & ~developer }.policy do
prevent :admin_vulnerability_issue_link
prevent :admin_vulnerability_external_issue_link
prevent :admin_vulnerability_merge_request_link
prevent :admin_vulnerability
end
rule { auditor & ~guest }.policy do
prevent :create_project
prevent :create_issue
prevent :create_note
prevent :upload_file
prevent :admin_issue_link
end
rule { ~can?(:push_code) }.prevent :push_code_to_protected_branches
rule { can?(:admin_push_rules) }.policy do
enable :change_push_rules
enable :read_commit_committer_check
enable :change_commit_committer_check
enable :read_commit_committer_name_check
enable :change_commit_committer_name_check
enable :read_reject_unsigned_commits
enable :change_reject_unsigned_commits
enable :read_reject_non_dco_commits
enable :change_reject_non_dco_commits
end
rule { ~push_rules_available }.policy do
prevent :change_push_rules
end
rule { ~commit_committer_check_available }.policy do
prevent :read_commit_committer_check
prevent :change_commit_committer_check
end
rule { ~commit_committer_name_check_available }.policy do
prevent :read_commit_committer_name_check
prevent :change_commit_committer_name_check
end
rule { ~reject_unsigned_commits_available }.policy do
prevent :read_reject_unsigned_commits
prevent :change_reject_unsigned_commits
end
rule { ~reject_non_dco_commits_available }.policy do
prevent :read_reject_non_dco_commits
prevent :change_reject_non_dco_commits
end
rule { owner | reporter | internal_access | public_project }.enable :build_read_project
rule { ~admin & owner & owner_cannot_destroy_project }.prevent :remove_project
rule { user_banned_from_namespace }.prevent_all
condition(:needs_new_sso_session) do
::Gitlab::Auth::GroupSaml::SsoEnforcer.access_restricted?(user: @user, resource: subject)
end
condition(:duo_code_review_bot) do
@user.duo_code_review_bot?
end
# NOTE: This condition does not use :subject scope because it needs to be evaluated for each request,
# as the request IP can change
condition(:ip_enforcement_prevents_access) do
!::Gitlab::IpRestriction::Enforcer.new(subject.group).allows_current_ip? if subject.group
end
rule { custom_role_enables_archive_project }.policy do
enable :archive_project
end
rule { custom_role_enables_remove_project }.policy do
enable :remove_project
end
rule { can?(:admin_project) | can?(:archive_project) | can?(:remove_project) | can?(:admin_compliance_framework) }.policy do
enable :view_edit_page
end
rule { needs_new_sso_session }.policy do
prevent :read_project
end
rule { ip_enforcement_prevents_access & ~admin & ~auditor }.policy do
prevent_all
end
rule { locked_approvers_rules }.policy do
prevent :modify_approvers_rules
end
rule { locked_merge_request_author_setting }.policy do
prevent :modify_merge_request_author_setting
end
rule { locked_merge_request_committer_setting }.policy do
prevent :modify_merge_request_committer_setting
end
rule { issue_analytics_enabled }.enable :read_issue_analytics
rule { can?(:read_merge_request) & code_review_analytics_enabled }.enable :read_code_review_analytics
rule { private_project & planner }.prevent :read_code_review_analytics
rule { (admin | reporter) & dora4_analytics_available }
.enable :read_dora4_analytics
rule { (admin | reporter) & project_merge_request_analytics_available }
.enable :read_project_merge_request_analytics
condition(:assigned_to_duo_enterprise) do
@user.assigned_to_duo_enterprise?(@subject)
end
condition(:assigned_to_duo_pro) do
@user.assigned_to_duo_pro?(@subject)
end
rule { can?(:read_product_analytics) & assigned_to_duo_pro }.enable :read_pro_ai_analytics
rule { can?(:read_product_analytics) & assigned_to_duo_enterprise }.enable :read_enterprise_ai_analytics
rule { combined_project_analytics_dashboards_enabled }.enable :read_combined_project_analytics_dashboards
rule { combined_project_analytics_dashboards_enabled & can?(:read_cycle_analytics) }.enable :read_project_level_value_stream_dashboard_overview_counts
rule { can?(:read_project) & requirements_available }.enable :read_requirement
rule { requirements_available & (planner | reporter | admin) }.policy do
enable :create_requirement
enable :create_requirement_test_report
enable :admin_requirement
enable :update_requirement
enable :import_requirements
enable :export_requirements
end
rule { requirements_available & (owner | admin) }.enable :destroy_requirement
rule { quality_management_available & planner_or_reporter_access & can?(:create_issue) }.policy do
enable :create_test_case
end
condition(:can_admin_compliance_framework_in_group) do
in_group? && can?(:admin_compliance_framework, @subject.group)
end
rule { can_admin_compliance_framework_in_group }.enable :admin_compliance_framework
rule { project_epics_available & planner_or_reporter_access & can?(:create_issue) }.policy do
enable :create_epic
end
rule { (admin | owner | auditor) & project_level_compliance_dashboard_enabled }.policy do
enable :read_compliance_dashboard
end
rule { (admin | owner | auditor) & project_level_compliance_adherence_report_enabled }.policy do
enable :read_compliance_adherence_report
end
rule { (admin | owner | auditor) & project_level_compliance_violations_report_enabled }.policy do
enable :read_compliance_violations_report
end
rule { status_page_available & can?(:owner_access) }.enable :mark_issue_for_publication
rule { status_page_available & can?(:developer_access) }.enable :publish_status_page
rule { google_cloud_support_available & can?(:maintainer_access) }.policy do
enable :read_runner_cloud_provisioning_info
enable :read_runner_gke_provisioning_info
enable :provision_cloud_runner
enable :provision_gke_runner
end
rule { google_cloud_support_available & can?(:reporter_access) }.enable :read_google_cloud_artifact_registry
rule { google_cloud_support_available & can?(:maintainer_access) }.enable :admin_google_cloud_artifact_registry
rule { hidden }.policy do
prevent :download_code
prevent :build_download_code
end
rule { read_only }.policy do
prevent(*readonly_abilities)
readonly_features.each do |feature|
prevent :"create_#{feature}"
prevent :"update_#{feature}"
prevent :"admin_#{feature}"
end
end
rule { auditor | can?(:developer_access) }.enable :add_project_to_instance_security_dashboard
rule { (admin | maintainer) & group_merge_request_approval_settings_enabled }.policy do
enable :admin_merge_request_approval_settings
end
rule { custom_role_enables_read_code }.enable :read_code
rule { custom_role_enables_read_vulnerability }.policy do
enable :access_security_and_compliance
enable :read_vulnerability
enable :read_security_resource
enable :create_vulnerability_export
enable :create_vulnerability_archive_export
end
rule { custom_role_enables_admin_merge_request }.policy do
enable :create_merge_request_from
enable :read_merge_request
enable :admin_merge_request
enable :download_code # required to negate https://gitlab.com/gitlab-org/gitlab/-/blob/3061d30d9b3d6d4c4dd5abe68bc1e4a8a93c7966/app/policies/project_policy.rb#L603-607
end
rule { custom_role_enables_admin_terraform_state }.policy do
enable :read_terraform_state
enable :admin_terraform_state
end
rule { custom_role_enables_admin_vulnerability }.policy do
enable :admin_vulnerability
end
rule { custom_role_enables_read_dependency & dependency_scanning_enabled }.policy do
enable :access_security_and_compliance
enable :read_dependency
end
rule { custom_role_enables_admin_compliance_framework }.policy do
enable :admin_compliance_framework
enable :read_compliance_dashboard
enable :read_compliance_adherence_report
enable :read_compliance_violations_report
end
rule { custom_role_enables_read_compliance_dashboard }.policy do
enable :read_compliance_dashboard
enable :read_compliance_adherence_report
enable :read_compliance_violations_report
end
rule { ~compliance_framework_available }.policy do
prevent :admin_compliance_framework
end
rule { ~project_level_compliance_dashboard_enabled }.policy do
prevent :read_compliance_dashboard
end
rule { ~project_level_compliance_adherence_report_enabled }.policy do
prevent :read_compliance_adherence_report
end
rule { ~project_level_compliance_violations_report_enabled }.policy do
prevent :read_compliance_violations_report
end
rule { custom_role_enables_manage_deploy_tokens }.policy do
enable :manage_deploy_tokens
enable :read_deploy_token
enable :create_deploy_token
enable :destroy_deploy_token
end
rule { custom_role_enables_admin_protected_branch }.policy do
enable :read_protected_branch
enable :create_protected_branch
enable :update_protected_branch
enable :destroy_protected_branch
enable :admin_protected_branch
end
rule { can?(:create_issue) & okrs_enabled }.policy do
enable :create_objective
enable :create_key_result
end
rule { suggested_reviewers_bot & suggested_reviewers_available & resource_access_token_feature_available & resource_access_token_creation_allowed }.policy do
enable :admin_project_member
enable :create_resource_access_tokens
end
rule { custom_role_enables_manage_project_access_tokens & resource_access_token_feature_available & resource_access_token_creation_allowed }.policy do
enable :read_resource_access_tokens
enable :create_resource_access_tokens
enable :destroy_resource_access_tokens
enable :manage_resource_access_tokens
end
rule { custom_role_enables_manage_merge_request_settings }.policy do
enable :manage_merge_request_settings
enable :edit_approval_rule
enable :modify_approvers_rules
enable :modify_merge_request_author_setting
enable :modify_merge_request_committer_setting
end
rule { can?(:manage_merge_request_settings) & target_branch_rules_available }.policy do
enable :admin_target_branch_rule
end
rule { can?(:manage_merge_request_settings) & group_merge_request_approval_settings_enabled }.policy do
enable :admin_merge_request_approval_settings
end
rule { security_policy_bot & project_allowed_for_job_token_by_scope }.policy do
enable :create_pipeline
enable :create_bot_pipeline
enable :build_download_code
end
desc "SPP project access to read policy config for pipeline execution policy"
condition(:spp_repository_access_allowed) do
Security::OrchestrationPolicyConfiguration.policy_management_project?(project) &&
project.project_setting.spp_repository_pipeline_access
end
rule { spp_repository_access_allowed & project_allowed_for_job_token_by_scope }.policy do
enable :download_code_spp_repository
end
rule do
summarize_new_merge_request_enabled & can?(:create_merge_request_in)
end.enable :access_summarize_new_merge_request
rule do
generate_description_enabled & can?(:create_issue)
end.enable :generate_description
rule do
summarize_notes_allowed & can?(:read_issue)
end.enable :summarize_comments
rule { target_branch_rules_available & maintainer }.policy do
enable :admin_target_branch_rule
end
rule { target_branch_rules_available }.policy do
enable :read_target_branch_rule
end
rule do
(maintainer | owner | admin) & pages_multiple_versions_available
end.enable :pages_multiple_versions
rule { can?(:reporter_access) & observability_enabled }.policy do
enable :read_observability
end
rule { can?(:developer_access) & observability_enabled }.policy do
enable :write_observability
end
rule { ci_cancellation_maintainers_only & ~can?(:maintainer_access) }.policy do
prevent :cancel_pipeline
prevent :cancel_build
end
rule { ci_cancellation_no_one }.policy do
prevent :cancel_pipeline
prevent :cancel_build
end
rule { guest | admin }.enable :read_limit_alert
rule { ai_available & generate_cube_query_enabled }.enable :generate_cube_query
rule { guest & agent_registry_enabled }.policy do
enable :read_ai_agents
end
rule { reporter & agent_registry_enabled }.policy do
enable :write_ai_agents
end
rule { can?(:read_project) & chat_allowed_for_parent_group & chat_available_for_user & duo_features_enabled }.policy do
enable :access_duo_chat
end
rule { can?(:read_project) & duo_features_enabled }.enable :access_duo_features
rule { can?(:read_project) & duo_core_features_enabled & duo_core_available_for_user }.enable :access_duo_core_features
desc "Project has saved replies support"
condition(:supports_saved_replies) do
@subject.supports_saved_replies?
end
rule { supports_saved_replies & guest }.enable :read_saved_replies
rule { supports_saved_replies & developer }.policy do
enable :create_saved_replies
enable :destroy_saved_replies
enable :update_saved_replies
end
condition(:secret_push_protection_available) do
@subject.licensed_feature_available?(:secret_push_protection)
end
rule { secret_push_protection_available & can?(:maintainer_access) }.policy do
enable :enable_secret_push_protection
end
condition(:container_scanning_for_registry_available) do
@subject.licensed_feature_available?(:container_scanning_for_registry)
end
rule { container_scanning_for_registry_available & can?(:maintainer_access) }.policy do
enable :enable_container_scanning_for_registry
end
rule { secret_push_protection_available & can?(:developer_access) }.policy do
enable :read_secret_push_protection_info
end
condition(:duo_workflow_enabled) do
::Feature.enabled?(:duo_workflow, @user)
end
with_scope :subject
condition(:duo_workflow_available) do
@subject.duo_features_enabled &&
::Gitlab::Llm::StageCheck.available?(@subject, :duo_workflow)
end
rule { duo_workflow_enabled & duo_workflow_available & can?(:developer_access) }.policy do
enable :duo_workflow
end
rule { custom_role_enables_admin_web_hook }.policy do
enable :read_web_hook
enable :admin_web_hook
end
with_scope :subject
condition(:runner_performance_insights_available) do
@subject.group&.licensed_feature_available?(:runner_performance_insights_for_namespace)
end
with_scope :global
condition(:clickhouse_main_database_available) do
::Gitlab::ClickHouse.configured?
end
rule { can?(:owner_access) }.policy do
enable :admin_project_secrets_manager
end
condition(:ai_review_mr_enabled) do
@subject.duo_features_enabled
end
condition(:user_allowed_to_use_ai_review_mr) do
@user&.allowed_to_use?(:review_merge_request, licensed_feature: :review_merge_request)
end
rule do
ai_review_mr_enabled &
user_allowed_to_use_ai_review_mr
end.enable :access_ai_review_mr
rule { duo_workflow_token & ~duo_features_enabled }.prevent_all
condition(:description_composer_enabled) do
subject.project_setting.duo_features_enabled? &&
::Feature.enabled?(:mr_description_composer, @user) &&
::Gitlab::Llm::FeatureAuthorizer.new(
container: @subject,
feature_name: :description_composer,
user: @user,
licensed_feature: :description_composer
).allowed?
end
rule do
description_composer_enabled & can?(:read_merge_request)
end.enable :access_description_composer
end
override :lookup_access_level!
def lookup_access_level!
return ::Gitlab::Access::NO_ACCESS if needs_new_sso_session?
return ::Gitlab::Access::REPORTER if security_bot?
return ::Gitlab::Access::DEVELOPER if duo_code_review_bot?
super
end
# Available in Core for self-managed but only paid for .com to prevent abuse
override :resource_access_token_create_feature_available?
def resource_access_token_create_feature_available?
return false unless resource_access_token_feature_available?
return super unless ::Gitlab.com?
namespace = project.namespace
namespace.licensed_feature_available?(:resource_access_token)
end
override :resource_access_token_feature_available?
def resource_access_token_feature_available?
return false if ::Gitlab::CurrentSettings.personal_access_tokens_disabled?
super
end
def security_scans_service
CloudConnector::AvailableServices.find_by_name(:sast)
end
def in_group?
project&.namespace&.group_namespace?
end
def custom_role_ability(user, subject)
strong_memoize_with(:custom_role_ability, user, subject) do
::Authz::CustomAbility.new(user, subject)
end
end
end
end