Skip to content

fix(api/migrate): allow known framework source dirs, not just the librefang home#5614

Merged
houko merged 2 commits into
mainfrom
fix/migrate-allowed-roots-siblings
May 22, 2026
Merged

fix(api/migrate): allow known framework source dirs, not just the librefang home#5614
houko merged 2 commits into
mainfrom
fix/migrate-allowed-roots-siblings

Conversation

@houko

@houko houko commented May 22, 2026

Copy link
Copy Markdown
Contributor

Problem (regression from #5577)

#5577 hardened POST /api/migrate and POST /api/migrate/scan by confining
source_dir / target_dir to an allow-list — but the allow-list was just the
librefang home (~/.librefang). The documented migration source dirs are
siblings of ~/.librefang, not descendants:

  • ~/.openclaw (legacy aliases ~/.clawdbot, ~/.moldbot, ~/.moltbot)
  • ~/.openfang, ~/.langchain, ~/.autogpt

So a real POST /api/migrate {"source":"openclaw","source_dir":"~/.openclaw"}
(and the sibling /scan) is rejected with "outside the allowed migration
roots"
. The migrate-from-OpenClaw flow that migrate_detect advertises is
broken on main.

Fix

Add migrate_source_roots(librefang_home, os_home):

  • Source allow-list = librefang home plus any known framework source dir
    that actually exists under the OS home. Only existing dirs are added —
    validate_path_containment returns 500 on a root it cannot
    canonicalize, so a missing ~/.autogpt must never enter the list.
  • migrate_scan and run_migrate's source_dir use this list.
  • run_migrate's target_dir keeps the librefang-home-only allow-list:
    reads may come from a source dir, but writes never leave ~/.librefang.

The #5577 containment guarantees are preserved — ../symlink escapes and the
arbitrary-path .exists() oracle are still blocked; only the legitimate,
existing sibling source roots are admitted, and only for reads.

Tests

crates/librefang-api/src/routes/config.rsmod migrate_roots_tests:

  • includes_only_existing_known_source_dirs — existing ~/.openclaw /
    ~/.langchain included; non-existent ~/.autogpt / ~/.openfang excluded.
  • no_os_home_yields_librefang_home_onlydirs::home_dir() == None falls
    back to the librefang home only.
  • source_under_known_root_passes_but_target_stays_confined — reproduces the
    regression: a source under ~/.openclaw is accepted; an off-list sibling is
    still rejected; and ~/.openclaw is rejected as a target root.

Verification

  • cargo test -p librefang-api --lib migrate_roots — 3 passed (run in a
    rust:latest container with libdbus-1-dev, since keyring
    dbus-secret-service pulls libdbus on Linux; the host cargo shim lacks it).
  • rustfmt --check clean on the touched file.

Relationship to #5355

Supersedes the source-dir half of the closed #5355 (which was itself
superseded by #5577 for the original audit). #5355's TOCTOU
post-creation re-canonicalize is not included here — it touches the
migration write path and is a separate hardening; flagged for a follow-up.

…refang home

#5577 confined both migrate source_dir and target_dir to the librefang home
(~/.librefang). But the documented migration sources — ~/.openclaw (and legacy
.clawdbot/.moldbot/.moltbot), ~/.openfang, ~/.langchain, ~/.autogpt — are
siblings of ~/.librefang, not descendants, so a real
POST /api/migrate {source_dir: "~/.openclaw"} (and POST /api/migrate/scan) was
rejected with "outside the allowed migration roots". The migrate-from-OpenClaw
flow regressed.

Add migrate_source_roots(): the source allow-list is the librefang home plus
any known framework source dir that actually exists under the OS home (only
existing dirs — validate_path_containment returns 500 on a root it cannot
canonicalize). source_dir / scan use this list; target_dir keeps the
librefang-home-only allow-list so writes never leave ~/.librefang. The #5577
containment guarantee (no ../symlink escape, no arbitrary-path oracle) is
preserved — only the legitimate sibling source roots are added.

Carries forward the source-dir half of the now-closed #5355.
@houko
houko enabled auto-merge (squash) May 22, 2026 14:09
@houko
houko merged commit 440572f into main May 22, 2026
@houko
houko deleted the fix/migrate-allowed-roots-siblings branch May 22, 2026 14:09
@github-actions github-actions Bot added the size/M 50-249 lines changed label May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M 50-249 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant