From 522765a8a17ce40dc3a0f8608db44455f13021c1 Mon Sep 17 00:00:00 2001 From: stewartshea Date: Mon, 13 Apr 2026 10:41:10 -0400 Subject: [PATCH 1/4] Fix dind: normalize os-release before features + in published image - Add .devcontainer/Dockerfile that patches /usr/lib/os-release and /etc/os-release to bookworm before docker-in-docker runs (works even when GHCR :latest is stale). - Switch devcontainer.json from image to build using that Dockerfile. - Mirror the same normalization in the repo root Dockerfile for CI builds. Made-with: Cursor --- .devcontainer/Dockerfile | 24 ++++++++++++++++++++++++ .devcontainer/devcontainer.json | 8 +++++++- Dockerfile | 16 ++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/Dockerfile diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..fe29d63 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,24 @@ +# Codespaces / Dev Containers apply features (docker-in-docker) in a follow-on build +# stage. That installer sources /etc/os-release and only allows known VERSION_CODENAME +# values. Upstream base images may still report "forky" while apt is bookworm. +# +# This thin layer runs *before* features, so dind works even when GHCR :latest has +# not yet picked up the same normalization in the repo root Dockerfile. +ARG DEVTOOLS_IMAGE=ghcr.io/runwhen-contrib/codecollection-devtools:latest +FROM ${DEVTOOLS_IMAGE} + +USER root +RUN set -eux; \ + for f in /usr/lib/os-release /etc/os-release; do \ + [ -e "$f" ] || continue; \ + target="$f"; \ + [ -L "$f" ] && target=$(readlink -f "$f"); \ + grep -q '^ID=debian' "$target" || continue; \ + sed -i \ + -e 's/^VERSION_CODENAME=.*/VERSION_CODENAME=bookworm/' \ + -e 's/^VERSION_ID=.*/VERSION_ID="12"/' \ + -e 's/^VERSION=.*/VERSION="12 (bookworm)"/' \ + -e 's|^PRETTY_NAME=.*|PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"|' \ + "$target"; \ + done +USER runwhen diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 5ae5361..b96444c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,12 @@ { "name": "CodeCollection DevTools", - "image": "ghcr.io/runwhen-contrib/codecollection-devtools:latest", + "build": { + "dockerfile": "Dockerfile", + "context": ".", + "args": { + "DEVTOOLS_IMAGE": "ghcr.io/runwhen-contrib/codecollection-devtools:latest" + } + }, "remoteUser": "runwhen", "updateRemoteUserUID": false, "overrideCommand": false, diff --git a/Dockerfile b/Dockerfile index 1635c1f..37c4385 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,6 +48,22 @@ RUN set -eux; \ apt-get clean; \ rm -rf /var/lib/apt/lists/* +# docker-in-docker (devcontainer feature) sources /etc/os-release; "forky" is rejected. +# Align with bookworm apt pin above (also patched in .devcontainer/Dockerfile pre-features). +RUN set -eux; \ + for f in /usr/lib/os-release /etc/os-release; do \ + [ -e "$f" ] || continue; \ + target="$f"; \ + [ -L "$f" ] && target=$(readlink -f "$f"); \ + grep -q '^ID=debian' "$target" || continue; \ + sed -i \ + -e 's/^VERSION_CODENAME=.*/VERSION_CODENAME=bookworm/' \ + -e 's/^VERSION_ID=.*/VERSION_ID="12"/' \ + -e 's/^VERSION=.*/VERSION="12 (bookworm)"/' \ + -e 's|^PRETTY_NAME=.*|PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"|' \ + "$target"; \ + done + RUN echo "runwhen ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers # Architecture detection for multi-arch tool installs From 7f4dcab058b2f6440143580f78f618e62f6bffc0 Mon Sep 17 00:00:00 2001 From: stewartshea Date: Mon, 13 Apr 2026 11:47:36 -0400 Subject: [PATCH 2/4] Revert devcontainer on-demand build; use CI image only Drop .devcontainer/Dockerfile and restore image: in devcontainer.json. os-release normalization stays in the root Dockerfile (built by Actions). Made-with: Cursor --- .devcontainer/Dockerfile | 24 ------------------------ .devcontainer/devcontainer.json | 8 +------- Dockerfile | 2 +- 3 files changed, 2 insertions(+), 32 deletions(-) delete mode 100644 .devcontainer/Dockerfile diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index fe29d63..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# Codespaces / Dev Containers apply features (docker-in-docker) in a follow-on build -# stage. That installer sources /etc/os-release and only allows known VERSION_CODENAME -# values. Upstream base images may still report "forky" while apt is bookworm. -# -# This thin layer runs *before* features, so dind works even when GHCR :latest has -# not yet picked up the same normalization in the repo root Dockerfile. -ARG DEVTOOLS_IMAGE=ghcr.io/runwhen-contrib/codecollection-devtools:latest -FROM ${DEVTOOLS_IMAGE} - -USER root -RUN set -eux; \ - for f in /usr/lib/os-release /etc/os-release; do \ - [ -e "$f" ] || continue; \ - target="$f"; \ - [ -L "$f" ] && target=$(readlink -f "$f"); \ - grep -q '^ID=debian' "$target" || continue; \ - sed -i \ - -e 's/^VERSION_CODENAME=.*/VERSION_CODENAME=bookworm/' \ - -e 's/^VERSION_ID=.*/VERSION_ID="12"/' \ - -e 's/^VERSION=.*/VERSION="12 (bookworm)"/' \ - -e 's|^PRETTY_NAME=.*|PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"|' \ - "$target"; \ - done -USER runwhen diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b96444c..5ae5361 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,12 +1,6 @@ { "name": "CodeCollection DevTools", - "build": { - "dockerfile": "Dockerfile", - "context": ".", - "args": { - "DEVTOOLS_IMAGE": "ghcr.io/runwhen-contrib/codecollection-devtools:latest" - } - }, + "image": "ghcr.io/runwhen-contrib/codecollection-devtools:latest", "remoteUser": "runwhen", "updateRemoteUserUID": false, "overrideCommand": false, diff --git a/Dockerfile b/Dockerfile index 37c4385..7439367 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,7 +49,7 @@ RUN set -eux; \ rm -rf /var/lib/apt/lists/* # docker-in-docker (devcontainer feature) sources /etc/os-release; "forky" is rejected. -# Align with bookworm apt pin above (also patched in .devcontainer/Dockerfile pre-features). +# Align with bookworm apt pin above so Codespaces can use the CI-built image + dind. RUN set -eux; \ for f in /usr/lib/os-release /etc/os-release; do \ [ -e "$f" ] || continue; \ From 91f8b8259e26a041ba71e353595a4cf4db3c0192 Mon Sep 17 00:00:00 2001 From: stewartshea Date: Mon, 13 Apr 2026 17:17:53 -0400 Subject: [PATCH 3/4] Update .gitignore, README, and Taskfile for improved setup and clarity - Added .cursor/rules/ to .gitignore to prevent committing generated Cursor rules. - Updated README to clarify the location of installed skills and the symlink for codecollection. - Modified Taskfile to create a symlink for codecollection during setup and improved messaging for clarity. - Removed the on-create.sh script as its functionality is now handled by Taskfile. These changes enhance the developer experience by streamlining the setup process and providing clearer instructions. --- .devcontainer/devcontainer.json | 3 +- .devcontainer/on-create.sh | 122 ----------------------------- .gitignore | 4 +- README.md | 24 +++--- Taskfile.yml | 28 +++++-- docs/cursor-remote-devcontainer.md | 2 +- 6 files changed, 39 insertions(+), 144 deletions(-) delete mode 100755 .devcontainer/on-create.sh diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 5ae5361..9a12f3f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,7 +4,6 @@ "remoteUser": "runwhen", "updateRemoteUserUID": false, "overrideCommand": false, - "workspaceFolder": "/home/runwhen", "forwardPorts": [3000], "portsAttributes": { @@ -63,7 +62,7 @@ } }, "codespaces": { - "openFiles": ["codecollection/README.md"] + "openFiles": ["README.md"] } } } diff --git a/.devcontainer/on-create.sh b/.devcontainer/on-create.sh deleted file mode 100755 index 9f64dbf..0000000 --- a/.devcontainer/on-create.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/bash -# ====================================================================================== -# on-create.sh — Bootstrap a codecollection into the devtools environment -# -# Runs once when the devcontainer is created (onCreateCommand). -# Clones the target codecollection repo, installs its Python deps, and -# optionally checks out a PR branch for review. -# -# Environment variables (set via devcontainer.json or Codespaces secrets): -# -# CODECOLLECTION_REPO Git URL or GitHub shorthand (org/repo) of the -# codecollection to work on. -# Default: runwhen-contrib/rw-cli-codecollection -# -# CODECOLLECTION_BRANCH Branch to check out after clone. -# Default: main -# -# PR_NUMBER If set, fetch and check out the PR branch instead -# of CODECOLLECTION_BRANCH. Requires gh CLI auth. -# -# GITHUB_TOKEN Passed through for gh CLI auth (Codespaces injects -# this automatically). -# ====================================================================================== -set -euo pipefail - -RUNWHEN_HOME="/home/runwhen" -CODECOLLECTION_DIR="${RUNWHEN_HOME}/codecollection" -DEFAULT_REPO="runwhen-contrib/rw-cli-codecollection" - -REPO="${CODECOLLECTION_REPO:-$DEFAULT_REPO}" -BRANCH="${CODECOLLECTION_BRANCH:-main}" - -# Normalise shorthand "org/repo" → full HTTPS URL -if [[ "$REPO" != http* && "$REPO" != git@* ]]; then - REPO="https://github.com/${REPO}.git" -fi - -echo "=== CodeCollection DevTools Bootstrap ===" -echo " Repo: ${REPO}" -echo " Branch: ${BRANCH}" -echo " PR: ${PR_NUMBER:-none}" -echo "==========================================" - -# ------------------------------------------------------------------ -# 1. Clone the codecollection -# ------------------------------------------------------------------ -if [ -d "${CODECOLLECTION_DIR}/.git" ]; then - echo "Codecollection already cloned at ${CODECOLLECTION_DIR}, pulling latest..." - git -C "${CODECOLLECTION_DIR}" fetch --all --prune -else - # Remove placeholder dir if the image created one - rm -rf "${CODECOLLECTION_DIR}" - echo "Cloning ${REPO} → ${CODECOLLECTION_DIR} ..." - git clone --branch "${BRANCH}" "${REPO}" "${CODECOLLECTION_DIR}" -fi - -# ------------------------------------------------------------------ -# 2. Optionally check out a PR -# ------------------------------------------------------------------ -if [ -n "${PR_NUMBER:-}" ]; then - echo "Checking out PR #${PR_NUMBER}..." - cd "${CODECOLLECTION_DIR}" - if command -v gh &>/dev/null; then - gh pr checkout "${PR_NUMBER}" - else - echo "gh CLI not found — falling back to git fetch" - git fetch origin "pull/${PR_NUMBER}/head:pr-${PR_NUMBER}" - git checkout "pr-${PR_NUMBER}" - fi - echo "On branch: $(git branch --show-current)" -fi - -# ------------------------------------------------------------------ -# 3. Install codecollection Python dependencies -# ------------------------------------------------------------------ -if [ -f "${CODECOLLECTION_DIR}/requirements.txt" ]; then - echo "Installing codecollection requirements..." - pip install --user --no-cache-dir -r "${CODECOLLECTION_DIR}/requirements.txt" -fi - -# ------------------------------------------------------------------ -# 4. Install CodeBundle authoring skills as Cursor rules -# ------------------------------------------------------------------ -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -DEVTOOLS_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" -SKILLS_SRC="${DEVTOOLS_ROOT}/skills" -RULES_DIR="${CODECOLLECTION_DIR}/.cursor/rules" - -if [ -d "${SKILLS_SRC}" ]; then - mkdir -p "${RULES_DIR}" - for skill in "${SKILLS_SRC}"/*.md; do - [ -f "$skill" ] || continue - base=$(basename "$skill" .md) - cp "$skill" "${RULES_DIR}/${base}.mdc" - echo " Installed skill: ${base}" - done - if [ ! -f "${RULES_DIR}/.gitignore" ]; then - printf '# Injected by codecollection-devtools -- do not commit\n*.mdc\n' > "${RULES_DIR}/.gitignore" - fi - echo "Skills installed to ${RULES_DIR}" -else - echo "Skills directory not found at ${SKILLS_SRC}, skipping." -fi - -# ------------------------------------------------------------------ -# 5. Ensure auth directory exists for credential mounts -# ------------------------------------------------------------------ -mkdir -p "${RUNWHEN_HOME}/auth" - -# ------------------------------------------------------------------ -# 6. Verify key tools are available -# ------------------------------------------------------------------ -echo "" -echo "--- Environment ready ---" -echo " ro: $(command -v ro && echo 'ok' || echo 'MISSING')" -echo " robot: $(command -v robot && echo 'ok' || echo 'MISSING')" -echo " kubectl: $(command -v kubectl && echo 'ok' || echo 'MISSING')" -echo " gh: $(command -v gh && echo 'ok' || echo 'MISSING')" -echo " python: $(python --version 2>&1)" -echo "" -echo "Codecollection bootstrapped at ${CODECOLLECTION_DIR}" -echo "Run 'cd codecollection/codebundles/ && ro' to test a codebundle." diff --git a/.gitignore b/.gitignore index c33a103..051548f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,8 +8,8 @@ __pycache__ *robot_logs* .python-version .vscode/settings.json +# Generated by `task install-skills` (Cursor rules); do not commit +.cursor/rules/ node_modules/ package-lock.json package.json -/workspace/codecollection-devtools/rw-cli-codecollection -/workspace/codecollection-devtools/rw-generic-codecollection diff --git a/README.md b/README.md index f0ae905..00c27a7 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ generation rules, SLI patterns, and test infrastructure conventions. | `test-infra-azure-devops.md` | DevOps projects, pipelines, agent pools via Terraform | | `test-infra-cloud.md` | Shared conventions across all cloud platforms | -Skills are copied to `{codecollection}/.cursor/rules/*.mdc` at setup time. A +Skills are copied to `.cursor/rules/*.mdc` (the workspace root) at setup time. A `.gitignore` is placed in that directory to prevent accidental commits. To re-install after an update, run: @@ -197,7 +197,7 @@ Base packages installed in the image (from `requirements.txt`): - `rw-cli-keywords` (includes `rw-core-keywords` — handles `RW_MODE=dev` for local development) - `jmespath`, `python-dateutil`, `thefuzz`, `jinja2` -Each codecollection's `requirements.txt` is installed at bootstrap time by `on-create.sh`. +Each codecollection's `requirements.txt` is installed at bootstrap time by `task setup`. --- @@ -206,8 +206,7 @@ Each codecollection's `requirements.txt` is installed at bootstrap time by `on-c ``` codecollection-devtools/ ├── .devcontainer/ -│ ├── devcontainer.json # devcontainer config (pulls pre-built image) -│ └── on-create.sh # bootstrap script (called by Taskfile) +│ └── devcontainer.json # devcontainer config (pulls pre-built image) ├── .github/ │ └── workflows/ │ ├── build-push.yaml # CI: multi-arch build → GHCR + GCP Artifact Registry @@ -246,16 +245,23 @@ All image builds happen in **GitHub Actions** — never locally: ``` devcontainer opens → pulls pre-built image from GHCR + → workspace root is /workspaces/codecollection-devtools/ (the repo mount) → starts log HTTP server on port 3000 → user runs: task setup REPO=org/repo PR=123 1. clones repo into /home/runwhen/codecollection/ - 2. checks out PR branch (if PR set) - 3. pip installs codecollection's requirements.txt - 4. installs skills/ as .cursor/rules/*.mdc - 5. verifies tools (ro, robot, kubectl, gh, python) - → ready to develop + 2. symlinks ./codecollection → /home/runwhen/codecollection + 3. checks out PR branch (if PR set) + 4. pip installs codecollection's requirements.txt + 5. installs skills/ as .cursor/rules/*.mdc (workspace root) + 6. verifies tools (ro, robot, kubectl, gh, python) + → ready: cd codecollection/codebundles/ && ro ``` +> **Two repos, one tree.** The workspace root is the devtools repo. The `codecollection/` +> directory is a symlink to a separate git clone. `git` commands inside `codecollection/` +> operate on the codecollection repo — not devtools. The `.gitignore` prevents the +> symlink from being tracked. + --- ## For codecollection authors diff --git a/Taskfile.yml b/Taskfile.yml index f13456a..c5654f9 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -54,6 +54,15 @@ tasks: echo "Cloning {{.REPO_URL}} → {{.CODECOLLECTION_DIR}} ..." git clone --branch "{{.BRANCH}}" "{{.REPO_URL}}" "{{.CODECOLLECTION_DIR}}" fi + - | + LINK="{{.TASKFILE_DIR}}/codecollection" + if [ "$(readlink -f "$LINK" 2>/dev/null)" = "$(readlink -f "{{.CODECOLLECTION_DIR}}")" ]; then + : + else + rm -f "$LINK" + ln -s "{{.CODECOLLECTION_DIR}}" "$LINK" + echo "Symlinked $LINK → {{.CODECOLLECTION_DIR}}" + fi checkout-pr: desc: Check out a PR branch @@ -84,22 +93,20 @@ tasks: desc: Install CodeBundle authoring skills as Cursor rules cmds: - | - RULES_DIR="{{.CODECOLLECTION_DIR}}/.cursor/rules" if [ ! -d "{{.SKILLS_SRC}}" ]; then echo "Skills directory not found at {{.SKILLS_SRC}}, skipping." exit 0 fi + RULES_DIR="{{.TASKFILE_DIR}}/.cursor/rules" mkdir -p "$RULES_DIR" for skill in "{{.SKILLS_SRC}}"/*.md; do [ -f "$skill" ] || continue base=$(basename "$skill" .md) - target="$RULES_DIR/${base}.mdc" - cp "$skill" "$target" - echo " Installed skill: ${base}" + cp "$skill" "$RULES_DIR/${base}.mdc" + echo " Installed: ${base}" done if [ ! -f "$RULES_DIR/.gitignore" ]; then - echo "# Injected by codecollection-devtools -- do not commit" > "$RULES_DIR/.gitignore" - echo "*.mdc" >> "$RULES_DIR/.gitignore" + printf '# Injected by codecollection-devtools -- do not commit\n*.mdc\n' > "$RULES_DIR/.gitignore" fi echo "Skills installed to $RULES_DIR" @@ -114,12 +121,17 @@ tasks: - 'printf " %-12s %s\n" "gh:" "$(command -v gh 2>/dev/null && echo ok || echo MISSING)"' - 'printf " %-12s %s\n" "python:" "$(python --version 2>&1)"' - echo "" - - echo "Codecollection at {{.CODECOLLECTION_DIR}}" - - echo "Run 'cd codecollection/codebundles/ && ro' to test a codebundle." + - echo "Codecollection at {{.CODECOLLECTION_DIR}} (symlinked from ./codecollection)" + - echo "" + - echo "Your work happens in the codecollection (its own git repo):" + - echo " cd codecollection/codebundles/ && ro" + - echo "" + - echo "Commits in ./codecollection go to the codecollection repo, not devtools." clean: desc: Remove the cloned codecollection (start fresh) prompt: This will delete {{.CODECOLLECTION_DIR}}. Continue? cmds: + - rm -f "{{.TASKFILE_DIR}}/codecollection" - rm -rf "{{.CODECOLLECTION_DIR}}" - echo "Cleaned. Run 'task setup REPO=... ' to start again." diff --git a/docs/cursor-remote-devcontainer.md b/docs/cursor-remote-devcontainer.md index 13d5314..9ee04e1 100644 --- a/docs/cursor-remote-devcontainer.md +++ b/docs/cursor-remote-devcontainer.md @@ -75,7 +75,7 @@ sed -i.bak \ ~/.ssh/codespaces ``` -In Cursor: **Remote-SSH: Connect to Host…** → select that host → **Open Folder** → **`/home/runwhen`**. +In Cursor: **Remote-SSH: Connect to Host…** → select that host → **Open Folder** → **`/workspaces/codecollection-devtools`** (the devcontainer workspace root). After `task setup`, the `codecollection/` symlink gives you direct access to codebundles. --- From 3e4f700011a94f0354308c8270402bb2fe158022 Mon Sep 17 00:00:00 2001 From: stewartshea Date: Mon, 13 Apr 2026 17:28:55 -0400 Subject: [PATCH 4/4] Enhance Dockerfile and devcontainer configuration for SSH setup - Updated Dockerfile to create the .ssh directory and set appropriate permissions for SSH access. - Added a postCreateCommand in devcontainer.json to ensure the .ssh directory and authorized_keys file are created with correct permissions automatically. - Revised documentation to clarify that SSH permission errors should not occur due to these automated setups. These changes improve the security and usability of the development environment. --- .devcontainer/devcontainer.json | 1 + Dockerfile | 8 +++++--- docs/cursor-remote-devcontainer.md | 8 +------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 9a12f3f..03e4077 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -19,6 +19,7 @@ "GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}" }, + "postCreateCommand": "chmod 755 /home/runwhen && mkdir -p /home/runwhen/.ssh && chmod 700 /home/runwhen/.ssh && touch /home/runwhen/.ssh/authorized_keys && chmod 600 /home/runwhen/.ssh/authorized_keys", "postStartCommand": "python -m http.server --bind 0.0.0.0 --directory /robot_logs 3000 &", "features": { diff --git a/Dockerfile b/Dockerfile index 7439367..b1cf68c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -176,9 +176,11 @@ RUN mkdir -p $ROBOT_LOG_DIR && \ COPY --chown=runwhen:0 .pylintrc.google LICENSE ro requirements.txt . COPY --chown=runwhen:0 .devcontainer/ .devcontainer/ -RUN mkdir -p auth && \ - chown -R runwhen:0 ${RUNWHEN_HOME}/.devcontainer ${RUNWHEN_HOME}/auth && \ - chmod -R 0775 ${RUNWHEN_HOME}/ro ${RUNWHEN_HOME}/auth ${RUNWHEN_HOME}/.devcontainer +RUN mkdir -p auth .ssh && \ + chown -R runwhen:0 ${RUNWHEN_HOME}/.devcontainer ${RUNWHEN_HOME}/auth ${RUNWHEN_HOME}/.ssh && \ + chmod -R 0775 ${RUNWHEN_HOME}/ro ${RUNWHEN_HOME}/auth ${RUNWHEN_HOME}/.devcontainer && \ + chmod 755 ${RUNWHEN_HOME} && \ + chmod 700 ${RUNWHEN_HOME}/.ssh USER runwhen ENV USER="runwhen" diff --git a/docs/cursor-remote-devcontainer.md b/docs/cursor-remote-devcontainer.md index 9ee04e1..c16a619 100644 --- a/docs/cursor-remote-devcontainer.md +++ b/docs/cursor-remote-devcontainer.md @@ -82,13 +82,7 @@ In Cursor: **Remote-SSH: Connect to Host…** → select that host → **Open Fo ## 5. Troubleshooting - Run **`gh codespace ssh -c YOUR_CODESPACE_NAME --`** again if the connection or auth state seems off. -- For **`authorized_keys`** permission errors inside the codespace: - - ```bash - sudo chmod 755 /home/runwhen - sudo chmod 700 /home/runwhen/.ssh - sudo chmod 600 /home/runwhen/.ssh/authorized_keys - ``` +- SSH permission errors should not occur — the image and `postCreateCommand` set `/home/runwhen` (755), `.ssh` (700), and `authorized_keys` (600) automatically. ---