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
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,16 @@ jobs:
ports:
- 5432:5432

minio_cdn:
image: minio/minio:edge-cicd
rustfs_cdn:
image: rustfs/rustfs:1.0.0-rc.5
env:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
RUSTFS_ACCESS_KEY: minioadmin
RUSTFS_SECRET_KEY: minioadmin
RUSTFS_ADDRESS: ":9000"
ports:
- 9000:9000
- 9001:9001
options: >-
--health-cmd "curl -f http://localhost:9000/minio/health/live || exit 1"
--health-cmd "curl -f http://localhost:9000/health || exit 1"
--health-interval 10s
--health-timeout 5s
--health-retries 5
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/integration-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ jobs:
ports:
- 5432:5432

minio_cdn:
image: minio/minio:edge-cicd
rustfs_cdn:
image: rustfs/rustfs:1.0.0-rc.5
env:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
RUSTFS_ACCESS_KEY: minioadmin
RUSTFS_SECRET_KEY: minioadmin
RUSTFS_ADDRESS: ":9000"
ports:
- 9000:9000
- 9001:9001
options: >-
--health-cmd "curl -f http://localhost:9000/minio/health/live || exit 1"
--health-cmd "curl -f http://localhost:9000/health || exit 1"
--health-interval 10s
--health-timeout 5s
--health-retries 5
Expand Down
16 changes: 8 additions & 8 deletions packages/function-resolution/__tests__/capabilities.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ describe('function-resolution capability resolution', () => {

it('resolve_capabilities(): declarations become one resolved bundle', async () => {
const [{ bundle }] = await pg.any(
`SELECT function_resolution.resolve_capabilities($1, 'database', $1, $2, 'database', $1, $3::jsonb, 'api') AS bundle`,
`SELECT function_resolution.resolve_capabilities($1, 'database', $1, $2, 'database', $3::jsonb, 'api') AS bundle`,
[TENANT_DB, ids.exporter, JSON.stringify({ subject: 'monthly' })]
);

Expand All @@ -530,7 +530,7 @@ describe('function-resolution capability resolution', () => {

it('resolve_capabilities(): echoes required_capabilities as declared', async () => {
const [{ bundle }] = await pg.any(
`SELECT function_resolution.resolve_capabilities($1, 'database', $1, $2, 'database', $1, '{}'::jsonb, 'api') AS bundle`,
`SELECT function_resolution.resolve_capabilities($1, 'database', $1, $2, 'database', '{}'::jsonb, 'api') AS bundle`,
[TENANT_DB, ids.declaring]
);
expect(bundle.capabilities).toEqual([
Expand All @@ -548,7 +548,7 @@ describe('function-resolution capability resolution', () => {
);

const [{ bundle }] = await pg.any(
`SELECT function_resolution.resolve_capabilities($1, 'database', $1, $2, 'database', $1) AS bundle`,
`SELECT function_resolution.resolve_capabilities($1, 'database', $1, $2, 'database') AS bundle`,
[TENANT_DB, ids.ambiguous]
);
expect(bundle.buckets.variants.bucket_id).toBe(ids.publicVariants);
Expand All @@ -563,7 +563,7 @@ describe('function-resolution capability resolution', () => {

await expect(
pg.any(
`SELECT function_resolution.resolve_capabilities($1, 'database', $1, $2, 'database', $1)`,
`SELECT function_resolution.resolve_capabilities($1, 'database', $1, $2, 'database')`,
[TENANT_DB, ids.ambiguous]
)
).rejects.toThrow(/CAPABILITY_BINDING_UNREACHABLE/);
Expand All @@ -576,7 +576,7 @@ describe('function-resolution capability resolution', () => {
it('resolve_capabilities(): an undeclared channel is refused', async () => {
await expect(
pg.any(
`SELECT function_resolution.resolve_capabilities($1, 'database', $1, $2, 'database', $1, '{}'::jsonb, 'cron')`,
`SELECT function_resolution.resolve_capabilities($1, 'database', $1, $2, 'database', '{}'::jsonb, 'cron')`,
[TENANT_DB, ids.exporter]
)
).rejects.toThrow(/CAPABILITY_CHANNEL_REFUSED/);
Expand All @@ -585,21 +585,21 @@ describe('function-resolution capability resolution', () => {
it('resolve_capabilities(): a missing definition raises', async () => {
await expect(
pg.any(
`SELECT function_resolution.resolve_capabilities($1, 'database', $1, gen_random_uuid(), 'database', $1)`,
`SELECT function_resolution.resolve_capabilities($1, 'database', $1, gen_random_uuid(), 'database')`,
[TENANT_DB]
)
).rejects.toThrow(/CAPABILITY_DEFINITION_NOT_FOUND/);
});

it('validate_capabilities(): passes when resolvable, raises when not', async () => {
await pg.query(
`SELECT function_resolution.validate_capabilities($1, 'database', $1, $2, 'database', $1)`,
`SELECT function_resolution.validate_capabilities($1, 'database', $1, $2, 'database')`,
[TENANT_DB, ids.exporter]
);

await expect(
pg.any(
`SELECT function_resolution.validate_capabilities($1, 'database', $1, $2, 'database', $1)`,
`SELECT function_resolution.validate_capabilities($1, 'database', $1, $2, 'database')`,
[TENANT_DB, ids.ambiguous]
)
).rejects.toThrow(/CAPABILITY_BUCKET_AMBIGUOUS/);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,29 @@ BEGIN
USING ERRCODE = 'FR060';
END IF;

-- Two shapes only: a page ({path, task_identifier}, no target kind — it is
-- always a function), or a redirect ({path, target: 'redirect', to_path}) a
-- host given over to the page set uses to send its root at sign-in. A
-- service binding, or a page that names a kind, is a broken preset.
IF EXISTS (
SELECT 1
FROM jsonb_array_elements(install_mantra.bindings) AS b
WHERE jsonb_typeof(b) <> 'object'
OR coalesce(b ->> 'path', '') = ''
OR coalesce(b ->> 'task_identifier', '') = ''
OR b ? 'target'
OR CASE b ->> 'target'
WHEN 'redirect' THEN coalesce(b ->> 'to_path', '') = '' OR b ? 'task_identifier'
ELSE coalesce(b ->> 'task_identifier', '') = '' OR b ? 'target'
END
) THEN
RAISE EXCEPTION 'MANTRA_BINDINGS_INVALID: every binding must carry a non-empty path and task_identifier, and no target kind'
RAISE EXCEPTION 'MANTRA_BINDINGS_INVALID: every binding must carry a non-empty path and either a task_identifier with no target kind, or target "redirect" with a to_path'
USING ERRCODE = 'FR060';
END IF;

SELECT jsonb_agg(b || jsonb_build_object('target', 'function'))
SELECT jsonb_agg(
CASE WHEN b ->> 'target' = 'redirect' THEN b
ELSE b || jsonb_build_object('target', 'function')
END
)
INTO function_bindings
FROM jsonb_array_elements(install_mantra.bindings) AS b;

Expand All @@ -102,6 +112,6 @@ END;
$$ 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).';
'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 and no target kind, or is a {target: "redirect", to_path} entry sending a path (a dedicated host''s root) at one of the pages — 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).';

COMMIT;
Loading
Loading