Replace 5 workflow files with 2 clean ones:
- lint.yml: Go lint and UI lint as parallel jobs with consistent
push + pull_request triggers (fixes fork PRs never getting UI lint)
- build.yml: stripped to compile + test only, with pull_request
trigger added (PRs now get build feedback before merge)
Removed:
- stale-issues.yml (permanent dry-run no-op)
- smoketest.yml (frequently failing device tests)
- dependabot.yml (automated dependency bumps)
- golangci-lint.yml (folded into lint.yml)
- ui-lint.yml (folded into lint.yml)
Also fixed build.yml cache restore-keys to use a proper prefix
fallback instead of duplicating the full key.
* fix(ota): reject empty signature and require prerelease opt-in for bypass
Two OTA signature verification vulnerabilities:
1. Empty signature bypass: downloadSignature accepted a 0-byte response,
which caused verifyFile to skip GPG verification entirely via the
len(signature) > 0 guard. An attacker serving an empty .sig file
could bypass signature checks on any stable release.
2. Prerelease bypass without opt-in: shouldBypassSignatureCheck only
checked whether the remote version had a prerelease suffix, not
whether the device had opted into the dev channel. A compromised
server could push a version like "99.0.0-dev.1" to any device and
skip signature verification regardless of include_pre_release setting.
Fixes:
- downloadSignature now returns an error when signature bytes are empty
- shouldBypassSignatureCheck takes includePreRelease param and requires
it to be true before allowing prerelease bypass
Unit tests added for: empty signature, hash mismatch, non-200 sig
download, valid signature happy path, and prerelease opt-in table tests.
Made-with: Cursor
* test(e2e): add OTA signature edge case and prerelease rejection tests
Add wrong-key signature, empty signature, and prerelease-without-opt-in
E2E tests to catch signature bypass vulnerabilities on real devices.
Made-with: Cursor
* refactor(e2e): use Playwright projects and remove OTA shell scripts
Organize E2E tests into named Playwright projects (core, ota-signed,
ota-prerelease-unsigned, etc.) so each test suite can be run with
--project=<name>. Remove 5 OTA wrapper scripts that were just
boilerplate env-var setup, and inline them into the Makefile via a
shared OTA_ENV macro. Rename z-ota-* specs to ota-* now that ordering
is controlled by project selection, not alphabetical filename sorting.
Made-with: Cursor
* fix(ci): use Go 1.25 for golangci-lint to match build workflow
golangci-lint v2.1.6 (built with Go 1.24) panics when type-checking
code that requires Go 1.25. Align the lint workflow with build.yml
by using go-version: ^1.25.1 instead of oldstable.
Made-with: Cursor