Where policies run The Policy Gateway evaluates Cedar policies before every governed tool call. The model never sees the policy text — it cannot reason its way around a rule it never receives. This is the structural difference from prompt-stated guardrails: enforcement is not a suggestion.
The artifact: public_sources_only This is the production policy, verbatim, governing web access in the company research skill. It implements one boundary: public information only.
// ============================================================// public_sources_only — Policy 1: Public Information Only// Auth-walled / login-required / ToS-restricted domains are// blocked from SCRAPE and FETCH. Searching ABOUT these sources// stays permitted — search engines index their public snippets;// only direct scraping (which requires credentials or violates// ToS) is gated.// Structural half of Policy 1: no tool in this workflow accepts// credentials — the registry itself makes authenticated access// impossible. This module handles the domain boundary.// x.com is pattern-anchored (://x.com/) so box.com and// dropbox.com are NOT blocked — the substring collision trap.// GOVERNED TOOLS: firecrawl_scrape ONLY. web_fetch_exa takes// 'urls' (a LIST) — Cedar cannot inspect list elements, so no// deterministic per-URL gate exists for that tool; page reads// must route through firecrawl_scrape (dynamic mode, one URL// per item) for the domain boundary to apply.// ============================================================forbid( principal, action == Action::"firecrawl_scrape", resource)when { context.payload.url like "linkedin." || context.payload.url like "facebook." || context.payload.url like "instagram." || context.payload.url like "glassdoor." || context.payload.url like "crunchbase." || context.payload.url like "wellfound." || context.payload.url like "angellist." || context.payload.url like "twitter." || context.payload.url like "://x.com/" || context.payload.url like "://www.x.com/"};// PERMIT: normal public web URLs (has-guard: missing url fails closed)permit( principal, action == Action::"firecrawl_scrape", resource)when { context.payload has url && context.payload.url like "http*"}; Reading the policy, line by line The forbid block Cedar evaluates forbid with precedence over permit — if any forbid clause matches, the call is denied regardless of permits. Each like pattern blocks a family of auth-walled domains: LinkedIn, Facebook, Instagram, Glassdoor, Crunchbase, Wellfound, AngelList, Twitter.
The pattern anchoring trap context.payload.url like "://x.com/" Note this pattern is anchored with the scheme and path — ://x.com/. A naive substring check for x.com would also block box.com and dropbox.com, because they contain x.com as a substring. This is the substring collision trap, and it is why each domain gets an explicit, anchored pattern instead of a loose one.
The fail-closed has-guard context.payload has url &&context.payload.url like "http*" The permit requires the payload to have a url field before matching it. If the field is missing, the has check fails, the permit does not apply, and the call is denied by default. Policies fail closed — a malformed payload can never fall through to allowed.
The structural half: no credentials exist The comment marks the second half of the policy: no tool in this workflow accepts credentials at all. The tool registry makes authenticated access structurally impossible — there is no username/password parameter on any governed tool to misuse. The domain boundary (this policy) and the capability boundary (the registry) combine into a boundary the model cannot talk its way past.
The honest constraint: list parameters The comment also records a real limitation. web_fetch_exa takes urls — a list — and Cedar cannot inspect individual list elements. There is no deterministic per-URL gate for that tool. So the rule is: page reads route through firecrawl_scrape (one URL per item, dynamic mode), where the domain boundary does apply. Constraints like this are documented in the policy itself rather than hidden — the registry page lists which tools are governed per action.
What the model sees Nothing. The model asks for a scrape of a URL; the gateway evaluates the policy; blocked URLs return a policy denial the engine records in the evidence ledger. The model can ask about LinkedIn — searching about a company on LinkedIn-indexed snippets stays permitted. Only direct scraping is gated.
Writing a new policy Three rules hold for every Cedar policy in the registry:
Fail closed. Every permit requires positive has guards on the fields it matches. Missing data denies. Anchor patterns. Never use a bare domain substring match — anchor with scheme or path delimiters so sibling domains don't collide. Declare the governed surface. The policy header lists exactly which tool actions it governs. A policy that isn't attached to a concrete action is documentation, not enforcement.
