diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 072ae42..be18ff3 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -20,6 +20,13 @@ RUN npm install -g playwright \ && playwright install --with-deps chromium \ && chmod -R a+rx /ms-playwright +# Make `/workspaces` owned by the non-root `node` user so cloning repos into it +# works. The base image creates `/workspaces` as root, and envbuilder (used by +# Coder) does not chown the workspace to the target user, so `node` otherwise +# can't create directories there: +# git clone ... -> fatal: could not create work tree dir: Permission denied +RUN mkdir -p /workspaces && chown node:node /workspaces + # Tell dev container features where the target user's home directory is. # The devcontainer CLI passes `_REMOTE_USER_HOME`/`_CONTAINER_USER_HOME` to every # feature's install.sh, but envbuilder (used by Coder) only sets `_REMOTE_USER` diff --git a/scripts/verify-devcontainer.sh b/scripts/verify-devcontainer.sh index f2148c4..ba18d26 100755 --- a/scripts/verify-devcontainer.sh +++ b/scripts/verify-devcontainer.sh @@ -10,7 +10,8 @@ # It asserts the things that have previously broken on Coder/envbuilder: # 1. the effective user is `node`, not root, # 2. tmux is on PATH and can start a session that reads ~/.tmux.conf, -# 3. the lifecycle ran to completion (postCreateCommand sentinel exists). +# 3. the lifecycle ran to completion (postCreateCommand sentinel exists), +# 4. `/workspaces` is writable by `node` (so `git clone` into it works). # # Any failed check exits non-zero so CI fails loudly instead of silently # dropping you into a broken shell. @@ -80,6 +81,21 @@ else fail "lifecycle sentinel missing ($sentinel); postCreateCommand did not complete" fi +# 4. `/workspaces` must be writable by the current user so cloning repos into it +# (e.g. `git clone ...` from `/workspaces`) doesn't fail with "Permission denied". +workspaces_dir="/workspaces" +if [ -d "$workspaces_dir" ]; then + probe="${workspaces_dir}/.verify-write-$$" + if (umask 022 && mkdir "$probe") 2>/dev/null; then + pass "/workspaces is writable by $(id -un)" + rmdir "$probe" 2>/dev/null || true + else + fail "/workspaces is not writable by $(id -un); 'git clone' into it will fail" + fi +else + fail "/workspaces does not exist" +fi + echo "=== Verification complete ===" if [ "$failures" -ne 0 ]; then echo "$failures check(s) failed." >&2