From: Florian Schmidt Date: Mon, 17 Apr 2017 20:36:30 +0000 (+0200) Subject: registration: Only allow one extension to set a specific config setting X-Git-Tag: 1.31.0-rc.0~1686^2~2 X-Git-Url: https://git.heureux-cyclage.org/?a=commitdiff_plain;ds=sidebyside;h=50d7546057c1089228a2a6d7d4a49d78d72887e3;hp=d6276525455e6a00fffc90229ef81a1fc8feaa25;p=lhc%2Fweb%2Fwiklou.git registration: Only allow one extension to set a specific config setting ExtensionProcessor would previously just blindly overwrite duplicate config settings, which ends up depending upon load order. It's relatively hard to debug since it is silently overwritten. This now throws exceptions in case of duplicate config settings. This will also have some side-effects of catching people putting things like "ResourceModules" in their "config" section when it should be a top-level item. Bug: T152929 Change-Id: Iaef32efab397e82ff70ddca8ac79c545c5b7d2bb --- diff --git a/includes/registration/ExtensionProcessor.php b/includes/registration/ExtensionProcessor.php index ce262bd23e..14d822295c 100644 --- a/includes/registration/ExtensionProcessor.php +++ b/includes/registration/ExtensionProcessor.php @@ -450,7 +450,7 @@ class ExtensionProcessor implements Processor { } foreach ( $info['config'] as $key => $val ) { if ( $key[0] !== '@' ) { - $this->globals["$prefix$key"] = $val; + $this->addConfigGlobal( "$prefix$key", $val ); } } } @@ -478,11 +478,26 @@ class ExtensionProcessor implements Processor { if ( isset( $data['path'] ) && $data['path'] ) { $value = "$dir/$value"; } - $this->globals["$prefix$key"] = $value; + $this->addConfigGlobal( "$prefix$key", $value ); } } } + /** + * Helper function to set a value to a specific global, if it isn't set already. + * + * @param string $key The config key with the prefix and anything + * @param mixed $value The value of the config + */ + private function addConfigGlobal( $key, $value ) { + if ( array_key_exists( $key, $this->globals ) ) { + throw new RuntimeException( + "The configuration setting '$key' was already set by another extension," + . " and cannot be set again." ); + } + $this->globals[$key] = $value; + } + protected function extractServiceWiringFiles( $dir, array $info ) { if ( isset( $info['ServiceWiringFiles'] ) ) { foreach ( $info['ServiceWiringFiles'] as $path ) { diff --git a/tests/phpunit/includes/registration/ExtensionProcessorTest.php b/tests/phpunit/includes/registration/ExtensionProcessorTest.php index 7b56def1c3..5ef30e872a 100644 --- a/tests/phpunit/includes/registration/ExtensionProcessorTest.php +++ b/tests/phpunit/includes/registration/ExtensionProcessorTest.php @@ -220,6 +220,48 @@ class ExtensionProcessorTest extends MediaWikiTestCase { $this->assertEquals( 'somevalue', $extracted['globals']['egBar'] ); } + /** + * @covers ExtensionProcessor::addConfigGlobal() + * @expectedException RuntimeException + */ + public function testDuplicateConfigKey1() { + $processor = new ExtensionProcessor; + $info = [ + 'config' => [ + 'Bar' => '', + ] + ] + self::$default; + $info2 = [ + 'config' => [ + 'Bar' => 'g', + ], + 'name' => 'FooBar2', + ]; + $processor->extractInfo( $this->dir, $info, 1 ); + $processor->extractInfo( $this->dir, $info2, 1 ); + } + + /** + * @covers ExtensionProcessor::addConfigGlobal() + * @expectedException RuntimeException + */ + public function testDuplicateConfigKey2() { + $processor = new ExtensionProcessor; + $info = [ + 'config' => [ + 'Bar' => [ 'value' => 'somevalue' ], + ] + ] + self::$default; + $info2 = [ + 'config' => [ + 'Bar' => [ 'value' => 'somevalue' ], + ], + 'name' => 'FooBar2', + ]; + $processor->extractInfo( $this->dir, $info, 2 ); + $processor->extractInfo( $this->dir, $info2, 2 ); + } + public static function provideExtractExtensionMessagesFiles() { $dir = __DIR__ . '/FooBar/'; return [