Reusable GitHub Actions workflow for continuous code quality and security analysis using SonarCloud.
SonarCloud provides static analysis for:
- Code Quality: Bugs, code smells, technical debt
- Security: Vulnerabilities, security hotspots (OWASP Top 10)
- Test Coverage: Track and trend coverage over time
- Code Duplication: Identify duplicated code blocks
- Maintainability: Technical debt and complexity metrics
- Visit sonarcloud.io and sign in with GitHub
- Import your repository
- Note your organization and project key (format:
org_repo-name) - Generate token at sonarcloud.io/account/security
- Add
SONAR_TOKENto repository secrets
# .github/workflows/sonarcloud.yml
name: SonarCloud
on:
push:
branches: [main, develop]
pull_request:
types: [opened, synchronize, reopened]
jobs:
sonarcloud:
uses: ByronWilliamsCPA/.github/.github/workflows/python-sonarcloud.yml@v1
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
sonar-organization: 'your-org'
sonar-project-key: 'your-org_your-repo'| Input | Type | Description |
|---|---|---|
sonar-organization |
string | SonarCloud organization name |
sonar-project-key |
string | Project key (format: org_repo-name) |
| Input | Type | Default | Description |
|---|---|---|---|
python-version |
string | '3.12' | Python version for analysis |
source-directory |
string | 'src' | Source code directory |
coverage-paths |
string | 'coverage.xml' | Coverage report paths (comma-separated) |
coverage-exclusions |
string | See below | Paths to exclude from coverage |
test-exclusions |
string | '' | Paths to exclude from analysis |
extra-dependencies |
string | 'dev' | Additional uv sync extras |
pytest-args |
string | '' | Additional pytest arguments |
fail-on-quality-gate |
boolean | false | Fail workflow if quality gate fails |
skip-if-no-token |
boolean | true | Skip gracefully if SONAR_TOKEN missing |
timeout-minutes |
number | 15 | Job timeout |
additional-sonar-args |
string | '' | Extra SonarQube scanner arguments |
coverage-artifact-retention |
number | 7 | Days to retain artifacts |
Default Coverage Exclusions:
**/tests/**,**/validation/**,**/benchmarks/**,**/scripts/**
| Secret | Description |
|---|---|
SONAR_TOKEN |
SonarCloud authentication token (optional if skip-if-no-token: true) |
name: Code Quality
on:
push:
branches: [main]
pull_request:
jobs:
sonarcloud:
uses: ByronWilliamsCPA/.github/.github/workflows/python-sonarcloud.yml@v1
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
sonar-organization: 'acme-corp'
sonar-project-key: 'acme-corp_my-project'jobs:
sonarcloud:
uses: ByronWilliamsCPA/.github/.github/workflows/python-sonarcloud.yml@v1
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
sonar-organization: 'acme-corp'
sonar-project-key: 'acme-corp_my-project'
source-directory: 'app' # Custom source path
coverage-paths: 'coverage.xml,coverage-integration.xml'jobs:
sonarcloud:
uses: ByronWilliamsCPA/.github/.github/workflows/python-sonarcloud.yml@v1
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
sonar-organization: 'acme-corp'
sonar-project-key: 'acme-corp_my-project'
coverage-paths: 'coverage.xml,integration-coverage.xml,e2e-coverage.xml'jobs:
sonarcloud:
uses: ByronWilliamsCPA/.github/.github/workflows/python-sonarcloud.yml@v1
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
sonar-organization: 'acme-corp'
sonar-project-key: 'acme-corp_my-project'
fail-on-quality-gate: true # Block merge on failurejobs:
sonarcloud:
uses: ByronWilliamsCPA/.github/.github/workflows/python-sonarcloud.yml@v1
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
sonar-organization: 'acme-corp'
sonar-project-key: 'acme-corp_my-project'
coverage-exclusions: '**/tests/**,**/migrations/**,**/fixtures/**'
test-exclusions: '**/integration_tests/**'jobs:
sonarcloud:
uses: ByronWilliamsCPA/.github/.github/workflows/python-sonarcloud.yml@v1
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
sonar-organization: 'acme-corp'
sonar-project-key: 'acme-corp_my-project'
additional-sonar-args: >
-Dsonar.projectVersion=${{ github.ref_name }}
-Dsonar.links.homepage=https://example.com
-Dsonar.links.ci=${{ github.server_url }}/${{ github.repository }}/actionsFor advanced configuration, create sonar-project.properties in repository root:
# Project identification
sonar.organization=acme-corp
sonar.projectKey=acme-corp_my-project
sonar.projectName=My Project
sonar.projectVersion=1.0.0
# Source configuration
sonar.sources=src
sonar.tests=tests
sonar.python.version=3.12
# Coverage configuration
sonar.python.coverage.reportPaths=coverage.xml
sonar.coverage.exclusions=**/tests/**,**/migrations/**
# Code analysis
sonar.exclusions=**/generated/**
sonar.test.exclusions=**/integration_tests/**
# Additional settings
sonar.sourceEncoding=UTF-8Note: Workflow inputs override properties file settings.
Configure quality gates in SonarCloud dashboard:
| Metric | Threshold | Type |
|---|---|---|
| Coverage on New Code | ≥ 80% | New Code |
| Duplicated Lines on New Code | ≤ 3% | New Code |
| Maintainability Rating on New Code | ≤ A | New Code |
| Reliability Rating on New Code | ≤ A | New Code |
| Security Rating on New Code | ≤ A | New Code |
| Security Hotspots Reviewed | 100% | Overall |
- Go to SonarCloud dashboard
- Organization Settings → Quality Gates
- Create new gate or modify existing
- Set conditions for Overall Code and New Code
- Assign to project
SonarCloud automatically decorates pull requests with:
- Overall Status: Quality gate pass/fail
- New Issues: Bugs, vulnerabilities, code smells
- Coverage Impact: Coverage change on PR
- Inline Comments: Issues annotated in code
SonarCloud Quality Gate: Passed ✅
3 new issues:
- 1 Bug
- 2 Code Smells
Coverage: 85.2% (+2.1%)
View details: https://sonarcloud.io/dashboard?id=acme-corp_my-project&pullRequest=42
Error: Workflow skipped
Solution:
- Generate token at sonarcloud.io/account/security
- Add to repository: Settings → Secrets → Actions
- Name:
SONAR_TOKEN
Alternative: Set skip-if-no-token: false to require token
Warning: "Coverage report not found"
Causes:
- Tests failed to run
- Coverage not generated in XML format
- Incorrect
coverage-pathsconfiguration
Solution:
# Ensure pytest generates coverage.xml
pytest --cov=src --cov-report=xml:coverage.xmlError: "Quality Gate failed"
Review:
- Visit SonarCloud dashboard
- Check New Code tab for issues
- Address bugs, vulnerabilities, code smells
- Improve coverage if below threshold
Warning: "Shallow clone detected"
Solution: Workflow automatically uses fetch-depth: 0
Error: Job timeout after 15 minutes
Solution:
with:
timeout-minutes: 30 # Increase for large projectsname: CI and Quality
on: [push, pull_request]
jobs:
ci:
uses: ByronWilliamsCPA/.github/.github/workflows/python-ci.yml@v1
sonarcloud:
needs: ci
uses: ByronWilliamsCPA/.github/.github/workflows/python-sonarcloud.yml@v1
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
sonar-organization: 'acme-corp'
sonar-project-key: 'acme-corp_my-project'jobs:
security:
uses: ByronWilliamsCPA/.github/.github/workflows/python-security-analysis.yml@v1
sonarcloud:
uses: ByronWilliamsCPA/.github/.github/workflows/python-sonarcloud.yml@v1
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
sonar-organization: 'acme-corp'
sonar-project-key: 'acme-corp_my-project'| Metric | Description |
|---|---|
| Bugs | Issues that represent coding errors |
| Code Smells | Maintainability issues |
| Technical Debt | Estimated time to fix all code smells |
| Duplications | Percentage of duplicated code |
| Cognitive Complexity | How difficult code is to understand |
| Metric | Description |
|---|---|
| Vulnerabilities | Security issues (OWASP Top 10) |
| Security Hotspots | Code requiring security review |
| Security Rating | A (best) to E (worst) |
| Metric | Description |
|---|---|
| Line Coverage | % of lines executed by tests |
| Branch Coverage | % of branches executed by tests |
| Coverage on New Code | Coverage of code added in PR |
Set realistic thresholds for your project maturity level.
Prioritize quality on new code additions over fixing legacy issues.
Manually review all security hotspots flagged by SonarCloud.
Track technical debt trend and allocate time for remediation.
Target ≥80% coverage on new code to prevent regressions.
Exclude generated code, migrations, and test fixtures from analysis.
- Python Security Analysis - CodeQL, Bandit, Safety
- Python CI - Testing and linting
- Qlty Coverage - Alternative coverage tracking
See Also:
- USAGE_EXAMPLES.md - Complete workflow examples
- examples/ - Ready-to-use configurations