Skip to content

Add HTTP-layer connector attribution, enforcement, and Connector Approval interop - #6

Merged
ilicfilip merged 4 commits into
mainfrom
feat/connector-approval-http-guard
Jul 9, 2026
Merged

ilicfilip merged 4 commits into
mainfrom
feat/connector-approval-http-guard

Conversation

@ilicfilip

Copy link
Copy Markdown
Collaborator

What & why

WordPress 7.0 ships AI in core behind a shared Connectors API with no spend controls. Our known weak point (per CLAUDE.md) is attribution confidence — today the best signal is a cooperating plugin's self-ID hook (high) or a debug_backtrace path map (medium).

The official WP AI plugin now ships an experimental "Connector Approval" feature that enforces at the pre_http_request filter: it scans each outbound request for a configured connector credential, which identifies the exact connector leaving the site. This PR adopts that technique.

Two properties make it worth adopting:

  1. Exact connector identity at request time (the literal key is in the request) — a new, highest-confidence attribution tier.
  2. It catches plugins that bypass wp_ai_client_prompt() and call the provider API directly — traffic our prompt-hook path is structurally blind to.

Changes

New

  • Capture\Connector_Key_Index — builds {credential => connector_id} from core wp_get_connectors() (no hard dependency on the ai plugin), scans request URL + headers (raw + rawurlencoded).
  • Capture\Http_Guard — hooks pre_http_request (pri 5). Enriches the Gatekeeper's pending intent to exact confidence + connector_id, and optionally blocks via the shared Enforcer (translating its bool into a WP_Error 403). Observe-only until a hard limit is configured; fails open on any error.
  • Interop\Connector_Approval_Bridge — read-only view of the ai plugin's connector-approval experiment (its blocks never reach our capture path), exposed via GET /connector-approvals and a dashboard panel.

exact attribution tier

  • Caller_Resolver::CONFIDENCE_EXACT const + docblock ladder (exact > high > medium > low).
  • Usage_Recorder allows exact through its confidence allowlist.
  • Limit_Evaluator ranks exact (3) above high, so it satisfies every min_confidence gate. (Without this an exact request would fail the gate like low — the subtle bit.)

Wiring — Http_Guard is constructed in Plugin::register_runtime() reusing the same Caller_Resolver and Enforcer as the Gatekeeper, so both enforcement points evaluate limits identically.

Invariants respected

  • Observe-only / fail-open: the HTTP guard blocks only when Enforcer::should_block() returns true (which short-circuits to false with no enabled hard limits); the whole guard body fails open on any \Throwable. No double-block — for AI-Client calls the prompt hook runs first, and a prompt blocked there makes no HTTP request.
  • No hard dependency on the ai plugin: credentials come from core wp_get_connectors(); interop only reads options when the experiment is detected active.
  • Runtime-guarded: function_exists('wp_get_connectors') etc.; passes php -l with the core connector API absent.

Verification

Verified live on WordPress 7.0 with the real anthropic connector:

  • One real AI call captured at plugin_confidence=exact with real tokens (input=16 output=4 estimated=0), provider=anthropic, model=claude-sonnet-5, cost computed, and surfaced on the dashboard (requests=1, cost_micros=108) — proving core's real outbound request carries the credential in the expected shape.
  • Simulated-request coverage: credential scan (match / no-match / url-encoded), 403 block on a breached hard limit, fail-open on a throwing enforcer, interop active/inactive, REST 200 (admin) / 401 (anon).
  • Static: PHPCS (0 errors), PHPStan level 10, php-parallel-lint, JS build all clean.

Scope note

connector_id is kept as enrichment/enforcement-only (in-memory) for now — no new DB column this round, per the plan's "verify before widening the schema" decision. A follow-up can add the column + a connector breakdown on the dashboard.

🤖 Generated with Claude Code

…oval interop

Adopt the technique from the official WP AI plugin's experimental "Connector
Approval" feature: enforce/attribute at the `pre_http_request` filter by scanning
each outbound request for a configured connector credential. This gives an exact
connector identity at request time and also covers plugins that read a credential
option and call the provider API directly, bypassing wp_ai_client_prompt().

New:
- Capture\Connector_Key_Index — builds {credential => connector_id} from core
  wp_get_connectors() (no dependency on the ai plugin), scans URL + headers.
- Capture\Http_Guard — hooks pre_http_request (pri 5); enriches the Gatekeeper's
  pending intent to `exact` confidence + connector_id, and optionally blocks via
  the shared Enforcer (translating its bool decision into a WP_Error 403). Stays
  observe-only until a hard limit is configured; fails open on any error.
- Interop\Connector_Approval_Bridge — read-only view of the ai plugin's
  connector-approval experiment (its blocks never reach our capture path), plus a
  GET /connector-approvals REST route and a dashboard panel surfacing them.

Attribution ladder gains an `exact` tier above self-ID:
- Caller_Resolver::CONFIDENCE_EXACT const + docblock.
- Usage_Recorder allows `exact` through its confidence allowlist.
- Limit_Evaluator ranks `exact` (3) above high, so it satisfies every
  min_confidence gate.

Http_Guard is wired in Plugin::register_runtime() reusing the same Caller_Resolver
and Enforcer as the Gatekeeper so both enforcement points evaluate limits
identically.

Verified live on WordPress 7.0 (real anthropic connector): a single real AI call
captured at `exact` confidence with real tokens/provider/model and surfaced on the
dashboard; plus simulated-request coverage for the 403 block on a breached hard
limit, fail-open on error, interop active/inactive paths, and REST 200/401. Passes
PHPCS (0 errors), PHPStan level 10, php-parallel-lint, and the JS build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Signed-off-by: Filip Ilic <ilic.filip@gmail.com>
@github-actions

github-actions Bot commented Jul 9, 2026 •

Copy link
Copy Markdown

🧪 Test on WordPress Playground

Open this PR in WordPress Playground →

or download the plugin zip.

Note: this plugin needs WordPress 7.0+ (the AI Client API) and a configured
AI provider to capture real usage. In Playground you'll see the dashboard, the
empty state, and the Limits UI — but no live AI requests (no provider key).

ilicfilip added 3 commits July 9, 2026 10:30
…ce tier

- Connector_Key_Index_Test: credential match in header / url-encoded / array
  header, no-match on unrelated traffic, short-credential and empty-registry
  guards.
- Http_Guard_Test: passthrough of non-connector and pre-empted requests,
  enrichment of the pending intent to `exact` + connector id, WP_Error 403 when
  the enforcer blocks, allow when it doesn't, and fail-open when it throws.
- Limit_Evaluator: assert `exact` outranks high and satisfies a high gate.

Adds a protected Connector_Key_Index::get_connectors() seam so tests supply a
fixed connector set without depending on core's connector registry (which has no
registration filter and varies by WP version). No production behaviour change.

Full suite: 80 tests, 243 assertions, green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Signed-off-by: Filip Ilic <ilic.filip@gmail.com>
`npm run lint:js` (CI js.yml) was failing on pre-existing prettier violations in
App.js and Limits.js as well as the new dashboard panel. `npm run format`
normalises both files; net -68 lines (collapses multi-line __() calls). No
behaviour change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Signed-off-by: Filip Ilic <ilic.filip@gmail.com>
…nt point

Sync CLAUDE.md with the connector-approval work: the new `exact` attribution tier
(HTTP-guard credential match, above self-ID) and its confidence-gating rank; the
second enforcement point at pre_http_request sharing the Gatekeeper's Enforcer;
the new Capture/ + Interop/ files; and the GET /connector-approvals route.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Signed-off-by: Filip Ilic <ilic.filip@gmail.com>
@ilicfilip
ilicfilip merged commit a8b3d1b into main Jul 9, 2026
12 checks passed
@ilicfilip
ilicfilip deleted the feat/connector-approval-http-guard branch July 9, 2026 08:34
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.

1 participant