From eb35b765a3959460764a14cc558acb47ad9de4fa Mon Sep 17 00:00:00 2001
From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com>
Date: Tue, 2 Jun 2026 22:15:41 +0200
Subject: [PATCH] ci(release): manage store metadata via Fastlane
(deliver/supply) (#644)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## What
Implements #634 + its
[scope-extension](https://github.com/RealUnitCH/app/issues/634#issuecomment-4605096721):
drive the App Store + Play Store **listing** (metadata text,
screenshots, icon, featureGraphic) from git via Fastlane
`deliver`/`supply`, and make the handbook a **generated downstream
export** of that same metadata.
### Store metadata (#634)
- iOS `ios/fastlane/metadata/de-DE/` (10 .txt) + Android
`android/fastlane/metadata/android/de-DE/` (title, short/full
description, changelog, `video.txt`, `images/icon.png`). German text
from Dani; subtitle trimmed to `Sicher. Einfach. Unabhängig.` (28/30).
- `ios/fastlane/Deliverfile` (shared deliver defaults; team IDs stay in
`Appfile`).
- `beta` lanes push the listing alongside the binary; new metadata-only
`store_metadata` lane per platform (Android hard-pinned to the
`internal` track).
- `.github/workflows/store-metadata.yaml`: push-to-`main` +
`workflow_dispatch`; `preflight` job runs
`scripts/check-store-metadata.sh`. Reuses existing secrets — **no new
secrets**.
- `release.yaml` runs the same preflight in a gating
`store-metadata-preflight` job before either deploy lane, so a tag can
never ship a `FIXME-`/oversize/invalid-URL field to the live consoles.
- README workflow table + release section updated.
- 26 screenshots + featureGraphic delivered (alpha-stripped, dimensions
verified); privacy/support URLs resolved to
`https://realunit.ch/datenschutz/` + `…/kontakt/`.
### Handbook export (scope-extension)
- `scripts/assemble-handbook-store-listing.py` (stdlib only): copies the
PNGs under `/store/…` and renders
`scripts/templates/store-listing.html.tmpl` into the `` block of `docs/handbook/de/index.html` in
place (idempotent, single-pass substitution).
- New "S App Store / Play Store Listing" handbook section with a TOC
entry, CSS, and a **per-element `↗` source link** on every metadata
field and every image to its exact file at `…/blob/main/…`.
- `Dockerfile.handbook` `store-listing-builder` stage serves the PNGs +
the substituted page.
- `handbook-build-check.yaml` + `handbook-deploy.yaml` triggers extended
to the Fastlane metadata/screenshots/generator/template; build-check
adds a **sync gate** (re-run generator → fail if the committed handbook
is stale).
### Security hardening (review P0)
- The Android long description is rendered **unescaped** in the handbook
(Google Play allows an HTML subset). An allowlist sanitizer
(`sanitize_play_html`, stdlib `html.parser`) reduces it to the
Play-allowed tags, drops everything else, strips attributes except a
scheme-validated `href` on ``, and balances the output — so a
`okx'
+ out = gen.sanitize_play_html(payload)
+ assert "