Skip to content

CI/CD and supply chain

All automation lives in .github/workflows. Third-party actions are referenced by major version tag, and Dependabot keeps them current.

flowchart LR
  pr(["Pull request"]) --> ci["ci.yml"]
  pr --> tf["terraform.yml (deploy/terraform changes)"]
  pr --> k8s["k8s-deployment-test.yml (deploy changes)"]
  pr --> sbom["sbom-and-license.yml"]
  pr --> dock["docker.yml (pushes pr-N tags)"]
  main(["Push to main"]) --> ci
  main --> dock2["docker.yml: build, push to GHCR, Trivy"]
  main --> cd["cd.yml: ECR, then EKS via Helm"]
  main --> rel["release.yml: semantic-release"]
  main --> sbom
  sched(["Weekly cron"]) --> dep["dependencies.yml"]
  sched --> sbom
  bot(["Dependabot PR"]) --> am["dependabot-auto-merge.yml"]
  manual(["workflow_dispatch"]) --> perf["performance-test.yml (k6)"]
Workflow Trigger What it does
.github/workflows/ci.yml push and PR to main/develop Path filter decides which jobs run. Backend: dotnet restore/build/test with coverage summary. Security: Trivy filesystem scan (SARIF uploaded) and CodeQL for C# and JavaScript. Frontend: npm ci then nx affected lint, test and build in frontend/web. Docker build matrix for the 5 images. Helm lint, kube-score and a manifest validation script for deploy/**. PR status comment.
.github/workflows/docker.yml push to main/develop, tags v*, PR to main Buildx matrix for 5 images (linux/amd64; arm64 was dropped because protoc segfaults under QEMU). Pushes to GHCR, including on PRs, (ghcr.io/<repo>/<service>) with branch, PR, semver, main-<sha> and latest tags. Then Trivy scans each pushed image and uploads SARIF to the Security tab.
.github/workflows/cd.yml push to main, tags v*, manual (choose env and region) Assumes an AWS role over OIDC, builds linux/amd64 images, pushes to ECR (creating repos with scan-on-push), Trivy-scans them, then deploys DB, service and gateway charts to EKS with Helm, runs the S3 URL migration and a smoke check.
.github/workflows/terraform.yml PR or push touching deploy/terraform/** terraform fmt -check, init -backend=false + validate, TFLint, Trivy IaC scan (non-blocking), and on PRs plan posted as a comment.
.github/workflows/k8s-deployment-test.yml PR touching deploy paths, manual Starts Minikube, builds the 5 images and loads them, runs deploy/k8s/deploy-all.sh, waits for pods, checks service connectivity and endpoints, collects logs on failure, and comments a report.
.github/workflows/sbom-and-license.yml push and PR to main, weekly Builds each image, generates an SPDX SBOM with Syft (anchore/sbom-action), scans it with Grype (anchore/scan-action, cutoff high, non-blocking). License report for NuGet and npm, with license-checker --failOn "GPL-3.0;AGPL-3.0".
.github/workflows/release.yml push to main, manual Runs semantic-release (Angular commit convention, .releaserc.json). When a version is due: creates the tag and GitHub release, opens a CHANGELOG PR, notifies Slack and opens an announcement issue.
.github/workflows/dependabot-auto-merge.yml pull_request_target from bots Approves and enables squash auto-merge for Dependabot patch/minor bumps; comments on majors; auto-merges github-actions[bot] PRs that only change CHANGELOG.md.
.github/workflows/dependencies.yml Mondays 06:00 UTC, manual dotnet list package --vulnerable --include-transitive and npm audit in frontend/web. Informational.
.github/workflows/performance-test.yml manual only Builds and starts Catalog, Basket, Ordering and the gateway on the runner, then runs a k6 script chosen by test_type (smoke, stress, spike, soak) and uploads results.
flowchart TB
  dc["detect-changes (dorny/paths-filter)"] --> cq["code-quality: .NET build + test"]
  dc --> fq["frontend-quality: nx affected lint/test/build"]
  dc --> kv["kubernetes-validation: helm lint, kube-score, yamllint"]
  sec["security-scan: Trivy fs + CodeQL"]
  cq --> db["docker-build (5 images, GHA cache)"]
  fq --> db
  db --> it["integration-tests (PR only, Redis/Postgres/Mongo/RabbitMQ service containers)"]
  cq & fq & db & kv --> ns["notify-status"]

Path filtering keeps PRs fast. A frontend-only change skips the .NET build, and a docs change skips almost everything. The docker-build job tolerates a skipped upstream job (result == 'skipped') so it still runs on backend-only or frontend-only PRs.

.github/dependabot.yml covers five ecosystems every Monday at 06:00. The rationale is written up in docs/dependency-management.md.

Ecosystem Directory Grouping Ignored
NuGet / (central Directory.Packages.props) dotnet-minor-and-patch semver-major
npm /frontend/web minor-and-patch nx, @nx/*, @nrwl/*, semver-major
npm /frontend/legacy-angular minor-and-patch nx, @nx/*, @nrwl/*, semver-major
Docker /src/Services/*/*.API, /src/ApiGateways/* docker-images
GitHub Actions / github-actions

Two decisions stand out:

  • Nx is excluded. Nx core and every @nx/* plugin must move together through nx migrate. Piecemeal Dependabot bumps previously left the toolchain split across versions and produced a lockfile that npm ci rejected, which broke frontend-quality repeatedly. Nx upgrades are now a deliberate, manual migration (the most recent aligned everything on 23.2.1).
  • Grouping plus auto-merge. Non-major updates arrive as one PR per ecosystem and merge automatically once CI is green. Majors wait for a human. This keeps weekly dependency hygiene to a few minutes of review.
Tool Scope Where results go Blocking?
Trivy (fs) Repository files and lockfiles, CRITICAL/HIGH GitHub Security tab (SARIF) no
Trivy (image) Every pushed GHCR and ECR image Security tab (GHCR) no
Trivy (config) Terraform job log no (exit-code: 0)
CodeQL C# and JavaScript Security tab no
Syft + Grype SBOM per image (SPDX JSON, uploaded as an artifact) job log, artifact no (fail-build: false)
ECR scan-on-push Images in ECR AWS console no
License checker npm production deps step summary fails only on GPL-3.0/AGPL-3.0