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