From fb9a6b46b2ca667063274313ba82184980145ba0 Mon Sep 17 00:00:00 2001 From: Tee8z Date: Thu, 5 Nov 2026 17:43:20 -0500 Subject: [PATCH] feat(agents): add the rust-crap-score tools to the agent image The agent image ships the rust-crap-score engineering skill, but its collector refuses to run without cargo-llvm-cov 0.8.5, knots 1.16.0, and the toolchain's LLVM tools. Add llvm-tools-preview to the Rust toolchain, the checksum-pinned cargo-llvm-cov musl release for each architecture, and knots built from crates.io with its published lockfile, since its releases have no linux arm64 binary. The image test checks the exact versions and collects coverage and complexity for a small crate. Signed-off-by: Tee8z --- voltage/images/buzz-agent/Dockerfile | 26 ++++++++++++++++++++----- voltage/images/buzz-agent/README.md | 1 + voltage/images/buzz-agent/test-image.sh | 16 +++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/voltage/images/buzz-agent/Dockerfile b/voltage/images/buzz-agent/Dockerfile index 267ef6429c1..4cd82225448 100644 --- a/voltage/images/buzz-agent/Dockerfile +++ b/voltage/images/buzz-agent/Dockerfile @@ -16,6 +16,16 @@ RUN cargo build --locked --profile sprig -p sprig \ && strip target/sprig/sprig FROM rust:1.97.1-slim-trixie@sha256:8e8cf8f7fd54a2d23d5a743b3a03f56e26b6c774276c33fa0595111704ebb15c AS development-rust +# cargo-llvm-cov (the engineering-skills rust-crap-score skill) reads coverage +# with the toolchain's LLVM tools. +RUN rustup component add llvm-tools-preview + +# knots 1.16.0, the complexity analyzer rust-crap-score requires. Its releases +# have no linux arm64 binary, so build it from crates.io with its published +# Cargo.lock; cargo checks the crate against the registry checksum. +FROM development-rust AS crap-tools +RUN cargo install --locked --version 1.16.0 knots --root /opt/crap-tools \ + && strip /opt/crap-tools/bin/knots FROM node:22-trixie-slim@sha256:154ba2f4d6fec323d28e4f4bb86bba4677f1223391a1979cf521304e03a98dfa LABEL maintainer="Voltage " @@ -34,20 +44,22 @@ ENV RUSTUP_HOME=/opt/rustup CARGO_HOME=/home/agent/.cargo CARGO_BUILD_JOBS=2 # credentials enter only at runtime. ARG TARGETARCH RUN case "$TARGETARCH" in \ - amd64) via=x86_64 gitleaks=x64 sccache=x86_64 \ + amd64) via=x86_64 gitleaks=x64 sccache=x86_64 llvm_cov=x86_64 \ kubectl_sha=874d5e72dbb819f43cff16bcd1e4f8bac5b7f2361fe1e55049b0a6c676fb0cbf \ via_sha=9e5a7f9384cacda29061d814e9397e7b6d90a72ee4663775362978ac9b65d8b7 \ op_sha=198b05dcf9a0972778ce5a4e262c459979b0c837257b5da65e2fba6187734226 \ gitleaks_sha=551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb \ depot_sha=7a469c767bd3b7e67b3174f91af9c6315fea0ced4871948ee9d41a006fb2347e \ - sccache_sha=45f1447fbe231e3037bde351ef70677dd212216c8d62ae7ca409fecc4d6acc89 ;; \ - arm64) via=arm64 gitleaks=arm64 sccache=aarch64 \ + sccache_sha=45f1447fbe231e3037bde351ef70677dd212216c8d62ae7ca409fecc4d6acc89 \ + llvm_cov_sha=e9fc23dbbdc502ee9267544f8c6e8e162c6d7df8fb2e3f62d8289a4c0bd240ce ;; \ + arm64) via=arm64 gitleaks=arm64 sccache=aarch64 llvm_cov=aarch64 \ kubectl_sha=cc749967b62f4422260bc9c0aa7a7c55f45175ae38cb8d95767b5d2b7e04c1fd \ via_sha=26cc174802c875424b9846a398d4b2d890b911506f7c574dee96859620caa535 \ op_sha=7b5c361a23e738a3969cf676960f4843af4aa9aa68dbec23d18a9134da428ba3 \ gitleaks_sha=e4a487ee7ccd7d3a7f7ec08657610aa3606637dab924210b3aee62570fb4b080 \ depot_sha=042d846f544919e6b5bcb328387b1963af4e298bfa441a41f36bc46663202f2b \ - sccache_sha=2b3284d5da3b46a47dc4229e75bb7b88ac4aa99c8d754fb7d2f84997e5a4354a ;; \ + sccache_sha=2b3284d5da3b46a47dc4229e75bb7b88ac4aa99c8d754fb7d2f84997e5a4354a \ + llvm_cov_sha=bc14a4551e633b12ec89bb15469e6099b4ddc998a5d1bcad0fd95320b148a40f ;; \ *) echo "Unsupported architecture: $TARGETARCH" >&2; exit 1 ;; \ esac \ && curl -fsSL "https://github.com/tee8z/via/releases/download/v0.6.1/via-linux-$via.tar.gz" -o /tmp/via.tar.gz \ @@ -70,7 +82,10 @@ RUN case "$TARGETARCH" in \ && curl -fsSL "https://dl.k8s.io/release/v1.35.8/bin/linux/${TARGETARCH}/kubectl" -o /usr/local/bin/kubectl \ && echo "$kubectl_sha /usr/local/bin/kubectl" | sha256sum -c - \ && chmod 0755 /usr/local/bin/kubectl \ - && rm /tmp/via.tar.gz /tmp/op.zip /tmp/gitleaks.tar.gz /tmp/depot.tar.gz /tmp/sccache.tar.gz + && curl -fsSL "https://github.com/taiki-e/cargo-llvm-cov/releases/download/v0.8.5/cargo-llvm-cov-$llvm_cov-unknown-linux-musl.tar.gz" -o /tmp/cargo-llvm-cov.tar.gz \ + && echo "$llvm_cov_sha /tmp/cargo-llvm-cov.tar.gz" | sha256sum -c - \ + && tar -xzf /tmp/cargo-llvm-cov.tar.gz -C /usr/local/bin cargo-llvm-cov \ + && rm /tmp/via.tar.gz /tmp/op.zip /tmp/gitleaks.tar.gz /tmp/depot.tar.gz /tmp/sccache.tar.gz /tmp/cargo-llvm-cov.tar.gz COPY voltage/images/buzz-agent/checkpoint-gitleaks.toml /opt/agent-tools/checkpoint-gitleaks.toml WORKDIR /opt/buzz-runtimes COPY voltage/images/buzz-agent/package.json voltage/images/buzz-agent/package-lock.json ./ @@ -79,6 +94,7 @@ RUN npm ci --omit=dev --no-audit --no-fund \ && rm -rf node_modules/@anthropic-ai/*-linux-*-musl \ && npm cache clean --force COPY --from=builder /build/target/sprig/sprig /usr/local/bin/sprig +COPY --from=crap-tools /opt/crap-tools/bin/knots /usr/local/bin/knots COPY --chmod=0755 voltage/images/buzz-agent/account.py /usr/local/bin/buzz-agent-account COPY --chmod=0755 voltage/images/buzz-agent/profile.py /usr/local/bin/buzz-agent-profile COPY --chmod=0755 voltage/images/buzz-agent/cache.py /usr/local/bin/buzz-agent-cache diff --git a/voltage/images/buzz-agent/README.md b/voltage/images/buzz-agent/README.md index e6ae73c858c..56abd79c4ff 100644 --- a/voltage/images/buzz-agent/README.md +++ b/voltage/images/buzz-agent/README.md @@ -6,6 +6,7 @@ Staging agent workers are Graviton (`arm64`); the tool downloads in the Dockerfi Each developer supplies their own accounts at runtime. The image contains Codex and Claude ACP adapters, Rust, Node, Go, Python, Git, GitHub CLI, `via`, `kubectl`, and SQL clients. +For the `rust-crap-score` engineering skill, it also has `cargo-llvm-cov` 0.8.5 (checksum-pinned release), `knots` 1.16.0 (built from crates.io with its published lockfile), and the toolchain's `llvm-tools-preview` component. The skill rejects other versions. Buzz selects the runtime, model, persona, and arguments for each session. The image builds the Buzz source of the commit it is built from; npm dependencies use the committed lockfile. diff --git a/voltage/images/buzz-agent/test-image.sh b/voltage/images/buzz-agent/test-image.sh index 595e3cedb4b..22e6d64c31d 100755 --- a/voltage/images/buzz-agent/test-image.sh +++ b/voltage/images/buzz-agent/test-image.sh @@ -51,5 +51,21 @@ docker run --rm --tmpfs /home/agent:uid=10001,gid=10001,mode=0700 \ claude --version >/dev/null command -v codex-acp claude-agent-acp buzz-dev-mcp >/dev/null ' +# rust-crap-score accepts exactly these versions. Collect real coverage and +# complexity for a one-function crate, offline, as the skill does. +docker run --rm --entrypoint /bin/bash "$IMAGE" -ceu ' + test "$(cargo llvm-cov --version)" = "cargo-llvm-cov 0.8.5" + test "$(knots --version)" = "knots 1.16.0" + rustup component list --installed | grep -q "^llvm-tools" + cd "$(mktemp -d)" + cargo new --quiet --vcs none --lib crap-smoke + cd crap-smoke + printf "%s\n" "pub fn magnitude(x: i32) -> i32 { if x > 0 { x } else { -x } }" \ + "#[test] fn negative() { assert_eq!(magnitude(-1), 1); }" > src/lib.rs + cargo llvm-cov --offline --lcov --output-path lcov.info 2>/dev/null + grep -q "^SF:.*src/lib.rs" lcov.info + knots --recursive --language rust --count-anonymous-closures --format json src \ + | python3 -c "import json, sys; json.load(sys.stdin)" +' python3 "$(dirname "$0")/test-review.py" "$IMAGE" printf 'PASS: agent adapter packaging and unauthenticated ACP initialization (%s)\n' "$IMAGE"