Sign inSign up

daljeetbarmi/prisma-rql-builder

By daljeetbarmi

•Updated 4 months ago

Self-contained Docker container for Prisma Cloud RQL policy authoring, validation, and export.

Image
0

792

daljeetbarmi/prisma-rql-builder repository overview

⁠Prisma RQL Builder

A self-contained Docker container that helps security engineers author, validate, and export production-ready Prisma Cloud config policies — faster and with higher confidence.


⁠What problem does this solve?

Writing Prisma Cloud RQL (Resource Query Language) config policies is error-prone. The two most common failure modes are silent:

  • Wrong api.name — the query runs without error but returns zero results because the API mapping is incorrect.
  • Missing 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.


⁠Features

FeatureDescription
Guided policy builderStep-by-step form for cloud, API name, severity, json.rule, compliance standard, and labels
API CatalogAuthoritative api.name → ARM resource type mapping (26 entries: 20 Azure, 6 AWS) with fuzzy display-name lookup
Template ingestionUpload ARM JSON, Bicep, or any resource/policy JSON — 5-strategy catalog lookup auto-populates fields
Catalog auto-generationUnknown resources get a draft catalog entry generated from their field structure, ready to review and save
RQL validationStructural checks, anti-pattern detection (invalid operators, regex in matches, wildcard ports), corpus bad-pattern matching
Confidence scoringFour-signal score (High / Medium / Low) shown on every generated policy
Example corpusSQLite database of labelled good/bad RQL patterns; intent-aware search ranks examples by relevance
LLM AssistClaude / Ollama / OpenAI draft generation with per-request provider/model overrides
Git exportOne-click ZIP containing policy.yaml, README.md, commit_message.txt, and pr_description.md
Dry-run checklistEmbedded in every output — a mandatory validation checklist before merge

⁠Quick Start

⁠Prerequisites
  • Docker⁠ and Docker Compose
  • (Optional) Azure CLI with Bicep extension — only required if uploading .bicep files
  • (Optional) An LLM API key or local Ollama instance if you want LLM Assist mode
⁠Running from Docker Hub

Published 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

Open http://localhost:5000⁠

Note: Bicep file upload requires the Azure CLI with the Bicep extension installed on the host machine.


⁠Sample .env file
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


⁠Usage Guide

⁠Building a policy manually
  1. Fill in the Policy panel on the left sidebar:
    • Policy name — descriptive title used in commit messages and YAML output
    • Cloud — Azure, AWS, or GCP
    • Severity — Critical / High / Medium / Low / Informational
    • API name — start typing to autocomplete from the loaded catalog (e.g. azure-storage-account-list)
    • json.rule — the field condition (e.g. properties.supportsHttpsTrafficOnly is false)
    • Compliance — optional standard reference (e.g. CIS Azure 1.4)
    • Labels — comma-separated tags (e.g. security,azure,storage)
  2. Click Generate to produce the deterministic output.
  3. Use the tabs in the main panel to view RQL, YAML, Commit, PR, or README outputs.
  4. Review the Confidence panel to understand why a score was assigned.
  5. Click Export ZIP to download all outputs as a zip file ready for your Git repository.
⁠Ingesting a resource template

The Ingest panel accepts two file types:

File TypeHow 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 JSONTries 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.

⁠Resource JSON — five-strategy lookup

When you upload a resource JSON via the Prisma JSON upload button, the parser tries these strategies in order:

  1. type field → ARM resource type match
  2. resourceType field → ARM resource type match
  3. api.name field → direct Prisma api_name match
  4. apiName / api_name fields → direct Prisma api_name match
  5. type / resourceType / service / serviceName → fuzzy display-name match

If 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.

⁠Using LLM Assist mode

LLM Assist generates a draft policy when the deterministic builder cannot confidently produce a rule. Use it when:

  • The resource type is not in the API Catalog (new service or custom resource)
  • You want to describe your intent in plain English
  • The confidence score is Low from the deterministic builder

To use it:

  1. Fill in at least API name, Cloud, and the Intent field describing what the policy should enforce.
  2. Click LLM Draft instead of Generate.
  3. All outputs are tagged with a persistent [DRAFT — LLM GENERATED — REQUIRES PEER REVIEW BEFORE MERGE] banner.
  4. Any validation issues found in the generated RQL are shown inline beneath the output.

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.

⁠Validating a generated RQL

Click Validate at any time to run the current RQL through the full validator. Validation checks:

  • Structural prefix (config from cloud.resource where or config from iam where)
  • Presence of cloud.type and api.name
  • Missing json.rule condition
  • api.name membership in the API Catalog
  • Known-bad corpus patterns (Jaccard token overlap > 0.7)
  • Invalid operators (e.g. lists instead of contains)
  • Regex syntax in matches values (wildcards only are valid)
  • Blanket wildcard on port/CIDR fields
  • Multiple api.name clauses in a single query

Results are returned with structured severity (error/warning) and code fields, not just a flat message list.


⁠Confidence Score

Every generated policy shows a High / Medium / Low confidence score based on four signals:

SignalWhat it checks
✅ Known Prisma API mapping foundapi.name exists in api_catalog.json
✅ Known-good example matchedCorpus contains a similar labelled-good RQL (Jaccard overlap > 0.6)
✅ json.rule field verifiedThe json.rule field path appears in the uploaded template's properties
✅ Structural validation passedFull validator returned no errors and no warnings
  • High — all four signals green
  • Medium — 2–3 signals green; peer review recommended
  • Low — 0–1 signal; treat as draft only

Signal 4 runs the complete validator (structural + corpus + anti-pattern checks), not just a corpus match. Green means the RQL passed everything.


⁠Dry-Run Checklist

Every output embeds the following checklist. Do not merge a policy that hasn't passed this:

  • Confirm api.name exists in your Prisma Cloud tenant → Investigate tab → Config → filter by api.name
  • Run the RQL query in Prisma Investigate → Confirm results are returned (non-zero expected if misconfigs exist)
  • Validate result count is plausible → Too many results may indicate a missing or overly broad json.rule → Zero results may indicate wrong api.name or field path
  • Test against one known-compliant resource — it should not appear in results
  • Test against one known-non-compliant resource — it must appear in results
  • Peer review before merge — at minimum one other engineer reviews the json.rule logic

⁠API Catalog

rql/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.name in 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.

⁠Adding a catalog entry via API
# 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
  }'

⁠Example Corpus

The SQLite database (data/rql_examples.db) stores labelled RQL patterns used for validation and similarity matching.

⁠Searching examples by intent
# 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.

⁠Adding examples via API
# 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"

⁠LLM Configuration

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.


⁠REST API Reference

MethodPathDescription
GET/api/catalogReturn full API Catalog. Filter by ?cloud=azure|aws|gcp
POST/api/catalog/templateGenerate a draft catalog entry from a resource JSON body
POST/api/catalogAdd or overwrite a catalog entry
POST/api/generateGenerate RQL + all outputs from form fields
POST/api/llm-generateGenerate a draft policy via LLM; supports per-request llm_provider/llm_model/llm_api_key overrides
POST/api/validateValidate an RQL string; returns structured issues with severity, code, and message
GET/api/examples/searchIntent-aware search over known-good examples (?q=&api_name=&compliance=&limit=)
POST/upload/armUpload ARM JSON or Bicep file for resource extraction
POST/upload/prisma-jsonUpload any resource JSON or Prisma policy export (5-strategy catalog lookup)
GET/examplesList corpus examples (filter: cloud, label, api_name)
POST/examplesAdd a new example to the corpus
DELETE/examples/<id>Delete a corpus example by ID
POST/api/exportGenerate and download a ZIP of all outputs
⁠Example: generate a policy via API
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"]
  }'
⁠Example: validate an RQL string
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"
}

⁠Export ZIP Contents

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.


⁠Dependencies

PackageVersionPurpose
Flask≥3.0, <4.0Web framework and API server
PyYAML≥6.0, <7.0YAML policy output
requests≥2.31, <3.0Ollama HTTP client
anthropic≥0.40, <1.0Claude LLM provider (optional)
openai≥1.50, <2.0OpenAI 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.


⁠Docker Reference

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
⁠Backing up the database

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
⁠Restoring to a new container
# 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 with docker volume ls if it differs.


⁠Development Phases

PhaseScopeStatus
1 — Core BuilderFlask app + GUI wizard + deterministic RQL generation✅ Done
2 — API Catalog + YAML Outputapi_catalog.json (26 entries) + YAML generator✅ Done
3 — Template IngestionARM/Bicep parser + 5-strategy resource JSON parser + catalog auto-generation✅ Done
4 — Example Corpus + ValidationSQLite corpus + structural validator + anti-pattern detection + confidence score✅ Done
5 — LLM AssistClaude / Ollama / OpenAI + LlmConfig + per-request overrides + OPERATOR_REFERENCE in prompt✅ Done
6 — Git ExportZIP output + dry-run checklist in all outputs✅ Done
7 — Auth + HardeningBasic auth, volume persistence, example management, rate limiting🔲 Pending

⁠Tags

#prisma #rql #docker #flask #azure #aws #gcp #security #devsecops

Tag summary

Content type

Image

Digest

sha256:d65be35ef…

Size

225.3 MB

Last updated

4 months ago

docker pull daljeetbarmi/prisma-rql-builder