mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-04 08:02:23 +00:00
* feat(datatables): add an ACL editor for data table roles Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: take every pooled connection before the ACL apply locks Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BRoYE5ZeAVvrDYdfhDAYXb * fix: refresh grant options only after the ACL apply validates its plan Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BRoYE5ZeAVvrDYdfhDAYXb * fix: add only missing grant options before an ACL apply, never default privileges Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BRoYE5ZeAVvrDYdfhDAYXb * fix: run one data table ACL apply at a time per server before it connects Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BRoYE5ZeAVvrDYdfhDAYXb * fix: hold the ACL connection to the database that was authorized Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BRoYE5ZeAVvrDYdfhDAYXb * fix: build the ACL connection from the authorized data table entry Resolving the settings again could land on a resource with the same database name on another server, which the later entry checks never see. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BRoYE5ZeAVvrDYdfhDAYXb * fix: check ACL read reach against the entry it connects from Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BRoYE5ZeAVvrDYdfhDAYXb * chore: update ee-repo-ref to 7e338e4dabf91689bfd7fb0333c6534040b17b59 This commit updates the EE repository reference after PR #787 was merged in windmill-ee-private. Previous ee-repo-ref: 0edd40979cf36bfba59323f3f6a0811ae1369cf5 New ee-repo-ref: 7e338e4dabf91689bfd7fb0333c6534040b17b59 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
80 lines
3.0 KiB
Rust
80 lines
3.0 KiB
Rust
/*
|
|
* Author: Ruben Fiszel
|
|
* Copyright: Windmill Labs, Inc 2022
|
|
* This file and its contents are licensed under the AGPLv3 License.
|
|
* Please see the included NOTICE for copyright information and
|
|
* LICENSE-AGPL for a copy of the license.
|
|
*/
|
|
|
|
//! Who may connect to a data table as which role.
|
|
//!
|
|
//! The decision lives on the data table entry of the workspace that governs it, which is not
|
|
//! necessarily the workspace asking: a fork's entry points at its parent's, and everything here
|
|
//! resolves through that pointer first. Nothing in this module runs SQL against the data table —
|
|
//! a save is tenant lists and a default, and the Postgres roles themselves are the instance
|
|
//! catalog's business.
|
|
|
|
use axum::{routing::get, Router};
|
|
|
|
use windmill_api_auth::ApiAuthed;
|
|
use windmill_common::error::Result;
|
|
use windmill_common::workspaces::GoverningDatatable;
|
|
use windmill_common::DB;
|
|
|
|
use crate::datatable_permissions_oss as roles;
|
|
|
|
pub(crate) fn routes() -> Router {
|
|
Router::new()
|
|
.route(
|
|
"/datatable_permissions/{datatable_name}",
|
|
get(roles::get_datatable_permissions).post(roles::set_datatable_permissions),
|
|
)
|
|
.route(
|
|
"/datatable_usable_roles/{datatable_name}",
|
|
get(roles::list_usable_datatable_roles),
|
|
)
|
|
}
|
|
|
|
/// Administering a data table — its permissions, its migrations that declare no role, its exports
|
|
/// — is for the admins of the workspace that governs it. A fork can use the data table; it never
|
|
/// administers it.
|
|
// The gate for whatever administers a data table under roles, which the routes of this module alone
|
|
// do not always reach.
|
|
#[allow(dead_code)]
|
|
pub(crate) async fn ensure_governs_datatable(
|
|
db: &DB,
|
|
authed: &ApiAuthed,
|
|
w_id: &str,
|
|
governing: &GoverningDatatable,
|
|
) -> Result<()> {
|
|
roles::ensure_governs_datatable(db, authed, w_id, governing).await
|
|
}
|
|
|
|
/// Refuse a caller that no tenant of this data table covers.
|
|
///
|
|
/// The bookkeeping endpoints below open the data table's `admin` connection to read or create
|
|
/// `_wm_migrations` before they know which migration will run — so without this, someone covered
|
|
/// by no role at all can still force admin-backed reads and writes on a database they may not
|
|
/// touch. It asks only "may you reach this data table as anything"; which role a given migration
|
|
/// runs as is still decided per migration, and by the executor after that.
|
|
pub(crate) async fn ensure_reaches_datatable(
|
|
db: &DB,
|
|
w_id: &str,
|
|
datatable_name: &str,
|
|
authed: &ApiAuthed,
|
|
) -> Result<()> {
|
|
roles::ensure_reaches_datatable(db, w_id, datatable_name, authed).await
|
|
}
|
|
|
|
/// [`ensure_reaches_datatable`] against an entry already resolved, for a caller that goes on to
|
|
/// connect from that same entry.
|
|
pub(crate) async fn ensure_reaches_governing_datatable(
|
|
db: &DB,
|
|
w_id: &str,
|
|
datatable_name: &str,
|
|
governing: &GoverningDatatable,
|
|
authed: &ApiAuthed,
|
|
) -> Result<()> {
|
|
roles::ensure_reaches_governing_datatable(db, w_id, datatable_name, governing, authed).await
|
|
}
|