From cfe8d120a7e73342631789ebbd8cae3e96c36658 Mon Sep 17 00:00:00 2001 From: Toby Hede Date: Wed, 30 Oct 2024 17:09:56 +1100 Subject: [PATCH 01/12] Granular errors on encrypted columnb constraint --- sql/010-core.sql | 106 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 19 deletions(-) diff --git a/sql/010-core.sql b/sql/010-core.sql index 9f3be0c4..a8927139 100644 --- a/sql/010-core.sql +++ b/sql/010-core.sql @@ -14,17 +14,88 @@ BEGIN END $$; -DROP FUNCTION IF EXISTS _cs_encrypted_check_kind(jsonb); - -CREATE FUNCTION _cs_encrypted_check_kind(val jsonb) - RETURNS BOOLEAN -LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE -BEGIN ATOMIC - RETURN ( - (val->>'k' = 'ct' AND val ? 'c') OR - (val->>'k' = 'sv' AND val ? 'sv') - ) AND NOT val ? 'p'; -END; +-- +-- CT payload should include a c field +-- +DROP FUNCTION IF EXISTS _cs_encrypted_check_k_ct(jsonb); +CREATE FUNCTION _cs_encrypted_check_k_ct(val jsonb) + RETURNS boolean +AS $$ + BEGIN + IF (val->>'k' = 'ct' AND val ? 'c') THEN + RETURN true; + END IF; + RAISE 'Encrypted kind (k) of "ct" missing data field (c): %', val; + END; +$$ LANGUAGE plpgsql; + +-- +-- SV payload should include an sv field +-- +DROP FUNCTION IF EXISTS _cs_encrypted_check_k_sv(jsonb); +CREATE FUNCTION _cs_encrypted_check_k_sv(val jsonb) + RETURNS boolean +AS $$ + BEGIN + IF (val->>'k' = 'sv' AND val ? 'sv') THEN + RETURN true; + END IF; + RAISE 'Encrypted kind (k) of "sv" missing data field (sv): %', val; + END; +$$ LANGUAGE plpgsql; + + +-- Plaintext field should never be present in an encrypted column +DROP FUNCTION IF EXISTS _cs_encrypted_check_p(jsonb); +CREATE FUNCTION _cs_encrypted_check_p(val jsonb) + RETURNS boolean +AS $$ + BEGIN + IF NOT val ? 'p' THEN + RETURN true; + END IF; + RAISE 'Encrypted includes plaintext (p) field: %', val; + END; +$$ LANGUAGE plpgsql; + +-- Should include an ident field +DROP FUNCTION IF EXISTS _cs_encrypted_check_i(jsonb); +CREATE FUNCTION _cs_encrypted_check_i(val jsonb) + RETURNS boolean +AS $$ + BEGIN + IF val ? 'i' THEN + RETURN true; + END IF; + RAISE 'Encrypted missing ident (i) field: %', val; + END; +$$ LANGUAGE plpgsql; + +-- Should include an ident field +DROP FUNCTION IF EXISTS _cs_encrypted_check_i_ct(jsonb); +CREATE FUNCTION _cs_encrypted_check_i_ct(val jsonb) + RETURNS boolean +AS $$ + BEGIN + IF (val->'i' ?& array['t', 'c']) THEN + RETURN true; + END IF; + RAISE 'Encrypted ident (i) missing table (t) or column (c) fields: %', val; + END; +$$ LANGUAGE plpgsql; + +-- Should include an ident field +DROP FUNCTION IF EXISTS _cs_encrypted_check_v(jsonb); +CREATE FUNCTION _cs_encrypted_check_v(val jsonb) + RETURNS boolean +AS $$ + BEGIN + IF (val ? 'v') THEN + RETURN true; + END IF; + RAISE 'Encrypted missing version (v) field: %', val; + END; +$$ LANGUAGE plpgsql; DROP FUNCTION IF EXISTS cs_check_encrypted_v1(val jsonb); @@ -34,14 +105,11 @@ CREATE FUNCTION cs_check_encrypted_v1(val jsonb) LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE BEGIN ATOMIC RETURN ( - -- version and source are required - val ?& array['v'] AND - - -- table and column - val->'i' ?& array['t', 'c'] AND - - -- plaintext or ciphertext for kind - _cs_encrypted_check_kind(val) + _cs_encrypted_check_v(val) AND + _cs_encrypted_check_i(val) AND + _cs_encrypted_check_k_ct(val) AND + _cs_encrypted_check_k_sv(val) AND + _cs_encrypted_check_p(val) ); END; From 4fd756f5d98a3f1c57dd3c382aa82bf971b4047d Mon Sep 17 00:00:00 2001 From: Toby Hede Date: Thu, 31 Oct 2024 12:33:45 +1100 Subject: [PATCH 02/12] Add cast to add_column function --- sql/021-config-functions.sql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sql/021-config-functions.sql b/sql/021-config-functions.sql index 511b53bf..a0b88fc5 100644 --- a/sql/021-config-functions.sql +++ b/sql/021-config-functions.sql @@ -301,7 +301,7 @@ $$ LANGUAGE plpgsql; DROP FUNCTION IF EXISTS cs_add_column_v1(table_name text, column_name text); -CREATE FUNCTION cs_add_column_v1(table_name text, column_name text) +CREATE FUNCTION cs_add_column_v1(table_name text, column_name text, cast_as text DEFAULT 'text') RETURNS jsonb AS $$ DECLARE @@ -323,6 +323,8 @@ AS $$ SELECT _cs_config_add_column(table_name, column_name, _config) INTO _config; + SELECT _cs_config_add_cast(table_name, column_name, cast_as, _config) INTO _config; + -- create a new pending record if we don't have one INSERT INTO cs_configuration_v1 (state, data) VALUES ('pending', _config) ON CONFLICT (state) From 2e6f40e8899fe4c02d61ee01d3b282401c14b91e Mon Sep 17 00:00:00 2001 From: Toby Hede Date: Thu, 31 Oct 2024 12:34:03 +1100 Subject: [PATCH 03/12] Improved config constraint errors --- sql/020-config-schema.sql | 58 ++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/sql/020-config-schema.sql b/sql/020-config-schema.sql index f4ff92c2..b1cbf178 100644 --- a/sql/020-config-schema.sql +++ b/sql/020-config-schema.sql @@ -44,28 +44,66 @@ DROP FUNCTION IF EXISTS _cs_config_check_indexes(jsonb); CREATE FUNCTION _cs_config_check_indexes(val jsonb) RETURNS BOOLEAN -LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE -BEGIN ATOMIC - SELECT jsonb_object_keys(jsonb_path_query(val, '$.tables.*.*.indexes')) = ANY('{match, ore, unique, ste_vec}'); -END; +AS $$ + BEGIN + IF jsonb_path_query(val, '$.tables.*.*.indexes') <> '{}':jsonb THEN + IF EXISTS (SELECT jsonb_object_keys(jsonb_path_query(val, '$.tables.*.*.indexes')) = ANY('{match, ore, unique, ste_vec}')) THEN + RETURN true; + END IF; + RAISE 'Invalid index (%) in configuration. Index should be one of {match, ore, unique, ste_vec}', val; + END IF; + END; +$$ LANGUAGE plpgsql; DROP FUNCTION IF EXISTS _cs_config_check_cast(jsonb); CREATE FUNCTION _cs_config_check_cast(val jsonb) RETURNS BOOLEAN -LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE -BEGIN ATOMIC - SELECT jsonb_array_elements_text(jsonb_path_query_array(val, '$.tables.*.*.cast_as')) = ANY('{text, int, small_int, big_int, real, double, boolean, date, jsonb}'); -END; +AS $$ + BEGIN + IF EXISTS (SELECT jsonb_array_elements_text(jsonb_path_query_array(val, '$.tables.*.*.cast_as')) = ANY('{text, int, small_int, big_int, real, double, boolean, date, jsonb}')) THEN + RETURN true; + END IF; + RAISE 'Invalid cast (%) in configuration. Cast should be one of {text, int, small_int, big_int, real, double, boolean, date, jsonb}', val; + END; +$$ LANGUAGE plpgsql; + +-- +-- Should include a tables field +-- Tables should not be empty +DROP FUNCTION IF EXISTS _cs_config_check_tables(jsonb); +CREATE FUNCTION _cs_config_check_tables(val jsonb) + RETURNS boolean +AS $$ + BEGIN + IF (val ? 'tables') AND (val->'tables' <> '{"A":"a"}'::jsonb) THEN + RETURN true; + END IF; + RAISE 'Configuration missing tables (tables) field: %', val; + END; +$$ LANGUAGE plpgsql; + +-- Should include a version field +DROP FUNCTION IF EXISTS _cs_config_check_v(jsonb); +CREATE FUNCTION _cs_config_check_v(val jsonb) + RETURNS boolean +AS $$ + BEGIN + IF (val ? 'v') THEN + RETURN true; + END IF; + RAISE 'Configuration missing version (v) field: %', val; + END; +$$ LANGUAGE plpgsql; ALTER DOMAIN cs_configuration_data_v1 DROP CONSTRAINT IF EXISTS cs_configuration_data_v1_check; ALTER DOMAIN cs_configuration_data_v1 ADD CONSTRAINT cs_configuration_data_v1_check CHECK ( - VALUE ?& array['v', 'tables'] AND - VALUE->'tables' <> '{}'::jsonb AND + _cs_config_check_v(VALUE) AND + _cs_config_check_tables(VALUE) AND _cs_config_check_cast(VALUE) AND _cs_config_check_indexes(VALUE) ); From d5896a85bba52f266b8349893125c7698d4f8e20 Mon Sep 17 00:00:00 2001 From: Toby Hede Date: Thu, 31 Oct 2024 13:21:31 +1100 Subject: [PATCH 04/12] Fix type name in drop --- sql/666-drop_types.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/666-drop_types.sql b/sql/666-drop_types.sql index b494f36a..8de0cb64 100644 --- a/sql/666-drop_types.sql +++ b/sql/666-drop_types.sql @@ -2,7 +2,7 @@ DROP TYPE IF EXISTS ore_64_8_v1; DROP TYPE IF EXISTS ore_64_8_v1_term; DROP TYPE IF EXISTS cs_ste_vec_index_v1; -DROP TYPE IF EXISTS ste_vec_v1_entry; +DROP TYPE IF EXISTS cs_ste_vec_v1_entry; DROP TYPE IF EXISTS ore_cllw_8_v1; DROP TYPE IF EXISTS ore_cllw_8_variable_v1; DROP TYPE IF EXISTS cs_ste_vec_encrypted_term_v1; From 3670cb08e4682bcd2d818ac64e22b96d2fe821ce Mon Sep 17 00:00:00 2001 From: Toby Hede Date: Thu, 31 Oct 2024 13:27:07 +1100 Subject: [PATCH 05/12] How to boolean --- sql/010-core.sql | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sql/010-core.sql b/sql/010-core.sql index a8927139..046458be 100644 --- a/sql/010-core.sql +++ b/sql/010-core.sql @@ -22,10 +22,13 @@ CREATE FUNCTION _cs_encrypted_check_k_ct(val jsonb) RETURNS boolean AS $$ BEGIN - IF (val->>'k' = 'ct' AND val ? 'c') THEN - RETURN true; + IF (val->>'k' = 'ct') THEN + IF (val ? 'c') THEN + RETURN true; + END IF; + RAISE 'Encrypted kind (k) of "ct" missing data field (c): %', val; END IF; - RAISE 'Encrypted kind (k) of "ct" missing data field (c): %', val; + RETURN true; END; $$ LANGUAGE plpgsql; @@ -37,10 +40,13 @@ CREATE FUNCTION _cs_encrypted_check_k_sv(val jsonb) RETURNS boolean AS $$ BEGIN - IF (val->>'k' = 'sv' AND val ? 'sv') THEN - RETURN true; + IF (val->>'k' = 'sv') THEN + IF (val ? 'sv') THEN + RETURN true; + END IF; + RAISE 'Encrypted kind (k) of "sv" missing data field (sv): %', val; END IF; - RAISE 'Encrypted kind (k) of "sv" missing data field (sv): %', val; + RETURN true; END; $$ LANGUAGE plpgsql; From 89d518a6c9f88c3417883875f6e20dd43253e0d1 Mon Sep 17 00:00:00 2001 From: Toby Hede Date: Thu, 31 Oct 2024 13:58:17 +1100 Subject: [PATCH 06/12] Cleanup --- sql/010-core.sql | 29 +++++++++++++++++++++++------ sql/020-config-schema.sql | 2 +- tests/core.sql | 31 ++++++++++++++++++++++++++++++- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/sql/010-core.sql b/sql/010-core.sql index 046458be..1302c01c 100644 --- a/sql/010-core.sql +++ b/sql/010-core.sql @@ -14,6 +14,21 @@ BEGIN END $$; + +-- Should include a kind field +DROP FUNCTION IF EXISTS _cs_encrypted_check_k(jsonb); +CREATE FUNCTION _cs_encrypted_check_k(val jsonb) + RETURNS boolean +AS $$ + BEGIN + IF (val->>'k' = ANY('{ct, sv}')) THEN + RETURN true; + END IF; + RAISE 'Invalid kind (%) in Encrypted column. Kind should be one of {ct, sv}', val; + END; +$$ LANGUAGE plpgsql; + + -- -- CT payload should include a c field -- @@ -26,12 +41,13 @@ AS $$ IF (val ? 'c') THEN RETURN true; END IF; - RAISE 'Encrypted kind (k) of "ct" missing data field (c): %', val; + RAISE 'Encrypted column kind (k) of "ct" missing data field (c): %', val; END IF; RETURN true; END; $$ LANGUAGE plpgsql; + -- -- SV payload should include an sv field -- @@ -44,7 +60,7 @@ AS $$ IF (val ? 'sv') THEN RETURN true; END IF; - RAISE 'Encrypted kind (k) of "sv" missing data field (sv): %', val; + RAISE 'Encrypted column kind (k) of "sv" missing data field (sv): %', val; END IF; RETURN true; END; @@ -60,7 +76,7 @@ AS $$ IF NOT val ? 'p' THEN RETURN true; END IF; - RAISE 'Encrypted includes plaintext (p) field: %', val; + RAISE 'Encrypted column includes plaintext (p) field: %', val; END; $$ LANGUAGE plpgsql; @@ -73,7 +89,7 @@ AS $$ IF val ? 'i' THEN RETURN true; END IF; - RAISE 'Encrypted missing ident (i) field: %', val; + RAISE 'Encrypted column missing ident (i) field: %', val; END; $$ LANGUAGE plpgsql; @@ -86,7 +102,7 @@ AS $$ IF (val->'i' ?& array['t', 'c']) THEN RETURN true; END IF; - RAISE 'Encrypted ident (i) missing table (t) or column (c) fields: %', val; + RAISE 'Encrypted column ident (i) missing table (t) or column (c) fields: %', val; END; $$ LANGUAGE plpgsql; @@ -99,7 +115,7 @@ AS $$ IF (val ? 'v') THEN RETURN true; END IF; - RAISE 'Encrypted missing version (v) field: %', val; + RAISE 'Encrypted column missing version (v) field: %', val; END; $$ LANGUAGE plpgsql; @@ -113,6 +129,7 @@ BEGIN ATOMIC RETURN ( _cs_encrypted_check_v(val) AND _cs_encrypted_check_i(val) AND + _cs_encrypted_check_k(val) AND _cs_encrypted_check_k_ct(val) AND _cs_encrypted_check_k_sv(val) AND _cs_encrypted_check_p(val) diff --git a/sql/020-config-schema.sql b/sql/020-config-schema.sql index b1cbf178..60beafb9 100644 --- a/sql/020-config-schema.sql +++ b/sql/020-config-schema.sql @@ -77,7 +77,7 @@ CREATE FUNCTION _cs_config_check_tables(val jsonb) RETURNS boolean AS $$ BEGIN - IF (val ? 'tables') AND (val->'tables' <> '{"A":"a"}'::jsonb) THEN + IF (val ? 'tables') AND (val->'tables' <> '{}'::jsonb) THEN RETURN true; END IF; RAISE 'Configuration missing tables (tables) field: %', val; diff --git a/tests/core.sql b/tests/core.sql index 5480512d..5558f3b8 100644 --- a/tests/core.sql +++ b/tests/core.sql @@ -84,7 +84,7 @@ INSERT INTO users (name_encrypted) VALUES ( }'::jsonb ); --- no source detauils +-- no ident details INSERT INTO users (name_encrypted) VALUES ( '{ "v": 1, @@ -93,6 +93,35 @@ INSERT INTO users (name_encrypted) VALUES ( }'::jsonb ); +-- npo kind +INSERT INTO users (name_encrypted) VALUES ( + '{ + "v": 1, + "c": "ciphertext", + "i": { + "t": "users", + "c": "name" + } + }'::jsonb +); + + + +-- bad kind +INSERT INTO users (name_encrypted) VALUES ( + '{ + "v": 1, + "k": "vtha", + "c": "ciphertext", + "i": { + "t": "users", + "c": "name" + } + }'::jsonb +); + + + -- pt INSERT INTO users (name_encrypted) VALUES ( '{ From 1f30e52508b79db6ea92775b4588b3c2e6889f42 Mon Sep 17 00:00:00 2001 From: Toby Hede Date: Fri, 1 Nov 2024 11:37:45 +1100 Subject: [PATCH 07/12] Index constraint handling empty indexes --- sql/020-config-schema.sql | 23 ++++++++++++++++++----- sql/021-config-functions.sql | 2 +- tests/config.sql | 6 +++++- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/sql/020-config-schema.sql b/sql/020-config-schema.sql index 60beafb9..d3bcc7b5 100644 --- a/sql/020-config-schema.sql +++ b/sql/020-config-schema.sql @@ -33,25 +33,38 @@ DO $$ END $$; + + +-- +-- Extracts index keys/names from configuration json +-- +-- Used by the _cs_config_check_indexes as part of the cs_configuration_data_v1_check constraint +-- +DROP FUNCTION IF EXISTS _cs_extract_indexes(jsonb); +CREATE FUNCTION _cs_extract_indexes(val jsonb) + RETURNS SETOF text + LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE +BEGIN ATOMIC + SELECT jsonb_object_keys(jsonb_path_query(val,'$.tables.*.*.indexes')); +END; + -- -- _cs_check_config_indexes returns true if the table configuration only includes valid index types -- -- Used by the cs_configuration_data_v1_check constraint -- --- Function types cannot be changed after creation so we always DROP & CREATE for flexibility --- DROP FUNCTION IF EXISTS _cs_config_check_indexes(jsonb); - CREATE FUNCTION _cs_config_check_indexes(val jsonb) RETURNS BOOLEAN AS $$ BEGIN - IF jsonb_path_query(val, '$.tables.*.*.indexes') <> '{}':jsonb THEN - IF EXISTS (SELECT jsonb_object_keys(jsonb_path_query(val, '$.tables.*.*.indexes')) = ANY('{match, ore, unique, ste_vec}')) THEN + IF (SELECT EXISTS (SELECT _cs_extract_indexes(val))) THEN + IF (SELECT bool_and(index = ANY('{match, ore, unique, ste_vec}')) FROM _cs_extract_indexes(val) AS index) THEN RETURN true; END IF; RAISE 'Invalid index (%) in configuration. Index should be one of {match, ore, unique, ste_vec}', val; END IF; + RETURN true; END; $$ LANGUAGE plpgsql; diff --git a/sql/021-config-functions.sql b/sql/021-config-functions.sql index a0b88fc5..22093bc7 100644 --- a/sql/021-config-functions.sql +++ b/sql/021-config-functions.sql @@ -299,7 +299,7 @@ AS $$ $$ LANGUAGE plpgsql; -DROP FUNCTION IF EXISTS cs_add_column_v1(table_name text, column_name text); +DROP FUNCTION IF EXISTS cs_add_column_v1(table_name text, column_name text, cast_as text); CREATE FUNCTION cs_add_column_v1(table_name text, column_name text, cast_as text DEFAULT 'text') RETURNS jsonb diff --git a/tests/config.sql b/tests/config.sql index d094d6a8..64b117e2 100644 --- a/tests/config.sql +++ b/tests/config.sql @@ -148,8 +148,12 @@ INSERT INTO cs_configuration_v1 (state, data) VALUES ( "blah": { "cast_as": "text", "indexes": { - "match": {} + "match": {} } + }, + "vtha": { + "cast_as": "text", + "indexes": {} } } } From e8ca23a4c1ad7ce565e92b52e945f3af6426d0a6 Mon Sep 17 00:00:00 2001 From: Toby Hede Date: Mon, 4 Nov 2024 10:04:56 +1100 Subject: [PATCH 08/12] Update sql/010-core.sql Co-authored-by: Drew Thomas --- sql/010-core.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/010-core.sql b/sql/010-core.sql index 1302c01c..b3c655ad 100644 --- a/sql/010-core.sql +++ b/sql/010-core.sql @@ -93,7 +93,7 @@ AS $$ END; $$ LANGUAGE plpgsql; --- Should include an ident field +-- Ident field should include table and column DROP FUNCTION IF EXISTS _cs_encrypted_check_i_ct(jsonb); CREATE FUNCTION _cs_encrypted_check_i_ct(val jsonb) RETURNS boolean From d034b109a39871e4b048af7ff13d344633ed50cc Mon Sep 17 00:00:00 2001 From: Toby Hede Date: Mon, 4 Nov 2024 10:05:02 +1100 Subject: [PATCH 09/12] Update tests/core.sql Co-authored-by: Drew Thomas --- tests/core.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core.sql b/tests/core.sql index 5558f3b8..3076bff2 100644 --- a/tests/core.sql +++ b/tests/core.sql @@ -93,7 +93,7 @@ INSERT INTO users (name_encrypted) VALUES ( }'::jsonb ); --- npo kind +-- no kind INSERT INTO users (name_encrypted) VALUES ( '{ "v": 1, From 8b3c0b49441afe07840cbe76ef96add28952e2be Mon Sep 17 00:00:00 2001 From: Toby Hede Date: Mon, 4 Nov 2024 10:05:08 +1100 Subject: [PATCH 10/12] Update sql/010-core.sql Co-authored-by: Drew Thomas --- sql/010-core.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/010-core.sql b/sql/010-core.sql index b3c655ad..b0b42b94 100644 --- a/sql/010-core.sql +++ b/sql/010-core.sql @@ -106,7 +106,7 @@ AS $$ END; $$ LANGUAGE plpgsql; --- Should include an ident field +-- Should include a version field DROP FUNCTION IF EXISTS _cs_encrypted_check_v(jsonb); CREATE FUNCTION _cs_encrypted_check_v(val jsonb) RETURNS boolean From c1fda665cef36676280f0f22b755424b0d592313 Mon Sep 17 00:00:00 2001 From: Toby Hede Date: Mon, 4 Nov 2024 10:34:10 +1100 Subject: [PATCH 11/12] Add query q check --- sql/010-core.sql | 14 ++++++++++++++ sql/020-config-schema.sql | 4 ++-- tests/config.sql | 2 +- tests/core.sql | 29 ++++++++++++++++++++--------- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/sql/010-core.sql b/sql/010-core.sql index b0b42b94..ab639041 100644 --- a/sql/010-core.sql +++ b/sql/010-core.sql @@ -93,6 +93,19 @@ AS $$ END; $$ LANGUAGE plpgsql; +-- Query field should never be present in an encrypted column +DROP FUNCTION IF EXISTS _cs_encrypted_check_q(jsonb); +CREATE FUNCTION _cs_encrypted_check_q(val jsonb) + RETURNS boolean +AS $$ + BEGIN + IF val ? 'q' + RAISE 'Encrypted column should not have a query (q) field (%).', val->>'q'; + END IF; + RETURN true; + END; +$$ LANGUAGE plpgsql; + -- Ident field should include table and column DROP FUNCTION IF EXISTS _cs_encrypted_check_i_ct(jsonb); CREATE FUNCTION _cs_encrypted_check_i_ct(val jsonb) @@ -132,6 +145,7 @@ BEGIN ATOMIC _cs_encrypted_check_k(val) AND _cs_encrypted_check_k_ct(val) AND _cs_encrypted_check_k_sv(val) AND + _cs_encrypted_check_q(val) AND _cs_encrypted_check_p(val) ); END; diff --git a/sql/020-config-schema.sql b/sql/020-config-schema.sql index d3bcc7b5..a54b3dc2 100644 --- a/sql/020-config-schema.sql +++ b/sql/020-config-schema.sql @@ -62,7 +62,7 @@ AS $$ IF (SELECT bool_and(index = ANY('{match, ore, unique, ste_vec}')) FROM _cs_extract_indexes(val) AS index) THEN RETURN true; END IF; - RAISE 'Invalid index (%) in configuration. Index should be one of {match, ore, unique, ste_vec}', val; + RAISE 'Configuration has an invalid index (%). Index should be one of {match, ore, unique, ste_vec}', val; END IF; RETURN true; END; @@ -78,7 +78,7 @@ AS $$ IF EXISTS (SELECT jsonb_array_elements_text(jsonb_path_query_array(val, '$.tables.*.*.cast_as')) = ANY('{text, int, small_int, big_int, real, double, boolean, date, jsonb}')) THEN RETURN true; END IF; - RAISE 'Invalid cast (%) in configuration. Cast should be one of {text, int, small_int, big_int, real, double, boolean, date, jsonb}', val; + RAISE 'Configuration has an invalid cast_as (%). Cast should be one of {text, int, small_int, big_int, real, double, boolean, date, jsonb}', val; END; $$ LANGUAGE plpgsql; diff --git a/tests/config.sql b/tests/config.sql index 64b117e2..8274935a 100644 --- a/tests/config.sql +++ b/tests/config.sql @@ -211,7 +211,7 @@ TRUNCATE TABLE cs_configuration_v1; DO $$ BEGIN - RAISE NOTICE 'Configuration tests: 4 errors expected'; + RAISE NOTICE 'cs_configuration_v1 constraint tests: 4 errors expected here'; END; $$ LANGUAGE plpgsql; -- diff --git a/tests/core.sql b/tests/core.sql index 3076bff2..6349a4d1 100644 --- a/tests/core.sql +++ b/tests/core.sql @@ -59,7 +59,7 @@ $$ LANGUAGE plpgsql; -- ----------------------------------------------- --- --- cs_enncrypted)v1 tyoe +-- cs_encrypted_v1 tyoe -- Validate configuration schema -- Try and insert many invalid configurations -- None should exist @@ -70,6 +70,12 @@ TRUNCATE TABLE users; \set ON_ERROR_STOP off \set ON_ERROR_ROLLBACK on +DO $$ + BEGIN + RAISE NOTICE 'cs_encrypted_v1 constraint tests: 10 errors expected here'; + END; +$$ LANGUAGE plpgsql; + -- no version INSERT INTO users (name_encrypted) VALUES ( @@ -120,12 +126,9 @@ INSERT INTO users (name_encrypted) VALUES ( }'::jsonb ); - - -- pt INSERT INTO users (name_encrypted) VALUES ( '{ - "v": 1, "v": 1, "k": "pt", "i": { @@ -138,7 +141,6 @@ INSERT INTO users (name_encrypted) VALUES ( --pt with ciphertext INSERT INTO users (name_encrypted) VALUES ( '{ - "v": 1, "v": 1, "k": "pt", "c": "ciphertext", @@ -149,11 +151,9 @@ INSERT INTO users (name_encrypted) VALUES ( }'::jsonb ); - -- ct without ciphertext INSERT INTO users (name_encrypted) VALUES ( '{ - "v": 1, "v": 1, "k": "ct", "i": { @@ -167,7 +167,6 @@ INSERT INTO users (name_encrypted) VALUES ( -- ct with plaintext INSERT INTO users (name_encrypted) VALUES ( '{ - "v": 1, "v": 1, "k": "ct", "p": "plaintext", @@ -182,7 +181,6 @@ INSERT INTO users (name_encrypted) VALUES ( -- ciphertext without ct INSERT INTO users (name_encrypted) VALUES ( '{ - "v": 1, "v": 1, "c": "ciphertext", "i": { @@ -192,6 +190,19 @@ INSERT INTO users (name_encrypted) VALUES ( }'::jsonb ); +-- ciphertext with invalid q +INSERT INTO users (name_encrypted) VALUES ( + '{ + "v": 1, + "c": "ciphertext", + "i": { + "t": "users", + "c": "name" + }, + "q": "invalid" + }'::jsonb +); + -- Nothing should be in the DB DO $$ BEGIN From d990761df0fa03d0599e55a58bfb7e99eddd5f90 Mon Sep 17 00:00:00 2001 From: Toby Hede Date: Mon, 4 Nov 2024 10:49:03 +1100 Subject: [PATCH 12/12] Align constraint error language --- sql/010-core.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/010-core.sql b/sql/010-core.sql index ab639041..6ddc00da 100644 --- a/sql/010-core.sql +++ b/sql/010-core.sql @@ -100,7 +100,7 @@ CREATE FUNCTION _cs_encrypted_check_q(val jsonb) AS $$ BEGIN IF val ? 'q' - RAISE 'Encrypted column should not have a query (q) field (%).', val->>'q'; + RAISE 'Encrypted column includes query (q) field: %', val; END IF; RETURN true; END;