Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ See [toolshed/README.md](toolshed/README.md) for build instructions and

| tag | Python | GCC (native) | GCC (arm-none-eabi) | Clang (native) | Cmake | Host Platforms | Other Utilities |
|----------|--------|--------------|---------------------|----------------|-------|----------------|-----------------|
| [ts26.4.3](https://github.com/OpenCyphal/docker_toolchains/pkgs/container/toolshed) | 3.14 | 15.2.0 | 14.2.rel1 | 22.1.2 | 4.2.3 | <ul><li>linux/amd64</li><li>linux/arm64</li></ul> | <ul><li>Rust 1.93.1</li><li>Go 1.26</li><li>Node.js 22.22.1</li><li>TypeScript 5.2.2</li><li>Emscripten SDK 6.0.2</li><li>LLVM 22.1.2</li><li>MLIR 22.1.2</li><li>JLink V816</li><li>cppcheck</li><li>yakut</li><li>libpcap0.8-dev</li><li>network-tools</li><li>can-utils</li><li>doxygen 1.13.2</li><li>tox</li><li>nox</li><li>gcovr</li><li>lit</li><li>Dafny 4.11.0</li><li>.NET SDK 10.0</li><li>z3 4.13.3</li><li>Bazel 9.2.0 (bazelisk 1.29.0)</li><li>gcc-multilib (amd64 only)</li></ul> |
| [ts26.4.2](https://github.com/OpenCyphal/docker_toolchains/pkgs/container/toolshed) | 3.14 | 15.2.0 | 14.2.rel1 | 22.1.2 | 4.2.3 | <ul><li>linux/amd64</li><li>linux/arm64</li></ul> | <ul><li>Rust 1.93.1</li><li>Go 1.26</li><li>Node.js 22.22.1</li><li>TypeScript 5.2.2</li><li>Emscripten SDK 6.0.2</li><li>LLVM 22.1.2</li><li>MLIR 22.1.2</li><li>JLink V816</li><li>cppcheck</li><li>yakut</li><li>libpcap0.8-dev</li><li>network-tools</li><li>can-utils</li><li>doxygen 1.13.2</li><li>tox</li><li>nox</li><li>gcovr</li><li>lit</li><li>Dafny 4.11.0</li><li>.NET SDK 10.0</li><li>z3 4.13.3</li><li>gcc-multilib (amd64 only)</li></ul> |
| [ts26.4.1](https://github.com/OpenCyphal/docker_toolchains/pkgs/container/toolshed) | 3.14 | 15.2.0 | 14.2.rel1 | 22.1.2 | 4.2.3 | <ul><li>linux/amd64</li><li>linux/arm64</li></ul> | <ul><li>Rust 1.93.1</li><li>Go 1.26</li><li>Node.js 22.22.1</li><li>TypeScript 5.2.2</li><li>Emscripten SDK 6.0.2</li><li>LLVM 22.1.2</li><li>MLIR 22.1.2</li><li>JLink V816</li><li>cppcheck</li><li>yakut</li><li>libpcap0.8-dev</li><li>network-tools</li><li>can-utils</li><li>doxygen 1.13.2</li><li>tox</li><li>nox</li><li>gcovr</li><li>lit</li><li>gcc-multilib (amd64 only)</li></ul> |
| [ts24.4.3](https://github.com/OpenCyphal/docker_toolchains/pkgs/container/toolshed) | <ul><li>3.12</li><li>3.10</li></ul> | <ul><li>13.3.0</li><li>12.3.0</li><li>11.4.0</li><li>10.5.0</li><li>7.5.0</li></ul>| 13.3.1 | <ul><li>19.1.7</li><li>18.1.8</li></ul> | 3.31.5 | <ul><li>linux/amd64</li><li>linux/arm64</li></ul> | <ul><li>JLink V816</li><li>cppcheck-2.13</li><li>yakut 0.13.0</li><li>libpcap0.8-dev</li><li>network-tools</li><li>can-utils</li><li>doxygen 1.13.2</li><li>tox</li><li>nox</li><li>govr</li><li>gcc-multilib (amd64 only)</li></ul> |
Expand All @@ -48,7 +49,7 @@ You can use this in your workflow yaml like this:
jobs:
my-job:
runs-on: ubuntu-latest
container: ghcr.io/opencyphal/toolshed:ts26.4.2
container: ghcr.io/opencyphal/toolshed:ts26.4.3
```


Expand Down
52 changes: 52 additions & 0 deletions toolshed/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,58 @@
Per-release notes for the `ghcr.io/opencyphal/toolshed` image. The summary table of
every published tag lives in the [top-level README](../README.md#opencyphaltoolshedts).

## ts26.4.3

Adds:

- Bazel, via bazelisk 1.29.0, on both `linux/amd64` and `linux/arm64`
- Bazel 9.2.0, unpacked into the image rather than fetched on first use

`bazel` on `PATH` is bazelisk, not a Bazel release binary. Bazel's own apt
repository publishes `amd64` only while this image ships both architectures — the
same constraint that decided how Dafny is installed in ts26.4.2 — and bazelisk
publishes both. Installing the launcher rather than a fixed binary is also what
lets a project pin its own Bazel through `.bazelversion`.

`BAZELISK_HOME` is `/opt/bazelisk`, world-readable, rather than the default under
`$HOME`. The default is invisible to any other user the container runs as, which
CI routinely does; this is the trap `dotnet tool install --tool-path` avoids for
Dafny.

**`USE_BAZEL_VERSION` is deliberately not set.** It takes precedence over a
project's `.bazelversion` — measured, not assumed — so setting it here would
silently build every project with 9.2.0 whatever that project pinned. A project
that wants the pre-warmed toolchain writes `9.2.0` into its own `.bazelversion`,
which is where that decision belongs; a project pinning anything else downloads it
on first use.

### Bazel builds in this image are not offline

Worth stating plainly, because it is the first thing anyone reaching for Bazel
will assume otherwise.

Bazel's hermeticity guarantees cover action *execution* — sandboxed actions,
declared inputs, no leakage from the host. They have never covered the fetch
phase. Under bzlmod that phase is unavoidable: a module declaring **no**
dependencies at all still resolves `bazel_tools`' transitive deps
(`apple_support`, `protobuf`, `rules_java`, `rules_python`, `platforms`,
`rules_cc`, `bazel_skylib`, and more) from `bcr.bazel.build` before analysis
begins. `--noenable_bzlmod` does not escape it on Bazel 9.

None of the obvious mitigations move this, all measured against a cold cache:
a warmed `--repository_cache` holds archives rather than registry metadata; a
committed `MODULE.bazel.lock` records the resolution but still fetches the module
files; and `bazel vendor --vendor_dir` does not cover registry access either. What
does work is a warm per-user `$HOME/.cache/bazel`, which is no help to CI running
as an arbitrary uid.

A project that needs offline or air-gapped builds points Bazel at its own registry
mirror (`--registry=file:///...`) or vendors into its own workspace. Those are
per-project decisions — which modules you need is a function of your dependency
graph — so this image deliberately does not pin `--registry`, ship a partial
mirror that would go stale at every Bazel bump, or otherwise get in the way. It
supplies the toolchain; the dependency policy stays with the project.

## ts26.4.2

Adds:
Expand Down
78 changes: 77 additions & 1 deletion toolshed/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,82 @@ RUN printf 'method Smoke(x: int) requires x > 0 ensures x + 1 > 1 { }\n' > /tmp/
&& dafny verify /tmp/smoke.dfy \
&& rm /tmp/smoke.dfy

# +---------------------------------------------------------------------------+# LEAVE THE WORKDIR AS /repo
# +---------------------------------------------------------------------------+
# | INSTALL BAZEL
# +---------------------------------------------------------------------------+
# bazelisk rather than a Bazel release binary, and from GitHub rather than from
# apt. Bazel's own apt repository publishes amd64 only, and this image ships both
# architectures -- the same constraint that decided Dafny above. bazelisk
# publishes linux/amd64 and linux/arm64, so it is the one route that serves both.
#
# Installing bazelisk as `bazel` is also what lets a project pin its own Bazel:
# bazelisk reads .bazelversion from the workspace root and fetches that version.
FROM dafny AS bazel
WORKDIR /tmp
COPY cached-download.sh .

ARG BAZELISK_VERSION=1.29.0
# The version pre-warmed into the image below. A project pinning this one gets it
# without a download; any other version is fetched on first use.
ARG BAZEL_VERSION=9.2.0

# BAZELISK_HOME defaults to $HOME/.cache/bazelisk, which is invisible to any other
# user the container runs as -- and CI routinely runs as one. A shared path, made
# world-readable below, is what lets all of them use the pre-warmed Bazel. This is
# the same trap `dotnet tool install --tool-path` avoids for Dafny.
ENV BAZELISK_HOME=/opt/bazelisk

ARG BAZELISK_CHECKSUM_FILE=bazelisk-${BAZELISK_VERSION}-linux-${TARGETARCH}.sha256
COPY ${BAZELISK_CHECKSUM_FILE} .
RUN --mount=type=cache,target=/bazelisk-download \
./cached-download.sh \
--cache-target "/bazelisk-download" \
--download-url "https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VERSION}/bazelisk-linux-${TARGETARCH}" \
--download-to-file "/bazelisk-download/bazelisk-linux-${TARGETARCH}" \
--checksums "/tmp/${BAZELISK_CHECKSUM_FILE}" \
--algorithm 256 \
&& install -m 0755 "/bazelisk-download/bazelisk-linux-${TARGETARCH}" /usr/local/bin/bazel

# Bazel itself is unpacked into BAZELISK_HOME here rather than on first use. The
# throwaway workspace is what makes that happen: bazelisk honours .bazelversion
# only at a workspace root, and with no workspace it resolves "latest" over the
# network instead.
#
# Deliberately NOT setting USE_BAZEL_VERSION. That variable takes precedence over
# a project's .bazelversion -- measured, not assumed -- so an image setting it
# would silently build every project with this version whatever the project
# pinned. A project that wants the pre-warmed Bazel commits `9.2.0` to its own
# .bazelversion, which is where that decision belongs.
RUN mkdir -p /tmp/bazel-warm \
&& cd /tmp/bazel-warm \
&& printf 'module(name = "warm", version = "0.0.1")\n' > MODULE.bazel \
&& touch BUILD.bazel \
&& echo "${BAZEL_VERSION}" > .bazelversion \
&& bazel --version \
&& bazel shutdown \
&& cd /tmp \
&& rm -rf /tmp/bazel-warm \
&& chmod -R a+rX "${BAZELISK_HOME}"
Comment thread
Copilot marked this conversation as resolved.
Outdated

# Build something rather than just running --version. Launching proves bazelisk
# resolved a binary; building additionally proves that binary can execute an
# action and write an output, which is the part that silently goes missing.
#
# This step needs network, and so will any real Bazel build: Bazel resolves even
# its built-in module dependencies through the Bazel Central Registry, exactly as
# npm, cargo, and pip in this image fetch theirs. The image supplies the
# toolchain, not a hermetic dependency cache.
RUN mkdir -p /tmp/bazel-smoke \
&& cd /tmp/bazel-smoke \
&& printf 'module(name = "smoke", version = "0.0.1")\n' > MODULE.bazel \
&& printf 'genrule(name = "g", outs = ["o.txt"], cmd = "echo built > $@")\n' > BUILD.bazel \
&& echo "${BAZEL_VERSION}" > .bazelversion \
&& bazel build //:g \
&& grep -q built bazel-bin/o.txt \
&& bazel shutdown \
&& cd /tmp \
&& rm -rf /tmp/bazel-smoke

# +---------------------------------------------------------------------------+
# LEAVE THE WORKDIR AS /repo
WORKDIR /repo
1 change: 1 addition & 0 deletions toolshed/bazelisk-1.29.0-linux-amd64.sha256
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5a408715e932c0250d28bd84555f12edbf70117de42f9181691c736eacc4a992 bazelisk-linux-amd64
1 change: 1 addition & 0 deletions toolshed/bazelisk-1.29.0-linux-arm64.sha256
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
e20e8b0f4f240091b7a55bf17b9398bd4f40ee70ae0208dff95dd4c445fb4010 bazelisk-linux-arm64