Repository: nextcloud/appstore

Issue:
Require max-version to be set
Apps shouldn't assume to work with unknown releases.
So max-version should be enforced for the nextcloud version tag.


Discussion:

Resolving patch:
diff --git a/nextcloudappstore/core/api/v1/release/parser.py b/nextcloudappstore/core/api/v1/release/parser.py
--- a/nextcloudappstore/core/api/v1/release/parser.py
+++ b/nextcloudappstore/core/api/v1/release/parser.py
@@ -5,6 +5,8 @@
 import lxml.etree  # type: ignore
 from typing import Dict, Any, Tuple, List, Set
 
+from semantic_version import Version
+
 from nextcloudappstore.core.api.v1.release import ReleaseConfig
 from nextcloudappstore.core.versioning import pad_max_version, \
     pad_min_version, raw_version
@@ -261,10 +263,28 @@ def parse_app_metadata(xml: str, schema: str, pre_xslt: str,
     transformed_doc = transform(pre_transformed_doc)  # type: ignore
     mapped = element_to_dict(transformed_doc.getroot())  # type: ignore
     validate_english_present(mapped)
+    validate_pre_11(mapped, doc)
     fix_partial_translations(mapped)
     return mapped
 
 
+def validate_pre_11(info: Dict, doc: Any) -> None:
+    """
+    Apps before 11 need to provide an owncloud min-version tag to run
+    :param info: the transformed and parsed info xml
+    :param doc: the original xml document
+    :raises: InvalidAppMetadataXmlException if no owncloud min-version is
+    present for apps with min-version 9 or 10
+    """
+    min_version = Version(info['app']['release']['platform_min_version'])
+
+    test_xpath = 'dependencies/owncloud'
+    if min_version < Version('11.0.0') and len(doc.xpath(test_xpath)) == 0:
+        msg = '<owncloud> tag is required for apps that run on Nextcloud 9 ' \
+              'and 10'
+        raise InvalidAppMetadataXmlException(msg)
+
+
 def validate_english_present(info: Dict) -> None:
     """
     Validates that name, summary and description are present in english


Test patch:
diff --git a/nextcloudappstore/core/api/v1/tests/data/archives/full.tar.gz b/nextcloudappstore/core/api/v1/tests/data/archives/full.tar.gz
Binary files a/nextcloudappstore/core/api/v1/tests/data/archives/full.tar.gz and b/nextcloudappstore/core/api/v1/tests/data/archives/full.tar.gz differ
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/11.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/11.xml
new file mode 100644
--- /dev/null
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/11.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
+    <id>news</id>
+    <name>News</name>
+    <summary>An RSS/Atom feed reader</summary>
+    <description>An RSS/Atom feed reader</description>
+    <version>8.8.2</version>
+    <licence>agpl</licence>
+    <author>Bernhard Posselt</author>
+    <category>multimedia</category>
+    <dependencies>
+        <nextcloud min-version="11" max-version="11"/>
+    </dependencies>
+</info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/9and10.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/9and10.xml
new file mode 100644
--- /dev/null
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/9and10.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
+    <id>news</id>
+    <name>News</name>
+    <summary>An RSS/Atom feed reader</summary>
+    <description>An RSS/Atom feed reader</description>
+    <version>8.8.2</version>
+    <licence>agpl</licence>
+    <author>Bernhard Posselt</author>
+    <category>multimedia</category>
+    <dependencies>
+        <owncloud min-version="9.1" max-version="9.1"/>
+    </dependencies>
+</info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/9and10invalid.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/9and10invalid.xml
new file mode 100644
--- /dev/null
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/9and10invalid.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
+    <id>news</id>
+    <name>News</name>
+    <summary>An RSS/Atom feed reader</summary>
+    <description>An RSS/Atom feed reader</description>
+    <version>8.8.2</version>
+    <licence>agpl</licence>
+    <author>Bernhard Posselt</author>
+    <category>multimedia</category>
+    <dependencies>
+        <nextcloud min-version="10" max-version="10"/>
+    </dependencies>
+</info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/badcommand.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/badcommand.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/badcommand.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/badcommand.xml
@@ -9,7 +9,7 @@
     <author>Bernhard Posselt</author>
     <category>multimedia</category>
     <dependencies>
-        <owncloud min-version="9.0"/>
+        <owncloud min-version="9.0" max-version="9.0"/>
         <command>bad command</command>
     </dependencies>
 </info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/broken-xml.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/broken-xml.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/broken-xml.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/broken-xml.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
     <id>news</id>
     <name>News</name>
     <description>An RSS/Atom feed reader</description>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/category_mapping.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/category_mapping.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/category_mapping.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/category_mapping.xml
@@ -9,6 +9,6 @@
     <category>productivity</category>
     <category>tool</category>
     <dependencies>
-        <owncloud min-version="9.0"/>
+        <owncloud min-version="9.0" max-version="9.0"/>
     </dependencies>
 </info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/category_mapping_game.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/category_mapping_game.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/category_mapping_game.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/category_mapping_game.xml
@@ -8,6 +8,6 @@
     <author>Bernhard Posselt</author>
     <category>game</category>
     <dependencies>
-        <owncloud min-version="9.0"/>
+        <owncloud min-version="9.0" max-version="9.0"/>
     </dependencies>
 </info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/category_mapping_tool.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/category_mapping_tool.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/category_mapping_tool.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/category_mapping_tool.xml
@@ -8,6 +8,6 @@
     <author>Bernhard Posselt</author>
     <category>other</category>
     <dependencies>
-        <owncloud min-version="9.0"/>
+        <owncloud min-version="9.0" max-version="9.0"/>
     </dependencies>
 </info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/digits.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/digits.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/digits.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/digits.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
     <id>twofactor_u2f</id>
     <name>News</name>
     <description>An RSS/Atom feed reader</description>
@@ -8,6 +8,6 @@
     <author>Bernhard Posselt</author>
     <category>multimedia</category>
     <dependencies>
-        <owncloud min-version="9.0"/>
+        <owncloud min-version="9.0" max-version="9.0"/>
     </dependencies>
 </info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/entities.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/entities.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/entities.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/entities.xml
@@ -12,6 +12,6 @@
     <author>Bernhard Posselt</author>
     <category>multimedia</category>
     <dependencies>
-        <owncloud min-version="9.0"/>
+        <owncloud min-version="9.0" max-version="9.0"/>
     </dependencies>
 </info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/full.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/full.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/full.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/full.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
     <id>news</id>
 
     <!-- translation can be done via the lang attribute, defaults to English -->
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/invalid-elements.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/invalid-elements.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/invalid-elements.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/invalid-elements.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
     <id>news</id>
     <name>News</name>
     <summary>An RSS/Atom feed reader</summary>
@@ -9,7 +9,7 @@
     <author>Bernhard Posselt</author>
     <category>multimedia</category>
     <dependencies>
-        <owncloud min-version="9.0"/>
+        <owncloud min-version="9.0" max-version="9.0"/>
     </dependencies>
     <standalone/>
     <default_enable/>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/invalid.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/invalid.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/invalid.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/invalid.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
     <id>news</id>
     <name>News</name>
     <description>An RSS/Atom feed reader</description>
@@ -8,6 +8,6 @@
     <author>Bernhard Posselt</author>
     <category>multimedia</category>
     <dependencies>
-        <owncloud min-version="x9.0"/>
+        <owncloud min-version="x9.0" max-version="9.0"/>
     </dependencies>
 </info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/minimal.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/minimal.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/minimal.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/minimal.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
     <id>news</id>
     <name>News</name>
     <summary>An RSS/Atom feed reader</summary>
@@ -9,6 +9,6 @@
     <author>Bernhard Posselt</author>
     <category>multimedia</category>
     <dependencies>
-        <owncloud min-version="9.0"/>
+        <owncloud min-version="9.0" max-version="9.0"/>
     </dependencies>
 </info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_description.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_description.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_description.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_description.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
     <id>news</id>
     <name>News</name>
     <summary>An RSS/Atom feed reader</summary>
@@ -9,6 +9,6 @@
     <author>Bernhard Posselt</author>
     <category>multimedia</category>
     <dependencies>
-        <owncloud min-version="9.0"/>
+        <owncloud min-version="9.0" max-version="9.0"/>
     </dependencies>
 </info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_name.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_name.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_name.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_name.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
     <id>news</id>
     <name lang="de">News</name>
     <summary>An RSS/Atom feed reader</summary>
@@ -9,6 +9,6 @@
     <author>Bernhard Posselt</author>
     <category>multimedia</category>
     <dependencies>
-        <owncloud min-version="9.0"/>
+        <owncloud min-version="9.0" max-version="9.0"/>
     </dependencies>
 </info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_summary.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_summary.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_summary.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_summary.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
     <id>news</id>
     <name>News</name>
     <summary lang="de">An RSS/Atom feed reader</summary>
@@ -9,6 +9,6 @@
     <author>Bernhard Posselt</author>
     <category>multimedia</category>
     <dependencies>
-        <owncloud min-version="9.0"/>
+        <owncloud min-version="9.0" max-version="9.0"/>
     </dependencies>
 </info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/prerelease.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/prerelease.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/prerelease.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/prerelease.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
     <id>news</id>
     <name>News</name>
     <summary>An RSS/Atom feed reader</summary>
@@ -9,6 +9,6 @@
     <author>Bernhard Posselt</author>
     <category>multimedia</category>
     <dependencies>
-        <owncloud min-version="9.0"/>
+        <owncloud min-version="9.0" max-version="9.0"/>
     </dependencies>
 </info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/repair-and-jobs.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/repair-and-jobs.xml
--- a/nextcloudappstore/core/api/v1/tests/data/infoxmls/repair-and-jobs.xml
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/repair-and-jobs.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
     <id>news</id>
     <name>News</name>
     <summary>An RSS/Atom feed reader</summary>
@@ -9,7 +9,7 @@
     <author>Bernhard Posselt</author>
     <category>multimedia</category>
     <dependencies>
-        <owncloud min-version="9.0"/>
+        <owncloud min-version="9.0" max-version="9.0"/>
     </dependencies>
     <background-jobs>
         <job>OCA\DAV\CardDAV\Sync\SyncJob</job>
diff --git a/nextcloudappstore/core/api/v1/tests/test_parser.py b/nextcloudappstore/core/api/v1/tests/test_parser.py
--- a/nextcloudappstore/core/api/v1/tests/test_parser.py
+++ b/nextcloudappstore/core/api/v1/tests/test_parser.py
@@ -49,9 +49,9 @@ def test_parse_minimal(self):
                 'php_min_version': '*',
                 'raw_php_max_version': '*',
                 'raw_php_min_version': '*',
-                'platform_max_version': '*',
+                'platform_max_version': '10.0.0',
                 'platform_min_version': '9.0.0',
-                'raw_platform_max_version': '*',
+                'raw_platform_max_version': '9',
                 'raw_platform_min_version': '9',
                 'shell_commands': [],
                 'version': '8.8.2',
@@ -149,6 +149,21 @@ def test_validate_schema(self):
                                self.config.pre_info_xslt,
                                self.config.info_xslt)
 
+    def test_validate_pre_11(self):
+        xml = self._get_contents('data/infoxmls/9and10.xml')
+        parse_app_metadata(xml, self.config.info_schema,
+                           self.config.pre_info_xslt,
+                           self.config.info_xslt)
+        xml = self._get_contents('data/infoxmls/11.xml')
+        parse_app_metadata(xml, self.config.info_schema,
+                           self.config.pre_info_xslt,
+                           self.config.info_xslt)
+        xml = self._get_contents('data/infoxmls/9and10invalid.xml')
+        with (self.assertRaises(InvalidAppMetadataXmlException)):
+            parse_app_metadata(xml, self.config.info_schema,
+                               self.config.pre_info_xslt,
+                               self.config.info_xslt)
+
     def test_fixes_xml(self):
         xml = self._get_contents('data/infoxmls/news.xml')
         parse_app_metadata(xml, self.config.info_schema,
diff --git a/nextcloudappstore/core/api/v1/tests/test_release_importer.py b/nextcloudappstore/core/api/v1/tests/test_release_importer.py
--- a/nextcloudappstore/core/api/v1/tests/test_release_importer.py
+++ b/nextcloudappstore/core/api/v1/tests/test_release_importer.py
@@ -55,9 +55,9 @@ def test_import_minimal(self):
 
         release = app.releases.all()[0]
         self.assertEqual('8.8.2', release.version)
-        self.assertEqual('>=9.0.0', release.platform_version_spec)
+        self.assertEqual('>=9.0.0,<10.0.0', release.platform_version_spec)
         self.assertEqual('*', release.php_version_spec)
-        self.assertEqual('>=9', release.raw_platform_version_spec)
+        self.assertEqual('>=9,<=9', release.raw_platform_version_spec)
         self.assertEqual('*', release.raw_php_version_spec)
         self.assertEqual(32, release.min_int_size)
         self._assert_all_empty(release, ['signature', 'download'])