Deployment Pipeline - bcgov/eagle-dev-guides GitHub Wiki

Deployment Pipeline

This document describes the CI/CD pipeline used by Eagle applications for building, testing, and deploying to OpenShift.

Quick Reference

Deploy to Test/Prod requires semantic version tag (v1.2.3 format):

# Check existing tags
git ls-remote --tags origin | grep -E 'v[0-9]+\.[0-9]+\.[0-9]+$' | tail -3

# Deploy to test (workflow creates Git tag and GitHub release automatically)
gh workflow run "Deploy to Test" --repo bcgov/eagle-api -f version=v2.1.1

# Deploy to prod (same version)
gh workflow run "Deploy to Prod" --repo bcgov/eagle-api -f version=v2.1.1

IMPORTANT: Do NOT create Git tags manually. The "Deploy to Test" workflow creates them automatically if they don't exist.

Repository Deployment Differences

All Eagle repositories now use a consistent deployment pattern:

Repository Deployment Type Managed By Workflow Pattern
eagle-public Deployment Helm Build → Scan → Push → Helm upgrade
eagle-admin Deployment Helm Build → Scan → Push → Helm upgrade
eagle-api Deployment Helm Build → Scan → Push → Helm upgrade
eao-nginx (rproxy) Deployment Helm Build → Scan → Push → Helm upgrade

Note: eagle-api (Feb 2026) and eao-nginx (Feb 2026) were migrated from DeploymentConfig + S2I builds to the modern Helm + Dockerfile pattern.

Repository-Specific Details

eagle-api:

  • Node Version: Node 24 (eagle-public also uses Node 24)
  • Test Framework: Mocha (eagle-public uses Vitest, eagle-admin uses Karma)
  • Dependencies: Modern packages - axios ^1.8.2, bcryptjs, jwks-rsa ^3.2.2, sharp ~0.33.5

eao-nginx (rproxy):

  • Base Image: nginx:1.27-alpine (routes to eagle-public, eagle-admin, eagle-api, penguin-analytics)
  • See eao-nginx README for configuration details

Pipeline Overview (eagle-public / eagle-admin / eagle-api)

flowchart TD
    subgraph PR["Pull Request Phase"]
        A[Push to feature branch] --> B[PR Checks Workflow]
        B --> C{Lint}
        B --> D{Test}
        B --> E{Build}
        C & D & E -->|All Pass| F[Ready for Review]
    end
    
    subgraph Dev["Deploy to Dev"]
        G[Merge to develop] --> H[Install Dependencies]
        H --> I[Lint + Test + Build]
        I --> J[🔒 Trivy Security Scan]
        J -->|CRITICAL/HIGH found| X[❌ Deployment Blocked]
        J -->|Clean| K[Push to Registry]
        K --> L[Helm Deploy to Dev]
        L --> M[Tag: dev, ci-latest, SHA]
    end
    
    subgraph Test["Deploy to Test"]
        N[Manual Trigger] --> O[Input Version: v1.2.3]
        O --> P{Git Tag Exists?}
        P -->|No| Q[Create Git Tag]
        Q --> R[Create GitHub Release]
        R --> S[Tag ci-latest → v1.2.3]
        P -->|Yes| T[Verify Image Exists]
        S --> U[Tag v1.2.3 → test]
        T --> U
        U --> V[Helm Upgrade]
    end
    
    subgraph Prod["Deploy to Prod"]
        W[Manual Trigger] --> Y[Input Version: v1.2.3]
        Y --> Z[Verify Git Tag Exists]
        Z --> AA[Verify Image Tag Exists]
        AA --> AB[Tag v1.2.3 → prod]
        AB --> AC[Rollout Restart]
    end
    
    F -.->|Merge| G
    M -.->|Manual| N
    V -.->|Manual| W

Workflow Details

1. PR Checks (pr.yaml)

Trigger: Pull request to develop branch

Job Purpose Node Version
Install Cache dependencies 24.x (eagle-public), 22.x (eagle-admin/api)
Lint ESLint code quality 24.x (eagle-public), 22.x (eagle-admin/api)
Test Unit tests: Vitest (eagle-public), Karma (eagle-admin), Mocha (eagle-api) 24.x (eagle-public), 22.x (eagle-admin/api)
Build Production build 24.x (eagle-public), 22.x (eagle-admin/api)

All jobs must pass before merge is allowed.

2. Deploy to Dev (deploy-to-dev.yaml)

Trigger: Push to develop branch (or manual dispatch)

flowchart LR
    subgraph Jobs
        Install --> Lint & Test & Build
        Lint & Test & Build --> Scan
        Scan --> Push
        Push --> Deploy
    end
Job Description
Install Install and cache yarn dependencies
Lint Run ESLint
Test Run unit tests
Build Build production bundle
Scan 🔒 Trivy vulnerability scan (blocks on CRITICAL/HIGH)
Push Push image with tags: dev, ci-latest, {SHA}
Deploy Helm upgrade to dev namespace + tag images in ImageStream

Security Scanning

The Trivy scan step blocks deployment if CRITICAL or HIGH severity vulnerabilities are found:

- name: Run Trivy vulnerability scanner
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: ${{ env.IMAGE_NAME }}:${{ steps.short-sha.outputs.SHA }}
    exit-code: '1'
    ignore-unfixed: true
    severity: 'CRITICAL,HIGH'

3. Deploy to Test (deploy-to-test.yaml)

Trigger: Manual workflow dispatch with version input

Input Required:

  • version: Semantic version tag (e.g., v1.2.3)

Workflow Logic

flowchart TD
    A[Input: v1.2.3] --> B{Validate Format}
    B -->|Invalid| X[❌ Error: Must be v#.#.#]
    B -->|Valid| C{Check if Tag Exists}
    C -->|New Version| D[Create Git Tag]
    D --> E[Create GitHub Release]
    E --> F[Tag ci-latest → v1.2.3]
    C -->|Existing Version| G[Verify Image Exists]
    G -->|Not Found| Y[❌ Error: Image missing]
    G -->|Found| H[Rollback Mode]
    F --> I[Tag v1.2.3 → test]
    H --> I
    I --> J[Helm Upgrade to Test]

New Deployment Flow:

  1. Validates version format (v1.2.3)
  2. Creates Git tag on current develop HEAD
  3. Creates GitHub Release with auto-generated notes
  4. Tags ci-latest image as v1.2.3
  5. Tags v1.2.3 as test
  6. Installs Helm
  7. Runs helm upgrade --install with values-test.yaml
  8. Updates deployment configuration and pulls new image

Rollback Flow (existing version):

  1. Validates version format
  2. Detects tag already exists
  3. Verifies image tag exists in registry
  4. Tags existing v1.2.3 as test
  5. Installs Helm
  6. Runs helm upgrade --install to ensure correct configuration
  7. Deploys existing version

Why Helm in Test Workflow?

Unlike dev (which runs Helm on every merge), test deployments are infrequent. Using Helm ensures:

  • Reproducibility: Deployment can be fully recreated if deleted
  • Configuration Consistency: Environment-specific values always applied
  • Self-healing: Corrects any manual configuration drift

This is especially important for eagle-api which has complex secret references that differ between environments.

4. Deploy to Prod (deploy-to-prod.yaml)

Trigger: Manual workflow dispatch with version input

Input Required:

  • version: Semantic version tag (e.g., v1.2.3)

Requirements

  • Git tag must exist (created during test deployment)
  • Image tag must exist in registry
flowchart TD
    A[Input: v1.2.3] --> B{Validate Format}
    B -->|Invalid| X[❌ Error]
    B -->|Valid| C{Git Tag Exists?}
    C -->|No| Y[❌ Error: Deploy to test first]
    C -->|Yes| D{Image Tag Exists?}
    D -->|No| Z[❌ Error: Image not found]
    D -->|Yes| E[Tag v1.2.3 → prod]
    E --> F[Rollout Restart]

Image Tagging Strategy

flowchart LR
    subgraph "Dev Deploy"
        A[Build] --> B[dev]
        A --> C[ci-latest]
        A --> D[abc1234]
    end
    
    subgraph "Test Deploy"
        C --> E[v1.2.3]
        E --> F[test]
    end
    
    subgraph "Prod Deploy"
        E --> G[prod]
    end
Tag When Created Mutable Purpose
dev Every dev deploy Yes Latest dev build
ci-latest Every dev deploy Yes Promotion candidate
{SHA} Every dev deploy No Audit trail
v1.2.3 Test deploy (new) No Release version
test Every test deploy Yes Current test image
prod Every prod deploy Yes Current prod image

Environment URLs

Environment Public Admin API
Dev eagle-dev.apps.silver... /admin/ /api/
Test eagle-test.apps.silver... /admin/ /api/
Prod projects.eao.gov.bc.ca /admin/ /api/

Running Workflows

Deploy to Dev

Automatic on merge to develop, or manual:

  1. Go to ActionsDeploy to Dev
  2. Click Run workflow
  3. Select branch (usually develop)

Deploy to Test

  1. Go to ActionsDeploy to Test
  2. Click Run workflow
  3. Enter version (e.g., v1.2.3)
  4. Click Run workflow

Deploy to Prod

  1. Go to ActionsDeploy to Prod
  2. Click Run workflow
  3. Enter same version deployed to test (e.g., v1.2.3)
  4. Click Run workflow

Troubleshooting

Trivy Scan Failing

The build is blocked due to security vulnerabilities. Options:

  1. Update base image or dependencies to patch vulnerabilities
  2. Add apk upgrade --no-cache in Dockerfile to get latest patches
  3. Review vulnerabilities - if false positives, update .trivyignore

Deploy Failing - Deployment Not Found

Test workflows now use helm upgrade --install which will automatically create the deployment if it doesn't exist. This ensures reproducibility - if the deployment is accidentally deleted, the next workflow run will recreate it with the correct configuration.

For first-time setup:

  1. Ensure required secrets exist in the namespace (see Helm Charts)
  2. Run the deploy-to-test workflow with a version tag
  3. Helm will create all resources (Deployment, Service, Route, ConfigMap, PVC)

Version Tag Already Exists

This is normal for rollbacks. The workflow will:

  1. Skip release creation
  2. Verify the image tag exists
  3. Deploy the existing version

Related Documentation