mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-28 00:02:42 +00:00
* 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. * feat: add workspace roles settings UI and role pickers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: show the server's reason when a settings save fails Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: default role pickers to a defined role and confirm resets of unknown capabilities Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: treat null role capabilities as unset and key role drafts by map Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: gate the frontend on workspace role capabilities Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: gate deploys, bulk actions and chat composition per role kind Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: treat a superadmin as full in deploy permission checks Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: leave page visibility out of isRestricted, as the server does Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: let a member discard their own draft without the authoring right Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: show custom roles as inactive without a valid license Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: keep the user store import on the agent page Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: show custom roles as frozen without a valid license Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: reorder instance roles with a drag handle Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * 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> * fix: move the instance role label into the expanded panel 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>
72 lines
2.8 KiB
TypeScript
72 lines
2.8 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import type { RoleCapabilities } from '$lib/gen'
|
|
import type { UserExt } from '$lib/stores'
|
|
import { FULL_CAPABILITIES, legacyOperatorCapabilities } from '$lib/roleCapabilities'
|
|
import { canEditItem, roleCanAuthor, roleCanDraft } from './editRights'
|
|
|
|
function user(overrides: Partial<UserExt>): UserExt {
|
|
return {
|
|
email: 'op@windmill.dev',
|
|
username: 'op',
|
|
name: 'op',
|
|
is_admin: false,
|
|
is_super_admin: false,
|
|
created_at: '',
|
|
groups: [],
|
|
pgroups: [],
|
|
folders: [],
|
|
folders_owners: [],
|
|
folders_read: [],
|
|
operator: true,
|
|
...overrides
|
|
} as UserExt
|
|
}
|
|
|
|
const role = (overrides: Partial<RoleCapabilities>): RoleCapabilities => ({
|
|
...legacyOperatorCapabilities(undefined),
|
|
...overrides
|
|
})
|
|
|
|
describe('edit rights', () => {
|
|
it('lets a compose-only flow role author flows and nothing else', () => {
|
|
const builder = role({ flows: 'compose' })
|
|
expect(roleCanAuthor('flow', builder)).toBe(true)
|
|
expect(roleCanAuthor('script', builder)).toBe(false)
|
|
expect(roleCanAuthor('raw_app', builder)).toBe(false)
|
|
expect(roleCanDraft('raw_app', builder)).toBe(false)
|
|
expect(roleCanDraft('raw_app', role({ apps: 'compose' }))).toBe(true)
|
|
})
|
|
|
|
// apps.rs `require_full_apps`: a composing role builds full-code apps, never low-code ones.
|
|
it('keeps low-code apps for full app authors', () => {
|
|
expect(roleCanAuthor('app', role({ apps: 'compose' }))).toBe(false)
|
|
expect(roleCanAuthor('raw_app', role({ apps: 'compose' }))).toBe(true)
|
|
const scripter = { ...FULL_CAPABILITIES, apps: 'none' as const }
|
|
expect(roleCanAuthor('script', scripter)).toBe(true)
|
|
expect(roleCanAuthor('app', scripter)).toBe(false)
|
|
expect(roleCanAuthor('raw_app', scripter)).toBe(false)
|
|
})
|
|
|
|
// drafts.rs admits a restricted role's draft of a kind it could deploy, and no other.
|
|
it('lets a role draft schedules and triggers until the right is withdrawn', () => {
|
|
expect(roleCanDraft('schedule', role({}))).toBe(true)
|
|
expect(roleCanDraft('trigger', role({}))).toBe(true)
|
|
expect(roleCanDraft('schedule', role({ manage_schedules: false }))).toBe(false)
|
|
expect(roleCanDraft('trigger', role({ manage_triggers: false }))).toBe(false)
|
|
})
|
|
|
|
it('lets any role draft resources and variables, but scripts only with code', () => {
|
|
expect(roleCanDraft('resource', role({}))).toBe(true)
|
|
expect(roleCanDraft('variable', role({}))).toBe(true)
|
|
expect(roleCanDraft('script', role({}))).toBe(false)
|
|
expect(roleCanDraft('script', role({ code: true }))).toBe(true)
|
|
})
|
|
|
|
// The role alone is not enough: a builder still cannot edit a flow in a folder they only read.
|
|
it('requires write access to the item on top of the role', () => {
|
|
const builder = role({ flows: 'compose' })
|
|
expect(canEditItem('flow', 'f/demo/sum', {}, user({}), builder)).toBe(false)
|
|
expect(canEditItem('flow', 'u/op/sum', {}, user({}), builder)).toBe(true)
|
|
})
|
|
})
|