Deployment

CI/CD integration

pgroles integrates into CI/CD pipelines as a drift gate, a deployment step, or both.

For Cloud SQL or RDS connectivity setup (auth proxies, VPC access, IAM authentication), see the Google Cloud SQL or AWS RDS guides.


Drift detection

pgroles diff --exit-code returns specific exit codes for automation:

Exit codeMeaning
0Database is in sync with the manifest
2Drift detected — roles, grants, or memberships differ
OtherCommand or connectivity failure

GitHub Actions

These examples use the published Docker image, which requires no toolchain installation. Your runner needs network access to the database — see the platform guides linked above if you need to set up a proxy or VPN.

Drift check on PRs

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

      - name: Check for drift
        run: |
          docker run --rm \
            -e DATABASE_URL="${{ secrets.DATABASE_URL }}" \
            -v "${{ github.workspace }}:/work" \
            ghcr.io/hardbyte/pgroles:latest \
            diff -f /work/pgroles.yaml --exit-code

Apply on merge

jobs:
  apply-roles:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Apply roles
        run: |
          docker run --rm \
            -e DATABASE_URL="${{ secrets.DATABASE_URL }}" \
            -v "${{ github.workspace }}:/work" \
            ghcr.io/hardbyte/pgroles:latest \
            apply -f /work/pgroles.yaml

Diff as a PR comment

Post the planned SQL changes as a PR comment for review:

      - name: Generate diff
        id: diff
        run: |
          OUTPUT=$(docker run --rm \
            -e DATABASE_URL="${{ secrets.DATABASE_URL }}" \
            -v "${{ github.workspace }}:/work" \
            ghcr.io/hardbyte/pgroles:latest \
            diff -f /work/pgroles.yaml 2>&1) || true
          echo "diff<<EOF" >> "$GITHUB_OUTPUT"
          echo "$OUTPUT" >> "$GITHUB_OUTPUT"
          echo "EOF" >> "$GITHUB_OUTPUT"

      - name: Comment on PR
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const diff = `${{ steps.diff.outputs.diff }}`;
            if (diff.trim()) {
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                body: `### pgroles diff\n\`\`\`sql\n${diff}\n\`\`\``
              });
            }

Using cargo install

If you prefer installing from source instead of Docker, add a Rust toolchain step first:

      - uses: dtolnay/rust-toolchain@stable
      - run: cargo install pgroles-cli
      - run: pgroles diff -f pgroles.yaml --exit-code
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}

GitLab CI

The published Docker image is a static binary with no shell, so it can't be used directly as a GitLab CI image: (which requires /bin/sh to run script: blocks). Use a Rust image and install from source:

drift-check:
  image: rust:latest
  script:
    - cargo install pgroles-cli
    - pgroles diff -f pgroles.yaml --exit-code
  variables:
    DATABASE_URL: $DATABASE_URL

Output formats

pgroles diff supports multiple output formats:

# Raw SQL (default) — human-readable, good for PR comments
pgroles diff -f pgroles.yaml

# JSON — machine-readable, good for programmatic processing
pgroles diff -f pgroles.yaml --format json

# Summary — high-level change counts
pgroles diff -f pgroles.yaml --format summary

Multiple environments

Use the same manifest against different databases, or maintain separate manifests:

# Same manifest, different targets
pgroles apply -f pgroles.yaml --database-url "$STAGING_DATABASE_URL"
pgroles apply -f pgroles.yaml --database-url "$PROD_DATABASE_URL"
Previous
Memberships