Advanced Tutorial

CI/CD Pipeline Security Gates

Integrate security scanning into GitHub Actions, GitLab CI, or Jenkins to block insecure deployments.

Overview

Shift security left by integrating automated security scanning directly into your CI/CD pipeline. This tutorial shows you how to use reNgine Cloud API to scan staging environments, block deployments with critical vulnerabilities, and track security debt over time.

What You'll Learn

  • API-based scan triggering from CI/CD workflows
  • Fail pipelines on critical security findings
  • Parallel scanning of staging environments
  • Generate security badges for README files
  • Track security debt metrics over time

Step 1: API-Based Scan Triggering

Use the reNgine Cloud API to trigger scans automatically when code is pushed to staging or production branches. Store your API key as a CI/CD secret for secure authentication.

# GitHub Actions Workflow
name: Security Scan
on:
  push:
    branches: [staging, main]
  pull_request:
    branches: [main]

jobs:
  security_scan:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger reNgine Scan
        env:
          RENGINE_API_KEY: ${{ secrets.RENGINE_API_KEY }}
          RENGINE_URL: ${{ secrets.RENGINE_URL }}
        run: |
          SCAN_ID=$(curl -X POST "$RENGINE_URL/api/scans" \
            -H "Authorization: Bearer $RENGINE_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{
              "target": "staging.example.com",
              "scan_type": "full",
              "notify_on_completion": true
            }' | jq -r '.scan_id')

          echo "SCAN_ID=$SCAN_ID" >> $GITHUB_ENV
          echo "Started scan: $SCAN_ID"

Step 2: Fail Pipelines on Critical Findings

Poll the scan status API until completion, then check for critical or high-severity vulnerabilities. Fail the pipeline if security thresholds are exceeded.

      - name: Wait for Scan Completion
        run: |
          while true; do
            STATUS=$(curl -s "$RENGINE_URL/api/scans/$SCAN_ID/status" \
              -H "Authorization: Bearer $RENGINE_API_KEY" \
              | jq -r '.status')

            if [ "$STATUS" = "completed" ]; then
              break
            fi

            echo "Scan status: $STATUS. Waiting 30s..."
            sleep 30
          done

      - name: Check Security Findings
        run: |
          RESULTS=$(curl -s "$RENGINE_URL/api/scans/$SCAN_ID/results" \
            -H "Authorization: Bearer $RENGINE_API_KEY")

          CRITICAL=$(echo $RESULTS | jq '.findings.critical // 0')
          HIGH=$(echo $RESULTS | jq '.findings.high // 0')

          echo "Critical: $CRITICAL, High: $HIGH"

          # Fail if critical findings exist
          if [ "$CRITICAL" -gt 0 ]; then
            echo "❌ CRITICAL vulnerabilities found! Blocking deployment."
            exit 1
          fi

          # Warn if high findings exist
          if [ "$HIGH" -gt 3 ]; then
            echo "⚠️  Warning: $HIGH HIGH severity findings detected"
            exit 1
          fi

          echo "✅ Security scan passed"

Step 3: Parallel Staging Environment Scans

For microservices architectures, scan multiple staging endpoints in parallel to reduce total pipeline time. Use matrix builds to scale across services.

GitLab CI Configuration

stages:
  - deploy
  - security

deploy_staging:
  stage: deploy
  script:
    - deploy_to_staging.sh
  environment:
    name: staging

security_scan:
  stage: security
  parallel:
    matrix:
      - SERVICE: [api, web, admin, mobile-api]
  script:
    - |
      curl -X POST "$RENGINE_URL/api/scans" \
        -H "Authorization: Bearer $RENGINE_API_KEY" \
        -d "{\"target\": \"$SERVICE.staging.example.com\"}"
  only:
    - staging
    - main

Step 4: Generate Security Badges

Create visual security status badges for your README to communicate security posture to stakeholders. Use shields.io or generate custom SVG badges via API.

      - name: Generate Security Badge
        run: |
          SCORE=$(curl -s "$RENGINE_URL/api/scans/$SCAN_ID/score" \
            -H "Authorization: Bearer $RENGINE_API_KEY" \
            | jq -r '.security_score')

          # Determine badge color
          if [ "$SCORE" -gt 90 ]; then COLOR="brightgreen"
          elif [ "$SCORE" -gt 70 ]; then COLOR="yellow"
          else COLOR="red"; fi

          # Generate badge URL
          BADGE_URL="https://img.shields.io/badge/security-$SCORE%25-$COLOR"

          echo "![Security Score]($BADGE_URL)" >> security-badge.md

      - name: Update README
        run: |
          # Replace security badge in README
          sed -i "s|!\[Security\].*|$(cat security-badge.md)|" README.md

      - name: Commit Badge Update
        uses: stefanzweifel/git-auto-commit-action@v4
        with:
          commit_message: "Update security badge [skip ci]"
          file_pattern: README.md

Step 5: Track Security Debt Over Time

Store scan results as CI/CD artifacts and track security metrics across deployments. Use dashboards to visualize trends and measure security improvement.

Jenkins Pipeline Example

pipeline {
  agent any

  stages {
    stage('Deploy to Staging') {
      steps {
        sh 'deploy_staging.sh'
      }
    }

    stage('Security Scan') {
      steps {
        script {
          def scanId = sh(
            script: """curl -X POST ${env.RENGINE_URL}/api/scans \
              -H 'Authorization: Bearer ${env.RENGINE_API_KEY}' \
              -d '{"target": "staging.example.com"}' \
              | jq -r '.scan_id'""",
            returnStdout: true
          ).trim()

          env.SCAN_ID = scanId
        }
      }
    }

    stage('Wait & Validate') {
      steps {
        script {
          timeout(time: 30, unit: 'MINUTES') {
            waitUntil {
              def status = sh(
                script: "curl -s ${env.RENGINE_URL}/api/scans/${env.SCAN_ID}/status | jq -r '.status'",
                returnStdout: true
              ).trim()
              return status == 'completed'
            }
          }

          def critical = sh(
            script: "curl -s ${env.RENGINE_URL}/api/scans/${env.SCAN_ID}/results | jq '.findings.critical'",
            returnStdout: true
          ).trim().toInteger()

          if (critical > 0) {
            error("Critical vulnerabilities found! Deployment blocked.")
          }
        }
      }
    }
  }

  post {
    always {
      archiveArtifacts artifacts: 'security-report.json', allowEmptyArchive: true
      publishHTML([
        reportDir: 'security',
        reportFiles: 'report.html',
        reportName: 'Security Scan Report'
      ])
    }
  }
}

Best Practices

  • Scan Staging First: Never run destructive scans against production
  • Define Thresholds: Set clear severity thresholds for pipeline failures
  • Cache Results: Avoid re-scanning identical deployments
  • Timeout Protection: Set maximum wait times to prevent hung pipelines
  • Exception Workflow: Allow security team to approve exceptions for known issues
  • Notifications: Alert security team on pipeline failures

Next Steps