diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 0b7ae58..cade23a 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -44,6 +44,10 @@ jobs: # releases API instead. Drop this once no cube runs the old updater. # Runs before the workflow stages dist/, which only adds to it. post-build-run: mkdir -p dist && cp -v ".pio/build/$PIO_ENV/firmware.bin" dist/esp32s3.bin + # The telemetry broker and its shared login (lib/cube/telemetry.h), + # from repository secrets through build-env below. Without them the + # build just does not report. + pre-build-run: python3 scripts/write_secrets.py # GitHub-hosted for now. Switching to a self-hosted runner is this one # line (a single label -- the input is a string). # runs-on: platformio @@ -51,3 +55,9 @@ jobs: # ESP-DASH-Pro is a private repository (its license forbids publishing # the source), so cloning it needs a token that can read it. gh-token: ${{ secrets.GH_PAT }} + # Compiled into the firmware, so readable from any release: the broker's + # ACL confines this login to each cube's own topics (README, Telemetry). + build-env: | + MQTT_URL=${{ secrets.MQTT_URL }} + MQTT_USER=${{ secrets.MQTT_USER }} + MQTT_PASSWORD=${{ secrets.MQTT_PASSWORD }} diff --git a/CLAUDE.md b/CLAUDE.md index f9e60a6..756ec34 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -198,6 +198,10 @@ Callers of the shared workflows in `elliotmatson/pio-actions@v1`: (`pio test -e native`), plus `dependency-updates.yml` (weekly `platformio.ini` bumps through `elliotmatson/platformio-dependency-updater`) and Dependabot for actions. +`build-release.yml` passes the `MQTT_URL`, `MQTT_USER` and `MQTT_PASSWORD` +repository secrets through pio-actions' `build-env` (v1.9.0+), and +`scripts/write_secrets.py` turns them into `lib/cube/secrets.h` before the +build; without them the firmware just does not report. `docs.yml` publishes Doxygen to GitHub Pages from `main`. ## Conventions diff --git a/scripts/write_secrets.py b/scripts/write_secrets.py new file mode 100644 index 0000000..4f7495a --- /dev/null +++ b/scripts/write_secrets.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +"""Writes lib/cube/secrets.h for a CI build from the environment. + +The release workflow passes MQTT_URL, MQTT_USER and MQTT_PASSWORD from +repository secrets (pio-actions' build-env). Without MQTT_URL nothing is +written, and the build simply does not report (see lib/cube/telemetry.h). +Values are escaped as C string literals, so any password works. +""" + +import json +import os +from pathlib import Path + +HEADER = Path(__file__).resolve().parent.parent / "lib" / "cube" / "secrets.h" + + +def c_string(value: str) -> str: + # JSON string escaping is valid C for these: \" \\ \n and \uXXXX. + return json.dumps(value) + + +def main() -> None: + url = os.environ.get("MQTT_URL", "").strip() + if not url: + print("write_secrets: no MQTT_URL; this build will not report") + return + lines = ["// Written by scripts/write_secrets.py in CI. Do not commit.", "#pragma once"] + for key in ("MQTT_URL", "MQTT_USER", "MQTT_PASSWORD"): + value = os.environ.get(key, "") + if value: + lines.append(f"#define {key} {c_string(value)}") + HEADER.write_text("\n".join(lines) + "\n") + print(f"write_secrets: wrote {HEADER.name} ({', '.join(k for k in ('MQTT_URL', 'MQTT_USER', 'MQTT_PASSWORD') if os.environ.get(k))})") + + +if __name__ == "__main__": + main()