Repository: owncloud/ocis
Pull request #8823 (2024-04-10 11:14:21)

[tests-only][full-ci] updated drone file to display pipeline in order by trigger
<!--
Thanks for submitting a change to ownCloud!

This is the bug tracker for the oCIS component. Find other components at https://github.com/owncloud/core/blob/master/.github/CONTRIBUTING.md#guidelines

For fixing potential security issues please see https://owncloud.org/security/

To make it possible for us to get your change reviewed and merged please carefully fill out the requested information below.

Please note that any kind of change needs first be submitted to the master branch which holds the next version of oCIS.

Please set the following labels:

- Set label "Status:Needs-Review" for review or "Status:In-Progress" if the PR still has open tasks.
- Assignment: assign to self
- Reviewers: pick at least one
-->

## Description
This PR updates the `.drone.star` file to manage pipelines in order of the trigger time.

## Related Issue
<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->
- https://github.com/owncloud/ocis/issues/8794

## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->

## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->

## Screenshots (if appropriate):

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Technical debt
- [ ] Tests only (no source changes)

## Checklist:
<!-- Tick the checkboxes when done. -->
<!-- Raise documentation ticket in owncloud.github.io/ -->
- [ ] Code changes
- [ ] Unit tests added
- [ ] Acceptance tests added
- [ ] Documentation ticket raised: <link> 



Patch:
diff --git a/.drone.star b/.drone.star
index e20d51ef052..eb77f6584af 100644
--- a/.drone.star
+++ b/.drone.star
@@ -246,25 +246,27 @@ def main(ctx):
 
     pipelines = []
 
+    build_release_helpers = [
+        changelog(),
+        docs(),
+        licenseCheck(ctx),
+    ]
+
     test_pipelines = \
         codestyle(ctx) + \
         checkTestSuitesInExpectedFailures(ctx) + \
         buildWebCache(ctx) + \
         getGoBinForTesting(ctx) + \
         [buildOcisBinaryForTesting(ctx)] + \
+        checkStarlark() + \
+        build_release_helpers + \
         testOcisAndUploadResults(ctx) + \
         testPipelines(ctx)
 
     build_release_pipelines = \
-        [licenseCheck(ctx)] + \
         dockerReleases(ctx) + \
         binaryReleases(ctx)
 
-    build_release_helpers = [
-        changelog(),
-        docs(),
-    ]
-
     test_pipelines.append(
         pipelineDependsOn(
             purgeBuildArtifactCache(ctx),
@@ -272,7 +274,7 @@ def main(ctx):
         ),
     )
 
-    pipelines = test_pipelines + build_release_pipelines + build_release_helpers
+    pipelines = test_pipelines + build_release_pipelines
 
     if ctx.build.event == "cron":
         pipelines = \
@@ -289,14 +291,13 @@ def main(ctx):
     # always append notification step
     pipelines.append(
         pipelineDependsOn(
-            notify(),
+            notify(ctx),
             pipelines,
         ),
     )
 
     pipelines = pipelines + k6LoadTests(ctx)
 
-    pipelines += checkStarlark()
     pipelineSanityChecks(ctx, pipelines)
     return pipelines
 
@@ -331,7 +332,7 @@ def testOcisAndUploadResults(ctx):
     scan_result_upload["depends_on"] = getPipelineNames([pipeline])
 
     security_scan = scanOcis(ctx)
-    return [pipeline, scan_result_upload, security_scan]
+    return [security_scan, pipeline, scan_result_upload]
 
 def testPipelines(ctx):
     pipelines = []
@@ -1956,7 +1957,11 @@ def makeGoGenerate(module):
         },
     ]
 
-def notify():
+def notify(ctx):
+    status = ["failure"]
+    if ctx.build.event == "cron":
+        status.append("success")
+
     return {
         "kind": "pipeline",
         "type": "docker",
@@ -1983,9 +1988,7 @@ def notify():
                 "refs/heads/release*",
                 "refs/tags/**",
             ],
-            "status": [
-                "failure",
-            ],
+            "status": status,
         },
     }
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7ac7f5eea9c..a7f2d558b8d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,8 @@
 # Table of Contents
 
 * [Changelog for unreleased](#changelog-for-unreleased-unreleased)
+* [Changelog for 5.0.1](#changelog-for-501-2024-04-10)
+* [Changelog for 4.0.7](#changelog-for-407-2024-03-27)
 * [Changelog for 5.0.0](#changelog-for-500-2024-03-18)
 * [Changelog for 4.0.6](#changelog-for-406-2024-02-07)
 * [Changelog for 4.0.5](#changelog-for-405-2023-12-21)
@@ -38,7 +40,7 @@
 
 The following sections list the changes for unreleased.
 
-[unreleased]: https://github.com/owncloud/ocis/compare/v5.0.0...master
+[unreleased]: https://github.com/owncloud/ocis/compare/v5.0.1...master
 
 ## Summary
 
@@ -58,6 +60,7 @@ The following sections list the changes for unreleased.
 * Bugfix - Fix restarting of postprocessing: [#8782](https://github.com/owncloud/ocis/pull/8782)
 * Bugfix - Fix the create personal space cache: [#8799](https://github.com/owncloud/ocis/pull/8799)
 * Bugfix - Fix removing groups from space: [#8803](https://github.com/owncloud/ocis/pull/8803)
+* Bugfix - Validate conditions for sharing roles by resource type: [#8815](https://github.com/owncloud/ocis/pull/8815)
 * Bugfix - Fix creating the drive item: [#8817](https://github.com/owncloud/ocis/pull/8817)
 * Change - Change the default store for presigned keys to nats-js-kv: [#8419](https://github.com/owncloud/ocis/pull/8419)
 * Change - Disable resharing by default for deprecation: [#8653](https://github.com/owncloud/ocis/pull/8653)
@@ -207,6 +210,16 @@ The following sections list the changes for unreleased.
    https://github.com/owncloud/ocis/issues/8768
    https://github.com/owncloud/ocis/pull/8803
 
+* Bugfix - Validate conditions for sharing roles by resource type: [#8815](https://github.com/owncloud/ocis/pull/8815)
+
+   We improved the validation of the allowed sharing roles for specific resource
+   type for various sharing related graph API endpoints. This allows e.g. the web
+   client to restrict the sharing roles presented to the user based on the type of
+   the resource that is being shared.
+
+   https://github.com/owncloud/ocis/issues/8331
+   https://github.com/owncloud/ocis/pull/8815
+
 * Bugfix - Fix creating the drive item: [#8817](https://github.com/owncloud/ocis/pull/8817)
 
    We fixed the issue when creating a drive item with random item id was allowed
@@ -455,6 +468,103 @@ The following sections list the changes for unreleased.
    https://github.com/owncloud/ocis/pull/8812
    https://github.com/owncloud/web/releases/tag/v9.0.0-alpha.4
 
+# Changelog for [5.0.1] (2024-04-10)
+
+The following sections list the changes for 5.0.1.
+
+[5.0.1]: https://github.com/owncloud/ocis/compare/v4.0.7...v5.0.1
+
+## Summary
+
+* Bugfix - Make IDP cookies same site strict: [#8716](https://github.com/owncloud/ocis/pull/8716)
+* Bugfix - Update reva to v2.19.4: [#8781](https://github.com/owncloud/ocis/pull/8781)
+* Bugfix - Fix restarting of postprocessing: [#8782](https://github.com/owncloud/ocis/pull/8782)
+* Bugfix - Fix the create personal space cache: [#8799](https://github.com/owncloud/ocis/pull/8799)
+
+## Details
+
+* Bugfix - Make IDP cookies same site strict: [#8716](https://github.com/owncloud/ocis/pull/8716)
+
+   To enhance the security of our application and prevent Cross-Site Request
+   Forgery (CSRF) attacks, we have updated the SameSite attribute of the build in
+   Identity Provider (IDP) cookies to Strict.
+
+   This change restricts the browser from sending these cookies with any cross-site
+   requests, thereby limiting the exposure of the user's session to potential
+   threats.
+
+   This update does not impact the existing functionality of the application but
+   provides an additional layer of security where needed.
+
+   This only affects cookies set by the built-in IDP. Production systems should not
+   be affected.
+
+   https://github.com/owncloud/ocis/pull/8716
+
+* Bugfix - Update reva to v2.19.4: [#8781](https://github.com/owncloud/ocis/pull/8781)
+
+   We updated reva to v2.19.4
+
+  *   Bugfix [cs3org/reva#4612](https://github.com/cs3org/reva/pull/4612): Use gateway selector in jsoncs3 to scale the service
+
+   Https://github.com/owncloud/ocis/pull/8787
+
+   We updated reva to v2.19.3
+
+  *   Bugfix[cs3org/reva#4607](https://github.com/cs3org/reva/pull/4607): Mask user email in output
+
+   https://github.com/owncloud/ocis/pull/8781
+
+* Bugfix - Fix restarting of postprocessing: [#8782](https://github.com/owncloud/ocis/pull/8782)
+
+   When an upload is not found, the logic to restart postprocessing was bunked.
+   Additionally we extended the upload sessions command to be able to restart the
+   uploads without using a second command.
+
+   NOTE: This also includes a breaking fix for the deprecated `ocis storage-users
+   uploads list` command
+
+   https://github.com/owncloud/ocis/pull/8782
+
+* Bugfix - Fix the create personal space cache: [#8799](https://github.com/owncloud/ocis/pull/8799)
+
+   We fixed a problem with the config for the create personal space cache which
+   resulted in the cache never being used.
+
+   https://github.com/owncloud/ocis/pull/8799
+
+# Changelog for [4.0.7] (2024-03-27)
+
+The following sections list the changes for 4.0.7.
+
+[4.0.7]: https://github.com/owncloud/ocis/compare/v5.0.0...v4.0.7
+
+## Summary
+
+* Bugfix - Update reva to include bugfixes and improvements: [#8718](https://github.com/owncloud/ocis/pull/8718)
+* Enhancement - Update to go 1.22: [#8597](https://github.com/owncloud/ocis/pull/8597)
+
+## Details
+
+* Bugfix - Update reva to include bugfixes and improvements: [#8718](https://github.com/owncloud/ocis/pull/8718)
+
+   ## Changelog for reva 2.13.4
+
+  *   Bugfix [cs3org/reva#4398](https://github.com/cs3org/reva/pull/4398): Fix ceph build
+  *   Bugfix [cs3org/reva#4396](https://github.com/cs3org/reva/pull/4396): Allow an empty credentials chain in the auth middleware
+  *   Bugfix [cs3org/reva#4423](https://github.com/cs3org/reva/pull/4423): Fix disconnected traces
+  *   Bugfix [cs3org/reva#4590](https://github.com/cs3org/reva/pull/4590): Fix uploading via a public link
+  *   Bugfix [cs3org/reva#4470](https://github.com/cs3org/reva/pull/4470): Keep failed processing status
+  *   Enhancement [cs3org/reva#4397](https://github.com/cs3org/reva/pull/4397): Introduce UploadSessionLister interface
+
+   https://github.com/owncloud/ocis/pull/8718
+
+* Enhancement - Update to go 1.22: [#8597](https://github.com/owncloud/ocis/pull/8597)
+
+   We have updated go to version 1.22.
+
+   https://github.com/owncloud/ocis/pull/8597
+
 # Changelog for [5.0.0] (2024-03-18)
 
 The following sections list the changes for 5.0.0.
@@ -3388,6 +3498,7 @@ The following sections list the changes for 3.0.0.
 * Bugfix - Fix the wrong status code when appRoleAssignments is forbidden: [#6037](https://github.com/owncloud/ocis/issues/6037)
 * Bugfix - Fix Search reindexing performance regression: [#6085](https://github.com/owncloud/ocis/pull/6085)
 * Bugfix - Fix userlog panic: [#6114](https://github.com/owncloud/ocis/pull/6114)
+* Bugfix - Fix wrong compile date: [#6132](https://github.com/owncloud/ocis/pull/6132)
 * Bugfix - Fix Logout Url config name: [#6227](https://github.com/owncloud/ocis/pull/6227)
 * Bugfix - Allow selected updates on graph users: [#6233](https://github.com/owncloud/ocis/pull/6233)
 * Bugfix - Add missing response to blocked requests: [#6277](https://github.com/owncloud/ocis/pull/6277)
@@ -3613,6 +3724,13 @@ The following sections list the changes for 3.0.0.
 
    https://github.com/owncloud/ocis/pull/6114
 
+* Bugfix - Fix wrong compile date: [#6132](https://github.com/owncloud/ocis/pull/6132)
+
+   We fixed that current date is always printed.
+
+   https://github.com/owncloud/ocis/issues/6124
+   https://github.com/owncloud/ocis/pull/6132
+
 * Bugfix - Fix Logout Url config name: [#6227](https://github.com/owncloud/ocis/pull/6227)
 
    We fixed the yaml and json name of the logout url option.
diff --git a/changelog/3.0.0_2023-06-06/fix-compile-date.md b/changelog/3.0.0_2023-06-06/fix-compile-date.md
new file mode 100644
index 00000000000..78f44d154a9
--- /dev/null
+++ b/changelog/3.0.0_2023-06-06/fix-compile-date.md
@@ -0,0 +1,6 @@
+Bugfix: fix wrong compile date
+
+We fixed that current date is always printed.
+
+https://github.com/owncloud/ocis/pull/6132
+https://github.com/owncloud/ocis/issues/6124
\ No newline at end of file
diff --git a/changelog/4.0.7_2024-03-27/bump-go-122.md b/changelog/4.0.7_2024-03-27/bump-go-122.md
new file mode 100644
index 00000000000..67227d9a877
--- /dev/null
+++ b/changelog/4.0.7_2024-03-27/bump-go-122.md
@@ -0,0 +1,5 @@
+Enhancement: Update to go 1.22
+
+We have updated go to version 1.22.
+
+https://github.com/owncloud/ocis/pull/8597
diff --git a/changelog/4.0.7_2024-03-27/update-reva.md b/changelog/4.0.7_2024-03-27/update-reva.md
new file mode 100644
index 00000000000..ec1728f5d05
--- /dev/null
+++ b/changelog/4.0.7_2024-03-27/update-reva.md
@@ -0,0 +1,12 @@
+Bugfix: Update reva to include bugfixes and improvements
+
+## Changelog for reva 2.13.4
+
+*   Bugfix [cs3org/reva#4398](https://github.com/cs3org/reva/pull/4398): Fix ceph build
+*   Bugfix [cs3org/reva#4396](https://github.com/cs3org/reva/pull/4396): Allow an empty credentials chain in the auth middleware
+*   Bugfix [cs3org/reva#4423](https://github.com/cs3org/reva/pull/4423): Fix disconnected traces
+*   Bugfix [cs3org/reva#4590](https://github.com/cs3org/reva/pull/4590): Fix uploading via a public link
+*   Bugfix [cs3org/reva#4470](https://github.com/cs3org/reva/pull/4470): Keep failed processing status
+*   Enhancement [cs3org/reva#4397](https://github.com/cs3org/reva/pull/4397): Introduce UploadSessionLister interface
+
+https://github.com/owncloud/ocis/pull/8718
diff --git a/changelog/5.0.1_2024-04-10/bump-reva.md b/changelog/5.0.1_2024-04-10/bump-reva.md
new file mode 100644
index 00000000000..57c4a4c2eb1
--- /dev/null
+++ b/changelog/5.0.1_2024-04-10/bump-reva.md
@@ -0,0 +1,13 @@
+Bugfix: Update reva to v2.19.4
+
+We updated reva to v2.19.4
+
+*   Bugfix [cs3org/reva#4612](https://github.com/cs3org/reva/pull/4612): Use gateway selector in jsoncs3 to scale the service
+
+https://github.com/owncloud/ocis/pull/8787
+
+We updated reva to v2.19.3
+
+*   Bugfix[cs3org/reva#4607](https://github.com/cs3org/reva/pull/4607): Mask user email in output
+
+https://github.com/owncloud/ocis/pull/8781
diff --git a/changelog/5.0.1_2024-04-10/enhancement-strict-same-site-cookie.md b/changelog/5.0.1_2024-04-10/enhancement-strict-same-site-cookie.md
new file mode 100644
index 00000000000..c3a4e1a1f37
--- /dev/null
+++ b/changelog/5.0.1_2024-04-10/enhancement-strict-same-site-cookie.md
@@ -0,0 +1,14 @@
+Bugfix: Make IDP cookies same site strict
+
+To enhance the security of our application and prevent Cross-Site Request Forgery (CSRF) attacks, we have updated the
+SameSite attribute of the build in Identity Provider (IDP) cookies to Strict.
+
+This change restricts the browser from sending these cookies with any cross-site requests,
+thereby limiting the exposure of the user's session to potential threats.
+
+This update does not impact the existing functionality of the application but provides an additional layer of security
+where needed.
+
+This only affects cookies set by the built-in IDP. Production systems should not be affected.
+
+https://github.com/owncloud/ocis/pull/8716
diff --git a/changelog/5.0.1_2024-04-10/fix-create-personal-space-cache.md b/changelog/5.0.1_2024-04-10/fix-create-personal-space-cache.md
new file mode 100644
index 00000000000..cd7831bce19
--- /dev/null
+++ b/changelog/5.0.1_2024-04-10/fix-create-personal-space-cache.md
@@ -0,0 +1,5 @@
+Bugfix: Fix the create personal space cache
+
+We fixed a problem with the config for the create personal space cache which resulted in the cache never being used.
+
+https://github.com/owncloud/ocis/pull/8799
diff --git a/changelog/5.0.1_2024-04-10/fix-postprocessing-restart.md b/changelog/5.0.1_2024-04-10/fix-postprocessing-restart.md
new file mode 100644
index 00000000000..6183701f168
--- /dev/null
+++ b/changelog/5.0.1_2024-04-10/fix-postprocessing-restart.md
@@ -0,0 +1,8 @@
+Bugfix: Fix restarting of postprocessing
+
+When an upload is not found, the logic to restart postprocessing was bunked. Additionally we extended the upload sessions
+command to be able to restart the uploads without using a second command.
+
+NOTE: This also includes a breaking fix for the deprecated `ocis storage-users uploads list` command
+
+https://github.com/owncloud/ocis/pull/8782
diff --git a/changelog/unreleased/fix-graph-allowed-roles.md b/changelog/unreleased/fix-graph-allowed-roles.md
new file mode 100644
index 00000000000..bfd334e41cb
--- /dev/null
+++ b/changelog/unreleased/fix-graph-allowed-roles.md
@@ -0,0 +1,9 @@
+Bugfix: Validate conditions for sharing roles by resource type
+
+We improved the validation of the allowed sharing roles for specific resource type
+for various sharing related graph API endpoints. This allows e.g. the web client to
+restrict the sharing roles presented to the user based on the type of the resource
+that is being shared.
+
+https://github.com/owncloud/ocis/pull/8815
+https://github.com/owncloud/ocis/issues/8331
diff --git a/deployments/continuous-deployment-config/ocis_keycloak/released.yml b/deployments/continuous-deployment-config/ocis_keycloak/released.yml
index cf91c92d609..68187812118 100644
--- a/deployments/continuous-deployment-config/ocis_keycloak/released.yml
+++ b/deployments/continuous-deployment-config/ocis_keycloak/released.yml
@@ -32,7 +32,7 @@
         env:
           INSECURE: "false"
           TRAEFIK_ACME_MAIL: mbarz@owncloud.com
-          OCIS_DOCKER_TAG: 5.0.0
+          OCIS_DOCKER_TAG: 5.0.1
           OCIS_DOMAIN: ocis.ocis-keycloak.released.owncloud.works
           KEYCLOAK_DOMAIN: keycloak.ocis-keycloak.released.owncloud.works
           COMPOSE_FILE: docker-compose.yml:monitoring_tracing/docker-compose-additions.yml
diff --git a/deployments/continuous-deployment-config/ocis_ldap/released.yml b/deployments/continuous-deployment-config/ocis_ldap/released.yml
index 9beff9103ba..1936bf75885 100644
--- a/deployments/continuous-deployment-config/ocis_ldap/released.yml
+++ b/deployments/continuous-deployment-config/ocis_ldap/released.yml
@@ -32,7 +32,7 @@
         env:
           INSECURE: "false"
           TRAEFIK_ACME_MAIL: mbarz@owncloud.com
-          OCIS_DOCKER_TAG: 5.0.0
+          OCIS_DOCKER_TAG: 5.0.1
           OCIS_DOMAIN: ocis.ocis-ldap.released.owncloud.works
           LDAP_MANAGER_DOMAIN: ldap.ocis-ldap.released.owncloud.works
           COMPOSE_FILE: docker-compose.yml:monitoring_tracing/docker-compose-additions.yml
diff --git a/deployments/continuous-deployment-config/ocis_traefik/released.yml b/deployments/continuous-deployment-config/ocis_traefik/released.yml
index d0ff5fc7895..1345b85f12c 100644
--- a/deployments/continuous-deployment-config/ocis_traefik/released.yml
+++ b/deployments/continuous-deployment-config/ocis_traefik/released.yml
@@ -32,7 +32,7 @@
         env:
           INSECURE: "false"
           TRAEFIK_ACME_MAIL: mbarz@owncloud.com
-          OCIS_DOCKER_TAG: 5.0.0
+          OCIS_DOCKER_TAG: 5.0.1
           OCIS_DOMAIN: ocis.ocis-traefik.released.owncloud.works
           DEMO_USERS: "true"
           INBUCKET_DOMAIN: mail.ocis-traefik.released.owncloud.works
diff --git a/deployments/continuous-deployment-config/ocis_wopi/released.yml b/deployments/continuous-deployment-config/ocis_wopi/released.yml
index f570f3a52d3..4673fb4872d 100644
--- a/deployments/continuous-deployment-config/ocis_wopi/released.yml
+++ b/deployments/continuous-deployment-config/ocis_wopi/released.yml
@@ -32,7 +32,7 @@
         env:
           INSECURE: "false"
           TRAEFIK_ACME_MAIL: mbarz@owncloud.com
-          OCIS_DOCKER_TAG: 5.0.0
+          OCIS_DOCKER_TAG: 5.0.1
           OCIS_DOMAIN: ocis.ocis-wopi.released.owncloud.works
           COMPANION_DOMAIN: companion.ocis-wopi.released.owncloud.works
           COMPANION_IMAGE: owncloud/uppy-companion:3.12.13-owncloud
diff --git a/docs/helpers/env_vars.yaml b/docs/helpers/env_vars.yaml
index e13c33debeb..7bfdd5f773e 100644
--- a/docs/helpers/env_vars.yaml
+++ b/docs/helpers/env_vars.yaml
@@ -6902,28 +6902,28 @@ OCIS_ASYNC_UPLOADS:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_CACHE_AUTH_PASSWORD:
-  name: OCIS_CACHE_AUTH_PASSWORD;STORAGE_SYSTEM_CACHE_AUTH_PASSWORD
+  name: OCIS_CACHE_AUTH_PASSWORD;FRONTEND_OCS_STAT_CACHE_AUTH_PASSWORD
   defaultValue: ""
   type: string
-  description: Password for the configured store. Only applies when store type 'nats-js-kv'
-    is configured.
+  description: The password to use for authentication. Only applies when using the
+    'nats-js-kv' store type.
   introductionVersion: "5.0"
   deprecationVersion: ""
   removalVersion: ""
   deprecationInfo: ""
 OCIS_CACHE_AUTH_USERNAME:
-  name: OCIS_CACHE_AUTH_USERNAME;STORAGE_SYSTEM_CACHE_AUTH_USERNAME
+  name: OCIS_CACHE_AUTH_USERNAME;FRONTEND_OCS_STAT_CACHE_AUTH_USERNAME
   defaultValue: ""
   type: string
-  description: Username for the configured store. Only applies when store type 'nats-js-kv'
-    is configured.
+  description: The username to use for authentication. Only applies when using the
+    'nats-js-kv' store type.
   introductionVersion: "5.0"
   deprecationVersion: ""
   removalVersion: ""
   deprecationInfo: ""
 OCIS_CACHE_DATABASE:
   name: OCIS_CACHE_DATABASE
-  defaultValue: storage-system
+  defaultValue: cache-stat
   type: string
   description: The database name the configured store should use.
   introductionVersion: pre5.0
@@ -6931,28 +6931,26 @@ OCIS_CACHE_DATABASE:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_CACHE_DISABLE_PERSISTENCE:
-  name: OCIS_CACHE_DISABLE_PERSISTENCE;STORAGE_SYSTEM_CACHE_DISABLE_PERSISTENCE
+  name: OCIS_CACHE_DISABLE_PERSISTENCE;FRONTEND_OCS_STAT_CACHE_DISABLE_PERSISTENCE
   defaultValue: "false"
   type: bool
-  description: Disables persistence of the cache. Only applies when store type 'nats-js-kv'
-    is configured. Defaults to false.
+  description: Disable persistence of the cache. Only applies when using the 'nats-js-kv'
+    store type. Defaults to false.
   introductionVersion: "5.0"
   deprecationVersion: ""
   removalVersion: ""
   deprecationInfo: ""
 OCIS_CACHE_SIZE:
-  name: OCIS_CACHE_SIZE;STORAGE_SYSTEM_CACHE_SIZE
+  name: OCIS_CACHE_SIZE;FRONTEND_OCS_STAT_CACHE_SIZE
   defaultValue: "0"
   type: int
-  description: The maximum quantity of items in the user info cache. Only applies
-    when store type 'ocmem' is configured. Defaults to 512 which is derived from the
-    ocmem package though not exclicitely set as default.
+  description: Max number of entries to hold in the cache.
   introductionVersion: pre5.0
   deprecationVersion: ""
   removalVersion: ""
   deprecationInfo: ""
 OCIS_CACHE_STORE:
-  name: OCIS_CACHE_STORE;STORAGE_SYSTEM_CACHE_STORE
+  name: OCIS_CACHE_STORE;FRONTEND_OCS_STAT_CACHE_STORE
   defaultValue: memory
   type: string
   description: 'The type of the cache store. Supported values are: ''memory'', ''redis-sentinel'',
@@ -6962,7 +6960,7 @@ OCIS_CACHE_STORE:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_CACHE_STORE_NODES:
-  name: OCIS_CACHE_STORE_NODES;STORAGE_SYSTEM_CACHE_STORE_NODES
+  name: OCIS_CACHE_STORE_NODES;FRONTEND_OCS_STAT_CACHE_STORE_NODES
   defaultValue: '[127.0.0.1:9233]'
   type: '[]string'
   description: A list of nodes to access the configured store. This has no effect
@@ -6974,18 +6972,18 @@ OCIS_CACHE_STORE_NODES:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_CACHE_TTL:
-  name: OCIS_CACHE_TTL;STORAGE_SYSTEM_CACHE_TTL
-  defaultValue: 24m0s
+  name: OCIS_CACHE_TTL;FRONTEND_OCS_STAT_CACHE_TTL
+  defaultValue: 5m0s
   type: Duration
-  description: Default time to live for user info in the user info cache. Only applied
-    when access tokens has no expiration. See the Environment Variable Types description
+  description: Default time to live for user info in the cache. Only applied when
+    access tokens has no expiration. See the Environment Variable Types description
     for more details.
   introductionVersion: pre5.0
   deprecationVersion: ""
   removalVersion: ""
   deprecationInfo: ""
 OCIS_CORS_ALLOW_CREDENTIALS:
-  name: OCIS_CORS_ALLOW_CREDENTIALS;USERLOG_CORS_ALLOW_CREDENTIALS
+  name: OCIS_CORS_ALLOW_CREDENTIALS;WEBDAV_CORS_ALLOW_CREDENTIALS
   defaultValue: "true"
   type: bool
   description: 'Allow credentials for CORS.See following chapter for more details:
@@ -6995,9 +6993,9 @@ OCIS_CORS_ALLOW_CREDENTIALS:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_CORS_ALLOW_HEADERS:
-  name: OCIS_CORS_ALLOW_HEADERS;USERLOG_CORS_ALLOW_HEADERS
+  name: OCIS_CORS_ALLOW_HEADERS;WEBDAV_CORS_ALLOW_HEADERS
   defaultValue: '[Authorization Origin Content-Type Accept X-Requested-With X-Request-Id
-    Ocs-Apirequest]'
+    Cache-Control]'
   type: '[]string'
   description: 'A list of allowed CORS headers. See following chapter for more details:
     *Access-Control-Request-Headers* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Headers.
@@ -7007,8 +7005,8 @@ OCIS_CORS_ALLOW_HEADERS:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_CORS_ALLOW_METHODS:
-  name: OCIS_CORS_ALLOW_METHODS;USERLOG_CORS_ALLOW_METHODS
-  defaultValue: '[GET]'
+  name: OCIS_CORS_ALLOW_METHODS;WEBDAV_CORS_ALLOW_METHODS
+  defaultValue: '[GET POST PUT PATCH DELETE OPTIONS]'
   type: '[]string'
   description: 'A list of allowed CORS methods. See following chapter for more details:
     *Access-Control-Request-Method* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Method.
@@ -7018,7 +7016,7 @@ OCIS_CORS_ALLOW_METHODS:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_CORS_ALLOW_ORIGINS:
-  name: OCIS_CORS_ALLOW_ORIGINS;USERLOG_CORS_ALLOW_ORIGINS
+  name: OCIS_CORS_ALLOW_ORIGINS;WEBDAV_CORS_ALLOW_ORIGINS
   defaultValue: '[*]'
   type: '[]string'
   description: 'A list of allowed CORS origins. See following chapter for more details:
@@ -7285,7 +7283,7 @@ OCIS_JWT_SECRET:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_KEYCLOAK_BASE_PATH:
-  name: OCIS_KEYCLOAK_BASE_PATH;INVITATIONS_KEYCLOAK_BASE_PATH
+  name: OCIS_KEYCLOAK_BASE_PATH;GRAPH_KEYCLOAK_BASE_PATH
   defaultValue: ""
   type: string
   description: The URL to access keycloak.
@@ -7294,16 +7292,16 @@ OCIS_KEYCLOAK_BASE_PATH:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_KEYCLOAK_CLIENT_ID:
-  name: OCIS_KEYCLOAK_CLIENT_ID;INVITATIONS_KEYCLOAK_CLIENT_ID
+  name: OCIS_KEYCLOAK_CLIENT_ID;GRAPH_KEYCLOAK_CLIENT_ID
   defaultValue: ""
   type: string
-  description: The client ID to authenticate with keycloak.
+  description: The client id to authenticate with keycloak.
   introductionVersion: pre5.0
   deprecationVersion: ""
   removalVersion: ""
   deprecationInfo: ""
 OCIS_KEYCLOAK_CLIENT_REALM:
-  name: OCIS_KEYCLOAK_CLIENT_REALM;INVITATIONS_KEYCLOAK_CLIENT_REALM
+  name: OCIS_KEYCLOAK_CLIENT_REALM;GRAPH_KEYCLOAK_CLIENT_REALM
   defaultValue: ""
   type: string
   description: The realm the client is defined in.
@@ -7312,7 +7310,7 @@ OCIS_KEYCLOAK_CLIENT_REALM:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_KEYCLOAK_CLIENT_SECRET:
-  name: OCIS_KEYCLOAK_CLIENT_SECRET;INVITATIONS_KEYCLOAK_CLIENT_SECRET
+  name: OCIS_KEYCLOAK_CLIENT_SECRET;GRAPH_KEYCLOAK_CLIENT_SECRET
   defaultValue: ""
   type: string
   description: The client secret to use in authentication.
@@ -7321,7 +7319,7 @@ OCIS_KEYCLOAK_CLIENT_SECRET:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_KEYCLOAK_INSECURE_SKIP_VERIFY:
-  name: OCIS_KEYCLOAK_INSECURE_SKIP_VERIFY;INVITATIONS_KEYCLOAK_INSECURE_SKIP_VERIFY
+  name: OCIS_KEYCLOAK_INSECURE_SKIP_VERIFY;GRAPH_KEYCLOAK_INSECURE_SKIP_VERIFY
   defaultValue: "false"
   type: bool
   description: Disable TLS certificate validation for Keycloak connections. Do not
@@ -7331,7 +7329,7 @@ OCIS_KEYCLOAK_INSECURE_SKIP_VERIFY:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_KEYCLOAK_USER_REALM:
-  name: OCIS_KEYCLOAK_USER_REALM;INVITATIONS_KEYCLOAK_USER_REALM
+  name: OCIS_KEYCLOAK_USER_REALM;GRAPH_KEYCLOAK_USER_REALM
   defaultValue: ""
   type: string
   description: The realm users are defined.
@@ -7340,7 +7338,7 @@ OCIS_KEYCLOAK_USER_REALM:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_BIND_DN:
-  name: OCIS_LDAP_BIND_DN;USERS_LDAP_BIND_DN
+  name: OCIS_LDAP_BIND_DN;AUTH_BASIC_LDAP_BIND_DN
   defaultValue: uid=reva,ou=sysusers,o=libregraph-idm
   type: string
   description: LDAP DN to use for simple bind authentication with the target LDAP
@@ -7350,7 +7348,7 @@ OCIS_LDAP_BIND_DN:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_BIND_PASSWORD:
-  name: OCIS_LDAP_BIND_PASSWORD;USERS_LDAP_BIND_PASSWORD
+  name: OCIS_LDAP_BIND_PASSWORD;AUTH_BASIC_LDAP_BIND_PASSWORD
   defaultValue: ""
   type: string
   description: Password to use for authenticating the 'bind_dn'.
@@ -7359,7 +7357,7 @@ OCIS_LDAP_BIND_PASSWORD:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_CACERT:
-  name: OCIS_LDAP_CACERT;USERS_LDAP_CACERT
+  name: OCIS_LDAP_CACERT;AUTH_BASIC_LDAP_CACERT
   defaultValue: /var/lib/ocis/idm/ldap.crt
   type: string
   description: Path/File name for the root CA certificate (in PEM format) used to
@@ -7370,7 +7368,7 @@ OCIS_LDAP_CACERT:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_DISABLE_USER_MECHANISM:
-  name: OCIS_LDAP_DISABLE_USER_MECHANISM;USERS_LDAP_DISABLE_USER_MECHANISM
+  name: OCIS_LDAP_DISABLE_USER_MECHANISM;AUTH_BASIC_DISABLE_USER_MECHANISM
   defaultValue: attribute
   type: string
   description: An option to control the behavior for disabling users. Valid options
@@ -7383,7 +7381,7 @@ OCIS_LDAP_DISABLE_USER_MECHANISM:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_DISABLED_USERS_GROUP_DN:
-  name: OCIS_LDAP_DISABLED_USERS_GROUP_DN;USERS_LDAP_DISABLED_USERS_GROUP_DN
+  name: OCIS_LDAP_DISABLED_USERS_GROUP_DN;AUTH_BASIC_DISABLED_USERS_GROUP_DN
   defaultValue: cn=DisabledUsersGroup,ou=groups,o=libregraph-idm
   type: string
   description: The distinguished name of the group to which added users will be classified
@@ -7393,7 +7391,7 @@ OCIS_LDAP_DISABLED_USERS_GROUP_DN:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_GROUP_BASE_DN:
-  name: OCIS_LDAP_GROUP_BASE_DN;USERS_LDAP_GROUP_BASE_DN
+  name: OCIS_LDAP_GROUP_BASE_DN;AUTH_BASIC_LDAP_GROUP_BASE_DN
   defaultValue: ou=groups,o=libregraph-idm
   type: string
   description: Search base DN for looking up LDAP groups.
@@ -7402,7 +7400,7 @@ OCIS_LDAP_GROUP_BASE_DN:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_GROUP_FILTER:
-  name: OCIS_LDAP_GROUP_FILTER;USERS_LDAP_GROUP_FILTER
+  name: OCIS_LDAP_GROUP_FILTER;AUTH_BASIC_LDAP_GROUP_FILTER
   defaultValue: ""
   type: string
   description: LDAP filter to add to the default filters for group searches.
@@ -7411,17 +7409,17 @@ OCIS_LDAP_GROUP_FILTER:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_GROUP_OBJECTCLASS:
-  name: OCIS_LDAP_GROUP_OBJECTCLASS;USERS_LDAP_GROUP_OBJECTCLASS
+  name: OCIS_LDAP_GROUP_OBJECTCLASS;AUTH_BASIC_LDAP_GROUP_OBJECTCLASS
   defaultValue: groupOfNames
   type: string
   description: The object class to use for groups in the default group search filter
-    like 'groupOfNames'.
+    ('groupOfNames').
   introductionVersion: pre5.0
   deprecationVersion: ""
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_GROUP_SCHEMA_DISPLAYNAME:
-  name: OCIS_LDAP_GROUP_SCHEMA_DISPLAYNAME;USERS_LDAP_GROUP_SCHEMA_DISPLAYNAME
+  name: OCIS_LDAP_GROUP_SCHEMA_DISPLAYNAME;AUTH_BASIC_LDAP_GROUP_SCHEMA_DISPLAYNAME
   defaultValue: cn
   type: string
   description: LDAP Attribute to use for the displayname of groups (often the same
@@ -7431,7 +7429,7 @@ OCIS_LDAP_GROUP_SCHEMA_DISPLAYNAME:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_GROUP_SCHEMA_GROUPNAME:
-  name: OCIS_LDAP_GROUP_SCHEMA_GROUPNAME;USERS_LDAP_GROUP_SCHEMA_GROUPNAME
+  name: OCIS_LDAP_GROUP_SCHEMA_GROUPNAME;AUTH_BASIC_LDAP_GROUP_SCHEMA_GROUPNAME
   defaultValue: cn
   type: string
   description: LDAP Attribute to use for the name of groups.
@@ -7440,28 +7438,28 @@ OCIS_LDAP_GROUP_SCHEMA_GROUPNAME:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_GROUP_SCHEMA_ID:
-  name: OCIS_LDAP_GROUP_SCHEMA_ID;USERS_LDAP_GROUP_SCHEMA_ID
+  name: OCIS_LDAP_GROUP_SCHEMA_ID;AUTH_BASIC_LDAP_GROUP_SCHEMA_ID
   defaultValue: ownclouduuid
   type: string
-  description: LDAP Attribute to use as the unique ID for groups. This should be a
-    stable globally unique ID like a UUID.
+  description: LDAP Attribute to use as the unique id for groups. This should be a
+    stable globally unique id (e.g. a UUID).
   introductionVersion: pre5.0
   deprecationVersion: ""
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING:
-  name: OCIS_LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING;USERS_LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING
+  name: OCIS_LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING;AUTH_BASIC_LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING
   defaultValue: "false"
   type: bool
   description: Set this to true if the defined 'id' attribute for groups is of the
     'OCTETSTRING' syntax. This is e.g. required when using the 'objectGUID' attribute
-    of Active Directory for the group ID's.
+    of Active Directory for the group IDs.
   introductionVersion: pre5.0
   deprecationVersion: ""
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_GROUP_SCHEMA_MAIL:
-  name: OCIS_LDAP_GROUP_SCHEMA_MAIL;USERS_LDAP_GROUP_SCHEMA_MAIL
+  name: OCIS_LDAP_GROUP_SCHEMA_MAIL;AUTH_BASIC_LDAP_GROUP_SCHEMA_MAIL
   defaultValue: mail
   type: string
   description: LDAP Attribute to use for the email address of groups (can be empty).
@@ -7470,7 +7468,7 @@ OCIS_LDAP_GROUP_SCHEMA_MAIL:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_GROUP_SCHEMA_MEMBER:
-  name: OCIS_LDAP_GROUP_SCHEMA_MEMBER;USERS_LDAP_GROUP_SCHEMA_MEMBER
+  name: OCIS_LDAP_GROUP_SCHEMA_MEMBER;AUTH_BASIC_LDAP_GROUP_SCHEMA_MEMBER
   defaultValue: member
   type: string
   description: LDAP Attribute that is used for group members.
@@ -7479,7 +7477,7 @@ OCIS_LDAP_GROUP_SCHEMA_MEMBER:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_GROUP_SCOPE:
-  name: OCIS_LDAP_GROUP_SCOPE;USERS_LDAP_GROUP_SCOPE
+  name: OCIS_LDAP_GROUP_SCOPE;AUTH_BASIC_LDAP_GROUP_SCOPE
   defaultValue: sub
   type: string
   description: LDAP search scope to use when looking up groups. Supported values are
@@ -7489,7 +7487,7 @@ OCIS_LDAP_GROUP_SCOPE:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_INSECURE:
-  name: OCIS_LDAP_INSECURE;USERS_LDAP_INSECURE
+  name: OCIS_LDAP_INSECURE;AUTH_BASIC_LDAP_INSECURE
   defaultValue: "false"
   type: bool
   description: Disable TLS certificate validation for the LDAP connections. Do not
@@ -7511,7 +7509,7 @@ OCIS_LDAP_SERVER_WRITE_ENABLED:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_URI:
-  name: OCIS_LDAP_URI;USERS_LDAP_URI
+  name: OCIS_LDAP_URI;AUTH_BASIC_LDAP_URI
   defaultValue: ldaps://localhost:9235
   type: string
   description: URI of the LDAP Server to connect to. Supported URI schemes are 'ldaps://'
@@ -7521,7 +7519,7 @@ OCIS_LDAP_URI:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_USER_BASE_DN:
-  name: OCIS_LDAP_USER_BASE_DN;USERS_LDAP_USER_BASE_DN
+  name: OCIS_LDAP_USER_BASE_DN;AUTH_BASIC_LDAP_USER_BASE_DN
   defaultValue: ou=users,o=libregraph-idm
   type: string
   description: Search base DN for looking up LDAP users.
@@ -7530,7 +7528,7 @@ OCIS_LDAP_USER_BASE_DN:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_USER_ENABLED_ATTRIBUTE:
-  name: OCIS_LDAP_USER_ENABLED_ATTRIBUTE;USERS_LDAP_USER_ENABLED_ATTRIBUTE
+  name: OCIS_LDAP_USER_ENABLED_ATTRIBUTE;AUTH_BASIC_LDAP_USER_ENABLED_ATTRIBUTE
   defaultValue: ownCloudUserEnabled
   type: string
   description: LDAP attribute to use as a flag telling if the user is enabled or disabled.
@@ -7539,7 +7537,7 @@ OCIS_LDAP_USER_ENABLED_ATTRIBUTE:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_USER_FILTER:
-  name: OCIS_LDAP_USER_FILTER;USERS_LDAP_USER_FILTER
+  name: OCIS_LDAP_USER_FILTER;AUTH_BASIC_LDAP_USER_FILTER
   defaultValue: ""
   type: string
   description: LDAP filter to add to the default filters for user search like '(objectclass=ownCloud)'.
@@ -7548,17 +7546,17 @@ OCIS_LDAP_USER_FILTER:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_USER_OBJECTCLASS:
-  name: OCIS_LDAP_USER_OBJECTCLASS;USERS_LDAP_USER_OBJECTCLASS
+  name: OCIS_LDAP_USER_OBJECTCLASS;AUTH_BASIC_LDAP_USER_OBJECTCLASS
   defaultValue: inetOrgPerson
   type: string
   description: The object class to use for users in the default user search filter
-    like 'inetOrgPerson'.
+    ('inetOrgPerson').
   introductionVersion: pre5.0
   deprecationVersion: ""
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_USER_SCHEMA_DISPLAYNAME:
-  name: OCIS_LDAP_USER_SCHEMA_DISPLAYNAME;USERS_LDAP_USER_SCHEMA_DISPLAYNAME
+  name: OCIS_LDAP_USER_SCHEMA_DISPLAYNAME;AUTH_BASIC_LDAP_USER_SCHEMA_DISPLAYNAME
   defaultValue: displayname
   type: string
   description: LDAP Attribute to use for the displayname of users.
@@ -7567,7 +7565,7 @@ OCIS_LDAP_USER_SCHEMA_DISPLAYNAME:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_USER_SCHEMA_ID:
-  name: OCIS_LDAP_USER_SCHEMA_ID;USERS_LDAP_USER_SCHEMA_ID
+  name: OCIS_LDAP_USER_SCHEMA_ID;AUTH_BASIC_LDAP_USER_SCHEMA_ID
   defaultValue: ownclouduuid
   type: string
   description: LDAP Attribute to use as the unique ID for users. This should be a
@@ -7577,18 +7575,18 @@ OCIS_LDAP_USER_SCHEMA_ID:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_USER_SCHEMA_ID_IS_OCTETSTRING:
-  name: OCIS_LDAP_USER_SCHEMA_ID_IS_OCTETSTRING;USERS_LDAP_USER_SCHEMA_ID_IS_OCTETSTRING
+  name: OCIS_LDAP_USER_SCHEMA_ID_IS_OCTETSTRING;AUTH_BASIC_LDAP_USER_SCHEMA_ID_IS_OCTETSTRING
   defaultValue: "false"
   type: bool
   description: Set this to true if the defined 'ID' attribute for users is of the
     'OCTETSTRING' syntax. This is e.g. required when using the 'objectGUID' attribute
-    of Active Directory for the user ID's.
+    of Active Directory for the user IDs.
   introductionVersion: pre5.0
   deprecationVersion: ""
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_USER_SCHEMA_MAIL:
-  name: OCIS_LDAP_USER_SCHEMA_MAIL;USERS_LDAP_USER_SCHEMA_MAIL
+  name: OCIS_LDAP_USER_SCHEMA_MAIL;AUTH_BASIC_LDAP_USER_SCHEMA_MAIL
   defaultValue: mail
   type: string
   description: LDAP Attribute to use for the email address of users.
@@ -7607,7 +7605,7 @@ OCIS_LDAP_USER_SCHEMA_USER_TYPE:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_USER_SCHEMA_USERNAME:
-  name: OCIS_LDAP_USER_SCHEMA_USERNAME;USERS_LDAP_USER_SCHEMA_USERNAME
+  name: OCIS_LDAP_USER_SCHEMA_USERNAME;AUTH_BASIC_LDAP_USER_SCHEMA_USERNAME
   defaultValue: uid
   type: string
   description: LDAP Attribute to use for username of users.
@@ -7616,7 +7614,7 @@ OCIS_LDAP_USER_SCHEMA_USERNAME:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LDAP_USER_SCOPE:
-  name: OCIS_LDAP_USER_SCOPE;USERS_LDAP_USER_SCOPE
+  name: OCIS_LDAP_USER_SCOPE;AUTH_BASIC_LDAP_USER_SCOPE
   defaultValue: sub
   type: string
   description: LDAP search scope to use when looking up users. Supported values are
@@ -7626,7 +7624,7 @@ OCIS_LDAP_USER_SCOPE:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LOG_COLOR:
-  name: OCIS_LOG_COLOR;USERLOG_LOG_COLOR
+  name: OCIS_LOG_COLOR;WEBDAV_LOG_COLOR
   defaultValue: "false"
   type: bool
   description: Activates colorized log output.
@@ -7635,7 +7633,7 @@ OCIS_LOG_COLOR:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LOG_FILE:
-  name: OCIS_LOG_FILE;USERLOG_LOG_FILE
+  name: OCIS_LOG_FILE;WEBDAV_LOG_FILE
   defaultValue: ""
   type: string
   description: The path to the log file. Activates logging to this file if set.
@@ -7644,7 +7642,7 @@ OCIS_LOG_FILE:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LOG_LEVEL:
-  name: OCIS_LOG_LEVEL;USERLOG_LOG_LEVEL
+  name: OCIS_LOG_LEVEL;WEBDAV_LOG_LEVEL
   defaultValue: ""
   type: string
   description: 'The log level. Valid values are: ''panic'', ''fatal'', ''error'',
@@ -7654,7 +7652,7 @@ OCIS_LOG_LEVEL:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_LOG_PRETTY:
-  name: OCIS_LOG_PRETTY;USERLOG_LOG_PRETTY
+  name: OCIS_LOG_PRETTY;WEBDAV_LOG_PRETTY
   defaultValue: "false"
   type: bool
   description: Activates pretty log output.
@@ -7684,7 +7682,7 @@ OCIS_OIDC_CLIENT_ID:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_OIDC_ISSUER:
-  name: OCIS_URL;OCIS_OIDC_ISSUER;PROXY_OIDC_ISSUER
+  name: OCIS_URL;OCIS_OIDC_ISSUER;AUTH_BEARER_OIDC_ISSUER
   defaultValue: https://localhost:9200
   type: string
   description: URL of the OIDC issuer. It defaults to URL of the builtin IDP.
@@ -7911,12 +7909,11 @@ OCIS_SHOW_USER_EMAIL_IN_RESULTS:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_SPACES_MAX_QUOTA:
-  name: OCIS_SPACES_MAX_QUOTA;STORAGE_USERS_OCIS_MAX_QUOTA
+  name: OCIS_SPACES_MAX_QUOTA;FRONTEND_MAX_QUOTA
   defaultValue: "0"
   type: uint64
-  description: Set a global max quota for spaces in bytes. A value of 0 equals unlimited.
-    If not using the global OCIS_SPACES_MAX_QUOTA, you must define the FRONTEND_MAX_QUOTA
-    in the frontend service.
+  description: Set the global max quota value in bytes. A value of 0 equals unlimited.
+    The value is provided via capabilities.
   introductionVersion: pre5.0
   deprecationVersion: ""
   removalVersion: ""
@@ -7952,7 +7949,7 @@ OCIS_SYSTEM_USER_IDP:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_TRACING_COLLECTOR:
-  name: OCIS_TRACING_COLLECTOR;USERLOG_TRACING_COLLECTOR
+  name: OCIS_TRACING_COLLECTOR;WEBDAV_TRACING_COLLECTOR
   defaultValue: ""
   type: string
   description: The HTTP endpoint for sending spans directly to a collector, i.e. http://jaeger-collector:14268/api/traces.
@@ -7962,7 +7959,7 @@ OCIS_TRACING_COLLECTOR:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_TRACING_ENABLED:
-  name: OCIS_TRACING_ENABLED;USERLOG_TRACING_ENABLED
+  name: OCIS_TRACING_ENABLED;WEBDAV_TRACING_ENABLED
   defaultValue: "false"
   type: bool
   description: Activates tracing.
@@ -7971,7 +7968,7 @@ OCIS_TRACING_ENABLED:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_TRACING_ENDPOINT:
-  name: OCIS_TRACING_ENDPOINT;USERLOG_TRACING_ENDPOINT
+  name: OCIS_TRACING_ENDPOINT;WEBDAV_TRACING_ENDPOINT
   defaultValue: ""
   type: string
   description: The endpoint of the tracing agent.
@@ -7980,7 +7977,7 @@ OCIS_TRACING_ENDPOINT:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_TRACING_TYPE:
-  name: OCIS_TRACING_TYPE;USERLOG_TRACING_TYPE
+  name: OCIS_TRACING_TYPE;WEBDAV_TRACING_TYPE
   defaultValue: ""
   type: string
   description: The type of tracing. Defaults to '', which is the same as 'jaeger'.
@@ -8010,10 +8007,10 @@ OCIS_TRANSLATION_PATH:
   removalVersion: ""
   deprecationInfo: ""
 OCIS_URL:
-  name: OCIS_URL;OCDAV_PUBLIC_URL
-  defaultValue: https://localhost:9200
+  name: OCIS_URL;OCIS_PUBLIC_URL
+  defaultValue: https://127.0.0.1:9200
   type: string
-  description: URL where oCIS is reachable for users.
+  description: URL, where oCIS is reachable for users.
   introductionVersion: pre5.0
   deprecationVersion: ""
   removalVersion: ""
@@ -12455,7 +12452,7 @@ STORAGE_USERS_OCIS_LOCK_CYCLE_DURATION_FACTOR:
   type: int
   description: When trying to lock files, ocis will multiply the cycle with this factor
     and use it as a millisecond timeout. Values of 0 or below will be ignored and
-    the default value of 30 will be used.
+    the default value will be used.
   introductionVersion: pre5.0
   deprecationVersion: ""
   removalVersion: ""
@@ -12466,8 +12463,7 @@ STORAGE_USERS_OCIS_MAX_ACQUIRE_LOCK_CYCLES:
   type: int
   description: When trying to lock files, ocis will try this amount of times to acquire
     the lock before failing. After each try it will wait for an increasing amount
-    of time. Values of 0 or below will be ignored and the default value of 20 will
-    be used.
+    of time. Values of 0 or below will be ignored and the default value will be used.
   introductionVersion: pre5.0
   deprecationVersion: ""
   removalVersion: ""
@@ -12478,7 +12474,7 @@ STORAGE_USERS_OCIS_MAX_CONCURRENCY:
   type: int
   description: Maximum number of concurrent go-routines. Higher values can potentially
     get work done faster but will also cause more load on the system. Values of 0
-    or below will be ignored and the default value of 100 will be used.
+    or below will be ignored and the default value will be used.
   introductionVersion: pre5.0
   deprecationVersion: ""
   removalVersion: ""
diff --git a/docs/services/app-registry/_index.md b/docs/services/app-registry/_index.md
index fc1f49bae8e..bf4f6b61339 100755
--- a/docs/services/app-registry/_index.md
+++ b/docs/services/app-registry/_index.md
@@ -1,6 +1,6 @@
 ---
 title: App Registry
-date: 2024-04-04T15:08:13.220767367+02:00
+date: 2024-04-08T14:03:04.981194969+02:00
 weight: 20
 geekdocRepo: https://github.com/owncloud/ocis
 geekdocEditPath: edit/master/services/app-registry
diff --git a/services/frontend/README.md b/services/frontend/README.md
index 83b395348b0..d66736f0b60 100644
--- a/services/frontend/README.md
+++ b/services/frontend/README.md
@@ -22,6 +22,10 @@ The datagateway endpoint, by default `/data`, forwards file up- and download req
 
 The ocs endpoint, by default `/ocs`, implements the ownCloud 10 Open Collaboration Services API by translating it into CS3 API requests. It can handle users, groups, capabilities and also implements the files sharing functionality on top of CS3. The `/ocs/v[12].php/cloud/user/signing-key` is currently handled by the dedicated [ocs](https://github.com/owncloud/ocis/tree/master/services/ocs) service.
 
+#### Event Handler
+
+The `frontend` service contains an eventhandler for handling `ocs` related events. As of now, it only listens to the `ShareCreated` event.
+
 ### Sharing
 
 Aggregating share information is one of the most time consuming operations in OCIS. The service fetches a list of either received or created shares and has to stat every resource individually. While stats are fast, the default behavior scales linearly with the number of shares.
@@ -63,15 +67,13 @@ Store specific notes:
   -   When using `nats-js-kv` it is recommended to set `OCIS_CACHE_STORE_NODES` to the same value as `OCIS_EVENTS_ENDPOINT`. That way the cache uses the same nats instance as the event bus.
   -   When using the `nats-js-kv` store, it is possible to set `OCIS_CACHE_DISABLE_PERSISTENCE` to instruct nats to not persist cache data on disc.
 
-## Event Handler
-
-The `frontend` service contains an eventhandler for handling `ocs` related events. As of now, it only listens to the `ShareCreated` event.
-
 ### Auto-Accept Shares
 
 When setting the `FRONTEND_AUTO_ACCEPT_SHARES` to `true`, all incoming shares will be accepted automatically. Users can overwrite this setting individually in their profile.
 
-## The password policy
+## Passwords
+
+### The Password Policy
 
 Note that the password policy currently impacts only **public link password validation**.
 
@@ -104,7 +106,7 @@ These variables are global ocis variables because they are used not only in the
 
 Note that a password can have a maximum length of **72 bytes**. Depending on the alphabet used, a character is encoded by 1 to 4 bytes, defining the maximum length of a password indirectly. While US-ASCII will only need one byte, Latin alphabets and also Greek or Cyrillic ones need two bytes. Three bytes are needed for characters in Chinese, Japanese and Korean etc.
 
-### The password policy capability
+### The Password Policy Capability
 
 The capabilities endpoint (e.g. https://ocis.test/ocs/v1.php/cloud/capabilities?format=json) gives you following capabilities which are relevant for the password policy:
 
@@ -126,3 +128,19 @@ The capabilities endpoint (e.g. https://ocis.test/ocs/v1.php/cloud/capabilities?
   }
 }
 ```
+
+### Password Enforcement for all Public Links
+
+For public accessible shares, independent if read only or writable, a password is enforced. To change this requirement, set the following environment variable to `false`:
+
+`OCIS_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD`
+
+### Password Enforcement for Writeable Public Links
+
+For public accessible writable shares, a password can be enforced. To change the current setting, set the following environment variable to `true`:
+
+`OCIS_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD`
+
+Note that changing this environment variable only makes sense if\
+`OCIS_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD`\
+is set to `false`.
diff --git a/services/frontend/pkg/config/config.go b/services/frontend/pkg/config/config.go
index 6404c33ccb6..1408cd75954 100644
--- a/services/frontend/pkg/config/config.go
+++ b/services/frontend/pkg/config/config.go
@@ -142,8 +142,9 @@ type OCS struct {
 	EnableDenials                        bool               `yaml:"enable_denials" env:"FRONTEND_OCS_ENABLE_DENIALS" desc:"EXPERIMENTAL: enable the feature to deny access on folders." introductionVersion:"pre5.0"`
 	ListOCMShares                        bool               `yaml:"list_ocm_shares" env:"FRONTEND_OCS_LIST_OCM_SHARES" desc:"Include OCM shares when listing shares. See the OCM service documentation for more details." introductionVersion:"5.0"`
 	PublicShareMustHavePassword          bool               `yaml:"public_sharing_share_must_have_password" env:"OCIS_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD;FRONTEND_OCS_PUBLIC_SHARE_MUST_HAVE_PASSWORD" desc:"Set this to true if you want to enforce passwords on all public shares." introductionVersion:"5.0"`
-	WriteablePublicShareMustHavePassword bool               `yaml:"public_sharing_writeableshare_must_have_password" env:"OCIS_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD;FRONTEND_OCS_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD" desc:"Set this to true if you want to enforce passwords on Uploader, Editor or Contributor shares." introductionVersion:"5.0"`
+	WriteablePublicShareMustHavePassword bool               `yaml:"public_sharing_writeableshare_must_have_password" env:"OCIS_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD;FRONTEND_OCS_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD" desc:"Set this to true if you want to enforce passwords for writable shares. Only effective if the setting for 'passwords on all public shares' is set to false." introductionVersion:"5.0"`
 	IncludeOCMSharees                    bool               `yaml:"include_ocm_sharees" env:"FRONTEND_OCS_INCLUDE_OCM_SHAREES" desc:"Include OCM sharees when listing sharees." introductionVersion:"5.0"`
+	ShowUserEmailInResults               bool               `yaml:"show_email_in_results" env:"OCIS_SHOW_USER_EMAIL_IN_RESULTS" desc:"Mask user email addresses in responses." introductionVersion:"5.1"`
 }
 
 type CacheWarmupDrivers struct {
diff --git a/services/frontend/pkg/revaconfig/config.go b/services/frontend/pkg/revaconfig/config.go
index 769a6f6d1a0..1a94ae323eb 100644
--- a/services/frontend/pkg/revaconfig/config.go
+++ b/services/frontend/pkg/revaconfig/config.go
@@ -338,7 +338,8 @@ func FrontendConfigFromStruct(cfg *config.Config, logger log.Logger) (map[string
 							"productversion": version.GetString(),
 						},
 					},
-					"include_ocm_sharees": cfg.OCS.IncludeOCMSharees,
+					"include_ocm_sharees":   cfg.OCS.IncludeOCMSharees,
+					"show_email_in_results": cfg.OCS.ShowUserEmailInResults,
 				},
 			},
 		},
diff --git a/services/graph/pkg/errorcode/cs3.go b/services/graph/pkg/errorcode/cs3.go
index 12bd7b5c8b3..6b3f71be317 100644
--- a/services/graph/pkg/errorcode/cs3.go
+++ b/services/graph/pkg/errorcode/cs3.go
@@ -17,12 +17,12 @@ import (
 //
 // This function is particularly useful when dealing with CS3 responses,
 // and a unified error handling within the application is necessary.
-func FromCS3Status(status *cs3rpc.Status, inerr error, ignore ...cs3rpc.Code) *Error {
+func FromCS3Status(status *cs3rpc.Status, inerr error, ignore ...cs3rpc.Code) error {
 	if inerr != nil {
-		return &Error{msg: inerr.Error(), errorCode: GeneralException}
+		return Error{msg: inerr.Error(), errorCode: GeneralException}
 	}
 
-	err := &Error{errorCode: GeneralException, msg: "unspecified error has occurred"}
+	err := Error{errorCode: GeneralException, msg: "unspecified error has occurred"}
 
 	if status != nil {
 		err.msg = status.GetMessage()
@@ -33,7 +33,7 @@ func FromCS3Status(status *cs3rpc.Status, inerr error, ignore ...cs3rpc.Code) *E
 	case slices.Contains(ignore, status.GetCode()):
 		fallthrough
 	case code == cs3rpc.Code_CODE_OK:
-		err = nil
+		return nil
 	case code == cs3rpc.Code_CODE_NOT_FOUND:
 		err.errorCode = ItemNotFound
 	case code == cs3rpc.Code_CODE_PERMISSION_DENIED:
@@ -61,11 +61,11 @@ func FromCS3Status(status *cs3rpc.Status, inerr error, ignore ...cs3rpc.Code) *E
 	return err
 }
 
-// FromStat transforms a *provider.StatResponse object and an error into an *Error.
+// FromStat transforms a *provider.StatResponse object and an error into an Error.
 //
 // It takes a stat of type *provider.StatResponse, an error, and a variadic parameter of type cs3rpc.Code.
 // It invokes the FromCS3Status function with the StatResponse Status and the ignore codes.
-func FromStat(stat *provider.StatResponse, err error, ignore ...cs3rpc.Code) *Error {
+func FromStat(stat *provider.StatResponse, err error, ignore ...cs3rpc.Code) error {
 	// TODO: look into ResourceInfo to get the postprocessing state and map that to 425 status?
 	return FromCS3Status(stat.GetStatus(), err, ignore...)
 }
diff --git a/services/graph/pkg/errorcode/errorcode.go b/services/graph/pkg/errorcode/errorcode.go
index 88bb421f24b..f4a9bda4102 100644
--- a/services/graph/pkg/errorcode/errorcode.go
+++ b/services/graph/pkg/errorcode/errorcode.go
@@ -166,7 +166,8 @@ func RenderError(w http.ResponseWriter, r *http.Request, err error) {
 	var errcode Error
 	if errors.As(err, &errcode) {
 		errcode.Render(w, r)
-	} else {
-		GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
+		return
 	}
+
+	GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
 }
diff --git a/services/graph/pkg/service/v0/api_driveitem_permissions.go b/services/graph/pkg/service/v0/api_driveitem_permissions.go
index 1fd6caa56b1..df98081d9a5 100644
--- a/services/graph/pkg/service/v0/api_driveitem_permissions.go
+++ b/services/graph/pkg/service/v0/api_driveitem_permissions.go
@@ -83,15 +83,14 @@ func (s DriveItemPermissionsService) Invite(ctx context.Context, resourceId stor
 	}
 
 	statResponse, err := gatewayClient.Stat(ctx, &storageprovider.StatRequest{Ref: &storageprovider.Reference{ResourceId: &resourceId}})
-	if errCode := errorcode.FromStat(statResponse, err); errCode != nil {
-		s.logger.Warn().Err(errCode).Interface("stat.res", statResponse).Msg("stat failed")
-		return libregraph.Permission{}, *errCode
+	if err := errorcode.FromStat(statResponse, err); err != nil {
+		s.logger.Warn().Err(err).Interface("stat.res", statResponse).Msg("stat failed")
+		return libregraph.Permission{}, err
 	}
 
-	resourceInfo := statResponse.GetInfo()
-	condition := unifiedrole.UnifiedRoleConditionGrantee
-	if IsSpaceRoot(resourceInfo.GetId()) {
-		condition = unifiedrole.UnifiedRoleConditionOwner
+	var condition string
+	if condition, err = roleConditionForResourceType(statResponse.GetInfo()); err != nil {
+		return libregraph.Permission{}, err
 	}
 
 	unifiedRolePermissions := []*libregraph.UnifiedRolePermission{{AllowedResourceActions: invite.LibreGraphPermissionsActions}}
@@ -116,7 +115,7 @@ func (s DriveItemPermissionsService) Invite(ctx context.Context, resourceId stor
 	cs3ResourcePermissions := unifiedrole.PermissionsToCS3ResourcePermissions(unifiedRolePermissions)
 
 	createShareRequest := &collaboration.CreateShareRequest{
-		ResourceInfo: resourceInfo,
+		ResourceInfo: statResponse.GetInfo(),
 		Grant: &collaboration.ShareGrant{
 			Permissions: &collaboration.SharePermissions{
 				Permissions: cs3ResourcePermissions,
@@ -178,14 +177,14 @@ func (s DriveItemPermissionsService) Invite(ctx context.Context, resourceId stor
 	}
 
 	createShareResponse, err := gatewayClient.CreateShare(ctx, createShareRequest)
-	if errCode := errorcode.FromCS3Status(createShareResponse.GetStatus(), err); errCode != nil {
+	if err := errorcode.FromCS3Status(createShareResponse.GetStatus(), err); err != nil {
 		s.logger.Debug().Err(err).Msg("share creation failed")
-		return libregraph.Permission{}, *errCode
+		return libregraph.Permission{}, err
 	}
 
 	if id := createShareResponse.GetShare().GetId().GetOpaqueId(); id != "" {
 		permission.Id = conversions.ToPointer(id)
-	} else if IsSpaceRoot(resourceInfo.GetId()) {
+	} else if IsSpaceRoot(statResponse.GetInfo().GetId()) {
 		// permissions on a space root are not handled by a share manager so
 		// they don't get a share-id
 		permission.SetId(identitySetToSpacePermissionID(permission.GetGrantedToV2()))
@@ -227,14 +226,14 @@ func (s DriveItemPermissionsService) ListPermissions(ctx context.Context, itemID
 	}
 
 	statResponse, err := gatewayClient.Stat(ctx, &storageprovider.StatRequest{Ref: &storageprovider.Reference{ResourceId: &itemID}})
-	if errCode := errorcode.FromStat(statResponse, err); errCode != nil {
-		s.logger.Warn().Err(errCode).Interface("stat.res", statResponse).Msg("stat failed")
+	if err := errorcode.FromStat(statResponse, err); err != nil {
+		s.logger.Warn().Err(err).Interface("stat.res", statResponse).Msg("stat failed")
 		return collectionOfPermissions, err
 	}
 
-	condition := unifiedrole.UnifiedRoleConditionGrantee
-	if IsSpaceRoot(statResponse.GetInfo().GetId()) {
-		condition = unifiedrole.UnifiedRoleConditionOwner
+	var condition string
+	if condition, err = roleConditionForResourceType(statResponse.GetInfo()); err != nil {
+		return collectionOfPermissions, err
 	}
 
 	permissionSet := *statResponse.GetInfo().GetPermissionSet()
diff --git a/services/graph/pkg/service/v0/api_driveitem_permissions_links.go b/services/graph/pkg/service/v0/api_driveitem_permissions_links.go
index c1410d880c8..3de834a331d 100644
--- a/services/graph/pkg/service/v0/api_driveitem_permissions_links.go
+++ b/services/graph/pkg/service/v0/api_driveitem_permissions_links.go
@@ -290,8 +290,8 @@ func (s DriveItemPermissionsService) updatePublicLinkPermission(ctx context.Cont
 			},
 		})
 
-	if errCode := errorcode.FromCS3Status(statResp.GetStatus(), err); errCode != nil {
-		return nil, *errCode
+	if err := errorcode.FromCS3Status(statResp.GetStatus(), err); err != nil {
+		return nil, err
 	}
 
 	if newPermission.HasExpirationDateTime() {
@@ -369,8 +369,8 @@ func (s DriveItemPermissionsService) updatePublicLinkPassword(ctx context.Contex
 			},
 		},
 	})
-	if errCode := errorcode.FromCS3Status(changeLinkRes.GetStatus(), err); errCode != nil {
-		return nil, *errCode
+	if err := errorcode.FromCS3Status(changeLinkRes.GetStatus(), err); err != nil {
+		return nil, err
 	}
 	permission, err := s.libreGraphPermissionFromCS3PublicShare(changeLinkRes.GetShare())
 	if err != nil {
@@ -396,8 +396,8 @@ func (s DriveItemPermissionsService) updatePublicLink(ctx context.Context, permi
 		},
 	})
 
-	if errCode := errorcode.FromCS3Status(changeLinkRes.GetStatus(), err); errCode != nil {
-		return nil, *errCode
+	if err := errorcode.FromCS3Status(changeLinkRes.GetStatus(), err); err != nil {
+		return nil, err
 	}
 
 	permission, err := s.libreGraphPermissionFromCS3PublicShare(changeLinkRes.GetShare())
diff --git a/services/graph/pkg/service/v0/api_drives_drive_item.go b/services/graph/pkg/service/v0/api_drives_drive_item.go
index 2b874d5eb31..882132fa0d1 100644
--- a/services/graph/pkg/service/v0/api_drives_drive_item.go
+++ b/services/graph/pkg/service/v0/api_drives_drive_item.go
@@ -71,11 +71,11 @@ func (s DrivesDriveItemService) UnmountShare(ctx context.Context, resourceID sto
 			},
 		},
 	)
-	if errCode := errorcode.FromCS3Status(getReceivedShareResponse.GetStatus(), err); errCode != nil {
-		s.logger.Debug().Err(errCode).
+	if err := errorcode.FromCS3Status(getReceivedShareResponse.GetStatus(), err); err != nil {
+		s.logger.Debug().Err(err).
 			Str("shareid", shareId).
 			Msg("failed to read share")
-		return errCode
+		return err
 	}
 
 	// Find all accepted shares for this resource
diff --git a/services/graph/pkg/service/v0/base.go b/services/graph/pkg/service/v0/base.go
index e1bec910931..ace9091de3d 100644
--- a/services/graph/pkg/service/v0/base.go
+++ b/services/graph/pkg/service/v0/base.go
@@ -21,13 +21,14 @@ import (
 	"github.com/cs3org/reva/v2/pkg/storagespace"
 	"github.com/cs3org/reva/v2/pkg/utils"
 	libregraph "github.com/owncloud/libre-graph-api-go"
+	"google.golang.org/protobuf/types/known/fieldmaskpb"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
 	"github.com/owncloud/ocis/v2/services/graph/pkg/config"
 	"github.com/owncloud/ocis/v2/services/graph/pkg/errorcode"
 	"github.com/owncloud/ocis/v2/services/graph/pkg/identity"
 	"github.com/owncloud/ocis/v2/services/graph/pkg/linktype"
 	"github.com/owncloud/ocis/v2/services/graph/pkg/unifiedrole"
-	"google.golang.org/protobuf/types/known/fieldmaskpb"
 )
 
 // BaseGraphService implements a couple of helper functions that are
@@ -165,7 +166,7 @@ func (g BaseGraphService) cs3SpacePermissionsToLibreGraph(ctx context.Context, s
 			p.SetExpirationDateTime(time.Unix(int64(exp.GetSeconds()), int64(exp.GetNanos())))
 		}
 
-		if role := unifiedrole.CS3ResourcePermissionsToUnifiedRole(*perm, unifiedrole.UnifiedRoleConditionOwner); role != nil {
+		if role := unifiedrole.CS3ResourcePermissionsToUnifiedRole(*perm, unifiedrole.UnifiedRoleConditionDrive); role != nil {
 			switch apiVersion {
 			case APIVersion_1:
 				if r := unifiedrole.GetLegacyName(*role); r != "" {
@@ -287,7 +288,17 @@ func (g BaseGraphService) cs3UserSharesToDriveItems(ctx context.Context, shares
 			}
 			item = *itemptr
 		}
-		perm, err := g.cs3UserShareToPermission(ctx, s, false)
+
+		var condition string
+		switch {
+		case item.Root != nil:
+			condition = unifiedrole.UnifiedRoleConditionDrive
+		case item.Folder != nil:
+			condition = unifiedrole.UnifiedRoleConditionFolder
+		case item.File != nil:
+			condition = unifiedrole.UnifiedRoleConditionFile
+		}
+		perm, err := g.cs3UserShareToPermission(ctx, s, condition)
 
 		var errcode errorcode.Error
 		switch {
@@ -303,10 +314,10 @@ func (g BaseGraphService) cs3UserSharesToDriveItems(ctx context.Context, shares
 	return driveItems, nil
 }
 
-func (g BaseGraphService) cs3UserShareToPermission(ctx context.Context, share *collaboration.Share, isSpacePermission bool) (*libregraph.Permission, error) {
+func (g BaseGraphService) cs3UserShareToPermission(ctx context.Context, share *collaboration.Share, roleCondition string) (*libregraph.Permission, error) {
 	perm := libregraph.Permission{}
 	perm.SetRoles([]string{})
-	if !isSpacePermission {
+	if roleCondition != unifiedrole.UnifiedRoleConditionDrive {
 		perm.SetId(share.GetId().GetOpaqueId())
 	}
 	grantedTo := libregraph.SharePointIdentitySet{}
@@ -322,7 +333,7 @@ func (g BaseGraphService) cs3UserShareToPermission(ctx context.Context, share *c
 			return nil, errorcode.New(errorcode.GeneralException, err.Error())
 		default:
 			grantedTo.SetUser(user)
-			if isSpacePermission {
+			if roleCondition == unifiedrole.UnifiedRoleConditionDrive {
 				perm.SetId("u:" + user.GetId())
 			}
 		}
@@ -337,7 +348,7 @@ func (g BaseGraphService) cs3UserShareToPermission(ctx context.Context, share *c
 			return nil, errorcode.New(errorcode.GeneralException, err.Error())
 		default:
 			grantedTo.SetGroup(group)
-			if isSpacePermission {
+			if roleCondition == unifiedrole.UnifiedRoleConditionDrive {
 				perm.SetId("g:" + group.GetId())
 			}
 		}
@@ -347,13 +358,9 @@ func (g BaseGraphService) cs3UserShareToPermission(ctx context.Context, share *c
 	if share.GetExpiration() != nil {
 		perm.SetExpirationDateTime(cs3TimestampToTime(share.GetExpiration()))
 	}
-	condition := unifiedrole.UnifiedRoleConditionGrantee
-	if isSpacePermission {
-		condition = unifiedrole.UnifiedRoleConditionOwner
-	}
 	role := unifiedrole.CS3ResourcePermissionsToUnifiedRole(
 		*share.GetPermissions().GetPermissions(),
-		condition,
+		roleCondition,
 	)
 	if role != nil {
 		perm.SetRoles([]string{role.GetId()})
@@ -418,8 +425,8 @@ func (g BaseGraphService) getCS3PublicShareByID(ctx context.Context, permissionI
 			},
 		},
 	)
-	if errCode := errorcode.FromCS3Status(getPublicShareResp.GetStatus(), err); errCode != nil {
-		return nil, *errCode
+	if err := errorcode.FromCS3Status(getPublicShareResp.GetStatus(), err); err != nil {
+		return nil, err
 	}
 	return getPublicShareResp.GetShare(), nil
 }
@@ -441,8 +448,8 @@ func (g BaseGraphService) removePublicShare(ctx context.Context, permissionID st
 				},
 			},
 		})
-	if errcode := errorcode.FromCS3Status(removePublicShareResp.GetStatus(), err); errcode != nil {
-		return *errcode
+	if err := errorcode.FromCS3Status(removePublicShareResp.GetStatus(), err); err != nil {
+		return err
 	}
 	// We need to return an untyped nil here otherwise the error==nil check won't work
 	return nil
@@ -466,8 +473,8 @@ func (g BaseGraphService) removeUserShare(ctx context.Context, permissionID stri
 			},
 		})
 
-	if errCode := errorcode.FromCS3Status(removeShareResp.GetStatus(), err); errCode != nil {
-		return *errCode
+	if err := errorcode.FromCS3Status(removeShareResp.GetStatus(), err); err != nil {
+		return err
 	}
 	// We need to return an untyped nil here otherwise the error==nil check won't work
 	return nil
@@ -495,8 +502,8 @@ func (g BaseGraphService) removeSpacePermission(ctx context.Context, permissionI
 		},
 	})
 
-	if errCode := errorcode.FromCS3Status(removeShareResp.GetStatus(), err); errCode != nil {
-		return *errCode
+	if err := errorcode.FromCS3Status(removeShareResp.GetStatus(), err); err != nil {
+		return err
 	}
 	// We need to return an untyped nil here otherwise the error==nil check won't work
 	return nil
@@ -527,15 +534,20 @@ func (g BaseGraphService) getCS3UserShareByID(ctx context.Context, permissionID
 				},
 			},
 		})
-	if errCode := errorcode.FromCS3Status(getShareResp.GetStatus(), err); errCode != nil {
-		return nil, *errCode
+	if err := errorcode.FromCS3Status(getShareResp.GetStatus(), err); err != nil {
+		return nil, err
 	}
 	return getShareResp.GetShare(), nil
 }
 
 func (g BaseGraphService) getPermissionByID(ctx context.Context, permissionID string, itemID *storageprovider.ResourceId) (*libregraph.Permission, *storageprovider.ResourceId, error) {
-	publicShare, err := g.getCS3PublicShareByID(ctx, permissionID)
 	var errcode errorcode.Error
+	gatewayClient, err := g.gatewaySelector.Next()
+	if err != nil {
+		g.logger.Debug().Err(err).Msg("selecting gatewaySelector failed")
+		return nil, nil, err
+	}
+	publicShare, err := g.getCS3PublicShareByID(ctx, permissionID)
 	switch {
 	case err == nil:
 		// the id is referencing a public share
@@ -546,13 +558,7 @@ func (g BaseGraphService) getPermissionByID(ctx context.Context, permissionID st
 		return permission, publicShare.GetResourceId(), nil
 	case IsSpaceRoot(itemID):
 		// itemID is referencing a spaceroot this is a space permission. Handle
-		// that next
-		gatewayClient, err := g.gatewaySelector.Next()
-		if err != nil {
-			g.logger.Debug().Err(err).Msg("selecting gatewaySelector failed")
-			return nil, nil, err
-		}
-		// get space id
+		// that here and get space id
 		resourceInfo, err := utils.GetResourceByID(ctx, itemID, gatewayClient)
 		if err != nil {
 			return nil, nil, err
@@ -573,7 +579,15 @@ func (g BaseGraphService) getPermissionByID(ctx context.Context, permissionID st
 		if err != nil {
 			return nil, nil, err
 		}
-		permission, err := g.cs3UserShareToPermission(ctx, share, false)
+		resourceInfo, err := utils.GetResourceByID(ctx, itemID, gatewayClient)
+		if err != nil {
+			return nil, nil, err
+		}
+		condition, err := roleConditionForResourceType(resourceInfo)
+		if err != nil {
+			return nil, nil, err
+		}
+		permission, err := g.cs3UserShareToPermission(ctx, share, condition)
 		if err != nil {
 			return nil, nil, err
 		}
@@ -590,6 +604,14 @@ func (g BaseGraphService) updateUserShare(ctx context.Context, permissionID stri
 		return nil, err
 	}
 
+	resourceInfo, err := utils.GetResourceByID(ctx, itemID, gatewayClient)
+	if err != nil {
+		return nil, err
+	}
+	condition, err := roleConditionForResourceType(resourceInfo)
+	if err != nil {
+		return nil, err
+	}
 	var cs3UpdateShareReq collaboration.UpdateShareRequest
 	// When updating a space root we need to reference the share by resourceId and grantee
 	if IsSpaceRoot(itemID) {
@@ -632,11 +654,6 @@ func (g BaseGraphService) updateUserShare(ctx context.Context, permissionID stri
 				return nil, err
 			}
 
-			condition := unifiedrole.UnifiedRoleConditionGrantee
-			if IsSpaceRoot(itemID) {
-				condition = unifiedrole.UnifiedRoleConditionOwner
-			}
-			// FIXME: When setting permissions on a space, we need to use UnifiedRoleConditionOwner here
 			allowedResourceActions = unifiedrole.GetAllowedResourceActions(role, condition)
 			if len(allowedResourceActions) == 0 {
 				return nil, errorcode.New(errorcode.InvalidRequest, "role not applicable to this resource")
@@ -667,11 +684,11 @@ func (g BaseGraphService) updateUserShare(ctx context.Context, permissionID stri
 	}
 
 	updateUserShareResp, err := gatewayClient.UpdateShare(ctx, &cs3UpdateShareReq)
-	if errCode := errorcode.FromCS3Status(updateUserShareResp.GetStatus(), err); errCode != nil {
-		return nil, *errCode
+	if err := errorcode.FromCS3Status(updateUserShareResp.GetStatus(), err); err != nil {
+		return nil, err
 	}
 
-	permission, err := g.cs3UserShareToPermission(ctx, updateUserShareResp.GetShare(), IsSpaceRoot(itemID))
+	permission, err := g.cs3UserShareToPermission(ctx, updateUserShareResp.GetShare(), condition)
 	if err != nil {
 		return nil, err
 	}
diff --git a/services/graph/pkg/service/v0/drives.go b/services/graph/pkg/service/v0/drives.go
index b8416210605..60527674520 100644
--- a/services/graph/pkg/service/v0/drives.go
+++ b/services/graph/pkg/service/v0/drives.go
@@ -27,7 +27,7 @@ import (
 	revactx "github.com/cs3org/reva/v2/pkg/ctx"
 	"github.com/cs3org/reva/v2/pkg/storagespace"
 	"github.com/cs3org/reva/v2/pkg/utils"
-	"github.com/owncloud/ocis/v2/ocis-pkg/conversions"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/l10n"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
 	v0 "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
@@ -78,7 +78,7 @@ func (g Graph) GetDrives(version APIVersion) http.HandlerFunc {
 func (g Graph) GetDrivesV1(w http.ResponseWriter, r *http.Request) {
 	spaces, errCode := g.getDrives(r, false, APIVersion_1)
 	if errCode != nil {
-		errCode.Render(w, r)
+		errorcode.RenderError(w, r, errCode)
 		return
 	}
 
@@ -99,7 +99,7 @@ func (g Graph) GetDrivesV1(w http.ResponseWriter, r *http.Request) {
 func (g Graph) GetDrivesV1Beta1(w http.ResponseWriter, r *http.Request) {
 	spaces, errCode := g.getDrives(r, false, APIVersion_1_Beta_1)
 	if errCode != nil {
-		errCode.Render(w, r)
+		errorcode.RenderError(w, r, errCode)
 		return
 	}
 
@@ -133,7 +133,7 @@ func (g Graph) GetAllDrives(version APIVersion) http.HandlerFunc {
 func (g Graph) GetAllDrivesV1(w http.ResponseWriter, r *http.Request) {
 	spaces, errCode := g.getDrives(r, true, APIVersion_1)
 	if errCode != nil {
-		errCode.Render(w, r)
+		errorcode.RenderError(w, r, errCode)
 		return
 	}
 
@@ -153,7 +153,7 @@ func (g Graph) GetAllDrivesV1(w http.ResponseWriter, r *http.Request) {
 func (g Graph) GetAllDrivesV1Beta1(w http.ResponseWriter, r *http.Request) {
 	drives, errCode := g.getDrives(r, true, APIVersion_1_Beta_1)
 	if errCode != nil {
-		errCode.Render(w, r)
+		errorcode.RenderError(w, r, errCode)
 		return
 	}
 
@@ -168,7 +168,7 @@ func (g Graph) GetAllDrivesV1Beta1(w http.ResponseWriter, r *http.Request) {
 }
 
 // getDrives implements the Service interface.
-func (g Graph) getDrives(r *http.Request, unrestricted bool, apiVersion APIVersion) ([]*libregraph.Drive, *errorcode.Error) {
+func (g Graph) getDrives(r *http.Request, unrestricted bool, apiVersion APIVersion) ([]*libregraph.Drive, error) {
 	logger := g.logger.SubloggerWithRequestID(r.Context())
 	logger.Info().
 		Interface("query", r.URL.Query()).
@@ -179,20 +179,20 @@ func (g Graph) getDrives(r *http.Request, unrestricted bool, apiVersion APIVersi
 	odataReq, err := godata.ParseRequest(r.Context(), sanitizedPath, r.URL.Query())
 	if err != nil {
 		logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("could not get drives: query error")
-		return nil, conversions.ToPointer(errorcode.New(errorcode.InvalidRequest, err.Error()))
+		return nil, errorcode.New(errorcode.InvalidRequest, err.Error())
 	}
 	ctx := r.Context()
 
 	filters, err := generateCs3Filters(odataReq)
 	if err != nil {
 		logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("could not get drives: error parsing filters")
-		return nil, conversions.ToPointer(errorcode.New(errorcode.NotSupported, err.Error()))
+		return nil, errorcode.New(errorcode.NotSupported, err.Error())
 	}
 	if !unrestricted {
 		user, ok := revactx.ContextGetUser(r.Context())
 		if !ok {
 			logger.Debug().Msg("could not create drive: invalid user")
-			return nil, conversions.ToPointer(errorcode.New(errorcode.AccessDenied, "invalid user"))
+			return nil, errorcode.New(errorcode.AccessDenied, "invalid user")
 		}
 		filters = append(filters, &storageprovider.ListStorageSpacesRequest_Filter{
 			Type: storageprovider.ListStorageSpacesRequest_Filter_TYPE_USER,
@@ -210,32 +210,32 @@ func (g Graph) getDrives(r *http.Request, unrestricted bool, apiVersion APIVersi
 	switch {
 	case err != nil:
 		logger.Error().Err(err).Msg("could not get drives: transport error")
-		return nil, conversions.ToPointer(errorcode.New(errorcode.GeneralException, err.Error()))
+		return nil, errorcode.New(errorcode.GeneralException, err.Error())
 	case res.Status.Code != cs3rpc.Code_CODE_OK:
 		if res.Status.Code == cs3rpc.Code_CODE_NOT_FOUND {
 			// ok, empty return
 			return nil, nil
 		}
 		logger.Debug().Str("message", res.GetStatus().GetMessage()).Msg("could not get drives: grpc error")
-		return nil, conversions.ToPointer(errorcode.New(errorcode.GeneralException, res.Status.Message))
+		return nil, errorcode.New(errorcode.GeneralException, res.Status.Message)
 	}
 
 	webDavBaseURL, err := g.getWebDavBaseURL()
 	if err != nil {
 		logger.Error().Err(err).Str("url", webDavBaseURL.String()).Msg("could not get drives: error parsing url")
-		return nil, conversions.ToPointer(errorcode.New(errorcode.GeneralException, err.Error()))
+		return nil, errorcode.New(errorcode.GeneralException, err.Error())
 	}
 
 	spaces, err := g.formatDrives(ctx, webDavBaseURL, res.StorageSpaces, apiVersion)
 	if err != nil {
 		logger.Debug().Err(err).Msg("could not get drives: error parsing grpc response")
-		return nil, conversions.ToPointer(errorcode.New(errorcode.GeneralException, err.Error()))
+		return nil, errorcode.New(errorcode.GeneralException, err.Error())
 	}
 
 	spaces, err = sortSpaces(odataReq, spaces)
 	if err != nil {
 		logger.Debug().Err(err).Msg("could not get drives: error sorting the spaces list according to query")
-		return nil, conversions.ToPointer(errorcode.New(errorcode.InvalidRequest, err.Error()))
+		return nil, errorcode.New(errorcode.InvalidRequest, err.Error())
 	}
 
 	return spaces, nil
diff --git a/services/graph/pkg/service/v0/l10n/locale/bg/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/bg/LC_MESSAGES/graph.po
index 1f9090f501d..b3255c4a901 100644
--- a/services/graph/pkg/service/v0/l10n/locale/bg/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/bg/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-05 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: Martin <github@diemattels.at>, 2024\n"
 "Language-Team: Bulgarian (https://app.transifex.com/owncloud-org/teams/6149/bg/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: bg\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "Тук можете да добавите описание на това пространство."
diff --git a/services/graph/pkg/service/v0/l10n/locale/de/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/de/LC_MESSAGES/graph.po
index 131b9e2506c..1f2ade6724f 100644
--- a/services/graph/pkg/service/v0/l10n/locale/de/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/de/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-05 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: Martin <github@diemattels.at>, 2024\n"
 "Language-Team: German (https://app.transifex.com/owncloud-org/teams/6149/de/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: de\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "Hier können Sie eine Beschreibung für diesen Space einfügen."
diff --git a/services/graph/pkg/service/v0/l10n/locale/en_GB/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/en_GB/LC_MESSAGES/graph.po
index fbf642e9c4e..9b547c240db 100644
--- a/services/graph/pkg/service/v0/l10n/locale/en_GB/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/en_GB/LC_MESSAGES/graph.po
@@ -2,21 +2,26 @@
 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 # This file is distributed under the same license as the PACKAGE package.
 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
+# 
+# Translators:
+# Andi Chandler <andi@gowling.com>, 2024
+# 
 #, fuzzy
-msgid   ""
-msgstr  "Project-Id-Version: \n"
-        "Report-Msgid-Bugs-To: EMAIL\n"
-        "POT-Creation-Date: 2024-03-26 15:11+0100\n"
-        "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-        "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-        "Language-Team: LANGUAGE <LL@li.org>\n"
-        "Language: \n"
-        "MIME-Version: 1.0\n"
-        "Content-Type: text/plain; charset=CHARSET\n"
-        "Content-Transfer-Encoding: 8bit\n"
-
-#: pkg/service/v0/spacetemplates.go:29
-msgid   "Here you can add a description for this Space."
-msgstr  ""
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: EMAIL\n"
+"POT-Creation-Date: 2024-04-13 01:20+0000\n"
+"PO-Revision-Date: 2024-04-04 00:17+0000\n"
+"Last-Translator: Andi Chandler <andi@gowling.com>, 2024\n"
+"Language-Team: English (United Kingdom) (https://app.transifex.com/owncloud-org/teams/6149/en_GB/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: en_GB\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
+#. default description for new spaces
+#: pkg/service/v0/spacetemplates.go:37
+msgid "Here you can add a description for this Space."
+msgstr "Here you can add a description for this Space."
diff --git a/services/graph/pkg/service/v0/l10n/locale/es/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/es/LC_MESSAGES/graph.po
index 2b494c474d5..8a0d990ee8d 100644
--- a/services/graph/pkg/service/v0/l10n/locale/es/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/es/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-05 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: Martin <github@diemattels.at>, 2024\n"
 "Language-Team: Spanish (https://app.transifex.com/owncloud-org/teams/6149/es/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: es\n"
 "Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "Aquí puede añadir una descripción para este espacio."
diff --git a/services/graph/pkg/service/v0/l10n/locale/fr/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/fr/LC_MESSAGES/graph.po
index ecc3ecc4944..8b27d281dfa 100644
--- a/services/graph/pkg/service/v0/l10n/locale/fr/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/fr/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-05 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: Ldm Public <ldmpub@gmail.com>, 2024\n"
 "Language-Team: French (https://app.transifex.com/owncloud-org/teams/6149/fr/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: fr\n"
 "Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "Vous pouvez ajouter une description pour cet Espace ici."
diff --git a/services/graph/pkg/service/v0/l10n/locale/fr_FR/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/fr_FR/LC_MESSAGES/graph.po
index a6ebeaed13b..c5575214c5f 100644
--- a/services/graph/pkg/service/v0/l10n/locale/fr_FR/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/fr_FR/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-08 00:04+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: pr topi, 2024\n"
 "Language-Team: French (France) (https://app.transifex.com/owncloud-org/teams/6149/fr_FR/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: fr_FR\n"
 "Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "Vous pouvez ajouter ici une description pour cet Espace."
diff --git a/services/graph/pkg/service/v0/l10n/locale/ja_JP/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/ja_JP/LC_MESSAGES/graph.po
index 7e64f6fbaa0..3bc7323d7b4 100644
--- a/services/graph/pkg/service/v0/l10n/locale/ja_JP/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/ja_JP/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-05 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: hoshi1800 <hoshi1800@gmail.com>, 2024\n"
 "Language-Team: Japanese (Japan) (https://app.transifex.com/owncloud-org/teams/6149/ja_JP/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: ja_JP\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "ここでこのスペースの説明を追加できます。"
diff --git a/services/graph/pkg/service/v0/l10n/locale/ko/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/ko/LC_MESSAGES/graph.po
index 12d18d08621..130c50ecf77 100644
--- a/services/graph/pkg/service/v0/l10n/locale/ko/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/ko/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-05 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: Martin <github@diemattels.at>, 2024\n"
 "Language-Team: Korean (https://app.transifex.com/owncloud-org/teams/6149/ko/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: ko\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "여기에 이 스페이스 대한 설명을 추가할 수 있습니다."
diff --git a/services/graph/pkg/service/v0/l10n/locale/nl/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/nl/LC_MESSAGES/graph.po
index a987b2076a4..6b517dce5c0 100644
--- a/services/graph/pkg/service/v0/l10n/locale/nl/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/nl/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-05 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: 2a344c4626711d8707658672303caf6a_6d7f053, 2024\n"
 "Language-Team: Dutch (https://app.transifex.com/owncloud-org/teams/6149/nl/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: nl\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "Hier kan u een beschrijving toevoegen voor deze Space."
diff --git a/services/graph/pkg/service/v0/l10n/locale/pt_BR/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/pt_BR/LC_MESSAGES/graph.po
index a47e178d8e8..5c4679a8057 100644
--- a/services/graph/pkg/service/v0/l10n/locale/pt_BR/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/pt_BR/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-10 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: Flávio Veras <flaviove@gmail.com>, 2024\n"
 "Language-Team: Portuguese (Brazil) (https://app.transifex.com/owncloud-org/teams/6149/pt_BR/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: pt_BR\n"
 "Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "Aqui você pode adicionar uma descrição para este Espaço."
diff --git a/services/graph/pkg/service/v0/l10n/locale/ru/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/ru/LC_MESSAGES/graph.po
index 9359465f5fd..3a44509dce1 100644
--- a/services/graph/pkg/service/v0/l10n/locale/ru/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/ru/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-05 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: Alex <hostspepc@gmail.com>, 2024\n"
 "Language-Team: Russian (https://app.transifex.com/owncloud-org/teams/6149/ru/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: ru\n"
 "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "Здесь вы можете добавить описание этого пространства."
diff --git a/services/graph/pkg/service/v0/l10n/locale/sq/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/sq/LC_MESSAGES/graph.po
index 9298a2a7390..6f4d32dc334 100644
--- a/services/graph/pkg/service/v0/l10n/locale/sq/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/sq/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-05 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: Besnik Bleta <besnik@programeshqip.org>, 2024\n"
 "Language-Team: Albanian (https://app.transifex.com/owncloud-org/teams/6149/sq/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: sq\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "Këtu mund të shtoni një përshkrim për këtë Hapësirë."
diff --git a/services/graph/pkg/service/v0/l10n/locale/tr/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/tr/LC_MESSAGES/graph.po
index 004d6e72d39..83b23e74517 100644
--- a/services/graph/pkg/service/v0/l10n/locale/tr/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/tr/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-05 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: Martin <github@diemattels.at>, 2024\n"
 "Language-Team: Turkish (https://app.transifex.com/owncloud-org/teams/6149/tr/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: tr\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "Buraya bu Alan için bir açıklama ekleyebilirsiniz."
diff --git a/services/graph/pkg/service/v0/l10n/locale/vi/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/vi/LC_MESSAGES/graph.po
index 9605aa37be5..b18d9a0a3e1 100644
--- a/services/graph/pkg/service/v0/l10n/locale/vi/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/vi/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-05 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: Nguyễn Tiến Trình <tunglam062000@gmail.com>, 2024\n"
 "Language-Team: Vietnamese (https://app.transifex.com/owncloud-org/teams/6149/vi/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: vi\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "Ở đây bạn có thể thêm mô tả cho không gian này."
diff --git a/services/graph/pkg/service/v0/l10n/locale/zh/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/zh/LC_MESSAGES/graph.po
index 12c2c65dde1..4da8f6136ac 100644
--- a/services/graph/pkg/service/v0/l10n/locale/zh/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/zh/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-05 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: Martin <github@diemattels.at>, 2024\n"
 "Language-Team: Chinese (https://app.transifex.com/owncloud-org/teams/6149/zh/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: zh\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "在此处添加此空间的描述。"
diff --git a/services/graph/pkg/service/v0/l10n/locale/zh_HK/LC_MESSAGES/graph.po b/services/graph/pkg/service/v0/l10n/locale/zh_HK/LC_MESSAGES/graph.po
index 6dff64597a4..b4c465e5c84 100644
--- a/services/graph/pkg/service/v0/l10n/locale/zh_HK/LC_MESSAGES/graph.po
+++ b/services/graph/pkg/service/v0/l10n/locale/zh_HK/LC_MESSAGES/graph.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: EMAIL\n"
-"POT-Creation-Date: 2024-04-05 00:41+0000\n"
+"POT-Creation-Date: 2024-04-12 01:22+0000\n"
 "PO-Revision-Date: 2024-04-04 00:17+0000\n"
 "Last-Translator: Ann Li <dn.annli@gmail.com>, 2024\n"
 "Language-Team: Chinese (Hong Kong) (https://app.transifex.com/owncloud-org/teams/6149/zh_HK/)\n"
@@ -21,7 +21,7 @@ msgstr ""
 "Language: zh_HK\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 
-#. text for the readme.md file
+#. default description for new spaces
 #: pkg/service/v0/spacetemplates.go:37
 msgid "Here you can add a description for this Space."
 msgstr "你可以在此添加這空間的描述"
diff --git a/services/graph/pkg/service/v0/sharedwithme.go b/services/graph/pkg/service/v0/sharedwithme.go
index 42d02d76c55..8d88206d272 100644
--- a/services/graph/pkg/service/v0/sharedwithme.go
+++ b/services/graph/pkg/service/v0/sharedwithme.go
@@ -34,9 +34,9 @@ func (g Graph) listSharedWithMe(ctx context.Context) ([]libregraph.DriveItem, er
 	}
 
 	listReceivedSharesResponse, err := gatewayClient.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{})
-	if errCode := errorcode.FromCS3Status(listReceivedSharesResponse.GetStatus(), err); errCode != nil {
+	if err := errorcode.FromCS3Status(listReceivedSharesResponse.GetStatus(), err); err != nil {
 		g.logger.Error().Err(err).Msg("listing shares failed")
-		return nil, *errCode
+		return nil, err
 	}
 
 	return cs3ReceivedSharesToDriveItems(ctx, g.logger, gatewayClient, g.identityCache, listReceivedSharesResponse.GetShares())
diff --git a/services/graph/pkg/service/v0/spacetemplates.go b/services/graph/pkg/service/v0/spacetemplates.go
index b9d41438aa3..6e502d80cdf 100644
--- a/services/graph/pkg/service/v0/spacetemplates.go
+++ b/services/graph/pkg/service/v0/spacetemplates.go
@@ -33,7 +33,7 @@ var (
 	// path to the image file
 	_imagepath = "spacetemplate/image.png"
 
-	// text for the readme.md file
+	// default description for new spaces
 	_readmeText = l10n.Template("Here you can add a description for this Space.")
 
 	// name of the readme.md file
diff --git a/services/graph/pkg/service/v0/utils.go b/services/graph/pkg/service/v0/utils.go
index 55311185b67..525c6cdafc2 100644
--- a/services/graph/pkg/service/v0/utils.go
+++ b/services/graph/pkg/service/v0/utils.go
@@ -3,6 +3,7 @@ package svc
 import (
 	"context"
 	"encoding/json"
+	"errors"
 	"io"
 	"net/http"
 	"reflect"
@@ -16,6 +17,7 @@ import (
 	"golang.org/x/sync/errgroup"
 
 	libregraph "github.com/owncloud/libre-graph-api-go"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
 	"github.com/owncloud/ocis/v2/services/graph/pkg/errorcode"
 	"github.com/owncloud/ocis/v2/services/graph/pkg/identity"
@@ -166,18 +168,21 @@ func cs3ReceivedSharesToDriveItems(ctx context.Context,
 				},
 			})
 
-			switch errCode := errorcode.FromCS3Status(shareStat.GetStatus(), err); {
-			case errCode == nil:
-				break
+			var errCode errorcode.Error
+			errors.As(errorcode.FromCS3Status(shareStat.GetStatus(), err), &errCode)
+
+			switch {
 			// skip ItemNotFound shares, they might have been deleted in the meantime or orphans.
 			case errCode.GetCode() == errorcode.ItemNotFound:
 				return nil
+			case err == nil:
+				break
 			default:
 				logger.Error().Err(errCode).Msg("could not stat")
 				return errCode
 			}
 
-			driveItem, err := fillDriveItemPropertiesFromReceivedShare(ctx, logger, identityCache, receivedShares)
+			driveItem, err := fillDriveItemPropertiesFromReceivedShare(ctx, logger, identityCache, receivedShares, shareStat.GetInfo())
 			if err != nil {
 				return err
 			}
@@ -313,7 +318,8 @@ func cs3ReceivedSharesToDriveItems(ctx context.Context,
 }
 
 func fillDriveItemPropertiesFromReceivedShare(ctx context.Context, logger *log.Logger,
-	identityCache identity.IdentityCache, receivedShares []*collaboration.ReceivedShare) (*libregraph.DriveItem, error) {
+	identityCache identity.IdentityCache, receivedShares []*collaboration.ReceivedShare,
+	resourceInfo *storageprovider.ResourceInfo) (*libregraph.DriveItem, error) {
 
 	driveItem := libregraph.NewDriveItem()
 	permissions := make([]libregraph.Permission, 0, len(receivedShares))
@@ -327,7 +333,7 @@ func fillDriveItemPropertiesFromReceivedShare(ctx context.Context, logger *log.L
 			oldestReceivedShare = receivedShare
 		}
 
-		permission, err := cs3ReceivedShareToLibreGraphPermissions(ctx, logger, identityCache, receivedShare)
+		permission, err := cs3ReceivedShareToLibreGraphPermissions(ctx, logger, identityCache, receivedShare, resourceInfo)
 		if err != nil {
 			return driveItem, err
 		}
@@ -387,7 +393,8 @@ func fillDriveItemPropertiesFromReceivedShare(ctx context.Context, logger *log.L
 }
 
 func cs3ReceivedShareToLibreGraphPermissions(ctx context.Context, logger *log.Logger,
-	identityCache identity.IdentityCache, receivedShare *collaboration.ReceivedShare) (*libregraph.Permission, error) {
+	identityCache identity.IdentityCache, receivedShare *collaboration.ReceivedShare,
+	resourceInfo *storageprovider.ResourceInfo) (*libregraph.Permission, error) {
 	permission := libregraph.NewPermission()
 	if id := receivedShare.GetShare().GetId().GetOpaqueId(); id != "" {
 		permission.SetId(id)
@@ -398,10 +405,11 @@ func cs3ReceivedShareToLibreGraphPermissions(ctx context.Context, logger *log.Lo
 	}
 
 	if permissionSet := receivedShare.GetShare().GetPermissions().GetPermissions(); permissionSet != nil {
-		role := unifiedrole.CS3ResourcePermissionsToUnifiedRole(
-			*permissionSet,
-			unifiedrole.UnifiedRoleConditionGrantee,
-		)
+		condition, err := roleConditionForResourceType(resourceInfo)
+		if err != nil {
+			return nil, err
+		}
+		role := unifiedrole.CS3ResourcePermissionsToUnifiedRole(*permissionSet, condition)
 
 		if role != nil {
 			permission.SetRoles([]string{role.GetId()})
@@ -433,3 +441,16 @@ func cs3ReceivedShareToLibreGraphPermissions(ctx context.Context, logger *log.Lo
 
 	return permission, nil
 }
+
+func roleConditionForResourceType(ri *storageprovider.ResourceInfo) (string, error) {
+	switch {
+	case utils.ResourceIDEqual(ri.GetSpace().GetRoot(), ri.GetId()):
+		return unifiedrole.UnifiedRoleConditionDrive, nil
+	case ri.Type == storageprovider.ResourceType_RESOURCE_TYPE_CONTAINER:
+		return unifiedrole.UnifiedRoleConditionFolder, nil
+	case ri.Type == storageprovider.ResourceType_RESOURCE_TYPE_FILE:
+		return unifiedrole.UnifiedRoleConditionFile, nil
+	default:
+		return "", errorcode.New(errorcode.InvalidRequest, "unsupported resource type")
+	}
+}
diff --git a/services/graph/pkg/unifiedrole/unifiedrole.go b/services/graph/pkg/unifiedrole/unifiedrole.go
index 91c3dfa3634..c06d3d4bb15 100644
--- a/services/graph/pkg/unifiedrole/unifiedrole.go
+++ b/services/graph/pkg/unifiedrole/unifiedrole.go
@@ -28,12 +28,12 @@ const (
 	// UnifiedRoleManagerID Unified role manager id.
 	UnifiedRoleManagerID = "312c0871-5ef7-4b3a-85b6-0e4074c64049"
 
-	// UnifiedRoleConditionSelf defines constraint where the principal matches the target resource
-	UnifiedRoleConditionSelf = "@Subject.objectId == @Resource.objectId"
-	// UnifiedRoleConditionOwner defines constraints when the principal is the owner of the target resource
-	UnifiedRoleConditionOwner = "@Subject.objectId Any_of @Resource.owners"
-	// UnifiedRoleConditionGrantee does not exist in MS Graph, but we use it to express permissions on shared resources
-	UnifiedRoleConditionGrantee = "@Subject.objectId Any_of @Resource.grantee"
+	// UnifiedRoleConditionDrive defines constraint that matches a Driveroot/Spaceroot
+	UnifiedRoleConditionDrive = "exists @Resource.Root"
+	// UnifiedRoleConditionFolder defines constraints that matches a DriveItem representing a Folder
+	UnifiedRoleConditionFolder = "exists @Resource.Folder"
+	// UnifiedRoleConditionFile defines a constraint that matches a DriveItem representing a File
+	UnifiedRoleConditionFile = "exists @Resource.File"
 
 	DriveItemPermissionsCreate = "libre.graph/driveItem/permissions/create"
 	DriveItemChildrenCreate    = "libre.graph/driveItem/children/create"
@@ -68,7 +68,7 @@ var legacyNames map[string]string = map[string]string{
 	UnifiedRoleManagerID:     conversions.RoleManager,
 }
 
-// NewViewerUnifiedRole creates a viewer role. `sharing` indicates if sharing permission should be added
+// NewViewerUnifiedRole creates a viewer role.
 func NewViewerUnifiedRole() *libregraph.UnifiedRoleDefinition {
 	r := conversions.NewViewerRole()
 	return &libregraph.UnifiedRoleDefinition{
@@ -78,7 +78,11 @@ func NewViewerUnifiedRole() *libregraph.UnifiedRoleDefinition {
 		RolePermissions: []libregraph.UnifiedRolePermission{
 			{
 				AllowedResourceActions: convert(r),
-				Condition:              proto.String(UnifiedRoleConditionGrantee),
+				Condition:              proto.String(UnifiedRoleConditionFile),
+			},
+			{
+				AllowedResourceActions: convert(r),
+				Condition:              proto.String(UnifiedRoleConditionFolder),
 			},
 		},
 		LibreGraphWeight: proto.Int32(0),
@@ -95,14 +99,14 @@ func NewSpaceViewerUnifiedRole() *libregraph.UnifiedRoleDefinition {
 		RolePermissions: []libregraph.UnifiedRolePermission{
 			{
 				AllowedResourceActions: convert(r),
-				Condition:              proto.String(UnifiedRoleConditionOwner),
+				Condition:              proto.String(UnifiedRoleConditionDrive),
 			},
 		},
 		LibreGraphWeight: proto.Int32(0),
 	}
 }
 
-// NewEditorUnifiedRole creates an editor role. `sharing` indicates if sharing permission should be added
+// NewEditorUnifiedRole creates an editor role.
 func NewEditorUnifiedRole() *libregraph.UnifiedRoleDefinition {
 	r := conversions.NewEditorRole()
 	return &libregraph.UnifiedRoleDefinition{
@@ -112,7 +116,7 @@ func NewEditorUnifiedRole() *libregraph.UnifiedRoleDefinition {
 		RolePermissions: []libregraph.UnifiedRolePermission{
 			{
 				AllowedResourceActions: convert(r),
-				Condition:              proto.String(UnifiedRoleConditionGrantee),
+				Condition:              proto.String(UnifiedRoleConditionFolder),
 			},
 		},
 		LibreGraphWeight: proto.Int32(0),
@@ -129,7 +133,7 @@ func NewSpaceEditorUnifiedRole() *libregraph.UnifiedRoleDefinition {
 		RolePermissions: []libregraph.UnifiedRolePermission{
 			{
 				AllowedResourceActions: convert(r),
-				Condition:              proto.String(UnifiedRoleConditionOwner),
+				Condition:              proto.String(UnifiedRoleConditionDrive),
 			},
 		},
 		LibreGraphWeight: proto.Int32(0),
@@ -146,7 +150,7 @@ func NewFileEditorUnifiedRole() *libregraph.UnifiedRoleDefinition {
 		RolePermissions: []libregraph.UnifiedRolePermission{
 			{
 				AllowedResourceActions: convert(r),
-				Condition:              proto.String(UnifiedRoleConditionGrantee),
+				Condition:              proto.String(UnifiedRoleConditionFile),
 			},
 		},
 		LibreGraphWeight: proto.Int32(0),
@@ -163,7 +167,7 @@ func NewUploaderUnifiedRole() *libregraph.UnifiedRoleDefinition {
 		RolePermissions: []libregraph.UnifiedRolePermission{
 			{
 				AllowedResourceActions: convert(r),
-				Condition:              proto.String(UnifiedRoleConditionGrantee),
+				Condition:              proto.String(UnifiedRoleConditionFolder),
 			},
 		},
 		LibreGraphWeight: proto.Int32(0),
@@ -180,7 +184,7 @@ func NewManagerUnifiedRole() *libregraph.UnifiedRoleDefinition {
 		RolePermissions: []libregraph.UnifiedRolePermission{
 			{
 				AllowedResourceActions: convert(r),
-				Condition:              proto.String(UnifiedRoleConditionOwner),
+				Condition:              proto.String(UnifiedRoleConditionDrive),
 			},
 		},
 		LibreGraphWeight: proto.Int32(0),
@@ -219,19 +223,20 @@ func GetApplicableRoleDefinitionsForActions(actions []string, constraints string
 	definitions := make([]*libregraph.UnifiedRoleDefinition, 0, len(builtin))
 
 	for _, definition := range builtin {
-		definitionMatch := true
+		var definitionMatch bool
 
 		for _, permission := range definition.GetRolePermissions() {
 			if permission.GetCondition() != constraints {
-				definitionMatch = false
 				continue
 			}
 
-			for _, action := range permission.GetAllowedResourceActions() {
+			for i, action := range permission.GetAllowedResourceActions() {
 				if !slices.Contains(actions, action) {
-					definitionMatch = false
 					break
 				}
+				if i == len(permission.GetAllowedResourceActions())-1 {
+					definitionMatch = true
+				}
 			}
 
 			if definitionMatch {
@@ -239,30 +244,33 @@ func GetApplicableRoleDefinitionsForActions(actions []string, constraints string
 			}
 		}
 
-		if !definitionMatch {
-			continue
+		if definitionMatch {
+			definitions = append(definitions, definition)
 		}
 
-		definitions = append(definitions, definition)
 	}
 
-	return WeightRoleDefinitions(definitions, descending)
+	return WeightRoleDefinitions(definitions, constraints, descending)
 }
 
 // WeightRoleDefinitions sorts the provided role definitions by the number of permissions[n].actions they grant,
 // the implementation is optimistic and assumes that the weight relies on the number of available actions.
 // descending - false - sorts the roles from least to most permissions
 // descending - true - sorts the roles from most to least permissions
-func WeightRoleDefinitions(roleDefinitions []*libregraph.UnifiedRoleDefinition, descending bool) []*libregraph.UnifiedRoleDefinition {
+func WeightRoleDefinitions(roleDefinitions []*libregraph.UnifiedRoleDefinition, constraints string, descending bool) []*libregraph.UnifiedRoleDefinition {
 	slices.SortFunc(roleDefinitions, func(i, j *libregraph.UnifiedRoleDefinition) int {
 		var ia []string
 		for _, rp := range i.GetRolePermissions() {
-			ia = append(ia, rp.GetAllowedResourceActions()...)
+			if rp.GetCondition() == constraints {
+				ia = append(ia, rp.GetAllowedResourceActions()...)
+			}
 		}
 
 		var ja []string
 		for _, rp := range j.GetRolePermissions() {
-			ja = append(ja, rp.GetAllowedResourceActions()...)
+			if rp.GetCondition() == constraints {
+				ja = append(ja, rp.GetAllowedResourceActions()...)
+			}
 		}
 
 		switch descending {
diff --git a/services/ocs/pkg/config/config.go b/services/ocs/pkg/config/config.go
index 1c64050ac6e..4097ff4ef68 100644
--- a/services/ocs/pkg/config/config.go
+++ b/services/ocs/pkg/config/config.go
@@ -19,7 +19,6 @@ type Config struct {
 	Debug   Debug    `yaml:"debug"`
 
 	HTTP HTTP `yaml:"http"`
-	API  API  `yaml:"api"`
 
 	GRPCClientTLS *shared.GRPCClientTLS `yaml:"grpc_client_tls"`
 	GrpcClient    client.Client         `yaml:"-"`
@@ -39,7 +38,3 @@ type SigningKeys struct {
 	AuthUsername string        `yaml:"username" env:"OCIS_CACHE_AUTH_USERNAME;OCS_PRESIGNEDURL_SIGNING_KEYS_STORE_AUTH_USERNAME" desc:"The username to authenticate with the store. Only applies when store type 'nats-js-kv' is configured." introductionVersion:"5.0"`
 	AuthPassword string        `yaml:"password" env:"OCIS_CACHE_AUTH_PASSWORD;OCS_PRESIGNEDURL_SIGNING_KEYS_STORE_AUTH_PASSWORD" desc:"The password to authenticate with the store. Only applies when store type 'nats-js-kv' is configured." introductionVersion:"5.0"`
 }
-
-type API struct {
-	ShowUserEmailInResults bool `yaml:"show_email_in_results" env:"OCIS_SHOW_USER_EMAIL_IN_RESULTS" desc:"Mask user email addresses in responses." introductionVersion:"5.1"`
-}
diff --git a/services/postprocessing/README.md b/services/postprocessing/README.md
index 5b583193182..305d669c241 100644
--- a/services/postprocessing/README.md
+++ b/services/postprocessing/README.md
@@ -79,27 +79,27 @@ See the [cs3 org](https://github.com/cs3org/reva/blob/edge/pkg/events/postproces
 
 ### Resume Postprocessing
 
-If postprocessing fails in one step due to an unforseen error, current uploads will not be retried automatically. A system admin can instead run a CLI command to retry the failed upload which is a two step process:
+If postprocessing fails in one step due to an unforseen error, current uploads will not be retried automatically. A system admin can instead run a CLI command to retry the failed upload which is a two step process. For details on the `storage-users` command see the **Manage Unfinished Uploads** documentation in the `storage-users` service documentation:
 
 -   First list ongoing upload sessions
-```bash
-ocis storage-users uploads sessions
-```
+    ```bash
+    ocis storage-users uploads sessions
+    ```
 
 -   If you want to restart all uploads just rerun the command with the `--restart` flag
-```bash
-ocis storage-users uploads sessions --restart
-```
+    ```bash
+    ocis storage-users uploads sessions --restart
+    ```
 
 -   If you want to restart only one upload use the postprocessing restart command
-```bash
-ocis postprocessing restart -u <uploadID>
-```
+    ```bash
+    ocis postprocessing restart -u <uploadID>
+    ```
 
 Instead of starting one specific upload, a system admin can also restart all uploads that are currently in a specific step.
 Examples:
 ```
-ocis postprocessing restart # Restarts all uploads where postprocessing is finished, but upload is not finished
-ocis postprocessing restart -s "finished" # Equivalent to the above
+ocis postprocessing restart                # Restarts all uploads where postprocessing is finished, but upload is not finished
+ocis postprocessing restart -s "finished"  # Equivalent to the above
 ocis postprocessing restart -s "virusscan" # Restart all uploads currently in virusscan step
 ```
diff --git a/services/storage-users/README.md b/services/storage-users/README.md
index c59ab5584ab..7cb6cdc1486 100644
--- a/services/storage-users/README.md
+++ b/services/storage-users/README.md
@@ -43,15 +43,15 @@ When using Infinite Scale as user storage, a directory named `storage/users/uplo
 
 *   **In the rare case of a failure**, after the upload succeeded but the file was not moved to its target location, which can happen when postprocessing fails, the situation is the same as with expired uploads.
 
-Example cases for expired uploads
+Example cases for expired uploads:
 
 *   In the final step the upload blob is moved from the upload area to the final blobstore (e.g. S3). 
 
 *   If the bandwidth is limited and the file to transfer can't be transferred completely before the upload expiration time is reached, the file expires and can't be processed.
 
-The admin can restart the postprocessing for this with the postprocessing cli.
+*   If the upload was technically successful, but the postprocessing step failed due to an internal error, it will not get further processed. See the procedure **Resume Post-Processing** in the `postprocessing` service documentation for details how to solve this.
 
-The storage users service can only list and clean upload sessions:
+The following commands are available to manage unfinished uploads:
 
 ```bash
 ocis storage-users uploads <command>


Test patch:
diff --git a/services/graph/pkg/errorcode/cs3_test.go b/services/graph/pkg/errorcode/cs3_test.go
index f4a1f60a198..5b160e7ad78 100644
--- a/services/graph/pkg/errorcode/cs3_test.go
+++ b/services/graph/pkg/errorcode/cs3_test.go
@@ -8,45 +8,44 @@ import (
 	cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
 	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
 
-	"github.com/owncloud/ocis/v2/ocis-pkg/conversions"
 	"github.com/owncloud/ocis/v2/services/graph/pkg/errorcode"
 )
 
 func TestFromCS3Status(t *testing.T) {
 	var tests = []struct {
-		status *cs3rpc.Status
-		err    error
-		ignore []cs3rpc.Code
-		result *errorcode.Error
+		status   *cs3rpc.Status
+		err      error
+		ignore   []cs3rpc.Code
+		expected error
 	}{
-		{nil, nil, nil, conversions.ToPointer(errorcode.New(errorcode.GeneralException, "unspecified error has occurred"))},
-		{nil, errors.New("test error"), nil, conversions.ToPointer(errorcode.New(errorcode.GeneralException, "test error"))},
+		{nil, nil, nil, errorcode.New(errorcode.GeneralException, "unspecified error has occurred")},
+		{nil, errors.New("test error"), nil, errorcode.New(errorcode.GeneralException, "test error")},
 		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_OK}, nil, nil, nil},
 		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_NOT_FOUND}, nil, []cs3rpc.Code{cs3rpc.Code_CODE_NOT_FOUND}, nil},
 		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_PERMISSION_DENIED}, nil, []cs3rpc.Code{cs3rpc.Code_CODE_NOT_FOUND, cs3rpc.Code_CODE_PERMISSION_DENIED}, nil},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_NOT_FOUND, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.ItemNotFound, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_PERMISSION_DENIED, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.AccessDenied, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_UNAUTHENTICATED, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.Unauthenticated, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_INVALID_ARGUMENT, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.InvalidRequest, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_ALREADY_EXISTS, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.NameAlreadyExists, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_FAILED_PRECONDITION, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.InvalidRequest, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_UNIMPLEMENTED, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.NotSupported, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_INVALID, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.GeneralException, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_CANCELLED, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.GeneralException, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_UNKNOWN, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.GeneralException, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_RESOURCE_EXHAUSTED, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.GeneralException, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_ABORTED, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.GeneralException, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_OUT_OF_RANGE, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.InvalidRange, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_INTERNAL, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.GeneralException, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_UNAVAILABLE, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.ServiceNotAvailable, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_REDIRECTION, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.GeneralException, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_INSUFFICIENT_STORAGE, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.QuotaLimitReached, "msg"))},
-		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_LOCKED, Message: "msg"}, nil, nil, conversions.ToPointer(errorcode.New(errorcode.ItemIsLocked, "msg"))},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_NOT_FOUND, Message: "msg"}, nil, nil, errorcode.New(errorcode.ItemNotFound, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_PERMISSION_DENIED, Message: "msg"}, nil, nil, errorcode.New(errorcode.AccessDenied, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_UNAUTHENTICATED, Message: "msg"}, nil, nil, errorcode.New(errorcode.Unauthenticated, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_INVALID_ARGUMENT, Message: "msg"}, nil, nil, errorcode.New(errorcode.InvalidRequest, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_ALREADY_EXISTS, Message: "msg"}, nil, nil, errorcode.New(errorcode.NameAlreadyExists, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_FAILED_PRECONDITION, Message: "msg"}, nil, nil, errorcode.New(errorcode.InvalidRequest, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_UNIMPLEMENTED, Message: "msg"}, nil, nil, errorcode.New(errorcode.NotSupported, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_INVALID, Message: "msg"}, nil, nil, errorcode.New(errorcode.GeneralException, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_CANCELLED, Message: "msg"}, nil, nil, errorcode.New(errorcode.GeneralException, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_UNKNOWN, Message: "msg"}, nil, nil, errorcode.New(errorcode.GeneralException, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_RESOURCE_EXHAUSTED, Message: "msg"}, nil, nil, errorcode.New(errorcode.GeneralException, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_ABORTED, Message: "msg"}, nil, nil, errorcode.New(errorcode.GeneralException, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_OUT_OF_RANGE, Message: "msg"}, nil, nil, errorcode.New(errorcode.InvalidRange, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_INTERNAL, Message: "msg"}, nil, nil, errorcode.New(errorcode.GeneralException, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_UNAVAILABLE, Message: "msg"}, nil, nil, errorcode.New(errorcode.ServiceNotAvailable, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_REDIRECTION, Message: "msg"}, nil, nil, errorcode.New(errorcode.GeneralException, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_INSUFFICIENT_STORAGE, Message: "msg"}, nil, nil, errorcode.New(errorcode.QuotaLimitReached, "msg")},
+		{&cs3rpc.Status{Code: cs3rpc.Code_CODE_LOCKED, Message: "msg"}, nil, nil, errorcode.New(errorcode.ItemIsLocked, "msg")},
 	}
 
 	for _, test := range tests {
-		if output := errorcode.FromCS3Status(test.status, test.err, test.ignore...); !reflect.DeepEqual(output, test.result) {
-			t.Error("Test Failed: {} expected, received: {}", test.result, output)
+		if got := errorcode.FromCS3Status(test.status, test.err, test.ignore...); !reflect.DeepEqual(got, test.expected) {
+			t.Error("Test Failed: {} expected, received: {}", test.expected, got)
 		}
 	}
 }
@@ -55,9 +54,9 @@ func TestFromStat(t *testing.T) {
 	var tests = []struct {
 		stat   *provider.StatResponse
 		err    error
-		result *errorcode.Error
+		result error
 	}{
-		{nil, errors.New("some error"), conversions.ToPointer(errorcode.New(errorcode.GeneralException, "some error"))},
+		{nil, errors.New("some error"), errorcode.New(errorcode.GeneralException, "some error")},
 		{&provider.StatResponse{Status: &cs3rpc.Status{Code: cs3rpc.Code_CODE_OK}}, nil, nil},
 	}
 
diff --git a/services/graph/pkg/errorcode/errorcode_test.go b/services/graph/pkg/errorcode/errorcode_test.go
new file mode 100644
index 00000000000..003bdfc8f96
--- /dev/null
+++ b/services/graph/pkg/errorcode/errorcode_test.go
@@ -0,0 +1,45 @@
+package errorcode_test
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+
+	"github.com/owncloud/ocis/v2/services/graph/pkg/errorcode"
+)
+
+type customErr struct{}
+
+func (customErr) Error() string {
+	return "some error"
+}
+
+func TestRenderError(t *testing.T) {
+	t.Parallel()
+
+	t.Run("errorcode.Error value error", func(t *testing.T) {
+		r := httptest.NewRequest("GET", "/", nil)
+		w := httptest.NewRecorder()
+		err := errorcode.New(errorcode.ItemNotFound, "test error")
+		errorcode.RenderError(w, r, err)
+		require.Equal(t, http.StatusNotFound, w.Code)
+	})
+
+	t.Run("errorcode.Error zero value error", func(t *testing.T) {
+		r := httptest.NewRequest("GET", "/", nil)
+		w := httptest.NewRecorder()
+		var err errorcode.Error
+		errorcode.RenderError(w, r, err)
+		require.Equal(t, http.StatusForbidden, w.Code)
+	})
+
+	t.Run("custom error", func(t *testing.T) {
+		r := httptest.NewRequest("GET", "/", nil)
+		w := httptest.NewRecorder()
+		var err customErr
+		errorcode.RenderError(w, r, err)
+		require.Equal(t, http.StatusInternalServerError, w.Code)
+	})
+}
diff --git a/services/graph/pkg/service/v0/api_driveitem_permissions_test.go b/services/graph/pkg/service/v0/api_driveitem_permissions_test.go
index 3c2d25bb829..20ee36a42ad 100644
--- a/services/graph/pkg/service/v0/api_driveitem_permissions_test.go
+++ b/services/graph/pkg/service/v0/api_driveitem_permissions_test.go
@@ -27,6 +27,10 @@ import (
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	libregraph "github.com/owncloud/libre-graph-api-go"
+	"github.com/stretchr/testify/mock"
+	"github.com/tidwall/gjson"
+	"google.golang.org/grpc"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
 	"github.com/owncloud/ocis/v2/services/graph/mocks"
 	"github.com/owncloud/ocis/v2/services/graph/pkg/config/defaults"
@@ -35,9 +39,6 @@ import (
 	"github.com/owncloud/ocis/v2/services/graph/pkg/linktype"
 	svc "github.com/owncloud/ocis/v2/services/graph/pkg/service/v0"
 	"github.com/owncloud/ocis/v2/services/graph/pkg/unifiedrole"
-	"github.com/stretchr/testify/mock"
-	"github.com/tidwall/gjson"
-	"google.golang.org/grpc"
 )
 
 var _ = Describe("DriveItemPermissionsService", func() {
@@ -103,6 +104,10 @@ var _ = Describe("DriveItemPermissionsService", func() {
 
 		BeforeEach(func() {
 			gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
+			statResponse.Info = &provider.ResourceInfo{
+				Id:   &driveItemId,
+				Type: provider.ResourceType_RESOURCE_TYPE_FILE,
+			}
 
 			getGroupResponse = &grouppb.GetGroupResponse{
 				Status: status.NewOK(ctx),
@@ -158,7 +163,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
 			Expect(permission.GrantedToV2.Group.GetId()).To(Equal("2"))
 		})
 
-		It("with roles (happy path)", func() {
+		It("succeeds with file roles (happy path)", func() {
 			gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
 			gatewayClient.On("CreateShare", mock.Anything, mock.Anything).Return(createShareResponse, nil)
 			driveItemInvite.Recipients = []libregraph.DriveRecipient{
@@ -173,7 +178,23 @@ var _ = Describe("DriveItemPermissionsService", func() {
 			Expect(permission.GetRoles()[0]).To(Equal(unifiedrole.NewViewerUnifiedRole().GetId()))
 		})
 
-		It("fails with wrong role", func() {
+		It("succeeds with folder roles (happy path)", func() {
+			statResponse.Info.Type = provider.ResourceType_RESOURCE_TYPE_CONTAINER
+			gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
+			gatewayClient.On("CreateShare", mock.Anything, mock.Anything).Return(createShareResponse, nil)
+			driveItemInvite.Recipients = []libregraph.DriveRecipient{
+				{ObjectId: libregraph.PtrString("1"), LibreGraphRecipientType: libregraph.PtrString("user")},
+			}
+			driveItemInvite.Roles = []string{unifiedrole.NewEditorUnifiedRole().GetId()}
+
+			permission, err := driveItemPermissionsService.Invite(context.Background(), driveItemId, driveItemInvite)
+			Expect(err).ToNot(HaveOccurred())
+
+			Expect(permission.GetRoles()).To(HaveLen(1))
+			Expect(permission.GetRoles()[0]).To(Equal(unifiedrole.NewEditorUnifiedRole().GetId()))
+		})
+
+		It("fails with when trying to set a space role on a file", func() {
 			driveItemInvite.Recipients = []libregraph.DriveRecipient{
 				{ObjectId: libregraph.PtrString("1"), LibreGraphRecipientType: libregraph.PtrString("user")},
 			}
@@ -184,6 +205,29 @@ var _ = Describe("DriveItemPermissionsService", func() {
 			Expect(permission).To(BeZero())
 		})
 
+		It("fails with when trying to set a folder role on a file", func() {
+			driveItemInvite.Recipients = []libregraph.DriveRecipient{
+				{ObjectId: libregraph.PtrString("1"), LibreGraphRecipientType: libregraph.PtrString("user")},
+			}
+			driveItemInvite.Roles = []string{unifiedrole.NewEditorUnifiedRole().GetId()}
+			permission, err := driveItemPermissionsService.Invite(context.Background(), driveItemId, driveItemInvite)
+
+			Expect(err).To(MatchError(errorcode.New(errorcode.InvalidRequest, "role not applicable to this resource")))
+			Expect(permission).To(BeZero())
+		})
+
+		It("fails with when trying to set a file role on a folder", func() {
+			statResponse.Info.Type = provider.ResourceType_RESOURCE_TYPE_CONTAINER
+			driveItemInvite.Recipients = []libregraph.DriveRecipient{
+				{ObjectId: libregraph.PtrString("1"), LibreGraphRecipientType: libregraph.PtrString("user")},
+			}
+			driveItemInvite.Roles = []string{unifiedrole.NewFileEditorUnifiedRole().GetId()}
+			permission, err := driveItemPermissionsService.Invite(context.Background(), driveItemId, driveItemInvite)
+
+			Expect(err).To(MatchError(errorcode.New(errorcode.InvalidRequest, "role not applicable to this resource")))
+			Expect(permission).To(BeZero())
+		})
+
 		It("with actions (happy path)", func() {
 			gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
 			gatewayClient.On("CreateShare", mock.Anything, mock.Anything).Return(createShareResponse, nil)
@@ -245,6 +289,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
 			createShareResponse = &collaboration.CreateShareResponse{
 				Status: status.NewOK(ctx),
 			}
+			statResponse.Info = &provider.ResourceInfo{}
 		})
 
 		It("adds a user to a space as expected (happy path)", func() {
@@ -254,6 +299,10 @@ var _ = Describe("DriveItemPermissionsService", func() {
 				SpaceId:   "2",
 				OpaqueId:  "3",
 			}
+			statResponse.Info.Id = listSpacesResponse.StorageSpaces[0].Root
+			statResponse.Info.Space = &provider.StorageSpace{
+				Root: listSpacesResponse.StorageSpaces[0].Root,
+			}
 
 			gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(listSpacesResponse, nil)
 			gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
@@ -307,12 +356,13 @@ var _ = Describe("DriveItemPermissionsService", func() {
 				Status: status.NewOK(ctx),
 				Shares: []*collaboration.Share{},
 			}
-		})
-		It("populates allowedValues for files that are not shared", func() {
 			statResponse.Info = &provider.ResourceInfo{
 				Id:            &itemID,
+				Type:          provider.ResourceType_RESOURCE_TYPE_FILE,
 				PermissionSet: roleconversions.NewViewerRole().CS3ResourcePermissions(),
 			}
+		})
+		It("populates allowedValues for files that are not shared", func() {
 			gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
 			gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(listSharesResponse, nil)
 			gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(listPublicSharesResponse, nil)
@@ -322,10 +372,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
 			Expect(len(permissions.LibreGraphPermissionsRolesAllowedValues)).ToNot(BeZero())
 		})
 		It("returns one permission per share", func() {
-			statResponse.Info = &provider.ResourceInfo{
-				Id:            &itemID,
-				PermissionSet: roleconversions.NewEditorRole().CS3ResourcePermissions(),
-			}
+			statResponse.Info.PermissionSet = roleconversions.NewEditorRole().CS3ResourcePermissions()
 			listSharesResponse.Shares = []*collaboration.Share{
 				{
 					Id: &collaboration.ShareId{OpaqueId: "1"},
@@ -394,6 +441,10 @@ var _ = Describe("DriveItemPermissionsService", func() {
 					},
 				},
 			}
+			statResponse.Info = &provider.ResourceInfo{
+				Type:          provider.ResourceType_RESOURCE_TYPE_FILE,
+				PermissionSet: roleconversions.NewViewerRole().CS3ResourcePermissions(),
+			}
 		})
 
 		It("adds a user to a space as expected (happy path)", func() {
@@ -406,10 +457,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
 
 			gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(listSpacesResponse, nil)
 			gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(listPublicSharesResponse, nil)
-			statResponse.Info = &provider.ResourceInfo{
-				Id:            listSpacesResponse.StorageSpaces[0].Root,
-				PermissionSet: roleconversions.NewViewerRole().CS3ResourcePermissions(),
-			}
+			statResponse.Info.Id = listSpacesResponse.StorageSpaces[0].Root
 			gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
 			permissions, err := driveItemPermissionsService.ListSpaceRootPermissions(context.Background(), driveId)
 			Expect(err).ToNot(HaveOccurred())
@@ -649,7 +697,6 @@ var _ = Describe("DriveItemPermissionsService", func() {
 					},
 				},
 			}
-
 		})
 		It("fails when no share is found", func() {
 			getShareMockResponse.Share = nil
@@ -714,6 +761,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
 			Expect(res.Link.GetLibreGraphDisplayName() == TestLinkName)
 		})
 		It("updates the expiration date", func() {
+			gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
 			gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
 			getPublicShareMockResponse.Share = nil
 			getPublicShareMockResponse.Status = status.NewNotFound(ctx, "not found")
@@ -743,6 +791,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
 			Expect(res.GetExpirationDateTime().Equal(expiration)).To(BeTrue())
 		})
 		It("deletes the expiration date", func() {
+			gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
 			gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
 			getPublicShareMockResponse.Share = nil
 			getPublicShareMockResponse.Status = status.NewNotFound(ctx, "not found")
@@ -770,6 +819,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
 			Expect(ok).To(BeFalse())
 		})
 		It("fails to update the share permissions for a file share when setting a space specific role", func() {
+			gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
 			getPublicShareMockResponse.Share = nil
 			getPublicShareMockResponse.Status = status.NewNotFound(ctx, "not found")
 			gatewayClient.On("GetPublicShare", mock.Anything, mock.MatchedBy(func(req *link.GetPublicShareRequest) bool {
@@ -788,6 +838,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
 			Expect(res).To(BeZero())
 		})
 		It("fails to update the space permissions for a space share when setting a file specific role", func() {
+			gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
 			getPublicShareMockResponse.Share = nil
 			getPublicShareMockResponse.Status = status.NewNotFound(ctx, "not found")
 			gatewayClient.On("GetPublicShare", mock.Anything, mock.Anything).Return(getPublicShareMockResponse, nil)
@@ -809,6 +860,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
 			Expect(res).To(BeZero())
 		})
 		It("updates the share permissions when changing the resource permission actions", func() {
+			gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
 			getPublicShareMockResponse.Share = nil
 			getPublicShareMockResponse.Status = status.NewNotFound(ctx, "not found")
 			gatewayClient.On("GetPublicShare", mock.Anything, mock.Anything).Return(getPublicShareMockResponse, nil)
diff --git a/services/graph/pkg/service/v0/api_drives_drive_item_test.go b/services/graph/pkg/service/v0/api_drives_drive_item_test.go
index 960d58d7259..6c7f4684bea 100644
--- a/services/graph/pkg/service/v0/api_drives_drive_item_test.go
+++ b/services/graph/pkg/service/v0/api_drives_drive_item_test.go
@@ -24,6 +24,7 @@ import (
 	"github.com/cs3org/reva/v2/pkg/rgrpc/status"
 	"github.com/cs3org/reva/v2/pkg/storagespace"
 	cs3mocks "github.com/cs3org/reva/v2/tests/cs3mocks/mocks"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
 	"github.com/owncloud/ocis/v2/services/graph/mocks"
 	"github.com/owncloud/ocis/v2/services/graph/pkg/errorcode"
@@ -377,7 +378,7 @@ var _ = Describe("DrivesDriveItemService", func() {
 					Return(&collaborationv1beta1.GetReceivedShareResponse{}, errors.New("listing shares failed"))
 
 				err := drivesDriveItemService.UnmountShare(context.Background(), storageprovider.ResourceId{})
-				Expect(err).To(MatchError(&expectedError))
+				Expect(err).To(MatchError(expectedError))
 			})
 
 			It("uses the correct filters to get the shares", func() {
diff --git a/services/graph/pkg/service/v0/sharedbyme_test.go b/services/graph/pkg/service/v0/sharedbyme_test.go
index 6d4840686a7..e87ef7094b7 100644
--- a/services/graph/pkg/service/v0/sharedbyme_test.go
+++ b/services/graph/pkg/service/v0/sharedbyme_test.go
@@ -176,7 +176,8 @@ var _ = Describe("sharedbyme", func() {
 			Return(&provider.StatResponse{
 				Status: status.NewOK(ctx),
 				Info: &provider.ResourceInfo{
-					Id: userShare.ResourceId,
+					Id:   userShare.ResourceId,
+					Type: provider.ResourceType_RESOURCE_TYPE_CONTAINER,
 				},
 			}, nil)
 
diff --git a/services/graph/pkg/unifiedrole/unifiedrole_test.go b/services/graph/pkg/unifiedrole/unifiedrole_test.go
index 3c87114ab25..5b0e21ba916 100644
--- a/services/graph/pkg/unifiedrole/unifiedrole_test.go
+++ b/services/graph/pkg/unifiedrole/unifiedrole_test.go
@@ -24,12 +24,13 @@ var _ = Describe("unifiedroles", func() {
 			Expect(r.GetId()).To(Equal(unifiedRole.GetId()))
 
 		},
-		Entry(rConversions.RoleViewer, rConversions.NewViewerRole(), unifiedrole.NewViewerUnifiedRole(), unifiedrole.UnifiedRoleConditionGrantee),
-		Entry(rConversions.RoleEditor, rConversions.NewEditorRole(), unifiedrole.NewEditorUnifiedRole(), unifiedrole.UnifiedRoleConditionGrantee),
-		Entry(rConversions.RoleFileEditor, rConversions.NewFileEditorRole(), unifiedrole.NewFileEditorUnifiedRole(), unifiedrole.UnifiedRoleConditionGrantee),
-		Entry(rConversions.RoleManager, rConversions.NewManagerRole(), unifiedrole.NewManagerUnifiedRole(), unifiedrole.UnifiedRoleConditionOwner),
-		Entry(rConversions.RoleSpaceViewer, rConversions.NewSpaceViewerRole(), unifiedrole.NewSpaceViewerUnifiedRole(), unifiedrole.UnifiedRoleConditionOwner),
-		Entry(rConversions.RoleSpaceEditor, rConversions.NewSpaceEditorRole(), unifiedrole.NewSpaceEditorUnifiedRole(), unifiedrole.UnifiedRoleConditionOwner),
+		Entry(rConversions.RoleViewer, rConversions.NewViewerRole(), unifiedrole.NewViewerUnifiedRole(), unifiedrole.UnifiedRoleConditionFile),
+		Entry(rConversions.RoleViewer, rConversions.NewViewerRole(), unifiedrole.NewViewerUnifiedRole(), unifiedrole.UnifiedRoleConditionFolder),
+		Entry(rConversions.RoleEditor, rConversions.NewEditorRole(), unifiedrole.NewEditorUnifiedRole(), unifiedrole.UnifiedRoleConditionFolder),
+		Entry(rConversions.RoleFileEditor, rConversions.NewFileEditorRole(), unifiedrole.NewFileEditorUnifiedRole(), unifiedrole.UnifiedRoleConditionFile),
+		Entry(rConversions.RoleManager, rConversions.NewManagerRole(), unifiedrole.NewManagerUnifiedRole(), unifiedrole.UnifiedRoleConditionDrive),
+		Entry(rConversions.RoleSpaceViewer, rConversions.NewSpaceViewerRole(), unifiedrole.NewSpaceViewerUnifiedRole(), unifiedrole.UnifiedRoleConditionDrive),
+		Entry(rConversions.RoleSpaceEditor, rConversions.NewSpaceEditorRole(), unifiedrole.NewSpaceEditorUnifiedRole(), unifiedrole.UnifiedRoleConditionDrive),
 	)
 
 	DescribeTable("UnifiedRolePermissionsToCS3ResourcePermissions",
@@ -57,9 +58,9 @@ var _ = Describe("unifiedroles", func() {
 	)
 
 	DescribeTable("WeightRoleDefinitions",
-		func(roleDefinitions []*libregraph.UnifiedRoleDefinition, descending bool, expectedDefinitions []*libregraph.UnifiedRoleDefinition) {
+		func(roleDefinitions []*libregraph.UnifiedRoleDefinition, constraint string, descending bool, expectedDefinitions []*libregraph.UnifiedRoleDefinition) {
 
-			for i, generatedDefinition := range unifiedrole.WeightRoleDefinitions(roleDefinitions, descending) {
+			for i, generatedDefinition := range unifiedrole.WeightRoleDefinitions(roleDefinitions, constraint, descending) {
 				Expect(generatedDefinition.Id).To(Equal(expectedDefinitions[i].Id))
 			}
 		},
@@ -69,6 +70,7 @@ var _ = Describe("unifiedroles", func() {
 				unifiedrole.NewViewerUnifiedRole(),
 				unifiedrole.NewFileEditorUnifiedRole(),
 			},
+			unifiedrole.UnifiedRoleConditionFile,
 			false,
 			[]*libregraph.UnifiedRoleDefinition{
 				unifiedrole.NewViewerUnifiedRole(),
@@ -81,6 +83,7 @@ var _ = Describe("unifiedroles", func() {
 				unifiedrole.NewViewerUnifiedRole(),
 				unifiedrole.NewFileEditorUnifiedRole(),
 			},
+			unifiedrole.UnifiedRoleConditionFile,
 			true,
 			[]*libregraph.UnifiedRoleDefinition{
 				unifiedrole.NewFileEditorUnifiedRole(),
@@ -130,7 +133,7 @@ var _ = Describe("unifiedroles", func() {
 			Entry(
 				"ViewerUnifiedRole",
 				rolesToAction(unifiedrole.NewViewerUnifiedRole()),
-				unifiedrole.UnifiedRoleConditionGrantee,
+				unifiedrole.UnifiedRoleConditionFolder,
 				[]*libregraph.UnifiedRoleDefinition{
 					unifiedrole.NewViewerUnifiedRole(),
 				},
@@ -139,7 +142,7 @@ var _ = Describe("unifiedroles", func() {
 			Entry(
 				"ViewerUnifiedRole | share",
 				rolesToAction(unifiedrole.NewViewerUnifiedRole()),
-				unifiedrole.UnifiedRoleConditionGrantee,
+				unifiedrole.UnifiedRoleConditionFile,
 				[]*libregraph.UnifiedRoleDefinition{
 					unifiedrole.NewViewerUnifiedRole(),
 				},
@@ -148,17 +151,7 @@ var _ = Describe("unifiedroles", func() {
 			Entry(
 				"NewFileEditorUnifiedRole",
 				rolesToAction(unifiedrole.NewFileEditorUnifiedRole()),
-				unifiedrole.UnifiedRoleConditionGrantee,
-				[]*libregraph.UnifiedRoleDefinition{
-					unifiedrole.NewViewerUnifiedRole(),
-					unifiedrole.NewFileEditorUnifiedRole(),
-				},
-			),
-
-			Entry(
-				"NewFileEditorUnifiedRole - share",
-				rolesToAction(unifiedrole.NewFileEditorUnifiedRole()),
-				unifiedrole.UnifiedRoleConditionGrantee,
+				unifiedrole.UnifiedRoleConditionFile,
 				[]*libregraph.UnifiedRoleDefinition{
 					unifiedrole.NewViewerUnifiedRole(),
 					unifiedrole.NewFileEditorUnifiedRole(),
@@ -168,35 +161,31 @@ var _ = Describe("unifiedroles", func() {
 			Entry(
 				"NewEditorUnifiedRole",
 				rolesToAction(unifiedrole.NewEditorUnifiedRole()),
-				unifiedrole.UnifiedRoleConditionGrantee,
+				unifiedrole.UnifiedRoleConditionFolder,
 				[]*libregraph.UnifiedRoleDefinition{
 					unifiedrole.NewUploaderUnifiedRole(),
 					unifiedrole.NewViewerUnifiedRole(),
-					unifiedrole.NewFileEditorUnifiedRole(),
 					unifiedrole.NewEditorUnifiedRole(),
 				},
 			),
 
 			Entry(
-				"NewEditorUnifiedRole - share",
-				rolesToAction(unifiedrole.NewEditorUnifiedRole()),
-				unifiedrole.UnifiedRoleConditionGrantee,
+				"GetBuiltinRoleDefinitionList",
+				rolesToAction(unifiedrole.GetBuiltinRoleDefinitionList()...),
+				unifiedrole.UnifiedRoleConditionFile,
 				[]*libregraph.UnifiedRoleDefinition{
-					unifiedrole.NewUploaderUnifiedRole(),
 					unifiedrole.NewViewerUnifiedRole(),
 					unifiedrole.NewFileEditorUnifiedRole(),
-					unifiedrole.NewEditorUnifiedRole(),
 				},
 			),
 
 			Entry(
 				"GetBuiltinRoleDefinitionList",
 				rolesToAction(unifiedrole.GetBuiltinRoleDefinitionList()...),
-				unifiedrole.UnifiedRoleConditionGrantee,
+				unifiedrole.UnifiedRoleConditionFolder,
 				[]*libregraph.UnifiedRoleDefinition{
 					unifiedrole.NewUploaderUnifiedRole(),
 					unifiedrole.NewViewerUnifiedRole(),
-					unifiedrole.NewFileEditorUnifiedRole(),
 					unifiedrole.NewEditorUnifiedRole(),
 				},
 			),
@@ -204,7 +193,7 @@ var _ = Describe("unifiedroles", func() {
 			Entry(
 				"GetBuiltinRoleDefinitionList",
 				rolesToAction(unifiedrole.GetBuiltinRoleDefinitionList()...),
-				unifiedrole.UnifiedRoleConditionOwner,
+				unifiedrole.UnifiedRoleConditionDrive,
 				[]*libregraph.UnifiedRoleDefinition{
 					unifiedrole.NewSpaceViewerUnifiedRole(),
 					unifiedrole.NewSpaceEditorUnifiedRole(),
@@ -212,29 +201,17 @@ var _ = Describe("unifiedroles", func() {
 				},
 			),
 
-			Entry(
-				"GetBuiltinRoleDefinitionList - share",
-				rolesToAction(unifiedrole.GetBuiltinRoleDefinitionList()...),
-				unifiedrole.UnifiedRoleConditionGrantee,
-				[]*libregraph.UnifiedRoleDefinition{
-					unifiedrole.NewUploaderUnifiedRole(),
-					unifiedrole.NewViewerUnifiedRole(),
-					unifiedrole.NewFileEditorUnifiedRole(),
-					unifiedrole.NewEditorUnifiedRole(),
-				},
-			),
-
 			Entry(
 				"single",
 				[]string{unifiedrole.DriveItemQuotaRead},
-				unifiedrole.UnifiedRoleConditionGrantee,
+				unifiedrole.UnifiedRoleConditionFile,
 				[]*libregraph.UnifiedRoleDefinition{},
 			),
 
 			Entry(
 				"mixed",
 				append(rolesToAction(unifiedrole.NewUploaderUnifiedRole()), unifiedrole.DriveItemQuotaRead),
-				unifiedrole.UnifiedRoleConditionGrantee,
+				unifiedrole.UnifiedRoleConditionFolder,
 				[]*libregraph.UnifiedRoleDefinition{
 					unifiedrole.NewUploaderUnifiedRole(),
 				},
diff --git a/tests/acceptance/features/apiSharingNg/deletePermissions.feature b/tests/acceptance/features/apiSharingNg/deletePermissions.feature
index 2cac0783bcd..68563621a56 100644
--- a/tests/acceptance/features/apiSharingNg/deletePermissions.feature
+++ b/tests/acceptance/features/apiSharingNg/deletePermissions.feature
@@ -177,3 +177,41 @@ Feature: Remove access to a drive item
       | view             |
       | edit             |
       | blocksDownload   |
+
+  
+  Scenario Outline: user removes user member from project space
+    Given the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API
+    And user "Alice" has created a space "NewSpace" with the default quota using the Graph API
+    And user "Alice" has sent the following share invitation:
+      | space           | NewSpace           |
+      | sharee          | Brian              |
+      | shareType       | user               |
+      | permissionsRole | <permissions-role> |
+    When user "Alice" removes the share permission of user "Brian" from space "NewSpace" using the Graph API
+    Then the HTTP status code should be "204"
+    And the user "Brian" should not have a space called "NewSpace"
+    Examples:
+      | permissions-role |
+      | Space Viewer     |
+      | Space Editor     |
+      | Manager          |
+
+  @issue-8768
+  Scenario Outline: user removes group from project space
+    Given the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API
+    And user "Alice" has created a space "NewSpace" with the default quota using the Graph API
+    And group "group1" has been created
+    And user "Brian" has been added to group "group1"
+    And user "Alice" has sent the following share invitation:
+      | space           | NewSpace           |
+      | sharee          | group1              |
+      | shareType       | group               |
+      | permissionsRole | <permissions-role> |
+    When user "Alice" removes the share permission of group "group1" from space "NewSpace" using the Graph API
+    Then the HTTP status code should be "204"
+    And the user "Brian" should not have a space called "NewSpace"
+    Examples:
+      | permissions-role |
+      | Space Viewer     |
+      | Space Editor     |
+      | Manager          |    
diff --git a/tests/acceptance/features/apiSharingNg/enableDisableShareSync.feature b/tests/acceptance/features/apiSharingNg/enableDisableShareSync.feature
index 3dc198b10bd..fe2badcc1aa 100644
--- a/tests/acceptance/features/apiSharingNg/enableDisableShareSync.feature
+++ b/tests/acceptance/features/apiSharingNg/enableDisableShareSync.feature
@@ -148,3 +148,150 @@ Feature:  enable or disable sync of incoming shares
       | resource      |
       | textfile0.txt |
       | FolderToShare |
+
+
+  Scenario Outline: enable sync of shared resource from project space
+    Given user "Brian" has disabled the auto-sync share
+    And the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API
+    And user "Alice" has created a space "NewSpace" with the default quota using the Graph API
+    And user "Alice" has created a folder "FolderToShare" in space "NewSpace"
+    And user "Alice" has uploaded a file inside space "NewSpace" with content "hello world" to "/textfile0.txt"
+    And user "Alice" has sent the following share invitation:
+      | resource        | <resource> |
+      | space           | NewSpace   |
+      | sharee          | Brian      |
+      | shareType       | user       |
+      | permissionsRole | Viewer     |
+    When user "Brian" enables sync of share "<resource>" offered by "Alice" from "NewSpace" space using the Graph API
+    Then the HTTP status code should be "201"
+    And the JSON data of the response should match
+      """
+      {
+        "type": "object",
+        "required": [
+          "@client.synchronize"
+        ],
+        "properties": {
+          "@client.synchronize": {
+            "const": true
+          }
+        }
+      }
+      """
+    Examples:
+      | resource      |
+      | textfile0.txt |
+      | FolderToShare |
+
+
+  Scenario Outline: disable sync of shared resource from project space
+    Given the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API
+    And user "Alice" has created a space "NewSpace" with the default quota using the Graph API
+    And user "Alice" has created a folder "FolderToShare" in space "NewSpace"
+    And user "Alice" has uploaded a file inside space "NewSpace" with content "hello world" to "/textfile0.txt"
+    And user "Alice" has sent the following share invitation:
+      | resource        | <resource> |
+      | space           | NewSpace   |
+      | sharee          | Brian      |
+      | shareType       | user       |
+      | permissionsRole | Viewer     |
+    When user "Brian" disables sync of share "<resource>" using the Graph API
+    And user "Brian" lists the shares shared with him using the Graph API
+    Then the HTTP status code of responses on all endpoints should be "200"
+    And the JSON data of the response should match
+    """
+    {
+      "type": "object",
+      "required": [
+        "value"
+      ],
+      "properties": {
+        "value": {
+          "type": "array",
+          "minItems": 1,
+          "maxItems": 1,
+          "items": {
+            "type": "object",
+            "required": [
+              "@client.synchronize"
+            ],
+            "properties": {
+              "@client.synchronize": {
+                "const": false
+              }
+            }
+          }
+        }
+      }
+    }
+    """
+    Examples:
+      | resource      |
+      | textfile0.txt |
+      | FolderToShare |
+
+
+  Scenario Outline: enable a group share sync shared from Project Space by only one user in a group
+    Given user "Carol" has been created with default attributes and without skeleton files
+    And the administrator has assigned the role "Space Admin" to user "Carol" using the Graph API
+    And group "grp1" has been created
+    And user "Alice" has been added to group "grp1"
+    And user "Brian" has been added to group "grp1"
+    And user "Alice" has disabled the auto-sync share
+    And user "Brian" has disabled the auto-sync share
+    And user "Carol" has created a space "NewSpace" with the default quota using the Graph API
+    And user "Carol" has created a folder "FolderToShare" in space "NewSpace"
+    And user "Carol" has uploaded a file inside space "NewSpace" with content "hello world" to "/textfile0.txt"
+    And user "Carol" has sent the following share invitation:
+      | resource        | <resource> |
+      | space           | NewSpace   |
+      | sharee          | grp1       |
+      | shareType       | group      |
+      | permissionsRole | Viewer     |
+    When user "Alice" enables sync of share "<resource>" offered by "Carol" from "NewSpace" space using the Graph API
+    Then the HTTP status code should be "201"
+    And the JSON data of the response should match
+      """
+      {
+        "type": "object",
+        "required": [
+          "@client.synchronize"
+        ],
+        "properties": {
+          "@client.synchronize": {
+            "const": true
+          }
+        }
+      }
+      """
+    And user "Alice" should have sync enabled for share "<resource>"
+    And user "Brian" should have sync disabled for share "<resource>"
+    Examples:
+      | resource      |
+      | textfile0.txt |
+      | FolderToShare |
+
+
+  Scenario Outline: disable group share sync shared from Project space by only one user in a group
+    Given user "Carol" has been created with default attributes and without skeleton files
+    And the administrator has assigned the role "Space Admin" to user "Carol" using the Graph API
+    And group "grp1" has been created
+    And user "Alice" has been added to group "grp1"
+    And user "Brian" has been added to group "grp1"
+    And user "Carol" has created a space "NewSpace" with the default quota using the Graph API
+    And user "Carol" has created a folder "FolderToShare" in space "NewSpace"
+    And user "Carol" has uploaded a file inside space "NewSpace" with content "hello world" to "/textfile0.txt"
+    And user "Carol" has sent the following share invitation:
+      | resource        | <resource> |
+      | space           | NewSpace   |
+      | sharee          | grp1       |
+      | shareType       | group      |
+      | permissionsRole | Viewer     |
+    When user "Alice" disables sync of share "<resource>" using the Graph API
+    Then the HTTP status code should be "200"
+    And user "Alice" should have sync disabled for share "<resource>"
+    And user "Brian" should have sync enabled for share "<resource>"
+    Examples:
+      | resource      |
+      | textfile0.txt |
+      | FolderToShare |
diff --git a/tests/acceptance/features/apiSharingNg/listPermissions.feature b/tests/acceptance/features/apiSharingNg/listPermissions.feature
index a3877df6fe8..5efcbb718c7 100644
--- a/tests/acceptance/features/apiSharingNg/listPermissions.feature
+++ b/tests/acceptance/features/apiSharingNg/listPermissions.feature
@@ -48,8 +48,8 @@ Feature: List a sharing permissions
           },
           "@libre.graph.permissions.roles.allowedValues": {
             "type": "array",
-            "minItems": 4,
-            "maxItems": 4,
+            "minItems": 3,
+            "maxItems": 3,
             "uniqueItems": true,
             "items": {
               "oneOf": [
@@ -138,41 +138,6 @@ Feature: List a sharing permissions
                         3
                       ]
                     },
-                    "description": {
-                      "type": "string",
-                      "enum": [
-                        "View, download and edit."
-                      ]
-                    },
-                    "displayName": {
-                      "type": "string",
-                      "enum": [
-                        "Can edit"
-                      ]
-                    },
-                    "id": {
-                      "type": "string",
-                      "enum": [
-                        "2d00ce52-1fc2-4dbc-8b95-a73b73395f5a"
-                      ]
-                    }
-                  }
-                },
-                {
-                  "type": "object",
-                  "required": [
-                    "@libre.graph.weight",
-                    "description",
-                    "displayName",
-                    "id"
-                  ],
-                  "properties": {
-                    "@libre.graph.weight": {
-                      "type": "integer",
-                      "enum": [
-                        4
-                      ]
-                    },
                     "description": {
                       "type": "string",
                       "enum": [
@@ -594,4 +559,4 @@ Feature: List a sharing permissions
           }
         }
       }
-      """
\ No newline at end of file
+      """
diff --git a/tests/acceptance/features/apiSharingNg/shareInvitations.feature b/tests/acceptance/features/apiSharingNg/shareInvitations.feature
index b6307f87b78..187a62122ed 100644
--- a/tests/acceptance/features/apiSharingNg/shareInvitations.feature
+++ b/tests/acceptance/features/apiSharingNg/shareInvitations.feature
@@ -1570,7 +1570,7 @@ Feature: Send a sharing invitations
               "message": {
                 "type": "string",
                 "enum": [
-                  "cannot set the requested permissions on that type of resource"
+                  "role not applicable to this resource"
                 ]
               }
             }
@@ -2356,9 +2356,9 @@ Feature: Send a sharing invitations
       """
     Examples:
       | permissions-role | error-message                                                                                      |
-      | Space Viewer     | space type is not eligible for sharing                                                             |
-      | Space Editor     | space type is not eligible for sharing                                                             |
-      | Manager          | space type is not eligible for sharing                                                             |
+      | Space Viewer     | role not applicable to this resource								      |
+      | Space Editor     | role not applicable to this resource                                                               |
+      | Manager          | role not applicable to this resource                                                               |
       | Co Owner         | Key: 'DriveItemInvite.Roles' Error:Field validation for 'Roles' failed on the 'available_role' tag |
 
 
diff --git a/tests/acceptance/features/bootstrap/SharingNgContext.php b/tests/acceptance/features/bootstrap/SharingNgContext.php
index 81e8185ad3a..e68d86446aa 100644
--- a/tests/acceptance/features/bootstrap/SharingNgContext.php
+++ b/tests/acceptance/features/bootstrap/SharingNgContext.php
@@ -450,10 +450,10 @@ class SharingNgContext implements Context {
 
 	/**
 	 * @param string $sharer
-	 * @param string $shareType (user|group)
-	 * @param string $resource
+	 * @param string $shareType (user|group|link)
 	 * @param string $space
-	 * @param string|null $sharee can be both user or group
+	 * @param string|null $resource
+	 * @param string|null $recipient
 	 *
 	 * @return ResponseInterface
 	 * @throws GuzzleException
@@ -462,12 +462,12 @@ class SharingNgContext implements Context {
 	public function removeSharePermission(
 		string $sharer,
 		string $shareType,
-		string $resource,
 		string $space,
-		?string $sharee = null
+		?string $resource = null,
+		?string $recipient = null
 	): ResponseInterface {
 		$spaceId = ($this->spacesContext->getSpaceByName($sharer, $space))["id"];
-		$itemId = $this->spacesContext->getResourceId($sharer, $space, $resource);
+		$itemId = (isset($resource)) ? $this->spacesContext->getResourceId($sharer, $space, $resource) : $this->spacesContext->getResourceId($sharer, $space, $space);
 
 		$permId = ($shareType === 'link')
 			? $this->featureContext->shareNgGetLastCreatedLinkShareID()
@@ -488,8 +488,8 @@ class SharingNgContext implements Context {
 	 * @When /^user "([^"]*)" removes the share permission of (user|group) "([^"]*)" from (?:file|folder|resource) "([^"]*)" of space "([^"]*)" using the Graph API$/
 	 *
 	 * @param string $sharer
-	 * @param string $shareType (user|group)
-	 * @param string $sharee can be both user or group
+	 * @param string $recipientType (user|group)
+	 * @param string $recipient can be both user or group
 	 * @param string $resource
 	 * @param string $space
 	 *
@@ -499,13 +499,36 @@ class SharingNgContext implements Context {
 	 */
 	public function userRemovesSharePermissionOfUserFromResourceOfSpaceUsingGraphAPI(
 		string $sharer,
-		string $shareType,
-		string $sharee,
+		string $recipientType,
+		string $recipient,
 		string $resource,
 		string $space
 	): void {
 		$this->featureContext->setResponse(
-			$this->removeSharePermission($sharer, $shareType, $resource, $space)
+			$this->removeSharePermission($sharer, $recipientType, $space, $resource)
+		);
+	}
+
+	/**
+	 * @When /^user "([^"]*)" removes the share permission of (user|group) "([^"]*)" from space "([^"]*)" using the Graph API$/
+	 *
+	 * @param string $sharer
+	 * @param string $recipientType (user|group)
+	 * @param string $recipient can be both user or group
+	 * @param string $space
+	 *
+	 * @return void
+	 * @throws JsonException
+	 * @throws \GuzzleHttp\Exception\GuzzleException
+	 */
+	public function userRemovesSharePermissionOfUserFromSpaceUsingGraphAPI(
+		string $sharer,
+		string $recipientType,
+		string $recipient,
+		string $space
+	): void {
+		$this->featureContext->setResponse(
+			$this->removeSharePermission($sharer, $recipientType, $space)
 		);
 	}
 
@@ -526,7 +549,7 @@ class SharingNgContext implements Context {
 		string $space
 	):void {
 		$this->featureContext->setResponse(
-			$this->removeSharePermission($sharer, 'link', $resource, $space)
+			$this->removeSharePermission($sharer, 'link', $space, $resource)
 		);
 	}
 
@@ -629,18 +652,19 @@ class SharingNgContext implements Context {
 		);
 		$responseBody = $this->featureContext->getJsonDecodedResponse($response);
 		$expectedValue = $status === "enabled" ? "true" : "false";
+		$actualValue = "";
 		foreach ($responseBody["value"] as $value) {
 			if ($value["remoteItem"]["name"] === $resource) {
 				// var_export converts values to their string representations
 				// e.g.: true -> 'true'
-				$actaulValue = var_export($value["@client.synchronize"], true);
+				$actualValue = var_export($value["@client.synchronize"], true);
 				break;
 			}
 		}
 		Assert::assertSame(
-			$actaulValue,
+			$actualValue,
 			$expectedValue,
-			"Expected property '@client.synchronize' to be '$expectedValue' but found '$actaulValue'"
+			"Expected property '@client.synchronize' to be '$expectedValue' but found '$actualValue'"
 		);
 	}
 }