Remove obsolete push_rules organizations loose foreign key
What does this MR do and why?
Removes the loose foreign key (LFK) definition push_rules -> organizations (column: organization_id, on_delete: async_delete) from config/gitlab_loose_foreign_keys.yml, and adds push_rules: %w[organization_id] to the ignored_fk_columns_map in spec/db/schema_spec.rb.
The spec addition is required because spec/db/schema_spec.rb requires every *_id column to be covered by a real FK, a loose FK, or an ignore-map entry. push_rules.organization_id has no real Postgres FK, and this LFK entry was its only coverage.
No database migrations are needed; this is a config + spec change only.
Why this is safe
The LFK is dead config:
- Organization-level push rules were migrated to the dedicated
organization_push_rulestable, which has a real Postgres foreign key onorganization_idwithON DELETE CASCADE, so organization deletions are handled at the database level. - New organization-level rows in
push_rulesare impossible:PushRulehas an application-levelvalidates :project_id, presence: true(added in !246324 (merged)), and on GitLab.com theNOT NULLconstraint onpush_rules.project_idis validated. - No runtime code reads
push_rules.organization_id(theread_organization_push_rulesfeature flag paths were removed in !219558 (merged)). - The
organizationsdeletion-tracking trigger is not removed: many other LFK definitions still referenceorganizationsas parent, so per the loose foreign keys development docs the trigger must stay.
Self-managed instances
Removing this LFK is safe on self-managed even though the NOT NULL constraint on push_rules.project_id is not yet validated and DeleteNullProjectIdPushRules is not finalized:
- No new organization-level rows can be created anywhere: migration
20260715040848(19.3, unguarded) addedcheck_1d23f0a102 CHECK (project_id IS NOT NULL) NOT VALID, and PostgreSQL enforcesNOT VALIDconstraints on all newINSERTs/UPDATEs — only existing rows are unchecked.PushRulealso hasvalidates :project_id, presence: true. - Legacy rows with
NULLproject_idmay still exist until the requeuedDeleteNullProjectIdPushRulesBBM is finalized (#607954, 19.6). If an organization is deleted before then, its legacy rows become orphans instead of being async-deleted — benign, since no code path readspush_rulesbyorganization_id. - The BBM's scope is
relation.where(project_id: nil), so it deletes those orphans whether or not the organization still exists. - Sequencing: finalization (#607954) runs before the self-managed constraint validation (#607955), so orphaned rows can never cause the
NOT NULLvalidation to fail.
Verification
bundle exec rspec spec/lib/gitlab/database/loose_foreign_keys_spec.rb— passed (17 examples, 0 failures, 1 pending)bundle exec rspec spec/db/schema_spec.rb— passed except one pre-existing quarantined failure unrelated to this change (the "jsonb columns uses json schema validator" example, quarantined via https://gitlab.com/gitlab-org/quality/test-failure-issues/-/issues/9460, failing about jsonb schema validators on ~97 models)
Out of scope
Dropping the push_rules.organization_id and is_sample columns themselves is tracked in #623433, blocked by #607954 and #607955.
Closes #606845 (closed)