From c17af597d26466d3f1841d88d5d208b6ed3c7b05 Mon Sep 17 00:00:00 2001 From: Stephan D Date: Mon, 10 Nov 2025 17:46:12 +0100 Subject: [PATCH] chain gateway build --- .woodpecker/chain_gateway.yml | 74 +++++++++++ ci/prod/.env.runtime | 14 +++ ci/prod/compose/chain_gateway.dockerfile | 40 ++++++ ci/prod/compose/chain_gateway.yml | 49 ++++++++ ci/prod/scripts/deploy/chain_gateway.sh | 150 +++++++++++++++++++++++ ci/scripts/chain_gateway/build-image.sh | 85 +++++++++++++ ci/scripts/chain_gateway/deploy.sh | 66 ++++++++++ 7 files changed, 478 insertions(+) create mode 100644 .woodpecker/chain_gateway.yml create mode 100644 ci/prod/compose/chain_gateway.dockerfile create mode 100644 ci/prod/compose/chain_gateway.yml create mode 100644 ci/prod/scripts/deploy/chain_gateway.sh create mode 100644 ci/scripts/chain_gateway/build-image.sh create mode 100644 ci/scripts/chain_gateway/deploy.sh diff --git a/.woodpecker/chain_gateway.yml b/.woodpecker/chain_gateway.yml new file mode 100644 index 0000000..d27f59b --- /dev/null +++ b/.woodpecker/chain_gateway.yml @@ -0,0 +1,74 @@ +matrix: + include: + - CHAIN_GATEWAY_IMAGE_PATH: chain/gateway + CHAIN_GATEWAY_DOCKERFILE: ci/prod/compose/chain_gateway.dockerfile + CHAIN_GATEWAY_MONGO_SECRET_PATH: sendico/db + CHAIN_GATEWAY_RUNTIME_SECRET_PATH: sendico/chain/gateway + CHAIN_GATEWAY_ENV: prod + +when: + - event: push + branch: main + +steps: + - name: version + image: alpine:latest + commands: + - set -euo pipefail 2>/dev/null || set -eu + - apk add --no-cache git + - GIT_REV="$(git rev-parse --short HEAD)" + - BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)" + - APP_V="$(cat version)" + - BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)" + - BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}" + - printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \ + "$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version + + - name: proto + image: golang:alpine + depends_on: [ version ] + commands: + - set -eu + - apk add --no-cache bash git build-base protoc protobuf-dev + - go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + - go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + - export PATH="$(go env GOPATH)/bin:$PATH" + - bash ci/scripts/proto/generate.sh + + - name: secrets + image: alpine:latest + depends_on: [ version ] + environment: + VAULT_ADDR: { from_secret: VAULT_ADDR } + VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE } + VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID } + commands: + - set -euo pipefail + - apk add --no-cache bash coreutils openssh-keygen curl sed python3 + - mkdir -p secrets + - ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600 + - base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY + - chmod 600 secrets/SSH_KEY + - ssh-keygen -y -f secrets/SSH_KEY >/dev/null + - ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER + - ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD + + - name: build-image + image: gcr.io/kaniko-project/executor:debug + depends_on: [ proto, secrets ] + commands: + - sh ci/scripts/chain_gateway/build-image.sh + + - name: deploy + image: alpine:latest + depends_on: [ secrets, build-image ] + environment: + VAULT_ADDR: { from_secret: VAULT_ADDR } + VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE } + VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID } + commands: + - set -euo pipefail + - apk add --no-cache bash openssh-client rsync coreutils curl sed python3 + - mkdir -p /root/.ssh + - install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa + - sh ci/scripts/chain_gateway/deploy.sh diff --git a/ci/prod/.env.runtime b/ci/prod/.env.runtime index 57bbf67..e623026 100644 --- a/ci/prod/.env.runtime +++ b/ci/prod/.env.runtime @@ -59,3 +59,17 @@ FEES_MONGO_PORT=27017 FEES_MONGO_DATABASE=billing_fees FEES_MONGO_AUTH_SOURCE=admin FEES_MONGO_REPLICA_SET=sendico-rs + +# Chain gateway stack +CHAIN_GATEWAY_DIR=chain_gateway +CHAIN_GATEWAY_COMPOSE_PROJECT=sendico-chain-gateway +CHAIN_GATEWAY_SERVICE_NAME=sendico_chain_gateway +CHAIN_GATEWAY_GRPC_PORT=50070 +CHAIN_GATEWAY_METRICS_PORT=9403 + +# Chain gateway Mongo settings +CHAIN_GATEWAY_MONGO_HOST=sendico_db1 +CHAIN_GATEWAY_MONGO_PORT=27017 +CHAIN_GATEWAY_MONGO_DATABASE=chain_gateway +CHAIN_GATEWAY_MONGO_AUTH_SOURCE=admin +CHAIN_GATEWAY_MONGO_REPLICA_SET=sendico-rs diff --git a/ci/prod/compose/chain_gateway.dockerfile b/ci/prod/compose/chain_gateway.dockerfile new file mode 100644 index 0000000..bcd4e38 --- /dev/null +++ b/ci/prod/compose/chain_gateway.dockerfile @@ -0,0 +1,40 @@ +# syntax=docker/dockerfile:1.7 + +ARG TARGETOS=linux +ARG TARGETARCH=amd64 + +FROM golang:alpine AS build +ARG APP_VERSION=dev +ARG GIT_REV=unknown +ARG BUILD_BRANCH=unknown +ARG BUILD_DATE=unknown +ARG BUILD_USER=ci +ENV GO111MODULE=on +ENV PATH="/go/bin:${PATH}" +WORKDIR /src +COPY . . +RUN apk add --no-cache bash git build-base protoc protobuf-dev \ + && go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \ + && go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \ + && bash ci/scripts/proto/generate.sh +WORKDIR /src/api/chain/gateway +RUN --mount=type=cache,target=/root/.cache/go-build \ + --mount=type=cache,target=/go/pkg/mod \ + CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \ + go build -trimpath -ldflags "\ + -s -w \ + -X github.com/tech/sendico/chain/gateway/internal/appversion.Version=${APP_VERSION} \ + -X github.com/tech/sendico/chain/gateway/internal/appversion.Revision=${GIT_REV} \ + -X github.com/tech/sendico/chain/gateway/internal/appversion.Branch=${BUILD_BRANCH} \ + -X github.com/tech/sendico/chain/gateway/internal/appversion.BuildUser=${BUILD_USER} \ + -X github.com/tech/sendico/chain/gateway/internal/appversion.BuildDate=${BUILD_DATE}" \ + -o /out/chain-gateway . + +FROM alpine:latest AS runtime +RUN apk add --no-cache ca-certificates tzdata wget +WORKDIR /app +COPY api/chain/gateway/config.yml /app/config.yml +COPY --from=build /out/chain-gateway /app/chain-gateway +EXPOSE 50070 9403 +ENTRYPOINT ["/app/chain-gateway"] +CMD ["--config.file", "/app/config.yml"] diff --git a/ci/prod/compose/chain_gateway.yml b/ci/prod/compose/chain_gateway.yml new file mode 100644 index 0000000..546a3c5 --- /dev/null +++ b/ci/prod/compose/chain_gateway.yml @@ -0,0 +1,49 @@ +# Compose v2 - Chain gateway + +x-common-env: &common-env + env_file: + - ../env/.env.runtime + - ../env/.env.version + +networks: + sendico-net: + external: true + name: sendico-net + +services: + sendico_chain_gateway: + <<: *common-env + container_name: sendico-chain-gateway + restart: unless-stopped + image: ${REGISTRY_URL}/chain/gateway:${APP_V} + pull_policy: always + environment: + CHAIN_GATEWAY_MONGO_HOST: ${CHAIN_GATEWAY_MONGO_HOST} + CHAIN_GATEWAY_MONGO_PORT: ${CHAIN_GATEWAY_MONGO_PORT} + CHAIN_GATEWAY_MONGO_DATABASE: ${CHAIN_GATEWAY_MONGO_DATABASE} + CHAIN_GATEWAY_MONGO_USER: ${CHAIN_GATEWAY_MONGO_USER} + CHAIN_GATEWAY_MONGO_PASSWORD: ${CHAIN_GATEWAY_MONGO_PASSWORD} + CHAIN_GATEWAY_MONGO_AUTH_SOURCE: ${CHAIN_GATEWAY_MONGO_AUTH_SOURCE} + CHAIN_GATEWAY_MONGO_REPLICA_SET: ${CHAIN_GATEWAY_MONGO_REPLICA_SET} + CHAIN_GATEWAY_GRPC_PORT: ${CHAIN_GATEWAY_GRPC_PORT} + CHAIN_GATEWAY_METRICS_PORT: ${CHAIN_GATEWAY_METRICS_PORT} + CHAIN_GATEWAY_ARBITRUM_RPC_URL: ${CHAIN_GATEWAY_ARBITRUM_RPC_URL} + CHAIN_GATEWAY_SERVICE_WALLET_KEY: ${CHAIN_GATEWAY_SERVICE_WALLET_KEY} + CHAIN_GATEWAY_VAULT_TOKEN: ${CHAIN_GATEWAY_VAULT_TOKEN} + NATS_URL: ${NATS_URL} + NATS_HOST: ${NATS_HOST} + NATS_PORT: ${NATS_PORT} + NATS_USER: ${NATS_USER} + NATS_PASSWORD: ${NATS_PASSWORD} + command: ["--config.file", "/app/config.yml"] + ports: + - "0.0.0.0:${CHAIN_GATEWAY_GRPC_PORT}:50070" + - "0.0.0.0:${CHAIN_GATEWAY_METRICS_PORT}:${CHAIN_GATEWAY_METRICS_PORT}" + healthcheck: + test: ["CMD-SHELL","wget -qO- http://localhost:${CHAIN_GATEWAY_METRICS_PORT}/health | grep -q '\"status\":\"ok\"'"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s + networks: + - sendico-net diff --git a/ci/prod/scripts/deploy/chain_gateway.sh b/ci/prod/scripts/deploy/chain_gateway.sh new file mode 100644 index 0000000..d472b9f --- /dev/null +++ b/ci/prod/scripts/deploy/chain_gateway.sh @@ -0,0 +1,150 @@ +#!/usr/bin/env bash +set -euo pipefail +[[ "${DEBUG_DEPLOY:-0}" = "1" ]] && set -x +trap 'echo "[deploy-chain-gateway] error at line $LINENO" >&2' ERR + +: "${REMOTE_BASE:?missing REMOTE_BASE}" +: "${SSH_USER:?missing SSH_USER}" +: "${SSH_HOST:?missing SSH_HOST}" +: "${CHAIN_GATEWAY_DIR:?missing CHAIN_GATEWAY_DIR}" +: "${CHAIN_GATEWAY_COMPOSE_PROJECT:?missing CHAIN_GATEWAY_COMPOSE_PROJECT}" +: "${CHAIN_GATEWAY_SERVICE_NAME:?missing CHAIN_GATEWAY_SERVICE_NAME}" + +REMOTE_DIR="${REMOTE_BASE%/}/${CHAIN_GATEWAY_DIR}" +REMOTE_TARGET="${SSH_USER}@${SSH_HOST}" +COMPOSE_FILE="chain_gateway.yml" +SERVICE_NAMES="${CHAIN_GATEWAY_SERVICE_NAME}" + +REQUIRED_SECRETS=( + CHAIN_GATEWAY_MONGO_USER + CHAIN_GATEWAY_MONGO_PASSWORD + NATS_USER + NATS_PASSWORD + NATS_URL + CHAIN_GATEWAY_ARBITRUM_RPC_URL + CHAIN_GATEWAY_SERVICE_WALLET_KEY + CHAIN_GATEWAY_VAULT_TOKEN +) + +for var in "${REQUIRED_SECRETS[@]}"; do + if [[ -z "${!var:-}" ]]; then + echo "missing required secret env: ${var}" >&2 + exit 65 + fi +done + +if [[ ! -s .env.version ]]; then + echo ".env.version is missing; run version step first" >&2 + exit 66 +fi + +b64enc() { + printf '%s' "$1" | base64 | tr -d '\n' +} + +CHAIN_GATEWAY_MONGO_USER_B64="$(b64enc "${CHAIN_GATEWAY_MONGO_USER}")" +CHAIN_GATEWAY_MONGO_PASSWORD_B64="$(b64enc "${CHAIN_GATEWAY_MONGO_PASSWORD}")" +NATS_USER_B64="$(b64enc "${NATS_USER}")" +NATS_PASSWORD_B64="$(b64enc "${NATS_PASSWORD}")" +NATS_URL_B64="$(b64enc "${NATS_URL}")" +CHAIN_GATEWAY_ARBITRUM_RPC_URL_B64="$(b64enc "${CHAIN_GATEWAY_ARBITRUM_RPC_URL}")" +CHAIN_GATEWAY_SERVICE_WALLET_KEY_B64="$(b64enc "${CHAIN_GATEWAY_SERVICE_WALLET_KEY}")" +CHAIN_GATEWAY_VAULT_TOKEN_B64="$(b64enc "${CHAIN_GATEWAY_VAULT_TOKEN}")" + +SSH_OPTS=( + -i /root/.ssh/id_rsa + -o StrictHostKeyChecking=no + -o UserKnownHostsFile=/dev/null + -o LogLevel=ERROR + -q +) +if [[ "${DEBUG_DEPLOY:-0}" = "1" ]]; then + SSH_OPTS=("${SSH_OPTS[@]/-q/}" -vv) +fi + +RSYNC_FLAGS=(-az --delete) +[[ "${DEBUG_DEPLOY:-0}" = "1" ]] && RSYNC_FLAGS=(-avz --delete) + +ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" "mkdir -p ${REMOTE_DIR}/{compose,env}" + +rsync "${RSYNC_FLAGS[@]}" -e "ssh ${SSH_OPTS[*]}" ci/prod/compose/ "$REMOTE_TARGET:${REMOTE_DIR}/compose/" +rsync "${RSYNC_FLAGS[@]}" -e "ssh ${SSH_OPTS[*]}" ci/prod/.env.runtime "$REMOTE_TARGET:${REMOTE_DIR}/env/.env.runtime" +rsync "${RSYNC_FLAGS[@]}" -e "ssh ${SSH_OPTS[*]}" .env.version "$REMOTE_TARGET:${REMOTE_DIR}/env/.env.version" + +SERVICES_LINE="${SERVICE_NAMES}" + +ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" \ + REMOTE_DIR="$REMOTE_DIR" \ + COMPOSE_FILE="$COMPOSE_FILE" \ + COMPOSE_PROJECT="$CHAIN_GATEWAY_COMPOSE_PROJECT" \ + SERVICES_LINE="$SERVICES_LINE" \ + CHAIN_GATEWAY_MONGO_USER_B64="$CHAIN_GATEWAY_MONGO_USER_B64" \ + CHAIN_GATEWAY_MONGO_PASSWORD_B64="$CHAIN_GATEWAY_MONGO_PASSWORD_B64" \ + NATS_USER_B64="$NATS_USER_B64" \ + NATS_PASSWORD_B64="$NATS_PASSWORD_B64" \ + NATS_URL_B64="$NATS_URL_B64" \ + CHAIN_GATEWAY_ARBITRUM_RPC_URL_B64="$CHAIN_GATEWAY_ARBITRUM_RPC_URL_B64" \ + CHAIN_GATEWAY_SERVICE_WALLET_KEY_B64="$CHAIN_GATEWAY_SERVICE_WALLET_KEY_B64" \ + CHAIN_GATEWAY_VAULT_TOKEN_B64="$CHAIN_GATEWAY_VAULT_TOKEN_B64" \ + bash -s <<'EOSSH' +set -euo pipefail +cd "${REMOTE_DIR}/compose" +set -a +. ../env/.env.runtime +. ../env/.env.version +set +a + +if base64 -d >/dev/null 2>&1 <<<'AA=='; then + BASE64_DECODE_FLAG='-d' +else + BASE64_DECODE_FLAG='--decode' +fi + +decode_b64() { + val="$1" + if [[ -z "$val" ]]; then + printf '' + return + fi + printf '%s' "$val" | base64 "${BASE64_DECODE_FLAG}" +} + +CHAIN_GATEWAY_MONGO_USER="$(decode_b64 "$CHAIN_GATEWAY_MONGO_USER_B64")" +CHAIN_GATEWAY_MONGO_PASSWORD="$(decode_b64 "$CHAIN_GATEWAY_MONGO_PASSWORD_B64")" +NATS_USER="$(decode_b64 "$NATS_USER_B64")" +NATS_PASSWORD="$(decode_b64 "$NATS_PASSWORD_B64")" +NATS_URL="$(decode_b64 "$NATS_URL_B64")" +CHAIN_GATEWAY_ARBITRUM_RPC_URL="$(decode_b64 "$CHAIN_GATEWAY_ARBITRUM_RPC_URL_B64")" +CHAIN_GATEWAY_SERVICE_WALLET_KEY="$(decode_b64 "$CHAIN_GATEWAY_SERVICE_WALLET_KEY_B64")" +CHAIN_GATEWAY_VAULT_TOKEN="$(decode_b64 "$CHAIN_GATEWAY_VAULT_TOKEN_B64")" + +export \ + CHAIN_GATEWAY_MONGO_USER \ + CHAIN_GATEWAY_MONGO_PASSWORD \ + NATS_USER \ + NATS_PASSWORD \ + NATS_URL \ + CHAIN_GATEWAY_ARBITRUM_RPC_URL \ + CHAIN_GATEWAY_SERVICE_WALLET_KEY \ + CHAIN_GATEWAY_VAULT_TOKEN + +COMPOSE_PROJECT_NAME="$COMPOSE_PROJECT" +export COMPOSE_PROJECT_NAME +read -r -a SERVICES <<<"${SERVICES_LINE}" + +pull_cmd=(docker compose -f "$COMPOSE_FILE" pull) +up_cmd=(docker compose -f "$COMPOSE_FILE" up -d --remove-orphans) +ps_cmd=(docker compose -f "$COMPOSE_FILE" ps) +if [[ "${#SERVICES[@]}" -gt 0 ]]; then + pull_cmd+=("${SERVICES[@]}") + up_cmd+=("${SERVICES[@]}") + ps_cmd+=("${SERVICES[@]}") +fi + +"${pull_cmd[@]}" +"${up_cmd[@]}" +"${ps_cmd[@]}" + +date -Is > .last_deploy +logger -t "deploy-${COMPOSE_PROJECT_NAME}" "${COMPOSE_PROJECT_NAME} deployed at $(date -Is) in ${REMOTE_DIR}" +EOSSH diff --git a/ci/scripts/chain_gateway/build-image.sh b/ci/scripts/chain_gateway/build-image.sh new file mode 100644 index 0000000..ed90ca6 --- /dev/null +++ b/ci/scripts/chain_gateway/build-image.sh @@ -0,0 +1,85 @@ +#!/bin/sh +set -eu + +if ! set -o pipefail 2>/dev/null; then + : +fi + +REPO_ROOT="$(cd "$(dirname "$0")/../../.." && pwd)" +cd "${REPO_ROOT}" + +sh ci/scripts/common/ensure_env_version.sh + +normalize_env_file() { + file="$1" + tmp="${file}.tmp.$$" + tr -d '\r' <"$file" >"$tmp" + mv "$tmp" "$file" +} + +load_env_file() { + file="$1" + while IFS= read -r line || [ -n "$line" ]; do + case "$line" in + ''|\#*) continue ;; + esac + key="${line%%=*}" + value="${line#*=}" + key="$(printf '%s' "$key" | tr -d '[:space:]')" + value="${value#"${value%%[![:space:]]*}"}" + value="${value%"${value##*[![:space:]]}"}" + export "$key=$value" + done <"$file" +} + +CHAIN_GATEWAY_ENV_NAME="${CHAIN_GATEWAY_ENV:-prod}" +RUNTIME_ENV_FILE="./ci/${CHAIN_GATEWAY_ENV_NAME}/.env.runtime" + +if [ ! -f "${RUNTIME_ENV_FILE}" ]; then + echo "[chain-gateway-build] runtime env file not found: ${RUNTIME_ENV_FILE}" >&2 + exit 1 +fi + +normalize_env_file "${RUNTIME_ENV_FILE}" +normalize_env_file ./.env.version + +load_env_file "${RUNTIME_ENV_FILE}" +load_env_file ./.env.version + +REGISTRY_URL="${REGISTRY_URL:?missing REGISTRY_URL}" +APP_V="${APP_V:?missing APP_V}" +CHAIN_GATEWAY_DOCKERFILE="${CHAIN_GATEWAY_DOCKERFILE:?missing CHAIN_GATEWAY_DOCKERFILE}" +CHAIN_GATEWAY_IMAGE_PATH="${CHAIN_GATEWAY_IMAGE_PATH:?missing CHAIN_GATEWAY_IMAGE_PATH}" + +REGISTRY_HOST="${REGISTRY_URL#http://}" +REGISTRY_HOST="${REGISTRY_HOST#https://}" +REGISTRY_USER="$(cat secrets/REGISTRY_USER)" +REGISTRY_PASSWORD="$(cat secrets/REGISTRY_PASSWORD)" +: "${REGISTRY_USER:?missing registry user}" +: "${REGISTRY_PASSWORD:?missing registry password}" + +mkdir -p /kaniko/.docker +AUTH_B64="$(printf '%s:%s' "$REGISTRY_USER" "$REGISTRY_PASSWORD" | base64 | tr -d '\n')" +cat </kaniko/.docker/config.json +{ + "auths": { + "https://${REGISTRY_HOST}": { "auth": "${AUTH_B64}" } + } +} +EOF + +BUILD_CONTEXT="${CHAIN_GATEWAY_BUILD_CONTEXT:-${WOODPECKER_WORKSPACE:-${CI_WORKSPACE:-${PWD:-/workspace}}}}" +if [ ! -d "${BUILD_CONTEXT}" ]; then + BUILD_CONTEXT="/workspace" +fi + +/kaniko/executor \ + --context "${BUILD_CONTEXT}" \ + --dockerfile "${CHAIN_GATEWAY_DOCKERFILE}" \ + --destination "${REGISTRY_URL}/${CHAIN_GATEWAY_IMAGE_PATH}:${APP_V}" \ + --build-arg APP_VERSION="${APP_V}" \ + --build-arg GIT_REV="${GIT_REV}" \ + --build-arg BUILD_BRANCH="${BUILD_BRANCH}" \ + --build-arg BUILD_DATE="${BUILD_DATE}" \ + --build-arg BUILD_USER="${BUILD_USER}" \ + --single-snapshot diff --git a/ci/scripts/chain_gateway/deploy.sh b/ci/scripts/chain_gateway/deploy.sh new file mode 100644 index 0000000..20b99be --- /dev/null +++ b/ci/scripts/chain_gateway/deploy.sh @@ -0,0 +1,66 @@ +#!/bin/sh +set -eu + +if ! set -o pipefail 2>/dev/null; then + : +fi + +REPO_ROOT="$(cd "$(dirname "$0")/../../.." && pwd)" +cd "${REPO_ROOT}" + +sh ci/scripts/common/ensure_env_version.sh + +normalize_env_file() { + file="$1" + tmp="${file}.tmp.$$" + tr -d '\r' <"$file" >"$tmp" + mv "$tmp" "$file" +} + +load_env_file() { + file="$1" + while IFS= read -r line || [ -n "$line" ]; do + case "$line" in + ''|\#*) continue ;; + esac + key="${line%%=*}" + value="${line#*=}" + key="$(printf '%s' "$key" | tr -d '[:space:]')" + value="${value#"${value%%[![:space:]]*}"}" + value="${value%"${value##*[![:space:]]}"}" + export "$key=$value" + done <"$file" +} + +CHAIN_GATEWAY_ENV_NAME="${CHAIN_GATEWAY_ENV:-prod}" +RUNTIME_ENV_FILE="./ci/${CHAIN_GATEWAY_ENV_NAME}/.env.runtime" + +if [ ! -f "${RUNTIME_ENV_FILE}" ]; then + echo "[chain-gateway-deploy] runtime env file not found: ${RUNTIME_ENV_FILE}" >&2 + exit 1 +fi + +normalize_env_file "${RUNTIME_ENV_FILE}" +normalize_env_file ./.env.version + +load_env_file "${RUNTIME_ENV_FILE}" +load_env_file ./.env.version + +CHAIN_GATEWAY_MONGO_SECRET_PATH="${CHAIN_GATEWAY_MONGO_SECRET_PATH:?missing CHAIN_GATEWAY_MONGO_SECRET_PATH}" +CHAIN_GATEWAY_RUNTIME_SECRET_PATH="${CHAIN_GATEWAY_RUNTIME_SECRET_PATH:?missing CHAIN_GATEWAY_RUNTIME_SECRET_PATH}" +: "${NATS_HOST:?missing NATS_HOST}" +: "${NATS_PORT:?missing NATS_PORT}" + +export CHAIN_GATEWAY_MONGO_USER="$(./ci/vlt kv_get kv "${CHAIN_GATEWAY_MONGO_SECRET_PATH}" user)" +export CHAIN_GATEWAY_MONGO_PASSWORD="$(./ci/vlt kv_get kv "${CHAIN_GATEWAY_MONGO_SECRET_PATH}" password)" + +export NATS_USER="$(./ci/vlt kv_get kv sendico/nats user)" +export NATS_PASSWORD="$(./ci/vlt kv_get kv sendico/nats password)" +export NATS_URL="nats://${NATS_USER}:${NATS_PASSWORD}@${NATS_HOST}:${NATS_PORT}" + +export CHAIN_GATEWAY_ARBITRUM_RPC_URL="$(./ci/vlt kv_get kv "${CHAIN_GATEWAY_RUNTIME_SECRET_PATH}" arbitrum_rpc_url)" +export CHAIN_GATEWAY_SERVICE_WALLET_KEY="$(./ci/vlt kv_get kv "${CHAIN_GATEWAY_RUNTIME_SECRET_PATH}" service_wallet_key)" +export CHAIN_GATEWAY_VAULT_TOKEN="$(./ci/vlt kv_get kv "${CHAIN_GATEWAY_RUNTIME_SECRET_PATH}" vault_token)" + +bash ci/prod/scripts/bootstrap/network.sh +bash ci/prod/scripts/deploy/chain_gateway.sh