mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-23 01:59:24 +02:00
* feat(autopilot): add View/Write permission layer Autopilot write and execute operations were gated only by workspace membership, so any member could edit, delete, trigger, or rotate the webhook of any autopilot, and GetAutopilot returned webhook tokens to every member (a token alone can trigger the autopilot). - Add canWriteAutopilot / requireAutopilotWrite: update, delete, trigger, replay-delivery, and all trigger/secret management now require the autopilot creator or a workspace owner/admin. - Redact webhook_token/path/url in GetAutopilot for callers without write access; trigger metadata otherwise stays visible (View default = all members). Creating an autopilot stays open to any member. - ANDs with the existing private-assignee-agent dispatch gate. MUL-3807 Co-authored-by: multica-agent <github@multica.ai> * feat(autopilot): delegate write access via collaborators + manage-access UI Adds an explicit grant primitive so an autopilot's creator/admin can authorize specific workspace members to manage it, with a frontend entry point — beyond the implicit creator/owner-admin set from the prior commit. Backend: - New autopilot_collaborator table (migration 128, members-only, app-layer cleanup, no FK) + sqlc queries. - memberCanWriteAutopilot now also honors explicit collaborators; the write gate, webhook-secret redaction, and a new per-caller can_write flag (on list + detail) all flow through it. - POST/DELETE /api/autopilots/{id}/collaborators (writer-gated); GetAutopilot embeds the collaborators list. Delete cleans up grants in its transaction. - Tests: grant->write->revoke flow, non-writer can't grant, non-member rejected. Frontend (web + desktop via packages/views): - ManageAccessDialog: member picker to grant/revoke, current list with remove. - 'Manage access' entry in the autopilot detail header; edit/run/add-trigger/ delete and the list-row kebab + per-trigger rotate/delete now gate on can_write (absent => allowed, server stays the gate). - can_write wired through types/schema/api client/mutations; en + zh-Hans copy. MUL-3807 Co-authored-by: multica-agent <github@multica.ai> * fix(autopilot): add manage-access i18n keys to ja/ko locales The locale parity test requires every non-EN bundle to cover every EN key. The prior commit added detail.manage_access + the access.* block to en and zh-Hans only, failing parity for ja and ko. Add the translated keys to both. Co-authored-by: multica-agent <github@multica.ai> * fix(autopilot): restrict access-list management to creator/admin only Final-review fix: AddAutopilotCollaborator/RemoveAutopilotCollaborator used requireAutopilotWrite, which counts granted collaborators as writers — so a collaborator could in turn grant/revoke others, a privilege escalation contradicting the 'collaborators cannot re-grant' design. - New requireAutopilotAccessManagement guard uses the narrower autopilotWriteByOwnership predicate (creator or workspace owner/admin only); swapped into both collaborator endpoints. Collaborators keep their edit/trigger/secret write-execute rights. - GetAutopilot now also stamps can_manage_access (narrower than can_write); the detail page gates the 'Manage access' button on it so collaborators no longer see an entry that would 403. - Tests: collaborator grant-others -> 403, revoke-peer -> 403, while retaining edit; can_manage_access true for owner, false for collaborator. MUL-3807 Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: J <j@multica.ai> Co-authored-by: multica-agent <github@multica.ai>
24 lines
1.2 KiB
SQL
24 lines
1.2 KiB
SQL
-- Explicit write grants for autopilots: lets an autopilot's creator (or a
|
||
-- workspace owner/admin) authorize specific workspace members to manage the
|
||
-- autopilot, beyond the implicit "creator ∪ owner/admin" set. A member listed
|
||
-- here is treated as a writer — they can edit, delete, trigger, replay
|
||
-- deliveries, and manage triggers/webhook secrets (MUL-3807).
|
||
--
|
||
-- No foreign keys or cascades — autopilot existence and workspace membership
|
||
-- are enforced in the application layer (the autopilot delete handler removes
|
||
-- these rows in the same transaction; membership is checked at the API
|
||
-- boundary), per the repo rule. Mirrors autopilot_subscriber.
|
||
CREATE TABLE autopilot_collaborator (
|
||
autopilot_id UUID NOT NULL,
|
||
user_type TEXT NOT NULL CHECK (user_type IN ('member')),
|
||
user_id UUID NOT NULL,
|
||
granted_by UUID NOT NULL,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
PRIMARY KEY (autopilot_id, user_type, user_id)
|
||
);
|
||
|
||
-- Reverse-lookup index for "which autopilots can this member write?" — the PK
|
||
-- can't answer that since autopilot_id is its leading column.
|
||
CREATE INDEX idx_autopilot_collaborator_user
|
||
ON autopilot_collaborator (user_type, user_id);
|