mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-12 00:06:14 +00:00
fix(datatables): close the fail-open in role resolution, and gate the ACL endpoints
A role with a stored pg_rolename but no password resolved to the data table's own connection, which owns everything — so a caller authorized as one role got the admin one instead. Exports and git-synced settings redact that password, so a restored config is exactly the shape that produced it. Refuse instead, and name the fix. The ACL endpoints took any workspace member: on a data table without roles every member resolves to that same admin connection, so ownership and grants there are the workspace admins' to change, as the roles themselves are. Also: check a migration batch's roles before applying any of it, keep the role picker for a single non-default role, drop the revoke button from a default privilege on types (which no scope can express), and say what get_datatable_resource_as_default_role actually resolves as.
This commit is contained in:
@@ -2472,10 +2472,11 @@ async fn get_datatable_table_schema(
|
||||
}))
|
||||
}
|
||||
|
||||
/// Resolve a data table for an API caller. Schema browsing and the database
|
||||
/// manager always connect as `root`, so a permissioned data table is reachable
|
||||
/// from the UI only by a tenant of its `root` role (and by admins).
|
||||
async fn get_datatable_resource_as_admin(
|
||||
/// Resolve a data table for an API caller as the role it defaults to — schema
|
||||
/// browsing, the database manager and copy-between-databases name none — so a
|
||||
/// permissioned data table is reachable from the UI only by a tenant of that
|
||||
/// role (and by workspace admins, who may use any of them).
|
||||
async fn get_datatable_resource_as_default_role(
|
||||
db: &DB,
|
||||
authed: &ApiAuthed,
|
||||
w_id: &str,
|
||||
@@ -2514,7 +2515,7 @@ async fn get_datatable_schema(
|
||||
datatable_name: &str,
|
||||
) -> Result<SchemaMap> {
|
||||
// Get the datatable resource (connection credentials)
|
||||
let db_resource = get_datatable_resource_as_admin(db, authed, w_id, datatable_name).await?;
|
||||
let db_resource = get_datatable_resource_as_default_role(db, authed, w_id, datatable_name).await?;
|
||||
|
||||
// Parse the resource as PgDatabase
|
||||
let pg_db: PgDatabase = serde_json::from_value(db_resource)
|
||||
@@ -2763,7 +2764,7 @@ async fn get_datatable_table_columns(
|
||||
)));
|
||||
}
|
||||
|
||||
let db_resource = get_datatable_resource_as_admin(db, authed, w_id, datatable_name).await?;
|
||||
let db_resource = get_datatable_resource_as_default_role(db, authed, w_id, datatable_name).await?;
|
||||
let pg_db: PgDatabase = serde_json::from_value(db_resource)
|
||||
.map_err(|e| Error::internal_err(format!("Failed to parse database credentials: {}", e)))?;
|
||||
let (client, connection) = pg_db.connect(Some(db)).await?;
|
||||
@@ -2986,7 +2987,7 @@ pub(crate) async fn resolve_pg_source_checked(
|
||||
source: &str,
|
||||
) -> Result<PgDatabase> {
|
||||
let db_resource = if let Some(name) = source.strip_prefix("datatable://") {
|
||||
get_datatable_resource_as_admin(db, authed, w_id, name).await?
|
||||
get_datatable_resource_as_default_role(db, authed, w_id, name).await?
|
||||
} else if let Some(path) = source.strip_prefix("$res:") {
|
||||
let db_with_authed = windmill_common::db::DbWithOptAuthed::from_authed(
|
||||
authed,
|
||||
|
||||
Reference in New Issue
Block a user