1. Тема дня
Строим путь прошивки от коммита до безопасного релиза:
исходный код
→ воспроизводимая сборка в Docker
→ проверки и unit-тесты
→ контроль размера Flash/RAM
→ release bundle
→ подпись firmware
→ HIL-тестирование
→ staged rollout
→ OTA с rollbackГлавная мысль: прошивка считается готовой не потому, что она один раз собралась на компьютере разработчика, а потому, что её можно повторно собрать в чистом окружении, проверить автоматически, идентифицировать и безопасно развернуть.
2. Зачем это нужно
Без CI трудно доказать:
- каким ESP-IDF и компилятором собрана прошивка;
- совпадает ли firmware.bin с Git-коммитом;
- не вырос ли образ за пределы OTA-раздела;
- не изменился ли sdkconfig случайно;
- прошла ли миграция NVS;
- работает ли rollback;
- не сломались ли UART parser, watchdog или phase detector.3. Теория
CI, CD и HIL
CI:
compile
static checks
unit tests
size check
config check
artifact generationCD формирует релизный комплект: firmware binary, manifest, SHA-256, signature, ELF/MAP, partition table, release notes. HIL проверяет реальную плату: flash, boot, UART console, GPIO, I2C, CAN/RS-485, watchdog reset, OTA rollback, power interruption.
Воспроизводимая сборка
Фиксируй:
Git commit
ESP-IDF version
compiler/toolchain version
sdkconfig
component versions
partition table
build flagsНе используй latest для production. Используй точный Docker image/tag и lock-файлы.
Что хранить в репозитории
project/
├── CMakeLists.txt
├── sdkconfig.defaults
├── partitions_ota.csv
├── dependencies.lock
├── main/
├── components/
├── tests/
├── ci/
└── .github/workflows/Не хранить: build, private signing keys, device certificates, production passwords.
Release bundle
Храни для каждого релиза:
app.bin
bootloader.bin
partition-table.bin
flasher_args.json
project.elf
project.map
sdkconfig
size.json
manifest.json
SHA256SUMS
release-notes.mdELF нужен для backtrace, core dump и расследования старых production crash.
Подпись отдельно от сборки
PR-job не должен получать signing key. Схема:
untrusted build job:
source → unsigned firmware → tests
protected release job:
download verified artifact
check Git SHA
sign firmware
verify signature
generate release bundleHIL на Raspberry Pi
Raspberry Pi Zero 2W может быть HIL-оркестратором:
USB → ESP32 UART/JTAG
GPIO → входы через развязку
USB relay/MOSFET → питание DUT
CAN adapter
RS-485 adapter
Python test runner4. Типичные ошибки
- Использовать latest.
- Собирать release на ноутбуке.
- Хранить только .bin без .elf и .map.
- Подписывать firmware в PR-job.
- Не контролировать размер OTA-slot.
- HIL проверяет только ping.
- HIL-runner доступен недоверенному коду.
- Сразу обновлять весь парк.
5. Практическое задание
Добавь firmware-ci.yml:
name: Firmware CI
on:
pull_request:
push:
branches: [ main ]
tags: [ "v*" ]
permissions:
contents: read
env:
IDF_IMAGE: espressif/idf:v6.0.2
IDF_TARGET: esp32
PROJECT_NAME: control
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
- name: Build in ESP-IDF Docker
run: |
docker run --rm \
-v "$PWD:/project" \
-w /project \
-u "$(id -u):$(id -g)" \
-e HOME=/tmp \
-e IDF_TARGET="${IDF_TARGET}" \
"${IDF_IMAGE}" \
bash -lc 'idf.py set-target "$IDF_TARGET" && idf.py build && idf.py size --format json2 > build/size.json'Добавь размерный budget: firmware не больше 85% OTA-slot.
6. Что попробовать дальше
- Добавить manifest generation.
- Добавить SHA256SUMS.
- Сохранять ELF/MAP/size.json.
- Сделать HIL smoke-test через pyserial.
- Разделить unsigned build и protected signing job.
Задание
Pull request меняет firmware build script. Опишите границу доверия, запрещающую его job доступ к signing key и управление HIL runner.
Критерии самопроверки: Отдельно указать credentials, artifact verification и runner access. Успех unit tests не делает произвольный PR code доверенным.
Показать ответ автора
Выполнить недоверенную сборку и тесты без signing credentials и прямого HIL control. Защищённый release job проверяет artifact и Git SHA перед подписью; к аппаратному runner допускаются только проверенные доверенные входы.
Задание
Определите доказательства для расследования crash старого развёрнутого релиза и подтверждения установленного binary.
Критерии самопроверки: Использовать исторический matching ELF, а не новую сборку; включить воспроизводимые входы и identity установленного artifact.
Показать ответ автора
Сохранить точные firmware binary, manifest, SHA256SUMS, ELF/MAP, configuration и release identity, связанные с Git commit/toolchain. Сопоставить release identity устройства с bundle и использовать соответствующий ELF для анализа crash.