Documentation

GitHub Action Integration

Automate evidence collection in CI/CD pipelines with the evidence GitHub Action.

Quick Start

Add evidence collection to any GitHub repository:

# .github/workflows/evidence.yml
name: evidence collection

on:
  schedule:
    - cron: '0 0 1 * *'  # Monthly on the 1st
  workflow_dispatch:       # Manual trigger

jobs:
  collect:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: evidence-sdk/action@v1
        with:
          command: collect
          upload: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          EVIDENCE_SIGNING_KEY: ${{ secrets.EVIDENCE_SIGNING_KEY }}
          EVIDENCE_API_KEY: ${{ secrets.EVIDENCE_API_KEY }}

What this does:

  • Runs monthly (1st of each month at midnight UTC)
  • Can also be triggered manually via GitHub UI
  • Collects evidence using configuration in repository
  • Automatically uploads bundle to evidence platform
  • Uses GitHub-provided GITHUB_TOKEN for authentication

Installation

Step 1: Add Configuration File

Create evidence.yaml in your repository root:

framework: soc2_type1

controls:
  - CC6.1
  - CC6.6
  - CC7.2

sources:
  github:
    mode: token
    token_env: GITHUB_TOKEN
    org: your-org
    repos:
      - your-org/backend
      - your-org/frontend

bundle:
  signing:
    private_key_env: EVIDENCE_SIGNING_KEY

Step 2: Generate Signing Key

Generate an Ed25519 signing key locally:

# Install evidence CLI
npm install -g @evidence-oss/cli

# Generate key pair
evidence init --generate-keys

# Copy private key (base64-encoded for GitHub Secrets)
cat ~/.evidence/keys/private.pem | base64

Step 3: Add Repository Secrets

Go to Repository Settings → Secrets and variables → Actions:

Add these secrets:

Secret NameValueSource
EVIDENCE_SIGNING_KEYBase64-encoded private keyOutput from Step 2
EVIDENCE_API_KEYAPI key for evidence platformevidence platform dashboard

Note: GITHUB_TOKEN is provided automatically by GitHub Actions. No need to add it.

Step 4: Create Workflow File

Create .github/workflows/evidence.yml:

name: evidence collection

on:
  schedule:
    - cron: '0 0 1 * *'  # Monthly
  workflow_dispatch:

jobs:
  collect:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: evidence-sdk/action@v1
        with:
          command: collect
          upload: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          EVIDENCE_SIGNING_KEY: ${{ secrets.EVIDENCE_SIGNING_KEY }}
          EVIDENCE_API_KEY: ${{ secrets.EVIDENCE_API_KEY }}

Step 5: Test Workflow

Trigger manually to test:

  1. Go to repository → Actions tab
  2. Select "evidence collection" workflow
  3. Click "Run workflow" → "Run workflow"
  4. Monitor execution in Actions tab

Expected output:

✓ Configuration valid
✓ GitHub connection successful
✓ Collecting evidence...
✓ Bundle created
✓ Bundle verified
✓ Uploaded to evidence platform

Trigger Patterns

Scheduled Collection

Monthly (SOC 2 Type I):

on:
  schedule:
    - cron: '0 0 1 * *'  # 1st of month, midnight UTC

Weekly (Frequent monitoring):

on:
  schedule:
    - cron: '0 0 * * 1'  # Every Monday, midnight UTC

Daily (Dev/testing):

on:
  schedule:
    - cron: '0 0 * * *'  # Every day, midnight UTC

Custom schedule:

on:
  schedule:
    # Every 1st and 15th at 3:00 AM UTC
    - cron: '0 3 1,15 * *'

Manual Triggers

on:
  workflow_dispatch:  # Enables "Run workflow" button in Actions tab

With inputs:

on:
  workflow_dispatch:
    inputs:
      upload:
        description: 'Upload bundle to platform'
        required: false
        default: 'true'
        type: boolean

jobs:
  collect:
    steps:
      - uses: evidence-sdk/action@v1
        with:
          upload: ${{ inputs.upload }}

Event-Triggered Collection

On release:

on:
  release:
    types: [published]

On push to main:

on:
  push:
    branches: [main]

On PR merge:

on:
  pull_request:
    types: [closed]
    branches: [main]

Action Inputs

Complete reference for evidence-sdk/action@v1:

InputTypeRequiredDefaultDescription
commandstringYes-Command to run: collect, verify, upload
config-pathstringNo./evidence.yamlPath to configuration file
output-pathstringNo./evidence-bundlesOutput directory for bundles
bundle-pathstringNo-Path to bundle (for verify/upload)
uploadbooleanNofalseAuto-upload after collect
cli-versionstringNolatestevidence CLI version to use

Examples

Collect only (no upload):

- uses: evidence-sdk/action@v1
  with:
    command: collect
    upload: false

Custom config path:

- uses: evidence-sdk/action@v1
  with:
    command: collect
    config-path: ./config/evidence.production.yaml

Specific CLI version:

- uses: evidence-sdk/action@v1
  with:
    command: collect
    cli-version: '0.1.0'

Action Outputs

Outputs available via steps.<step-id>.outputs:

OutputTypeDescription
bundle-pathstringPath to created bundle
bundle-idstringBundle ID from manifest
upload-urlstringURL of uploaded bundle (if upload: true)
verifiedbooleanBundle verification status

Example Usage

jobs:
  collect:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - id: collect-evidence
        uses: evidence-sdk/action@v1
        with:
          command: collect
          upload: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          EVIDENCE_SIGNING_KEY: ${{ secrets.EVIDENCE_SIGNING_KEY }}

      - name: Print bundle info
        run: |
          echo "Bundle created: ${{ steps.collect-evidence.outputs.bundle-path }}"
          echo "Bundle ID: ${{ steps.collect-evidence.outputs.bundle-id }}"
          echo "Upload URL: ${{ steps.collect-evidence.outputs.upload-url }}"

Multi-Source Configuration

Collect from multiple sources (GitHub, AWS, Google Workspace):

name: evidence collection (multi-source)

on:
  schedule:
    - cron: '0 0 1 * *'

jobs:
  collect:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: evidence-sdk/action@v1
        with:
          command: collect
          upload: true
        env:
          # GitHub
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

          # AWS
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: us-east-1

          # Google Workspace
          GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}

          # evidence Platform
          EVIDENCE_SIGNING_KEY: ${{ secrets.EVIDENCE_SIGNING_KEY }}
          EVIDENCE_API_KEY: ${{ secrets.EVIDENCE_API_KEY }}

Configuration file:

# evidence.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
    log_groups: '*'

  google_workspace:
    mode: service_account
    credentials_env: GOOGLE_APPLICATION_CREDENTIALS
    customer_id: C0xxxxxxx
    admin_email: admin@acme.com

bundle:
  signing:
    private_key_env: EVIDENCE_SIGNING_KEY

Advanced Workflows

Collect → Verify → Upload

Separate steps for more control:

jobs:
  collect-and-verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # Step 1: Collect
      - id: collect
        uses: evidence-sdk/action@v1
        with:
          command: collect
          upload: false  # Don't upload yet
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          EVIDENCE_SIGNING_KEY: ${{ secrets.EVIDENCE_SIGNING_KEY }}

      # Step 2: Verify
      - uses: evidence-sdk/action@v1
        with:
          command: verify
          bundle-path: ${{ steps.collect.outputs.bundle-path }}

      # Step 3: Upload (only if verified)
      - uses: evidence-sdk/action@v1
        with:
          command: upload
          bundle-path: ${{ steps.collect.outputs.bundle-path }}
        env:
          EVIDENCE_API_KEY: ${{ secrets.EVIDENCE_API_KEY }}

Store Bundle as Artifact

Save bundle for manual review:

jobs:
  collect:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - id: collect
        uses: evidence-sdk/action@v1
        with:
          command: collect
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          EVIDENCE_SIGNING_KEY: ${{ secrets.EVIDENCE_SIGNING_KEY }}

      # Upload as GitHub Actions artifact
      - uses: actions/upload-artifact@v4
        with:
          name: evidence-bundle
          path: ${{ steps.collect.outputs.bundle-path }}
          retention-days: 90

Download later:

  1. Go to workflow run → Artifacts
  2. Download evidence-bundle
  3. Extract and inspect locally

Notify on Failure

Send notifications if collection fails:

jobs:
  collect:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: evidence-sdk/action@v1
        id: collect-evidence
        with:
          command: collect
          upload: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          EVIDENCE_SIGNING_KEY: ${{ secrets.EVIDENCE_SIGNING_KEY }}

      # Notify on failure
      - name: Notify Slack on failure
        if: failure()
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "evidence collection failed for ${{ github.repository }}",
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "evidence collection failed\n*Repository:* ${{ github.repository }}\n*Workflow:* ${{ github.workflow }}\n*Run:* ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
                  }
                }
              ]
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

Matrix Strategy (Multiple Orgs)

Collect evidence for multiple organizations in parallel:

jobs:
  collect:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        org:
          - name: acme-corp
            config: evidence.acme.yaml
          - name: acme-labs
            config: evidence.labs.yaml

    steps:
      - uses: actions/checkout@v4

      - uses: evidence-sdk/action@v1
        with:
          command: collect
          config-path: ${{ matrix.org.config }}
          upload: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          EVIDENCE_SIGNING_KEY: ${{ secrets[format('{0}_SIGNING_KEY', matrix.org.name)] }}
          EVIDENCE_API_KEY: ${{ secrets.EVIDENCE_API_KEY }}

Security Best Practices

1. Use Repository Secrets

Never hardcode credentials:

# ❌ BAD
env:
  GITHUB_TOKEN: ghp_hardcoded_token

# ✅ GOOD
env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

2. Limit Workflow Permissions

Restrict what workflows can do:

permissions:
  contents: read  # Read-only access to repository
  actions: read   # Read workflow files

3. Pin Action Versions

Use specific versions, not @main:

# ❌ BAD - uses latest, could break
- uses: evidence-sdk/action@main

# ✅ GOOD - pinned version
- uses: evidence-sdk/action@v1.0.0

# ✅ ACCEPTABLE - major version
- uses: evidence-sdk/action@v1

4. Separate Keys Per Environment

# Production workflow
env:
  EVIDENCE_SIGNING_KEY: ${{ secrets.PROD_SIGNING_KEY }}

# Staging workflow
env:
  EVIDENCE_SIGNING_KEY: ${{ secrets.STAGING_SIGNING_KEY }}

5. Use Environment Protection Rules

Set up environment-specific secrets:

  1. Go to Repository Settings → Environments
  2. Create production environment
  3. Add protection rules (required reviewers, wait timer)
  4. Add environment-specific secrets
jobs:
  collect:
    runs-on: ubuntu-latest
    environment: production  # Requires approval

    steps:
      - uses: evidence-sdk/action@v1
        env:
          EVIDENCE_API_KEY: ${{ secrets.EVIDENCE_API_KEY }}

Troubleshooting

Collection Fails with "Invalid Token"

Symptom:

✗ GitHub connection failed: Bad credentials

Causes:

  • GITHUB_TOKEN secret not set
  • Token expired or revoked
  • Insufficient token permissions

Solution:

  1. Verify secret exists: Repository Settings → Secrets
  2. Check GitHub Actions can access secret
  3. Verify token has required scopes (repo:read, read:org)

Bundle Verification Fails

Symptom:

✗ Signature verification failed

Causes:

  • EVIDENCE_SIGNING_KEY malformed (not base64)
  • Different key used for signing vs. verification
  • Key rotation without updating secret

Solution:

  1. Regenerate key: evidence init --generate-keys
  2. Base64 encode: cat private.pem | base64
  3. Update secret in repository settings
  4. Verify: Re-run workflow

Workflow Not Triggering on Schedule

Symptom: Workflow doesn't run at scheduled time

Causes:

  • Repository inactive (GitHub disables scheduled workflows after 60 days)
  • Workflow file syntax error
  • Schedule timezone (UTC only)

Solution:

  1. Check workflow syntax: Actions tab → workflow → "View workflow file"
  2. Test manually: "Run workflow" button
  3. Verify cron syntax: Use crontab.guru
  4. Re-enable scheduled workflows if repository was inactive

Next Steps

Complete Examples See full workflow examples for different scenarios.

Examples →

Configure Multi-Source Collection Add AWS and Google Workspace to your evidence collection.

Configuration Guide →

Monitor Compliance Over Time View continuous compliance timeline in evidence platform.

evidence Platform →