Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/function-resolution/__tests__/capabilities.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ describe('function-resolution capability resolution', () => {
resource_installations_table_id, apps_table_id, buckets_table_id,
sites_web_config_table_id, sites_error_pages_table_id,
sites_app_links_table_id, sites_deep_links_table_id,
redirects_table_id, bindings_table_id, scope)
VALUES ($1, $2, $3, $3, $4, $3, $3, $3, $3, $3, $3, $5, $3, $3, $3, $3, $3, $6, 'database')`,
redirects_table_id, bindings_table_id, images_table_id, scope)
VALUES ($1, $2, $3, $3, $4, $3, $3, $3, $3, $3, $3, $5, $3, $3, $3, $3, $3, $6, $3, 'database')`,
[
TENANT_DB,
catFunctions.schemaId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ describe('function-resolution catalog fast-path', () => {
resource_installations_table_id, apps_table_id, buckets_table_id,
sites_web_config_table_id, sites_error_pages_table_id,
sites_app_links_table_id, sites_deep_links_table_id,
redirects_table_id, bindings_table_id, scope)
VALUES ($1, $2, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, 'app')`,
redirects_table_id, bindings_table_id, images_table_id, scope)
VALUES ($1, $2, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, 'app')`,
[TENANT_DB, catSchema.id, catTable.id]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ describe('capability resolution against the published catalog planes', () => {
bindings_table_id, sites_web_config_table_id,
sites_error_pages_table_id,
sites_app_links_table_id, sites_deep_links_table_id,
redirects_table_id, scope)
VALUES ($1, $2, $3, $3, $4, $3, $3, $3, $3, $3, $3, $5, $6, $3, $3, $3, $3, $3, 'database')`,
redirects_table_id, images_table_id, scope)
VALUES ($1, $2, $3, $3, $4, $3, $3, $3, $3, $3, $3, $5, $6, $3, $3, $3, $3, $3, $3, 'database')`,
[dbId, schemaId, bucketsTableId, apisTableId, bucketsTableId, bindingsTableId]
);
// Label kept for readability of the fixture rows above.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ describe('function-resolution against the published catalog plane', () => {
resource_installations_table_id, apps_table_id, buckets_table_id,
sites_web_config_table_id, sites_error_pages_table_id,
sites_app_links_table_id, sites_deep_links_table_id,
redirects_table_id, bindings_table_id, scope)
VALUES ($1, $2, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, 'app')`,
redirects_table_id, bindings_table_id, images_table_id, scope)
VALUES ($1, $2, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, 'app')`,
[dbId, schemaId, tableId]
);

Expand Down
4 changes: 2 additions & 2 deletions packages/function-resolution/__tests__/resolution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ describe('function-resolution end-to-end (format-based, no AST)', () => {
resource_installations_table_id, apps_table_id, buckets_table_id,
sites_web_config_table_id, sites_error_pages_table_id,
sites_app_links_table_id, sites_deep_links_table_id,
redirects_table_id, bindings_table_id, scope)
VALUES ($1, $2, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, 'app')`,
redirects_table_id, bindings_table_id, images_table_id, scope)
VALUES ($1, $2, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, $3, 'app')`,
[TENANT_DB, catSchema.id, catTable.id]
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
-- Deploy schemas/function_resolution/procedures/image_catalog_row to pg

-- requires: schemas/function_resolution/schema
-- requires: schemas/function_resolution/procedures/frame_candidates

BEGIN;

-- image_catalog_row: load one container image the execution is allowed to run.
--
-- An image foreign key never leaves its own scope, so a tenant that runs a
-- platform-published image holds no reference to it: the reference is a name,
-- and this is where a name becomes coordinates. The frame candidates join
-- catalog_private.images nearest frame first, so a scope's own image shadows a
-- published one of the same name — the read-down is a fallback, not an override.
--
-- The shared plane holds every database's rows, so each candidate carries the
-- row's expected database_id (its own key at database scope, the frame's lookup
-- database otherwise); without it a name could resolve against a row belonging
-- to another tenant. A row owned by another database additionally needs
-- is_visible (the source row's is_published), and platform_only rows are never
-- reachable from outside the database that owns them.
--
-- Returns no row when the image is not reachable, leaving the fail-loud wording
-- to the caller, which knows what named it.
--
-- plpgsql, not sql: this module is portable and deploys into databases that host
-- no catalog module, so catalog_private must be resolved on first call rather
-- than at CREATE FUNCTION time.
CREATE FUNCTION function_resolution.image_catalog_row(
database_id uuid,
scope text,
entity_id uuid,
image_name text
) RETURNS TABLE (
image_id uuid,
name text,
registry_host text,
repository text,
tag text,
digest text,
runtime text,
labels jsonb,
owner_database_id uuid,
owner_scope text,
owner_key uuid
) AS $$
BEGIN
RETURN QUERY
SELECT i.id,
i.name,
i.registry_host,
i.repository,
i.tag,
i.digest,
i.runtime,
i.labels,
i.database_id,
i.owner_scope,
i.owner_key
FROM function_resolution.frame_candidates(
image_catalog_row.database_id,
image_catalog_row.scope,
image_catalog_row.entity_id
) cand
JOIN catalog_private.images i
ON i.owner_scope = cand.owner_scope
AND i.owner_key IS NOT DISTINCT FROM cand.owner_key
AND i.database_id = CASE
WHEN cand.owner_scope = 'database' THEN cand.owner_key
ELSE cand.lookup_database_id
END
WHERE i.name = image_catalog_row.image_name
AND (
i.database_id = image_catalog_row.database_id
OR (i.is_visible AND NOT i.platform_only)
)
ORDER BY cand.ord
LIMIT 1;
END;
$$ LANGUAGE plpgsql STABLE SECURITY DEFINER;

COMMIT;
1 change: 1 addition & 0 deletions packages/function-resolution/pgpm.plan
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ schemas/function_resolution/procedures/bound_bucket_id [schemas/function_resolut
schemas/function_resolution/procedures/resolve_payload_refs [schemas/function_resolution/schema schemas/function_resolution/procedures/resolve_bucket schemas/function_resolution/procedures/resolve_api] 2017-08-11T08:11:51Z constructive <constructive@5b0c196eeb62> # tagged payload refs to coordinates
schemas/function_resolution/procedures/resolve_capabilities [schemas/function_resolution/schema schemas/function_resolution/procedures/definitions_location schemas/function_resolution/procedures/frame_candidates schemas/function_resolution/procedures/resolve_bucket schemas/function_resolution/procedures/bucket_catalog_row schemas/function_resolution/procedures/bound_bucket_id schemas/function_resolution/procedures/resolve_api schemas/function_resolution/procedures/resolve_payload_refs] 2017-08-11T08:11:51Z constructive <constructive@5b0c196eeb62> # resolve-before-dispatch capability bundle
schemas/function_resolution/procedures/validate_capabilities [schemas/function_resolution/schema schemas/function_resolution/procedures/resolve_capabilities] 2017-08-11T08:11:51Z constructive <constructive@5b0c196eeb62> # prove declarations resolvable
schemas/function_resolution/procedures/image_catalog_row [schemas/function_resolution/schema schemas/function_resolution/procedures/frame_candidates] 2017-08-11T08:11:51Z constructive <constructive@5b0c196eeb62> # reachable image by name (nearest frame wins)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- Revert schemas/function_resolution/procedures/image_catalog_row from pg

BEGIN;

DROP FUNCTION function_resolution.image_catalog_row(uuid, text, uuid, text);

COMMIT;
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -1594,4 +1594,57 @@ BEGIN
validate_capabilities.channel
);
END;
$EOFCODE$ LANGUAGE plpgsql STABLE SECURITY DEFINER;

CREATE FUNCTION function_resolution.image_catalog_row(
database_id uuid,
scope text,
entity_id uuid,
image_name text
) RETURNS TABLE (
image_id uuid,
name text,
registry_host text,
repository text,
tag text,
digest text,
runtime text,
labels jsonb,
owner_database_id uuid,
owner_scope text,
owner_key uuid
) AS $EOFCODE$
BEGIN
RETURN QUERY
SELECT i.id,
i.name,
i.registry_host,
i.repository,
i.tag,
i.digest,
i.runtime,
i.labels,
i.database_id,
i.owner_scope,
i.owner_key
FROM function_resolution.frame_candidates(
image_catalog_row.database_id,
image_catalog_row.scope,
image_catalog_row.entity_id
) cand
JOIN catalog_private.images i
ON i.owner_scope = cand.owner_scope
AND i.owner_key IS NOT DISTINCT FROM cand.owner_key
AND i.database_id = CASE
WHEN cand.owner_scope = 'database' THEN cand.owner_key
ELSE cand.lookup_database_id
END
WHERE i.name = image_catalog_row.image_name
AND (
i.database_id = image_catalog_row.database_id
OR (i.is_visible AND NOT i.platform_only)
)
ORDER BY cand.ord
LIMIT 1;
END;
$EOFCODE$ LANGUAGE plpgsql STABLE SECURITY DEFINER;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- Verify schemas/function_resolution/procedures/image_catalog_row on pg

BEGIN;

SELECT assert_function('function_resolution.image_catalog_row(uuid, text, uuid, text)'::regprocedure);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ exports[`db_meta_modules should have all expected module tables 1`] = `
"graph_execution_module",
"graph_module",
"hierarchy_module",
"http_route_module",
"i18n_module",
"identity_providers_module",
"image_module",
Expand Down Expand Up @@ -85,8 +84,8 @@ exports[`db_meta_modules should have all expected module tables 1`] = `

exports[`db_meta_modules should verify all module tables exist in metaschema_modules_public schema 1`] = `
{
"moduleTablesCount": 76,
"totalTables": 85,
"moduleTablesCount": 75,
"totalTables": 84,
}
`;

Expand Down Expand Up @@ -153,13 +152,13 @@ exports[`db_meta_modules should verify emails_module table structure 1`] = `

exports[`db_meta_modules should verify module table structures have database_id foreign keys 1`] = `
{
"constraintCount": 76,
"constraintCount": 75,
}
`;

exports[`db_meta_modules should verify module tables have proper foreign key relationships 1`] = `
{
"constraintCount": 551,
"constraintCount": 546,
"foreignTables": [
"catalog_module",
"database",
Expand All @@ -171,10 +170,8 @@ exports[`db_meta_modules should verify module tables have proper foreign key rel
"infra_secrets_module",
"merkle_store_module",
"namespace_module",
"resource_module",
"schema",
"site_surface_module",
"storage_module",
"table",
],
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ BEGIN;
-- Typed catalog module configuration: one row per database installs the typed
-- catalog tables (catalog_private.domains / apis / sites / namespaces /
-- functions / resources / resource_definitions / resource_installations /
-- apps / buckets / redirects / bindings). The catalog is
-- apps / buckets / images / redirects / bindings). The catalog is
-- a system projection surface holding ALL scopes of each type; scoped source
-- tables register into it via catalog_register. The stable schema-qualified
-- table names are load-bearing deployment contracts.
Expand All @@ -32,6 +32,7 @@ CREATE TABLE metaschema_modules_public.catalog_module (
resource_installations_table_id uuid NOT NULL DEFAULT uuid_nil(),
apps_table_id uuid NOT NULL DEFAULT uuid_nil(),
buckets_table_id uuid NOT NULL DEFAULT uuid_nil(),
images_table_id uuid NOT NULL DEFAULT uuid_nil(),
bindings_table_id uuid NOT NULL DEFAULT uuid_nil(),
sites_web_config_table_id uuid NOT NULL DEFAULT uuid_nil(),
sites_error_pages_table_id uuid NOT NULL DEFAULT uuid_nil(),
Expand All @@ -50,6 +51,7 @@ CREATE TABLE metaschema_modules_public.catalog_module (
resource_installations_table_name text NOT NULL DEFAULT 'resource_installations',
apps_table_name text NOT NULL DEFAULT 'apps',
buckets_table_name text NOT NULL DEFAULT 'buckets',
images_table_name text NOT NULL DEFAULT 'images',
bindings_table_name text NOT NULL DEFAULT 'bindings',
sites_web_config_table_name text NOT NULL DEFAULT 'sites_web_config',
sites_error_pages_table_name text NOT NULL DEFAULT 'sites_error_pages',
Expand Down Expand Up @@ -125,6 +127,10 @@ CREATE TABLE metaschema_modules_public.catalog_module (
FOREIGN KEY (buckets_table_id)
REFERENCES metaschema_public.table (id)
ON DELETE CASCADE,
CONSTRAINT catalog_module_images_table_fkey
FOREIGN KEY (images_table_id)
REFERENCES metaschema_public.table (id)
ON DELETE CASCADE,
CONSTRAINT catalog_module_bindings_table_fkey
FOREIGN KEY (bindings_table_id)
REFERENCES metaschema_public.table (id)
Expand Down Expand Up @@ -162,6 +168,7 @@ CREATE UNIQUE INDEX catalog_module_unique_database
CREATE INDEX catalog_module_apis_table_id_idx ON metaschema_modules_public.catalog_module ( apis_table_id );
CREATE INDEX catalog_module_apps_table_id_idx ON metaschema_modules_public.catalog_module ( apps_table_id );
CREATE INDEX catalog_module_buckets_table_id_idx ON metaschema_modules_public.catalog_module ( buckets_table_id );
CREATE INDEX catalog_module_images_table_id_idx ON metaschema_modules_public.catalog_module ( images_table_id );
CREATE INDEX catalog_module_bindings_table_id_idx ON metaschema_modules_public.catalog_module ( bindings_table_id );
CREATE INDEX catalog_module_sites_web_config_table_id_idx ON metaschema_modules_public.catalog_module ( sites_web_config_table_id );
CREATE INDEX catalog_module_sites_error_pages_table_id_idx ON metaschema_modules_public.catalog_module ( sites_error_pages_table_id );
Expand All @@ -188,6 +195,7 @@ COMMENT ON COLUMN metaschema_modules_public.catalog_module.bindings_table_id IS
COMMENT ON COLUMN metaschema_modules_public.catalog_module.buckets_table_id IS '@module_table';
COMMENT ON COLUMN metaschema_modules_public.catalog_module.domains_table_id IS '@module_table';
COMMENT ON COLUMN metaschema_modules_public.catalog_module.functions_table_id IS '@module_table';
COMMENT ON COLUMN metaschema_modules_public.catalog_module.images_table_id IS '@module_table';
COMMENT ON COLUMN metaschema_modules_public.catalog_module.namespaces_table_id IS '@module_table';
COMMENT ON COLUMN metaschema_modules_public.catalog_module.resource_definitions_table_id IS '@module_table';
COMMENT ON COLUMN metaschema_modules_public.catalog_module.resource_installations_table_id IS '@module_table';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,20 @@ CREATE TABLE metaschema_modules_public.compute_log_module (
retention text NOT NULL DEFAULT '12 months',
premake int NOT NULL DEFAULT 2,

-- Scope configuration: 'app' = per-app usage (actor_id RLS)
-- Scope the log plane is installed at. Rows are read through
-- entity membership on entity_id at every scope, plus the actor's own rows
-- outside the constructive scopes.
scope text NOT NULL,
actor_fk_table_id uuid NULL,
entity_fk_table_id uuid NULL,

-- Table name prefix. Auto-derived from scope by the trigger when empty.
prefix text NOT NULL DEFAULT '',

-- Name of the AST-generated rollup function in the private schema. It
-- carries the same prefix as the tables, so two scopes of this module
-- share one private schema without colliding, and a reader (the worker's
-- rollup pass) calls the function belonging to the instance it loaded.
rollup_function_name text NOT NULL DEFAULT '',

-- API routing (configurable per-module)
api_name text DEFAULT 'usage',
private_api_name text DEFAULT NULL,
Expand Down
Loading
Loading