##// END OF EJS Templates
narrow: prevent removal of ACL-defined excludes
Arun Kulshreshtha -
r52202:9b44b25d stable
parent child Browse files
Show More
@@ -1,160 +1,182 b''
1 1 # narrowwirepeer.py - passes narrow spec with unbundle command
2 2 #
3 3 # Copyright 2017 Google, Inc.
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8
9 from mercurial.i18n import _
10
11 from mercurial.utils import stringutil
12
9 13 from mercurial import (
10 14 bundle2,
11 15 error,
12 16 exchange,
13 17 extensions,
14 18 hg,
15 19 narrowspec,
16 20 wireprototypes,
17 21 wireprotov1peer,
18 22 wireprotov1server,
19 23 )
20 24
21 25 from . import narrowbundle2
22 26
23 27
24 28 def uisetup():
25 29 wireprotov1peer.wirepeer.narrow_widen = peernarrowwiden
26 30
27 31
28 32 def reposetup(repo):
29 33 def wirereposetup(ui, peer):
30 34 def wrapped(orig, cmd, *args, **kwargs):
31 35 if cmd == b'unbundle':
32 36 # TODO: don't blindly add include/exclude wireproto
33 37 # arguments to unbundle.
34 38 include, exclude = repo.narrowpats
35 39 kwargs["includepats"] = b','.join(include)
36 40 kwargs["excludepats"] = b','.join(exclude)
37 41 return orig(cmd, *args, **kwargs)
38 42
39 43 extensions.wrapfunction(peer, '_calltwowaystream', wrapped)
40 44
41 45 hg.wirepeersetupfuncs.append(wirereposetup)
42 46
43 47
44 48 @wireprotov1server.wireprotocommand(
45 49 b'narrow_widen',
46 50 b'oldincludes oldexcludes'
47 51 b' newincludes newexcludes'
48 52 b' commonheads cgversion'
49 53 b' known ellipses',
50 54 permission=b'pull',
51 55 )
52 56 def narrow_widen(
53 57 repo,
54 58 proto,
55 59 oldincludes,
56 60 oldexcludes,
57 61 newincludes,
58 62 newexcludes,
59 63 commonheads,
60 64 cgversion,
61 65 known,
62 66 ellipses,
63 67 ):
64 68 """wireprotocol command to send data when a narrow clone is widen. We will
65 69 be sending a changegroup here.
66 70
67 71 The current set of arguments which are required:
68 72 oldincludes: the old includes of the narrow copy
69 73 oldexcludes: the old excludes of the narrow copy
70 74 newincludes: the new includes of the narrow copy
71 75 newexcludes: the new excludes of the narrow copy
72 76 commonheads: list of heads which are common between the server and client
73 77 cgversion(maybe): the changegroup version to produce
74 78 known: list of nodes which are known on the client (used in ellipses cases)
75 79 ellipses: whether to send ellipses data or not
76 80 """
77 81
78 82 preferuncompressed = False
79 83 try:
80 84
81 85 def splitpaths(data):
82 86 # work around ''.split(',') => ['']
83 87 return data.split(b',') if data else []
84 88
85 oldincludes = splitpaths(oldincludes)
86 newincludes = splitpaths(newincludes)
87 oldexcludes = splitpaths(oldexcludes)
88 newexcludes = splitpaths(newexcludes)
89 oldincludes = set(splitpaths(oldincludes))
90 newincludes = set(splitpaths(newincludes))
91 oldexcludes = set(splitpaths(oldexcludes))
92 newexcludes = set(splitpaths(newexcludes))
89 93
90 94 # enforce narrow acl if set
91 95 if repo.ui.has_section(exchange._NARROWACL_SECTION):
92 exchange.applynarrowacl(repo, {'includepats': newincludes})
96 kwargs = exchange.applynarrowacl(
97 repo, {'includepats': newincludes, 'excludepats': newexcludes}
98 )
99 newincludes = kwargs['includepats']
100 requiredexcludes = kwargs['excludepats'] - newexcludes
101 if requiredexcludes:
102 # XXX: The below code to get the username was copied from exchange.py,
103 # where it is noted that this is technically a layering violation for
104 # assuming the existence of HTTP. Using it anyway to make the error
105 # message consistent with the error message for invalid includes.
106 ui = repo.ui
107 username = ui.shortuser(
108 ui.environ.get(b'REMOTE_USER') or ui.username()
109 )
110 raise error.Abort(
111 _(b"The following excludes cannot be removed for %s: %s")
112 % (username, stringutil.pprint(list(requiredexcludes)))
113 )
114 newexcludes = kwargs['excludepats']
93 115
94 116 # validate the patterns
95 narrowspec.validatepatterns(set(oldincludes))
96 narrowspec.validatepatterns(set(newincludes))
97 narrowspec.validatepatterns(set(oldexcludes))
98 narrowspec.validatepatterns(set(newexcludes))
117 narrowspec.validatepatterns(oldincludes)
118 narrowspec.validatepatterns(newincludes)
119 narrowspec.validatepatterns(oldexcludes)
120 narrowspec.validatepatterns(newexcludes)
99 121
100 122 common = wireprototypes.decodelist(commonheads)
101 123 known = wireprototypes.decodelist(known)
102 124 if ellipses == b'0':
103 125 ellipses = False
104 126 else:
105 127 ellipses = bool(ellipses)
106 128 cgversion = cgversion
107 129
108 130 bundler = bundle2.bundle20(repo.ui)
109 131 newmatch = narrowspec.match(
110 132 repo.root, include=newincludes, exclude=newexcludes
111 133 )
112 134 oldmatch = narrowspec.match(
113 135 repo.root, include=oldincludes, exclude=oldexcludes
114 136 )
115 137 if not ellipses:
116 138 bundle2.widen_bundle(
117 139 bundler,
118 140 repo,
119 141 oldmatch,
120 142 newmatch,
121 143 common,
122 144 known,
123 145 cgversion,
124 146 ellipses,
125 147 )
126 148 else:
127 149 narrowbundle2.generate_ellipses_bundle2_for_widening(
128 150 bundler,
129 151 repo,
130 152 oldmatch,
131 153 newmatch,
132 154 cgversion,
133 155 common,
134 156 known,
135 157 )
136 158 except error.Abort as exc:
137 159 bundler = bundle2.bundle20(repo.ui)
138 160 manargs = [(b'message', exc.message)]
139 161 advargs = []
140 162 if exc.hint is not None:
141 163 advargs.append((b'hint', exc.hint))
142 164 bundler.addpart(bundle2.bundlepart(b'error:abort', manargs, advargs))
143 165 preferuncompressed = True
144 166
145 167 chunks = bundler.getchunks()
146 168 return wireprototypes.streamres(
147 169 gen=chunks, prefer_uncompressed=preferuncompressed
148 170 )
149 171
150 172
151 173 def peernarrowwiden(remote, **kwargs):
152 174 for ch in ('commonheads', 'known'):
153 175 kwargs[ch] = wireprototypes.encodelist(kwargs[ch])
154 176
155 177 for ch in ('oldincludes', 'newincludes', 'oldexcludes', 'newexcludes'):
156 178 kwargs[ch] = b','.join(kwargs[ch])
157 179
158 180 kwargs['ellipses'] = b'%i' % bool(kwargs['ellipses'])
159 181 f = remote._callcompressable(b'narrow_widen', **kwargs)
160 182 return bundle2.getunbundler(remote.ui, f)
@@ -1,81 +1,75 b''
1 1 Test exclusion-based ACL enforcement
2 2 $ . "$TESTDIR/narrow-library.sh"
3 3
4 4 $ hg init master
5 5 $ cd master
6 6
7 7 $ for x in `$TESTDIR/seq.py 3`; do
8 8 > echo $x > "f$x"
9 9 > hg add "f$x"
10 10 > hg commit -m "Add $x"
11 11 > done
12 12 $ cat >> .hg/hgrc << EOF
13 13 > [narrowacl]
14 14 > default.includes=*
15 15 > default.excludes=f2 f3
16 16 > test.excludes=f3
17 17 > EOF
18 18 $ hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid
19 19 $ cat hg.pid >> "$DAEMON_PIDS"
20 20
21 21 $ cd ..
22 22 $ hg clone http://localhost:$HGPORT1 narrowclone1
23 23 requesting all changes
24 24 adding changesets
25 25 adding manifests
26 26 adding file changes
27 27 added 3 changesets with 2 changes to 2 files
28 28 new changesets * (glob)
29 29 updating to branch default
30 30 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
31 31
32 32 The clone directory should only contain f1 and f2
33 33 $ ls -A -1 narrowclone1 | sort
34 34 .hg
35 35 f1
36 36 f2
37 37
38 38 Requirements should contain narrowhg
39 39 $ hg debugrequires -R narrowclone1 | grep narrowhg
40 40 narrowhg-experimental
41 41
42 42 NarrowHG should exclude f3.
43 43 $ hg -R narrowclone1 tracked
44 44 I path:.
45 45 X path:f3
46 46
47 47 Narrow should not be able to widen to include f3
48 48 $ hg -R narrowclone1 tracked --addinclude f3
49 49 comparing with http://localhost:$HGPORT1/
50 50 searching for changes
51 51 adding changesets
52 52 adding manifests
53 53 adding file changes
54 54 $ ls -A -1 narrowclone1 | sort
55 55 .hg
56 56 f1
57 57 f2
58 58 $ hg -R narrowclone1 tracked
59 59 I path:.
60 60 X path:f3
61 61
62 62
63 63 Narrow should not be able to remove the exclusion for f3
64 64 $ hg -R narrowclone1 tracked --removeexclude f3
65 65 comparing with http://localhost:$HGPORT1/
66 66 searching for changes
67 adding changesets
68 adding manifests
69 adding file changes
70 added 0 changesets with 1 changes to 1 files
67 abort: The following excludes cannot be removed for test: ['path:f3']
68 [255]
71 69 $ ls -A -1 narrowclone1 | sort
72 70 .hg
73 71 f1
74 72 f2
75 f3
76 73 $ hg -R narrowclone1 tracked
77 74 I path:.
78
79
80 XXX: BUG! This test demonstrates that we are presently
81 able to gain access to f3 by removing the exclusion.
75 X path:f3
General Comments 0
You need to be logged in to leave comments. Login now