Ci Security Gates
Automate security scanning in your CI/CD pipeline. --- Security gates enforce minimum security standards: - Block merges with critical vulnerabilities -...
CI Security Gates
Automate security scanning in your CI/CD pipeline.
Overview
Security gates enforce minimum security standards:
- Block merges with critical vulnerabilities
- Require security review for high findings
- Track security metrics over time
- Create audit trail
GitHub Actions
Basic Setup
# .github/workflows/security.yml
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: Install BlockSecOps CLI
run: npm install -g @blocksecops/cli
- name: Run Security Scan
env:
BLOCKSECOPS_API_KEY: ${{ secrets.BLOCKSECOPS_API_KEY }}
run: |
blocksecops scan ./contracts --preset standard --fail-on critical
With Build Step
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive # For Foundry
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
- name: Build
run: forge build
- name: Security Scan
env:
BLOCKSECOPS_API_KEY: ${{ secrets.BLOCKSECOPS_API_KEY }}
run: |
blocksecops scan ./src --preset standard --fail-on critical
PR Comments
- name: Security Scan
id: scan
env:
BLOCKSECOPS_API_KEY: ${{ secrets.BLOCKSECOPS_API_KEY }}
run: |
OUTPUT=$(blocksecops scan ./contracts --preset standard --format json)
echo "results<<EOF" >> $GITHUB_OUTPUT
echo "$OUTPUT" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
continue-on-error: true
- name: Comment on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const results = JSON.parse(`${{ steps.scan.outputs.results }}`);
const body = `## Security Scan Results
| Severity | Count |
|----------|-------|
| Critical | ${results.summary.critical} |
| High | ${results.summary.high} |
| Medium | ${results.summary.medium} |
| Low | ${results.summary.low} |
View Details`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});
GitLab CI
Basic Setup
# .gitlab-ci.yml
stages:
- build
- security
security-scan:
stage: security
image: node:18
before_script:
- npm install -g @blocksecops/cli
script:
- blocksecops scan ./contracts --preset standard --fail-on critical
variables:
BLOCKSECOPS_API_KEY: $BLOCKSECOPS_API_KEY
only:
changes:
- contracts/**/*.sol
With Artifacts
security-scan:
stage: security
script:
- blocksecops scan ./contracts --preset standard --format json > security-report.json
- blocksecops scan ./contracts --preset standard --fail-on critical
artifacts:
paths:
- security-report.json
expire_in: 30 days
Different Presets by Context
Quick for PRs, Standard for Main
# GitHub Actions
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Determine Preset
id: preset
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo "preset=quick" >> $GITHUB_OUTPUT
echo "threshold=critical" >> $GITHUB_OUTPUT
else
echo "preset=standard" >> $GITHUB_OUTPUT
echo "threshold=high" >> $GITHUB_OUTPUT
fi
- name: Security Scan
run: |
blocksecops scan ./contracts \
--preset ${{ steps.preset.outputs.preset }} \
--fail-on ${{ steps.preset.outputs.threshold }}
Deep for Releases
release-scan:
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deep Security Scan
run: |
blocksecops scan ./contracts --preset deep --fail-on high
Required Status Checks
GitHub Branch Protection
- Go to Settings → Branches
- Add rule for
main - Enable "Require status checks"
- Search and select "security-scan"
- Save
Now PRs can't merge without passing security scan.
GitLab Protected Branches
# gitlab-ci.yml
security-scan:
stage: security
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- blocksecops scan ./contracts --preset standard --fail-on critical
allow_failure: false # Block MR if fails
Handling Failures
Allow High with Review
security-scan:
runs-on: ubuntu-latest
steps:
- name: Security Scan
id: scan
run: |
blocksecops scan ./contracts --preset standard --fail-on critical
continue-on-error: true
- name: Check for High Findings
if: steps.scan.outcome == 'failure'
run: |
echo "::warning::Security scan found critical issues. Review required."
- name: Require Security Review
if: steps.scan.outcome == 'failure'
run: |
gh pr edit ${{ github.event.number }} --add-label "security-review-required"
Notify on Failure
- name: Notify Slack on Failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Security scan failed for ${{ github.repository }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Caching
Cache Dependencies
- name: Cache node_modules
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
- name: Cache Foundry
uses: actions/cache@v4
with:
path: |
~/.foundry
lib
key: ${{ runner.os }}-foundry-${{ hashFiles('foundry.toml') }}
Skip Unchanged
- name: Check for changes
uses: dorny/paths-filter@v2
id: changes
with:
filters: |
contracts:
- 'contracts/**/*.sol'
- 'src/**/*.sol'
- name: Security Scan
if: steps.changes.outputs.contracts == 'true'
run: blocksecops scan ./contracts --preset standard
Matrix Builds
Multiple Projects
strategy:
matrix:
project: [token, vault, governance]
steps:
- name: Scan ${{ matrix.project }}
run: |
blocksecops scan ./packages/${{ matrix.project }}/contracts \
--preset standard --fail-on critical
Multiple Presets
strategy:
matrix:
include:
- preset: quick
threshold: critical
- preset: standard
threshold: high
steps:
- name: Scan (${{ matrix.preset }})
run: |
blocksecops scan ./contracts \
--preset ${{ matrix.preset }} \
--fail-on ${{ matrix.threshold }}
Metrics and Reporting
Save Results as Artifact
- name: Export Report
run: |
blocksecops scan ./contracts --preset standard --format json > results.json
- name: Upload Report
uses: actions/upload-artifact@v4
with:
name: security-report
path: results.json
Track Over Time
- name: Record Metrics
run: |
RESULTS=$(blocksecops scan ./contracts --format json)
CRITICAL=$(echo $RESULTS | jq '.summary.critical')
HIGH=$(echo $RESULTS | jq '.summary.high')
# Send to metrics system
curl -X POST "$METRICS_URL" \
-d "critical=$CRITICAL&high=$HIGH&repo=$GITHUB_REPOSITORY"
Quality Gates (API-Based)
Quality Gates provide project-level security thresholds configured in the BlockSecOps dashboard. Unlike CLI-based --fail-on flags, Quality Gates persist configuration across all CI/CD integrations.
Configuration
Configure in Project Settings → Quality Gate:
| Setting | Description | Default |
|---|---|---|
| Block on Critical | Fail if ANY critical | Enabled |
| Block on High | Fail if ANY high | Disabled |
| Max Critical | Max allowed (0 = none) | 0 |
| Max High | Max allowed (-1 = unlimited) | -1 |
| Max Medium | Max allowed (-1 = unlimited) | -1 |
| Max Low | Max allowed (-1 = unlimited) | -1 |
API Integration
# GitHub Actions with Quality Gate API
- name: Evaluate Quality Gate
run: |
RESULT=$(curl -s -X POST "$BLOCKSECOPS_API_URL/quality-gates/projects/$PROJECT_ID/evaluate" \
-H "Authorization: Bearer ${{ secrets.BLOCKSECOPS_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{
"scan_id": "'$SCAN_ID'",
"triggered_by": "ci",
"ci_context": {
"branch": "'${{ github.ref_name }}'",
"commit": "'${{ github.sha }}'",
"pr": ${{ github.event.pull_request.number || 'null' }}
}
}')
PASSED=$(echo $RESULT | jq -r '.passed')
if [ "$PASSED" != "true" ]; then
echo "Quality Gate FAILED"
echo "$RESULT" | jq '.violations'
exit 1
fi
Build Status Endpoint
Check current quality gate status:
curl -s "$BLOCKSECOPS_API_URL/quality-gates/projects/$PROJECT_ID/build-status" \
-H "Authorization: Bearer $API_KEY"
Response:
{
"status": "passing",
"quality_gate_name": "Production Gate",
"critical_count": 0,
"high_count": 2,
"violations": [],
"badge_url": "/api/v1/quality-gates/projects/{id}/badge.svg"
}
README Badge
Add a security status badge to your README:
[](https://app.blocksecops.com/projects/YOUR_PROJECT_ID)
The badge updates automatically based on latest scan results (cached 5 minutes).
Tier Requirement
Quality Gates require Developer tier or higher. Free tier users should use CLI --fail-on flags instead.
Best Practices
1. Fail Early
Use Quick preset for PRs - get feedback fast.
2. Strict for Main
Use Standard preset and --fail-on high for main branch.
3. Deep for Releases
Run Deep scan before any release or deployment.
4. Don't Skip
Avoid continue-on-error: true for security jobs.
5. Review, Don't Bypass
If scan fails, fix the issue rather than skipping.
Next Steps
- GitHub Actions Guide - Detailed setup
- GitLab CI Guide - GitLab specifics
- Pre-Commit Hooks - Local enforcement