From 6e54807af5a5691685a8381eab03b16bc2f8b382 Mon Sep 17 00:00:00 2001 From: Samuel Bailey Date: Sun, 1 Mar 2026 16:56:59 -0600 Subject: [PATCH 01/12] Add .gitignore Exclude OS files (.DS_Store), IDE directories (.idea/, .vscode/), Docker build artifacts (*.tar), and .claude/ from version control. --- .gitignore | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..99f2536 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# OS +.DS_Store +Thumbs.db + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# Docker artifacts +*.tar +*.tar.gz + +# Claude +.claude/ From bacc6e5649a708e5f648e571f83e64a5bdaa3fda Mon Sep 17 00:00:00 2001 From: Samuel Bailey Date: Sun, 1 Mar 2026 16:57:42 -0600 Subject: [PATCH 02/12] Add .dockerignore Exclude .git, .github, LICENSE, README.md, and other non-build files from Docker build context to reduce context size and build time. --- .dockerignore | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..65203fb --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +.git +.github +.claude +.DS_Store +.gitignore +.dockerignore +LICENSE +README.md +*.tar +*.tar.gz From 01a06c47490d111642a5f394dc4396769b10c003 Mon Sep 17 00:00:00 2001 From: Samuel Bailey Date: Sun, 1 Mar 2026 16:58:05 -0600 Subject: [PATCH 03/12] Add tool validation script Bash script that runs --version on every installed tool (~30 tools), counts passes/fails, and exits non-zero if anything is missing. Used in CI to verify the image is complete. --- scripts/validate-tools.sh | 82 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100755 scripts/validate-tools.sh diff --git a/scripts/validate-tools.sh b/scripts/validate-tools.sh new file mode 100755 index 0000000..b0f515c --- /dev/null +++ b/scripts/validate-tools.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +# validate-tools.sh — verify every tool installed in the builder image. +# Exits non-zero if any tool is missing or fails its version check. +set -euo pipefail + +PASS=0 +FAIL=0 +FAILED_TOOLS="" + +check() { + local name="$1" + shift + if "$@" > /dev/null 2>&1; then + printf " %-20s OK\n" "$name" + PASS=$((PASS + 1)) + else + printf " %-20s FAIL\n" "$name" + FAIL=$((FAIL + 1)) + FAILED_TOOLS="${FAILED_TOOLS} ${name}" + fi +} + +echo "=== Cloud CLIs ===" +check "aws" aws --version +check "gcloud" gcloud --version +check "az" az --version +check "vault" vault --version + +echo "" +echo "=== Languages & Runtimes ===" +check "go" go version +check "python3" python3 --version +check "pip3" pip3 --version +check "node" node --version +check "npm" npm --version + +echo "" +echo "=== Container & Image Tools ===" +check "docker" docker --version +check "buildx" docker buildx version +check "trivy" trivy --version +check "hadolint" hadolint --version +check "dive" dive --version + +echo "" +echo "=== Kubernetes & IaC ===" +check "kubectl" kubectl version --client +check "helm" helm version --short +check "terraform" terraform --version + +echo "" +echo "=== Debugging ===" +check "strace" strace -V +check "ltrace" ltrace -V +check "tcpdump" tcpdump --version +check "netstat" netstat --version +check "dig" dig -v +check "htop" htop --version + +echo "" +echo "=== Build & Dev Utilities ===" +check "git" git --version +check "make" make --version +check "curl" curl --version +check "wget" wget --version +check "jq" jq --version +check "yq" yq --version +check "vim" vim --version +check "unzip" unzip -v +check "shellcheck" shellcheck --version + +echo "" +echo "===============================" +printf "PASS: %d FAIL: %d\n" "$PASS" "$FAIL" + +if [ "$FAIL" -gt 0 ]; then + echo "FAILED TOOLS:${FAILED_TOOLS}" + exit 1 +fi + +echo "All tools validated successfully." +exit 0 From 905e24bb30f692b61f80cb767ebd04f409f933d6 Mon Sep 17 00:00:00 2001 From: Samuel Bailey Date: Sun, 1 Mar 2026 16:58:58 -0600 Subject: [PATCH 04/12] Rewrite Dockerfile with multi-stage build Replace single-stage monolithic build with a two-stage approach: - Stage 1 (downloader): fetches and extracts standalone binaries - Stage 2 (final): installs system packages and copies binaries Key changes: - Pin ubuntu:24.04 base image - Pin all tool versions via ARG for reproducibility - Multi-arch support via TARGETARCH (amd64/arm64) - Remove dead languages (Java 11, Ruby, Rust) saving ~2 GB - Add container tools (Docker CLI, buildx, Trivy, hadolint, dive) - Add K8s/IaC tools (kubectl, Helm, Terraform) - Add debugging tools (strace, ltrace, tcpdump, htop, etc.) - Azure CLI installed via pip venv instead of piped curl|bash - Use modern signed-by keyrings instead of deprecated apt-key - --no-install-recommends on every apt-get install - Clean apt lists in same RUN layer as install --- Dockerfile | 268 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 190 insertions(+), 78 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8b3a448..c91727f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,84 +1,196 @@ -# Stage 1: Build stage -FROM ubuntu as builder - -# Install dependencies -RUN apt-get update && apt-get install -y \ - curl \ - unzip \ - gnupg \ - software-properties-common \ - apt-transport-https \ - ca-certificates \ - lsb-release \ - jq \ - vim \ +# syntax=docker/dockerfile:1 +# ============================================================================ +# Builder — pre-configured dev environment for debugging and building images +# ============================================================================ + +# --------------------------------------------------------------------------- +# Pinned tool versions — update these ARGs to bump versions +# --------------------------------------------------------------------------- +ARG UBUNTU_VERSION=24.04 + +ARG AWSCLI_VERSION=2.24.4 +ARG GCLOUD_VERSION=514.0.0 +ARG VAULT_VERSION=1.18.4 +ARG GO_VERSION=1.23.5 +ARG NODE_MAJOR=22 +ARG KUBECTL_VERSION=1.32.1 +ARG HELM_VERSION=3.17.0 +ARG TERRAFORM_VERSION=1.10.5 +ARG TRIVY_VERSION=0.58.2 +ARG HADOLINT_VERSION=2.12.0 +ARG DIVE_VERSION=0.12.0 +ARG YQ_VERSION=4.45.1 + +# ============================================================================ +# Stage 1: downloader — fetch and extract standalone binaries +# ============================================================================ +FROM ubuntu:${UBUNTU_VERSION} AS downloader + +ARG TARGETARCH + +ARG AWSCLI_VERSION +ARG GCLOUD_VERSION +ARG VAULT_VERSION +ARG GO_VERSION +ARG KUBECTL_VERSION +ARG HELM_VERSION +ARG TERRAFORM_VERSION +ARG TRIVY_VERSION +ARG HADOLINT_VERSION +ARG DIVE_VERSION +ARG YQ_VERSION + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + unzip \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /staging + +# --- AWS CLI v2 --- +RUN ARCH_SUFFIX=$([ "$TARGETARCH" = "arm64" ] && echo "aarch64" || echo "x86_64") \ + && curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-${ARCH_SUFFIX}-${AWSCLI_VERSION}.zip" -o awscli.zip \ + && unzip -q awscli.zip \ + && ./aws/install --install-dir /opt/aws-cli --bin-dir /usr/local/bin \ + && rm -rf awscli.zip aws/ + +# --- Google Cloud CLI --- +RUN ARCH_SUFFIX=$([ "$TARGETARCH" = "arm64" ] && echo "arm" || echo "x86_64") \ + && curl -fsSL "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-${GCLOUD_VERSION}-linux-${ARCH_SUFFIX}.tar.gz" \ + | tar -xz -C /opt \ + && /opt/google-cloud-sdk/install.sh --quiet --path-update=false + +# --- HashiCorp Vault --- +RUN curl -fsSL "https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_linux_${TARGETARCH}.zip" -o vault.zip \ + && unzip -q vault.zip -d /usr/local/bin \ + && rm vault.zip + +# --- Go --- +RUN curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz" \ + | tar -xz -C /usr/local + +# --- kubectl --- +RUN curl -fsSL "https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/linux/${TARGETARCH}/kubectl" \ + -o /usr/local/bin/kubectl \ + && chmod +x /usr/local/bin/kubectl + +# --- Helm --- +RUN curl -fsSL "https://get.helm.sh/helm-v${HELM_VERSION}-linux-${TARGETARCH}.tar.gz" \ + | tar -xz --strip-components=1 -C /usr/local/bin linux-${TARGETARCH}/helm + +# --- Terraform --- +RUN curl -fsSL "https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_${TARGETARCH}.zip" -o terraform.zip \ + && unzip -q terraform.zip -d /usr/local/bin \ + && rm terraform.zip + +# --- Trivy --- +RUN curl -fsSL "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-${TARGETARCH}.tar.gz" \ + | tar -xz -C /usr/local/bin trivy + +# --- hadolint --- +RUN ARCH_SUFFIX=$([ "$TARGETARCH" = "arm64" ] && echo "arm64" || echo "x86_64") \ + && curl -fsSL "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-Linux-${ARCH_SUFFIX}" \ + -o /usr/local/bin/hadolint \ + && chmod +x /usr/local/bin/hadolint + +# --- dive --- +RUN ARCH_SUFFIX=$([ "$TARGETARCH" = "arm64" ] && echo "arm64" || echo "amd64") \ + && curl -fsSL "https://github.com/wagoodman/dive/releases/download/v${DIVE_VERSION}/dive_${DIVE_VERSION}_linux_${ARCH_SUFFIX}.tar.gz" \ + | tar -xz -C /usr/local/bin dive + +# --- yq --- +RUN ARCH_SUFFIX=$([ "$TARGETARCH" = "arm64" ] && echo "arm64" || echo "amd64") \ + && curl -fsSL "https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_${ARCH_SUFFIX}" \ + -o /usr/local/bin/yq \ + && chmod +x /usr/local/bin/yq + + +# ============================================================================ +# Stage 2: final — assemble the runtime image +# ============================================================================ +FROM ubuntu:${UBUNTU_VERSION} AS final + +ARG NODE_MAJOR +ARG TARGETARCH + +ENV DEBIAN_FRONTEND=noninteractive +ENV PATH="/opt/google-cloud-sdk/bin:/usr/local/go/bin:${PATH}" + +# --- System packages, debugging tools, and build utilities --- +RUN apt-get update && apt-get install -y --no-install-recommends \ + # core utilities + ca-certificates \ + curl \ + gnupg \ + unzip \ + jq \ + vim \ + git \ + make \ + wget \ + shellcheck \ + # debugging + strace \ + ltrace \ + tcpdump \ + net-tools \ + dnsutils \ + htop \ + # python + python3 \ + python3-pip \ + python3-venv \ + && rm -rf /var/lib/apt/lists/* + +# --- Azure CLI via pip in a venv (no piped scripts) --- +RUN python3 -m venv /opt/azure-cli \ + && /opt/azure-cli/bin/pip install --no-cache-dir azure-cli \ + && ln -s /opt/azure-cli/bin/az /usr/local/bin/az + +# --- Node.js via NodeSource (pinned major version) --- +RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \ + | gpg --dearmor -o /usr/share/keyrings/nodesource.gpg \ + && echo "deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" \ + > /etc/apt/sources.list.d/nodesource.list \ + && apt-get update && apt-get install -y --no-install-recommends nodejs \ && rm -rf /var/lib/apt/lists/* -# Install AWS CLI -RUN ARCH=$(dpkg --print-architecture) && \ - if [ "$ARCH" = "amd64" ]; then \ - curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"; \ - elif [ "$ARCH" = "arm64" ]; then \ - curl "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip" -o "awscliv2.zip"; \ - else \ - echo "Unsupported architecture: $ARCH"; exit 1; \ - fi && \ - unzip awscliv2.zip && \ - ./aws/install - -# Install gcloud CLI -RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list \ - && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - \ - && apt-get update && apt-get install -y google-cloud-sdk - -# Install HashiCorp Vault -RUN curl -fsSL https://apt.releases.hashicorp.com/gpg | apt-key add - \ - && apt-add-repository "deb [arch=$(dpkg --print-architecture)] https://apt.releases.hashicorp.com $(lsb_release -cs) main" \ - && apt-get update && apt-get install -y vault - -# Bug found here -> https://github.com/hashicorp/vault/issues/10924 -RUN setcap -r /usr/bin/vault - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash - -# Install programming languages -RUN apt-get update --fix-missing && apt-get install -y \ - openjdk-11-jdk \ - openjdk-11-jre-headless \ - golang-go \ - python3 \ - python3-pip \ - nodejs \ - npm \ - ruby \ +# --- Docker CLI + buildx from official Docker apt repo --- +RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ + | gpg --dearmor -o /usr/share/keyrings/docker.gpg \ + && echo "deb [arch=${TARGETARCH} signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu noble stable" \ + > /etc/apt/sources.list.d/docker.list \ + && apt-get update && apt-get install -y --no-install-recommends \ + docker-ce-cli \ + docker-buildx-plugin \ && rm -rf /var/lib/apt/lists/* -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - -# Set python3 as default python -RUN export python=python3 && export pip=pip3 - -# Set PATH for AWS CLI and Rust -ENV PATH="/usr/local/aws-cli/v2/current/bin:$PATH" -ENV PATH="/root/.cargo/bin:$PATH" - -# Verify installations -RUN aws --version \ - && gcloud --version \ - && vault --version \ - && az --version \ - && jq --version \ - && java -version \ - && go version \ - && python3 --version \ - && node --version \ - && npm --version \ - && ruby --version \ - && rustc --version - -# Clean up unnecessary files -RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +# --- Copy binaries from downloader stage --- +COPY --from=downloader /opt/aws-cli /opt/aws-cli +COPY --from=downloader /usr/local/bin/aws /usr/local/bin/aws +COPY --from=downloader /usr/local/bin/aws_completer /usr/local/bin/aws_completer +COPY --from=downloader /opt/google-cloud-sdk /opt/google-cloud-sdk +COPY --from=downloader /usr/local/bin/vault /usr/local/bin/vault +COPY --from=downloader /usr/local/go /usr/local/go +COPY --from=downloader /usr/local/bin/kubectl /usr/local/bin/kubectl +COPY --from=downloader /usr/local/bin/helm /usr/local/bin/helm +COPY --from=downloader /usr/local/bin/terraform /usr/local/bin/terraform +COPY --from=downloader /usr/local/bin/trivy /usr/local/bin/trivy +COPY --from=downloader /usr/local/bin/hadolint /usr/local/bin/hadolint +COPY --from=downloader /usr/local/bin/dive /usr/local/bin/dive +COPY --from=downloader /usr/local/bin/yq /usr/local/bin/yq + +# --- Vault capability fix (https://github.com/hashicorp/vault/issues/10924) --- +RUN setcap -r /usr/local/bin/vault || true + +# --- Validation script --- +COPY scripts/validate-tools.sh /usr/local/bin/validate-tools.sh + +# --- OCI labels --- +LABEL org.opencontainers.image.title="builder" \ + org.opencontainers.image.description="Pre-configured dev environment for debugging and building images" \ + org.opencontainers.image.source="https://github.com/decima-cloud/builder" \ + org.opencontainers.image.licenses="MIT" CMD ["bash"] From 6c54a946ba1719d18878d082c357cf5ce83baf9e Mon Sep 17 00:00:00 2001 From: Samuel Bailey Date: Sun, 1 Mar 2026 16:59:48 -0600 Subject: [PATCH 05/12] Overhaul CI/CD with scanning and testing Delete build-base.yaml and replace with build.yaml containing: - lint: hadolint Dockerfile linting - build: multi-platform (linux/amd64, linux/arm64) with QEMU + buildx, pushes to GHCR using GITHUB_TOKEN, GHA layer cache - scan: Trivy vulnerability scanning with SARIF upload to Security tab - test: runs validate-tools.sh inside the built image - size-report: outputs image size to GitHub Actions step summary Triggers on push to main, tags (v*), PRs, weekly schedule, and manual dispatch. Removes macOS/Windows from build matrix and eliminates custom GHCR secrets in favour of GITHUB_TOKEN. --- .github/workflows/build-base.yaml | 43 --------- .github/workflows/build.yaml | 155 ++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 43 deletions(-) delete mode 100644 .github/workflows/build-base.yaml create mode 100644 .github/workflows/build.yaml diff --git a/.github/workflows/build-base.yaml b/.github/workflows/build-base.yaml deleted file mode 100644 index 2c267b8..0000000 --- a/.github/workflows/build-base.yaml +++ /dev/null @@ -1,43 +0,0 @@ -name: Build base image - -on: - workflow_dispatch: - push: - branches: - - main - schedule: - - cron: "0 19 * * *" - -permissions: - id-token: write - contents: read - -jobs: - build-images: - runs-on: ubuntu-latest - strategy: - matrix: - platform: [linux/amd64, linux/arm64, macOS/arm64, macOS/amd64, windows/amd64, windows/arm64, linux/arm64/v8] - steps: - - name: "Checkout GitHub Action" - uses: actions/checkout@v4 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ secrets.REGISTRY_USERNAME }} - password: ${{ secrets.REGISTRY_PASSWORD }} - - - name: Set platform tag - id: platform_tag - run: echo "PLATFORM_TAG=${{ matrix.platform }}" | sed 's/\//-/g' >> $GITHUB_ENV - - - name: Build and push - uses: docker/build-push-action@v6 - with: - platform: ${{ matrix.platform }} - context: . - push: true - tags: | - ghcr.io/${{ github.repository_owner }}/builder:${{ env.PLATFORM_TAG }} diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..4f2a886 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,155 @@ +name: Build, scan, and publish + +on: + push: + branches: [main] + tags: ["v*"] + pull_request: + branches: [main] + schedule: + - cron: "0 6 * * 1" # weekly Monday 06:00 UTC + workflow_dispatch: + +permissions: + contents: read + packages: write + security-events: write + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + # ------------------------------------------------------------------- + # Lint — hadolint Dockerfile linting + # ------------------------------------------------------------------- + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Lint Dockerfile + uses: hadolint/hadolint-action@v3.1.0 + with: + dockerfile: Dockerfile + + # ------------------------------------------------------------------- + # Build — multi-platform image, push to GHCR + # ------------------------------------------------------------------- + build: + runs-on: ubuntu-latest + needs: lint + outputs: + digest: ${{ steps.build-push.outputs.digest }} + steps: + - uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata for tags and labels + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value={{date 'YYYYMMDD'}},enable={{is_default_branch}} + type=raw,value=latest,enable={{is_default_branch}} + type=sha,prefix= + + - name: Build and push + id: build-push + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + load: ${{ github.event_name == 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + # ------------------------------------------------------------------- + # Scan — Trivy vulnerability scanning with SARIF upload + # ------------------------------------------------------------------- + scan: + runs-on: ubuntu-latest + needs: build + if: github.event_name != 'pull_request' + steps: + - uses: actions/checkout@v4 + + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@0.28.0 + with: + image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }} + format: sarif + output: trivy-results.sarif + severity: CRITICAL,HIGH + + - name: Upload Trivy SARIF to GitHub Security + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: trivy-results.sarif + + # ------------------------------------------------------------------- + # Test — run validate-tools.sh inside the built image + # ------------------------------------------------------------------- + test: + runs-on: ubuntu-latest + needs: build + if: github.event_name != 'pull_request' + steps: + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Pull and validate tools + run: | + docker pull "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }}" + docker run --rm "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }}" \ + /usr/local/bin/validate-tools.sh + + # ------------------------------------------------------------------- + # Size report — output image size to step summary + # ------------------------------------------------------------------- + size-report: + runs-on: ubuntu-latest + needs: build + if: github.event_name != 'pull_request' + steps: + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Report image size + run: | + docker pull "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }}" + SIZE=$(docker image inspect "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }}" --format '{{.Size}}') + SIZE_MB=$((SIZE / 1024 / 1024)) + echo "## Image Size Report" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "| Metric | Value |" >> "$GITHUB_STEP_SUMMARY" + echo "|--------|-------|" >> "$GITHUB_STEP_SUMMARY" + echo "| Raw size | ${SIZE_MB} MB |" >> "$GITHUB_STEP_SUMMARY" + echo "| Digest | \`${{ needs.build.outputs.digest }}\` |" >> "$GITHUB_STEP_SUMMARY" From c395c8d960bd5050df6d393aa698d21085924c23 Mon Sep 17 00:00:00 2001 From: Samuel Bailey Date: Sun, 1 Mar 2026 17:00:23 -0600 Subject: [PATCH 06/12] Rewrite README to reflect actual capabilities Replace misleading README with accurate documentation: - Remove false claims about multi-stage builds and macOS/Windows support - Add tool inventory tables with pinned versions by category - Add usage examples for CI, debugging, building, and linting - Document tagging strategy (semver, date, sha, latest) - Explain image size reduction approach - Update contributing guide with local validation steps --- README.md | 194 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 127 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 8fe0016..fa55873 100644 --- a/README.md +++ b/README.md @@ -1,91 +1,151 @@ # Builder -Builder is a base Dockerfile designed to streamline the development process by providing a pre-configured environment with commonly used tools and programming languages. This Dockerfile is intended for the community to help get things done faster and more efficiently. - -## Features - -One of the best/worst feature of this project is that the images are rebuilt every day at midnight so they will always have security patches built in. - -- **Multi-architecture support**: Supports both `amd64` and `arm64` architectures. -- **Pre-installed tools**: - - AWS CLI - - Google Cloud SDK (gcloud CLI) - - Azure CLI - - HashiCorp Vault - - jq -- **Pre-installed programming languages**: - - Java (OpenJDK 11) - - Go - - Python 3 - - Node.js and npm - - Ruby - - Rust -- **Optimized for size**: Uses multi-stage builds to minimize the final image size. +![Validation](https://img.shields.io/github/actions/workflow/status/decima-cloud/builder/build.yaml?branch=main&label=build) -## Supported Platforms - -You would download this by doing something like `docker pull ghcr.io/decima-cloud/builder:macOS-amd64`. where the tag could be any supported platform -Builder supports the following platforms: - -- **macOS**: - - amd64 - - arm64 -- **Windows**: - - amd64 - - arm64 -- **Linux**: - - amd64 - - arm64 - - arm64-v8 +Pre-configured Docker image for debugging, building other images, and working with cloud infrastructure. Ships with pinned versions of cloud CLIs, container tools, languages, and debugging utilities. -### Building the Docker Image Locally - -To build the Docker image, run the following command: +## Quick Start ```sh -docker build -t builder:latest . +docker pull ghcr.io/decima-cloud/builder:latest +docker run --rm -it ghcr.io/decima-cloud/builder:latest ``` -## Customization - -If you need to customize the Dockerfile to include additional tools or dependencies, you can modify the `Dockerfile` directly. Here are some common customizations: +## Supported Platforms -### Adding New Tools +| OS | Architecture | +|-------|-------------| +| Linux | amd64 | +| Linux | arm64 | + +## Tool Inventory + +All versions are pinned via `ARG` in the Dockerfile for reproducibility. + +### Cloud CLIs + +| Tool | Version | Purpose | +|-----------|---------|--------------------| +| AWS CLI | 2.24.4 | AWS management | +| gcloud | 514.0.0 | GCP management | +| Azure CLI | latest | Azure management | +| Vault | 1.18.4 | Secrets management | + +### Languages & Runtimes + +| Tool | Version | Purpose | +|---------|---------|------------------| +| Go | 1.23.5 | Go development | +| Python | 3.x | Python scripting | +| Node.js | 22.x | JS runtime | +| pip | latest | Python packages | + +### Container & Image Tools + +| Tool | Version | Purpose | +|----------|---------|-----------------------| +| Docker | latest | Container CLI | +| buildx | latest | Multi-platform builds | +| Trivy | 0.58.2 | Vulnerability scanner | +| hadolint | 2.12.0 | Dockerfile linter | +| dive | 0.12.0 | Image layer explorer | + +### Kubernetes & IaC + +| Tool | Version | Purpose | +|-----------|---------|----------------------| +| kubectl | 1.32.1 | Cluster management | +| Helm | 3.17.0 | Chart management | +| Terraform | 1.10.5 | Infrastructure as code | + +### Debugging + +| Tool | Purpose | +|----------|--------------------------| +| strace | System call tracing | +| ltrace | Library call tracing | +| tcpdump | Packet capture | +| net-tools| netstat, ifconfig, etc. | +| dnsutils | dig, nslookup | +| htop | Process monitoring | + +### Build & Dev Utilities + +| Tool | Purpose | +|------------|------------------------| +| git | Version control | +| make | Build automation | +| curl | HTTP client | +| wget | File downloads | +| jq | JSON processing | +| yq | YAML processing | +| vim | Text editor | +| shellcheck | Shell script linter | +| unzip | Archive extraction | + +## Usage Examples + +### CI Pipeline Base Image + +```yaml +jobs: + deploy: + container: + image: ghcr.io/decima-cloud/builder:latest + steps: + - run: terraform init && terraform apply -auto-approve +``` -To add a new tool, you can include the installation commands in the build stage of the Dockerfile. For example, to add `wget`, you can modify the `Dockerfile` as follows: +### Debugging a Running Container -```dockerfile -# Install wget -RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/* +```sh +docker run --rm -it \ + --pid=host --net=host \ + ghcr.io/decima-cloud/builder:latest ``` -### Adding New Programming Languages - -To add a new programming language, you can include the installation commands in the build stage of the Dockerfile. For example, to add Ruby, you can modify the `Dockerfile` as follows(this is just an example ruby is installed already): +### Building and Scanning Images -```dockerfile -# Install Ruby -RUN apt-get update && apt-get install -y ruby && rm -rf /var/lib/apt/lists/* +```sh +docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \ + ghcr.io/decima-cloud/builder:latest \ + sh -c "docker build -t myapp . && trivy image myapp" ``` -## Contributing +### Linting Dockerfiles + +```sh +docker run --rm -v "$(pwd)":/work -w /work \ + ghcr.io/decima-cloud/builder:latest \ + hadolint Dockerfile +``` -We welcome contributions from the community! If you have any improvements or new features to add, please follow these steps: +## Image Tags -1. Fork the repository. -2. Create a new branch for your feature or bugfix. -3. Make your changes and commit them with a descriptive message. -4. Push your changes to your forked repository. -5. Create a pull request to the main repository. +| Tag Format | Example | Description | +|-------------|------------------|---------------------------------| +| `latest` | `latest` | Latest build from main | +| `YYYYMMDD` | `20260301` | Date-stamped build | +| `vX.Y.Z` | `v1.0.0` | Semantic version release | +| `vX.Y` | `v1.0` | Minor version (tracks patches) | +| `` | `a1b2c3d` | Specific commit | -## License +## Image Size -This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details. +Target: ~1 GB (down from 3.5-5.5 GB). Achieved through: +- Multi-stage build (download stage discarded) +- Removed unused languages (Java 11, Ruby, Rust) +- `--no-install-recommends` on all apt installs +- Apt lists cleaned in the same layer as installs -## Acknowledgements +## Contributing -We would like to thank the open-source community for their contributions and support. +1. Fork the repository +2. Create a feature branch +3. Update tool versions by changing the `ARG` values in the Dockerfile +4. Run validation locally: `docker build -t builder:test . && docker run --rm builder:test validate-tools.sh` +5. Open a pull request — CI will lint, build, scan, and test automatically -## Contact +## License -If you have any questions or need further assistance, please open an issue in the repository or contact the maintainers. +MIT. See [LICENSE](LICENSE). From c06bb62fbf5a0add14a8ee8b5c7b9252bf6fed1f Mon Sep 17 00:00:00 2001 From: Samuel Bailey Date: Sun, 1 Mar 2026 17:05:26 -0600 Subject: [PATCH 07/12] Fix hadolint DL4006: add SHELL pipefail to both stages Set SHELL ["/bin/bash", "-o", "pipefail", "-c"] in both the downloader and final stages so piped RUN commands fail properly if any command in the pipeline exits non-zero. --- Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Dockerfile b/Dockerfile index c91727f..26a17a1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,6 +26,8 @@ ARG YQ_VERSION=4.45.1 # ============================================================================ FROM ubuntu:${UBUNTU_VERSION} AS downloader +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + ARG TARGETARCH ARG AWSCLI_VERSION @@ -111,6 +113,8 @@ RUN ARCH_SUFFIX=$([ "$TARGETARCH" = "arm64" ] && echo "arm64" || echo "amd64") \ # ============================================================================ FROM ubuntu:${UBUNTU_VERSION} AS final +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + ARG NODE_MAJOR ARG TARGETARCH From b9f6169c0b680f0110134c80ccf3701ff8519040 Mon Sep 17 00:00:00 2001 From: Samuel Bailey Date: Sun, 1 Mar 2026 17:05:40 -0600 Subject: [PATCH 08/12] Add hadolint config to ignore DL3008 System packages get security patches via weekly scheduled rebuilds. Pinning apt versions across amd64/arm64 is fragile and would defeat the purpose of automatic security updates. --- .hadolint.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .hadolint.yaml diff --git a/.hadolint.yaml b/.hadolint.yaml new file mode 100644 index 0000000..84ddffb --- /dev/null +++ b/.hadolint.yaml @@ -0,0 +1,6 @@ +# DL3008: Pin versions in apt-get install +# Ignored because system packages receive security patches via the weekly +# scheduled rebuild. Pinning apt versions across amd64/arm64 is fragile +# and defeats the purpose of automatic security updates. +ignored: + - DL3008 From 6ba81db21bfb77f43de131d0d683bec2d094dd9e Mon Sep 17 00:00:00 2001 From: Samuel Bailey Date: Sun, 1 Mar 2026 17:07:28 -0600 Subject: [PATCH 09/12] Fix multi-platform build on PRs Docker --load does not support exporting manifest lists, so restrict PR builds to linux/amd64 only. Multi-platform (amd64 + arm64) builds still run on push to main and tags where images are pushed to GHCR. --- .github/workflows/build.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 4f2a886..c6a269a 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -75,7 +75,9 @@ jobs: uses: docker/build-push-action@v6 with: context: . - platforms: linux/amd64,linux/arm64 + # Multi-platform on push; single platform on PR (--load does not + # support manifest lists, so we build only the runner's native arch) + platforms: ${{ github.event_name != 'pull_request' && 'linux/amd64,linux/arm64' || 'linux/amd64' }} push: ${{ github.event_name != 'pull_request' }} load: ${{ github.event_name == 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} From 61599b60c814b3a2cad2e4aa2a41422bd91be1b6 Mon Sep 17 00:00:00 2001 From: Samuel Bailey Date: Sun, 1 Mar 2026 17:54:21 -0600 Subject: [PATCH 10/12] Fix unzip conflicts in downloader stage Use unzip -o (overwrite) flag for Vault, Terraform, and AWS CLI extractions. Both Vault and Terraform zips contain LICENSE.txt which causes a collision prompt that fails in non-interactive builds. --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 26a17a1..72a555d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -53,7 +53,7 @@ WORKDIR /staging # --- AWS CLI v2 --- RUN ARCH_SUFFIX=$([ "$TARGETARCH" = "arm64" ] && echo "aarch64" || echo "x86_64") \ && curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-${ARCH_SUFFIX}-${AWSCLI_VERSION}.zip" -o awscli.zip \ - && unzip -q awscli.zip \ + && unzip -oq awscli.zip \ && ./aws/install --install-dir /opt/aws-cli --bin-dir /usr/local/bin \ && rm -rf awscli.zip aws/ @@ -65,7 +65,7 @@ RUN ARCH_SUFFIX=$([ "$TARGETARCH" = "arm64" ] && echo "arm" || echo "x86_64") \ # --- HashiCorp Vault --- RUN curl -fsSL "https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_linux_${TARGETARCH}.zip" -o vault.zip \ - && unzip -q vault.zip -d /usr/local/bin \ + && unzip -oq vault.zip -d /usr/local/bin \ && rm vault.zip # --- Go --- @@ -83,7 +83,7 @@ RUN curl -fsSL "https://get.helm.sh/helm-v${HELM_VERSION}-linux-${TARGETARCH}.ta # --- Terraform --- RUN curl -fsSL "https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_${TARGETARCH}.zip" -o terraform.zip \ - && unzip -q terraform.zip -d /usr/local/bin \ + && unzip -oq terraform.zip -d /usr/local/bin \ && rm terraform.zip # --- Trivy --- From 76cf0c96653bff3c9ddff55b36e7048af39c32db Mon Sep 17 00:00:00 2001 From: Samuel Bailey Date: Sun, 1 Mar 2026 18:32:04 -0600 Subject: [PATCH 11/12] Fix Trivy download URL and bump to v0.69.2 Trivy release assets use Linux-64bit/Linux-ARM64 naming convention, not Linux-amd64/Linux-arm64. Add architecture mapping and update from non-existent v0.58.2 to latest v0.69.2. --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 72a555d..2f5f46f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ ARG NODE_MAJOR=22 ARG KUBECTL_VERSION=1.32.1 ARG HELM_VERSION=3.17.0 ARG TERRAFORM_VERSION=1.10.5 -ARG TRIVY_VERSION=0.58.2 +ARG TRIVY_VERSION=0.69.2 ARG HADOLINT_VERSION=2.12.0 ARG DIVE_VERSION=0.12.0 ARG YQ_VERSION=4.45.1 @@ -87,7 +87,8 @@ RUN curl -fsSL "https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/te && rm terraform.zip # --- Trivy --- -RUN curl -fsSL "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-${TARGETARCH}.tar.gz" \ +RUN ARCH_SUFFIX=$([ "$TARGETARCH" = "arm64" ] && echo "ARM64" || echo "64bit") \ + && curl -fsSL "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-${ARCH_SUFFIX}.tar.gz" \ | tar -xz -C /usr/local/bin trivy # --- hadolint --- From 612c18fc9f40c5a96a980946d2ef1fc5e511ed0c Mon Sep 17 00:00:00 2001 From: Samuel Bailey Date: Sun, 1 Mar 2026 18:32:13 -0600 Subject: [PATCH 12/12] Update Trivy version in README to match Dockerfile --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa55873..94d8d20 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ All versions are pinned via `ARG` in the Dockerfile for reproducibility. |----------|---------|-----------------------| | Docker | latest | Container CLI | | buildx | latest | Multi-platform builds | -| Trivy | 0.58.2 | Vulnerability scanner | +| Trivy | 0.69.2 | Vulnerability scanner | | hadolint | 2.12.0 | Dockerfile linter | | dive | 0.12.0 | Image layer explorer |