##// END OF EJS Templates
sslutil: require TLS 1.1+ when supported...
sslutil: require TLS 1.1+ when supported Currently, Mercurial will use TLS 1.0 or newer when connecting to remote servers, selecting the highest TLS version supported by both peers. On older Pythons, only TLS 1.0 is available. On newer Pythons, TLS 1.1 and 1.2 should be available. Security professionals recommend avoiding TLS 1.0 if possible. PCI DSS 3.1 "strongly encourages" the use of TLS 1.2. Known attacks like BEAST and POODLE exist against TLS 1.0 (although mitigations are available and properly configured servers aren't vulnerable). I asked Eric Rescorla - Mozilla's resident crypto expert - whether Mercurial should drop support for TLS 1.0. His response was "if you can get away with it." Essentially, a number of servers on the Internet don't support TLS 1.1+. This is why web browsers continue to support TLS 1.0 despite desires from security experts. This patch changes Mercurial's default behavior on modern Python versions to require TLS 1.1+, thus avoiding known security issues with TLS 1.0 and making Mercurial more secure by default. Rather than drop TLS 1.0 support wholesale, we still allow TLS 1.0 to be used if configured. This is a compromise solution - ideally we'd disallow TLS 1.0. However, since we're not sure how many Mercurial servers don't support TLS 1.1+ and we're not sure how much user inconvenience this change will bring, I think it is prudent to ship an escape hatch that still allows usage of TLS 1.0. In the default case our users get better security. In the worst case, they are no worse off than before this patch. This patch has no effect when running on Python versions that don't support TLS 1.1+. As the added test shows, connecting to a server that doesn't support TLS 1.1+ will display a warning message with a link to our wiki, where we can guide people to configure their client to allow less secure connections.

File last commit:

r28774:21a507f9 default
r29560:303e9300 default
Show More
test-ancestor.py
262 lines | 8.2 KiB | text/x-python | PythonLexer
Robert Stanca
py3: use print_function in test-ancestor.py
r28723 from __future__ import absolute_import, print_function
Gregory Szorc
tests/test-ancestor: use absolute_import
r27280
import binascii
import getopt
import math
import os
import random
import sys
import time
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 from mercurial.node import nullrev
Gregory Szorc
tests/test-ancestor: use absolute_import
r27280 from mercurial import (
ancestor,
commands,
hg,
Yuya Nishihara
tests: alias ui as uimod in test-ancestor
r28774 ui as uimod,
Gregory Szorc
tests/test-ancestor: use absolute_import
r27280 util,
)
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331
def buildgraph(rng, nodes=100, rootprob=0.05, mergeprob=0.2, prevprob=0.7):
'''nodes: total number of nodes in the graph
rootprob: probability that a new node (not 0) will be a root
mergeprob: probability that, excluding a root a node will be a merge
prevprob: probability that p1 will be the previous node
return value is a graph represented as an adjacency list.
'''
graph = [None] * nodes
for i in xrange(nodes):
if i == 0 or rng.random() < rootprob:
graph[i] = [nullrev]
elif i == 1:
graph[i] = [0]
elif rng.random() < mergeprob:
if i == 2 or rng.random() < prevprob:
# p1 is prev
p1 = i - 1
else:
p1 = rng.randrange(i - 1)
p2 = rng.choice(range(0, p1) + range(p1 + 1, i))
graph[i] = [p1, p2]
elif rng.random() < prevprob:
graph[i] = [i - 1]
else:
graph[i] = [rng.randrange(i - 1)]
return graph
def buildancestorsets(graph):
ancs = [None] * len(graph)
for i in xrange(len(graph)):
ancs[i] = set([i])
if graph[i] == [nullrev]:
continue
for p in graph[i]:
ancs[i].update(ancs[p])
return ancs
Siddharth Agarwal
test-ancestor: move naive missing ancestor algorithm into a class...
r23335 class naiveincrementalmissingancestors(object):
def __init__(self, ancs, bases):
self.ancs = ancs
self.bases = set(bases)
Siddharth Agarwal
ancestor: add a way to add to bases of a missing ancestor object...
r23341 def addbases(self, newbases):
self.bases.update(newbases)
Siddharth Agarwal
ancestor: add a way to remove ancestors of bases from a given set...
r23342 def removeancestorsfrom(self, revs):
for base in self.bases:
if base != nullrev:
revs.difference_update(self.ancs[base])
revs.discard(nullrev)
Siddharth Agarwal
test-ancestor: move naive missing ancestor algorithm into a class...
r23335 def missingancestors(self, revs):
res = set()
for rev in revs:
if rev != nullrev:
res.update(self.ancs[rev])
for base in self.bases:
if base != nullrev:
res.difference_update(self.ancs[base])
return sorted(res)
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331
def test_missingancestors(seed, rng):
# empirically observed to take around 1 second
graphcount = 100
Siddharth Agarwal
test-ancestor: add support for multiple tests against one incremental object...
r23336 testcount = 10
inccount = 10
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 nerrs = [0]
# the default mu and sigma give us a nice distribution of mostly
# single-digit counts (including 0) with some higher ones
def lognormrandom(mu, sigma):
return int(math.floor(rng.lognormvariate(mu, sigma)))
def samplerevs(nodes, mu=1.1, sigma=0.8):
count = min(lognormrandom(mu, sigma), len(nodes))
return rng.sample(nodes, count)
Siddharth Agarwal
test-ancestor: add support for multiple tests against one incremental object...
r23336 def err(seed, graph, bases, seq, output, expected):
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 if nerrs[0] == 0:
Robert Stanca
py3: use print_function in test-ancestor.py
r28723 print('seed:', hex(seed)[:-1], file=sys.stderr)
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 if gerrs[0] == 0:
Robert Stanca
py3: use print_function in test-ancestor.py
r28723 print('graph:', graph, file=sys.stderr)
print('* bases:', bases, file=sys.stderr)
print('* seq: ', seq, file=sys.stderr)
print('* output: ', output, file=sys.stderr)
print('* expected:', expected, file=sys.stderr)
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 nerrs[0] += 1
gerrs[0] += 1
for g in xrange(graphcount):
graph = buildgraph(rng)
ancs = buildancestorsets(graph)
gerrs = [0]
for _ in xrange(testcount):
# start from nullrev to include it as a possibility
graphnodes = range(nullrev, len(graph))
bases = samplerevs(graphnodes)
# fast algorithm
Siddharth Agarwal
ancestor.missingancestors: turn into a state-keeping class...
r23334 inc = ancestor.incrementalmissingancestors(graph.__getitem__, bases)
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 # reference slow algorithm
Siddharth Agarwal
test-ancestor: move naive missing ancestor algorithm into a class...
r23335 naiveinc = naiveincrementalmissingancestors(ancs, bases)
Siddharth Agarwal
test-ancestor: add support for multiple tests against one incremental object...
r23336 seq = []
Siddharth Agarwal
ancestor: add a way to remove ancestors of bases from a given set...
r23342 revs = []
Siddharth Agarwal
test-ancestor: add support for multiple tests against one incremental object...
r23336 for _ in xrange(inccount):
Siddharth Agarwal
ancestor: add a way to add to bases of a missing ancestor object...
r23341 if rng.random() < 0.2:
newbases = samplerevs(graphnodes)
seq.append(('addbases', newbases))
inc.addbases(newbases)
naiveinc.addbases(newbases)
Siddharth Agarwal
ancestor: add a way to remove ancestors of bases from a given set...
r23342 if rng.random() < 0.4:
# larger set so that there are more revs to remove from
revs = samplerevs(graphnodes, mu=1.5)
seq.append(('removeancestorsfrom', revs))
hrevs = set(revs)
rrevs = set(revs)
inc.removeancestorsfrom(hrevs)
naiveinc.removeancestorsfrom(rrevs)
if hrevs != rrevs:
err(seed, graph, bases, seq, sorted(hrevs),
sorted(rrevs))
else:
revs = samplerevs(graphnodes)
seq.append(('missingancestors', revs))
h = inc.missingancestors(revs)
r = naiveinc.missingancestors(revs)
if h != r:
err(seed, graph, bases, seq, h, r)
Siddharth Agarwal
ancestor: move missingancestors doctest out into a separate file...
r18079
# graph is a dict of child->parent adjacency lists for this graph:
# o 13
# |
# | o 12
# | |
# | | o 11
# | | |\
# | | | | o 10
# | | | | |
# | o---+ | 9
# | | | | |
# o | | | | 8
# / / / /
# | | o | 7
# | | | |
# o---+ | 6
# / / /
# | | o 5
# | |/
# | o 4
# | |
# o | 3
# | |
# | o 2
# |/
# o 1
# |
# o 0
graph = {0: [-1], 1: [0], 2: [1], 3: [1], 4: [2], 5: [4], 6: [4],
7: [4], 8: [-1], 9: [6, 7], 10: [5], 11: [3, 7], 12: [9],
13: [8]}
Siddharth Agarwal
ancestor: add lazy membership testing to lazyancestors...
r18091 def genlazyancestors(revs, stoprev=0, inclusive=False):
Robert Stanca
py3: use print_function in test-ancestor.py
r28723 print(("%% lazy ancestor set for %s, stoprev = %s, inclusive = %s" %
(revs, stoprev, inclusive)))
Siddharth Agarwal
ancestor.lazyancestors: take parentrevs function rather than changelog...
r23328 return ancestor.lazyancestors(graph.get, revs, stoprev=stoprev,
Siddharth Agarwal
ancestor: add lazy membership testing to lazyancestors...
r18091 inclusive=inclusive)
def printlazyancestors(s, l):
Robert Stanca
py3: use print_function in test-ancestor.py
r28723 print('membership: %r' % [n for n in l if n in s])
print('iteration: %r' % list(s))
Siddharth Agarwal
ancestor: add lazy membership testing to lazyancestors...
r18091
def test_lazyancestors():
# Empty revs
s = genlazyancestors([])
printlazyancestors(s, [3, 0, -1])
# Standard example
s = genlazyancestors([11, 13])
printlazyancestors(s, [11, 13, 7, 9, 8, 3, 6, 4, 1, -1, 0])
Pierre-Yves David
test-ancestor: add a test for `ancestor` with ancestry within the initset...
r22355 # Standard with ancestry in the initial set (1 is ancestor of 3)
s = genlazyancestors([1, 3])
printlazyancestors(s, [1, -1, 0])
Siddharth Agarwal
ancestor: add lazy membership testing to lazyancestors...
r18091 # Including revs
s = genlazyancestors([11, 13], inclusive=True)
printlazyancestors(s, [11, 13, 7, 9, 8, 3, 6, 4, 1, -1, 0])
# Test with stoprev
s = genlazyancestors([11, 13], stoprev=6)
printlazyancestors(s, [11, 13, 7, 9, 8, 3, 6, 4, 1, -1, 0])
s = genlazyancestors([11, 13], stoprev=6, inclusive=True)
printlazyancestors(s, [11, 13, 7, 9, 8, 3, 6, 4, 1, -1, 0])
Siddharth Agarwal
ancestor.deepest: ignore ninteresting while building result (issue3984)...
r19504
# The C gca algorithm requires a real repo. These are textual descriptions of
Mads Kiilerich
spelling: fixes from spell checker
r21024 # DAGs that have been known to be problematic.
Siddharth Agarwal
ancestor.deepest: ignore ninteresting while building result (issue3984)...
r19504 dagtests = [
'+2*2*2/*3/2',
'+3*3/*2*2/*4*4/*4/2*4/2*2',
]
def test_gca():
Yuya Nishihara
tests: alias ui as uimod in test-ancestor
r28774 u = uimod.ui()
Siddharth Agarwal
ancestor.deepest: ignore ninteresting while building result (issue3984)...
r19504 for i, dag in enumerate(dagtests):
repo = hg.repository(u, 'gca%d' % i, create=1)
cl = repo.changelog
if not util.safehasattr(cl.index, 'ancestors'):
# C version not available
return
commands.debugbuilddag(u, repo, dag)
# Compare the results of the Python and C versions. This does not
# include choosing a winner when more than one gca exists -- we make
# sure both return exactly the same set of gcas.
for a in cl:
for b in cl:
cgcas = sorted(cl.index.ancestors(a, b))
pygcas = sorted(ancestor.ancestors(cl.parentrevs, a, b))
if cgcas != pygcas:
Robert Stanca
py3: use print_function in test-ancestor.py
r28723 print("test_gca: for dag %s, gcas for %d, %d:"
% (dag, a, b))
print(" C returned: %s" % cgcas)
print(" Python returned: %s" % pygcas)
Siddharth Agarwal
ancestor.deepest: ignore ninteresting while building result (issue3984)...
r19504
Siddharth Agarwal
test-ancestor: define a main function...
r23330 def main():
Siddharth Agarwal
test-ancestor: use random testing for missing ancestors...
r23331 seed = None
opts, args = getopt.getopt(sys.argv[1:], 's:', ['seed='])
for o, a in opts:
if o in ('-s', '--seed'):
seed = long(a, base=0) # accepts base 10 or 16 strings
if seed is None:
try:
seed = long(binascii.hexlify(os.urandom(16)), 16)
except AttributeError:
seed = long(time.time() * 1000)
rng = random.Random(seed)
test_missingancestors(seed, rng)
Siddharth Agarwal
ancestor: add lazy membership testing to lazyancestors...
r18091 test_lazyancestors()
Siddharth Agarwal
ancestor.deepest: ignore ninteresting while building result (issue3984)...
r19504 test_gca()
Siddharth Agarwal
test-ancestor: define a main function...
r23330
if __name__ == '__main__':
main()