GitHub Actions Integration¶
Automate compliance scanning with GitHub Actions.
Basic Workflow¶
Create .github/workflows/compliance.yml:
name: Compliance Scan
on:
schedule:
- cron: '0 6 * * *' # Daily at 6 AM UTC
workflow_dispatch: # Manual trigger
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25'
- name: Install PipelineConductor
run: go install github.com/grokify/pipelineconductor/cmd/pipelineconductor@latest
- name: Run compliance scan
env:
GITHUB_TOKEN: ${{ secrets.SCAN_TOKEN }}
run: |
pipelineconductor scan \
--orgs ${{ github.repository_owner }} \
--format markdown \
--output report.md
- name: Upload report
uses: actions/upload-artifact@v4
with:
name: compliance-report
path: report.md
Token Setup¶
Create a Personal Access Token¶
- Go to GitHub Settings > Developer settings > Personal access tokens
- Create a new token (classic) with scopes:
repo- Access repositoriesread:org- Read organization membership- Copy the token
Add as Repository Secret¶
- Go to repository Settings > Secrets and variables > Actions
- Click New repository secret
- Name:
SCAN_TOKEN - Value: Your personal access token
Workflow Examples¶
SARIF Upload to Security Tab¶
name: Compliance Scan with SARIF
on:
schedule:
- cron: '0 6 * * *'
workflow_dispatch:
jobs:
scan:
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25'
- name: Install PipelineConductor
run: go install github.com/grokify/pipelineconductor/cmd/pipelineconductor@latest
- name: Run scan
env:
GITHUB_TOKEN: ${{ secrets.SCAN_TOKEN }}
run: |
pipelineconductor scan \
--orgs ${{ github.repository_owner }} \
--format sarif \
--output results.sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
category: compliance
Multiple Output Formats¶
name: Compliance Reports
on:
schedule:
- cron: '0 6 * * 1' # Weekly on Monday
workflow_dispatch:
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25'
- name: Install PipelineConductor
run: go install github.com/grokify/pipelineconductor/cmd/pipelineconductor@latest
- name: Run scans
env:
GITHUB_TOKEN: ${{ secrets.SCAN_TOKEN }}
run: |
# JSON for archival
pipelineconductor scan --orgs myorg --format json --output report.json
# Markdown for review
pipelineconductor scan --orgs myorg --format markdown --output report.md
# CSV for spreadsheets
pipelineconductor scan --orgs myorg --format csv --output report.csv
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: compliance-reports
path: |
report.json
report.md
report.csv
Slack Notification¶
name: Compliance Scan with Slack
on:
schedule:
- cron: '0 6 * * *'
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25'
- name: Install PipelineConductor
run: go install github.com/grokify/pipelineconductor/cmd/pipelineconductor@latest
- name: Run scan
id: scan
env:
GITHUB_TOKEN: ${{ secrets.SCAN_TOKEN }}
run: |
pipelineconductor scan \
--orgs myorg \
--format json \
--output report.json
# Extract summary
TOTAL=$(jq '.summary.total' report.json)
COMPLIANT=$(jq '.summary.compliant' report.json)
RATE=$(jq '.summary.complianceRate' report.json)
echo "total=$TOTAL" >> $GITHUB_OUTPUT
echo "compliant=$COMPLIANT" >> $GITHUB_OUTPUT
echo "rate=$RATE" >> $GITHUB_OUTPUT
- name: Send Slack notification
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Compliance Report",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Daily Compliance Report*\n• Total: ${{ steps.scan.outputs.total }}\n• Compliant: ${{ steps.scan.outputs.compliant }}\n• Rate: ${{ steps.scan.outputs.rate }}%"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Fail on Non-Compliance¶
name: Compliance Gate
on:
pull_request:
branches: [main]
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25'
- name: Install PipelineConductor
run: go install github.com/grokify/pipelineconductor/cmd/pipelineconductor@latest
- name: Run scan
env:
GITHUB_TOKEN: ${{ secrets.SCAN_TOKEN }}
run: |
pipelineconductor scan \
--orgs ${{ github.repository_owner }} \
--format json \
--output report.json
- name: Check compliance
run: |
COMPLIANT=$(jq '.summary.compliant' report.json)
TOTAL=$(jq '.summary.total' report.json)
if [ "$COMPLIANT" -ne "$TOTAL" ]; then
echo "::error::Not all repositories are compliant"
jq '.repos[] | select(.compliant == false) | .repo.fullName' report.json
exit 1
fi
echo "All repositories are compliant"
Caching¶
Speed up workflows by caching Go modules:
steps:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25'
cache: true
- name: Install PipelineConductor
run: go install github.com/grokify/pipelineconductor/cmd/pipelineconductor@latest
Scheduled Scans¶
Common cron schedules:
| Schedule | Cron | Description |
|---|---|---|
| Daily | 0 6 * * * |
6 AM UTC daily |
| Weekly | 0 6 * * 1 |
Monday at 6 AM |
| Monthly | 0 6 1 * * |
1st of month at 6 AM |
Troubleshooting¶
Token Permission Errors¶
Ensure your token has:
reposcope for private reposread:orgfor organization access
Rate Limiting¶
PipelineConductor includes built-in rate limit handling with:
- Automatic retry on 429 (Too Many Requests) and 403 (rate limit exceeded)
- Exponential backoff with jitter
- Respect for GitHub's
X-RateLimit-*andRetry-Afterheaders - Up to 5 retry attempts by default
For very large scans across many organizations, you can still add delays between orgs if needed:
- name: Scan with delay
run: |
for org in org1 org2 org3; do
pipelineconductor scan --orgs $org --output "${org}.json"
sleep 60 # Wait between orgs
done
Verbose Output¶
Add -v for debugging:
See Also¶
- SARIF Integration - Security tab setup
- Configuration - Config file options