/ .github / workflows / mirror-radicle.yml
mirror-radicle.yml
  1  name: Mirror to Radicle
  2  # Mirrors every push to main → Radicle seed.radicle.garden
  3  
  4  on:
  5    push:
  6      branches: [main]
  7  
  8  jobs:
  9    mirror:
 10      runs-on: ubuntu-latest
 11      env:
 12        RAD_PASSPHRASE: ""
 13  
 14      steps:
 15        - uses: actions/checkout@v4
 16          with:
 17            fetch-depth: 0
 18  
 19        - name: Install rad CLI
 20          # To upgrade: update RAD_VERSION + RAD_SHA256 from https://files.radicle.xyz/releases/
 21          env:
 22            RAD_VERSION: 1.7.1
 23            RAD_SHA256: 37980a3b7660704007c3fa100bb6aa452ffb3cd13426fbf0f4f824f8f49bca95
 24          run: |
 25            curl -fsSL "https://files.radicle.xyz/releases/${RAD_VERSION}/radicle-${RAD_VERSION}-x86_64-unknown-linux-musl.tar.xz" \
 26              -o radicle.tar.xz
 27            echo "${RAD_SHA256}  radicle.tar.xz" | sha256sum -c
 28            tar -xJf radicle.tar.xz
 29            sudo mv radicle-*/bin/rad /usr/local/bin/rad
 30            sudo mv radicle-*/bin/radicle-node /usr/local/bin/radicle-node
 31            sudo mv radicle-*/bin/git-remote-rad /usr/local/bin/git-remote-rad
 32            rad --version
 33  
 34        - name: Set up Radicle identity
 35          env:
 36            RAD_KEYGEN_SEED: ${{ secrets.RAD_KEYGEN_SEED }}
 37          run: |
 38            rad auth --alias github-ci
 39  
 40        - name: Push to Radicle seed
 41          env:
 42            RAD_RID: ${{ secrets.RAD_RID }}
 43            RAD_COB_BUNDLE: ${{ secrets.RAD_COB_BUNDLE }}
 44          run: |
 45            trap 'kill $NODE_PID 2>/dev/null || true' EXIT
 46  
 47            # RAD_RID may include "rad:" prefix; storage dirs use just the hash
 48            RID="${RAD_RID#rad:}"
 49  
 50            # Restore COB bundle into local storage.
 51            # git bundle unbundle drops refs/namespaces/* silently; use git fetch instead.
 52            mkdir -p "${HOME}/.radicle/storage/${RID}"
 53            git -C "${HOME}/.radicle/storage/${RID}" init --bare --quiet
 54  
 55            # Seed storage with git objects first — the COB bundle uses the current HEAD
 56            # as a prerequisite for refs/heads/main (so no history objects in the bundle),
 57            # but git fetch will reject the bundle unless those objects already exist here.
 58            git -C "${HOME}/.radicle/storage/${RID}" fetch "${GITHUB_WORKSPACE}" \
 59              "+refs/heads/main:refs/tmp/bootstrap"
 60            git -C "${HOME}/.radicle/storage/${RID}" update-ref -d refs/tmp/bootstrap 2>/dev/null || true
 61  
 62            # Restore COB bundle — includes k7's refs/namespaces/.../refs/heads/main
 63            # (with prerequisite satisfied by the checkout objects above)
 64            echo "${RAD_COB_BUNDLE}" | base64 -d > /tmp/cob.bundle
 65            git -C "${HOME}/.radicle/storage/${RID}" fetch /tmp/cob.bundle \
 66              "+refs/namespaces/*:refs/namespaces/*" \
 67              "+refs/rad/*:refs/rad/*" || exit 1
 68            rm /tmp/cob.bundle
 69  
 70            echo "=== Profile check ==="
 71            CI_NID=$(rad self --nid 2>/dev/null)
 72            echo "CI NID: ${CI_NID}"
 73  
 74            echo "=== Radicle home ==="
 75            ls -la "${HOME}/.radicle/" 2>&1 || true
 76            ls -la "${HOME}/.radicle/keys/" 2>&1 || true
 77  
 78            echo "=== git-remote-rad ==="
 79            which git-remote-rad 2>&1 || true
 80            ls -la "$(which git-remote-rad 2>/dev/null)" 2>&1 || true
 81  
 82            git config --global user.name "github-ci"
 83            git config --global user.email "ci@harvest316.github.com"
 84  
 85            git remote add rad "rad://${RID}" 2>/dev/null || \
 86              git remote set-url rad "rad://${RID}"
 87            git remote set-url --push rad "rad://${RID}/${CI_NID}"
 88  
 89            # seed.radicle.garden = iris.radicle.xyz (NID from https://seed.radicle.garden/api/v1/node)
 90            SEED_NID="z6MkrLMMsiPWUcNPHcRajuMi9mDfYckSoJyPwwnknocNYPm7"
 91            git config rad.seed seed.radicle.garden
 92  
 93            radicle-node --listen 0.0.0.0:8776 &
 94            NODE_PID=$!
 95  
 96            # Wait for node to bind its port (up to 10s)
 97            for i in $(seq 1 20); do
 98              nc -z 0.0.0.0 8776 2>/dev/null && break
 99              sleep 0.5
100            done
101            nc -z 0.0.0.0 8776 2>/dev/null || { echo "radicle-node failed to start"; exit 1; }
102  
103            # Give bootstrap peers time to connect (iris must be in routing table for announce)
104            sleep 5
105  
106            echo "=== Node state ==="
107            rad node status 2>&1 || true
108            rad ls 2>&1 || true
109  
110            # Seed the repo to register it with the node (allows git-remote-rad to push)
111            rad seed "rad:${RID}" 2>&1 || true
112  
113            echo "=== Node socket ==="
114            ls -la "${HOME}/.radicle/node/" 2>&1 || true
115  
116            echo "=== Attempting git push ==="
117            RAD_HOME="${HOME}/.radicle" GIT_TRACE2_EVENT=/tmp/git-trace.json \
118              git push rad main --force 2>&1 || {
119              echo "=== git push failed, trace tail ==="
120              tail -20 /tmp/git-trace.json 2>/dev/null || true
121              exit 1
122            }
123  
124            # Announce to iris — CI runner has a public IP so iris can inbound-fetch
125            rad sync --announce --seed "${SEED_NID}"