Repository: owncloud/ocis
Pull request #6959 (2023-08-03 11:14:43)

[tests-only][full-ci] Remove `@skipOnStable2.0` tag
Part of: https://github.com/owncloud/ocis/issues/6726

As we don't run the tests in `stable-2.0` branch these tags are not need so this PR removes them


Patch:
diff --git a/.drone.star b/.drone.star
index efd81f54b15..bef76ed4b31 100644
--- a/.drone.star
+++ b/.drone.star
@@ -31,7 +31,7 @@ PLUGINS_S3_CACHE = "plugins/s3-cache:1"
 PLUGINS_SLACK = "plugins/slack:1"
 REDIS = "redis:6-alpine"
 SELENIUM_STANDALONE_CHROME = "selenium/standalone-chrome:104.0-20220812"
-SONARSOURCE_SONAR_SCANNER_CLI = "sonarsource/sonar-scanner-cli:4.7.0"
+SONARSOURCE_SONAR_SCANNER_CLI = "sonarsource/sonar-scanner-cli:5.0"
 
 DEFAULT_PHP_VERSION = "7.4"
 DEFAULT_NODEJS_VERSION = "18"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7487ee168e5..12f4b3a7fab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,30 @@
+# Changelog for [unreleased] (UNRELEASED)
+
+The following sections list the changes for unreleased.
+
+[unreleased]: https://github.com/owncloud/ocis/compare/v3.1.0...master
+
+## Summary
+
+* Enhancement - Bump sonarcloud: [#6961](https://github.com/owncloud/ocis/pull/6961)
+* Enhancement - Extendable policy mimetype extension mapping: [#6869](https://github.com/owncloud/ocis/pull/6869)
+
+## Details
+
+* Enhancement - Bump sonarcloud: [#6961](https://github.com/owncloud/ocis/pull/6961)
+
+   Bump sonarcloud to `5.0` to avoid java errors
+
+   https://github.com/owncloud/ocis/pull/6961
+
+* Enhancement - Extendable policy mimetype extension mapping: [#6869](https://github.com/owncloud/ocis/pull/6869)
+
+   The extension mimetype mappings known from rego can now be extended. To do this, ocis must be
+   informed where the mimetype file (apache mime.types file format) is located.
+
+   `export OCIS_MACHINE_AUTH_API_KEY=$OCIS_HOME/mime.types`
+
+   https://github.com/owncloud/ocis/pull/6869
 # Changelog for [3.1.0] (2023-08-02)
 
 The following sections list the changes for 3.1.0.
diff --git a/changelog/unreleased/bump-sonarcloud.md b/changelog/unreleased/bump-sonarcloud.md
new file mode 100644
index 00000000000..2eeac433b6a
--- /dev/null
+++ b/changelog/unreleased/bump-sonarcloud.md
@@ -0,0 +1,5 @@
+Enhancement: Bump sonarcloud
+
+Bump sonarcloud to `5.0` to avoid java errors
+
+https://github.com/owncloud/ocis/pull/6961
diff --git a/changelog/unreleased/enhancement-extendable-policy-mimetype-extension-mapping.md b/changelog/unreleased/enhancement-extendable-policy-mimetype-extension-mapping.md
new file mode 100644
index 00000000000..d33c4adeb5c
--- /dev/null
+++ b/changelog/unreleased/enhancement-extendable-policy-mimetype-extension-mapping.md
@@ -0,0 +1,8 @@
+Enhancement: Extendable policy mimetype extension mapping
+
+The extension mimetype mappings known from rego can now be extended.
+To do this, ocis must be informed where the mimetype file (apache mime.types file format) is located.
+
+`export OCIS_MACHINE_AUTH_API_KEY=$OCIS_HOME/mime.types`
+
+https://github.com/owncloud/ocis/pull/6869
diff --git a/services/policies/README.md b/services/policies/README.md
index 4dccbf52d85..067c3312a6b 100644
--- a/services/policies/README.md
+++ b/services/policies/README.md
@@ -20,7 +20,7 @@ To configure the policies service, three environment variables need to be define
 
 Note that each query setting defines the [Complete Rules](https://www.openpolicyagent.org/docs/latest/#complete-rules) variable defined in the rego rule set the corresponding step uses for the evaluation. If the variable is mistyped or not found, the evaluation defaults to deny. Individual query definitions can be defined for each module.
 
-To activate a the policies service for a module, it must be started with a yaml configuration that points to one or more rego files. Note that if the service is scaled horizontally, each instance should have access to the same rego files to avoid unpredictable results. If a file path has been configured but the file it is not present or accessible, the evaluation defaults to deny.
+To activate the policies service for a module, it must be started with a yaml configuration that points to one or more rego files. Note that if the service is scaled horizontally, each instance should have access to the same rego files to avoid unpredictable results. If a file path has been configured but the file is not present or accessible, the evaluation defaults to deny.
 
 When using async post-processing which is done via the postprocessing service, the value `policies` must be added to the `POSTPROCESSING_STEPS` configuration in postprocessing service in the order where the evaluation should take place.
 
@@ -88,8 +88,8 @@ proxy:
 
 The same can be achieved by setting the following environment variable:
 
-```yaml
-PROXY_POLICIES_QUERY=data.proxy.granted
+```shell
+export PROXY_POLICIES_QUERY=data.proxy.granted
 ```
 
 ### Postprocessing
@@ -102,14 +102,14 @@ policies:
 
 The same can be achieved by setting the following environment variable:
 
-```yaml
-POLICIES_POSTPROCESSING_QUERY=data.postprocessing.granted
+```shell
+export POLICIES_POSTPROCESSING_QUERY=data.postprocessing.granted
 ```
 
 As soon as that query is configured, the postprocessing service must be informed to use the policies step by setting the environment variable:
 
-```yaml
-POSTPROCESSING_STEPS=policies
+```shell
+export POSTPROCESSING_STEPS=policies
 ```
 
 Note that additional steps can be configured and their position in the list defines the order of processing. For details see the postprocessing service documentation.
@@ -118,6 +118,30 @@ Note that additional steps can be configured and their position in the list defi
 
 To identify available keys for OPA, you need to look at [engine.go](https://github.com/owncloud/ocis/blob/master/services/policies/pkg/engine/engine.go) and the [policies.swagger.json](https://github.com/owncloud/ocis/blob/master/protogen/gen/ocis/services/policies/v0/policies.swagger.json) file. Note that which keys are available depends on from which module it is used.
 
+## Extend Mimetype File Extension Mapping
+
+In the extended set of the rego query language, it is possible to get a list of associated file extensions based on a mimetype, for example `ocis.mimetype.extensions("application/pdf")`.
+
+The list of mappings is restricted by default and is provided by the host system ocis is installed on.
+
+In order to extend this list, ocis must be provided with the path to a custom `mime.types` file that maps mimetypes to extensions.
+The location for the file must be accessible by all instances of the policy service. As a rule of thumb, use the directory where the ocis configuration files are stored.
+Note that existing mappings from the host are extended by the definitions from the mime types file, but not replaced.
+
+The path to that file can be provided via a yaml configuration or an environment variable. Note to replace the `OCIS_CONFIG_DIR` string by an existing path.
+
+```shell
+export OCIS_MACHINE_AUTH_API_KEY=OCIS_CONFIG_DIR/mime.types
+```
+
+```yaml
+policies:
+  engine:
+    mimes: OCIS_CONFIG_DIR/mime.types
+```
+
+A good example of how such a file should be formatted can be found in the [Apache svn repository](https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types).
+
 ## Example Policies
 
 The policies service contains a set of preconfigured example policies. See the [deployment examples](https://github.com/owncloud/ocis/tree/master/deployments/examples) directory for details. The contained policies disallow Infinite Scale to create certain file types, both via the proxy middleware and the events service via postprocessing.
diff --git a/services/policies/pkg/config/config.go b/services/policies/pkg/config/config.go
index 3eb9b05f0d1..11011376c4a 100644
--- a/services/policies/pkg/config/config.go
+++ b/services/policies/pkg/config/config.go
@@ -45,6 +45,8 @@ type TokenManager struct {
 type Engine struct {
 	Timeout  time.Duration `yaml:"timeout" env:"POLICIES_ENGINE_TIMEOUT" desc:"Sets the timeout the rego expression evaluation can take. The timeout can be set as number followed by a unit identifier like ms, s, etc. Rules default to deny if the timeout was reached."`
 	Policies []string      `yaml:"policies"`
+	// Mimes file path, RFC 4288
+	Mimes string `yaml:"mimes" env:"POLICIES_ENGINE_MIMES" desc:"Sets the mimes file path which maps mimetypes to associated file extensions. See the text description for details."`
 }
 
 // Postprocessing defines the config options for the postprocessing policy handling.
diff --git a/services/policies/pkg/engine/opa/engine.go b/services/policies/pkg/engine/opa/engine.go
index 45bd211bf79..21c07cdb4aa 100644
--- a/services/policies/pkg/engine/opa/engine.go
+++ b/services/policies/pkg/engine/opa/engine.go
@@ -2,6 +2,8 @@ package opa
 
 import (
 	"context"
+	"io"
+	"os"
 	"time"
 
 	"github.com/open-policy-agent/opa/rego"
@@ -17,16 +19,38 @@ type OPA struct {
 	printHook print.Hook
 	policies  []string
 	timeout   time.Duration
+	options   []func(r *rego.Rego)
 }
 
 // NewOPA returns a ready to use opa engine.
 func NewOPA(timeout time.Duration, logger log.Logger, conf config.Engine) (OPA, error) {
+	var mtReader io.ReadCloser
+
+	if conf.Mimes != "" {
+		var err error
+		mtReader, err = os.Open(conf.Mimes)
+		if err != nil {
+			return OPA{}, err
+		}
+
+		defer mtReader.Close()
+	}
+
+	rfMimetypeExtensions, err := RFMimetypeExtensions(mtReader)
+	if err != nil {
+		return OPA{}, err
+	}
+
 	return OPA{
-			policies:  conf.Policies,
-			timeout:   timeout,
-			printHook: logPrinter{logger: logger},
+		policies:  conf.Policies,
+		timeout:   timeout,
+		printHook: logPrinter{logger: logger},
+		options: []func(r *rego.Rego){
+			RFMimetypeDetect,
+			RFResourceDownload,
+			rfMimetypeExtensions,
 		},
-		nil
+	}, nil
 }
 
 // Evaluate evaluates the opa policies and returns the result.
@@ -34,19 +58,13 @@ func (o OPA) Evaluate(ctx context.Context, qs string, env engine.Environment) (b
 	ctx, cancel := context.WithTimeout(ctx, o.timeout)
 	defer cancel()
 
-	customFns := []func(r *rego.Rego){
-		RFResourceDownload,
-		RFMimetypeDetect,
-		RFMimetypeExtensions,
-	}
-
 	q, err := rego.New(
 		append([]func(r *rego.Rego){
 			rego.Query(qs),
 			rego.Load(o.policies, nil),
 			rego.EnablePrintStatements(true),
 			rego.PrintHook(o.printHook),
-		}, customFns...)...,
+		}, o.options...)...,
 	).PrepareForEval(ctx)
 	if err != nil {
 		return false, err
diff --git a/services/policies/pkg/engine/opa/rf_mimetype.go b/services/policies/pkg/engine/opa/rf_mimetype.go
index 033d664b660..f3b7b300f9f 100644
--- a/services/policies/pkg/engine/opa/rf_mimetype.go
+++ b/services/policies/pkg/engine/opa/rf_mimetype.go
@@ -1,6 +1,8 @@
 package opa
 
 import (
+	"bufio"
+	"io"
 	"mime"
 	"strings"
 
@@ -10,34 +12,70 @@ import (
 	"github.com/open-policy-agent/opa/types"
 )
 
-var RFMimetypeExtensions = rego.Function1(
-	&rego.Function{
-		Name:             "ocis.mimetype.extensions",
-		Decl:             types.NewFunction(types.Args(types.S), types.A),
-		Memoize:          true,
-		Nondeterministic: true,
-	},
-	func(_ rego.BuiltinContext, a *ast.Term) (*ast.Term, error) {
-		var mt string
+// RFMimetypeExtensions extends the rego dictionary with the possibility of mapping mimetypes to file extensions.
+// Be careful calling this multiple times with individual readers, the mime store is global,
+// which results in one global store which holds all known mimetype mappings at once.
+//
+// Rego: `ocis.mimetype.extensions("application/pdf")`
+// Result `[.pdf]`
+func RFMimetypeExtensions(f io.Reader) (func(*rego.Rego), error) {
+	if f != nil {
+		scanner := bufio.NewScanner(f)
+		for scanner.Scan() {
+			fields := strings.Fields(scanner.Text())
+			if len(fields) <= 1 || fields[0][0] == '#' {
+				continue
+			}
+			mimeType := fields[0]
+			for _, ext := range fields[1:] {
+				if ext[0] == '#' {
+					break
+				}
+				if err := mime.AddExtensionType("."+ext, mimeType); err != nil {
+					return nil, err
+				}
 
-		if err := ast.As(a.Value, &mt); err != nil {
-			return nil, err
+			}
 		}
-
-		detectedExtensions, err := mime.ExtensionsByType(mt)
-		if err != nil {
+		if err := scanner.Err(); err != nil {
 			return nil, err
 		}
+	}
 
-		var mimeTerms []*ast.Term
-		for _, extension := range detectedExtensions {
-			mimeTerms = append(mimeTerms, ast.NewTerm(ast.String(extension)))
-		}
+	return rego.Function1(
+		&rego.Function{
+			Name:             "ocis.mimetype.extensions",
+			Decl:             types.NewFunction(types.Args(types.S), types.A),
+			Memoize:          true,
+			Nondeterministic: true,
+		},
+		func(_ rego.BuiltinContext, a *ast.Term) (*ast.Term, error) {
+			var mt string
 
-		return ast.ArrayTerm(mimeTerms...), nil
-	},
-)
+			if err := ast.As(a.Value, &mt); err != nil {
+				return nil, err
+			}
+
+			detectedExtensions, err := mime.ExtensionsByType(mt)
+			if err != nil {
+				return nil, err
+			}
+
+			var mimeTerms []*ast.Term
+			for _, extension := range detectedExtensions {
+				mimeTerms = append(mimeTerms, ast.NewTerm(ast.String(extension)))
+			}
+
+			return ast.ArrayTerm(mimeTerms...), nil
+		},
+	), nil
+}
 
+// RFMimetypeDetect extends the rego dictionary with the possibility to detect mimetypes.
+// Be careful, the list of known mimetypes is limited.
+//
+// Rego: `ocis.mimetype.extensions(".txt")`
+// Result `text/plain`
 var RFMimetypeDetect = rego.Function1(
 	&rego.Function{
 		Name:             "ocis.mimetype.detect",
diff --git a/services/policies/pkg/engine/opa/rf_resource.go b/services/policies/pkg/engine/opa/rf_resource.go
index 60543c0b83c..9ff1d0ba1ee 100644
--- a/services/policies/pkg/engine/opa/rf_resource.go
+++ b/services/policies/pkg/engine/opa/rf_resource.go
@@ -11,6 +11,10 @@ import (
 	"github.com/open-policy-agent/opa/types"
 )
 
+// RFResourceDownload extends the rego dictionary with the possibility to download oCis resources.
+//
+// Rego: `ocis.resource.download("ocis/path/0034892347349827")`
+// Result: bytes
 var RFResourceDownload = rego.Function1(
 	&rego.Function{
 		Name:             "ocis.resource.download",


Test patch:
diff --git a/services/policies/pkg/engine/opa/rf_mimetype_test.go b/services/policies/pkg/engine/opa/rf_mimetype_test.go
index 404dc2b456d..d2f692deba9 100644
--- a/services/policies/pkg/engine/opa/rf_mimetype_test.go
+++ b/services/policies/pkg/engine/opa/rf_mimetype_test.go
@@ -2,6 +2,8 @@ package opa_test
 
 import (
 	"context"
+	"io"
+	"strings"
 
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
@@ -19,13 +21,37 @@ var _ = Describe("opa ocis mimetype functions", func() {
 			Expect(rs[0].Expressions[0].String()).To(Equal("text/plain"))
 		})
 	})
+	Describe("ocis.mimetype.extensions", func() {
+		DescribeTable("resolves extensions by mimetype",
+			func(mimetype string, expectations []string, f io.Reader) {
+				rfMimetypeExtensions, err := opa.RFMimetypeExtensions(f)
+				Expect(err).ToNot(HaveOccurred())
 
-	Describe("ocis.mimetype.extension_for_mimetype", func() {
-		It("provides matching extensions", func() {
-			r := rego.New(rego.Query(`ocis.mimetype.extensions("application/pdf")`), opa.RFMimetypeExtensions)
-			rs, err := r.Eval(context.Background())
-			Expect(err).ToNot(HaveOccurred())
-			Expect(rs[0].Expressions[0].String()).To(Equal("[.pdf]"))
-		})
+				r := rego.New(rego.Query(`ocis.mimetype.extensions("`+mimetype+`")`), rfMimetypeExtensions)
+				rs, err := r.Eval(context.Background())
+				Expect(err).ToNot(HaveOccurred())
+
+				got := rs[0].Expressions[0].String()
+
+				if len(expectations) == 0 {
+					Expect(got).To(Equal("[]"))
+				}
+
+				for i, expectation := range expectations {
+					if i+1 != len(expectations) {
+						expectation += " "
+					}
+
+					Expect(string(got[0])).To(Equal("["))
+					Expect(strings.Contains(got, expectation)).To(BeTrue())
+					Expect(string(got[len(got)-1])).To(Equal("]"))
+				}
+			},
+			Entry("With default mimetype", "application/pdf", []string{".pdf"}, nil),
+			Entry("With unknown mimetype", "ocis/with.custom.mt", []string{}, nil),
+			Entry("With custom mimetype", "ocis/with.custom.mt", []string{".with.custom.mt"}, strings.NewReader("ocis/with.custom.mt    with.custom.mt")),
+			Entry("With multiple custom mimetypes", "ocis/with.multiple.custom.mt", []string{".with.multiple.custom.1.mt", ".with.multiple.custom.2.mt"}, strings.NewReader("ocis/with.multiple.custom.mt                                with.multiple.custom.1.mt with.multiple.custom.2.mt")),
+			Entry("With custom ignored mimetype", "ocis/with.multiple.custom.ignored.mt", []string{}, strings.NewReader("#ocis/with.multiple.custom.ignored.mt with.multiple.custom.ignored.mt")),
+		)
 	})
 })
diff --git a/tests/acceptance/features/apiGraph/assignRole.feature b/tests/acceptance/features/apiGraph/assignRole.feature
index b14533c93f2..24dc67e3bb4 100644
--- a/tests/acceptance/features/apiGraph/assignRole.feature
+++ b/tests/acceptance/features/apiGraph/assignRole.feature
@@ -1,4 +1,4 @@
-@api @skipOnStable2.0
+@api 
 Feature: assign role
   As an admin,
   I want to assign roles to users.
diff --git a/tests/acceptance/features/apiGraph/createUser.feature b/tests/acceptance/features/apiGraph/createUser.feature
index 9d9b5b555e0..a6aab253a2f 100644
--- a/tests/acceptance/features/apiGraph/createUser.feature
+++ b/tests/acceptance/features/apiGraph/createUser.feature
@@ -34,12 +34,8 @@ Feature: create user
       | name.with.dots               | user                                    | name.w.dots@example.org | 123                          | 200  | true   | should      |
       | 123456789                    | user                                    | 123456789@example.org   | 123                          | 400  | true   | should not  |
       | 0.0                          | user                                    | float@example.org       | 123                          | 400  | true   | should not  |
-
-    @skipOnStable2.0
-    Examples:
-      | userName     | displayName   | email           | password | code | enable | shouldOrNot |
-      | withoutEmail | without email |                 | 123      | 200  | true   | should      |
-      | Alice        | same userName | new@example.org | 123      | 409  | true   | should      |
+      | withoutEmail                 | without email                           |                         | 123                          | 200  | true   | should      |
+      | Alice                        | same userName                           | new@example.org         | 123                          | 409  | true   | should      |
 
 
   Scenario: user cannot be created with empty name
@@ -82,7 +78,7 @@ Feature: create user
       | accountEnabled | true                  |
     Then the HTTP status code should be "409"
 
-  @skipOnStable2.0
+
   Scenario: user can be created with the name of the deleted user
     Given user "Brian" has been created with default attributes and without skeleton files
     And the administrator has assigned the role "Admin" to user "Alice" using the Graph API
@@ -129,7 +125,7 @@ Feature: create user
     When the administrator retrieves the assigned role of user "sam" using the Graph API
     Then the HTTP status code should be "200"
     And the Graph API response should have no role
-    
+
 
   @env-config
   Scenario: create user with setting OCIS assign the default user role
diff --git a/tests/acceptance/features/apiGraph/editUser.feature b/tests/acceptance/features/apiGraph/editUser.feature
index 85f3b84e576..b60ac73753b 100644
--- a/tests/acceptance/features/apiGraph/editUser.feature
+++ b/tests/acceptance/features/apiGraph/editUser.feature
@@ -43,7 +43,7 @@ Feature: edit user
       | empty mail                |                      | 400  | brian@example.com    |
       | change to a invalid email | invalidEmail         | 400  | brian@example.com    |
 
-  @skipOnStable2.0 @issue-5763
+   @issue-5763
   Scenario Outline: admin user can edit another user's name
     Given user "Carol" has been created with default attributes and without skeleton files
     When the user "Alice" changes the user name of user "Carol" to "<userName>" using the Graph API
@@ -70,7 +70,7 @@ Feature: edit user
       | change to existing user name | Brian    | 409  | Brian       |
       | empty user name              |          | 400  | Brian       |
 
-  @skipOnStable2.0
+  
   Scenario: admin user changes the name of a user to the name of an existing disabled user
     Given the user "Alice" has created a new user using the Graph API with the following settings:
       | userName    | sam             |
@@ -96,7 +96,7 @@ Feature: edit user
     }
     """
 
-  @skipOnStable2.0
+  
   Scenario: admin user changes the name of a user to the name of a previously deleted user
     Given the user "Alice" has created a new user using the Graph API with the following settings:
       | userName    | sam             |
@@ -318,7 +318,7 @@ Feature: edit user
       | User Light  | User Light  |
       | User Light  | Admin       |
 
-  @skipOnStable2.0
+  
   Scenario: admin user disables another user
     When the user "Alice" disables user "Brian" using the Graph API
     Then the HTTP status code should be "200"
@@ -360,7 +360,7 @@ Feature: edit user
     }
     """
 
-  @skipOnStable2.0
+  
   Scenario Outline: normal user should not be able to disable another user
     Given user "Carol" has been created with default attributes and without skeleton files
     And the administrator has assigned the role "<role>" to user "Brian" using the Graph API
@@ -409,7 +409,7 @@ Feature: edit user
       | User        |
       | User Light  |
 
-  @skipOnStable2.0
+  
   Scenario: admin user enables disabled user
     Given the user "Alice" has disabled user "Brian" using the Graph API
     When the user "Alice" enables user "Brian" using the Graph API
@@ -452,7 +452,7 @@ Feature: edit user
     }
     """
 
-  @skipOnStable2.0
+  
   Scenario Outline: normal user should not be able to enable another user
     Given user "Carol" has been created with default attributes and without skeleton files
     And the user "Alice" has disabled user "Carol" using the Graph API
diff --git a/tests/acceptance/features/apiGraph/getApplications.feature b/tests/acceptance/features/apiGraph/getApplications.feature
index 8ab7fa13845..3655a42156e 100644
--- a/tests/acceptance/features/apiGraph/getApplications.feature
+++ b/tests/acceptance/features/apiGraph/getApplications.feature
@@ -1,4 +1,4 @@
-@api @skipOnStable2.0
+@api
 Feature: get applications
   As a user
   I want to be able to get application information with existing roles
@@ -13,9 +13,9 @@ Feature: get applications
     When user "Alice" gets all applications using the Graph API
     Then the HTTP status code should be "200"
     And the user API response should contain the following application information:
-      | key                        | value                   |
-      | displayName                | ownCloud Infinite Scale |
-      | id                         | %uuid_v4%               |
+      | key         | value                   |
+      | displayName | ownCloud Infinite Scale |
+      | id          | %uuid_v4%               |
     And the user API response should contain the following app roles:
       | Admin       |
       | Space Admin |
diff --git a/tests/acceptance/features/apiGraph/getUser.feature b/tests/acceptance/features/apiGraph/getUser.feature
index fee9d72cd62..6b49ea2db3d 100644
--- a/tests/acceptance/features/apiGraph/getUser.feature
+++ b/tests/acceptance/features/apiGraph/getUser.feature
@@ -10,7 +10,7 @@ Feature: get users
       | Alice    |
       | Brian    |
 
-  @skipOnStable2.0
+  
   Scenario: admin user gets the information of a user
     Given the administrator has assigned the role "Admin" to user "Alice" using the Graph API
     When user "Alice" gets information of user "Brian" using Graph API
@@ -93,7 +93,7 @@ Feature: get users
       | User Light  | User Light  |
       | User Light  | Admin       |
 
-  @skipOnStable2.0
+  
   Scenario: admin user gets all users
     Given the administrator has assigned the role "Admin" to user "Alice" using the Graph API
     When user "Alice" gets all users using the Graph API
@@ -159,7 +159,7 @@ Feature: get users
     }
     """
 
-  @skipOnStable2.0
+  
   Scenario: admin user gets all users include disabled users
     Given the administrator has assigned the role "Admin" to user "Alice" using the Graph API
     And the user "Alice" has disabled user "Brian" using the Graph API
@@ -258,7 +258,7 @@ Feature: get users
       | User        |
       | User Light  |
 
-  @skipOnStable2.0
+  
   Scenario: admin user gets the drive information of a user
     Given the administrator has assigned the role "Admin" to user "Alice" using the Graph API
     When the user "Alice" gets user "Brian" along with his drive information using Graph API
@@ -381,7 +381,7 @@ Feature: get users
       }
     """
 
-  @skipOnStable2.0
+  
   Scenario Outline: non-admin user gets his/her own drive information
     Given the administrator has assigned the role "<userRole>" to user "Brian" using the Graph API
     When the user "Brian" gets his drive information using Graph API
@@ -509,7 +509,7 @@ Feature: get users
       | User        |
       | User Light  |
 
-  @skipOnStable2.0
+  
   Scenario: admin user gets the group information of a user
     Given the administrator has assigned the role "Admin" to user "Alice" using the Graph API
     And group "tea-lover" has been created
@@ -617,7 +617,7 @@ Feature: get users
       | User Light  | User Light  |
       | User Light  | Admin       |
 
-  @skipOnStable2.0
+  
   Scenario: admin user gets all users of certain groups
     Given the administrator has assigned the role "Admin" to user "Alice" using the Graph API
     And user "Carol" has been created with default attributes and without skeleton files
@@ -751,7 +751,7 @@ Feature: get users
     And the JSON data of the response should not contain the user "Alice Hansen" in the item 'value'
 
 
-  @skipOnStable2.0
+  
   Scenario: admin user gets all users of two groups
     Given the administrator has assigned the role "Admin" to user "Alice" using the Graph API
     And user "Carol" has been created with default attributes and without skeleton files
@@ -825,7 +825,7 @@ Feature: get users
     """
     But the JSON data of the response should not contain the user "Carol King" in the item 'value'
 
-  @skipOnStable2.0
+  
   Scenario Outline: non admin user tries to get users of certain groups
     Given the administrator has assigned the role "Admin" to user "Alice" using the Graph API
     And the administrator has assigned the role "<role>" to user "Brian" using the Graph API
@@ -860,7 +860,7 @@ Feature: get users
       | User        |
       | User Light  |
 
-  @skipOnStable2.0
+  
   Scenario: admin user gets all users with certain roles and members of a certain group
     Given the administrator has assigned the role "Admin" to user "Alice" using the Graph API
     And user "Carol" has been created with default attributes and without skeleton files
@@ -965,7 +965,7 @@ Feature: get users
     """
     But the JSON data of the response should not contain the user "Carol King" in the item 'value'
 
-  @skipOnStable2.0
+  
   Scenario Outline: non-admin user tries to get users with a certain role
     Given the administrator has assigned the role "<userRole>" to user "Alice" using the Graph API
     When the user "Alice" gets all users with role "<role>" using the Graph API
diff --git a/tests/acceptance/features/apiSpaces/spaceManagement.feature b/tests/acceptance/features/apiSpaces/spaceManagement.feature
index 975c0414b32..e1946b925b6 100644
--- a/tests/acceptance/features/apiSpaces/spaceManagement.feature
+++ b/tests/acceptance/features/apiSpaces/spaceManagement.feature
@@ -90,7 +90,7 @@ Feature: Space management
     And the json responded should not contain a space with name "Project"
     And the json responded should not contain a space with name "Alice Hansen"
 
-  @skipOnStable2.0
+  
   Scenario: space admin user changes the name of the project space
     When user "Brian" changes the name of the "Project" space to "New Name" owned by user "Alice"
     Then the HTTP status code should be "200"
@@ -116,7 +116,7 @@ Feature: Space management
     Then the HTTP status code should be "404"
     And the user "Alice" should have a space called "Project"
 
-  @skipOnStable2.0
+  
   Scenario: space admin user changes the description of the project space
     When user "Brian" changes the description of the "Project" space to "New description" owned by user "Alice"
     Then the HTTP status code should be "200"
@@ -142,7 +142,7 @@ Feature: Space management
     When user "Carol" tries to change the description of the "Project" space to "New description" owned by user "Alice"
     Then the HTTP status code should be "404"
 
-  @skipOnStable2.0
+  
   Scenario: space admin user disables the project space
     When user "Brian" disables a space "Project" owned by user "Alice"
     Then the HTTP status code should be "204"
@@ -162,7 +162,7 @@ Feature: Space management
       | Brian |
       | Carol |
 
-  @skipOnStable2.0
+  
   Scenario: space admin user deletes the project space
     Given user "Alice" has disabled a space "Project"
     When user "Brian" deletes a space "Project" owned by user "Alice"
@@ -175,7 +175,7 @@ Feature: Space management
     When user "Carol" tries to delete a space "Project" owned by user "Alice"
     Then the HTTP status code should be "404"
 
-  @skipOnStable2.0
+  
   Scenario: space admin user enables the project space
     Given user "Alice" has disabled a space "Project"
     When user "Brian" restores a disabled space "Project" owned by user "Alice"
diff --git a/tests/acceptance/features/apiSpaces/tag.feature b/tests/acceptance/features/apiSpaces/tag.feature
index e14cfb5bcde..e5d5a9df64c 100644
--- a/tests/acceptance/features/apiSpaces/tag.feature
+++ b/tests/acceptance/features/apiSpaces/tag.feature
@@ -1,4 +1,4 @@
-@api @skipOnStable2.0
+@api 
 Feature: Tag
   As a user
   I want to tag resources
diff --git a/tests/acceptance/features/apiSpacesShares/shareSubItemOfSpace.feature b/tests/acceptance/features/apiSpacesShares/shareSubItemOfSpace.feature
index 5c697e13a94..75b9fc1f452 100644
--- a/tests/acceptance/features/apiSpacesShares/shareSubItemOfSpace.feature
+++ b/tests/acceptance/features/apiSpacesShares/shareSubItemOfSpace.feature
@@ -119,7 +119,7 @@ Feature: Share a file or folder that is inside a space
     And the information about the last share for user "Brian" should include
       | expiration | 2042-01-01 |
 
-  @skipOnStable2.0
+  
   Scenario: user changes the expiration date
     Given user "Alice" has created a share inside of space "share sub-item" with settings:
       | path       | folder                   |
@@ -147,7 +147,7 @@ Feature: Share a file or folder that is inside a space
     And the information about the last share for user "Brian" should include
       | expiration |  |
 
-  @skipOnStable2.0
+  
   Scenario: check the end of expiration date in user share
     Given user "Alice" has created a share inside of space "share sub-item" with settings:
       | path       | folder                   |
@@ -159,7 +159,7 @@ Feature: Share a file or folder that is inside a space
     Then the HTTP status code should be "200"
     Then as "Brian" folder "Shares/folder" should not exist
 
-  @issue-5823 @skipOnStable2.0
+  @issue-5823 
   Scenario: check the end of expiration date in group share
     Given group "sales" has been created
     And the administrator has added a user "Brian" to the group "sales" using GraphApi