Skip to content

Commit 532a54e

Browse files
castrojoCopilot
andcommitted
feat(devcontainer): add devc CLI helper and devcontainer skill doc
- install.sh: devc CLI (up/shell/build/stop/self-install) adapted from trailofbits/devcontainer-setup skill pattern - skills/devcontainer.md: documents design decisions, local workflow, how to add tools, and devcontainers/ci future migration plan Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b8ca533 commit 532a54e

File tree

2 files changed

+130
-0
lines changed

2 files changed

+130
-0
lines changed

.devcontainer/install.sh

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env bash
2+
# devc — CLI helper for the testhub devcontainer
3+
# Adapted from trailofbits/devcontainer-setup (https://skills.sh/trailofbits/skills/devcontainer-setup)
4+
#
5+
# Usage:
6+
# .devcontainer/install.sh self-install # install `devc` to ~/.local/bin
7+
# devc up # start the devcontainer
8+
# devc shell # open a shell in the running container
9+
# devc build <app> # run `just loop <app>` inside the container
10+
# devc stop # stop the devcontainer
11+
12+
set -euo pipefail
13+
14+
WORKSPACE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
15+
SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/install.sh"
16+
17+
case "${1:-help}" in
18+
self-install)
19+
mkdir -p "$HOME/.local/bin"
20+
ln -sf "$SCRIPT_PATH" "$HOME/.local/bin/devc"
21+
echo "✓ devc installed to ~/.local/bin/devc"
22+
echo " Make sure ~/.local/bin is on your PATH"
23+
;;
24+
25+
up)
26+
echo "Starting devcontainer..."
27+
devcontainer up --workspace-folder "$WORKSPACE_DIR"
28+
;;
29+
30+
shell)
31+
devcontainer exec --workspace-folder "$WORKSPACE_DIR" bash
32+
;;
33+
34+
build)
35+
APP="${2:-}"
36+
if [[ -z "$APP" ]]; then
37+
echo "Usage: devc build <app>" >&2
38+
exit 1
39+
fi
40+
devcontainer exec --workspace-folder "$WORKSPACE_DIR" just loop "$APP"
41+
;;
42+
43+
stop)
44+
# devcontainer CLI doesn't have stop; find and stop the container
45+
CONTAINER=$(docker ps --filter "label=devcontainer.local_folder=$WORKSPACE_DIR" -q | head -1)
46+
if [[ -z "$CONTAINER" ]]; then
47+
echo "No running devcontainer found for $WORKSPACE_DIR" >&2
48+
exit 1
49+
fi
50+
docker stop "$CONTAINER"
51+
echo "✓ devcontainer stopped"
52+
;;
53+
54+
help|*)
55+
echo "Usage: devc <command>"
56+
echo ""
57+
echo "Commands:"
58+
echo " self-install Install devc to ~/.local/bin"
59+
echo " up Start the devcontainer"
60+
echo " shell Open a shell in the running container"
61+
echo " build <app> Run \`just loop <app>\` inside the container"
62+
echo " stop Stop the running container"
63+
;;
64+
esac

skills/devcontainer.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Devcontainer
2+
3+
Adapted from [trailofbits/devcontainer-setup](https://skills.sh/trailofbits/skills/devcontainer-setup).
4+
5+
## Overview
6+
7+
The devcontainer uses `ghcr.io/flathub-infra/flatpak-github-actions:gnome-49` — the same
8+
image CI uses for `compile-oci`. This gives full local/CI parity: same tools, same runtime,
9+
same `flatpak-builder` version.
10+
11+
**Open in VS Code:** "Reopen in Container"
12+
**CLI helper:** `.devcontainer/install.sh self-install` → adds `devc` command to PATH
13+
14+
## Key design decisions
15+
16+
| Decision | Reason |
17+
|---|---|
18+
| Same gnome-49 image as CI | Local/CI parity; no drift |
19+
| `SOURCE_DATE_EPOCH=0` in containerEnv | Deterministic builds match CI |
20+
| `postCreateCommand` installs just + yq | These are not in base image; versions pinned to match CI |
21+
| No Dockerfile | Base image is immutable infra-managed; avoid drift by not layering |
22+
| `.flatpak-builder/` not in a volume | It lives in the workspace (bind mount) so it persists naturally |
23+
24+
## Persistent volumes (from Trail of Bits pattern)
25+
26+
Named volumes survive container rebuilds. Format:
27+
28+
```json
29+
"mounts": [
30+
"source={{PROJECT_SLUG}}-<purpose>-${devcontainerId},target=<path>,type=volume"
31+
]
32+
```
33+
34+
Currently no extra volumes are needed — workspace bind mount covers `.flatpak-builder/`
35+
cache and OSTree repos. Add volumes if any of these move outside the workspace.
36+
37+
## Local build workflow
38+
39+
```bash
40+
# Build one app locally (same as CI compile-oci, no ghcr.io push)
41+
just loop <app>
42+
43+
# Build all apps locally
44+
just loop-all
45+
46+
# Run full build + push to ghcr.io (requires GITHUB_TOKEN with packages:write)
47+
just build <app>
48+
```
49+
50+
## Adding new tools to the devcontainer
51+
52+
1. If the tool has a `just install-tools-*` recipe, add it to `postCreateCommand`
53+
2. If not, add an `apt-get install` or `curl` step — do NOT modify the base image
54+
3. Pin versions to match CI (check `.github/workflows/build.yml`)
55+
56+
## `devcontainers/ci` in CI (future work)
57+
58+
The goal is to replace the bare `container:` stanza in `compile-oci` with
59+
`devcontainers/ci@v0.3` so this `devcontainer.json` becomes the single source of truth.
60+
61+
**Blocker:** `flatpak/flatpak-github-actions/flatpak-builder@v6` is a GitHub Action that
62+
cannot be called from inside `devcontainers/ci`'s `runCmd`. Migration requires replacing
63+
it with direct `flatpak-builder` commands + manual ccache wiring in a Justfile recipe.
64+
65+
See `skills/pipeline.md` → "devcontainers/ci for compile-oci (future work)" for the
66+
full migration plan.

0 commit comments

Comments
 (0)