Skip to content

Container Images

Images in use

Every reference in .github/workflows/ci.yml, .devcontainer/docker-compose.yml and ci/docker-compose.bdd.yml is pinned by digest — <repo>@sha256:…. The tag below is the readable handle; the digest in the files is what actually resolves. The tag is kept alongside each reference: as a trailing comment on a container: or Compose image: key, and in the comment above the step for a docker run invocation, whose line continuation cannot carry one. Digests are deliberately not repeated here, so there is one authoritative copy per reference and nothing to drift.

Image Tag Used by
ghcr.io/cososo-ltd/cpputest sha-6715942 devcontainer (gcc service), most CI jobs. Now ships include-what-you-use 0.23 (clang_19) matching the cpputest-clang build, so local iwyu runs work in the gcc container
ghcr.io/cososo-ltd/cpputest-clang sha-5905aea clang compose service, build-linux-clang CI job, analyze-iwyu CI job
ghcr.io/cososo-ltd/cpputest-freertos sha-ad10bf2 freertos-host compose service, build-freertos-host-tdd-plustcp CI job — adds FreeRTOS-Kernel / Plus-TCP / Plus-FAT / lwIP / FatFs / Mbed TLS sources for host-TDD of FreeRTOS adapters against fakes; inherits IWYU from the rebased cpputest base, enabling the freertos-aware analyze-iwyu lane
ghcr.io/cososo-ltd/cpputest-freertos-cross sha-ad10bf2 freertos-target compose service, build-freertos-target-plustcp CI job, behave-freertos BDD service, bdd-freertos-qemu-plustcp CI job — adds gcc-arm-none-eabi, libnewlib-arm-none-eabi, gdb-multiarch (aliased as arm-none-eabi-gdb), qemu-system-arm, python3 + behave, FreeRTOS-Kernel / Plus-TCP / Plus-FAT / lwIP / FatFs sources at /opt/freertos-kernel / /opt/freertos-plus-tcp / /opt/freertos/plus-fat / /opt/lwip / /opt/fatfs for cross builds, on-QEMU runs, and BDD scenarios driving a QEMU target
balabit/syslog-ng 4.8.2 syslog-ng-linux and syslog-ng-freertos services — BDD test oracles, one per target pair. Pinned to the 4.8 LTS line; 4.11.0 (latest as of 2026-02-24) regressed by aborting on STATS over the control socket, which crashed the oracle and cascaded to the dev-container network when freertos-target shares the namespace.
ghcr.io/cososo-ltd/behave sha-be8da62 behave-linux service — Debian trixie + Python 3.12 + Behave for Linux BDD scenarios. The FreeRTOS BDD runner uses the cpputest-freertos-cross image instead (which carries QEMU + Behave).
ghcr.io/cososo-ltd/mkdocs-mkdoxy sha-34173c0 docs-build CI job — builds the MkDocs documentation site. Doxygen 1.9.4 + mkdocs 1.6.1 + mkdocs-material 9.7.6 + mkdoxy 1.2.8 + mkdocs-github-admonitions-plugin 0.1.1. mkdoxy renders Core/Interface/*.h as native Material API pages.

Docker Compose setup

The devcontainer uses Docker Compose (.devcontainer/docker-compose.yml). VS Code connects to the gcc service (GCC). The clang service is on-demand only: it starts when you explicitly run a command against it and stops when done.

BDD testing pairs each target with its own syslog-ng oracle so jobs running in parallel (or developers switching containers) never interfere:

Target Behave runner Oracle
Linux behave-linux syslog-ng-linux
FreeRTOS inside freertos-target (image carries both QEMU and Behave) syslog-ng-freertos

The gcc service depends on syslog-ng-linux so it starts automatically with the devcontainer; the freertos-target service depends on syslog-ng-freertos and shares its network namespace via network_mode: service:syslog-ng-freertos, so QEMU's slirp gateway 10.0.2.2 NATs to the pair's loopback where syslog-ng-freertos is listening on 0.0.0.0:5514. Both oracles also alias as the bare hostname syslog-ng on their network so the existing BDD target wiring (Bdd/Targets/Linux/BddTarget*Config.c, the BDD step helpers) keeps resolving without per-target host overrides. The pairs never run together, so the alias collision is academic.

As more cross-compilation targets are added, each gets its own oracle pair in the same shape (syslog-ng-<target> + a runner service or in-container Behave).

FreeRTOS networking backend selection

cpputest-freertos and cpputest-freertos-cross both ship the FreeRTOS-Plus-TCP and lwIP source trees side-by-side, and a default build selects both — you can work on either networking stack, and run both stacks' unit tests, without reconfiguring. The configure says so:

-- SolidSyslog tests: both FreeRTOS networking stacks selected — lwIP and Plus-TCP suites build together.

To work in one stack only, deselect the other with its own switch (-DSOLIDSYSLOG_PLUSTCP=OFF or -DSOLIDSYSLOG_LWIPRAW=OFF), which drops that platform and its tests together. The lwIP lint lanes do exactly this.

Which BDD ELF a cross build produces is separate, and maintainer-only — SOLIDSYSLOG_BDD_FREERTOS_NET=PLUSTCP (default) or LWIP. It selects a test artefact, not a platform — platforms are named in SOLIDSYSLOG_PLATFORMS like everything else.

CI runs both cross targets in isolation, and both are required checks: build-freertos-target-plustcp and build-freertos-target-lwip.

Running the clang build locally

From a host terminal (not inside the devcontainer):

docker compose -f .devcontainer/docker-compose.yml run --rm clang \
    cmake --preset clang-debug

docker compose -f .devcontainer/docker-compose.yml run --rm clang \
    cmake --build --preset clang-debug --target junit

Updating an image

When a new image tag is available:

  1. Build and push the new image in the container image repo
  2. Resolve the new tag to its digest:
docker buildx imagetools inspect ghcr.io/cososo-ltd/<image>:sha-<new> \
  --format '{{.Manifest.Digest}}'

Pin exactly what this command prints — the image index digest for a multi-architecture image, or the single manifest digest for a single-platform one. Do not substitute a per-platform digest dug out of --raw: for an index that would nail the reference to one architecture. Of the images here, only balabit/syslog-ng is genuinely multi-arch (linux/amd64 and linux/arm64); the rest are linux/amd64 only.

  1. Update the digest and the accompanying tag comment in every file that references the image (see table below), plus the tag in docs/containers.md
  2. Rebuild the devcontainer (Ctrl+Shift+P → "Dev Containers: Rebuild Container") and verify locally
  3. Raise a PR: use chore: bump container image to <sha> as the title
Image Files to update
cpputest .devcontainer/docker-compose.yml, .github/workflows/ci.yml, docs/containers.md
cpputest-clang .devcontainer/docker-compose.yml, .github/workflows/ci.yml, docs/containers.md
cpputest-freertos .devcontainer/docker-compose.yml, .github/workflows/ci.yml, docs/containers.md
cpputest-freertos-cross .devcontainer/docker-compose.yml, .github/workflows/ci.yml, ci/docker-compose.bdd.yml, docs/containers.md
behave .devcontainer/docker-compose.yml, ci/docker-compose.bdd.yml, docs/bdd.md, docs/containers.md
mkdocs-mkdoxy .github/workflows/ci.yml, docs/containers.md
syslog-ng .devcontainer/docker-compose.yml, ci/docker-compose.bdd.yml, docs/containers.md

syslog-ng is the one upstream image in that table — it is published by balabit, not by us, so step 1 does not apply and the version is chosen rather than built. Read the 4.8 LTS pinning rationale in the first table before moving it.

The cpputest-freertos and cpputest-freertos-cross images both come from CppUTestFreertosDocker. A single push to that repo's main rebuilds and publishes both images at the same sha-<short> tag; always update both rows together.

The mkdocs-mkdoxy image comes from MkdocsMkdoxyDocker; a push to that repo's main rebuilds and publishes it at a new sha-<short> tag.

mkdocs-mkdoxy is a CI-only image; it is not a devcontainer service, so the generic "rebuild the devcontainer and verify" step above does not exercise it. Verify a tag bump by running the same command the docs-build job runs, from the repo root, before raising the bump PR:

docker run --rm -v "$PWD:/docs" \
  ghcr.io/cososo-ltd/mkdocs-mkdoxy@sha256:<new> mkdocs build --strict

All references to a given image must use the same digest. Never update one without the others. To check that invariant across the tree:

grep -rhno 'ghcr.io/cososo-ltd/[a-z-]*@sha256:[0-9a-f]*\|balabit/syslog-ng@sha256:[0-9a-f]*' \
  .github/workflows/ci.yml .devcontainer/docker-compose.yml ci/docker-compose.bdd.yml \
  | sed 's/^[0-9]*://' | sort -u

One line per image means every reference agrees; two lines for the same image name means a bump was applied unevenly.

Switching to a different container as the devcontainer

The available services and the build preset each one drives:

Service Use case BUILD_PRESET
gcc Primary C/C++ development (default) debug
clang Clang-specific debugging / portability clang-debug
freertos-host TDD of FreeRTOS adapters against host-side fakes debug
freertos-target Cross builds, on-QEMU runs, GDB attach (Cortex-M3, mps2-an385), BDD against the QEMU target freertos-cross
behave-linux Linux BDD scenario development (Python + Behave) (none — cmake skipped)

To switch:

  1. In .devcontainer/devcontainer.json, change "service": "gcc" to the target service name (e.g. "freertos-target").
  2. Ctrl+Shift+P → "Dev Containers: Rebuild Container".
  3. Work normally; Ctrl+Shift+B and all other tasks pick up the right preset via $BUILD_PRESET.

When done, revert "service" back to "gcc" and rebuild again.

The same VS Code keys work across every service:

  • Ctrl+Shift+B runs the build and test task, which adapts to the active BUILD_PRESET. Under freertos-cross it builds the SolidSyslogBddTarget ELF; under debug / clang-debug it builds and runs SolidSyslogTests; with BUILD_PRESET empty (the behave-linux service) it runs behave.
  • F5 debugs:
  • Debug SolidSyslogTests (host): works in gcc, clang, and freertos-host (path resolves via ${env:BUILD_PRESET}). Builds first via the same build and test task and stops at main.
  • Debug FreeRTOS BDD Target (QEMU): works in freertos-target (cortex-debug + arm-none-eabi-gdb + qemu-system-arm). Stops at main via runToEntryPoint.
  • After switching the devcontainer service, pick the matching config from the Run-and-Debug dropdown once. VS Code remembers the last-picked config per workspace (not per container), so the previous choice survives a container rebuild; a stale selection will fail with the wrong debugger type.
  • Ctrl+Shift+P → "Tasks: Run Task" → run on QEMU (FreeRTOS): one-shot QEMU run for sanity-checking the build, output to the integrated terminal. Use only in the freertos-target service.

For the FreeRTOS BDD target, see Bdd/Targets/FreeRtos/README.md for build / run / GDB-attach instructions.