Files
vdm/.github/workflows/ci.yml
T
samiandClaude Sonnet 5 2cb1959bff ext: no-download-logic ESLint gate in the extension-lint CI job
CLAUDE.md §3's rule was prose only for extension/ (GUI already has
gui_no_download_logic as a ctest). eslint.config.mjs adds a
no-restricted-syntax/no-restricted-globals rule banning fetch/XHR/Request,
ReadableStream.getReader, Range/Content-Range header construction, and
IndexedDB in src/**/*.ts. Verified red on a planted violation (fetch +
Range header + stream reader) and green on ordinary code; that check is
now a permanent regression test (tests/lint/no-download-logic.test.ts)
rather than a one-off manual run. Wired into the existing extension-lint
job in .github/workflows/ci.yml, ahead of web-ext lint.

Generated protocol code (src/shared/protocol/**) is excluded from lint
entirely — it must never be hand-edited, so flagging it as fixable would
be a lie.

Answers gui/docs/ext-requests-m1.md.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Ed8KEmAW48v4YHdxLtqsMB
2026-09-11 12:25:19 +04:00

228 lines
9.3 KiB
YAML

name: CI
on:
push:
branches: [main]
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
# GitHub-hosted runners are Ubuntu 24.04; the project targets 26.04. bootstrap.sh warns
# but proceeds. Revisit when 26.04 runners exist.
DEBIAN_FRONTEND: noninteractive
jobs:
# --- fast lint jobs: no compiler, no heavy deps -------------------------------------
clang-format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install clang-format
run: sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends clang-format
- name: Check formatting
run: |
shopt -s globstar nullglob
files=(core/**/*.{cpp,hpp} daemon/**/*.{cpp,hpp} cli/**/*.{cpp,hpp} nmhost/**/*.{cpp,hpp})
if [ ${#files[@]} -eq 0 ]; then echo "no C++ sources yet — skipping"; exit 0; fi
printf '%s\n' "${files[@]}"
clang-format --dry-run --Werror "${files[@]}"
testserver:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: testserver self-test
run: python3 tools/testserver/selftest.py
bootstrap-script:
# Keeps tools/bootstrap.sh honest on the runner image: it must run clean and its
# --check must pass. ubuntu-latest is 24.04; the project ships on 26.04, so this
# exercises the 24.04 archive only. bootstrap-script-2604 below is what validates
# the package names against the release the project actually targets.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: sudo ./tools/bootstrap.sh --with-clang
- run: ./tools/bootstrap.sh --check --with-clang
# Cheap: apt-cache only. Validates the M6 packaging names now so they can't rot
# unnoticed until M6.
- run: ./tools/bootstrap.sh --check --with-clang --packaging
bootstrap-script-2604:
# The project targets 26.04 and GitHub has no 26.04 runner image yet, so the one
# automated place bootstrap.sh runs is on the wrong release to catch a name that is
# valid on 24.04 and gone on 26.04 — which is exactly how libqt6svg6-dev reached a
# contributor's VM (gui/docs/pkg-qa-requests-m1.md R1/R2). Run the real install in a
# 26.04 container, with --with-clang: the fuzz toolchain had never been exercised
# anywhere (CORE ran clang++-21 directly because it can't sudo).
runs-on: ubuntu-latest
container: ubuntu:26.04
steps:
- name: Base tools for checkout
run: |
apt-get update -qq
apt-get install -y --no-install-recommends ca-certificates git sudo
- uses: actions/checkout@v4
- name: Full bootstrap on 26.04 (--with-clang)
run: ./tools/bootstrap.sh --with-clang
- name: Re-verify
run: ./tools/bootstrap.sh --check --with-clang
extension-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: check
# "Has EXT landed?" is answered by a manifest, not by extension/package.json:
# a guard keyed to one filename passes vacuously the day EXT ships the lane
# under any other name. Skip only when the lane genuinely is not here; once a
# manifest exists, a missing lint entrypoint is a hard failure, not a skip.
run: |
manifest=""
for m in extension/manifest.json extension/src/manifest.json extension/public/manifest.json; do
if [ -f "$m" ]; then manifest="$m"; break; fi
done
if [ -z "$manifest" ]; then
echo "extension/ has not landed yet (no manifest.json) — skipping web-ext lint."
echo "present=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "EXT has landed: $manifest"
echo "present=true" >> "$GITHUB_OUTPUT"
if [ ! -f extension/package.json ]; then
echo "::error::$manifest exists but extension/package.json does not — this job" \
"cannot lint the extension. Wire web-ext lint in here; do not let the check" \
"pass green over an unlinted lane."
exit 1
fi
- uses: actions/setup-node@v4
if: steps.check.outputs.present == 'true'
with:
node-version: '22'
- name: eslint (no-download-logic gate + general rules)
if: steps.check.outputs.present == 'true'
working-directory: extension
run: |
npm ci
npx eslint .
- name: web-ext lint
if: steps.check.outputs.present == 'true'
working-directory: extension
run: |
npx web-ext lint --source-dir .
# --- build + test matrix ----------------------------------------------------------
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
compiler: [gcc, clang]
env:
CC: ${{ matrix.compiler == 'gcc' && 'gcc' || 'clang' }}
CXX: ${{ matrix.compiler == 'gcc' && 'g++' || 'clang++' }}
steps:
- uses: actions/checkout@v4
- name: Bootstrap toolchain
run: sudo ./tools/bootstrap.sh --with-clang
- name: Configure
run: cmake --preset ci
- name: Build
run: cmake --build --preset ci
- name: Test
# -E '^conformance$' drops the end-to-end run.sh test (npm installs, its own
# mockd, ~24 s); the dedicated `conformance` job owns that one run. The native
# `conformance_cpp` test is not excluded and still runs on every matrix leg.
run: ctest --preset ci --output-on-failure -E '^conformance$'
sanitizers:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
preset: [dev, tsan] # dev = ASan + UBSan
steps:
- uses: actions/checkout@v4
- name: Bootstrap toolchain
run: sudo ./tools/bootstrap.sh --with-clang
- name: Configure
run: cmake --preset ${{ matrix.preset }}
- name: Build
run: cmake --build --preset ${{ matrix.preset }}
- name: Test
# See the build job: the end-to-end run.sh test is the dedicated `conformance`
# job's; sanitizing a suite that shells out to its own unsanitized g++ build and
# a node process buys nothing. `conformance_cpp` still runs here under the sanitizer.
run: ctest --preset ${{ matrix.preset }} --output-on-failure -E '^conformance$'
env:
ASAN_OPTIONS: detect_leaks=1:halt_on_error=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
TSAN_OPTIONS: halt_on_error=1
clang-tidy:
# Advisory through M1 (see .clang-tidy WarningsAsErrors: ''); becomes required at M2.
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- id: check
run: |
if ls core/CMakeLists.txt daemon/CMakeLists.txt >/dev/null 2>&1; then
echo "present=true" >> "$GITHUB_OUTPUT"
else echo "present=false" >> "$GITHUB_OUTPUT"; fi
- name: Bootstrap toolchain
if: steps.check.outputs.present == 'true'
run: sudo ./tools/bootstrap.sh
- name: Configure (for compile_commands.json)
if: steps.check.outputs.present == 'true'
run: cmake --preset dev
- name: Run clang-tidy on changed files
if: steps.check.outputs.present == 'true'
run: |
mapfile -t files < <(git diff --name-only --diff-filter=ACM \
"${{ github.event.pull_request.base.sha || 'HEAD~1' }}" HEAD \
-- '*.cpp' '*.hpp' || true)
[ ${#files[@]} -eq 0 ] && { echo "no C++ changes"; exit 0; }
printf '%s\n' "${files[@]}"
clang-tidy -p build/dev "${files[@]}"
- name: skipped
if: steps.check.outputs.present == 'false'
run: echo "no C++ lane has landed a CMakeLists yet — skipping clang-tidy"
conformance:
# The M0 exit gate. Proves the generated C++ daemon surface and the generated TS
# extension surface agree with contracts/fixtures without either side having run
# against the other. Required on every PR — branch protection is a repo setting,
# recorded in .github/BRANCH_PROTECTION.md.
#
# Canonical entry point is `ctest -L conformance`. tests/conformance/CMakeLists.txt
# (owned by PROTO) registers two tests under that label: `conformance`, which shells
# out to run.sh end to end, and `conformance_cpp`, the finer-grained native runner.
# CI drives it exactly as a developer does — one definition of "the suite passed",
# and PROTO's registration is on the exercised path so it cannot rot. See
# docs/adr/0014-conformance-runs-through-ctest.md.
#
# `noTestsAction: error` in the dev test preset is the rot guard: if the label ever
# matches nothing (registration deleted, typo), ctest exits non-zero instead of
# passing vacuously.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Bootstrap toolchain
run: sudo ./tools/bootstrap.sh
- uses: actions/setup-node@v4
with:
node-version: '22' # apt ships < 20; run.sh's TS replay runner needs >= 20
- name: Configure
run: cmake --preset dev
- name: Build the native conformance runner
run: cmake --build --preset dev --target velox_conformance_cpp
- name: Run conformance (ctest -L conformance)
run: ctest --preset dev -L conformance --output-on-failure