From fbc591c5bcd018e56c23f331abd61a993b818dde Mon Sep 17 00:00:00 2001 From: Teo Calin Date: Thu, 8 Oct 2026 16:28:05 +0300 Subject: [PATCH] ops: one-off rotation of io.pilot.wallet's publisher pin The key the catalogue pins for the wallet is held by no workflow, so wallet 0.4.0 (all four platforms, key recovery) could not be signed. A small command runs the same admin-gated rotation the publish-server's /admin/rotate-key does (publish.RotatePublisher, re-signed with CATALOG_SIGN_KEY), and a manual workflow runs it for io.pilot.wallet only, with the new key fixed in the file. The workflow is to be deleted once the rotation has merged. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/rotate-wallet-publisher.yml | 32 +++++++++++++++++++ cmd/rotate-publisher/main.go | 31 ++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 .github/workflows/rotate-wallet-publisher.yml create mode 100644 cmd/rotate-publisher/main.go diff --git a/.github/workflows/rotate-wallet-publisher.yml b/.github/workflows/rotate-wallet-publisher.yml new file mode 100644 index 0000000..91b1978 --- /dev/null +++ b/.github/workflows/rotate-wallet-publisher.yml @@ -0,0 +1,32 @@ +name: rotate-wallet-publisher + +# One-off, admin-approved rotation of io.pilot.wallet's publisher pin +# (2026-10-08). The key the catalogue pinned (ed25519:VF8fdEP…) is held by +# no workflow, so wallet 0.4.0 could not be signed with it. This re-points +# the pin to the new wallet key and opens the catalogue PR, re-signed with +# CATALOG_SIGN_KEY (publish.RotatePublisher, as /admin/rotate-key does). +# The app id and the key are fixed here so the workflow cannot re-pin +# anything else; delete this file once the rotation has merged. + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + rotate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - name: Rotate io.pilot.wallet's publisher pin + env: + CATALOG_PUBLISH_TOKEN: ${{ secrets.CATALOG_PUBLISH_TOKEN }} + CATALOG_SIGN_KEY: ${{ secrets.CATALOG_SIGN_KEY }} + run: | + go run ./cmd/rotate-publisher \ + -id io.pilot.wallet \ + -publisher 'ed25519:xAD0ai5GYWo8v0cmdhytZYRjSbi2edgEthWkBnO+1ik=' diff --git a/cmd/rotate-publisher/main.go b/cmd/rotate-publisher/main.go new file mode 100644 index 0000000..e785c39 --- /dev/null +++ b/cmd/rotate-publisher/main.go @@ -0,0 +1,31 @@ +// rotate-publisher re-points an app's publisher pin in the catalogue and opens +// the re-signed catalogue PR: the same admin-gated rotation the publish-server's +// /admin/rotate-key does (publish.RotatePublisher), for use from a workflow that +// holds CATALOG_PUBLISH_TOKEN and CATALOG_SIGN_KEY. +// +// rotate-publisher -id io.pilot.wallet -publisher ed25519: +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/pilot-protocol/app-template/internal/publish" +) + +func main() { + id := flag.String("id", "", "app id whose publisher pin to re-point") + pub := flag.String("publisher", "", "new publisher pin, ed25519:") + flag.Parse() + if *id == "" || *pub == "" { + fmt.Fprintln(os.Stderr, "usage: rotate-publisher -id -publisher ed25519:") + os.Exit(2) + } + url, err := publish.RotatePublisher(*id, *pub, os.Getenv("CATALOG_PUBLISH_TOKEN"), os.Getenv("CATALOG_SIGN_KEY")) + if err != nil { + fmt.Fprintln(os.Stderr, "rotate:", err) + os.Exit(1) + } + fmt.Println(url) +}