Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/build-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
- '*/smoke-test.sh'
- '*/node-keyring.kbx'
- '*/githubcli-archive-keyring.gpg'
- '*/rustup-init-*.sha256'
- build-config.sh
- .trivyignore.yaml
push:
Expand All @@ -20,6 +21,7 @@ on:
- '*/smoke-test.sh'
- '*/node-keyring.kbx'
- '*/githubcli-archive-keyring.gpg'
- '*/rustup-init-*.sha256'
- build-config.sh

permissions: {}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,8 @@ jobs:
fi

# Commit each changed README via the contents API (one commit per
# file, same pattern as update-keys.yml). Commits are created by
# the app, so they are verified.
# file, same pattern as update-material.yml). Commits are created
# by the app, so they are verified.
while IFS= read -r path; do
image="${path%%/*}"
existing_sha=$(gh api "repos/${REPO}/contents/${path}?ref=${BRANCH}" \
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
name: Update Trusted Keys
name: Update Trusted Material

# Keeps trust material committed to this repository — signing keys,
# keyrings, and per-version checksum files with no signature of their
# own — in sync with each upstream. Format-specific verification (GPG,
# minisign, sha256sum) happens in each image's Dockerfile against the
# committed file; this workflow only keeps that file's content current.

on:
pull_request:
paths:
- .github/workflows/update-keys.yml
- .github/workflows/update-material.yml
# Entries with a version_file re-run promptly when Renovate bumps the
# pinned version, since the currently committed checksum would
# otherwise go stale until the next scheduled run.
- rust/build.yaml
schedule:
- cron: '0 6 * * 3'
workflow_dispatch:
Expand Down Expand Up @@ -72,6 +82,33 @@ jobs:
[cli.github.com](https://cli.github.com/packages/githubcli-archive-keyring.gpg),
the GPG keyring that signs GitHub's official apt repository used to
install the `gh` CLI in the uv builder stage.
- id: rust-rustup-init-sha256-amd64
path: rust/rustup-init-amd64.sha256
# VERSION is replaced with RUSTUP_VERSION, read from version_file below.
url: https://static.rust-lang.org/rustup/archive/VERSION/x86_64-unknown-linux-gnu/rustup-init.sha256
version_file: rust/build.yaml
version_key: RUSTUP_VERSION
title: "chore(rust): update rustup-init checksum (amd64)"
body: >-
Automated sync of `rust/rustup-init-amd64.sha256` from
[static.rust-lang.org](https://static.rust-lang.org/rustup/), matching the
currently pinned `RUSTUP_VERSION`. rustup publishes no GPG/minisign signature
for `rustup-init`, so this checksum file, committed to the repo and reviewed
like any other change, is the trust anchor `rust/Dockerfile` verifies the
downloaded binary against.
- id: rust-rustup-init-sha256-arm64
path: rust/rustup-init-arm64.sha256
url: https://static.rust-lang.org/rustup/archive/VERSION/aarch64-unknown-linux-gnu/rustup-init.sha256
version_file: rust/build.yaml
version_key: RUSTUP_VERSION
title: "chore(rust): update rustup-init checksum (arm64)"
body: >-
Automated sync of `rust/rustup-init-arm64.sha256` from
[static.rust-lang.org](https://static.rust-lang.org/rustup/), matching the
currently pinned `RUSTUP_VERSION`. rustup publishes no GPG/minisign signature
for `rustup-init`, so this checksum file, committed to the repo and reviewed
like any other change, is the trust anchor `rust/Dockerfile` verifies the
downloaded binary against.
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
Expand All @@ -81,7 +118,14 @@ jobs:
- name: Download remote file
env:
URL: ${{ matrix.url }}
run: wget -q -T 30 -t 3 -O /tmp/downloaded "${URL}"
VERSION_FILE: ${{ matrix.version_file }}
VERSION_KEY: ${{ matrix.version_key }}
run: |
if [ -n "$VERSION_FILE" ]; then
VERSION=$(KEY="$VERSION_KEY" yq '.variants[0].build_args.[strenv(KEY)]' "$VERSION_FILE")
URL="${URL//VERSION/${VERSION}}"
fi
wget -q -T 30 -t 3 -O /tmp/downloaded "${URL}"

- name: Check for changes
id: diff
Expand Down
19 changes: 12 additions & 7 deletions rust/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,22 @@ ENV PATH=/home/dev/.cargo/bin:${PATH}

USER dev

# rustup publishes no signature for rustup-init, so verify it against a
# checksum file committed to this repository (kept in sync by
# .github/workflows/update-material.yml and reviewed like any other change)
# instead of one fetched from the same server as the binary.
# hadolint ignore=DL3003 # cd only used in subshell
RUN case "${TARGETARCH}" in \
amd64) RUST_ARCH="x86_64" ;; \
arm64) RUST_ARCH="aarch64" ;; \
RUN --mount=type=bind,source=rustup-init-amd64.sha256,target=/tmp/rustup-init-amd64.sha256,ro \
--mount=type=bind,source=rustup-init-arm64.sha256,target=/tmp/rustup-init-arm64.sha256,ro \
case "${TARGETARCH}" in \
amd64) RUST_ARCH="x86_64"; RUSTUP_SHA256_FILE="/tmp/rustup-init-amd64.sha256" ;; \
arm64) RUST_ARCH="aarch64"; RUSTUP_SHA256_FILE="/tmp/rustup-init-arm64.sha256" ;; \
*) echo "Unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \
esac \
&& RUSTUP_TMPDIR="$(mktemp -d)" \
&& RUSTUP_URL="https://static.rust-lang.org/rustup/archive/${RUSTUP_VERSION}/${RUST_ARCH}-unknown-linux-gnu" \
&& wget -q -T 30 -t 3 -P "${RUSTUP_TMPDIR}" "${RUSTUP_URL}/rustup-init" \
&& wget -q -T 30 -t 3 -P "${RUSTUP_TMPDIR}" "${RUSTUP_URL}/rustup-init.sha256" \
&& (cd "${RUSTUP_TMPDIR}" && sha256sum -c rustup-init.sha256) \
&& wget -q -T 30 -t 3 -P "${RUSTUP_TMPDIR}" \
"https://static.rust-lang.org/rustup/archive/${RUSTUP_VERSION}/${RUST_ARCH}-unknown-linux-gnu/rustup-init" \
&& (cd "${RUSTUP_TMPDIR}" && sha256sum -c "${RUSTUP_SHA256_FILE}") \
&& chmod +x "${RUSTUP_TMPDIR}/rustup-init" \
&& "${RUSTUP_TMPDIR}/rustup-init" -y --no-modify-path --default-toolchain none \
&& rm -rf "${RUSTUP_TMPDIR}" \
Expand Down
2 changes: 1 addition & 1 deletion rust/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Dev container image with Rust installed via `rustup`, built on the [debian](../debian) base image.

`rustup` is downloaded directly from the official [rustup release archive](https://static.rust-lang.org/rustup/) and verified against its published SHA-256 checksum. Rust toolchains are managed by `rustup` and stored in `~/.cargo`.
`rustup` is downloaded directly from the official [rustup release archive](https://static.rust-lang.org/rustup/). rustup publishes no signature for `rustup-init`, so it is verified against a SHA-256 checksum file committed to this repository (`rust/rustup-init-<arch>.sha256`) rather than one fetched from the same server as the binary. The committed checksum files are kept in sync with the pinned `RUSTUP_VERSION` by an automated workflow and reviewed like any other change, so later tampering with the download channel cannot affect builds. Rust toolchains are managed by `rustup` and stored in `~/.cargo`.

## Image

Expand Down
1 change: 1 addition & 0 deletions rust/rustup-init-amd64.sha256
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
4acc9acc76d5079515b46346a485974457b5a79893cfb01112423c89aeb5aa10 *./rustup-init
1 change: 1 addition & 0 deletions rust/rustup-init-arm64.sha256
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
9732d6c5e2a098d3521fca8145d826ae0aaa067ef2385ead08e6feac88fa5792 *./rustup-init
2 changes: 1 addition & 1 deletion uv/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ USER root
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# Install gh from GitHub's official apt repository to verify uv's GitHub
# Artifact Attestation below. The repository keyring is committed to this repo
# and kept in sync by the update-keys workflow.
# and kept in sync by .github/workflows/update-material.yml.
RUN --mount=type=bind,source=githubcli-archive-keyring.gpg,target=/etc/apt/keyrings/githubcli-archive-keyring.gpg,readonly \
--mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
Expand Down