From d1cfd9bacf6ccf229e51747782e8fde9101fbfa8 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Mon, 9 Mar 2020 16:23:07 -0700 Subject: [PATCH] BOD-5 #comment Data level changes to support audit trails. Only enabled for jobs. Potentially big impact changes from this commit forward. Details logged in reference file. --- _reference/AuditTriggerFunctions.sql | 92 +++++++++++++++++++ client/debug.log | 3 + .../1583795241718_run_sql_migration/down.yaml | 1 + .../1583795241718_run_sql_migration/up.yaml | 15 +++ .../down.yaml | 5 + .../up.yaml | 10 ++ .../down.yaml | 12 +++ .../up.yaml | 10 ++ .../down.yaml | 5 + .../up.yaml | 10 ++ .../1583795349329_run_sql_migration/down.yaml | 1 + .../1583795349329_run_sql_migration/up.yaml | 9 ++ .../1583795594722_run_sql_migration/down.yaml | 1 + .../1583795594722_run_sql_migration/up.yaml | 25 +++++ .../1583795623008_run_sql_migration/down.yaml | 1 + .../1583795623008_run_sql_migration/up.yaml | 6 ++ .../down.yaml | 30 ++++++ .../up.yaml | 52 +++++++++++ .../down.yaml | 6 ++ .../up.yaml | 32 +++++++ .../down.yaml | 6 ++ .../up.yaml | 30 ++++++ .../down.yaml | 31 +++++++ .../up.yaml | 6 ++ 24 files changed, 399 insertions(+) create mode 100644 _reference/AuditTriggerFunctions.sql create mode 100644 client/debug.log create mode 100644 hasura/migrations/1583795241718_run_sql_migration/down.yaml create mode 100644 hasura/migrations/1583795241718_run_sql_migration/up.yaml create mode 100644 hasura/migrations/1583795259202_set_fk_public_audit_trail_useremail/down.yaml create mode 100644 hasura/migrations/1583795259202_set_fk_public_audit_trail_useremail/up.yaml create mode 100644 hasura/migrations/1583795265403_set_fk_public_audit_trail_useremail/down.yaml create mode 100644 hasura/migrations/1583795265403_set_fk_public_audit_trail_useremail/up.yaml create mode 100644 hasura/migrations/1583795281646_set_fk_public_audit_trail_bodyshopid/down.yaml create mode 100644 hasura/migrations/1583795281646_set_fk_public_audit_trail_bodyshopid/up.yaml create mode 100644 hasura/migrations/1583795349329_run_sql_migration/down.yaml create mode 100644 hasura/migrations/1583795349329_run_sql_migration/up.yaml create mode 100644 hasura/migrations/1583795594722_run_sql_migration/down.yaml create mode 100644 hasura/migrations/1583795594722_run_sql_migration/up.yaml create mode 100644 hasura/migrations/1583795623008_run_sql_migration/down.yaml create mode 100644 hasura/migrations/1583795623008_run_sql_migration/up.yaml create mode 100644 hasura/migrations/1583795859969_track_all_relationships/down.yaml create mode 100644 hasura/migrations/1583795859969_track_all_relationships/up.yaml create mode 100644 hasura/migrations/1583795952143_update_permission_user_public_table_audit_trail/down.yaml create mode 100644 hasura/migrations/1583795952143_update_permission_user_public_table_audit_trail/up.yaml create mode 100644 hasura/migrations/1583795958753_update_permission_user_public_table_audit_trail/down.yaml create mode 100644 hasura/migrations/1583795958753_update_permission_user_public_table_audit_trail/up.yaml create mode 100644 hasura/migrations/1583795964235_delete_permission_user_public_table_audit_trail/down.yaml create mode 100644 hasura/migrations/1583795964235_delete_permission_user_public_table_audit_trail/up.yaml diff --git a/_reference/AuditTriggerFunctions.sql b/_reference/AuditTriggerFunctions.sql new file mode 100644 index 000000000..639c06e42 --- /dev/null +++ b/_reference/AuditTriggerFunctions.sql @@ -0,0 +1,92 @@ + + +CREATE SCHEMA audit; + +CREATE TABLE audit_trail ( + + id serial PRIMARY KEY, + + tstamp timestamp DEFAULT now(), + + schemaname text, + + tabname text, + + operation text, + recordid uuid, + + -- who text DEFAULT current_user, + + new_val json, + + old_val json, + useremail text, + bodyshopid uuid + +); + +-- More as an example than anything else, I wanted a function that would take two JSONB objects in PostgreSQL, and return how the left-hand side differs from the right-hand side. This means any key that is in the left but not in the right would be returned, along with any key whose value on the left is different from the right. + +-- Here’s a quick example of how to do this in a single SELECT. In real life, you probably want more error checking, but it shows how nice the built-in primitives are: +CREATE OR REPLACE FUNCTION json_diff(l JSONB, r JSONB) RETURNS JSONB AS +$json_diff$ + SELECT jsonb_object_agg(a.key, a.value) FROM + ( SELECT key, value FROM jsonb_each(l) ) a LEFT OUTER JOIN + ( SELECT key, value FROM jsonb_each(r) ) b ON a.key = b.key + WHERE a.value != b.value OR b.key IS NULL; +$json_diff$ + LANGUAGE sql; + + +CREATE OR REPLACE FUNCTION audit_trigger() RETURNS trigger AS $$ + + DECLARE + shopid text ; + email text; + + BEGIN + + select b.id, u.email INTO shopid, email from users u join associations a on u.email = a.useremail join bodyshops b on b.id = a.shopid where u.authid = current_setting('hasura.user', 't')::jsonb->>'x-hasura-user-id' and a.active = true; + + IF TG_OP = 'INSERT' + + THEN + + INSERT INTO public.audit_trail (tabname, schemaname, operation, new_val, recordid, bodyshopid, useremail) + + VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(NEW), NEW.id, shopid, email); + + RETURN NEW; + + ELSIF TG_OP = 'UPDATE' + + THEN + + INSERT INTO public.audit_trail (tabname, schemaname, operation, old_val, new_val, recordid, bodyshopid, useremail) + + VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, + + json_diff(to_jsonb(OLD), to_jsonb(NEW)) , json_diff(to_jsonb(NEW), to_jsonb(OLD)), OLD.id, shopid, email); + + RETURN NEW; + + ELSIF TG_OP = 'DELETE' + + THEN + + INSERT INTO public.audit_trail (tabname, schemaname, operation, old_val, recordid, bodyshopid, useremail) + + VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(OLD), OLD.ID, shopid, email); + + RETURN OLD; + + END IF; + + END; + +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + + + +CREATE TRIGGER audit_trigger_users AFTER INSERT OR UPDATE OR DELETE ON users + FOR EACH ROW EXECUTE PROCEDURE audit_trigger(); \ No newline at end of file diff --git a/client/debug.log b/client/debug.log new file mode 100644 index 000000000..5ae6436f8 --- /dev/null +++ b/client/debug.log @@ -0,0 +1,3 @@ +[0309/123120.472:ERROR:process_reader_win.cc(108)] process 40916 not found +[0309/123120.472:ERROR:exception_snapshot_win.cc(98)] thread ID 50448 not found in process +[0309/123120.472:ERROR:scoped_process_suspend.cc(40)] NtResumeProcess: An attempt was made to access an exiting process. (0xc000010a) diff --git a/hasura/migrations/1583795241718_run_sql_migration/down.yaml b/hasura/migrations/1583795241718_run_sql_migration/down.yaml new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/hasura/migrations/1583795241718_run_sql_migration/down.yaml @@ -0,0 +1 @@ +[] diff --git a/hasura/migrations/1583795241718_run_sql_migration/up.yaml b/hasura/migrations/1583795241718_run_sql_migration/up.yaml new file mode 100644 index 000000000..f8bdf2c76 --- /dev/null +++ b/hasura/migrations/1583795241718_run_sql_migration/up.yaml @@ -0,0 +1,15 @@ +- args: + cascade: false + read_only: false + sql: "CREATE TABLE audit_trail (\r\n \r\n id serial PRIMARY + KEY, \r\n \r\n created timestamp DEFAULT now(),\r\n + \r\n schemaname text,\r\n \r\n tabname text,\r\n + \r\n operation text,\r\n recordid uuid,\r\n \r\n + \ -- who text DEFAULT current_user,\r\n \r\n new_val + \ json,\r\n \r\n old_val json,\r\n + \ useremail text,\r\n bodyshopid uuid\r\n \r\n);" + type: run_sql +- args: + name: audit_trail + schema: public + type: add_existing_table_or_view diff --git a/hasura/migrations/1583795259202_set_fk_public_audit_trail_useremail/down.yaml b/hasura/migrations/1583795259202_set_fk_public_audit_trail_useremail/down.yaml new file mode 100644 index 000000000..5126a58aa --- /dev/null +++ b/hasura/migrations/1583795259202_set_fk_public_audit_trail_useremail/down.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: alter table "public"."audit_trail" drop constraint "audit_trail_useremail_fkey"; + type: run_sql diff --git a/hasura/migrations/1583795259202_set_fk_public_audit_trail_useremail/up.yaml b/hasura/migrations/1583795259202_set_fk_public_audit_trail_useremail/up.yaml new file mode 100644 index 000000000..f9377b0d6 --- /dev/null +++ b/hasura/migrations/1583795259202_set_fk_public_audit_trail_useremail/up.yaml @@ -0,0 +1,10 @@ +- args: + cascade: false + read_only: false + sql: |- + alter table "public"."audit_trail" + add constraint "audit_trail_useremail_fkey" + foreign key ("useremail") + references "public"."users" + ("email") on update restrict on delete restrict; + type: run_sql diff --git a/hasura/migrations/1583795265403_set_fk_public_audit_trail_useremail/down.yaml b/hasura/migrations/1583795265403_set_fk_public_audit_trail_useremail/down.yaml new file mode 100644 index 000000000..7190d6942 --- /dev/null +++ b/hasura/migrations/1583795265403_set_fk_public_audit_trail_useremail/down.yaml @@ -0,0 +1,12 @@ +- args: + cascade: false + read_only: false + sql: |- + alter table "public"."audit_trail" drop constraint "audit_trail_useremail_fkey", + add constraint "audit_trail_useremail_fkey" + foreign key ("useremail") + references "public"."users" + ("email") + on update restrict + on delete restrict; + type: run_sql diff --git a/hasura/migrations/1583795265403_set_fk_public_audit_trail_useremail/up.yaml b/hasura/migrations/1583795265403_set_fk_public_audit_trail_useremail/up.yaml new file mode 100644 index 000000000..77cd23149 --- /dev/null +++ b/hasura/migrations/1583795265403_set_fk_public_audit_trail_useremail/up.yaml @@ -0,0 +1,10 @@ +- args: + cascade: false + read_only: false + sql: |- + alter table "public"."audit_trail" drop constraint "audit_trail_useremail_fkey", + add constraint "audit_trail_useremail_fkey" + foreign key ("useremail") + references "public"."users" + ("email") on update restrict on delete restrict; + type: run_sql diff --git a/hasura/migrations/1583795281646_set_fk_public_audit_trail_bodyshopid/down.yaml b/hasura/migrations/1583795281646_set_fk_public_audit_trail_bodyshopid/down.yaml new file mode 100644 index 000000000..28b059e7b --- /dev/null +++ b/hasura/migrations/1583795281646_set_fk_public_audit_trail_bodyshopid/down.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: alter table "public"."audit_trail" drop constraint "audit_trail_bodyshopid_fkey"; + type: run_sql diff --git a/hasura/migrations/1583795281646_set_fk_public_audit_trail_bodyshopid/up.yaml b/hasura/migrations/1583795281646_set_fk_public_audit_trail_bodyshopid/up.yaml new file mode 100644 index 000000000..19c6197ee --- /dev/null +++ b/hasura/migrations/1583795281646_set_fk_public_audit_trail_bodyshopid/up.yaml @@ -0,0 +1,10 @@ +- args: + cascade: false + read_only: false + sql: |- + alter table "public"."audit_trail" + add constraint "audit_trail_bodyshopid_fkey" + foreign key ("bodyshopid") + references "public"."bodyshops" + ("id") on update restrict on delete restrict; + type: run_sql diff --git a/hasura/migrations/1583795349329_run_sql_migration/down.yaml b/hasura/migrations/1583795349329_run_sql_migration/down.yaml new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/hasura/migrations/1583795349329_run_sql_migration/down.yaml @@ -0,0 +1 @@ +[] diff --git a/hasura/migrations/1583795349329_run_sql_migration/up.yaml b/hasura/migrations/1583795349329_run_sql_migration/up.yaml new file mode 100644 index 000000000..ea55a6583 --- /dev/null +++ b/hasura/migrations/1583795349329_run_sql_migration/up.yaml @@ -0,0 +1,9 @@ +- args: + cascade: true + read_only: false + sql: "CREATE OR REPLACE FUNCTION json_diff(l JSONB, r JSONB) RETURNS JSONB AS\r\n$json_diff$\r\n + \ SELECT jsonb_object_agg(a.key, a.value) FROM\r\n ( SELECT key, value + FROM jsonb_each(l) ) a LEFT OUTER JOIN\r\n ( SELECT key, value FROM jsonb_each(r) + ) b ON a.key = b.key\r\n WHERE a.value != b.value OR b.key IS NULL;\r\n$json_diff$\r\n + \ LANGUAGE sql;" + type: run_sql diff --git a/hasura/migrations/1583795594722_run_sql_migration/down.yaml b/hasura/migrations/1583795594722_run_sql_migration/down.yaml new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/hasura/migrations/1583795594722_run_sql_migration/down.yaml @@ -0,0 +1 @@ +[] diff --git a/hasura/migrations/1583795594722_run_sql_migration/up.yaml b/hasura/migrations/1583795594722_run_sql_migration/up.yaml new file mode 100644 index 000000000..b5587b2db --- /dev/null +++ b/hasura/migrations/1583795594722_run_sql_migration/up.yaml @@ -0,0 +1,25 @@ +- args: + cascade: true + read_only: false + sql: "CREATE OR REPLACE FUNCTION audit_trigger() RETURNS trigger AS $$\r\n \r\n + DECLARE\r\n shopid uuid ;\r\n email text;\r\n\r\n BEGIN\r\n \r\n select + b.id, u.email INTO shopid, email from users u join associations a on u.email + = a.useremail join bodyshops b on b.id = a.shopid where u.authid = current_setting('hasura.user', + 't')::jsonb->>'x-hasura-user-id' and a.active = true;\r\n\r\n IF + \ TG_OP = 'INSERT'\r\n \r\n THEN\r\n \r\n INSERT + INTO public.audit_trail (tabname, schemaname, operation, new_val, recordid, + bodyshopid, useremail)\r\n \r\n VALUES (TG_RELNAME, + TG_TABLE_SCHEMA, TG_OP, row_to_json(NEW), NEW.id, shopid, email);\r\n \r\n RETURN + NEW;\r\n \r\n ELSIF TG_OP = 'UPDATE'\r\n \r\n THEN\r\n + \r\n INSERT INTO public.audit_trail (tabname, schemaname, + operation, old_val, new_val, recordid, bodyshopid, useremail)\r\n \r\n VALUES + (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP,\r\n \r\n json_diff(to_jsonb(OLD), + to_jsonb(NEW)) , json_diff(to_jsonb(NEW), to_jsonb(OLD)), OLD.id, shopid, + email);\r\n \r\n RETURN NEW;\r\n \r\n ELSIF + \ TG_OP = 'DELETE'\r\n \r\n THEN\r\n \r\n INSERT + INTO public.audit_trail (tabname, schemaname, operation, old_val, recordid, + bodyshopid, useremail)\r\n \r\n VALUES (TG_RELNAME, + TG_TABLE_SCHEMA, TG_OP, row_to_json(OLD), OLD.ID, shopid, email);\r\n \r\n + \ RETURN OLD;\r\n \r\n END IF;\r\n \r\n + \ END;\r\n \r\n$$ LANGUAGE 'plpgsql' SECURITY DEFINER;" + type: run_sql diff --git a/hasura/migrations/1583795623008_run_sql_migration/down.yaml b/hasura/migrations/1583795623008_run_sql_migration/down.yaml new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/hasura/migrations/1583795623008_run_sql_migration/down.yaml @@ -0,0 +1 @@ +[] diff --git a/hasura/migrations/1583795623008_run_sql_migration/up.yaml b/hasura/migrations/1583795623008_run_sql_migration/up.yaml new file mode 100644 index 000000000..9808a5e1e --- /dev/null +++ b/hasura/migrations/1583795623008_run_sql_migration/up.yaml @@ -0,0 +1,6 @@ +- args: + cascade: true + read_only: false + sql: "CREATE TRIGGER audit_trigger_jobs AFTER INSERT OR UPDATE OR DELETE ON jobs\r\n + \ FOR EACH ROW EXECUTE PROCEDURE audit_trigger();" + type: run_sql diff --git a/hasura/migrations/1583795859969_track_all_relationships/down.yaml b/hasura/migrations/1583795859969_track_all_relationships/down.yaml new file mode 100644 index 000000000..22113aaa1 --- /dev/null +++ b/hasura/migrations/1583795859969_track_all_relationships/down.yaml @@ -0,0 +1,30 @@ +- args: + relationship: user + table: + name: audit_trail + schema: public + type: drop_relationship +- args: + relationship: bodyshop + table: + name: audit_trail + schema: public + type: drop_relationship +- args: + relationship: audit_trails + table: + name: bodyshops + schema: public + type: drop_relationship +- args: + relationship: invoices + table: + name: jobs + schema: public + type: drop_relationship +- args: + relationship: audit_trails + table: + name: users + schema: public + type: drop_relationship diff --git a/hasura/migrations/1583795859969_track_all_relationships/up.yaml b/hasura/migrations/1583795859969_track_all_relationships/up.yaml new file mode 100644 index 000000000..4dd73c75d --- /dev/null +++ b/hasura/migrations/1583795859969_track_all_relationships/up.yaml @@ -0,0 +1,52 @@ +- args: + name: user + table: + name: audit_trail + schema: public + using: + foreign_key_constraint_on: useremail + type: create_object_relationship +- args: + name: bodyshop + table: + name: audit_trail + schema: public + using: + foreign_key_constraint_on: bodyshopid + type: create_object_relationship +- args: + name: audit_trails + table: + name: bodyshops + schema: public + using: + foreign_key_constraint_on: + column: bodyshopid + table: + name: audit_trail + schema: public + type: create_array_relationship +- args: + name: invoices + table: + name: jobs + schema: public + using: + foreign_key_constraint_on: + column: jobid + table: + name: invoices + schema: public + type: create_array_relationship +- args: + name: audit_trails + table: + name: users + schema: public + using: + foreign_key_constraint_on: + column: useremail + table: + name: audit_trail + schema: public + type: create_array_relationship diff --git a/hasura/migrations/1583795952143_update_permission_user_public_table_audit_trail/down.yaml b/hasura/migrations/1583795952143_update_permission_user_public_table_audit_trail/down.yaml new file mode 100644 index 000000000..a089342f6 --- /dev/null +++ b/hasura/migrations/1583795952143_update_permission_user_public_table_audit_trail/down.yaml @@ -0,0 +1,6 @@ +- args: + role: user + table: + name: audit_trail + schema: public + type: drop_insert_permission diff --git a/hasura/migrations/1583795952143_update_permission_user_public_table_audit_trail/up.yaml b/hasura/migrations/1583795952143_update_permission_user_public_table_audit_trail/up.yaml new file mode 100644 index 000000000..98f8fe2c6 --- /dev/null +++ b/hasura/migrations/1583795952143_update_permission_user_public_table_audit_trail/up.yaml @@ -0,0 +1,32 @@ +- args: + permission: + allow_upsert: true + check: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + columns: + - id + - created + - schemaname + - tabname + - operation + - recordid + - new_val + - old_val + - useremail + - bodyshopid + localPresets: + - key: "" + value: "" + set: {} + role: user + table: + name: audit_trail + schema: public + type: create_insert_permission diff --git a/hasura/migrations/1583795958753_update_permission_user_public_table_audit_trail/down.yaml b/hasura/migrations/1583795958753_update_permission_user_public_table_audit_trail/down.yaml new file mode 100644 index 000000000..08e9eb62d --- /dev/null +++ b/hasura/migrations/1583795958753_update_permission_user_public_table_audit_trail/down.yaml @@ -0,0 +1,6 @@ +- args: + role: user + table: + name: audit_trail + schema: public + type: drop_select_permission diff --git a/hasura/migrations/1583795958753_update_permission_user_public_table_audit_trail/up.yaml b/hasura/migrations/1583795958753_update_permission_user_public_table_audit_trail/up.yaml new file mode 100644 index 000000000..e36789f21 --- /dev/null +++ b/hasura/migrations/1583795958753_update_permission_user_public_table_audit_trail/up.yaml @@ -0,0 +1,30 @@ +- args: + permission: + allow_aggregations: false + columns: + - id + - new_val + - old_val + - operation + - schemaname + - tabname + - useremail + - created + - bodyshopid + - recordid + computed_fields: [] + filter: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + limit: null + role: user + table: + name: audit_trail + schema: public + type: create_select_permission diff --git a/hasura/migrations/1583795964235_delete_permission_user_public_table_audit_trail/down.yaml b/hasura/migrations/1583795964235_delete_permission_user_public_table_audit_trail/down.yaml new file mode 100644 index 000000000..e98aa1da4 --- /dev/null +++ b/hasura/migrations/1583795964235_delete_permission_user_public_table_audit_trail/down.yaml @@ -0,0 +1,31 @@ +- args: + permission: + check: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + columns: + - id + - created + - schemaname + - tabname + - operation + - recordid + - new_val + - old_val + - useremail + - bodyshopid + localPresets: + - key: "" + value: "" + set: {} + role: user + table: + name: audit_trail + schema: public + type: create_insert_permission diff --git a/hasura/migrations/1583795964235_delete_permission_user_public_table_audit_trail/up.yaml b/hasura/migrations/1583795964235_delete_permission_user_public_table_audit_trail/up.yaml new file mode 100644 index 000000000..a089342f6 --- /dev/null +++ b/hasura/migrations/1583795964235_delete_permission_user_public_table_audit_trail/up.yaml @@ -0,0 +1,6 @@ +- args: + role: user + table: + name: audit_trail + schema: public + type: drop_insert_permission