From eef317fb3a378d0522bb54b8575669e15b7e9f9b Mon Sep 17 00:00:00 2001 From: DSH Agent Date: Sun, 20 Sep 2026 02:54:22 -0400 Subject: [PATCH] dependency-check: run in an image that has both cargo and Node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first run died on `exec: node: not found` — rust:1.95-bookworm has no Node, and the report needs cargo to resolve the workspace graph alongside Node to read the registries. .gitea/scripts/ci.Dockerfile layers the two official images together, so the parsing exists once rather than once per language. --- .gitea/scripts/ci.Dockerfile | 21 +++++++++++++++++++++ .gitea/workflows/dependency-check.yml | 18 ++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 .gitea/scripts/ci.Dockerfile diff --git a/.gitea/scripts/ci.Dockerfile b/.gitea/scripts/ci.Dockerfile new file mode 100644 index 0000000..15a6f27 --- /dev/null +++ b/.gitea/scripts/ci.Dockerfile @@ -0,0 +1,21 @@ +# CI-only image for the dependency check. +# +# The report is a Node script because it has to compare semantic versions and +# read four different HTTP APIs, and the official `rust` image ships no Node — +# while the `node` image ships no cargo, which `cargo metadata` needs to resolve +# the workspace graph. Rather than maintain the parsing twice in two languages, +# this layers the two together. +# +# Node is copied from the official image rather than installed from a +# third-party apt repository: no extra signing key, no extra network +# dependency at build time, and the same binaries everyone else runs. +ARG RUST_VERSION=1.95 +ARG NODE_VERSION=22-bookworm-slim + +FROM node:${NODE_VERSION} AS node + +FROM rust:${RUST_VERSION}-bookworm +COPY --from=node /usr/local/bin/node /usr/local/bin/node +COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules +RUN ln -sf /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \ + && node --version diff --git a/.gitea/workflows/dependency-check.yml b/.gitea/workflows/dependency-check.yml index 3dec59e..ff4d733 100644 --- a/.gitea/workflows/dependency-check.yml +++ b/.gitea/workflows/dependency-check.yml @@ -53,8 +53,11 @@ jobs: # The workspace is streamed into the container over stdin rather than # bind-mounted, so this works whether the runner shares a filesystem with - # the daemon or not. The official rust image already carries the - # toolchain, so nothing is downloaded inside. + # the daemon or not. + # + # The image is rust + node, built from .gitea/scripts/ci.Dockerfile: the + # report needs cargo to resolve the workspace graph and Node to read the + # registries, and neither official image has both. # # RUSTUP_TOOLCHAIN overrides rust-toolchain.toml: the image's own # toolchain is enough to read Cargo.lock, and honouring the file would @@ -66,10 +69,17 @@ jobs: - name: Generate report run: | set -eu + VERSION="${{ steps.rust.outputs.version }}" + docker build \ + --build-arg "RUST_VERSION=${VERSION}" \ + --tag "dep-check:${VERSION}" \ + --file .gitea/scripts/ci.Dockerfile \ + .gitea/scripts > /dev/null + tar cf - --exclude=./.git --exclude=./target . | docker run --rm -i \ - -e RUSTUP_TOOLCHAIN="${{ steps.rust.outputs.version }}" \ + -e RUSTUP_TOOLCHAIN="${VERSION}" \ -e CARGO_TERM_COLOR=never \ - "rust:${{ steps.rust.outputs.version }}-bookworm" \ + "dep-check:${VERSION}" \ sh -ec 'mkdir -p /work && cd /work && tar xf - && exec node .gitea/scripts/dependency-report.mjs' \ > /tmp/report.md 2> /tmp/report.err || { echo "::error::the dependency report failed to generate"