fix: namespace sandbox temp paths by sandbox ID to prevent cross-session collisions

DifyCli and AppAssets used hardcoded absolute paths under /tmp/.dify/,
causing concurrent sandbox sessions on the same host (e.g. SSH provider)
to overwrite each other's config files and CLI binaries.

- Add Sandbox.id property (uuid4 hex) as a stable, path-safe identifier
  independent of provider-specific environment IDs
- Convert DifyCli/AppAssets from static constants to per-sandbox instances
  namespaced under /tmp/.dify/{sandbox.id}/
- Replace all vm.metadata.id references with sandbox.id
- Replace upload_file with heredoc-based pipeline step in session.py to
  reduce round-trips
This commit is contained in:
Harry
2026-03-11 19:19:17 +08:00
parent 6fe221518e
commit 76c02db094
7 changed files with 85 additions and 34 deletions

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import logging
import threading
from typing import TYPE_CHECKING
from uuid import uuid4
from libs.attr_map import AttrMap
@ -14,6 +15,18 @@ logger = logging.getLogger(__name__)
class Sandbox:
"""Represents a single sandbox environment.
Each ``Sandbox`` owns a stable, path-safe ``id`` (a 32-char hex
UUID4) that is independent of the underlying provider's environment
ID. Use ``sandbox.id`` for any path or resource namespacing
(e.g. ``DifyCli(sandbox.id)``).
The raw provider identifier is still accessible via
``sandbox.vm.metadata.id`` when needed (logging, API calls back to
the provider, etc.).
"""
def __init__(
self,
*,
@ -24,6 +37,7 @@ class Sandbox:
app_id: str,
assets_id: str,
) -> None:
self._id = uuid4().hex
self._vm = vm
self._storage = storage
self._tenant_id = tenant_id
@ -35,6 +49,11 @@ class Sandbox:
self._cancel_event = threading.Event()
self._init_error: Exception | None = None
@property
def id(self) -> str:
"""Stable, path-safe identifier for this sandbox (UUID4 hex)."""
return self._id
@property
def attrs(self) -> AttrMap:
return self._attributes
@ -100,7 +119,7 @@ class Sandbox:
def release(self) -> None:
self.cancel_init()
sandbox_id = self._vm.metadata.id
sandbox_id = self.id
try:
self._storage.unmount(self._vm)
logger.info("Sandbox storage unmounted: sandbox_id=%s", sandbox_id)