From c45956c3212494359deeb8dd8119f460576266d5 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 15 Jun 2026 18:10:22 +0000 Subject: [PATCH 1/3] fix: unpin apt packages to stop build breakage on Debian point releases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Debian drops old point-release package versions from the bookworm mirror, so exact pins (e.g. ca-certificates=20230311) vanish and the build fails (apt exit 100) — this broke build-test. Unpin the OS utility packages (keep --no-install-recommends) and ignore hadolint DL3008. Supply-chain integrity is unchanged where it matters: Terraform and AWS CLI stay version-pinned and GPG/checksum-verified; base image stays tag-pinned. Records the decision and trade-off as ADR-0010. https://claude.ai/code/session_01EESGRwTzyd1G16yv7R2Eqd --- Dockerfile | 29 +++++---- docs/adr/0010-apt-package-pinning-strategy.md | 61 +++++++++++++++++++ docs/adr/README.md | 1 + docs/roadmap.md | 1 + hadolint.yaml | 1 + 5 files changed, 78 insertions(+), 15 deletions(-) create mode 100644 docs/adr/0010-apt-package-pinning-strategy.md diff --git a/Dockerfile b/Dockerfile index 2af6f55..568153a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,11 +9,10 @@ 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 unzip=6.0-28 +RUN apt-get install --no-install-recommends -y ca-certificates +RUN apt-get install --no-install-recommends -y curl +RUN apt-get install --no-install-recommends -y gnupg +RUN apt-get install --no-install-recommends -y unzip WORKDIR /workspace RUN curl --silent --show-error --fail --remote-name https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_${TARGETARCH}.zip COPY security/hashicorp.asc ./ @@ -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 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 ca-certificates +RUN apt-get install -y --no-install-recommends curl +RUN apt-get install -y --no-install-recommends gnupg +RUN apt-get install -y --no-install-recommends unzip +RUN apt-get install -y --no-install-recommends git +RUN apt-get install -y --no-install-recommends jq 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 \ + git \ + jq \ + openssh-client \ && 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..1f8700c --- /dev/null +++ b/docs/adr/0010-apt-package-pinning-strategy.md @@ -0,0 +1,61 @@ +# 0010 — APT package pinning strategy + +- Status: Accepted +- Date: 2026-06-15 +- Deciders: @bgauduch + +## Context and problem statement + +The Dockerfile pinned every OS package to an exact version +(`ca-certificates=20230311`, `curl=7.88.1-10+deb12u4`, …). Debian removes old +point-release versions from the `bookworm` mirror as it publishes new ones, so +those exact pins disappear and the build breaks with `apt-get … exit code 100`. +This is exactly what failed `build-test` on PR #119 +(`ca-certificates=20230311` no longer available). It recurs every Debian point +release and there is no good automation to chase apt pins. + +## Decision drivers + +- Builds must not break on routine Debian point releases. +- Low maintenance (no manual apt-version chasing; Renovate can't manage these). +- Keep reproducibility/supply-chain integrity **where it matters** — the bundled + tools. + +## Considered options + +- **Keep exact pins** and chase versions on every break (status quo). +- **Pin against `snapshot.debian.org`** for frozen, reproducible apt versions. +- **Unpin the OS utility packages**, relying on the Debian *stable* suite + the + pinned base image for adequate reproducibility. + +## Decision outcome + +Chosen option: **unpin the OS utility packages** +(`ca-certificates`, `curl`, `gnupg`, `unzip`, `git`, `jq`, `openssh-client`), +keeping `--no-install-recommends`. Hadolint **DL3008** is ignored +(`hadolint.yaml`) since unpinning is now intentional. + +Crucially, this does **not** weaken supply-chain integrity for what matters: + +- **Terraform** and **AWS CLI** remain version-pinned (`supported_versions.json`) + and verified by **GPG signature + checksum** at build time. +- The **base image** stays tag-pinned (digest pin + bump tracked in Phase 3 / + #108). + +Only the auxiliary OS utilities float, bounded by the `bookworm` stable suite. + +### Consequences + +- Good: builds stop breaking on Debian point releases; no apt-version chasing. +- Cost: exact OS-package versions are no longer reproducible byte-for-byte + (acceptable for a tools image; the security-critical binaries are still pinned + and verified). +- Lint: DL3008 ignored, documented in `hadolint.yaml`. +- Follow-ups: base-image digest pin + bump (#108); adopt `snapshot.debian.org` + later only if strict OS reproducibility is ever required. + +## More information + +Superseded approach: the per-package exact pins added in earlier Dockerfile +revisions. The bundled-binary verification chain is unchanged +(`docs/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/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/hadolint.yaml b/hadolint.yaml index 5807ba7..571122d 100644 --- a/hadolint.yaml +++ b/hadolint.yaml @@ -1,2 +1,3 @@ ignored: - DL3059 # Ignore https://github.com/hadolint/hadolint/wiki/DL3059, specific to build stages + - DL3008 # APT packages intentionally unpinned (stable suite); see docs/adr/0010-apt-package-pinning-strategy.md From 75bf119faedc788eb8804383cbc3c52505af1da7 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 15 Jun 2026 18:21:25 +0000 Subject: [PATCH 2/3] fix: refresh apt package pins to current bookworm versions Debian superseded the old point-release pins (e.g. ca-certificates 20230311 -> +deb12u1), so apt-get install failed. Re-pin all OS packages to the current bookworm candidates; keep exact pinning (ADR-0010) rather than unpinning. Document the refresh procedure in dependencies-upgrades.md. https://claude.ai/code/session_01EESGRwTzyd1G16yv7R2Eqd --- Dockerfile | 28 +++---- docs/adr/0010-apt-package-pinning-strategy.md | 74 ++++++++++--------- docs/dependencies-upgrades.md | 9 ++- hadolint.yaml | 1 - 4 files changed, 61 insertions(+), 51 deletions(-) diff --git a/Dockerfile b/Dockerfile index 568153a..baf352d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,10 +9,10 @@ FROM debian:${DEBIAN_VERSION} as terraform ARG TARGETARCH ARG TERRAFORM_VERSION RUN apt-get update -RUN apt-get install --no-install-recommends -y ca-certificates -RUN apt-get install --no-install-recommends -y curl -RUN apt-get install --no-install-recommends -y gnupg -RUN apt-get install --no-install-recommends -y unzip +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 COPY security/hashicorp.asc ./ @@ -26,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 -RUN apt-get install -y --no-install-recommends curl -RUN apt-get install -y --no-install-recommends gnupg -RUN apt-get install -y --no-install-recommends unzip -RUN apt-get install -y --no-install-recommends git -RUN apt-get install -y --no-install-recommends jq +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.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 ./ @@ -46,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 \ - git \ - jq \ - openssh-client \ + 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 index 1f8700c..6002269 100644 --- a/docs/adr/0010-apt-package-pinning-strategy.md +++ b/docs/adr/0010-apt-package-pinning-strategy.md @@ -6,56 +6,60 @@ ## Context and problem statement -The Dockerfile pinned every OS package to an exact version -(`ca-certificates=20230311`, `curl=7.88.1-10+deb12u4`, …). Debian removes old -point-release versions from the `bookworm` mirror as it publishes new ones, so -those exact pins disappear and the build breaks with `apt-get … exit code 100`. -This is exactly what failed `build-test` on PR #119 -(`ca-certificates=20230311` no longer available). It recurs every Debian point -release and there is no good automation to chase apt pins. +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 -- Builds must not break on routine Debian point releases. -- Low maintenance (no manual apt-version chasing; Renovate can't manage these). -- Keep reproducibility/supply-chain integrity **where it matters** — the bundled - tools. +- Reproducibility and supply-chain integrity of the image. +- Predictable, reviewable dependency changes. +- Acceptable maintenance for a low-traffic project. ## Considered options -- **Keep exact pins** and chase versions on every break (status quo). -- **Pin against `snapshot.debian.org`** for frozen, reproducible apt versions. -- **Unpin the OS utility packages**, relying on the Debian *stable* suite + the - pinned base image for adequate reproducibility. +- **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: **unpin the OS utility packages** +Chosen option: **keep exact version pins** for all OS packages (`ca-certificates`, `curl`, `gnupg`, `unzip`, `git`, `jq`, `openssh-client`), -keeping `--no-install-recommends`. Hadolint **DL3008** is ignored -(`hadolint.yaml`) since unpinning is now intentional. +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). -Crucially, this does **not** weaken supply-chain integrity for what matters: +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. -- **Terraform** and **AWS CLI** remain version-pinned (`supported_versions.json`) - and verified by **GPG signature + checksum** at build time. -- The **base image** stays tag-pinned (digest pin + bump tracked in Phase 3 / - #108). - -Only the auxiliary OS utilities float, bounded by the `bookworm` stable suite. +**`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: builds stop breaking on Debian point releases; no apt-version chasing. -- Cost: exact OS-package versions are no longer reproducible byte-for-byte - (acceptable for a tools image; the security-critical binaries are still pinned - and verified). -- Lint: DL3008 ignored, documented in `hadolint.yaml`. -- Follow-ups: base-image digest pin + bump (#108); adopt `snapshot.debian.org` - later only if strict OS reproducibility is ever required. +- 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 -Superseded approach: the per-package exact pins added in earlier Dockerfile -revisions. The bundled-binary verification chain is unchanged -(`docs/binaries-verifications.md`). +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/dependencies-upgrades.md b/docs/dependencies-upgrades.md index c675333..21ae6a9 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 and update the Dockerfile: + + ```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/hadolint.yaml b/hadolint.yaml index 571122d..5807ba7 100644 --- a/hadolint.yaml +++ b/hadolint.yaml @@ -1,3 +1,2 @@ ignored: - DL3059 # Ignore https://github.com/hadolint/hadolint/wiki/DL3059, specific to build stages - - DL3008 # APT packages intentionally unpinned (stable suite); see docs/adr/0010-apt-package-pinning-strategy.md From a66b0bd241c991869f1c440346684e5ef5d4d6cc Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 15 Jun 2026 18:27:30 +0000 Subject: [PATCH 3/3] test: align container-structure git assertion with refreshed pin The structure test hard-codes the git version; bump 2.39.2 -> 2.39.5 to match the refreshed Dockerfile pin. Note in the upgrade checklist that test assertions must be refreshed alongside the apt pins. https://claude.ai/code/session_01EESGRwTzyd1G16yv7R2Eqd --- docs/dependencies-upgrades.md | 2 +- tests/container-structure-tests.yml.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dependencies-upgrades.md b/docs/dependencies-upgrades.md index 21ae6a9..b2a522d 100644 --- a/docs/dependencies-upgrades.md +++ b/docs/dependencies-upgrades.md @@ -16,7 +16,7 @@ * 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 and update the Dockerfile: + * 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 \ 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"