Changeset 63348
- Timestamp:
- 08/26/2026 11:48:53 AM (6 hours ago)
- Location:
- trunk
- Files:
-
- 2 edited
-
src/wp-includes/connectors.php (modified) (1 diff)
-
tests/phpunit/tests/connectors/wpConnectorsRestSettingsDispatch.php (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/connectors.php
r62684 r63348 732 732 $value = $data[ $setting_name ]; 733 733 734 // On update, validate AI provider keys before masking.734 // On update, validate AI provider keys submitted in the request before masking. 735 735 // Non-AI connectors accept keys as-is; the service plugin handles its own validation. 736 if ( $is_update && is_string( $value ) && '' !== $value && 'ai_provider' === $connector_data['type'] ) { 736 if ( $is_update 737 && $request->has_param( $setting_name ) 738 && is_string( $value ) && '' !== $value 739 && 'ai_provider' === $connector_data['type'] 740 ) { 737 741 if ( true !== _wp_connectors_is_ai_api_key_valid( $value, $connector_id ) ) { 738 742 update_option( $setting_name, '' ); -
trunk/tests/phpunit/tests/connectors/wpConnectorsRestSettingsDispatch.php
r62684 r63348 1 1 <?php 2 3 require_once dirname( __DIR__, 2 ) . '/includes/wp-ai-client-mock-provider-trait.php'; 4 2 5 /** 3 6 * Tests for _wp_connectors_rest_settings_dispatch(). … … 8 11 class Tests_Connectors_WpConnectorsRestSettingsDispatch extends WP_UnitTestCase { 9 12 13 use WP_AI_Client_Mock_Provider_Trait; 14 10 15 const CONNECTOR_ID = 'wp_test_application_password_connector'; 11 16 const CREDENTIALS_SETTING_NAME = 'connectors_test_remote_credentials'; 17 const AI_KEY_SETTING_NAME = 'connectors_ai_mock_connectors_test_api_key'; 18 19 /** 20 * Registers the mock AI provider connector once before any tests in this class run. 21 */ 22 public static function set_up_before_class(): void { 23 parent::set_up_before_class(); 24 self::register_mock_connectors_provider(); 25 } 26 27 /** 28 * Unregisters the mock AI provider's setting after all tests in this class have run. 29 */ 30 public static function tear_down_after_class(): void { 31 self::unregister_mock_connector_setting(); 32 parent::tear_down_after_class(); 33 } 12 34 13 35 /** … … 16 38 public function set_up(): void { 17 39 parent::set_up(); 40 41 self::set_mock_provider_configured( true ); 18 42 19 43 WP_Connector_Registry::get_instance()->register( … … 64 88 $this->assertNotSame( $application_password, $data[ self::CREDENTIALS_SETTING_NAME ]['password'] ); 65 89 } 90 91 /** 92 * Ensures a stored AI provider key is not re-validated, and therefore not reset, 93 * when it is not part of the current settings update. 94 * 95 * The /wp/v2/settings response always carries every registered setting, so the 96 * response data alone cannot tell which keys the request actually submitted. 97 * 98 * @ticket 65554 99 */ 100 public function test_does_not_validate_or_reset_unsubmitted_ai_key(): void { 101 $stored_key = 'sk-stored-valid-key'; 102 update_option( self::AI_KEY_SETTING_NAME, $stored_key ); 103 104 // A provider that would fail validation if it were consulted. 105 self::set_mock_provider_configured( false ); 106 107 // An update that submits an unrelated setting. 108 $request = new WP_REST_Request( 'POST', '/wp/v2/settings' ); 109 $request->set_param( 'title', 'New Site Title' ); 110 $response = new WP_REST_Response( array( self::AI_KEY_SETTING_NAME => $stored_key ) ); 111 112 $result = _wp_connectors_rest_settings_dispatch( $response, rest_get_server(), $request ); 113 $data = $result->get_data(); 114 115 $this->assertSame( 116 $stored_key, 117 get_option( self::AI_KEY_SETTING_NAME ), 118 'An AI provider key that was not submitted should not be reset.' 119 ); 120 $this->assertSame( 121 _wp_connectors_mask_api_key( $stored_key ), 122 $data[ self::AI_KEY_SETTING_NAME ], 123 'The stored AI provider key should still be masked in the response.' 124 ); 125 } 126 127 /** 128 * Ensures a submitted AI provider key that fails validation is still discarded. 129 * 130 * @ticket 65554 131 */ 132 public function test_discards_submitted_invalid_ai_key(): void { 133 $submitted_key = 'sk-submitted-invalid-key'; 134 update_option( self::AI_KEY_SETTING_NAME, $submitted_key ); 135 136 self::set_mock_provider_configured( false ); 137 138 $request = new WP_REST_Request( 'POST', '/wp/v2/settings' ); 139 $request->set_param( self::AI_KEY_SETTING_NAME, $submitted_key ); 140 $response = new WP_REST_Response( array( self::AI_KEY_SETTING_NAME => $submitted_key ) ); 141 142 $result = _wp_connectors_rest_settings_dispatch( $response, rest_get_server(), $request ); 143 $data = $result->get_data(); 144 145 $this->assertSame( 146 '', 147 get_option( self::AI_KEY_SETTING_NAME ), 148 'A submitted AI provider key that fails validation should be discarded.' 149 ); 150 $this->assertSame( 151 '', 152 $data[ self::AI_KEY_SETTING_NAME ], 153 'The discarded key should be returned as an empty string.' 154 ); 155 } 156 157 /** 158 * Ensures a submitted AI provider key that passes validation is kept and masked. 159 * 160 * @ticket 65554 161 */ 162 public function test_keeps_and_masks_submitted_valid_ai_key(): void { 163 $submitted_key = 'sk-submitted-valid-key'; 164 update_option( self::AI_KEY_SETTING_NAME, $submitted_key ); 165 166 self::set_mock_provider_configured( true ); 167 168 $request = new WP_REST_Request( 'POST', '/wp/v2/settings' ); 169 $request->set_param( self::AI_KEY_SETTING_NAME, $submitted_key ); 170 $response = new WP_REST_Response( array( self::AI_KEY_SETTING_NAME => $submitted_key ) ); 171 172 $result = _wp_connectors_rest_settings_dispatch( $response, rest_get_server(), $request ); 173 $data = $result->get_data(); 174 175 $this->assertSame( 176 $submitted_key, 177 get_option( self::AI_KEY_SETTING_NAME ), 178 'A submitted AI provider key that passes validation should be kept.' 179 ); 180 $this->assertSame( 181 _wp_connectors_mask_api_key( $submitted_key ), 182 $data[ self::AI_KEY_SETTING_NAME ], 183 'The submitted AI provider key should be masked in the response.' 184 ); 185 } 66 186 }
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)