Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/TEMPLATES/secret-mapping-opencrvs-deps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ traefik-cert:
type: tls
namespace: traefik
data:
- SSL_CRT: cert
- SSL_KEY: key
- SSL_CRT: tls.crt
- SSL_KEY: tls.key

# If backup is configured then workflow will use GitHub secrets for current environment
# If restore is configured then workflow will fetch secrets from source environment (usually production)
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/deploy-dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
options:
- ""
env:
DEPENDENCIES_CHART_VERSION: "v1.9.12"
DEPENDENCIES_CHART_VERSION: "1.9.15"
TRAEFIK_CHART_VERSION: "39.0.0"
jobs:
approve:
Expand Down Expand Up @@ -64,7 +64,7 @@ jobs:
--create-namespace \
-f environments/${ENV}/traefik/values.yaml \
-f environments/${ENV}/traefik/values.override.yaml
kubectl scale deployment traefik --replicas=1 --namespace traefik
kubectl scale deployment traefik --replicas=1 --namespace traefik || true

- name: Install OpenCRVS dependencies
id: deploy
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/deploy-opencrvs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ on:
core-image-tag:
description: "Tag of the core image"
required: true
default: "v1.9.12"
default: "1.9.15"
countryconfig-image-tag:
description: "Tag of the countryconfig image"
required: true
default: "v1.9.12"
default: "1.9.15"
data-seed-enabled:
description: "Data seeding during deployment"
required: false
Expand All @@ -36,7 +36,7 @@ on:

env:
# Assuming chart version matches core image tag
OPENCRVS_CHART_VERSION: "v1.9.12"
OPENCRVS_CHART_VERSION: "1.9.15"
jobs:
approve:
environment: ${{ inputs.environment }}
Expand Down Expand Up @@ -145,8 +145,8 @@ jobs:
--atomic \
--wait \
--wait-for-jobs \
--set image.tag="$CORE_IMAGE_TAG" \
--set countryconfig.image.tag="$COUNTRYCONFIG_IMAGE_TAG" \
--set-string platform.tag="$CORE_IMAGE_TAG" \
--set-string countryconfig.image.tag="$COUNTRYCONFIG_IMAGE_TAG" \
--set countryconfig.image.name="$COUNTRYCONFIG_IMAGE_NAME" \
--set data_seed.env.ACTIVATE_USERS="${{ vars.ACTIVATE_USERS || 'false' }}" \
--set data_seed.enabled="${{ inputs.data-seed-enabled }}" \
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/github-to-k8s-sync-env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,6 @@ jobs:
echo BACKUP_HOST=$BACKUP_HOST >> $env_file
echo BACKUP_HOST_PRIVATE_KEY=$BACKUP_HOST_PRIVATE_KEY >> $env_file
echo BACKUP_SERVER_USER=$BACKUP_SERVER_USER >> $env_file
echo POSTGRES_USER=$POSTGRES_USER >> $env_file
echo POSTGRES_PASSWORD=$POSTGRES_PASSWORD >> $env_file
grep BACKUP_HOST_PRIVATE_KEY $env_file || echo "No restore encryption passphrase to add"

- name: Preprocess mapping into Secret YAMLs
Expand Down Expand Up @@ -293,6 +291,7 @@ jobs:
echo "🚀 Applying $f within namespace"
kubectl get namespace $namespace >/dev/null 2>&1 || kubectl create namespace $namespace
yq eval . "$f" > /dev/null && echo "✅ $f is valid YAML" || echo "❌ $f has YAML errors" && cat "$f"
kubectl delete --ignore-not-found -n $namespace -f "$f"
kubectl apply -n $namespace -f "$f"
echo "Dropping last-applied-configuration annotation for secret $(basename ${f/.yaml/})"
kubectl annotate secret -n $namespace "$(basename ${f/.yaml/})" kubectl.kubernetes.io/last-applied-configuration-
Expand Down
216 changes: 216 additions & 0 deletions .github/workflows/init-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
#
# OpenCRVS is also distributed under the terms of the Civil Registration
# & Healthcare Disclaimer located at http://opencrvs.org/license.
#
# Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.

# Gitflow release initialisation workflow.
#
# Triggered by opencrvs-core's init-release workflow (or manually) with a
# semver version string (e.g. 1.7.2).
#
# What this workflow does, in order:
# 1. Derives the base branch:
# - patch release (z > 0) → release/<x>.<y>.<z-1>
# - minor/major (z = 0) → develop
# 2. Creates a release branch (release/<version>) from the base branch.
# 3. Bumps Chart.yaml and prepends a CHANGELOG section, then pushes
# both commits to the release branch.
# 4. Opens two PRs — both PRs already contain the version-bump commits:
# a. release/<version> → master (the release PR)
# b. release/<version> → develop (merge-back PR, keeps develop in sync)
# 5. Creates a draft GitHub release and immediately deletes the backing tag
# (the tag will be re-created by the publish workflow after the PR merges).
name: 11. Release - Start a new release
on:
workflow_dispatch:
inputs:
version:
type: string
required: true
description: 'Version to release'

jobs:
release_workflow:
runs-on: ubuntu-latest
steps:
# Derive base_branch and target_branch from the version number.
# - patch (z > 0): base = release/<x>.<y>.<z-1>, target = master
# - minor/major (z = 0): base = develop, target = master
- name: Determine the Base Branch
id: get_base_branch
run: |
version="${{ inputs.version }}"

if [[ ! $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid version was provided as input: $version" >&2
echo "Please follow semver format for versioning, e/g 1.7.2"
exit 1
fi

IFS='.' read -r x y z <<< "$version"
if [ "$z" = "0" ]; then
base_branch="develop"
else
previous_version="$((x)).$((y)).$((z-1))"
base_branch="release/$previous_version"
fi
echo "target_branch=master" >> $GITHUB_OUTPUT
echo "base_branch=$base_branch" >> $GITHUB_OUTPUT

# Full history is required so yarn can traverse the commit graph.
- name: Checkout ${{ steps.get_base_branch.outputs.base_branch }}
uses: actions/checkout@v4
with:
ref: ${{ steps.get_base_branch.outputs.base_branch }}
fetch-depth: 0
token: ${{ secrets.INFRASTRUCTURE_WORKFLOW_TOKEN }}

- name: Check if release branch already exists
id: check_branch
run: |
if git ls-remote --exit-code --heads origin "release/${{ inputs.version }}" > /dev/null 2>&1; then
echo "Branch release/${{ inputs.version }} already exists, skipping creation."
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "exists=false" >> $GITHUB_OUTPUT
fi

# Create the release branch, bump helm chart version, and update the
# CHANGELOG — then push. The PRs are opened only after these commits
# exist on the remote, so both PRs immediately include the version-bump
# commits.
# Skipped if the release branch was already created by a previous run.
- name: Create release branch and update version numbers and CHANGELOG
if: steps.check_branch.outputs.exists == 'false'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

git checkout -b "release/${{ inputs.version }}"
export VERSION="${{ inputs.version }}"
# Bump helm chart version: sed instead of yq to preserve formatting and comments.
sed -i \
-e "s/^\(\s*OPENCRVS_CHART_VERSION:\s*\).*/\1\"$VERSION\"/" \
-e '/core-image-tag:/,/default:/ s/default: ".*"/default: "'"$VERSION"'"/' \
-e '/countryconfig-image-tag:/,/default:/ s/default: ".*"/default: "'"$VERSION"'"/' \
.github/workflows/deploy-opencrvs.yml
sed -i \
-e "s/^\(\s*DEPENDENCIES_CHART_VERSION:\s*\).*/\1\"$VERSION\"/" \
.github/workflows/deploy-dependencies.yml
git add .
git commit -m "chore: update version to ${{ inputs.version }}"

# Prepend a new "Release Candidate" section to the top of CHANGELOG.md.
# sed removes the existing "# Changelog" header (lines 1-2) so we can
# rewrite it with the new section underneath.
sed -i '1,2d' CHANGELOG.md
cp CHANGELOG.md COPY_CHANGELOG.md
{
echo "# Changelog"
echo ""
echo "## ${{ inputs.version }} Release Candidate"
echo ""
cat COPY_CHANGELOG.md
} > CHANGELOG.md
rm COPY_CHANGELOG.md
git add CHANGELOG.md
git commit -m "docs: update changelog for ${{ inputs.version }} release candidate"

git push origin "release/${{ inputs.version }}"

# A dedicated merge-back branch is used for the develop PR so that any
# conflict-resolution commits do not land on the release branch itself.
- name: Create merge-back branch for develop PR
run: |
MERGEBACK_BRANCH="merge-back/release-${{ inputs.version }}-to-develop"
if git ls-remote --exit-code --heads origin "$MERGEBACK_BRANCH" > /dev/null 2>&1; then
echo "Branch $MERGEBACK_BRANCH already exists, skipping."
else
git fetch origin "release/${{ inputs.version }}"
git checkout -b "$MERGEBACK_BRANCH" "origin/release/${{ inputs.version }}"
git push origin "$MERGEBACK_BRANCH"
fi

# Two PRs are always created:
#
# PR 1 — release/<version> → master
# The release PR. Merging this ships the version to production.
#
# PR 2 — merge-back/release-<version>-to-develop → develop
# Uses a dedicated branch so conflict-resolution commits stay off
# the release branch.
# - z=0 (base is develop): carries only the two bump commits, clean diff.
# - z>0 (base is a prior release branch): also backports any patch fixes.
# Each PR is checked individually — one may already exist while the other
# does not, so both are always evaluated.
- name: Create Pull Requests
run: |
PR_BRANCH="release/${{ inputs.version }}"
MERGEBACK_BRANCH="merge-back/release-${{ inputs.version }}-to-develop"
TARGET_BRANCH="${{ steps.get_base_branch.outputs.target_branch }}"

if [ -f .github/TEMPLATES/RELEASE_PR_TEMPLATE.md ]; then
BODY=$(cat .github/TEMPLATES/RELEASE_PR_TEMPLATE.md)
else
BODY=""
fi

EXISTING_MASTER_PR=$(gh pr list --head "$PR_BRANCH" --base "$TARGET_BRANCH" --state open --json number --jq '.[0].number // ""')
if [ -z "$EXISTING_MASTER_PR" ]; then
gh pr create \
--base "$TARGET_BRANCH" \
--head "$PR_BRANCH" \
--title "Release v${{ inputs.version }}" \
--body "$BODY"
else
echo "PR $PR_BRANCH → $TARGET_BRANCH already exists (#$EXISTING_MASTER_PR), skipping."
fi

EXISTING_DEVELOP_PR=$(gh pr list --head "$MERGEBACK_BRANCH" --base "develop" --state open --json number --jq '.[0].number // ""')
if [ -z "$EXISTING_DEVELOP_PR" ]; then
gh pr create \
--base "develop" \
--head "$MERGEBACK_BRANCH" \
--title "chore: merge release v${{ inputs.version }} back to develop" \
--body "Merge release branch back to develop to include version bump and changelog updates."
else
echo "PR $MERGEBACK_BRANCH → develop already exists (#$EXISTING_DEVELOP_PR), skipping."
fi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# Create a draft release so the release notes page exists immediately.
# The tag is deleted right after: the publish workflow re-creates it when
# the release PR is merged into master, which is the canonical tag point.
# Skipped if a release for this version already exists from a previous run.
- name: Create a draft release
run: |
TAG_NAME="v${{ inputs.version }}"
if gh release view "$TAG_NAME" > /dev/null 2>&1; then
echo "Release $TAG_NAME already exists, skipping."
else
TITLE="OpenCRVS - $TAG_NAME"
NOTES="Release notes for version ${{ inputs.version }}"
git tag "$TAG_NAME"
git push origin "$TAG_NAME"
gh release create "$TAG_NAME" \
--title "$TITLE" \
--notes "$NOTES" \
--draft
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Delete the tag
run: |
TAG_NAME="v${{ inputs.version }}"
if git ls-remote --exit-code --tags origin "$TAG_NAME" > /dev/null 2>&1; then
git tag -d "$TAG_NAME" 2>/dev/null || true
git push origin ":refs/tags/$TAG_NAME"
else
echo "Tag $TAG_NAME does not exist on remote, skipping."
fi
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Changelog

## 1.9.15 Release Candidate

## 1.9.14 Release Candidate

### Fixes

- Improved internet connectivity checks by replacing ICMP ping with HTTPS endpoint validation and detailed diagnostics for restricted environments.
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ redis:
postgres:
auth_mode: auto
host: postgres-0.postgres.opencrvs-deps-{{env}}.svc.cluster.local

imagePullSecrets:
# Default value for credentials created while yarn environment:init
- name: dockerhub-credentials
platform:
imagePullSecrets:
# Default value for credentials created while yarn environment:init
- name: dockerhub-credentials

countryconfig:
secrets:
Expand Down
1 change: 1 addition & 0 deletions infrastructure/server-setup/tasks/all/tools.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- zip
- python3-pip
- python3-kubernetes
- pigz

- name: 'Ensure python-3pexpect is absent'
apt:
Expand Down
2 changes: 2 additions & 0 deletions infrastructure/server-setup/tasks/k8s/ufw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
- { port: 7946, proto: "udp" } # Used by some CNIs (e.g., Flannel, Weave)
- { port: 8472, proto: "udp" } # VXLAN (Flannel/Calico; verify if needed)
- { port: 4789, proto: "udp" } # VXLAN (Calico; verify if needed)
- { port: 179, proto: "tcp" } # BGP (Calico)
- { port: 179, proto: "udp" } # BGP (Calico)
# Expose traefik on node port
# Rules are required for internet facing load balancer (if exists)
- { port: 30080, proto: "tcp" } # NodePort HTTP
Expand Down
8 changes: 4 additions & 4 deletions scripts/bootstrap/node-runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ if [[ ! -f "runner.tar.gz" ]]; then
fi

echo "[+] Download URL: $RUNNER_LATEST_URL into folder $(pwd)"
if ! curl -fL "$RUNNER_LATEST_URL" -o runner.tar.gz; then
if ! sudo -u $RUNAS_USER curl -fL "$RUNNER_LATEST_URL" -o runner.tar.gz; then
echo "❌ Failed to download runner archive."
exit 1
fi
Expand All @@ -111,9 +111,9 @@ else
fi

echo "[+] Extracting runner..."
tar xzf runner.tar.gz
sudo -u $RUNAS_USER tar xzf runner.tar.gz
echo "[+] Setting permissions... `pwd`"
chown -R $RUNAS_USER:$RUNAS_GROUP .
sudo chown -R $RUNAS_USER:$RUNAS_GROUP .
# --- GET REGISTRATION TOKEN ---
echo "[+] Requesting registration token..."
REG_TOKEN=$(curl -s -X POST \
Expand All @@ -133,7 +133,7 @@ sudo -u $RUNAS_USER ./config.sh \
# --- SETUP SYSTEMD SERVICE ---
echo "[+] Installing systemd service..."

sudo ./svc.sh install
sudo ./svc.sh install provision

# Fix service to run as specific user/group
SERVICE_FILE_PATH=$(ls /etc/systemd/system/actions.runner.*.service 2>/dev/null | head -n1)
Expand Down
Loading