Zálohovanie služieb cez GitHub Actions sa mi už stalo trochu zvykom. Existuje jedno pre faktury-online.com, jedno pre Bitwarden a jedno pre Cloudflare. Tentoraz je na rade Resend, emailová služba, ktorú používam na transakčné emaily.

Nápad je vždy rovnaký: zavolaj API, ulož všetko do JSON súborov a výsledok commitni do súkromného repozitára podľa rozvrhu. Čo sa zálohovuje tentoraz:

  • domény
  • API kľúče (názvy a ID, nie samotné tajné hodnoty)
  • audiences a kontakty podľa audience
  • kontakty (plochý zoznam)
  • webhooky
  • broadcasts
  • šablóny
  • topics
  • vlastnosti kontaktov
  • segmenty a kontakty podľa segmentu

Samotný workflow zostáva čistý, pretože všetka logika žije v backup.sh:

name: Resend Backup

on:
  workflow_dispatch:
  schedule:
    - cron: "20 3 * * 0"

jobs:
  backup:
    runs-on: ubuntu-24.04

    permissions:
      contents: write

    env:
      RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}

    steps:
      - uses: actions/checkout@v6

      - run: ./backup.sh

      - uses: stefanzweifel/git-auto-commit-action@v7

Skript spracováva stránkovanie založené na kurzore, takže stiahne všetko bez ohľadu na to, koľko položiek máš. Kľúčová časť je malá pomocná funkcia, ktorá sa opakuje, kým nie sú žiadne ďalšie stránky:

fetch_all() {
  local endpoint="$1"
  local results="[]"
  local after=""

  while true; do
    if [ -n "$after" ]; then
      query="?limit=100&after=$after"
    else
      query="?limit=100"
    fi

    response=$(curl -s -X GET "https://api.resend.com${endpoint}${query}" \
      -H "Authorization: Bearer $RESEND_API_KEY" \
      -H "Content-Type: application/json")

    data=$(echo "$response" | jq '.data // []')
    results=$(printf '%s\n%s' "$results" "$data" | jq -s 'add')

    has_more=$(echo "$response" | jq -r '.has_more // false')
    [ "$has_more" != "true" ] && break

    after=$(echo "$response" | jq -r '.data[-1].id')
  done

  echo "$results"
}

Všetky zdroje potom nasledujú rovnaký vzor. Audiences a segmenty majú kontakty stiahnuté jednotlivo v cykle:

audiences=$(fetch_all "/audiences")
echo "$audiences" | jq > audiences.json

audience_ids=$(echo "$audiences" | jq -r '.[].id // empty')
for audience_id in $audience_ids; do
  fetch_all "/audiences/$audience_id/contacts" | jq > "contacts/$audience_id.json"
done

Inštrukcie #

  1. Získaj Resend API kľúč
  2. Pridaj ho do svojho Github repozitára ako secret s názvom RESEND_API_KEY
  3. Povol Github Actions oprávnenia na zápis, keďže táto akcia vytvára automatické commity
  4. Záloha sa spúšťa každú nedeľu skoro ráno, podľa potreby uprav schedule v .github/workflows/main.yml

Resend API kľúč #

Jedna vec stojí za zmienku: Resend neponúka API kľúče len na čítanie. Každý kľúč má plný prístup. Workflow robí len GET požiadavky, ale kľúč samotný je technicky schopný viac. Oplatí sa na to pamätať pri jeho ukladaní.

Postup vytvorenia Resend API kľúča:

  1. Prihlás sa na https://resend.com/
  2. V ľavom postrannom paneli klikni na “API Keys”
  3. Klikni na “Create API Key”
  4. Zadaj opisný názov, napríklad “Backup”
  5. Oprávnenie nechaj na “Full access” — možnosť len na čítanie neexistuje
  6. Voliteľne obmedzuj na konkrétnu doménu
  7. Klikni na “Add” a okamžite skopíruj kľúč (zobrazí sa len raz)

Pridávanie Github Secrets #

  1. Prejdi do svojho Github repozitára → “Settings”
  2. V ľavom postrannom paneli: “Secrets and variables” → “Actions”
  3. Klikni na “New repository secret”:
  • Názov: RESEND_API_KEY
  • Hodnota: tvoj Resend API kľúč
  1. Klikni na “Add secret”

Povolenie oprávnení na zápis pre Github Actions #

  1. Prejdi do svojho Github repozitára → “Settings”
  2. “Actions” pod “Code and automation” → “Workflow permissions”
  3. Vyber “Read and write permissions”
  4. Klikni na “Save”

Lokálny vývoj #

Nainštaluj nektos/act:

brew install act

Získaj fine-grained Personal Access Token, potom:

cp .secrets.example .secrets

Vyplň RESEND_API_KEY aj GITHUB_TOKEN, potom spusti:

act workflow_dispatch --no-skip-checkout

Ak spúšťaš act prvýkrát, preferovane vyber Medium Docker image (500 MB).

Vytvorenie fine-grained Personal Access Token #

  1. Github → profilová fotka → “Settings” → “Developer settings”
  2. “Personal access tokens” → “Fine-grained tokens” → “Generate new token”
  3. Zadaj názov, nastav platnosť, vyber tento repozitár pod “Repository access”
  4. Pod “Repository permissions” nastav “Contents” na “Read and write”, všetko ostatné nechaj na “No access”
  5. Vygeneruj a okamžite skopíruj

GITHUB_TOKEN je automaticky injektovaný pri spúšťaní na Github. Lokálne pre act ho potrebuješ vyplniť ručne. Nech sa darí!

Odkazy #