Fix docker volume mounts for host directory access
- Replace named volume (agent_data) with bind mounts for /opt/letsbe/{env,stacks,nginx}
- Update ALLOWED_FILE_ROOT default from /opt/agent_data to /opt/letsbe
- Add startup validation that warns (but doesn't block) if host dirs missing
This fixes ENV_UPDATE writes going to container filesystem instead of host,
and DOCKER_RELOAD failing with "File does not exist" errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
b351217509
commit
9385ab09e4
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(python -m venv:*)",
|
||||||
|
"Bash(.venv/Scripts/python.exe -m pip:*)",
|
||||||
|
"Bash(.venv/Scripts/python.exe:*)",
|
||||||
|
"Bash(timeout 15 .venv/Scripts/python.exe:*)",
|
||||||
|
"Bash(ORCHESTRATOR_URL=http://localhost:8000 AGENT_TOKEN=test-token timeout 20 .venv/Scripts/python.exe:*)",
|
||||||
|
"Bash(ORCHESTRATOR_URL=http://nonexistent:9999 AGENT_TOKEN=test-token timeout 15 .venv/Scripts/python.exe:*)",
|
||||||
|
"Bash(docker compose:*)",
|
||||||
|
"Bash(curl:*)",
|
||||||
|
"Bash(docker logs:*)",
|
||||||
|
"Bash(powershell -Command:*)",
|
||||||
|
"Bash(jq:*)",
|
||||||
|
"Bash(pytest:*)",
|
||||||
|
"Bash(python -m pytest:*)",
|
||||||
|
"Bash(.venvScriptspython.exe -m pip install -r requirements.txt -q)",
|
||||||
|
"Bash(.venvScriptspython.exe -m pytest tests/executors/test_env_update_executor.py -v)",
|
||||||
|
"Bash(..venvScriptspython.exe -m pytest tests/executors/test_env_update_executor.py -v)",
|
||||||
|
"mcp__serena__get_symbols_overview",
|
||||||
|
"mcp__serena__find_symbol",
|
||||||
|
"Bash(..venvScriptspython.exe -m pytest tests/executors/test_composite_executor.py -v)",
|
||||||
|
"Bash(git init:*)",
|
||||||
|
"Bash(git remote add:*)",
|
||||||
|
"Bash(git add:*)",
|
||||||
|
"Bash(git commit:*)",
|
||||||
|
"Bash(git push:*)",
|
||||||
|
"Bash(git remote:*)",
|
||||||
|
"Bash(git config:*)",
|
||||||
|
"Bash(git fetch:*)"
|
||||||
|
],
|
||||||
|
"deny": [],
|
||||||
|
"ask": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -54,7 +54,7 @@ class Settings(BaseSettings):
|
||||||
circuit_breaker_cooldown: int = Field(default=300, ge=30, le=900, description="Cooldown period in seconds")
|
circuit_breaker_cooldown: int = Field(default=300, ge=30, le=900, description="Cooldown period in seconds")
|
||||||
|
|
||||||
# Security - File operations
|
# Security - File operations
|
||||||
allowed_file_root: str = Field(default="/opt/agent_data", description="Root directory for file operations")
|
allowed_file_root: str = Field(default="/opt/letsbe", description="Root directory for file operations")
|
||||||
allowed_env_root: str = Field(default="/opt/letsbe/env", description="Root directory for ENV file operations")
|
allowed_env_root: str = Field(default="/opt/letsbe/env", description="Root directory for ENV file operations")
|
||||||
max_file_size: int = Field(default=10 * 1024 * 1024, description="Max file size in bytes (default 10MB)")
|
max_file_size: int = Field(default=10 * 1024 * 1024, description="Max file size in bytes (default 10MB)")
|
||||||
|
|
||||||
|
|
|
||||||
30
app/main.py
30
app/main.py
|
|
@ -3,6 +3,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from app import __version__
|
from app import __version__
|
||||||
|
|
@ -28,6 +29,34 @@ def print_banner() -> None:
|
||||||
print(banner)
|
print(banner)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_mounted_directories() -> None:
|
||||||
|
"""Check that required host directories are mounted.
|
||||||
|
|
||||||
|
Logs warnings if directories are missing but does not prevent startup.
|
||||||
|
"""
|
||||||
|
logger = get_logger("main")
|
||||||
|
|
||||||
|
required_dirs = [
|
||||||
|
"/opt/letsbe/env",
|
||||||
|
"/opt/letsbe/stacks",
|
||||||
|
"/opt/letsbe/nginx",
|
||||||
|
]
|
||||||
|
|
||||||
|
missing = []
|
||||||
|
for dir_path in required_dirs:
|
||||||
|
if not Path(dir_path).is_dir():
|
||||||
|
missing.append(dir_path)
|
||||||
|
|
||||||
|
if missing:
|
||||||
|
logger.warning(
|
||||||
|
"mounted_directories_missing",
|
||||||
|
missing=missing,
|
||||||
|
message="Some host directories are not mounted. Tasks requiring these paths will fail.",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logger.info("mounted_directories_ok", directories=required_dirs)
|
||||||
|
|
||||||
|
|
||||||
async def main() -> int:
|
async def main() -> int:
|
||||||
"""Main async entry point.
|
"""Main async entry point.
|
||||||
|
|
||||||
|
|
@ -41,6 +70,7 @@ async def main() -> int:
|
||||||
logger = get_logger("main")
|
logger = get_logger("main")
|
||||||
|
|
||||||
print_banner()
|
print_banner()
|
||||||
|
validate_mounted_directories()
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
"agent_starting",
|
"agent_starting",
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ services:
|
||||||
- CIRCUIT_BREAKER_COOLDOWN=${CIRCUIT_BREAKER_COOLDOWN:-300}
|
- CIRCUIT_BREAKER_COOLDOWN=${CIRCUIT_BREAKER_COOLDOWN:-300}
|
||||||
|
|
||||||
# Security
|
# Security
|
||||||
- ALLOWED_FILE_ROOT=${ALLOWED_FILE_ROOT:-/opt/agent_data}
|
- ALLOWED_FILE_ROOT=${ALLOWED_FILE_ROOT:-/opt/letsbe}
|
||||||
- MAX_FILE_SIZE=${MAX_FILE_SIZE:-10485760}
|
- MAX_FILE_SIZE=${MAX_FILE_SIZE:-10485760}
|
||||||
- SHELL_TIMEOUT=${SHELL_TIMEOUT:-60}
|
- SHELL_TIMEOUT=${SHELL_TIMEOUT:-60}
|
||||||
|
|
||||||
|
|
@ -39,8 +39,10 @@ services:
|
||||||
# Hot reload in development
|
# Hot reload in development
|
||||||
- ./app:/app/app:ro
|
- ./app:/app/app:ro
|
||||||
|
|
||||||
# Agent data directory
|
# Host directory mounts for real infrastructure access
|
||||||
- agent_data:/opt/agent_data
|
- /opt/letsbe/env:/opt/letsbe/env
|
||||||
|
- /opt/letsbe/stacks:/opt/letsbe/stacks
|
||||||
|
- /opt/letsbe/nginx:/opt/letsbe/nginx
|
||||||
|
|
||||||
# Pending results persistence
|
# Pending results persistence
|
||||||
- agent_home:/home/agent/.letsbe-agent
|
- agent_home:/home/agent/.letsbe-agent
|
||||||
|
|
@ -62,7 +64,5 @@ services:
|
||||||
memory: 64M
|
memory: 64M
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
agent_data:
|
|
||||||
name: letsbe-agent-data
|
|
||||||
agent_home:
|
agent_home:
|
||||||
name: letsbe-agent-home
|
name: letsbe-agent-home
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue