Hard deletion of users doesn't work when they have authored issues
Summary
If someone makes an abuse report against a user who has issues, the administrator can click "Remove user and report", which should remove the user and all their contributions from the database (i.e., their data shouldn't be ghosted)
Steps to reproduce
- Allow a user to create an issue
- Report that user in the admin panel
- As the admin, review the abuse report and choose "remove user & report"
What is the current bug behavior?
A sidekiq job is enqueued to perform the deletion asynchronously. That job fails, like so:
17:00:00 gitlab-workhorse.1 | localhost:3000 127.0.0.1:59376 - - [2017-06-01 17:00:00.726481875 +0100 BST] "DELETE /admin/abuse_reports/24?remove_user=true HTTP/1.1" 200 0 "http://localhost:3000/admin/abuse_reports" "Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0" 0.085230
17:00:02 rails-background-jobs.1 | 2017-06-01T16:00:02.404Z 9339 TID-gro5tyykg DeleteUserWorker JID-6a1aa37ad262487f294d1404 INFO: fail: 1.596 sec
17:00:02 rails-background-jobs.1 | 2017-06-01T16:00:02.404Z 9339 TID-gro5tyykg WARN: {"context":"Job raised exception","job":{"class":"DeleteUserWorker","args":[1,6,{"delete_solo_owned_groups":true,"hard_delete":true}],"retry":3,"queue":"delete_user","jid":"6a1aa37ad262487f294d1404","created_at":1496332800.8056617,"enqueued_at":1496332800.8070748,"error_message":"Cannot delete record because of dependent issues","error_class":"ActiveRecord::DeleteRestrictionError","failed_at":1496332802.403342,"retry_count":0},"jobstr":"{\"class\":\"DeleteUserWorker\",\"args\":[1,6,{\"delete_solo_owned_groups\":true,\"hard_delete\":true}],\"retry\":3,\"queue\":\"delete_user\",\"jid\":\"6a1aa37ad262487f294d1404\",\"created_at\":1496332800.8056617,\"enqueued_at\":1496332800.8070748}"}
17:00:02 rails-background-jobs.1 | 2017-06-01T16:00:02.404Z 9339 TID-gro5tyykg WARN: ActiveRecord::DeleteRestrictionError: Cannot delete record because of dependent issues
17:00:02 rails-background-jobs.1 | 2017-06-01T16:00:02.404Z 9339 TID-gro5tyykg WARN: /home/lupine/.gem/ruby/2.3.4/gems/activerecord-4.2.8/lib/active_record/associations/has_many_association.rb:14:in `handle_dependency'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activerecord-4.2.8/lib/active_record/associations/builder/association.rb:146:in `block in add_destroy_callbacks'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activesupport-4.2.8/lib/active_support/callbacks.rb:448:in `instance_exec'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activesupport-4.2.8/lib/active_support/callbacks.rb:448:in `block in make_lambda'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activesupport-4.2.8/lib/active_support/callbacks.rb:164:in `block in halting'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activesupport-4.2.8/lib/active_support/callbacks.rb:504:in `block in call'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activesupport-4.2.8/lib/active_support/callbacks.rb:504:in `each'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activesupport-4.2.8/lib/active_support/callbacks.rb:504:in `call'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activesupport-4.2.8/lib/active_support/callbacks.rb:92:in `__run_callbacks__'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activesupport-4.2.8/lib/active_support/callbacks.rb:778:in `_run_destroy_callbacks'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activerecord-4.2.8/lib/active_record/callbacks.rb:292:in `destroy'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activerecord-4.2.8/lib/active_record/transactions.rb:281:in `block in destroy'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activerecord-4.2.8/lib/active_record/transactions.rb:351:in `block in with_transaction_returning_status'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activerecord-4.2.8/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activerecord-4.2.8/lib/active_record/connection_adapters/abstract/transaction.rb:184:in `within_new_transaction'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activerecord-4.2.8/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activerecord-4.2.8/lib/active_record/transactions.rb:220:in `transaction'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activerecord-4.2.8/lib/active_record/transactions.rb:348:in `with_transaction_returning_status'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/activerecord-4.2.8/lib/active_record/transactions.rb:281:in `destroy'
17:00:02 rails-background-jobs.1 | /home/lupine/dev/gitlab.com/gitlab-org/gitlab-development-kit/gitlab/app/services/users/destroy_service.rb:33:in `execute'
17:00:02 rails-background-jobs.1 | /home/lupine/dev/gitlab.com/gitlab-org/gitlab-development-kit/gitlab/app/workers/delete_user_worker.rb:9:in `perform'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:204:in `execute_job'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:175:in `block (2 levels) in process'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/middleware/chain.rb:128:in `block in invoke'
17:00:02 rails-background-jobs.1 | /home/lupine/dev/gitlab.com/gitlab-org/gitlab-development-kit/gitlab/lib/gitlab/sidekiq_status/server_middleware.rb:5:in `call'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/middleware/chain.rb:130:in `block in invoke'
17:00:02 rails-background-jobs.1 | /home/lupine/dev/gitlab.com/gitlab-org/gitlab-development-kit/gitlab/lib/gitlab/sidekiq_middleware/request_store_middleware.rb:6:in `call'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/middleware/chain.rb:130:in `block in invoke'
17:00:02 rails-background-jobs.1 | /home/lupine/dev/gitlab.com/gitlab-org/gitlab-development-kit/gitlab/lib/gitlab/sidekiq_middleware/arguments_logger.rb:6:in `call'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/middleware/chain.rb:130:in `block in invoke'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/middleware/server/active_record.rb:15:in `call'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/middleware/chain.rb:130:in `block in invoke'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sentry-raven-2.4.0/lib/raven/integrations/sidekiq.rb:7:in `call'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/middleware/chain.rb:130:in `block in invoke'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/middleware/chain.rb:133:in `invoke'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:174:in `block in process'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:146:in `block (6 levels) in dispatch'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/job_retry.rb:97:in `local'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:145:in `block (5 levels) in dispatch'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq.rb:36:in `block in <module:Sidekiq>'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:141:in `block (4 levels) in dispatch'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:220:in `stats'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:136:in `block (3 levels) in dispatch'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/job_logger.rb:8:in `call'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:135:in `block (2 levels) in dispatch'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/job_retry.rb:72:in `global'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:134:in `block in dispatch'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/logging.rb:32:in `with_context'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:133:in `dispatch'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:173:in `process'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:85:in `process_one'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/processor.rb:73:in `run'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/util.rb:17:in `watchdog'
17:00:02 rails-background-jobs.1 | /home/lupine/.gem/ruby/2.3.4/gems/sidekiq-5.0.0/lib/sidekiq/util.rb:26:in `block in safe_thread'
What is the expected correct behavior?
User should be hard-deleted
Possible fixes
Presumably there's a missing foreign key or dependent: destroy
somewhere....
I'm focusing on issues here, but it's possible other contributions block user removal too.
Hard deletion for abuse reports was initially added in https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10723 - @stanhu did you observe this working at the time? The specs that were added stub out the service, so it's possible it silently broke due to later model / schema changes.