Toolchain¶
Every tool of the gates with version, purpose, place of running, license and reason. A test keeps
the versions on this page equal to the pins (tools/docs/tests/test_toolchain_doc.py):
tools/uv.lock, tools/node/package-lock.json, tools/bin/tools.lock.json, Makefile,
tools/sonarqube/compose.yaml, .pre-commit-config.yaml, the workflows, the
tool directives of the Go modules under services/ and (code generators of the SDKs)
sdk/python/uv.lock and sdk/typescript/package-lock.json.
Place of running: "local" means via make on the developer's host, "CI" means in the
same make target in GitHub Actions. All gate tools run in both places.
Gate tools¶
| Tool | Version | Purpose | License | Why this one |
|---|---|---|---|---|
uv |
system tool | Python environment and lock for all Python tools | MIT OR Apache-2.0 | one lock with hashes for all Python tools; downloads the Python version itself |
pyyaml |
6.0.3 |
reading YAML in the check scripts | MIT | standard for YAML in Python; on: is deliberately not read as a boolean |
ruff |
0.17.0 |
format and lint for Python | MIT | replaces several linters, fast |
mypy |
2.4.0 |
type checking (strict) | MIT | reference type checker for Python |
playwright |
1.64.0 |
headless browsers of make console-e2e (SEC-T05, M6-03); the browsers come from the Playwright image of the same version, pinned by digest in infra/compose/test/compose.console-e2e.yaml |
Apache-2.0 | the browser automation with Chromium, Firefox and WebKit, CDP access for the virtual WebAuthn authenticator |
bandit |
1.9.4 |
security patterns in Python | Apache-2.0 | required by the requirement; adds security rules to ruff |
pytest |
9.1.1 |
tests of the tools | MIT | standard |
pytest-cov |
7.1.0 |
coverage in pytest | MIT | standard |
coverage |
7.16.2 |
coverage threshold | Apache-2.0 | basis of pytest-cov |
schemathesis |
4.30.1 |
property-based contract tests G7 against the server of the working tree (make contract-test, tools/contract/) |
MIT | 06 "Contract tests and gate": the version probed there; derives cases and stateful sequences from openapi.yaml and takes a custom auth for the DPoP proofs |
cryptography |
50.0.2 |
ES256 signatures of the DPoP proofs of G7 (tools/contract/dpop.py) |
Apache-2.0 OR BSD-3-Clause | the maintained OpenSSL binding of Python; the standard library has no ECDSA |
markdown-it-py |
4.2.0 |
CommonMark parser as the oracle in the tests of tools/configdoc (code spans and code blocks for rule D7) |
MIT | CommonMark-compliant parser with GFM tables (markdown-it-py, retrieved 2026-10-12); only in tests, the tool itself stays with the standard library and PyYAML |
pre-commit |
4.6.2 |
hooks for commit, commit-msg, pre-push | MIT | widespread, hooks as a file in the repository |
pre-commit-hooks |
v6.0.0 |
file hygiene hooks | MIT | maintained standard hooks, pinned by commit SHA |
check-jsonschema |
0.38.2 |
schema check of issue forms, Renovate and CodeRabbit configuration | Apache-2.0 | ships the schemas of the formats |
zizmor |
1.30.1 |
security analysis of the workflows | MIT | required by the planning basis; checks injection, permissions, pinning |
mkdocs |
1.6.1 |
docs site | BSD | ADR 0045 |
mkdocs-material |
9.7.7 |
theme of the docs site | MIT | ADR 0045 |
mkdocstrings |
1.0.8 |
API reference of the Python SDK from its docstrings (docs/sdk/python.md) |
ISC | the MkDocs plugin for references from source code (23 "Documentation in code", M2-29) |
mkdocstrings-python |
2.0.10 |
Python handler of mkdocstrings: reads the SDK with griffe without importing it, google docstrings | ISC | the official Python handler of mkdocstrings |
semgrep |
1.180.0 |
project rules (.semgrep/) |
LGPL-2.1 | pattern rules for project invariants without an own parser (R-QA-05) |
@mermaid-js/mermaid-cli |
11.17.0 |
rendering diagrams | MIT | reference renderer of Mermaid; major 11 as at planning time |
puppeteer |
25.13.0 |
browser control for mermaid-cli | Apache-2.0 | dependency of mermaid-cli; determines the browser version |
katex |
0.18.10 |
math typesetting inside Mermaid diagrams | MIT | dependency of mermaid-cli and mermaid, which still ask for 0.16; pinned through overrides in tools/node/package.json to a release with the fix for GHSA-238p-pmpm-9mq7 (https://github.com/advisories/GHSA-238p-pmpm-9mq7, ranges in https://registry.npmjs.org/@mermaid-js/mermaid-cli/11.17.0 and https://registry.npmjs.org/mermaid/11.17.2, retrieved 2026-10-11; D-DEPS-1) |
@redocly/cli |
2.62.1 |
lint of OpenAPI and AsyncAPI | MIT | lints both formats with its own rules |
@sonar/scan |
5.0.1 |
SonarScanner without a local Java installation | LGPL-3.0 | same scanner locally and in CI, no Docker for the scan |
actionlint |
1.7.12 |
syntax and expressions of the workflows | MIT | required by the planning basis |
gitleaks |
8.30.1 |
secrets in all commits | MIT | as a CLI, not as an action (license obligation of the action in organizations) |
golangci-lint |
2.14.0 |
Go linter bundle including gosec and depguard | GPL-3.0 | standard for Go; dependency rules of the modules (chapter 02) |
oapi-codegen |
v2.8.0 |
Go server interface and models from docs/api/openapi.yaml (tool in services/server/go.mod, runs in make codegen-check) |
Apache-2.0 (LICENSE, retrieved 2026-10-12) | ADR 0013; 06 "Code generation" |
openapi-python-client |
0.29.1 |
core of the Python SDK from docs/api/openapi.yaml (dev group of sdk/python/pyproject.toml, runs in make api-clients) |
MIT | 06 "Code generation", ADR 0026 |
openapi-typescript |
7.13.0 |
types of the TypeScript SDK from docs/api/openapi.yaml (devDependencies of sdk/typescript/package.json, runs in make api-clients) |
MIT | 06 "Code generation", ADR 0026 |
typedoc |
0.28.17 |
API reference of the TypeScript SDK from its TSDoc comments (devDependencies of sdk/typescript/package.json): npm run docs builds it in make docs, npm run docs:check fails the script lint on an undocumented export (validation.notDocumented) |
Apache-2.0 | 23 "Documentation in code" (TypeScript row), docs/decisions.d/M2-30.md D-M2-30-12 |
openapitools/openapi-generator-cli |
v7.26.0@sha256:a304ddf1e2e5f24f68fa3153568d6174cea4959d09aa8e3db6d526fd0782326d (digest of the multi-architecture index) |
generator dart-dio for packages/api_client from docs/api/openapi.yaml (GENERATOR_IMAGE in packages/api_client/Makefile, runs with docker run --network none in make api-clients) |
Apache-2.0 | 06 "Code generation", ADR 0026; the image brings the Java runtime the repository does not pin otherwise (docs/DECISIONS.md D-M4-02-1) |
gotestsum |
1.13.0 |
runs the Go tests in CI with reruns of failed tests and the flake report (tools/ci/flakes.py; gates.md, section "Flakes") |
Apache-2.0 | only reruns the failed tests and keeps a test that fails in every attempt failing |
go-arch-lint |
1.19.0 |
module boundaries of the Go modules from the module register | MIT | checked in 02 "go-arch-lint" on a skeleton of all modules; checks packages and third-party libraries |
sqlc |
1.31.1 |
typed Go code from SQL, drift check | MIT | ADR 0007 |
govulncheck |
v1.8.0 |
reachable Go vulnerabilities | BSD-3-Clause | checks call graphs instead of only versions |
go-licenses |
v2.0.1 |
licenses of linked Go packages | Apache-2.0 | required by the research ruling |
lychee |
0.24.2 |
links and anchors in Markdown | Apache-2.0 OR MIT | checks anchors in Markdown files offline |
osv-scanner |
2.6.0 |
vulnerabilities and licenses of all lock files | Apache-2.0 | one tool for Go, Dart, Python and npm |
trivy |
0.69.3 |
misconfiguration and image vulnerabilities | Apache-2.0 | image scan at release; version see below |
shellcheck |
0.11.0 |
static analysis of the shell scripts of the Compose installation (make lint; install.sh as POSIX sh) |
GPL-3.0-only | the standard shell linter the brief M7-29 names; a build tool only, nothing of it is shipped (like golangci-lint) |
debian (container image) |
trixie-slim@sha256:a29215f6a35e51e22adffa17f89e9d2ef06214e64a2bad10d765c46aea49f11f (digest of the multi-architecture index) |
runs the tests of install.sh with dash and util-linux script (INSTALL_TEST_IMAGE in the Makefile, make install-test); base of the host image of the terminal conformance suite (infra/compose/test/host/Dockerfile, M2-48), whose APT sources point at the timestamp 20261015T000000Z of snapshot.debian.org (ARG SNAPSHOT, with Acquire::Check-Valid-Until off because the Release files of a snapshot expire), so its package set is reproducible |
DFSG (Debian) | the shell most Linux hosts run as /bin/sh; no second shell is installed on the build host |
nginxinc/nginx-unprivileged (container image) |
the tag BOTHY_NGINX_VERSION of the example edge of M2-47 (infra/compose/.env.example, configuration.md 9) |
the test-only TLS front tls-front of the terminal conformance suite for the instance origin (infra/compose/test/compose.terminal.yaml, M2-48) |
BSD-2-Clause (nginx) | the same image and version as the example edge, so the suite adds no image of its own; it runs unprivileged and read-only |
cosign |
3.1.3 |
signs and verifies the release images, binaries and SHA256SUMS (release.yml, make release-trial) |
Apache-2.0 | the Sigstore signing tool of ADR 0036; with a key pair and a signing configuration without Rekor, Fulcio and timestamp service in the private phase (ADR 0062) |
syft |
1.54.1 |
SPDX and CycloneDX SBOMs of every release image per platform and every binary | Apache-2.0 | the SBOM generator behind anchore/sbom-action, as a binary so that the trial release and release.yml run the same version (18, section 6) |
git-cliff |
2.14.2 |
selects and parses the commits of one component for make release-prep |
MIT OR Apache-2.0 | ADR 0060: path filter and tag pattern per component, offline |
registry |
3.1.2 |
local registry of make release-trial on 127.0.0.1 (image pinned by digest in tools/ci/release_trial.py) |
Apache-2.0 | the reference implementation of the OCI distribution API (CNCF Distribution); no account, removed after the run |
scancode-toolkit |
32.5.0 |
license and copyright scan of the tracked tree before a release (make scancode, image from tools/scancode/Dockerfile) |
Apache-2.0 | named by licenses.md section 4; text-level detection that the lock-file license checks lack |
otelcol-contrib |
0.162.0 |
otelcol-contrib validate for the collector base, every overlay and pairs of two overlays (ops-check) |
Apache-2.0 | the same distribution and version as the collector image (BOTHY_OTELCOL_VERSION); only it knows the contrib components of the overlays |
promtool |
3.15.0 |
promtool check config, check rules and test rules (ops-check); check rules on the dashboard queries (signal-check, M1-68) |
Apache-2.0 | check tool from the Prometheus release of the image version (BOTHY_PROMETHEUS_VERSION) |
amtool |
0.34.1 |
amtool check-config and routing tests (ops-check) |
Apache-2.0 | check tool from the Alertmanager release of the image version (BOTHY_ALERTMANAGER_VERSION) |
loki |
3.7.8 |
loki -verify-config (ops-check) |
AGPL-3.0-only | only Loki itself knows its configuration keys; version of the image (BOTHY_LOKI_VERSION). It is only run for the check and not distributed; AGPL-3.0 applies to distribution and to network use of modified versions (AGPL-3.0, sections 0 "convey" and 13, retrieved 2026-10-12), and neither happens here |
tempo |
3.1.0 |
tempo -config.verify=true (ops-check) |
AGPL-3.0-only | only Tempo itself knows its configuration keys; version of the image (BOTHY_TEMPO_VERSION). It is only run for the check and not distributed; AGPL-3.0 applies to distribution and to network use of modified versions (AGPL-3.0, sections 0 "convey" and 13, retrieved 2026-10-12), and neither happens here |
sloth |
0.16.0 |
regenerate the SLO rules and compare them with the checked-in ones (ops-check) |
Apache-2.0 | generator of the burn-rate rules (ADR 0035); the same version stands in the header of the generated files |
tofu |
1.13.1 |
tofu init and tofu validate per module under infra/tofu/modules/ (ops-check); make tofu-check (fmt, offline init and validate of the roots under infra/tofu/test/, tofu test of the cloud modules with mocked providers, brief M7-16), the plan of the generic-vm test and make tofu-vm-test (brief M7-15) |
MPL-2.0 | tool of the modules (ADR 0012); checks HCL, types and validations without access to a provider |
sonarqube |
26.9.0.129388-community |
local SonarQube Community Build | LGPL-3.0 | ADR 0040 |
postgres |
18.6-trixie |
database of the local SonarQube | PostgreSQL | required by the Community Build for continuous operation (H2 only for tests) |
The API reference pages of the site (M7-19) need no tool of their own: the MkDocs hook
tools/docs/mkdocs_api_reference.py renders them with pyyaml and mkdocs from the table
above, and tools/docs/external_assets_check.py uses only the standard library. Redocly's
build-docs was compared and not taken (docs/DECISIONS.md, M7-19/1).
The terminal conformance suite (M2-48, services/server/test/terminal) pulls no server image: each
end-to-end test package builds services/server/Dockerfile from the worktree with
docker buildx build --load for the platform of the Docker host, with the pinned stages of that
Dockerfile, and tags the result termsuite-server:<first 12 hex of the image ID>. The host image
termsuite-host:<first 12 hex of the SHA-256 of infra/compose/test/host/Dockerfile> is built from
the debian image above when the tag is missing. Both tags stay as local build cache;
infra/compose/test/README.md says how to remove them. The
other images of the stack are those of the installation and of the smoke overlay of M1-73.
Licenses: PyPI, npm and the LICENSE files of the projects, retrieved 2026-10-10 [verified]. Development tools are not shipped; the license rules for shipped dependencies are in licenses.md.
Language toolchains¶
Go and Flutter are not pinned gate tools; they come from the components themselves:
- Go from the
goandtoolchainlines of the modules underservices/. All modules carry the same lines, because CI installs one Go (ADR 0005);tools/ci/tests/test_ci_toolchains.py(test_go_directives_agree) holds that. - Flutter from
environment.flutterof the rootpubspec.yamlof the Dart workspace, one exact version that the root and every member repeat (test_flutter_pins_agree, docs/DECISIONS.md D-M4-01-1); CI reads it withflutter-version-file: pubspec.yaml. The pure Dart packages useflutter testonly as their test runner.
GitHub Actions¶
All pinned by full commit SHA; the comment names the release tag. The SHAs were
looked up on 2026-10-10 with git ls-remote in the original repository (for annotated
tags, the commit SHA behind the tag).
| Action | Version | For what |
|---|---|---|
actions/checkout |
v7.0.1 |
checkout without stored credentials |
actions/setup-node |
v7.1.0 |
Node for the Node tools, with npm cache |
actions/setup-go |
v7.0.0 |
one Go for all modules under services/, from the go.mod of the server (otherwise of the host service) |
astral-sh/setup-uv |
v10.3.0 |
uv, with cache over tools/uv.lock |
actions/cache |
v6.1.0 |
binary cache and pre-commit environments |
actions/upload-artifact |
v7.0.2 |
release artifacts, Scorecard result |
actions/download-artifact |
v8.0.2 |
collecting release artifacts |
actions/attest |
v4.2.2 |
build provenance and SBOM attestation (public) |
anchore/sbom-action |
v0.24.3 |
SBOM (SPDX) of the release artifacts |
docker/setup-buildx-action |
v4.4.1 |
Buildx with provenance and SBOM; tag only after the scan (imagetools create) |
docker/login-action |
v4.6.0 |
login to ghcr.io |
docker/build-push-action |
v7.4.0 |
build and push the server image (multi-arch by cross compilation in the Dockerfile, without QEMU) |
subosito/flutter-action |
v2.23.0 |
Flutter for every Dart package (jobs gates, sonar, apps (macOS), apps (iOS), apps (Windows) and the Pages build), from environment.flutter of the root pubspec.yaml |
actions/setup-java |
v6.1.0 |
Temurin 17 for the Gradle builds of the Android code (jobs gates, sonar, apps (Android API 26), apps (Android API 36), brief M5-01) |
android-actions/setup-android |
v4.0.4 |
Android SDK for the JVM tests of the Android core in make test (jobs gates, sonar) |
reactivecircus/android-emulator-runner |
v2.38.0 |
Android emulators with API 26 and 36 for the instrumented tests (jobs apps (Android API 26) and apps (Android API 36)) |
github/codeql-action |
v4.38.3 |
CodeQL and SARIF upload (public) |
ossf/scorecard-action |
v2.4.4 |
OpenSSF Scorecard (public) |
actions/upload-pages-artifact |
v5.0.0 |
upload the docs site (public) |
actions/deploy-pages |
v5.0.1 |
publish the docs site (public) |
Updates¶
- Renovate proposes updates grouped and with a waiting period (ADR 0041). An update is only done when this page names the new version; the test enforces this.
- Release binaries: after the Renovate proposal,
make tools-lock TOOL=<name> VERSION=<version>; the command takes over the sha256 values that GitHub reports for the release files. Check the diff, thenmake bootstrapandmake check. - The validators of the helper services (
otelcol-contrib,promtool,amtool,loki,tempo) follow the image versions ininfra/compose/: Renovate raises the images (group "Compose-Images", ADR 0041) and is switched off for these five pins. In the pull request of the image update the maintainer refreshes them withmake tools-lock; until then the checktool-versionsofmake ops-checkfails, because a validator of another version accepts or rejects other keys than the running component. - New tools come with a row on this page, a pin, a license check and a reason.
- A transitive Node package pinned through
overridesintools/node/package.json(for a security fix that the tool releases do not take yet) also gets a row here; the test enforces this. Remove the override once the tool asks for a fixed version itself.
Trivy: keep the version¶
Trivy stays on 0.69.3. Background: on 2026-03-19, a malicious Trivy version 0.69.4 was
published with stolen credentials, and tags of trivy-action and
setup-trivy were redirected; the advisory names 0.69.3 as not affected, protected
by immutable releases
(https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23,
retrieved 2026-10-10) [verified]. Renovate is switched off for Trivy. A move to a
newer version needs:
- The release is marked as immutable (GitHub release API, field
immutable). - The signature of the checksum file is verified with cosign against the workflow identity of the Trivy repository.
- The advisory or a later one names no incident for this version.
- A pull request with
make tools-lock TOOL=trivy VERSION=<new>and the check record in the description.
Trivy is never included via trivy-action or setup-trivy, but as a pinned
binary via tools/bin/fetch_tools.py.
Known limitations¶
- actionlint 1.7.12 does not yet know the new notation
uses: $/...for workflows in the same repository; zizmor recommends it (auditself-repository). Until actionlint understands it,./stays, with a justified zizmor exception inrelease.yml. - Without
GH_TOKEN, zizmor checks only offline; online audits (for example fake commits behind a SHA) run in CI with the workflow token. - There are no binary pins for Windows hosts; contributors use WSL.
- oasdiff is not a gate tool. The breaking change check G6 (
make api-breaking) is the own comparisontools/api-checks/breaking.pyover PyYAML, because oasdiff 1.33.0 missed rows of the 06 13 table ondocs/api/openapi.yaml(docs/DECISIONS.md D-M7-11-1); nothing new is pinned.