Skip to content

CI CD Integration

Jean-Marc Strauven edited this page Aug 1, 2025 · 1 revision

πŸš€ CI/CD Integration Guide

Laravel Safeguard is designed to integrate seamlessly with continuous integration and deployment pipelines. This guide shows you how to automate security checks across different CI/CD platforms.

🎯 Benefits of CI/CD Integration

  • πŸ”’ Automated Security Checks: Run security audits on every commit
  • 🚫 Prevent Insecure Deployments: Block deployments with security issues
  • πŸ“Š Security Reports: Generate detailed security reports for teams
  • ⏰ Early Detection: Catch security issues before they reach production
  • πŸ”„ Consistent Standards: Enforce security standards across all environments

πŸ™ GitHub Actions

Basic Security Workflow

Create .github/workflows/security.yml:

name: Security Audit

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

jobs:
  security:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
      
    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
        php-version: '8.3'
        extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite
        
    - name: Cache Composer packages
      id: composer-cache
      uses: actions/cache@v3
      with:
        path: vendor
        key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
        restore-keys: |
          ${{ runner.os }}-php-
          
    - name: Install dependencies
      run: composer install --prefer-dist --no-progress --no-interaction
      
    - name: Create .env file
      run: |
        cp .env.example .env
        php artisan key:generate
        
    - name: Run security checks
      run: php artisan safeguard:check --env=production --fail-on-error --format=ci

Advanced Multi-Environment Workflow

name: Advanced Security Audit

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]
  schedule:
    - cron: '0 2 * * *'  # Daily at 2 AM

jobs:
  security:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        environment: [staging, production]
        
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
      
    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
        php-version: '8.3'
        
    - name: Install dependencies
      run: composer install --prefer-dist --no-progress --optimize-autoloader
      
    - name: Setup environment
      run: |
        cp .env.example .env
        php artisan key:generate
        
    - name: Run security checks for ${{ matrix.environment }}
      run: |
        php artisan safeguard:check \\
          --env=${{ matrix.environment }} \\
          --format=json \\
          --fail-on-error > security-report-${{ matrix.environment }}.json
          
    - name: Upload security report
      uses: actions/upload-artifact@v3
      if: always()
      with:
        name: security-report-${{ matrix.environment }}
        path: security-report-${{ matrix.environment }}.json
        retention-days: 30
        
    - name: Comment PR with security results
      if: github.event_name == 'pull_request'
      uses: actions/github-script@v6
      with:
        script: |
          const fs = require('fs');
          try {
            const report = JSON.parse(fs.readFileSync('security-report-${{ matrix.environment }}.json', 'utf8'));
            const { summary } = report;
            
            const body = \\`
            ## πŸ” Security Audit Results (${{ matrix.environment }})
            
            - βœ… **Passed**: \\${summary.passed}
            - ❌ **Failed**: \\${summary.failed}
            - ⚠️ **Warnings**: \\${summary.warnings}
            - πŸ“Š **Total Checks**: \\${summary.total}
            
            \\${summary.failed > 0 ? '❌ **Security issues detected!** Please review and fix before merging.' : 'βœ… **All security checks passed!**'}
            \\`;
            
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: body
            });
          } catch (error) {
            console.log('Could not parse security report:', error);
          }

Security Report Workflow

name: Generate Security Report

on:
  schedule:
    - cron: '0 6 * * 1'  # Every Monday at 6 AM
  workflow_dispatch:  # Manual trigger

jobs:
  security-report:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
      
    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
        php-version: '8.3'
        
    - name: Install dependencies
      run: composer install --prefer-dist --no-progress
      
    - name: Setup environment
      run: |
        cp .env.example .env
        php artisan key:generate
        
    - name: Generate comprehensive security report
      run: |
        mkdir -p reports
        php artisan safeguard:check --env=production --format=json > reports/security-report.json
        php artisan safeguard:check --env=production --format=html > reports/security-report.html
        
    - name: Upload report artifacts
      uses: actions/upload-artifact@v3
      with:
        name: weekly-security-report
        path: reports/
        retention-days: 90
        
    - name: Send report via email (if configured)
      if: failure()
      uses: dawidd6/action-send-mail@v3
      with:
        server_address: ${{ secrets.SMTP_SERVER }}
        server_port: 587
        username: ${{ secrets.SMTP_USERNAME }}
        password: ${{ secrets.SMTP_PASSWORD }}
        subject: 'Weekly Security Report - Issues Found'
        from: '[email protected]'
        to: '[email protected]'
        body: 'Security issues have been detected. Please review the attached report.'
        attachments: reports/security-report.html

🦊 GitLab CI

Basic Configuration

Create .gitlab-ci.yml:

stages:
  - test
  - security
  - deploy

variables:
  COMPOSER_CACHE_DIR: \"$CI_PROJECT_DIR/.composer-cache\"

cache:
  paths:
    - .composer-cache/
    - vendor/

security_check:
  stage: security
  image: php:8.3-cli
  
  before_script:
    - apt-get update -yqq
    - apt-get install -yqq git unzip
    - curl -sS https://getcomposer.org/installer | php
    - mv composer.phar /usr/local/bin/composer
    - composer install --prefer-dist --no-progress --optimize-autoloader
    - cp .env.example .env
    - php artisan key:generate
  
  script:
    - php artisan safeguard:check --env=production --fail-on-error --format=junit > security-results.xml
  
  artifacts:
    when: always
    reports:
      junit: security-results.xml
    paths:
      - security-results.xml
    expire_in: 1 week
  
  only:
    - master
    - develop
    - merge_requests

Advanced GitLab CI Configuration

stages:
  - test
  - security
  - deploy

.security_template: &security_template
  image: php:8.3-cli
  before_script:
    - apt-get update -yqq
    - apt-get install -yqq git unzip
    - curl -sS https://getcomposer.org/installer | php
    - mv composer.phar /usr/local/bin/composer
    - composer install --no-dev --optimize-autoloader
    - cp .env.example .env
    - php artisan key:generate

security:staging:
  <<: *security_template
  stage: security
  script:
    - php artisan safeguard:check --env=staging --fail-on-error --format=json > security-staging.json
  artifacts:
    when: always
    paths:
      - security-staging.json
    expire_in: 1 week
  only:
    - develop

security:production:
  <<: *security_template
  stage: security
  script:
    - php artisan safeguard:check --env=production --fail-on-error --format=json > security-production.json
  artifacts:
    when: always
    paths:
      - security-production.json
    expire_in: 1 week
  only:
    - master

security:report:
  <<: *security_template
  stage: security
  script:
    - php artisan safeguard:check --env=production --format=html > security-report.html
  artifacts:
    when: always
    paths:
      - security-report.html
    expire_in: 30 days
  only:
    - schedules

πŸ”¨ Jenkins

Declarative Pipeline

Create Jenkinsfile:

pipeline {
    agent any
    
    environment {
        COMPOSER_HOME = \"${WORKSPACE}/.composer\"
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        
        stage('Install Dependencies') {
            steps {
                sh 'composer install --no-dev --optimize-autoloader'
                sh 'cp .env.example .env'
                sh 'php artisan key:generate'
            }
        }
        
        stage('Security Checks') {
            parallel {
                stage('Production Security') {
                    steps {
                        sh 'php artisan safeguard:check --env=production --fail-on-error --format=json > security-production.json'
                    }
                }
                stage('Staging Security') {
                    steps {
                        sh 'php artisan safeguard:check --env=staging --fail-on-error --format=json > security-staging.json'
                    }
                }
            }
            post {
                always {
                    archiveArtifacts artifacts: 'security-*.json', fingerprint: true
                    publishHTML([
                        allowMissing: false,
                        alwaysLinkToLastBuild: true,
                        keepAll: true,
                        reportDir: '.',
                        reportFiles: 'security-production.json',
                        reportName: 'Security Report'
                    ])
                }
                failure {
                    emailext (
                        subject: \"Security Check Failed: \\${env.JOB_NAME} - \\${env.BUILD_NUMBER}\",
                        body: \"Security issues detected in build \\${env.BUILD_NUMBER}. Please check the attached report.\",
                        to: \"\\${env.CHANGE_AUTHOR_EMAIL}, [email protected]\",
                        attachmentsPattern: 'security-*.json'
                    )
                }
            }
        }
        
        stage('Deploy') {
            when {
                allOf {
                    branch 'master'
                    not { changeRequest() }
                }
            }
            steps {
                echo 'Deploying to production...'
                // Your deployment steps here
            }
        }
    }
}

Scripted Pipeline with Security Gates

node {
    try {
        stage('Checkout') {
            checkout scm
        }
        
        stage('Install Dependencies') {
            sh 'composer install --no-dev --optimize-autoloader'
            sh 'cp .env.example .env'
            sh 'php artisan key:generate'
        }
        
        stage('Security Gate') {
            def securityResult = sh(
                script: 'php artisan safeguard:check --env=production --format=json',
                returnStatus: true
            )
            
            if (securityResult != 0) {
                error('Security checks failed. Deployment blocked.')
            }
            
            echo 'Security checks passed. Proceeding with deployment.'
        }
        
        stage('Deploy') {
            if (env.BRANCH_NAME == 'master') {
                echo 'Deploying to production...'
                // Deployment steps
            }
        }
        
    } catch (Exception e) {
        currentBuild.result = 'FAILURE'
        throw e
    } finally {
        // Archive security reports
        archiveArtifacts artifacts: 'security-*.json', allowEmptyArchive: true
        
        // Send notifications
        if (currentBuild.result == 'FAILURE') {
            emailext (
                subject: \"Security Check Failed: \\${env.JOB_NAME}\",
                body: \"Security issues detected. Check Jenkins for details.\",
                to: \"\\${env.CHANGE_AUTHOR_EMAIL}\"
            )
        }
    }
}

☁️ Azure DevOps

Azure Pipelines YAML

Create azure-pipelines.yml:

trigger:
  branches:
    include:
      - main
      - develop

pr:
  branches:
    include:
      - main

pool:
  vmImage: 'ubuntu-latest'

variables:
  phpVersion: '8.3'

stages:
- stage: SecurityCheck
  displayName: 'Security Audit'
  jobs:
  - job: SecurityAudit
    displayName: 'Run Security Checks'
    steps:
    - task: UsePhpVersion@0
      inputs:
        versionSpec: '$(phpVersion)'
      displayName: 'Use PHP $(phpVersion)'
      
    - script: |
        curl -sS https://getcomposer.org/installer | php
        sudo mv composer.phar /usr/local/bin/composer
        composer install --prefer-dist --no-progress --optimize-autoloader
      displayName: 'Install Composer dependencies'
      
    - script: |
        cp .env.example .env
        php artisan key:generate
      displayName: 'Setup Laravel environment'
      
    - script: |
        php artisan safeguard:check --env=production --fail-on-error --format=junit > security-results.xml
      displayName: 'Run security checks'
      continueOnError: true
      
    - task: PublishTestResults@2
      inputs:
        testResultsFormat: 'JUnit'
        testResultsFiles: 'security-results.xml'
        testRunTitle: 'Security Audit Results'
        failTaskOnFailedTests: true
      displayName: 'Publish security results'
      
    - task: PublishBuildArtifacts@1
      inputs:
        pathToPublish: 'security-results.xml'
        artifactName: 'security-report'
      displayName: 'Archive security report'

🐳 Docker Integration

Dockerfile for CI/CD

FROM php:8.3-cli

# Install system dependencies
RUN apt-get update && apt-get install -y \\
    git \\
    curl \\
    libpng-dev \\
    libonig-dev \\
    libxml2-dev \\
    zip \\
    unzip

# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Set working directory
WORKDIR /var/www

# Copy application files
COPY . .

# Install dependencies
RUN composer install --no-dev --optimize-autoloader

# Setup Laravel
RUN cp .env.example .env && php artisan key:generate

# Run security checks
CMD [\"php\", \"artisan\", \"safeguard:check\", \"--env=production\", \"--fail-on-error\"]

Docker Compose for CI

version: '3.8'

services:
  security-check:
    build: .
    volumes:
      - ./reports:/var/www/reports
    command: >
      sh -c \"
        php artisan safeguard:check --env=production --format=json > reports/security-report.json &&
        php artisan safeguard:check --env=production --format=html > reports/security-report.html
      \"
    environment:
      - APP_ENV=production
      - APP_DEBUG=false

πŸ“Š Output Formats for CI/CD

JSON Format

Perfect for programmatic processing:

php artisan safeguard:check --format=json > security-report.json

CI Format

Optimized for CI/CD environments:

php artisan safeguard:check --format=ci --fail-on-error

JUnit XML Format

For test result integration:

php artisan safeguard:check --format=junit > security-results.xml

HTML Format

For human-readable reports:

php artisan safeguard:check --format=html > security-report.html

πŸ”§ Advanced CI/CD Patterns

Security as Code

Create reusable security configurations:

# .github/workflows/reusable-security.yml
name: Reusable Security Workflow

on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
      php-version:
        required: false
        type: string
        default: '8.3'

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ inputs.php-version }}
      - name: Install dependencies
        run: composer install --prefer-dist --no-progress
      - name: Run security checks
        run: php artisan safeguard:check --env=${{ inputs.environment }} --fail-on-error

Use in multiple workflows:

# .github/workflows/deploy-staging.yml
name: Deploy to Staging

on:
  push:
    branches: [develop]

jobs:
  security:
    uses: ./.github/workflows/reusable-security.yml
    with:
      environment: staging
      
  deploy:
    needs: security
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to staging
        run: echo \"Deploying to staging...\"

Progressive Security Checks

#!/bin/bash
# scripts/progressive-security-check.sh

echo \"πŸ” Running progressive security checks...\"

# Level 1: Critical security issues only
echo \"πŸ“Š Level 1: Critical issues\"
php artisan safeguard:check --severity=critical --fail-on-error
if [ $? -ne 0 ]; then
    echo \"❌ Critical security issues found. Stopping deployment.\"
    exit 1
fi

# Level 2: Add error-level issues
echo \"πŸ“Š Level 2: Critical + Error issues\"
php artisan safeguard:check --severity=critical,error --fail-on-error
if [ $? -ne 0 ]; then
    echo \"⚠️ Security errors found. Manual review required.\"
    exit 2
fi

# Level 3: Full security audit
echo \"πŸ“Š Level 3: Full security audit\"
php artisan safeguard:check --fail-on-error
if [ $? -ne 0 ]; then
    echo \"⚠️ Security warnings found. Consider addressing before deployment.\"
    exit 3
fi

echo \"βœ… All security checks passed!\"

Notification Integration

Slack Notifications

- name: Notify Slack on security failure
  if: failure()
  uses: 8398a7/action-slack@v3
  with:
    status: failure
    custom_payload: |
      {
        \"text\": \"🚨 Security check failed in ${{ github.repository }}\",
        \"attachments\": [{
          \"color\": \"danger\",
          \"fields\": [{
            \"title\": \"Repository\",
            \"value\": \"${{ github.repository }}\",
            \"short\": true
          }, {
            \"title\": \"Branch\",
            \"value\": \"${{ github.ref }}\",
            \"short\": true
          }]
        }]
      }
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

Microsoft Teams Notifications

- name: Notify Teams on security failure
  if: failure()
  uses: skitionek/notify-microsoft-teams@master
  with:
    webhook_url: ${{ secrets.TEAMS_WEBHOOK_URL }}
    message: \"🚨 Security check failed in ${{ github.repository }} on branch ${{ github.ref }}\"

πŸ“‹ CI/CD Checklist

βœ… Setup Checklist

  • Security workflow added to CI/CD pipeline
  • Appropriate environment configurations set
  • Failure conditions properly configured
  • Security reports generated and archived
  • Team notifications configured
  • Manual review process defined for failures

πŸ”§ Configuration Checklist

  • --fail-on-error flag used to block deployments
  • Appropriate output format selected
  • Environment-specific rules configured
  • Performance timeout settings configured
  • Artifact retention policies set

πŸ“Š Monitoring Checklist

  • Security trend monitoring implemented
  • Regular security report generation scheduled
  • Alert thresholds configured
  • Team training on security results completed

🀝 Best Practices

  1. 🚫 Fail Fast: Use --fail-on-error to stop deployments with security issues
  2. πŸ“Š Multiple Formats: Generate both machine-readable and human-readable reports
  3. 🌍 Environment-Specific: Run different rule sets for different environments
  4. πŸ“ˆ Trend Monitoring: Track security metrics over time
  5. πŸ‘₯ Team Involvement: Ensure the whole team understands security results
  6. πŸ”„ Regular Updates: Keep security rules updated as your application evolves

πŸ“š Related Documentation


Next Step: πŸ“Š Learn about different output formats

🏠 Home | ⚑ Quick Start | βš™οΈ Configuration | πŸ“Š Output Formats

Clone this wiki locally