Policy Workflow Examples
This guide provides real-world examples of integrating JMo Security Policy-as-Code into CI/CD pipelines and development workflows.
Table of Contents
- GitHub Actions
- Basic Policy Gating
- Multi-Policy Enforcement
- PR Comment Automation
- GitLab CI
- Basic Policy Gating
- Multi-Environment Policies
- MR Policy Reports
- Jenkins
- Declarative Pipeline
- Scripted Pipeline
- Pre-Commit Hooks
- Docker Compose
- Kubernetes
GitHub Actions
Basic Policy Gating (GitHub Actions)
Fail CI/CD if secrets detected:
name: Security Scan with Zero-Secrets Policy
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install OPA
run: |
wget https://github.com/open-policy-agent/opa/releases/download/v1.10.0/opa_linux_amd64
chmod +x opa_linux_amd64
sudo mv opa_linux_amd64 /usr/local/bin/opa
- name: Install JMo Security
run: pip install jmo-security
- name: Run Security Scan
run: |
jmo ci \
--repo . \
--policy zero-secrets \
--fail-on-policy-violation \
--profile-name fast
- name: Upload Policy Results
if: always()
uses: actions/upload-artifact@v4
with:
name: policy-results
path: |
results/summaries/POLICY_REPORT.md
results/summaries/policy_results.json
Multi-Policy Enforcement (GitHub Actions)
Enforce multiple policies based on branch:
name: Multi-Policy Security Scan
on:
push:
branches: [main, develop, 'release/*']
pull_request:
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup OPA
uses: open-policy-agent/setup-opa@v2
with:
version: '1.10.0'
- name: Install JMo Security
run: pip install jmo-security
- name: Determine Policies (Main Branch)
if: github.ref == 'refs/heads/main'
run: echo "POLICIES=zero-secrets owasp-top-10 production-hardening" >> $GITHUB_ENV
- name: Determine Policies (Develop Branch)
if: github.ref == 'refs/heads/develop'
run: echo "POLICIES=zero-secrets owasp-top-10" >> $GITHUB_ENV
- name: Determine Policies (Pull Requests)
if: github.event_name == 'pull_request'
run: echo "POLICIES=zero-secrets" >> $GITHUB_ENV
- name: Run Security Scan
run: |
jmo ci \
--repo . \
--policy $POLICIES \
--fail-on-policy-violation \
--profile-name balanced
- name: Upload Results
if: always()
uses: actions/upload-artifact@v4
with:
name: policy-results-${{ github.sha }}
path: results/summaries/
PR Comment Automation
Post policy results as PR comments:
name: Security Scan with PR Comment
on:
pull_request:
branches: [main]
jobs:
security-scan:
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Setup OPA
uses: open-policy-agent/setup-opa@v2
with:
version: '1.10.0'
- name: Install JMo Security
run: pip install jmo-security
- name: Run Security Scan
id: scan
continue-on-error: true
run: |
jmo ci \
--repo . \
--policy zero-secrets \
--policy owasp-top-10 \
--fail-on-policy-violation \
--profile-name balanced
- name: Post PR Comment
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
// Read policy report
const policyReport = fs.readFileSync('results/summaries/POLICY_REPORT.md', 'utf8');
// Post as PR comment
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## 🔒 Security Policy Evaluation\n\n${policyReport}`
});
- name: Fail if policies failed
if: steps.scan.outcome == 'failure'
run: exit 1
GitLab CI
Basic Policy Gating (GitLab CI)
security-scan:
stage: test
image: python:3.11
before_script:
- pip install jmo-security
- wget https://github.com/open-policy-agent/opa/releases/download/v1.10.0/opa_linux_amd64
- chmod +x opa_linux_amd64
- mv opa_linux_amd64 /usr/local/bin/opa
script:
- |
jmo ci \
--repo . \
--policy zero-secrets \
--policy owasp-top-10 \
--fail-on-policy-violation \
--profile-name balanced
artifacts:
when: always
paths:
- results/summaries/
reports:
junit: results/summaries/policy_results.json
expire_in: 30 days
only:
- merge_requests
- main
- develop
Multi-Environment Policies (GitLab CI)
Different policies for different environments:
variables:
POLICY_DEVELOP: "zero-secrets"
POLICY_STAGING: "zero-secrets owasp-top-10"
POLICY_PRODUCTION: "zero-secrets owasp-top-10 production-hardening pci-dss"
.scan_template: &scan_template
image: python:3.11
before_script:
- pip install jmo-security
- wget https://github.com/open-policy-agent/opa/releases/download/v1.10.0/opa_linux_amd64
- chmod +x opa_linux_amd64
- mv opa_linux_amd64 /usr/local/bin/opa
artifacts:
when: always
paths:
- results/summaries/
expire_in: 30 days
security-scan-develop:
<<: *scan_template
stage: test
script:
- jmo ci --repo . --policy $POLICY_DEVELOP --fail-on-policy-violation
only:
- develop
security-scan-staging:
<<: *scan_template
stage: test
script:
- jmo ci --repo . --policy $POLICY_STAGING --fail-on-policy-violation
only:
- staging
security-scan-production:
<<: *scan_template
stage: test
script:
- jmo ci --repo . --policy $POLICY_PRODUCTION --fail-on-policy-violation
only:
- main
- tags
MR Policy Reports
Post policy results to merge request notes:
security-scan:
stage: test
image: python:3.11
before_script:
- pip install jmo-security python-gitlab
- wget https://github.com/open-policy-agent/opa/releases/download/v1.10.0/opa_linux_amd64
- chmod +x opa_linux_amd64
- mv opa_linux_amd64 /usr/local/bin/opa
script:
- |
# Run scan
jmo ci \
--repo . \
--policy zero-secrets \
--policy owasp-top-10 \
--fail-on-policy-violation || true
# Post to MR
if [ -f results/summaries/POLICY_REPORT.md ]; then
python3 - <<'EOF'
import gitlab
import os
gl = gitlab.Gitlab(os.environ['CI_SERVER_URL'], private_token=os.environ['GITLAB_TOKEN'])
project = gl.projects.get(os.environ['CI_PROJECT_ID'])
mr = project.mergerequests.get(os.environ['CI_MERGE_REQUEST_IID'])
with open('results/summaries/POLICY_REPORT.md', 'r') as f:
report = f.read()
mr.notes.create({'body': f'## 🔒 Security Policy Evaluation\n\n{report}'})
EOF
fi
artifacts:
when: always
paths:
- results/summaries/
only:
- merge_requests
Jenkins
Declarative Pipeline (Jenkins)
pipeline {
agent any
environment {
OPA_VERSION = '1.10.0'
}
stages {
stage('Setup') {
steps {
sh '''
# Install OPA
wget https://github.com/open-policy-agent/opa/releases/download/v${OPA_VERSION}/opa_linux_amd64
chmod +x opa_linux_amd64
sudo mv opa_linux_amd64 /usr/local/bin/opa
# Install JMo Security
pip install jmo-security
'''
}
}
stage('Security Scan') {
steps {
script {
def policies = []
// Branch-specific policies
if (env.BRANCH_NAME == 'main') {
policies = ['zero-secrets', 'owasp-top-10', 'production-hardening']
} else if (env.BRANCH_NAME == 'develop') {
policies = ['zero-secrets', 'owasp-top-10']
} else {
policies = ['zero-secrets']
}
def policyArgs = policies.collect { "--policy $it" }.join(' ')
sh """
jmo ci \
--repo . \
${policyArgs} \
--fail-on-policy-violation \
--profile-name balanced
"""
}
}
}
}
post {
always {
archiveArtifacts artifacts: 'results/summaries/*', fingerprint: true
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'results/summaries',
reportFiles: 'POLICY_REPORT.md',
reportName: 'Policy Report'
])
}
}
}
Scripted Pipeline (Jenkins)
node {
stage('Checkout') {
checkout scm
}
stage('Setup') {
sh '''
wget https://github.com/open-policy-agent/opa/releases/download/v1.10.0/opa_linux_amd64
chmod +x opa_linux_amd64
sudo mv opa_linux_amd64 /usr/local/bin/opa
pip install jmo-security
'''
}
stage('Security Scan') {
try {
sh '''
jmo ci \
--repo . \
--policy zero-secrets \
--policy owasp-top-10 \
--fail-on-policy-violation \
--profile-name balanced
'''
} catch (Exception e) {
currentBuild.result = 'FAILURE'
error("Policy violations detected: ${e.message}")
}
}
stage('Archive Results') {
archiveArtifacts artifacts: 'results/summaries/*', fingerprint: true
}
}
Pre-Commit Hooks
Local Pre-Commit Hook
Create .git/hooks/pre-commit:
#!/bin/bash
echo "🔒 Running security policy check..."
# Run JMo scan with zero-secrets policy
jmo ci \
--repo . \
--policy zero-secrets \
--fail-on-policy-violation \
--profile-name fast
if [ $? -ne 0 ]; then
echo "❌ COMMIT BLOCKED: Security policy violations detected"
echo "📋 View report: results/summaries/POLICY_REPORT.md"
exit 1
fi
echo "✅ Security policy check passed"
exit 0
Make executable:
Pre-Commit Framework Integration
Add to .pre-commit-config.yaml:
repos:
- repo: local
hooks:
- id: jmo-security-scan
name: JMo Security Scan
entry: bash -c 'jmo ci --repo . --policy zero-secrets --fail-on-policy-violation --profile-name fast'
language: system
pass_filenames: false
always_run: true
Install hook:
Docker Compose
Policy Gating in Docker Compose
version: '3.8'
services:
jmo-security-scan:
image: jmo-security:latest
volumes:
- .:/scan
- ./results:/results
environment:
- JMO_POLICY_ENABLED=true
- JMO_POLICY_DEFAULT_POLICIES=zero-secrets,owasp-top-10
- JMO_POLICY_FAIL_ON_VIOLATION=true
command: |
bash -c "
jmo ci \
--repo /scan \
--policy zero-secrets \
--policy owasp-top-10 \
--fail-on-policy-violation \
--profile-name balanced
"
Run:
Kubernetes
Kubernetes Job for Policy Scanning
apiVersion: batch/v1
kind: Job
metadata:
name: jmo-security-scan
namespace: ci-cd
spec:
template:
metadata:
labels:
app: jmo-security
spec:
restartPolicy: Never
containers:
- name: scanner
image: jmo-security:latest
env:
- name: JMO_POLICY_ENABLED
value: "true"
- name: JMO_POLICY_DEFAULT_POLICIES
value: "zero-secrets,owasp-top-10,production-hardening"
- name: JMO_POLICY_FAIL_ON_VIOLATION
value: "true"
command:
- /bin/bash
- -c
- |
jmo ci \
--repo /scan \
--policy zero-secrets \
--policy owasp-top-10 \
--policy production-hardening \
--fail-on-policy-violation \
--profile-name balanced
volumeMounts:
- name: source-code
mountPath: /scan
- name: results
mountPath: /results
volumes:
- name: source-code
gitRepo:
repository: https://github.com/your-org/your-repo.git
revision: main
- name: results
persistentVolumeClaim:
claimName: jmo-results-pvc
Additional Resources
Support
- GitHub Issues: jmo-security-repo/issues
- Community Forum: GitHub Discussions