Running it in CI¶
QueryFence needs nothing special: it runs inside the tests you already run.
A violation fails the test that executed the query, so the build fails where the problem is.
The report¶
Every run writes target/queryfence/report.json, grouped per policy:
{
"generatedAt": "2026-09-24T09:12:03Z",
"disabled": false,
"disabledReasons": [],
"policies": [
{
"policy": "queryfence.yml",
"mode": "FAIL",
"summary": { "tests": 48, "statements": 50, "findings": 1 },
"findings": [
{
"test": "com.acme.order.OrderServiceTest#listsPendingOrders",
"rule": "tenant-isolation",
"code": "MISSING_PREDICATE",
"table": "purchase_order",
"alias": "o",
"message": "purchase_order (o) has no tenant filter. Add …",
"sql": "SELECT o.id FROM purchase_order o WHERE o.status = ?",
"origin": { "class": "com.acme.order.OrderRepository", "method": "findByStatus",
"file": "OrderRepository.java", "line": 42 }
}
]
}
]
}
Keep it as a build artifact:
- name: Upload the QueryFence report
if: always()
uses: actions/upload-artifact@v4
with:
name: queryfence-report
path: "**/target/queryfence/report.json"
Summarising it¶
The repository ships a small script with no dependencies:
python3 tools/queryfence-summary.py target/queryfence/report.json
python3 tools/queryfence-summary.py target/queryfence/report.json --triage
It groups findings by rule, table, code and origin, and --triage prints one entry per origin —
the list to work through when adopting QueryFence on an existing project.
Do not switch it off to go green¶
queryfence.enabled=false fails the build when CI is set, unless someone also sets
queryfence.allowDisabledInCi=true. A pipeline that checks nothing should not look green.