Skip to content

Golden vectors

Golden vectors #11

name: Golden vectors
# Rebuilds official libcsp v2.1 (commit 48f7fb0) from source, regenerates every
# committed CAN capture under tests/golden_vectors/, and fails if the fresh
# capture differs from what is committed. This catches an upstream libcsp
# change (or a moved v2.1 tag) even when no local change triggers the run.
on:
schedule:
- cron: "0 3 * * *" # nightly, 03:00 UTC
push:
branches: [main]
paths:
- "tests/golden_vectors/**"
- "Dockerfile"
- "docker-compose.yml"
# Its own definition, so a change to this job is verified by running it
# rather than by waiting for the nightly schedule to report the result.
- ".github/workflows/golden-vectors.yml"
pull_request:
paths:
- "tests/golden_vectors/**"
- "Dockerfile"
- "docker-compose.yml"
# Its own definition, so a change to this job is verified by running it
# rather than by waiting for the nightly schedule to report the result.
- ".github/workflows/golden-vectors.yml"
workflow_dispatch: {}
jobs:
regenerate-and-diff:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
# The container creates vcan0 inside its own network namespace, but kernel
# modules are global: with vcan absent from the host kernel, the
# entrypoint's `ip link add type vcan` fails, `set -eu` takes the
# entrypoint down with it, and the container is already gone when a later
# step tries to exec into it. Loading it from inside is not an option --
# /lib/modules is not mounted there, so modprobe has nothing to read.
# A developer machine that has generated vectors before already has vcan
# loaded, which is why this only ever failed on a fresh CI runner.
# The runner's azure-flavour kernel image ships without the CAN modules --
# `modprobe vcan` there reports "Module vcan not found in directory
# /lib/modules/<version>". They live in the matching linux-modules-extra
# package, which has to be installed for that exact kernel ABI, so this
# cannot be pinned to a version and must follow `uname -r`.
- name: Load the vcan kernel module on the runner
run: |
if sudo modprobe vcan 2>/dev/null; then
lsmod | grep '^vcan'
exit 0
fi
package="linux-modules-extra-$(uname -r)"
echo "vcan is absent from this runner's kernel image; installing $package"
sudo apt-get update
if ! sudo apt-get install -y "$package"; then
echo "::error::$package is unavailable for kernel $(uname -r); the Ubuntu archive may not have published it for this runner image yet."
exit 1
fi
sudo modprobe vcan
lsmod | grep '^vcan'
- name: Build the libcsp golden-vector image
run: docker compose build
- name: Start the golden-vector container
run: docker compose up -d
# `up -d` exits 0 for a container that starts and immediately dies, so the
# first sign of trouble used to be "service is not running" from the step
# below, with the entrypoint's own error nowhere in the log. Check here
# instead, and print that output either way.
- name: Verify the container stayed up
run: |
if [ -z "$(docker compose ps --status running --quiet libcsp-vectors)" ]; then
echo "::error::The golden-vector container exited during startup; its entrypoint output follows."
docker compose logs --no-color libcsp-vectors
exit 1
fi
docker compose logs --no-color libcsp-vectors
- name: Regenerate every committed vector from a fresh libcsp build
run: docker compose exec -T libcsp-vectors /app/tests/golden_vectors/scripts/regenerate-vectors.sh
- name: Container logs
if: failure()
run: docker compose logs --no-color libcsp-vectors
- name: Stop the golden-vector container
if: always()
run: docker compose down
- name: Fail if regenerated vectors differ from committed fixtures
run: |
if ! git diff --exit-code -- tests/golden_vectors/*.txt; then
echo "::error::Freshly captured CAN traffic from libcsp v2.1 (48f7fb0) no longer matches the committed golden vectors."
echo "::error::Either upstream libcsp changed on-wire behavior, or a committed fixture is stale. Investigate before merging."
exit 1
fi