CI/CD Pipeline
The CI pipeline lives in xred-eln-integrations and runs automatically for changed apps only. Deployment to Minerva is handled by a separate manually-triggered workflow.
CI Pipeline
The pipeline detects which apps changed using git diff and runs jobs only for those apps via a matrix strategy. Repo-wide checks run once regardless.
Pre-Commit
Static analysis and hygiene checks that run in parallel.
- Ruff — Python linter and formatter (replaces flake8, isort, black) — per app
- ESLint — JavaScript/TypeScript linting — per app
- React Doctor — Detects common React anti-patterns and compatibility issues — per app
- Secrets Scan — Scans git history for leaked credentials using gitleaks — repo-wide
- Big Files — Rejects files larger than 5 MB — repo-wide
- YAML Lint — Validates YAML syntax across the repo — repo-wide
Test
Runs after all pre-commit checks pass.
- Pytest — Runs the backend test suite with coverage reporting
- Ruff Warn — Runs all Ruff rules in advisory mode (non-blocking) to surface potential improvements
Security
Three layers of security scanning:
- CodeQL — GitHub’s code scanning engine. Analyses Python and JavaScript/TypeScript for
vulnerabilities (injection, auth issues, etc.) on every push and PR. Enabled automatically
by the
roche-innersourceorg — no configuration needed. - Dependabot — Monitors pip, npm, and GitHub Actions dependencies for known vulnerabilities
and opens PRs to update them. Configured via
.github/dependabot.yml. Alerts must be enabled per-repo in Settings → Code security. - uv audit — Audits Python dependencies against the PyPI advisory database using uv’s built-in auditing. Generates a JSON report as a build artifact.
Build
Builds and pushes Docker images for the frontend and backend to ghcr.io. Runs on push to
environment branches (main, develop, uat, sandbox).
Docker image tagging
Each image gets a rolling branch tag and a pinned tag with the CI run number:
| Branch | Tags |
|---|---|
main | :main, :main.42 |
develop | :develop, :develop.42 |
uat | :uat, :uat.42 |
sandbox | :sandbox, :sandbox.42 |
The run number (.42) gives each build a unique, ordered identifier. Use the rolling tag
(:develop) for always-latest, or pin to a specific build (:develop.42) for reproducibility.
Images are scoped per app: ghcr.io/roche-innersource/xred-eln-integrations/<app>/backend and <app>/frontend.
Deploy workflow
Deployment to Minerva is a separate, manually-triggered workflow. It updates (or scaffolds) the Kubernetes manifests in the infrastructure repo , and ArgoCD picks up the change automatically.
How to deploy
- Go to Actions → Deploy
- Click Run workflow
- Select the branch that matches your target environment
- Enter the app name and select components (backend, frontend, or both)
| Branch | Environment | Image tag | Domain |
|---|---|---|---|
develop | DEV | :develop | minerva.sandbox.pcloud.roche.com |
uat | UAT | :uat | apps.uat.minerva.roche.com |
main | PROD | :main | apps.minerva.roche.com |
Preflight checks
Before deploying, the workflow validates:
- Valid branch — must be
develop,uat, ormain - App exists — the app directory must exist under
apps/ - Dockerfiles present — the requested components must have Dockerfiles
- CI passed — the latest CI run on the branch must have succeeded
- Docker image exists — the image must be available in GHCR
- Infra token configured — the
INFRA_REPO_TOKENsecret must be set
If any check fails, deployment is blocked with a clear error message.
First deploy vs update
- First deploy — if the app’s K8s directory doesn’t exist in the infrastructure repo, the workflow scaffolds all manifests (deployment, service, ingress, kustomization) with the correct Minerva labels, hostnames, and TLS configuration.
- Subsequent deploys — updates the image tag in the existing deployment manifest.
Deployments to UAT and PROD can only be triggered from the uat or main branch
respectively. This ensures only merged and reviewed code gets deployed.
ArgoCD
After the workflow pushes to the infrastructure repo, ArgoCD syncs the changes:
Roche CA certificates
Docker images include Roche CA certificates from certs/ at the repo root. These are downloaded from
certinfo.roche.com and committed to the repo so builds work
on GitHub-hosted runners without VPN access.