summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Frysinger <vapier@google.com>2021-03-01 21:38:08 -0500
committerMike Frysinger <vapier@google.com>2021-03-02 03:18:57 +0000
commit541339720451b0a05dc7ebe83e17bafb89863c6f (patch)
tree769d23948beab6523127880f013fc806de8eef87
parent13cb7f799dc61093ed69726093a5af8bf48c65d1 (diff)
downloadgit-repo-541339720451b0a05dc7ebe83e17bafb89863c6f.tar.gz
manifest: relax include name rules for user-specified pathv2.13.1
Allow the user to specify relative or absolute or any other funky path that they want when using `repo init` or `repo sync`. Our goal is to restrict the paths in the remote manifest git repo we cloned from the network, not protect the user from themselves. Bug: https://crbug.com/gerrit/14156 Change-Id: I1ccfb2a6bd1dce2bd765e261bef0bbf0f8a9beb6 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/298823 Reviewed-by: Jonathan Nieder <jrn@google.com> Tested-by: Mike Frysinger <vapier@google.com>
-rw-r--r--error.py4
-rw-r--r--manifest_xml.py41
-rw-r--r--tests/test_manifest_xml.py32
3 files changed, 62 insertions, 15 deletions
diff --git a/error.py b/error.py
index 2fb6aa0f..25ff80d1 100644
--- a/error.py
+++ b/error.py
@@ -22,12 +22,12 @@ class ManifestParseError(Exception):
22 """ 22 """
23 23
24 24
25class ManifestInvalidRevisionError(Exception): 25class ManifestInvalidRevisionError(ManifestParseError):
26 """The revision value in a project is incorrect. 26 """The revision value in a project is incorrect.
27 """ 27 """
28 28
29 29
30class ManifestInvalidPathError(Exception): 30class ManifestInvalidPathError(ManifestParseError):
31 """A path used in <copyfile> or <linkfile> is incorrect. 31 """A path used in <copyfile> or <linkfile> is incorrect.
32 """ 32 """
33 33
diff --git a/manifest_xml.py b/manifest_xml.py
index cd5954df..e96e0620 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -624,16 +624,22 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
624 b = b[len(R_HEADS):] 624 b = b[len(R_HEADS):]
625 self.branch = b 625 self.branch = b
626 626
627 # The manifestFile was specified by the user which is why we allow include
628 # paths to point anywhere.
627 nodes = [] 629 nodes = []
628 nodes.append(self._ParseManifestXml(self.manifestFile, 630 nodes.append(self._ParseManifestXml(
629 self.manifestProject.worktree)) 631 self.manifestFile, self.manifestProject.worktree,
632 restrict_includes=False))
630 633
631 if self._load_local_manifests and self.local_manifests: 634 if self._load_local_manifests and self.local_manifests:
632 try: 635 try:
633 for local_file in sorted(platform_utils.listdir(self.local_manifests)): 636 for local_file in sorted(platform_utils.listdir(self.local_manifests)):
634 if local_file.endswith('.xml'): 637 if local_file.endswith('.xml'):
635 local = os.path.join(self.local_manifests, local_file) 638 local = os.path.join(self.local_manifests, local_file)
636 nodes.append(self._ParseManifestXml(local, self.repodir)) 639 # Since local manifests are entirely managed by the user, allow
640 # them to point anywhere the user wants.
641 nodes.append(self._ParseManifestXml(
642 local, self.repodir, restrict_includes=False))
637 except OSError: 643 except OSError:
638 pass 644 pass
639 645
@@ -651,7 +657,19 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
651 657
652 self._loaded = True 658 self._loaded = True
653 659
654 def _ParseManifestXml(self, path, include_root, parent_groups=''): 660 def _ParseManifestXml(self, path, include_root, parent_groups='',
661 restrict_includes=True):
662 """Parse a manifest XML and return the computed nodes.
663
664 Args:
665 path: The XML file to read & parse.
666 include_root: The path to interpret include "name"s relative to.
667 parent_groups: The groups to apply to this projects.
668 restrict_includes: Whether to constrain the "name" attribute of includes.
669
670 Returns:
671 List of XML nodes.
672 """
655 try: 673 try:
656 root = xml.dom.minidom.parse(path) 674 root = xml.dom.minidom.parse(path)
657 except (OSError, xml.parsers.expat.ExpatError) as e: 675 except (OSError, xml.parsers.expat.ExpatError) as e:
@@ -670,10 +688,11 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
670 for node in manifest.childNodes: 688 for node in manifest.childNodes:
671 if node.nodeName == 'include': 689 if node.nodeName == 'include':
672 name = self._reqatt(node, 'name') 690 name = self._reqatt(node, 'name')
673 msg = self._CheckLocalPath(name) 691 if restrict_includes:
674 if msg: 692 msg = self._CheckLocalPath(name)
675 raise ManifestInvalidPathError( 693 if msg:
676 '<include> invalid "name": %s: %s' % (name, msg)) 694 raise ManifestInvalidPathError(
695 '<include> invalid "name": %s: %s' % (name, msg))
677 include_groups = '' 696 include_groups = ''
678 if parent_groups: 697 if parent_groups:
679 include_groups = parent_groups 698 include_groups = parent_groups
@@ -681,13 +700,13 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
681 include_groups = node.getAttribute('groups') + ',' + include_groups 700 include_groups = node.getAttribute('groups') + ',' + include_groups
682 fp = os.path.join(include_root, name) 701 fp = os.path.join(include_root, name)
683 if not os.path.isfile(fp): 702 if not os.path.isfile(fp):
684 raise ManifestParseError("include %s doesn't exist or isn't a file" 703 raise ManifestParseError("include [%s/]%s doesn't exist or isn't a file"
685 % (name,)) 704 % (include_root, name))
686 try: 705 try:
687 nodes.extend(self._ParseManifestXml(fp, include_root, include_groups)) 706 nodes.extend(self._ParseManifestXml(fp, include_root, include_groups))
688 # should isolate this to the exact exception, but that's 707 # should isolate this to the exact exception, but that's
689 # tricky. actual parsing implementation may vary. 708 # tricky. actual parsing implementation may vary.
690 except (KeyboardInterrupt, RuntimeError, SystemExit): 709 except (KeyboardInterrupt, RuntimeError, SystemExit, ManifestParseError):
691 raise 710 raise
692 except Exception as e: 711 except Exception as e:
693 raise ManifestParseError( 712 raise ManifestParseError(
diff --git a/tests/test_manifest_xml.py b/tests/test_manifest_xml.py
index f69e9cf8..6977b417 100644
--- a/tests/test_manifest_xml.py
+++ b/tests/test_manifest_xml.py
@@ -298,8 +298,8 @@ class IncludeElementTests(ManifestParseTestCase):
298 # Check level2 proj group not removed. 298 # Check level2 proj group not removed.
299 self.assertIn('l2g1', proj.groups) 299 self.assertIn('l2g1', proj.groups)
300 300
301 def test_bad_name_checks(self): 301 def test_allow_bad_name_from_user(self):
302 """Check handling of bad name attribute.""" 302 """Check handling of bad name attribute from the user's input."""
303 def parse(name): 303 def parse(name):
304 manifest = self.getXmlManifest(f""" 304 manifest = self.getXmlManifest(f"""
305<manifest> 305<manifest>
@@ -311,6 +311,34 @@ class IncludeElementTests(ManifestParseTestCase):
311 # Force the manifest to be parsed. 311 # Force the manifest to be parsed.
312 manifest.ToXml() 312 manifest.ToXml()
313 313
314 # Setup target of the include.
315 target = os.path.join(self.tempdir, 'target.xml')
316 with open(target, 'w') as fp:
317 fp.write('<manifest></manifest>')
318
319 # Include with absolute path.
320 parse(os.path.abspath(target))
321
322 # Include with relative path.
323 parse(os.path.relpath(target, self.manifest_dir))
324
325 def test_bad_name_checks(self):
326 """Check handling of bad name attribute."""
327 def parse(name):
328 # Setup target of the include.
329 with open(os.path.join(self.manifest_dir, 'target.xml'), 'w') as fp:
330 fp.write(f'<manifest><include name="{name}"/></manifest>')
331
332 manifest = self.getXmlManifest("""
333<manifest>
334 <remote name="default-remote" fetch="http://localhost" />
335 <default remote="default-remote" revision="refs/heads/main" />
336 <include name="target.xml" />
337</manifest>
338""")
339 # Force the manifest to be parsed.
340 manifest.ToXml()
341
314 # Handle empty name explicitly because a different codepath rejects it. 342 # Handle empty name explicitly because a different codepath rejects it.
315 with self.assertRaises(error.ManifestParseError): 343 with self.assertRaises(error.ManifestParseError):
316 parse('') 344 parse('')