From 224d1184c135e69d7fbe84933f3a5599ebae0648 Mon Sep 17 00:00:00 2001 From: Ghassen kefi Date: Wed, 28 Oct 2026 09:59:20 +0100 Subject: [PATCH 1/2] fix(core): drop unused bruteforce_attempts_ip index Brute force attempts are only looked up and reset by subnet, and the cleanup job filters on the occurred column. No query filters on ip, so the index only adds write overhead on every registered attempt. Fixes #49841 Assisted-by: ClaudeCode:claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 Signed-off-by: Ghassen kefi --- .../Version36000Date20261028100000.php | 42 +++++++++++++ lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + .../Version36000Date20261028100000Test.php | 63 +++++++++++++++++++ version.php | 2 +- 5 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 core/Migrations/Version36000Date20261028100000.php create mode 100644 tests/Core/Migrations/Version36000Date20261028100000Test.php diff --git a/core/Migrations/Version36000Date20261028100000.php b/core/Migrations/Version36000Date20261028100000.php new file mode 100644 index 0000000000000..69661089afea5 --- /dev/null +++ b/core/Migrations/Version36000Date20261028100000.php @@ -0,0 +1,42 @@ +getTable('bruteforce_attempts'); + + // Index added in Version13000Date20170718121200 + if ($table->hasIndex('bruteforce_attempts_ip')) { + $table->dropIndex('bruteforce_attempts_ip'); + return $schema; + } + + return null; + } +} diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index b3b5b63fb3a1e..c1883c382d08c 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -1759,6 +1759,7 @@ 'OC\\Core\\Migrations\\Version34000Date20260518163022' => $baseDir . '/core/Migrations/Version34000Date20260518163022.php', 'OC\\Core\\Migrations\\Version34000Date20260521110333' => $baseDir . '/core/Migrations/Version34000Date20260521110333.php', 'OC\\Core\\Migrations\\Version35000Date20260527162338' => $baseDir . '/core/Migrations/Version35000Date20260527162338.php', + 'OC\\Core\\Migrations\\Version36000Date20261028100000' => $baseDir . '/core/Migrations/Version36000Date20261028100000.php', 'OC\\Core\\Notification\\CoreNotifier' => $baseDir . '/core/Notification/CoreNotifier.php', 'OC\\Core\\ResponseDefinitions' => $baseDir . '/core/ResponseDefinitions.php', 'OC\\Core\\Service\\CronService' => $baseDir . '/core/Service/CronService.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 35c872fd7527d..d260c6783df78 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -1800,6 +1800,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Migrations\\Version34000Date20260518163022' => __DIR__ . '/../../..' . '/core/Migrations/Version34000Date20260518163022.php', 'OC\\Core\\Migrations\\Version34000Date20260521110333' => __DIR__ . '/../../..' . '/core/Migrations/Version34000Date20260521110333.php', 'OC\\Core\\Migrations\\Version35000Date20260527162338' => __DIR__ . '/../../..' . '/core/Migrations/Version35000Date20260527162338.php', + 'OC\\Core\\Migrations\\Version36000Date20261028100000' => __DIR__ . '/../../..' . '/core/Migrations/Version36000Date20261028100000.php', 'OC\\Core\\Notification\\CoreNotifier' => __DIR__ . '/../../..' . '/core/Notification/CoreNotifier.php', 'OC\\Core\\ResponseDefinitions' => __DIR__ . '/../../..' . '/core/ResponseDefinitions.php', 'OC\\Core\\Service\\CronService' => __DIR__ . '/../../..' . '/core/Service/CronService.php', diff --git a/tests/Core/Migrations/Version36000Date20261028100000Test.php b/tests/Core/Migrations/Version36000Date20261028100000Test.php new file mode 100644 index 0000000000000..5a467f1910092 --- /dev/null +++ b/tests/Core/Migrations/Version36000Date20261028100000Test.php @@ -0,0 +1,63 @@ +table = $this->createMock(ITable::class); + $this->schema = $this->createMock(ISchemaWrapper::class); + $this->schema->method('getTable') + ->with('bruteforce_attempts') + ->willReturn($this->table); + $this->migration = new Version36000Date20261028100000(); + } + + private function runMigration(): ?ISchemaWrapper { + return $this->migration->changeSchema( + $this->createMock(IOutput::class), + fn () => $this->schema, + [], + ); + } + + public function testDropsIpIndex(): void { + $this->table->method('hasIndex') + ->with('bruteforce_attempts_ip') + ->willReturn(true); + $this->table->expects($this->once()) + ->method('dropIndex') + ->with('bruteforce_attempts_ip'); + + $this->assertSame($this->schema, $this->runMigration()); + } + + public function testNoChangeWhenIndexIsAlreadyGone(): void { + $this->table->method('hasIndex') + ->with('bruteforce_attempts_ip') + ->willReturn(false); + $this->table->expects($this->never()) + ->method('dropIndex'); + + $this->assertNull($this->runMigration()); + } +} diff --git a/version.php b/version.php index 31e5cb2bcda4c..ca54c28709bc6 100644 --- a/version.php +++ b/version.php @@ -11,7 +11,7 @@ // between betas, final and RCs. This is _not_ the public version number. Reset minor/patch level // when updating major/minor version number. -$OC_Version = [36, 0, 0, 0]; +$OC_Version = [36, 0, 0, 1]; // The human-readable string $OC_VersionString = '36.0.0 dev'; From 62e82632e8041170f3b21ab31793607be5ead80a Mon Sep 17 00:00:00 2001 From: Ghassen kefi Date: Thu, 29 Oct 2026 21:07:47 +0100 Subject: [PATCH 2/2] fix(core): stop creating bruteforce_attempts_ip index on new installs Fresh installs no longer create the index, and the migration test is dropped as it only covered a trivial schema change. Assisted-by: ClaudeCode:claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 Signed-off-by: Ghassen kefi --- .../Version13000Date20170718121200.php | 1 - .../Version36000Date20261028100000.php | 2 +- .../Version36000Date20261028100000Test.php | 63 ------------------- 3 files changed, 1 insertion(+), 65 deletions(-) delete mode 100644 tests/Core/Migrations/Version36000Date20261028100000Test.php diff --git a/core/Migrations/Version13000Date20170718121200.php b/core/Migrations/Version13000Date20170718121200.php index 79f4534518461..70665dad92444 100644 --- a/core/Migrations/Version13000Date20170718121200.php +++ b/core/Migrations/Version13000Date20170718121200.php @@ -630,7 +630,6 @@ public function changeSchema(IOutput $output, \Closure $schemaClosure, array $op 'default' => '', ]); $table->setPrimaryKey(['id']); - $table->addIndex(['ip'], 'bruteforce_attempts_ip'); $table->addIndex(['subnet'], 'bruteforce_attempts_subnet'); } diff --git a/core/Migrations/Version36000Date20261028100000.php b/core/Migrations/Version36000Date20261028100000.php index 69661089afea5..a36e01fd9cd72 100644 --- a/core/Migrations/Version36000Date20261028100000.php +++ b/core/Migrations/Version36000Date20261028100000.php @@ -31,7 +31,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $table = $schema->getTable('bruteforce_attempts'); - // Index added in Version13000Date20170718121200 + // Index was created by Version13000Date20170718121200 on older instances if ($table->hasIndex('bruteforce_attempts_ip')) { $table->dropIndex('bruteforce_attempts_ip'); return $schema; diff --git a/tests/Core/Migrations/Version36000Date20261028100000Test.php b/tests/Core/Migrations/Version36000Date20261028100000Test.php deleted file mode 100644 index 5a467f1910092..0000000000000 --- a/tests/Core/Migrations/Version36000Date20261028100000Test.php +++ /dev/null @@ -1,63 +0,0 @@ -table = $this->createMock(ITable::class); - $this->schema = $this->createMock(ISchemaWrapper::class); - $this->schema->method('getTable') - ->with('bruteforce_attempts') - ->willReturn($this->table); - $this->migration = new Version36000Date20261028100000(); - } - - private function runMigration(): ?ISchemaWrapper { - return $this->migration->changeSchema( - $this->createMock(IOutput::class), - fn () => $this->schema, - [], - ); - } - - public function testDropsIpIndex(): void { - $this->table->method('hasIndex') - ->with('bruteforce_attempts_ip') - ->willReturn(true); - $this->table->expects($this->once()) - ->method('dropIndex') - ->with('bruteforce_attempts_ip'); - - $this->assertSame($this->schema, $this->runMigration()); - } - - public function testNoChangeWhenIndexIsAlreadyGone(): void { - $this->table->method('hasIndex') - ->with('bruteforce_attempts_ip') - ->willReturn(false); - $this->table->expects($this->never()) - ->method('dropIndex'); - - $this->assertNull($this->runMigration()); - } -}