Skip to main content

Overview

This guide shows a complete DevSecOps workflow using ZenVeil: from a developer’s first commit to production deployment, with security validation at every stage.
Developer writes code


zenveil scan repo .        ← Local: immediate feedback


git push → CI pipeline

      ├── zenveil scan repo .    ← PR gate: blocks merge on CRITICAL/HIGH
      └── zenveil scan github    ← Scheduled: weekly CVE checks


          Merge to main


          zenveil scan api       ← Post-deploy: header check

Stage 1: Local development

Make ZenVeil part of your development loop. Run it before every commit:
# Add to your commit workflow
git add .
zenveil scan repo . && git commit -m "feat: add payment flow"
# ↑ Only commit if scan passes (no CRITICAL/HIGH)
Or add it as a git pre-commit hook:
# .git/hooks/pre-commit
#!/bin/bash
echo "Running ZenVeil security scan..."
zenveil scan repo .
if [ $? -eq 1 ]; then
  echo ""
  echo "✗ ZenVeil found CRITICAL or HIGH security issues."
  echo "  Run 'zenveil list --severity critical,high' to see them."
  echo "  Run 'zenveil explain <id>' for AI analysis."
  echo "  Fix the issues or use 'git commit --no-verify' to bypass."
  exit 1
fi
echo "✓ ZenVeil scan passed."
chmod +x .git/hooks/pre-commit
Use git commit --no-verify to bypass the hook when you’re committing a work-in-progress that you know has issues — the CI pipeline will still catch it.

Stage 2: Pull request gate (GitHub Actions)

Every PR is scanned before it can be merged:
# .github/workflows/security.yml
name: Security Gate

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

jobs:
  security-scan:
    name: ZenVeil Security Scan
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
      security-events: write

    steps:
      - name: Checkout
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
          cache: 'pip'

      - name: Install ZenVeil
        run: pip install zenveil

      - name: Scan repository
        id: scan
        env:
          ZENVEIL_API_KEY: ${{ secrets.ZENVEIL_API_KEY }}
        run: |
          zenveil scan repo . --json security-results.json
          echo "exit_code=$?" >> $GITHUB_OUTPUT

      - name: Comment on PR
        if: always()
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const results = JSON.parse(fs.readFileSync('security-results.json'));
            const critical = results.findings.filter(f => f.severity === 'CRITICAL').length;
            const high = results.findings.filter(f => f.severity === 'HIGH').length;
            const total = results.finding_count;

            const statusIcon = (critical + high) > 0 ? '🚨' : '✅';
            const body = [
              `## ${statusIcon} ZenVeil Security Scan`,
              ``,
              `| Severity | Count |`,
              `|---|---|`,
              `| 🔴 CRITICAL | ${critical} |`,
              `| 🟠 HIGH | ${high} |`,
              `| 🟡 MEDIUM | ${results.findings.filter(f => f.severity === 'MEDIUM').length} |`,
              `| 🟢 LOW | ${results.findings.filter(f => f.severity === 'LOW').length} |`,
              ``,
              critical + high > 0
                ? `**❌ This PR cannot be merged until CRITICAL and HIGH findings are resolved.**`
                : `**✅ Security gate passed. No blocking findings.**`,
            ].join('\n');

            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body,
            });

      - name: Upload results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: security-scan-${{ github.sha }}
          path: security-results.json

      - name: Fail if blocking findings
        if: steps.scan.outputs.exit_code == '1'
        run: exit 1

Stage 3: Weekly scheduled scan

Catch newly disclosed CVEs in your dependencies:
# .github/workflows/weekly-security.yml
name: Weekly Security Scan

on:
  schedule:
    - cron: '0 9 * * 1'  # Every Monday at 9am UTC
  workflow_dispatch:       # Manual trigger

jobs:
  weekly-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744

      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - run: pip install zenveil

      - name: Scan with CVE checks
        env:
          ZENVEIL_API_KEY: ${{ secrets.ZENVEIL_API_KEY }}
        run: zenveil scan repo . --check-cves --json weekly-scan.json

      - name: Notify Slack on critical findings
        if: failure()
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {"text": "🚨 Weekly security scan found critical issues in ${{ github.repository }}. Check the Actions tab."}
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK

      - name: Store results
        uses: actions/upload-artifact@v4
        with:
          name: weekly-security-${{ github.run_id }}
          path: weekly-scan.json
          retention-days: 365

Stage 4: Post-deploy API scan

After each deployment, verify security headers are set correctly:
# .github/workflows/post-deploy.yml
name: Post-Deploy Security Check

on:
  deployment_status:

jobs:
  api-scan:
    if: github.event.deployment_status.state == 'success'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - run: pip install zenveil

      - name: Scan deployed API
        env:
          ZENVEIL_API_KEY: ${{ secrets.ZENVEIL_API_KEY }}
          DEPLOY_URL: ${{ github.event.deployment_status.environment_url }}
        run: |
          zenveil scan api $DEPLOY_URL --json api-headers.json

Stage 5: Developer feedback loop

After fixing issues, close the loop with feedback:
# Record that findings were real and fixed
zenveil feedback ZG-A1B2 correct
zenveil feedback ZG-C3D4 correct

# Record false positives to improve future scanning
zenveil feedback ZG-X1Y2 false_positive

# Suppress known acceptable risks
zenveil ignore ZG-L3M4 --reason "Accepted risk: internal admin tool, not customer-facing"

Security posture over time

With this workflow in place, your security posture compounds:
StageWhat you gain
Local pre-commit hookSecrets never reach git history
PR gateVulnerabilities don’t ship to main
Weekly CVE scanNew vulnerabilities in old code are caught
Post-deploy API scanConfiguration drift is detected
Feedback loopFalse positive rate drops, signal improves
After 4 weeks: fewer findings, faster reviews, more developer confidence. After 3 months: your codebase has a measurable security improvement baseline. After 6 months: security is part of how the team ships — not a separate audit.