fix(schema): enforce cross-space FK on tasks.project_id via composite key
Security review flagged that tasks.project_id could reference a project in a different space. Added composite FK (project_id, space_id) -> projects(id, space_id) with ON DELETE SET NULL (project_id) so a deleted project leaves the task in its space with project_id NULL rather than orphaning into a NULL space. Added two regression tests: cross-space FK rejection + cascade behavior.
This commit is contained in:
@@ -20,13 +20,18 @@ CREATE TABLE projects (
|
||||
completed_at timestamptz,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
UNIQUE (space_id, slug)
|
||||
UNIQUE (space_id, slug),
|
||||
-- Composite key target for tasks.(project_id, space_id) FK below
|
||||
UNIQUE (id, space_id)
|
||||
);
|
||||
|
||||
CREATE TABLE tasks (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
space_id uuid NOT NULL REFERENCES spaces(id) ON DELETE CASCADE,
|
||||
project_id uuid REFERENCES projects(id) ON DELETE SET NULL,
|
||||
project_id uuid,
|
||||
-- Cross-space FK enforcement: a task's project (if set) must live in the same space.
|
||||
FOREIGN KEY (project_id, space_id) REFERENCES projects(id, space_id)
|
||||
ON DELETE SET NULL (project_id),
|
||||
title text NOT NULL,
|
||||
body text,
|
||||
status text NOT NULL DEFAULT 'todo'
|
||||
|
||||
Reference in New Issue
Block a user