Reva AI Authorization SDK
reva-ai-authz protects inbound agent/tool boundaries and outbound
Agent, API, and MCP hops with Reva Trust Gateway (RTG/PDP) authorization.
It also carries authenticated caller identity, W3C tracing, and sanitized
multi-hop intent history across supported integrations.
Release state
| Item | Version |
|---|---|
| Version described by this source tree | 1.0.3 |
| Public PyPI baseline last verified on 2026-08-12 | 1.0.2; 1.0.3 was not published at that check |
| Authoritative current state | installed package metadata and the public PyPI release files |
This packaged README is immutable release documentation, not a live package index. Check the public PyPI project before changing a production pin. If the reviewed 1.0.3 wheel and sdist are not both published and public-index verification has not passed, remain on the verified baseline:
python3.10 -m pip install "reva-ai-authz==1.0.2"
The intended annotated tag is lowercase v1.0.3 with message
Release reva-ai-authz 1.0.3. Creating that tag builds a candidate; it does
not publish until an authorized maintainer runs the protected manual job.
To test the 1.0.3 candidate, install the reviewed wheel artifact from the tag pipeline, not a similarly named file from an ad hoc build:
python3.10 -m pip install ./reva_ai_authz-1.0.3-py3-none-any.whl
python3.10 -c 'from importlib.metadata import version; import reva_ai; assert version("reva-ai-authz") == reva_ai.__version__ == "1.0.3"'
Once PyPI shows the reviewed 1.0.3 wheel and sdist and public-index verification passes, install with:
python3.10 -m pip install "reva-ai-authz==1.0.3"
Python 3.10–3.13 are supported by the 1.0.3 CI matrix. Framework packages such as LangChain, LangGraph, CrewAI, AutoGen, and MCP are application dependencies; this distribution does not install them.
Migrating from 1.0.2
- Deploy the coordinated 1.0.3 PDP and RTG evaluator changes before changing
the customer wheel. An older PDP ignores
rtg/a2a.contextand cannot carry it between Issue Token and Validate Token. - Audit every
proxy.mcp(...)call. Protection now defaults on; useendpoint_protected=Falseonly for an intentionally local, non-policy tool. - Restrict direct
cedar_contextand every value resolved bycedar_context_mapto exact schema keys with string, boolean, safe integer, or homogeneous scalar-list values. Null, float, record, nested, and mixed-list values fail validation. Prefer the declarative map for values in the current schema-validated business payload. Keep the encoded mapping within 512 bytes; transaction JWEs over 4,096 bytes and complete PDP header carriers over 6,144 bytes fail closed. Complete compact PDP JSON is limited to 1,048,576 bytes; keep PDPPDP_AI_REQUEST_BODY_MAX_BYTES=1048576to match that fixed SDK preflight. History is rejected—not truncated—above 65,536 bytes, depth 32, 32 logical events, 2,048 JSON values, or 16,384 UTF-8 bytes in one string. - Handle
PDPRequestError,PDPUnavailableError, andPDPProtocolErrorseparately from a definitiveRevaAuthorizationErrordeny. - Use HTTPS for
RTG_URL. Plain HTTP requires the explicit local/private/ in-cluster development escape hatch described below. - Final-turn recording now requires an explicit FastAPI-route opt-in and an
approved same-RTG-origin HTTPS endpoint. The old
mock_rtg_record_final_turnimport remains temporarily compatible but only emits a deprecation warning and transmits nothing. - Replace direct context/history mutation with the documented decorators,
proxies, adapters, and one isolated
standalone_work_itemper authenticated worker message.
Do not change a production pin until the candidate wheel and the coordinated PDP/RTG deployment pass the acceptance checklist. The presence of this migration guide is not evidence of publication; use the public index and installed package metadata as the authority.
What must exist before code integration
The SDK cannot invent control-plane metadata. Register and test all of the following in the customer's policy store before running these examples:
- the exact
agent_nameused by each inbound route; - every destination Agent, API, MCP server, and tool resource ID;
- each source-to-destination topology edge and action (
invokeAgent,invokeTool,read,write, ordelete); - the static destination URL and endpoint type used for resource resolution;
- every Cedar context attribute used by policy, with identical spelling and type; and
- the resource skill catalog used by PDP's
promptIntentmatcher.
An ID mismatch is expected to deny. A Cedar policy on context.HSNewApp_mrn
does not match a payload field named mrn unless the application maps it with
cedar_context={"HSNewApp_mrn": value} or declaratively with
cedar_context_map={"HSNewApp_mrn": "mrn"}.
SDK 1.0.3's managed context and intent-consistency guarantees require the
coordinated 1.0.3 PDP and RTG evaluator changes. An older PDP parses the request
but ignores rtg/a2a.context; an older evaluator may accept ALIGNED for a
proven action change. Record the deployed SDK wheel hash plus PDP, RTG, gateway,
policy-schema, and guardrail-template versions during customer acceptance.
Environment
Set configuration before importing reva_ai or defining protected routes:
export RTG_URL="https://rtg.customer.example"
export POLICYSTORE_ID="customer-policy-store-id"
# Optional platform credential, injected from the customer's secret manager.
export RTG_AUTH_TOKEN="..."
# Logs may contain business data. Use a writable protected path and a safe level.
export REVA_AI_LOG_FILE="/var/log/customer-agent/reva-ai-sdk.log"
export REVA_AI_LOG_LEVEL="WARNING"
export REVA_AI_LOG_STDOUT="false"
# PDP may spend up to five minutes on authoritative guardrail retries.
export REVA_AI_PDP_TIMEOUT_SECONDS="330"
The SDK does not create a file unless REVA_AI_LOG_FILE is explicitly set.
If an explicitly configured file cannot be opened, file logging is disabled
with a warning rather than failing package import. Application logging handlers
or REVA_AI_LOG_STDOUT=true can be used in read-only containers.
Do not set RTG_DISABLED or REVA_AI_ALLOW_EXTERNAL_CONTEXT_WRITES in a
protected environment. RTG_DISABLED is an explicit local-test bypass.
RTG_URL must be an absolute HTTPS base URL without embedded credentials,
query parameters, fragments, or path-traversal segments. A base path is
allowed. For local/private/in-cluster development only, plain HTTP also
requires REVA_AI_ALLOW_INSECURE_RTG_HTTP=1 and emits a warning. Keep that
escape hatch unset in production; it does not apply to final-turn delivery.
The SDK sends RTG_AUTH_TOKEN to RTG/PDP as X-API-Token; it does not replace
the end-user access credential or transaction token. Never put either token in
a prompt, business body, cedar_context, history, log field, or model-visible
tool argument.
REVA_AI_PDP_TIMEOUT_SECONDS is the timeout for PDP authorization calls only;
it defaults to 330 seconds and accepts finite values from 1 to 900. The default
exceeds PDP's five-minute total guardrail budget by 30 seconds. Keep gateway,
ingress, load-balancer, and application request deadlines above this value, or
reduce the coordinated PDP retry budget. Downstream agent/API/MCP transport
timeouts remain separate.
If the application uses reva_ai_discover, treat it as optional startup
telemetry: it stores application metadata and performs a synchronous
/discovery-logs POST. It does not provide missing RTG_URL or
POLICYSTORE_ID to authorization; protected paths read those values from the
environment and fail closed when either is absent.
Minimal FastAPI boundary
Use a strict object schema, validate a nonblank prompt, and decorate the route inside the normal FastAPI decorator:
from typing import Annotated
from fastapi import FastAPI, Request
from pydantic import BaseModel, ConfigDict, StringConstraints
from reva_ai.sdk.ai import reva_ai_authorise
NonBlank = Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
class InvokeBody(BaseModel):
model_config = ConfigDict(extra="forbid")
message: NonBlank
conversation_id: NonBlank
app = FastAPI()
@app.post("/invoke")
@reva_ai_authorise(
agent_name="support-agent",
action="invokeAgent",
auth_key="Authorization",
prompt_key="message",
principal_claim="sub",
cedar_context_map={"SupportApp_conversationId": "conversation_id"},
)
async def invoke(body: InvokeBody, request: Request) -> dict[str, str]:
# Customer code runs only after PDP allows.
return {"answer": f"Accepted {body.conversation_id}"}
Pass exactly one of agent_name, tool_name, or crew_name. The body key
rtg/a2a is SDK-owned and is removed before a strict downstream handler runs.
Do not catch RevaAuthorizationError and continue protected work.
The whole-app middleware helper intentionally skips GET, HEAD, and
OPTIONS. Decorate sensitive read routes directly; do not claim that the
middleware protects them.
Agent-to-agent HTTP
Call the proxy inside a decorated request or an isolated worker context. URLs must come from static allowlisted configuration, never unchecked user/model output:
from reva_ai.sdk.ai.proxy import proxy
async def call_fulfilment(message: str, order_id: str) -> dict:
response = await proxy.agent(
endpoint_url="https://fulfilment-agent.internal.example/invoke",
method="POST",
body={"message": message, "order_id": order_id},
prompt_key="message",
resource_id="fulfilment-agent",
cedar_context_map={"OrderApp_orderId": "order_id"},
)
response.raise_for_status()
return response.json()
cedar_context and cedar_context_map are PDP-only assertion channels. The
SDK places the combined validated result under managed rtg/a2a.context for
authorization, but does not add the Cedar target aliases to the downstream
Agent/API/MCP business payload or customer handler arguments. Existing source
business fields remain unchanged.
Use cedar_context={"Cedar_key": value} when the application already holds a
validated value. Use cedar_context_map={"Cedar_key": "business.path"} to
resolve a value from the current invocation on every call. The latter is
available on validated inbound @reva_ai_authorise route/tool boundaries,
outbound Agent/API/protected-MCP proxies, inner-call helpers, and supported
framework adapters. A path is case-sensitive and may be an exact top-level key,
a dotted path such as patient.mrn, or an indexed path such as
items[0].code:
cedar_context_map = {
"HSNewApp_mrn": "patient.mrn",
"HSNewApp_primaryCode": "items[0].code",
}
The mapper is declarative; it does not execute a callback. A missing path, a
resolved null, a target also supplied in cedar_context, or a path selecting a
credential-shaped segment, history, onBehalfOf, promptIntent, or
rtg/a2a raises ValidationError before PDP. The combined direct and mapped
result then uses the limits below.
The mapping accepts at most 64 attributes and 512 bytes of encoded UTF-8 JSON.
Keys must be nonblank strings of at most 128 characters. Values must be a
string, boolean, integer in [-(2**53 - 1), 2**53 - 1], or a list/tuple whose
items all have one of those same scalar types. Empty lists are accepted. Null,
every float (including 1.0), records/objects, nested collections, mixed-type
lists, unsafe integers, identity fields such as onBehalfOf, promptIntent,
subject, or principal, routing/prompt/history fields, credential-like keys,
credential-shaped values, and non-JSON values are rejected.
Explicit/resolved context wins over a same-named root business field at Issue
Token. On allow, PDP binds only that validated managed mapping—not arbitrary
business fields—into the encrypted transaction token. At the receiving
Validate Token PEP, PDP combines the new business body with the authenticated
token mapping;
a colliding body field or caller-written rtg/a2a.context cannot replace the
token-bound value. A later authorized Issue Token call may supply a new mapping
for its replacement token; if it supplies none, the prior authenticated mapping
is preserved. This two-PEP behavior requires the coordinated 1.0.3 PDP and is
not supplied by the published 1.0.2 wheel alone.
Treat these values as request assertions, not proof of user identity or role.
The route decorator maps only the FastAPI/Pydantic-validated value, and the MCP
tool decorator maps the value actually passed to the tool; raw transport JSON
cannot supply a different policy value. reva_ai_authorise_request and
whole-app middleware run before route-model validation, so they reject nonempty
cedar_context_map. The sub-app compatibility decorator exposes only fixed
cedar_context. Use fixed context on those boundaries or a direct route
decorator for dynamic mapping:
validated_mrn = body.mrn # validated by the application schema
cedar_context = {"HSNewApp_mrn": validated_mrn}
Never copy arbitrary model output into cedar_context, and never derive a
cedar_context_map from caller/model input.
The PDP endpoints have related but non-identical contracts:
| Endpoint | Context shape | Role |
|---|---|---|
POST /pdp/access/v1/token/enrich |
managed rtg/a2a.context |
Outbound proxies authorize Issue Token and mint the encrypted transaction token that carries the explicit mapping. |
POST /pdp/access/v1/agent/evaluation |
managed rtg/a2a.context; authenticated token claim wins during transaction-token validation |
Inbound decorators and inner-call adapters authorize Validate Token/logical invocations. |
POST /pdp/access/v1/ai/evaluation |
top-level context |
Runs the same strict managed-context, principal-last, history, Cedar/AVP, and guardrail rules over the direct body shape. It does not mint the proxy transaction token and is not an identical fallback or a second opinion after deny. |
For direct evaluation, exact context.chatHistory, context.conversation, and
context.hops members are separated as guardrail-history metadata before the
remaining context members are validated as managed Cedar attributes. This
keeps the existing direct-client history shapes working without admitting
nested records through the strict Cedar-value channel. A direct
principal.type and principal.id become the same authoritative typed
onBehalfOf entity used by Cedar/AVP and guardrails.
All three endpoints reject a complete compact UTF-8 JSON body larger than
1,048,576 bytes before authorization, audit, or guardrail work. SDK-managed
calls measure and send the exact same byte sequence. A direct client should do
the same, as below; chunked transfer and omitted Content-Length do not bypass
the PDP limit. Keep PDP PDP_AI_REQUEST_BODY_MAX_BYTES=1048576 for exact SDK
parity. PDP permits an explicitly configured value from 131,072 through
8,388,608 bytes, but changing it is a deployment-contract change: a lower
value can reject an SDK-preflighted request and a higher value does not raise
the SDK's fixed 1 MiB limit. PDP independently caps the canonical JSON sent to
an external guardrail endpoint at 262,144 bytes before the first HTTP attempt.
Oversized authoritative evaluator input fails closed and is never truncated or
retried; an informational endpoint records the failure without becoming
authority.
Call direct AI evaluation only through the authenticated gateway. Pass secrets and tenant configuration from a trusted secret/config provider:
import json
from typing import Any
from urllib.parse import urlsplit
import httpx
async def evaluate_direct_ai(
*,
gateway_url: str,
api_token: str,
policy_store_id: str,
prompt: str,
mrn: str,
caller_agent_id: str,
principal_user_id: str,
audit_authorization: str | None = None,
) -> dict[str, Any]:
gateway_url = gateway_url.strip().rstrip("/")
api_token = api_token.strip()
policy_store_id = policy_store_id.strip()
prompt = prompt.strip()
mrn = mrn.strip()
caller_agent_id = caller_agent_id.strip()
principal_user_id = principal_user_id.strip()
parsed_gateway = urlsplit(gateway_url)
if parsed_gateway.scheme != "https" or not parsed_gateway.netloc:
raise ValueError("gateway_url must use HTTPS")
if not all(
(api_token, policy_store_id, prompt, mrn, caller_agent_id, principal_user_id)
):
raise ValueError("all direct AI evaluation inputs are required")
headers = {
"Content-Type": "application/json",
"X-API-Token": api_token,
"policyStoreId": policy_store_id,
}
if audit_authorization and audit_authorization.strip():
headers["Authorization"] = audit_authorization.strip()
body = {
"subject": {"type": "Agent", "id": caller_agent_id},
"action": {"name": "invokeAgent"},
"resource": {"type": "Agent", "id": "records-review-agent"},
"principal": {"type": "User", "id": principal_user_id},
"context": {"HSNewApp_mrn": mrn},
"transmission": {
"promptKey": "content",
"role": "user",
"content": prompt,
},
}
payload_bytes = json.dumps(
body,
ensure_ascii=False,
separators=(",", ":"),
allow_nan=False,
).encode("utf-8")
if len(payload_bytes) > 1_048_576:
raise ValueError("direct AI evaluation body exceeds 1 MiB")
# Must exceed PDP's five-minute authoritative guardrail budget.
async with httpx.AsyncClient(timeout=330.0) as client:
response = await client.post(
f"{gateway_url}/pdp/access/v1/ai/evaluation",
headers=headers,
content=payload_bytes,
)
if response.status_code == 403:
raise PermissionError("PDP denied direct AI evaluation")
response.raise_for_status()
result = response.json()
if result.get("decision") is not True:
raise PermissionError("PDP denied direct AI evaluation")
return result
subject is the asserted calling workload, while principal is the asserted
originating user/on-behalf-of identity. Today the direct endpoint authenticates
the gateway request with mandatory X-API-Token, but it does not itself
cryptographically bind body subject, body principal, or policyStoreId to
that credential. Treat /ai/evaluation as a trusted-service assertion API:
never expose it to an untrusted caller, never populate those fields from raw
request/model input, scope the service credential to the tenant, and source
the identities and policy-store ID only from authenticated service/user context
and fixed trusted configuration. They must also match registered policy
metadata. An optional Authorization value is captured only as sanitized
decision-audit context; it does not authenticate this endpoint or affect the
decision. Do not send promptIntent: it is ignored as caller input and remains
server-owned. A deny ends the operation. Direct evaluation neither mints an
X-Transaction-Token nor permits /token/enrich or another endpoint as
fallback after denial.
For protected MCP, acceptance testing must prove the attribute at both calls:
the client-side /token/enrich Issue Token decision and the server decorator's
/agent/evaluation Validate Token decision.
Trusted external API
proxy.api keeps the downstream body unchanged, maps HTTP methods to
read/write/delete, and sends the newly issued transaction token to the
target. Use it only with a registered, trusted HTTPS service that is permitted
to receive that token:
from reva_ai.sdk.ai.proxy import proxy
async def payment_status(payment_id: str) -> dict:
response = await proxy.api(
endpoint_url="https://payments-api.internal.example/v1/status-lookups",
method="POST",
endpoint_type="Api",
body={"payment_id": payment_id},
prompt_key="payment_id",
cedar_context={"Payments_paymentId": payment_id},
)
response.raise_for_status()
return response.json()
Do not use this helper to send Reva transaction credentials to a public SaaS
endpoint. Query parameters are sent downstream but are not part of the current
PDP business body; place authorization-relevant fields in the object body or
explicit cedar_context.
Protected MCP client
MCP proxying is protected by default in 1.0.3. Supply the exact registered MCP resource ID; the JSON-RPC tool name and the policy resource ID are not assumed to be interchangeable:
from reva_ai.sdk.ai.proxy import proxy
async def get_labs(mrn: str):
return await proxy.mcp(
tool="get_lab_results_lg",
arguments={
"message": f"Review the latest lab results for {mrn}",
"mrn": mrn,
},
mcp_client="https://healthsphere-mcp.internal.example/mcp",
resource_id="healthsphere-mcp_lg/get_lab_results_lg",
transport="streamable_http",
cedar_context_map={"HSNewApp_mrn": "mrn"},
)
The agent-to-tool operation makes two security-relevant calls:
- Agent → PDP
POST /pdp/access/v1/token/enrich(invokeTool/ MCP), where Cedar and synchronous guardrails run and a transaction token is issued. - Agent → MCP server
tools/call, where the server's@reva_ai_authorise(tool_name=...)validates the token.
rtg/a2a is the name of the managed metadata key shared by Agent and MCP
envelopes; it is not the Agent-to-Agent URL path.
Managed context is capped at 512 bytes before encryption so its JWE/base64url expansion plus existing claims stays within deployed HTTP header budgets. PDP and the SDK fail closed if a newly issued compact transaction JWE exceeds 4,096 UTF-8 bytes. The SDK also rejects the complete PDP request-header set before network I/O when its serialized size exceeds 6,144 bytes. Reduce bounded policy context or metadata; never truncate a credential or bypass authorization to fit it.
Credentials remain HTTP transport headers and are not mirrored into
model-visible params.arguments. Protected stdio is therefore rejected while
RTG is enabled because it has no reviewed transport-isolated credential
channel. Use streamable HTTPS for protected MCP. An intentionally unprotected
local tool requires the visible opt-out endpoint_protected=False.
Unknown proxy.mcp keyword arguments raise TypeError; misspelled security
options no longer disappear silently.
Protected MCP server
The server decorator uses the physical MCP HTTP transport credential. Customer tool functions should expose only business arguments:
from mcp.server.fastmcp import FastMCP
from reva_ai.sdk.ai import reva_ai_authorise
mcp = FastMCP("healthsphere-mcp")
@mcp.tool()
@reva_ai_authorise(
tool_name="get_lab_results_lg",
action="invokeTool",
prompt_key="message",
principal_claim="sub",
)
async def get_lab_results_lg(message: str, mrn: str) -> dict:
return {"mrn": mrn, "results": []}
Verify the exact FastMCP version exposes the current physical HTTP request to
the decorator. Test tools/call; a successful initialize or tools/list
does not prove tool authorization.
Standalone workers
Use one context per work item. The context manager clears identity, credentials, history, and tracing even if customer code raises.
A true first-hop queue message may establish one sanitized originating prompt:
from reva_ai.sdk.ai.adapters import (
authorise_inner_call_async,
standalone_work_item,
)
async def process_first_hop(message) -> None:
payload = message.json()
with standalone_work_item(
agent_name="batch-supervisor-agent",
agent_type="Agent",
auth_token=message.headers["Authorization"],
incoming_headers=message.headers,
principal_claim="sub",
originating_payload=payload,
originating_prompt_key="message",
):
await authorise_inner_call_async(
resource_name="billing-agent",
resource_type="Agent",
action="invokeAgent",
current_payload=payload,
prompt_key="message",
cedar_context={"Billing_accountId": payload["account_id"]},
)
await process_authorized_payload(payload)
originating_payload creates only a minimal root prompt hop. It does not import
caller-supplied raw history, identity, or credentials. It requires a fresh
context and cannot be combined with a transaction token.
A delegated queue message must carry the authenticated managed envelope instead:
from reva_ai.sdk.ai.adapters import (
authorise_inner_call_async,
standalone_work_item,
)
async def process_delegated_message(message) -> None:
payload = message.json()
with standalone_work_item(
agent_name="batch-supervisor-agent",
agent_type="Agent",
auth_token=message.headers["X-Transaction-Token"],
incoming_headers=message.headers,
inbound_rtg_a2a=payload["rtg/a2a"],
):
await authorise_inner_call_async(
resource_name="batch-supervisor-agent",
resource_type="Agent",
action="invokeAgent",
current_payload=payload,
prompt_key="message",
)
await process_delegated_payload(payload)
standalone_work_item only isolates and seeds SDK context. It does not
authenticate the queue message, verify broker provenance, or authorize
business work. The consumer must authenticate/trust the ingress transport,
keep the managed envelope bound to its transaction token, and obtain an allow
from PDP before any business side effect.
Applications must not call internal history setters or enable external context writes to manufacture a more favorable guardrail baseline.
Framework adapters
Adapters require a decorated outer request or standalone_work_item.
LangChain:
from reva_ai.sdk.ai.adapters.langchain import protect_runnable, protect_tool
protected_chain = protect_runnable(
chain,
agent_name="summarizer-agent",
prompt_key="message",
)
protected_tool = protect_tool(
account_tool,
tool_name="account-mcp/lookup-account",
resource_type="MCP",
prompt_key="account_id",
)
batch and abatch authorize every item before executing any item.
LangGraph:
from reva_ai.sdk.ai.adapters.langgraph import protect_node
@protect_node(agent_name="planner-agent", prompt_key="message")
async def planner_node(state: dict, config: dict) -> dict:
return await plan(state)
AutoGen:
from reva_ai.sdk.ai.adapters.autogen import protect_agent
protected_assistant = protect_agent(
assistant,
agent_name="research-assistant-agent",
prompt_key="content",
)
CrewAI factories must retain their return annotations and perform construction only. Keep network calls, writes, and tool execution out of a factory body.
Errors and fallback behavior
Import exceptions from reva_ai.sdk.ai.utils:
from reva_ai.sdk.ai.utils import (
ConfigurationError,
HistoryValidationError,
PDPProtocolError,
PDPRequestBodyTooLargeError,
PDPRequestError,
PDPUnavailableError,
RevaAuthorizationError,
)
| Exception | Meaning | Retry/fallback guidance |
|---|---|---|
RevaAuthorizationError |
PDP returned 401/403 or an explicit deny | Do not retry through another authorization path |
PDPRequestError |
Non-denial 4xx; request/config contract is invalid | Fix the request or deployment configuration |
PDPUnavailableError |
Timeout, network failure, 408/425/429, or 5xx | Protected work stays stopped; bounded infrastructure retry only for an idempotent authorization call |
PDPProtocolError |
Successful HTTP response is malformed or missing token/decision | Stop; SDK/PDP versions are incompatible or PDP is faulty |
HistoryValidationError |
Security history is malformed or exceeds the shared history limits | Safe HTTP 400; fix the input; do not truncate history |
PDPRequestBodyTooLargeError |
Compact SDK-to-PDP JSON exceeds 1,048,576 bytes | Safe HTTP 413 before network access; reduce the payload |
ConfigurationError |
Required local SDK configuration is missing | Fix startup configuration |
FastAPI's default response detail is safe-by-default: it omits raw PDP bodies,
policy reasons, and internal error codes. The exception object deliberately
retains reason, code, pdp_response, and (where applicable)
upstream_status_code for trusted diagnostics. Do not serialize the exception
object or those fields into customer responses or ordinary logs. After PDP
allows and execution enters the customer handler, the decorator re-raises the
application's exception unchanged so existing FastAPI exception handlers keep
their normal semantics.
Fallback to an alternate endpoint is permitted only for
PDPUnavailableError, when Reva has explicitly defined that endpoint as the
same authorization authority. Never catch RevaAuthorizationError and ask a
different path for a second opinion.
The SDK does not retry business side effects automatically. A lost downstream response is not evidence that the operation did not happen.
Intent history, promptIntent, and guardrail authority
These concepts are intentionally separate:
rtg/a2a.historyis the sanitized recursive hop chain. The RTG evaluator selects the deepest prompt-bearing history node as originating intent and compares it with the current hop.context.promptIntentis generated by PDP from the current prompt and the destination resource's registered skill catalog. It is a list of matched Skill entity references, not originating natural language. The SDK never sets it. An empty list can mean no usable skills/match or matcher failure; it does not prove that history was lost.- Exactly one guardrail endpoint is the synchronous
decisionMaker. In the standard split IBAC template,/ibac/scoreis authoritative, while/ibac/intentand/ibac/driftare post-decision informational endpoints. Changing a rule to ENFORCE does not make an informationalBLOCKresponse authoritative.
SDK 1.0.3 and the coordinated PDP reject history that exceeds 65,536 compact
UTF-8 JSON bytes, depth 32, 32 logical events, 2,048 total JSON values, or
16,384 UTF-8 bytes in one string. A linked history node and each
chatHistory item count once; conversation.messages and hops are unioned,
with entries sharing the same numeric seq counted once. The rtg/a2a
metadata block and promptless conversation/hops compatibility wrappers do not
count independently. A canonical linked wrapper retained by the guardrail
builder does count. Cycles, non-JSON values, and non-finite
numbers also fail with a safe HTTP 400. Security history is never truncated to
pass authorization.
The 1.0.3 RTG evaluator applies a server-owned 0.85 deny floor when explicit
operation-family or polarity replacement is proven over the same business
object. The regression case is “review MRN-1004 lab results” followed by
“place Furosemide order for MRN-1004”; /score can no longer accept
ALIGNED / 0.05 for that canonical input.
Optional final-turn recording
Conversation metadata alone does not send content. Recording is disabled by default and requires all of the following:
record_final_turn=Trueon a FastAPI route decorator;conversation_keyandconversation_key_location(headerorbody);- an explicit absolute HTTPS
final_turn_url, orREVA_AI_FINAL_TURN_URL; and - customer approval for payload content, retention, residency, tenancy, and failure handling.
The endpoint must use exactly the same HTTPS scheme, host, and port as
RTG_URL, with no embedded credentials, query, or fragment, because the POST
carries RTG_AUTH_TOKEN. The insecure RTG development escape hatch does not
apply. Recording runs only for an edge request without
X-Transaction-Token; chained-agent responses are not recorded by this path.
@app.post("/chat")
@reva_ai_authorise(
agent_name="support-agent",
prompt_key="message",
conversation_key="conversation_id",
conversation_key_location="body",
record_final_turn=True,
final_turn_url="https://rtg.customer.example/v1/final-turn",
)
async def chat(body: InvokeBody, request: Request) -> dict:
return {"answer": "..."}
The POST is background-dispatched and does not delay a non-streaming response.
Delivery is best effort: it has a 10-second HTTP timeout, no retry/durable
queue/shutdown drain, and a maximum of 100 concurrent recording tasks; excess
turns are dropped. Responses are capped at 50,000 characters (the rolling tail
for a stream). Recording failures never turn an allowed business response into
an error. The recorder adds no dedicated prompt/response log, but optional
TRACE logging elsewhere remains payload-capable. There is no derived
/mock/... endpoint in 1.0.3. The deprecated
mock_rtg_record_final_turn helper remains importable as a warning-emitting,
non-transmitting no-op.
Security boundary and current limitations
- Gateway verification is mandatory. The SDK can inspect access-token
claims without locally verifying their signature. The API gateway must use an
algorithm allowlist and trusted JWKS, validate token use/type, issuer,
audience/client,
exp, andnbf, strip forbidden caller metadata, and block direct workload/PDP bypass. A sharedRTG_AUTH_TOKENalone is not proof of the asserted workload identity. - Outbound headers require trust-domain review. Proxy construction starts from a broad inbound header snapshot. Until strict per-target allowlists are implemented, strip unrelated cookies, proxy authorization, CSRF values, and customer secrets at ingress; call only approved targets and assert the exact destination headers in tests. The SDK strips its RTG platform token and replaces session credentials, but that is not a general header allowlist.
- Destination URL allowlisting is application-owned. Public proxy helpers do not enforce a complete HTTPS host allowlist or prevent DNS rebinding. Endpoints must be static trusted configuration, never user/model output; review environment-proxy behavior as well.
- Some async proxy paths block for PDP. Agent/API/MCP async calls perform synchronous token enrichment before downstream async I/O. Load-test event loop latency and use bounded concurrency.
- Logs are sensitive. The SDK eagerly creates a non-rotating file handler. INFO can include service/action/resource/tool names, paths, and URLs; explicit TRACE can additionally include redacted business bodies, prompts, history, arguments, and responses. Use WARNING in production where possible, protect the file, rotate/retain it deliberately, and do not treat heuristic redaction as removal of all customer data.
- Framework boundaries are specific. Whole-app middleware skips
GET/HEAD/OPTIONS. Protected MCP stdio is rejected; prefer static streamable HTTPS. Legacy SSE requires live same-origin/security testing, and WebSocket is unsupported. Slow MCP initialization can consume encrypted transaction-token TTL; PDP, not the SDK's local three-part-JWT check, is authoritative for the five-part JWE expiry. - Context does not authorize detached work. A detached task can inherit
ContextVaridentity, token, and history. Enqueue sanitized data and start a fresh authenticatedstandalone_work_itemrather than launching detached protected business work from a request. - CrewAI factories execute before their PDP check. Keep construction pure: no network call, write, or tool side effect in a factory body. Keep required return annotations and test against the pinned framework version.
- Guardrail outage behavior is server policy. Verify the effective
synchronous
decisionMakerand its failure mode for every ENFORCE template; SDK exception names do not prove that evaluator outage is fail closed. - The optional top-level
ainame is not an invocation API.reva_ai.sdk.ai.aimay beNone; use the documented decorators, proxies, and adapters.
No SDK can guarantee an error-free or universally secure deployment. Customer readiness requires the actual gateway, broker, policy store, PDP/RTG versions, framework versions, endpoints, logs, and data-handling controls to pass the acceptance tests below.
Acceptance checklist
Before customer handoff, prove in the deployed environment:
- Missing/invalid credentials deny before customer code runs.
- Cedar allow and deny policies work for exact registered IDs and schema keys.
For direct
/ai/evaluation, prove the gateway/service boundary prevents an untrusted caller from selectingsubject,principal, orpolicyStoreId, and that the API credential is tenant-scoped. The endpoint does not perform that binding itself. - Direct
cedar_contextand nested/indexedcedar_context_mapvalues reach Issue Token, win over same-name business keys, cannot override server-owned identity/intent, remain absent from the downstream body, and reach Validate Token through the authenticated transaction-token claim; missing, null, protected, or colliding mapper configuration fails before PDP, and a forged downstream body value cannot replace token-bound context. Exact and over-limit checks pass at 512-byte context, 4,096-byte compact-token, and 6,144-byte complete-PDP-header boundaries; all three PDP body shapes pass at the exact 1,048,576-byte compact UTF-8 boundary and fail above it; canonical external-guardrail JSON passes at 262,144 bytes and fails above it before any HTTP attempt. Keep PDPPDP_AI_REQUEST_BODY_MAX_BYTES=1048576so its configured streamed-body limit matches the SDK's fixed preflight. - Agent → Agent and Agent → MCP chains preserve principal, current prompt, originating history, canonical resource ID, thread ID, and trace ID; exact 32-event history passes and 33 events, excessive depth/value/string/byte counts, cycles, and non-finite data fail without truncation.
- A PDP deny never triggers a fallback call; an unavailable failure is typed separately.
- Protected MCP is the default, credentials remain off tool arguments, and strict tool schemas accept the call.
- Worker ingress is authenticated and PDP-authorized before business work; consecutive items cannot see one another's token/history/context.
- The exact lab-review → medication-order regression denies at authoritative score, while approved retrieval/format/order substeps remain aligned.
- Logs, traces, safe HTTP error details, and final-turn behavior satisfy the customer's data-handling requirements; final-turn delivery uses the exact RTG HTTPS origin and tested overload/drop behavior.
- The tested wheel hash and all compatible platform versions are recorded.
License
Proprietary — © Reva AI, Inc. All rights reserved. Use requires a valid commercial agreement with Reva. See LICENSE or contact legal@reva.ai.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file reva_ai_authz-1.0.3.tar.gz.
File metadata
- Download URL: reva_ai_authz-1.0.3.tar.gz
- Upload date:
- Size: 153.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b0d8831a9b237c43817881dd4a0a6b7b30abf9932e2f3cd4d5c7c2c0898fba65
|
|
| MD5 |
84e0295ec7724dca1ad4a6d00e821874
|
|
| BLAKE2b-256 |
45bc2e986b2e9aae8aa49c2cb406d853452dcbb1ae61f8f06de76e775013a8ef
|
File details
Details for the file reva_ai_authz-1.0.3-py3-none-any.whl.
File metadata
- Download URL: reva_ai_authz-1.0.3-py3-none-any.whl
- Upload date:
- Size: 148.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3fdcbaa92e1091fc21b706a145db30287f7638e35d03056c49399f003d952825
|
|
| MD5 |
b42f15e9b5e13f46648ab044894eddde
|
|
| BLAKE2b-256 |
82a059f7432be8f41b5e4e018a43a95f2cde1812d4914842c334172c70bf6508
|