Skip to content

Commit 8b3c6f2

Browse files
authored
Fix/setup flow (#28)
* 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 * 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 * 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. * 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.
1 parent 54b55da commit 8b3c6f2

7 files changed

Lines changed: 46 additions & 154 deletions

File tree

.devcontainer/devcontainer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"remoteUser": "runwhen",
55
"updateRemoteUserUID": false,
66
"overrideCommand": false,
7-
"workspaceFolder": "/home/runwhen",
87

98
"forwardPorts": [3000],
109
"portsAttributes": {
@@ -20,6 +19,7 @@
2019
"GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}"
2120
},
2221

22+
"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",
2323
"postStartCommand": "python -m http.server --bind 0.0.0.0 --directory /robot_logs 3000 &",
2424

2525
"features": {
@@ -63,7 +63,7 @@
6363
}
6464
},
6565
"codespaces": {
66-
"openFiles": ["codecollection/README.md"]
66+
"openFiles": ["README.md"]
6767
}
6868
}
6969
}

.devcontainer/on-create.sh

Lines changed: 0 additions & 122 deletions
This file was deleted.

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ __pycache__
88
*robot_logs*
99
.python-version
1010
.vscode/settings.json
11+
# Generated by `task install-skills` (Cursor rules); do not commit
12+
.cursor/rules/
1113
node_modules/
1214
package-lock.json
1315
package.json
14-
/workspace/codecollection-devtools/rw-cli-codecollection
15-
/workspace/codecollection-devtools/rw-generic-codecollection

Dockerfile

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,11 @@ RUN mkdir -p $ROBOT_LOG_DIR && \
176176

177177
COPY --chown=runwhen:0 .pylintrc.google LICENSE ro requirements.txt .
178178
COPY --chown=runwhen:0 .devcontainer/ .devcontainer/
179-
RUN mkdir -p auth && \
180-
chown -R runwhen:0 ${RUNWHEN_HOME}/.devcontainer ${RUNWHEN_HOME}/auth && \
181-
chmod -R 0775 ${RUNWHEN_HOME}/ro ${RUNWHEN_HOME}/auth ${RUNWHEN_HOME}/.devcontainer
179+
RUN mkdir -p auth .ssh && \
180+
chown -R runwhen:0 ${RUNWHEN_HOME}/.devcontainer ${RUNWHEN_HOME}/auth ${RUNWHEN_HOME}/.ssh && \
181+
chmod -R 0775 ${RUNWHEN_HOME}/ro ${RUNWHEN_HOME}/auth ${RUNWHEN_HOME}/.devcontainer && \
182+
chmod 755 ${RUNWHEN_HOME} && \
183+
chmod 700 ${RUNWHEN_HOME}/.ssh
182184

183185
USER runwhen
184186
ENV USER="runwhen"

README.md

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ generation rules, SLI patterns, and test infrastructure conventions.
167167
| `test-infra-azure-devops.md` | DevOps projects, pipelines, agent pools via Terraform |
168168
| `test-infra-cloud.md` | Shared conventions across all cloud platforms |
169169

170-
Skills are copied to `{codecollection}/.cursor/rules/*.mdc` at setup time. A
170+
Skills are copied to `.cursor/rules/*.mdc` (the workspace root) at setup time. A
171171
`.gitignore` is placed in that directory to prevent accidental commits. To
172172
re-install after an update, run:
173173

@@ -197,7 +197,7 @@ Base packages installed in the image (from `requirements.txt`):
197197
- `rw-cli-keywords` (includes `rw-core-keywords` — handles `RW_MODE=dev` for local development)
198198
- `jmespath`, `python-dateutil`, `thefuzz`, `jinja2`
199199

200-
Each codecollection's `requirements.txt` is installed at bootstrap time by `on-create.sh`.
200+
Each codecollection's `requirements.txt` is installed at bootstrap time by `task setup`.
201201

202202
---
203203

@@ -206,8 +206,7 @@ Each codecollection's `requirements.txt` is installed at bootstrap time by `on-c
206206
```
207207
codecollection-devtools/
208208
├── .devcontainer/
209-
│ ├── devcontainer.json # devcontainer config (pulls pre-built image)
210-
│ └── on-create.sh # bootstrap script (called by Taskfile)
209+
│ └── devcontainer.json # devcontainer config (pulls pre-built image)
211210
├── .github/
212211
│ └── workflows/
213212
│ ├── build-push.yaml # CI: multi-arch build → GHCR + GCP Artifact Registry
@@ -246,16 +245,23 @@ All image builds happen in **GitHub Actions** — never locally:
246245
```
247246
devcontainer opens
248247
→ pulls pre-built image from GHCR
248+
→ workspace root is /workspaces/codecollection-devtools/ (the repo mount)
249249
→ starts log HTTP server on port 3000
250250
→ user runs: task setup REPO=org/repo PR=123
251251
1. clones repo into /home/runwhen/codecollection/
252-
2. checks out PR branch (if PR set)
253-
3. pip installs codecollection's requirements.txt
254-
4. installs skills/ as .cursor/rules/*.mdc
255-
5. verifies tools (ro, robot, kubectl, gh, python)
256-
→ ready to develop
252+
2. symlinks ./codecollection → /home/runwhen/codecollection
253+
3. checks out PR branch (if PR set)
254+
4. pip installs codecollection's requirements.txt
255+
5. installs skills/ as .cursor/rules/*.mdc (workspace root)
256+
6. verifies tools (ro, robot, kubectl, gh, python)
257+
→ ready: cd codecollection/codebundles/<name> && ro
257258
```
258259

260+
> **Two repos, one tree.** The workspace root is the devtools repo. The `codecollection/`
261+
> directory is a symlink to a separate git clone. `git` commands inside `codecollection/`
262+
> operate on the codecollection repo — not devtools. The `.gitignore` prevents the
263+
> symlink from being tracked.
264+
259265
---
260266

261267
## For codecollection authors

Taskfile.yml

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@ tasks:
5454
echo "Cloning {{.REPO_URL}} → {{.CODECOLLECTION_DIR}} ..."
5555
git clone --branch "{{.BRANCH}}" "{{.REPO_URL}}" "{{.CODECOLLECTION_DIR}}"
5656
fi
57+
- |
58+
LINK="{{.TASKFILE_DIR}}/codecollection"
59+
if [ "$(readlink -f "$LINK" 2>/dev/null)" = "$(readlink -f "{{.CODECOLLECTION_DIR}}")" ]; then
60+
:
61+
else
62+
rm -f "$LINK"
63+
ln -s "{{.CODECOLLECTION_DIR}}" "$LINK"
64+
echo "Symlinked $LINK → {{.CODECOLLECTION_DIR}}"
65+
fi
5766
5867
checkout-pr:
5968
desc: Check out a PR branch
@@ -84,22 +93,20 @@ tasks:
8493
desc: Install CodeBundle authoring skills as Cursor rules
8594
cmds:
8695
- |
87-
RULES_DIR="{{.CODECOLLECTION_DIR}}/.cursor/rules"
8896
if [ ! -d "{{.SKILLS_SRC}}" ]; then
8997
echo "Skills directory not found at {{.SKILLS_SRC}}, skipping."
9098
exit 0
9199
fi
100+
RULES_DIR="{{.TASKFILE_DIR}}/.cursor/rules"
92101
mkdir -p "$RULES_DIR"
93102
for skill in "{{.SKILLS_SRC}}"/*.md; do
94103
[ -f "$skill" ] || continue
95104
base=$(basename "$skill" .md)
96-
target="$RULES_DIR/${base}.mdc"
97-
cp "$skill" "$target"
98-
echo " Installed skill: ${base}"
105+
cp "$skill" "$RULES_DIR/${base}.mdc"
106+
echo " Installed: ${base}"
99107
done
100108
if [ ! -f "$RULES_DIR/.gitignore" ]; then
101-
echo "# Injected by codecollection-devtools -- do not commit" > "$RULES_DIR/.gitignore"
102-
echo "*.mdc" >> "$RULES_DIR/.gitignore"
109+
printf '# Injected by codecollection-devtools -- do not commit\n*.mdc\n' > "$RULES_DIR/.gitignore"
103110
fi
104111
echo "Skills installed to $RULES_DIR"
105112
@@ -114,12 +121,17 @@ tasks:
114121
- 'printf " %-12s %s\n" "gh:" "$(command -v gh 2>/dev/null && echo ok || echo MISSING)"'
115122
- 'printf " %-12s %s\n" "python:" "$(python --version 2>&1)"'
116123
- echo ""
117-
- echo "Codecollection at {{.CODECOLLECTION_DIR}}"
118-
- echo "Run 'cd codecollection/codebundles/<name> && ro' to test a codebundle."
124+
- echo "Codecollection at {{.CODECOLLECTION_DIR}} (symlinked from ./codecollection)"
125+
- echo ""
126+
- echo "Your work happens in the codecollection (its own git repo):"
127+
- echo " cd codecollection/codebundles/<name> && ro"
128+
- echo ""
129+
- echo "Commits in ./codecollection go to the codecollection repo, not devtools."
119130

120131
clean:
121132
desc: Remove the cloned codecollection (start fresh)
122133
prompt: This will delete {{.CODECOLLECTION_DIR}}. Continue?
123134
cmds:
135+
- rm -f "{{.TASKFILE_DIR}}/codecollection"
124136
- rm -rf "{{.CODECOLLECTION_DIR}}"
125137
- echo "Cleaned. Run 'task setup REPO=... ' to start again."

docs/cursor-remote-devcontainer.md

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,20 +75,14 @@ sed -i.bak \
7575
~/.ssh/codespaces
7676
```
7777

78-
In Cursor: **Remote-SSH: Connect to Host…** → select that host → **Open Folder****`/home/runwhen`**.
78+
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.
7979

8080
---
8181

8282
## 5. Troubleshooting
8383

8484
- Run **`gh codespace ssh -c YOUR_CODESPACE_NAME --`** again if the connection or auth state seems off.
85-
- For **`authorized_keys`** permission errors inside the codespace:
86-
87-
```bash
88-
sudo chmod 755 /home/runwhen
89-
sudo chmod 700 /home/runwhen/.ssh
90-
sudo chmod 600 /home/runwhen/.ssh/authorized_keys
91-
```
85+
- SSH permission errors should not occur — the image and `postCreateCommand` set `/home/runwhen` (755), `.ssh` (700), and `authorized_keys` (600) automatically.
9286

9387
---
9488

0 commit comments

Comments
 (0)