Skip to content
Public template

MIT License Merge Analysis Scheduled

QuickStart for OpenShift

Pull Request-Based Workflows with Sample Stack

This repository provides a template to rapidly deploy a modern web application stack to OpenShift using GitHub Actions, incorporating best practices for CI/CD, security, and observability. By hitting the ground running we can save weeks‑to‑months of development time, receive regular updates, and built‑in Maintenance Mode Automation, which allows an app to go on autopilot for security and dependency updates. This limits developmer involvement to critical issues only, drastically reducing labor costs and freeing up resources for higher priority work.

Includes:

  • Pull Request-based pipeline
  • Sandboxed development environments
  • Gated/controlled production deployments (optional)
  • Container publishing (ghcr.io) and importing (OpenShift)
  • Security, vulnerability, infrastructure, and container scan tools
  • Out-of-the-box alignment with OWASP ASVS Level 1 & 2 controls (see SECURITY.md)
  • Automatic dependency patching via bcgov/renovate-config
  • Maintenance Mode Automation (hands‑off updates, low‑dev mode) via the same Renovate config
  • Enforced code reviews and workflow jobs (pass|fail)
  • OpenShift Templates
  • Prometheus Metrics export from Backend/Frontend
  • Resource Tuning with Horizontal Pod Autoscaler
  • Affinity and anti-affinity for Scheduling on different worker nodes
  • Rolling updates with zero downtime in PROD
  • Database Migrations with Flyway
  • Pod disruption budgets for high availability
  • Self-healing through probes/checks (startup, readiness, liveness)
  • Sample application stack:
    • Database: Postgres, Flyway
    • Frontend: TypeScript, Caddy Server with Coraza WAF
    • Backend: TypeScript, Nest.js

Setup

Setup takes an hour or less. Scripts in scripts/ do the GitHub and OpenShift parts. Each one previews its changes by default, makes them only with --apply, and is safe to re-run: it changes only what differs and leaves everything else alone. Running any of them without --apply verifies the setup: it ends with All set: nothing to change., or exits non-zero with the number of things to change. It confirms secrets exist but can't verify their values. Run them yourself, with your own logins.

Checklist

  1. Accounts (by hand): GitHub accounts for the team. For BC Government, also IDIR accounts and membership in the bcgov GitHub organization (instructions).

  2. OpenShift namespaces (by hand): request a project set (DEV, TEST and PROD) from Platform Services at the registry. You get a licence plate, e.g. abc123, and namespaces abc123-dev, abc123-test and abc123-prod.

  3. Create the repository (by hand): use this repository as a template, with bcgov/quickstart-openshift selected under Repository template.

  4. Log in (by hand): gh auth login, then in the OpenShift console select your name (top right) > Copy login command and paste it into a shell (oc login --token=... --server=...). You need admin rights on the repo and edit rights in all three namespaces. Then run steps 5 to 7 with one command, which previews by default and exits non-zero if anything needs changing; add --apply to make the changes:

    scripts/setup.sh --plate abc123 --reviewers alice,bcgov/my-team   # preview, then add --apply
  5. OpenShift deploy account: creates the github-actions service account, edit role binding and token Secret in each namespace.

    scripts/setup-openshift.sh --plate abc123          # preview, then add --apply
  6. GitHub environments, secrets and variables: creates the test and prod environments (PROD with required reviewers if you name them; without --reviewers it reports the current ones), and sets the OC_NAMESPACE variable and OC_TOKEN and DB_PASSWORD secrets for pull requests (repository level), TEST and PROD, plus the OC_SERVER variable. Without --plate it reads the plate from existing OC_NAMESPACE variables. It won't generate a DB_PASSWORD for a namespace that already has a database, since a new password would lock the app out. Secrets that are already set are never overwritten. Secret values are piped from oc or openssl straight into gh secret set; they're never printed or written to disk, and previews show only the secret's name.

    scripts/setup-environments.sh --plate abc123 --reviewers alice,bcgov/my-team   # preview, then add --apply
  7. GitHub repository settings: the main ruleset, pull request settings and private vulnerability reporting (see Repository Configuration).

    scripts/setup-github.sh                              # preview, then add --apply
  8. First pull request: open one to run the pipeline, then make the packages public (see Packages).

  9. Optional (by hand): SonarCloud, Renovate, Sysdig, a vanity URL with TLS, PROD deployment rules and team members, all described below.

Secrets, Variables and Environments

Workflows read these values. Repository-level values are used by pull request deploys; test and prod environment values override them for those deploys. Steps 5 and 6 set the required ones.

Environment Name Description
none vars.OC_SERVER OpenShift API server (repository-level)
none vars.OC_NAMESPACE PR namespace, <plate>-dev
none secrets.OC_TOKEN PR service token
none secrets.DB_PASSWORD PR database password
test vars.OC_NAMESPACE TEST namespace, <plate>-test
test secrets.OC_TOKEN TEST service token
test secrets.DB_PASSWORD TEST database password
prod vars.OC_NAMESPACE PROD namespace, <plate>-prod
prod secrets.OC_TOKEN PROD service token
prod secrets.DB_PASSWORD PROD database password
prod (opt) vars.ROUTE_HOST Vanity URL hostname (repository or environment)
prod (opt) secrets.TLS_CERTIFICATE Leaf certificate PEM for vanity URL
prod (opt) secrets.TLS_PRIVATE_KEY Private key PEM for vanity URL
prod (opt) secrets.TLS_CA_CERTIFICATE Issuing CA PEM for vanity URL
none (opt) secrets.SONAR_TOKEN_BACKEND, secrets.SONAR_TOKEN_FRONTEND See SonarCloud
none (opt) secrets.SYSDIG_API_TOKEN PROD alert sync

DB_PASSWORD is generated separately for each environment. Don't change it after the first deploy: PostgreSQL keeps its first password.

Copied the template before OC_NAMESPACE became a variable? Move it: gh variable set OC_NAMESPACE --body <plate>-dev, and the same with --env test / --env prod (or run scripts/setup-environments.sh --apply). The old secret is unused and can be deleted.

Optional Values

Set these by hand with gh secret set / gh variable set when you need them.

SYSDIG_API_TOKEN

Sysdig API token used to sync the PROD email-alert set on every merge. Sourced from the in-cluster Secret materialized by your SysdigTeam CR (BC Gov platform-services provisions this in your *-tools namespace). Optional — if unset, the monitor-prod step no-ops with a warning, so the deploy still succeeds.

  • Reference: ${{ secrets.SYSDIG_API_TOKEN }}
  • Alert templates live in monitoring/alerts/. Add or remove files to customize the alert set per app — see bcgov/action-sysdig-monitor for the template schema and placeholder vocabulary.

TLS_CERTIFICATE, TLS_PRIVATE_KEY, TLS_CA_CERTIFICATE

PEM-formatted certificates and private key for custom vanity URL TLS on the PROD frontend OpenShift Route. Optional — required only when vars.ROUTE_HOST is configured.

  • References: ${{ secrets.TLS_CERTIFICATE }}, ${{ secrets.TLS_PRIVATE_KEY }}, ${{ secrets.TLS_CA_CERTIFICATE }}
  • Validated and applied on-demand via the standalone .github/workflows/route-tls.yml workflow using bcgov/actions-openshift/route-tls, which checks key matching, CA chain, expiration, and archives previous certificates to an OpenShift secret.
  • Store these as prod environment secrets (not repository secrets), and configure the prod environment's deployment branches and tags to restrict access (e.g. to main or release tags); environment scoping alone does not prevent a pull-request job from requesting these secrets.
  • Do not pass PEMs or private keys as workflow_dispatch inputs—dispatch inputs are recorded in plaintext in workflow run logs. Rotation is handled by updating the prod secrets and triggering the Route TLS workflow with dry_run=true to validate, then dry_run=false to apply.

When receiving a certificate package from Entrust, map the files to GitHub secrets as follows:

Secret File in package Notes
TLS_CERTIFICATE <host>.pem Leaf certificate only (CN/SAN matches hostname).
TLS_PRIVATE_KEY <host>.key Unencrypted private key (BEGIN PRIVATE KEY). Never commit this.
TLS_CA_CERTIFICATE Entrust OV TLS Issuing RSA CA 2.pem Issuing intermediate CA only (one PEM).

Leave out root certificates (e.g. Sectigo Public Server Authentication Root R46.pem or USERTrust RSA Certification Authority.pem) because clients already have them in their trust stores. Omit <host>.csr (the signing request is finished).

Upload these secrets to the prod environment via GitHub CLI:

CERT_HOST='myapp.gov.bc.ca' # Replace with the certificate filename prefix
gh secret set TLS_CERTIFICATE --env prod < "${CERT_HOST}.pem"
gh secret set TLS_PRIVATE_KEY --env prod < "${CERT_HOST}.key"
gh secret set TLS_CA_CERTIFICATE --env prod < 'Entrust OV TLS Issuing RSA CA 2.pem'

ROUTE_HOST

Vanity URL hostname for the application (e.g., myapp.gov.bc.ca — hostname only, no scheme). Optional — can be set as a repository variable or environment variable on prod. When set, the standalone Route TLS workflow (.github/workflows/route-tls.yml) configures an OpenShift Route with custom TLS for the frontend service.

  • Reference: ${{ vars.ROUTE_HOST }}

PROD Deployment Branches and Tags (optional)

By default, an environment allows deployments from any branch or tag ("No restriction"). To ensure pull requests and untrusted branches cannot access production secrets without adding human approval gates, configure deployment restrictions:

  1. Select Settings > Environments > prod
  2. Under Deployment branches and tags, change the dropdown to Selected branches and tags
  3. Click Add deployment branch or tag rule:
    • To gate by branch: select Branch and enter main (or your protected release branch).
    • To gate by release tag: select Tag and enter a pattern like v*.*.* or v* so only release tags can trigger deployment.

Releases (optional)

Two workflows can deploy PROD, and both are active by default:

  • merge.yml deploys every merge to TEST, runs the tests, then deploys PROD by PR number.
  • release.yml deploys a published GitHub release to PROD. It finds the PR that the release's commit came from and deploys that PR's images, the same ones merge.yml deployed. Nothing is rebuilt.

To make PROD release-only, comment out the deploy-prod, monitor-prod and promote jobs in merge.yml. Merges then go to TEST and stop, and PROD changes only when you publish a release.

Notes:

  • Publish releases from a commit on main that was merged from a PR. Commits pushed straight to main have no PR images to deploy.
  • If the prod environment limits deployment branches and tags, add a tag rule for your release tags (e.g. v*), or releases can't deploy.
  • Both workflows share a concurrency group, so they never deploy PROD at the same time.

Updating Dependencies

Dependabot and Mend Renovate can both provide dependency updates using pull requests. Dependabot is simpler to configure, while Renovate is much more configurable and lighter on resources.

Renovate

A configuration file (renovate.json) is included with this template that sources configuration from our renovate repository.

Tip

Once Renovate is set up, you can enable Maintenance Mode Automation by following the checklist in the Maintenance Mode Automation section of this README. This will let Renovate auto‑merge safe updates after all CI checks pass.

BC Government employees can request having the Renovate and Renovate Approve GitHub Apps installed on their repository through the CITZ Service Desk. Most others can add their repositories directly from the Renovate and Renovate Approve GitHub Apps.

Dependabot

Dependabot is no longer recommended as an alternative to Renovate for generating security, vulnerability and dependency pull requests. It can still be used to generate warnings under the GitHub Security tab, which is only viewable by repository administrators.

Code Quality with SonarCloud

SonarCloud performs static code analysis, test coverage tracking, and quality gate checks via the bcgov/action-test-and-analyse action in .github/workflows/analysis.yml. SonarCloud integration is optional—the test suites and CI pipeline run successfully without it.

BC Government employees can request SonarCloud projects via devops-requests (select Request for import GitHub repository on SonarCloud) or directly through the CITZ Service Desk.

Onboarding Steps

Before submitting the request, ensure the designated project administrator has logged in to the SonarCloud console under bcgov-sonarcloud using their GitHub account.

Fill out the intake form using the following selections:

Field Selection Notes
GitHub username <admin-username> Must be the user who logged into SonarCloud above; will be assigned project administrator.
GitHub Repo URL https://github.com/bcgov/<repo> Full repository URL.
New Code Definition Previous version Quality gates evaluate changes relative to previous releases rather than a rolling day count.
Setup as a monorepo Yes Quickstart repositories contain both backend and frontend.
Additional Comments backend, frontend Explicitly list component names so separate SonarCloud sub-projects are created.

Post-Provisioning Configuration

Once the platform team provisions the projects, two separate SonarCloud projects are created (one for backend and one for frontend):

  1. Generate analysis tokens in SonarCloud for both projects and save them as repository secrets: SONAR_TOKEN_BACKEND and SONAR_TOKEN_FRONTEND. Both tokens are required; this repository does not use a single shared SONAR_TOKEN.
  2. Update -Dsonar.projectKey in .github/workflows/analysis.yml for both jobs to match your repository (e.g. <repo>_backend and <repo>_frontend instead of quickstart-openshift_*).

Dependency Scanning with Knip

This repository uses Knip for dependency scanning to identify unused dependencies and exports. Knip runs automatically as part of the Analysis workflow via the bcgov/action-test-and-analyse action.

Note: As a template repository, Knip runs in warning mode (non-blocking) to allow teams to customize dependencies without build failures. Teams can optionally change dep_scan: warning to dep_scan: error in their forks to enforce dependency scanning as a blocking check.

Handling Unused Dependencies

When Knip identifies unused dependencies, you have two options:

  1. Remove the dependency - If it's truly unused, remove it from package.json
  2. Report as false positive - If the dependency is used but not detected by static analysis

Reporting False Positives

Do not create team-specific knip.config.ts files. All Knip configuration is managed centrally in the upstream action repository.

If you encounter a false positive (a dependency that is used but flagged as unused), report it upstream:

  1. Verify it's a false positive by checking:

    • Is it exported from a utility file (e.g., test-utils.tsx)?
    • Is it used via dynamic imports?
    • Is it required by build tools or other dependencies?
    • Is it used in configuration files that Knip doesn't analyze?
  2. Open a PR to the upstream repository:

  3. Include justification in your PR:

    • Why it's a false positive
    • How the dependency is used
    • Example: "Exported from test-utils files for use in tests but may not be directly imported yet. Common pattern in testing utilities."

Example: Reporting a False Positive

If @testing-library/user-event is flagged but exported from test-utils.tsx:

Upstream PR to bcgov/action-test-and-analyse/.knip.json:

{
  "ignoreDependencies": [
    "swagger-ui-express",
    "rimraf",
    "@types/node",
    "@types/react",
    "@types/react-dom",
    "@testing-library/user-event"
  ],
  "ignoreBinaries": [
    "rimraf"
  ]
}

PR Description:

Add @testing-library/user-event to ignoreDependencies

This dependency is exported from test-utils files for use in tests but may not be directly imported yet. This is a common pattern in testing utilities where dependencies are re-exported for convenience.

Common False Positive Patterns

  • Exported APIs: Dependencies exported from utility files (like test-utils.tsx) that are intended for use but may not be directly imported yet
  • Indirect usage: Dependencies used by build tools, scripts, or other dependencies that static analysis can't detect
  • Dynamic imports: Dependencies loaded via dynamic imports or string-based requires
  • Configuration files: Dependencies used in config files that aren't detected by static analysis
  • Type-only imports: TypeScript type-only imports that are stripped at runtime

Repository Configuration

scripts/setup-github.sh (checklist step 7) sets:

  • Ruleset main on the default branch: blocks deletion and force pushes; requires a pull request with 1 approval and resolved conversations, merged by squash only; requires CodeQL code scanning results with no alerts at high or higher; and requires these status checks, which must be up to date with main:

    • PR Results (PR workflow)
    • Analysis Results (Analysis workflow)
    • Validate Results (PR Validate workflow)

    Each is the summary job of a workflow that runs on every pull request. The jobs they summarize (builds, deploys, tests, scans) are left out because they're skipped when their paths don't change, which would block merges. Repository admins may bypass the ruleset only by merging a pull request. Trivy results are still reported to the Security tab, but Trivy is deliberately not a merge gate because it fails often. Other rules already in the ruleset (e.g. Copilot code review) are kept.

  • Pull requests: squash merging only, defaulting to the pull request title; suggest updating branches; allow auto-merge; delete head branches after merge.

  • Private vulnerability reporting, which SECURITY.md points reporters to.

Packages

Packages are available from your repository (link on right). All should have visibility set to public for the workflows to run successfully.

E.g. https://github.com/bcgov/quickstart-openshift/packages

Adding Team Members

Don't forget to add your team members!

  1. Select Settings (gear, top right) *> Collaborators and teams (under Access)
  2. Click Add people or Add teams
  3. Use the search box to find people or teams
  4. Choose a role (read, triage, write, maintain, admin)
  5. Click Add

Security & OWASP ASVS Alignment

This repository is architected and hardened out-of-the-box to align with Levels 1 and 2 of the OWASP Application Security Verification Standard (ASVS) v4.0.3. A detailed security mapping matrix is documented in SECURITY.md, detailing our implementation of:

  • Active WAF Defense: Inline Coraza WAF running inside the Caddy reverse proxy.
  • Tiered Isolation: NetworkPolicies enforcing network boundaries between the frontend, backend, and database tiers.
  • Platform/Container Hardening: Read-only root filesystems, non-root execution, privilege escalation blocks, default seccomp profiles, and drop capabilities.
  • Build-Time & Dynamic Testing: Automated static analysis (Trivy, CodeQL), dependency auditing (Renovate, Knip), and weekly dynamic vulnerability scans (OWASP ZAP).

Container Hardening & Writable Paths

Out of the box, the deployment templates in this repository enforce strict container-level security contexts:

  • Read-Only Root Filesystems: Containers cannot write to the root filesystem at runtime (readOnlyRootFilesystem: true).
  • Non-Root Execution: Containers are blocked from executing as the root user (runAsNonRoot: true).
  • Privilege Escalation Blocked: Containers cannot gain more privileges than their parent process (allowPrivilegeEscalation: false).

Handling Dynamic Writes

If your application requires writing files at runtime (e.g., temporary caches, uploaded attachments, config logs):

  1. Do not disable the security context.
  2. Mount a memory-backed (tmpfs) volume on the writable path using emptyDir in openshift.deploy.yml:
              volumeMounts:
                - mountPath: /tmp
                  name: tmp
          volumes:
            - name: tmp
              emptyDir:
                medium: Memory
                sizeLimit: 256Mi
  3. Always specify a sizeLimit. Running memory-backed volumes without a size limit allows a runaway container to exhaust the host node's RAM, triggering an out-of-memory (OOM) storm that will terminate other pods.

Workflows

These workflows and actions enforce a pull request based flow.

flowchart TD
    A1(PR_Env_1) -->|tests| B
    A2(PR_Env_2) -->|tests| B
    A3(PR_Env_3) -->|tests| B
    Ad@{ shape: text, label: "..." }
    An(PR Env n) -->|tests| B
    B(TEST_Env) -->|tests| C(PROD_Env)

    %% Define styles with good contrast for light/dark modes
    %% PR Environments (using distinct, reasonably bright colors)
    style A1 fill:#ffeadb,stroke:#ff8c42,stroke-width:2px,color:#5c3d1e  %% Light Orange/Orange
    style A2 fill:#dbeaff,stroke:#4285f4,stroke-width:2px,color:#1a3f7a  %% Light Blue/Blue
    style A3 fill:#dfffea,stroke:#34a853,stroke-width:2px,color:#154b24  %% Light Green/Green
    style An fill:#fce8ff,stroke:#a142f4,stroke-width:2px,color:#4d1e7a  %% Light Purple/Purple
    %% TEST Environment
    style B fill:#e6f4ea,stroke:#34a853,stroke-width:3px,color:#154b24  %% Lighter Green/Green
    %% PROD Environment
    style C fill:#fff4d8,stroke:#fbbc05,stroke-width:3px,color:#7a5f01  %% Light Gold/Gold

    %% Link style
    linkStyle default stroke:#757575,stroke-width:1px
Loading

Here's a more detailed view showing a single pull request.

flowchart TD
    A(Developer)
    B(Pull Request)
    Ba(Build Images,<br/>Deploy Images,<br/>E2E Tests)
    Bb(Unit Tests,<br/>Security Analysis,<br/>Vulnerability Analysis)
    Bc(Validate PR Title,<br/>Provide User Feedback)
    Bd(Code Review)
    C{Verify Results}
    D(Merge)
    E(Deploy Images to TEST)
    F{E2E Tests,<br/>Load Tests,<br/>Analysis}
    G(Deploy Images to PROD)
    H(Tag Images as PROD)

    A --> B
    B --> Ba --> C
    B --> Bb --> C
    B --> Bc --> C
    B --> Bd --> C
    C -- fail --> A
    C -- pass --> D --> E --> F
    F -- fail --> A
    F -- pass --> G --> H

    %% Define styles with good contrast for light/dark modes
    %% Developer & PR Actions (Blue)
    style A fill:#dbeaff,stroke:#4285f4,stroke-width:2px,color:#1a3f7a
    style B fill:#dbeaff,stroke:#4285f4,stroke-width:2px,color:#1a3f7a
    %% PR Checks & Validation (Light Green)
    style Ba fill:#e6f4ea,stroke:#34a853,stroke-width:2px,color:#154b24
    style Bb fill:#e6f4ea,stroke:#34a853,stroke-width:2px,color:#154b24
    style Bc fill:#e6f4ea,stroke:#34a853,stroke-width:2px,color:#154b24
    %% Code Review (Light Gold - requires attention)
    style Bd fill:#fff4d8,stroke:#fbbc05,stroke-width:2px,color:#7a5f01
    %% Decision Points (Purple)
    style C fill:#fce8ff,stroke:#a142f4,stroke-width:2px,color:#4d1e7a
    style F fill:#fce8ff,stroke:#a142f4,stroke-width:2px,color:#4d1e7a
    %% Merge & TEST Deployment (Green)
    style D fill:#dfffea,stroke:#34a853,stroke-width:2px,color:#154b24
    style E fill:#e6f4ea,stroke:#34a853,stroke-width:3px,color:#154b24
    %% PROD Deployment & Tagging (Gold)
    style G fill:#fff4d8,stroke:#fbbc05,stroke-width:3px,color:#7a5f01
    style H fill:#fff4d8,stroke:#fbbc05,stroke-width:3px,color:#7a5f01

    %% Link style
    linkStyle default stroke:#757575,stroke-width:1px
Loading

Pull Request

Runs on pull request submission.

  • Provides safe, sandboxed deployment environments
  • Build action pushes to GitHub Container Registry (ghcr.io)
  • Build triggers select new builds vs reusing builds
  • Deploy only when changes are made
  • Deployment includes curl checks and optional penetration tests
  • Run tests (e2e, load, integration) when changes are made
  • Posts sticky comment with deployment links when deployments occur
  • Other checks and updates as required

Validation

Runs on pull request submission.

  • Enforces conventional commits in PR title

Analysis

Runs on pull request submission or merge to the default branch.

  • Unit tests (should include coverage)
  • CodeQL/GitHub security reporting (now handled as GitHub default!)
  • Trivy password, vulnerability and security scanning

Pull Request Closed

Runs on pull request close or merge.

  • Cleans up OpenShift objects/artifacts
  • Merge retags successful build images as latest

Merge

Runs on merge to main branch.

  • Code scanning and reporting to GitHub Security overview
  • Zero-downtime* TEST deployment
  • Penetration tests on TEST deployment (optional)
  • Zero-downtime* PROD deployment
  • Labels successful deployment images as PROD
  • Sysdig email alerts synced to PROD (no-op if SYSDIG_API_TOKEN is unset)

* excludes database changes

Scheduled

Runs on scheduled job (cronjob) or workflow dispatch.

  • PR environment purge
  • Generate SchemaSpy documentation
  • Tests (e2e, load, integration) on TEST deployment

Maintenance Mode Automation

This repository supports operating downstream projects in a low-maintenance, sustainment-only mode. When configured, dependency updates can be completely automated with zero manual intervention required for minor and patch updates, and optional hands-off major version bumps.

How It Works

  1. Automated Dependency Updates: The repository includes a renovate.json file configured to extend bcgov/renovate-config. This allows Mend Renovate to scan for updates, group related package updates together, and prepare automated Pull Requests.
  2. Branch Protection & Gated Merging: GitHub branch protection rules on main ensure that no PR is merged without verifying that the application remains functional.
  3. CI/CD Validation: The PR workflow builds, deploys, and runs tests against sandboxed preview environments; PR Validate enforces PR title/description conventions.
  4. (Optional) Automerging: If Renovate automerge is enabled and all required checks pass, Renovate can merge updates back to the main branch, triggering an automated rolling deployment.

Maintenance Mode Readiness Checklist

Before transitioning an application utilizing this template to full maintenance mode, downstream teams should verify and meet the following criteria:

  • Robust Automated Test Coverage: A high test coverage threshold (e.g., 70% or higher for both statements and branches) should be enforced. Unit, integration, and end-to-end tests must be capable of catching regressions automatically.
  • PR Preview Environments: Ensure sandboxed preview environments deploy reliably to OpenShift for all pull requests.
  • Automated Smoke Tests / Probes: The application must implement runtime health checks that verify connectivity to database instances and external downstream services (e.g., S3, Keycloak, or mail services).
  • Automerge Policies: Verify that the Mend Renovate GitHub app is integrated and allowed to manage automerges for passing builds.

Runtime Health Checks & Smoke Testing

To safely automate dependency updates, runtime health checks are mandatory to catch runtime connectivity failures before an update is merged.

QuickStart Health Check Implementation

This template provides out-of-the-box support for self-healing and verification through container probes:

  • NestJS Backend: Implements an /api/health endpoint using NestJS Terminus (currently checks DB connectivity via Prisma).
  • Frontend (Caddy/Vite): OpenShift readiness/liveness probes are configured to check / to confirm the web server is responsive and serving assets.

Tip: For a fully mature maintenance mode setup, customize the backend health checks to query external APIs and database migrations. If a dependency goes down, the health check should return 503 Service Unavailable, blocking the automated merge.

Automerge Expectations

When Automerge Occurs

  • Renovate creates PRs for dependency updates (npm packages, GitHub Actions, Docker base images).
  • All status checks pass successfully:
    • Linting and unit tests complete.
    • Preview environment successfully deploys to OpenShift.
    • Automated smoke tests verify the preview environment is fully functional.
  • No merge conflicts are detected.

When Manual Intervention is Needed

  • A dependency upgrade causes compile, build, lint, or test failures.
  • A smoke test or deep health check fails post-deployment.
  • A security vulnerability scanner (e.g., Trivy or CodeQL) flags a new vulnerability.