fix: use sudo/root to create /workspace symlink in manifest entrypoint

The previous commit moved the pi-agent repo mount from /workspace to
/home/user/{repo_name}. This exposed a permission bug: the Dockerfile
creates /workspace as a root-owned symlink in the image, and the
non-root entrypoint could not replace it because / is owned by root.

- Update compile_entrypoint to recreate /workspace via sudo when running
  as the container user, or directly when running as root
- Add unit test covering sudo/root symlink creation
- Update OpenSpec change docs with the additional root cause

Quality gates:
- pytest tests/unit: 208 passed
- ruff: clean on changed files
- mypy: clean on changed files
- alembic heads: single head
This commit is contained in:
Developer
2026-06-14 20:29:03 +00:00
parent fe82a248ec
commit bd94cc9bbf
16 changed files with 53 additions and 26 deletions
@@ -343,7 +343,14 @@ def compile_entrypoint(manifest: dict) -> str:
lines.append('fix_owner "$WORKSPACE_TARGET"')
lines.append("")
lines.append("# Create /workspace compatibility symlink")
lines.append('ln -sfn "$WORKSPACE_TARGET" /workspace')
lines.append("# / is owned by root, so we need root or passwordless sudo.")
lines.append('if [ -n "$SUDO" ]; then')
lines.append(' sudo ln -sfn "$WORKSPACE_TARGET" /workspace')
lines.append('elif [ "$(id -u)" = "0" ]; then')
lines.append(' ln -sfn "$WORKSPACE_TARGET" /workspace')
lines.append('else')
lines.append(' ln -sfn "$WORKSPACE_TARGET" /workspace 2>/dev/null || true')
lines.append('fi')
lines.append("")
lines.append("# Fix ownership of declared mount targets (top-level only)")
for mount in manifest.get("mounts", []):