mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-18 06:13:54 +00:00
Merge main (roles and access revamp) into connectors
Main's access model (team editors and viewers, edit_credentials, owner-only OAuth servers, per-user tool preferences, resource sponsors) now applies to connection-backed tools and sources. Our migrations are renumbered to 0040_connections and 0041_connection_account_name, after main's 0038_resource_access_settings and 0039_resource_sponsors. Where the two sides met: MCP tools save and load their connections as the tool owner, editors may add a key (a new connection on the owner's account) but never rewrite an existing connection's secret, fixed values stay owner-only, and a member's own connection is used in member mode.
This commit is contained in:
commit
a1789d2ab4
167 files changed
+16909
-2126
No files matched your search
@@ -0,0 +1,65 @@
|
||||
"""0038 resource access settings — per-asset sharing switches and tool chat prefs.
|
||||
|
||||
``resource_share_settings`` holds the owner's per-asset switches that adjust
|
||||
what the fixed roles may do on one shared resource ("Editors can share",
|
||||
"Viewers can see logs", ...). One row per ``(resource_type, resource_id)``;
|
||||
a missing row means every switch is at its default. The table is polymorphic
|
||||
like ``team_resource_grants``, so it has no FK and the switch keys are
|
||||
validated in code (``docsgpt/api/user/resource_access.py``), which keeps new
|
||||
switches migration-free.
|
||||
|
||||
``user_tool_preferences`` is the personal "In my chats" switch for a tool
|
||||
shared with the caller. A grantee can't write the owner's ``user_tools.status``
|
||||
(that is the owner's own chat setting), so each grantee gets a row here.
|
||||
A missing row means off: sharing a tool never adds it to anyone's chats.
|
||||
|
||||
Idempotent both ways.
|
||||
|
||||
Revision ID: 0038_resource_access_settings
|
||||
Revises: 0037_request_traces
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
|
||||
|
||||
revision: str = "0038_resource_access_settings"
|
||||
down_revision: Union[str, None] = "0037_request_traces"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS resource_share_settings (
|
||||
resource_type TEXT NOT NULL
|
||||
CONSTRAINT resource_share_settings_type_check
|
||||
CHECK (resource_type IN ('agent', 'source', 'prompt', 'tool')),
|
||||
resource_id UUID NOT NULL,
|
||||
settings JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
updated_by TEXT,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (resource_type, resource_id)
|
||||
);
|
||||
"""
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS user_tool_preferences (
|
||||
user_id TEXT NOT NULL,
|
||||
tool_id UUID NOT NULL REFERENCES user_tools(id) ON DELETE CASCADE,
|
||||
in_chat BOOLEAN NOT NULL DEFAULT false,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (user_id, tool_id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS user_tool_preferences_tool_idx
|
||||
ON user_tool_preferences (tool_id);
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.execute("DROP TABLE IF EXISTS user_tool_preferences;")
|
||||
op.execute("DROP TABLE IF EXISTS resource_share_settings;")
|
||||
@@ -0,0 +1,40 @@
|
||||
"""0039 resource sponsors — who vouches for a saved resource the owner can't use.
|
||||
|
||||
An agent (and a workflow) runs as its owner, so every source, prompt and tool
|
||||
it references is authorized against the owner. A team editor who attaches
|
||||
their own private tool, prompt or source would have it dropped at run time.
|
||||
``resource_sponsors`` records the editor who attached such a resource, keyed
|
||||
``"<type>:<id>"`` (e.g. ``{"tool:<uuid>": "bob"}``). At run time the resource
|
||||
is authorized as that sponsor, provided they can still edit the agent and
|
||||
still use the resource (``docsgpt/api/user/resource_access.py``).
|
||||
|
||||
An empty map means today's behaviour: owner-only authorization.
|
||||
|
||||
Idempotent both ways.
|
||||
|
||||
Revision ID: 0039_resource_sponsors
|
||||
Revises: 0038_resource_access_settings
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
|
||||
|
||||
revision: str = "0039_resource_sponsors"
|
||||
down_revision: Union[str, None] = "0038_resource_access_settings"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
for table in ("agents", "workflows"):
|
||||
op.execute(
|
||||
f"ALTER TABLE {table} ADD COLUMN IF NOT EXISTS "
|
||||
"resource_sponsors JSONB NOT NULL DEFAULT '{}'::jsonb;"
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
for table in ("agents", "workflows"):
|
||||
op.execute(f"ALTER TABLE {table} DROP COLUMN IF EXISTS resource_sponsors;")
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
"""0038 connections — connector_sessions becomes the connections table.
|
||||
"""0040 connections — connector_sessions becomes the connections table.
|
||||
|
||||
``connector_sessions`` already holds one row per signed-in account (OAuth
|
||||
ingest providers) or per MCP server. This migration names what each row is
|
||||
@@ -49,8 +49,8 @@ until then. The instance-wide "Allow custom MCP servers" switch
|
||||
is the ``connectors.allow_custom_mcp`` key in ``app_metadata`` (absent means
|
||||
allowed).
|
||||
|
||||
Revision ID: 0038_connections
|
||||
Revises: 0037_request_traces
|
||||
Revision ID: 0040_connections
|
||||
Revises: 0039_resource_sponsors
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
@@ -58,8 +58,8 @@ from typing import Sequence, Union
|
||||
from alembic import op
|
||||
|
||||
|
||||
revision: str = "0038_connections"
|
||||
down_revision: Union[str, None] = "0037_request_traces"
|
||||
revision: str = "0040_connections"
|
||||
down_revision: Union[str, None] = "0039_resource_sponsors"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
"""0039 connection account name — what the user calls an account.
|
||||
"""0041 connection account name — what the user calls an account.
|
||||
|
||||
``account_label`` identifies an account: the email an OAuth sign-in returns,
|
||||
or a hint of a pasted key. Signing in again finds the connection by it, so it
|
||||
@@ -9,8 +9,8 @@ user never named it.
|
||||
|
||||
Idempotent both ways.
|
||||
|
||||
Revision ID: 0039_connection_account_name
|
||||
Revises: 0038_connections
|
||||
Revision ID: 0041_connection_account_name
|
||||
Revises: 0040_connections
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
@@ -18,8 +18,8 @@ from typing import Sequence, Union
|
||||
from alembic import op
|
||||
|
||||
|
||||
revision: str = "0039_connection_account_name"
|
||||
down_revision: Union[str, None] = "0038_connections"
|
||||
revision: str = "0041_connection_account_name"
|
||||
down_revision: Union[str, None] = "0040_connections"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
Reference in new issue
Block a user