signal-bot/.github/workflows/ci.yml
Krzysztof kuhy Rudnicki 486c478618
Some checks are pending
CI / check (push) Waiting to run
CI / web (push) Waiting to run
fix: give heif-enc an encoder, and prove it before the suite runs
heif-enc resolved and still could not work: Ubuntu splits the HEVC encoder
into libheif-plugin-x265, so the binary is installed and answers "No HEVC
encoder available". Confirmed the package exists in noble, which is what
ubuntu-latest is, rather than guessing at a name for the third time.

The step now performs one real encode. Resolving a binary is not the same
claim as being able to use it, and this is the third distinct way the same
step has failed -- missing tool, missing tool, missing codec -- each of which
only surfaced inside a fixture builder several minutes into the run. A probe
that encodes fails in the install step, with a message naming the problem.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01416TegJ3sa8xL5qGGgrygP
2026-08-31 15:43:52 +02:00

123 lines
4.7 KiB
YAML

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# scripts/install_service.sh installs both of these for the host and
# this file never did, so ./scripts/e2e.sh has failed on every commit
# for as long as it has existed: tool/e2e_fixtures.py builds its JPEG
# and MP4 fixtures with ffmpeg, and signal_bot/media_strip.py strips
# metadata with exiftool. Verified rather than trusted, because an
# apt exit code is not the same claim as "the binary resolves".
# Every binary tool/e2e_fixtures.py shells out to, which is the whole
# list rather than the first one that failed: ffmpeg builds the JPEG
# and MP4 fixtures, heif-enc the HEIC one, and exiftool is what
# signal_bot/media_strip.py strips metadata with. scripts/e2e.sh has
# needed all three since it was written and this file installed none of
# them, which is why CI has been red on every commit.
#
# Verified by resolving each binary, not by trusting apt's exit code --
# the same distinction install_service.sh makes for the host.
- name: Install the tools the fixtures are built with
run: |
sudo apt-get update
sudo apt-get install -y ffmpeg libimage-exiftool-perl \
libheif-examples libheif-plugin-x265
for tool in ffmpeg exiftool heif-enc; do
command -v "$tool" || { echo "::error::$tool did not resolve"; exit 1; }
done
# Resolving heif-enc is not the same claim as being able to encode:
# Ubuntu splits the HEVC encoder into its own plugin, so the binary
# is there and answers "No HEVC encoder available". One real encode
# fails here, naming the problem, instead of inside a fixture builder.
ffmpeg -loglevel error -f lavfi -i color=c=red:s=32x32 -frames:v 1 -y /tmp/probe.png
heif-enc -q 50 /tmp/probe.png -o /tmp/probe.heic
test -s /tmp/probe.heic || { echo "::error::heif-enc produced nothing"; exit 1; }
- name: Install uv
uses: astral-sh/setup-uv@v5
- name: Set up Python
run: uv python install 3.14
- name: Install dependencies
run: |
uv venv .venv
uv pip install --python .venv/bin/python -e '.[dev]'
# Mirrors the no-noqa pre-commit hook. A suppression must not be able
# to reach main just because someone committed without hooks installed.
- name: block suppressions
run: |
if grep -rnEi '#\s*(noqa|type:\s*ignore|ruff:\s*noqa)' \
--include='*.py' signal_bot fake_signal tests; then
echo '::error::suppressions are not allowed; fix the finding or ask first'
exit 1
fi
# The name half of this check needs the operator's private data and so
# can only run locally; the shape half -- phone numbers, uuids, Signal
# group ids -- works anywhere and is what CI enforces on every push.
- name: no personal data
run: ./scripts/check_personal_data.sh --all
- name: ruff format
run: .venv/bin/ruff format --check .
- name: ruff check (ALL rules)
run: .venv/bin/ruff check .
- name: mypy --strict
run: .venv/bin/mypy signal_bot fake_signal
- name: shellcheck
# --severity=style is the floor CI enforces; the local pre-commit hook
# uses the same flag so a version skew cannot pass locally and fail here.
run: shellcheck -x --severity=style ./*.sh scripts/*.sh
- name: pytest (100% branch coverage)
run: .venv/bin/python -m pytest -q
# The real bot against the fake Signal server. No account, no network.
- name: end-to-end
run: ./scripts/e2e.sh
# Boot order reversed: the bot starts first and Signal appears later,
# which is what a reboot looks like and what put the unit in `failed`
# for eight hours on 2026-08-30.
- name: cold start
run: ./scripts/cold_start.sh
# The management page. Its own job rather than more steps on `check`: it
# needs a Node toolchain that the Python job has no use for, and the two
# halves fail for unrelated reasons.
web:
runs-on: ubuntu-latest
defaults:
run:
working-directory: web
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "24.20.0"
- run: corepack enable
- name: install (exact pins, from the lockfile)
run: pnpm install --frozen-lockfile
- name: tsc --noEmit and eslint
run: pnpm lint
- name: vitest (100% coverage, no excludes)
run: pnpm coverage