PluginProbe ʕ •ᴥ•ʔ
Atarim – AI Agency for WordPress: Edit Pages, Fix Code, Update Plugins, SEO & Client Feedback / trunk
Atarim – AI Agency for WordPress: Edit Pages, Fix Code, Update Plugins, SEO & Client Feedback vtrunk
5.1.3 5.1.2 5.1.1 5.1 5.0 trunk 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 3.2.0 3.2.1 3.22 3.22.1 3.22.2 3.22.3 3.22.4 3.22.5 3.22.6 3.3.0 3.3.1 3.3.2 3.3.2.1 3.3.2.2 3.3.3 3.30 3.31 3.32 3.4 3.4.1 3.4.3 3.4.4 3.5 3.5.1 3.6 3.6.1 3.7 3.8 3.9 3.9.1 3.9.2 3.9.3 3.9.4 3.9.6 3.9.6.1 4.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.2 4.2.1 4.2.2 4.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.4
atarim-visual-collaboration / doit / class-avcf-diagnostic.php
atarim-visual-collaboration / doit Last commit date
abilities 2 days ago avcf-cluster-loader.php 2 days ago class-avcf-diagnostic.php 3 weeks ago class-avcf-mcp-auth.php 3 weeks ago class-avcf-mcp.php 2 days ago
class-avcf-diagnostic.php
131 lines
1 <?php
2 /**
3 * Diagnostic REST endpoint.
4 *
5 * Exposes GET /wp-json/atarim/v1/diagnostic for the Atarim backend to check
6 * whether this site meets MCP requirements (WordPress version, PHP version).
7 * Always returns HTTP 200 — the response body's "mcp_available" flag is
8 * how the dashboard knows the actual health state.
9 *
10 * Auth is the same X-Atarim-Token check used by the MCP endpoint, so the
11 * version info isn't world-readable. Unauthenticated requests get 401.
12 *
13 * Lives outside the MCP adapter conditional in the bootstrap so it works
14 * even on sites where MCP itself doesn't (which is the point — when MCP
15 * doesn't work, the diagnostic endpoint is how the dashboard finds out
16 * why).
17 *
18 * @package atarim-visual-collaboration
19 */
20
21 if ( ! defined('ABSPATH') ) {
22 exit;
23 }
24
25 class AVCF_Diagnostic {
26
27 /**
28 * Minimum required WordPress version. WP 6.9 ships the Abilities API
29 * which the MCP adapter requires.
30 */
31 const REQUIRED_WP = '6.9';
32
33 /**
34 * Minimum required PHP version. WordPress core's floor is 7.4 but the
35 * MCP adapter uses PHP 8.0 syntax (typed properties, constructor promotion),
36 * so 8.0 is the effective floor for MCP-enabled sites.
37 */
38 const REQUIRED_PHP = '8.0';
39
40 /**
41 * @var AVCF_MCP_Auth
42 */
43 private $auth;
44
45 /**
46 * @var AVCF_Functions
47 */
48 private $function;
49
50 public function __construct() {
51 $this->auth = new AVCF_MCP_Auth();
52 $this->function = new AVCF_Functions();
53 add_action( 'rest_api_init', [ $this, 'register_routes' ] );
54 }
55
56 public function register_routes() {
57 register_rest_route(
58 'atarim/v1',
59 '/diagnostic',
60 [
61 'methods' => 'GET',
62 'callback' => [ $this, 'handle_diagnostic' ],
63 'permission_callback' => [ $this, 'check_permission' ],
64 ]
65 );
66 }
67
68 /**
69 * Gate the diagnostic endpoint behind the same X-Atarim-Token check
70 * as the MCP endpoint. Returning detailed environment info without auth
71 * would help attackers (knowing WP 6.3.1 narrows their CVE search).
72 */
73 public function check_permission() {
74 if ( ! $this->auth->avcf_mcp_validate_request() ) {
75 return new WP_Error(
76 'avcf_diagnostic_unauthorized',
77 'Your token is invalid. Reactivate the site to set a valid token.',
78 [ 'status' => 401 ]
79 );
80 }
81 return true;
82 }
83
84 /**
85 * Return the diagnostic payload.
86 *
87 * Always HTTP 200 — the request itself succeeded. The "mcp_available"
88 * boolean in the body indicates whether MCP can actually be used. Same
89 * pattern as a typical /health endpoint.
90 */
91 public function handle_diagnostic() {
92 $wp_actual = (string) get_bloginfo( 'version' );
93 $php_actual = PHP_VERSION;
94
95 $wp_met = version_compare( $wp_actual, self::REQUIRED_WP, '>=' );
96 $php_met = version_compare( $php_actual, self::REQUIRED_PHP, '>=' );
97
98 $plugin_version = '';
99 if ( defined( 'AVCF_PLUGIN_BASE' ) ) {
100 if ( ! function_exists( 'get_plugin_data' ) ) {
101 require_once ABSPATH . 'wp-admin/includes/plugin.php';
102 }
103 $plugin_file = WP_PLUGIN_DIR . '/' . AVCF_PLUGIN_BASE;
104 if ( file_exists( $plugin_file ) ) {
105 $data = get_plugin_data( $plugin_file, false, false );
106 $plugin_version = isset( $data['Version'] ) ? (string) $data['Version'] : '';
107 }
108 }
109
110 $response = [
111 'mcp_available' => ( $wp_met && $php_met ),
112 'requirements' => [
113 'wordpress' => [
114 'required' => self::REQUIRED_WP,
115 'actual' => $wp_actual,
116 'met' => $wp_met,
117 ],
118 'php' => [
119 'required' => self::REQUIRED_PHP,
120 'actual' => $php_actual,
121 'met' => $php_met,
122 ],
123 ],
124 'plugin_version' => $plugin_version,
125 'site_url' => get_site_url(),
126 ];
127
128 return new WP_REST_Response( $response, 200 );
129 }
130 }
131