Skip to main content

SonarQube

SonarQube Community Edition runs static code analysis on the crawbl-backend Go codebase. It detects bugs, code smells, and duplicated code. Security vulnerability scanning is provided by gosec (a free Go security linter) whose findings are imported as external issues.

SonarQube is dev-only — it is not deployed in the production cluster.


Connection Details

PropertyValue
URLhttps://sonar-dev.crawbl.com
Service namesonarqube-sonarqube
Namespacesonarqube
Port9000
EditionCommunity (free)
Imagesonarqube:26.3.0.120487-community
Databasesonarqube db in backend-postgresql
Storage5 Gi persistent volume
Memory2 Gi request / 4 Gi limit
JVM heapsWeb 512m + CE 512m + ES 512m = 1.5 Gi

Credentials

UserPasswordNotes
adminSet on first loginChange immediately after first boot

Database credentials

The SonarQube database password is stored in AWS Secrets Manager at crawbl/dev/sonarqube/postgresql and synced to the Kubernetes secret sonarqube-db-secret by External Secrets:

kubectl get secret sonarqube-db-secret -n sonarqube \
-o jsonpath='{.data.jdbc-password}' | base64 -d

Architecture

┌──────────────┐     ┌──────────────────┐     ┌─────────────────────┐
│ Developer │ │ sonar-scanner │ │ SonarQube Server │
│ workstation │────▶│ + gosec │────▶│ (sonarqube ns) │
└──────────────┘ └──────────────────┘ └──────────┬──────────┘

┌──────────▼──────────┐
│ backend-postgresql │
│ (backend ns) │
└─────────────────────┘
  • gosec runs locally, outputs a SonarQube-compatible JSON report
  • sonar-scanner uploads the report + runs its own bug/smell analysis
  • SonarQube stores results in the sonarqube database inside the shared backend-postgresql instance
  • The init-db PreSync Job automatically creates the database and user on first deploy

Running a Scan

crawbl app scan

This runs:

  1. gosec — Go security scanner (OWASP vulnerabilities, hardcoded secrets, weak crypto)
  2. sonar-scanner — uploads gosec report + SonarQube's own analysis

Results appear at https://sonar-dev.crawbl.com/dashboard?id=crawbl-backend.

Automatic scanning on deploy

crawbl app deploy platform runs the scan automatically after pushing (enabled by default):

crawbl app deploy platform            # includes scan + gc
crawbl app deploy platform --scan=false # skip scan

Prerequisites

Both tools are managed by mise:

mise install   # installs sonar-scanner-cli + gosec

The SONARQUBE_TOKEN environment variable must be set (already in .env):

set -a && source .env && set +a
crawbl app scan

What Gets Scanned

SonarQube native rules (36 Go rules)

TypeCountExamples
Bug7Unreachable code, self-assignment, identical conditions
Code Smell29Cognitive complexity, empty functions, deep nesting, duplicated strings

gosec imported rules (external issues)

CategoryExamples
InjectionSQL injection, command injection, LDAP injection
CryptoWeak hash (MD5/SHA1), hardcoded credentials, insecure TLS
File I/OPath traversal, file permissions, directory traversal
NetworkUnvalidated redirects, SSRF patterns
Error handlingUnchecked errors on security-critical operations

Excluded from scanning

PathReason
vendor/**Third-party dependencies
api/**Generated CRD types (kubebuilder)
**/*.pb.goProtobuf generated code
**/*_generated.goController-gen output
**/zz_generated.*.goDeep copy generated code
**/testdata/**Test fixtures
migrations/**SQL migrations
proto/**Protobuf definitions
.cache/**, .github/**Build cache, CI config

Configuration lives in sonar-project.properties at the repo root.


Quality Gate

The project uses a custom Crawbl quality gate (not the default "Sonar way"):

ConditionThresholdNotes
New violations> 0 failsAny new bug or code smell fails the gate
New duplication> 3% failsCopy-paste detection on new code
Security hotspots reviewed< 100% failsAll hotspots must be reviewed

No coverage requirement — coverage tracking is not enforced.

The quality gate applies only to new code (code changed since the previous version tag). Existing code does not trigger gate failures.


Security Scanning Strategy

SonarQube Community Edition has zero security rules for Go. Security coverage comes from two free tools:

ToolWhat it findsWhere results appear
gosecOWASP vulnerabilities, hardcoded secrets, weak crypto, injectionSonarQube dashboard (external issues)
SnykDependency vulnerabilities, first-party code issues, license complianceSnyk dashboard + Claude Code MCP

Together they provide better coverage than SonarQube Developer Edition alone.


ArgoCD Configuration

SonarQube is deployed via ArgoCD as a standard component:

ResourcePath
Root Application CRcrawbl-argocd-apps/root/sonarqube.yaml
Helm chart (vendored)crawbl-argocd-apps/components/sonarqube/chart/
Dev valuescrawbl-argocd-apps/components/sonarqube/envs/dev.yaml
ExternalSecret (DB password)crawbl-argocd-apps/components/sonarqube/resources/es-sonarqube-secrets.yaml
ExternalSecret (PG superuser)crawbl-argocd-apps/components/sonarqube/resources/es-pg-superuser.yaml
Init DB Jobcrawbl-argocd-apps/components/sonarqube/resources/init-db-job.yaml
HTTPRoutecrawbl-argocd-apps/components/sonarqube/resources/httproute.yaml

Sync wave: 6 (same as orchestrator — after PostgreSQL at wave 5).

Dev only: The root CR exists in root/ but not root-prod/.


Secrets Reference

SecretLocation (AWS SM)K8s SecretNamespaceUsed by
SonarQube DB passwordcrawbl/dev/sonarqube/postgresqlsonarqube-db-secretsonarqubeStatefulSet (JDBC)
PG superuser passwordcrawbl/dev/backend/postgresqlsonarqube-pg-superusersonarqubeInit DB Job
Scanner token.env (SONARQUBE_TOKEN)N/Alocalcrawbl app scan

Troubleshooting

"SonarQube pod OOM-killed"

SonarQube runs Elasticsearch + Web + Compute Engine in one container. If any JVM heap is too large, the pod exceeds its memory limit.

Current heaps: Web 512m + CE 512m + ES 512m = 1.5 Gi (within 4 Gi limit).

kubectl describe pod sonarqube-sonarqube-0 -n sonarqube | grep -A 3 "Last State"

If OOM-killed, check SONAR_WEB_JAVAOPTS, SONAR_CE_JAVAOPTS, and SONAR_SEARCH_JAVAOPTS in envs/dev.yaml.

"Scan fails with 503"

The SonarQube pod is restarting (usually after an ArgoCD sync). Wait for readiness:

kubectl get pods -n sonarqube -l app=sonarqube -w

Then retry crawbl app scan.

"Quality gate shows ERROR"

Check the dashboard for which condition failed. Common causes:

  • New code has a code smell or bug → fix it or mark as "won't fix" in the UI
  • All existing code treated as "new" → set new code period to "previous version" in Project Settings > New Code

"Badges show 'project not found' on GitHub"

The sonar.forceAuthentication setting must be false in envs/dev.yaml so badge APIs are public. If the pod restarted and lost the setting, verify:

kubectl port-forward svc/sonarqube-sonarqube 9001:9000 -n sonarqube
curl -s "http://localhost:9001/api/settings/values?keys=sonar.forceAuthentication" \
-u "admin:<password>"

"gosec report not showing in SonarQube"

Verify gosec-report.json was generated:

ls -la gosec-report.json
cat gosec-report.json | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'Issues: {len(d.get(\"issues\",[]))}')"

If the file is empty or missing, run gosec manually:

gosec -fmt=sonarqube -out=gosec-report.json -exclude-dir=vendor -exclude-dir=api ./...

Then re-run crawl app scan.