Skip to content

Operations

xNetVN Development edited this page Nov 12, 2026 · 1 revision

Operations

This page covers deployment, packaging, cache expectations, retention, multisite behavior, backup and the signals worth monitoring. Sources: readme.txt, docs/en/DEPLOYMENT.md, docs/en/operations.md, docs/en/operations/backup-restore.md and bin/*.sh.

Deployment model

The product is a single WordPress plugin with no vendor service, no license server and no telemetry. Keys, audit rows, settings and the pepper stay in the site's own database (readme.txt).

Outbound traffic has exactly one product path: upload-media-from-url, and only when an administrator enables public HTTPS media downloads (off by default) and a key calls it. It never fires on installation, activation, cron or an admin page load. The destination is the client-supplied URL, not a fixed provider (readme.txt, "External services").

The plugin implements no update check of its own: a source search finds no update hooks. Any update check is WordPress core's normal behavior for a plugin distributed through WordPress.org, and this repository neither contains nor evidences that request.

Deployment fact Value
Minimum PHP / WordPress 8.2 / 6.9 (xnetvn-agent-hub-wp.php)
Required companion Official MCP Adapter >=0.7.0 <0.8.0, active (src/Bootstrap/Requirements.php)
Activation without adapter Allowed; MCP stays disabled with an admin notice
Unsupported adapter Plugin stays loadable, MCP boot closed

Release ZIP contents

composer build runs packaging regressions, then bin/build-zip.sh. The builder copies an allowlist into a staging directory, installs production-only Composer dependencies there, removes the lock file from the staging copy only, archives as dist/xnetvn-agent-hub-wp-<version>.zip, and verifies the result.

Included Excluded (examples)
xnetvn-agent-hub-wp.php, readme.txt, LICENSE, uninstall.php, index.php tests/, docs/, bin/, infra/, node_modules/
src/, languages/, assets/ composer.lock, package.json, package-lock.json
composer.json and production vendor/ phpunit*, phpcs*, phpstan*, compose*.yaml, Markdown files, dotfiles, lab overrides, .distignore

bin/verify-zip.sh requires vendor/autoload.php, src/Bootstrap/Loader.php, assets/admin.js and languages/xnetvn-agent-hub-wp.pot, rejects excluded paths and refuses archive traversal. To check the actual package, infra/remote/check-package.sh activates it in separate CLI-only tables inside the lab and runs Plugin Check (docs/en/development.md).

Do not ship a ZIP built from a dirty tree, and do not treat a structural pass as activation evidence.

Cache and rate-limit expectations

Rate limiting uses WpBucketStore:

Backend Mechanism Requirement
Persistent object cache present wp_cache_add / wp_cache_incr in group xnetvn_agent_hub_wp_rate, 180 s TTL Shared, atomic increments across PHP workers
No persistent cache Atomic SQL increment in non-autoloaded per-site options One authoritative database primary

Operational rules (docs/en/operations.md, docs/en/DEPLOYMENT.md):

  • Use noeviction and a unique cache prefix per site.
  • Do not enable a provider's "graceful" local-memory fallback: it can lose shared counters.
  • A total cache failure can abort WordPress before this plugin loads, producing a core 500 rather than the plugin's 503 unavailable response. Recover the backend first.
  • Flushing the cache removes ephemeral buckets, so infrastructure operations must stay outside delegated tools that could reset their own limits.
  • Key and audit writes, and MySQL named locks, need one primary for read-your-writes. Multi-primary and NDB clusters are unsupported unless session locking is guaranteed.

Audit retention

Audit rows are buffered and written as one bounded INSERT at shutdown. Retention defaults to 90 days (audit_retention_days) and runs daily on xnetvn_agent_hub_wp_purge_audit, deleting at most 1000 rows per pass and rescheduling a backlog event when more remain. The same pass removes expired rate buckets and notice markers; a storage failure dispatches xnetvn_agent_hub_wp_audit_unavailable instead of reporting a zero backlog (src/Audit/Retention.php).

Multisite

Settings, tables, pepper and rate buckets are per site. Identical key IDs and peppers on different sites stay independent because every table and option is prefixed per blog (docs/en/architecture/persistence.md).

  • Network-wide deactivation visits every site in bounded pages under switch_to_blog(), clears the plugin's four owned events, and restores the current blog in finally. Keys, audit rows and settings remain.
  • Uninstall checks each site's delete_data_on_uninstall; a site that preserves data keeps the shared per-user preferences alive (uninstall.php).
  • Super administrators keep default use and management, but an explicit site role matrix and corrupt policy still deny delegated use (docs/en/architecture/overview.md).
  • New sites get only their own tables; nothing is copied from another blog.

Backup and rollback

Back up these four stores together; a partial restore breaks authentication:

Store Why
{prefix}xnetvn_agent_hub_wp_keys Key metadata and HMAC hashes
{prefix}xnetvn_agent_hub_wp_audit Activity history
xnetvn_agent_hub_wp_pepper Critical. Losing it invalidates every existing key
xnetvn_agent_hub_wp_settings, xnetvn_agent_hub_wp_db_version Site policy and migration state

Rollback: enable maintenance mode, restore the previous plugin directory, run wp cache flush, then disable maintenance mode (docs/en/DEPLOYMENT.md). Deleting the pepper option and reloading generates a fresh pepper and immediately invalidates all keys — the correct emergency move after a database leak, never a routine operation (docs/en/guides/operation-guide.md).

Monitoring signals

The plugin exposes hooks rather than a metrics endpoint. Watch these:

Signal Source Meaning
auth_failed rows and xnetvn_agent_hub_wp_auth_failed Audit table, hook Missing, malformed, revoked, expired or unknown keys; carries a fixed reason and validated peer IP only
rate_limited rows, HTTP 429 with Retry-After Audit table, src/Auth/Authenticator.php Per-IP failed-auth or per-key budget exhausted
denied rows Audit table Policy or capability refusal at call time
HTTP 401 with WWW-Authenticate REST response headers Credential missing or rejected
xnetvn_agent_hub_wp_audit_unavailable Hook Audit storage failing; treat as a data-loss risk
xnetvn_agent_hub_wp_rotation_incomplete Hook Key rotation did not commit cleanly; reconcile before retrying
Audit table growth Database Retention cron not completing

docs/en/guides/monitoring-guide.md publishes indicative thresholds (for example 401 below 1%, 429 below 0.1%, audit table below one million rows). Those are guidance, not measured capacity; do not read them as a service-level guarantee. Confirm the cron event exists with wp cron event list and keep DISABLE_WP_CRON in mind before relying on retention.

Uninstall and deactivation are different operations: deactivation keeps all data; uninstall deletes owned tables and prefixed options by default. Test uninstall only on disposable sites (docs/en/development.md). See Release-and-Versioning for how a package is produced and Testing for how it is checked.

Clone this wiki locally