feat: grant a new plugin or connector to everyone by default — the admin's job is now removal, not distribution
Nightly Build / build (push) Successful in 7m23s
Nightly Build / build (push) Successful in 7m23s
The grant junctions (plugin_access, mcp_global_access, mcp_catalog_access)
stay deny-by-default internally, but the rows are written for you at two
moments and never again:
— an object is CREATED: PluginManager::update_config (first toggle —
the plugins row's birth), mcp::catalog_upsert, marketplace install,
mcp::global_enable
— a user is CREATED: UserManager::register_user
Who is included is the role attrs.auto_grant flag (default true, so every
role predating the attribute behaves like an adult member). The seeded
Children preset sets it to false, which is the whole reason the attribute
exists. Admins are skipped because they hold everything implicitly. The
role editor now exposes the switch as a checkbox.
New crate module: db::access_defaults (seed_new_object, seed_new_user,
set_grant_by_default). Additive columns: grant_by_default on plugins,
mcp_catalog, mcp_global_servers (INTEGER NOT NULL DEFAULT 1).
On the frontend the Roles page gets a "New extensions" column and
checklist; the user's plugin/connector rosters are unchanged. i18n:
en, fr, it.
Docs: new docs/access.md for the assistant, plus index.md cross-link.
CLAUDE.md updated with a full default-access section.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
pub mod access_defaults;
|
||||
pub mod activated_tools;
|
||||
pub mod approval_rules;
|
||||
pub mod project_members;
|
||||
@@ -275,14 +276,19 @@ async fn create_registry_tables(pool: &SqlitePool) -> Result<()> {
|
||||
|
||||
sqlx::query(
|
||||
"CREATE TABLE IF NOT EXISTS plugins (
|
||||
id TEXT PRIMARY KEY,
|
||||
enabled INTEGER NOT NULL DEFAULT 0,
|
||||
config TEXT NOT NULL DEFAULT '{}',
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
id TEXT PRIMARY KEY,
|
||||
enabled INTEGER NOT NULL DEFAULT 0,
|
||||
config TEXT NOT NULL DEFAULT '{}',
|
||||
grant_by_default INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
)",
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
// See `db::access_defaults`: the default audience of a newly-created object.
|
||||
// Additive so an existing box keeps its rows — and inherits the open default,
|
||||
// which only matters for *future* users (existing ones keep their grants).
|
||||
ensure_column(pool, "plugins", "grant_by_default", "INTEGER NOT NULL DEFAULT 1").await?;
|
||||
|
||||
// Which users may see/configure each plugin. `plugin_id` is deliberately
|
||||
// NOT a foreign key to plugins.id: plugin identity comes from compiled
|
||||
@@ -561,11 +567,13 @@ async fn create_registry_tables(pool: &SqlitePool) -> Result<()> {
|
||||
version INTEGER, -- marketplace build number: the update-comparison key
|
||||
version_string TEXT, -- semver, display only
|
||||
version_release_date TEXT, -- ISO date, display only
|
||||
grant_by_default INTEGER NOT NULL DEFAULT 1, -- auto-grant to auto-grant roles (db::access_defaults)
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
)",
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
ensure_column(pool, "mcp_catalog", "grant_by_default", "INTEGER NOT NULL DEFAULT 1").await?;
|
||||
// OAuth columns are additive (§15) — reach an already-created catalog in place.
|
||||
ensure_column(pool, "mcp_catalog", "oauth_provider", "TEXT").await?;
|
||||
ensure_column(pool, "mcp_catalog", "oauth_scopes_json", "TEXT").await?;
|
||||
@@ -598,11 +606,13 @@ async fn create_registry_tables(pool: &SqlitePool) -> Result<()> {
|
||||
friendly_name TEXT,
|
||||
description TEXT,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
grant_by_default INTEGER NOT NULL DEFAULT 1, -- auto-grant to auto-grant roles (db::access_defaults)
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
)",
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
ensure_column(pool, "mcp_global_servers", "grant_by_default", "INTEGER NOT NULL DEFAULT 1").await?;
|
||||
|
||||
// Which users may use each globally-active connector (§15 per-user access).
|
||||
// Mirrors `shared_folder_members`: both FKs are registry→registry, allowed.
|
||||
|
||||
Reference in New Issue
Block a user