[go: up one dir, main page]

Skip to content

Unassign policies for expired Ultimate licenses

What does this MR do and why?

Introduces a cron worker to automatically unassign security policy configurations when an Ultimate license or plan expires. This worker identifies namespaces with expired Ultimate subscriptions (SaaS) or expired Ultimate licenses (self-managed) and schedules a dedicated worker to remove their associated policy configurations. This ensures that security policies are only active with a valid Ultimate plan.

References

This is part 2 of fixing #431229

Part 1 MR : !208917 (merged)

Database Query Plans

SELECT 
    gsh.*
FROM 
    gitlab_subscription_histories gsh
INNER JOIN 
    plans hosted_plan 
    ON hosted_plan.id = gsh.hosted_plan_id
WHERE 
    gsh.end_date = '2025-10-20'
    AND hosted_plan.name IN ('ultimate', 'ultimate_trial', 'ultimate_trial_paid_customer');

explain: https://console.postgres.ai/gitlab/gitlab-production-main/sessions/44794/commands/137546

Screenshots or screen recordings

Before After

How to set up and validate locally

  1. Simulate SAAS instance https://docs.gitlab.com/development/ee_features/#simulate-a-saas-instance
  2. Create a new test group and one project in it
  3. Enable Allow use of licensed EE features and assign Ultimate plan to the test group following the steps mentioned here
  4. Create security policies with any security policy for the project and group
  5. Update the group plan to "Premium"
  6. Find the subscription_history and update the end_date then execute the cron worker
namespace = Namespace.find_by(path: 'your-namespace-path')
subscription_histories = namespace.gitlab_subscription_histories.with_a_ultimate_hosted_plan.first.update!(end_date: 3.days.ago.to_date)
Security::UnassignPolicyConfigurationsForExpiredLicensesCronWorker.new.perform
  1. Verify the security policies are unlinked
    • Through UI: Update the group license to "Ultimate" and see the policies are no longer exists
    • From rails console:
# should return zero
namespace = Namespace.find_by(path: 'your-namespace-path')
namespace_ids = namespace.self_and_descendants.pluck_primary_key
project_ids = namespace.all_project_ids
Security::OrchestrationPolicyConfiguration.for_namespace_and_projects(namespace_ids, project_ids).count

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.

Related to #431229

Edited by Imam Hossain

Merge request reports

Loading