Contents

Part 3: Scanning Java Code with SonarQube (SAST)

🔎 Why Scan Your Code?

In Part 2, we scanned our dependencies with Snyk (SCA).But what about the actual Java code we write?

That’s where SAST comes in — Static Application Security Testing. It’s a fancy term for “scan your source code for security issues and code quality problems before it’s compiled or deployed.”

We’ll use SonarQube to do exactly that.

🧠 What Does SonarQube Do?

SonarQube scans your code and detects:

  • Code smells (bad practices, redundancy, maintainability)

  • Bugs (null pointers, logic errors, bad conditions)

  • Security vulnerabilities (like SQL injection, unsafe APIs)

  • Test coverage gaps (if you integrate with testing tools)

It’s like a security + quality assistant baked into your pipeline.

🔧 Running SonarQube in Azure DevOps

There are two common ways to use SonarQube:

  1. Self-hosted SonarQube (running on a server you manage)

  2. SonarCloud, the hosted version (easier to get started)

We’ll walk through the self-hosted option here. If you’re using SonarCloud, the steps are nearly the same.

✅ Step 1: Install SonarQube and Get the Token

  • Run SonarQube locally (Docker or zip installer)

  • Create a project and generate a project token

  • Store that token in Azure DevOps as a secret variable: SONAR_TOKEN

✅ Step 2: Add SonarQube Service Connection (if needed)

In Azure DevOps → Project Settings → Service connections→ Add a SonarQube connection with your server URL→ Give it a name like SonarQubeService

✅ Step 3: Add SonarQube Stage to Your YAML

Here’s how you can configure your Azure DevOps pipeline to include SonarQube for static code analysis:

- stage: SAST
  displayName: 'SAST with SonarQube'
  dependsOn: SCA
  jobs:
    - job: sonarScan
      displayName: 'Scan Java Code with SonarQube'
      pool:
        vmImage: 'ubuntu-latest'
      steps:
        - checkout: self
        - task: SonarQubePrepare@5
          inputs:
            SonarQube: 'SonarQubeService'  # Name of your service connection
            scannerMode: 'CLI'
            configMode: 'manual'
            cliProjectKey: 'devsecops-java'
            cliProjectName: 'DevSecOps Java'
            extraProperties: |
              sonar.java.binaries=target
              sonar.sources=src
              sonar.sourceEncoding=UTF-8
        - script: mvn clean verify
          displayName: 'Build Java Project'
        - task: SonarQubeAnalyze@5
          displayName: 'Run SonarQube Scan'
        - task: SonarQubePublish@5
          inputs:
            pollingTimeoutSec: '300'
          displayName: 'Publish SonarQube Results'

🧠 How It Works

  • Prepare: Configures the scanner with project info

  • Build: You run mvn verify, which compiles the code and runs tests

  • Analyze: SonarQube scans the compiled bytecode and source code

  • Publish: Sends results to your SonarQube dashboard

❌ What Can It Catch?

Examples:

  • SQL injection (Statement.execute(“SELECT * FROM " + userInput))

  • Hardcoded credentials

  • Repeated code blocks

  • Missed null checks

  • Unused variables or methods

And much more.

✅ Pro Tips

  • Keep SonarQube running and connected during the scan

  • You can fail the pipeline if code quality is below a threshold (like < 80%)

  • Use Quality Gates to enforce rules

🔄 Example Output

After the scan, you’ll get:

  • ✅ A code quality score

  • 🐛 A list of bugs

  • ⚠️ Security hotspots

  • 🧼 Suggestions for improvement

  • 💯 Coverage stats (if tests are run with coverage reports)

⏭️ What’s Next?

We’ve now scanned:

  • ✅ Dependencies (SCA with Snyk)

  • ✅ Code (SAST with SonarQube)

Next up?

We shift our attention to the infrastructure layer.In Part 4, we’ll scan our Terraform files using Checkov — and make sure we’re not deploying anything with public IPs, overly open firewalls, or hardcoded secrets.

👉 Continue to Part 4 – Terraform Security Scanning with Checkov