diff --git a/docs/skills/ai-stacks.md b/docs/skills/ai-stacks.md index 7c69e2a..0174498 100644 --- a/docs/skills/ai-stacks.md +++ b/docs/skills/ai-stacks.md @@ -196,6 +196,7 @@ Detection: `shutil.which(tool.command)` for brew tools. | Mistake | Fix | |---|---| +| Updating a container to an unprivileged image without reviewing bind mounts | Move mount targets to the image's new data paths and use `:U` when prior bind directories must be chowned to the container UID. | | Calling deploy from button handler without `@work` | `push_screen_wait` requires `@work(exclusive=True)` | | Using `_discover_stacks()` with hardcoded system path | Function handles system → bundled fallback automatically | | `systemctl start` without `--user` flag | AI stacks are user-level systemd units | diff --git a/src/bluefinctl/stacks/amd/lemonade/lemonade.container b/src/bluefinctl/stacks/amd/lemonade/lemonade.container index fb093e1..afc528d 100644 --- a/src/bluefinctl/stacks/amd/lemonade/lemonade.container +++ b/src/bluefinctl/stacks/amd/lemonade/lemonade.container @@ -4,16 +4,16 @@ After=network-online.target [Container] ContainerName=lemonade -Image=ghcr.io/lemonade-sdk/lemonade-server:v10.8.0 +Image=ghcr.io/lemonade-sdk/lemonade-server:v11.0.0 AddDevice=/dev/kfd AddDevice=/dev/dri PodmanArgs=--security-opt=label=disable PodmanArgs=--group-add=video Network=lemonade-network.network PublishPort=13305:13305 -Volume=%h/ai-workspaces/lemonade/cache:/root/.cache/huggingface:z +Volume=%h/ai-workspaces/lemonade/cache:/opt/lemonade/.cache/huggingface:z,U Volume=%h/ai-workspaces/lemonade/llama:/opt/lemonade/llama:z -Volume=%h/ai-workspaces/lemonade/config:/root/.cache/lemonade:z +Volume=%h/ai-workspaces/lemonade/config:/opt/lemonade/.cache/lemonade:z,U [Service] Restart=on-failure diff --git a/tests/test_ai.py b/tests/test_ai.py index 411493d..a101915 100644 --- a/tests/test_ai.py +++ b/tests/test_ai.py @@ -3,6 +3,7 @@ from __future__ import annotations import inspect +from pathlib import Path import pytest from textual.widgets import ListView @@ -11,6 +12,24 @@ from bluefinctl.screens.ai import AIScreen, ToolsTab +def test_lemonade_quadlet_v11_uses_unprivileged_cache_paths() -> None: + """Lemonade v11 needs writable cache mounts owned by its non-root user.""" + container = ( + Path(__file__).parents[1] / "src/bluefinctl/stacks/amd/lemonade/lemonade.container" + ).read_text() + + assert "Image=ghcr.io/lemonade-sdk/lemonade-server:v11.0.0" in container + assert ( + "Volume=%h/ai-workspaces/lemonade/cache:/opt/lemonade/.cache/huggingface:z,U" + in container + ) + assert ( + "Volume=%h/ai-workspaces/lemonade/config:/opt/lemonade/.cache/lemonade:z,U" + in container + ) + assert "/root/.cache" not in container + + def test_ai_screen_has_no_filter_placeholder() -> None: """The placeholder category filter binding/action was removed.""" assert all(binding.key != "f" for binding in AIScreen.BINDINGS)