mirror of
https://gerrit.googlesource.com/git-repo
synced 2024-12-21 07:16:21 +00:00
manifest: allow toplevel project checkouts
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>
This commit is contained in:
parent
68d5d4dfe5
commit
0458faa502
@ -1039,7 +1039,8 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
if not path:
|
if not path:
|
||||||
path = name
|
path = name
|
||||||
else:
|
else:
|
||||||
msg = self._CheckLocalPath(path, dir_ok=True)
|
# NB: The "." project is handled specially in Project.Sync_LocalHalf.
|
||||||
|
msg = self._CheckLocalPath(path, dir_ok=True, cwd_dot_ok=True)
|
||||||
if msg:
|
if msg:
|
||||||
raise ManifestInvalidPathError(
|
raise ManifestInvalidPathError(
|
||||||
'<project> invalid "path": %s: %s' % (path, msg))
|
'<project> invalid "path": %s: %s' % (path, msg))
|
||||||
@ -1227,7 +1228,9 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
# our constructed logic here. Especially since manifest authors only use
|
# our constructed logic here. Especially since manifest authors only use
|
||||||
# / in their paths.
|
# / in their paths.
|
||||||
resep = re.compile(r'[/%s]' % re.escape(os.path.sep))
|
resep = re.compile(r'[/%s]' % re.escape(os.path.sep))
|
||||||
parts = resep.split(path)
|
# Strip off trailing slashes as those only produce '' elements, and we use
|
||||||
|
# parts to look for individual bad components.
|
||||||
|
parts = resep.split(path.rstrip('/'))
|
||||||
|
|
||||||
# Some people use src="." to create stable links to projects. Lets allow
|
# Some people use src="." to create stable links to projects. Lets allow
|
||||||
# that but reject all other uses of "." to keep things simple.
|
# that but reject all other uses of "." to keep things simple.
|
||||||
|
12
project.py
12
project.py
@ -1227,6 +1227,18 @@ class Project(object):
|
|||||||
self.CleanPublishedCache(all_refs)
|
self.CleanPublishedCache(all_refs)
|
||||||
revid = self.GetRevisionId(all_refs)
|
revid = self.GetRevisionId(all_refs)
|
||||||
|
|
||||||
|
# Special case the root of the repo client checkout. Make sure it doesn't
|
||||||
|
# contain files being checked out to dirs we don't allow.
|
||||||
|
if self.relpath == '.':
|
||||||
|
PROTECTED_PATHS = {'.repo'}
|
||||||
|
paths = set(self.work_git.ls_tree('-z', '--name-only', '--', revid).split('\0'))
|
||||||
|
bad_paths = paths & PROTECTED_PATHS
|
||||||
|
if bad_paths:
|
||||||
|
syncbuf.fail(self,
|
||||||
|
'Refusing to checkout project that writes to protected '
|
||||||
|
'paths: %s' % (', '.join(bad_paths),))
|
||||||
|
return
|
||||||
|
|
||||||
def _doff():
|
def _doff():
|
||||||
self._FastForward(revid)
|
self._FastForward(revid)
|
||||||
self._CopyAndLinkFiles()
|
self._CopyAndLinkFiles()
|
||||||
|
@ -32,6 +32,7 @@ INVALID_FS_PATHS = (
|
|||||||
'..',
|
'..',
|
||||||
'../',
|
'../',
|
||||||
'./',
|
'./',
|
||||||
|
'.//',
|
||||||
'foo/',
|
'foo/',
|
||||||
'./foo',
|
'./foo',
|
||||||
'../foo',
|
'../foo',
|
||||||
@ -427,6 +428,28 @@ class ProjectElementTests(ManifestParseTestCase):
|
|||||||
self.assertEqual(manifest.projects[0].objdir,
|
self.assertEqual(manifest.projects[0].objdir,
|
||||||
os.path.join(self.tempdir, '.repo/project-objects/a/path.git'))
|
os.path.join(self.tempdir, '.repo/project-objects/a/path.git'))
|
||||||
|
|
||||||
|
manifest = parse('a/path', 'foo//////')
|
||||||
|
self.assertEqual(manifest.projects[0].gitdir,
|
||||||
|
os.path.join(self.tempdir, '.repo/projects/foo.git'))
|
||||||
|
self.assertEqual(manifest.projects[0].objdir,
|
||||||
|
os.path.join(self.tempdir, '.repo/project-objects/a/path.git'))
|
||||||
|
|
||||||
|
def test_toplevel_path(self):
|
||||||
|
"""Check handling of path=. specially."""
|
||||||
|
def parse(name, path):
|
||||||
|
return self.getXmlManifest(f"""
|
||||||
|
<manifest>
|
||||||
|
<remote name="default-remote" fetch="http://localhost" />
|
||||||
|
<default remote="default-remote" revision="refs/heads/main" />
|
||||||
|
<project name="{name}" path="{path}" />
|
||||||
|
</manifest>
|
||||||
|
""")
|
||||||
|
|
||||||
|
for path in ('.', './', './/', './//'):
|
||||||
|
manifest = parse('server/path', path)
|
||||||
|
self.assertEqual(manifest.projects[0].gitdir,
|
||||||
|
os.path.join(self.tempdir, '.repo/projects/..git'))
|
||||||
|
|
||||||
def test_bad_path_name_checks(self):
|
def test_bad_path_name_checks(self):
|
||||||
"""Check handling of bad path & name attributes."""
|
"""Check handling of bad path & name attributes."""
|
||||||
def parse(name, path):
|
def parse(name, path):
|
||||||
@ -454,8 +477,11 @@ class ProjectElementTests(ManifestParseTestCase):
|
|||||||
|
|
||||||
with self.assertRaises(error.ManifestInvalidPathError):
|
with self.assertRaises(error.ManifestInvalidPathError):
|
||||||
parse(path, 'ok')
|
parse(path, 'ok')
|
||||||
with self.assertRaises(error.ManifestInvalidPathError):
|
|
||||||
parse('ok', path)
|
# We have a dedicated test for path=".".
|
||||||
|
if path not in {'.'}:
|
||||||
|
with self.assertRaises(error.ManifestInvalidPathError):
|
||||||
|
parse('ok', path)
|
||||||
|
|
||||||
|
|
||||||
class SuperProjectElementTests(ManifestParseTestCase):
|
class SuperProjectElementTests(ManifestParseTestCase):
|
||||||
|
Loading…
Reference in New Issue
Block a user