--- phase: 09-tooling-portable-setup plan: 01 type: execute wave: 1 depends_on: [] files_modified: - ngn-agent/docker/Dockerfile - ngn-agent/docker/build.sh autonomous: true requirements: [TOOL-01] must_haves: truths: - "Custom Docker image can be built with a single command (docker/build.sh)" - "Built image includes aws-cli v2, terraform, helm, kubectl, and datadog CLI (pup)" - "Image is tagged ngn-agent:latest (local only, no registry push)" - "Each tool version is pinned for reproducibility" - "Build uses Dockerfile from the project repo (ngn-agent/docker/Dockerfile)" artifacts: - path: "ngn-agent/docker/Dockerfile" provides: "Custom Hermes-compatible Docker image definition with 5 platform tools" min_lines: 80 - path: "ngn-agent/docker/build.sh" provides: "Single-command image build entry point" min_lines: 15 key_links: - from: "ngn-agent/docker/build.sh" to: "ngn-agent/docker/Dockerfile" via: "docker build -f" pattern: "docker build.*-f.*Dockerfile" - from: "Dockerfile" to: "aws-cli v2" via: "curl → unzip → aws/install" pattern: "awscli\\.amazonaws\\.com/awscli-exe" - from: "Dockerfile" to: "terraform" via: "HashiCorp apt repo" pattern: "apt\\.releases\\.hashicorp\\.com" - from: "Dockerfile" to: "helm" via: "Buildkite apt repo" pattern: "packages\\.buildkite\\.com/helm" - from: "Dockerfile" to: "kubectl" via: "Google Kubernetes apt repo" pattern: "pkgs\\.k8s\\.io" - from: "Dockerfile" to: "pup (Datadog CLI)" via: "GitHub releases binary download" pattern: "github\\.com/DataDog/pup/releases" --- **Custom Hermes Docker Image with Platform Engineering Tools** Create a custom Docker image extending `nikolaik/python-nodejs:python3.11-nodejs20` with five platform engineering CLI tools pre-installed: AWS CLI v2, Terraform, Helm, kubectl, and Datadog CLI (pup). The image is buildable with a single `docker/build.sh` command and tagged `ngn-agent:latest` for local use. **Purpose:** Eliminate per-session tool installation overhead — tools are baked into the Docker image so every Hermes session has immediate access to aws-cli, terraform, helm, kubectl, and pup without runtime installs. **Output:** - `ngn-agent/docker/Dockerfile` — Version-pinned tool installations on top of the base Hermes image - `ngn-agent/docker/build.sh` — Single-command build entry point @/Users/bapung/.config/opencode/gsd-core/workflows/execute-plan.md @/Users/bapung/.config/opencode/gsd-core/templates/summary.md @.planning/ROADMAP.md @.planning/phases/09-tooling-portable-setup/09-CONTEXT.md @.planning/phases/09-tooling-portable-setup/09-RESEARCH.md Task 1: Create Dockerfile with version-pinned tool installations ngn-agent/docker/Dockerfile Create `ngn-agent/docker/Dockerfile` that: 1. **FROM** extends `nikolaik/python-nodejs:python3.11-nodejs20` (per D-01). Add a comment above FROM noting: "D-01: Base image tag python3.11-nodejs20 — verify availability at build time; if manifest not found, update to python3.11-nodejs22-bookworm (Node.js 20 EOL April 2026)." 2. **LABEL** with `description="ngn-agent: Custom Hermes Docker image with platform engineering tools"` and `maintainer="ngn-agent"`. 3. **ARGs for version pinning** (per D-02): - `TERRAFORM_VERSION=1.15.6` - `HELM_VERSION=4.2.1` - `KUBECTL_VERSION=1.36.1` - `PUPP_VERSION=1.1.0` (AWS CLI v2 is the latest stable — per D-03, install without version pinning but pin to latest known at time of build.) 4. **Install system dependencies** in a single RUN: `curl`, `ca-certificates`, `unzip`, `gnupg`, `wget` — clean apt lists after install. 5. **Install AWS CLI v2** (per D-03): Use the official curl → unzip → `./aws/install` method (no apt repo for v2). Install to `/usr/local/bin` and `/usr/local/aws-cli`. Clean up zip and extracted files. Reference D-03 in a comment. 6. **Install Terraform** (per D-03): Add HashiCorp GPG key, add HashiCorp apt repo, `apt-get install -y terraform=${TERRAFORM_VERSION}`. Clean apt lists. Reference D-03. 7. **Install kubectl** (per D-03): Add Google Kubernetes GPG key, add kubernetes apt repo for v1.36, `apt-get install -y kubectl`. Do NOT version-pin kubectl (it must match the target cluster version — per D-03: "latest stable matching cluster version"). Clean apt lists. Reference D-03. 8. **Install Helm** (per D-03): Add Buildkite GPG key, add Helm apt repo, `apt-get install -y helm=${HELM_VERSION}`. Clean apt lists. Reference D-03. 9. **Install Datadog CLI (pup)** (per D-03): Download the Linux x86_64 tarball from GitHub Releases, extract `pup` binary to `/usr/local/bin/`, clean up. Reference D-03. 10. **Verify step**: Single RUN with `echo "=== Tool versions ===" && aws --version && terraform --version && helm version --short && kubectl version --client --output=yaml 2>/dev/null | grep gitVersion && pup --version`. Use `|| true` on version checks that may exit non-zero so build doesn't fail on a single tool being unreachable. 11. **CMD** `["bash"]` — matching base image behavior. **Build hygiene:** - Do NOT `COPY .` or any full-directory copy — this prevents leaking secrets into image layers (T-09-02 mitigation). - Order tool installs from most-frequently-changed to least-changed to optimize layer caching. - Use `--no-install-recommends` on all apt-get install commands. - Remove apt lists after each apt install to keep image small. - All tool downloads use HTTPS URLs (T-09-01 mitigation). - Add inline comments referencing each D-NN decision for traceability. test -f /Users/bapung/Razer/ngn-agent/docker/Dockerfile && wc -l /Users/bapung/Razer/ngn-agent/docker/Dockerfile - Dockerfile exists at ngn-agent/docker/Dockerfile - All 5 tools (aws-cli, terraform, helm, kubectl, pup) are installed via RUN commands - Tool versions are pinned via ARGs (except kubectl which matches cluster version) - D-01 through D-03 are referenced in comments - No `COPY .` or directory-wide copy present Task 2: Create build.sh and verify image builds successfully ngn-agent/docker/build.sh Create `ngn-agent/docker/build.sh` (per D-04): 1. Shebang: `#!/bin/bash` with `set -euo pipefail`. 2. Constants: - `IMAGE_NAME="ngn-agent"` - `IMAGE_TAG="latest"` - `DOCKER_DIR` resolved from script location: `"$(cd "$(dirname "$0")" && pwd)"` 3. Print build banner: `echo "==> Building ${IMAGE_NAME}:${IMAGE_TAG}..."` 4. `docker build` command: - `-t "${IMAGE_NAME}:${IMAGE_TAG}"` - `-f "${DOCKER_DIR}/Dockerfile"` - Build context: `"${DOCKER_DIR}"` (not the repo root — prevents leaking files) - Per D-05: tag is `ngn-agent:latest` (local only, no registry push) 5. Print completion banner: `echo "==> Build complete: ${IMAGE_NAME}:${IMAGE_TAG}"` followed by `docker images "${IMAGE_NAME}:${IMAGE_TAG}"`. 6. Make the script executable: `chmod +x /Users/bapung/Razer/ngn-agent/docker/build.sh`. **Verify the build** by running `docker/build.sh` (or `bash docker/build.sh` if script path issues). If the base image tag `python3.11-nodejs20` fails with a manifest error, update the Dockerfile FROM line to `nikolaik/python-nodejs:python3.11-nodejs22-bookworm` as recommended by research, add a comment noting the change, and retry. After successful build: - Run `docker run --rm ngn-agent:latest aws --version` — confirms aws-cli is installed and executable - Run `docker run --rm ngn-agent:latest terraform --version` — confirms terraform works - Run `docker run --rm ngn-agent:latest helm version --short` — confirms helm works - Run `docker run --rm ngn-agent:latest kubectl version --client` — confirms kubectl works - Run `docker run --rm ngn-agent:latest pup --version` — confirms pup works If any tool fails in the container, fix the Dockerfile and rebuild. The image must have all 5 tools working. docker run --rm ngn-agent:latest sh -c 'aws --version && terraform --version && helm version --short && kubectl version --client && pup --version' - build.sh exists and is executable - `ngn-agent:latest` image builds successfully - All 5 tools execute correctly inside the container - Build script references D-04 and D-05 decisions - If base image tag was updated to python3.11-nodejs22-bookworm due to deprecation, the FROM line is updated and a comment explains the change ## Trust Boundaries | Boundary | Description | |----------|-------------| | Docker build host → Docker daemon | Docker context is read by build daemon | | Docker build → external tool repos | Tool downloads cross HTTPS boundaries | | Docker image layers → local storage | Built image stored on host filesystem | ## STRIDE Threat Register | Threat ID | Category | Component | Disposition | Mitigation Plan | |-----------|----------|-----------|-------------|-----------------| | T-09-01 | Tampering | Tool download MITM (curl/wget from S3, GitHub, apt repos) | mitigate | All downloads use HTTPS. apt repos use GPG key verification to sign packages. | | T-09-02 | Information Disclosure | Build context leak (COPY . could send .env into Docker daemon) | mitigate | Build context is `docker/` directory only — not repo root. Dockerfile does not COPY . anywhere. | | T-09-03 | Tampering | Base image supply chain (nikolaik/python-nodejs) | accept | Widely used community image; no custom base image available. | | T-09-04 | Denial of Service | Base image tag python3.11-nodejs20 may not exist | mitigate | Dockerfile comment flags potential deprecation. If build fails with manifest error, update to python3.11-nodejs22-bookworm. | ## Package Legitimacy Gate | Package | Registry | Verdict | Disposition | |---------|----------|---------|-------------| | (none) | — | — | No npm/pip/cargo packages installed. All tools via apt or curl binary downloads. | - Automated: `docker run --rm ngn-agent:latest sh -c 'aws --version && terraform --version && helm version --short && kubectl version --client && pup --version'` passes with all 5 tools - Manual: User can inspect `docker/images` output to confirm tag and creation date 1. The image `ngn-agent:latest` exists in local Docker daemon 2. Running `docker run --rm ngn-agent:latest --version` succeeds for all 5 tools 3. `docker/build.sh` is the single entry point for rebuilding 4. Both files are committed to the ngn-agent git repo 5. Tool versions are pinned (ARGS in Dockerfile) for future reproducibility