Skip to content

Fix #159: Allow browsing home directory when running as root (WSL) - #284

Open
zwanski-start wants to merge 1 commit into
AutoForgeAI:masterfrom
zwanski-start:swarm/issue-159-dennis
Open

zwanski-start wants to merge 1 commit into
AutoForgeAI:masterfrom
zwanski-start:swarm/issue-159-dennis

Conversation

@zwanski-start

Copy link
Copy Markdown

Closes #159

Problem

In WSL the default user is root, so Path.home() is /root. /root is in LINUX_BLOCKED, and the folder browser's first call (GET /api/filesystem/list with no path → home) returned 403 "Blocked access to restricted path: /root", so users couldn't pick a folder for a new project. projects.py and scaffold.py use the same is_path_blocked(), so creating a project under /root/... was also rejected. The same issue hits systems that keep homes under /var (e.g. /var/home/<user> on Fedora Silverblue).

Change (server/routers/filesystem.py)

  • Split the blocklist into system paths (get_system_blocked_paths) and home-relative credential dirs (get_sensitive_blocked_paths).
  • is_path_blocked() now:
    1. Always blocks credential dirs (~/.ssh, ~/.aws, …) — even inside home.
    2. Allows the user's own home directory and everything inside it.
    3. Otherwise applies the platform system blocklist as before.
  • A home of / is ignored (get_browsable_home() returns None) so it can't unblock the whole filesystem.
  • Removed the now-unused combined get_blocked_paths() (no other callers).

Other users' /root stays blocked for non-root users, and only the home subtree of /var is opened up, not /var itself.

Verification

  • New test_filesystem_security.py (5 tests, monkeypatches Path.home): root home browsable, /root/.ssh still blocked, /var/home/alice browsable while /var and /var/log stay blocked, regular user still blocked from /root//etc, HOME=/ ignored.
  • Exercised the router with FastAPI's TestClient and Path.home set to /root: /root gets past the blocklist, while /etc and /root/.ssh still return "Access to this directory is not allowed".
  • ruff check . clean; python test_security.py passes.
  • test_ws_security.py / test_devserver_security.py have 21 failures that are already on master (same count with my change stashed). They're unrelated to this fix.
  • Backend-only change, so I didn't check it in the browser.

Assumptions

  • The issue mentions autoforge --workspace, but the CLI has no such flag. The root cause is the home-directory default, not the workspace, so this PR doesn't add one.

🤖 Generated with Claude Code

… lives under a blocked system path

When the server runs as root (the default user in WSL), Path.home() is
/root, which is in LINUX_BLOCKED, so the folder browser's default listing
returned 403 and new projects could not be created. The same happened for
homes under /var (e.g. /var/home/<user> on Fedora Silverblue).

is_path_blocked() now exempts the user's own home directory (and anything
inside it) from the platform system blocklist, while credential
directories (~/.ssh, ~/.aws, ...) remain blocked unconditionally. A home
of / is ignored so it cannot unblock the whole filesystem.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zwanski-start

Copy link
Copy Markdown
Author

🔍 QA report: ✅ Passed

Tester: Ada (cubefarm agent, in a fresh session) · Round: 1 · Author: Dennis

The fix resolves #159: when the home directory sits under a blocked system path (/root in WSL, /var/home on Silverblue), the folder browser opens at home and projects can be created there, while system dirs (/etc, /var, /root for other users, /tmp) and credential dirs (~/.ssh, ~/.aws) stay blocked. I confirmed the bug on master, then exercised the fix end to end by running the server with HOME pointed at a real directory under /var and creating a project through the UI. The 5 new tests, ruff, the security suites, the other pytest files and the UI build all pass. The mypy errors and the 21 ws/devserver test failures are the same on master.

Check Details
✅ Issue repro on master On origin/master with Path.home() patched to /root, is_path_blocked(/root) and is_path_blocked(/root/projects) both return True, which reproduces the 403. On the PR branch both return False.
✅ Default folder-browser listing when home is under a blocked path Server started with HOME=/var/tmp/qa-ada-284-home (under blocked /var). GET /api/filesystem/list with no path returns 200, lists the home contents, and hides blocked .ssh/.aws.
✅ System and credential paths still blocked GET /api/filesystem/list returns 403 for /var, /var/tmp, /etc, /root, /tmp, /.ssh and /.aws. Validating /var/tmp/x returns 'Access to this directory is not allowed'. create-directory in /var/tmp and /.ssh returns 403.
✅ Project creation under home (projects.py path check) POST /api/projects with a path under home returns 200 and the project is registered. A path under /var/tmp or /.ssh returns 403 'Cannot create project in system or sensitive directory'. create-directory under home returns 200.
✅ UI new-project flow in the browser New Project > name > folder browser opens at the home under /var (breadcrumbs / > var > tmp > qa-ada-284-home). I browsed into projects/existing and selected it, then Blank > Edit Templates Manually showed 'Project Created!' and redirected to the project dashboard. Console: 403s only when I clicked the blocked 'var' breadcrumb (expected). The other error, an invalid pattern regex on the project-name input, is already on master.
✅ Code review: security edge cases Paths are resolved before the home exemption, so a symlink from home to /etc stays blocked. Credential dirs are checked before the home exemption. HOME=/ is ignored. Only the home subtree is exempted, not its blocked parent. get_blocked_paths had no other callers. scaffold.py, projects.py and filesystem.py all use the same is_path_blocked.
✅ Blocked intermediate breadcrumb UX Minor, not blocking: clicking a blocked breadcrumb (e.g. 'var') shows an empty list with no error message and you have to press Cancel. It does not happen in the WSL /root case, where '/' and 'root' are both browsable.
✅ New unit tests test_filesystem_security.py has 5 tests covering root home, credential dirs, home under /var, a regular user, and HOME=/. All pass.
✅ Regression vs master baseline mypy shows 25 errors on both master and this branch (filesystem.py ones are the Windows-only ctypes.windll). test_ws_security.py and test_devserver_security.py show 21 failed / 67 passed on both.
⏭️ UI e2e (Playwright suite) PR is backend-only (no ui/ changes). The UI build and lint were run instead.
✅ Phone-size layout At 390x844 the project dashboard renders. The cramped layout is already on master and this PR doesn't touch the UI.
✅ Cleanup / orphan processes Server stopped. No leftover uvicorn on 5571. Test home dir and the throwaway master worktree removed. Worktree is clean.
🧪 Commands run
Command Result
ruff check . All checks passed
mypy . 25 errors in 10 files (same 25 on origin/master; none new)
python test_security.py ALL TESTS PASSED
python test_security_integration.py ALL INTEGRATION TESTS PASSED
python -m pytest test_filesystem_security.py test_client.py test_dependency_resolver.py test_rate_limit_utils.py 60 passed, 0 failed
python -m pytest test_ws_security.py test_devserver_security.py 21 failed, 67 passed (same on origin/master)
npm --prefix ui run build success (tsc -b && vite build)
npm --prefix ui run lint 0 errors, 6 warnings
HOME=/var/tmp/qa-ada-284-home uvicorn server.main:app --host 127.0.0.1 --port 5571 + curl probes of /api/filesystem/list, /validate, /create-directory, /api/projects home 200; system/credential paths 403 as expected
master-branch probe script (Path.home=/root) calling is_path_blocked /root blocked: True on master (bug reproduced)

No browser screenshots were taken in this round.

Posted by cubefarm · merges automatically once GitHub's checks pass

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.

Access Restriction Error When Creating New Projects in WSL

1 participant