| 开发者 | benkalsky |
|---|---|
| 更新时间 | 2026年9月18日 06:17 |
| PHP版本: | 7.4 及以上 |
| WordPress版本: | 7.1 |
| 版权: | GPLv2 or later |
| 版权网址: | 版权信息 |
manage_options / update_*). Only authorized administrators can trigger actions.X-Aura-Token header. Only a SHA-256 hash is stored (never the raw token), compared timing-safely. Tokens from older versions migrate to a hash automatically./wp-json/aura/v1/:
GET /status — Full site health reportGET /updates — Check available updates (core, plugins, themes, translations)POST /update/core / /update/plugin / /update/theme / /update/translations — Apply updatesPOST /update/database — Run WordPress database upgradesPOST /connect — Magic-link token exchange (public, HMAC-signed, 10-minute expiry)/wp-json/aura/v2/:
GET /health — HTTP, PHP fatal, white-screen and DB connectivity checksPOST /update/batch — Chunked batch updates with auto-rollback on health failurePOST /rollback/{plugin} — Restore a plugin from its most recent backupPOST /rules — Receive Aura's signed operator ruleset; carrying unbind: true it ends this site's binding instead403 aura_site_unbound and reads keep working; the disconnect answer carries
cleanup_complete and leftovers (what the site still holds), and GET /status
reports unbound until the site is reconnected or the remaining Aura data is removed
from the settings screen.
MCP tools under /wp-json/aura/mcp/:
POST /tools/list / POST /tools/execute — Enumerate and run AI-agent toolsGET /context — Full site context for AI decision-makingget_site_context — WordPress/PHP/theme/plugin/disk/performance snapshot with detected issuesget_database_info — Database size, largest tables, autoloaded-options weight, expired transientsscan_security — Scored security posture (file-edit lockdown, debug exposure, SSL, default admin/prefix, open registration, PHP version)scan_seo — SEO posture (search-engine visibility, permalinks, XML sitemap, site title) plus a sampled content audit (thin content, missing excerpts/featured images)scan_a11y — Accessibility audit over sampled content (images missing alt text, non-descriptive link text, heading structure, document language)perf_check — Performance posture (persistent object cache, OPcache, page-cache plugin, PHP version, autoload weight, active plugin count, memory limit)scan_broken_links — Link triage over a content sample with no outbound HTTP (empty/anchor-only links, dev/staging hosts, unresolved internal links)list_users — Users with roles and post counts, administrators flagged (never returns secrets)check_health — Live health gate: HTTP status, PHP fatals, white-screen, database connectivityscan_error_log — Tails and severity-groups the error log, surfacing recent fatalscheck_vulnerabilities — Plugin update-currency check against WordPress.org (a version check, not a vulnerability/CVE feed; covers wp.org-hosted plugins)check_core_checksums — Core-file integrity against the official WordPress.org checksum manifest (modified/missing/unexpected files, fetched over HTTPS only)scan_executable_files — Uploads-directory observations: PHP/executable files, .htaccess overrides, and symlinks (reported, never followed)audit_admin_accounts — Privileged-account facts: administrators with recency, admin capabilities outside the role, application-password counts, multisite super adminsaudit_cron — Bounded WP-Cron inventory with sub-60-second-schedule and unresolved-callback fact-flagsaudit_mcp_exposure — Which other MCP servers are registered on this site, and how many abilities pass the discovery rule such a server applies (abilities are registered site-wide, not per-plugin, so a server resolving targets from that registry picks up mutating ones outside SiteAgent's approval path). The counts describe the abilities, not what any server currently serves. Reports only; changes nothingaudit_agent_code — Executable code an AI agent authored or can author on this site: Angie code snippets (recorded, agent-authored, live per environment), the SiteAgent Power Pack's execute-php / file-write / wp-cli flags, and third-party exec stores. Counts and presence only; never file contents, never a verdict. Reports only; changes nothingaudit_rules — Whether a signed operator ruleset is present and how old it is, 24h block/warn counts, expired-but-listed rules, and the enforcement points in this build. Reports only; changes nothingget_seo_meta — Read a post/page's SEO title, description, and focus keyword from the active SEO plugin (Rank Math, Yoast, or SEOPress)list_page_blocks — Read a page's Gutenberg block structure (block names, attributes, nesting)snapshot_get — Retrieve a stored snapshot of page content (reversible write metadata)elementor_replay_ability — Executes an approved held Elementor write (destructive, requires Aura approval): claims the hold, re-judges it against the current ruleset, and runs the original Elementor mutation as the user who askedupdate_plugin_safely — Backup, update, health-check, auto-rollback on failureclear_caches — Flush object/opcode caches and detected page-cache pluginscleanup_transients — Remove expired transients to reduce autoload bloatcleanup_orphaned_assets — Find and remove unused media (dry-run by default)backup_plugins — Zip-snapshot one or all active plugins as a rollback safety netset_seo_meta — Write a post/page's SEO title / description / focus keyword on the active SEO plugin (Rank Math, Yoast, or SEOPress) — on-site, so it works even when a WAF blocks the plugin's own REST endpointupdate_page_block — Update a Gutenberg block's content or attributes (snapshot-first, reversible)create_page_from_blocks — Create a new page from a Gutenberg block spec (draft-first)read_file — read a text file from inside wp-content (jailed; refuses wp-config.php).db_query — a single read-only SQL statement (SELECT / SHOW / EXPLAIN), row-capped.write_file — write a file inside wp-content, snapshot-first so it can be rolled back.run_wp_cli — run an allowlisted WP-CLI command, with no shell and no metacharacters.execute_php — run a PHP snippet against the full WordPress API.wp-config.php for each one. Installing the Power Pack alone enables no writes and no code execution.execute_php is powerful by design. The controls are the constant you set, the human who approves the call, and the audit trail — not a promise that arbitrary code is safe.
Learn more at my-aura.app/siteagent.
About Aura
Aura is a full-stack operations dashboard by Digitizer that brings servers, applications, DNS zones, and CDN pull zones from Cloudways, Hostinger VPS, Cloudflare, and Bunny.net into a single unified interface.
SiteAgent extends that reach into every WordPress installation — so you can manage your entire infrastructure, including WordPress sites, from one place.
Free to Use
The plugin is completely free and open source (GPLv2+). You need a free or paid Aura account to connect your sites. Sign up at my-aura.app.
Links
wp plugin install digitizer-site-worker --activate
Manual Upload
Yes, you need an Aura account to connect your WordPress sites. Aura offers a free tier that includes up to 3 WordPress sites. Sign up at my-aura.app.
Yes. The plugin uses defence-in-depth: WordPress Application Passwords (the same standard mechanism used by the block editor), a per-site token stored only as a SHA-256 hash and verified timing-safely, per-IP brute-force throttling, an HMAC-signed onboarding handshake, and an optional IP/domain allowlist. No data is transmitted unless a request is made by your Aura instance.
SiteAgent can require a per-action, cryptographically signed approval before it runs a state-changing MCP tool (cleanups, cache flushes, SEO writes, safe plugin updates run through the tool interface). Once enabled, each such write must carry a single-use signature that only the Aura dashboard can mint, after a human approves the action — so a leaked Site Token cannot run those tools on its own. This gate turns on automatically once the site holds Aura's approval key, which is provisioned securely during connection. If you installed or updated the plugin but have not reconnected the site since, the gate is dormant and the site runs in the standard token-only mode. To activate it, simply reconnect the site from your Aura dashboard — no reinstall is needed. Note: the approval gate currently covers the MCP tool path. Core, plugin, and theme updates performed over the plugin's direct REST update endpoints are still authorized by the Site Token alone (the standard site-management model), so treat the Site Token as a sensitive credential regardless. Grant coverage for those update endpoints is on the roadmap.
No. The plugin registers only REST API endpoints. It does not load any code, scripts, or database queries on frontend page loads. Your visitors experience zero impact.
WordPress 6.2 or higher is required. This is needed for full Application Password support. The plugin has been tested up to WordPress 7.1.
PHP 7.4 or higher. PHP 8.0+ is recommended.
Yes. The plugin supports an optional IP whitelist. If configured, only requests from the specified IP addresses will be accepted. Cloudflare and reverse proxy headers (CF-Connecting-IP, X-Forwarded-For, X-Real-IP) are fully supported for IP detection.
The plugin is designed for single WordPress installations. Multisite support is not currently available but is on the roadmap.
Only a SHA-256 hash of the Site Token is stored, in the WordPress option aura_worker_site_token — the raw token is never persisted. It is generated on first activation and shown once so you can copy it; the Aura dashboard keeps the only raw copy. Tokens created by older versions are upgraded to a hash automatically on first use.
Yes. Use Regenerate Token on the Settings → SiteAgent page. The new token is shown once. Regenerating invalidates the old token and disconnects the site from Aura until you reconnect with the new one.
Remove the site from your Aura dashboard, or deactivate or delete the plugin. If you deactivate the plugin, the REST API endpoints are unregistered and Aura can no longer communicate with the site. Since 2.13.0, disconnecting from the Aura dashboard happens in two phases. The site is marked disconnected immediately and refuses every change from that moment on — reads keep working — and Aura then has it revoke the Application Password it minted, clear the stored ruleset and gateway key, and finally delete the site token. If the site was mid-disconnect when it lost contact, it finishes the job by itself on its next page load.
Open Settings → SiteAgent. A disconnected site says so ("Disconnected by Aura at …") and offers Remove remaining Aura data, which revokes what is left and clears the disconnect record — but only once everything it names, the site token included, is proven gone. If it tells you it cannot say which user holds an Application Password, revoke it under Users → Profile → Application Passwords and try again. Reconnecting the site to Aura also clears the record, after settling what the previous connection still owed.
No. Aura uses WordPress Application Passwords, not your main admin password. Application Passwords are scoped specifically for REST API access and can be revoked at any time from Users → Your Profile in wp-admin.
Yes. SiteAgent is open source under the GPLv2 or later license. The source code is available on GitHub.
https://hooks.zapier.com\hooks\catch\1/…, also percent- or HTML-encoded) is redacted whole, including the part after the first backslash that earlier releases left in place.hooks.zapier.com and hooks。zapier.com are redacted like hooks.zapier.com.a@b@host, an encoded slash or backslash inside it) and an empty port (host:/) are read as the parser reads them in the backslash and encoded forms above; a plain https://host:/path with nothing encoded is still matched by the older rule that wants a port digit (tracked as #121).file: URLs./, : or @ are percent-encoded or HTML-escaped, including numeric character references left without a trailing semicolon. Before this, an encoded Make, Zapier, Slack, Discord, IFTTT or Telegram hook URL could reach an agent unredacted.payload: null, payload_redacted: true instead.aura-redacted:v1:<kind>, including inside Elementor page data and snapshot payloads. People in wp-admin, public visitors and Aura's own system calls see the real values.aura_redacted_placeholder): leave that field out and the stored value is kept.aura_unredacted_grant_invalid when it does not verify).audit_rules reports redacted_24h and placeholder_refused_24h; /status reports redaction..php files (WP Engine is the proven case), every Aura-driven plugin change — the self-update, a single or batch plugin update, update_plugin_safely — is refused before anything is touched, with code: aura_php_writes_blocked (or aura_upgrade_dir_unwritable when wp-content/upgrade cannot be written at all). Such a host failed every update at unpack, and the restore that followed deleted the plugin's non-PHP files: SiteAgent's own readme.txt, and a plugin's CSS, JS and images. The check creates and removes a temporary file, and runs only when WordPress writes files directly..php files in the plugins directory, and every directory of the plugin is writable — before it deletes anything; otherwise it answers stage: preflight and leaves the directory untouched. A failed install that changed no file is no longer restored at all (restore_skipped: unchanged)./status reports the host's last recorded answer as host: { php_writes, checked_at }, so Aura can stop sending updates to such a site.update_plugin_safely returns the refusal's code and message (it lost both before).readme.txt on every run. The refusal answers code: aura_self_update_same_version. An archive that cannot be read falls through to the previous path.aura_self_update_not_replaced); without that proof both causes are named (aura_self_update_version_unchanged).clear or extract), and the message says what is on disk. A failed clear can remove some files before it stops, so the directory is no longer described as untouched.overwrite_file() record now stores the sha256 of the content it wrote (replaced_with_sha256), and restoring that record puts the old bytes back ONLY while the file still holds exactly what the write left there. A file edited since is refused untouched (aura_file_changed_since); a file already holding the old bytes answers already and is not rewritten; a record taken without that hash — a direct POST /aura/v2/snapshot, or a Power Pack older than 0.2.5 — is refused as unfenced (aura_snapshot_unfenced), because nothing proves what it would be writing over.write_seq, taken under that path's lock and strictly increasing per target, so two writes to one file can be ordered after the fact — Aura rolls a run back in that order.aura_file_changed_since, aura_snapshot_unfenced, aura_snapshot_voided (the create's rollback record is gone) and aura_path_locked (another write to the path is in progress) — each answered as an HTTP 409 refusal rather than a 500. Restoring a created file that is already gone answers already.create_file(), the new overwrite_file(), and the restore of a created file — runs under a per-path lock, so two agent writes racing one new file can no longer interleave in the same inode (a concurrent in-place overwrite passed the inode check). After a publish the target must hash to the recorded content, else the record is voided as interrupted and the staged bytes kept.overwrite_file() replaces an existing file the way the engine creates one — old bytes snapshotted, new content staged beside the target with its own mode, then renamed over it: a reader sees the old file or the new, never a truncated one, and a short write touches nothing. The Power Pack's write_file adopts it in 0.2.5.flock() the record and path locks are mkdir() directories (atomic everywhere; a lock older than five minutes is a crashed holder and is broken) instead of running unlocked, which let a stage sweep retire the record of a publish that then completed.link(), an executable created file that was edited since is verified in place and left where it is on file_changed_since — the claim by rename came first and the put-back refused exec bits, stranding the edited file under its .aura-restore-* name.delete() removes the record's lock file with the record.create_file() publishes without link(). Most managed hosts put link() in disable_functions for web PHP (Cloudways does), and 2.17.0 refused every new-file create there (unsupported_filesystem). Without link() the target is now claimed with an exclusive create — it refuses an existing path and returns an inode this call owns — and the bytes are written into that handle; ownership is checked by inode after the write, so nothing that took the path meanwhile is ever overwritten. What this mode gives up is the empty-to-complete jump: a reader in the milliseconds of the write can see the file grow. A short write leaves the entry empty, never truncated content. Restoring a created file that was edited since puts it back the same way instead of leaving it aside under its .aura-restore-* name. A publish interrupted mid-write is reconciled by the stage sweep: the record is voided and marked interrupted, the file is never deleted by a restore. create_file() answers published: link | write.audit_agent_code: power_pack.create_publish says how a create lands on this host (link or write).audit_agent_code: executable code an AI agent authored or can author on this site — Angie code snippets (recorded, agent-authored, and which are live in the environment the loader includes, correlated per snippet directory in both environments), the SiteAgent Power Pack's execute-php / file-write / wp-cli flags, and third-party exec stores (EMCP Pro sandbox, Atarim exec abilities). Counts and presence only; never file contents, never a verdict. Bounded (200 directory entries per environment, coverage.truncated), null for anything unreadable, { error } per subtree.create_file() creates a NEW file with the engine owning the whole create — staged beside the target under a non-PHP name, recorded, then published with link() (atomic, no-clobber) — so no target ever exists without its record and no partial content is ever visible. Restoring the record claims the path with an atomic rename, verifies the claimed file, and removes it only while its bytes still match; a file edited since is put back and refused (file_changed_since), never deleted. The Power Pack's write_file adopts it in 0.2.4.{} rather than [] (SA#83).aura_self_update_multisite_unsupported: the update lock is per site while the plugin directory is shared (SA#79). Other plugins are unaffected.sites, or release it./status's door fragment carries observation, a per-site door-version witness bumped atomically by every door-state mutation (never by a mere poll) and clock-floored so a restored backup can never reissue a value it already served, so Aura can order overlapping polls by the site's own witness instead of request timestamps; elementor.governor reports the current value. The observation witness requires InnoDB for wp_options and 64-bit PHP; without them ordering falls back to Aura's own request order for that site (elementor.governor reports why via observation_unsupported: engine or php32)./status also accepts door_observation_seen — Aura's own last accepted observation, echoed back — so the site can bump its witness forward, clock-floored, when a restore rewound its own copy behind Aura's. Accepted for ANY non-negative integer the site's own witness could ever report (no magnitude ceiling — the witness only counts up); honoured only within a fixed headroom below the class ceiling, silently ignored (200, no bump, no error) above it.elementor.governor reports counters_as_of beside the four _30d rolling counters, which observation does not cover; the counters themselves are int|null.interrupted / running / held are null, not [], when their own queue could not be read, and observation is withheld entirely whenever any read behind the fragment was unreadable.door_write_unsupported reason reconnect_guard_unavailable: a governed write refuses outright on a $wpdb replacement that cannot disable reconnects, rather than risk a mutation replaying on a session this plugin no longer controls.committed tri-state (true / false / unknown) and answer a retryable 503 with may_have_run: true whenever a commit cannot be proven — claims, holds, acks, and rotations alike; replay() now forwards claim()'s own error instead of a generic one./status door fragment and audit_mcp_exposure's elementor.governor carry binding, the site's current binding generation, so Aura can label a departed client's door-log entries without inferring the generation from the rows.allow rule covers it; block refuses; every write that runs is snapshotted first on the site and recorded in a per-site door log Aura drains. New tools elementor_replay_ability, snapshot_get; new routes /aura/v1/door/reject, /aura/v1/door/ack; /status carries door; audit_mcp_exposure carries elementor.governor. Rules gain the allow effect and the design_system / page_create targets.elementor block: Elementor >= 4.3's official MCP module state, every elementor_mcp_consent row, every Elementor MCP… Application Password across all users (full detail), and the other Application Passwords of edit_posts users as counts. Every list is bounded (50 / 50 / 200) with a truncation flag beside it; no usermeta value over 256 KB is decoded; a scan that fails is reported as { error } in its place, never as an empty list. Read-only.backed_up: false so the caller knows this one had no way back. After
installing, SiteAgent asks the new build to prove it came up. The proof is
written by the build itself: a boot beacon recorded the first time the new
code serves a request, and a fatal beacon recorded by
a shutdown guard when the new code dies while loading. A build whose own
records say it broke is rolled back to the archived one, and compiled
copies are asked out of the opcode cache (best-effort — a host that
restricts opcache_invalidate() may serve the old compiled code until its
cache revalidates). The result reports exactly what happened (backed_up,
verified, rolled_back). When neither record appears, the update stands
and says it was not verified, never guessed.403 aura_site_unbound until the site is reconnected. Reads
keep working, /status keeps answering, and Aura's own ruleset endpoint
stays reachable so the disconnect can be finished or retried.leftovers lists the credentials or stores this site could not prove it had
released (app_passwords, options, ruleset, grant_pubkey), alongside
cleanup_complete. An empty list means only the shared site token was still
outstanding; a non-empty one means Aura must keep waiting.{ "unbind": true, … } body on POST /wp-json/aura/v2/rules, authenticated
by the site token alone. A site that DOES hold a gateway key refuses the
bare form and requires the signed envelope.503 aura_site_busy, which is
retryable. A claim left behind by a killed request is taken over after two
minutes rather than blocking the site indefinitely./status reports unbound: { at, site_ref } while a
disconnect is outstanding, and app_password_probe_unproven: { count, at, owner } when the site cannot prove an Application Password was
revoked — the usual reason a disconnect never finishes. Both are bounded and
contain no secrets.aura_site_unbound (403 — the site is disconnected),
aura_site_busy (503 — retry), aura_unbind_incomplete (409 — something is
still owed; the answer lists it), aura_unbind_unreadable (409 — the
disconnect record could not be read, which is NOT the same as an incomplete
cleanup), aura_unbind_unrepairable (409), aura_unbind_marker_stuck
(500 — everything was removed but the record itself would not delete),
aura_unbind_marker_malformed (500), aura_unbind_store_failed (500) and
aura_ruleset_client_mismatch (409 — a disconnect addressed to a different
Aura client), which the bare unkeyed form now checks too.