Self-contained Docker container for Prisma Cloud RQL policy authoring, validation, and export.
792
A self-contained Docker container that helps security engineers author, validate, and export production-ready Prisma Cloud config policies — faster and with higher confidence.
Writing Prisma Cloud RQL (Resource Query Language) config policies is error-prone. The two most common failure modes are silent:
api.name — the query runs without error but returns zero results because the API mapping is incorrect.json.rule — the query matches every resource of a given type, generating 100% false-positive alerts.Prisma RQL Builder addresses both by combining a curated API Catalog, a validated example corpus, structural + anti-pattern validation, and an optional LLM assist layer into a single UI — producing outputs ready for immediate PR review.
| Feature | Description |
|---|---|
| Guided policy builder | Step-by-step form for cloud, API name, severity, json.rule, compliance standard, and labels |
| API Catalog | Authoritative api.name → ARM resource type mapping (26 entries: 20 Azure, 6 AWS) with fuzzy display-name lookup |
| Template ingestion | Upload ARM JSON, Bicep, or any resource/policy JSON — 5-strategy catalog lookup auto-populates fields |
| Catalog auto-generation | Unknown resources get a draft catalog entry generated from their field structure, ready to review and save |
| RQL validation | Structural checks, anti-pattern detection (invalid operators, regex in matches, wildcard ports), corpus bad-pattern matching |
| Confidence scoring | Four-signal score (High / Medium / Low) shown on every generated policy |
| Example corpus | SQLite database of labelled good/bad RQL patterns; intent-aware search ranks examples by relevance |
| LLM Assist | Claude / Ollama / OpenAI draft generation with per-request provider/model overrides |
| Git export | One-click ZIP containing policy.yaml, README.md, commit_message.txt, and pr_description.md |
| Dry-run checklist | Embedded in every output — a mandatory validation checklist before merge |
.bicep filesPublished image:
daljeetbarmi/prisma-rql-builder:latest
Pull and run:
docker pull daljeetbarmi/prisma-rql-builder:latest
docker run -p 5000:5000 --env-file .env -v prisma-rql-builder_rql_data:/app/data daljeetbarmi/prisma-rql-builder:latest
Note: Bicep file upload requires the Azure CLI with the Bicep extension installed on the host machine.
LLM_PROVIDER=ollama
# Ollama
OLLAMA_HOST=http://X.X.X.X:11434
OLLAMA_MODEL=qwen3.5:9b
# Anthropic
ANTHROPIC_API_KEY=
ANTHROPIC_MODEL=claude-sonnet-4-6
# OpenAI
OPENAI_API_KEY=
OPENAI_MODEL=gpt-4o
# LLM runtime
LLM_MAX_TOKENS=2048
LLM_TIMEOUT_SECONDS=1800
azure-storage-account-list)properties.supportsHttpsTrafficOnly is false)CIS Azure 1.4)security,azure,storage)The Ingest panel accepts two file types:
| File Type | How it's used |
|---|---|
ARM JSON / Bicep (.json, .bicep) | Parses resources, resolves each against the API Catalog, and auto-populates the builder form. Click a detected resource to select it. |
| Any resource or policy JSON | Tries five lookup strategies to resolve api.name. If matched, pre-fills the builder. If not matched, generates a draft catalog entry for review. |
Upload a file and click the corresponding Upload button. Detected resources appear in a clickable list beneath the upload controls.
When you upload a resource JSON via the Prisma JSON upload button, the parser tries these strategies in order:
type field → ARM resource type matchresourceType field → ARM resource type matchapi.name field → direct Prisma api_name matchapiName / api_name fields → direct Prisma api_name matchtype / resourceType / service / serviceName → fuzzy display-name matchIf all strategies fail, a draft catalog entry is generated automatically from the resource's field structure. You can review it and save it to the catalog with one click, then retry generation.
LLM Assist generates a draft policy when the deterministic builder cannot confidently produce a rule. Use it when:
To use it:
[DRAFT — LLM GENERATED — REQUIRES PEER REVIEW BEFORE MERGE] banner.Per-request provider override: You can override the server's default LLM provider, model, and API key for a single request by supplying llm_provider, llm_model, and llm_api_key in the request body. Useful for testing different models without restarting the container.
LLM-generated output is a candidate, not a finished policy. It must pass the dry-run checklist before merge.
Click Validate at any time to run the current RQL through the full validator. Validation checks:
config from cloud.resource where or config from iam where)cloud.type and api.namejson.rule conditionapi.name membership in the API Cataloglists instead of contains)matches values (wildcards only are valid)api.name clauses in a single queryResults are returned with structured severity (error/warning) and code fields, not just a flat message list.
Every generated policy shows a High / Medium / Low confidence score based on four signals:
| Signal | What it checks |
|---|---|
| ✅ Known Prisma API mapping found | api.name exists in api_catalog.json |
| ✅ Known-good example matched | Corpus contains a similar labelled-good RQL (Jaccard overlap > 0.6) |
| ✅ json.rule field verified | The json.rule field path appears in the uploaded template's properties |
| ✅ Structural validation passed | Full validator returned no errors and no warnings |
Signal 4 runs the complete validator (structural + corpus + anti-pattern checks), not just a corpus match. Green means the RQL passed everything.
Every output embeds the following checklist. Do not merge a policy that hasn't passed this:
api.name exists in your Prisma Cloud tenant
→ Investigate tab → Config → filter by api.namejson.rule
→ Zero results may indicate wrong api.name or field pathjson.rule logicrql/api_catalog.json is the authoritative mapping between ARM resource types and Prisma api.name values. Currently contains 26 entries (20 Azure, 6 AWS) plus a _NOT_AVAILABLE sentinel that lists api.names confirmed not to exist in this tenant.
Example entry:
{
"azure-storage-account-list": {
"api_name": "azure-storage-account-list",
"cloud": "azure",
"resource_type": "Microsoft.Storage/storageAccounts",
"display_names": [],
"common_fields": [
"properties.supportsHttpsTrafficOnly",
"properties.networkAcls.defaultAction",
"properties.allowBlobPublicAccess",
"sku.name",
"kind"
],
"validated": true,
"notes": "Use for storage account-level checks. For blob container ACLs use azure-storage-blob-container."
}
}
The display_names field allows fuzzy matching from human-readable names (e.g. "Azure Container Registry" → azure-container-registry).
A missing or incorrect
api.namein this file is the difference between a policy that fires and one that silently does nothing. Treat changes to this file as peer-reviewed infrastructure changes.
# Generate a draft entry from a resource JSON
curl -X POST http://localhost:5000/api/catalog/template \
-H 'Content-Type: application/json' \
-d @my-resource.json
# Save a catalog entry (set overwrite:true to replace an existing key)
curl -X POST http://localhost:5000/api/catalog \
-H 'Content-Type: application/json' \
-d '{
"catalog_key": "azure-my-new-resource",
"entry": {
"api_name": "azure-my-new-resource",
"cloud": "azure",
"resource_type": "Microsoft.MyNamespace/myResources",
"common_fields": ["properties.enabled"],
"validated": false,
"notes": "Pending validation in Prisma Investigate"
},
"overwrite": false
}'
The SQLite database (data/rql_examples.db) stores labelled RQL patterns used for validation and similarity matching.
# Find known-good examples related to an intent
curl "http://localhost:5000/api/examples/search?q=https+enforced&api_name=azure-storage-account-list&limit=5"
Results are ranked by Jaccard token overlap with the query, with an api_name exact-match bonus and a compliance bonus.
# Add a good example
curl -X POST http://localhost:5000/examples \
-H 'Content-Type: application/json' \
-d '{
"rql": "config from cloud.resource where cloud.type = '\''azure'\'' AND api.name = '\''azure-storage-account-list'\'' AND json.rule = properties.supportsHttpsTrafficOnly is false",
"label": "good",
"reason": "Targets specific boolean field; api.name validated against catalog",
"source": "org-validated"
}'
# List examples for a specific api.name
curl "http://localhost:5000/examples?api_name=azure-storage-account-list&label=good"
Set the following variables in your .env file:
# Required: choose your provider
LLM_PROVIDER=ollama # anthropic | ollama | openai
# Anthropic (Claude)
ANTHROPIC_API_KEY=sk-ant-...
ANTHROPIC_MODEL=claude-sonnet-4-6
# Ollama (local / air-gapped)
OLLAMA_HOST=http://10.0.0.200:11434
OLLAMA_MODEL=qwen3.5:9b
# OpenAI
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4o
# LLM request limits
LLM_MAX_TOKENS=2048
LLM_TIMEOUT_SECONDS=1800
# Flask
FLASK_DEBUG=false
Ollama runs on http://10.0.0.200:11434 for this setup. See the Ollama documentation for model setup.
| Method | Path | Description |
|---|---|---|
GET | /api/catalog | Return full API Catalog. Filter by ?cloud=azure|aws|gcp |
POST | /api/catalog/template | Generate a draft catalog entry from a resource JSON body |
POST | /api/catalog | Add or overwrite a catalog entry |
POST | /api/generate | Generate RQL + all outputs from form fields |
POST | /api/llm-generate | Generate a draft policy via LLM; supports per-request llm_provider/llm_model/llm_api_key overrides |
POST | /api/validate | Validate an RQL string; returns structured issues with severity, code, and message |
GET | /api/examples/search | Intent-aware search over known-good examples (?q=&api_name=&compliance=&limit=) |
POST | /upload/arm | Upload ARM JSON or Bicep file for resource extraction |
POST | /upload/prisma-json | Upload any resource JSON or Prisma policy export (5-strategy catalog lookup) |
GET | /examples | List corpus examples (filter: cloud, label, api_name) |
POST | /examples | Add a new example to the corpus |
DELETE | /examples/<id> | Delete a corpus example by ID |
POST | /api/export | Generate and download a ZIP of all outputs |
curl -X POST http://localhost:5000/api/generate \
-H 'Content-Type: application/json' \
-d '{
"cloud": "azure",
"api_name": "azure-storage-account-list",
"json_rule": "properties.supportsHttpsTrafficOnly is false",
"policy_name": "Azure Storage Account - HTTPS not enforced",
"severity": "High",
"compliance": "CIS Azure 1.4",
"labels": ["security", "azure", "storage"],
"template_fields": ["properties.supportsHttpsTrafficOnly", "kind"]
}'
curl -X POST http://localhost:5000/api/validate \
-H 'Content-Type: application/json' \
-d '{
"rql": "config from cloud.resource where cloud.type = '\''azure'\'' AND api.name = '\''azure-storage-account-list'\'' AND json.rule = properties.supportsHttpsTrafficOnly is false"
}'
Response shape:
{
"valid": true,
"errors": [],
"warnings": [],
"issues": [],
"api_name": "azure-storage-account-list",
"cloud": "azure",
"json_rule": "properties.supportsHttpsTrafficOnly is false"
}
Every generated policy can be exported as a .zip file containing:
<policy-slug>.zip
├── policy.yaml ← Prisma-ready policy definition
├── README.md ← Human-readable policy summary + confidence signals
├── commit_message.txt ← Conventional commit, ready to paste
└── pr_description.md ← Full PR body with metadata table, confidence signals, and dry-run checklist
The policy.yaml follows the Prisma Cloud policy import format and includes the full dry-run checklist in a remediationChecklist field.
| Package | Version | Purpose |
|---|---|---|
Flask | ≥3.0, <4.0 | Web framework and API server |
PyYAML | ≥6.0, <7.0 | YAML policy output |
requests | ≥2.31, <3.0 | Ollama HTTP client |
anthropic | ≥0.40, <1.0 | Claude LLM provider (optional) |
openai | ≥1.50, <2.0 | OpenAI LLM provider (optional) |
python-dotenv | ≥1.0 | .env file loading (optional) |
Bicep transpilation uses the Azure CLI (az bicep build) at runtime. Install it in the container or on the host as needed.
The container exposes port 5000. Data (the SQLite corpus) is persisted via a named Docker volume so examples survive container restarts.
# docker-compose.yml (reference)
services:
prisma-rql-builder:
build: .
ports:
- "5000:5000"
env_file: .env
volumes:
- rql_data:/app/data
volumes:
rql_data:
To reset the corpus and start fresh:
docker compose down -v # removes the named volume
docker compose up --build
The database is at /app/data/rql_examples.db inside the container. Three options:
Copy from running container (simplest)
docker cp prisma-rql-builder:/app/data/rql_examples.db ./rql_examples_backup.db
Safe for a low-traffic internal tool. SQLite's WAL mode handles concurrent reads, though it is technically a file copy mid-write.
SQLite hot backup via docker exec (safest)
docker exec prisma-rql-builder sqlite3 /app/data/rql_examples.db ".backup '/app/data/rql_examples_backup.db'"
docker cp prisma-rql-builder:/app/data/rql_examples_backup.db ./rql_examples_backup.db
Uses SQLite's built-in online backup API — guaranteed consistent even if writes are in progress.
Read the volume directly (container stopped)
docker run --rm \
-v prisma-rql-builder_rql_data:/data \
-v $(pwd):/backup \
alpine \
cp /data/rql_examples.db /backup/rql_examples_backup.db
# Copy the backup into the volume before starting
docker run --rm \
-v prisma-rql-builder_rql_data:/data \
-v $(pwd):/backup \
alpine \
cp /backup/rql_examples_backup.db /data/rql_examples.db
docker compose up --build
The volume name is
prisma-rql-builder_rql_data— Docker prefixes it with the project directory name. Confirm yours withdocker volume lsif it differs.
| Phase | Scope | Status |
|---|---|---|
| 1 — Core Builder | Flask app + GUI wizard + deterministic RQL generation | ✅ Done |
| 2 — API Catalog + YAML Output | api_catalog.json (26 entries) + YAML generator | ✅ Done |
| 3 — Template Ingestion | ARM/Bicep parser + 5-strategy resource JSON parser + catalog auto-generation | ✅ Done |
| 4 — Example Corpus + Validation | SQLite corpus + structural validator + anti-pattern detection + confidence score | ✅ Done |
| 5 — LLM Assist | Claude / Ollama / OpenAI + LlmConfig + per-request overrides + OPERATOR_REFERENCE in prompt | ✅ Done |
| 6 — Git Export | ZIP output + dry-run checklist in all outputs | ✅ Done |
| 7 — Auth + Hardening | Basic auth, volume persistence, example management, rate limiting | 🔲 Pending |
#prisma #rql #docker #flask #azure #aws #gcp #security #devsecops
Content type
Image
Digest
sha256:d65be35ef…
Size
225.3 MB
Last updated
4 months ago
docker pull daljeetbarmi/prisma-rql-builder