GitHub Actions Integration¶
Automate compliance scanning with GitHub Actions.
Composite Action (Recommended)¶
PipelineConductor provides a composite action for easy integration:
name: Compliance Check
on:
push:
branches: [main]
paths:
- '.github/workflows/**'
pull_request:
branches: [main]
paths:
- '.github/workflows/**'
workflow_dispatch:
permissions:
contents: read
jobs:
compliance:
name: Check Workflow Compliance
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Check Compliance
id: compliance
uses: grokify/pipelineconductor@main
with:
ref-repo: 'myorg/.github'
ref-branch: 'main'
languages: 'Go'
strict: 'false'
fail-on-non-compliant: 'false'
- name: Report Results
run: |
echo "Compliance Level: ${{ steps.compliance.outputs.compliance-level }}"
echo "Compliance Rate: ${{ steps.compliance.outputs.compliance-rate }}%"
Action Inputs¶
| Input | Description | Default |
|---|---|---|
ref-repo |
Reference workflow repository (owner/repo) | grokify/.github |
ref-branch |
Branch in reference repo | main |
languages |
Languages to check (comma-separated) | Go |
strict |
Require exact reusable workflow usage | false |
fail-on-non-compliant |
Fail if any workflows are missing | false |
Action Outputs¶
| Output | Description |
|---|---|
compliance-level |
Overall compliance level (full, partial, none) |
compliance-rate |
Compliance rate percentage |
missing-workflows |
JSON array of missing workflows |
Create Issue for Non-Compliance¶
- name: Create Issue for Non-Compliance
if: steps.compliance.outputs.compliance-level != 'full'
uses: actions/github-script@v7
with:
script: |
const missing = JSON.parse('${{ steps.compliance.outputs.missing-workflows }}');
if (missing.length === 0) return;
const body = `## Workflow Compliance Issue
This repository has non-compliant workflows.
**Compliance Level:** ${{ steps.compliance.outputs.compliance-level }}
**Compliance Rate:** ${{ steps.compliance.outputs.compliance-rate }}%
### Missing Workflows
${missing.map(m => `- **${m.workflowType}** (${m.severity}): ${m.description}`).join('\n')}
### How to Fix
Run the following command to generate compliant workflows:
\`\`\`bash
pipelineconductor remediate --local . --orgs ${context.repo.owner} --languages Go
\`\`\`
`;
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'Workflow Compliance: Non-compliant workflows detected',
body: body,
labels: ['workflow-compliance', 'automation']
});
Basic Workflow (Manual Setup)¶
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/plexusone/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/plexusone/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/plexusone/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/plexusone/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/plexusone/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/plexusone/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