Repository navigation
161 lines (151 loc) · 7.5 KB
/
Copy pathfirmware-release.yml
File metadata and controls
161 lines (151 loc) · 7.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
name: Firmware Release
# Attach the firmware images to a published release.
#
# Why this exists: for a long time it did not, and the images only ever lived
# at patternflow.work/flash/bin/<version>/. From the repository there was no
# way to get the firmware a given release *was* — you had to know to look at
# the website. Worse, one version (v3.6.3) was re-cut and overwritten in place
# when fixes folded in, so the same version name carried two different
# binaries and nothing recorded which one you had.
#
# The images are not built here. Building the sketch needs the ESP32 toolchain
# and takes minutes; the release process already produces the files and commits
# them under web/public/flash/bin/<tag>/ for the browser flasher. This workflow
# takes them from the tag and attaches them, so the release and the website
# cannot drift apart — they are literally the same bytes.
#
# FLASHING.md carries a sha256 for each one. That is the part that makes a
# version name mean something: if an image is ever re-cut, the hash says so.
on:
release:
types: [published]
# For releases published before this workflow existed, and for a run that
# failed.
workflow_dispatch:
inputs:
tag:
description: "Release tag to attach images for (e.g. v3.6.3)"
required: true
# v3.6.3 was built with patternflow_secrets.h present and carries the
# maintainer's Wi-Fi credentials. The risk was assessed and accepted — it
# needs RF proximity — but the guard below still refuses it, and it
# should: an accepted risk is not the same as an invisible one. Ticking
# this is how you say "I know about this image", once, per run. It is not
# available on the automatic path at all.
known_secrets:
description: "This image is known to contain build-time credentials — attach it anyway"
type: boolean
default: false
concurrency:
group: firmware-release-${{ github.event.release.tag_name || inputs.tag }}
cancel-in-progress: false
permissions:
contents: write
jobs:
attach:
runs-on: ubuntu-latest
env:
TAG: ${{ github.event.release.tag_name || inputs.tag }}
steps:
# The default branch, with full history so the tag is reachable. NOT the
# tag: checking that out replaces this workflow's own script with
# whatever existed back then, which for every release so far is nothing.
# Tooling comes from here; only the images come from the tag.
- uses: actions/checkout@v4
with:
fetch-depth: 0
# A release with no images under its own version is not worth failing the
# run over — v1/v2-era tags predate this layout, and a prerelease may not
# have had a build cut. Say so and stop. The same for a tag that is not
# a core version at all: an edition's own write-up (`audio-v0.5.2`) is a
# release too, and its image is attached by hand from the shelf.
- name: Take the images from the tag
id: find
run: |
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
echo "::notice::$TAG is not a core vX.Y.Z tag — nothing to attach from the shelf"
echo "found=0" >> "$GITHUB_OUTPUT"
exit 0
fi
git rev-parse -q --verify "refs/tags/$TAG" >/dev/null || {
echo "::error::no tag $TAG in this repository"
exit 1
}
# Since the shelf (2026-08) the core's folder is core-<tag>; releases
# before it used the bare tag. Take whichever the tag carries.
DIR=""
for candidate in "web/public/flash/bin/core-$TAG" "web/public/flash/bin/$TAG"; do
if git ls-tree -r --name-only "$TAG" -- "$candidate" | grep -q .; then
DIR="$candidate"
break
fi
done
if [ -z "$DIR" ]; then
echo "::notice::$TAG has no images under web/public/flash/bin/ — nothing to attach"
echo "found=0" >> "$GITHUB_OUTPUT"
exit 0
fi
# The images AS THEY WERE at the tag, not as they are on the default
# branch. v3.6.3 was re-cut and overwritten in place, so those are
# not always the same bytes.
rm -rf "$DIR"
git checkout "$TAG" -- "$DIR"
echo "dir=$DIR" >> "$GITHUB_OUTPUT"
echo "found=1" >> "$GITHUB_OUTPUT"
ls -l "$DIR"
# The app image is the one part that must be there. The other three are
# expected but not universal: releases before v3.2.0 predate the four-part
# layout and carry no boot_app0.bin, which is not a build output at all —
# it comes from the ESP32 core. Attach what exists and let FLASHING.md
# describe exactly that, rather than failing on history.
- name: Work out which parts exist
if: steps.find.outputs.found == '1'
run: |
cd "${{ steps.find.outputs.dir }}"
[ -f patternflow.ino.bin ] || {
echo "::error::patternflow.ino.bin is missing — nothing to publish"
exit 1
}
for f in patternflow.ino.bootloader.bin patternflow.ino.partitions.bin boot_app0.bin; do
[ -f "$f" ] || echo "::warning::$f is not in this release"
done
# The one check that cannot be made after the fact. net_config.h bakes
# whatever patternflow_secrets.h defines straight into the image, and
# three published releases went out carrying the maintainer's home Wi-Fi
# credentials because of it. A clean image still has the placeholder in
# it; an image built with the secrets file does not.
- name: Refuse to publish an image built with secrets
if: steps.find.outputs.found == '1'
run: |
BIN="${{ steps.find.outputs.dir }}/patternflow.ino.bin"
if grep -qa YOUR_WIFI_SSID "$BIN"; then
echo "placeholder SSID present — built without patternflow_secrets.h"
elif [ "${{ inputs.known_secrets }}" = "true" ]; then
echo "::warning::$BIN has no placeholder SSID and is being attached"
echo "::warning::anyway, because this run said so. It carries whatever"
echo "::warning::patternflow_secrets.h defined when it was built."
else
echo "::error::$BIN has no placeholder SSID. Either it was built with"
echo "::error::patternflow_secrets.h present, or the placeholder changed."
echo "::error::Do not publish it until you know which."
echo "::error::To attach a known-leaky image deliberately, re-run this"
echo "::error::workflow by hand with 'This image is known to contain"
echo "::error::build-time credentials' ticked."
exit 1
fi
# The generator is a script rather than a heredoc so it can be run
# against a real image directory and read before anything is published:
# .github/scripts/flashing-md.sh web/public/flash/bin/v3.7.0 v3.7.0
- name: Write FLASHING.md
if: steps.find.outputs.found == '1'
run: |
bash .github/scripts/flashing-md.sh "${{ steps.find.outputs.dir }}" "$TAG" "$(git log -1 --format=%cs "$TAG")" > FLASHING.md
cat FLASHING.md
- name: Attach them to the release
if: steps.find.outputs.found == '1'
env:
GH_TOKEN: ${{ github.token }}
run: |
DIR="${{ steps.find.outputs.dir }}"
gh release upload "$TAG" "$DIR"/*.bin FLASHING.md --clobber
echo "attached $(ls "$DIR"/*.bin | wc -l) images and FLASHING.md to $TAG"