From a873f4d8cfc278c6a16ac888742a6e75423506bc Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Tue, 1 Sep 2026 21:02:37 +0000 Subject: [PATCH] feat(function-resolution): port the route-validated invocation surface from constructive-db Adds function_resolution.create_invocation (the one request-role insert surface for a sync invocation, with route-validated anonymous access) and its grants, and teaches install_route_bindings to install the typed routes.anonymous column. --- .../procedures/create_invocation.sql | 358 ++++++++++++++++++ .../grant_execute_create_invocation.sql | 17 + .../procedures/install_route_bindings.sql | 15 +- packages/function-resolution/pgpm.plan | 2 + .../procedures/create_invocation.sql | 7 + .../grant_execute_create_invocation.sql | 10 + ...-function-resolution--0.44.0.bundle.tar.gz | Bin 40460 -> 46284 bytes .../sql/pgpm-function-resolution--0.44.0.sql | 300 ++++++++++++++- .../procedures/create_invocation.sql | 7 + .../grant_execute_create_invocation.sql | 8 + 10 files changed, 716 insertions(+), 8 deletions(-) create mode 100644 packages/function-resolution/deploy/schemas/function_resolution/procedures/create_invocation.sql create mode 100644 packages/function-resolution/deploy/schemas/function_resolution/procedures/grants/grant_execute_create_invocation.sql create mode 100644 packages/function-resolution/revert/schemas/function_resolution/procedures/create_invocation.sql create mode 100644 packages/function-resolution/revert/schemas/function_resolution/procedures/grants/grant_execute_create_invocation.sql create mode 100644 packages/function-resolution/verify/schemas/function_resolution/procedures/create_invocation.sql create mode 100644 packages/function-resolution/verify/schemas/function_resolution/procedures/grants/grant_execute_create_invocation.sql diff --git a/packages/function-resolution/deploy/schemas/function_resolution/procedures/create_invocation.sql b/packages/function-resolution/deploy/schemas/function_resolution/procedures/create_invocation.sql new file mode 100644 index 00000000..fe399db3 --- /dev/null +++ b/packages/function-resolution/deploy/schemas/function_resolution/procedures/create_invocation.sql @@ -0,0 +1,358 @@ +-- Deploy schemas/function_resolution/procedures/create_invocation to pg +-- requires: schemas/function_resolution/schema +-- requires: schemas/function_resolution/procedures/resolve +-- requires: schemas/function_resolution/procedures/definitions_location +-- requires: metaschema-modules:schemas/metaschema_modules_public/tables/function_invocation_module/table +-- requires: metaschema-modules:schemas/metaschema_modules_public/tables/route_module/table +-- requires: pgpm-app-scope:schemas/app_scope/procedures/frames +-- requires: pgpm-app-scope:schemas/app_scope/procedures/routing_tables +-- requires: pgpm-jwt-claims:schemas/jwt_private/procedures/require_database_id +-- requires: pgpm-jwt-claims:schemas/jwt_public/procedures/current_user_id + +BEGIN; + +-- create_invocation: the one sanctioned way a REQUEST-role session opens a +-- ledger row for a sync invocation. +-- +-- The sync gateway inserts the invocation under the caller's own role — +-- authenticated when the request carries an identity, anonymous when it does +-- not — because a request's ledger row is the request's own write and no +-- gateway should hold a general RLS bypass. Every SSO lane starts pre-login +-- (the session probe, the sign-in/sign-up pages), so "anonymous" is an ordinary +-- request shape here, not an exception. But an invocations plane grants INSERT +-- to authenticated only, and its permissive arm additionally wants app-admin +-- membership, so both the anonymous lanes AND ordinary signed-in callers are +-- locked out of their own ledger. +-- +-- Rather than widen the table (a broad anonymous policy, or a bypass role that +-- can write any row anywhere), this follows the platform's existing pre-login +-- precedent — authenticate / sign_in_identity / sign_up_identity are SECURITY +-- DEFINER functions granted to anonymous — and makes the WRITE itself the +-- narrow surface: one row, in the addressed database's own invocations plane, +-- for a task that database's frames actually publish on the sync channel, and +-- for an anonymous caller only when the definition DECLARES itself callable +-- without an identity and the route it arrived through DECLARES itself +-- anonymous. +-- +-- What is checked, in order, all of it fail-loud: +-- +-- 1. the session's database claim IS the addressed database — a SECURITY +-- DEFINER function is RLS-exempt, so this is the tenant boundary and it is +-- checked first, not inferred from a policy that no longer applies; +-- 2. the task resolves to a definition across that (database, scope, entity) +-- frame chain — an unpublished or unknown task never reaches the ledger; +-- 3. the winning definition declares the sync channel (access_channels), read +-- from its OWN home plane, which is transport eligibility; +-- 4. anonymous callers additionally prove authorization, twice over: the +-- winning definition declares anonymous_callable — the code consenting to +-- run for a caller carrying no identity — and the route binding the +-- gateway resolved this request through exists on the routes plane serving +-- that scope, is active, targets THAT definition, is owned by the same +-- key, and declares anonymous access. Neither half opens anything alone: a +-- route cannot publish a definition that never consented, and a consenting +-- definition is still only reachable at a URL that says so. +-- access_channels is neither half — it says a lane may carry the call, +-- never who may make it — and the route id is validated here rather than +-- trusted from the caller. +-- +-- The row is then inserted into the plane the module registration names, keyed +-- by the column that registration records (entity_field, stamped at +-- provisioning by metaschema_generators.scope_key_column): the database itself +-- at database scope, the owning entity at an entity scope, no key column at a +-- global scope. Actor/entity attribution is NOT accepted as an argument and NOT +-- stamped here — identity rides the transaction, and the plane's own BEFORE +-- INSERT trigger fills actor_id / principal_id / entity_id / entity_type from +-- the claims and asserts attribution, exactly as it does for every other +-- ingress path. That trigger also resolves and stamps the winning +-- (function_definition_id, definition_scope) pair, which is returned so the +-- caller settles the same row it opened. +-- +-- The dynamic SQL is install_route_bindings' case: every relation is named by a +-- module registration and proved to exist by an ordinary catalog join first, +-- and no value is ever interpolated — only verified relation and column names. +CREATE FUNCTION function_resolution.create_invocation( + database_id uuid, + scope text, + task_identifier text, + payload jsonb DEFAULT '{}'::jsonb, + channel text DEFAULT 'sync', + provenance jsonb DEFAULT '{}'::jsonb, + route_binding_id uuid DEFAULT NULL, + entity_id uuid DEFAULT NULL +) RETURNS TABLE ( + id uuid, + created_at timestamptz, + started_at timestamptz, + function_definition_id uuid, + definition_scope text +) AS $$ +DECLARE + -- The invocations plane this row lands in, and the scope-key column its + -- registration records (NULL at a global scope). + invocations_schema text; + invocations_table text; + invocations_key text; + -- One key value for the write: the database itself at database scope, the + -- owning entity at an entity scope, NULL at a global scope. + key_value uuid; + -- The winning definition and where it lives, from the same resolver every + -- other ingress path uses. + v_definition_id uuid; + v_definition_scope text; + v_definition_database_id uuid; + definitions_schema text; + definitions_table text; + sync_callable boolean; + -- The definition's own consent to run for a caller with no identity, read + -- from the same plane as its channels. + anonymous_callable boolean; + -- The routes plane serving this scope, and its own recorded ownership key, + -- for the anonymous route check. + routes_schema text; + routes_table text; + routes_key text; + route_authorized boolean; + query text; +BEGIN + IF create_invocation.database_id IS NULL THEN + RAISE EXCEPTION 'INVOCATION_DATABASE_REQUIRED: database_id is required' + USING ERRCODE = 'FR070'; + END IF; + + -- Hard contract, matching enqueue and app_scope: the execution scope is + -- known at the call site and never silently defaulted. + IF create_invocation.scope IS NULL THEN + RAISE EXCEPTION 'INVOCATION_SCOPE_REQUIRED: scope is required (no default scope)' + USING ERRCODE = 'FR070'; + END IF; + + IF coalesce(create_invocation.task_identifier, '') = '' THEN + RAISE EXCEPTION 'INVOCATION_TASK_REQUIRED: task_identifier is required' + USING ERRCODE = 'FR070'; + END IF; + + -- This surface exists for the request lanes that cannot write the table + -- directly. Every other channel already has a trusted path (the worker's + -- own role, the api binding's policy arm, the graph/cron triggers), so a + -- caller naming one here would be claiming a provenance it does not have. + IF create_invocation.channel IS DISTINCT FROM 'sync' THEN + RAISE EXCEPTION 'INVOCATION_CHANNEL_UNSUPPORTED: create_invocation opens sync invocations only, got %', + coalesce(create_invocation.channel, '') + USING ERRCODE = 'FR070'; + END IF; + + -- 1. The tenant boundary. SECURITY DEFINER means RLS does not hold it, so + -- it is an explicit check against the session's own database claim + -- (require_database_id raises when the session established none). + IF jwt_private.require_database_id() <> create_invocation.database_id THEN + RAISE EXCEPTION 'INVOCATION_DATABASE_MISMATCH: session is claimed to database % and cannot open an invocation in %', + jwt_private.require_database_id(), create_invocation.database_id + USING ERRCODE = 'FR071'; + END IF; + + -- The plane, from the registration for exactly this (database, scope). No + -- probing of neighbouring scopes: the caller's scope is explicit. + SELECT s.schema_name, t.name, fim.entity_field + INTO invocations_schema, invocations_table, invocations_key + FROM metaschema_modules_public.function_invocation_module AS fim + JOIN metaschema_public."table" AS t ON t.id = fim.invocations_table_id + JOIN metaschema_public.schema AS s ON s.id = t.schema_id + WHERE fim.database_id = create_invocation.database_id + AND fim.scope = create_invocation.scope; + + IF invocations_schema IS NULL THEN + RAISE EXCEPTION 'INVOCATION_MODULE_NOT_PROVISIONED: database % has no function_invocation_module at scope "%"', + create_invocation.database_id, create_invocation.scope + USING ERRCODE = 'FR072'; + END IF; + + -- The scope key, from the plane's recorded column rather than the scope + -- name: the scope's own key answers "whose ledger", never "who did it". + IF invocations_key IS NULL THEN + key_value := NULL; + ELSIF invocations_key = 'database_id' THEN + key_value := create_invocation.database_id; + ELSE + IF create_invocation.entity_id IS NULL THEN + RAISE EXCEPTION 'INVOCATION_ENTITY_REQUIRED: scope "%" is keyed by %, so entity_id is required', + create_invocation.scope, invocations_key + USING ERRCODE = 'FR070'; + END IF; + key_value := create_invocation.entity_id; + END IF; + + -- 2. The task must resolve, at this (database, scope, entity), to a + -- definition some frame publishes. A definition-less sync request has + -- nothing to authorize and nothing to run. + SELECT r.function_definition_id, r.resolved_scope, r.owner_database_id + INTO v_definition_id, v_definition_scope, v_definition_database_id + FROM function_resolution.resolve( + create_invocation.database_id, + create_invocation.scope, + create_invocation.entity_id, + create_invocation.task_identifier, + false + ) AS r; + + IF v_definition_id IS NULL THEN + RAISE EXCEPTION 'INVOCATION_DEFINITION_NOT_FOUND: no function definition publishes "%" to database % at scope "%"', + create_invocation.task_identifier, create_invocation.database_id, create_invocation.scope + USING ERRCODE = 'FR073'; + END IF; + + -- 3. Sync eligibility, read from the definition's OWN home plane — a + -- platform-declared definition is answered by the platform's + -- definitions table, the same place discovery found it. + IF v_definition_database_id IS NULL THEN + SELECT f.lookup_database_id + INTO v_definition_database_id + FROM app_scope.frames( + create_invocation.database_id, + create_invocation.scope, + create_invocation.entity_id + ) AS f + WHERE f.scope = v_definition_scope + LIMIT 1; + END IF; + + SELECT dl.schema_name, dl.table_name + INTO definitions_schema, definitions_table + FROM function_resolution.definitions_location( + coalesce(v_definition_database_id, create_invocation.database_id), + v_definition_scope + ) AS dl; + + IF definitions_schema IS NULL THEN + RAISE EXCEPTION 'INVOCATION_DEFINITIONS_PLANE_NOT_FOUND: scope "%" of database % has no definitions plane to read channel eligibility from', + v_definition_scope, coalesce(v_definition_database_id, create_invocation.database_id) + USING ERRCODE = 'FR072'; + END IF; + + -- Both definition-side facts in one read: the channel it declares, and + -- whether it consents to run for a caller with no identity. + query := format( + 'SELECT ''sync'' = ANY(d.access_channels), d.anonymous_callable FROM %I.%I AS d WHERE d.id = $1', + definitions_schema, + definitions_table + ); + + -- pgsql-lint-disable-next-line no-dynamic-sql -- lookup-only: the definitions plane is named by its own function_module registration + EXECUTE query INTO sync_callable, anonymous_callable USING v_definition_id; + + IF sync_callable IS NOT TRUE THEN + RAISE EXCEPTION 'INVOCATION_CHANNEL_NOT_DECLARED: definition % does not declare the sync channel', + v_definition_id + USING ERRCODE = 'FR074'; + END IF; + + -- 4. Anonymous authorization. A signed-in caller writing its own ledger row + -- for a sync-eligible task is authorized by being the session it is; an + -- anonymous one has no identity to weigh, so two declarations stand in + -- for it: the definition consents to run without one, and the route it + -- came through exposes it to the public. Both are proved here, against + -- the planes, rather than taken from the caller. + IF jwt_public.current_user_id() IS NULL THEN + IF anonymous_callable IS NOT TRUE THEN + RAISE EXCEPTION 'INVOCATION_ANONYMOUS_NOT_CALLABLE: definition % does not declare anonymous_callable, so "%" cannot run without an identity', + v_definition_id, create_invocation.task_identifier + USING ERRCODE = 'FR075'; + END IF; + + IF create_invocation.route_binding_id IS NULL THEN + RAISE EXCEPTION 'INVOCATION_ANONYMOUS_ROUTE_REQUIRED: an anonymous invocation must name the route binding it arrived through' + USING ERRCODE = 'FR075'; + END IF; + + SELECT r.routes_schema, r.routes_table + INTO routes_schema, routes_table + FROM app_scope.routing_tables(create_invocation.database_id, create_invocation.scope) AS r; + + IF routes_schema IS NULL OR routes_table IS NULL THEN + RAISE EXCEPTION 'INVOCATION_ROUTES_PLANE_NOT_FOUND: scope "%" has no routes plane on any frame of database %, so no route can authorize an anonymous invocation', + create_invocation.scope, create_invocation.database_id + USING ERRCODE = 'FR072'; + END IF; + + SELECT rm.entity_field + INTO routes_key + FROM metaschema_modules_public.route_module AS rm + JOIN metaschema_public."table" AS t ON t.id = rm.routes_table_id + JOIN metaschema_public.schema AS s ON s.id = t.schema_id + WHERE s.schema_name = routes_schema + AND t.name = routes_table; + + query := format( + 'SELECT EXISTS (SELECT 1 FROM %I.%I AS r' + || ' WHERE r.id = $1 AND r.target_function_id = $2 AND r.is_active' + || ' AND r.anonymous%s)', + routes_schema, + routes_table, + CASE WHEN routes_key IS NULL + THEN ' AND $3 IS NULL' + ELSE format(' AND r.%I = $3', routes_key) + END + ); + + -- pgsql-lint-disable-next-line no-dynamic-sql -- lookup-only: the routes plane is named by app_scope.routing_tables + EXECUTE query + INTO route_authorized + USING create_invocation.route_binding_id, v_definition_id, key_value; + + IF NOT route_authorized THEN + RAISE EXCEPTION 'INVOCATION_ANONYMOUS_NOT_AUTHORIZED: route % of %.% does not expose "%" anonymously', + create_invocation.route_binding_id, routes_schema, routes_table, create_invocation.task_identifier + USING ERRCODE = 'FR075'; + END IF; + END IF; + + -- The write. Every invocations plane carries database_id — the scope key at + -- database scope, attribution elsewhere — so it is stamped either way, and + -- the scope-key column is added only when the plane records one. + -- + -- created_at is truncated to milliseconds because it is half of the row's + -- identity pair (created_at, id): the caller settles the row by that pair, + -- and a microsecond that no JS timestamp can carry makes the settle address + -- a row that does not exist. The worker's own insert path stamps the same + -- millisecond precision. + query := format( + 'INSERT INTO %I.%I AS i (task_identifier, payload, channel, provenance, status, created_at, started_at, database_id%s)' + || ' VALUES ($1, $2, $3, $4, ''running'',' + || ' date_trunc(''milliseconds'', now()), date_trunc(''milliseconds'', now()), $5%s)' + || ' RETURNING i.id, i.created_at, i.started_at, i.function_definition_id, i.definition_scope', + invocations_schema, + invocations_table, + CASE WHEN invocations_key IS NULL OR invocations_key = 'database_id' + THEN '' + ELSE format(', %I', invocations_key) + END, + CASE WHEN invocations_key IS NULL OR invocations_key = 'database_id' + THEN '' + ELSE ', $6' + END + ); + + IF invocations_key IS NULL OR invocations_key = 'database_id' THEN + -- pgsql-lint-disable-next-line no-dynamic-sql -- write: the invocations plane is named by its own function_invocation_module registration; every value is bound + RETURN QUERY EXECUTE query + USING create_invocation.task_identifier, + coalesce(create_invocation.payload, '{}'::jsonb), + create_invocation.channel, + coalesce(create_invocation.provenance, '{}'::jsonb), + create_invocation.database_id; + ELSE + -- pgsql-lint-disable-next-line no-dynamic-sql -- write: the invocations plane is named by its own function_invocation_module registration; every value is bound + RETURN QUERY EXECUTE query + USING create_invocation.task_identifier, + coalesce(create_invocation.payload, '{}'::jsonb), + create_invocation.channel, + coalesce(create_invocation.provenance, '{}'::jsonb), + create_invocation.database_id, + key_value; + END IF; +END; +$$ LANGUAGE plpgsql VOLATILE SECURITY DEFINER; + +COMMENT ON FUNCTION function_resolution.create_invocation(uuid, text, text, jsonb, text, jsonb, uuid, uuid) IS +'Open one running sync invocation row in the addressed database''s own invocations plane, under the caller''s request role. Proves the session''s database claim, that the task resolves to a definition declaring the sync channel, and — for an anonymous caller — that the definition declares anonymous_callable and that the named route binding is active, targets that definition and declares anonymous access. Attribution and the (function_definition_id, definition_scope) pair are stamped by the plane''s own BEFORE INSERT trigger from the transaction claims.'; + +COMMIT; diff --git a/packages/function-resolution/deploy/schemas/function_resolution/procedures/grants/grant_execute_create_invocation.sql b/packages/function-resolution/deploy/schemas/function_resolution/procedures/grants/grant_execute_create_invocation.sql new file mode 100644 index 00000000..a79c9c49 --- /dev/null +++ b/packages/function-resolution/deploy/schemas/function_resolution/procedures/grants/grant_execute_create_invocation.sql @@ -0,0 +1,17 @@ +-- Deploy schemas/function_resolution/procedures/grants/grant_execute_create_invocation to pg + +-- requires: schemas/function_resolution/schema +-- requires: schemas/function_resolution/procedures/create_invocation + +BEGIN; + +-- The request roles reach exactly one function in this schema. Schema USAGE is +-- not a widening: pgpm-defaults revokes EXECUTE on new functions from PUBLIC and +-- this schema grants it only to administrator, so the sibling resolver functions +-- stay unreachable and the grant below is the whole surface. +GRANT USAGE ON SCHEMA function_resolution TO anonymous; + +GRANT EXECUTE ON FUNCTION function_resolution.create_invocation(uuid, text, text, jsonb, text, jsonb, uuid, uuid) TO authenticated; +GRANT EXECUTE ON FUNCTION function_resolution.create_invocation(uuid, text, text, jsonb, text, jsonb, uuid, uuid) TO anonymous; + +COMMIT; diff --git a/packages/function-resolution/deploy/schemas/function_resolution/procedures/install_route_bindings.sql b/packages/function-resolution/deploy/schemas/function_resolution/procedures/install_route_bindings.sql index 0a748918..6b3217be 100644 --- a/packages/function-resolution/deploy/schemas/function_resolution/procedures/install_route_bindings.sql +++ b/packages/function-resolution/deploy/schemas/function_resolution/procedures/install_route_bindings.sql @@ -22,9 +22,14 @@ BEGIN; -- -- The bindings document is a JSON array whose every entry NAMES ITS TARGET KIND: -- --- {"path": "/login", "target": "function", "task_identifier": "mantra:signin"} +-- {"path": "/login", "target": "function", "task_identifier": "mantra:signin", "anonymous": true} -- {"path": "/app", "target": "service", "service_id": ""} -- +-- An entry may declare `anonymous`, which is the route's half of the anonymous +-- contract: the URL answers callers carrying no identity. It opens nothing on +-- its own — the definition behind it must declare anonymous_callable too — and +-- defaults to false, so a document that says nothing installs closed routes. +-- -- The kind is never inferred from which key happens to be present, and an entry -- carrying keys for two kinds is a malformed document rather than a precedence -- question: guessing is how a deployment silently binds /app to the wrong plane. @@ -124,6 +129,7 @@ DECLARE entry_target text; entry_task text; entry_service uuid; + entry_anonymous boolean; target_column text; target_id uuid; service_found boolean; @@ -374,6 +380,7 @@ BEGIN LOOP entry_path := entry ->> 'path'; entry_target := entry ->> 'target'; + entry_anonymous := coalesce((entry ->> 'anonymous')::boolean, false); IF entry_target = 'function' THEN entry_task := entry ->> 'task_identifier'; @@ -426,8 +433,8 @@ BEGIN -- pgsql-lint-disable-next-line no-dynamic-sql -- write-only: insert into the routes plane named by app_scope.routing_tables; every value is a bound parameter query := format( - 'INSERT INTO %I.%I (%s%sdomain_id, path, %I) - SELECT %s%s$1, $2, $3 + 'INSERT INTO %I.%I (%s%sdomain_id, path, anonymous, %I) + SELECT %s%s$1, $2, $6, $3 WHERE NOT EXISTS ( SELECT 1 FROM %I.%I AS x WHERE x.domain_id = $1 AND x.path = $2%s)', @@ -447,7 +454,7 @@ BEGIN ); EXECUTE query USING domain_id, entry_path, target_id, key_value, - install_route_bindings.site_id; + install_route_bindings.site_id, entry_anonymous; GET DIAGNOSTICS inserted = ROW_COUNT; IF inserted > 0 THEN diff --git a/packages/function-resolution/pgpm.plan b/packages/function-resolution/pgpm.plan index abe69283..16b51afe 100644 --- a/packages/function-resolution/pgpm.plan +++ b/packages/function-resolution/pgpm.plan @@ -25,3 +25,5 @@ schemas/function_resolution/procedures/validate_capabilities [schemas/function_r schemas/function_resolution/procedures/image_catalog_row [schemas/function_resolution/schema schemas/function_resolution/procedures/frame_candidates] 2017-08-11T08:11:51Z constructive # reachable image by name (nearest frame wins) schemas/function_resolution/procedures/install_route_bindings [schemas/function_resolution/schema schemas/function_resolution/procedures/resolve metaschema-modules:schemas/metaschema_modules_public/tables/site_surface_module/table metaschema-modules:schemas/metaschema_modules_public/tables/route_module/table metaschema-modules:schemas/metaschema_modules_public/tables/resource_module/table pgpm-app-scope:schemas/app_scope/procedures/routing_tables] 2026-08-19T22:00:01Z devin # install a set of route bindings (function or service targets) onto a site at one scope for one entity schemas/function_resolution/procedures/install_mantra [schemas/function_resolution/schema schemas/function_resolution/procedures/install_route_bindings] 2026-08-19T22:00:02Z devin # the mantra page set as function-target bindings over the general engine +schemas/function_resolution/procedures/create_invocation [schemas/function_resolution/schema schemas/function_resolution/procedures/resolve schemas/function_resolution/procedures/definitions_location metaschema-modules:schemas/metaschema_modules_public/tables/function_invocation_module/table metaschema-modules:schemas/metaschema_modules_public/tables/route_module/table pgpm-app-scope:schemas/app_scope/procedures/frames pgpm-app-scope:schemas/app_scope/procedures/routing_tables pgpm-jwt-claims:schemas/jwt_private/procedures/require_database_id pgpm-jwt-claims:schemas/jwt_public/procedures/current_user_id] 2026-09-01T03:00:00Z devin # the one request-role insert surface for a sync invocation, with route-validated anonymous access +schemas/function_resolution/procedures/grants/grant_execute_create_invocation [schemas/function_resolution/schema schemas/function_resolution/procedures/create_invocation] 2026-09-01T03:00:01Z devin # grant the request roles EXECUTE on create_invocation (and anonymous USAGE on the schema) diff --git a/packages/function-resolution/revert/schemas/function_resolution/procedures/create_invocation.sql b/packages/function-resolution/revert/schemas/function_resolution/procedures/create_invocation.sql new file mode 100644 index 00000000..c13797a6 --- /dev/null +++ b/packages/function-resolution/revert/schemas/function_resolution/procedures/create_invocation.sql @@ -0,0 +1,7 @@ +-- Revert schemas/function_resolution/procedures/create_invocation from pg + +BEGIN; + +DROP FUNCTION function_resolution.create_invocation(uuid, text, text, jsonb, text, jsonb, uuid, uuid); + +COMMIT; diff --git a/packages/function-resolution/revert/schemas/function_resolution/procedures/grants/grant_execute_create_invocation.sql b/packages/function-resolution/revert/schemas/function_resolution/procedures/grants/grant_execute_create_invocation.sql new file mode 100644 index 00000000..6f697406 --- /dev/null +++ b/packages/function-resolution/revert/schemas/function_resolution/procedures/grants/grant_execute_create_invocation.sql @@ -0,0 +1,10 @@ +-- Revert schemas/function_resolution/procedures/grants/grant_execute_create_invocation from pg + +BEGIN; + +REVOKE EXECUTE ON FUNCTION function_resolution.create_invocation(uuid, text, text, jsonb, text, jsonb, uuid, uuid) FROM anonymous; +REVOKE EXECUTE ON FUNCTION function_resolution.create_invocation(uuid, text, text, jsonb, text, jsonb, uuid, uuid) FROM authenticated; + +REVOKE USAGE ON SCHEMA function_resolution FROM anonymous; + +COMMIT; diff --git a/packages/function-resolution/sql/pgpm-function-resolution--0.44.0.bundle.tar.gz b/packages/function-resolution/sql/pgpm-function-resolution--0.44.0.bundle.tar.gz index 0381cbba31a1e4fa96e6a437a1b275a82757eb9b..1ae12f0d41154da04e9d51346dcd48200d024937 100644 GIT binary patch delta 44289 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%0DEbt-6K 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 'path'; entry_target := entry ->> 'target'; + entry_anonymous := coalesce((entry ->> 'anonymous')::boolean, false); IF entry_target = 'function' THEN entry_task := entry ->> 'task_identifier'; @@ -1997,8 +1999,8 @@ BEGIN -- pgsql-lint-disable-next-line no-dynamic-sql -- write-only: insert into the routes plane named by app_scope.routing_tables; every value is a bound parameter query := format( - 'INSERT INTO %I.%I (%s%sdomain_id, path, %I) - SELECT %s%s$1, $2, $3 + 'INSERT INTO %I.%I (%s%sdomain_id, path, anonymous, %I) + SELECT %s%s$1, $2, $6, $3 WHERE NOT EXISTS ( SELECT 1 FROM %I.%I AS x WHERE x.domain_id = $1 AND x.path = $2%s)', @@ -2018,7 +2020,7 @@ BEGIN ); EXECUTE query USING domain_id, entry_path, target_id, key_value, - install_route_bindings.site_id; + install_route_bindings.site_id, entry_anonymous; GET DIAGNOSTICS inserted = ROW_COUNT; IF inserted > 0 THEN @@ -2137,4 +2139,294 @@ BEGIN END; $EOFCODE$ LANGUAGE plpgsql VOLATILE; -COMMENT ON FUNCTION function_resolution.install_mantra(uuid, regclass, uuid, jsonb, uuid) IS 'Install the Mantra page set (a JSON array of {path, task_identifier}, which the generated verb reads from the content_presets catalog at kind ''route_bindings'') onto one site as ordinary function-target routes. The sites plane arrives by reference as a regclass, so a generated caller never spells a schema name in a bare string literal the platform export''s AST rename cannot follow. A thin wrapper holding the Mantra document contract — every entry names a task, none names a target kind — over function_resolution.install_route_bindings, which owns the one-scope install: scope and ownership key read from the sites plane''s own registration, the routes plane from app_scope.routing_tables, resolution at that same (scope, entity), idempotent per (domain_id, path).'; \ No newline at end of file +COMMENT ON FUNCTION function_resolution.install_mantra(uuid, regclass, uuid, jsonb, uuid) IS 'Install the Mantra page set (a JSON array of {path, task_identifier}, which the generated verb reads from the content_presets catalog at kind ''route_bindings'') onto one site as ordinary function-target routes. The sites plane arrives by reference as a regclass, so a generated caller never spells a schema name in a bare string literal the platform export''s AST rename cannot follow. A thin wrapper holding the Mantra document contract — every entry names a task, none names a target kind — over function_resolution.install_route_bindings, which owns the one-scope install: scope and ownership key read from the sites plane''s own registration, the routes plane from app_scope.routing_tables, resolution at that same (scope, entity), idempotent per (domain_id, path).'; + +CREATE FUNCTION function_resolution.create_invocation( + database_id uuid, + scope text, + task_identifier text, + payload jsonb DEFAULT '{}'::jsonb, + channel text DEFAULT 'sync', + provenance jsonb DEFAULT '{}'::jsonb, + route_binding_id uuid DEFAULT NULL, + entity_id uuid DEFAULT NULL +) RETURNS TABLE ( + id uuid, + created_at timestamptz, + started_at timestamptz, + function_definition_id uuid, + definition_scope text +) AS $EOFCODE$ +DECLARE + -- The invocations plane this row lands in, and the scope-key column its + -- registration records (NULL at a global scope). + invocations_schema text; + invocations_table text; + invocations_key text; + -- One key value for the write: the database itself at database scope, the + -- owning entity at an entity scope, NULL at a global scope. + key_value uuid; + -- The winning definition and where it lives, from the same resolver every + -- other ingress path uses. + v_definition_id uuid; + v_definition_scope text; + v_definition_database_id uuid; + definitions_schema text; + definitions_table text; + sync_callable boolean; + -- The definition's own consent to run for a caller with no identity, read + -- from the same plane as its channels. + anonymous_callable boolean; + -- The routes plane serving this scope, and its own recorded ownership key, + -- for the anonymous route check. + routes_schema text; + routes_table text; + routes_key text; + route_authorized boolean; + query text; +BEGIN + IF create_invocation.database_id IS NULL THEN + RAISE EXCEPTION 'INVOCATION_DATABASE_REQUIRED: database_id is required' + USING ERRCODE = 'FR070'; + END IF; + + -- Hard contract, matching enqueue and app_scope: the execution scope is + -- known at the call site and never silently defaulted. + IF create_invocation.scope IS NULL THEN + RAISE EXCEPTION 'INVOCATION_SCOPE_REQUIRED: scope is required (no default scope)' + USING ERRCODE = 'FR070'; + END IF; + + IF coalesce(create_invocation.task_identifier, '') = '' THEN + RAISE EXCEPTION 'INVOCATION_TASK_REQUIRED: task_identifier is required' + USING ERRCODE = 'FR070'; + END IF; + + -- This surface exists for the request lanes that cannot write the table + -- directly. Every other channel already has a trusted path (the worker's + -- own role, the api binding's policy arm, the graph/cron triggers), so a + -- caller naming one here would be claiming a provenance it does not have. + IF create_invocation.channel IS DISTINCT FROM 'sync' THEN + RAISE EXCEPTION 'INVOCATION_CHANNEL_UNSUPPORTED: create_invocation opens sync invocations only, got %', + coalesce(create_invocation.channel, '') + USING ERRCODE = 'FR070'; + END IF; + + -- 1. The tenant boundary. SECURITY DEFINER means RLS does not hold it, so + -- it is an explicit check against the session's own database claim + -- (require_database_id raises when the session established none). + IF jwt_private.require_database_id() <> create_invocation.database_id THEN + RAISE EXCEPTION 'INVOCATION_DATABASE_MISMATCH: session is claimed to database % and cannot open an invocation in %', + jwt_private.require_database_id(), create_invocation.database_id + USING ERRCODE = 'FR071'; + END IF; + + -- The plane, from the registration for exactly this (database, scope). No + -- probing of neighbouring scopes: the caller's scope is explicit. + SELECT s.schema_name, t.name, fim.entity_field + INTO invocations_schema, invocations_table, invocations_key + FROM metaschema_modules_public.function_invocation_module AS fim + JOIN metaschema_public."table" AS t ON t.id = fim.invocations_table_id + JOIN metaschema_public.schema AS s ON s.id = t.schema_id + WHERE fim.database_id = create_invocation.database_id + AND fim.scope = create_invocation.scope; + + IF invocations_schema IS NULL THEN + RAISE EXCEPTION 'INVOCATION_MODULE_NOT_PROVISIONED: database % has no function_invocation_module at scope "%"', + create_invocation.database_id, create_invocation.scope + USING ERRCODE = 'FR072'; + END IF; + + -- The scope key, from the plane's recorded column rather than the scope + -- name: the scope's own key answers "whose ledger", never "who did it". + IF invocations_key IS NULL THEN + key_value := NULL; + ELSIF invocations_key = 'database_id' THEN + key_value := create_invocation.database_id; + ELSE + IF create_invocation.entity_id IS NULL THEN + RAISE EXCEPTION 'INVOCATION_ENTITY_REQUIRED: scope "%" is keyed by %, so entity_id is required', + create_invocation.scope, invocations_key + USING ERRCODE = 'FR070'; + END IF; + key_value := create_invocation.entity_id; + END IF; + + -- 2. The task must resolve, at this (database, scope, entity), to a + -- definition some frame publishes. A definition-less sync request has + -- nothing to authorize and nothing to run. + SELECT r.function_definition_id, r.resolved_scope, r.owner_database_id + INTO v_definition_id, v_definition_scope, v_definition_database_id + FROM function_resolution.resolve( + create_invocation.database_id, + create_invocation.scope, + create_invocation.entity_id, + create_invocation.task_identifier, + false + ) AS r; + + IF v_definition_id IS NULL THEN + RAISE EXCEPTION 'INVOCATION_DEFINITION_NOT_FOUND: no function definition publishes "%" to database % at scope "%"', + create_invocation.task_identifier, create_invocation.database_id, create_invocation.scope + USING ERRCODE = 'FR073'; + END IF; + + -- 3. Sync eligibility, read from the definition's OWN home plane — a + -- platform-declared definition is answered by the platform's + -- definitions table, the same place discovery found it. + IF v_definition_database_id IS NULL THEN + SELECT f.lookup_database_id + INTO v_definition_database_id + FROM app_scope.frames( + create_invocation.database_id, + create_invocation.scope, + create_invocation.entity_id + ) AS f + WHERE f.scope = v_definition_scope + LIMIT 1; + END IF; + + SELECT dl.schema_name, dl.table_name + INTO definitions_schema, definitions_table + FROM function_resolution.definitions_location( + coalesce(v_definition_database_id, create_invocation.database_id), + v_definition_scope + ) AS dl; + + IF definitions_schema IS NULL THEN + RAISE EXCEPTION 'INVOCATION_DEFINITIONS_PLANE_NOT_FOUND: scope "%" of database % has no definitions plane to read channel eligibility from', + v_definition_scope, coalesce(v_definition_database_id, create_invocation.database_id) + USING ERRCODE = 'FR072'; + END IF; + + -- Both definition-side facts in one read: the channel it declares, and + -- whether it consents to run for a caller with no identity. + query := format( + 'SELECT ''sync'' = ANY(d.access_channels), d.anonymous_callable FROM %I.%I AS d WHERE d.id = $1', + definitions_schema, + definitions_table + ); + + -- pgsql-lint-disable-next-line no-dynamic-sql -- lookup-only: the definitions plane is named by its own function_module registration + EXECUTE query INTO sync_callable, anonymous_callable USING v_definition_id; + + IF sync_callable IS NOT TRUE THEN + RAISE EXCEPTION 'INVOCATION_CHANNEL_NOT_DECLARED: definition % does not declare the sync channel', + v_definition_id + USING ERRCODE = 'FR074'; + END IF; + + -- 4. Anonymous authorization. A signed-in caller writing its own ledger row + -- for a sync-eligible task is authorized by being the session it is; an + -- anonymous one has no identity to weigh, so two declarations stand in + -- for it: the definition consents to run without one, and the route it + -- came through exposes it to the public. Both are proved here, against + -- the planes, rather than taken from the caller. + IF jwt_public.current_user_id() IS NULL THEN + IF anonymous_callable IS NOT TRUE THEN + RAISE EXCEPTION 'INVOCATION_ANONYMOUS_NOT_CALLABLE: definition % does not declare anonymous_callable, so "%" cannot run without an identity', + v_definition_id, create_invocation.task_identifier + USING ERRCODE = 'FR075'; + END IF; + + IF create_invocation.route_binding_id IS NULL THEN + RAISE EXCEPTION 'INVOCATION_ANONYMOUS_ROUTE_REQUIRED: an anonymous invocation must name the route binding it arrived through' + USING ERRCODE = 'FR075'; + END IF; + + SELECT r.routes_schema, r.routes_table + INTO routes_schema, routes_table + FROM app_scope.routing_tables(create_invocation.database_id, create_invocation.scope) AS r; + + IF routes_schema IS NULL OR routes_table IS NULL THEN + RAISE EXCEPTION 'INVOCATION_ROUTES_PLANE_NOT_FOUND: scope "%" has no routes plane on any frame of database %, so no route can authorize an anonymous invocation', + create_invocation.scope, create_invocation.database_id + USING ERRCODE = 'FR072'; + END IF; + + SELECT rm.entity_field + INTO routes_key + FROM metaschema_modules_public.route_module AS rm + JOIN metaschema_public."table" AS t ON t.id = rm.routes_table_id + JOIN metaschema_public.schema AS s ON s.id = t.schema_id + WHERE s.schema_name = routes_schema + AND t.name = routes_table; + + query := format( + 'SELECT EXISTS (SELECT 1 FROM %I.%I AS r' + || ' WHERE r.id = $1 AND r.target_function_id = $2 AND r.is_active' + || ' AND r.anonymous%s)', + routes_schema, + routes_table, + CASE WHEN routes_key IS NULL + THEN ' AND $3 IS NULL' + ELSE format(' AND r.%I = $3', routes_key) + END + ); + + -- pgsql-lint-disable-next-line no-dynamic-sql -- lookup-only: the routes plane is named by app_scope.routing_tables + EXECUTE query + INTO route_authorized + USING create_invocation.route_binding_id, v_definition_id, key_value; + + IF NOT route_authorized THEN + RAISE EXCEPTION 'INVOCATION_ANONYMOUS_NOT_AUTHORIZED: route % of %.% does not expose "%" anonymously', + create_invocation.route_binding_id, routes_schema, routes_table, create_invocation.task_identifier + USING ERRCODE = 'FR075'; + END IF; + END IF; + + -- The write. Every invocations plane carries database_id — the scope key at + -- database scope, attribution elsewhere — so it is stamped either way, and + -- the scope-key column is added only when the plane records one. + -- + -- created_at is truncated to milliseconds because it is half of the row's + -- identity pair (created_at, id): the caller settles the row by that pair, + -- and a microsecond that no JS timestamp can carry makes the settle address + -- a row that does not exist. The worker's own insert path stamps the same + -- millisecond precision. + query := format( + 'INSERT INTO %I.%I AS i (task_identifier, payload, channel, provenance, status, created_at, started_at, database_id%s)' + || ' VALUES ($1, $2, $3, $4, ''running'',' + || ' date_trunc(''milliseconds'', now()), date_trunc(''milliseconds'', now()), $5%s)' + || ' RETURNING i.id, i.created_at, i.started_at, i.function_definition_id, i.definition_scope', + invocations_schema, + invocations_table, + CASE WHEN invocations_key IS NULL OR invocations_key = 'database_id' + THEN '' + ELSE format(', %I', invocations_key) + END, + CASE WHEN invocations_key IS NULL OR invocations_key = 'database_id' + THEN '' + ELSE ', $6' + END + ); + + IF invocations_key IS NULL OR invocations_key = 'database_id' THEN + -- pgsql-lint-disable-next-line no-dynamic-sql -- write: the invocations plane is named by its own function_invocation_module registration; every value is bound + RETURN QUERY EXECUTE query + USING create_invocation.task_identifier, + coalesce(create_invocation.payload, '{}'::jsonb), + create_invocation.channel, + coalesce(create_invocation.provenance, '{}'::jsonb), + create_invocation.database_id; + ELSE + -- pgsql-lint-disable-next-line no-dynamic-sql -- write: the invocations plane is named by its own function_invocation_module registration; every value is bound + RETURN QUERY EXECUTE query + USING create_invocation.task_identifier, + coalesce(create_invocation.payload, '{}'::jsonb), + create_invocation.channel, + coalesce(create_invocation.provenance, '{}'::jsonb), + create_invocation.database_id, + key_value; + END IF; +END; +$EOFCODE$ LANGUAGE plpgsql VOLATILE SECURITY DEFINER; + +COMMENT ON FUNCTION function_resolution.create_invocation(uuid, text, text, jsonb, text, jsonb, uuid, uuid) IS 'Open one running sync invocation row in the addressed database''s own invocations plane, under the caller''s request role. Proves the session''s database claim, that the task resolves to a definition declaring the sync channel, and — for an anonymous caller — that the definition declares anonymous_callable and that the named route binding is active, targets that definition and declares anonymous access. Attribution and the (function_definition_id, definition_scope) pair are stamped by the plane''s own BEFORE INSERT trigger from the transaction claims.'; + +GRANT USAGE ON SCHEMA function_resolution TO anonymous; + +GRANT EXECUTE ON FUNCTION function_resolution.create_invocation(uuid, text, text, jsonb, text, jsonb, uuid, uuid) TO authenticated; + +GRANT EXECUTE ON FUNCTION function_resolution.create_invocation(uuid, text, text, jsonb, text, jsonb, uuid, uuid) TO anonymous; \ No newline at end of file diff --git a/packages/function-resolution/verify/schemas/function_resolution/procedures/create_invocation.sql b/packages/function-resolution/verify/schemas/function_resolution/procedures/create_invocation.sql new file mode 100644 index 00000000..3bb76504 --- /dev/null +++ b/packages/function-resolution/verify/schemas/function_resolution/procedures/create_invocation.sql @@ -0,0 +1,7 @@ +-- Verify schemas/function_resolution/procedures/create_invocation on pg + +BEGIN; + +SELECT assert_function('function_resolution.create_invocation(uuid, text, text, jsonb, text, jsonb, uuid, uuid)'::regprocedure); + +ROLLBACK; diff --git a/packages/function-resolution/verify/schemas/function_resolution/procedures/grants/grant_execute_create_invocation.sql b/packages/function-resolution/verify/schemas/function_resolution/procedures/grants/grant_execute_create_invocation.sql new file mode 100644 index 00000000..3b10f080 --- /dev/null +++ b/packages/function-resolution/verify/schemas/function_resolution/procedures/grants/grant_execute_create_invocation.sql @@ -0,0 +1,8 @@ +-- Verify schemas/function_resolution/procedures/grants/grant_execute_create_invocation on pg + +BEGIN; + +SELECT assert_function_grant('function_resolution.create_invocation(uuid, text, text, jsonb, text, jsonb, uuid, uuid)'::regprocedure, 'authenticated', 'EXECUTE'); +SELECT assert_function_grant('function_resolution.create_invocation(uuid, text, text, jsonb, text, jsonb, uuid, uuid)'::regprocedure, 'anonymous', 'EXECUTE'); + +ROLLBACK;