Bug 1 (high): replace fixed sleep 1 with caller-PID polling in both
kickstart and start-after-exit handoff modes. The helper now waits until
kill -0 $caller_pid fails before issuing launchctl kickstart -k.
Bug 2 (medium): gate enable+bootstrap fallback on isLaunchctlNotLoaded().
Only attempt re-registration when kickstart -k fails because the job is
absent; all other kickstart failures now re-throw the original error.
Follows up on 3c0fd3dffe.
Fixes#43311, #43406, #43035, #43049
tsx, jiti, ts-node, ts-node-esm, vite-node, and esno were not recognized
as interpreter-style script runners in invoke-system-run-plan.ts. These
runners produced mutableFileOperand: null, causing invoke-system-run.ts
to skip revalidation entirely. A mutated script payload would execute
without the approval binding check that node ./run.js already enforced.
Two-part fix:
- Add tsx, jiti, and related TypeScript/ESM loaders to the known script
runner set so they produce a valid mutableFileOperand from the planner
- Add a fail-closed runtime guard in invoke-system-run.ts that denies
execution when a script run should have a mutable-file binding but the
approval plan is missing it, preventing unknown future runners from
silently bypassing revalidation
Fixes GHSA-qc36-x95h-7j53
In trusted-proxy mode, enforceOriginCheckForAnyClient was set to false
whenever proxy headers were present. This allowed browser-originated
WebSocket connections from untrusted origins to bypass origin validation
entirely, as the check only ran for control-ui and webchat client types.
An attacker serving a page from an untrusted origin could connect through
a trusted reverse proxy, inherit proxy-injected identity, and obtain
operator.admin access via the sharedAuthOk / roleCanSkipDeviceIdentity
path without any origin restriction.
Remove the hasProxyHeaders exemption so origin validation runs for all
browser-originated connections regardless of how the request arrived.
Fixes GHSA-5wcw-8jjv-m286
On macOS, launchctl bootout permanently unloads the LaunchAgent plist.
Even with KeepAlive: true, launchd cannot respawn a service whose plist
has been removed from its registry. This left users with a dead gateway
requiring manual 'openclaw gateway install' to recover.
Affected trigger paths:
- openclaw gateway restart from an agent session (#43311)
- SIGTERM on config reload (#43406)
- Gateway self-restart via SIGTERM (#43035)
- Hot reload on channel config change (#43049)
Switch restartLaunchAgent() to launchctl kickstart -k, which force-kills
and restarts the service without unloading the plist. When the restart
originates from inside the launchd-managed process tree, delegate to a
new detached handoff helper (launchd-restart-handoff.ts) to avoid the
caller being killed mid-command. Self-restart paths in process-respawn.ts
now schedule the detached start-after-exit handoff before exiting instead
of relying on exit/KeepAlive timing.
Fixes#43311, #43406, #43035, #43049
Add Ollama as a auth provider in onboarding with Cloud + Local mode
selection, browser-based sign-in via /api/me, smart model suggestions
per mode, and graceful fallback when the default model is unavailable.
- Extract shared ollama-models.ts
- Auto-pull missing models during onboarding
- Non-interactive mode support for CI/automation
Closes#8239Closes#3494
Co-Authored-By: Jeffrey Morgan <jmorganca@gmail.com>
The nodes tool was missing from OWNER_ONLY_TOOL_NAME_FALLBACKS in
tool-policy.ts. applyOwnerOnlyToolPolicy() correctly removed gateway
and cron for non-owners but kept nodes, which internally issues
privileged gateway calls: node.pair.approve (operator.pairing) and
node.invoke (operator.write).
A non-owner sender could approve pending node pairings and invoke
arbitrary node commands, extending to system.run on paired nodes.
Add nodes to the fallback owner-only set. Non-owners no longer receive
the nodes tool after policy application; owners retain it.
Fixes GHSA-r26r-9hxr-r792