diff --git a/Dockerfile b/Dockerfile index 2af6f55..baf352d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,10 +9,9 @@ FROM debian:${DEBIAN_VERSION} as terraform ARG TARGETARCH ARG TERRAFORM_VERSION RUN apt-get update -# RUN apt-get install --no-install-recommends -y libcurl4=7.74.0-1.3+deb11u7 -RUN apt-get install --no-install-recommends -y ca-certificates=20230311 -RUN apt-get install --no-install-recommends -y curl=7.88.1-10+deb12u4 -RUN apt-get install --no-install-recommends -y gnupg=2.2.40-1.1 +RUN apt-get install --no-install-recommends -y ca-certificates=20230311+deb12u1 +RUN apt-get install --no-install-recommends -y curl=7.88.1-10+deb12u14 +RUN apt-get install --no-install-recommends -y gnupg=2.2.40-1.1+deb12u2 RUN apt-get install --no-install-recommends -y unzip=6.0-28 WORKDIR /workspace RUN curl --silent --show-error --fail --remote-name https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_${TARGETARCH}.zip @@ -27,12 +26,12 @@ RUN unzip -j terraform_${TERRAFORM_VERSION}_linux_${TARGETARCH}.zip FROM debian:${DEBIAN_VERSION} as aws-cli ARG AWS_CLI_VERSION RUN apt-get update -RUN apt-get install -y --no-install-recommends ca-certificates=20230311 -RUN apt-get install -y --no-install-recommends curl=7.88.1-10+deb12u4 -RUN apt-get install -y --no-install-recommends gnupg=2.2.40-1.1 +RUN apt-get install -y --no-install-recommends ca-certificates=20230311+deb12u1 +RUN apt-get install -y --no-install-recommends curl=7.88.1-10+deb12u14 +RUN apt-get install -y --no-install-recommends gnupg=2.2.40-1.1+deb12u2 RUN apt-get install -y --no-install-recommends unzip=6.0-28 -RUN apt-get install -y --no-install-recommends git=1:2.39.2-1.1 -RUN apt-get install -y --no-install-recommends jq=1.6-2.1 +RUN apt-get install -y --no-install-recommends git=1:2.39.5-0+deb12u3 +RUN apt-get install -y --no-install-recommends jq=1.6-2.1+deb12u1 WORKDIR /workspace RUN curl --show-error --fail --output "awscliv2.zip" --remote-name "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-${AWS_CLI_VERSION}.zip" COPY security/awscliv2.asc ./ @@ -47,10 +46,10 @@ FROM debian:${DEBIAN_VERSION} as build LABEL maintainer="bgauduch@github" RUN apt-get update \ && apt-get install -y --no-install-recommends \ - ca-certificates=20230311\ - git=1:2.39.2-1.1 \ - jq=1.6-2.1 \ - openssh-client=1:9.2p1-2+deb12u1 \ + ca-certificates=20230311+deb12u1 \ + git=1:2.39.5-0+deb12u3 \ + jq=1.6-2.1+deb12u1 \ + openssh-client=1:9.2p1-2+deb12u10 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* WORKDIR /workspace diff --git a/docs/adr/0010-apt-package-pinning-strategy.md b/docs/adr/0010-apt-package-pinning-strategy.md new file mode 100644 index 0000000..6002269 --- /dev/null +++ b/docs/adr/0010-apt-package-pinning-strategy.md @@ -0,0 +1,65 @@ +# 0010 — APT package pinning strategy + +- Status: Accepted +- Date: 2026-06-15 +- Deciders: @bgauduch + +## Context and problem statement + +The Dockerfile pins every OS package to an exact version +(`ca-certificates=20230311+deb12u1`, `curl=7.88.1-10+deb12u14`, …). Debian +removes superseded point-release versions from the `bookworm` mirror, so a stale +pin eventually disappears and the build fails with `apt-get … exit code 100`. +This broke `build-test` (the pin `ca-certificates=20230311` had been superseded +by `…+deb12u1`). The question is whether to keep pinning, drop pins, or freeze +the mirror. + +## Decision drivers + +- Reproducibility and supply-chain integrity of the image. +- Predictable, reviewable dependency changes. +- Acceptable maintenance for a low-traffic project. + +## Considered options + +- **Keep exact version pins** and refresh them when Debian supersedes a version + (or on base-image bumps). +- **Unpin** the OS utility packages (rely on the stable suite). *Rejected — loses + reproducibility and makes dependency changes invisible.* +- **`snapshot.debian.org`** as a frozen apt source so exact pins never disappear. + +## Decision outcome + +Chosen option: **keep exact version pins** for all OS packages +(`ca-certificates`, `curl`, `gnupg`, `unzip`, `git`, `jq`, `openssh-client`), +with `--no-install-recommends`. Pins are **refreshed** when a build breaks on a +superseded version or when the base image is bumped — the procedure is documented +in [`docs/dependencies-upgrades.md`](../dependencies-upgrades.md). + +Unpinning was explicitly rejected: the bundled tools (Terraform, AWS CLI) are +already pinned + GPG/checksum-verified, and keeping the OS packages pinned too +keeps the whole image reproducible and every change explicit in the diff. + +**`snapshot.debian.org`** is recorded as the path to make pins *never* break +(fully reproducible builds); it is deferred to a future ADR/PR rather than +adopted now, to keep this change minimal. + +### Consequences + +- Good: reproducible, explicit dependencies; supply-chain integrity preserved. +- Cost: pins must be refreshed periodically (when Debian supersedes a version) — + a manual step today, a candidate for a Renovate custom manager later (#20). +- Lint: hadolint `DL3008` stays **enforced** (pinning required). + +## More information + +Pin values are read with: + +```bash +docker run --rm debian:bookworm-slim bash -c \ + 'apt-get update -qq && for p in ca-certificates curl gnupg unzip git jq openssh-client; do \ + printf "%s=%s\n" "$p" "$(apt-cache policy "$p" | awk "/Candidate:/{print \$2}")"; done' +``` + +The bundled-binary verification chain is unchanged +([`docs/binaries-verifications.md`](../binaries-verifications.md)). diff --git a/docs/adr/README.md b/docs/adr/README.md index 7a4a2fd..06fcf1c 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -58,3 +58,4 @@ Phase 6) will scaffold this automatically. | [0007](0007-adopt-entire-checkpoints.md) | Adopt Entire / Checkpoints for agent-session capture | Proposed | | [0008](0008-conventional-branch-naming.md) | Conventional branch naming | Accepted | | [0009](0009-agent-agnostic-framework.md) | Agent-agnostic framework with a tool-specific adapter layer | Accepted | +| [0010](0010-apt-package-pinning-strategy.md) | APT package pinning strategy | Accepted | diff --git a/docs/dependencies-upgrades.md b/docs/dependencies-upgrades.md index c675333..b2a522d 100644 --- a/docs/dependencies-upgrades.md +++ b/docs/dependencies-upgrades.md @@ -3,7 +3,7 @@ * Supported tools versions: * [Report to the doc](https://github.com/zenika-open-source/terraform-aws-cli/tree/master/docs/binaries-verifications.md) to add required security files (stored under `security/`, e.g. `security/hashicorp.asc`) when adding a new supported versions * check available **AWS CLI** version on the [project release page](https://github.com/aws/aws-cli/tags) - * check available **Terraform CLI** version (keep all minor versions from 0.11) on the [project release page](https://github.com/hashicorp/terraform/releases) + * check available **Terraform CLI** version (keep one patch per minor, from 1.0 — see ADR-0004) on the [project release page](https://github.com/hashicorp/terraform/releases) * Dockerfile: * check **base image** version [on DockerHub](https://hub.docker.com/_/debian?tab=tags&page=1&name=bookworm) * check OS package versions on Debian package repository @@ -16,6 +16,13 @@ * Available **curl** versions on the [Debian Packages repository](https://packages.debian.org/search?suite=bookworm&arch=any&searchon=names&keywords=curl) * Available **gnupg** versions on the [Debian Packages repository](https://packages.debian.org/search?suite=bookworm&arch=any&searchon=names&keywords=gnupg) * Available **unzip** versions on the [Debian Packages repository](https://packages.debian.org/search?suite=bookworm&arch=any&searchon=names&keywords=unzip) + * OS packages are **pinned to exact versions** in the Dockerfile (see ADR-0010). When a build fails with `apt-get ... exit code 100`, a pin was superseded by Debian — refresh **all** pins to the current candidates, then update the Dockerfile **and** the matching version assertions in [`tests/container-structure-tests.yml.template`](tests/container-structure-tests.yml.template) (e.g. the git/jq/openssh versions): + + ```bash + docker run --rm debian:bookworm-slim bash -c \ + 'apt-get update -qq && for p in ca-certificates curl gnupg unzip git jq openssh-client; do \ + printf "%s=%s\n" "$p" "$(apt-cache policy "$p" | awk "/Candidate:/{print \$2}")"; done' + ``` * Dockerfile tests : update version according to changes in Dockerfile in [tests/container-structure-tests.yml.template](tests/container-structure-tests.yml.template) * Github actions: * check [runner version](https://github.com/actions/virtual-environments#available-environments) diff --git a/docs/roadmap.md b/docs/roadmap.md index 4d60718..f6fe02d 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -110,6 +110,7 @@ Code) (Phase 2). | Dependency bot | **Renovate only** (Dependabot retired) | ADR-0002 | | ADR format | MADR (Nygard considered, rejected for simplicity) | ADR-0005 | | Terraform deprecation | Drop versions `< 1.0` from `supported_versions.json` | ADR-0004 | +| APT package pinning | OS utility packages unpinned (stable suite); bundled binaries stay pinned + GPG/checksum verified | ADR-0010 | | Rollback policy | No mutation of immutable full tags; consumers re-pin an older tag | `docs/rollback.md` | | ADR enforcement | PR-template checkbox + `adr-check.yml` CI gate + CODEOWNERS (no soft-rule-only) | this doc | | Branch naming | `type/topic` (Conventional types), `type/phase-N-topic` for phases; no tool names | ADR-0008 | diff --git a/tests/container-structure-tests.yml.template b/tests/container-structure-tests.yml.template index 619fc87..fe292c6 100644 --- a/tests/container-structure-tests.yml.template +++ b/tests/container-structure-tests.yml.template @@ -11,7 +11,7 @@ commandTests: - name: "Check Git version" command: "git" args: ["--version"] - expectedOutput: ["git version 2.39.2"] + expectedOutput: ["git version 2.39.5"] - name: "Check JQ version" command: "jq"