Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</a>
<img src="https://img.shields.io/badge/WordPress-6.2%E2%80%937.1-21759b?logo=wordpress" alt="WordPress" />
<img src="https://img.shields.io/badge/PHP-7.4%2B-777bb4?logo=php" alt="PHP" />
<img src="https://img.shields.io/badge/Stable-2.21.0-green" alt="Stable" />
<img src="https://img.shields.io/badge/Stable-2.22.0-green" alt="Stable" />
</p>

---
Expand Down Expand Up @@ -239,6 +239,12 @@ These plug straight into **Aura's Fleet MCP Gateway**: read tools run on demand,

## Changelog

### 2.22.0

- **An install ledger** (Digitizers/Aura spec 2026-09-21 §4, P6.3 phase 2). New `Aura_Worker_Install_Ledger` observes the upgrader for plugin and theme runs only — a per-run token in `hook_extra`, `upgrader_pre_download` at `PHP_INT_MAX`, the entry at `upgrader_install_package_result` — and records and never decides. Each entry: when, type, action, slug, version (the main file), transport (`siteagent` for SiteAgent's own upgrader object, `wp_cli`, `auto_update` only inside core's `wp_maybe_auto_update` — never the upgrader skin, `cron`, `rest`, `wp_admin`), user id, auth, the application password's name (never its uuid), REST route, and the package source (`wporg`, `uploaded_zip`, `remote_host` + host, `local_path`, `unknown`). (#139)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Capture ledger context before WordPress downloads

The advertised source and siteagent transport classification cannot work with these hooks: WP_Upgrader::run() invokes download_package() (and therefore upgrader_pre_download) before install_package() applies upgrader_package_options. Consequently, the token added by on_package_options() is never present when on_pre_download() checks it, no frame is created, and on_install_result() always falls back to context(false) plus source: unknown (class-aura-worker-install-ledger.php:527-529,574-580,641-665). This makes SiteAgent-driven installs indistinguishable from their ambient request transport and discards the package source for every normal upgrade, undermining the grading this release claims to enable; correlate the pre-download observation without relying on a token added later in the upgrader flow.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Not the order in core. WordPress 7.1.2 wp-admin/includes/class-wp-upgrader.php, WP_Upgrader::run(): line 818 $options = apply_filters( 'upgrader_package_options', $options ); → line 849 $download = $this->download_package( $options['package'], false, $options['hook_extra'] ); (which applies upgrader_pre_download at line 322 with that same $hook_extra) → line 898 install_package → line 917 apply_filters( 'upgrader_install_package_result', $result, $options['hook_extra'] ). The token added at 818 is therefore present at pre-download and at the result, which is what the ledger relies on (spec §4.1, read from core). The staging field check before promotion exercises this on a real install.

- **Storage that only under-claims.** A ring of 200 entries / 90 days in two non-autoloaded options (network options on multisite), purged physically on read and daily (`wp_scheduled_delete`); every stored row is validated; unreadable storage answers `ledger_unreadable` and is recovered behind a coverage boundary; writes are ordered and read back so an interruption can only shorten `since`. Reactivation restarts coverage; a network where SiteAgent is not network-active answers `ledger_partial_network`. (#139)
- **`audit_agent_code` reports it as `installs`** — `{ since, entries, total, evicted }` — consumed by Aura's `agent_installed_package` grading. Uninstall removes the network rows. `user_id`, the password name and the route are personal data kept by owner decision, bounded as above — while the plugin is active; a deactivated SiteAgent runs no purge, so its rows stay until the first purge after reactivation (the next audit read, install or daily `wp_scheduled_delete` pass — activation itself only restarts coverage) or uninstall. (#139)

### 2.21.0

- **The approval queue sees elementor-mcp writes' rule verdicts.** `tools/preview` answers a name its own registry does not know by asking elementor-mcp ≥ 1.38.0's `Elementor_MCP_Governance::declare_touches()` (Digitizers/Aura#586) — exactly the touches the fork's early rules gate judges — with `_mcpPath` removed, and returns `{success, supported: false, preview: null, touches, rule_match}`. Fail-closed: no fork, an older fork, a throw, a malformed answer or touch, or a declaration of nothing (a dry run) answer `Unknown tool` as before. (#137)
Expand Down
4 changes: 2 additions & 2 deletions digitizer-site-worker/digitizer-site-worker.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Plugin Name: SiteAgent for Aura
* Plugin URI: https://my-aura.app/siteagent
* Description: Remote site management agent for Aura dashboard. Enables secure updates, health monitoring, and maintenance operations via REST API.
* Version: 2.21.0
* Version: 2.22.0
* Requires at least: 6.2
* Requires PHP: 7.4
* Author: Digitizer
Expand All @@ -18,7 +18,7 @@
exit;
}

define( 'AURA_WORKER_VERSION', '2.21.0' );
define( 'AURA_WORKER_VERSION', '2.22.0' );
define( 'AURA_WORKER_FILE', __FILE__ );
define( 'AURA_WORKER_DIR', plugin_dir_path( __FILE__ ) );

Expand Down
9 changes: 8 additions & 1 deletion digitizer-site-worker/includes/class-aura-worker.php
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,14 @@ public function add_privacy_policy_content() {
}
wp_add_privacy_policy_content(
'SiteAgent',
wp_kses_post( wpautop( __( 'This site uses the SiteAgent plugin to enable remote management from the Aura dashboard (my-aura.app). When connected, the Aura dashboard may access site health information including WordPress version, PHP version, installed plugins and themes, and database metadata. No personal user data is collected or transmitted by this plugin.', 'digitizer-site-worker' ) ) )
wp_kses_post(
wpautop(
__( 'This site uses the SiteAgent plugin to enable remote management from the Aura dashboard (my-aura.app). When connected, the Aura dashboard may access site health information including WordPress version, PHP version, installed plugins and themes, and database metadata.', 'digitizer-site-worker' )
. "\n\n"
// Since 2.22.0 the install ledger keeps personal data (Aura spec 2026-09-21 §4.2).
. __( 'SiteAgent also keeps a record of each plugin and theme installation or update: when it happened, how it was made (for example the dashboard, the REST API or WP-CLI), the ID of the user who made it, the name of the application password used (never the password itself) and the REST route. This record is sent to the connected Aura dashboard as part of its security audit. While the plugin is active, records older than 90 days, or beyond the latest 200 installations, are deleted; all of them are deleted when the plugin is uninstalled.', 'digitizer-site-worker' )
)
)
);
}

Expand Down
6 changes: 5 additions & 1 deletion digitizer-site-worker/readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Tags: ai, automation, maintenance, updates, wordpress management
Requires at least: 6.2
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 2.21.0
Stable tag: 2.22.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Expand Down Expand Up @@ -253,6 +253,10 @@ Yes. SiteAgent is open source under the GPLv2 or later license. The source code

== Changelog ==

= 2.22.0 =
* New: an install ledger. Every plugin and theme install or update is recorded with how it arrived (wp-admin, REST, WP-CLI, cron, a WordPress auto-update, or SiteAgent itself), which user and application password, and where the package came from, so Aura can flag packages an AI agent installed. It only observes; it never blocks an install. Nothing to configure.
* Privacy: each record keeps the user ID, the application password's name (never the password) and the REST route. While the plugin is active, records older than 90 days (or beyond the latest 200 installs) are deleted; a deactivated plugin cannot delete anything, so they stay until its first cleanup after reactivation (the daily clean-up, an audit or the next install) or until it is uninstalled. Records are not autoloaded and are deleted when the plugin is uninstalled.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Update the generated privacy-policy disclosure

The release now explicitly stores user_id, Application Password names, and REST routes and exposes them through audit_agent_code, but Aura_Worker::add_privacy_policy_content() still tells site owners that “No personal user data is collected or transmitted by this plugin.” Sites that use WordPress's suggested policy text will therefore publish a false disclosure after upgrading to 2.22.0; update that generated privacy-policy content to describe the ledger data, its transmission to Aura, and its retention.

Useful? React with 👍 / 👎.


= 2.21.0 =
* The Aura approval queue now shows whether an operator rule would block or warn about an Elementor design change made through the elementor-mcp plugin (1.38.0 or later), before anyone approves it. Nothing runs when the queue asks. No new settings.

Expand Down
38 changes: 38 additions & 0 deletions tests/unit/PrivacyPolicyContentTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php
/**
* The suggested privacy-policy text names the install ledger's personal data
* (2.22.0, Aura spec 2026-09-21 §4.2) — never "no personal data".
*
* @package Aura_Worker\Tests
*/

use PHPUnit\Framework\TestCase;

if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) {
function wp_add_privacy_policy_content( $plugin_name, $policy_text ) {
$GLOBALS['_sa_privacy_policy'][ $plugin_name ] = $policy_text;
}
}
if ( ! function_exists( 'wpautop' ) ) {
function wpautop( $text ) {
return $text;
}
}
if ( ! function_exists( 'wp_kses_post' ) ) {
function wp_kses_post( $text ) {
return $text;
}
}

final class PrivacyPolicyContentTest extends TestCase {

public function test_the_policy_text_discloses_the_install_ledger(): void {
unset( $GLOBALS['_sa_privacy_policy'] );
( new Aura_Worker() )->add_privacy_policy_content();
$text = (string) ( $GLOBALS['_sa_privacy_policy']['SiteAgent'] ?? '' );
$this->assertStringNotContainsString( 'No personal user data', $text );
foreach ( array( 'ID of the user', 'application password', 'REST route', '90 days', 'uninstalled' ) as $needle ) {
$this->assertStringContainsString( $needle, $text );
}
}
}
Loading