summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Frysinger <vapier@google.com>2021-03-10 23:35:44 -0500
committerMike Frysinger <vapier@google.com>2021-03-12 16:31:14 +0000
commit0458faa502e9992a4305bfbb282fbee344d505bf (patch)
treea91a10bd124b06c55c3a8ca522143d810070d1a6
parent68d5d4dfe5375be53f935c8b72060a56801dda24 (diff)
downloadgit-repo-0458faa502e9992a4305bfbb282fbee344d505bf.tar.gz
manifest: allow toplevel project checkoutsv2.13.5
Re-allow checking out projects to the top of the repo client checkout. We add checks to prevent checking out files under .repo/ as that path is only managed by us, and projects cannot inject content or settings into it. Bug: https://crbug.com/gerrit/14156 Bug: https://crbug.com/gerrit/14200 Change-Id: Id6bf9e882f5be748442b2c35bbeaee3549410b25 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/299623 Reviewed-by: Michael Mortensen <mmortensen@google.com> Tested-by: Mike Frysinger <vapier@google.com>
-rw-r--r--manifest_xml.py7
-rw-r--r--project.py12
-rw-r--r--tests/test_manifest_xml.py30
3 files changed, 45 insertions, 4 deletions
diff --git a/manifest_xml.py b/manifest_xml.py
index 6d8fca1d..d67ba72d 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -1039,7 +1039,8 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
1039 if not path: 1039 if not path:
1040 path = name 1040 path = name
1041 else: 1041 else:
1042 msg = self._CheckLocalPath(path, dir_ok=True) 1042 # NB: The "." project is handled specially in Project.Sync_LocalHalf.
1043 msg = self._CheckLocalPath(path, dir_ok=True, cwd_dot_ok=True)
1043 if msg: 1044 if msg:
1044 raise ManifestInvalidPathError( 1045 raise ManifestInvalidPathError(
1045 '<project> invalid "path": %s: %s' % (path, msg)) 1046 '<project> invalid "path": %s: %s' % (path, msg))
@@ -1227,7 +1228,9 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
1227 # our constructed logic here. Especially since manifest authors only use 1228 # our constructed logic here. Especially since manifest authors only use
1228 # / in their paths. 1229 # / in their paths.
1229 resep = re.compile(r'[/%s]' % re.escape(os.path.sep)) 1230 resep = re.compile(r'[/%s]' % re.escape(os.path.sep))
1230 parts = resep.split(path) 1231 # Strip off trailing slashes as those only produce '' elements, and we use
1232 # parts to look for individual bad components.
1233 parts = resep.split(path.rstrip('/'))
1231 1234
1232 # Some people use src="." to create stable links to projects. Lets allow 1235 # Some people use src="." to create stable links to projects. Lets allow
1233 # that but reject all other uses of "." to keep things simple. 1236 # that but reject all other uses of "." to keep things simple.
diff --git a/project.py b/project.py
index bc385f20..2567c57d 100644
--- a/project.py
+++ b/project.py
@@ -1227,6 +1227,18 @@ class Project(object):
1227 self.CleanPublishedCache(all_refs) 1227 self.CleanPublishedCache(all_refs)
1228 revid = self.GetRevisionId(all_refs) 1228 revid = self.GetRevisionId(all_refs)
1229 1229
1230 # Special case the root of the repo client checkout. Make sure it doesn't
1231 # contain files being checked out to dirs we don't allow.
1232 if self.relpath == '.':
1233 PROTECTED_PATHS = {'.repo'}
1234 paths = set(self.work_git.ls_tree('-z', '--name-only', '--', revid).split('\0'))
1235 bad_paths = paths & PROTECTED_PATHS
1236 if bad_paths:
1237 syncbuf.fail(self,
1238 'Refusing to checkout project that writes to protected '
1239 'paths: %s' % (', '.join(bad_paths),))
1240 return
1241
1230 def _doff(): 1242 def _doff():
1231 self._FastForward(revid) 1243 self._FastForward(revid)
1232 self._CopyAndLinkFiles() 1244 self._CopyAndLinkFiles()
diff --git a/tests/test_manifest_xml.py b/tests/test_manifest_xml.py
index 9060ef3d..eda06968 100644
--- a/tests/test_manifest_xml.py
+++ b/tests/test_manifest_xml.py
@@ -32,6 +32,7 @@ INVALID_FS_PATHS = (
32 '..', 32 '..',
33 '../', 33 '../',
34 './', 34 './',
35 './/',
35 'foo/', 36 'foo/',
36 './foo', 37 './foo',
37 '../foo', 38 '../foo',
@@ -427,6 +428,28 @@ class ProjectElementTests(ManifestParseTestCase):
427 self.assertEqual(manifest.projects[0].objdir, 428 self.assertEqual(manifest.projects[0].objdir,
428 os.path.join(self.tempdir, '.repo/project-objects/a/path.git')) 429 os.path.join(self.tempdir, '.repo/project-objects/a/path.git'))
429 430
431 manifest = parse('a/path', 'foo//////')
432 self.assertEqual(manifest.projects[0].gitdir,
433 os.path.join(self.tempdir, '.repo/projects/foo.git'))
434 self.assertEqual(manifest.projects[0].objdir,
435 os.path.join(self.tempdir, '.repo/project-objects/a/path.git'))
436
437 def test_toplevel_path(self):
438 """Check handling of path=. specially."""
439 def parse(name, path):
440 return self.getXmlManifest(f"""
441<manifest>
442 <remote name="default-remote" fetch="http://localhost" />
443 <default remote="default-remote" revision="refs/heads/main" />
444 <project name="{name}" path="{path}" />
445</manifest>
446""")
447
448 for path in ('.', './', './/', './//'):
449 manifest = parse('server/path', path)
450 self.assertEqual(manifest.projects[0].gitdir,
451 os.path.join(self.tempdir, '.repo/projects/..git'))
452
430 def test_bad_path_name_checks(self): 453 def test_bad_path_name_checks(self):
431 """Check handling of bad path & name attributes.""" 454 """Check handling of bad path & name attributes."""
432 def parse(name, path): 455 def parse(name, path):
@@ -454,8 +477,11 @@ class ProjectElementTests(ManifestParseTestCase):
454 477
455 with self.assertRaises(error.ManifestInvalidPathError): 478 with self.assertRaises(error.ManifestInvalidPathError):
456 parse(path, 'ok') 479 parse(path, 'ok')
457 with self.assertRaises(error.ManifestInvalidPathError): 480
458 parse('ok', path) 481 # We have a dedicated test for path=".".
482 if path not in {'.'}:
483 with self.assertRaises(error.ManifestInvalidPathError):
484 parse('ok', path)
459 485
460 486
461class SuperProjectElementTests(ManifestParseTestCase): 487class SuperProjectElementTests(ManifestParseTestCase):