Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
175 changes: 175 additions & 0 deletions .github/workflows/build-containers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# Build + publish the wro.cpp toolset containers to ghcr.io/wrocpp/cpp-*.
# Matrix build; cluster images depend on cpp-base, so cpp-base goes
# first and the rest run after it succeeds.
#
# Triggers:
# * push to any branch touching containers/** -> build all + tag the branch
# * push to main touching containers/** -> tag rolling 2026-05
# * workflow_dispatch -> build everything ad-hoc
#
# Tag scheme:
# * 2026-05 : rolling release, what /toolset/ pages link to
# * sha-<short> : per-build snapshot, useful for debugging
# * branch-<name> : per-feature-branch builds for PR review
#
# SECURITY: every value used in run: blocks comes from controlled
# system context (github.ref_name, github.sha, github.actor, secrets).
# No user-controlled input (issue body, PR title, commit message body)
# flows into shell. See
# https://github.blog/security/vulnerability-research/how-to-catch-github-actions-workflow-injections-before-attackers-do/

name: build-containers

on:
push:
branches: ["**"]
paths:
- "containers/**"
- ".github/workflows/build-containers.yml"
workflow_dispatch:

env:
REGISTRY: ghcr.io
ORG: wrocpp

jobs:
base:
name: build cpp-base
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
tag: ${{ steps.meta.outputs.tag }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Resolve tag
id: meta
env:
REF_NAME: ${{ github.ref_name }}
run: |
if [ "$REF_NAME" = "main" ]; then
echo "tag=2026-05" >> "$GITHUB_OUTPUT"
else
sanitized=$(echo "$REF_NAME" | tr '/' '-')
echo "tag=branch-${sanitized}" >> "$GITHUB_OUTPUT"
fi

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build + push cpp-base (multi-arch)
uses: docker/build-push-action@v5
with:
context: containers/base
push: true
platforms: linux/amd64,linux/arm64
tags: |
${{ env.REGISTRY }}/${{ env.ORG }}/cpp-base:${{ steps.meta.outputs.tag }}
${{ env.REGISTRY }}/${{ env.ORG }}/cpp-base:sha-${{ github.sha }}
cache-from: type=gha,scope=cpp-base
cache-to: type=gha,mode=max,scope=cpp-base

cluster:
name: build cpp-${{ matrix.image }}
needs: base
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
image: [safety, performance, security, compliance]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build + push cpp-${{ matrix.image }}
uses: docker/build-push-action@v5
with:
context: containers/${{ matrix.image }}
push: true
platforms: linux/amd64,linux/arm64
build-args: |
BASE_TAG=${{ needs.base.outputs.tag }}
tags: |
${{ env.REGISTRY }}/${{ env.ORG }}/cpp-${{ matrix.image }}:${{ needs.base.outputs.tag }}
${{ env.REGISTRY }}/${{ env.ORG }}/cpp-${{ matrix.image }}:sha-${{ github.sha }}
cache-from: type=gha,scope=cpp-${{ matrix.image }}
cache-to: type=gha,mode=max,scope=cpp-${{ matrix.image }}

reflection:
name: build cpp-reflection
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Resolve tag
id: meta
env:
REF_NAME: ${{ github.ref_name }}
run: |
if [ "$REF_NAME" = "main" ]; then
echo "tag=2026-05" >> "$GITHUB_OUTPUT"
else
sanitized=$(echo "$REF_NAME" | tr '/' '-')
echo "tag=branch-${sanitized}" >> "$GITHUB_OUTPUT"
fi

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build + push cpp-reflection (FROM vsavkov/clang-p2996)
uses: docker/build-push-action@v5
with:
context: containers/reflection
push: true
# vsavkov/clang-p2996 ships per-arch tags (amd64, arm64);
# the Dockerfile uses TARGETARCH (auto-set by buildx) to
# pick the right one per platform. Multi-arch manifest emerges.
platforms: linux/amd64,linux/arm64
tags: |
${{ env.REGISTRY }}/${{ env.ORG }}/cpp-reflection:${{ steps.meta.outputs.tag }}
${{ env.REGISTRY }}/${{ env.ORG }}/cpp-reflection:sha-${{ github.sha }}
cache-from: type=gha,scope=cpp-reflection
cache-to: type=gha,mode=max,scope=cpp-reflection
86 changes: 86 additions & 0 deletions containers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# wro.cpp toolset containers

Pre-built Docker images that back the "Reproduce locally" affordances
on every wro.cpp toolset page (https://wrocpp.github.io/toolset/).

## Image map

| Image | Purpose | Base |
|---|---|---|
| `ghcr.io/wrocpp/cpp-base` | Shared substrate. Ubuntu 24.04 + clang-19 + GCC 14 + CMake + Ninja + Python3. | `ubuntu:24.04` |
| `ghcr.io/wrocpp/cpp-safety` | Safety-cluster `Today` demos: sanitizers (ASan/UBSan/TSan/MSan/HWASan), AFL++, libFuzzer, clang-tidy. | `cpp-base` |
| `ghcr.io/wrocpp/cpp-performance` | Performance-cluster `Today` demos: perf, Tracy server + capture, Perfetto SDK, google-benchmark. | `cpp-base` |
| `ghcr.io/wrocpp/cpp-security` | Security-cluster `Today` demos: vcpkg, Conan, syft (SBOM), grype (CVE scan), libsodium-dev, OpenSSL dev headers. | `cpp-base` |
| `ghcr.io/wrocpp/cpp-compliance` | Compliance-cluster `Today` demos: cppcheck-MISRA, clang-tidy MISRA / AUTOSAR / CERT-C++ check sets. | `cpp-base` |
| `ghcr.io/wrocpp/cpp-reflection` | Powers every `Reflection today` triptych sub-section across all clusters. clang-p2996 fork ready to use. | `vsavkov/clang-p2996` (community-maintained) |

## Tag scheme

- `2026-05` -- rolling release. What the toolset pages link to.
- `2026-05-DD` -- quarterly immutable snapshot. Pinned in
`containers/scripts/*.sh` for reproducibility.
- `sha-<git-sha>` -- per-build snapshot. Debugging only.
- `branch-<name>` -- per-feature-branch builds for PR review.

## Pull

```bash
docker pull ghcr.io/wrocpp/cpp-base:2026-05
docker pull ghcr.io/wrocpp/cpp-safety:2026-05
docker pull ghcr.io/wrocpp/cpp-performance:2026-05
docker pull ghcr.io/wrocpp/cpp-security:2026-05
docker pull ghcr.io/wrocpp/cpp-compliance:2026-05
docker pull ghcr.io/wrocpp/cpp-reflection:2026-05
```

All images are public; no `docker login` required.

## Run

The standard pattern is to mount the current directory and pick the
right image for the task:

```bash
docker run --rm -it \
-v "$PWD":/work -w /work \
ghcr.io/wrocpp/cpp-safety:2026-05 \
containers/scripts/run-asan.sh examples/use-after-free.cpp
```

Each toolset page (https://wrocpp.github.io/toolset/) carries an
embedded `docker run` block under "Reproduce locally". Copy + paste.

## Build local (for container development)

GitHub Actions builds + pushes to GHCR on every push to `main` (and
on any push touching `containers/`). To iterate locally:

```bash
docker buildx build --load -t cpp-base:local containers/base
docker buildx build --load -t cpp-safety:local --build-arg BASE=cpp-base:local containers/safety
# ... etc
```

See `.github/workflows/build-containers.yml` for the canonical build
recipe.

## Why two compiler families?

- **clang-19 + GCC 14 in cpp-base** -- the cluster containers (safety,
performance, security, compliance) deal with sanitizers, profilers,
supply chain, MISRA checkers. None of these need C++26 reflection.
Apt-installable compilers keep the build fast.
- **clang-p2996 in cpp-reflection** -- every triptych sub-section's
`Reflection today` demo uses the Bloomberg fork. We pull it as a
community-maintained pre-built (`vsavkov/clang-p2996`) instead of
building it ourselves; building from source takes 45-90 minutes per
CI run.

If you need GCC 16.1 (released April 2026, ships C++26 reflection),
godbolt's `g161` toolchain has it. We do not bake it into a container
yet; once it lands in `apt` for Ubuntu LTS, we'll add it to cpp-base.

## Scripts

`containers/scripts/run-*.sh` are tiny wrappers that the toolset
DockerRun blocks invoke. They keep the per-page command short.
52 changes: 52 additions & 0 deletions containers/base/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# cpp-base: shared substrate for the wro.cpp toolset cluster containers.
#
# What's in here: Ubuntu 24.04 + apt clang-19 + apt GCC 14 (current LTS
# default) + CMake + Ninja + Python3. Designed to be small and fast to
# build (<5 min on GH Actions) so cluster images that FROM cpp-base
# stay equally cheap.
#
# What's NOT in here: clang-p2996 (reflection -- that lives in
# cpp-reflection, FROM vsavkov/clang-p2996). The toolset cluster pages
# (safety, performance, security, compliance) do not need P2996 for
# their "Today" demos; reflection-augmented examples use cpp-reflection
# instead.
#
# See containers/README.md for the full image map.

FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
clang-19 \
clang-tools-19 \
clang-tidy-19 \
clang-format-19 \
lld-19 \
libc++-19-dev \
libc++abi-19-dev \
gcc \
g++ \
cmake \
ninja-build \
make \
git \
python3 \
python3-pip \
curl \
&& rm -rf /var/lib/apt/lists/*

# Symlink versioned clang to bare names so user examples just work.
RUN ln -sf /usr/bin/clang-19 /usr/local/bin/clang \
&& ln -sf /usr/bin/clang++-19 /usr/local/bin/clang++ \
&& ln -sf /usr/bin/clang-tidy-19 /usr/local/bin/clang-tidy \
&& ln -sf /usr/bin/clang-format-19 /usr/local/bin/clang-format \
&& ln -sf /usr/bin/lld-19 /usr/local/bin/lld

LABEL org.opencontainers.image.source="https://github.com/wrocpp/cpp26-reflection-examples"
LABEL org.opencontainers.image.description="wro.cpp shared substrate: Ubuntu 24.04 + clang-19 + GCC 14 + CMake + Ninja"
LABEL org.opencontainers.image.licenses="MIT"

WORKDIR /work
CMD ["/bin/bash"]
29 changes: 29 additions & 0 deletions containers/compliance/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# cpp-compliance: compliance-cluster `Today` demos.
# What's added on top of cpp-base: cppcheck (with bundled MISRA addon),
# clang-tidy MISRA / AUTOSAR / CERT-C++ checksets (clang-19 already
# carries the engine; the checksets are configured here). No qualified
# vendor compilers (GHS, IAR) -- those are proprietary; the toolset
# page documents how to point your CI at them.

ARG BASE_TAG=2026-05
FROM ghcr.io/wrocpp/cpp-base:${BASE_TAG}

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y --no-install-recommends \
cppcheck \
&& rm -rf /var/lib/apt/lists/*

# Ship a default .clang-tidy preset that turns on the MISRA / AUTOSAR /
# CERT-C++ checksets. Containers/scripts/run-misra.sh + run-cert.sh
# point at this file by default.
COPY clang-tidy-misra.yml /opt/wrocpp/clang-tidy-misra.yml
COPY clang-tidy-cert.yml /opt/wrocpp/clang-tidy-cert.yml
COPY cppcheck-misra.cfg /opt/wrocpp/cppcheck-misra.cfg

LABEL org.opencontainers.image.source="https://github.com/wrocpp/cpp26-reflection-examples"
LABEL org.opencontainers.image.description="wro.cpp compliance cluster: cppcheck-MISRA, clang-tidy MISRA / AUTOSAR / CERT-C++ presets on cpp-base."
LABEL org.opencontainers.image.licenses="MIT"

WORKDIR /work
CMD ["/bin/bash"]
14 changes: 14 additions & 0 deletions containers/compliance/clang-tidy-cert.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# clang-tidy preset for the wro.cpp compliance cluster's
# SEI CERT C++ demos. The cert-* checks are clang-tidy's first-party
# implementation of CERT C / C++ secure coding rules.
Checks: >
-*,
cert-*,
bugprone-undefined-memory-manipulation,
bugprone-use-after-move,
cppcoreguidelines-no-malloc,
cppcoreguidelines-owning-memory

WarningsAsErrors: 'cert-*'
HeaderFilterRegex: '.*'
FormatStyle: file
20 changes: 20 additions & 0 deletions containers/compliance/clang-tidy-misra.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# clang-tidy preset for the wro.cpp compliance cluster's MISRA C++ demos.
# Enables the closest open-source clang-tidy checks that map onto
# MISRA C++ rules. Not a substitute for a qualified MISRA tool;
# documents intent + provides reproducible CI starter.
Checks: >
-*,
bugprone-*,
cert-*,
cppcoreguidelines-*,
hicpp-*,
misc-*,
modernize-avoid-c-arrays,
modernize-avoid-bind,
modernize-deprecated-headers,
performance-*,
readability-*

WarningsAsErrors: ''
HeaderFilterRegex: '.*'
FormatStyle: file
10 changes: 10 additions & 0 deletions containers/compliance/cppcheck-misra.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# cppcheck MISRA addon configuration. The MISRA rule text is NOT
# distributed with cppcheck (licensing); this config wires up the
# addon and sets the default rule severity. Readers add their own
# misra_rules.txt next to it for full text expansion.
{
"script": "misra.py",
"args": [
"--rule-texts=/opt/wrocpp/misra_rules.txt"
]
}
Loading
Loading