Skip to content

Post-apply restart safety

This guide explains how Patcherly keeps post-apply automation — shell steps that run after a successful patch — under control. It complements App restart automation and the in-dashboard risk confirmation you see before saving a manifest.

Applies to Python, Node.js, and PHP targets when your plan includes app restart automation. WordPress targets never run shell commands from the plugin.


What post-apply automation does

After Patcherly applies a fix on your server, the connector may run a short list of commands you define — reload a service, clear a cache, run a smoke test, and similar steps. You write these in a YAML manifest on the target settings page.

Because these commands run as the connector's OS user, Patcherly treats them as high privilege and applies several independent safeguards.


Who is trusted for what

Party Responsibility
You (dashboard user) Write and confirm the manifest. You see a risk acknowledgment before save.
Patcherly Stores the manifest, signs API responses, enforces plan limits and hourly restart caps, and records changes in audit logs.
Connector on your server Fetches the manifest, verifies signatures and hash, executes steps with safe argv-style invocation, and reports success or failure back.

If someone compromises the connector host, they could already run commands as that OS user — the manifest does not create a new privilege boundary on the machine. It does prevent a remote attacker from pushing arbitrary commands through Patcherly without passing authentication, signing, and your explicit configuration.


Safeguards in plain language

Signed, verified manifests

The connector downloads the manifest over an authenticated, HMAC-signed API response. It checks the signature and compares a cryptographic hash to the value Patcherly issued before running any step. Stale or tampered manifests are rejected.

Opt-in and plan gates

Steps run only when all of the following are true:

  • Automation is enabled on the target.
  • Your workspace plan includes App restart automation.
  • You completed the dashboard opt-in / risk acknowledgment.
  • A fix was successfully applied for that error (not on failed or quarantined paths).
  • Hourly restart caps still allow another run.

Rate limits and auto-disable

Patcherly enforces a maximum number of restarts per hour per target. On Targets, the At limit chip (e.g. 0 / 3) reflects only the hourly cap — not automation disabled after a failed step, tamper detection, or a superadmin review lock.

If steps fail repeatedly, automation can auto-disable until you review the manifest and re-enable it — reducing runaway or misconfigured loops. That safety lock is separate from the Targets App restart On/Off pause toggle (which keeps your YAML while pausing runs).

Safe command execution

Connectors reject shell chaining (&&, pipes, redirection, backticks, and similar) in string-form manifest commands. Commands are tokenized and executed with the language's safe subprocess API (execFile, create_subprocess_exec, proc_open with an argv array).

Array-form run (a YAML list such as ['node', 'scripts/reload.js']) skips the string denylist scan but argv[0] must still be on the connector binary allowlist. Defaults include language runtimes and common process managers (systemctl, pm2, supervisorctl). Other binaries need a platform allowlist change via POST_APPLY_ALLOWED_BINARIES.

See Connectors overview — post-apply restart manifest for per-stack detail.

Known disable reasons

When automation is turned off after a failed run, the Targets App restart modal shows a short reason code. Use this table to fix the manifest, then save with confirmation to re-enable:

Reason What it means What to do
unsafe_command A string-form run used shell metacharacters (&&, \|, ;, backticks, redirection, etc.). Split into multiple steps, or use array-form run (YAML list) when a -c / -e body needs semicolons.
binary_not_allowed argv[0] is not on the platform binary allowlist. Use an allowed basename (shown in the App restart modal), or ask your platform operator about POST_APPLY_ALLOWED_BINARIES — customers cannot raise this per workspace.
step_failed A step exited with a non-zero status (and was not marked ignore_failure: true). Fix the command or environment on the server; check the reason text for rc= and log tail.
step_timeout A step exceeded its timeout_seconds. Raise the step timeout if the work is legitimately slow, or speed up / split the command.
Content hash / tamper Manifest fingerprint did not match what Patcherly issued (content_sha256 mismatch). Re-save the manifest from the dashboard so the connector gets a fresh signed copy.
Entitlement / plan lock Workspace plan no longer includes app restart, or the target type cannot run shell steps. Check Profile → Billing, or use a Python / Node.js / PHP target (not WordPress plugin-only).
Hourly rate limit Not a permanent disable — successful restarts hit the rolling-hour cap. Wait for the window to roll, or pause with the On/Off toggle. The At limit chip is separate from a failure lock.

Per-error deduplication

The same error cannot trigger more than one restart burst in a single connector process lifetime, avoiding duplicate reload storms.

No secrets in YAML

Commands inherit the connector's environment. Do not embed passwords or API keys in the manifest — use environment variables already configured on the server. Store ~/.patcherly/credentials.json with restrictive file permissions.


After a run completes

The connector sends a status report back to Patcherly — which steps succeeded, which failed, and any error text. You can review outcomes in the dashboard and Audit logs. Failed steps contribute to auto-disable logic; there is no silent failure.

For operational setup (YAML examples, PHP OPcache notes, smoke tests), see App restart automation and Restarting apps.


Residual risks to understand

  • Manifest content is powerful. Anyone with dashboard access to edit the target can change commands. Restrict target settings to trusted admins.
  • Shared hosts. Multiple processes on one machine are not coordinated by a global OS lock; server-side dedupe limits duplicate restarts per error but does not replace proper deployment practices.
  • Shell injection via manifest text is mitigated by authenticated editing, auditing, and metacharacter rejection — still treat manifests like production config.