GitHub Action Workflow Example
Complete CI/CD automation for automated evidence collection using GitHub Actions.
Use Case
Perfect for:
- Automated monthly/quarterly collections
- Multi-environment deployments (dev, staging, production)
- Scheduled compliance evidence gathering
- Integration with existing CI/CD pipelines
Coverage: Fully automated evidence collection with notifications and artifact storage
What This Automates
| Task | Automation |
|---|---|
| Evidence collection | Scheduled monthly runs |
| Credential management | GitHub Secrets integration |
| Bundle verification | Automated integrity checks |
| Artifact storage | GitHub Artifacts + optional S3/GCS |
| Notifications | Slack/email on success/failure |
| Multi-environment | Dev, staging, production workflows |
Result: Zero-touch compliance evidence collection
Prerequisites
1. GitHub Repository
- Repository with
evidence.yamlconfiguration - Admin access to configure secrets
- GitHub Actions enabled
2. Credentials
Required secrets:
GITHUB_TOKEN(automatically provided by GitHub Actions)EVIDENCE_SIGNING_KEY(private key contents)EVIDENCE_API_KEY(optional, for platform upload)
Optional secrets (multi-source):
AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYGOOGLE_APPLICATION_CREDENTIALS(JSON contents)
3. Configuration File
Repository structure:
your-repo/
├── .github/
│ └── workflows/
│ └── evidence-collection.yml
├── evidence.yaml
└── README.mdBasic Workflow - Monthly Collection
Workflow File
Create .github/workflows/evidence-collection.yml:
name: Evidence Collection
on:
# Run on first day of each month at 2 AM UTC
schedule:
- cron: '0 2 1 * *'
# Allow manual triggering
workflow_dispatch:
jobs:
collect:
name: Collect Evidence
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install evidence CLI
run: npm install -g @evidence-oss/cli
- name: Setup signing key
run: |
mkdir -p ~/.evidence/keys
echo '${{ secrets.EVIDENCE_SIGNING_KEY }}' > ~/.evidence/keys/private.pem
chmod 600 ~/.evidence/keys/private.pem
- name: Collect evidence
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: evidence collect
- name: Verify bundle
run: evidence verify evidence-bundles/evidence-bundle-*.tar.gz
- name: Upload bundle artifact
uses: actions/upload-artifact@v4
with:
name: evidence-bundle-${{ github.run_number }}
path: evidence-bundles/*.tar.gz
retention-days: 90Configuration
evidence.yaml:
framework: soc2_type1
controls:
- CC6.1
- CC6.6
- CC7.2
sources:
github:
mode: token
token_env: GITHUB_TOKEN
org: your-org
repos: '*'
bundle:
signing:
private_key_path: ~/.evidence/keys/private.pem
output_path: ./evidence-bundlesSetup Secrets
1. Generate signing key locally:
evidence init --generate-keys
cat ~/.evidence/keys/private.pem2. Add to GitHub Secrets:
- Go to repository → Settings → Secrets and variables → Actions
- Click "New repository secret"
- Name:
EVIDENCE_SIGNING_KEY - Value: Paste entire contents of
private.pem - Click "Add secret"
Expected Output
Successful run:
Run evidence collect
Validating configuration...
✓ Configuration valid (1 source)
✓ Signing key found
Validating credentials...
✓ GitHub token valid (scopes: repo, read:org)
Collecting from GitHub...
→ Fetching organization settings
→ Discovering repositories (23 found)
→ Fetching branch protection (23 repos)
→ Fetching CODEOWNERS (19 repos)
✓ GitHub: 45 artifacts collected
Creating bundle...
→ Generating manifest
→ Computing checksums (45 files)
→ Signing bundle
✓ Bundle created: evidence-bundle-20260110-020145.tar.gz
✓ Collection complete
Bundle ID: evidence-bundle-20260110-020145
Size: 18.3 KB
Artifacts: 45
Duration: 8.2 secondsCommon Workflow - Multi-Source with Upload
Workflow File
name: Evidence Collection (Production)
on:
schedule:
- cron: '0 2 1 * *' # Monthly
workflow_dispatch:
jobs:
collect:
name: Collect and Upload Evidence
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # For OIDC if using AWS assume role
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install evidence CLI
run: npm install -g @evidence-oss/cli
- name: Setup signing key
run: |
mkdir -p ~/.evidence/keys
echo '${{ secrets.EVIDENCE_SIGNING_KEY }}' > ~/.evidence/keys/private.pem
chmod 600 ~/.evidence/keys/private.pem
- name: Setup Google credentials
run: |
echo '${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}' > /tmp/google-sa.json
chmod 600 /tmp/google-sa.json
- name: Collect evidence
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-east-1
GOOGLE_APPLICATION_CREDENTIALS: /tmp/google-sa.json
run: evidence collect
- name: Verify bundle integrity
run: evidence verify evidence-bundles/evidence-bundle-*.tar.gz
- name: Upload to evidence platform
env:
EVIDENCE_API_KEY: ${{ secrets.EVIDENCE_API_KEY }}
run: evidence upload evidence-bundles/evidence-bundle-*.tar.gz
- name: Upload to GitHub Artifacts (backup)
uses: actions/upload-artifact@v4
with:
name: evidence-bundle-${{ github.run_number }}
path: evidence-bundles/*.tar.gz
retention-days: 180
- name: Cleanup credentials
if: always()
run: |
rm -f /tmp/google-sa.json
rm -f ~/.evidence/keys/private.pemConfiguration
evidence.yaml:
framework: soc2_type1
controls:
- CC6.1
- CC6.6
- CC7.2
sources:
github:
mode: token
token_env: GITHUB_TOKEN
org: acme
repos: '*'
branch: main
aws:
mode: env
region: us-east-1
cloudtrail:
trails:
- production-audit-trail
log_groups:
- /aws/lambda/production-*
google_workspace:
mode: service_account
credentials_env: GOOGLE_APPLICATION_CREDENTIALS
customer_id: C01234567
admin_email: evidence-admin@acme.com
domains:
- acme.com
bundle:
signing:
private_key_path: ~/.evidence/keys/private.pem
max_size_mb: 100
naming_pattern: '{org}-{framework}-{timestamp}'
upload:
enabled: true
retention_days: 730
tags:
environment: production
automation: github-actions
verify_before_upload: trueSetup All Secrets
Required secrets:
EVIDENCE_SIGNING_KEY # Private key contents
EVIDENCE_API_KEY # API key from evidence platform
AWS_ACCESS_KEY_ID # AWS access key
AWS_SECRET_ACCESS_KEY # AWS secret key
GOOGLE_APPLICATION_CREDENTIALS # Google service account JSONAdd each via: Repository → Settings → Secrets and variables → Actions → New repository secret
Advanced Workflow - Multi-Environment
Workflow File
name: Evidence Collection (All Environments)
on:
schedule:
# Development: Weekly on Monday 2 AM
- cron: '0 2 * * 1'
# Production: Monthly on 1st at 2 AM
- cron: '0 2 1 * *'
workflow_dispatch:
inputs:
environment:
description: 'Environment to collect from'
required: true
type: choice
options:
- development
- staging
- production
jobs:
determine-environment:
name: Determine Environment
runs-on: ubuntu-latest
outputs:
environment: ${{ steps.set-env.outputs.environment }}
steps:
- name: Set environment based on schedule or input
id: set-env
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
echo "environment=${{ inputs.environment }}" >> $GITHUB_OUTPUT
elif [ "$(date +%d)" == "01" ]; then
echo "environment=production" >> $GITHUB_OUTPUT
else
echo "environment=development" >> $GITHUB_OUTPUT
fi
collect:
name: Collect Evidence - ${{ needs.determine-environment.outputs.environment }}
runs-on: ubuntu-latest
needs: determine-environment
environment: ${{ needs.determine-environment.outputs.environment }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install evidence CLI
run: npm install -g @evidence-oss/cli
- name: Setup signing key
run: |
mkdir -p ~/.evidence/keys
echo '${{ secrets.EVIDENCE_SIGNING_KEY }}' > ~/.evidence/keys/private.pem
chmod 600 ~/.evidence/keys/private.pem
- name: Setup Google credentials
run: |
echo '${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}' > /tmp/google-sa.json
chmod 600 /tmp/google-sa.json
- name: Select configuration file
run: |
cp evidence.${{ needs.determine-environment.outputs.environment }}.yaml evidence.yaml
- name: Collect evidence
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ vars.AWS_REGION }}
GOOGLE_APPLICATION_CREDENTIALS: /tmp/google-sa.json
run: evidence collect
- name: Verify bundle
run: evidence verify evidence-bundles/evidence-bundle-*.tar.gz
- name: Upload to evidence platform
env:
EVIDENCE_API_KEY: ${{ secrets.EVIDENCE_API_KEY }}
run: evidence upload evidence-bundles/evidence-bundle-*.tar.gz
- name: Upload to S3 (long-term storage)
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
BUNDLE_FILE=$(ls evidence-bundles/evidence-bundle-*.tar.gz)
BUNDLE_NAME=$(basename $BUNDLE_FILE)
aws s3 cp $BUNDLE_FILE \
s3://acme-evidence-bundles/${{ needs.determine-environment.outputs.environment }}/$BUNDLE_NAME \
--region us-east-1
- name: Send Slack notification (success)
if: success()
uses: slackapi/slack-github-action@v1
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
payload: |
{
"text": "✅ Evidence collection succeeded",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Evidence Collection Succeeded*\n\n*Environment:* ${{ needs.determine-environment.outputs.environment }}\n*Workflow:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run>\n*Time:* $(date -u +%Y-%m-%dT%H:%M:%SZ)"
}
}
]
}
- name: Send Slack notification (failure)
if: failure()
uses: slackapi/slack-github-action@v1
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
payload: |
{
"text": "❌ Evidence collection failed",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Evidence Collection Failed*\n\n*Environment:* ${{ needs.determine-environment.outputs.environment }}\n*Workflow:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run>\n*Time:* $(date -u +%Y-%m-%dT%H:%M:%SZ)\n\n@channel Please investigate"
}
}
]
}
- name: Cleanup credentials
if: always()
run: |
rm -f /tmp/google-sa.json
rm -f ~/.evidence/keys/private.pemPer-Environment Configurations
evidence.development.yaml:
framework: soc2_type1
controls: [CC6.1]
sources:
github:
mode: token
token_env: GITHUB_TOKEN
org: acme
repos:
- acme/backend-dev
bundle:
signing:
private_key_path: ~/.evidence/keys/private.pem
naming_pattern: 'dev-{timestamp}'
upload:
enabled: true
retention_days: 90
tags:
environment: developmentevidence.staging.yaml:
framework: soc2_type1
controls: [CC6.1, CC6.6]
sources:
github:
mode: token
token_env: GITHUB_TOKEN
org: acme
repos:
- acme/backend-staging
aws:
mode: env
region: us-east-1
cloudtrail:
trails: [staging-audit-trail]
bundle:
signing:
private_key_path: ~/.evidence/keys/private.pem
naming_pattern: 'staging-{timestamp}'
upload:
enabled: true
retention_days: 180
tags:
environment: stagingevidence.production.yaml:
framework: soc2_type1
controls: [CC6.1, CC6.6, CC7.2]
sources:
github:
mode: token
token_env: GITHUB_TOKEN
org: acme
repos: '*'
aws:
mode: env
region: us-east-1
cloudtrail:
trails: [production-audit-trail]
log_groups: [/aws/lambda/production-*]
google_workspace:
mode: service_account
credentials_env: GOOGLE_APPLICATION_CREDENTIALS
customer_id: C01234567
admin_email: evidence-admin@acme.com
bundle:
signing:
private_key_path: ~/.evidence/keys/private.pem
max_size_mb: 100
naming_pattern: 'prod-{timestamp}'
upload:
enabled: true
retention_days: 730
tags:
environment: productionNotifications
Slack Integration
Setup:
- Create Slack webhook: Slack → Apps → Incoming Webhooks
- Add to GitHub Secrets:
SLACK_WEBHOOK_URL
Basic notification step:
- name: Notify Slack
if: always()
uses: slackapi/slack-github-action@v1
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
payload: |
{
"text": "${{ job.status == 'success' && '✅' || '❌' }} Evidence collection ${{ job.status }}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Evidence Collection ${{ job.status }}*\n\n*Repository:* ${{ github.repository }}\n*Run:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Details>"
}
}
]
}Email Notification
Using GitHub Actions email:
- name: Send email notification
if: failure()
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.EMAIL_USERNAME }}
password: ${{ secrets.EMAIL_PASSWORD }}
subject: Evidence Collection Failed - ${{ github.repository }}
to: security@acme.com
from: github-actions@acme.com
body: |
Evidence collection failed in ${{ github.repository }}.
Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
Please investigate immediately.Storage Options
GitHub Artifacts (Built-in)
- name: Upload bundle to GitHub Artifacts
uses: actions/upload-artifact@v4
with:
name: evidence-bundle-${{ github.run_number }}
path: evidence-bundles/*.tar.gz
retention-days: 90 # Max 90 days for free tier
compression-level: 9Retrieval:
# Via GitHub CLI
gh run download <run-id> -n evidence-bundle-<run-number>
# Via web UI
Repository → Actions → Workflow run → Artifacts sectionAWS S3 Storage
- name: Upload to S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
BUNDLE_FILE=$(ls evidence-bundles/evidence-bundle-*.tar.gz)
BUNDLE_NAME=$(basename $BUNDLE_FILE)
aws s3 cp $BUNDLE_FILE \
s3://acme-evidence-bundles/$(date +%Y)/$(date +%m)/$BUNDLE_NAME \
--region us-east-1 \
--storage-class STANDARD_IA \
--server-side-encryption AES256S3 bucket configuration:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:user/github-actions"
},
"Action": [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::acme-evidence-bundles/*"
}
]
}Google Cloud Storage
- name: Upload to GCS
run: |
echo '${{ secrets.GCP_SERVICE_ACCOUNT_KEY }}' > /tmp/gcp-key.json
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
BUNDLE_FILE=$(ls evidence-bundles/evidence-bundle-*.tar.gz)
BUNDLE_NAME=$(basename $BUNDLE_FILE)
gsutil cp $BUNDLE_FILE \
gs://acme-evidence-bundles/$(date +%Y)/$(date +%m)/$BUNDLE_NAME
rm -f /tmp/gcp-key.jsonError Handling
Retry on Failure
- name: Collect evidence (with retry)
uses: nick-invision/retry@v2
with:
timeout_minutes: 30
max_attempts: 3
retry_wait_seconds: 300
command: evidence collect
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Continue on Error (Non-Critical Steps)
- name: Upload to secondary storage
continue-on-error: true
run: |
# Upload to backup location
# Failure won't stop the workflowConditional Steps
- name: Verify bundle
id: verify
run: evidence verify evidence-bundles/evidence-bundle-*.tar.gz
- name: Upload only if verified
if: steps.verify.outcome == 'success'
run: evidence upload evidence-bundles/evidence-bundle-*.tar.gzSecurity Best Practices
1. Least Privilege Secrets
Create dedicated GitHub PAT:
- Scopes:
repo:read,read:orgonly - Expiration: 90 days
- Regular rotation schedule
Create dedicated AWS IAM user:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:GetAccountPasswordPolicy",
"cloudtrail:DescribeTrails",
"cloudtrail:GetTrailStatus"
],
"Resource": "*"
}
]
}2. Environment Isolation
Use GitHub Environments:
jobs:
collect:
environment: production
# Requires approval for production runsConfigure in repository: Settings → Environments → New environment → Add protection rules
3. Credential Cleanup
Always cleanup sensitive files:
- name: Cleanup credentials
if: always()
run: |
rm -f /tmp/google-sa.json
rm -f ~/.evidence/keys/private.pem
rm -f /tmp/gcp-key.json4. Audit Logging
Log all collection runs:
- name: Log collection metadata
run: |
cat > collection-log.json <<EOF
{
"workflow_run_id": "${{ github.run_id }}",
"workflow_run_number": "${{ github.run_number }}",
"triggered_by": "${{ github.actor }}",
"event": "${{ github.event_name }}",
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"repository": "${{ github.repository }}",
"ref": "${{ github.ref }}"
}
EOF
# Upload to audit log storage
aws s3 cp collection-log.json \
s3://acme-audit-logs/evidence-collections/$(date +%Y%m%d)-${{ github.run_number }}.jsonMonitoring
Check Last Successful Run
Add status badge to README:
[](https://github.com/acme/backend/actions/workflows/evidence-collection.yml)Create Monitoring Dashboard
GitHub CLI script:
#!/bin/bash
# check-evidence-status.sh
# Get last 10 workflow runs
gh run list --workflow=evidence-collection.yml --limit=10 --json status,conclusion,createdAt
# Check for recent failures
RECENT_FAILURES=$(gh run list --workflow=evidence-collection.yml --limit=5 --json conclusion --jq '[.[] | select(.conclusion=="failure")] | length')
if [ "$RECENT_FAILURES" -gt 2 ]; then
echo "WARNING: $RECENT_FAILURES failures in last 5 runs"
# Send alert
fiTroubleshooting
Workflow Fails at "Collect evidence"
Check logs:
- name: Collect evidence (with debug)
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DEBUG: evidence:*
run: evidence collect --verboseCommon issues:
- Missing environment variable
- Invalid GitHub token
- Rate limiting
- Network timeout
Bundle Verification Fails
Debug steps:
- name: Debug bundle contents
if: failure()
run: |
ls -lh evidence-bundles/
tar -tzf evidence-bundles/evidence-bundle-*.tar.gz
- name: Verify with verbose output
if: failure()
run: evidence verify evidence-bundles/evidence-bundle-*.tar.gz --verboseUpload Timeout
Increase timeout:
- name: Upload to evidence platform
timeout-minutes: 15 # Default is 6 hours, but set reasonable limit
env:
EVIDENCE_API_KEY: ${{ secrets.EVIDENCE_API_KEY }}
run: evidence upload evidence-bundles/evidence-bundle-*.tar.gzRate Limiting (GitHub API)
Solution: Workflow automatically pauses and retries
⚠ Rate limit approaching (98 remaining)
Pausing collection...
Rate limit resets at 2026-01-10T14:00:00Z (in 5 minutes)
Waiting...
✓ Rate limit reset
Resuming collection...Or schedule during off-hours:
on:
schedule:
- cron: '0 2 * * 1' # 2 AM UTC (low activity)Testing Workflows
Manual Trigger
Trigger via GitHub UI:
- Go to Actions tab
- Select "evidence Collection" workflow
- Click "Run workflow"
- Select branch
- Click "Run workflow"
Trigger via GitHub CLI:
gh workflow run evidence-collection.ymlTest with Dry Run
Add test job:
jobs:
test:
name: Test Configuration
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install evidence CLI
run: npm install -g @evidence-oss/cli
- name: Validate configuration
run: evidence collect --dry-run
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Complete Production Example
Repository structure:
acme-backend/
├── .github/
│ └── workflows/
│ ├── evidence-collection.yml
│ └── evidence-test.yml
├── evidence.yaml
├── evidence.development.yaml
├── evidence.staging.yaml
├── evidence.production.yaml
└── README.mdMain workflow (.github/workflows/evidence-collection.yml):
name: Evidence Collection (Production)
on:
schedule:
- cron: '0 2 1 * *' # Monthly on 1st
workflow_dispatch:
jobs:
collect:
name: Collect and Upload
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install evidence CLI
run: npm install -g @evidence-oss/cli
- name: Setup signing key
run: |
mkdir -p ~/.evidence/keys
echo '${{ secrets.EVIDENCE_SIGNING_KEY }}' > ~/.evidence/keys/private.pem
chmod 600 ~/.evidence/keys/private.pem
- name: Setup Google credentials
run: |
echo '${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}' > /tmp/google-sa.json
chmod 600 /tmp/google-sa.json
- name: Collect evidence
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
GOOGLE_APPLICATION_CREDENTIALS: /tmp/google-sa.json
run: evidence collect
- name: Verify bundle
run: evidence verify evidence-bundles/evidence-bundle-*.tar.gz
- name: Upload to evidence platform
env:
EVIDENCE_API_KEY: ${{ secrets.EVIDENCE_API_KEY }}
run: evidence upload evidence-bundles/evidence-bundle-*.tar.gz
- name: Backup to S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
BUNDLE_FILE=$(ls evidence-bundles/evidence-bundle-*.tar.gz)
aws s3 cp $BUNDLE_FILE s3://acme-evidence-bundles/production/ --region us-east-1
- name: Upload to GitHub Artifacts
uses: actions/upload-artifact@v4
with:
name: evidence-bundle-${{ github.run_number }}
path: evidence-bundles/*.tar.gz
retention-days: 90
- name: Notify Slack (success)
if: success()
uses: slackapi/slack-github-action@v1
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
payload: |
{
"text": "✅ Evidence collection succeeded",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Evidence Collection Succeeded*\n\n*Environment:* production\n*Run:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Details>"
}
}
]
}
- name: Notify Slack (failure)
if: failure()
uses: slackapi/slack-github-action@v1
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
payload: |
{
"text": "❌ Evidence collection failed - @channel",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Evidence Collection Failed*\n\n*Environment:* production\n*Run:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Details>\n\nPlease investigate immediately."
}
}
]
}
- name: Cleanup
if: always()
run: |
rm -f /tmp/google-sa.json
rm -f ~/.evidence/keys/private.pemSee Also
- Minimal GitHub Example - Simple starting point
- Multi-Source Example - Production multi-source setup
- Configuration Reference - All configuration options
- Credential Management - Security best practices
- Troubleshooting - Common issues and solutions