coysh-digital / craft-manager-connector
Reports operational metadata from a Craft CMS installation to a Manager platform over signed outbound requests, with one inbound endpoint whose only meaning is "check in now".
Package info
github.com/Coysh-Digital/craft-manager-connector
Type:craft-plugin
pkg:composer/coysh-digital/craft-manager-connector
Requires
- php: >=8.1
- ext-sodium: *
- coysh-digital/manager-protocol: ^1.10
- craftcms/cms: ^4.4 || ^5.0
Requires (Dev)
- craftcms/ecs: dev-main
- craftcms/phpstan: dev-main
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^10.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-22 21:46:29 UTC
README
Reports operational metadata from a Craft CMS 4 or 5 installation to Manager for Craft over signed outbound requests. Manager can knock to ask for an early check-in; it cannot ask for anything else.
Requires PHP 8.1+ and Craft CMS 4.4+ or 5.0+.
What it does
- Generates an ED25519 keypair on your server. The private key never leaves it.
- Signs every request it sends, so the platform can prove it came from this installation.
- Reports version numbers, update availability, licence state and similar operational metadata.
What it cannot do
These are not promises about intent; they are properties of the code.
| Property | Why it holds |
|---|---|
| No inbound instruction | The plugin registers no URL rules at all. One endpoint answers without a session, and all it can say is "check in now" - it reads no parameters, takes no body, and pushes the same task the site already runs on its own timer. Everything the platform wants done is still discovered by this plugin calling out and reading a signed answer. Nothing depends on a nudge arriving, so a site behind NAT still needs no inbound firewall rule; it just waits for its own schedule. |
| No remote execution | There is no console-command runner, no PHP evaluation, no SQL, no shell, no arbitrary file access. Jobs come from a closed registry, and this plugin refuses any type it does not itself implement - so a compromised platform cannot make your site do something new. |
| No credentials held | Manager never receives an administrator password, an SSH credential or a database password. There is nowhere in its schema to put one. |
| No site content | What may be transmitted is fixed by a shared schema. The platform rejects anything outside it rather than quietly discarding the extra. |
What it reports
Version numbers, plugin and Composer package names and versions, a handful of safe configuration booleans, queue and migration counts, locally-computed licence state, and an environment classification.
Never entries, assets, user records, password hashes, sessions, logs, environment-variable values, security keys, licence keys, API credentials, database credentials or configuration file contents.
Do not take that on trust. See exactly what your site would send:
php craft manager-connector/preview
Documentation
Full documentation is at managerforcraft.com/docs; its source
lives in the docs folder of this repository. This README is the short version. The docs
go deeper on pairing, exactly what is and is not sent, what each capability permits, how backups
work, the security model, the console commands, and troubleshooting.
Requirements
- Craft CMS 4.4 or later, or Craft CMS 5.0 or later
- PHP 8.1 or later (Craft 4 itself runs on 8.0.2+, but this plugin does not - see the changelog for why)
- A Manager installation to report to, self-hosted or Manager Cloud
Installation
composer require "coysh-digital/craft-manager-connector:^1.16.1" -w && php craft plugin/install manager-connector
Three details in that line, each of which has cost somebody a support message:
- The version is pinned and quoted. Unquoted,
^is a glob operator in zsh withextendedglobset, which is the default on a lot of macOS setups - the shell eats the constraint before Composer sees it. -wis--with-dependencies, which lets Composer move the plugin's own dependencies rather than refusing because one of them is already locked. If Composer answers that a root requirement such ascraftcms/cmsis in the way, use-W(--with-all-dependencies) instead - Composer says so in as many words when it happens.&&rather than two lines, so the install does not run against acomposer requirethat failed.plugin/installon a plugin Composer did not manage to add fails with a message about the handle, which sends people looking in the wrong place.
Installing does not create a config file, and the plugin runs without one - you are asked for the platform address on the pairing screen instead. Creating it is optional and recommended:
// config/manager-connector.php return [ 'platformUrl' => 'https://manager.example.org', ];
Copy vendor/coysh-digital/craft-manager-connector/src/config.php if you want the commented version
of every option.
Kept in version control rather than in the database on purpose: pointing a site at a different Manager platform should take a deployment. With it set, the pairing screen shows the address as fixed, so this site cannot be repointed from the control panel. It is also the only place a recovery key fingerprint can be pinned - see Backups.
Pairing
Ask your administrator for a single-use enrolment code, then:
php craft manager-connector/pair mgr_enrol_...
The code is valid once and expires quickly. If the host this site serves from differs from the domain the platform expected, pairing is held until a person confirms it - nothing is reported in the meantime.
Scheduling
One cron entry runs everything:
*/5 * * * * cd /path/to/site && php craft manager-connector/run
Every run sends the heartbeat and collects any work Manager has queued. The other four reports go out
when they are due: sign-in counters every 30 minutes, inventory hourly, runtime every 6 hours and the
update check daily. A run a few seconds late still counts, and run --force sends everything now. It
exits non-zero if any task failed.
With cron in place, turn the web trigger off so the schedule comes from one place. In
config/manager-connector.php:
return [ 'webTrigger' => false, ];
Leaving it on does no harm, since cron and web traffic share one set of claims and cannot both fire a task in the same interval, but there is nothing left for it to do.
Scheduling is optional. The plugin works without cron: webTrigger is on by default and drives the same
schedule from ordinary web traffic. Cron is more predictable, because it does not depend on the site
having visitors or on Craft's queue running.
Prefer one entry per task? Each command in the table below runs on its own, and Console commands has the matching crontab.
The heartbeat carries no data at all. The update check runs once a day from whenever each site first ran it, so a fleet of sites does not all ask Craft's update service at once.
jobs is what makes anything the platform asks for actually happen. No work is ever pushed to your
site: the platform may knock to ask for an early check-in, but that is all it can say, and this command
is still the site choosing to ask and deciding for itself what to do with the answer. Nothing depends on
that knock arriving - if it cannot reach you, the schedule above is all that happens.
Commands
| Command | Purpose |
|---|---|
manager-connector/pair <code> |
Pair with a platform |
manager-connector/run |
Run everything that is due. The one cron entry |
manager-connector/heartbeat |
Report liveness |
manager-connector/report |
Send an inventory report |
manager-connector/updates |
Check for updates and report what is available |
manager-connector/system |
Report disk usage, PHP limits and response timings |
manager-connector/logins |
Report counts of failed control-panel sign-ins |
manager-connector/jobs |
Ask the platform whether there is anything to do, and do it |
manager-connector/preview |
Print what would be sent, without sending it |
manager-connector/status |
Show the current connection |
manager-connector/disconnect |
Delete this site's signing key |
Pairing and disconnection are console commands rather than buttons. Both are deliberate acts by someone with server access, and behind a button a hijacked control-panel session could hand a platform access to your site, or take it away.
Disconnecting
php craft manager-connector/disconnect
The keypair is deleted outright rather than flagged, so there is nothing to reactivate. Reconnecting needs a new enrolment code. Revoke the connector in Manager as well, so the platform stops expecting it.
What is tested, and what is not
Stated plainly, because "no test directory" and "untested" are not the same thing and a reader has no way to tell them apart from the outside.
| Layer | Where it is covered |
|---|---|
| Encryption, sealing, key fingerprints, the artifact envelope and the signing protocol | manager-protocol, which has its own suite and committed cross-implementation fixtures. This plugin calls into it and implements none of it |
| Shape of the plugin: no URL rules, no shelling out, no destination as a parameter, no unpinned recovery key, no dependency outside a fixed allowlist | bin/verify-invariants.php, run on every push. It reads the source, so it needs no Craft install and takes about a second |
| The upload destination, the closed task registry, and the declared Node.js version parser | tests/, run on both Craft majors |
| The backup pipeline end to end: dump, encrypt, seal, sign, upload, clean up | Nothing yet. It is coupled to a live Craft application, so covering it needs a Craft harness this repository does not have. It is exercised by hand against a real Craft 5 testbed before a release, and that is not the same as a test |
The last row is the honest gap. It is here rather than left to be discovered.
Security
Report vulnerabilities privately to support@managerforcraft.com. Please do not open a public issue.
Dependencies are limited to the shared protocol package and PHP's own sodium extension; HTTP goes
through the Guzzle client Craft already ships.
Licence
MIT. See LICENSE.md.