---
title: "CI/CD & Deployment Process"
slug: onboarding-cicd-deployment
section: Developer Onboarding
status: stable
description: "How a change you make actually reaches a running environment — the current, live process."
last-updated: 2026-10-07
---

# CI/CD & Deployment Process

How a change you make actually reaches a running environment — the current, live process. (The Git Branching & Release Model page is the full specification of the sandbox branching model; this page is the short version of what's in effect today. Updated 2026-10-06, when BackOfficePrototype became the last portal repo to move onto it.)

## Overview

Every portal repo (BackOfficePrototype, PPPToo, HostPortalPrototype, WildPacksApplicationForm) is on the sandbox branching model (WildPacks since 2026-10-03, PPPToo and HostPortal since 2026-10-04, BackOfficePrototype since 2026-10-06): branches are cut from `main`, deploy to pooled development and QA slots, and reach production through a blue-green cutover. Every deploy is a branch-driven GitHub Actions run — never a manual deploy, and never Cloud Build for these repos specifically, despite some older internal docs referencing it.

> **There is no "staging" environment.** The only valid Globus environments are `development`, `QA`, and `production`. Any reference to `staging` or a staging-prefixed resource in a repo is legacy/dead and should not be used as a deploy target.

## Promotion Path

```
feature/<asana-gid>-*  →  release/<name>  →  main
```

- **feature/`<asana-gid>`-\*** — cut from `main`; a push deploys to a pooled **development** slot (`dev-N.…`; `globus-dev-N` for BackOfficePrototype). It reaches the release branch by PR.
- **release/`<name>`** — cut from `main`; a push deploys to a pooled **QA** slot (`qa-N.…`; `globus-qa-N` for BackOfficePrototype, whose current release branch is `release/2026-10-globus-pilot`).
- **main** — production. A `release/*` → `main` PR (reviewed and approved; BackOfficePrototype also requires a Code Owner review and the `governance-approved` label for protected paths) runs the blue-green cutover. `hotfix/<asana-gid>-*` → `main` is the only other way in.

`development` is an environment, not a branch. The legacy `development`/`qa` branches are frozen (PPPToo, HostPortal, WildPacks) or dead rails awaiting their freeze ruleset (BackOfficePrototype, whose `deploy-development.yml`/`deploy-qa.yml`/`deploy-production.yml` were disabled on 2026-10-05) — never target them.

## Pipeline Tool

GitHub Actions is the mandated CI/CD tool across the ecosystem — workflow files live in each repo's `.github/workflows/`. If you're debugging a deploy and find yourself looking at Cloud Build triggers for a portal repo, you're very likely looking in the wrong place; Cloud Build is used for a small number of specific microservices (OCR, Translation), not the main portals.

## Repo-Specific Processes

Two repos have their own deliberately different promotion mechanics — know these before assuming the generic feature → release → `main` flow applies everywhere:

- **form-engine-portable** — this is a *published package*, not a deployed service. Merging to `main` does **not** ship anything to consumers. Publishing only happens when a `v*` tag is pushed, which triggers the GitHub Actions publish workflow to GitHub Packages. Consumers (BackOfficePrototype, PPPToo) then need their own `package.json` bumped and redeployed to actually pick up the change. Skipping the tag push is the single most common way a form-engine fix looks merged but isn't actually running anywhere.
- **n8n-workflows** — workflow changes are applied live via the n8n API first, verified for zero crashes, *then* the updated workflow JSON is fetched back and committed to the repo. This is the reverse order from normal code changes (commit → deploy); here it's apply → verify → commit. Pushing requires a GitHub App token, not a personal OAuth token, which lacks write access for this repo's automation. It is also the one repo still promoted `development` → `qa` → `main` by the dev-to-qa-sync-agent (the only `promote` repo left since vertex-agents #285, 2026-10-06).

## Pre-Merge Gates

Nothing merges on CI green alone. Before a PR is approved:

- **slopgate** runs against the diff to catch AI-generated code smells (not just lint) — run it locally before pushing (`slopgate --base origin/<current release branch>` for a feature branch — e.g. `origin/release/2026-10-globus-pilot` in BackOfficePrototype — and `origin/main` for a hotfix or a release → main PR), since local-green and CI-green can drift on slopgate's own version.
- The PR review process pulls the branch and **functionally verifies** the change returns correct data — a passing test suite is necessary, not sufficient. See the PR & Code Review Process page.

## Post-Deploy Verification

After a deploy lands, don't consider it "done" until you've confirmed the running service actually reflects it — check the service's health endpoint, and for anything touching secrets or environment config, confirm the new revision picked up the right values rather than assuming the deploy succeeded because the pipeline went green.

BackOfficePrototype also posts deploy results to the Platform Pulse Teams channel. Its `Notify Platform Pulse` workflow runs when any other workflow in the repo completes, and alerts in two cases only: any workflow failure (the notifier itself is excluded), and a successful run of exactly `Deploy to Development`, `Deploy to QA` or `Deploy to Production`. The success match is exact workflow-name equality against that allowlist, never a substring check, so a PR linter such as `Lint Deploy Workflows` never triggers a deploy alert. The card is labelled `Deployed` on success and `Build Failure` on failure, and is posted through the Alliance MCP Gateway with a robot PAT.

**Database settings (BackOfficePrototype).** All are optional environment variables with defaults. Connection pool: `DB_POOL_MAX` (default 20), `DB_POOL_IDLE_TIMEOUT_MS` (30000), `DB_POOL_CONNECTION_TIMEOUT_MS` (5000) and `DB_KEEPALIVE_DELAY_MS` (10000, the initial delay for TCP keepalive probes that stop Cloud SQL silently closing idle connections). Boot-time connect retry, so a slow first connection does not kill the process before it listens: `DB_BOOT_CONNECT_ATTEMPTS` (default 6, minimum 1) attempts spaced `DB_BOOT_CONNECT_RETRY_MS` (default 2000 ms, minimum 0); a non-numeric value falls back to the default, and after the last failed attempt startup throws.
