diff --git a/mercurial/narrowspec.py b/mercurial/narrowspec.py --- a/mercurial/narrowspec.py +++ b/mercurial/narrowspec.py @@ -20,6 +20,15 @@ FILENAME = 'narrowspec' +# Pattern prefixes that are allowed in narrow patterns. This list MUST +# only contain patterns that are fast and safe to evaluate. Keep in mind +# that patterns are supplied by clients and executed on remote servers +# as part of wire protocol commands. +VALID_PREFIXES = ( + b'path:', + b'rootfilesin:', +) + def parseserverpatterns(text): """Parses the narrowspec format that's returned by the server.""" includepats = set() @@ -82,8 +91,43 @@ return '%s:%s' % normalizesplitpattern(kind, pat) def parsepatterns(pats): - """Parses a list of patterns into a typed pattern set.""" - return set(normalizepattern(p) for p in pats) + """Parses a list of patterns into a typed pattern set. + + Patterns are assumed to be ``path:`` if no prefix is present. + For safety and performance reasons, only the ``path:`` and + ``rootfilesin:`` prefixes are allowed. + """ + res = set() + + for orig in pats: + pat = normalizepattern(orig) + + if not pat.startswith(VALID_PREFIXES): + raise error.Abort(_('narrow pattern must begin with the following ' + 'prefixes: %s; got %s') % ( + ', '.join(VALID_PREFIXES), orig)) + + res.add(pat) + + return res + +def validatepatterns(pats): + """Validate that patterns are in the expected data structure and format. + + And that is a set of normalized patterns beginning with ``path:`` or + ``rootfilesin:``. + """ + if not isinstance(pats, set): + raise error.ProgrammingError('narrow patterns should be a set; ' + 'got %r' % pats) + + for pat in pats: + if not pat.startswith(VALID_PREFIXES): + # Use a Mercurial exception because this can happen due to user + # bugs (e.g. manually updating spec file). + raise error.Abort(_('narrow pattern must begin with the following ' + 'prefixes: %s; got %s') % ( + ', '.join(VALID_PREFIXES), pat)) def format(includes, excludes): output = '[include]\n' diff --git a/tests/test-narrow-clone.t b/tests/test-narrow-clone.t --- a/tests/test-narrow-clone.t +++ b/tests/test-narrow-clone.t @@ -16,6 +16,18 @@ $ for x in `$TESTDIR/seq.py 20`; do echo $x > "t$x"; hg add "t$x"; hg commit -m "Commit test $x"; done $ cd ../../.. +Only path: and rootfilesin: pattern prefixes are allowed + + $ hg clone --narrow ssh://user@dummy/master badnarrow --noupdate --include 'glob:**' + requesting all changes + abort: narrow pattern must begin with the following prefixes: path:, rootfilesin:; got glob:** + [255] + + $ hg clone --narrow ssh://user@dummy/master badnarrow --noupdate --exclude 'set:ignored' + requesting all changes + abort: narrow pattern must begin with the following prefixes: path:, rootfilesin:; got set:ignored + [255] + narrow clone a file, f10 $ hg clone --narrow ssh://user@dummy/master narrow --noupdate --include "dir/src/f10" @@ -254,3 +266,16 @@ I path:dir/tests I path:file:dir/src/f12 $ cd .. + +Narrow spec with invalid patterns is rejected + + $ cat > narrowspecs < [include] + > glob:** + > EOF + + $ hg clone ssh://user@dummy/master badspecfile --narrowspec narrowspecs + reading narrowspec from '$TESTTMP/narrowspecs' + requesting all changes + abort: narrow pattern must begin with the following prefixes: path:, rootfilesin:; got glob:** + [255] diff --git a/tests/test-narrow-patterns.t b/tests/test-narrow-patterns.t --- a/tests/test-narrow-patterns.t +++ b/tests/test-narrow-patterns.t @@ -427,3 +427,13 @@ | o 0 2a4f0c3b67da... root + +Illegal patterns are rejected + + $ hg tracked --addinclude glob:** + abort: narrow pattern must begin with the following prefixes: path:, rootfilesin:; got glob:** + [255] + + $ hg tracked --addexclude set:ignored + abort: narrow pattern must begin with the following prefixes: path:, rootfilesin:; got set:ignored + [255]