How to Generate and Validate Policies¶
Auto-generate Rego policy skeletons from FastAPI routes and validate at startup or in CI.
CLI Commands¶
Generate Policies¶
Output:
Scanning routes...
Generated policies/myapp/GET/documents.rego
Generated policies/myapp/POST/documents.rego
Generated policies/myapp/check.rego (ReBAC)
Generated 3 policies from 2 routes
Options:
fastapi-topaz generate-policies \
--app myapp.main:app \
--output policies/ \
--config myapp.config:config \
--overwrite \
--dry-run \
--format flat
Validate Policies (CI Integration)¶
Output:
Scanning routes... 12 routes found
Scanning policies... 10 policies found
Missing policies (routes without policies):
- myapp.DELETE.documents.__id
Route: DELETE /documents/{id}
Orphaned policies (no matching route):
- myapp.GET.old_endpoint
Summary: 1 missing, 1 orphaned
Exit code: 1
Generate Route Map¶
Output:
| Route | Method | Policy Path | Status |
|-------|--------|-------------|--------|
| /documents | GET | myapp.GET.documents | OK |
| /documents | POST | myapp.POST.documents | OK |
| /documents/{id} | DELETE | myapp.DELETE.documents.__id | Missing |
Startup Validation¶
@app.on_event("startup")
async def startup():
result = await config.validate_policies_from_app(app)
if not result.valid:
for missing in result.missing_policies:
print(f"Missing policy: {missing.policy_path}")
print(f" Route: {missing.method} {missing.path}")
raise RuntimeError(
f"Missing {len(result.missing_policies)} policies. "
"Run 'fastapi-topaz generate-policies' to create them."
)
Quick validation (one-liner):
@app.on_event("startup")
async def startup():
await config.validate_policies_from_app(app, fail_on_missing=True)
Generated Rego Template¶
Policy route (GET /documents):
package myapp.GET.documents
import rego.v1
default allowed = false
# Route: GET /documents
# Generated by fastapi-topaz
allowed if {
input.identity.type == "IDENTITY_TYPE_SUB"
}
ReBAC policy (myapp.check):
package myapp.check
import rego.v1
default allowed = false
allowed if {
ds.check({
"object_type": input.resource.object_type,
"object_id": input.resource.object_id,
"relation": input.resource.relation,
"subject_type": input.resource.subject_type,
"subject_id": input.identity.value,
})
}
CI/CD Integration¶
GitHub Actions¶
name: Policy Validation
on: [push, pull_request]
jobs:
validate-policies:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- run: pip install fastapi-topaz
- run: |
fastapi-topaz policy-diff \
--app myapp.main:app \
--policies policies/ \
--strict
Pre-commit Hook¶
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: policy-diff
name: Validate Topaz policies
entry: fastapi-topaz policy-diff --app myapp.main:app --policies policies/
language: system
pass_filenames: false
Python API¶
from fastapi_topaz.codegen import generate_policies, policy_diff
# Generate policies
policies = generate_policies(app, config)
for policy_path, rego_content in policies.items():
print(f"# {policy_path}\n{rego_content}\n")
# Check diff
diff = await policy_diff(app, config, policies_dir="policies/")
print(f"Missing: {diff.missing}")
print(f"Orphaned: {diff.orphaned}")
See Also¶
- CLI Reference - Complete CLI documentation
- API Reference - Python API