From 2572efe6dcba44831bfd03ac7dc5e527216c809f Mon Sep 17 00:00:00 2001 From: Not Darko <93942788+darkobas2@users.noreply.github.com> Date: Wed, 26 Aug 2026 20:20:01 +0200 Subject: [PATCH] ci: add Batch Sync workflow skeleton Adds a manually-triggered Batch Sync workflow exposing every batch-export flag as a typed input: start/end block, max requests per second, block range limit, output path, compression and verbosity. The job runs on the self-hosted bee runners, whose egress addresses are inside the RPC provider's allowlist, so no credential is needed there. If it is ever moved to a hosted runner the endpoint requires HTTP Basic auth, so the Compose endpoint step builds an authenticated URL when a user and password are available and falls back to the bare URL when they are not. The composed value is masked and passed through the environment rather than echoed, and the endpoint itself comes from a secret so no infrastructure hostname is committed here. The final sync step is deliberately a failing TODO: the export half is runnable, but the publish destination has not been decided yet. --- .github/workflows/batch-sync.yml | 127 +++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 .github/workflows/batch-sync.yml diff --git a/.github/workflows/batch-sync.yml b/.github/workflows/batch-sync.yml new file mode 100644 index 0000000..1ba2563 --- /dev/null +++ b/.github/workflows/batch-sync.yml @@ -0,0 +1,127 @@ +name: Batch Sync + +# Skeleton. The export step below is wired and runnable; the "sync" step that +# publishes the artifact is intentionally left as a TODO — fill it in once the +# destination is decided. +# +# Runner: the self-hosted `bee` runners are inside the RPC's network allowlist, +# so they reach the endpoint without credentials. If this is ever moved to a +# GitHub-hosted runner, the endpoint requires HTTP Basic auth — see the +# "Compose endpoint" step. + +on: + workflow_dispatch: + inputs: + start_block: + description: "Start block (0 = contract start block)" + required: true + default: "31306381" + type: string + end_block: + description: "End block (0 = latest)" + required: true + default: "0" + type: string + max_request: + description: "Max RPC requests per second" + required: true + default: "15" + type: string + block_range_limit: + description: "Max blocks per eth_getLogs query (keep low; large ranges can OOM the node)" + required: true + default: "5" + type: string + output: + description: "Output file path (NDJSON)" + required: true + default: "export.ndjson" + type: string + compress: + description: "Compress output to GZIP" + required: true + default: false + type: boolean + verbosity: + description: "Log verbosity" + required: true + default: "info" + type: choice + options: [silent, error, warn, info, debug] + + # Uncomment to run on a schedule once the sync destination is wired up. + # schedule: + # - cron: "0 3 * * *" + +permissions: + contents: read + +concurrency: + group: batch-sync + cancel-in-progress: false + +jobs: + sync: + name: Export and sync + runs-on: [self-hosted, linux, bee] + timeout-minutes: 120 + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Go + uses: actions/setup-go@v6 + with: + cache: true + go-version-file: go.mod + + # `make binary` (not `make build`) is the target that emits dist/batch-export; + # `make build` only runs `go build ./...` and produces no artifact. + - name: Build + run: make binary + + # The bare URL works from the self-hosted runners because their egress IPs + # are allowlisted. USER/PASSWORD are only needed off-allowlist; when they + # are absent the bare URL is used unchanged. Secrets are masked in logs, + # and the composed value is written to GITHUB_ENV rather than echoed. + - name: Compose endpoint + env: + RPC_URL: ${{ secrets.PRIVATE_GNOSIS_RPC_URL }} + RPC_USER: ${{ secrets.GNOSIS_RPC_USER }} + RPC_PASSWORD: ${{ secrets.GNOSIS_RPC_PASSWORD }} + run: | + set -euo pipefail + if [ -z "${RPC_URL}" ]; then + echo "::error::PRIVATE_GNOSIS_RPC_URL is not set for this repository" + exit 1 + fi + if [ -n "${RPC_USER}" ] && [ -n "${RPC_PASSWORD}" ]; then + # Insert credentials after the scheme without printing the result. + endpoint="$(printf '%s' "${RPC_URL}" \ + | sed -E "s#^(https?://)#\1${RPC_USER}:${RPC_PASSWORD}@#")" + echo "using authenticated endpoint" + else + endpoint="${RPC_URL}" + echo "using unauthenticated endpoint (runner is inside the allowlist)" + fi + echo "::add-mask::${endpoint}" + echo "RPC_ENDPOINT=${endpoint}" >> "${GITHUB_ENV}" + + - name: Export + run: | + set -euo pipefail + ./dist/batch-export export \ + --endpoint "${RPC_ENDPOINT}" \ + --start "${{ inputs.start_block }}" \ + --end "${{ inputs.end_block }}" \ + --max-request "${{ inputs.max_request }}" \ + --block-range-limit "${{ inputs.block_range_limit }}" \ + --output "${{ inputs.output }}" \ + --verbosity "${{ inputs.verbosity }}" \ + ${{ inputs.compress && '--compress' || '' }} + + - name: Sync + run: | + echo "TODO: publish ${{ inputs.output }} to its destination." + exit 1