Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

cedar_macro_plus_temporal_leaf

A def cedar boolean macro (level_ok) conjoined mid-expression with an inline temporal { … } leaf. The Cedar macro is expanded before the surrounding expression is lowered (which hoists the temporal leaf). The guide shows a temporal { /* ... */ } placeholder; here it is promoted to a concrete recent-login leaf: formerly within 1h ...Login..., pinned to the same server via input.server: context.input.server.

The policy permits Alert only when both conjuncts hold:

  • level_ok(context.input.level) — the Cedar macro requires level >= 2.
  • the temporal leaf — a Login for the same server occurred within the last hour.

The trace exercises every combination:

  • @0 — a Login (not an Alert; no permit rule applies) → DENY.
  • @10Alert level 3 on s1, with a recent login on s1ALLOW (both conjuncts true).
  • @20Alert level 1 on s1DENY (macro conjunct false: 1 < 2).
  • @30Alert level 5 on s2, no login on s2DENY (temporal conjunct false: server mismatch).

Referenced by guide/06-macros.md.

Policy

// A Cedar macro conjoined with a temporal block mid-expression: the Cedar
// macro `level_ok` is expanded BEFORE the surrounding expression is lowered
// (which hoists the temporal leaf). Guide shows a `temporal { /* ... */ }`
// placeholder; promoted here to a concrete recent-login leaf.
def cedar level_ok(?n) { ?n >= 2 };

@id("alert_level_and_recent_login")
permit (
    principal,
    action == Drupe::Action::"Alert",
    resource
)
when {
    level_ok(context.input.level)
    && temporal {
        formerly within 1h Drupe::Action::"Login"::request{
            input.user: _, input.server: context.input.server
        }
    }
};

Schema

namespace Drupe {
  type AlertInput = {
    level: Long,
    server: String
  };

  type AlertOutput = {  };

  type ContentFilterFinding = {
    severityScore: decimal
  };

  type LoginInput = {
    server: String,
    user: String
  };

  type LoginOutput = {  };

  type PromptAttackFinding = {
    severityScore: decimal
  };

  type SensitiveInfoFinding = {
    confidenceScore: decimal
  };

  type SystemContext = {
    now: datetime
  };

  entity Gateway;

  entity IamEntity = {
    id: String
  };

  entity OAuthUser = {
    id: String
  } tags String;

  entity UnauthenticatedUser;

  action "Alert" in [Action::"CallTool"] appliesTo {
    principal: [IamEntity, OAuthUser, UnauthenticatedUser],
    resource: [Gateway],
    context: {
      input: AlertInput,
      output?: AlertOutput,
      system: SystemContext
    }
  };

  action "CallTool" in [Action::"Mcp"] appliesTo {
    principal: [OAuthUser, IamEntity, UnauthenticatedUser],
    resource: [Gateway],
    context: {
      system: SystemContext
    }
  };

  action "Http" appliesTo {
    principal: [OAuthUser, IamEntity, UnauthenticatedUser],
    resource: [Gateway],
    context: {
      system: SystemContext
    }
  };

  action "InvokeAgent" in [Action::"Http"] appliesTo {
    principal: [OAuthUser, IamEntity, UnauthenticatedUser],
    resource: [Gateway],
    context: {
      input?: {      },
      system: SystemContext
    }
  };

  action "InvokeLLM" in [Action::"Http"] appliesTo {
    principal: [OAuthUser, IamEntity, UnauthenticatedUser],
    resource: [Gateway],
    context: {
      input?: {      },
      system: SystemContext
    }
  };

  action "Login" in [Action::"CallTool"] appliesTo {
    principal: [IamEntity, OAuthUser, UnauthenticatedUser],
    resource: [Gateway],
    context: {
      input: LoginInput,
      output?: LoginOutput,
      system: SystemContext
    }
  };

  action "Mcp" appliesTo {
    principal: [OAuthUser, IamEntity, UnauthenticatedUser],
    resource: [Gateway],
    context: {
      system: SystemContext
    }
  };

  action "UnknownTool" in [Action::"CallTool"] appliesTo {
    principal: [OAuthUser, IamEntity, UnauthenticatedUser],
    resource: [Gateway],
    context: {
      system: SystemContext
    }
  };
}

Trace

@0 scope(principal: Drupe::OAuthUser::"alice", resource: Drupe::Gateway::"gw1") request_context(input: { server: "s1", user: "alice" }) Drupe::Action::"Login"::request(input: { server: "s1", user: "alice" }, callerPrincipal: Drupe::OAuthUser::"alice", callerResource: Drupe::Gateway::"gw1", requestId: "u1")
@10 scope(principal: Drupe::OAuthUser::"alice", resource: Drupe::Gateway::"gw1") request_context(input: { level: 3, server: "s1" }) Drupe::Action::"Alert"::request(input: { level: 3, server: "s1" }, callerPrincipal: Drupe::OAuthUser::"alice", callerResource: Drupe::Gateway::"gw1", requestId: "u2")
@20 scope(principal: Drupe::OAuthUser::"alice", resource: Drupe::Gateway::"gw1") request_context(input: { level: 1, server: "s1" }) Drupe::Action::"Alert"::request(input: { level: 1, server: "s1" }, callerPrincipal: Drupe::OAuthUser::"alice", callerResource: Drupe::Gateway::"gw1", requestId: "u3")
@30 scope(principal: Drupe::OAuthUser::"alice", resource: Drupe::Gateway::"gw1") request_context(input: { level: 5, server: "s2" }) Drupe::Action::"Alert"::request(input: { level: 5, server: "s2" }, callerPrincipal: Drupe::OAuthUser::"alice", callerResource: Drupe::Gateway::"gw1", requestId: "u4")

Expected Output

@0 (time point 0): DENY
@10 (time point 1): ALLOW  [rules: 0]
@20 (time point 2): DENY
@30 (time point 3): DENY