fix(profiles): export allow-list + symlink preservation across export and clone paths (3-PR salvage) - #58506
Merged
Merged
Conversation
Collaborator
3-PR salvage onto current main with all authors' commits preserved: #58397 (@liuhao1024, symlinks), #58445 (@Ahmett101, allowlist superset), and the clone-path half of #11573 (@mvanhorn). Related to those and to issue anchors #58394 / #11560 -- not a duplicate; maintainer picks whether to merge this consolidated version or the individual PRs. |
shutil.copytree() defaults to symlinks=False which follows symlinks and crashes on broken ones. In Docker/custom HERMES_HOME deployments, unrelated directories may contain stale symlinks that break export. Add symlinks=True to both copytree() calls in export_profile() so broken symlinks are preserved as symlink entries in the archive. Fixes #58394
…8394) `hermes profile export default` crashed with `shutil.Error` when HERMES_HOME pointed outside ~/.hermes (common in Docker deployments) and the workspace contained broken symlinks. Two root causes: 1. `copytree` defaults to `symlinks=False` and follows link targets; broken ones crash. #58397 (liuhao1024) drafted a minimal `symlinks=True` flag fix; this PR adopts that change. 2. `copytree` was invoked against the entire HERMES_HOME root (which doubles as cwd in Docker layouts). The post-hoc blacklist at `_DEFAULT_EXPORT_EXCLUDE_ROOT` is a fixed-length enumerate-and-pray list that can't anticipate every unrelated sibling directory (`x11-dev/`, etc.). Replaced with a positive allow-list at `_DEFAULT_EXPORT_INCLUDE_ROOT` enumerating the known Hermes profile artifacts (config, persona, skills, cron, scripts, sessions, plugins, memories, knowledge, preferences). Sensitive runtime surfaces (`state.db`, `logs/`, auth files, other profiles) are intentionally not in the allow-list so the export stays a portable, credential-free snapshot of the user-facing surface — which means the existing `test_export_default_excludes_infrastructure` regressions remain green. Adds two regression tests: * test_export_default_uses_allowlist_for_unrelated_dirs — >x11-dev< sibling directories must not leak into the archive. * test_export_default_handles_broken_symlinks — symlinks inside allowed artifacts survive instead of crashing the export. closing that PR as superseded once this lands. Closes #58394
Widens the symlinks=True fix to the create_profile clone sites so a symlink pointing at a parent directory can't recurse infinitely during 'hermes profile create <name> --clone-all' (#11560). Export paths were covered by the salvaged #58397/#58445 commits; this carries the clone half of open PR #11573. Fixes #11560
teknium1
force-pushed
the
salvage/profile-export-hardening
branch
from
July 5, 2026 07:44
1785eab to
14d307f
Compare
teknium1
enabled auto-merge (rebase)
July 5, 2026 07:44
This was referenced Jul 5, 2026
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
Profile export stops crashing on broken symlinks and stops slurping unrelated directories:
copytreenow preserves symlinks, and the default-profile export uses a positive allow-list of known Hermes artifacts instead of a blacklist that can't anticipate arbitrary cwd contents (DockerHERMES_HOMEdeployments). The clone paths get the same symlink fix.Salvages #58397 (@liuhao1024, symlinks — earlier), #58445 (@Ahmett101, allowlist superset), and the clone-path half of long-open #11573 (@mvanhorn, April) onto current main — all three authors' commits preserved.
Changes
hermes_cli/profiles.py:symlinks=Trueon both export copytree calls;_DEFAULT_EXPORT_INCLUDE_ROOTallow-list (config/persona/skills/cron/sessions/plugins/memories, credentials/state.db/logs excluded);symlinks=Trueon thecreate_profileclone-all and skills-clone copytree calls (fixes the infinite-recursion crash in hermes profile --clone-all crashes with RecursionError on recursive symlink #11560)Validation
shutil.Error)profile create --clone-allwith parent-dir symlinkTargeted suite: tests/hermes_cli/test_profiles.py — 155 tests, all pass.
Fixes #58394. Fixes #11560. Closes #58397. Closes #58445. Closes #11573.
Infographic