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 requireslevel >= 2.- the temporal leaf — a
Loginfor the same server occurred within the last hour.
The trace exercises every combination:
@0— aLogin(not anAlert; no permit rule applies) → DENY.@10—Alertlevel 3 ons1, with a recent login ons1→ ALLOW (both conjuncts true).@20—Alertlevel 1 ons1→ DENY (macro conjunct false:1 < 2).@30—Alertlevel 5 ons2, no login ons2→ DENY (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