Commit 8135836449 for woocommerce

commit 8135836449bec5169e1b3272b1365a61bfa591d2
Author: Chi-Hsuan Huang <chihsuan.tw@gmail.com>
Date:   Fri Apr 25 17:45:17 2025 +0800

    [Blueprint] Add restrictions for options in Blueprint importer (#57381)

    * Implement restricted options handling in ImportSetSiteOptions

    - Added a list of restricted WordPress options that cannot be modified for security reasons.
    - Updated the process method to skip updates for these restricted options and log warnings accordingly.
    - Enhanced unit tests to verify that restricted options are not modified and appropriate warnings are generated.

    * Add changelog

    * Change message

diff --git a/packages/php/blueprint/changelog/wooplug-3964-blueprint-protect-critical-options b/packages/php/blueprint/changelog/wooplug-3964-blueprint-protect-critical-options
new file mode 100644
index 0000000000..8554256dbd
--- /dev/null
+++ b/packages/php/blueprint/changelog/wooplug-3964-blueprint-protect-critical-options
@@ -0,0 +1,4 @@
+Significance: patch
+Type: enhancement
+
+Implement restricted options handling in ImportSetSiteOptions
diff --git a/packages/php/blueprint/src/Importers/ImportSetSiteOptions.php b/packages/php/blueprint/src/Importers/ImportSetSiteOptions.php
index 53cd70e791..7cda12f099 100644
--- a/packages/php/blueprint/src/Importers/ImportSetSiteOptions.php
+++ b/packages/php/blueprint/src/Importers/ImportSetSiteOptions.php
@@ -17,6 +17,28 @@ use Automattic\WooCommerce\Blueprint\UseWPFunctions;
 class ImportSetSiteOptions implements StepProcessor {
 	use UseWPFunctions;

+	/**
+	 * List of WordPress options that should not be modified.
+	 *
+	 * @var array<string>
+	 */
+	private const RESTRICTED_OPTIONS = array(
+		'siteurl',
+		'home',
+		'active_plugins',
+		'template',
+		'stylesheet',
+		'admin_email',
+		'unfiltered_html',
+		'users_can_register',
+		'default_role',
+		'db_version',
+		'cron',
+		'rewrite_rules',
+		'wp_user_roles',
+	);
+
+
 	/**
 	 * Process the step.
 	 *
@@ -27,16 +49,23 @@ class ImportSetSiteOptions implements StepProcessor {
 	public function process( $schema ): StepProcessorResult {
 		$result = StepProcessorResult::success( SetSiteOptions::get_step_name() );
 		foreach ( $schema->options as $key => $value ) {
+			// Skip if the option should not be modified.
+			if ( in_array( $key, self::RESTRICTED_OPTIONS, true ) ) {
+				$result->add_warn( "Cannot modify '{$key}' option: Modifying is restricted for this key." );
+				continue;
+			}
+
 			$value   = json_decode( wp_json_encode( $value ), true );
 			$updated = $this->wp_update_option( $key, $value );

 			if ( $updated ) {
-				$result->add_info( "{$key} has been updated" );
-			} else {
-				$current_value = $this->wp_get_option( $key );
-				if ( $current_value === $value ) {
-					$result->add_info( "{$key} has not been updated because the current value is already up to date." );
-				}
+				$result->add_info( "{$key} has been updated." );
+				continue;
+			}
+
+			$current_value = $this->wp_get_option( $key );
+			if ( $current_value === $value ) {
+				$result->add_info( "{$key} has not been updated because the current value is already up to date." );
 			}
 		}

diff --git a/packages/php/blueprint/tests/Unit/Importers/ImportSetSiteOptionsTest.php b/packages/php/blueprint/tests/Unit/Importers/ImportSetSiteOptionsTest.php
index 8f6facda1b..3d2a1cdd87 100644
--- a/packages/php/blueprint/tests/Unit/Importers/ImportSetSiteOptionsTest.php
+++ b/packages/php/blueprint/tests/Unit/Importers/ImportSetSiteOptionsTest.php
@@ -32,8 +32,8 @@ class ImportSetSiteOptionsTest extends TestCase {
 	public function test_process_updates_options_successfully() {
 		$schema          = Mockery::mock();
 		$schema->options = array(
-			'site_name'   => 'My New Site',
-			'admin_email' => 'admin@example.com',
+			'site_name'                   => 'My New Site',
+			'woocommerce_default_country' => 'JP',
 		);

 		$import_set_site_options = Mockery::mock( ImportSetSiteOptions::class )
@@ -45,7 +45,7 @@ class ImportSetSiteOptionsTest extends TestCase {
 			->with( 'site_name', 'My New Site' )
 			->andReturn( true );
 		$import_set_site_options->shouldReceive( 'wp_update_option' )
-			->with( 'admin_email', 'admin@example.com' )
+			->with( 'woocommerce_default_country', 'JP' )
 			->andReturn( true );

 		$result = $import_set_site_options->process( $schema );
@@ -55,8 +55,8 @@ class ImportSetSiteOptionsTest extends TestCase {

 		$messages = $result->get_messages( 'info' );
 		$this->assertCount( 2, $messages );
-		$this->assertEquals( 'site_name has been updated', $messages[0]['message'] );
-		$this->assertEquals( 'admin_email has been updated', $messages[1]['message'] );
+		$this->assertEquals( 'site_name has been updated.', $messages[0]['message'] );
+		$this->assertEquals( 'woocommerce_default_country has been updated.', $messages[1]['message'] );
 	}

 	/**
@@ -94,6 +94,34 @@ class ImportSetSiteOptionsTest extends TestCase {
 		$this->assertEquals( 'site_name has not been updated because the current value is already up to date.', $messages[0]['message'] );
 	}

+	/**
+	 * Test when restricted options are attempted to be updated.
+	 *
+	 * @return void
+	 */
+	public function test_process_restricted_options() {
+		$schema                  = Mockery::mock();
+		$schema->options         = array(
+			'admin_email'    => 'danger@example.com',
+			'active_plugins' => array( 'fake-plugin/fake-plugin.php' ),
+		);
+		$import_set_site_options = Mockery::mock( ImportSetSiteOptions::class )
+			->makePartial()
+			->shouldAllowMockingProtectedMethods();
+
+		$result = $import_set_site_options->process( $schema );
+
+		$this->assertInstanceOf( StepProcessorResult::class, $result );
+		$this->assertTrue( $result->is_success() );
+
+		$messages = $result->get_messages( 'warn' );
+		$this->assertCount( 2, $messages );
+		$this->assertEquals( "Cannot modify 'admin_email' option: Modifying is restricted for this key.", $messages[0]['message'] );
+		$this->assertEquals( "Cannot modify 'active_plugins' option: Modifying is restricted for this key.", $messages[1]['message'] );
+		$this->assertNotEquals( get_option( 'admin_email' ), 'danger@example.com' );
+		$this->assertNotEquals( get_option( 'active_plugins' ), array( 'fake-plugin/fake-plugin.php' ) );
+	}
+
 	/**
 	 * Test getting the step class.
 	 *