Revert "Migrate S3 permissions to modal"

This reverts commit 0631d03cb0.
This commit is contained in:
Diego Imbert
2025-11-26 18:58:09 +01:00
parent 0631d03cb0
commit ff70cfb085
2 changed files with 129 additions and 164 deletions
@@ -1,149 +0,0 @@
<script lang="ts">
import { enterpriseLicense } from '$lib/stores'
import { defaultS3AdvancedPermissions, type S3ResourceSettings } from '$lib/workspace_settings'
import { Plus } from 'lucide-svelte'
import Alert from '../common/alert/Alert.svelte'
import Button from '../common/button/Button.svelte'
import ClearableInput from '../common/clearableInput/ClearableInput.svelte'
import CloseButton from '../common/CloseButton.svelte'
import Modal2 from '../common/modal/Modal2.svelte'
import MultiSelect from '../select/MultiSelect.svelte'
import Toggle from '../Toggle.svelte'
import { emptyString } from '$lib/utils'
type Props = {
opened: NonNullable<S3ResourceSettings['secondaryStorage']>[number][1] | undefined
}
let { opened: storage = $bindable() }: Props = $props()
</script>
<Modal2
title="Advanced S3 Permissions"
bind:isOpen={() => !!storage, (v) => !v && (storage = undefined)}
target="#content"
contentClasses="flex flex-col gap-3"
fixedWidth="md"
fixedHeight="xl"
>
{#if !!storage}
{#if !$enterpriseLicense}
<Alert
type={storage.advancedPermissions ? 'error' : 'info'}
title="Advanced permission rules are an Enterprise feature"
>
Consider upgrading to Windmill EE to use advanced permission rules to control access to your
object storage at a more granular level.</Alert
>
{/if}
<Toggle
bind:checked={
() => !!storage!.advancedPermissions,
(v) => {
storage!.advancedPermissions = v
? defaultS3AdvancedPermissions(!!$enterpriseLicense)
: undefined
if (v) storage!.publicResource = false
}
}
options={{
right: 'Enable advanced permission rules',
rightTooltip: 'Control precisely which paths are allowed to your users.'
}}
disabled={!storage.advancedPermissions && !$enterpriseLicense}
/>
{#if storage.advancedPermissions}
<Alert title="Standard Unix-style glob syntax is supported">
The following will be interpolated :
<ul class="list-disc pl-6">
<li><code>{'{username}'}</code> : Nickname of the user doing the request</li>
<li><code>{'{group}'}</code> : Any group that the user belongs to</li>
<li><code>{'{folder_read}'}</code> : Any folder that the user has read access to</li>
<li><code>{'{folder_write}'}</code> : Any folder that the user has write access to</li>
</ul>
<br />
Note that changes may take up to 1 minute to propagate due to cache invalidation
</Alert>
<div class="flex flex-col flex-1 gap-2 overflow-y-auto">
{#each storage.advancedPermissions ?? [] as item, idx}
<div class="flex gap-2">
<ClearableInput bind:value={item.pattern} placeholder="Pattern" />
<MultiSelect
items={[
{ value: 'read' },
{ value: 'write' },
{ value: 'delete' },
{ value: 'list' }
]}
bind:value={item.allow}
disablePortal
class="w-[20rem]"
placeholder="Deny all access"
hideMainClearBtn
/>
<CloseButton onClick={() => storage!.advancedPermissions?.splice(idx, 1)} />
</div>
{/each}
</div>
<Button
size="xs"
variant="default"
on:click={() => storage!.advancedPermissions?.push({ pattern: '', allow: [] })}
>
<Plus size={14} />
Add permission rule
</Button>
{/if}
{#if !storage.advancedPermissions}
{#if storage.resourceType == 's3'}
<div class="flex flex-col mt-2 mb-1 gap-1">
<Toggle
disabled={emptyString(storage.resourcePath)}
bind:checked={storage.publicResource}
options={{
right:
'S3 resource details and content can be accessed by all users of this workspace',
rightTooltip:
'If set, all users of this workspace will have access the to entire content of the S3 bucket, as well as the resource details and the "open preview" button. This effectively by-pass the permissions set on the resource and makes it public to everyone.'
}}
/>
{#if storage.publicResource === true}
<div class="pt-2"></div>
<Alert
type="warning"
title="(Legacy) S3 bucket content and resource details are shared"
>
S3 resource public access is ON, which means that the entire content of the S3 bucket
will be accessible to all the users of this workspace regardless of whether they have
access the resource or not. Similarly, certain Windmill SDK endpoints can be used in
scripts to access the resource details, including public and private keys.
</Alert>
{/if}
</div>
{:else}
<div class="flex flex-col mt-5 mb-1 gap-1 max-w-[40rem]">
<Toggle
disabled={emptyString(storage.resourcePath)}
bind:checked={storage.publicResource}
options={{
right: 'object storage content can be accessed by all users of this workspace',
rightTooltip:
'If set, all users of this workspace will have access the to entire content of the object storage.'
}}
/>
{#if storage.publicResource === true}
<div class="pt-2"></div>
<Alert
type="warning"
title="(Legacy) Object storage content and resource details are shared"
>
object public access is ON, which means that the entire content of the object store
will be accessible to all the users of this workspace regardless of whether they have
access the resource or not.
</Alert>
{/if}
</div>
{/if}
{/if}
{/if}
</Modal2>
@@ -8,19 +8,23 @@
import Tabs from '../common/tabs/Tabs.svelte'
import Description from '../Description.svelte'
import ResourcePicker from '../ResourcePicker.svelte'
import Toggle from '../Toggle.svelte'
import Tooltip from '../Tooltip.svelte'
import {
convertFrontendToBackendSetting,
defaultS3AdvancedPermissions,
type S3ResourceSettings
type S3ResourceSettings,
type S3ResourceSettingsItem
} from '$lib/workspace_settings'
import { WorkspaceService } from '$lib/gen'
import S3FilePicker from '../S3FilePicker.svelte'
import Portal from '../Portal.svelte'
import Popover from '../meltComponents/Popover.svelte'
import ClearableInput from '../common/clearableInput/ClearableInput.svelte'
import MultiSelect from '../select/MultiSelect.svelte'
import CloseButton from '../common/CloseButton.svelte'
import TextInput from '../text_input/TextInput.svelte'
import Select from '../select/Select.svelte'
import AdvancedS3PermissionModal from './AdvancedS3PermissionModal.svelte'
let {
s3ResourceSettings = $bindable(),
@@ -41,9 +45,6 @@
sendUserToast(`Large file storage settings changed`)
onSave?.()
}
let advancedS3PermissionModalOpened:
| NonNullable<S3ResourceSettings['secondaryStorage']>[number][1]
| undefined = $state()
</script>
<Portal name="workspace-settings">
@@ -228,15 +229,128 @@
{/if}
{#snippet permissionBtn(storage: NonNullable<S3ResourceSettings['secondaryStorage']>[number][1])}
<Button
variant="default"
wrapperClasses="h-full"
btnClasses="px-2.5"
size="sm"
onClick={() => (advancedS3PermissionModalOpened = storage)}
>
<Shield size={16} /> Permissions <ChevronDown size={14} />
</Button>
<Popover closeOnOtherPopoverOpen placement="left">
<svelte:fragment slot="trigger">
<Button variant="default" wrapperClasses="h-full" btnClasses="px-2.5" size="sm">
<Shield size={16} /> Permissions <ChevronDown size={14} />
</Button>
</svelte:fragment>
<svelte:fragment slot="content">
<div class="flex flex-col gap-3 mx-4 pb-4 pt-5 w-[48rem]">
{#if !$enterpriseLicense}
<Alert
type={storage.advancedPermissions ? 'error' : 'info'}
title="Advanced permission rules are an Enterprise feature"
>
Consider upgrading to Windmill EE to use advanced permission rules to control access to
your object storage at a more granular level.</Alert
>
{/if}
<Toggle
bind:checked={
() => !!storage.advancedPermissions,
(v) => {
storage.advancedPermissions = v
? defaultS3AdvancedPermissions(!!$enterpriseLicense)
: undefined
if (v) storage.publicResource = false
}
}
options={{
right: 'Enable advanced permission rules',
rightTooltip: 'Control precisely which paths are allowed to your users.'
}}
disabled={!storage.advancedPermissions && !$enterpriseLicense}
/>
{#if storage.advancedPermissions}
{@render advancedPermissionsEditor(storage.advancedPermissions)}
{/if}
{#if !storage.advancedPermissions}
{#if storage.resourceType == 's3'}
<div class="flex flex-col mt-2 mb-1 gap-1">
<Toggle
disabled={emptyString(storage.resourcePath)}
bind:checked={storage.publicResource}
options={{
right:
'S3 resource details and content can be accessed by all users of this workspace',
rightTooltip:
'If set, all users of this workspace will have access the to entire content of the S3 bucket, as well as the resource details and the "open preview" button. This effectively by-pass the permissions set on the resource and makes it public to everyone.'
}}
/>
{#if storage.publicResource === true}
<div class="pt-2"></div>
<Alert
type="warning"
title="(Legacy) S3 bucket content and resource details are shared"
>
S3 resource public access is ON, which means that the entire content of the S3
bucket will be accessible to all the users of this workspace regardless of whether
they have access the resource or not. Similarly, certain Windmill SDK endpoints
can be used in scripts to access the resource details, including public and
private keys.
</Alert>
{/if}
</div>
{:else}
<div class="flex flex-col mt-5 mb-1 gap-1 max-w-[40rem]">
<Toggle
disabled={emptyString(storage.resourcePath)}
bind:checked={storage.publicResource}
options={{
right: 'object storage content can be accessed by all users of this workspace',
rightTooltip:
'If set, all users of this workspace will have access the to entire content of the object storage.'
}}
/>
{#if storage.publicResource === true}
<div class="pt-2"></div>
<Alert
type="warning"
title="(Legacy) Object storage content and resource details are shared"
>
object public access is ON, which means that the entire content of the object
store will be accessible to all the users of this workspace regardless of whether
they have access the resource or not.
</Alert>
{/if}
</div>
{/if}
{/if}
</div>
</svelte:fragment>
</Popover>
{/snippet}
<AdvancedS3PermissionModal bind:opened={advancedS3PermissionModalOpened} />
{#snippet advancedPermissionsEditor(rules: S3ResourceSettingsItem['advancedPermissions'])}
<Alert title="Standard Unix-style glob syntax is supported">
The following will be interpolated :
<ul class="list-disc pl-6">
<li><code>{'{username}'}</code> : Nickname of the user doing the request</li>
<li><code>{'{group}'}</code> : Any group that the user belongs to</li>
<li><code>{'{folder_read}'}</code> : Any folder that the user has read access to</li>
<li><code>{'{folder_write}'}</code> : Any folder that the user has write access to</li>
</ul>
<br />
Note that changes may take up to 1 minute to propagate due to cache invalidation
</Alert>
{#each rules ?? [] as item, idx}
<div class="flex gap-2">
<ClearableInput bind:value={item.pattern} placeholder="Pattern" />
<MultiSelect
items={[{ value: 'read' }, { value: 'write' }, { value: 'delete' }, { value: 'list' }]}
bind:value={item.allow}
disablePortal
class="w-[20rem]"
placeholder="Deny all access"
hideMainClearBtn
/>
<CloseButton onClick={() => rules?.splice(idx, 1)} />
</div>
{/each}
<Button size="xs" variant="default" on:click={() => rules?.push({ pattern: '', allow: [] })}>
<Plus size={14} />
Add permission rule
</Button>
{/snippet}