mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-23 08:03:33 +00:00
feat: configurable workspace roles with per-workspace overrides (#11821)
* feat: configurable workspace roles with per-workspace overrides Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: close role review gaps in pickers, declarative sync and removal Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: keep resolve_role_name doc on its function Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: validate overrides on instance role changes and bill admins fully Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: allow pipeline drafts and keep role checks on one connection Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: list data pipelines in operator_can_draft Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: expect a 403 role refusal when an operator resolves jobs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: require a valid license for custom workspace roles Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: freeze workspace roles when the license lapses Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: pin the ee companion for workspace roles Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor: broadcast role override changes from the write path, not a trigger Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: update ee-repo-ref to b5294d38db082bdd104d5358a47695390694c05d This commit updates the EE repository reference after PR #891 was merged in windmill-ee-private. Previous ee-repo-ref: 688e00c5982865b14098f530d54280e2311994c0 New ee-repo-ref: b5294d38db082bdd104d5358a47695390694c05d Automated by sync-ee-ref workflow. * fix: let an admin row that kept the operator flag hold full rights everywhere Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: treat superadmin members as admins and return role names from get user Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
windmill-internal-app[bot]
parent
c740a8f369
commit
21d2a49971
@@ -185,6 +185,10 @@ async fn list_scripts(
|
||||
Query(pagination): Query<Pagination>,
|
||||
Query(lq): Query<ListScriptQuery>,
|
||||
) -> JsonResult<Vec<ListableScript>> {
|
||||
// A role that cannot write code lists only what it can run: no libraries, no drafts.
|
||||
let cannot_code = !windmill_common::roles::caller_capabilities(&db, &w_id, &authed)
|
||||
.await?
|
||||
.code;
|
||||
let (per_page, offset) = paginate_without_limits(pagination);
|
||||
let mut sqlb = SqlBuilder::select_from("script as o")
|
||||
.fields(&[
|
||||
@@ -255,7 +259,7 @@ async fn list_scripts(
|
||||
.as_ref()
|
||||
.map(|x| !x.contains(&"preprocessor".to_string()))
|
||||
.unwrap_or(true))
|
||||
|| authed.is_operator
|
||||
|| cannot_code
|
||||
{
|
||||
// only include scripts that have a runnable entrypoint. Use a
|
||||
// deny-list: anything that isn't a 'lib' (library script without
|
||||
@@ -312,7 +316,7 @@ async fn list_scripts(
|
||||
);
|
||||
}
|
||||
}
|
||||
if authed.is_operator {
|
||||
if cannot_code {
|
||||
sqlb.and_where_eq("kind", quote("script"));
|
||||
} else if let Some(lowercased_kinds) = lowercased_kinds {
|
||||
let safe_kinds = lowercased_kinds
|
||||
@@ -360,7 +364,7 @@ async fn list_scripts(
|
||||
// `include_draft_only` so picker callers stay deployed-only (home page opts in);
|
||||
// skipped past page 0 or under any narrowing filter to keep pagination clean.
|
||||
if lq.include_draft_only.unwrap_or(false)
|
||||
&& !authed.is_operator
|
||||
&& !cannot_code
|
||||
&& offset == 0
|
||||
&& lq.path_start.is_none()
|
||||
&& lq.path_exact.is_none()
|
||||
@@ -1352,11 +1356,7 @@ async fn create_script_internal<'c>(
|
||||
Option<PostCommitDeploy>,
|
||||
Vec<MovedNativeTrigger>,
|
||||
)> {
|
||||
if authed.is_operator {
|
||||
return Err(Error::NotAuthorized(
|
||||
"Operators cannot create scripts for security reasons".to_string(),
|
||||
));
|
||||
}
|
||||
windmill_common::workspaces::check_role_can_code(&db, &w_id, &authed, "create scripts").await?;
|
||||
check_scopes(&authed, || format!("scripts:write:{}", ns.path))?;
|
||||
|
||||
// Normalize positive-only settings so a `<= 0` value (e.g. a CLI-pushed `0`) persists as
|
||||
@@ -4086,11 +4086,8 @@ async fn archive_script_by_path(
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
) -> Result<()> {
|
||||
if authed.is_operator {
|
||||
return Err(Error::NotAuthorized(
|
||||
"Operators cannot archive scripts for security reasons".to_string(),
|
||||
));
|
||||
}
|
||||
windmill_common::workspaces::check_role_can_code(&db, &w_id, &authed, "archive scripts")
|
||||
.await?;
|
||||
let path = path.to_path();
|
||||
check_scopes(&authed, || format!("scripts:write:{}", path))?;
|
||||
if let RuleCheckResult::Blocked(msg) = check_deploy_rules(
|
||||
@@ -4182,11 +4179,8 @@ async fn archive_script_by_hash(
|
||||
Extension(webhook): Extension<WebhookShared>,
|
||||
Path((w_id, hash)): Path<(String, ScriptHash)>,
|
||||
) -> JsonResult<Script<ScriptRunnableSettingsInline>> {
|
||||
if authed.is_operator {
|
||||
return Err(Error::NotAuthorized(
|
||||
"Operators cannot archive scripts for security reasons".to_string(),
|
||||
));
|
||||
}
|
||||
windmill_common::workspaces::check_role_can_code(&db, &w_id, &authed, "archive scripts")
|
||||
.await?;
|
||||
if let RuleCheckResult::Blocked(msg) = check_deploy_rules(
|
||||
&w_id,
|
||||
AuditAuthorable::username(&authed),
|
||||
|
||||
Reference in New Issue
Block a user