commit ccbb7f5c54e0dd314cb182170793c58c82b04b49 Author: James Brechtel Date: Thu Jun 4 15:25:34 2026 -0400 chore: add OCI image design spec for Roc compiler/dev environment diff --git a/docs/specs/2026-06-04-roc-oci-images-design.md b/docs/specs/2026-06-04-roc-oci-images-design.md new file mode 100644 index 0000000..4b511fa --- /dev/null +++ b/docs/specs/2026-06-04-roc-oci-images-design.md @@ -0,0 +1,170 @@ +# Roc Language OCI Images + +**Date:** 2026-06-04 +**Status:** Design — approved + +## Overview + +Build and publish OCI container images for the [Roc language](https://roc-lang.org/) compiler/development environment. Three images (base, dev, ci) defined in a single multi-stage `Containerfile`, published to a self-hosted Gitea container registry (`git.roo.lol`). + +## Image Architecture + +``` +debian:bookworm-slim + └── roc-tools-base — Roc compiler binary + lib/wasi-libc.a + LICENSE + ├── roc-tools-dev — Base + LSP + git + curl + bash + ca-certificates + └── roc-tools-ci — Base + ca-certificates (minimal runner) +``` + +## Repository Structure + +``` +roc-lang-tools/ +├── Containerfile # Multi-stage: base / dev / ci targets +├── Makefile # Build & push convenience commands +├── scripts/ +│ └── download-roc.sh # Download & extract a specific Roc release tarball +├── docs/ +│ └── specs/ +│ └── 2026-06-04-roc-oci-images-design.md +└── .gitea/ + └── workflows/ + └── build.yaml # Gitea Actions CI: build & push on version tags +``` + +## Image Registry + +All images published to `git.roo.lol/jbrechtel/` with the following naming: + +| Image | Repository | Tags | +|----------|------------------------------------------|-------------------------------| +| base | `git.roo.lol/jbrechtel/roc-tools-base` | `:X.Y.Z`, `:X.Y.Z-alphaN` | +| dev | `git.roo.lol/jbrechtel/roc-tools-dev` | `:X.Y.Z`, `:X.Y.Z-alphaN` | +| ci | `git.roo.lol/jbrechtel/roc-tools-ci` | `:X.Y.Z`, `:X.Y.Z-alphaN` | + +Tags mirror Roc release tags (e.g., `0.0.0-alpha2`). The `:latest` tag follows the most recently built version tag. + +## Build Arguments + +The `Containerfile` accepts two build arguments: + +| Argument | Description | Default | +|----------------|------------------------------------------|----------------| +| `ROC_VERSION` | Roc GitHub release tag to download | `0.0.0-alpha2` | +| `TARGETARCH` | Target CPU architecture (set by buildx) | `amd64` | + +Multi-arch is supported via `docker buildx` — the download script maps `TARGETARCH` to Roc tarball names (`x86_64` / `aarch64`). + +## Image Details + +### Base (`roc-tools-base`) + +The base image provides just the Roc compiler and its runtime library. + +**Installed:** +- `/opt/roc/bin/roc` — Roc compiler binary +- `/opt/roc/lib/wasi-libc.a` — WASI libc runtime library (required by some platforms) +- `/opt/roc/LICENSE` — Roc license file +- `ca-certificates` (build-time only, removed from final layer) +- `roc` user/group (UID 1000) +- `PATH` includes `/opt/roc/bin` + +**Entrypoint:** `roc` + +### Dev (`roc-tools-dev`) + +Full interactive development environment. + +**Inherits:** Base image + +**Additional packages:** `git`, `curl`, `bash`, `ca-certificates` + +**Additional files:** +- `/opt/roc/bin/roc_language_server` — Roc LSP server (included in the release tarball) + +**Entrypoint:** `bash` + +**Use case:** +```bash +docker run -it --rm -v $(pwd):/work -w /work git.roo.lol/jbrechtel/roc-tools-dev +``` + +### CI (`roc-tools-ci`) + +Minimal image for CI/CD runner pipelines (Gitea Actions, GitLab CI, etc.). + +**Inherits:** Base image + +**Additional packages:** `ca-certificates` + +**Entrypoint:** `roc` + +**Use case:** +```yaml +- run: docker run --rm git.roo.lol/jbrechtel/roc-tools-ci roc build +``` + +## Release Download Strategy + +The `scripts/download-roc.sh` script: + +1. Accepts `ROC_VERSION` and `TARGETARCH` arguments +2. Constructs the GitHub release URL: + ``` + https://github.com/roc-lang/roc/releases/download/{ROC_VERSION}/roc-linux_{ARCH}-{ROC_VERSION}.tar.gz + ``` + Where `ARCH` is `x86_64` (for amd64) or `aarch64` (for arm64). +3. Downloads and extracts the tarball +4. Copies the `roc` and `roc_language_server` binaries to `/opt/roc/bin/` +5. Copies `lib/wasi-libc.a` to `/opt/roc/lib/` +6. Copies `LICENSE` to `/opt/roc/` + +The tarball contains a top-level directory with a nightly-derived name (e.g., `roc_nightly-linux_x86_64-2025-09-09-d73ea109/`), so the script uses a glob/wildcard rather than assuming a fixed directory name. + +## Build Workflow + +### Local Development + +```bash +# Build all three images +make build-all ROC_VERSION=0.0.0-alpha2 + +# Build a specific target +make build-dev ROC_VERSION=0.0.0-alpha2 + +# Build and push +make push-all ROC_VERSION=0.0.0-alpha2 + +# Override registry +make build-base ROC_VERSION=0.0.0-alpha2 REGISTRY=localhost:5000 +``` + +### CI/CD (Gitea Actions) + +The `.gitea/workflows/build.yaml` workflow triggers on Git tags matching `v*` (e.g., `v0.0.0-alpha2`). It: + +1. Extracts the Roc version from the tag (`v0.0.0-alpha2` → `0.0.0-alpha2`) +2. Sets up Docker Buildx with multi-arch support (linux/amd64, linux/arm64) +3. Logs into the Gitea container registry using the Gitea Actions token +4. Builds and pushes all three image targets in a single build command +5. Tags each image with both the version and `:latest` + +## Makefile Targets + +| Target | Description | +|--------------|-----------------------------------------| +| `build-base` | Build the base image | +| `build-dev` | Build the dev image | +| `build-ci` | Build the ci image | +| `push-all` | Build all images and push to registry | +| `build-all` | Build all three images (no push) | + +Variables: `ROC_VERSION` (default `0.0.0-alpha2`), `REGISTRY` (default `git.roo.lol/jbrechtel`). + +## Security Considerations + +- Images run as non-root `roc` user (UID 1000) +- `debian:bookworm-slim` base receives regular security patches +- Only `ca-certificates` and essential packages are added beyond the binary +- The base image has no shell or package manager in the final stage +- Dev image has a shell (bash) by design for interactive use