Skip to content
Ironflow is pre-1.0: APIs can change between releases. Pin a version. What is ready →

Policy set input

Every evaluation of a policy set gets one input document. The document has two views. This page lists every field. The published JSON schema has the same fields. ironflow policy pull writes it to .ironflow/input.schema.json.

The native view is present for every check.

FieldTypeMeaning
actionstringThe verb, for example functions:invoke, orgs:manage, runs:read. It is the action that the route maps to, not the resource name in the URL. Every non-GET write on /api/v1/policy-set has orgs:manage.
resourcestringThe IRN of the resource, for example irn:ironflow:org_acme:proj_default:function:env_default:fn_payments. It is an empty string when the check has no resource. A ConnectRPC call at the route gate has an empty resource. For events:emit on a user emit, it is the event IRN irn:ironflow:{org}:{project}:event:{env}:{name}. Raw event names and invoked function IDs are encoded once: % becomes %25, then : becomes %3A. The resource is compared without percent-decoding.
environmentstringThe environment ID (for example env_default), not its name.
org_idstringThe organization of the caller.

The shape is the same for API-key callers and for dashboard (JWT) callers.

FieldTypeMeaning
idstringThe user ID (user_...). Empty for a raw API key.
user_emailstringThe email of the user. Empty for a raw API key without a bound user.
rolesarray of stringsThe role names of the caller. Always an array, never null.
groupsarray of stringsThe group memberships. Always an array, never null. It is empty today.
orgstringThe home organization of the caller.
projectstringThe home project of the caller.
envstringThe home environment of the caller.
api_key_idstringThe key ID (ak_...) for an API-key caller. Empty otherwise.
is_platformbooleanTrue for a platform principal.
webhook_source_idstringThe webhook source ID for an event that a webhook delivery emits. Empty otherwise. Such a subject has no role and may only do events:emit.

The Envoy view is present when the check is for an HTTP request: the pre-route gate for every HTTP and ConnectRPC request. Handler-side checks, such as the impersonation check, have no HTTP request and carry the native view only. The view copies the input of the OPA-Envoy plugin.

FieldTypeMeaning
input.attributes.request.http.methodstringThe HTTP method.
input.attributes.request.http.pathstringThe path with the raw query string. The path is the one that the router acts on. It is normalized, and percent-decoding is applied as the router applies it. The token query parameter is removed.
input.attributes.request.http.hoststringThe Host of the request.
input.attributes.request.http.schemestringhttp or https.
input.attributes.request.http.headersobjectHeader values by lower-case name. A header with many values is joined with a comma. The pseudo-headers :method, :path and :authority are present, as in Envoy.
input.parsed_patharray of stringsThe path without the query, split on /, with a leading / removed. Each segment is percent-decoded. An encoded slash stays inside its segment.
input.parsed_queryobjectEach query key maps to an array of values. The token key is removed.
  • Headers. These headers never enter input: authorization, proxy-authorization, cookie, set-cookie, ironflow-lease-token, x-api-key and sec-websocket-protocol. The last one carries the bearer token of the WebSocket client. A policy can copy any input value into a deny reason, and reasons reach the audit log, so credentials must not be in input.
  • The token query parameter. It is a legacy bearer credential and the webhook ingest token. Ironflow removes it from path and parsed_query. If the query does not parse, Ironflow drops the whole query.
  • The body. input.attributes.request.http.body and input.parsed_body are absent. Ironflow does not buffer bodies, because that would break file uploads and streaming.
  • Source and destination. input.attributes.source and input.attributes.destination are absent.

A policy that decodes the bearer token itself needs an adapter that reads input.subject. See Run an Envoy policy.

This document is the input for a runs:read check from a dashboard user. The test suite uses it as a golden input.

{
"request": {"action": "runs:read", "resource": "irn:ironflow:o:p:run:e:*", "environment": "env_default", "org_id": "org_test"},
"subject": {"id": "u1", "user_email": "a@example.test", "roles": ["admin"], "groups": [], "org": "org_test", "project": "", "env": "", "api_key_id": "", "webhook_source_id": "", "is_platform": false},
"attributes": {"request": {"http": {
"method": "GET", "path": "/api/v1/runs/run_1?expand=steps", "host": "ironflow.example.test", "scheme": "https",
"headers": {"x-request-id": "r-1", ":method": "GET", ":path": "/api/v1/runs/run_1?expand=steps", ":authority": "ironflow.example.test"}
}}},
"parsed_path": ["api", "v1", "runs", "run_1"],
"parsed_query": {"expand": ["steps"]}
}

A dry-run takes the same document. It must have an input.request object and an input.subject object. It evaluates the decision rule of the set only when the document has an attributes key. Without it, the dry-run behaves like a handler-side check and evaluates deny only.

The server type-checks rules in package ironflow.authz against the schema when you write a set. A rule that treats a string field as a number fails with policy_set_schema_error. Other packages are not checked. They are your own policies, for your own input shape.