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
5 changes: 5 additions & 0 deletions .changeset/fetch-bundled-drivers-at-build-time.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ftw": patch
---

`make drivers` fetches the bundled snapshot from the pinned device-drivers commit, and CI proves a build works from the pin alone.
50 changes: 50 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,56 @@ jobs:
- run: npm ci --prefer-offline --no-audit --no-fund
- run: npm test

# Proves the cutover before it happens: throw the committed drivers away,
# fetch them from the pin alone, and run the suites that read them. While
# the files are still committed this is redundant with the drift check. The
# moment they stop being committed it is the only thing standing between a
# fresh clone and a build that cannot find a driver.
drivers-from-pin:
name: drivers build from the pin alone
needs: changes
if: needs.changes.outputs.drivers == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v7
with:
go-version: '1.26'
cache-dependency-path: go/go.sum

- name: Discard the committed snapshot
run: rm -f drivers/*.lua

- name: The presence guard notices
run: |
if make drivers-present 2>/dev/null; then
echo "::error::drivers-present passed with no drivers on disk"
exit 1
fi
echo "guard fired as expected"

- name: Fetch from the pin
run: make drivers

- name: Every pinned driver came back
run: |
want="$(jq -r '.drivers | length' drivers/BUNDLED_SOURCE.json)"
got="$(ls drivers/*.lua | wc -l | tr -d ' ')"
echo "pinned ${want}, fetched ${got}"
[ "$want" = "$got" ] || { echo "::error::fetched ${got} of ${want}"; exit 1; }

# The fetched files land at the same path the committed ones did, so
# nothing that reads drivers/ needs to know where they came from.
- name: The driver suites pass against the fetched copies
working-directory: go
run: go test ./internal/drivers/... ./internal/driverinventory/...

- name: They are byte-for-byte what was committed
run: |
git diff --exit-code -- drivers/ \
|| { echo "::error::fetched snapshot differs from the committed one"; exit 1; }
echo "identical"

drivers:
name: drivers
needs: changes
Expand Down
25 changes: 23 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@

.PHONY: help test optimizer-install optimizer-test compose-migration-test container-boundary-test build build-arm64 build-amd64 build-windows-amd64 release \
run-sim dev fmt vet clean e2e ci ci-ui ci-hw-pi docs \
verify verify-all install-hooks driver-repository-validate driver-versions
verify verify-all install-hooks driver-repository-validate driver-versions \
drivers drivers-present

VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
LDFLAGS := -s -w -X main.Version=$(VERSION)
Expand Down Expand Up @@ -42,11 +43,31 @@ help:
@echo " ci-ui browser smoke against FTW_BASE_URL"
@echo " ci-hw-pi deploy candidate to Pi CI slot + browser smoke"
@echo " fmt vet Go format + static checks"
@echo " drivers fetch drivers/ from the pinned device-drivers commit"
@echo " clean nuke build artifacts"

# ---- Bundled drivers ----
#
# drivers/ is a snapshot of srcfl/device-drivers at the commit pinned in
# drivers/BUNDLED_SOURCE.json. It is fetched, not authored here. The Go tests
# read it, the container image copies it, and the release tarballs carry it,
# so it has to be populated before any of those run.

# Fetch the snapshot. Safe to re-run; it writes the same bytes every time.
drivers:
bash scripts/sync-bundled-drivers.sh
Comment on lines +57 to +58

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove drivers no longer listed by the pin

When a pin update removes a driver, make drivers invokes the existing sync script in write mode, which reports the old file as UNLISTED but exits successfully without deleting it; for example, dropping zap leaves drivers/zap.lua on disk while printing that 36 drivers were written. The new target therefore does not reliably recreate the pinned snapshot in an existing checkout, so it should remove unlisted files or fail instead.

AGENTS.md reference: AGENTS.md:L12-L15

Useful? React with 👍 / 👎.


# Cheap enough to run before every test invocation, and it costs no network.
# Fetching here instead would put a remote call in the inner loop.
drivers-present:
@ls drivers/*.lua >/dev/null 2>&1 || { \
echo "drivers/ has no .lua files. Run 'make drivers' to fetch the" >&2; \
echo "snapshot pinned in drivers/BUNDLED_SOURCE.json." >&2; \
exit 1; }

# ---- Testing ----

test: optimizer/.venv/.installed
test: optimizer/.venv/.installed drivers-present

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Gate release archives on the driver snapshot

When the committed .lua files are removed—or a developer has discarded them as this workflow does—only test checks drivers-present; release still archives the metadata-only drivers/ directory successfully and produces artifacts with no recovery drivers. Make release depend on fetching or validating the complete snapshot before the planned deletion can land.

AGENTS.md reference: AGENTS.md:L12-L15

Useful? React with 👍 / 👎.

@status=0; \
optimizer/.venv/bin/pytest -q optimizer/tests & py_pid=$$!; \
(cd go && go test ./...) & go_pid=$$!; \
Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,14 @@ editable source and FTW's default signed driver channel.
[`drivers/BUNDLED_SOURCE.json`](drivers/BUNDLED_SOURCE.json). It exists because
startup is deliberately local: a gateway boots and runs without the network, so
a remote refresh must never block it. Editing a `.lua` file here is not a way to
change a driver — fix it upstream, move the pin, and run
`scripts/sync-bundled-drivers.sh`. CI fails if the two drift.
change a driver — fix it upstream, move the pin, and run `make drivers`.
CI fails if the two drift.

A fresh clone gets the files from git today. `make drivers` fetches the same
bytes from the pin, and CI proves the two agree on every pull request by
throwing the committed copies away and rebuilding from the pin alone. That is
the groundwork for dropping them from git entirely, so this repository holds no
driver source at all.

## Install on Linux

Expand Down