Skip to content

fix(daemon): give capture measurements in a reply reason to root only #1942

fix(daemon): give capture measurements in a reply reason to root only

fix(daemon): give capture measurements in a reply reason to root only #1942

Workflow file for this run

# AddressSanitizer over the test suite.
#
# irlume is mostly safe Rust, so this is aimed at the places where it is not:
# the NSS `getpwnam_r`/`getpwuid_r` buffer handling, the mlock/madvise page
# arithmetic that protects a decrypted secret, `secure_getenv`, the UVC XU
# control ioctl, and the SO_PEERCRED socket path the daemon authorizes callers
# with. Those are a few dozen lines, but they are the lines where a mistake is
# a memory-safety bug in a program that authenticates people, and clippy cannot
# see into them.
#
# Deliberately NOT a required check, and deliberately not on the fast path: it
# needs a nightly toolchain (`-Zsanitizer` is unstable), so an unrelated nightly
# regression must not be able to block a pull request. It runs on pushes that
# touch the code, on main, and weekly, so a break is visible without being in
# the way.
#
# Two known interactions, both handled rather than papered over:
# * the sanitizer runtime defines its own `mlock`, so the RLIMIT_MEMLOCK
# refusal test cannot reach the kernel. That test detects the interception
# and reports which assertion it skipped.
# * `pamwire`'s wiring tests leak a `&'static str` on purpose; the scope and
# the reasoning are in .github/lsan-suppressions.txt.
name: ASan
# Push-triggered on every branch, so a same-repo pull request picks this up
# through its own branch. A fork PR fires no push event here and therefore gets
# no ASan run, which is acceptable precisely because this is not a required
# check.
on:
push:
branches: ["**"]
paths:
- "crates/**"
- "Cargo.toml"
- "Cargo.lock"
- ".github/workflows/asan.yml"
- ".github/lsan-suppressions.txt"
- "scripts/ci-bubblewrap.sh"
- "scripts/fetch-ort.sh"
schedule:
- cron: "40 4 * * 3" # Wednesdays 04:40 UTC, clear of the other scheduled jobs
workflow_dispatch:
# Rapid pushes to a branch should not stack ASan runs; only the newest commit is
# worth sanitizing, and this job is one of the slowest in the repo. Cancelling is
# safe because ASan is not a required check, so a superseded run going away
# cannot block a merge.
#
# The schedule gets its OWN group, and that separation is the load-bearing part.
# A scheduled run fires on the default branch, so keying the group on the ref
# alone would put the weekly run in `asan-refs/heads/main` alongside ordinary
# main pushes. A concurrency group holds exactly one PENDING run, and a newly
# queued run "is canceled and replaced" per GitHub's concurrency documentation.
# `cancel-in-progress: false` does not save it: that protects the run already
# executing, not the one waiting behind it. So a main push landing while the
# weekly run sat pending would have silently deleted the weekly run, which is
# the opposite of what this block exists to do.
#
# Cancelling stays off on main so an in-flight run there still finishes.
concurrency:
group: asan-${{ github.event_name == 'schedule' && 'weekly' || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
permissions:
contents: read
jobs:
asan:
name: AddressSanitizer (test suite)
runs-on: ubuntu-24.04
timeout-minutes: 40
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# Do not leave the job token in .git/config for later steps to reach.
persist-credentials: false
- name: Cache model weights
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: models
key: models-${{ hashFiles('models/SHA256SUMS') }}
- name: Fetch model weights (models-v1 release, sha256-verified)
run: bash scripts/fetch-models.sh
- name: Install system build dependencies
run: |
command -v apt-get >/dev/null || { echo "deps preinstalled on the self-hosted runner"; exit 0; }
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential pkg-config clang libclang-dev libpam0g-dev libtss2-dev libudev-dev libdbus-1-dev dbus-daemon llvm bubblewrap apparmor
- name: Prepare and verify isolated CLI test namespaces
run: bash scripts/ci-bubblewrap.sh
# A leak suppression matches the SYMBOL NAMES in an allocation stack, so
# without a symbolizer it matches nothing and the deliberate test leak
# comes back as a failure with a stack of bare addresses. That is how this
# job failed the first time it ran here, while passing locally where a
# symbolizer happened to be installed. Resolve it explicitly and stop if it
# is missing, rather than let the job degrade into an unreadable report.
- name: Locate llvm-symbolizer (suppressions and reports both need it)
run: |
sym=$(command -v llvm-symbolizer || true)
if [ -z "$sym" ]; then
# Versioned installs land in /usr/lib/llvm-N/bin; take the newest.
sym=$(find /usr/lib -maxdepth 3 -path '*/bin/llvm-symbolizer' -type f 2>/dev/null \
| sort -V | tail -1)
fi
if [ -z "$sym" ]; then
echo "no llvm-symbolizer found; ASan reports would be bare addresses" >&2
exit 1
fi
"$sym" --version
echo "ASAN_SYMBOLIZER_PATH=$sym" >> "$GITHUB_ENV"
- name: Install nightly Rust (-Zsanitizer is unstable)
# @master (declares the `toolchain` input); the version tag branches
# have no such input and ignore `with: toolchain:`.
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # v1
with:
toolchain: nightly
# The sanitizer runtimes ship with the standard library for the
# explicit target, which is also why --target is passed below: without
# it, build scripts and proc macros would be instrumented too.
components: rust-src
targets: x86_64-unknown-linux-gnu
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
# Own cache key: an instrumented build shares nothing with the normal
# one, and PRs restore without saving (see ci.yml for the quota).
key: asan
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Fetch the ONNX runtime (ort loads it dynamically at runtime)
run: |
ver=1.28.1
bash scripts/fetch-ort.sh "$ver"
echo "ORT_DYLIB_PATH=$PWD/onnxruntime-linux-x64-${ver}/lib/libonnxruntime.so" >> "$GITHUB_ENV"
- name: test (instrumented with AddressSanitizer + LeakSanitizer)
env:
RUSTFLAGS: -Zsanitizer=address
# A leak report names the allocation, not the leak's owner, so keep
# the whole stack: the deliberate one is only distinguishable by the
# test function that allocated it.
ASAN_OPTIONS: detect_stack_use_after_return=1
run: |
# print_suppressions puts "Suppressions used:" in the log, so a reader
# can see the deliberate leak was matched rather than assume it.
# Guarded because `cargo test` exits 0 even when it discovers no tests
# at all. No cfg gates the test set by toolchain, so the nightly run
# selects the same tests the stable lanes do.
LSAN_OPTIONS="suppressions=$PWD/.github/lsan-suppressions.txt:print_suppressions=1" \
./scripts/run-tests-guarded.sh --min 2720 -- \
cargo +nightly test --workspace --locked \
--target x86_64-unknown-linux-gnu