[bitbake-devel,v3,3/7] fetch2/npm.py: restrict version parameter

Submitted by Jean-Marie LEMETAYER on Nov. 20, 2019, 9:34 a.m. | Patch ID: 167179

Details

Message ID 20191120093412.11519-4-jean-marie.lemetayer@savoirfairelinux.com
State New
Headers show

Commit Message

Jean-Marie LEMETAYER Nov. 20, 2019, 9:34 a.m.
The npm command allows version to be actual versions, tags or ranges.
The fetcher must be more restrictive and only allows fixed versions
(which are following the semver specification [1]).

The 'latest' tag which is automatically set to the latest published
version is also allowed to make the use of the 'devtool add' command
easier.

1: https://semver.org/spec/v2.0.0.html

Signed-off-by: Jean-Marie LEMETAYER <jean-marie.lemetayer@savoirfairelinux.com>
---
 lib/bb/fetch2/npm.py | 50 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

Patch hide | download patch | download mbox

diff --git a/lib/bb/fetch2/npm.py b/lib/bb/fetch2/npm.py
index e377d18a..e253cf3e 100644
--- a/lib/bb/fetch2/npm.py
+++ b/lib/bb/fetch2/npm.py
@@ -46,6 +46,33 @@  class Npm(FetchMethod):
         """
         return ud.type in ['npm']
 
+    @staticmethod
+    def _is_semver(version):
+        """
+            Is the version string following the semver semantic?
+
+            https://semver.org/spec/v2.0.0.html
+        """
+        regex = re.compile(
+        r"""
+        ^
+        (0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)
+        (?:-(
+            (?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)
+            (?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*
+        ))?
+        (?:\+(
+            [0-9a-zA-Z-]+
+            (?:\.[0-9a-zA-Z-]+)*
+        ))?
+        $
+        """, re.VERBOSE)
+
+        if regex.match(version) is None:
+            return False
+
+        return True
+
     def urldata_init(self, ud, d):
         """
             Init npm specific variables within url data
@@ -65,6 +92,9 @@  class Npm(FetchMethod):
         if not ud.version:
             raise MissingParameterError("Parameter 'version' required", ud.url)
 
+        if not self._is_semver(ud.version) and not ud.version == "latest":
+            raise ParameterError("Parameter 'version' is invalid", ud.url)
+
         # Get the 'registry' part of the url
         registry = re.sub(r"^npm://", "", ud.url.split(";")[0])
         ud.registry = "http://" + registry
@@ -96,6 +126,18 @@  class Npm(FetchMethod):
             ud.basecmd += " --passive-ftp"
             ud.basecmd += " --no-check-certificate"
 
+    def need_update(self, ud, d):
+        """
+            Force a fetch, even if localpath exists?
+        """
+        if ud.version == "latest":
+            return True
+
+        if os.path.exists(ud.localpath):
+            return False
+
+        return True
+
     @staticmethod
     def _run_npm_view(ud, d):
         """
@@ -158,6 +200,14 @@  class Npm(FetchMethod):
         integrity = view.get("dist", {}).get("integrity")
         shasum = view.get("dist", {}).get("shasum")
 
+        # Check if version is valid
+        if ud.version == "latest":
+            bb.warn("The npm package '{}' is using the latest version " \
+                    "available. This could lead to non-reproducible " \
+                    "builds.".format(ud.name))
+        elif ud.version != view.get("version"):
+            raise ParameterError("Parameter 'version' is invalid", ud.url)
+
         cmd = ud.basecmd
 
         bb.utils.mkdirhier(os.path.dirname(ud.localpath))