Skip to content

feat: phase 1 mat-view refresh hardening #118

feat: phase 1 mat-view refresh hardening

feat: phase 1 mat-view refresh hardening #118

# =============================================================================
# Deploy to Dev
# =============================================================================
# Triggered on push to develop branch.
# Builds Docker image, scans for vulnerabilities, pushes to OpenShift registry,
# and deploys with Helm. Also rebuilds typesense-sync when its code changes.
# =============================================================================
name: Deploy to Dev
on:
push:
branches:
- develop
paths-ignore:
- ".github/**"
- "helm/eagle-api/README.md"
workflow_dispatch:
permissions: write-all
env:
OPENSHIFT_NAMESPACE_TOOLS: 6cdc9e-tools
OPENSHIFT_NAMESPACE_DEV: 6cdc9e-dev
IMAGE_NAME: eagle-api
SYNC_IMAGE_NAME: typesense-sync
APP_NAME: eagle-api
jobs:
install:
name: Install Dependencies
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [24.x]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Enable Corepack
run: corepack enable
- name: Setup node
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: "yarn"
- run: yarn install --immutable
lint:
name: Lint
runs-on: ubuntu-latest
needs: install
strategy:
matrix:
node-version: [24.x]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Enable Corepack
run: corepack enable
- name: Setup node
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: "yarn"
- run: yarn install --immutable
- name: Lint (stubbed)
run: |
echo "Linting skipped - not configured for eagle-api"
exit 0
test:
name: Test
runs-on: ubuntu-latest
needs: install
strategy:
matrix:
node-version: [24.x]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Enable Corepack
run: corepack enable
- name: Setup node
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: "yarn"
- run: yarn install --immutable
- run: yarn test
build:
name: Build
runs-on: ubuntu-latest
needs: install
strategy:
matrix:
node-version: [24.x]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Enable Corepack
run: corepack enable
- name: Setup node
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: "yarn"
- run: yarn install --immutable
scan:
name: Security Scan
runs-on: ubuntu-latest
needs: [lint, test, build]
outputs:
SHORT_SHA: ${{ steps.short-sha.outputs.SHA }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Get short SHA
id: short-sha
run: echo "SHA=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Build Docker image for scanning
uses: docker/build-push-action@v7
with:
context: .
push: false
tags: ${{ env.IMAGE_NAME }}:${{ steps.short-sha.outputs.SHA }}
load: true
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.IMAGE_NAME }}:${{ steps.short-sha.outputs.SHA }}
format: 'table'
exit-code: '1'
ignore-unfixed: true
vuln-type: 'os,library'
severity: 'CRITICAL,HIGH'
env:
TRIVY_DB_REPOSITORY: ghcr.io/aquasecurity/trivy-db:2
push:
name: Push Image
runs-on: ubuntu-latest
needs: scan
outputs:
IMAGE_TAG: ${{ steps.push.outputs.digest }}
SHORT_SHA: ${{ needs.scan.outputs.SHORT_SHA }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Login to OpenShift registry
uses: docker/login-action@v4
with:
registry: ${{ secrets.OPENSHIFT_REPOSITORY }}
username: ${{ secrets.OPENSHIFT_REPOSITORY_USERNAME }}
password: ${{ secrets.OPENSHIFT_REPOSITORY_PASSWORD }}
- name: Build and push Docker image
id: push
uses: docker/build-push-action@v7
with:
context: .
push: true
tags: |
${{ secrets.OPENSHIFT_REPOSITORY }}/${{ env.OPENSHIFT_NAMESPACE_TOOLS }}/${{ env.IMAGE_NAME }}:dev
${{ secrets.OPENSHIFT_REPOSITORY }}/${{ env.OPENSHIFT_NAMESPACE_TOOLS }}/${{ env.IMAGE_NAME }}:ci-latest
${{ secrets.OPENSHIFT_REPOSITORY }}/${{ env.OPENSHIFT_NAMESPACE_TOOLS }}/${{ env.IMAGE_NAME }}:${{ needs.scan.outputs.SHORT_SHA }}
deploy:
name: Deploy to Dev
needs: push
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Install OpenShift CLI
run: |
curl -LO "https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest/openshift-client-linux.tar.gz"
tar -xvzf openshift-client-linux.tar.gz
sudo mv oc /usr/local/bin/
rm -f openshift-client-linux.tar.gz
- name: Install Helm
run: |
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
helm version
- name: Log into OpenShift
run: oc login --token=${{ secrets.OPENSHIFT_TOKEN }} --server=${{ secrets.OPENSHIFT_URL }}
- name: Tag images in OpenShift ImageStream
run: |
echo "Tagging images in OpenShift ImageStream..."
oc -n ${{ env.OPENSHIFT_NAMESPACE_TOOLS }} tag \
${{ env.IMAGE_NAME }}:${{ needs.push.outputs.SHORT_SHA }} ${{ env.IMAGE_NAME }}:dev
oc -n ${{ env.OPENSHIFT_NAMESPACE_TOOLS }} tag \
${{ env.IMAGE_NAME }}:${{ needs.push.outputs.SHORT_SHA }} ${{ env.IMAGE_NAME }}:ci-latest
- name: Deploy with Helm
run: |
helm upgrade --install ${{ env.APP_NAME }} ./helm/${{ env.APP_NAME }} \
--namespace ${{ env.OPENSHIFT_NAMESPACE_DEV }} \
--values ./helm/${{ env.APP_NAME }}/values-dev.yaml \
--set image.tag=dev \
--wait --timeout=5m
echo "Restarting deployment to pull updated image..."
oc rollout restart deployment/${{ env.APP_NAME }} -n ${{ env.OPENSHIFT_NAMESPACE_DEV }}
- name: Verify deployment
run: |
echo "Waiting for rollout to complete..."
oc rollout status deployment/${{ env.APP_NAME }} -n ${{ env.OPENSHIFT_NAMESPACE_DEV }} --timeout=5m
echo "Deployment successful!"
oc get pods -n ${{ env.OPENSHIFT_NAMESPACE_DEV }} -l app.kubernetes.io/name=${{ env.APP_NAME }}
# Verify MongoDB deployment if enabled
if oc get deployment eagle-api-mongodb -n ${{ env.OPENSHIFT_NAMESPACE_DEV }} &>/dev/null; then
echo ""
echo "Verifying MongoDB deployment..."
oc rollout status deployment/eagle-api-mongodb -n ${{ env.OPENSHIFT_NAMESPACE_DEV }} --timeout=3m
echo "✓ MongoDB deployment verified"
fi
build-sync:
name: Build Sync Image
needs: scan
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Login to OpenShift registry
uses: docker/login-action@v4
with:
registry: ${{ secrets.OPENSHIFT_REPOSITORY }}
username: ${{ secrets.OPENSHIFT_REPOSITORY_USERNAME }}
password: ${{ secrets.OPENSHIFT_REPOSITORY_PASSWORD }}
- name: Build and push sync image
uses: docker/build-push-action@v7
with:
context: ./typesense-sync
push: true
tags: |
${{ secrets.OPENSHIFT_REPOSITORY }}/${{ env.OPENSHIFT_NAMESPACE_TOOLS }}/${{ env.SYNC_IMAGE_NAME }}:dev
${{ secrets.OPENSHIFT_REPOSITORY }}/${{ env.OPENSHIFT_NAMESPACE_TOOLS }}/${{ env.SYNC_IMAGE_NAME }}:${{ needs.scan.outputs.SHORT_SHA }}
deploy-sync:
name: Deploy Sync to Dev
needs: [deploy, build-sync]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Install OpenShift CLI
run: |
curl -LO "https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest/openshift-client-linux.tar.gz"
tar -xvzf openshift-client-linux.tar.gz
sudo mv oc /usr/local/bin/
rm -f openshift-client-linux.tar.gz
- name: Install Helm
run: |
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
helm version
- name: Log into OpenShift
run: oc login --token=${{ secrets.OPENSHIFT_TOKEN }} --server=${{ secrets.OPENSHIFT_URL }}
- name: Upgrade Typesense chart
run: |
helm upgrade --install typesense ./helm/typesense \
--namespace ${{ env.OPENSHIFT_NAMESPACE_DEV }} \
--values ./helm/typesense/values-dev.yaml \
--wait --timeout=5m
- name: Restart sync deployment
run: |
echo "Restarting typesense-sync deployment to pick up new image..."
if oc get deployment typesense-typesense-sync -n ${{ env.OPENSHIFT_NAMESPACE_DEV }} &>/dev/null; then
oc rollout restart deployment/typesense-typesense-sync -n ${{ env.OPENSHIFT_NAMESPACE_DEV }}
oc rollout status deployment/typesense-typesense-sync -n ${{ env.OPENSHIFT_NAMESPACE_DEV }} --timeout=3m
echo "✓ Sync deployment restarted"
else
echo "⚠ typesense-sync deployment not found — skipping"
fi
smoke-test:
name: Smoke Test Dev
needs: [deploy, deploy-sync]
runs-on: ubuntu-latest
environment:
name: dev
strategy:
matrix:
node-version: [24.x]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Enable Corepack
run: corepack enable
- name: Setup node
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: "yarn"
- run: yarn install --immutable
- name: Wait for API to be ready
run: |
echo "Waiting 30s for pod to stabilise after rollout..."
sleep 30
for i in $(seq 1 10); do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://eagle-dev.apps.silver.devops.gov.bc.ca/api/health || true)
if [ "$STATUS" = "200" ]; then
echo "API is ready (attempt $i)"
break
fi
echo "Attempt $i: API returned $STATUS, retrying in 15s..."
sleep 15
done
- name: Run smoke tests
run: yarn test:smoke
env:
SMOKE_TEST_URL: https://eagle-dev.apps.silver.devops.gov.bc.ca
SMOKE_API_KEY: ${{ secrets.SMOKE_API_KEY }}