Skip to content

feat(theme): bearer validator auto-provisions WP Subscriber on first sign-in (Phase 5 Track B)#176

Merged
JohnRDOrazio merged 2 commits into
mainfrom
feat/phase5-bearer-auto-provision
Jun 5, 2026
Merged

feat(theme): bearer validator auto-provisions WP Subscriber on first sign-in (Phase 5 Track B)#176
JohnRDOrazio merged 2 commits into
mainfrom
feat/phase5-bearer-auto-provision

Conversation

@JohnRDOrazio
Copy link
Copy Markdown
Member

@JohnRDOrazio JohnRDOrazio commented Jun 5, 2026

Summary

Track B of Phase 5 of the cdcf-role-mirroring plan (planner-side). Supersedes locked decision #1 of ~/.claude/plans/cdcf-bio-edit-zitadel.md ("no auto-provisioning") for the Subscriber path only. Elevated roles still flow through Phase 6's admin-approval workflow (separate, not in this PR).

Why

After deploying bio-edit Phase 4 to staging, the operator signed up via Zitadel (open sign-up + email verification per umbrella policy) but no corresponding WP user existed yet — so /api/my-bio/check correctly returned {linked: false} and the bearer validator fell through. Bridging that gap manually for every new sign-up is operationally untenable. Phase 5 closes it: any email-verified Zitadel sign-up gets a WP Subscriber automatically on first request. Subscriber has zero edit capabilities in WP core, so the blast radius is bounded.

Cross-system identity primary key: Zitadel sub

The Zitadel sub claim is the immutable cross-system identity primary key. Stored as WP user meta cdcf_zitadel_sub at provisioning / first sign-in. Email is mutable in Zitadel, so using email-only would silently create a second WP user every time the operator changed their Zitadel email — the never-a-second-WP-user invariant is the load-bearing requirement.

User-resolution flow (cdcf_zitadel_bearer_resolve_user)

  1. By sub via user_meta cdcf_zitadel_sub. If found and the claim's email differs from wp_users.user_email, wp_update_user to match — the email-drift sync. Never creates a second WP user.
  2. By email (one-time migration for users created before sub binding existed). Writes cdcf_zitadel_sub user-meta on match so subsequent requests take path 1.
  3. Auto-provision a Subscriber via wp_insert_user:
    • user_login = full email (immutable per WP, matches the umbrella Zitadel UserEmailAsUsername=true invariant at creation time)
    • user_email = email
    • user_pass = wp_generate_password(64, true, true) — never surfaced, sign-in must always flow through Zitadel
    • role = subscriber
    • display_name = Zitadel name claim → fallback email

Then bind cdcf_zitadel_sub user-meta.

Concurrency safety

Two parallel sign-ins for the same sub both reach the auto-provision branch. The first wp_insert_user wins; the second gets WP_Error(existing_user_email). The validator recovers by re-querying for the sub-bound user (the winner's row) — same id, no duplicate.

Fail-safes preserved

Cross-track ordering

cdcf-infra PR #13 (Track A) updates the CDCF Website project's Zitadel role catalog to mirror WP (subscriber, contributor, author, editor, administrator). This PR uses 'subscriber' as the WP role assigned on provision; that role exists in WP core so the WP write succeeds regardless of cdcf-infra ordering.

Order them as A → B in the prod rollout so Phase 6's elevation flow has a clean canonical role catalog to write userGrants against later.

This PR is also independent of cdcf-website PR #174 (bio editor UI — orthogonal scope, mid-review).

Tests

  • 7 new tests in ZitadelBearerTest.php:
    • test_sub_primary_key_lookup_hits_no_email_drift
    • test_sub_match_with_drifted_email_updates_wp_user_email
    • test_sub_miss_email_match_binds_sub_meta_for_migration
    • test_sub_claim_missing_falls_through_without_provisioning
    • test_auto_provision_uses_zitadel_name_for_display_name
    • test_auto_provision_falls_back_to_email_for_display_name_when_name_missing
    • test_auto_provision_race_recovers_via_sub_relookup
  • 1 renamed: test_no_matching_wp_user_falls_throughtest_no_matching_wp_user_auto_provisions_subscriber. The old behavior is documented inline as a marker of the policy reversal.
  • tests/bootstrap.php WP_User stub gains user_email / user_login / display_name typed string properties so PHP 8.2+ doesn't deprecate the dynamic-property writes.

Theme suite locally: 457 / 457 (was 450 → +7), 1056 assertions, no deprecations.

Deploy

WP theme change. Needs gh workflow run deploy.yml -f environment=production after merge — a staging-target run skips theme/plugin steps and the new resolver won't reach live WP.

Test plan

  • cdcf-infra PR Bump the npm_and_yarn group across 1 directory with 5 updates #13 lands first (role catalog) so the canonical role list matches what Phase 6 will later grant.
  • Operator's existing Zitadel test user signs in on staging → WP auto-provisions a Subscriber → wp user list --role=subscriber shows the new row with user_email matching the Zitadel claim and cdcf_zitadel_sub meta set.
  • In Zitadel, change the test user's email; sign in again on staging; verify the same WP user row now has the updated user_email (no second user, sub binding still set).
  • Forged token whose sub matches an existing WP user but aud is wrong → audience check rejects before any user resolution runs.

Summary by CodeRabbit

  • New Features

    • Auto-provision Subscriber accounts when Zitadel auth finds no matching user.
    • One-time migration that binds Zitadel subject to existing WP users when email matches.
  • Improvements

    • Identity resolution now uses Zitadel subject as primary key and syncs changed emails to WP.
    • Short-lived token→user caching to speed repeated requests.
  • Documentation

    • Updated docs to describe the revised Zitadel bearer auth flow and acceptance criteria.
  • Tests

    • Expanded tests covering subject-driven lookup, email drift sync, migration, provisioning, and edge cases.

…sign-in (Phase 5 Track B)

Supersedes locked decision #1 of cdcf-bio-edit-zitadel ("no auto-
provisioning") for the Subscriber path only. Elevated roles still
flow through the Phase 6 admin-approval workflow (separate, not in
this PR).

Why
---
After deploying bio-edit Phase 4 to staging, the operator signed up
via Zitadel (open sign-up + email verification per umbrella policy)
but no corresponding WP user existed yet — so /api/my-bio/check
correctly returned {linked:false} and the bearer validator fell
through. Bridging that gap manually for every new sign-up is
operationally untenable. Phase 5 closes it: any email-verified
Zitadel sign-up gets a WP Subscriber automatically on first request.
Subscriber has zero edit capabilities in WP core, so the blast radius
is bounded.

Cross-system identity primary key: Zitadel sub claim
----------------------------------------------------
The Zitadel sub claim is the immutable cross-system identity primary
key. Stored as WP user meta `cdcf_zitadel_sub` at provisioning / first
sign-in. Email is mutable in Zitadel, so using email-only would
silently create a second WP user every time the operator changed
their Zitadel email — the never-a-second-WP-user invariant is the
load-bearing requirement.

User resolution flow (cdcf_zitadel_bearer_resolve_user)
-------------------------------------------------------
1. By sub via user_meta cdcf_zitadel_sub → if claim email differs
   from wp_users.user_email, wp_update_user to match (email-drift
   sync). Never creates a second WP user.
2. By email (one-time migration for users created before sub binding
   existed) → write cdcf_zitadel_sub meta so subsequent requests
   take path 1.
3. Auto-provision a Subscriber via wp_insert_user with:
   - user_login = full email (immutable per WP, matches the umbrella
     Zitadel UserEmailAsUsername=true invariant at creation time)
   - user_email = email
   - user_pass = wp_generate_password(64, true, true) — never
     surfaced, sign-in must always flow through Zitadel
   - role = 'subscriber'
   - display_name = Zitadel `name` claim, falling back to email
   Then bind cdcf_zitadel_sub user-meta.

Concurrency-safe: if two parallel sign-ins for the same sub race into
the auto-provision branch, the second wp_insert_user fails with
user_email_exists, and the validator recovers by re-querying for the
sub-bound user (the winner's row) — same id, no duplicate.

Validator fail-safes preserved
------------------------------
- Audience verification (PR #173 multi-aud allow-list) runs FIRST,
  before any new code.
- email_verified=false still falls through (no provision).
- Missing sub claim still falls through (no email-only resolution,
  no provision) — required for safety.
- Transient cache is keyed by sha256(token) and stores the resolved
  WP id, same as before.

Files
-----
- includes/auth/zitadel-bearer.php: cdcf_zitadel_bearer_authenticate
  now delegates user resolution to cdcf_zitadel_bearer_resolve_user.
  Two new helpers: cdcf_zitadel_bearer_user_by_sub() and
  cdcf_zitadel_bearer_auto_provision_subscriber().
- tests/ZitadelBearerTest.php: 7 new tests covering sub-primary-key
  hit, email-drift sync, sub-miss/email-match migration, missing-sub
  fallthrough, Zitadel `name` → display_name + email fallback, and
  the auto-provision race recovery.
- tests/bootstrap.php: WP_User stub gains user_email, user_login,
  display_name (typed string properties) to silence PHP 8.2+ dynamic-
  property deprecations from the new tests.
- AGENTS.md (+CLAUDE.md symlink): replaces the "no auto-provisioning"
  paragraph in the Zitadel bearer auth section with the new three-
  step resolution flow.

Theme suite: 450 → 457 tests, 1033 → 1056 assertions, all green.

Track A dependency
------------------
cdcf-infra PR #13 updates the CDCF Website project's role catalog to
mirror WP (subscriber, contributor, author, editor, administrator).
This PR uses 'subscriber' as the WP role assigned on provision; that
role exists in WP core so the WP write succeeds regardless of cdcf-
infra ordering. Order them as A → B in the prod rollout so the
elevation flow (Phase 6) has a clean canonical role catalog to write
userGrants against later.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 5, 2026

Worried about impact? Review this PR in Change Stack to explore blast radius before you approve or request changes.

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9b37a670-031c-46f1-bf39-df5446c466d3

📥 Commits

Reviewing files that changed from the base of the PR and between a266df3 and 536ed2b.

📒 Files selected for processing (3)
  • AGENTS.md
  • wordpress/themes/cdcf-headless/includes/auth/zitadel-bearer.php
  • wordpress/themes/cdcf-headless/tests/ZitadelBearerTest.php
✅ Files skipped from review due to trivial changes (1)
  • AGENTS.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • wordpress/themes/cdcf-headless/includes/auth/zitadel-bearer.php
  • wordpress/themes/cdcf-headless/tests/ZitadelBearerTest.php

📝 Walkthrough

Walkthrough

Bearer authentication for WordPress REST API now resolves user identity via Zitadel sub claim instead of email, with fallback email migration for existing users and automatic Subscriber provisioning for new identities, including handling of concurrent provisioning and email drift synchronization.

Changes

Zitadel Sub-Driven User Resolution

Layer / File(s) Summary
Bearer auth entry point & documentation
AGENTS.md, wordpress/themes/cdcf-headless/includes/auth/zitadel-bearer.php
Documented the new flow (audience check → userinfo verification → require sub → resolve user → cache result). HTTP handler now validates claims, calls cdcf_zitadel_bearer_resolve_user, and caches successful user_id results in a transient; the prior email-only path is replaced.
User resolution & provisioning functions
wordpress/themes/cdcf-headless/includes/auth/zitadel-bearer.php
cdcf_zitadel_bearer_resolve_user orchestrates three resolution paths: sub-based lookup (with email-drift sync), email fallback binding (one-time migration), and auto-provisioning. cdcf_zitadel_bearer_user_by_sub performs meta-based lookup. cdcf_zitadel_bearer_auto_provision_subscriber inserts a subscriber, sets cdcf_zitadel_sub, and handles insert conflicts via relookup.
Test infrastructure & helpers
wordpress/themes/cdcf-headless/tests/bootstrap.php, wordpress/themes/cdcf-headless/tests/ZitadelBearerTest.php
WP_User test stub gains typed user_email, user_login, display_name. stubWp() now stubs is_email() and defaults get_users to empty results for sub lookups. buildUserinfoResponse() injects a default sub for HTTP 200 responses.
Resolution & provisioning test cases
wordpress/themes/cdcf-headless/tests/ZitadelBearerTest.php
Phase 5 tests replace the prior fallthrough test with subscriber auto-provision assertions and add coverage: sub primary-key hit (no drift), email-drift sync, email-match migration binding, missing sub fallthrough, display-name selection from name or email, and race-condition recovery after insert conflict.

Sequence Diagram

sequenceDiagram
  participant Client
  participant BearerHandler as Bearer Handler
  participant Resolver as Resolve User
  participant WordPress as WordPress
  participant Cache as Transient Cache
  
  Client->>BearerHandler: HTTP request + Bearer token
  BearerHandler->>BearerHandler: Decode JWT & verify audience
  BearerHandler->>BearerHandler: Fetch userinfo, verify email_verified
  BearerHandler->>BearerHandler: Require sub claim
  BearerHandler->>Resolver: cdcf_zitadel_bearer_resolve_user(sub, email, name)
  
  rect rgba(200, 220, 255, 0.5)
  Note over Resolver,WordPress: Sub-based lookup
  Resolver->>WordPress: get_users(meta: cdcf_zitadel_sub)
  WordPress-->>Resolver: WP_User (if found)
  alt Found by sub
    Resolver->>Resolver: Check email drift
    alt Email drifted
      Resolver->>WordPress: wp_update_user(new email)
    end
  end
  end
  
  rect rgba(220, 200, 255, 0.5)
  Note over Resolver,WordPress: Email fallback (migration)
  alt Not found by sub
    Resolver->>WordPress: get_users(user_email)
    WordPress-->>Resolver: WP_User (if found)
    alt Found by email
      Resolver->>WordPress: update_user_meta(cdcf_zitadel_sub)
    end
  end
  end
  
  rect rgba(255, 220, 200, 0.5)
  Note over Resolver,WordPress: Auto-provision
  alt User not found
    Resolver->>WordPress: wp_insert_user(subscriber)
    WordPress-->>Resolver: user_id or error
    alt Insert conflict
      Resolver->>WordPress: get_users(meta: cdcf_zitadel_sub)
      WordPress-->>Resolver: WP_User
    end
    Resolver->>WordPress: update_user_meta(cdcf_zitadel_sub)
  end
  end
  
  Resolver-->>BearerHandler: user_id
  BearerHandler->>Cache: Store user_id
  BearerHandler-->>Client: Authenticated
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • CatholicOS/cdcf-website#172: Multi-audience bearer validator updates that establish the JWT validation foundation this PR extends with sub-driven user resolution.

Poem

🐰 A rabbit hops where tokens hum,
sub takes the lead and emails come,
When drifts occur the patch is sewn,
New subscribers find a home,
Race-safe hops — the flow goes on!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: auto-provisioning WordPress Subscribers on first Zitadel sign-in as part of Phase 5 Track B, which is the primary focus of the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/phase5-bearer-auto-provision

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Jun 5, 2026

Codecov Report

❌ Patch coverage is 83.92857% with 9 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...mes/cdcf-headless/includes/auth/zitadel-bearer.php 83.92% 9 Missing ⚠️

📢 Thoughts on this report? Let us know!

@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented Jun 5, 2026

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 25 complexity

Metric Results
Complexity 25

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@JohnRDOrazio
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 5, 2026

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
wordpress/themes/cdcf-headless/includes/auth/zitadel-bearer.php (1)

5-20: ⚡ Quick win

Update the file header docblock to match current behavior.

The top docblock still says the resolver is email-based and does not auto-provision, which no longer matches this implementation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wordpress/themes/cdcf-headless/includes/auth/zitadel-bearer.php` around lines
5 - 20, Update the file header docblock to reflect the current implementation:
describe that the code hooks into the determine_current_user filter and accepts
an Authorization: Bearer <token> header, validates the token against Zitadel's
/oidc/v1/userinfo endpoint, caches accepted token-hash → user_id pairs using
sha256(token) in a transient (TTL 60s default), and resolves the WP user by the
current claim used in the code (replace the outdated "email-based" wording with
the actual claim the implementation uses, e.g., sub or preferred_username). Also
update the provisioning statement to reflect current behavior (if the code now
auto-provisions users or still falls through, state that accurately) and remove
any references that contradict the implemented logic such as "does not
auto-provision" or "email-based resolver" and keep mention of author_team_member
linkage if still relevant.
wordpress/themes/cdcf-headless/tests/ZitadelBearerTest.php (1)

453-457: ⚡ Quick win

Tighten get_users() mocks to assert sub-lookup query args.

These aliases return a user without validating meta_key/meta_value, so a regression in sub-query wiring could still pass. Assert cdcf_zitadel_sub and expected sub in these mocks.

Also applies to: 585-593

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wordpress/themes/cdcf-headless/tests/ZitadelBearerTest.php` around lines 453
- 457, The get_users() test aliases should inspect incoming query args and
assert the sub-lookup keys instead of always returning a user; update the
Functions\when('get_users')->alias callbacks (the one creating a WP_User) to
accept the query args, assert that args['meta_key'] === 'cdcf_zitadel_sub' and
args['meta_value'] === the expected sub value, then return the WP_User with the
desired email; apply the same change to the other get_users() mock block (the
second alias) so both mocks validate meta_key/meta_value before returning a
user.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@AGENTS.md`:
- Around line 215-220: The "Fails closed on every unhappy path" paragraph still
lists the stale example "no WP user match" which contradicts the new
auto-provisioning behavior described in the earlier bullets (the auto-provision
Subscriber flow and user-resolution steps that write cdcf_zitadel_sub); update
that paragraph by removing the "no WP user match" example so the fail-closed
list only contains true unhappy paths (opaque non-JWT token, wrong audience,
non-200 userinfo, malformed JSON, unverified email, etc.) and ensure the text
references the auto-provisioning/user-resolution behavior (cdcf_zitadel_sub,
user_login=user email, display_name seeded from name claim) to avoid future
contradiction.

In `@wordpress/themes/cdcf-headless/includes/auth/zitadel-bearer.php`:
- Around line 251-255: The current guard uses empty($userinfo['email_verified'])
which allows non-boolean truthy values; update the check in the
authentication/resolver block that inspects $userinfo (the code around
$userinfo['email_verified'] and $userinfo['email'] that currently returns
$user_id) to require strict boolean true for email verification (e.g. verify
$userinfo['email_verified'] === true) while still ensuring $userinfo['email'] is
present; replace the empty() test with an explicit boolean check so untrusted
truthy values are rejected.

In `@wordpress/themes/cdcf-headless/tests/ZitadelBearerTest.php`:
- Around line 72-80: The docstring for the helper that "Build[s] a fake
wp_remote_post response" incorrectly says omitting the 'sub' key will bypass the
default; update the comment to state that the helper injects a default 'sub'
when the key is omitted and that tests that want a missing 'sub' must explicitly
pass 'sub' => null (not simply omit the key). Also update the other similar doc
block (the second paragraph noted) to the same wording so both places reflect
the actual behavior.
- Around line 243-250: Update the stale test comment in ZitadelBearerTest (the
block containing "PRE-PHASE-5" and the phrase "fall through, no
auto-provisioning") to reflect current behavior: remove or replace "fall
through, no auto-provisioning" and any pre-Phase-5 wording and instead state
that this test now validates successful auto-provisioning for the Subscriber
path (while keeping notes about other fallthrough cases like
email-verified-false and sub-missing as applicable).

---

Nitpick comments:
In `@wordpress/themes/cdcf-headless/includes/auth/zitadel-bearer.php`:
- Around line 5-20: Update the file header docblock to reflect the current
implementation: describe that the code hooks into the determine_current_user
filter and accepts an Authorization: Bearer <token> header, validates the token
against Zitadel's /oidc/v1/userinfo endpoint, caches accepted token-hash →
user_id pairs using sha256(token) in a transient (TTL 60s default), and resolves
the WP user by the current claim used in the code (replace the outdated
"email-based" wording with the actual claim the implementation uses, e.g., sub
or preferred_username). Also update the provisioning statement to reflect
current behavior (if the code now auto-provisions users or still falls through,
state that accurately) and remove any references that contradict the implemented
logic such as "does not auto-provision" or "email-based resolver" and keep
mention of author_team_member linkage if still relevant.

In `@wordpress/themes/cdcf-headless/tests/ZitadelBearerTest.php`:
- Around line 453-457: The get_users() test aliases should inspect incoming
query args and assert the sub-lookup keys instead of always returning a user;
update the Functions\when('get_users')->alias callbacks (the one creating a
WP_User) to accept the query args, assert that args['meta_key'] ===
'cdcf_zitadel_sub' and args['meta_value'] === the expected sub value, then
return the WP_User with the desired email; apply the same change to the other
get_users() mock block (the second alias) so both mocks validate
meta_key/meta_value before returning a user.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 12b97f24-7ce3-4b43-9cbf-346a343c2328

📥 Commits

Reviewing files that changed from the base of the PR and between a6a12e4 and a266df3.

📒 Files selected for processing (4)
  • AGENTS.md
  • wordpress/themes/cdcf-headless/includes/auth/zitadel-bearer.php
  • wordpress/themes/cdcf-headless/tests/ZitadelBearerTest.php
  • wordpress/themes/cdcf-headless/tests/bootstrap.php

Comment thread AGENTS.md Outdated
Comment thread wordpress/themes/cdcf-headless/includes/auth/zitadel-bearer.php Outdated
Comment thread wordpress/themes/cdcf-headless/tests/ZitadelBearerTest.php Outdated
Comment thread wordpress/themes/cdcf-headless/tests/ZitadelBearerTest.php Outdated
- zitadel-bearer.php header docblock now reflects Phase 5 sub-based
  resolution + auto-provisioning (was stale: email-only, no provisioning).
- email_verified gate tightened from empty() to === true so a
  spec-violating IdP can't trick it with non-boolean truthy payloads.
- AGENTS.md fail-closed list: "no WP user match" removed (it's an
  auto-provision case now); added missing-sub + auto-provision-failure.
- ZitadelBearerTest helper docstring: clarify that omitting 'sub'
  triggers default injection (tests for the missing-sub branch must
  override explicitly, e.g. by bypassing buildUserinfoResponse).
- ZitadelBearerTest test_no_matching_wp_user_auto_provisions_subscriber
  lead comment no longer says "fall through, no auto-provisioning".

Theme suite: 457/457, 1056 assertions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JohnRDOrazio
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 5, 2026

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@JohnRDOrazio JohnRDOrazio merged commit 8960ed8 into main Jun 5, 2026
14 checks passed
@JohnRDOrazio JohnRDOrazio deleted the feat/phase5-bearer-auto-provision branch June 5, 2026 23:10
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.

2 participants