Examples

Use the Examples section in the sidebar to open focused workflows.

Examples are split into small pages for digestibility:

  • CI Gate (Review + Policy): review across a git range, producing decision.json and gating CI.
  • Block JOIN changes by table pair: scope JoinConditionChanged to a specific join.
  • Critical filter heuristic: block dangerous WHERE changes scoped to a table + column.
  • LEFT JOIN nullability risk: block join type changes to LEFT.
  • DISTINCT removal exception: block DistinctRemoved unless an exception grant exists.

If you want a quick overview of what each command does, start at Quick Start.

CI Gate (Review + Policy)

This is the “PR workflow” most teams want:

  1. Compute semantic diff between base and head.
  2. Run static analysis on HEAD.
  3. Evaluate a policy bundle (allow/warn/block).
  4. Write a machine-readable decision artifact for CI gating.

Commit these files

Lexega supports JSON schemas for IDE validation (YAML plugins in most editors). A common convention is to keep these in a .lexega/ directory:

.lexega/
  policy.yaml
  exceptions.yaml        # optional
  custom_rules.yaml      # optional

You can see real examples used by the test suite under:

  • lexega-sql/tests/fixtures/ci_test/test_policy.yaml
  • lexega-sql/tests/fixtures/ci_test/exceptions.yaml

GitHub Actions example

This is adapted from the repo’s end-to-end CI workflow test script (lexega-sql/tests/test_ci_workflow.sh).

name: SQL Review (Lexega)
on:
  pull_request:
    paths:
      - 'models/**/*.sql'
      - 'macros/**/*.sql'

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # required for git-range diff

      # Install lexega-sql here (package, binary, or build-from-source)
      # The key is that `lexega-sql` is available on PATH.

      - name: Run Lexega review (diff + analysis + policy)
        run: |
          set -euo pipefail

          BASE_SHA='${{ github.event.pull_request.base.sha }}'
          HEAD_SHA='${{ github.sha }}'
          RANGE="$BASE_SHA..$HEAD_SHA"

          # Run review and write artifacts
          lexega-sql review "$RANGE" models/ -r \
            --policy .lexega/policy.yaml \
            --env ${{ github.base_ref == 'main' && 'prod' || 'staging' }} \
            --decision-out decision.json \
            --report-out artifacts/ \
            --format markdown > review.md

      - name: Gate on decision
        run: |
          set -euo pipefail

          ALLOWED=$(jq -r '.outcome.allowed' decision.json)
          if [ "$ALLOWED" != "true" ]; then
            REASON=$(jq -r '.outcome.blocked_reason // "(no reason)"' decision.json)
            echo "::error::Lexega blocked this change: $REASON"
            exit 1
          fi

      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: lexega
          path: |
            decision.json
            review.md
            artifacts/

What the decision artifact contains

decision.json is the stable machine interface for CI.

At minimum, CI typically checks:

  • outcome.allowed (boolean)
  • outcome.blocked_reason (string | null)

The full schema is here:

2) Policy authoring + linting

Before enabling a policy gate, validate the policy bundle:

lexega-sql policy-lint .lexega/policy.yaml

3) Custom Rules (Team-specific checks)

Custom rules are validated by schema:

Custom diff rules (semantic changes)

Custom diff rules attach via diff_triggers (they match semantic changes between base and head).

Example (based on the CI fixture rules, updated to match the schema):

# yaml-language-server: $schema=/schemas/v1/custom_rules.schema.json
metadata:
  name: Team Rules
  version: 1.0.0

rules:
  - id: CUSTOM-001
    name: Critical Table Modified
    risk_level: High
    message: "Critical table was modified"
    diff_triggers:
      - change_type: TableAdded
        match:
          tables:
            any_of:
              - '*_sensitive*'
              - '*_pii*'
              - 'raw.*'
      - change_type: TableRemoved
        match:
          tables:
            any_of:
              - '*_sensitive*'
              - '*_pii*'

Then load them in CI:

lexega-sql review main..HEAD models/ -r \
  --custom-rules .lexega/custom_rules.yaml \
  --policy .lexega/policy.yaml \
  --env staging \
  --decision-out decision.json

4) dbt/Jinja projects

If your models use dbt macros/Jinja, enable macro loading:

lexega-sql review main..HEAD models/ -r \
  --dbt-project . \
  --load-macros \
  --policy .lexega/policy.yaml \
  --env staging \
  --decision-out decision.json

Schemas (IDE Validation)

Need Help?

Can't find what you're looking for? Check out our GitHub or reach out to support.