Compare commits
62 Commits
test-pytho
...
test-bould
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e4bd0389e | ||
|
|
b06187f606 | ||
|
|
9801eef297 | ||
|
|
c04ff72765 | ||
|
|
f4fbed7714 | ||
|
|
30de14453a | ||
|
|
fa93b7e3ef | ||
|
|
45ae50a2be | ||
|
|
2d2e661fdd | ||
|
|
20e7b5c503 | ||
|
|
5e5b88a453 | ||
|
|
4114afb17a | ||
|
|
ef6a71fc13 | ||
|
|
3476c8c6db | ||
|
|
93e0109dba | ||
|
|
0547d2218f | ||
|
|
990c6d3c51 | ||
|
|
115175c658 | ||
|
|
905030c5a1 | ||
|
|
2488c98862 | ||
|
|
d418b1927b | ||
|
|
b50aed41f6 | ||
|
|
2165bfb903 | ||
|
|
fe196c933a | ||
|
|
2b1fc85b69 | ||
|
|
5607721a9b | ||
|
|
cf6b289987 | ||
|
|
0118a65c30 | ||
|
|
4e1b88a34e | ||
|
|
6a9d9e807b | ||
|
|
379f123ce1 | ||
|
|
addee821dd | ||
|
|
2378de966c | ||
|
|
73517cc30a | ||
|
|
cb16115ace | ||
|
|
dd86189c7e | ||
|
|
228c02fae9 | ||
|
|
2bbc62922b | ||
|
|
f56bcc763f | ||
|
|
9357f0dbc7 | ||
|
|
96ffb3cf59 | ||
|
|
811203e526 | ||
|
|
132f08101f | ||
|
|
7b9e811665 | ||
|
|
5e6119d758 | ||
|
|
11e5f72e7e | ||
|
|
2f6c9e4a2c | ||
|
|
25a080db6e | ||
|
|
9cd359ece4 | ||
|
|
65f464efeb | ||
|
|
9885c30fb1 | ||
|
|
af701498f6 | ||
|
|
e2a9adf9e1 | ||
|
|
69fb019663 | ||
|
|
dbb3712236 | ||
|
|
839821920b | ||
|
|
55af6736a1 | ||
|
|
1dc4f5386e | ||
|
|
a6a8c93295 | ||
|
|
16310a019e | ||
|
|
a664bead38 | ||
|
|
de11ec7370 |
155
.travis.yml
155
.travis.yml
@@ -34,98 +34,6 @@ extended-test-suite: &extended-test-suite
|
|||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
# Main test suite
|
|
||||||
- python: "2.7"
|
|
||||||
env: ACME_SERVER=pebble TOXENV=integration
|
|
||||||
sudo: required
|
|
||||||
services: docker
|
|
||||||
<<: *not-on-master
|
|
||||||
|
|
||||||
# This job is always executed, including on master
|
|
||||||
- python: "2.7"
|
|
||||||
env: TOXENV=py27-cover FYI="py27 tests + code coverage"
|
|
||||||
|
|
||||||
- python: "2.7"
|
|
||||||
env: TOXENV=lint
|
|
||||||
<<: *not-on-master
|
|
||||||
- python: "3.4"
|
|
||||||
env: TOXENV=mypy
|
|
||||||
<<: *not-on-master
|
|
||||||
- python: "3.5"
|
|
||||||
env: TOXENV=mypy
|
|
||||||
<<: *not-on-master
|
|
||||||
- python: "2.7"
|
|
||||||
# Ubuntu Trusty or older must be used because the oldest version of
|
|
||||||
# cryptography we support cannot be compiled against the version of
|
|
||||||
# OpenSSL in Xenial or newer.
|
|
||||||
dist: trusty
|
|
||||||
env: TOXENV='py27-{acme,apache,certbot,dns,nginx}-oldest'
|
|
||||||
sudo: required
|
|
||||||
services: docker
|
|
||||||
<<: *not-on-master
|
|
||||||
- python: "3.4"
|
|
||||||
env: TOXENV=py34
|
|
||||||
sudo: required
|
|
||||||
services: docker
|
|
||||||
<<: *not-on-master
|
|
||||||
- python: "3.7"
|
|
||||||
dist: xenial
|
|
||||||
env: TOXENV=py37
|
|
||||||
sudo: required
|
|
||||||
services: docker
|
|
||||||
<<: *not-on-master
|
|
||||||
- sudo: required
|
|
||||||
env: TOXENV=apache_compat
|
|
||||||
services: docker
|
|
||||||
before_install:
|
|
||||||
addons:
|
|
||||||
<<: *not-on-master
|
|
||||||
- sudo: required
|
|
||||||
env: TOXENV=le_auto_xenial
|
|
||||||
services: docker
|
|
||||||
<<: *not-on-master
|
|
||||||
- python: "2.7"
|
|
||||||
env: TOXENV=apacheconftest-with-pebble
|
|
||||||
sudo: required
|
|
||||||
services: docker
|
|
||||||
<<: *not-on-master
|
|
||||||
- python: "2.7"
|
|
||||||
env: TOXENV=nginxroundtrip
|
|
||||||
<<: *not-on-master
|
|
||||||
|
|
||||||
# Extended test suite on cron jobs and pushes to tested branches other than master
|
|
||||||
- sudo: required
|
|
||||||
env: TOXENV=nginx_compat
|
|
||||||
services: docker
|
|
||||||
before_install:
|
|
||||||
addons:
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- python: "2.7"
|
|
||||||
env:
|
|
||||||
- TOXENV=travis-test-farm-apache2
|
|
||||||
- secure: "f+j/Lj9s1lcuKo5sEFrlRd1kIAMnIJI4z0MTI7QF8jl9Fkmbx7KECGzw31TNgzrOSzxSapHbcueFYvNCLKST+kE/8ogMZBbwqXfEDuKpyF6BY3uYoJn+wPVE5pIb8Hhe08xPte8TTDSMIyHI3EyTfcAKrIreauoArePvh/cRvSw="
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- python: "2.7"
|
|
||||||
env:
|
|
||||||
- TOXENV=travis-test-farm-leauto-upgrades
|
|
||||||
- secure: "f+j/Lj9s1lcuKo5sEFrlRd1kIAMnIJI4z0MTI7QF8jl9Fkmbx7KECGzw31TNgzrOSzxSapHbcueFYvNCLKST+kE/8ogMZBbwqXfEDuKpyF6BY3uYoJn+wPVE5pIb8Hhe08xPte8TTDSMIyHI3EyTfcAKrIreauoArePvh/cRvSw="
|
|
||||||
git:
|
|
||||||
depth: false # This is needed to have the history to checkout old versions of certbot-auto.
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- python: "2.7"
|
|
||||||
env:
|
|
||||||
- TOXENV=travis-test-farm-certonly-standalone
|
|
||||||
- secure: "f+j/Lj9s1lcuKo5sEFrlRd1kIAMnIJI4z0MTI7QF8jl9Fkmbx7KECGzw31TNgzrOSzxSapHbcueFYvNCLKST+kE/8ogMZBbwqXfEDuKpyF6BY3uYoJn+wPVE5pIb8Hhe08xPte8TTDSMIyHI3EyTfcAKrIreauoArePvh/cRvSw="
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- python: "2.7"
|
|
||||||
env:
|
|
||||||
- TOXENV=travis-test-farm-sdists
|
|
||||||
- secure: "f+j/Lj9s1lcuKo5sEFrlRd1kIAMnIJI4z0MTI7QF8jl9Fkmbx7KECGzw31TNgzrOSzxSapHbcueFYvNCLKST+kE/8ogMZBbwqXfEDuKpyF6BY3uYoJn+wPVE5pIb8Hhe08xPte8TTDSMIyHI3EyTfcAKrIreauoArePvh/cRvSw="
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- python: "3.7"
|
|
||||||
dist: xenial
|
|
||||||
env: TOXENV=py37 CERTBOT_NO_PIN=1
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- python: "2.7"
|
- python: "2.7"
|
||||||
env: ACME_SERVER=boulder-v1 TOXENV=integration
|
env: ACME_SERVER=boulder-v1 TOXENV=integration
|
||||||
sudo: required
|
sudo: required
|
||||||
@@ -156,19 +64,6 @@ matrix:
|
|||||||
sudo: required
|
sudo: required
|
||||||
services: docker
|
services: docker
|
||||||
<<: *extended-test-suite
|
<<: *extended-test-suite
|
||||||
- python: "3.4"
|
|
||||||
env: TOXENV=py34
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- python: "3.5"
|
|
||||||
env: TOXENV=py35
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- python: "3.6"
|
|
||||||
env: TOXENV=py36
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- python: "3.7"
|
|
||||||
dist: xenial
|
|
||||||
env: TOXENV=py37
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- python: "3.4"
|
- python: "3.4"
|
||||||
env: ACME_SERVER=boulder-v1 TOXENV=integration
|
env: ACME_SERVER=boulder-v1 TOXENV=integration
|
||||||
sudo: required
|
sudo: required
|
||||||
@@ -211,46 +106,6 @@ matrix:
|
|||||||
sudo: required
|
sudo: required
|
||||||
services: docker
|
services: docker
|
||||||
<<: *extended-test-suite
|
<<: *extended-test-suite
|
||||||
- sudo: required
|
|
||||||
env: TOXENV=le_auto_jessie
|
|
||||||
services: docker
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- sudo: required
|
|
||||||
env: TOXENV=le_auto_centos6
|
|
||||||
services: docker
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- sudo: required
|
|
||||||
env: TOXENV=docker_dev
|
|
||||||
services: docker
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages: # don't install nginx and apache
|
|
||||||
- libaugeas0
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- language: generic
|
|
||||||
env: TOXENV=py27
|
|
||||||
os: osx
|
|
||||||
# Using this osx_image is a workaround for
|
|
||||||
# https://travis-ci.community/t/xcode-8-3-homebrew-outdated-error/3798.
|
|
||||||
osx_image: xcode10.2
|
|
||||||
addons:
|
|
||||||
homebrew:
|
|
||||||
packages:
|
|
||||||
- augeas
|
|
||||||
- python2
|
|
||||||
<<: *extended-test-suite
|
|
||||||
- language: generic
|
|
||||||
env: TOXENV=py3
|
|
||||||
os: osx
|
|
||||||
# Using this osx_image is a workaround for
|
|
||||||
# https://travis-ci.community/t/xcode-8-3-homebrew-outdated-error/3798.
|
|
||||||
osx_image: xcode10.2
|
|
||||||
addons:
|
|
||||||
homebrew:
|
|
||||||
packages:
|
|
||||||
- augeas
|
|
||||||
- python3
|
|
||||||
<<: *extended-test-suite
|
|
||||||
|
|
||||||
# container-based infrastructure
|
# container-based infrastructure
|
||||||
sudo: false
|
sudo: false
|
||||||
@@ -280,13 +135,3 @@ after_success: '[ "$TOXENV" == "py27-cover" ] && codecov -F linux'
|
|||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
irc:
|
|
||||||
channels:
|
|
||||||
# This is set to a secure variable to prevent forks from sending
|
|
||||||
# notifications. This value was created by installing
|
|
||||||
# https://github.com/travis-ci/travis.rb and running
|
|
||||||
# `travis encrypt "chat.freenode.net#certbot-devel"`.
|
|
||||||
- secure: "EWW66E2+KVPZyIPR8ViENZwfcup4Gx3/dlimmAZE0WuLwxDCshBBOd3O8Rf6pBokEoZlXM5eDT6XdyJj8n0DLslgjO62pExdunXpbcMwdY7l1ELxX2/UbnDTE6UnPYa09qVBHNG7156Z6yE0x2lH4M9Ykvp0G0cubjPQHylAwo0="
|
|
||||||
on_cancel: never
|
|
||||||
on_success: never
|
|
||||||
on_failure: always
|
|
||||||
|
|||||||
13
appveyor.yml
13
appveyor.yml
@@ -2,8 +2,7 @@ image: Visual Studio 2015
|
|||||||
|
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- TOXENV: py35
|
- TOXENV: integration-certbot
|
||||||
- TOXENV: py37-cover
|
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
@@ -24,14 +23,16 @@ init:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
# Use Python 3.7 by default
|
# Use Python 3.7 by default
|
||||||
- "SET PATH=C:\\Python37;C:\\Python37\\Scripts;%PATH%"
|
- SET PATH=C:\\Python37;C:\\Python37\\Scripts;%PATH%
|
||||||
|
# Using 4 processes is proven to be the most efficient integration tests config for AppVeyor
|
||||||
|
- IF %TOXENV%==integration-certbot SET PYTEST_ADDOPTS=--numprocesses=4
|
||||||
# Check env
|
# Check env
|
||||||
- "python --version"
|
- python --version
|
||||||
# Upgrade pip to avoid warnings
|
# Upgrade pip to avoid warnings
|
||||||
- "python -m pip install --upgrade pip"
|
- python -m pip install --upgrade pip
|
||||||
# Ready to install tox and coverage
|
# Ready to install tox and coverage
|
||||||
# tools/pip_install.py is used to pin packages to a known working version.
|
# tools/pip_install.py is used to pin packages to a known working version.
|
||||||
- "python tools\\pip_install.py tox codecov"
|
- python tools\\pip_install.py tox codecov
|
||||||
|
|
||||||
build: off
|
build: off
|
||||||
|
|
||||||
|
|||||||
11
certbot-ci/certbot_integration_tests/assets/hook.py
Executable file
11
certbot-ci/certbot_integration_tests/assets/hook.py
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
hook_script_type = os.path.basename(os.path.dirname(sys.argv[1]))
|
||||||
|
if hook_script_type == 'deploy' and ('RENEWED_DOMAINS' not in os.environ or 'RENEWED_LINEAGE' not in os.environ):
|
||||||
|
sys.stderr.write('Environment variables not properly set!\n')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(sys.argv[2], 'a') as file_h:
|
||||||
|
file_h.write(hook_script_type + '\n')
|
||||||
@@ -1,6 +1,17 @@
|
|||||||
"""This module contains advanced assertions for the certbot integration tests."""
|
"""This module contains advanced assertions for the certbot integration tests."""
|
||||||
import os
|
import os
|
||||||
import grp
|
try:
|
||||||
|
import grp
|
||||||
|
POSIX_MODE = True
|
||||||
|
except ImportError:
|
||||||
|
import win32api
|
||||||
|
import win32security
|
||||||
|
import ntsecuritycon
|
||||||
|
POSIX_MODE = False
|
||||||
|
|
||||||
|
EVERYBODY_SID = 'S-1-1-0'
|
||||||
|
SYSTEM_SID = 'S-1-5-18'
|
||||||
|
ADMINS_SID = 'S-1-5-32-544'
|
||||||
|
|
||||||
|
|
||||||
def assert_hook_execution(probe_path, probe_content):
|
def assert_hook_execution(probe_path, probe_content):
|
||||||
@@ -10,9 +21,10 @@ def assert_hook_execution(probe_path, probe_content):
|
|||||||
:param probe_content: content expected when the hook is executed
|
:param probe_content: content expected when the hook is executed
|
||||||
"""
|
"""
|
||||||
with open(probe_path, 'r') as file:
|
with open(probe_path, 'r') as file:
|
||||||
lines = file.readlines()
|
data = file.read()
|
||||||
|
|
||||||
assert '{0}{1}'.format(probe_content, os.linesep) in lines
|
lines = [line.strip() for line in data.splitlines()]
|
||||||
|
assert probe_content in lines
|
||||||
|
|
||||||
|
|
||||||
def assert_saved_renew_hook(config_dir, lineage):
|
def assert_saved_renew_hook(config_dir, lineage):
|
||||||
@@ -38,16 +50,51 @@ def assert_cert_count_for_lineage(config_dir, lineage, count):
|
|||||||
assert len(certs) == count
|
assert len(certs) == count
|
||||||
|
|
||||||
|
|
||||||
def assert_equals_permissions(file1, file2, mask):
|
def assert_equals_group_permissions(file1, file2):
|
||||||
"""
|
"""
|
||||||
Assert that permissions on two files are identical in respect to a given umask.
|
Assert that two files have the same permissions for group owner.
|
||||||
:param file1: first file path to compare
|
:param file1: first file path to compare
|
||||||
:param file2: second file path to compare
|
:param file2: second file path to compare
|
||||||
:param mask: 3-octal representation of a POSIX umask under which the two files mode
|
|
||||||
should match (eg. 0o074 will test RWX on group and R on world)
|
|
||||||
"""
|
"""
|
||||||
mode_file1 = os.stat(file1).st_mode & mask
|
# On Windows there is no group, so this assertion does nothing on this platform
|
||||||
mode_file2 = os.stat(file2).st_mode & mask
|
if POSIX_MODE:
|
||||||
|
mode_file1 = os.stat(file1).st_mode & 0o070
|
||||||
|
mode_file2 = os.stat(file2).st_mode & 0o070
|
||||||
|
|
||||||
|
assert mode_file1 == mode_file2
|
||||||
|
|
||||||
|
|
||||||
|
def assert_equals_world_read_permissions(file1, file2):
|
||||||
|
"""
|
||||||
|
Assert that two files have the same read permissions for everyone.
|
||||||
|
:param file1: first file path to compare
|
||||||
|
:param file2: second file path to compare
|
||||||
|
"""
|
||||||
|
if POSIX_MODE:
|
||||||
|
mode_file1 = os.stat(file1).st_mode & 0o004
|
||||||
|
mode_file2 = os.stat(file2).st_mode & 0o004
|
||||||
|
else:
|
||||||
|
everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID)
|
||||||
|
|
||||||
|
security1 = win32security.GetFileSecurity(file1, win32security.DACL_SECURITY_INFORMATION)
|
||||||
|
dacl1 = security1.GetSecurityDescriptorDacl()
|
||||||
|
|
||||||
|
mode_file1 = dacl1.GetEffectiveRightsFromAcl({
|
||||||
|
'TrusteeForm': win32security.TRUSTEE_IS_SID,
|
||||||
|
'TrusteeType': win32security.TRUSTEE_IS_USER,
|
||||||
|
'Identifier': everybody,
|
||||||
|
})
|
||||||
|
mode_file1 = mode_file1 & ntsecuritycon.FILE_GENERIC_READ
|
||||||
|
|
||||||
|
security2 = win32security.GetFileSecurity(file2, win32security.DACL_SECURITY_INFORMATION)
|
||||||
|
dacl2 = security2.GetSecurityDescriptorDacl()
|
||||||
|
|
||||||
|
mode_file2 = dacl2.GetEffectiveRightsFromAcl({
|
||||||
|
'TrusteeForm': win32security.TRUSTEE_IS_SID,
|
||||||
|
'TrusteeType': win32security.TRUSTEE_IS_USER,
|
||||||
|
'Identifier': everybody,
|
||||||
|
})
|
||||||
|
mode_file2 = mode_file2 & ntsecuritycon.FILE_GENERIC_READ
|
||||||
|
|
||||||
assert mode_file1 == mode_file2
|
assert mode_file1 == mode_file2
|
||||||
|
|
||||||
@@ -57,20 +104,57 @@ def assert_equals_group_owner(file1, file2):
|
|||||||
Assert that two files have the same group owner.
|
Assert that two files have the same group owner.
|
||||||
:param file1: first file path to compare
|
:param file1: first file path to compare
|
||||||
:param file2: second file path to compare
|
:param file2: second file path to compare
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
group_owner_file1 = grp.getgrgid(os.stat(file1).st_gid)[0]
|
# On Windows there is no group, so this assertion does nothing on this platform
|
||||||
group_owner_file2 = grp.getgrgid(os.stat(file2).st_gid)[0]
|
if POSIX_MODE:
|
||||||
|
group_owner_file1 = grp.getgrgid(os.stat(file1).st_gid)[0]
|
||||||
|
group_owner_file2 = grp.getgrgid(os.stat(file2).st_gid)[0]
|
||||||
|
|
||||||
assert group_owner_file1 == group_owner_file2
|
assert group_owner_file1 == group_owner_file2
|
||||||
|
|
||||||
|
|
||||||
def assert_world_permissions(file, mode):
|
def assert_world_no_permissions(file):
|
||||||
"""
|
"""
|
||||||
Assert that a file has the expected world permission.
|
Assert that the given file is not world-readable.
|
||||||
:param file: file path to check
|
:param file: path of the file to check
|
||||||
:param mode: world permissions mode expected
|
|
||||||
"""
|
"""
|
||||||
mode_file_all = os.stat(file).st_mode & 0o007
|
if POSIX_MODE:
|
||||||
|
mode_file_all = os.stat(file).st_mode & 0o007
|
||||||
|
assert mode_file_all == 0
|
||||||
|
else:
|
||||||
|
security = win32security.GetFileSecurity(file, win32security.DACL_SECURITY_INFORMATION)
|
||||||
|
dacl = security.GetSecurityDescriptorDacl()
|
||||||
|
mode = dacl.GetEffectiveRightsFromAcl({
|
||||||
|
'TrusteeForm': win32security.TRUSTEE_IS_SID,
|
||||||
|
'TrusteeType': win32security.TRUSTEE_IS_USER,
|
||||||
|
'Identifier': win32security.ConvertStringSidToSid(EVERYBODY_SID),
|
||||||
|
})
|
||||||
|
|
||||||
assert mode_file_all == mode
|
assert not mode
|
||||||
|
|
||||||
|
|
||||||
|
def assert_world_read_permissions(file):
|
||||||
|
"""
|
||||||
|
Assert that the given file is world-readable, but not world-writable or world-executable.
|
||||||
|
:param file: path of the file to check
|
||||||
|
"""
|
||||||
|
if POSIX_MODE:
|
||||||
|
mode_file_all = os.stat(file).st_mode & 0o007
|
||||||
|
assert mode_file_all == 4
|
||||||
|
else:
|
||||||
|
security = win32security.GetFileSecurity(file, win32security.DACL_SECURITY_INFORMATION)
|
||||||
|
dacl = security.GetSecurityDescriptorDacl()
|
||||||
|
mode = dacl.GetEffectiveRightsFromAcl({
|
||||||
|
'TrusteeForm': win32security.TRUSTEE_IS_SID,
|
||||||
|
'TrusteeType': win32security.TRUSTEE_IS_USER,
|
||||||
|
'Identifier': win32security.ConvertStringSidToSid(EVERYBODY_SID),
|
||||||
|
})
|
||||||
|
|
||||||
|
assert not mode & ntsecuritycon.FILE_GENERIC_WRITE
|
||||||
|
assert not mode & ntsecuritycon.FILE_GENERIC_EXECUTE
|
||||||
|
assert mode & ntsecuritycon.FILE_GENERIC_READ == ntsecuritycon.FILE_GENERIC_READ
|
||||||
|
|
||||||
|
|
||||||
|
def _get_current_user():
|
||||||
|
account_name = win32api.GetUserNameEx(win32api.NameSamCompatible)
|
||||||
|
return win32security.LookupAccountName(None, account_name)[0]
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
"""Module to handle the context of integration tests."""
|
"""Module to handle the context of integration tests."""
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
@@ -30,7 +31,10 @@ class IntegrationTestsContext(object):
|
|||||||
|
|
||||||
self.workspace = tempfile.mkdtemp()
|
self.workspace = tempfile.mkdtemp()
|
||||||
self.config_dir = os.path.join(self.workspace, 'conf')
|
self.config_dir = os.path.join(self.workspace, 'conf')
|
||||||
self.hook_probe = tempfile.mkstemp(dir=self.workspace)[1]
|
|
||||||
|
probe = tempfile.mkstemp(dir=self.workspace)
|
||||||
|
os.close(probe[0])
|
||||||
|
self.hook_probe = probe[1]
|
||||||
|
|
||||||
self.manual_dns_auth_hook = (
|
self.manual_dns_auth_hook = (
|
||||||
'{0} -c "import os; import requests; import json; '
|
'{0} -c "import os; import requests; import json; '
|
||||||
|
|||||||
@@ -11,8 +11,11 @@ from os.path import join, exists
|
|||||||
import pytest
|
import pytest
|
||||||
from certbot_integration_tests.certbot_tests import context as certbot_context
|
from certbot_integration_tests.certbot_tests import context as certbot_context
|
||||||
from certbot_integration_tests.certbot_tests.assertions import (
|
from certbot_integration_tests.certbot_tests.assertions import (
|
||||||
assert_hook_execution, assert_saved_renew_hook, assert_cert_count_for_lineage,
|
assert_hook_execution, assert_saved_renew_hook,
|
||||||
assert_world_permissions, assert_equals_group_owner, assert_equals_permissions,
|
assert_cert_count_for_lineage,
|
||||||
|
assert_world_no_permissions, assert_world_read_permissions,
|
||||||
|
assert_equals_group_owner, assert_equals_group_permissions, assert_equals_world_read_permissions,
|
||||||
|
EVERYBODY_SID
|
||||||
)
|
)
|
||||||
from certbot_integration_tests.utils import misc
|
from certbot_integration_tests.utils import misc
|
||||||
|
|
||||||
@@ -84,9 +87,9 @@ def test_http_01(context):
|
|||||||
context.certbot([
|
context.certbot([
|
||||||
'--domains', certname, '--preferred-challenges', 'http-01', 'run',
|
'--domains', certname, '--preferred-challenges', 'http-01', 'run',
|
||||||
'--cert-name', certname,
|
'--cert-name', certname,
|
||||||
'--pre-hook', 'echo wtf.pre >> "{0}"'.format(context.hook_probe),
|
'--pre-hook', misc.echo('wtf_pre', context.hook_probe),
|
||||||
'--post-hook', 'echo wtf.post >> "{0}"'.format(context.hook_probe),
|
'--post-hook', misc.echo('wtf_post', context.hook_probe),
|
||||||
'--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)
|
'--deploy-hook', misc.echo('deploy', context.hook_probe),
|
||||||
])
|
])
|
||||||
|
|
||||||
assert_hook_execution(context.hook_probe, 'deploy')
|
assert_hook_execution(context.hook_probe, 'deploy')
|
||||||
@@ -104,9 +107,9 @@ def test_manual_http_auth(context):
|
|||||||
'--cert-name', certname,
|
'--cert-name', certname,
|
||||||
'--manual-auth-hook', scripts[0],
|
'--manual-auth-hook', scripts[0],
|
||||||
'--manual-cleanup-hook', scripts[1],
|
'--manual-cleanup-hook', scripts[1],
|
||||||
'--pre-hook', 'echo wtf.pre >> "{0}"'.format(context.hook_probe),
|
'--pre-hook', misc.echo('wtf_pre', context.hook_probe),
|
||||||
'--post-hook', 'echo wtf.post >> "{0}"'.format(context.hook_probe),
|
'--post-hook', misc.echo('wtf_post', context.hook_probe),
|
||||||
'--renew-hook', 'echo renew >> "{0}"'.format(context.hook_probe)
|
'--renew-hook', misc.echo('renew', context.hook_probe),
|
||||||
])
|
])
|
||||||
|
|
||||||
with pytest.raises(AssertionError):
|
with pytest.raises(AssertionError):
|
||||||
@@ -122,9 +125,9 @@ def test_manual_dns_auth(context):
|
|||||||
'run', '--cert-name', certname,
|
'run', '--cert-name', certname,
|
||||||
'--manual-auth-hook', context.manual_dns_auth_hook,
|
'--manual-auth-hook', context.manual_dns_auth_hook,
|
||||||
'--manual-cleanup-hook', context.manual_dns_cleanup_hook,
|
'--manual-cleanup-hook', context.manual_dns_cleanup_hook,
|
||||||
'--pre-hook', 'echo wtf.pre >> "{0}"'.format(context.hook_probe),
|
'--pre-hook', misc.echo('wtf_pre', context.hook_probe),
|
||||||
'--post-hook', 'echo wtf.post >> "{0}"'.format(context.hook_probe),
|
'--post-hook', misc.echo('wtf_post', context.hook_probe),
|
||||||
'--renew-hook', 'echo renew >> "{0}"'.format(context.hook_probe)
|
'--renew-hook', misc.echo('renew', context.hook_probe),
|
||||||
])
|
])
|
||||||
|
|
||||||
with pytest.raises(AssertionError):
|
with pytest.raises(AssertionError):
|
||||||
@@ -173,21 +176,19 @@ def test_renew_files_permissions(context):
|
|||||||
certname = context.get_domain('renew')
|
certname = context.get_domain('renew')
|
||||||
context.certbot(['-d', certname])
|
context.certbot(['-d', certname])
|
||||||
|
|
||||||
|
privkey1 = join(context.config_dir, 'archive', certname, 'privkey1.pem')
|
||||||
|
privkey2 = join(context.config_dir, 'archive', certname, 'privkey2.pem')
|
||||||
|
|
||||||
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
||||||
assert_world_permissions(
|
assert_world_no_permissions(privkey1)
|
||||||
join(context.config_dir, 'archive', certname, 'privkey1.pem'), 0)
|
|
||||||
|
|
||||||
context.certbot(['renew'])
|
context.certbot(['renew'])
|
||||||
|
|
||||||
assert_cert_count_for_lineage(context.config_dir, certname, 2)
|
assert_cert_count_for_lineage(context.config_dir, certname, 2)
|
||||||
assert_world_permissions(
|
assert_world_no_permissions(privkey2)
|
||||||
join(context.config_dir, 'archive', certname, 'privkey2.pem'), 0)
|
assert_equals_group_owner(privkey1, privkey2)
|
||||||
assert_equals_group_owner(
|
assert_equals_world_read_permissions(privkey1, privkey2)
|
||||||
join(context.config_dir, 'archive', certname, 'privkey1.pem'),
|
assert_equals_group_permissions(privkey1, privkey2)
|
||||||
join(context.config_dir, 'archive', certname, 'privkey2.pem'))
|
|
||||||
assert_equals_permissions(
|
|
||||||
join(context.config_dir, 'archive', certname, 'privkey1.pem'),
|
|
||||||
join(context.config_dir, 'archive', certname, 'privkey2.pem'), 0o074)
|
|
||||||
|
|
||||||
|
|
||||||
def test_renew_with_hook_scripts(context):
|
def test_renew_with_hook_scripts(context):
|
||||||
@@ -211,15 +212,35 @@ def test_renew_files_propagate_permissions(context):
|
|||||||
|
|
||||||
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
||||||
|
|
||||||
os.chmod(join(context.config_dir, 'archive', certname, 'privkey1.pem'), 0o444)
|
privkey1 = join(context.config_dir, 'archive', certname, 'privkey1.pem')
|
||||||
|
privkey2 = join(context.config_dir, 'archive', certname, 'privkey2.pem')
|
||||||
|
|
||||||
|
if os.name != 'nt':
|
||||||
|
os.chmod(privkey1, 0o444)
|
||||||
|
else:
|
||||||
|
import win32security
|
||||||
|
import ntsecuritycon
|
||||||
|
# Get the current DACL of the private key
|
||||||
|
security = win32security.GetFileSecurity(privkey1, win32security.DACL_SECURITY_INFORMATION)
|
||||||
|
dacl = security.GetSecurityDescriptorDacl()
|
||||||
|
# Create a read permission for Everybody group
|
||||||
|
everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID)
|
||||||
|
dacl.AddAccessAllowedAce(win32security.ACL_REVISION, ntsecuritycon.FILE_GENERIC_READ, everybody)
|
||||||
|
# Apply the updated DACL to the private key
|
||||||
|
security.SetSecurityDescriptorDacl(1, dacl, 0)
|
||||||
|
win32security.SetFileSecurity(privkey1, win32security.DACL_SECURITY_INFORMATION, security)
|
||||||
|
|
||||||
context.certbot(['renew'])
|
context.certbot(['renew'])
|
||||||
|
|
||||||
assert_cert_count_for_lineage(context.config_dir, certname, 2)
|
assert_cert_count_for_lineage(context.config_dir, certname, 2)
|
||||||
assert_world_permissions(
|
if os.name != 'nt':
|
||||||
join(context.config_dir, 'archive', certname, 'privkey2.pem'), 4)
|
# On Linux, read world permissions + all group permissions will be copied from the previous private key
|
||||||
assert_equals_permissions(
|
assert_world_read_permissions(privkey2)
|
||||||
join(context.config_dir, 'archive', certname, 'privkey1.pem'),
|
assert_equals_world_read_permissions(privkey1, privkey2)
|
||||||
join(context.config_dir, 'archive', certname, 'privkey2.pem'), 0o074)
|
assert_equals_group_permissions(privkey1, privkey2)
|
||||||
|
else:
|
||||||
|
# On Windows, world will never have any permissions, and group permission is irrelevant for this platform
|
||||||
|
assert_world_no_permissions(privkey2)
|
||||||
|
|
||||||
|
|
||||||
def test_graceful_renew_it_is_not_time(context):
|
def test_graceful_renew_it_is_not_time(context):
|
||||||
@@ -229,7 +250,7 @@ def test_graceful_renew_it_is_not_time(context):
|
|||||||
|
|
||||||
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
||||||
|
|
||||||
context.certbot(['renew', '--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)],
|
context.certbot(['renew', '--deploy-hook', misc.echo('deploy', context.hook_probe)],
|
||||||
force_renew=False)
|
force_renew=False)
|
||||||
|
|
||||||
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
||||||
@@ -250,7 +271,7 @@ def test_graceful_renew_it_is_time(context):
|
|||||||
with open(join(context.config_dir, 'renewal', '{0}.conf'.format(certname)), 'w') as file:
|
with open(join(context.config_dir, 'renewal', '{0}.conf'.format(certname)), 'w') as file:
|
||||||
file.writelines(lines)
|
file.writelines(lines)
|
||||||
|
|
||||||
context.certbot(['renew', '--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)],
|
context.certbot(['renew', '--deploy-hook', misc.echo('deploy', context.hook_probe)],
|
||||||
force_renew=False)
|
force_renew=False)
|
||||||
|
|
||||||
assert_cert_count_for_lineage(context.config_dir, certname, 2)
|
assert_cert_count_for_lineage(context.config_dir, certname, 2)
|
||||||
@@ -317,9 +338,9 @@ def test_renew_hook_override(context):
|
|||||||
context.certbot([
|
context.certbot([
|
||||||
'certonly', '-d', certname,
|
'certonly', '-d', certname,
|
||||||
'--preferred-challenges', 'http-01',
|
'--preferred-challenges', 'http-01',
|
||||||
'--pre-hook', 'echo pre >> "{0}"'.format(context.hook_probe),
|
'--pre-hook', misc.echo('pre', context.hook_probe),
|
||||||
'--post-hook', 'echo post >> "{0}"'.format(context.hook_probe),
|
'--post-hook', misc.echo('post', context.hook_probe),
|
||||||
'--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)
|
'--deploy-hook', misc.echo('deploy', context.hook_probe),
|
||||||
])
|
])
|
||||||
|
|
||||||
assert_hook_execution(context.hook_probe, 'pre')
|
assert_hook_execution(context.hook_probe, 'pre')
|
||||||
@@ -330,14 +351,14 @@ def test_renew_hook_override(context):
|
|||||||
open(context.hook_probe, 'w').close()
|
open(context.hook_probe, 'w').close()
|
||||||
context.certbot([
|
context.certbot([
|
||||||
'renew', '--cert-name', certname,
|
'renew', '--cert-name', certname,
|
||||||
'--pre-hook', 'echo pre-override >> "{0}"'.format(context.hook_probe),
|
'--pre-hook', misc.echo('pre_override', context.hook_probe),
|
||||||
'--post-hook', 'echo post-override >> "{0}"'.format(context.hook_probe),
|
'--post-hook', misc.echo('post_override', context.hook_probe),
|
||||||
'--deploy-hook', 'echo deploy-override >> "{0}"'.format(context.hook_probe)
|
'--deploy-hook', misc.echo('deploy_override', context.hook_probe),
|
||||||
])
|
])
|
||||||
|
|
||||||
assert_hook_execution(context.hook_probe, 'pre-override')
|
assert_hook_execution(context.hook_probe, 'pre_override')
|
||||||
assert_hook_execution(context.hook_probe, 'post-override')
|
assert_hook_execution(context.hook_probe, 'post_override')
|
||||||
assert_hook_execution(context.hook_probe, 'deploy-override')
|
assert_hook_execution(context.hook_probe, 'deploy_override')
|
||||||
with pytest.raises(AssertionError):
|
with pytest.raises(AssertionError):
|
||||||
assert_hook_execution(context.hook_probe, 'pre')
|
assert_hook_execution(context.hook_probe, 'pre')
|
||||||
with pytest.raises(AssertionError):
|
with pytest.raises(AssertionError):
|
||||||
@@ -349,11 +370,11 @@ def test_renew_hook_override(context):
|
|||||||
open(context.hook_probe, 'w').close()
|
open(context.hook_probe, 'w').close()
|
||||||
context.certbot(['renew', '--cert-name', certname])
|
context.certbot(['renew', '--cert-name', certname])
|
||||||
|
|
||||||
assert_hook_execution(context.hook_probe, 'pre-override')
|
assert_hook_execution(context.hook_probe, 'pre_override')
|
||||||
assert_hook_execution(context.hook_probe, 'post-override')
|
assert_hook_execution(context.hook_probe, 'post_override')
|
||||||
assert_hook_execution(context.hook_probe, 'deploy-override')
|
assert_hook_execution(context.hook_probe, 'deploy_override')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_domain_with_dns_challenge(context):
|
def test_invalid_domain_with_dns_challenge(context):
|
||||||
"""Test certificate issuance failure with DNS-01 challenge."""
|
"""Test certificate issuance failure with DNS-01 challenge."""
|
||||||
# Manual dns auth hooks from misc are designed to fail if the domain contains 'fail-*'.
|
# Manual dns auth hooks from misc are designed to fail if the domain contains 'fail-*'.
|
||||||
@@ -512,7 +533,7 @@ def test_revoke_multiple_lineages(context):
|
|||||||
data = file.read()
|
data = file.read()
|
||||||
|
|
||||||
data = re.sub('archive_dir = .*\n',
|
data = re.sub('archive_dir = .*\n',
|
||||||
'archive_dir = {0}\n'.format(join(context.config_dir, 'archive', cert1)),
|
'archive_dir = {0}\n'.format(join(context.config_dir, 'archive', cert1).replace('\\', '\\\\')),
|
||||||
data)
|
data)
|
||||||
|
|
||||||
with open(join(context.config_dir, 'renewal', '{0}.conf'.format(cert2)), 'w') as file:
|
with open(join(context.config_dir, 'renewal', '{0}.conf'.format(cert2)), 'w') as file:
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ Misc module contains stateless functions that could be used during pytest execut
|
|||||||
or outside during setup/teardown of the integration tests environment.
|
or outside during setup/teardown of the integration tests environment.
|
||||||
"""
|
"""
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import logging
|
||||||
import errno
|
import errno
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import stat
|
import stat
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -62,6 +64,10 @@ class GracefulTCPServer(socketserver.TCPServer):
|
|||||||
allow_reuse_address = True
|
allow_reuse_address = True
|
||||||
|
|
||||||
|
|
||||||
|
def _run_server(port):
|
||||||
|
GracefulTCPServer(('', port), SimpleHTTPServer.SimpleHTTPRequestHandler).serve_forever()
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def create_http_server(port):
|
def create_http_server(port):
|
||||||
"""
|
"""
|
||||||
@@ -74,10 +80,7 @@ def create_http_server(port):
|
|||||||
current_cwd = os.getcwd()
|
current_cwd = os.getcwd()
|
||||||
webroot = tempfile.mkdtemp()
|
webroot = tempfile.mkdtemp()
|
||||||
|
|
||||||
def run():
|
process = multiprocessing.Process(target=_run_server, args=(port,))
|
||||||
GracefulTCPServer(('', port), SimpleHTTPServer.SimpleHTTPRequestHandler).serve_forever()
|
|
||||||
|
|
||||||
process = multiprocessing.Process(target=run)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# SimpleHTTPServer is designed to serve files from the current working directory at the
|
# SimpleHTTPServer is designed to serve files from the current working directory at the
|
||||||
@@ -119,15 +122,9 @@ def generate_test_file_hooks(config_dir, hook_probe):
|
|||||||
:param str config_dir: current certbot config directory
|
:param str config_dir: current certbot config directory
|
||||||
:param hook_probe: path to the hook probe to test hook scripts execution
|
:param hook_probe: path to the hook probe to test hook scripts execution
|
||||||
"""
|
"""
|
||||||
if sys.platform == 'win32':
|
hook_path = pkg_resources.resource_filename('certbot_integration_tests', 'assets/hook.py')
|
||||||
extension = 'bat'
|
|
||||||
else:
|
|
||||||
extension = 'sh'
|
|
||||||
|
|
||||||
renewal_hooks_dirs = list_renewal_hooks_dirs(config_dir)
|
for hook_dir in list_renewal_hooks_dirs(config_dir):
|
||||||
renewal_deploy_hook_path = os.path.join(renewal_hooks_dirs[1], 'hook.sh')
|
|
||||||
|
|
||||||
for hook_dir in renewal_hooks_dirs:
|
|
||||||
# We want an equivalent of bash `chmod -p $HOOK_DIR, that does not fail if one folder of
|
# We want an equivalent of bash `chmod -p $HOOK_DIR, that does not fail if one folder of
|
||||||
# the hierarchy already exists. It is not the case of os.makedirs. Python 3 has an
|
# the hierarchy already exists. It is not the case of os.makedirs. Python 3 has an
|
||||||
# optional parameter `exists_ok` to not fail on existing dir, but Python 2.7 does not.
|
# optional parameter `exists_ok` to not fail on existing dir, but Python 2.7 does not.
|
||||||
@@ -137,26 +134,25 @@ def generate_test_file_hooks(config_dir, hook_probe):
|
|||||||
except OSError as error:
|
except OSError as error:
|
||||||
if error.errno != errno.EEXIST:
|
if error.errno != errno.EEXIST:
|
||||||
raise
|
raise
|
||||||
hook_path = os.path.join(hook_dir, 'hook.{0}'.format(extension))
|
|
||||||
if extension == 'sh':
|
|
||||||
data = '''\
|
|
||||||
#!/bin/bash -xe
|
|
||||||
if [ "$0" = "{0}" ]; then
|
|
||||||
if [ -z "$RENEWED_DOMAINS" -o -z "$RENEWED_LINEAGE" ]; then
|
|
||||||
echo "Environment variables not properly set!" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo $(basename $(dirname "$0")) >> "{1}"\
|
|
||||||
'''.format(renewal_deploy_hook_path, hook_probe)
|
|
||||||
else:
|
|
||||||
# TODO: Write the equivalent bat file for Windows
|
|
||||||
data = '''\
|
|
||||||
|
|
||||||
'''
|
if os.name != 'nt':
|
||||||
with open(hook_path, 'w') as file:
|
entrypoint_script_path = os.path.join(hook_dir, 'entrypoint.sh')
|
||||||
file.write(data)
|
entrypoint_script = '''\
|
||||||
os.chmod(hook_path, os.stat(hook_path).st_mode | stat.S_IEXEC)
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
"{0}" "{1}" "{2}" "{3}"
|
||||||
|
'''.format(sys.executable, hook_path, entrypoint_script_path, hook_probe)
|
||||||
|
else:
|
||||||
|
entrypoint_script_path = os.path.join(hook_dir, 'entrypoint.bat')
|
||||||
|
entrypoint_script = '''\
|
||||||
|
@echo off
|
||||||
|
"{0}" "{1}" "{2}" "{3}"
|
||||||
|
'''.format(sys.executable, hook_path, entrypoint_script_path, hook_probe)
|
||||||
|
|
||||||
|
with open(entrypoint_script_path, 'w') as file_h:
|
||||||
|
file_h.write(entrypoint_script)
|
||||||
|
|
||||||
|
os.chmod(entrypoint_script_path, os.stat(entrypoint_script_path).st_mode | stat.S_IEXEC)
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
@@ -193,7 +189,7 @@ for _ in range(0, 10):
|
|||||||
except requests.exceptions.ConnectionError:
|
except requests.exceptions.ConnectionError:
|
||||||
pass
|
pass
|
||||||
raise ValueError('Error, url did not respond after 10 attempts: {{0}}'.format(url))
|
raise ValueError('Error, url did not respond after 10 attempts: {{0}}'.format(url))
|
||||||
'''.format(http_server_root, http_port))
|
'''.format(http_server_root.replace('\\', '\\\\'), http_port))
|
||||||
os.chmod(auth_script_path, 0o755)
|
os.chmod(auth_script_path, 0o755)
|
||||||
|
|
||||||
cleanup_script_path = os.path.join(tempdir, 'cleanup.py')
|
cleanup_script_path = os.path.join(tempdir, 'cleanup.py')
|
||||||
@@ -204,7 +200,7 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
well_known = os.path.join('{0}', '.well-known')
|
well_known = os.path.join('{0}', '.well-known')
|
||||||
shutil.rmtree(well_known)
|
shutil.rmtree(well_known)
|
||||||
'''.format(http_server_root))
|
'''.format(http_server_root.replace('\\', '\\\\')))
|
||||||
os.chmod(cleanup_script_path, 0o755)
|
os.chmod(cleanup_script_path, 0o755)
|
||||||
|
|
||||||
yield ('{0} {1}'.format(sys.executable, auth_script_path),
|
yield ('{0} {1}'.format(sys.executable, auth_script_path),
|
||||||
@@ -287,4 +283,32 @@ def load_sample_data_path(workspace):
|
|||||||
original = pkg_resources.resource_filename('certbot_integration_tests', 'assets/sample-config')
|
original = pkg_resources.resource_filename('certbot_integration_tests', 'assets/sample-config')
|
||||||
copied = os.path.join(workspace, 'sample-config')
|
copied = os.path.join(workspace, 'sample-config')
|
||||||
shutil.copytree(original, copied, symlinks=True)
|
shutil.copytree(original, copied, symlinks=True)
|
||||||
|
|
||||||
|
if os.name == 'nt':
|
||||||
|
# Fix the symlinks on Windows since GIT is not creating them upon checkout
|
||||||
|
for lineage in ['a.encryption-example.com', 'b.encryption-example.com']:
|
||||||
|
current_live = os.path.join(copied, 'live', lineage)
|
||||||
|
for name in os.listdir(current_live):
|
||||||
|
if name != 'README':
|
||||||
|
current_file = os.path.join(current_live, name)
|
||||||
|
with open(current_file) as file_h:
|
||||||
|
src = file_h.read()
|
||||||
|
os.unlink(current_file)
|
||||||
|
os.symlink(os.path.join(current_live, src), current_file)
|
||||||
|
|
||||||
return copied
|
return copied
|
||||||
|
|
||||||
|
|
||||||
|
def echo(keyword, path=None):
|
||||||
|
"""
|
||||||
|
Generate a platform independent executable command
|
||||||
|
that echoes the given keyword into the given file.
|
||||||
|
:param keyword: the keyword to echo (must be a single keyword)
|
||||||
|
:param path: path to the file were keyword is echoed
|
||||||
|
:return: the executable command
|
||||||
|
"""
|
||||||
|
if not re.match(r'^\w+$', keyword):
|
||||||
|
raise ValueError('Error, keyword `{0}` is not a single keyword.'
|
||||||
|
.format(keyword))
|
||||||
|
return '{0} -c "from __future__ import print_function; print(\'{1}\')"{2}'.format(
|
||||||
|
os.path.basename(sys.executable), keyword, ' >> "{0}"'.format(path) if path else '')
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import json
|
import json
|
||||||
import platform
|
|
||||||
import os
|
import os
|
||||||
import stat
|
import stat
|
||||||
|
|
||||||
@@ -13,9 +12,7 @@ ASSETS_PATH = pkg_resources.resource_filename('certbot_integration_tests', 'asse
|
|||||||
|
|
||||||
|
|
||||||
def fetch(workspace):
|
def fetch(workspace):
|
||||||
suffix = '{0}-{1}{2}'.format(platform.system().lower(),
|
suffix = 'linux-amd64' if os.name != 'nt' else 'windows-amd64.exe'
|
||||||
platform.machine().lower().replace('x86_64', 'amd64'),
|
|
||||||
'.exe' if platform.system() == 'Windows' else '')
|
|
||||||
|
|
||||||
pebble_path = _fetch_asset('pebble', suffix)
|
pebble_path = _fetch_asset('pebble', suffix)
|
||||||
challtestsrv_path = _fetch_asset('pebble-challtestsrv', suffix)
|
challtestsrv_path = _fetch_asset('pebble-challtestsrv', suffix)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from setuptools import setup
|
import sys
|
||||||
from setuptools import find_packages
|
|
||||||
|
from distutils.version import StrictVersion
|
||||||
|
from setuptools import setup, find_packages, __version__ as setuptools_version
|
||||||
|
|
||||||
|
|
||||||
version = '0.32.0.dev0'
|
version = '0.32.0.dev0'
|
||||||
@@ -17,6 +19,17 @@ install_requires = [
|
|||||||
'six',
|
'six',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Add pywin32 on Windows platforms to handle low-level system calls.
|
||||||
|
# This dependency needs to be added using environment markers to avoid its installation on Linux.
|
||||||
|
# However environment markers are supported only with setuptools >= 36.2.
|
||||||
|
# So this dependency is not added for old Linux distributions with old setuptools,
|
||||||
|
# in order to allow these systems to build certbot from sources.
|
||||||
|
if StrictVersion(setuptools_version) >= StrictVersion('36.2'):
|
||||||
|
install_requires.append("pywin32>=224 ; sys_platform == 'win32'")
|
||||||
|
elif 'bdist_wheel' in sys.argv[1:]:
|
||||||
|
raise RuntimeError('Error, you are trying to build certbot wheels using an old version '
|
||||||
|
'of setuptools. Version 36.2+ of setuptools is required.')
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='certbot-ci',
|
name='certbot-ci',
|
||||||
version=version,
|
version=version,
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -59,7 +59,7 @@ install_requires = [
|
|||||||
# So this dependency is not added for old Linux distributions with old setuptools,
|
# So this dependency is not added for old Linux distributions with old setuptools,
|
||||||
# in order to allow these systems to build certbot from sources.
|
# in order to allow these systems to build certbot from sources.
|
||||||
if StrictVersion(setuptools_version) >= StrictVersion('36.2'):
|
if StrictVersion(setuptools_version) >= StrictVersion('36.2'):
|
||||||
install_requires.append("pywin32 ; sys_platform == 'win32'")
|
install_requires.append("pywin32>=224 ; sys_platform == 'win32'")
|
||||||
elif 'bdist_wheel' in sys.argv[1:]:
|
elif 'bdist_wheel' in sys.argv[1:]:
|
||||||
raise RuntimeError('Error, you are trying to build certbot wheels using an old version '
|
raise RuntimeError('Error, you are trying to build certbot wheels using an old version '
|
||||||
'of setuptools. Version 36.2+ of setuptools is required.')
|
'of setuptools. Version 36.2+ of setuptools is required.')
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ pytest-sugar==0.9.2
|
|||||||
pytest-rerunfailures==4.2
|
pytest-rerunfailures==4.2
|
||||||
python-dateutil==2.6.1
|
python-dateutil==2.6.1
|
||||||
python-digitalocean==1.11
|
python-digitalocean==1.11
|
||||||
|
pywin32==224
|
||||||
PyYAML==3.13
|
PyYAML==3.13
|
||||||
repoze.sphinx.autointerface==0.8
|
repoze.sphinx.autointerface==0.8
|
||||||
requests-file==1.4.2
|
requests-file==1.4.2
|
||||||
|
|||||||
9
tox.ini
9
tox.ini
@@ -232,6 +232,15 @@ commands =
|
|||||||
coverage report --include 'certbot-nginx/*' --show-missing --fail-under=74
|
coverage report --include 'certbot-nginx/*' --show-missing --fail-under=74
|
||||||
passenv = DOCKER_*
|
passenv = DOCKER_*
|
||||||
|
|
||||||
|
[testenv:integration-certbot]
|
||||||
|
commands =
|
||||||
|
{[base]pip_install} acme . certbot-ci
|
||||||
|
pytest certbot-ci/certbot_integration_tests/certbot_tests \
|
||||||
|
--acme-server={env:ACME_SERVER:pebble} \
|
||||||
|
--cov=acme --cov=certbot --cov-report= \
|
||||||
|
--cov-config=certbot-ci/certbot_integration_tests/.coveragerc
|
||||||
|
coverage report --include 'certbot/*' --show-missing --fail-under=62
|
||||||
|
|
||||||
[testenv:integration-certbot-oldest]
|
[testenv:integration-certbot-oldest]
|
||||||
commands =
|
commands =
|
||||||
{[base]pip_install} .
|
{[base]pip_install} .
|
||||||
|
|||||||
Reference in New Issue
Block a user