From f4284e09129ca6a59b0d9a71295da50d1d021f99 Mon Sep 17 00:00:00 2001 From: Diego Imbert Date: Thu, 21 Aug 2025 16:23:32 +0200 Subject: [PATCH] change restriction to allow --- backend/windmill-api/openapi.yaml | 4 +- backend/windmill-common/src/s3_helpers.rs | 41 ++++++++++++------- .../workspaceSettings/StorageSettings.svelte | 6 +-- frontend/src/lib/workspace_settings.ts | 16 ++++---- 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index fa6d580f8a..3b9dfae61f 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -17506,7 +17506,7 @@ components: type: string public_resource: type: boolean - restricted_to_user_paths: + allow_user_paths: type: boolean secondary_storage: type: object @@ -17531,7 +17531,7 @@ components: type: string public_resource: type: boolean - restricted_to_user_paths: + allow_user_paths: type: boolean DucklakeSettings: diff --git a/backend/windmill-common/src/s3_helpers.rs b/backend/windmill-common/src/s3_helpers.rs index 557aa5615c..d0095196af 100644 --- a/backend/windmill-common/src/s3_helpers.rs +++ b/backend/windmill-common/src/s3_helpers.rs @@ -237,13 +237,23 @@ impl LargeFileStorage { LargeFileStorage::GoogleCloudStorage(gcs_lfs) => &gcs_lfs.gcs_resource_path, } } - pub fn is_restricted_to_user_paths(&self) -> bool { + pub fn allow_user_paths(&self) -> bool { match self { - LargeFileStorage::S3Storage(lfs) => lfs.restricted_to_user_paths, - LargeFileStorage::S3AwsOidc(lfs) => lfs.restricted_to_user_paths, - LargeFileStorage::AzureBlobStorage(lfs) => lfs.restricted_to_user_paths, - LargeFileStorage::AzureWorkloadIdentity(lfs) => lfs.restricted_to_user_paths, - LargeFileStorage::GoogleCloudStorage(glfs) => glfs.restricted_to_user_paths, + LargeFileStorage::S3Storage(lfs) => lfs.allow_user_paths, + LargeFileStorage::S3AwsOidc(lfs) => lfs.allow_user_paths, + LargeFileStorage::AzureBlobStorage(lfs) => lfs.allow_user_paths, + LargeFileStorage::AzureWorkloadIdentity(lfs) => lfs.allow_user_paths, + LargeFileStorage::GoogleCloudStorage(glfs) => glfs.allow_user_paths, + } + .unwrap_or(false) + } + pub fn is_public_resource(&self) -> bool { + match self { + LargeFileStorage::S3Storage(lfs) => lfs.public_resource, + LargeFileStorage::S3AwsOidc(lfs) => lfs.public_resource, + LargeFileStorage::AzureBlobStorage(lfs) => lfs.public_resource, + LargeFileStorage::AzureWorkloadIdentity(lfs) => lfs.public_resource, + LargeFileStorage::GoogleCloudStorage(glfs) => glfs.public_resource, } .unwrap_or(false) } @@ -255,7 +265,7 @@ pub struct S3Storage { #[serde(skip_serializing_if = "Option::is_none")] pub public_resource: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub restricted_to_user_paths: Option, + pub allow_user_paths: Option, } #[derive(Serialize, Deserialize, Debug)] @@ -264,7 +274,7 @@ pub struct AzureBlobStorage { #[serde(skip_serializing_if = "Option::is_none")] pub public_resource: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub restricted_to_user_paths: Option, + pub allow_user_paths: Option, } #[derive(Serialize, Deserialize, Debug)] @@ -273,7 +283,7 @@ pub struct GoogleCloudStorage { #[serde(skip_serializing_if = "Option::is_none")] pub public_resource: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub restricted_to_user_paths: Option, + pub allow_user_paths: Option, } #[derive(Clone, Debug)] @@ -1121,17 +1131,18 @@ pub fn check_lfs_object_path_permissions( object_path: &str, authed: &Authed, ) -> error::Result<()> { - if authed.is_admin { + if authed.is_admin || lfs.is_public_resource() { return Ok(()); } let username = authed.username.as_str(); - if lfs.is_restricted_to_user_paths() { - if !object_path.starts_with(&format!("u/{username}/")) { - return Err(error::Error::NotAuthorized(format!( - "Can only access u/{username}/**" - ))); + if lfs.allow_user_paths() { + if object_path.starts_with(&format!("u/{username}/")) { + return Ok(()); } + return Err(error::Error::NotAuthorized(format!( + "Cannot access path {object_path}" + ))); } Ok(()) } diff --git a/frontend/src/lib/components/workspaceSettings/StorageSettings.svelte b/frontend/src/lib/components/workspaceSettings/StorageSettings.svelte index 74e3228836..10e97d55ff 100644 --- a/frontend/src/lib/components/workspaceSettings/StorageSettings.svelte +++ b/frontend/src/lib/components/workspaceSettings/StorageSettings.svelte @@ -203,11 +203,11 @@
diff --git a/frontend/src/lib/workspace_settings.ts b/frontend/src/lib/workspace_settings.ts index d3ee1d2c07..6051aee3cd 100644 --- a/frontend/src/lib/workspace_settings.ts +++ b/frontend/src/lib/workspace_settings.ts @@ -8,7 +8,7 @@ type s3ResourceSettingsItem = { resourceType: s3type resourcePath: string | undefined publicResource: boolean | undefined - restrictedToUserPaths?: boolean + allowUserPaths?: boolean } export type S3ResourceSettings = s3ResourceSettingsItem & { secondaryStorage: [string, s3ResourceSettingsItem][] | undefined @@ -33,42 +33,42 @@ export function convertBackendSettingsToFrontendSettingsItem( resourceType: 's3', resourcePath: large_file_storage?.s3_resource_path?.replace('$res:', ''), publicResource: large_file_storage?.public_resource, - restrictedToUserPaths: large_file_storage?.restricted_to_user_paths + allowUserPaths: large_file_storage?.allow_user_paths } } else if (large_file_storage?.type === 'AzureBlobStorage') { return { resourceType: 'azure_blob', resourcePath: large_file_storage?.azure_blob_resource_path?.replace('$res:', ''), publicResource: large_file_storage?.public_resource, - restrictedToUserPaths: large_file_storage?.restricted_to_user_paths + allowUserPaths: large_file_storage?.allow_user_paths } } else if (large_file_storage?.type === 'AzureWorkloadIdentity') { return { resourceType: 'azure_workload_identity', resourcePath: large_file_storage?.azure_blob_resource_path?.replace('$res:', ''), publicResource: large_file_storage?.public_resource, - restrictedToUserPaths: large_file_storage?.restricted_to_user_paths + allowUserPaths: large_file_storage?.allow_user_paths } } else if (large_file_storage?.type === 'S3AwsOidc') { return { resourceType: 's3_aws_oidc', resourcePath: large_file_storage?.s3_resource_path?.replace('$res:', ''), publicResource: large_file_storage?.public_resource, - restrictedToUserPaths: large_file_storage?.restricted_to_user_paths + allowUserPaths: large_file_storage?.allow_user_paths } } else if (large_file_storage?.type === 'GoogleCloudStorage') { return { resourceType: 'gcloud_storage', resourcePath: large_file_storage?.gcs_resource_path?.replace('$res:', ''), publicResource: large_file_storage?.public_resource, - restrictedToUserPaths: large_file_storage?.restricted_to_user_paths + allowUserPaths: large_file_storage?.allow_user_paths } } else { return { resourceType: 's3', resourcePath: undefined, publicResource: undefined, - restrictedToUserPaths: undefined + allowUserPaths: undefined } } } @@ -93,7 +93,7 @@ export function convertFrontendToBackendettingsItem( let resourcePathWithPrefix = `$res:${s3ResourceSettings.resourcePath}` let params = { public_resource: s3ResourceSettings.publicResource, - restricted_to_user_paths: s3ResourceSettings.restrictedToUserPaths + allow_user_paths: s3ResourceSettings.allowUserPaths } if (s3ResourceSettings.resourceType === 'azure_blob') { let typ: LargeFileStorage['type'] = 'AzureBlobStorage'