Skip to content

Connector Approvals: stop blaming core's key check on the provider or Gutenberg - #1070

Merged
dkotter merged 4 commits into
WordPress:developfrom
epeicher:fix/connector-approval-provider-self-attribution
Sep 29, 2026
Merged

dkotter merged 4 commits into
WordPress:developfrom
epeicher:fix/connector-approval-provider-self-attribution

Conversation

@epeicher

@epeicher epeicher commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

What?

Closes #1069

Stops Connector Approvals from blocking core's connector key check by attributing it to the provider plugin or to Gutenberg, which makes Settings → Connectors reject valid keys.

Why?

Core validates a key by listing the provider's models, and Caller_Identifier attributes each request to the outermost plugin on the stack. Two cases blame a plugin for what is really core's check (details and stack in #1069):

  1. Provider blamed for its own key. When the provider's own class sends the request (the OpenRouter provider overrides sendListModelsRequest()), it is the only plugin on the stack. Providers that inherit the request from core's OpenAI-compatible base class are unaffected.
  2. Gutenberg blamed. Gutenberg 23.9 through 24.0 validates keys in its polyfill of core's connectors.php, which the skip list does not cover.

#595 aimed to let core's credential checks and requests that only pass through a provider go through without approval. These are the two gaps left.

How?

  • Http_Guard resolves the plugin that registered the connector's AI Client provider (AiClient::defaultRegistry()->getProviderClassName(), then the class file's plugin directory) and passes its slug to Caller_Identifier::identify().

  • Caller_Identifier::identify() / resolve() accept those slugs and skip the matching plugin frames the same way core frames are skipped. If nothing else is on the stack, the caller is null and the request passes, the guard's existing rule for core-originated requests. A plugin calling through the provider is still identified; test_identifies_consumer_calling_through_an_infrastructure_plugin pins that.

    I did not use "the connector's owner is always approved": a consumer hooked inside the provider's code would be attributed to the provider and let through that way.

  • Skip list gains gutenberg/lib/compat/wordpress-7.0/default-connectors.php, next to core's connectors.php. Gutenberg 24.1 RC no longer ships that file, so the entry becomes inert once sites upgrade.

  • The identifier's per-request cache key now includes the slugs.

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5.5
Used for: investigating the root cause, writing the fix, the tests and this description, under my direction.

Testing Instructions

Unit tests

npm run test:php -- --filter Caller_IdentifierTest

The three new tests are test_skips_infrastructure_plugin_frames_when_core_validates_a_key, test_skips_gutenberg_connectors_polyfill and test_identifies_consumer_calling_through_an_infrastructure_plugin. On develop the first two fail; the third passes on both and guards against exempting too much. The whole Connector_Approval folder passes (30 tests), and phpcs and PHPStan are clean.

Manual

  1. Activate the OpenRouter provider (ai-provider-for-openrouter from wordpress.org) and enable Connector Approvals. Keep Gutenberg inactive.
  2. Save any key in Settings → Connectors → OpenRouter.
  3. On develop: "It was not possible to connect to the provider using this key." and a pending ai-provider-for-openrouter request. On this branch: the key saves and nothing is pending. (OpenRouter's /models does not authenticate, so any key string passes the check once the request goes out.)
  4. With Gutenberg 24.0 or earlier active, develop records the pending request for gutenberg/gutenberg.php; this branch saves the key.

Saving an OpenRouter key through POST /wp/v2/settings on a clean site (AI plugin, OpenRouter provider 1.0.0, Connector Approvals on):

develop This branch
Gutenberg inactive rejected, pending for ai-provider-for-openrouter saved
Gutenberg 24.0.0 active rejected, pending for gutenberg/gutenberg.php saved

The same check for ai-provider-for-openai is allowed on both, since its request comes from core's base class.

Changelog Entry

Fixed - Connector Approvals no longer blocks core's connector key check by attributing it to the provider plugin or to Gutenberg.

Open WordPress Playground Preview

…utenberg

Core validates a connector key by listing the provider's models, and the
guard attributes every request to the outermost plugin on the stack.
Two cases blame a plugin for what is really core's key check, so the
request is blocked and the Connectors screen reports the key as invalid:

- A provider whose own classes send the request (the OpenRouter provider
  overrides sendListModelsRequest()) is the only plugin on the stack, so
  it is blamed for using its own connector. The guard now resolves the
  plugin that registered the connector's AI Client provider and treats
  its frames as infrastructure; a plugin calling through the provider is
  still identified.

- With Gutenberg 23.9 to 24.0 active, keys are validated by Gutenberg's
  polyfill of core's connectors.php, so Gutenberg is blamed. That file
  is now skipped like core's own connectors.php.
@epeicher
epeicher requested a review from a team September 29, 2026 11:53
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: epeicher <epeicher@git.wordpress.org>
Co-authored-by: jeffpaul <jeffpaul@git.wordpress.org>
Co-authored-by: dkotter <dkotter@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@codecov

codecov Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.74359% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.57%. Comparing base (dbbe3a4) to head (92abe0a).

Files with missing lines Patch % Lines
includes/Connector_Approval/Http_Guard.php 82.60% 4 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##             develop    #1070      +/-   ##
=============================================
+ Coverage      81.47%   81.57%   +0.10%     
- Complexity      3064     3077      +13     
=============================================
  Files            129      129              
  Lines          12236    12267      +31     
=============================================
+ Hits            9969    10007      +38     
+ Misses          2267     2260       -7     
Flag Coverage Δ
unit 81.57% <89.74%> (+0.10%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jeffpaul jeffpaul added this to the 1.4.0 milestone Sep 29, 2026
@jeffpaul jeffpaul mentioned this pull request Sep 29, 2026
21 of 24 tasks
…e vendored a provider plugin and that we can look at mu-plugins and themes, not just normal plugins
@dkotter
dkotter merged commit 747f943 into WordPress:develop Sep 29, 2026
33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Connector Approvals blocks core's key check, blaming the provider or Gutenberg ("not possible to connect" on Settings → Connectors)

3 participants

Sponsor
SponsoredKunjungi sekarang
Promo