Skip to main content

CI/CD Pipeline

Proxima Console uses GitLab CI/CD with a multi-stage pipeline. Different jobs run depending on the trigger: merge request, main branch push, or version tag.

The application tier is deployed via GitOps: CI builds and pushes images, then a manual job bumps image tags in the separate argocd-infra repository, and ArgoCD reconciles the proxima-production cluster. CI never connects to the cluster or the production database directly. See Production (Kubernetes) for the runtime architecture.

Pipeline Stages

lint → test → build → integration → e2e → docker → deploy → release

Pipeline Types

1. MR Pipeline (changes-based)

Triggered on merge requests. Jobs run only when relevant files change.

Stages: linttestbuild

JobStageWhat It Does
lint:golintRuns go mod verify, govulncheck, and golangci-lint on agent/, backend/, mcp/, and cli/
lint:frontendlintRuns ESLint + Prettier checks and npm audit --audit-level=high --omit=dev (fails on high-severity production vulnerabilities)
lint:swaggerlintValidates swagger spec well-formedness and freshness (regenerates and diffs)
test:go:unittestRuns gotestsum with -race flag, produces JUnit reports
test:frontend:unittestRuns vitest, produces JUnit reports
migration:checktestValidates migrations by running up → down → up
build:agentbuildCompiles the agent with go build

2. Main Pipeline (all jobs)

Triggered on pushes to main. Runs all MR jobs plus integration, e2e, Docker, and deploy stages.

Additional stages: integratione2edockerdeploy

JobStageWhat It Does
test:go:integrationintegrationRuns Go integration tests against real PostgreSQL and NATS services
test:e2ee2eFull-stack backend smoke tests against all services
test:e2e:playwrighte2ePlaywright browser tests — uses pre-built frontend (--mode test) and backend artifacts, resets admin MFA, proxies API calls through vite preview
docker:backenddockerBuilds backend image, scans with Trivy, pushes registry.prxm.uz/proxima/console/backend:$CI_COMMIT_SHA
docker:frontenddockerBuilds frontend image, scans with Trivy, pushes registry.prxm.uz/proxima/console/frontend:$CI_COMMIT_SHA
deploy:k8s-gitopsdeployManual gate, main only. Clones argocd-infra over an SSH deploy key, bumps every Console image tag under clusters/production/console-system/ to the new SHA, commits and pushes. ArgoCD then syncs and Argo Rollouts performs the blue-green promotion.

The remaining docker:* jobs (docker:mcp, docker:docs, docker:telegram-bot, docker:telegram-miniapp) follow the same pattern, building and pushing one registry.prxm.uz/proxima/console/<svc>:$CI_COMMIT_SHA image per service.

GitOps Deployment (how deploy:k8s-gitops works)

The deploy stage no longer touches a server. It is a pure Git operation against the argocd-infra repo:

  1. docker:* jobs build and push registry.prxm.uz/proxima/console/<svc>:$CI_COMMIT_SHA for every service.
  2. deploy:k8s-gitops (manual, main only) clones argocd-infra over an SSH deploy key (DEPLOY_REPO_SSH_PRIVATE_KEY — an SSH key, not an HTTPS token), rewrites every Console image tag under clusters/production/console-system/ to the new SHA, then commits and pushes.
  3. ArgoCD notices the new desired state and syncs the console-system namespace.
  4. Database migrations run inside the cluster as an ArgoCD PreSync-hook Job (console-migrate, golang-migrate migrate up) — not from CI, because CI cannot reach the cluster-internal database. ArgoCD waits for this hook to succeed before rolling out the backend.
  5. Argo Rollouts performs the backend blue-green promotion (preview → active), with automatic rollback if the preview never becomes healthy.

Retired jobs. The old deploy:dev (SSH to the box, docker-compose down/up, swapping IMAGE_TAG in systemd units) and migrate:dev (migrations against the dev-server PostgreSQL over SSH) jobs are gone. Migrations are now the responsibility of the ArgoCD PreSync hook, and rollout is the responsibility of ArgoCD + Argo Rollouts.

3. Tag Pipeline (v*)

Triggered when a version tag (e.g., v0.2.0) is pushed. Builds release artifacts and creates a GitLab release.

Stages: dockerrelease

JobStageWhat It Does
docker:backenddockerBuilds and pushes backend image with version tag
docker:frontenddockerBuilds and pushes frontend image with version tag
release:agent-binariesreleaseCross-compiles agent for linux/amd64 and linux/arm64, uploads binaries to Cloudflare R2
release:cli-binariesreleaseCross-compiles the pc CLI for linux/amd64, linux/arm64, darwin/amd64, and darwin/arm64, uploads binaries (with .sha256 checksums) to Cloudflare R2
release:gitlabreleaseCreates a GitLab release with notes extracted from CHANGELOG.md; attaches the agent and pc binaries (R2 download links) as release assets

Versioning

The project follows semver with a v prefix (e.g., v0.2.0).

  • Stable tags (e.g., v0.2.0): the Docker image is also tagged as :latest.
  • Pre-release tags (e.g., v0.2.0-beta.1): the Docker image is tagged with the version only, :latest is not updated.

CI Variables

VariableTypePurpose
DEPLOY_REPO_SSH_PRIVATE_KEYFile / MaskedSSH deploy key for pushing image-tag bumps to the argocd-infra repo (not an HTTPS token)
R2_ACCOUNT_IDVariableCloudflare account ID for R2 storage
R2_ACCESS_KEY_IDVariableR2 access key for uploading agent binaries
R2_SECRET_ACCESS_KEYMaskedR2 secret access key
R2_BUCKETVariableR2 bucket name for agent binary storage
R2_PUBLIC_URLVariablePublic download URL for agent binaries

Masked variables are hidden in job logs. All secrets should use the "Masked" type to prevent accidental exposure.