mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-04 22:13:34 +00:00
Deleting a team failed with SQLSTATE 23514 whenever it owned a team-scoped vault document. The vault_documents.team_id FK is ON DELETE SET NULL; when team_id became NULL the vault_docs_team_null_scope_fix() trigger (migration 000043) unconditionally set scope='personal'. Team docs have agent_id IS NULL, so the resulting (personal, agent_id NULL) row violates the vault_documents_scope_consistency CHECK and aborts the whole delete. PostgreSQL: migration 000089 replaces the trigger function to pick a valid target scope by ownership, and only rewrite genuinely team-scoped rows so scope='custom' docs that merely carry a team_id are preserved: agent_id IS NOT NULL -> 'personal' (defensive: legacy dirty rows) agent_id IS NULL -> 'shared' (normal team docs) SQLite: the same class of bug exists (FK SET NULL leaves scope='team' with a NULL team_id and aborts on the CHECK), but SQLite fires no trigger during the FK action, so a DB-level fix is impossible. SQLiteTeamStore.DeleteTeam now converts team-scoped docs in the same transaction before removing the team, scoped by tenant_id in the tenant path to keep tenant isolation. Adds regression tests on both engines and bumps RequiredSchemaVersion to 89. SQLite needs no schema migration since the fix is in Go code.
23 lines
1.2 KiB
PL/PgSQL
23 lines
1.2 KiB
PL/PgSQL
-- Fix issue #1077: deleting a team fails when it owns team-scoped vault docs.
|
|
--
|
|
-- vault_documents.team_id is a FK with ON DELETE SET NULL. When team_id becomes
|
|
-- NULL, the trg_vault_docs_team_null_scope trigger auto-corrects scope. The original
|
|
-- function (migration 000043) set scope='personal' unconditionally, but team-scoped
|
|
-- docs have agent_id IS NULL, so the resulting (scope='personal', agent_id IS NULL)
|
|
-- row violates vault_documents_scope_consistency (migration 000055/000056) and aborts
|
|
-- the whole delete with SQLSTATE 23514.
|
|
--
|
|
-- Pick a scope that keeps the ownership invariant, and only rewrite genuinely
|
|
-- team-scoped rows so scope='custom' docs that merely carry a team_id are left intact:
|
|
-- agent_id IS NOT NULL -> 'personal' (defensive: tolerate legacy dirty rows)
|
|
-- agent_id IS NULL -> 'shared' (normal team docs; the common case)
|
|
CREATE OR REPLACE FUNCTION vault_docs_team_null_scope_fix()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
IF NEW.team_id IS NULL AND OLD.team_id IS NOT NULL AND OLD.scope = 'team' THEN
|
|
NEW.scope := CASE WHEN NEW.agent_id IS NOT NULL THEN 'personal' ELSE 'shared' END;
|
|
END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|