Skip to content

Set up dev container features repo with publish pipeline #1

Closed

Description

Goal

Create a reusable dev container features repository for the savvy-web org. Features are modular install scripts published as OCI artifacts to ghcr.io/savvy-web/devcontainers/<feature> and referenced in any repo's devcontainer.json without needing a custom Dockerfile.

Background

We currently duplicate devcontainer Dockerfile setup across repos. The dev container features spec (https://containers.dev/implementors/features/) lets us extract reusable pieces into independently versioned, option-configurable install scripts. This repo will hold org-specific tooling features; general-purpose features (bats-kcov, language runtimes) will live in a separate personal repo.

Repo structure

devcontainers/
  src/
    claude-code/
      devcontainer-feature.json
      install.sh
    biome/
      devcontainer-feature.json
      install.sh
    outbound-firewall/
      devcontainer-feature.json
      install.sh
      init-firewall.sh
    savvy-toolchain/
      devcontainer-feature.json
      install.sh
  test/
    claude-code/
      test.sh
      scenarios.json
    biome/
      test.sh
      scenarios.json
    outbound-firewall/
      test.sh
      scenarios.json
    savvy-toolchain/
      test.sh
      scenarios.json
  .github/
    workflows/
      publish.yml
      test.yml

Planned features

claude-code

Installs Claude Code via Homebrew. Options: version (default: latest).

biome

Installs Biome as a pinned binary from GitHub releases. Options: version (required). Handles architecture detection (x64/arm64). Provides the LSP binary for the VS Code extension.

outbound-firewall

Installs an iptables-based outbound firewall that whitelists GitHub, npm, and Anthropic endpoints. Restricts AI agent internet access in dev containers. Options: extraDomains (additional domains to whitelist). Auto-skips in Codespaces (VS Code Server needs unrestricted outbound for relay communication).

savvy-toolchain

Installs the common savvy-web dev toolchain: commitlint config, lint-staged config, pnpm plugin. Options: commitlint (bool), lintStaged (bool). Sets up COREPACK_ENABLE_DOWNLOAD_PROMPT=0 and pnpm store directory.

Publish pipeline

Use devcontainers/action@v1 in GitHub Actions:

  • Test job: Runs test.sh for each feature against each scenario (different base images, option combinations)
  • Publish job: On push to main (after tests pass), packages each feature in src/ and pushes to ghcr.io/savvy-web/devcontainers/<feature>
  • Features are independently versioned via devcontainer-feature.json version field

Consumer usage

In any repo's devcontainer.json:

{
  "image": "mcr.microsoft.com/devcontainers/javascript-node:24",
  "features": {
    "ghcr.io/savvy-web/devcontainers/claude-code": {},
    "ghcr.io/savvy-web/devcontainers/biome": { "version": "2.4.9" },
    "ghcr.io/savvy-web/devcontainers/outbound-firewall": {},
    "ghcr.io/savvy-web/devcontainers/savvy-toolchain": {}
  },
  "postCreateCommand": "pnpm install"
}

No custom Dockerfile needed for most repos.

Tasks

  • Scaffold repo structure (src/, test/, .github/workflows/)
  • Implement claude-code feature
  • Implement biome feature
  • Implement outbound-firewall feature
  • Implement savvy-toolchain feature
  • Set up publish GitHub Action
  • Set up test GitHub Action with scenarios
  • Test features against javascript-node:24 and base:ubuntu images
  • Migrate vitest-bats devcontainer to use features

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions