Examples: Block JOIN Condition Changes for Specific Table Pairs
Goal: block JOIN condition changes, but only for a specific table pair that you consider high-risk.
This uses a custom rule to detect the change, and a policy to block it in specific environments.
Files to commit
.lexega/
custom_rules.yaml # defines detection logic
policy.yaml # references rule IDs for enforcement
exceptions.yaml # optional
1) Custom Rule: detect JOIN changes on specific tables
First, define a custom rule that fires when JOIN conditions change for your critical tables:
# .lexega/custom_rules.yaml
# yaml-language-server: $schema=/schemas/v1/custom_rules.schema.json
metadata:
name: Team Rules
version: 1.0.0
rules:
- id: JOIN-PAIR-ORDERS-CUSTOMERS
name: Critical JOIN pair changed
risk_level: High
message: "JOIN condition changed for critical table pair (ORDERS ↔ CUSTOMERS)"
diff_triggers:
- change_type: JoinConditionChanged
match:
tables:
any_of:
- 'ANALYTICS.ORDERS'
- 'ANALYTICS.CUSTOMERS'
How matching works:
change_type: JoinConditionChanged— only fires on JOIN predicate changestables.any_of— matches if ANY of these tables appear in the join- To require BOTH tables, use
tables.all_ofinstead
2) Policy: block that rule in prod
The policy references the rule ID — it doesn't define detection logic:
# .lexega/policy.yaml
# yaml-language-server: $schema=/schemas/v1/policy.schema.json
schema_version: 1
policy_id: team-policy
policy_version: 1.0.0
default_action: allow
policies:
- rule_id: JOIN-PAIR-ORDERS-CUSTOMERS
description: Block JOIN condition changes for high-risk table pair
envs: [prod]
action: block
requires_exception: true
3) Run review with policy (CI gate)
lexega-sql review main..HEAD models/ -r \
--custom-rules .lexega/custom_rules.yaml \
--policy .lexega/policy.yaml \
--env prod \
--decision-out decision.json \
--format markdown > review.md
Gate on the decision artifact:
ALLOWED=$(jq -r '.outcome.allowed' decision.json)
test "$ALLOWED" = "true"
4) Exception (optional)
If you need to permit a one-off change:
# .lexega/exceptions.yaml
# yaml-language-server: $schema=/schemas/v1/exceptions.schema.json
schema_version: 1
exceptions:
- exception_id: EX-2025-001
policy_id: team-policy
rule_id: JOIN-PAIR-ORDERS-CUSTOMERS
approved_by: data-governance@company.com
approved_at: "2025-12-31T00:00:00Z"
reason: "Reviewed JOIN predicate update, tested downstream impact"
ticket: DATA-1234
scope:
scoped:
path_prefixes:
- "models/"
expires_at: "2026-03-01T00:00:00Z"
Then run review with exceptions:
lexega-sql review main..HEAD models/ -r \
--custom-rules .lexega/custom_rules.yaml \
--policy .lexega/policy.yaml \
--exceptions .lexega/exceptions.yaml \
--env prod \
--decision-out decision.json
Key Concepts
Separation of concerns:
- Custom rules define WHAT to detect (detection logic)
- Policies define WHAT TO DO when a rule fires (enforcement)
- Exceptions grant one-off permissions for specific rules
This separation keeps policies simple and detection testable.
Need Help?
Can't find what you're looking for? Check out our GitHub or reach out to support.