Skip to content

Commit 04fd3c2

Browse files
authored
Merge pull request #46 from cipherstash/CIP-916/allow-jsonb-target-columns
Allow jsonb columns as encrypted targets
2 parents a2b70a0 + 84b5f31 commit 04fd3c2

File tree

4 files changed

+112
-7
lines changed

4 files changed

+112
-7
lines changed

sql/021-config-functions.sql

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,20 +226,39 @@ AS $$
226226
$$ LANGUAGE plpgsql;
227227

228228

229+
230+
--
231+
--
232+
-- Marks the currently `pending` configuration as `encrypting`.
233+
--
234+
-- Validates the database schema and raises an exception if the configured columns are not of `jsonb` or `cs_encrypted_v1` type.
235+
--
236+
-- Accepts an optional `force` parameter.
237+
-- If `force` is `true`, the schema validation is skipped.
238+
--
239+
-- Raises an exception if the configuration is already `encrypting` or if there is no `pending` configuration to encrypt.
240+
--
229241
DROP FUNCTION IF EXISTS cs_encrypt_v1();
230242

231-
CREATE FUNCTION cs_encrypt_v1()
243+
CREATE FUNCTION cs_encrypt_v1(force boolean DEFAULT false)
232244
RETURNS boolean
233245
AS $$
234246
BEGIN
235-
IF NOT cs_ready_for_encryption_v1() THEN
236-
RAISE EXCEPTION 'Some pending columns do not have an encrypted target';
247+
248+
IF EXISTS (SELECT FROM cs_configuration_v1 c WHERE c.state = 'encrypting') THEN
249+
RAISE EXCEPTION 'An encryption is already in progress';
237250
END IF;
238251

239252
IF NOT EXISTS (SELECT FROM cs_configuration_v1 c WHERE c.state = 'pending') THEN
240253
RAISE EXCEPTION 'No pending configuration exists to encrypt';
241254
END IF;
242255

256+
IF NOT force THEN
257+
IF NOT cs_ready_for_encryption_v1() THEN
258+
RAISE EXCEPTION 'Some pending columns do not have an encrypted target';
259+
END IF;
260+
END IF;
261+
243262
UPDATE cs_configuration_v1 SET state = 'encrypting' WHERE state = 'pending';
244263
RETURN true;
245264
END;

sql/030-encryptindex.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ AS $$
8787
LEFT JOIN information_schema.columns s ON
8888
s.table_name = c.table_name AND
8989
(s.column_name = c.column_name OR s.column_name = c.column_name || '_encrypted') AND
90-
s.domain_name = 'cs_encrypted_v1';
90+
(s.domain_name = 'cs_encrypted_v1' OR s.data_type = 'jsonb');
9191
$$ LANGUAGE sql;
9292

9393

sql/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
### Adding SQL
2+
3+
4+
- Never drop the configuration table as it may contain customer data and needs to live across EQL versions
5+
- Everything else should have a `DROP IF EXISTS`
6+
- Functions should be `DROP` and `CREATE`, instead of `CREATE OR REPLACE`
7+
- Data types cannot be changed once created, so dropping first is more flexible
8+
- Keep `DROP` and `CREATE` together in the code
9+
- Types need to be dropped last, add to the `666-drop_types.sql`
10+
11+
12+
13+

tests/encryptindex.sql

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ $$ LANGUAGE plpgsql;
114114

115115

116116
-- -----------------------------------------------
117-
-- Start encryptindexing wwith no target table
117+
-- Start encryptindexing with no target table
118118
--
119119
-- The schema should be validated first.
120120
-- Users table does not exist, so should fail.
@@ -129,7 +129,7 @@ DO $$
129129

130130
BEGIN
131131
PERFORM cs_encrypt_v1();
132-
RAISE NOTICE 'Missinbg users table. Encrypt should have failed.';
132+
RAISE NOTICE 'Missing users table. Encrypt should have failed.';
133133
ASSERT false; -- skipped by exception
134134
EXCEPTION
135135
WHEN OTHERS THEN
@@ -143,6 +143,29 @@ DO $$
143143
$$ LANGUAGE plpgsql;
144144

145145

146+
-- -----------------------------------------------
147+
-- FORCE start encryptindexing with no target table
148+
--
149+
-- Schema validation is skipped
150+
-- -----------------------------------------------
151+
DROP TABLE IF EXISTS users;
152+
TRUNCATE TABLE cs_configuration_v1;
153+
154+
155+
DO $$
156+
BEGIN
157+
PERFORM cs_add_index_v1('users', 'name', 'match');
158+
159+
PERFORM cs_encrypt_v1(true);
160+
RAISE NOTICE 'Missing users table. Encrypt should have failed.';
161+
162+
-- configuration state should be changed
163+
ASSERT (SELECT NOT EXISTS (SELECT FROM cs_configuration_v1 c WHERE c.state = 'pending'));
164+
ASSERT (SELECT EXISTS (SELECT FROM cs_configuration_v1 c WHERE c.state = 'encrypting'));
165+
166+
END;
167+
$$ LANGUAGE plpgsql;
168+
146169

147170
-- -----------------------------------------------
148171
-- With existing active config
@@ -171,7 +194,7 @@ INSERT INTO cs_configuration_v1 (state, data) VALUES (
171194
}'::jsonb
172195
);
173196

174-
-- Create a table with multiple plaintext columns
197+
-- Create a table with plaintext and encrypted columns
175198
DROP TABLE IF EXISTS users;
176199
CREATE TABLE users
177200
(
@@ -195,6 +218,56 @@ DO $$
195218
$$ LANGUAGE plpgsql;
196219

197220

221+
-- -----------------------------------------------
222+
-- With existing active config and an updated schema using a raw JSONB column
223+
-- Start encryptindexing
224+
-- The active config is unchanged
225+
-- The pending config should now be encrypting
226+
-- -----------------------------------------------
227+
TRUNCATE TABLE cs_configuration_v1;
228+
229+
-- create an active configuration
230+
INSERT INTO cs_configuration_v1 (state, data) VALUES (
231+
'active',
232+
'{
233+
"v": 1,
234+
"tables": {
235+
"users": {
236+
"name": {
237+
"cast_as": "text",
238+
"indexes": {
239+
"unique": {}
240+
}
241+
}
242+
}
243+
}
244+
}'::jsonb
245+
);
246+
247+
-- Create a table with plaintext and jsonb column
248+
DROP TABLE IF EXISTS users;
249+
CREATE TABLE users
250+
(
251+
id bigint GENERATED ALWAYS AS IDENTITY,
252+
name TEXT,
253+
name_encrypted jsonb,
254+
PRIMARY KEY(id)
255+
);
256+
257+
258+
-- An encrypting config should exist
259+
DO $$
260+
BEGIN
261+
PERFORM cs_add_index_v1('users', 'name', 'match');
262+
PERFORM cs_encrypt_v1();
263+
264+
ASSERT (SELECT EXISTS (SELECT FROM cs_configuration_v1 c WHERE c.state = 'active'));
265+
ASSERT (SELECT EXISTS (SELECT FROM cs_configuration_v1 c WHERE c.state = 'encrypting'));
266+
ASSERT (SELECT NOT EXISTS (SELECT FROM cs_configuration_v1 c WHERE c.state = 'pending'));
267+
END;
268+
$$ LANGUAGE plpgsql;
269+
270+
198271
-- -----------------------------------------------
199272
-- With existing active config
200273
-- Activate encrypting config

0 commit comments

Comments
 (0)