Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@
# buildroot-showsig` transcription remains the procedure for a hand bump, and
# the fallback whenever the sync run skipped (the PR then stays red at `make
# buildroot-verify`, which is the safe failure mode).
BUILDROOT_VERSION ?= 2026.05.2
BUILDROOT_SHA256 ?= f1c8157570bdc452163db2ff109978246cd25b4e93d3c4c9fefaeee3c4d6982d
BUILDROOT_VERSION ?= 2026.08
BUILDROOT_SHA256 ?= d678e810abf877d04513e03ca2c99f992dd49118b9c2e18d6e25f5f58fa8c5cd
BUILDROOT_URL = https://buildroot.org/downloads/buildroot-$(BUILDROOT_VERSION).tar.gz
BUILDROOT_SIG_URL = $(BUILDROOT_URL).sign

Expand Down
12 changes: 6 additions & 6 deletions PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ against the *source*, and a number did not survive. Every correction is marked
Target board: Terasic DE10-Nano (Cyclone V SoC, `armv7-a` Cortex-A9)

> **Phase 0 headline:** the central bet holds. All 12 SONAMEs the stock `MiSTer` binary
> needs survive at the same major version in Buildroot 2026.05 (`docs/package-manifest.md`),
> needs survive at the same major version in Buildroot 2026.08 (`docs/package-manifest.md`),
> so §1's "nothing needs rebuilding" premise is now *confirmed* rather than assumed.
>
> **All five Phase 0 open questions were decided on 2026-07-12** — see
Expand All @@ -31,7 +31,7 @@ with **glibc 2.31**, running **Linux 5.15.1** — a kernel forked in November 20
**never merged a single 5.15.y stable release**. The Buildroot configuration that produces
it is not published anywhere.

This plan replaces that image with one built from **Buildroot 2026.05** and a
This plan replaces that image with one built from **Buildroot 2026.08** and a
**mainline 6.18 LTS kernel**, in a public repository, with CI, with release artifacts
published as GitHub Release assets rather than committed blobs.

Expand All @@ -57,7 +57,7 @@ hash-verified update channel. **No permission, no fork of the cores, no fork of
|-|-|
|G1|A `linux.img` + `zImage_dtb` that boots the **unmodified, stock** `MiSTer` binary|
|G2|Modern kernel on a supported LTS with a real security-update path|
|G3|Modern package set (Buildroot 2026.05) with a real security-update path|
|G3|Modern package set (Buildroot 2026.08) with a real security-update path|
|G4|**No separate kernel repo.** All kernel patches live as `.patch` files in the Buildroot external tree and are applied to a pristine kernel.org tarball|
|G5|Fully reproducible: pinned Buildroot, pinned kernel + hash, checked-in `.config`, published SBOM|
|G6|Release artifacts published as **GitHub Release assets**. No binaries in git. Ever.|
Expand Down Expand Up @@ -786,7 +786,7 @@ binaries (67 MB) with no CI at all**.

### Reproducibility checklist

* \[x] Buildroot version pinned (2026.05.x)
* \[x] Buildroot version pinned (2026.08.x)
* \[x] Kernel version + upstream hash pinned; patches in-tree
* \[x] `BR2_DOWNLOAD_DIR` populated from upstream; no vendored tarballs
* \[x] `buildroot.config` and `linux.config` published with every release
Expand All @@ -802,7 +802,7 @@ builds twice and compares
Once the pipeline is stable and trusted, **Renovate** keeps every moving part current
automatically. This mechanizes the sustainability commitment of §13:

* Buildroot 2026.05.x tarball version + SHA-256 (custom/regex manager over the pin file)
* Buildroot 2026.08.x tarball version + SHA-256 (custom/regex manager over the pin file)
* Kernel 6.18.y version + hash (custom datasource over kernel.org's `releases.json`)
* morrownr driver packages and other commit pins (git datasource)
* CI container image digests and GitHub Actions versions
Expand Down Expand Up @@ -928,7 +928,7 @@ measured against stock would fail on stock itself.]**
|-|-|-|
|**P0 — Recon**|Write `docs/abi-contract.md`. Triage all \~60 kernel commits into classes A–F with provenance. Derive the Buildroot package set from the shipped image.|Patch triage table is complete and reviewed|
|**P1 — Kernel**|Buildroot builds 6.18 LTS from kernel.org + `linux-patches/`. Forward-port `MiSTer_fb`, audio-spi, cpufreq. Replace `loop=` with the initramfs (§5).|Boots to a serial console on real hardware|
|**P2 — Rootfs**|Buildroot 2026.05 rootfs, glibc, SONAME parity. Read-only root preserved.|**Stock `MiSTer` binary reaches the menu.**|
|**P2 — Rootfs**|Buildroot 2026.08 rootfs, glibc, SONAME parity. Read-only root preserved.|**Stock `MiSTer` binary reaches the menu.**|
|**P3 — Parity**|WiFi, Bluetooth, Samba, FTP, SSH, MIDI. CI + release artifacts + SBOM.|Hardware matrix (§11) green|
|**P4 — Beta**|Publish `db.json`. Recruit testers. Document rollback. Final pipeline hardening: Renovate dependency automation (§9).|Sustained opt-in use, no P1 bugs|
|**P5 — Full SD image + U-Boot from source**|*Optional.* Build `uboot.img` from the pinned `u-boot_MiSTer` submodule; produce a flashable `sdcard.img` — kernel, `linux.img`, bootloader, mr-fusion-parity payload + `update_all.sh` (§8, ADR 0017).|Fresh card flashed from `sdcard.img` boots to menu; built U-Boot passes behavioural parity + hardware matrix; recovery procedure drilled|
Expand Down
38 changes: 28 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ MiSTer's operating system ships as an opaque archive containing a **375 MiB ext4
(93% full) built from **Buildroot 2021.02.4** with **glibc 2.31**, running **Linux
5.15.1** — a kernel forked in November 2021 that has **never merged a single 5.15.y
stable release**. There is no public build recipe, no CI, no SBOM, and no update path for
any of it. This project rebuilds the whole thing from **Buildroot 2026.05.2** and a
any of it. This project rebuilds the whole thing from **Buildroot 2026.08** and a
**mainline 6.18 LTS kernel** in a public repository, with reproducible builds, a
signed-hash supply chain, a nine-workflow CI pipeline, and a per-commit reconciliation
of the entire kernel fork — then ships it through the same update channel users already
Expand All @@ -87,11 +87,11 @@ mainline can hold it.
|---|---|---|
| **Kernel** | 5.15.1, forked Nov 2021, **zero** `5.15.y` stable updates ever merged; 5.15 EOL Oct 2026 | **6.18 LTS**, on a live `.y` line with security backports |
| **Kernel delta** | 110 commits on a squashed-import fork with no shared ancestry with mainline — so no `merge-base`, and no per-commit disposition | **37 patch files** against a pristine tarball, each with provenance, upstream status, and an evidence-backed record |
| **Buildroot** | 2021.02.4 | **2026.05.2** (~5 years of upstream work) |
| **glibc / gcc** | 2.31 / gcc 10-era | **2.43 / 14.4.0** |
| **OpenSSL** | **1.1.1 — EOL since 2023-09-11**, no upstream fixes since | **3.6.3** |
| **Buildroot** | 2021.02.4 | **2026.08** (~5 years of upstream work) |
| **glibc / gcc** | 2.31 / gcc 10-era | **2.44 / 15.3.0** |
| **OpenSSL** | **1.1.1 — EOL since 2023-09-11**, no upstream fixes since | **3.6.4** |
| **OpenSSH** | 8.6p1 | **10.5p1** |
| **Samba** | ~4.14 | **4.24.5** |
| **Samba** | ~4.14 | **4.24.6** |
| **Python** | 3.9 | **3.14.7** |
| **SSH host keys** | **Identical on every MiSTer on Earth**, baked into the public download, dated 2016 | **Generated per device on first boot**, persisted to the FAT card ([ADR 0015](docs/decisions/0015-per-device-ssh-host-keys.md)) |
| **Timezone on a fresh card** | Unset — `/media/fat/linux/timezone` does not exist, so glibc falls back to **UTC** and stays there until the user finds the community `timezone.sh` script | **Detected once**, from the box's public IP, using the same provider and the same destination file as `timezone.sh` so the two are interchangeable. It is one dhcpcd hook, firing on the first connection the box makes — so a card that was offline on its first boot still gets it once Wi-Fi is set up, and a box with no network does nothing at all. Never overwrites a timezone you set, and it is opt-out-able before it ever runs ([ADR 0025](docs/decisions/0025-first-boot-timezone-autodetect.md)) |
Expand Down Expand Up @@ -133,7 +133,7 @@ re-read most recently), [`docs/package-manifest.md`](docs/package-manifest.md) (
|---|---|---|
| **0 — Recon & decisions** | ✅ Complete | Patch triage, ABI-contract verification, five open questions decided (ADRs 0010–0014) |
| **1 — Kernel & initramfs** | ✅ Complete | 6.18 LTS pinned; all 37 patches apply cleanly; `zImage_dtb` builds warning-free, boots under QEMU **and on real hardware** — from the **CI-built artifact**, not a local build |
| **2 — Rootfs & testing** | ✅ Complete | Buildroot 2026.05.2, glibc 2.43, reproducible ext4 image with full SBOM; menu and cores load on hardware — the ABI contract holds *in practice*, not just on paper |
| **2 — Rootfs & testing** | ✅ Complete | Buildroot 2026.08, glibc 2.44, reproducible ext4 image with full SBOM; menu and cores load on hardware — the ABI contract holds *in practice*, not just on paper |
| **3 — Module packages & HW matrix** | ✅ Complete | Wi-Fi, Bluetooth, controllers and special devices packaged; hardware-validated **for the chips actually present on the one test board**. The v10/v10.1/v10.2 driver + firmware expansion (Broadcom, Wi-Fi 6/6E, MediaTek, Atheros USB, Redpine) is packaged and mostly CI-asserted but **not** hardware-validated — see the [ledger](#hardware-validation-ledger) and the [chipset table](#wi-fi-and-bluetooth-hardware-support). The remaining matrix rows (Samba, MIDI) are build/CI-verified only |
| **4 — Release & sustainability** | 🔄 In progress | CI/CD, `db.json` distribution, beta program, governance, publication gate |
| **5 — Full SD image & U-Boot** | 🔄 Partially landed | `sdcard.img` builds, and `release.yml` verifies it with `scripts/check-sdcard.sh` ([ADR 0020](docs/decisions/0020-sdcard-exfat-reformat-installer.md)); U-Boot-from-source is planned but not started — now targeting **mainline U-Boot**, not the 2017.03 fork ([ADR 0024](docs/decisions/0024-mainline-uboot-capability-artifact.md), [plan](docs/uboot-mainline-port.md), [tasks](docs/uboot-tasks.md)) — and the SD image has not been flashed to a fresh card on hardware (P5.4) |
Expand Down Expand Up @@ -359,7 +359,7 @@ Full write-up with the reasoning for each: [`docs/patch-provenance.md` §10](doc

### 3. Security posture

- **OpenSSL 1.1.1 → 3.6.3.** Stock ships a TLS library that has been **end-of-life since
- **OpenSSL 1.1.1 → 3.6.4.** Stock ships a TLS library that has been **end-of-life since
2023-09-11** and has received no upstream fixes since. This is the single strongest
security argument for the whole project, and it is a plain, checkable fact.
- **Per-device SSH host keys.** Every stock MiSTer ships the *same* host keys, baked into
Expand All @@ -369,7 +369,17 @@ Full write-up with the reasoning for each: [`docs/patch-provenance.md` §10](doc
This image generates unique keys on first boot and persists them to an ext4 image on the
FAT partition, **reusing stock's own proven mechanism** for Bluetooth pairing keys.
([ADR 0015](docs/decisions/0015-per-device-ssh-host-keys.md))
- **OpenSSH 8.6p1 → 10.5p1**, **Samba ~4.14 → 4.24.5**, **BlueZ → 5.79**,
- **SSH key login that survives an update.** An OS update replaces `linux.img` wholesale,
and `/root/.ssh/authorized_keys` — the usual place for a key — lives inside it, so every
update discards it. (The root filesystem is read-only at boot and only becomes writable
once you log in, so putting a key there also means logging in first, which is circular
when the key *is* the login method.) `sshd` here also
reads **`/media/fat/linux/authorized_keys`**, on the exFAT partition an update never
touches: drop your `.pub` file there from any PC with a card reader and key login keeps
working across every future update. No shell access, no script to edit, and
`StrictModes` stays on — the initramfs mounts that partition `fmask=0022,dmask=0022`,
which is exactly what `sshd` requires. ([FAQ](docs/user/faq.md#ssh-key-persist))
- **OpenSSH 8.6p1 → 10.5p1**, **Samba ~4.14 → 4.24.6**, **BlueZ → 5.86**,
**wpa_supplicant 2.9 → 2.12** — the network-facing surface, several release cycles of
hardening each.
- **Python 3.9 → 3.14.7** — the on-device interpreter that runs the Downloader and
Expand Down Expand Up @@ -571,7 +581,15 @@ shipped **byte-identical to stock's**, fetched by hash.
which **broke every SSH connection on the shipped image** and forced a release to be
pulled. Buildroot classified that bump as `openssh: (no CVE assigned)`. Both parity
documents now say so at the top, with the specific unchecked question named. The
defconfig and `Makefile` pins are the ground truth; the prose is a dated reading of it.
**2026.08 line bump** then moved the compiler itself — **gcc 14.4.0 → 15.3.0**, glibc
2.43 → 2.44, gdb 15.2 → 16.3 — plus **bluez 5.79 → 5.86**, Samba 4.24.5 → 4.24.6 and
OpenSSL 3.6.3 → 3.6.4. Two of those had consequences a version table cannot show: bluez
5.86 already contains the CablePairing series this repo had been backporting, so
`board/mister/de10nano/patches/bluez5_utils/` was deleted outright; and Buildroot
**retired the 7.0 kernel-headers series**, which silently collapsed the DE25 toolchain
from glibc to uClibc until the headers pin was moved to 7.1 (see
[`buildroot-config`](docs/buildroot-config.md) §6.2 and the fragment's own comment).
The defconfig and `Makefile` pins are the ground truth; the prose is a dated reading of it.
For the kernel this is handled by not writing the number down: narrative prose says
"6.18 LTS", and `BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE` in the defconfig is the only
place the `.y` lives.
Expand Down Expand Up @@ -884,7 +902,7 @@ Start here if you want to run it: [**one-command install**](#install-it-on-a-rea
|---|------|
| G1 | A `linux.img` + `zImage_dtb` that boots the **unmodified, stock** `MiSTer` binary |
| G2 | Modern kernel on a supported LTS with a real security-update path |
| G3 | Modern package set (Buildroot 2026.05) with a real security-update path |
| G3 | Modern package set (Buildroot 2026.08) with a real security-update path |
| G4 | **No separate kernel repo.** All kernel patches live as `.patch` files in the Buildroot external tree, applied to a pristine kernel.org tarball |
| G5 | Fully reproducible: pinned Buildroot, pinned kernel + hash, checked-in `.config`, published SBOM |
| G6 | Release artifacts published as **GitHub Release assets**. No binaries in git. Ever. |
Expand Down
6 changes: 4 additions & 2 deletions TASKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -918,13 +918,15 @@ Exit criterion: beta users successfully opt in via `db.json` and can roll back (
- [ ] **P4.6 — Renovate onboarding (final pipeline-hardening step)** — [SONNET] — Size M — Depends: P4.1, P4.4
**Sequence after P4.8/P4.9, immediately before beta launch** — automate a pipeline
only once it is stable and trusted (PLAN.md §9). Onboard Renovate and configure
`renovate.json` to manage: the Buildroot 2026.05.x tarball version + SHA-256
`renovate.json` to manage: the Buildroot 2026.08.x tarball version + SHA-256
(custom/regex manager over the pin file from P1.1), morrownr package commit pins (git
datasource), CI container image digests, and GitHub Actions versions. Every Renovate
PR must trigger the full CI suite (build, patch-apply, ABI checks, reproducibility).
Automerge stays OFF — a human reviews green PRs. **Reference:**
`/mnt/source/sb-enema/renovate.json` — a working custom regex manager for
`BUILDROOT_VERSION` (github-tags datasource, `allowedVersions` pinned to `2026.05.x`);
`BUILDROOT_VERSION` (github-tags datasource, `allowedVersions` pinned to the current
line — `2026.08.x` today; a line bump moves that regex by hand, which is why a line
bump never arrives as a Renovate PR);
use it as the template.
**Done when:** a real or synthetic Renovate PR for a Buildroot point release opens
with passing CI; the pin file's regex manager is covered by a Renovate config test.
Expand Down
Loading
Loading