Releases: CaptainCore/captaincore-manager
Release list
v1.1.1
The pairing release. Connecting a CaptainCore CLI server to the Manager is now one command in each direction at once: captaincore connect --server-url=... fetches the CLI token and registers the CLI server's address with the Manager in the same request, so a fresh install needs no wp-config.php constant. The release also carries the second security sweep that ran after 1.1.0 shipped: fourteen fixes, most of them closing checks that failed open or that one entry point applied and another skipped.
Added
- The CLI server address no longer has to live in wp-config.php.
captaincore connect --server-url=https://...on the CLI server registers the address with the Manager over the same administrator-authenticated request that hands the CLI its token, so one command pairs both directions. The value is stored in the global configurations, shown and editable under Settings, Branding, as "CLI server", and read through a newcaptaincore_cli_address()helper that every dispatch call and the websocket address now use. ACAPTAINCORE_CLI_ADDRESSconstant still wins when defined, so existing installs keep working unchanged; the Settings field says so when that is the case. Only an administrator-authenticated connect can change the address; a token-authenticated--synccannot redirect dispatch.
Security
- The brute-force throttle and the new-location step-up now apply to wp-login.php and XML-RPC, not only to the dashboard's login endpoint. A user without two-factor authentication could previously be signed in from anywhere, with unlimited attempts, by posting to wp-login.php. The location check runs after core verifies the password so it cannot be used to trigger verification mail for arbitrary usernames; application passwords are exempt by design.
- Minting an application password through the dashboard now honours WordPress's application-password availability settings and the
create_app_passwordcapability. Being logged in was the only requirement before, so disabling application passwords had no effect and a user could re-enable them for themselves in one request. - The legacy dashboard shell requires a login. It rendered for anyone who asked for
?ui=legacy, and although every data call gated itself, the boot payload handed an anonymous visitor the CLI dispatch address and the object-storage base URI. The invite, welcome and connect flows keep their logged-out shell with those values emptied. - Three fail-open gaps in the authorization core are closed: the Users model's constructor expressed its administrator check as a discarded return value and so listed every WordPress user's name, email, login and roles to any caller that reached it; an unrecognised account tier resolved to full access instead of none; and an account's provisioning template and outstanding invoices were emitted untiered.
- Report and scheduled-report handlers fail closed when
site_idsis not an array. A string slipped past a hand-rolled ownership loop and could resolve another account's billing contact. Reading that address now also respects the account plan tier, matching the account view. - Scheduling an account-wide report respects the sites and timeline tiers, so a domains-only or sites-only member can no longer receive on a schedule what their tier withholds.
- Saving account site defaults checks recipe access before storing recipe ids. It was the one of three recipe-running doors without the check, and it let another user's private recipe run on a host the caller picked. All three doors now share one permission helper.
- Request values can no longer occupy argument positions on CLI commands. A body or query field of the same name outranked the URL segment, and where the value reached a legacy command string the dispatch server re-tokenized it into extra arguments on a fleet-privileged process. Backups, backup retrieval, log archive and the Mailgun deploy command move to the argv form the CLI server executes verbatim; quicksave hashes come from the URL only and must start alphanumeric; recipe ids are cast to integers before the ownership check rather than after.
- New site creation verifies the customer account a site is linked to. It was the one ownership-bearing field on that request never checked, and because site invites honour that link, it chained into cross-tenant account membership. Inviting your own address into an account is rejected as well.
- Outbound TLS verification is no longer switched off by the debug constant on the component-inventory calls, the updater's package download, or configuration sync, which had relaxed verification globally for the rest of the request. The updater's info path now applies the same host and hash checks as its update path. A Kinsta provider row the caller may not use is refused outright instead of falling through to the house API key.
- Values that reach a permission decision or a regular expression are validated: an account's billing user must be a member of that account; the login endpoint compares its command strictly so a JSON
trueno longer matches every branch; provider slugs are whitelisted on create as they already were on update; and version filters are escaped as regex literals, which also stops a version like 6.76 matching 6x76. - Customer-set values are escaped before they become markup in staff notification email, in the configurations tab (a product title containing an apostrophe could end the attribute early), and in the DNS result banner.
- The bundled Parsedown is updated to 1.8.0 with safe mode on, so raw HTML in customer-supplied Markdown is escaped by the parser as well as by kses. The shipped API docs opt out explicitly.
- A permission helper that returned a count rather than a boolean, and so was true for a bare subscriber at eight endpoints, is renamed to say what it tests. Every endpoint turned out to be protected by per-row scoping, so there was no live gap, but the next caller would have inherited a false gate.
v1.1.0
The security and scale release. Two audits ran against this cycle: the sweep that followed 1.0.0, which went over every REST route and both authorization primitives, and a second pass over the release candidate that found site provisioning trusting fields it had accepted from the browser. Both are fixed here. Alongside that, the dashboard picked up the parts of the legacy interface it was still missing, from domain registrar and account assignment to per account site defaults and renewal estimates, and an account with a large footprint opens in under a second instead of a minute.
Added
- The account named in a site's header opens that account. It was plain text, so reaching the account meant going back to the Accounts list and finding it again.
- Mailgun sending can be set up on a subdomain other than mg. The setup row now takes the label, defaulted to mg, with the domain shown after it, and the line above follows what is typed. The legacy dashboard asked for this and the rebuild had fixed it to mg. It matters because Mailgun sending domains are unique across the whole platform, so when mg for a domain is already registered to an account we do not hold, another label is the way through.
- Operators can turn a site's uptime monitor on or off from the Environment card on the site page, as the legacy dashboard allowed. The change is administrator-only on the server as well, and is recorded on the site's activity log. The Uptime monitor and Managed updates rows are now shown to operators only.
- A Help & shortcuts guide: the question-mark button in the top bar (or "Help & shortcuts" in the command palette) explains what ⌘K searches, how the terminal dock works, where right-click menus live, and lists every keyboard shortcut. Commands now list ahead of sites and domains in palette results once you start typing.
- Fleet core-update probe/apply runs are stored as a parent run plus per-site rows (core versions before and after, stage, error class, triage status) so agents can group failures. Email stays a short recap.
- New site supports multiple Kinsta connections: agencies with their own Kinsta company can pick which provider a new site is created on, and the clone list only offers sites from that same connection (Kinsta cannot clone across companies).
- Pay invoices right on the invoice: open invoices now show a payment section listing your saved payment methods with the default preselected, a Pay button for the chosen method, a "Pay with a new card" option that saves the card and pays in one step, and a Remove action on each saved method.
- Per-account site defaults: each account now has a Site defaults tab where administrators and full-access members set the default email, timezone, recipes and users applied to that account's new sites. Lower access tiers can no longer write defaults through the API.
- Domain account assignment is back: operators can assign a domain to accounts or unassign one straight from the domain screen, matching the legacy Edit Domain dialog.
- Operators can set where a domain is registered from the Registrar tab: an Edit link on the Registrar row picks one of the registrar connections (Hover.com, Spaceship) or marks the domain as registered externally, completing the legacy Edit Domain dialog. The Domains list column and the domain header update immediately.
- Site filters can exclude a version: the Plugin chip's Version list has the same Is / Is not toggle as Status, and the Theme chip now opens the same Version and Status popover. The chip label shows the sub-filter, so a negated version reads as ≠ 4.2.3 at a glance.
- Filter sites, then target them in the console: whenever a filter narrows the Sites list, a "Console" chip appears beside Clear that opens the terminal dock preselected with every matching site's production environment, and a hand-checked selection gets the same via "Open in console" in the bulk actions bar. The target picker shows the selection and can refine it before running.
- The Users page has its own address (/account/users), so it can be bookmarked, shared, and reached directly, and browser back and forward work through it. User rows now show the person's Gravatar profile picture when they have one, falling back to the initials monogram when they do not.
- An account's Plan tab now previews what the next renewal will cost. A Next renewal estimate card shows the renewal date, the estimated total for the billing interval, and every line behind it: the base plan, extra sites, storage and visits priced from your usage pricing, addons, one-off charges and credits. This is the breakdown the legacy dashboard hid behind a "See breakdown" link.
- New site can find the nearest datacenter from the customer's location: a map-pin button beside the Datacenter dropdown opens a place search (type the customer's city or address), and picking a match ranks every datacenter by distance with the closest one selected automatically. Any row in the ranked list can be chosen instead.
- The new-post email sent to blog subscribers now carries a Reply-To of the WordPress admin email (Settings → General), so replies reach the inbox instead of the SMTP sending address.
- A domain's Sending tab now lists the Mailgun MX records alongside the SPF, DKIM and tracking records, so nothing a sending zone needs is missing from the verification table, and a Copy DNS records button hands you the whole set as plain text ready to paste into a ticket or send to a customer's DNS provider.
- The Registry tab now shows whether each component is actually running. Deactivated plugins and themes are grouped below the ones WordPress loads and dimmed, must-use plugins and parent themes are labelled, and a summary line reads the risk that matters: how many critical and high findings sit on code that loads, and how many more are on deactivated components. A deactivated component can be deleted straight from its right-click menu.
Fixed
- Setting up Mailgun sending for a domain no longer fails silently. The new dashboard discarded the server's reason, so the button appeared to do nothing. The reason is now shown in the panel, and it is a clearer one: a sending domain that already exists is first looked for in the connected Mailgun account and adopted if it is there, and only reported when the name is genuinely held by an account we do not have, which says that it has to be released there first.
- Opening an account with a large site and domain footprint took about a minute, and its timeline was wrong once it arrived. A process log that touched many of the account's sites was fetched once per site, and each repeat re-filtered that log's sites against the account with a linear scan, which on one account came to roughly 2.2 billion comparisons. Repeating a log also rewrote the same record, so its timestamp came back empty and it was drawn as several identical rows. Logs are now read once each and the filter is a keyed lookup, taking that account from 42 seconds to well under a second with every site still listed on its entry.
- Opening the address of a site that has been deleted, or that your account cannot see, now shows a clear "This site is no longer here" page instead of another site's header with cards stuck on Loading.
- Requesting a site's removal no longer reports "Could not update the removal request" when it in fact succeeded. The server answered with an empty body, which the dashboard read as a failure. It now returns a proper result and the dashboard also tolerates empty replies.
- Every confirmation in the dashboard now uses its own dialog instead of the browser's alert box: deleting domains, DNS zones, environments, files, plugins, users and payment methods, revoking passwords, running tools, sending reports, transferring ownership, and more. Destructive actions get a red button named for the action; everything else stays blue. Request site deletion also lists each environment (Production, Staging) with its address so it is clear what the request covers.
- A new site provisioned at Kinsta, or a staging environment created or linked there, now reliably reaches the CaptainCore CLI. The hand-off was a single request with nothing behind it, so a busy or restarting core server left the CLI unaware of the new environment (Sync data then failed with "site-staging not found"). The provisioning chain now retries the push until the CLI accepts it, linking is idempotent (a retry can no longer add a duplicate Staging row), the environment list cache refreshes at the same moment, Sync data re-pushes any environment added in the last day before it runs, and the new UI kicks off the first staging Sync data as soon as the environment is ready, as the legacy UI did.
- New sites created on Kinsta by customers link into the dashboard again: a permission check introduced this cycle rejected the shared hosting connection for non-administrators, leaving the site orphaned at Kinsta, and the provisioning chain now retries and reports linking failures instead of discarding them.
- The legacy dashboard's light mode no longer paints the page, the top bar and every site header bar in the brand blue. Those surfaces now use the same near-white canvas as the new dashboard, with their text darkened to match, so the two do not clash when you switch between them. Dark mode is unchanged.
- A payment method can always be removed, including the primary one and a card that is the only method on file.
- Adding a domain works for customers again: the New domain dialog now asks which website the domain belongs to (required by the API) and reports errors instead of failing silently.
- Cloning a site no longer reports "Permission denied for the clone source" when several site records share the same provider site id. Any record the caller can reach now satisfies the check.
- The New domain and New site dialogs no longer present a preview-data account name as the preselected account. When the dialog opens, an account that does not exist ...
v1.0.0
The interface release. CaptainCore Manager reaches 1.0 with a rebuilt /account experience: a fast, hand-maintained single-page interface (templates/core/) that replaces the original Vue dashboard as the default, while the legacy app remains one switch away. This cut also records the control-plane work since 0.18.0: hash-based security operations, session monitoring, new hosting and registrar providers, email forwarding, in-browser logs and a terminal, customer reports, and a proper GitHub Releases cycle with a signed update manifest and self-updater.
Added
- New core interface: a rebuilt fleet dashboard served at
/account, wearing the Minn Admin design system with light and dark themes, a command palette, and a terminal dock for multi-target runs, cookbook recipes, scheduled scripts, grouped sessions and cancel. - Self-updater: the plugin now checks a release manifest on GitHub and offers updates through the WordPress Plugins screen, verifying each download against the sha256 published in the manifest before install.
- Release tooling:
bin/build-zip.shbuilds the distributable zip with dev files excluded and prints the sha256 for the manifest stamp. - Automatic database migrations: pending schema upgrades now run on the first admin request after an update, so updating through the Plugins screen no longer requires a manual
DB::upgrade()step. - Security operations: hash-based plugin, theme and loose-file inventory across the fleet, threat tracking, and security patches, wired to WP Registry so one audit of a build covers every site running that exact code.
- Site audits: stored reports with findings for security, malware, performance, accessibility, debug and incident work, plus WP-CLI queues that rank unaudited components and updates-before-audit.
- Session monitoring: daily snapshots of admin accounts, sessions and injected capabilities, with delta-based anomaly alerts instead of repeating the same baseline every day.
- Google Web Risk checks against every production home URL, with a log of each fleet run.
- Integrity alerts when core or plugin checksums fail, malware is detected, visual captures change unexpectedly, or a site's default role is unsafe.
- Provider APIs for Spaceship (registrar), GridPane, Rocket.net, Cloudflare and Forward Email, plus Kinsta site create, clone, and import of existing sites from a connected provider.
- Email forwarding per domain through Forward Email, with Mailgun zone deploy, verification, usage and suppressions.
- DNS zone create, toggle and delete from the domain screen.
- In-browser server logs, including a gunzip proxy so archived logs can be read without downloading.
- File manager on each environment, locked to the site home directory, with image previews and delete.
- Performance Monitor charts per environment.
- Activity log of operator and customer actions across sites, domains and accounts.
- Scheduled customer reports covering updates, backups, visits and process logs.
- Branded transactional mailer for invoices, invites, password resets, plan requests and security alerts.
- ACH bank payments through Stripe, alongside cards.
- Location-aware login verification: GeoIP fingerprints and a trusted-login list, with email challenges for new locations.
- Site labels for operator notes that do not change lifecycle status (moved, DNS elsewhere, down, domain expiring).
- Application passwords on Profile, with a built-in API documentation viewer.
- WP-CLI commands for web-risk checks, scan/component/update queues, session alerts, scheduled reports, DNS, Mailgun, provider sync, site labels and restic cache.
Improved
- The sidebar brand lockup now offers two destinations: the anchor icon links to the site homepage while the company name returns to the dashboard's Home screen.
- The sites, domains, accounts, billing, security and users screens show shimmer placeholders while their data loads instead of an empty page.
- Checksum failure rows identify the exact environment: each row shows the environment's home URL and a Production or Staging chip instead of repeating the site name.
- Page sizes changed from 25/50/100/250 to 24/48/96/240 so the card grid always fills its rows evenly, whatever the window width.
Fixed
- Account invite emails work again: invite links now open the invite preview and accept flow instead of the new dashboard, which had no way to redeem them.
- The account Plan tab's "Request changes" button now opens a request dialog and actually delivers the request to operations. Previously it showed a confirmation without sending anything.
- Removed a sample "Management key" card from Settings that displayed a fake SSH fingerprint and an inert Rotate control.
- Updates are back on the site screen: plugins and themes show pending updates from the fleet update queue, each row can update individually, and "Update all" runs the managed update with quicksaves before and after.
- Bulk site actions work: select sites and run Sync data, Update WP, Back up, Apply HTTPS or Scan errors across all of them.
- Connect manually works: a non-Kinsta site can be onboarded from the New site dialog with server credentials, protocol and port, creating production and optional staging environments.
- Domain mappings for Kinsta and Rocket.net sites are managed from a new Domains tab on the site: add a domain, delete one, or set the primary.
- Managed-update settings are editable per environment again: toggle updates and exclude specific plugins or themes from the site overview.
- Site requests are real again: the New site request form submits to operations, and both customers and operators see each request progress through Requested, Preparing and Ready on the Sites screen. Previously the form silently discarded the submission.