GitHub Actions Workflow for Redaction Validation

A GitHub Actions workflow turns the redaction regression suite into a required merge gate: it installs dependencies, runs the golden-corpus tests on every pull request, and blocks merge when any case fails, so an under-redacting rule change cannot reach the default branch. This how-to, part of CI/CD Redaction Validation, wires the pipeline and a pre-commit backstop.

Prerequisites and version matrix Permalink to this section

Component Version Role
GitHub Actions runner ubuntu-24.04 Hosted CI environment
actions/checkout v4 Fetch repo and private corpus submodule
actions/setup-python v5 Provision Python 3.11 with pip cache
pre-commit 3.7.x Local hook framework
pytest / pytest-xdist 8.2.x / 3.6.x Regression runner

You also need branch protection permissions on the repository and a private location for the golden corpus (see gotchas).

Step 1 — The workflow Permalink to this section

Save this as .github/workflows/redaction-validation.yml. It triggers on pull requests, caches pip, checks out the corpus submodule, and runs the suite:

name: Redaction Validation

on:
  pull_request:
    branches: [main]

jobs:
  regression:
    runs-on: ubuntu-24.04
    steps:
      - name: Check out code and private corpus submodule
        uses: actions/checkout@v4
        with:
          submodules: true            # golden corpus lives in a private submodule
          token: ${{ secrets.CORPUS_PAT }}

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
          cache: pip

      - name: Install dependencies
        run: pip install -r requirements-test.txt

      - name: Run golden-corpus regression suite
        run: pytest -n auto -q --maxfail=1

--maxfail=1 stops on the first divergence so a broken rule surfaces fast; the job’s non-zero exit is what the branch-protection gate reads as a failed check.

Step 2 — The pre-commit backstop Permalink to this section

Catch obvious regressions before they ever reach CI. Add .pre-commit-config.yaml:

repos:
  - repo: local
    hooks:
      - id: redaction-smoke
        name: redaction smoke regression
        entry: pytest -q -k smoke --maxfail=1
        language: system
        pass_filenames: false
        stages: [pre-commit]

Install it once per clone with pre-commit install. Keep the hook to a fast smoke subset — the full corpus belongs in CI, not in every local commit.

Step 3 — Make the check required Permalink to this section

A workflow that can be bypassed is not a gate. In the repository, open Settings → Branches → add a rule for main, enable “Require status checks to pass before merging”, and select the regression job. Merges are then blocked until the check reports success.

Compliance checkpoint Permalink to this section

A required, non-bypassable CI check implements NIST SP 800-53 Rev. 5 control CM-3 (Configuration Change Management), which requires that changes to a system be tested, validated, and approved before deployment. Branch protection supplies the approval-and-validation gate; the immutable Actions run log supplies the auditable record that each merged change passed redaction validation. Combined with pull-request review, this satisfies CM-3’s separation of change proposal from change authorization.

Gotchas Permalink to this section

  • Never commit the corpus or secrets to the repo. Golden fixtures may resemble real documents and must stay out of the public history. Keep them in a private submodule pulled with a scoped CORPUS_PAT, or download an encrypted artifact at job start and decrypt with an Actions secret. Fixtures and tokens in git history are effectively permanent.
  • Cache correctly. cache: pip keyed on requirements-test.txt speeds installs, but never cache the corpus checkout or decrypted fixtures — a stale or leaked cache undermines both correctness and confidentiality.
  • Required-check naming. Branch protection matches the check by job name (regression). Renaming the job silently disables the requirement until you re-select it, so treat workflow renames as a protected-branch change.
  • Fork pull requests. PRs from forks do not receive repository secrets, so the corpus checkout fails. Gate external contributions through pull_request_target with a manual approval step, or restrict the validation workflow to same-repo branches.

Verification Permalink to this section

Confirm the check is actually required on the branch using the GitHub CLI rather than trusting the UI:

gh api repos/:owner/:repo/branches/main/protection/required_status_checks \
  --jq '.checks[].context'

The output must list regression:

regression

Then open a pull request with a deliberately loosened rule; the merge button stays disabled and the failed regression check is shown as blocking, confirming the gate holds end to end.

This workflow enforces the Batch Redaction Regression Tests with pytest harness and the Deterministic Diff Assertions for Redacted PDFs it relies on. For the production execution side of the pipeline, see Async Batch Processing Pipelines. Part of the CI/CD Redaction Validation guide.