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

call_cedar_macros_composed

Two Cedar macros composed with && in one when { … } clause: is_eligible(context.input.shares, context.input.stock) && is_not_blocked(context.input.stock). Both macros are defined in the macro library (macros.dw) and loaded via --macros; each is called with a different argument shape (a Long and a String), showing that ?p literal-splicing carries call-site types through.

Validate with:

dogwood validate policy.dw --policy-schema schema.cedarschema --macros macros.dw

Referenced by guide/09-calling-macros.md.

Policy

// Two `def cedar` macros composed with `&&` in one `when` clause.
// Both are defined in the macro library (macros.dw); each is called
// with a different argument shape (Long, String).
@id("sell_eligible_unblocked")
permit (principal, action == Drupe::Action::"SellShares", resource)
when {
    is_eligible(context.input.shares, context.input.stock)
    && is_not_blocked(context.input.stock)
};

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
    }
  };
}

Macros

// Macro library: two reusable `def cedar` fragments composed by policy.dw.
//
// `is_eligible` takes a Long (?shares) and a String (?stock); `is_not_blocked`
// takes a String (?stock). Each is called with a different argument shape,
// proving ?p literal-splicing carries call-site types through.
def cedar is_eligible(?shares, ?stock) {
    ?shares < 100 || ?stock == "FOO"
};

def cedar is_not_blocked(?stock) {
    !(?stock == "BLOCKED")
};