Skip to content

SonarCloud Quality Gate

SonarCloud runs static analysis and ingests test coverage for App-name, then exposes a quality gate that the CI pipeline enforces before a build is allowed to proceed. See the CI/CD Overview for where this sits in the pipeline.

What SonarCloud does here

SonarCloud receives coverage reports from the frontend and backend test runs, evaluates them against the project's quality gate (coverage thresholds, new-code conditions, code smells, security hotspots), and returns a pass/fail status. The pipeline blocks on that status, so a regression in coverage or a gate violation stops the deploy.

Create the project and organization

  1. Sign in to https://sonarcloud.io with GitHub and authorize access to the <org> organization.
  2. Create (or reuse) the SonarCloud organization that maps to <org>. All of the organization's projects share it.
  3. Import the App-name repository to create the project. SonarCloud assigns a project key.

Projects share one organization

Because every project lives under the same organization, the project key is namespaced by it. The generic form is:

-Dsonar.projectKey=<org>_App-name

Substitute your real organization and project — do not hardcode another project's key.

CI configuration: token and toggle

Name Kind Purpose
SONAR_TOKEN Repository secret Authenticates the scanner to SonarCloud
SONAR_ENABLED Repository variable Toggle: set to true to run the gate, anything else to skip it

Generate SONAR_TOKEN under My Account → Security in SonarCloud and store it as a GitHub secret (see Secrets & Environment). The SONAR_ENABLED variable lets you switch the whole stage off — e.g. on a fork or while bootstrapping — without editing the workflow.

Feeding coverage in

The scanner does not run your tests; the test jobs produce coverage reports and SonarCloud reads them.

Frontend (React + Vite + TS) emits an LCOV report:

npm run test:coverage
# -> coverage/lcov.info

Backend — for FastAPI projects, pytest writes a Cobertura XML report:

pytest --cov=app --cov-report=xml
# -> coverage.xml

Point the scanner at both reports, typically in sonar-project.properties or via scanner flags:

sonar.organization=<org>
sonar.projectKey=<org>_App-name
sonar.sources=.
sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.python.coverage.reportPaths=coverage.xml

How the gate is enforced

Analysis upload is asynchronous, so the pipeline cannot trust the scanner's exit code alone. After uploading, the workflow polls the SonarCloud API and confirms the gate against the exact commit that triggered the run:

  1. Run the scanner to upload analysis for the current commit SHA.
  2. Poll the SonarCloud API until the analysis whose revision matches the current commit SHA appears (guards against reading a stale, earlier analysis).
  3. Query api/qualitygates/project_status for that analysis and read projectStatus.status.
  4. Fail the job unless the status is OK.
flowchart TD
    A[Scanner uploads analysis<br/>for commit SHA] --> B{Poll API:<br/>analysis revision == SHA?}
    B -- no --> B
    B -- yes --> C[GET qualitygates/project_status]
    C --> D{status == OK?}
    D -- yes --> E[Pipeline continues]
    D -- no --> F[Fail the build]

Why match the commit SHA

Polling for the analysis whose revision equals the current commit SHA prevents the pipeline from passing on a previous commit's green result. The gate must reflect the code actually being deployed.

When SONAR_ENABLED is not true, the workflow skips this entire stage, so coverage and the gate are advisory rather than blocking.