SCAN

CI/CD Integration

Integrate SCAN into your continuous integration and deployment pipelines to automatically detect secrets and sensitive data.

Overview

SCAN can be easily integrated into various CI/CD platforms to provide automatic security scanning as part of your build pipeline. This ensures that secrets and sensitive data are caught before they reach production.

Key Benefits

  • Automated security scanning on every commit
  • Fail builds when secrets are detected
  • Generate security reports for compliance
  • Integrate with existing workflows seamlessly

GitHub Actions

Integration with GitHub Actions is straightforward using the standard Gradle wrapper approach.

Basic Workflow

name: Security Scan

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  security-scan:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'
        
    - name: Setup Gradle
      uses: gradle/gradle-build-action@v2
      
    - name: Run SCAN Security Check
      run: ./gradlew scanForSecrets
      
    - name: Upload SCAN Results
      uses: actions/upload-artifact@v4
      if: always()
      with:
        name: scan-results
        path: scan-results/

Advanced Configuration

    - name: Run SCAN with Custom Config
      run: |
        ./gradlew scanForSecrets \
          --config-file=ci/scan-config.yml \
          --output-format=json \
          --fail-on-secrets=true
          
    - name: Comment PR with Results
      if: github.event_name == 'pull_request'
      uses: actions/github-script@v7
      with:
        script: |
          const fs = require('fs');
          const resultsPath = 'scan-results/scan-report.json';
          if (fs.existsSync(resultsPath)) {
            const results = JSON.parse(fs.readFileSync(resultsPath, 'utf8'));
            // Process and comment results
          }

Jenkins

Jenkins integration can be achieved through pipeline scripts or traditional job configurations.

Declarative Pipeline

pipeline {
    agent any
    
    tools {
        jdk 'JDK17'
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        
        stage('Security Scan') {
            steps {
                sh './gradlew scanForSecrets'
            }
            post {
                always {
                    archiveArtifacts artifacts: 'scan-results/**/*', 
                                   allowEmptyArchive: true
                    publishHTML([
                        allowMissing: false,
                        alwaysLinkToLastBuild: true,
                        keepAll: true,
                        reportDir: 'scan-results',
                        reportFiles: 'scan-report.html',
                        reportName: 'SCAN Security Report'
                    ])
                }
                failure {
                    emailext (
                        subject: "Security Scan Failed: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
                        body: "Security vulnerabilities detected. Check the report for details.",
                        to: "${env.CHANGE_AUTHOR_EMAIL}"
                    )
                }
            }
        }
    }
}

Scripted Pipeline

node {
    stage('Checkout') {
        checkout scm
    }
    
    stage('Security Scan') {
        try {
            sh './gradlew scanForSecrets --continue'
        } catch (Exception e) {
            currentBuild.result = 'UNSTABLE'
            echo "Security scan completed with findings"
        } finally {
            archiveArtifacts artifacts: 'scan-results/**/*'
        }
    }
}

GitLab CI

GitLab CI integration using the .gitlab-ci.yml configuration file.

stages:
  - security

variables:
  GRADLE_OPTS: "-Dorg.gradle.daemon=false"
  
security_scan:
  stage: security
  image: openjdk:17-jdk-alpine
  
  before_script:
    - chmod +x ./gradlew
    
  script:
    - ./gradlew scanForSecrets
    
  artifacts:
    when: always
    paths:
      - scan-results/
    reports:
      junit: scan-results/scan-report.xml
    expire_in: 1 week
    
  rules:
    - if: $CI_PIPELINE_SOURCE == "push"
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

# Security scan for merge requests
security_scan_mr:
  extends: security_scan
  script:
    - ./gradlew scanForSecrets --output-format=json
    - |
      if [ -f "scan-results/scan-report.json" ]; then
        echo "Security scan results:"
        cat scan-results/scan-report.json
      fi
  only:
    - merge_requests

Azure DevOps

Integration with Azure DevOps using YAML pipelines.

trigger:
  branches:
    include:
      - main
      - develop

pool:
  vmImage: 'ubuntu-latest'

variables:
  GRADLE_USER_HOME: $(Pipeline.Workspace)/.gradle

steps:
- task: JavaToolInstaller@0
  inputs:
    versionSpec: '17'
    jdkArchitectureOption: 'x64'
    jdkSourceOption: 'PreInstalled'

- task: Cache@2
  inputs:
    key: 'gradle | "$(Agent.OS)" | **/gradle-wrapper.properties'
    restoreKeys: gradle
    path: $(GRADLE_USER_HOME)
  displayName: Gradle build cache

- task: Gradle@2
  inputs:
    workingDirectory: ''
    gradleWrapperFile: 'gradlew'
    gradleOptions: '-Xmx3072m'
    javaHomeOption: 'JDKVersion'
    jdkVersionOption: '1.17'
    jdkArchitectureOption: 'x64'
    publishJUnitResults: false
    tasks: 'scanForSecrets'
  displayName: 'Run Security Scan'

- task: PublishBuildArtifacts@1
  condition: always()
  inputs:
    pathToPublish: 'scan-results'
    artifactName: 'security-scan-results'
  displayName: 'Publish Security Results'

- task: PublishTestResults@2
  condition: succeededOrFailed()
  inputs:
    testResultsFormat: 'JUnit'
    testResultsFiles: 'scan-results/scan-report.xml'
    testRunTitle: 'Security Scan Results'

CircleCI

CircleCI configuration using the .circleci/config.yml file.

version: 2.1

orbs:
  gradle: circleci/gradle@2.2.0

jobs:
  security-scan:
    docker:
      - image: cimg/openjdk:17.0
    
    steps:
      - checkout
      
      - gradle/with_cache:
          steps:
            - run:
                name: Run Security Scan
                command: ./gradlew scanForSecrets
                
      - store_artifacts:
          path: scan-results
          destination: security-reports
          
      - store_test_results:
          path: scan-results

workflows:
  main:
    jobs:
      - security-scan:
          filters:
            branches:
              only:
                - main
                - develop

TeamCity

TeamCity integration through build configuration and build steps.

Build Step Configuration

Step 1: Gradle Build Step

  • Runner type: Gradle
  • Gradle tasks: scanForSecrets
  • Gradle home path: Use Gradle wrapper
  • Additional command line parameters: --info

Kotlin DSL Configuration

import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs

object SecurityScan : BuildType({
    name = "Security Scan"
    
    vcs {
        root(DslContext.settingsRoot)
    }
    
    steps {
        gradle {
            tasks = "scanForSecrets"
            useGradleWrapper = true
            gradleParams = "--info --stacktrace"
        }
    }
    
    triggers {
        vcs {
            branchFilter = "+:*"
        }
    }
    
    features {
        publishArtifacts {
            artifactRules = "scan-results/** => security-reports.zip"
        }
    }
})

Best Practices

Pipeline Configuration

✅ Do

  • Run scans on every pull request
  • Cache Gradle dependencies
  • Store scan results as artifacts
  • Use appropriate JDK versions
  • Configure proper timeout values

❌ Don't

  • Ignore scan failures in production
  • Skip scans for "urgent" deployments
  • Store secrets in CI environment
  • Run scans without proper logging
  • Use overly permissive configurations

Security Considerations

  • Credential Management: Use CI platform's secret management features
  • Access Control: Limit who can modify scan configurations
  • Result Storage: Ensure scan results are stored securely
  • Notification: Set up alerts for security violations

Performance Optimization

  • Parallel Execution: Use Gradle's parallel execution features
  • Incremental Scanning: Configure for changed files only
  • Build Caching: Enable Gradle build cache for faster builds
  • Resource Limits: Set appropriate memory and CPU limits

Troubleshooting

Common Issues

Build Timeout

Solution: Increase timeout values or optimize scan configuration

timeout: 30m  # Increase timeout in CI configuration

Memory Issues

Solution: Increase JVM heap size

export GRADLE_OPTS="-Xmx4g -XX:MaxMetaspaceSize=1g"

False Positives

Solution: Configure exclusions and custom patterns

./gradlew scanForSecrets --exclude-paths="test/**" --config-file="ci-config.yml"

Debug Mode

Enable debug output for detailed troubleshooting:

./gradlew scanForSecrets --debug --stacktrace

Log Analysis

Check these log sections for common issues:

  • Configuration Loading: Verify custom configs are loaded
  • Pattern Matching: Check pattern compilation and matching
  • File Processing: Monitor file scanning progress
  • Report Generation: Ensure output files are created