Skip to content

fix(runtime): make helper paths container-friendly#80

Merged
chrysb merged 5 commits into
chrysb:mainfrom
kesslerio:fix/container-runtime-paths
Jun 3, 2026
Merged

fix(runtime): make helper paths container-friendly#80
chrysb merged 5 commits into
chrysb:mainfrom
kesslerio:fix/container-runtime-paths

Conversation

@kesslerio

@kesslerio kesslerio commented May 21, 2026

Copy link
Copy Markdown
Contributor

What

This makes AlphaClaw less picky about where it is allowed to write runtime helper files.

By default, nothing changes. AlphaClaw still uses /etc/cron.d/openclaw-hourly-sync, /usr/local/bin/git, and the existing askpass helper path. Deployments that run as a non-root user, mount read-only system paths, or manage cron outside the app can now set:

  • ALPHACLAW_SKIP_SYSTEM_CRON_INSTALL=true to keep AlphaClaw from writing /etc/cron.d
  • ALPHACLAW_GIT_SHIM_PATH=/some/writable/bin/git to move the managed git shim
  • ALPHACLAW_GIT_ASKPASS_PATH=/some/writable/path/git-askpass.sh to move the askpass helper

The same cron opt-out now applies in startup, onboarding, and the /api/sync-cron route. I also fixed the remote config restore helper so sanitized environments still keep PATH; without that, git can disappear even though the caller only meant to avoid passing secrets through.

Why

The current defaults are fine for a simple Docker image. They are brittle once AlphaClaw runs in a stricter container, on NixOS-style hosts, or anywhere /etc and /usr/local/bin are owned by the image or supervisor instead of the app process.

This keeps the friendly defaults but gives managed deployments a clean escape hatch. No local patching of packaged files, no special entrypoint rewrite, and no surprise write attempt to a host-level cron directory when cron is managed elsewhere.

Evidence

  • npm test -- tests/server/git-runtime.test.js tests/server/git-shim.test.js tests/server/routes-onboarding.test.js tests/server/routes-system.test.js
  • npm test
  • git diff --check
  • codex review --base origin/main, with no blocking findings
  • GitHub CI on this PR: test (22) passed

Real behavior proof

I tested this against a real AlphaClaw server process, not only mocks.

Runtime setup:

PORT=13190 \
SETUP_PASSWORD=test-password \
ALPHACLAW_ROOT_DIR=/tmp/alphaclaw-browser-smoke-XXXXXX \
ALPHACLAW_SKIP_SYSTEM_CRON_INSTALL=true \
ALPHACLAW_GIT_SHIM_PATH=/tmp/alphaclaw-browser-smoke-XXXXXX/bin/git \
ALPHACLAW_GIT_ASKPASS_PATH=/tmp/alphaclaw-browser-smoke-XXXXXX/tmp/git-askpass.sh \
node bin/alphaclaw.js start

Observed startup output included:

[alphaclaw] System cron setup skipped by ALPHACLAW_SKIP_SYSTEM_CRON_INSTALL
[alphaclaw] git auth shim installed
[alphaclaw] Express listening on :13190

Then I opened the setup UI in a browser, logged in with the test password, and reached the setup choice screen. I also verified that the custom git shim and askpass helper existed and were executable, while the smoke run did not create /etc/cron.d/openclaw-hourly-sync.

What I did not test: a full production onboarding against real GitHub credentials from this branch. The touched behavior is covered by the onboarding route tests and the live smoke above, but I did not create a real workspace repo during the smoke.

AI assistance

Built with Codex. I reviewed the diff, ran the tests above, and verified the runtime behavior locally before opening the PR.


Compound Engineering
Codex

kesslerio added 2 commits May 21, 2026 10:02
Signed-off-by: kesslerio <martin@kessler.io>
Signed-off-by: kesslerio <martin@kessler.io>

@chrysb chrysb left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left two inline review notes on the runtime path/cron behavior.

Comment thread bin/alphaclaw.js
});
const gitShimTemplatePath = path.join(__dirname, "..", "lib", "scripts", "git");
const gitShimDest = "/usr/local/bin/git";
const gitShimDest = resolveGitShimPath();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Make the custom shim discoverable by OpenClaw. If ALPHACLAW_GIT_SHIM_PATH points outside PATH (for example /state/bin/git), startup writes the shim successfully, but the managed OpenClaw process still inherits PATH unchanged, so plain git calls resolve to the real binary and bypass the askpass shim. Either prepend path.dirname(gitShimDest) to the gateway/onboarding command env when this override is set, or document/enforce that the configured directory must already be first on PATH; otherwise the new env var can look configured while auth still fails.

kSystemCronConfigPath,
JSON.stringify(nextConfig, null, 2),
);
if (shouldSkipSystemCronInstall()) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Don’t let skip mode leave an active stale cron. This early return means a user can set ALPHACLAW_SKIP_SYSTEM_CRON_INSTALL=true, disable sync via /api/sync-cron, and still keep a previously installed /etc/cron.d/openclaw-hourly-sync running. The cron script invokes alphaclaw git-sync unconditionally, so the disabled config is not honored by the already-installed scheduler. We should either remove AlphaClaw's managed cron file when disabling, even in skip mode, or make hourly-git-sync.sh exit when cron/system-sync.json has enabled:false.

Signed-off-by: kesslerio <martin@kessler.io>
@kesslerio

Copy link
Copy Markdown
Contributor Author

Thanks for the review. Fixed both.

  • ALPHACLAW_GIT_SHIM_PATH now prepends its directory to PATH before startup, so plain git resolves through the shim.
  • hourly-git-sync.sh now exits cleanly when cron/system-sync.json has enabled:false, so stale cron entries stop doing work.

Added coverage for PATH propagation and the disabled-sync script case. npm test passes locally: 89 files, 617 tests.

kesslerio added 2 commits June 2, 2026 15:58
…-paths

Signed-off-by: kesslerio <martin@kessler.io>
Signed-off-by: kesslerio <martin@kessler.io>
@kesslerio

Copy link
Copy Markdown
Contributor Author

@chrysb conflicts are resolved and pushed.

I merged current main into the PR branch and kept both sides of the conflicting changes:

  • the container/runtime cron-skip path work from this PR
  • the newer AlphaClaw config + OpenAI-compatible API toggle work from main

One extra thing came up after the merge: thinkingDefault: "high" was failing because the OpenClaw thinking adapter was relying on a minified export name. I changed that to resolve the right function by behavior instead, which should be less fragile across packaged OpenClaw builds.

Checked:

  • local focused tests passed: tests/server/agents-service.test.js and tests/server/routes-models.test.js
  • local full npm test passed: 92 files / 668 tests
  • GitHub CI test (22) passed on 0c3a174

Could you take another look when you get a chance?

@chrysb chrysb left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the refreshed PR. Prior runtime path and cron feedback is addressed, merge conflicts are resolved, and focused/full test suites passed locally.

@chrysb chrysb merged commit 50be8b7 into chrysb:main Jun 3, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants