This repository demonstrates a concrete pattern for building authorization-scoped retrieval in a RAG system:
- Cedar type-aware partial evaluation (TPE) is used to evaluate policies with a known principal, action, and context, but an unknown resource.
- Cedar produces a residual policy describing which resource attributes and relationships still matter for access.
- The application translates that residual into retrieval constraints (a metadata filter).
- Vector search runs with those constraints applied, so only authorized chunks can become LLM context.
This is not "policy in the prompt."
Authorization is enforced before any sensitive context is assembled.
In a retrieval-augmented generation (RAG) system, the application enriches a user's prompt with additional context retrieved from a vector database—documents, passages, or chunks that help the language model produce a more informed response. In an authorized RAG system, that enrichment is not generic or unconditional. As the diagram shows, authorization is evaluated before retrieval, not inside the prompt. Cedar's type-aware partial evaluation evaluates policy for a given principal and action and produces a policy residual, a constraint over resources. The application compiles that residual into a database-native query filter, ensuring that only authorized additional context is retrieved from the vector database. The prompt constructor then assembles the user's instruction together with this authorized additional context. The language model never decides what it is allowed to see; it operates entirely within a world that has already been shaped by authorization.
The flow:
- A person asks a question in an application.
- The application (acting as PEP) evaluates authorization using Cedar.
- Cedar runs partial evaluation with an abstract resource.
- Cedar returns a residual condition over resource attributes.
- The application compiles that residual into a vector DB filter.
- Vector search runs with the filter applied.
- Only authorized chunks are assembled as context for the model.
This repo is:
- A hands-on demo of policy-driven retrieval in a RAG pipeline
- An example of using Cedar TPE outputs to constrain vector search
- A minimal multi-tenant collaboration dataset (companies, users, shared documents)
This repo is not:
- A full RAG application or UI
- An agentic system
- A production reference architecture
The goal is to make one architectural boundary concrete:
The model never sees unauthorized data because the system never retrieves it.
cedar/— Cedar schema, policies, and entitiesdata/— demo documents and chunk metadatasrc/tpe/— Node scripts to run Cedar partial evaluationsrc/compile/— residual → datastore filter translationsrc/ingest/— embedding and OpenSearch ingestsrc/retrieve/— filtered vector queries and context assemblysrc/lib/— shared utilities for Cedar and OpenSearchexamples/— sample requests, residuals, and queriesinfra/— optional AWS OpenSearch Serverless setup
- Node.js 18+
- npm or pnpm
- Cedar CLI with experimental TPE feature enabled (see below)
- Optional: AWS account for OpenSearch Serverless
This demo uses the Cedar CLI for type-aware partial evaluation (TPE), which is currently an experimental feature. You'll need to build the Cedar CLI from source with the experimental feature enabled.
Option 1: Build from source (recommended)
-
Install Rust and Cargo (if not already installed):
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-
Install protobuf compiler (required for building Cedar):
# macOS brew install protobuf # Linux (Ubuntu/Debian) sudo apt-get install protobuf-compiler
-
Clone and build Cedar CLI with TPE feature:
git clone https://github.com/cedar-policy/cedar.git cd cedar cargo build --release --bin cedar --features tpe -
Add to PATH (or use full path):
# Add to ~/.zshrc or ~/.bashrc export PATH="$PATH:$(pwd)/target/release"
-
Verify installation:
cedar --version cedar tpe --help # Should show TPE command help
Option 2: Use pre-built binaries (if available)
If the Cedar project provides pre-built binaries with TPE enabled, you can use those instead. Check the Cedar releases page for availability.
Note: The TPE feature must be enabled at compile time. If you see an error like option 'tpe' is experimental, but this executable was not built with 'partial-eval' experimental feature enabled, you need to rebuild with --features tpe as shown above.
Get up and running in minutes:
-
Set up Cedar CLI (see Prerequisites section above for detailed instructions):
# Build Cedar CLI with TPE experimental feature git clone https://github.com/cedar-policy/cedar.git cd cedar cargo build --release --bin cedar --features tpe export PATH="$PATH:$(pwd)/target/release"
-
Clone and install dependencies:
git clone https://github.com/windley/cedar-rag-authz-demo.git cd cedar-rag-authz-demo npm install -
Review the policy model:
# Inspect the Cedar schema and policies cat cedar/schema.cedarschema ls cedar/policies/ -
Run a partial evaluation example:
# Generate a residual policy for customer "kate" node src/tpe/partial-eval.js \ --principal 'Platform::Customer::"kate"' \ --action 'Platform::Action::"view"' \ --resource-type Platform::Chunk \ --out out/residual-kate.json
-
Compile the residual to a filter:
# Translate residual into OpenSearch filter node src/compile/residual-to-filter.js \ --residual out/residual-kate.json \ --out examples/queries/opensearch-filter-kate.json -
Verify expected access:
# Check example requests and expected outcomes cat examples/requests/kate-view.json cat examples/expected/kate-scope.json
This demonstrates the core pattern: Cedar produces a residual describing authorized resources, which is compiled into a vector database filter that enforces access before retrieval.
For detailed explanations, see the steps below.
For a guided, interactive walkthrough of the entire demo, use the Jupyter notebook:
# Install Jupyter if you haven't already
pip install jupyter
# Launch Jupyter
jupyter notebook demo.ipynbThe notebook (demo.ipynb) provides:
- Step-by-step walkthrough of the authorization flow
- Interactive execution of TPE and compilation steps
- Visual comparisons of different principals (Kate, Alice, Mallory)
- Explanations of residual policies and OpenSearch filters
- Complete flow diagram showing how authorization-scoped retrieval works
The notebook covers:
- Understanding the policy model (schema, policies, entities)
- Running type-aware partial evaluation for different principals
- Compiling residuals to OpenSearch filters
- Comparing authorization scopes across principals
- Understanding the complete RAG authorization flow
This is the recommended way to explore the demo interactively.
Start by reviewing:
cedar/schema.cedarschemacedar/policies/cedar/entities.json
The policies model a multi-tenant collaboration platform where access depends on:
- tenant membership
- team-based sharing
- document classification
Note: The cedar/entities.json file includes chunk entities (e.g., "q3-plan#1", "hr-note#1") for demo/testing purposes. In a production RAG system, chunk entities are not required for TPE—only principal entities are needed. Chunk data is stored in the vector database with metadata fields that match the resource attributes referenced in policies.
In this demo, documents are split into chunks for vector search. Chunk identifiers follow the pattern {document-id}#{chunk-number}:
q3-plan#1= chunk #1 of the "q3-plan" documenthr-note#1= chunk #1 of the "hr-note" document- If a document had multiple chunks, you'd see:
q3-plan#1,q3-plan#2,q3-plan#3, etc.
Important notes:
-
Policies don't reference specific chunks - they reference resource attributes (like
resource.tenant,resource.customer_readers_team). This allows policies to work with any chunk without hardcoding IDs. -
For TPE, chunk entities aren't required - Type-aware partial evaluation only needs:
- Principal entities (to know their attributes like
tenant,teams) - The schema (to understand resource type structure)
- Chunk entities in
entities.jsonare included for demo/testing purposes only
- Principal entities (to know their attributes like
-
In production, chunks are stored in the vector database with metadata fields that match the attributes referenced in policies. The authorization filter derived from TPE is applied at query time to ensure only authorized chunks are retrieved.
Note about cedar/entities.json: This file includes chunk entities (e.g., "q3-plan#1", "hr-note#1") for demo/testing purposes. In a production RAG system, you would only need principal entities in entities.json for TPE. Chunk data lives in your vector database with metadata fields that correspond to the resource attributes referenced in policies (tenant, classification, customer_readers_team, employee_readers_team, etc.).
Note on mapping residuals to OpenSearch filters: the mapping from the policy residuals to an OpenSearch filter is for demonstration purposes. I have not done much testing on the filters to ensure the mapping is correct.
Example (illustrative command):
node src/tpe/partial-eval.js \
--principal 'Customer::"kate"' \
--action 'Action::"ask"' \
--context examples/requests/context-tenant-a.json \
--resource-type Chunk \
--out out/residual-kate.jsonThis runs Cedar with:
- a known principal and action
- known runtime context
- an abstract resource
The output is a residual policy describing what must be true about a Chunk for access to be permitted.
This step is application logic, not Cedar logic.
Cedar does not generate database queries. It tells you which attributes and relationships still matter.
This repo can optionally demonstrate enforcement using a real vector database.
High-level flow:
- Create an OpenSearch Serverless collection and index (see infra/)
- Embed and ingest chunks with metadata (see src/ingest/)
- Run a k-NN query with the compiled filter applied (see src/retrieve/)
Example query shape:
- vector similarity clause
- metadata filter derived from Cedar residual
This demo is intentionally strict about boundaries:
- Cedar decides authority.
- The application enforces scope.
- Retrieval is constrained before context exists.
- Prompts express intent, not access control.
The residual-to-filter translation is explicit so it can be audited, tested, and reasoned about.
Current focus:
- ✅ Policy model for a multi-tenant collaboration platform
- ✅ Sample requests and expected access outcomes
- ✅ Cedar TPE invocation via Node (using Cedar CLI with experimental features)
- ✅ Residual → OpenSearch filter compilation
- ⏳ OpenSearch Serverless ingest + filtered retrieval
- ⏳ End-to-end "authorized context" output
