1
0
Fork 0
mirror of https://github.com/imjasonh/esp32 synced 2026-07-06 23:52:24 +00:00
Commit graph

10 commits

Author SHA1 Message Date
ed1d18d8df ci: restore caches before cargo install espflash
`cargo install espflash --locked` builds from source. Moving the
.embuild + Swatinem cargo-cache restores ahead of it lets the install
use the cached registry index + downloaded crates instead of fetching
them fresh each run — shaves ~30 s off the install on warm caches.

Pure step-reordering; no behavioural change. Both caches still depend
on inputs that exist at checkout, so an earlier restore is safe.

Bigger speedup is available by replacing the cargo install with a
prebuilt-binary install (e.g. taiki-e/install-action drops espflash
from ~3-5 min to ~2 s). Deferred to its own PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 00:17:25 -04:00
fa32f0b774 Fix Dependabot on firmware crate; fold provisioning-plan.md into ota.md
Dependabot fix: drop the root rust-toolchain.toml so Dependabot's
runner doesn't try to use the (uninstalled) `esp` toolchain when
running `cargo update`. The firmware Make recipe now invokes
`cargo +esp build` explicitly so local + CI builds still pin the
right toolchain. Host tools (publisher, provision) keep their own
rust-toolchain.toml = stable.

Dependabot config: batch tools/publisher + tools/provision into one
weekly PR using the `directories:` (plural) field. Firmware Cargo
deps and GHA action versions stay in their own PRs.

ota.md: fold in the provisioning-plan.md content (now that
provisioning is shipped). Updates partition layout numbers, NVS
schema, bootstrap workflow, and trust-config description (no longer
compile-time consts). Adds a 'Soft vs hard trust' section folded
from the plan. Future Work merged.

provisioning-plan.md deleted; README and CLAUDE.md updated to point
at ota.md and drop the dropped file from the project layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 16:34:47 -04:00
1928dcfd47 Provision Wi-Fi creds + trust roots via NVS instead of compile-time embed
Implements provisioning-plan.md. The OTA-distributed firmware no longer
contains any secrets or per-device config — those live in NVS and are
written via USB by `make provision` from a (gitignored)
`provisioning.toml`. Same firmware bytes can run on any device.

Firmware changes:
- src/main.rs reads wifi/ssid + wifi/pass from NVS namespace `wifi`.
  Strict-inert (sit-and-log) when missing; no compile-time fallback.
  WIFI_SSID/WIFI_PASS env! macros gone.
- src/trust.rs becomes a `TrustConfig::load(nvs)` loader. Identities
  come from NVS namespace `trust`, key `identities` (JSON-encoded
  array). Sigstore root + intermediate PEMs come from `trust/fulcio_root`
  and `trust/fulcio_inter` blobs. include_str! gone.
- src/sig.rs and src/ota.rs thread &TrustConfig through verify_bundle
  and the OTA loop instead of reading global consts.
- build.rs no longer tracks WIFI_* env changes.

New tool:
- tools/provision/ host-side cargo crate. Reads provisioning.toml,
  emits an NVS CSV, shells out to ESP-IDF's nvs_partition_gen.py to
  produce a binary NVS image, optionally `espflash write-bin`'s it.

Make targets:
- `make provision` — build NVS image + flash it.
- `make bootstrap` — flash-all + provision (new device setup).
- `make build` no longer requires wifi.env.
- wifi.env removed from prereqs / WIFI_ENV variable removed.

Workflows:
- ci.yml: drops the placeholder wifi.env step, adds a `build provision`
  job alongside the firmware + publisher jobs.
- publish.yml: drops WIFI_SSID/WIFI_PASS secret reads. Only secret
  needed is the auto-injected GITHUB_TOKEN.

Docs:
- README updated to use `make bootstrap` + `make provision` flow.
  Project layout moved to a new repo-local CLAUDE.md.
- provisioning.toml.example committed as the template the user copies.
- wifi.env.example removed (no longer used).

Migration: existing devices need `make bootstrap` over USB. The new
firmware has no embedded creds; OTAing to it without provisioning
would just sit in strict-inert.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 16:14:26 -04:00
f94f0f9f8a Add Dependabot config: weekly grouped updates for GHA + Cargo deps
Three ecosystems: GitHub Actions (workflow files), firmware Cargo
deps (root), publisher Cargo deps (tools/publisher). Each ecosystem
groups all updates into a single weekly PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 14:41:15 -04:00
6596cfe0e0 publish.yml: pin cosign-installer to v4.1.1 (no v4 moving tag)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 14:38:22 -04:00
0e9559f375 CI: drop .embuild cache (corruption across runners), pass --target on publisher
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 14:27:42 -04:00
9ef15ba16d CI: pin setup-uv to v7 (no v8 moving tag), add publisher rust-toolchain
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 14:22:34 -04:00
71fa55f189 Add CI workflow, bump GHA actions, refresh + commit Cargo.lock
CI workflow (.github/workflows/ci.yml):
- Triggers on PRs (and main pushes for redundant fast feedback).
- Two parallel jobs: build the firmware (with placeholder wifi.env),
  build the host-side publisher tool. No publishing or signing -- that
  remains publish.yml's job.
- Per-PR concurrency: a new push to a branch cancels in-flight CI for
  the previous commit on that branch.

GHA action bumps (publish.yml + ci.yml both use the new versions):
- actions/checkout    v4 -> v6
- astral-sh/setup-uv  v3 -> v8
- esp-rs/xtensa-toolchain  v1.5 -> v1.7
- sigstore/cosign-installer  v3 -> v4 (defaults to cosign 3, which
  still produces the Sigstore Bundle v0.3 format we verify on-device)
- actions/cache       v4 -> v5
- Swatinem/rust-cache stays v2 (already current)

Gets us off the deprecated Node.js 20 actions runtime.

Cargo.lock: now tracked. Both crates (firmware and publisher) are
binaries, and binary Cargo.lock should be committed for reproducible
builds. `cargo update` was a no-op except for a couple transitive
patch bumps in the firmware (generic-array 0.14.7 -> 0.14.9).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 14:16:55 -04:00
58343daf1c GHA: drop invalid @3 spec on cargo install espflash
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 14:02:13 -04:00
6cc6f38ce0 Auto-publish from GHA on push to main; sign by immutable digest
GitHub Actions workflow at .github/workflows/publish.yml builds the
firmware on every push to main, pushes it to ghcr.io/imjasonh/esp32,
and cosign-signs it keylessly using the workflow's ambient OIDC token.
Required repo secrets: WIFI_SSID, WIFI_PASS (the GITHUB_TOKEN is
injected automatically).

Trust changes:
- src/trust.rs adds the GHA workflow identity to TRUSTED_IDENTITIES,
  alongside the existing email entry. The SAN URI pins the exact
  workflow file at refs/heads/main; a malicious commit that adds a
  different workflow won't match.
- src/sig.rs's SAN extractor now also handles GeneralName::Uniform-
  ResourceIdentifier (workflow URIs), not just Rfc822Name (emails).

Sign-by-digest:
- tools/publisher prints `digest: sha256:...` on stdout (tracing logs
  redirected to stderr) so downstream tooling can target the immutable
  manifest digest.
- Makefile captures that digest and runs `cosign sign ... $REPO@DIGEST`
  instead of `:latest`, eliminating the tag-race window between push
  and sign.

Bootstrap: the device's currently-running firmware doesn't know the
GHA identity yet, so the first GHA-signed publish will be rejected.
A manual `make publish` after this lands rolls out the new
TRUSTED_IDENTITIES, after which GHA-signed updates verify cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:58:44 -04:00