cedar_semver_gt
The RFC 0061 semver worked example for Cedar macros: a record-building macro
(semver, which constructs a { major, minor, patch } record) passed as an
argument to a comparator macro (semverGT). Nesting one macro call as an
argument to another is allowed — the compiler expands call arguments first,
then splices the result into the outer macro’s body.
Both macros are declared inline in policy.dw. The rule uses constant
arguments and a bare action scope, so it validates against the Drupe
schema (copied from write_after_read) with no event history.
Referenced by guide/06-macros.md.
Policy
// RFC 0061 worked example: `semver` builds a { major, minor, patch }
// record that `semverGT` compares. Nesting one macro call as an argument
// to another is allowed (call arguments are expanded first).
def cedar semver(?major, ?minor, ?patch) {
{ major: ?major, minor: ?minor, patch: ?patch }
};
def cedar semverGT(?a, ?b) {
if ?a.major == ?b.major
then (if ?a.minor == ?b.minor then ?a.patch > ?b.patch else ?a.minor > ?b.minor)
else ?a.major > ?b.major
};
@id("semver_gt_constant")
permit (principal, action, resource)
when { semverGT(semver(2, 1, 1), semver(2, 1, 0)) };
Schema
namespace Drupe {
type ApproveSaleInput = {
shares: Long,
stock: String
};
type ApproveSaleOutput = {
approved: Bool
};
type ContentFilterFinding = {
severityScore: decimal
};
type GetStockInfoInput = {
stock: String
};
type GetStockInfoOutput = {
info: String
};
type PromptAttackFinding = {
severityScore: decimal
};
type SellSharesInput = {
shares: Long,
stock: String
};
type SellSharesOutput = {
proceeds: decimal
};
type SensitiveInfoFinding = {
confidenceScore: decimal
};
type SystemContext = {
now: datetime
};
entity Gateway;
entity IamEntity = {
id: String
};
entity OAuthUser = {
id: String
} tags String;
entity UnauthenticatedUser;
action "ApproveSale" in [Action::"CallTool"] appliesTo {
principal: [IamEntity, OAuthUser, UnauthenticatedUser],
resource: [Gateway],
context: {
input: ApproveSaleInput,
output?: ApproveSaleOutput,
system: SystemContext
}
};
action "CallTool" in [Action::"Mcp"] appliesTo {
principal: [OAuthUser, IamEntity, UnauthenticatedUser],
resource: [Gateway],
context: {
system: SystemContext
}
};
action "GetStockInfo" in [Action::"CallTool"] appliesTo {
principal: [IamEntity, OAuthUser, UnauthenticatedUser],
resource: [Gateway],
context: {
input: GetStockInfoInput,
output?: GetStockInfoOutput,
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 "Mcp" appliesTo {
principal: [OAuthUser, IamEntity, UnauthenticatedUser],
resource: [Gateway],
context: {
system: SystemContext
}
};
action "SellShares" in [Action::"CallTool"] appliesTo {
principal: [IamEntity, OAuthUser, UnauthenticatedUser],
resource: [Gateway],
context: {
input: SellSharesInput,
output?: SellSharesOutput,
system: SystemContext
}
};
action "UnknownTool" in [Action::"CallTool"] appliesTo {
principal: [OAuthUser, IamEntity, UnauthenticatedUser],
resource: [Gateway],
context: {
system: SystemContext
}
};
}