Skip to content

migrate still leaves ~/ in nodeHost.workerRuns.folders and in list-entry includes of concatenated arrays #972

Open

Description

@shakkernerd

Summary

#937 covers ~/... config paths that ocm migrate and ocm adopt import copied verbatim into a new environment, where OpenClaw expands ~ against the environment root (OPENCLAW_HOME) instead of the user's home. The fix for #937 (PR #946) spells those values out against the source home for the settings OpenClaw's runtime config treats as paths and for a cited list of settings whose own consumers expand ~. Two cases are still left as written and still move under the environment root after migration.

1. nodeHost.workerRuns.folders

OpenClaw's node worker folder check (src/node-host/node-worker-device-folder.ts) expands a leading ~ with expandHomePrefix(value, { env }), which prefers OPENCLAW_HOME, and then resolves the result with fs.realpathSync.native. Because the consumer resolves symlinks before .., the lexical normalization the migration rewrite applies to other settings would not reproduce its meaning for values containing ... The setting was therefore left out of the rewrite. A plain textual replacement of ~ (without lexical cleanup) would preserve the meaning in every case.

2. An include placed at a list entry of an array that other includes concatenate

The migration rewrite types an include's recorded scope from the resolved config, so an include placed as a list entry is treated as one. When arrays from several includes are concatenated, the recorded index no longer matches the merged position. The include can then be typed as an object key, and its value is left unexpanded. Fixing this needs segment types recorded during include traversal, before merging.

Reproduction

Reproduced on PR #946's head (abfd18d4eb43ebe5bb525ba370db36d28e2e20a1), Linux, debug build, isolated HOME and OCM_HOME:

export HOME=$(mktemp -d) OCM_HOME=$(mktemp -d)
mkdir -p "$HOME/.openclaw" "$HOME/work" "$HOME/bin"
cd "$HOME/.openclaw"
echo '{"gateway":{"port":18789},"nodeHost":{"workerRuns":{"enabled":true,"folders":["~/work"]}},"hooks":{"$include":["./a.json","./b.json"]}}' > openclaw.json
echo '{"items":[{"paths":{"0":"literal"}}]}' > a.json
echo '{"items":[{"paths":[{"$include":"./p.json"}]}]}' > b.json
echo '"~/bin"' > p.json
ocm migrate demo
grep -o '"folders":[^]]*]' "$OCM_HOME/envs/demo/.openclaw/openclaw.json"
cat "$OCM_HOME/envs/demo/.openclaw/p.json"

Observed: migration succeeds, the copied config still has "folders":["~/work"], and the copied p.json still contains "~/bin". ocm env exec demo -- env shows OPENCLAW_HOME=$OCM_HOME/envs/demo, and neither $OCM_HOME/envs/demo/work nor $OCM_HOME/envs/demo/bin exists. In the plain install both values named $HOME/work and $HOME/bin.

Expected

Both values keep naming the same location they named in the plain install, as other path settings do after #946.

Impact

Narrower than #937: a node host that reads the migrated environment's config grants its worker access under the environment root instead of the configured folder (or rejects the folder if it does not exist there), and the include layout in case 2 is uncommon. Base main leaves both values unchanged as well; #946 does not make them worse.

Activity

  1. added
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    P2Normal priority bug or improvement with limited blast radius.
    clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.
    clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.
    clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.
    impact:securityThis issue is about security boundaries, credentials, authz, sandboxing, or sensitive data.
    impact:ux-frictionUser-facing flow adds avoidable confusion or support burden without fully blocking progress.
    issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.
    and removed
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    on Nov 2, 2026
  2. clawsweeper commented on Nov 2, 2026

    @clawsweeper

    Codex review: this still needs some work.

    Summary
    Keep this issue open: current main preserves the broken path spellings, the linked PR explicitly defers both cases, and the MEMBER author requires maintainer judgment.

    Reproducibility: Current source proves unchanged tilde values acquire a different home, and the linked PR reconstructs include types from positions changed by concatenation; the reporter supplies a CLI reproduction, but this review ran none.

    Maintainer decision needed

    • Question: Should the migration owner handle this follow-up after the broader tilde-path PR lands, with worker-folder authorization proof required before merge?
    • Recommendation: Prepare a coordinated follow-up: Keep the explicit split and require migration/adoption regressions plus allowed and forbidden worker-folder controls.
    • Why: The source establishes the defect, but the repair touches persisted consent roots and depends on an unmerged migration rewrite.

    Next step
    Coordinate the follow-up with the open migration PR and establish failing migrate/adopt regressions for concatenated includes and preserved worker-folder authorization.

    Security
    Needs attention: Migrated worker-folder settings can select different consent roots and require authorization-preservation review.

    Review details

    Best possible solution:

    Preserve each path consumer's home and traversal semantics, carrying typed include segments from traversal through migration.

    Do we have a high-confidence way to reproduce the issue?

    Current source proves unchanged tilde values acquire a different home, and the linked PR reconstructs include types from positions changed by concatenation; the reporter supplies a CLI reproduction, but this review ran none.

    Is this the best way to solve the issue?

    Repairing migration is appropriate, using consumer-specific prefix expansion and traversal-time include types rather than applying lexical normalization to physical consent paths.

    AGENTS.md: found and applied where relevant.

    Remaining risk / open question:

    Codex review notes: model internal, reasoning medium; reviewed against 4d6362f9f62e.

    Label changes

    Label changes:

    • add P2: The failures affect custom worker-folder configuration and an uncommon include layout, with the source installation preserved.
    • add impact:security: Changing the effective worker-folder root changes the filesystem locations authorized by persisted consent configuration.
    • add impact:ux-friction: Migration reports success while affected paths require diagnosis and configuration repair.
    • add issue-rating: 🦞 diamond lobster: Current issue advisory state selects this label.
    • add clawsweeper:source-repro: Current issue advisory state selects this label.
    • add clawsweeper:no-new-fix-pr: Current issue advisory state selects this label.
    • add clawsweeper:needs-security-review: Current issue advisory state selects this label.

    Label justifications:

    • P2: The failures affect custom worker-folder configuration and an uncommon include layout, with the source installation preserved.
    • impact:security: Changing the effective worker-folder root changes the filesystem locations authorized by persisted consent configuration.
    • impact:ux-friction: Migration reports success while affected paths require diagnosis and configuration repair.
    Evidence reviewed

    Security concerns:

    • [medium] Preserve worker-folder consent targets — src/store/openclaw_config.rs:205
      Leaving ~/work unchanged moves its effective root beneath the environment; replacing it through lexical cleanup can also change symlink-before-parent traversal, so verify the original allowed target and nearest forbidden target through the runtime consumer.
      Confidence: 0.98

    What I checked:

    How this review workflow works
    • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
    • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
    • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
    • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
    • Maintainers can also comment @clawsweeper review to request a fresh review only.
    • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge; those execution lanes are retired.
    • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

    Reviewed November 2, 2026, 1:36 AM ET / 06:36 UTC.

  3. shakkernerd commented on Nov 2, 2026

    @shakkernerd
    ContributorAuthor

    One more case belongs here. PR #946 leaves a ~/... value that contains a ${VAR} placeholder exactly as main does, for example skills.load.extraDirs: ["~/${SKILLS_DIR}/shared"]. OpenClaw replaces the leading ~, substitutes the placeholder and only then resolves .., so the lexical expansion the migration rewrite uses for other values could select a different directory (a placeholder such as UP=../.. followed by /.. would be cancelled before substitution). After migration such a value still expands against the environment root, as it does today. A fix would replace the leading ~ textually, without lexical cleanup, and check the ~/.openclaw prefix only on the literal part before the first ${.

  4. shakkernerd commented on Nov 2, 2026

    @shakkernerd
    ContributorAuthor

    Two more cases are deferred here from #946, both left exactly as main leaves them:

    • Values in an include placed at a list position, for example skills.load.extraDirs: [{"$include": "./dir.json"}] with dir.json containing "~/shared-skills". The recorded include scope cannot tell a list index from a digit-only object key once arrays from several includes are concatenated (a merged-tree lookup can misclassify in both directions), so fix: ~/ config paths outside ~/.openclaw point at missing locations after migrate #946 types every recorded scope segment as an object key and leaves such values unexpanded. A fix needs the include traversal to record segment types before merging.
    • The trust roots skills.load.allowSymlinkTargets and security.installPolicy.exec.trustedDirs. After migration a ~/... trust root still names a directory under the environment root, which normally grants nothing (fails closed). Rewriting them changes what is trusted, so it should come with end-to-end proof that allowed targets are admitted and neighboring targets stay rejected.
  5. shakkernerd commented on Nov 2, 2026

    @shakkernerd
    ContributorAuthor

    #983 resolves two of the cases here and turns the other two into explicit warnings, so this issue now tracks only those two.

    Resolved in #983. ocm migrate and ocm adopt import now spell out ~/... path values in an include placed at a list position, including arrays concatenated from several includes (include traversal records whether each scope step is a key or a list index before the arrays merge), and ~/... values containing a ${VAR} placeholder (only the literal directories before the first placeholder are resolved; OpenClaw substitutes and resolves the rest). A placeholder value that leads into ~/.openclaw, directly or through a symlink, stays as written and is named in a migration warning, because the placeholder may still lead elsewhere once substituted.

    Still open here, now reported instead of silent:

    • nodeHost.workerRuns.folders. OpenClaw resolves these entries to real paths and uses them as a permission boundary, and migration itself changes the links and directories they resolve through (it copies the state directory, relocates absolute state paths into the copy, and imports a linked or external workspace as workspaces/default). Every rewrite we tried had a layout in which the written entry admitted a folder the plain install rejected, so ~/... entries stay exactly as before and migration now prints warning: env <name> keeps the ~/ entries of nodeHost.workerRuns.folders[] as written; .... A fix needs worker-folder resolution that follows the source's links rather than the copied tree's.
    • The trust roots skills.load.allowSymlinkTargets and security.installPolicy.exec.trustedDirs. Rewriting them would change what the new environment trusts, so their ~/... entries stay as written (they still resolve under the environment root and grant nothing there) and migration now names each such setting in a warning.

    The workaround for both is to replace the ~/... entries with absolute paths before or after migration. docs/USAGE.md documents this limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal priority bug or improvement with limited blast radius.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:securityThis issue is about security boundaries, credentials, authz, sandboxing, or sensitive data.impact:ux-frictionUser-facing flow adds avoidable confusion or support burden without fully blocking progress.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions