author | Mahlon E. Smith <mahlon@martini.nu> |
Wed, 31 Oct 2018 13:22:13 -0700 | |
changeset 378 | a788cfad4cfa |
parent 372 | 80f78674c56e |
permissions | -rw-r--r-- |
242
03d8f07230b3
Tidy up file prologues; move credits to CREDITS
Paul Crowley <paul@lshift.net>
parents:
237
diff
changeset
|
1 |
""" |
03d8f07230b3
Tidy up file prologues; move credits to CREDITS
Paul Crowley <paul@lshift.net>
parents:
237
diff
changeset
|
2 |
Glob-based, order-based rules matcher that can answer "maybe" |
03d8f07230b3
Tidy up file prologues; move credits to CREDITS
Paul Crowley <paul@lshift.net>
parents:
237
diff
changeset
|
3 |
where the inputs make clear that something is unknown. |
03d8f07230b3
Tidy up file prologues; move credits to CREDITS
Paul Crowley <paul@lshift.net>
parents:
237
diff
changeset
|
4 |
""" |
18
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
5 |
|
32 | 6 |
import sys |
18
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
7 |
import re |
39
f5055ce263c7
New system. No breaking in, just putting files in /etc/mercurial-server
Paul Crowley <paul@lshift.net>
parents:
33
diff
changeset
|
8 |
import os |
f5055ce263c7
New system. No breaking in, just putting files in /etc/mercurial-server
Paul Crowley <paul@lshift.net>
parents:
33
diff
changeset
|
9 |
import os.path |
18
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
10 |
|
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
11 |
def globmatcher(pattern): |
106
0519745e7a57
Much less strict about most things
Paul Crowley <paul@lshift.net>
parents:
78
diff
changeset
|
12 |
p = "[^/]*".join(re.escape(c) for c in pattern.split("*")) |
0519745e7a57
Much less strict about most things
Paul Crowley <paul@lshift.net>
parents:
78
diff
changeset
|
13 |
# ** means "match recursively" ie "ignore directories" |
237
d30f3f312ece
Handle maybe matches properly
Paul Crowley <paul@lshift.net>
parents:
109
diff
changeset
|
14 |
return re.compile(p.replace("[^/]*[^/]*", ".*") + "$") |
18
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
15 |
|
300
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
16 |
# Returns 1 for a definite match |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
17 |
# -1 for a definite non-match |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
18 |
# 0 where we can't be sure because a key is None |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
19 |
def rmatch(k, m, kw): |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
20 |
if k not in kw: |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
21 |
return -1 |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
22 |
kkw = kw[k] |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
23 |
if kkw is None: |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
24 |
return 0 |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
25 |
elif m.match(kkw) is None: |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
26 |
return -1 |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
27 |
else: |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
28 |
return 1 |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
29 |
|
18
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
30 |
def rule(pairs): |
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
31 |
matchers = [(k, globmatcher(v)) for k, v in pairs] |
48
f0cb7ad9e4ab
Don't use keyword arguments everywhere
Paul Crowley <paul@lshift.net>
parents:
45
diff
changeset
|
32 |
def c(kw): |
300
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
33 |
return min(rmatch(k, m, kw) for k, m in matchers) |
371
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
34 |
c.patterns = [(k, m.pattern) for k, m in matchers] |
18
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
35 |
return c |
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
36 |
|
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
37 |
class Ruleset(object): |
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
38 |
'''Class representing the rules in a rule file''' |
311 | 39 |
|
372
80f78674c56e
Add support for phases
David Douard <david.douard@logilab.fr>
parents:
371
diff
changeset
|
40 |
levels = ["init", "publish", "write", "read", "deny"] |
18
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
41 |
|
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
42 |
def __init__(self): |
48
f0cb7ad9e4ab
Don't use keyword arguments everywhere
Paul Crowley <paul@lshift.net>
parents:
45
diff
changeset
|
43 |
self.rules = [] |
21
59540181a4bb
simplify by allowing some params to be preset in rules
Paul Crowley <paul@ciphergoth.org>
parents:
18
diff
changeset
|
44 |
self.preset = {} |
18
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
45 |
|
21
59540181a4bb
simplify by allowing some params to be preset in rules
Paul Crowley <paul@ciphergoth.org>
parents:
18
diff
changeset
|
46 |
def set(self, **kw): |
59540181a4bb
simplify by allowing some params to be preset in rules
Paul Crowley <paul@ciphergoth.org>
parents:
18
diff
changeset
|
47 |
self.preset.update(kw) |
311 | 48 |
|
78
2a3407a14654
Replaced env vars with Python globals
Paul Crowley <paul@lshift.net>
parents:
77
diff
changeset
|
49 |
def get(self, k): |
2a3407a14654
Replaced env vars with Python globals
Paul Crowley <paul@lshift.net>
parents:
77
diff
changeset
|
50 |
return self.preset.get(k, None) |
300
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
51 |
|
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
52 |
def allow(self, level, **kw): |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
53 |
levelindex = self.levels.index(level) |
21
59540181a4bb
simplify by allowing some params to be preset in rules
Paul Crowley <paul@ciphergoth.org>
parents:
18
diff
changeset
|
54 |
d = self.preset.copy() |
48
f0cb7ad9e4ab
Don't use keyword arguments everywhere
Paul Crowley <paul@lshift.net>
parents:
45
diff
changeset
|
55 |
d.update(kw) |
18
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
56 |
for a, c in self.rules: |
237
d30f3f312ece
Handle maybe matches properly
Paul Crowley <paul@lshift.net>
parents:
109
diff
changeset
|
57 |
m = c(d) |
300
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
58 |
if m == 1: |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
59 |
# Definite match - what it says goes |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
60 |
return a <= levelindex |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
61 |
elif m == 0: |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
62 |
# "Maybe match" - allow if it says yes, ignore if no |
31c2c6b383fd
Refactor ruleset.py so I can be more confident it's correct
Paul Crowley <paul@lshift.net>
parents:
297
diff
changeset
|
63 |
if a <= levelindex: |
237
d30f3f312ece
Handle maybe matches properly
Paul Crowley <paul@lshift.net>
parents:
109
diff
changeset
|
64 |
return True |
d30f3f312ece
Handle maybe matches properly
Paul Crowley <paul@lshift.net>
parents:
109
diff
changeset
|
65 |
return False |
311 | 66 |
|
39
f5055ce263c7
New system. No breaking in, just putting files in /etc/mercurial-server
Paul Crowley <paul@lshift.net>
parents:
33
diff
changeset
|
67 |
def readfile(self, fn): |
237
d30f3f312ece
Handle maybe matches properly
Paul Crowley <paul@lshift.net>
parents:
109
diff
changeset
|
68 |
f = open(fn) |
18
538d6b198f4a
Big change to support file conditions; format of hg-ssh-access.conf
Paul Crowley <paul@lshift.net>
parents:
diff
changeset
|
69 |
try: |
371
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
70 |
self.buildrules(f) |
237
d30f3f312ece
Handle maybe matches properly
Paul Crowley <paul@lshift.net>
parents:
109
diff
changeset
|
71 |
finally: |
d30f3f312ece
Handle maybe matches properly
Paul Crowley <paul@lshift.net>
parents:
109
diff
changeset
|
72 |
f.close() |
32 | 73 |
|
371
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
74 |
def buildrules(self, f): |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
75 |
"""Build rules from f |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
76 |
|
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
77 |
f shoud be iterable per line, each line is like: |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
78 |
|
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
79 |
level [user=pattern] [repo=pattern] [file=pattern] [branch=pattern] |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
80 |
""" |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
81 |
for l in f: |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
82 |
l = l.strip() |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
83 |
if not l or l.startswith("#"): |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
84 |
continue |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
85 |
l = l.split() |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
86 |
# Unrecognized actions are off the high end |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
87 |
if l[0] in self.levels: |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
88 |
ix = self.levels.index(l[0]) |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
89 |
else: |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
90 |
ix = len(self.levels) |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
91 |
self.rules.append((ix, |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
92 |
rule([c.split("=", 1) for c in l[1:]]))) |
e9ce904b62a9
[test] add unit tests for ruleset
David Douard <david.douard@logilab.fr>
parents:
311
diff
changeset
|
93 |
|
77
8d14aac93b5d
Most of the way through abolishing env vars
Paul Crowley <paul@lshift.net>
parents:
67
diff
changeset
|
94 |
rules = Ruleset() |