|
| 1 | +# SPDX-FileCopyrightText: Sudo Apt Holdings LLC |
| 2 | +# SPDX-License-Identifier: Apache-2.0 |
| 3 | +# |
| 4 | +# The OTP canary (owner decision D2, ADR-0014). The desktop pin in .tool-versions waits for |
| 5 | +# Burrito's ERTS builds; the container pin in ci/container.tool-versions does not. Every day this |
| 6 | +# asks whether Burrito can now fetch the container's OTP for all three desktop targets, and the |
| 7 | +# first day it can, it opens a pull request that moves the desktop pin there. Merging that pull |
| 8 | +# request is how the desktop gets the CVE-2026-89422 fix, and with it `Trinity.TLS` stops holding |
| 9 | +# the desktop's TLS clients to TLS 1.2 (it decides from the running runtime, not from a flag). |
| 10 | +# |
| 11 | +# Two things a reader of the pull request needs to know: |
| 12 | +# * a pull request opened with GITHUB_TOKEN starts no workflow, so its gate runs when a person |
| 13 | +# pushes to the branch (or closes and reopens it); |
| 14 | +# * the repository setting "Allow GitHub Actions to create and approve pull requests" must be on, |
| 15 | +# or the last step fails with a permissions error that names it. |
| 16 | +# It never opens a second pull request for the same version: a closed one is a person's answer. |
| 17 | +name: otp-canary |
| 18 | + |
| 19 | +on: |
| 20 | + schedule: |
| 21 | + - cron: "41 7 * * *" |
| 22 | + workflow_dispatch: |
| 23 | + |
| 24 | +permissions: |
| 25 | + contents: read |
| 26 | + |
| 27 | +jobs: |
| 28 | + probe: |
| 29 | + runs-on: ubuntu-latest |
| 30 | + outputs: |
| 31 | + result: ${{ steps.probe.outputs.result }} |
| 32 | + version: ${{ steps.probe.outputs.version }} |
| 33 | + steps: |
| 34 | + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 |
| 35 | + |
| 36 | + - name: Can Burrito fetch the container's OTP for every desktop target? |
| 37 | + id: probe |
| 38 | + run: scripts/otp_canary.sh probe | tee -a "$GITHUB_OUTPUT" |
| 39 | + |
| 40 | + flip: |
| 41 | + needs: probe |
| 42 | + if: needs.probe.outputs.result == 'ready' |
| 43 | + runs-on: ubuntu-latest |
| 44 | + # The branch push and the pull request, and nothing else in this workflow. |
| 45 | + permissions: |
| 46 | + contents: write |
| 47 | + pull-requests: write |
| 48 | + env: |
| 49 | + VERSION: ${{ needs.probe.outputs.version }} |
| 50 | + BRANCH: canary/otp-${{ needs.probe.outputs.version }} |
| 51 | + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 52 | + steps: |
| 53 | + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 |
| 54 | + |
| 55 | + - name: Has a pull request for this version been opened before? |
| 56 | + id: seen |
| 57 | + run: | |
| 58 | + count=$(gh pr list --head "$BRANCH" --state all --json number --jq length) |
| 59 | + if [ "$count" != 0 ] || git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null; then |
| 60 | + echo "::notice::$BRANCH already has a pull request or a branch; nothing to do" |
| 61 | + echo "seen=true" >> "$GITHUB_OUTPUT" |
| 62 | + else |
| 63 | + echo "seen=false" >> "$GITHUB_OUTPUT" |
| 64 | + fi |
| 65 | +
|
| 66 | + # The flip first, so setup-beam installs the OTP the pull request moves to: the licence list |
| 67 | + # names the OTP applications of the runtime that generates it, and VERSIONS.md is generated |
| 68 | + # from the pin list the flip edits. The gate checks both. |
| 69 | + - name: Move the desktop pin |
| 70 | + if: steps.seen.outputs.seen == 'false' |
| 71 | + run: scripts/otp_canary.sh flip |
| 72 | + |
| 73 | + - uses: erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124 # v1.24.1 |
| 74 | + if: steps.seen.outputs.seen == 'false' |
| 75 | + with: |
| 76 | + version-file: .tool-versions |
| 77 | + version-type: strict |
| 78 | + |
| 79 | + - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 |
| 80 | + if: steps.seen.outputs.seen == 'false' |
| 81 | + with: |
| 82 | + path: | |
| 83 | + deps |
| 84 | + _build |
| 85 | + key: ${{ runner.os }}-mix-canary-${{ hashFiles('mix.lock') }} |
| 86 | + restore-keys: ${{ runner.os }}-mix- |
| 87 | + |
| 88 | + - name: Regenerate VERSIONS.md and THIRD_PARTY_LICENSES.md on the new OTP |
| 89 | + if: steps.seen.outputs.seen == 'false' |
| 90 | + env: |
| 91 | + MIX_ENV: test |
| 92 | + run: | |
| 93 | + mix deps.get |
| 94 | + mix versions.gen |
| 95 | + mix trinity.sbom |
| 96 | + mix trinity.third_party_licenses --write |
| 97 | +
|
| 98 | + - name: Open the pull request |
| 99 | + if: steps.seen.outputs.seen == 'false' |
| 100 | + run: | |
| 101 | + git config user.name "github-actions[bot]" |
| 102 | + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" |
| 103 | + git switch -c "$BRANCH" |
| 104 | + git commit -s -a -m "build(otp): move the desktop pin to OTP $VERSION (ADR-0014)" |
| 105 | + git push origin "$BRANCH" |
| 106 | + cat > "$RUNNER_TEMP/body.md" <<EOF |
| 107 | + Burrito can now fetch OTP $VERSION for every desktop target (the probe in this run's |
| 108 | + log), so the desktop pin in \`.tool-versions\` moves to the container's pin. |
| 109 | +
|
| 110 | + What this changes: the desktop runs an OTP with the CVE-2026-89422 fix, and |
| 111 | + \`Trinity.TLS\` stops holding its TLS clients to TLS 1.2 on its own. |
| 112 | +
|
| 113 | + Before merging, by hand: |
| 114 | + - push a commit to this branch so the gate runs (a pull request opened by a workflow |
| 115 | + starts none); |
| 116 | + - update the Erlang/OTP row's note in \`lib/trinity/versions.ex\`, then \`mix versions.gen\` |
| 117 | + (the pin itself, \`VERSIONS.md\` and \`THIRD_PARTY_LICENSES.md\` are already moved); |
| 118 | + - update the OTP lines in \`README.md\` and \`docs/packaging.md\`; |
| 119 | + - append the closing of the window to \`docs/adr/0014-otp-pins-split.md\`; |
| 120 | + - check the \`package\` workflow on all three targets. |
| 121 | + EOF |
| 122 | + gh pr create --base main --head "$BRANCH" \ |
| 123 | + --title "build(otp): move the desktop pin to OTP $VERSION" \ |
| 124 | + --body-file "$RUNNER_TEMP/body.md" |
0 commit comments