Skip to content

[MOSIP-44613] use esignet_db_port placeholder in esignet-dsf files an… #130

[MOSIP-44613] use esignet_db_port placeholder in esignet-dsf files an…

[MOSIP-44613] use esignet_db_port placeholder in esignet-dsf files an… #130

name: Deploy eSignet using Helmsman
on:
workflow_dispatch:
inputs:
profile:
description: "Deployment profile to use"
required: true
default: "mosip-platform-java11"
type: choice
options:
- mosip-platform-java11
- mosip-platform-java21
- esignet
mode:
description: "Choose Helmsman mode: dry-run or apply"
required: true
default: "dry-run"
type: choice
options:
- dry-run
- apply
skip_mosip_dsf_check:
description: "Skip MOSIP DSF completion check (for standalone deployment)"
required: false
default: false
type: boolean
delete_existing_jobs:
description: "Delete existing onboarder jobs before deployment (required for re-runs)"
required: false
default: false
type: boolean
domain_name:
description: "Domain name for this environment (e.g. example.xyz.net)"
required: false
type: string
esignet_db_port:
description: "PostgreSQL port for eSignet databases (e.g. 5433 for MOSIP platform external postgres)"
required: false
type: string
cre_domain_name:
description: "CRE domain name for this environment (e.g. cre.xyz.net)"
required: false
type: string
qabase_domain_name:
description: "QA base domain name for this environment (e.g. qabase.xyz.net)"
required: false
type: string
env_name:
description: "Environment name (e.g. sandbox, dev, staging)"
required: false
type: string
push:
paths:
- Helmsman/dsf/**/esignet-dsf.yaml
permissions:
actions: write
contents: read
jobs:
validate-inputs:
runs-on: ubuntu-latest
environment:
name: ${{ github.ref_name }}
steps:
- name: Validate required variables
run: |
errors=()
PROFILE="${{ github.event.inputs.profile }}"
DOMAIN="${{ github.event.inputs.domain_name || vars.DOMAIN_NAME }}"
ENV="${{ github.event.inputs.env_name || vars.ENV_NAME }}"
[ -z "$DOMAIN" ] && errors+=("domain_name is empty — set vars.DOMAIN_NAME under Environment '${{ github.ref_name }}'")
[ -z "$ENV" ] && errors+=("env_name is empty — set vars.ENV_NAME under Environment '${{ github.ref_name }}'")
if [ ${#errors[@]} -gt 0 ]; then
echo "❌ Required variables missing:"
printf ' - %s\n' "${errors[@]}"
echo "Go to: Settings → Environments → ${{ github.ref_name }} → Variables"
exit 1
fi
echo "✓ domain_name = $DOMAIN"
echo "✓ env_name = $ENV"
# cre_domain_name and qabase_domain_name are esignet standalone only.
# Push events always target esignet (path filter); dispatch uses explicit profile input.
if [ -z "$PROFILE" ] || [ "$PROFILE" = "esignet" ]; then
CRE_DOMAIN="${{ github.event.inputs.cre_domain_name || vars.CRE_DOMAIN_NAME }}"
QABASE_DOMAIN="${{ github.event.inputs.qabase_domain_name || vars.QABASE_DOMAIN_NAME }}"
echo "✓ cre_domain_name = $CRE_DOMAIN (esignet standalone)"
echo "✓ qabase_domain_name = $QABASE_DOMAIN (esignet standalone)"
CRE_SPRING_LABEL="${{ vars.ESIGNET_CRE_SPRING_CONFIG_LABEL }}"
QA11_SPRING_LABEL="${{ vars.ESIGNET_QA11_SPRING_CONFIG_LABEL }}"
echo "✓ cre_spring_config_label = ${CRE_SPRING_LABEL:-develop} (esignet standalone, default: develop)"
echo "✓ qa11_spring_config_label = ${QA11_SPRING_LABEL:-develop} (esignet standalone, default: develop)"
else
CRE_PROVIDED="${{ github.event.inputs.cre_domain_name }}"
QABASE_PROVIDED="${{ github.event.inputs.qabase_domain_name }}"
if [ -n "$CRE_PROVIDED" ] || [ -n "$QABASE_PROVIDED" ]; then
echo "⚠ cre_domain_name / qabase_domain_name are only used for esignet standalone profile — ignoring for profile=$PROFILE"
fi
fi
deploy:
runs-on: ubuntu-latest
needs: validate-inputs
environment:
name: ${{ github.ref_name }}
env:
KUBECONFIG: ${{ github.workspace }}/.kube/config
PATH: ${{ github.workspace }}/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBECTL_PATH: ${{ github.workspace }}/.local/bin/kubectl
domain_name: ${{ github.event.inputs.domain_name || vars.DOMAIN_NAME }}
esignet_db_port: ${{ github.event.inputs.esignet_db_port || vars.ESIGNET_DB_PORT }}
cre_domain_name: ${{ github.event.inputs.cre_domain_name || vars.CRE_DOMAIN_NAME }}
qabase_domain_name: ${{ github.event.inputs.qabase_domain_name || vars.QABASE_DOMAIN_NAME }}
env_name: ${{ github.event.inputs.env_name || vars.ENV_NAME }}
# All secrets below are ENVIRONMENT secrets (not repository secrets)
# Configure them in: Repository → Settings → Environments → <branch-name> → Secrets
# Mock Relying Party Service secrets (base64 encoded PEM)
MOCK_RELYING_PARTY_CLIENT_PRIVATE_KEY: ${{ secrets.MOCK_RELYING_PARTY_CLIENT_PRIVATE_KEY }}
MOCK_RELYING_PARTY_JWE_PRIVATE_KEY: ${{ secrets.MOCK_RELYING_PARTY_JWE_PRIVATE_KEY }}
# eSignet Captcha secrets (plain text from Google reCAPTCHA)
ESIGNET_CAPTCHA_SITE_KEY: ${{ secrets.ESIGNET_CAPTCHA_SITE_KEY }}
ESIGNET_CAPTCHA_SECRET_KEY: ${{ secrets.ESIGNET_CAPTCHA_SECRET_KEY }}
# Per-namespace captcha secrets — required for esignet standalone profile only
ESIGNET_CRE_CAPTCHA_SITE_KEY: ${{ secrets.ESIGNET_CRE_CAPTCHA_SITE_KEY }}
ESIGNET_CRE_CAPTCHA_SECRET_KEY: ${{ secrets.ESIGNET_CRE_CAPTCHA_SECRET_KEY }}
ESIGNET_QA11_CAPTCHA_SITE_KEY: ${{ secrets.ESIGNET_QA11_CAPTCHA_SITE_KEY }}
ESIGNET_QA11_CAPTCHA_SECRET_KEY: ${{ secrets.ESIGNET_QA11_CAPTCHA_SECRET_KEY }}
# CRE / QA11 remote Keycloak admin + Postgres passwords (for testrig secrets created at esignet deploy time)
CRE_KEYCLOAK_ADMIN_PASSWORD: ${{ secrets.CRE_KEYCLOAK_ADMIN_PASSWORD }}
QA11_KEYCLOAK_ADMIN_PASSWORD: ${{ secrets.QA11_KEYCLOAK_ADMIN_PASSWORD }}
CRE_POSTGRES_PASSWORD: ${{ secrets.CRE_POSTGRES_PASSWORD }}
QA11_POSTGRES_PASSWORD: ${{ secrets.QA11_POSTGRES_PASSWORD }}
ESIGNET_SUNBIRD_CAPTCHA_SITE_KEY: ${{ secrets.ESIGNET_SUNBIRD_CAPTCHA_SITE_KEY }}
ESIGNET_SUNBIRD_CAPTCHA_SECRET_KEY: ${{ secrets.ESIGNET_SUNBIRD_CAPTCHA_SECRET_KEY }}
# Spring config label per namespace — controls which Git branch/tag the config-server uses
# Set as Environment Variables in Repository → Settings → Environments → <branch> → Variables
# If unset, hooks default to 'develop'
ESIGNET_CRE_SPRING_CONFIG_LABEL: ${{ vars.ESIGNET_CRE_SPRING_CONFIG_LABEL }}
ESIGNET_QA11_SPRING_CONFIG_LABEL: ${{ vars.ESIGNET_QA11_SPRING_CONFIG_LABEL }}
# Cluster access secrets
KUBECONFIG_SECRET: ${{ secrets.KUBECONFIG }}
CLUSTER_WIREGUARD_WG0: ${{ secrets.CLUSTER_WIREGUARD_WG0 }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Persist workflow inputs as environment variables
if: github.event_name == 'workflow_dispatch'
env:
GH_TOKEN: ${{ secrets.GH_INFRA_PAT }}
run: |
REPO="${{ github.repository }}"
ENVIRONMENT="${{ github.ref_name }}"
ENCODED_ENVIRONMENT=$(python3 -c "import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=''))" "$ENVIRONMENT")
save_var() {
local name=$1 value=$2
if [ -z "$value" ]; then echo "⏭ Skipping $name — no input provided, existing value preserved"; return; fi
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X PATCH \
-H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/$REPO/environments/$ENCODED_ENVIRONMENT/variables/$name" \
-d "{\"name\":\"$name\",\"value\":\"$value\"}")
if [ "$STATUS" = "404" ]; then
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
-H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/$REPO/environments/$ENCODED_ENVIRONMENT/variables" \
-d "{\"name\":\"$name\",\"value\":\"$value\"}")
if [ "$STATUS" = "201" ]; then
echo "✓ Created $name"
else
echo "✗ Failed to create $name (HTTP $STATUS)"; exit 1
fi
elif [ "$STATUS" = "200" ] || [ "$STATUS" = "204" ]; then
echo "✓ Updated $name"
else
echo "✗ Failed to save $name (HTTP $STATUS)"; exit 1
fi
}
save_var "DOMAIN_NAME" "${{ github.event.inputs.domain_name }}"
save_var "ESIGNET_DB_PORT" "${{ github.event.inputs.esignet_db_port }}"
save_var "CRE_DOMAIN_NAME" "${{ github.event.inputs.cre_domain_name }}"
save_var "QABASE_DOMAIN_NAME" "${{ github.event.inputs.qabase_domain_name }}"
save_var "ENV_NAME" "${{ github.event.inputs.env_name }}"
- name: Mask sensitive data
run: |
# Add masks for secrets to prevent accidental exposure in logs
echo "::add-mask::${{ secrets.MOCK_RELYING_PARTY_CLIENT_PRIVATE_KEY }}"
echo "::add-mask::${{ secrets.MOCK_RELYING_PARTY_JWE_PRIVATE_KEY }}"
echo "::add-mask::${{ secrets.KUBECONFIG }}"
echo "::add-mask::${{ secrets.CLUSTER_WIREGUARD_WG0 }}"
echo "::add-mask::${{ secrets.ESIGNET_CAPTCHA_SITE_KEY }}"
echo "::add-mask::${{ secrets.ESIGNET_CAPTCHA_SECRET_KEY }}"
echo "::add-mask::${{ secrets.ESIGNET_CRE_CAPTCHA_SITE_KEY }}"
echo "::add-mask::${{ secrets.ESIGNET_CRE_CAPTCHA_SECRET_KEY }}"
echo "::add-mask::${{ secrets.ESIGNET_QA11_CAPTCHA_SITE_KEY }}"
echo "::add-mask::${{ secrets.ESIGNET_QA11_CAPTCHA_SECRET_KEY }}"
echo "::add-mask::${{ secrets.ESIGNET_SUNBIRD_CAPTCHA_SITE_KEY }}"
echo "::add-mask::${{ secrets.ESIGNET_SUNBIRD_CAPTCHA_SECRET_KEY }}"
- name: Setup kubectl and kubeconfig
env:
KUBECONFIG_CONTENT: ${{ secrets.KUBECONFIG }}
run: |
# Create directories
mkdir -p ${{ github.workspace }}/.local/bin
mkdir -p ${{ github.workspace }}/.kube
# Install kubectl
curl -LO https://dl.k8s.io/release/v1.31.3/bin/linux/amd64/kubectl
chmod +x kubectl
mv ./kubectl ${{ github.workspace }}/.local/bin/kubectl
# Setup kubeconfig
echo "$KUBECONFIG_CONTENT" > ${{ github.workspace }}/.kube/config
chmod 400 ${{ github.workspace }}/.kube/config
# Add kubectl to GitHub PATH for subsequent steps
echo "${{ github.workspace }}/.local/bin" >> $GITHUB_PATH
# Export environment variables for immediate use
echo "KUBECTL_PATH=${{ github.workspace }}/.local/bin/kubectl" >> $GITHUB_ENV
# Verify installation
${{ github.workspace }}/.local/bin/kubectl version --client
${{ github.workspace }}/.local/bin/kubectl config view
- name: Set Default Mode
run: |
if [ -z "${{ github.event.inputs.mode }}" ]; then
echo "HELMSMAN_MODE=apply" >> $GITHUB_ENV
else
echo "HELMSMAN_MODE=${{ github.event.inputs.mode }}" >> $GITHUB_ENV
fi
- name: Set Profile
run: |
# Determine profile: from workflow input or detect from changed files on push
if [ -n "${{ github.event.inputs.profile }}" ]; then
PROFILE="${{ github.event.inputs.profile }}"
else
# Auto-detect profile from push trigger — extract profile dir name from changed files
# Fall back to HEAD~1 if github.event.before is unreachable (e.g. shallow clone)
BEFORE="${{ github.event.before }}"
SHA="${{ github.sha }}"
if [[ -z "$BEFORE" || "$BEFORE" == "0000000000000000000000000000000000000000" ]]; then
BEFORE="HEAD~1"
fi
CHANGED_FILES=$(git diff --name-only "$BEFORE" "$SHA" -- 'Helmsman/dsf/' 2>/dev/null || \
git diff --name-only HEAD~1 HEAD -- 'Helmsman/dsf/' 2>/dev/null || echo "")
PROFILE=$(echo "$CHANGED_FILES" | grep 'esignet-dsf.yaml' | head -1 | sed 's|Helmsman/dsf/\([^/]*\)/.*|\1|')
if [[ -z "$PROFILE" ]]; then
echo "Error: could not detect profile from changed DSF files."
exit 1
fi
fi
echo "PROFILE=$PROFILE" >> "$GITHUB_ENV"
echo "Using profile: $PROFILE"
- name: Setup ufw firewall
run: |
sudo ufw enable
sudo ufw allow ssh
sudo ufw allow 51820/udp
sudo ufw status
- name: Install WireGuard
run: sudo apt-get install -y wireguard
- name: Configure WireGuard
run: |
echo "${{ secrets.CLUSTER_WIREGUARD_WG0 }}" | sudo tee /etc/wireguard/wg0.conf > /dev/null
- name: Start WireGuard
run: |
sudo chmod 600 /etc/wireguard/wg0.conf
sudo chmod 700 /etc/wireguard/
sudo chmod 644 /lib/systemd/system/wg-quick@.service
sudo systemctl daemon-reload
sudo wg-quick up wg0
sudo wg show wg0
- name: Setup Helm
run: |
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
sudo chmod 700 get_helm.sh
sudo ./get_helm.sh
helm version --client
- name: Install Helmsman
run: |
curl -L https://github.com/Praqma/helmsman/releases/download/v3.17.1/helmsman_3.17.1_linux_amd64.tar.gz -o helmsman.tar.gz
tar xzf helmsman.tar.gz
sudo mv helmsman /usr/local/bin
# Verify tools are available
echo "Tools verification:"
echo "kubectl: $(which kubectl)"
echo "helmsman: $(which helmsman)"
kubectl version --client
helmsman -v
- name: Verify cluster access
run: |
# Verify tools are accessible
echo "Verifying tool availability:"
echo "kubectl path: $(which kubectl)"
echo "KUBECONFIG: $KUBECONFIG"
# Test kubectl functionality
kubectl version --client
kubectl get nodes
kubectl cluster-info
- name: Check if mosip-dsf label is completed
if: ${{ github.event.inputs.skip_mosip_dsf_check != 'true' && vars.ESIGNET_STANDALONE_MODE != 'true' && github.event.inputs.profile != 'esignet' }}
run: |
STATUS=$(kubectl get namespace default -o jsonpath='{.metadata.labels.mosip-dsf}' 2>/dev/null || echo "")
if [[ "$STATUS" != "completed" ]]; then
echo "❌ MOSIP DSF not completed. Please run the MOSIP DSF workflow first."
echo ""
echo "💡 To run eSignet DSF independently (standalone mode):"
echo " - For manual runs: Set 'skip_mosip_dsf_check' to true"
echo " - For push-triggered runs: Set repository variable ESIGNET_STANDALONE_MODE=true"
echo " (Repository → Settings → Secrets and variables → Actions → Variables)"
exit 1
fi
echo "✅ MOSIP DSF is completed. Proceeding with eSignet deployment."
- name: Standalone mode notice
if: ${{ github.event.inputs.skip_mosip_dsf_check == 'true' || vars.ESIGNET_STANDALONE_MODE == 'true' }}
run: |
echo "⚠️ Running in STANDALONE mode - MOSIP DSF check skipped"
echo " Triggered by: ${{ github.event.inputs.skip_mosip_dsf_check == 'true' && 'workflow input' || 'ESIGNET_STANDALONE_MODE variable' }}"
echo " Make sure all prerequisite namespaces and resources exist!"
- name: Validate required secrets
run: |
echo "Validating required secrets are configured..."
MISSING_SECRETS=0
if [ -z "$MOCK_RELYING_PARTY_CLIENT_PRIVATE_KEY" ]; then
echo "❌ MOCK_RELYING_PARTY_CLIENT_PRIVATE_KEY secret is not configured"
MISSING_SECRETS=1
else
echo "✅ MOCK_RELYING_PARTY_CLIENT_PRIVATE_KEY is configured"
fi
if [ -z "$MOCK_RELYING_PARTY_JWE_PRIVATE_KEY" ]; then
echo "❌ MOCK_RELYING_PARTY_JWE_PRIVATE_KEY secret is not configured"
MISSING_SECRETS=1
else
echo "✅ MOCK_RELYING_PARTY_JWE_PRIVATE_KEY is configured"
fi
if [ -z "$ESIGNET_CAPTCHA_SITE_KEY" ]; then
echo "❌ ESIGNET_CAPTCHA_SITE_KEY secret is not configured"
MISSING_SECRETS=1
else
echo "✅ ESIGNET_CAPTCHA_SITE_KEY is configured"
fi
if [ -z "$ESIGNET_CAPTCHA_SECRET_KEY" ]; then
echo "❌ ESIGNET_CAPTCHA_SECRET_KEY secret is not configured"
MISSING_SECRETS=1
else
echo "✅ ESIGNET_CAPTCHA_SECRET_KEY is configured"
fi
# Per-namespace captcha secrets — only required for esignet standalone profile
if [ "$PROFILE" = "esignet" ]; then
echo "--- Validating esignet standalone captcha secrets ---"
for var in ESIGNET_CRE_CAPTCHA_SITE_KEY ESIGNET_CRE_CAPTCHA_SECRET_KEY \
ESIGNET_QA11_CAPTCHA_SITE_KEY ESIGNET_QA11_CAPTCHA_SECRET_KEY \
ESIGNET_SUNBIRD_CAPTCHA_SITE_KEY ESIGNET_SUNBIRD_CAPTCHA_SECRET_KEY; do
val="${!var:-}"
if [ -z "$val" ]; then
echo "❌ $var secret is not configured (required for esignet standalone)"
MISSING_SECRETS=1
else
echo "✅ $var is configured"
fi
done
fi
if [ "$MISSING_SECRETS" -eq 1 ]; then
echo ""
echo "Please configure the missing secrets as ENVIRONMENT secrets:"
echo " Repository → Settings → Environments → ${{ github.ref_name }} → Add secret"
echo ""
echo "Required environment secrets:"
echo " - KUBECONFIG (base64 encoded kubeconfig file)"
echo " - CLUSTER_WIREGUARD_WG0 (WireGuard config)"
echo " - MOCK_RELYING_PARTY_CLIENT_PRIVATE_KEY (base64 encoded PEM)"
echo " - MOCK_RELYING_PARTY_JWE_PRIVATE_KEY (base64 encoded PEM)"
echo " - ESIGNET_CAPTCHA_SITE_KEY (reCAPTCHA site key - plain text)"
echo " - ESIGNET_CAPTCHA_SECRET_KEY (reCAPTCHA secret key - plain text)"
if [ "$PROFILE" = "esignet" ]; then
echo " - ESIGNET_CRE_CAPTCHA_SITE_KEY / ESIGNET_CRE_CAPTCHA_SECRET_KEY"
echo " - ESIGNET_QA11_CAPTCHA_SITE_KEY / ESIGNET_QA11_CAPTCHA_SECRET_KEY"
echo " - ESIGNET_SUNBIRD_CAPTCHA_SITE_KEY / ESIGNET_SUNBIRD_CAPTCHA_SECRET_KEY"
fi
exit 1
fi
echo "All required secrets are configured"
- name: Get DB User Password from postgres namespace
id: get-db-password
run: |
echo "Fetching db-common-secrets from postgres namespace..."
# Check if the secret exists
if kubectl -n postgres get secret db-common-secrets &>/dev/null; then
DB_USER_PASSWORD=$(kubectl -n postgres get secret db-common-secrets -o jsonpath='{.data.db-dbuser-password}' | base64 -d)
if [ -n "$DB_USER_PASSWORD" ]; then
# Mask the password in logs
echo "::add-mask::$DB_USER_PASSWORD"
# Export for subsequent steps
echo "DB_USER_PASSWORD=$DB_USER_PASSWORD" >> $GITHUB_ENV
echo "✅ DB_USER_PASSWORD retrieved successfully"
else
echo "❌ db-dbuser-password is empty in db-common-secrets"
exit 1
fi
else
echo "⚠️ db-common-secrets not found in postgres namespace"
echo "This is expected on first deployment - postgres-init will create the secret"
# Set empty value - postgres-init will generate a new password
echo "DB_USER_PASSWORD=" >> $GITHUB_ENV
fi
- name: Get Keycloak Client Secrets for esignet-keycloak-init
id: get-keycloak-secrets
run: |
echo "Fetching Keycloak client secrets from keycloak namespace..."
# Fixed key names — written to GITHUB_ENV so Helmsman can substitute ${VAR} in DSF
PMS_CLIENT_SECRET_KEY='mosip_pms_client_secret'
MPARTNER_DEFAULT_AUTH_SECRET_KEY='mpartner_default_auth_secret'
IDA_CLIENT_SECRET_KEY='mosip_ida_client_secret'
DEPLOYMENT_CLIENT_SECRET_KEY='mosip_deployment_client_secret'
MPARTNER_DEFAULT_MOBILE_SECRET_KEY='mpartner_default_mobile_secret'
echo "PMS_CLIENT_SECRET_KEY=$PMS_CLIENT_SECRET_KEY" >> $GITHUB_ENV
echo "MPARTNER_DEFAULT_AUTH_SECRET_KEY=$MPARTNER_DEFAULT_AUTH_SECRET_KEY" >> $GITHUB_ENV
echo "IDA_CLIENT_SECRET_KEY=$IDA_CLIENT_SECRET_KEY" >> $GITHUB_ENV
echo "DEPLOYMENT_CLIENT_SECRET_KEY=$DEPLOYMENT_CLIENT_SECRET_KEY" >> $GITHUB_ENV
echo "MPARTNER_DEFAULT_MOBILE_SECRET_KEY=$MPARTNER_DEFAULT_MOBILE_SECRET_KEY" >> $GITHUB_ENV
fetch_secret() {
kubectl -n keycloak get secret keycloak-client-secrets \
-o jsonpath="{.data.$1}" 2>/dev/null | base64 -d 2>/dev/null || echo ""
}
# Check if keycloak-client-secrets exists (empty on first deploy — keycloak-init generates them)
if kubectl -n keycloak get secret keycloak-client-secrets &>/dev/null; then
echo "✅ keycloak-client-secrets found in keycloak namespace"
PMS_CLIENT_SECRET_VALUE=$(fetch_secret "$PMS_CLIENT_SECRET_KEY")
MPARTNER_DEFAULT_AUTH_SECRET_VALUE=$(fetch_secret "$MPARTNER_DEFAULT_AUTH_SECRET_KEY")
IDA_CLIENT_SECRET_VALUE=$(fetch_secret "$IDA_CLIENT_SECRET_KEY")
DEPLOYMENT_CLIENT_SECRET_VALUE=$(fetch_secret "$DEPLOYMENT_CLIENT_SECRET_KEY")
MPARTNER_DEFAULT_MOBILE_SECRET_VALUE=$(fetch_secret "$MPARTNER_DEFAULT_MOBILE_SECRET_KEY")
# Mask all secret values before writing to GITHUB_ENV
for val in "$PMS_CLIENT_SECRET_VALUE" "$MPARTNER_DEFAULT_AUTH_SECRET_VALUE" \
"$IDA_CLIENT_SECRET_VALUE" "$DEPLOYMENT_CLIENT_SECRET_VALUE" \
"$MPARTNER_DEFAULT_MOBILE_SECRET_VALUE"; do
[ -n "$val" ] && echo "::add-mask::$val"
done
else
echo "⚠️ keycloak-client-secrets not found — first deploy, keycloak-init will generate secrets"
PMS_CLIENT_SECRET_VALUE=""
MPARTNER_DEFAULT_AUTH_SECRET_VALUE=""
IDA_CLIENT_SECRET_VALUE=""
DEPLOYMENT_CLIENT_SECRET_VALUE=""
MPARTNER_DEFAULT_MOBILE_SECRET_VALUE=""
fi
echo "PMS_CLIENT_SECRET_VALUE=$PMS_CLIENT_SECRET_VALUE" >> $GITHUB_ENV
echo "MPARTNER_DEFAULT_AUTH_SECRET_VALUE=$MPARTNER_DEFAULT_AUTH_SECRET_VALUE" >> $GITHUB_ENV
echo "IDA_CLIENT_SECRET_VALUE=$IDA_CLIENT_SECRET_VALUE" >> $GITHUB_ENV
echo "DEPLOYMENT_CLIENT_SECRET_VALUE=$DEPLOYMENT_CLIENT_SECRET_VALUE" >> $GITHUB_ENV
echo "MPARTNER_DEFAULT_MOBILE_SECRET_VALUE=$MPARTNER_DEFAULT_MOBILE_SECRET_VALUE" >> $GITHUB_ENV
- name: Show deployment variables
run: |
echo "domain_name = $domain_name"
echo "cre_domain_name = $cre_domain_name"
echo "qabase_domain_name = $qabase_domain_name"
echo "env_name = $env_name"
- name: Initiate helmsman to apply the DSF configurations
run: |
export HOME="${{ github.workspace }}"
export WORKDIR="$HOME/Helmsman"
# Conditional cleanup: Delete immutable Jobs only if checkbox is enabled
# Kubernetes Jobs cannot be updated, so we must delete them before Helmsman runs on re-deployments
DELETE_JOBS="${{ github.event.inputs.delete_existing_jobs }}"
if [ "$DELETE_JOBS" = "true" ]; then
echo "=============================================="
echo "Delete existing jobs option enabled"
echo "Running pre-Helmsman cleanup..."
echo "=============================================="
chmod +x $WORKDIR/hooks/pre-helmsman-cleanup.sh
$WORKDIR/hooks/pre-helmsman-cleanup.sh || echo "Cleanup script completed (may have warnings on first run)"
else
echo "Delete existing jobs option not enabled, skipping cleanup"
echo "Note: If you encounter 'Job is invalid: spec.template' errors, re-run with 'Delete existing onboarder jobs' checked"
fi
# Mock Relying Party secrets are already in env from job-level definition
# They are automatically masked by GitHub Actions
# DB_USER_PASSWORD is set from previous step (or empty on first deploy)
# Verify tools are available
echo "Using kubectl: $(which kubectl)"
echo "Using kubeconfig: $KUBECONFIG"
# For esignet standalone: skip softhsm upgrade if releases already exist.
# The softhsm chart regenerates a random PIN on every helm upgrade (randNumeric 8).
# If either the softhsm pod or the esignet pod restarts after a PIN rotation,
# they read the new PIN but the PVC token has the old one → CKR_PIN_INCORRECT.
# Fix: skip softhsm upgrade on re-runs so the PIN in the secret never changes.
SKIP_RELEASES_ARG=""
if [ "$PROFILE" = "esignet" ]; then
SKIP_RELEASES=""
for pair in "esignet-softhsm:esignet" "esignet-softhsm-cre:esignet-cre" "esignet-softhsm-qa11:esignet-qa11" "esignet-softhsm-sunbird:esignet-sunbird"; do
release="${pair%%:*}"
ns="${pair##*:}"
if helm status "$release" -n "$ns" &>/dev/null; then
echo "✓ $release already installed in $ns — skipping upgrade to preserve SoftHSM PIN"
SKIP_RELEASES="${SKIP_RELEASES:+$SKIP_RELEASES,}$release"
else
echo "⬆ $release not found in $ns — will install fresh"
fi
done
if [ -n "$SKIP_RELEASES" ]; then
SKIP_RELEASES_ARG="--skip-releases $SKIP_RELEASES"
echo "SoftHSM releases skipped: $SKIP_RELEASES"
fi
fi
# Run helmsman with the determined mode
# --keep-untracked-releases prevents deletion of releases managed by other DSF files (e.g., postgres-init from external-dsf)
echo "Using DSF: $WORKDIR/dsf/$PROFILE/esignet-dsf.yaml"
helmsman --${HELMSMAN_MODE} --keep-untracked-releases $SKIP_RELEASES_ARG -f $WORKDIR/dsf/$PROFILE/esignet-dsf.yaml
- name: Label namespace on successful deployment
if: success() && env.HELMSMAN_MODE == 'apply'
run: |
kubectl label namespace default esignet-dsf=completed --overwrite
echo "✅ eSignet DSF deployment completed successfully"
- name: Deployment Summary
if: always()
run: |
echo "=================================="
echo "eSignet Deployment Summary"
echo "=================================="
echo "Profile: $PROFILE"
echo "Mode: $HELMSMAN_MODE"
echo "Branch: ${{ github.ref_name }}"
echo "Commit: ${{ github.sha }}"
echo ""
echo "Namespaces created/updated:"
kubectl get ns esignet softhsm keycloak redis postgres 2>/dev/null || echo "Some namespaces may not exist yet"
echo ""
echo "eSignet pods status:"
kubectl get pods -n esignet 2>/dev/null || echo "esignet namespace not ready"
# ---------------------------------------------------------------------------
# Trigger signup workflow after successful esignet standalone deployment.
# Only fires when profile == 'esignet' (not for mosip-platform-java11/java21).
# ---------------------------------------------------------------------------
workflow-caller:
runs-on: ubuntu-latest
needs: [deploy]
if: |
success() &&
(github.event.inputs.profile == 'esignet' || github.event_name == 'push')
environment:
name: ${{ github.ref_name }}
steps:
- name: Trigger helmsman signup workflow
env:
GH_TOKEN: ${{ secrets.GH_INFRA_PAT }}
run: |
DOMAIN="${{ github.event.inputs.domain_name || vars.DOMAIN_NAME }}"
ENV="${{ github.event.inputs.env_name || vars.ENV_NAME }}"
MODE="${{ github.event.inputs.mode || 'apply' }}"
echo "Triggering signup workflow for profile=esignet"
echo " domain_name = $DOMAIN"
echo " env_name = $ENV"
echo " mode = $MODE"
curl -f -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GH_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/${{ github.repository }}/actions/workflows/helmsman_signup.yml/dispatches" \
-d "{\"ref\":\"${{ github.ref_name }}\",\"inputs\":{\"mode\":\"$MODE\",\"profile\":\"esignet\",\"domain_name\":\"$DOMAIN\",\"env_name\":\"$ENV\"}}"
echo "✅ Signup workflow triggered successfully"