Skip to content

Add a Site Health connection test and debug information section#192

Merged
pfefferle merged 9 commits into
trunkfrom
add/site-health-check
Jul 14, 2026
Merged

Add a Site Health connection test and debug information section#192
pfefferle merged 9 commits into
trunkfrom
add/site-health-check

Conversation

@pfefferle

Copy link
Copy Markdown
Member

Follow-up to #191 (based on that branch — the status test reads the reauth_reason marker it introduces; will auto-retarget to trunk when #191 merges).

Proposed changes:

Adds a Site Health integration (mirroring the wordpress-activitypub Health_Check layout), so connection problems are visible where users — and the people supporting them — actually look:

  • Status test (Tools → Site Health → Status). One direct test, options-only (no HTTP, can't slow the screen or flake): connected → good; never connected or deliberately disconnected → recommended; needs reconnect → critical with cause-specific copy. The key-changed case guides the user to define ATMOSPHERE_ENCRYPTION_KEY in wp-config.php before reconnecting so the next salt rotation doesn't break the connection again — and if the constant is defined but its value changed, says exactly that instead.
  • Debug information panel (Site Health → Info). An ATmosphere section with plugin version, connection status (including the reconnect reason), handle, DID, PDS endpoint, encryption key source (dedicated constant vs. WordPress security keys — never any key material), auto-publish state, and supported post types. Safe to paste into support threads, and makes them self-diagnosing.

Registered unconditionally on init (not admin-gated) because the weekly wp_site_health_scheduled_check cron runs direct tests in a non-admin context to feed the dashboard status counter.

Other information:

  • Have you written new tests for your changes, if applicable?

Testing instructions:

  • Start the environment (npm run env-start) and open Tools → Site Health with no Bluesky account connected. Expected: a "recommended" item saying ATmosphere is not connected yet, linking to the settings page; the Info tab has an ATmosphere section with status "Not connected".
  • Connect a Bluesky account. Expected: the status item turns good ("ATmosphere is connected to Bluesky"); the Info section shows handle, DID, PDS endpoint, and "Encryption Key Source: WordPress security keys".
  • Simulate a salt rotation (npm run wp-env run cli wp config shuffle-salts) and publish a post to trip the decrypt failure. Expected: Site Health shows a critical issue explaining the security keys changed, with the define( 'ATMOSPHERE_ENCRYPTION_KEY', … ); snippet and a settings-page link; the Info tab's connection status reads "Needs reconnect (security keys changed)".
  • Click Disconnect on the settings page. Expected: the critical issue becomes a "recommended" item with "You disconnected this site from Bluesky" copy.
  • composer lint and npm run env-test pass (929 tests).

Changelog entry

Entry committed on the branch (.github/changelog/add-site-health-check).

  • Automatically create a changelog entry from the details below.
Changelog Entry Details

Significance

  • Patch
  • Minor
  • Major

Type

  • Added - for new features
  • Changed - for changes in existing functionality
  • Deprecated - for soon-to-be removed features
  • Removed - for now removed features
  • Fixed - for any bug fixes
  • Security - in case of vulnerabilities

Message

…ecrypted

Salt rotation (a security plugin's scheduled rotation, a migration, or a
regenerated wp-config.php) changes the key the OAuth tokens are
encrypted with, leaving them permanently unreadable. Previously every
publish then failed with a retry hint that could never succeed (see the
'inconsistent post visibility' wp.org support topic).

- Flag the connection needs_reauth on decrypt failure (race-guarded on
  the ciphertext field that actually failed), so publishing
  short-circuits and the admin reconnect notice appears.
- Persist a domain-separated fingerprint of the encryption key with the
  connection and use it to tell 'security keys changed' apart from
  corrupted data, with cause-specific notice copy.
- Swap the editor-panel error for a reconnect link when re-saving
  cannot help.
- Support an ATMOSPHERE_ENCRYPTION_KEY constant that takes precedence
  over AUTH_KEY/AUTH_SALT for sites that rotate salts deliberately.
Surfaces the Bluesky connection state where users and supporters
actually look when something is wrong. The status test maps each
connection state to the right severity, and the key-changed case
guides the user to the ATMOSPHERE_ENCRYPTION_KEY constant so the next
salt rotation doesn't break the connection again. The debug panel
(version, connection status + reason, handle, DID, PDS endpoint,
encryption key source, auto-publish, post types — no key or token
material) makes support threads self-diagnosing.

Mirrors the wordpress-activitypub Health_Check layout.
@pfefferle pfefferle self-assigned this Jul 10, 2026
@pfefferle
pfefferle requested a review from a team July 10, 2026 22:53
@github-actions github-actions Bot added [Feature] WP Admin Admin UI and settings [Tests] Includes Tests PR includes test changes labels Jul 10, 2026
…te Health guidance

Mirrors WordPress's own secret-key service: instead of a placeholder
the user has to know how to replace, the key-changed guidance renders
a define() line with a freshly generated 64-character random key that
can be copied into wp-config.php as-is. Generated per render, never
stored; wp_generate_password()'s character set contains no quotes or
backslashes, so the value is safe in a single-quoted literal.
…rrors server-side

Quality pass over the recovery work:

- New helpers in functions.php — settings_url(), is_operator_disconnected()
  (owning the stale-marker rationale), get_reauth_reason() — replace
  triplicated predicates across the admin surfaces.
- The reauth_reason vocabulary becomes Client::REAUTH_REASON_* constants;
  a mistyped string comparison failed soft to the generic expiry copy.
- The publish-error REST field now carries a server-computed
  needs_reconnect flag, so the editor panel no longer hand-mirrors the
  PHP error-code list across languages.
- Encryption::has_dedicated_key() owns the defined-and-non-empty check
  reused by the admin surfaces.
- The reauth notice composes one shared tail sentence with per-cause
  lead sentences instead of four near-identical 40-word strings, and the
  key-changed wording is aligned with Site Health.
- mark_needs_reauth() requires the guard field explicitly.
Quality pass: a single connection_state() resolver feeds both the
status test and the debug panel instead of two parallel state ladders;
the reauth reason and operator-disconnect gates now come from the
shared helpers and Client::REAUTH_REASON_* constants; the dedicated-key
probe reuses Encryption::has_dedicated_key().
…ze decrypt handling

- Share the reauth cause sentences between the admin notice and Site
  Health via a single reauth_reason_lead() helper.
- Register the Site Health filters only on admin and cron requests.
- Use settings_url() for the remaining hardcoded admin redirects.
- Move the needs_reconnect judgment into Client::is_reconnect_error(),
  next to the code paths that mint those error codes.
- Route all connection-credential decrypts through Client::decrypt_field()
  so a failed decrypt always flags the row for reauth.
@github-actions github-actions Bot added [Feature] API PDS API client [Feature] OAuth OAuth flow and authentication labels Jul 13, 2026
@pfefferle
pfefferle requested a review from Copilot July 14, 2026 07:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a WordPress Site Health integration to surface ATmosphere’s Bluesky connection state in both the Status tests and the Info → Debug information panel, making connection problems and reconnect guidance visible in a standard, support-friendly place. It also refactors a couple of connection/reconnect helpers so the same reconnect “cause” copy and reconnect classification logic is reused consistently across surfaces.

Changes:

  • Introduces a new Site Health direct test plus an ATmosphere debug-information section (connection status, identity details, encryption key source, publishing config).
  • Adds PHPUnit coverage to ensure each connection state maps to the intended Site Health severity and copy (including key-change guidance).
  • Refactors shared connection helpers (centralized reconnect lead copy, centralized “needs reconnect” error classification, and a decrypt helper that flags reauth on failure).

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
includes/wp-admin/class-health-check.php Implements Site Health status test + debug info section, including key-change specific guidance/snippet.
includes/class-atmosphere.php Wires the Site Health integration during admin requests and cron-run scheduled Site Health checks.
tests/phpunit/tests/wp-admin/class-test-health-check.php Adds coverage for the status test + debug-information output across connection states.
includes/functions.php Adds reauth_reason_lead() and settings_url() helpers used by multiple UI surfaces.
includes/wp-admin/class-admin.php Reuses shared reconnect-lead copy and shared settings URL for redirects/notices.
includes/oauth/class-client.php Adds decrypt_field() and centralizes reconnect-only error codes via is_reconnect_error().
includes/class-api.php Uses Client::decrypt_field() for dpop_jwk decrypt + consistent failure handling.
.github/changelog/add-site-health-check Adds an end-user changelog entry for the new Site Health feature.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Base automatically changed from fix/decrypt-failure-recovery to trunk July 14, 2026 14:29
@github-actions github-actions Bot added the Docs label Jul 14, 2026
# Conflicts:
#	build/editor-plugin/plugin.asset.php
#	build/editor-plugin/plugin.js
#	build/pre-publish-panel/plugin.asset.php
#	build/pre-publish-panel/plugin.js
#	docs/developer-docs.md
#	includes/class-api.php
#	includes/class-atmosphere.php
#	includes/class-block-editor.php
#	includes/functions.php
#	includes/oauth/class-client.php
#	includes/oauth/class-encryption.php
#	includes/wp-admin/class-admin.php
#	src/config.js
#	src/editor-plugin/plugin.js
#	tests/phpunit/tests/oauth/class-test-client-decrypt.php
… filters lazily

The merge left Atmosphere's RECONNECT_ERROR_CODES const behind after
both consumers moved to Client::is_reconnect_error() — delete it so the
list really is declared once. Register the Site Health filters directly
on the pull filters instead of a context-gated init hook: they only
fire on Site Health surfaces (screen, weekly check, WP-CLI), so the
class loads only there and the is_admin/cron gate — which missed the
WP-CLI context — goes away. Use the canonical get_did() and
get_pds_endpoint() accessors in the debug panel.
@pfefferle
pfefferle merged commit 41faaff into trunk Jul 14, 2026
8 checks passed
@pfefferle
pfefferle deleted the add/site-health-check branch July 14, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Docs [Feature] API PDS API client [Feature] OAuth OAuth flow and authentication [Feature] WP Admin Admin UI and settings [Tests] Includes Tests PR includes test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants