fix(cron): allow profile-scoped jobs to reference default-profile scripts - #40918
Closed
maxmilian wants to merge 1 commit into
Closed
fix(cron): allow profile-scoped jobs to reference default-profile scripts#40918maxmilian wants to merge 1 commit into
maxmilian wants to merge 1 commit into
Conversation
maxmilian
force-pushed
the
fix/40801-cron-default-profile-scripts
branch
from
June 7, 2026 02:22
0b58ae4 to
1c97582
Compare
…ipts A profile-scoped cron job runs with a profile-switched home (~/.hermes/profiles/<name>), so _run_job_script validated the script path against only that profile's scripts dir. Shared/canonical scripts that live in the default-profile scripts dir (~/.hermes/scripts/) were hard-rejected for all three reference shapes — relative name, absolute path, and profile-local symlink whose realpath lands in the default dir — even though the default-profile scripts dir is a sanctioned Hermes location. This is the inverse of NousResearch#32091: routing profile jobs through the default scheduler narrowed script resolution to the profile-local dir. Accept a script that resolves into either the profile-local OR the default-profile scripts dir, and for relative names resolve profile-local first then fall through to default-profile (mirroring skill resolution: profile catalog before default catalog). The traversal/injection guard is unchanged in intent — both targets are Hermes-owned dirs, and absolute paths outside any scripts dir (/etc/passwd, ../) stay blocked. In non-profile mode get_default_hermes_root() equals the home, so allowed_dirs dedups to one entry and behavior is unchanged. Adds regression tests for the three previously-failing shapes, profile-local precedence, the still-blocked escape, and root resolution via both the Docker grandparent layout and the standard-install relative_to branch. Fixes NousResearch#40801 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maxmilian
force-pushed
the
fix/40801-cron-default-profile-scripts
branch
from
June 7, 2026 02:30
1c97582 to
f2461e1
Compare
maxmilian
marked this pull request as ready for review
June 7, 2026 02:44
Contributor
Author
|
Closing — the per-job cron |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #40801. A profile-scoped cron job runs with a profile-switched home (
~/.hermes/profiles/<name>), so_run_job_scriptvalidated the script path against only that profile's scripts dir. Shared/canonical scripts kept in the default-profile scripts dir (~/.hermes/scripts/) were hard-rejected for all three reference shapes — relative name, absolute path, and profile-local symlink whose realpath lands in the default dir — even though that dir is a sanctioned Hermes location. This is the inverse of #32091: routingprofile: <name>jobs through the default scheduler (with profile-switched execution at fire time) narrowed script resolution to the profile-local dir.Root cause
cron/scheduler.py::_run_job_scriptbuilt a singlescripts_dir = _get_hermes_home()/scriptsand rejected any resolved path notrelative_toit. Under profile switch_get_hermes_home()is~/.hermes/profiles/<name>, so the canonical~/.hermes/scripts/is "outside".Fix
Accept a script resolving into either the profile-local or the default-profile scripts dir (
get_default_hermes_root()/scripts— already the SSOT helper that walks a profile home up to its root). For relativescriptnames, resolve profile-local first then fall through to default-profile, mirroring how skill resolution walks the profile catalog before the default catalog (reporter's Option 3, combined with Option 2 for absolute/symlink). The traversal/injection guard is unchanged in intent — both targets are Hermes-owned dirs; absolute paths outside any scripts dir (/etc/passwd,../) stay blocked. In non-profile modeget_default_hermes_root()equals the home, soallowed_dirsdedups to one and behavior is byte-for-byte unchanged.Tests
scripts/run_tests.sh tests/cron/— 407/407 passing (+5 new). New regression tests under a profile-switched env cover: absolute path to default-profile script, relative fall-through to default-profile, profile-local precedence when the same name exists in both, profile-local symlink → default-profile realpath, and the still-blocked/etc/passwdescape.scripts/check-windows-footguns.pyclean.Scope
Only
_run_job_scriptpath validation. Does not change interpreter selection, secret redaction, timeout, or the profile-switch routing from #32091. Does not touch the error message's suggested remedy beyond widening what's accepted.Follow-up
The
Blocked:message still names only the profile-local dir; a future polish could list both sanctioned dirs to point users at the right remedy, but that's cosmetic and out of scope here.