|
| 1 | +# Keep a change record of the two published privacy-policy documents, and fail |
| 2 | +# when they drift apart. |
| 3 | +# |
| 4 | +# iubenda offers no version history and no "what changed" view (#871), so the |
| 5 | +# only way to answer "what did the policy say in March" is to keep the text |
| 6 | +# somewhere that has history. Committing it here makes git that record, which |
| 7 | +# is what #887 settled on when deciding what is owed to users who acknowledged |
| 8 | +# an older policy. |
| 9 | +# |
| 10 | +# The check half exists because **every clause in this policy is custom**, and |
| 11 | +# custom clauses do not propagate between languages in iubenda. #888 caught the |
| 12 | +# German document left behind in exactly that way. A check that needs no |
| 13 | +# discipline beats one that relies on someone being conscientious. |
| 14 | +# |
| 15 | +# What it compares, and why only those things: `tool/policy_snapshot.dart` |
| 16 | +# carries the reasoning. In short, only signals that survive translation can be |
| 17 | +# compared — the purpose taxonomy ids, the service count per purpose, and the |
| 18 | +# last-updated date. Service ids cannot: iubenda mints them per language. |
| 19 | +# |
| 20 | +# Divergences the maintainer cannot fix only warn. iubenda's own template text |
| 21 | +# differs between its languages in places (measured 2026-08-27: the English |
| 22 | +# App Store Connect section links support.apple.com for opt-out guidance, the |
| 23 | +# German one omits the sentence), and a check nobody can satisfy is a check |
| 24 | +# that gets ignored. |
| 25 | +# |
| 26 | +# The snapshot has the owner's postal address replaced with a placeholder. It is |
| 27 | +# on the published page already, so nothing is being hidden — but a public |
| 28 | +# repository's history is permanent in a way an editable page is not, and #886 |
| 29 | +# recorded a preference for a c/o address over the residential one. The script |
| 30 | +# throws rather than writing a snapshot it cannot redact. |
| 31 | +# |
| 32 | +# TWO THINGS TO KNOW ABOUT WHERE THIS RUNS: |
| 33 | +# |
| 34 | +# * Workflow files only take effect once they are on the **default branch**, so |
| 35 | +# neither the schedule nor the manual trigger does anything while this lives |
| 36 | +# on a feature branch. That is also why the first snapshot was committed by |
| 37 | +# hand from a local run: a before-and-after diff of the policy correction was |
| 38 | +# only available before the edits were made, and CI could not have run in |
| 39 | +# time to capture it. |
| 40 | +# * A scheduled run therefore starts on `main` — but `CONTRIBUTING.md` reserves |
| 41 | +# `main` for release merges only. So this checks out and commits to |
| 42 | +# `develop` explicitly rather than to whatever ref it was triggered on. |
| 43 | +# |
| 44 | +# No secrets. The read API is public and unauthenticated. |
| 45 | + |
| 46 | +name: Privacy policy snapshot |
| 47 | + |
| 48 | +on: |
| 49 | + schedule: |
| 50 | + # Weekly. The documents change a handful of times a year, and a daily run |
| 51 | + # would mostly be a daily no-op against a third party. |
| 52 | + - cron: '23 6 * * 1' |
| 53 | + workflow_dispatch: |
| 54 | + # Also on any change to the checker itself, so a broken parser is caught by |
| 55 | + # the pull request that breaks it rather than by a Monday-morning cron. |
| 56 | + pull_request: |
| 57 | + paths: |
| 58 | + - 'tool/policy_snapshot.dart' |
| 59 | + - '.github/workflows/policy-snapshot.yml' |
| 60 | + |
| 61 | +permissions: |
| 62 | + contents: read |
| 63 | + |
| 64 | +jobs: |
| 65 | + # On a pull request: check only. Nothing may be committed — the branch is not |
| 66 | + # necessarily ours, and a bot commit would rewrite a contributor's PR. |
| 67 | + check: |
| 68 | + if: github.event_name == 'pull_request' |
| 69 | + runs-on: ubuntu-latest |
| 70 | + permissions: |
| 71 | + contents: read |
| 72 | + steps: |
| 73 | + - name: Checkout code |
| 74 | + uses: actions/checkout@v7 |
| 75 | + |
| 76 | + - name: Setup Flutter + cache packages |
| 77 | + uses: ./.github/actions/setup-flutter-cache |
| 78 | + |
| 79 | + - name: Install Flutter packages |
| 80 | + run: flutter pub get |
| 81 | + |
| 82 | + - name: Check the two documents agree |
| 83 | + run: dart run tool/policy_snapshot.dart --check |
| 84 | + |
| 85 | + snapshot: |
| 86 | + if: github.event_name != 'pull_request' |
| 87 | + runs-on: ubuntu-latest |
| 88 | + permissions: |
| 89 | + contents: write |
| 90 | + steps: |
| 91 | + - name: Checkout develop |
| 92 | + uses: actions/checkout@v7 |
| 93 | + with: |
| 94 | + # Not the triggering ref. A scheduled run fires on the default |
| 95 | + # branch, and `main` takes release merges only. |
| 96 | + ref: develop |
| 97 | + |
| 98 | + - name: Setup Flutter + cache packages |
| 99 | + uses: ./.github/actions/setup-flutter-cache |
| 100 | + |
| 101 | + - name: Install Flutter packages |
| 102 | + run: flutter pub get |
| 103 | + |
| 104 | + - name: Snapshot both documents and check they agree |
| 105 | + run: dart run tool/policy_snapshot.dart |
| 106 | + |
| 107 | + # Runs even when the check failed: a divergence is exactly the state |
| 108 | + # worth having a record of, and discarding the snapshot would throw away |
| 109 | + # the evidence of the thing the job just complained about. |
| 110 | + - name: Commit the snapshot if it changed |
| 111 | + if: always() |
| 112 | + run: | |
| 113 | + set -euo pipefail |
| 114 | + if git diff --quiet -- docs/privacy-policy; then |
| 115 | + echo "Neither document changed." |
| 116 | + exit 0 |
| 117 | + fi |
| 118 | + git config user.name "github-actions[bot]" |
| 119 | + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" |
| 120 | + git add docs/privacy-policy |
| 121 | + git commit -m "docs: snapshot the published privacy policy" |
| 122 | + git push origin HEAD:develop |
0 commit comments