main
dev
chore/365-cut-1.2.1
fix/363-pin-db-path
feat/351-contact-settings-menu
feat/349-window-geometry
feat/355-migration-merge
integration/290-306-335
release/1.1.2-rc.3-allplatforms
fix/309-path-len-decode
chore/298-path-logging
fix/285-ingest-timelog
fix/252-block-outgoing-dm
feat/64-observer-config
feat/batch1-ux
chore/offband-rebrand
v1.2.1
v1.2.0
v1.1.2-rc.3-allplatforms
v1.1.2-rc.3
v1.1.2-rc.2
v1.0.0
observer-g2-rc3
observer-g2-rc4
observer-g2-rc5
observer-g2-rc6
observer-g2-rc7
observer-g2-rc8
observer-g2-rc9
v1.1.0-rc.1
v1.1.0-rc.2
v1.1.0-rc.3
v1.1.2-beta.1
v1.1.2-beta.2
v1.1.2-beta.3
v1.1.2-ble-test
v1.1.2-queuediag
v1.1.2-rc.1
v1.1.2-rc.1-b45-nearbyrep
v1.1.2-rc.1-b46-pathhash
v1.1.2-rc.1-b47-tracewidth
v1.1.2-rc.1-b48-repeatertrace
v1.1.2-rc.1-b49-maptrace
v1.1.2-rc.1-b50-tracefix
v1.1.2-rc.1-b51-originstrip
v1.1.2-rc.1-b52-channelqr
v1.1.2-rc.1-b53-viarepeater
v1.1.2-rc.1-b54-rxfed
v1.1.2-rc.1-b55-topology
v1.1.2-rc.1-b57-routeux
v1.1.2-rc.1-b58-toporeadout
v1.1.2-rc.3-b59-pathlen
${ noResults }
6 Commits (ee5afefb7185635ebe642aeee75720b33f0fb284)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
ee5afefb71 |
chore(#353): add drift codegen to the release pipeline's build jobs
Follow-up to #348 (now merged): dev has drift, but release-signed.yml had no build_runner step, so the next v* release would fail its android/windows/linux builds on the missing offband_database.g.dart. Adds `dart run build_runner build --delete-conflicting-outputs` after `flutter pub get` in the three jobs that build (android, windows, linux). gate and release don't compile Dart, so no codegen there. Matches the step #348 added to build.yml/flutter_dart/deploy-web. This one couldn't ride #348 because release-signed.yml had diverged on dev (#342/#346) and editing the stale copy caused a merge conflict — see #348 discussion. Part of epic #312. Agent: SapphireCompass (session 8d755b5e) |
22 hours ago |
|
|
5f01f91dbd |
fix(#342): Gemini review — atomic release publish + verify the AAB cert
Both findings from the adversarial review, verified before applying. 1. Draft-then-publish (was: create-then-upload). Creating the release first made it publicly visible with zero assets until uploads finished; a stalled upload or dead runner would strand a partial public release — the exact failure this pipeline exists to prevent. Now: create --draft → upload → edit --draft=false, which `gh release create --help` documents as the correct pattern. Both the create and retry branches end published, so a run retried after a mid-way death can't get stuck as a draft. gh flags verified via --help. 2. Verify the AAB certificate, not just the APK. The APK check was a proxy; the AAB is what Play actually receives. apksigner can't read an AAB, so this uses keytool -printcert -jarfile and pins the same e7da8cd5… fingerprint. Verified locally: built a debug AAB, confirmed the extraction command yields 765fb469… matching the known debug fingerprint, so the check would correctly FAIL a debug-signed AAB. Part of epic #312, plan #321. Agent: SapphireCompass (session 8d755b5e) |
1 day ago |
|
|
602776c601 |
feat(#342): full-platform release automation + four-file notes gate
Today a tag builds and signs an APK/AAB but creates no release and attaches nothing. That is the same partial-release failure mode as rc.2/rc.3 (Play-only, no changelog). This closes it. release-signed.yml becomes a complete release pipeline off a v* tag: gate -> release-notes gate (backstop; fails in seconds) android -> signed APK + AAB, cert-verified (environment-gated) windows -> zipped Release build linux -> tarred bundle release -> create GitHub release, body = release notes, attach all four Security invariant preserved: only the android job references the release-signing Environment, so only it receives the keystore. The windows/linux/release jobs never see it. Still no pull_request trigger. The release job runs ONLY after every build passes, so a signing failure yields no release rather than an empty one. Published directly because the notes were reviewed in the cut PR. Four-file notes gate (.github/scripts/release-gate.sh), run on every PR (release-gate.yml) and as job one of the tag workflow: CHANGELOG.md section for the pubspec version release-notes/<v>.md non-empty -> GitHub release body play/<v>.txt non-empty, <=500 chars (Play limit) discord/<v>.md non-empty play and discord are human-pasted; CI validates, never sends. Any missing/oversize file fails the build, so a noteless release (rc.2/rc.3) is unmergeable. Gate script lives in .github/scripts/ because /scripts is in .git/info/exclude (would not commit). Verified locally: fail surfaces all four problems at once, pass is clean, 500 passes, 501 fails. Backfills the combined rc.2/rc.3 CHANGELOG entry the two versions shipped without. release-notes/, play/, discord/ seeded with README conventions. No ref input needed: the rc.3 backfill branch will carry these workflow files, so tagging that branch runs them at that commit. Part of epic #312, plan #321. Agent: SapphireCompass (session 8d755b5e) |
1 day ago |
|
|
1f128174b7 |
feat(#330): pin Flutter and pass GIPHY_API_KEY in the signed build
Rebased onto dev after #331 landed. Brings the signing workflow in line with the rest of the matrix: - Pinned to Flutter 3.44.1, matching the bench and every other workflow. A release artifact in particular must not be built by whatever `stable` happens to point at that day, which was the whole argument for #331. - Generates dart_defines.json and passes --dart-define-from-file, so the signed release does not ship with a dead GIF picker. - Cleanup step now removes dart_defines.json alongside the keystore material, since it holds the Giphy key. Verified that a job pinned to an environment still receives repository secrets (precedence is org < repo < environment, environment winning on a name collision), so the repo-scoped GIPHY_API_KEY reaches this job while the keystore secrets stay environment-scoped behind the reviewer gate. Part of epic #312, plan #321 (Phase 5). |
1 day ago |
|
|
29ca744667 |
feat(#330): pin the expected signing certificate SHA-256
Rejecting only CN=Android Debug catches the #111 fallback but not a DIFFERENT key being substituted, which breaks cross-channel updates against Play just as badly. Now asserts the exact fingerprint. Established from artifacts users have already installed, with no access to the keystore password (reading a certificate off a signed APK needs none): release b55 (2026-07-06) e7da8cd5... release b58 (2026-07-10) e7da8cd5... local release build e7da8cd5... Three independent sources agree, and the owner confirmed the same strycher-personal.jks is enrolled for Play App Signing, so this is the fingerprint that must hold for a GitHub download to update over a Play install. Found while establishing it: published release b59 (2026-07-20) is DEBUG-SIGNED (765fb469, CN=Android Debug), unlike b55 and b58. That is #111 occurring in production. Filed separately. Part of epic #312, plan #321 (Phase 5). |
1 day ago |
|
|
8d60b00b1b |
feat(#330): release-signed APK + AAB behind an approval-gated environment
CI has only ever produced debug-signed Android artifacts, because build.gradle.kts:63-70 falls back to signingConfigs "debug" when key.properties is absent, which is exactly the CI condition (#111). Debug-signed builds cannot be installed over a Play install or over a properly signed GitHub release, so users hit "App not installed". Adds a separate workflow that signs with the real keystore. Security posture, given this repo is PUBLIC and the keystore is the one credential that cannot be replaced if leaked: - No pull_request trigger. A PR, including from a fork, must never run a job that can read these secrets. - Pinned to the release-signing Environment, which carries a required reviewer and only accepts main or v* tags. The signing secrets are scoped to that environment, NOT to the repo, so a workflow that omits the environment key cannot read them at all. - Keystore decoded to disk only for the build, removed in a step with if: always() so a failed build leaves nothing behind. - Secrets passed via env: and printf'd into a file, never placed on a command line where they would appear in process listings, and never echoed. Includes an apksigner check that fails the job if the built APK carries CN=Android Debug. A green build alone does not prove release signing, because the gradle fallback is silent; that check is what makes this verifiable rather than assumed. The keystore is PKCS12 despite its .jks extension, and PKCS12 cannot carry a key password distinct from the store password, so one secret correctly populates both fields. Part of epic #312, plan #321 (Phase 5). |
1 day ago |