# Upgrade and Release Process (/docs/deployment/playbooks/upgrade-and-release-process)



This playbook describes how a new `bsqai-platform` version moves from `develop` to a tagged release, and how that release reaches a running cluster. It complements the [Deployment Sequence](/docs/deployment/playbooks/deployment-sequence) playbook, which covers deploying a given version for the first time.

Versioning [#versioning]

The platform version lives in a single `VERSION` file at the repository root, following SemVer. `scripts/version-bump.sh <new-version>` updates both `VERSION` and the version badge/title in `README.md` in one step, and validates that the argument is a well-formed SemVer string before writing anything.

Cutting a Release [#cutting-a-release]

Two GitHub Actions workflows drive release preparation, both triggered manually (`workflow_dispatch`):

* **Create Release Branch & Dev Bump** — cuts `release/<target_version>` from `develop` (or a chosen source branch), running `version-bump.sh` on the release branch itself. It also immediately bumps `develop` forward to the next development version via a separate `bump/<next_dev_version>` branch and opens a PR back into `develop`, so development can continue without waiting for the release to stabilize. Optionally posts a feature-freeze notice to Slack.
* **Create Release PR** — a simpler flow that computes the next version (patch/minor/major, or a custom value), branches `release/v<version>` from `develop`, updates `VERSION`/`README.md`, and opens a PR against `main`.

Once a release branch is stable, **Finalize Release** must be run from that `release/*` branch (it explicitly refuses to run from anything else). It resolves the version from the `VERSION` file (or an override input), fails if that tag already exists, and then creates a GitHub Release with auto-generated release notes. A downstream job posts a Slack notification to `#bullsequana-ai-product` announcing the release, or a failure notice if tagging failed.

Security Scanning [#security-scanning]

`Helm Chart Security Scan` (`scan_platform_charts.py`, `scripts/helm-chart-scanner/`) runs Trivy against every image referenced by the platform's rendered Helm charts, pulled directly from the ACR Helm repository. It runs on three triggers, each scanning a different scope:

| Trigger                                             | Scope                              | Purpose                                                    |
| --------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------- |
| Pull request                                        | Single component (`cert-manager`)  | Lightweight smoke test that the scanner itself still works |
| Schedule (`1st` and `15th` of the month, 01:30 UTC) | `main` + `develop`, all components | Recurring CVE sweep of both active branches                |
| Manual dispatch                                     | Chosen branch, all components      | On-demand full scan                                        |

The scanner accepts a `--severity` filter (default `CRITICAL,HIGH,MEDIUM,LOW`) and a `--fail-on` threshold (`HIGH`, `CRITICAL`, or `none`) that controls its exit code independently of which severities are reported — the scheduled/PR runs currently use `--fail-on none`, so the workflow does not hard-fail the build on findings; it reports them instead. Results are written as a Markdown report to the job summary, and aggregated CVE counts per branch are posted to Slack after non-PR runs. Image tags that resolve to `latest` are flagged rather than scanned, since a floating tag would not reflect a version actually pinned by the codebase.

Deploying a Release to a Cluster [#deploying-a-release-to-a-cluster]

The reusable `Cluster Upgrade` workflow (`upgrade-cluster.yml`) applies a given branch/version to one of three long-lived clusters — `demo`, `development`, or `release-staging` — each mapped to its own AKS resource group and base domain. On a push to `main` or `develop` it auto-selects `demo`/`development` respectively; other targets require manual dispatch.

The rollout sequence is the same CLI flow used for first-time deployment:

1. Connect to the target AKS cluster and save its kubeconfig as a build artifact.
2. Generate `platform.env` (registry/Azure/DNS settings) and `local.env` (Git manifests target, tokens) from repository secrets.
3. `uv run -m src.cli.main validate` — validate every component's configuration before rendering anything.
4. `uv run -m src.cli.main apply all -r` — render manifests for all components.
5. `uv run -m src.cli.main apply-sealing-key` — ensure the cluster has the sealed-secrets key needed to decrypt the sealed secrets just rendered.
6. `uv run -m src.cli.main push-manifests "CI: upgrade <environment> cluster"` — push rendered manifests to `bsqai-platform-manifests`.
7. `uv run -m src.cli.main helm-apply argocd` — apply/upgrade the ArgoCD Helm release directly (ArgoCD manages every other component, but has to be present to do so).
8. Wait for the ArgoCD server pod to become ready and confirm the `applications.argoproj.io` API is reachable.

After this workflow completes, no manual sync step is needed — ArgoCD's automated sync policy picks up the pushed manifest changes and reconciles the cluster on its own, typically within 10–15 minutes for a full release.

Related Pages [#related-pages]

* [Platform CLI](/docs/deployment/platform-cli)
* [GitOps workflow](/docs/deployment/gitops-workflow)
* [Deployment Sequence](/docs/deployment/playbooks/deployment-sequence)
* [Component anatomy](/docs/deployment/component-anatomy)
