From cedff5154a143bc2a064e64d2e51643ed3307c33 Mon Sep 17 00:00:00 2001 From: Michelangelo Mori Date: Fri, 22 Nov 2024 14:43:56 +0100 Subject: [PATCH] Add project id foreign key to data sources tables. Tables `data_sources_functions` and `rule_type_data_sources` added by migration 108 lacked a reference to their containing project. This change adds `project_id` foreign key in the style of `rule_instances` in order to avoid future mistakes like exposing resouces by id to users that don't have rights on the containing project. --- .../000109_data_sources_project_id.down.sql | 17 +++++ .../000109_data_sources_project_id.up.sql | 69 +++++++++++++++++++ internal/db/models.go | 2 + 3 files changed, 88 insertions(+) create mode 100644 database/migrations/000109_data_sources_project_id.down.sql create mode 100644 database/migrations/000109_data_sources_project_id.up.sql diff --git a/database/migrations/000109_data_sources_project_id.down.sql b/database/migrations/000109_data_sources_project_id.down.sql new file mode 100644 index 0000000000..6354f3ca23 --- /dev/null +++ b/database/migrations/000109_data_sources_project_id.down.sql @@ -0,0 +1,17 @@ +-- SPDX-FileCopyrightText: Copyright 2024 The Minder Authors +-- SPDX-License-Identifier: Apache-2.0 + +BEGIN; + +DROP INDEX data_sources_functions_name_lower_idx; + +ALTER TABLE data_sources_functions + DROP COLUMN project_id; + +CREATE UNIQUE INDEX data_sources_functions_name_lower_idx + ON data_sources_functions (data_source_id, lower(name)); + +ALTER TABLE rule_type_data_sources + DROP COLUMN project_id; + +COMMIT; diff --git a/database/migrations/000109_data_sources_project_id.up.sql b/database/migrations/000109_data_sources_project_id.up.sql new file mode 100644 index 0000000000..8025de93b5 --- /dev/null +++ b/database/migrations/000109_data_sources_project_id.up.sql @@ -0,0 +1,69 @@ +-- SPDX-FileCopyrightText: Copyright 2024 The Minder Authors +-- SPDX-License-Identifier: Apache-2.0 + +BEGIN; + +-- In the previous migration we forgot to add `project_id` foreign key +-- to both `data_sources_functions` and `rule_type_data_sources` +-- tables. +-- +-- While having that foreign key is not terribly important from the +-- data model perspective, since a function is indirectly connected to +-- a project id anyway, from the security perspective we want to +-- ensure that all database objects are tied to a single project and +-- all statements operating on them explicitly filter by project id, +-- since project is the entity by which we enforce permissions. + +-- fix data_sources_functions + +ALTER TABLE data_sources_functions + ADD COLUMN project_id UUID; + +DO $$ +DECLARE + ds_id UUID; + pj_id UUID; +BEGIN + FOR ds_id, pj_id IN SELECT id, project_id FROM data_sources + LOOP + UPDATE data_sources_functions + SET project_id = pj_id + WHERE data_source_id = ds_id; + END LOOP; +END $$; + +ALTER TABLE data_sources_functions + ALTER COLUMN project_id SET NOT NULL; +ALTER TABLE data_sources_functions + ADD CONSTRAINT data_sources_functions_project_id_fkey + FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; + +DROP INDEX data_sources_functions_name_lower_idx; +CREATE UNIQUE INDEX data_sources_functions_name_lower_idx + ON data_sources_functions (data_source_id, project_id, lower(name)); + +-- fix rule_type_data_sources + +ALTER TABLE rule_type_data_sources + ADD COLUMN project_id UUID; + +DO $$ +DECLARE + ds_id UUID; + pj_id UUID; +BEGIN + FOR ds_id, pj_id IN SELECT id, project_id FROM data_sources + LOOP + UPDATE rule_type_data_sources + SET project_id = pj_id + WHERE data_sources_id = ds_id; + END LOOP; +END $$; + +ALTER TABLE rule_type_data_sources + ALTER COLUMN project_id SET NOT NULL; +ALTER TABLE rule_type_data_sources + ADD CONSTRAINT rule_type_data_sources_project_id_fkey + FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; + +COMMIT; diff --git a/internal/db/models.go b/internal/db/models.go index 85de72ccc2..8011451821 100644 --- a/internal/db/models.go +++ b/internal/db/models.go @@ -512,6 +512,7 @@ type DataSourcesFunction struct { Definition json.RawMessage `json:"definition"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` + ProjectID uuid.UUID `json:"project_id"` } type Entitlement struct { @@ -758,6 +759,7 @@ type RuleType struct { type RuleTypeDataSource struct { RuleTypeID uuid.UUID `json:"rule_type_id"` DataSourcesID uuid.UUID `json:"data_sources_id"` + ProjectID uuid.UUID `json:"project_id"` } type SessionStore struct {