diff --git a/.github/workflows/build-chezmoi-image.yml b/.github/workflows/build-chezmoi-image.yml new file mode 100644 index 0000000..a05f058 --- /dev/null +++ b/.github/workflows/build-chezmoi-image.yml @@ -0,0 +1,82 @@ +name: Build and Push Chezmoi Image + +on: + push: + branches: + - main + paths: + - 'chezmoi/**' + - '.github/workflows/build-chezmoi-image.yml' + pull_request: + branches: + - main + paths: + - 'chezmoi/**' + - '.github/workflows/build-chezmoi-image.yml' + workflow_run: + workflows: ["Build and Push Base Image"] + types: + - completed + branches: + - main + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }}/chezmoi + +jobs: + build-and-push: + runs-on: ubuntu-latest + if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Determine base image tag + id: base-tag + run: | + if [ "${{ github.event_name }}" = "workflow_run" ]; then + echo "tag=sha-$(echo ${{ github.event.workflow_run.head_sha }} | cut -c1-7)" >> $GITHUB_OUTPUT + else + echo "tag=latest" >> $GITHUB_OUTPUT + fi + + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=sha,prefix=sha- + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: ./chezmoi + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + BASE_IMAGE_TAG=${{ steps.base-tag.outputs.tag }} + cache-from: type=gha + cache-to: type=gha,mode=max + diff --git a/README.md b/README.md index 0543081..0821c5d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,48 @@ # toolbox Various special purpose toolboxes as container images + +## Available Toolboxes + +### Base +Base toolbox image with common dependencies (ca-certificates, curl, git, zsh, mise). + +### Devcontainer +Development container image with SSH, GPG, and locale support. + +### Chezmoi +Container image with chezmoi for dotfiles management. Supports optional initialization with a dotfiles repository. + +#### Usage + +Build without initializing a dotfiles repo: +```bash +docker build -t my-chezmoi ./chezmoi +``` + +Build and initialize with a public dotfiles repo: +```bash +docker build --build-arg CHEZMOI_REPO=https://github.com/username/dotfiles.git -t my-chezmoi ./chezmoi +``` + +Build and initialize with a private dotfiles repo using SSH keys: +```bash +# For GitHub +docker buildx build --ssh default --build-arg CHEZMOI_REPO=git@github.com:username/dotfiles.git -t my-chezmoi ./chezmoi + +# For GitLab or other Git hosts +docker buildx build --ssh default --build-arg CHEZMOI_REPO=git@gitlab.com:username/dotfiles.git -t my-chezmoi ./chezmoi +``` + +Build and initialize with a private dotfiles repo using token: +```bash +docker build --build-arg CHEZMOI_REPO=https://token@github.com/username/dotfiles.git -t my-chezmoi ./chezmoi +``` + +> [!WARNING] +> Using `CHEZMOI_REPO` will execute code from the dotfiles repository during the build process. Only use with trusted repositories. + +Run the container: +```bash +docker run -it my-chezmoi +``` + diff --git a/base/Dockerfile b/base/Dockerfile index a47a802..7784085 100644 --- a/base/Dockerfile +++ b/base/Dockerfile @@ -6,6 +6,7 @@ RUN apt-get update &&\ apt-get install --no-install-recommends -y \ ca-certificates=20250419\ curl=8.14.1-2+deb13u2 \ + git=1:2.47.3-0+deb13u1 \ zsh=5.9-8+b14 &&\ apt-get clean -y &&\ rm -rf /var/lib/apt/lists/* diff --git a/chezmoi/Dockerfile b/chezmoi/Dockerfile new file mode 100644 index 0000000..798572c --- /dev/null +++ b/chezmoi/Dockerfile @@ -0,0 +1,40 @@ +ARG BASE_IMAGE_TAG=latest +FROM ghcr.io/jhulten/toolbox/base:${BASE_IMAGE_TAG} + +LABEL org.opencontainers.image.title="Toolbox Chezmoi" +LABEL org.opencontainers.image.description="Container image with chezmoi for dotfiles management" +LABEL org.opencontainers.image.source="https://github.com/jhulten/toolbox" +LABEL org.opencontainers.image.licenses="MIT" + +ENV DEBIAN_FRONTEND=noninteractive + +USER toolsmith +WORKDIR /home/toolsmith + +# Install chezmoi using mise +ARG CHEZMOI_VERSION=2.56.1 +RUN mise use --global aqua:twpayne/chezmoi@${CHEZMOI_VERSION} + +# Optional: Initialize chezmoi with a dotfiles repo +# WARNING: This will execute code from the dotfiles repository during build. +# Only use with trusted repositories. +# +# For public repos or repos with token: +# docker build --build-arg CHEZMOI_REPO=https://github.com/user/dotfiles.git +# docker build --build-arg CHEZMOI_REPO=https://token@github.com/user/dotfiles.git +# +# For private repos with SSH: +# docker buildx build --ssh default --build-arg CHEZMOI_REPO=git@github.com:user/dotfiles.git +# docker buildx build --ssh default --build-arg CHEZMOI_REPO=git@gitlab.com:user/dotfiles.git +ARG CHEZMOI_REPO="" +RUN --mount=type=ssh \ + if [ -n "$CHEZMOI_REPO" ]; then \ + if echo "$CHEZMOI_REPO" | grep -q "^git@"; then \ + mkdir -p ~/.ssh && \ + GIT_HOST=$(echo "$CHEZMOI_REPO" | sed -E 's|^git@([^:]+):.*|\1|') && \ + ssh-keyscan "$GIT_HOST" >> ~/.ssh/known_hosts 2>/dev/null || true; \ + fi && \ + chezmoi init --apply "$CHEZMOI_REPO"; \ + fi + +CMD ["/bin/zsh"] diff --git a/devcontainer/Dockerfile b/devcontainer/Dockerfile index 3a3d2d1..e05b815 100644 --- a/devcontainer/Dockerfile +++ b/devcontainer/Dockerfile @@ -12,7 +12,6 @@ USER root RUN apt-get update &&\ apt-get install --no-install-recommends -y \ - git=1:2.47.3-0+deb13u1 \ openssh-client=1:10.0p1-7 \ gnupg=2.4.7-21 \ locales=2.41-12 &&\