Run hooks with Powershell on Windows (#7800)

Fixes #7713.

As discussed in #7713, providing a Powershell script as hook for Certbot is not working currently. This is because hooks are run in a `cmd` environment, that recognizes only `.bat` files as valid scripts that can be run from their bare name on command line.

On the other hand, the Powershell both `.bat` and `.ps1` scripts as valid scripts.

This PR makes hooks command be executed by Powershell, instead of `cmd` as `Popen` does by default when `shell=true` is used. It also modifies the tests to handle this new environment, in particular in term of encoding (UTF-16-LE is the default one in Powershell).

* Run hooks in powershell on Windows

* Fix hook test

* Fallback to unittest.mock

* In fact, shell_cmd as a list of str could not work. Declare only str as acceptable input for shell_cmd.

* Added changelog
This commit is contained in:
Adrien Ferrand
2020-04-27 09:38:30 -07:00
committed by GitHub
parent 01dc981a09
commit 9cbb13ef04
9 changed files with 107 additions and 77 deletions
@@ -1,4 +1,5 @@
#!/usr/bin/env python
from __future__ import print_function
import os
import sys
@@ -7,5 +8,4 @@ if hook_script_type == 'deploy' and ('RENEWED_DOMAINS' not in os.environ or 'REN
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')
print(hook_script_type)
@@ -1,4 +1,5 @@
"""This module contains advanced assertions for the certbot integration tests."""
import io
import os
try:
@@ -21,7 +22,8 @@ def assert_hook_execution(probe_path, probe_content):
:param probe_path: path to the file that received the hook output
:param probe_content: content expected when the hook is executed
"""
with open(probe_path, 'r') as file:
encoding = 'utf-8' if POSIX_MODE else 'utf-16'
with io.open(probe_path, 'rt', encoding=encoding) as file:
data = file.read()
lines = [line.strip() for line in data.splitlines()]
@@ -140,13 +140,12 @@ def generate_test_file_hooks(config_dir, hook_probe):
entrypoint_script = '''\
#!/usr/bin/env bash
set -e
"{0}" "{1}" "{2}" "{3}"
"{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_path = os.path.join(hook_dir, 'entrypoint.ps1')
entrypoint_script = '''\
@echo off
"{0}" "{1}" "{2}" "{3}"
& "{0}" "{1}" "{2}" >> "{3}"
'''.format(sys.executable, hook_path, entrypoint_script_path, hook_probe)
with open(entrypoint_script_path, 'w') as file_h: