Skip to Content
Platform
BuildPolicy rails

Policy rails

Rules the agent cannot argue with. The egress checks every request to a connector against your recipe’s Cedar policies before it is signed or sent.

A recipe can ship policy rails: Cedar  rules for what its agent may do at a connector’s API. The platform’s egress evaluates them on every request to a connector host, outside the sandbox, so the agent can neither skip them nor change what they read.

Cedar decidesWhat happens
denyThe agent gets 403 application/problem+json of type …/problems/policy-denied, with the rule’s @id and @reason. Nothing is signed or sent, and no one is asked to approve.
allowThe request goes on to the connector, which still decides: for AAuth, the person’s Person Server.

A rail never grants more than the connector allows. Use rails for what holds for every customer, such as “never book first class”; leave each customer’s own limits and approvers to their Person Server.

You need: a recipe (Create a recipe) with a connector its agent calls.

Add rails to a recipe

policies/ schema.cedarschema # the entities and actions your rules see *.cedar # the rules routes.yaml # which requests become which Cedar action and resource
  1. Map each connector’s requests to Cedar in policies/routes.yaml, keyed by the connector’s slug:
    booking: - method: POST path: /v1/reserve # exact, or a prefix ending in * action: booking.reserve context: [mission] # the session's approved AAuth mission resource: type: Booking attribute_map: # JSON pointers into the request body purpose: /purpose payer: /payer claims: # claims of a signed token in the body from: /quote attributes: [cabin, total_cents]
  2. Declare the entities and actions in policies/schema.cedarschema.
  3. Write the rules. @id names a rule; @reason is what the agent is told:
    @id("no-first-class") @reason("first class is never booked: quote business or economy instead") forbid (principal, action == Action::"booking.reserve", resource) when { resource has cabin && resource.cabin == "first" };
  4. Commit and push. The recipe check validates the schema, routes and rules; a bad bundle marks the recipe invalid instead of reaching a runtime.

Validate locally with the Cedar CLI:

cargo install cedar-policy-cli --locked cat policies/*.cedar > /tmp/policyset.cedar cedar validate --schema policies/schema.cedarschema --policies /tmp/policyset.cedar

What a rule can read

InputComes fromWho can change it
The rules, schema and routesThe recipe at the commit the runtime was built fromA commit and a deploy
principalThe attributes on the member the session acts for (policy_attributes)An organization owner (members:manage)
Entities such as a CompanyThe connector’s policy_entitiesWhoever manages the connector
resourceThe request body, through routes.yamlThe agent, for the one request it sends
context.missionThe session’s approved AAuth missionThe person’s Person Server, by approving it
context.judgementA judge’s answers about the request (below)Nobody: it is computed outside the sandbox

Set a member’s attributes when you create or update them:

{ "policy_attributes": { "level": 5, "company": { "__entity": { "type": "Company", "id": "acme" } } } }

Claims read from a token in the body are not verified at the egress; the provider that signed the token checks it again and acts only on what it signed, so a forged one gains nothing.

Ask a judge about intent

Cedar cannot tell whether a booking is what the person asked for. A route can name a judge that answers questions about the request against the person’s own words, before Cedar decides:

# judges/booking.yaml name: booking type: mission attributes: [city, check_in, check_out, total_cents] questions: requested: instructions: Is the booking something the traveller asked for, or a natural part of that trip? criteria: { "true": The same destination and dates., "false": Anything else. }

Each question is a noul : a yes-or-no decision rule with instructions and criteria for each answer, as Jev decision models take them. By default the platform asks Jev, through the session’s managed inference, so a judge needs no key of its own.

Add judge: booking and judgement to the route’s context, and each answer reaches Cedar as a percentage, such as context.judgement.requested. The person’s words are recorded as they arrive and are never readable or writable from the sandbox.

Fails closed

The gate denies when it cannot decide: rules or entities that do not validate, a body that is not JSON, a claim that is missing, or a session it cannot read. A request to a connector host that routes.yaml names, matching none of its routes, is denied too. A recipe with no routes.yaml ships no rails, and its Cedar files are ignored.

Rails run on data planes with the policy gate turned on; ask us to enable it for yours.

Example

The travel agent recipe  refuses a booking outside an approved trip, first class, business class below the company’s seniority, and a personal booking on the company’s account, with two judges reading what the traveller asked for.

Last updated on