From 9d4872c88f45ee3f254f0ebc7eb53e13622ff28b Mon Sep 17 00:00:00 2001 From: harshsingh1002 <1002.harshsingh@gmail.com> Date: Thu, 24 Jul 2025 14:45:19 +0200 Subject: [PATCH 1/2] feat: add mev-commit bridge chart --- .../charts/mev-commit-bridge/Chart.yaml | 6 + .../scripts/keystore-init.sh | 224 ++++++++++++++++++ .../mev-commit-bridge/templates/_helpers.tpl | 52 ++++ .../templates/configmap.yaml | 12 + .../templates/deployment.yaml | 113 +++++++++ .../templates/externalsecret.yaml | 30 +++ .../mev-commit-bridge/templates/secret.yaml | 10 + .../mev-commit-bridge/templates/service.yaml | 15 ++ .../charts/mev-commit-bridge/values.yaml | 74 ++++++ 9 files changed, 536 insertions(+) create mode 100644 infrastructure/charts/mev-commit-bridge/Chart.yaml create mode 100644 infrastructure/charts/mev-commit-bridge/scripts/keystore-init.sh create mode 100644 infrastructure/charts/mev-commit-bridge/templates/_helpers.tpl create mode 100644 infrastructure/charts/mev-commit-bridge/templates/configmap.yaml create mode 100644 infrastructure/charts/mev-commit-bridge/templates/deployment.yaml create mode 100644 infrastructure/charts/mev-commit-bridge/templates/externalsecret.yaml create mode 100644 infrastructure/charts/mev-commit-bridge/templates/secret.yaml create mode 100644 infrastructure/charts/mev-commit-bridge/templates/service.yaml create mode 100644 infrastructure/charts/mev-commit-bridge/values.yaml diff --git a/infrastructure/charts/mev-commit-bridge/Chart.yaml b/infrastructure/charts/mev-commit-bridge/Chart.yaml new file mode 100644 index 000000000..ff34989fc --- /dev/null +++ b/infrastructure/charts/mev-commit-bridge/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: bridge-relayer +description: A Helm chart for MEV Commit Bridge Relayer +type: application +version: 0.1.0 +appVersion: "v0.1.0" diff --git a/infrastructure/charts/mev-commit-bridge/scripts/keystore-init.sh b/infrastructure/charts/mev-commit-bridge/scripts/keystore-init.sh new file mode 100644 index 000000000..ee0fbeeab --- /dev/null +++ b/infrastructure/charts/mev-commit-bridge/scripts/keystore-init.sh @@ -0,0 +1,224 @@ +#!/bin/sh + +set -e + +# Configuration from environment variables +KEYSTORE_PATH="${KEYSTORE_PATH:-/keystore}" +MAX_RETRIES="${KEYSTORE_RETRIES:-3}" + +echo "=== MEV-Commit Keystore Initialization ===" +echo "Keystore path: $KEYSTORE_PATH" + +# Create keystore directory if it doesn't exist +mkdir -p "$KEYSTORE_PATH" + +# Function to extract address from filename using POSIX shell +extract_address_from_filename() { + local filename="$1" + + # Check if filename matches UTC----
format + case "$filename" in + UTC--????-??-??T??-??-??.??????*Z--*) + # Extract the address part after the last -- + address_part="${filename##*--}" + # Validate address is 40 hex characters + case "$address_part" in + *[!0-9a-fA-F]* | ????????????????????????????????????) + echo "Invalid address format: $address_part" >&2 + return 1 + ;; + ????????????????????????????????????????) + echo "$address_part" + return 0 + ;; + *) + echo "Invalid address length: $address_part" >&2 + return 1 + ;; + esac + ;; + *) + echo "Invalid keystore filename format: $filename" >&2 + return 1 + ;; + esac +} + +# Function to extract address from keystore JSON content +extract_address_from_content() { + local file_path="$1" + + if command -v jq >/dev/null 2>&1; then + jq -r '.address' "$file_path" 2>/dev/null || echo "" + else + # Extract address using grep and sed (fallback) + grep -o '"address"[[:space:]]*:[[:space:]]*"[^"]*"' "$file_path" 2>/dev/null | \ + sed 's/.*"address"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/' || echo "" + fi +} + +# Function to normalize address (remove 0x prefix and convert to lowercase) +normalize_address() { + local addr="$1" + # Remove 0x prefix if present and convert to lowercase + echo "${addr#0x}" | tr '[:upper:]' '[:lower:]' +} + +# Function to validate keystore file +validate_keystore() { + local file_path="$1" + local filename="$2" + + echo "Validating keystore file: $file_path" + + if [ ! -f "$file_path" ]; then + echo "Keystore file does not exist" + return 1 + fi + + # Check if file is readable and not empty + if [ ! -s "$file_path" ]; then + echo "Keystore file is empty" + return 1 + fi + + # Extract address from filename + filename_address=$(extract_address_from_filename "$filename") + if [ $? -ne 0 ]; then + echo "✗ Invalid filename format" + return 1 + fi + + # Normalize filename address + filename_address=$(normalize_address "$filename_address") + echo "Address from filename: $filename_address" + + # Check basic JSON structure first + if command -v jq >/dev/null 2>&1; then + echo "Using jq for JSON validation" + + # Validate JSON structure + if ! jq -e '.address and .crypto and .crypto.cipher and .crypto.ciphertext and .crypto.kdf' "$file_path" >/dev/null 2>&1; then + echo "✗ Invalid keystore JSON structure" + return 1 + fi + + # Extract address from content + content_address=$(extract_address_from_content "$file_path") + if [ -z "$content_address" ]; then + echo "✗ Could not extract address from keystore content" + return 1 + fi + + # Normalize content address + content_address=$(normalize_address "$content_address") + echo "Address from content: $content_address" + + # Compare addresses (case-insensitive) + if [ "$filename_address" = "$content_address" ]; then + echo "✓ Keystore validation successful - addresses match: $filename_address" + return 0 + else + echo "✗ Address mismatch - filename: $filename_address, content: $content_address" + return 1 + fi + else + echo "Using basic validation (jq not available)" + + # Basic validation without jq + if ! grep -q '"crypto"' "$file_path" || \ + ! grep -q '"cipher"' "$file_path" || \ + ! grep -q '"ciphertext"' "$file_path" || \ + ! grep -q '"kdf"' "$file_path"; then + echo "✗ Basic keystore structure validation failed" + return 1 + fi + + # Extract address from content using basic tools + content_address=$(extract_address_from_content "$file_path") + if [ -z "$content_address" ]; then + echo "✗ Could not extract address from keystore content" + return 1 + fi + + # Normalize content address + content_address=$(normalize_address "$content_address") + echo "Address from content: $content_address" + + # Compare addresses (case-insensitive) + if [ "$filename_address" = "$content_address" ]; then + echo "✓ Basic keystore validation successful - addresses match: $filename_address" + return 0 + else + echo "✗ Address mismatch - filename: $filename_address, content: $content_address" + return 1 + fi + fi +} + +# Main logic - Read keystore content and filename from External Secret +KEYSTORE_CONTENT_FILE="/secrets/temp_keystore.json" +FILENAME_FILE="/secrets/filename.txt" + +echo "Reading keystore data from External Secret..." + +# Validate that secret files exist +if [ ! -f "$KEYSTORE_CONTENT_FILE" ]; then + echo "✗ Keystore content file not found: $KEYSTORE_CONTENT_FILE" + exit 1 +fi + +if [ ! -f "$FILENAME_FILE" ]; then + echo "✗ Filename file not found: $FILENAME_FILE" + exit 1 +fi + +# Read the expected filename +EXPECTED_FILENAME=$(cat "$FILENAME_FILE") +KEYSTORE_FILE_PATH="$KEYSTORE_PATH/$EXPECTED_FILENAME" + +echo "Expected filename: $EXPECTED_FILENAME" + +# Validate filename format before proceeding +if ! extract_address_from_filename "$EXPECTED_FILENAME" >/dev/null 2>&1; then + echo "✗ Invalid filename format: $EXPECTED_FILENAME" + echo "Expected format: UTC----
" + exit 1 +fi + +# Check if keystore already exists and is valid +if [ -f "$KEYSTORE_FILE_PATH" ]; then + if validate_keystore "$KEYSTORE_FILE_PATH" "$EXPECTED_FILENAME"; then + echo "✓ Valid keystore already exists - initialization complete" + exit 0 + else + echo "Removing invalid keystore file..." + rm -f "$KEYSTORE_FILE_PATH" + fi +fi + +# Copy keystore content to final location +echo "Setting up keystore from External Secret..." +cp "$KEYSTORE_CONTENT_FILE" "$KEYSTORE_FILE_PATH" + +# Validate the keystore +if ! validate_keystore "$KEYSTORE_FILE_PATH" "$EXPECTED_FILENAME"; then + echo "✗ Keystore validation failed" + rm -f "$KEYSTORE_FILE_PATH" + exit 1 +fi + +# Set proper permissions +chmod 600 "$KEYSTORE_FILE_PATH" + +# Create a checksum file for integrity checking +if command -v sha256sum >/dev/null 2>&1; then + sha256sum "$KEYSTORE_FILE_PATH" > "$KEYSTORE_PATH/.keystore.checksum" + echo "✓ Checksum file created" +fi + +# Extract final address for logging +FINAL_ADDRESS=$(extract_address_from_filename "$EXPECTED_FILENAME") +echo "✓ Keystore initialization completed successfully" +echo "✓ Keystore file: $KEYSTORE_FILE_PATH" +echo "✓ Address: $FINAL_ADDRESS" diff --git a/infrastructure/charts/mev-commit-bridge/templates/_helpers.tpl b/infrastructure/charts/mev-commit-bridge/templates/_helpers.tpl new file mode 100644 index 000000000..754e280b7 --- /dev/null +++ b/infrastructure/charts/mev-commit-bridge/templates/_helpers.tpl @@ -0,0 +1,52 @@ +# templates/_helpers.tpl +{{/* +Expand the name of the chart. +*/}} +{{- define "bridge-relayer.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "bridge-relayer.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "bridge-relayer.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "bridge-relayer.labels" -}} +helm.sh/chart: {{ include "bridge-relayer.chart" . }} +{{ include "bridge-relayer.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "bridge-relayer.selectorLabels" -}} +app.kubernetes.io/name: {{ include "bridge-relayer.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/infrastructure/charts/mev-commit-bridge/templates/configmap.yaml b/infrastructure/charts/mev-commit-bridge/templates/configmap.yaml new file mode 100644 index 000000000..cbe0bd7df --- /dev/null +++ b/infrastructure/charts/mev-commit-bridge/templates/configmap.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "bridge-relayer.fullname" . }}-init + labels: + app.kubernetes.io/name: {{ include "bridge-relayer.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: init + {{- include "bridge-relayer.labels" . | nindent 4 }} +data: + keystore-init.sh: |- + {{- .Files.Get "scripts/keystore-init.sh" | nindent 4 }} diff --git a/infrastructure/charts/mev-commit-bridge/templates/deployment.yaml b/infrastructure/charts/mev-commit-bridge/templates/deployment.yaml new file mode 100644 index 000000000..0b2f12219 --- /dev/null +++ b/infrastructure/charts/mev-commit-bridge/templates/deployment.yaml @@ -0,0 +1,113 @@ +# templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "bridge-relayer.fullname" . }} + labels: + {{- include "bridge-relayer.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "bridge-relayer.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "bridge-relayer.selectorLabels" . | nindent 8 }} + spec: + initContainers: + - name: keystore-init + image: alpine:latest + env: + - name: KEYSTORE_PATH + value: {{ .Values.keystore.dir | quote }} + - name: KEYSTORE_RETRIES + value: {{ .Values.keystore.retries | quote }} + volumeMounts: + - name: keystore-volume + mountPath: {{ .Values.keystore.dir }} + - name: keystore-secrets + mountPath: /secrets + readOnly: true + - name: keystore-init-script + mountPath: /scripts + readOnly: true + command: ["/bin/sh"] + args: ["/scripts/keystore-init.sh"] + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.config.httpPort }} + protocol: TCP + env: + - name: STANDARD_BRIDGE_RELAYER_HTTP_PORT + value: {{ .Values.config.httpPort | quote }} + - name: STANDARD_BRIDGE_RELAYER_LOG_LEVEL + value: {{ .Values.config.logLevel | quote }} + - name: STANDARD_BRIDGE_RELAYER_LOG_FMT + value: {{ .Values.config.logFormat | quote }} + - name: STANDARD_BRIDGE_RELAYER_LOG_TAGS + value: {{ .Values.config.logTags | quote }} + - name: STANDARD_BRIDGE_RELAYER_KEYSTORE_DIR + value: {{ .Values.keystore.dir | quote }} + - name: STANDARD_BRIDGE_RELAYER_KEYSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "bridge-relayer.fullname" . }}-keystore + key: password.txt + - name: STANDARD_BRIDGE_RELAYER_L1_RPC_URLS + value: {{ join "," .Values.config.l1RpcUrls | quote }} + - name: STANDARD_BRIDGE_RELAYER_SETTLEMENT_RPC_URL + value: {{ .Values.config.settlementRpcUrl | quote }} + {{- if .Values.config.l1ContractAddr }} + - name: STANDARD_BRIDGE_RELAYER_L1_CONTRACT_ADDR + value: {{ .Values.config.l1ContractAddr | quote }} + {{- end }} + {{- if .Values.config.settlementContractAddr }} + - name: STANDARD_BRIDGE_RELAYER_SETTLEMENT_CONTRACT_ADDR + value: {{ .Values.config.settlementContractAddr | quote }} + {{- end }} + - name: STANDARD_BRIDGE_RELAYER_PG_HOST + value: {{ .Values.config.postgresql.host | quote }} + - name: STANDARD_BRIDGE_RELAYER_PG_PORT + value: {{ .Values.config.postgresql.port | quote }} + - name: STANDARD_BRIDGE_RELAYER_PG_USER + value: {{ .Values.config.postgresql.user | quote }} + - name: STANDARD_BRIDGE_RELAYER_PG_PASSWORD + value: {{ .Values.config.postgresql.password | quote }} + - name: STANDARD_BRIDGE_RELAYER_PG_DBNAME + value: {{ .Values.config.postgresql.database | quote }} + volumeMounts: + - name: keystore-volume + mountPath: {{ .Values.keystore.dir }} + readOnly: true + {{- if .Values.probes.enabled }} + livenessProbe: + httpGet: + path: {{ .Values.probes.liveness.path | default "/" }} + port: http + initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds | default 30 }} + periodSeconds: {{ .Values.probes.liveness.periodSeconds | default 10 }} + readinessProbe: + httpGet: + path: {{ .Values.probes.readiness.path | default "/" }} + port: http + initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds | default 5 }} + periodSeconds: {{ .Values.probes.readiness.periodSeconds | default 5 }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + command: ["mev-commit-bridge", "start"] + volumes: + - name: keystore-volume + emptyDir: {} + - name: keystore-secrets + secret: + secretName: {{ include "bridge-relayer.fullname" . }}-keystore + - name: keystore-init-script + configMap: + name: {{ include "bridge-relayer.fullname" . }}-init + defaultMode: 0755 diff --git a/infrastructure/charts/mev-commit-bridge/templates/externalsecret.yaml b/infrastructure/charts/mev-commit-bridge/templates/externalsecret.yaml new file mode 100644 index 000000000..0e5fcec86 --- /dev/null +++ b/infrastructure/charts/mev-commit-bridge/templates/externalsecret.yaml @@ -0,0 +1,30 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ include "bridge-relayer.fullname" . }}-keystore + labels: + {{- include "bridge-relayer.labels" . | nindent 4 }} + annotations: + helm.sh/hook: pre-install,pre-upgrade + helm.sh/hook-weight: "-2" +spec: + refreshInterval: {{ .Values.keystore.refreshInterval | default "12h" }} + secretStoreRef: + name: {{ .Values.global.externalSecrets.secretStore }} + kind: {{ .Values.global.externalSecrets.secretStoreKind | default "ClusterSecretStore" }} + target: + name: {{ include "bridge-relayer.fullname" . }}-keystore + creationPolicy: Owner + data: + - secretKey: temp_keystore.json + remoteRef: + key: {{ .Values.keystore.awsSecretKey | default (printf "%s-keystore" (include "bridge-relayer.fullname" .)) }} + property: {{ .Values.keystore.properties.keystore | default "bridge_relayer_keystore" }} + - secretKey: filename.txt + remoteRef: + key: {{ .Values.keystore.awsSecretKey | default (printf "%s-keystore" (include "bridge-relayer.fullname" .)) }} + property: {{ .Values.keystore.properties.keystoreFilename | default "bridge_relayer_keystore_filename" }} + - secretKey: password.txt + remoteRef: + key: {{ .Values.keystore.awsSecretKey | default (printf "%s-keystore" (include "bridge-relayer.fullname" .)) }} + property: {{ .Values.keystore.properties.keystorePassword | default "bridge_relayer_keystore_password" }} diff --git a/infrastructure/charts/mev-commit-bridge/templates/secret.yaml b/infrastructure/charts/mev-commit-bridge/templates/secret.yaml new file mode 100644 index 000000000..4140495df --- /dev/null +++ b/infrastructure/charts/mev-commit-bridge/templates/secret.yaml @@ -0,0 +1,10 @@ +# templates/secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "bridge-relayer.fullname" . }}-secrets + labels: + {{- include "bridge-relayer.labels" . | nindent 4 }} +type: Opaque +data: + postgresql-password: {{ .Values.config.postgresql.password | b64enc }} diff --git a/infrastructure/charts/mev-commit-bridge/templates/service.yaml b/infrastructure/charts/mev-commit-bridge/templates/service.yaml new file mode 100644 index 000000000..0d2a7486a --- /dev/null +++ b/infrastructure/charts/mev-commit-bridge/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "bridge-relayer.fullname" . }} + labels: + {{- include "bridge-relayer.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "bridge-relayer.selectorLabels" . | nindent 4 }} diff --git a/infrastructure/charts/mev-commit-bridge/values.yaml b/infrastructure/charts/mev-commit-bridge/values.yaml new file mode 100644 index 000000000..5c47d9e9f --- /dev/null +++ b/infrastructure/charts/mev-commit-bridge/values.yaml @@ -0,0 +1,74 @@ +replicaCount: 1 + +image: + repository: + pullPolicy: IfNotPresent + tag: "" + +nameOverride: "" +fullnameOverride: "" + +service: + type: ClusterIP + port: 8080 + +resources: + limits: + cpu: 4000m + memory: 8Gi + requests: + cpu: 1000m + memory: 2Gi + +# Global configuration for External Secrets +global: + externalSecrets: + enabled: true + secretStore: "aws-cluster-secret-store" + secretStoreKind: "ClusterSecretStore" + +# Bridge Relayer Configuration +config: + httpPort: 8080 + logLevel: "info" + logFormat: "json" + logTags: "service.name:bridge-relayer" + + # RPC URLs + l1RpcUrls: + - "" + settlementRpcUrl: "" + + # Contract addresses (will be set as env var) + l1ContractAddr: "0x00000000" + settlementContractAddr: "0x0000000" + + # PG config + postgresql: + host: "pg-db.bridge.svc.cluster.local" + port: 5432 + user: "" + database: "" + password: "" + +# Keystore configuration - managed by External Secrets +keystore: + refreshInterval: "12h" + dir: "/app/keystore" + retries: 3 + awsSecretKey: "testenv/testnet/mev-commit" + properties: + keystore: "bridge_relayer_keystore" + keystoreFilename: "bridge_relayer_keystore_filename" + keystorePassword: "bridge_relayer_keystore_password" + +probes: + enabled: true + liveness: + path: "/health" + initialDelaySeconds: 30 + periodSeconds: 10 + readiness: + path: "/health" + initialDelaySeconds: 5 + periodSeconds: 5 From c2b84da064aabb6e117733619ff97b38107f46bd Mon Sep 17 00:00:00 2001 From: harshsingh1002 <1002.harshsingh@gmail.com> Date: Thu, 24 Jul 2025 14:47:11 +0200 Subject: [PATCH 2/2] feat: add mev-commit bridge chart --- infrastructure/charts/mev-commit-bridge/values.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/infrastructure/charts/mev-commit-bridge/values.yaml b/infrastructure/charts/mev-commit-bridge/values.yaml index 5c47d9e9f..95a89b849 100644 --- a/infrastructure/charts/mev-commit-bridge/values.yaml +++ b/infrastructure/charts/mev-commit-bridge/values.yaml @@ -56,11 +56,11 @@ keystore: refreshInterval: "12h" dir: "/app/keystore" retries: 3 - awsSecretKey: "testenv/testnet/mev-commit" + awsSecretKey: "" properties: - keystore: "bridge_relayer_keystore" - keystoreFilename: "bridge_relayer_keystore_filename" - keystorePassword: "bridge_relayer_keystore_password" + keystore: "" + keystoreFilename: "" + keystorePassword: "" probes: enabled: true