From 544569ddbd621c97b251886801f41eb4cd313e53 Mon Sep 17 00:00:00 2001 From: AFredefon Date: Wed, 11 Mar 2026 02:04:51 +0100 Subject: [PATCH] fix: use ~/.fuzzforge for user-global data, keep workspace .fuzzforge for project storage --- .../src/fuzzforge_cli/commands/mcp.py | 7 ++-- .../src/fuzzforge_cli/tui/helpers.py | 35 ++++++++++++++----- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/fuzzforge-cli/src/fuzzforge_cli/commands/mcp.py b/fuzzforge-cli/src/fuzzforge_cli/commands/mcp.py index 9eaf907..8d29b78 100644 --- a/fuzzforge-cli/src/fuzzforge_cli/commands/mcp.py +++ b/fuzzforge-cli/src/fuzzforge_cli/commands/mcp.py @@ -174,9 +174,10 @@ def _generate_mcp_config( command = "uv" args = ["--directory", str(fuzzforge_root), "run", "fuzzforge-mcp"] - # Self-contained storage paths for FuzzForge containers - # This isolates FuzzForge from system Podman and avoids snap issues - fuzzforge_home = Path.cwd() / ".fuzzforge" + # User-global storage paths for FuzzForge containers. + # Kept under ~/.fuzzforge so images are built once and shared across + # all workspaces — regardless of where `fuzzforge mcp install` is run. + fuzzforge_home = Path.home() / ".fuzzforge" graphroot = fuzzforge_home / "containers" / "storage" runroot = fuzzforge_home / "containers" / "run" diff --git a/fuzzforge-cli/src/fuzzforge_cli/tui/helpers.py b/fuzzforge-cli/src/fuzzforge_cli/tui/helpers.py index b8af752..63c4b40 100644 --- a/fuzzforge-cli/src/fuzzforge_cli/tui/helpers.py +++ b/fuzzforge-cli/src/fuzzforge_cli/tui/helpers.py @@ -30,12 +30,25 @@ FUZZFORGE_DEFAULT_HUB_URL = "git@github.com:FuzzingLabs/mcp-security-hub.git" FUZZFORGE_DEFAULT_HUB_NAME = "mcp-security-hub" +def get_fuzzforge_user_dir() -> Path: + """Return the user-global ``~/.fuzzforge/`` directory. + + Stores data that is shared across all workspaces: cloned hub + repositories, the hub registry, container storage (graphroot/runroot), + and the hub workspace volume. + + :return: ``Path.home() / ".fuzzforge"`` + + """ + return Path.home() / ".fuzzforge" + + def get_fuzzforge_dir() -> Path: """Return the project-local ``.fuzzforge/`` directory. - Uses the current working directory so that each project gets its - own isolated FuzzForge configuration, hubs, and storage — similar - to how ``.git/`` or ``.venv/`` work. + Stores data that is specific to the current workspace: fuzzing + results and project artifacts. Similar to how ``.git/`` scopes + version-control data to a single project. :return: ``Path.cwd() / ".fuzzforge"`` @@ -238,21 +251,27 @@ def uninstall_agent_config(agent: AIAgent) -> str: def get_hubs_registry_path() -> Path: - """Return path to the hubs registry file (``.fuzzforge/hubs.json``). + """Return path to the hubs registry file (``~/.fuzzforge/hubs.json``). + + Stored in the user-global directory so the registry is shared across + all workspaces. :return: Path to the registry JSON file. """ - return get_fuzzforge_dir() / "hubs.json" + return get_fuzzforge_user_dir() / "hubs.json" def get_default_hubs_dir() -> Path: - """Return default directory for cloned hubs (``.fuzzforge/hubs/``). + """Return default directory for cloned hubs (``~/.fuzzforge/hubs/``). + + Stored in the user-global directory so hubs are cloned once and + reused in every workspace. :return: Path to the default hubs directory. """ - return get_fuzzforge_dir() / "hubs" + return get_fuzzforge_user_dir() / "hubs" def load_hubs_registry() -> dict[str, Any]: @@ -322,7 +341,7 @@ def scan_hub_for_servers(hub_path: Path) -> list[dict[str, Any]]: "image": f"{tool_name}:latest", "category": category, "capabilities": capabilities, - "volumes": [f"{get_fuzzforge_dir()}/hub/workspace:/data"], + "volumes": [f"{get_fuzzforge_user_dir()}/hub/workspace:/data"], "enabled": True, } )