diff --git a/gems/gitlab-housekeeper/lib/gitlab/housekeeper/keeps/rubocop_fixer.rb b/gems/gitlab-housekeeper/lib/gitlab/housekeeper/keeps/rubocop_fixer.rb
index f0085e17ed7834e01ca3e7dc0b8da3e89dea9c62..1ce66805621cf6b535624bd2d10c76c7a9565f10 100644
--- a/gems/gitlab-housekeeper/lib/gitlab/housekeeper/keeps/rubocop_fixer.rb
+++ b/gems/gitlab-housekeeper/lib/gitlab/housekeeper/keeps/rubocop_fixer.rb
@@ -40,9 +40,7 @@ def each_change
               remove_first_exclusions(rule, rule_file_path, violating_files.count)
             end
 
-            begin
-              ::Gitlab::Housekeeper::Shell.execute('rubocop', '--autocorrect', *violating_files)
-            rescue ::Gitlab::Housekeeper::Shell::Error
+            unless Gitlab::Housekeeper::Shell.rubocop_autocorrect(violating_files)
               @logger.warn "Failed to autocorrect files. Reverting"
               # Ignore when it cannot be automatically fixed. But we need to checkout any files we might have updated.
               ::Gitlab::Housekeeper::Shell.execute('git', 'checkout', rule_file_path, *violating_files)
diff --git a/gems/gitlab-housekeeper/lib/gitlab/housekeeper/shell.rb b/gems/gitlab-housekeeper/lib/gitlab/housekeeper/shell.rb
index ed51073f0edfd080f76993f07ba5217d4eec5bb8..4a8034d849ec3cf4d54eb1e08acd4633ebfb32d4 100644
--- a/gems/gitlab-housekeeper/lib/gitlab/housekeeper/shell.rb
+++ b/gems/gitlab-housekeeper/lib/gitlab/housekeeper/shell.rb
@@ -7,8 +7,10 @@ module Housekeeper
     class Shell
       Error = Class.new(StandardError)
 
-      def self.execute(*cmd)
-        stdin, stdout, stderr, wait_thr = Open3.popen3(*cmd)
+      def self.execute(*cmd, env: {})
+        env = ENV.to_h.merge(env)
+
+        stdin, stdout, stderr, wait_thr = Open3.popen3(env, *cmd)
 
         stdin.close
         out = stdout.read
@@ -22,6 +24,20 @@ def self.execute(*cmd)
 
         out + err
       end
+
+      # Run `rubocop --autocorrect --force-exclusion`.
+      #
+      # RuboCop is run without revealed TODOs.
+      def self.rubocop_autocorrect(files)
+        # Stop revealing RuboCop TODOs so RuboCop is only fixing material offenses.
+        env = { 'REVEAL_RUBOCOP_TODO' => nil }
+        cmd = ['rubocop', '--autocorrect', '--force-exclusion']
+
+        ::Gitlab::Housekeeper::Shell.execute(*cmd, *files, env: env)
+        true
+      rescue ::Gitlab::Housekeeper::Shell::Error
+        false
+      end
     end
   end
 end
diff --git a/gems/gitlab-housekeeper/spec/gitlab/housekeeper/keeps/rubocop_fixer_spec.rb b/gems/gitlab-housekeeper/spec/gitlab/housekeeper/keeps/rubocop_fixer_spec.rb
index 80dad94dc4f7d9d3a8f2fbdde201756512e50cef..6c40290c9d81785eb996e0f264cf470f2c1080c1 100644
--- a/gems/gitlab-housekeeper/spec/gitlab/housekeeper/keeps/rubocop_fixer_spec.rb
+++ b/gems/gitlab-housekeeper/spec/gitlab/housekeeper/keeps/rubocop_fixer_spec.rb
@@ -1,5 +1,6 @@
 # frozen_string_literal: true
 
+require 'tmpdir'
 require 'spec_helper'
 
 # rubocop:disable RSpec/MultipleMemoizedHelpers
@@ -49,7 +50,10 @@
     it 'iterates over todo_dir_pattern files' do
       yielded_times = 0
 
+      # Stub out git
       allow(::Gitlab::Housekeeper::Shell).to receive(:execute)
+      # Spy on rubocop
+      allow(::Gitlab::Housekeeper::Shell).to receive(:rubocop_autocorrect).and_call_original
 
       rubocop_fixer.each_change do |change|
         yielded_times += 1
@@ -66,8 +70,8 @@
             *rule1_violating_files
           ])
 
-          expect(::Gitlab::Housekeeper::Shell).to have_received(:execute)
-            .with('rubocop', '--autocorrect', *rule1_violating_files)
+          expect(::Gitlab::Housekeeper::Shell).to have_received(:rubocop_autocorrect)
+            .with(rule1_violating_files)
         elsif change.identifiers.include?('RuboCop/FakeRule2')
           # rule2 contained 8 total exclusions and we fixed 5 of them so there should be 3 left
           expect(File).to exist(rule2_file)
@@ -79,8 +83,8 @@
             *rule2_violating_files.first(5)
           ])
 
-          expect(::Gitlab::Housekeeper::Shell).to have_received(:execute)
-            .with('rubocop', '--autocorrect', *rule2_violating_files.first(5))
+          expect(::Gitlab::Housekeeper::Shell).to have_received(:rubocop_autocorrect)
+            .with(rule2_violating_files.first(5))
         else
           raise "Unexpected change: #{change.identifiers}"
         end
@@ -91,24 +95,21 @@
 
     context 'when rubocop fails to fix the errors' do
       it 'checks out the files' do
-        expect(::Gitlab::Housekeeper::Shell).to receive(:execute)
+        expect(::Gitlab::Housekeeper::Shell).to receive(:rubocop_autocorrect)
           .once
-          .ordered
-          .with('rubocop', '--autocorrect', *rule1_violating_files)
-          .and_raise(::Gitlab::Housekeeper::Shell::Error)
+          .with(rule1_violating_files)
+          .and_return(false)
         expect(::Gitlab::Housekeeper::Shell).to receive(:execute)
           .once
           .ordered
           .with('git', 'checkout', rule1_file, *rule1_violating_files)
 
-        expect(::Gitlab::Housekeeper::Shell).to receive(:execute)
+        expect(::Gitlab::Housekeeper::Shell).to receive(:rubocop_autocorrect)
           .once
-          .ordered
-          .with('rubocop', '--autocorrect', *rule2_violating_files.first(5))
-          .and_raise(::Gitlab::Housekeeper::Shell::Error)
+          .with(rule2_violating_files.first(5))
+          .and_return(false)
         expect(::Gitlab::Housekeeper::Shell).to receive(:execute)
           .once
-          .ordered
           .with('git', 'checkout', rule2_file, *rule2_violating_files.first(5))
 
         rubocop_fixer.each_change
diff --git a/gems/gitlab-housekeeper/spec/gitlab/housekeeper/shell_spec.rb b/gems/gitlab-housekeeper/spec/gitlab/housekeeper/shell_spec.rb
index 2c7b3fb01c898c70b070cb4d440e123a55f8160b..de301f9274319ad579cdbc775384af807c1f218c 100644
--- a/gems/gitlab-housekeeper/spec/gitlab/housekeeper/shell_spec.rb
+++ b/gems/gitlab-housekeeper/spec/gitlab/housekeeper/shell_spec.rb
@@ -6,7 +6,7 @@
 RSpec.describe ::Gitlab::Housekeeper::Shell do
   describe '.execute' do
     it 'delegates to popen3 and returns stdout' do
-      expect(Open3).to receive(:popen3).with('echo', 'hello world')
+      expect(Open3).to receive(:popen3).with(ENV.to_h, 'echo', 'hello world')
         .and_call_original
 
       expect(described_class.execute('echo', 'hello world')).to eq("hello world\n")
@@ -21,4 +21,27 @@
       )
     end
   end
+
+  describe '.rubocop_autocorrect' do
+    it 'delegates to #execute and returns true on success' do
+      expect(described_class)
+        .to receive(:execute)
+        .with(
+          'rubocop', '--autocorrect', '--force-exclusion', 'foo.rb',
+          env: a_hash_including('REVEAL_RUBOCOP_TODO' => nil)
+        )
+        .and_return('output')
+
+      expect(described_class.rubocop_autocorrect('foo.rb')).to eq(true)
+    end
+
+    it 'delegates to #execute and returns false on failure' do
+      allow(described_class)
+        .to receive(:execute)
+        .with(any_args)
+        .and_raise(described_class::Error.new)
+
+      expect(described_class.rubocop_autocorrect('foo.rb')).to eq(false)
+    end
+  end
 end
diff --git a/keeps/overdue_finalize_background_migration.rb b/keeps/overdue_finalize_background_migration.rb
index a7ebbc041a999372fdaff668a614dd83fad5f814..19d4735e4891805928f0f73b72c5b026693fcab5 100644
--- a/keeps/overdue_finalize_background_migration.rb
+++ b/keeps/overdue_finalize_background_migration.rb
@@ -80,7 +80,7 @@ def each_change
         change.changed_files = [migration_file]
 
         add_ensure_call_to_migration(migration_file, queue_method_node, job_name, migration_record)
-        ::Gitlab::Housekeeper::Shell.execute('rubocop', '-a', migration_file)
+        ::Gitlab::Housekeeper::Shell.rubocop_autocorrect(migration_file)
 
         digest = Digest::SHA256.hexdigest(generator.migration_number)
         digest_file = Pathname.new('db').join('schema_migrations', generator.migration_number.to_s).to_s