From 6e1696ba32ef8c1162bb0cd85df5a22113952828 Mon Sep 17 00:00:00 2001 From: Alexis Date: Wed, 29 Jun 2022 15:52:50 -0700 Subject: [PATCH] Add Signed Windows Installer Workflow (#9076) * Add Code Signing action for Windows Installer * Clean up variable names and input * Amend and add to documentation per PR guidelines * Update tools/finish_release.py Co-authored-by: Brad Warren * Update tools/finish_release.py Amend typo Co-authored-by: Brad Warren * Amend release script for better work flow - SCP commands to upload and download unsigned & signed installers from CSS * Collapse spaces * Update tools/finish_release.py Co-authored-by: Brad Warren * Create new windows signer function * Update Windows Installer Script - Update change log - add new function for signing and document - @TODO Streammline SSH session * Remove Azure and Github release methods - Methods moved to CSS - Reduced to a ssh function that triggers the process on a CSS * Amend Chnagelog and Remove Unneeded Deps * Update tools/finish_release.py Co-authored-by: Brad Warren * Add Verison Fetch Function - For the purpose of snap releases - Add back package to dev extras for function * Chaneg path in ssh command * Amend release script * Amend the ssh command for CSS * Update tools/finish_release.py Co-authored-by: Brad Warren * Update script with proper path and subprocess call * Update ssh command * Correct typo in path * Fix typo in path * Update certbot/CHANGELOG.md Co-authored-by: ohemorange * Remove missed conflict text Co-authored-by: Brad Warren Co-authored-by: ohemorange --- AUTHORS.md | 1 + certbot/CHANGELOG.md | 3 +- certbot/setup.py | 1 - tools/finish_release.py | 114 ++++++++++++++-------------------------- 4 files changed, 43 insertions(+), 76 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index d5cb664cb..9e92568c5 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -17,6 +17,7 @@ Authors * [Alex Halderman](https://github.com/jhalderm) * [Alex Jordan](https://github.com/strugee) * [Alex Zorin](https://github.com/alexzorin) +* [Alexis Hancock](https://github.com/zoracon) * [Amir Omidi](https://github.com/aaomidi) * [Amjad Mashaal](https://github.com/TheNavigat) * [amplifi](https://github.com/amplifi) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 8a54bf94e..d5efff8a1 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -6,7 +6,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Added -* +* Updated Windows installer to be signed and trusted in Windows ### Changed @@ -28,6 +28,7 @@ More details about these changes can be found on our GitHub repo. * Updated Apache/NGINX TLS configs to document contents are based on ssl-config.mozilla.org + ### Changed * A change to order finalization has been made to the `acme` module and Certbot: diff --git a/certbot/setup.py b/certbot/setup.py index 092e88135..8f1de50ca 100644 --- a/certbot/setup.py +++ b/certbot/setup.py @@ -67,7 +67,6 @@ install_requires = [ dev_extras = [ 'azure-devops', 'ipdb', - 'PyGithub', # poetry 1.2.0+ is required for it to pin pip, setuptools, and wheel. See # https://github.com/python-poetry/poetry/issues/1584. 'poetry>=1.2.0a1', diff --git a/tools/finish_release.py b/tools/finish_release.py index aa224e38f..6e0d1d490 100755 --- a/tools/finish_release.py +++ b/tools/finish_release.py @@ -8,17 +8,13 @@ This currently includes: * Publishing the Windows installer in a GitHub release Setup: - - Create a github personal access token - - https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token#creating-a-token - - You'll need repo scope - - Save the token to somewhere like ~/.ssh/githubpat.txt - Install the snapcraft command line tool and log in to a privileged account. - https://snapcraft.io/docs/installing-snapcraft - Use the command `snapcraft login` to log in. Run: -python tools/finish_release.py ~/.ssh/githubpat.txt +python tools/finish_release.py --css Testing: @@ -36,10 +32,10 @@ import re import subprocess import sys import tempfile +import getpass +from azure.devops.connection import Connection from zipfile import ZipFile -from azure.devops.connection import Connection -from github import Github import requests # Path to the root directory of the Certbot repository containing this script @@ -68,7 +64,7 @@ def parse_args(args): # Use the file's docstring for the help text and don't let argparse reformat it. parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument('githubpat', help='path to your GitHub personal access token') + parser.add_argument('--css', type=str, required=True, help='hostname of code signing server') group = parser.add_mutually_exclusive_group() # We use 'store_false' and a destination related to the other type of # artifact to cause the flag being set to disable publishing of the other @@ -80,63 +76,19 @@ def parse_args(args): help='Skip publishing other artifacts and only publish the Windows installer') return parser.parse_args(args) + +def publish_windows(css): + """SSH into CSS and trigger downloading Azure Pipeline assets, sign, and upload to Github -def download_azure_artifacts(tempdir): - """Download and unzip build artifacts from Azure pipelines. - - :param str path: path to a temporary directory to save the files - - :returns: released certbot version number as a prefix-free string - :rtype: str + :param str css: CSS host name """ - # Create a connection to the azure org - organization_url = 'https://dev.azure.com/certbot' - connection = Connection(base_url=organization_url) - - # Find the build artifacts - build_client = connection.clients.get_build_client() - get_builds_response = build_client.get_builds('certbot', definitions='3') - build_id = get_builds_response.value[0].id - artifacts = build_client.get_artifacts('certbot', build_id) - - # Save and unzip files - for filename in ('windows-installer', 'changelog'): - print("Downloading artifact %s" % filename) - url = build_client.get_artifact('certbot', build_id, filename).resource.download_url - r = requests.get(url) - r.raise_for_status() - with open(tempdir + '/' + filename + '.zip', 'wb') as f: - f.write(r.content) - print("Extracting %s" % filename) - with ZipFile(tempdir + '/' + filename + '.zip', 'r') as zipObj: - zipObj.extractall(tempdir) - - version = build_client.get_build('certbot', build_id).source_branch.split('v')[1] - return version - -def create_github_release(github_access_token, tempdir, version): - """Use build artifacts to create a github release, including uploading additional assets - - :param str github_access_token: string containing github access token - :param str path: path to a temporary directory where azure artifacts are located - :param str version: Certbot version number, e.g. 1.7.0 - - """ - # Create release - g = Github(github_access_token) - repo = g.get_user('certbot').get_repo('certbot') - release_notes = open(tempdir + '/changelog/release_notes.md', 'r').read() - print("Creating git release") - release= repo.create_git_release('v{0}'.format(version), - 'Certbot {0}'.format(version), - release_notes, - draft=True) - - # Upload windows installer to release - print("Uploading windows installer") - release.upload_asset(tempdir + '/windows-installer/certbot-beta-installer-win_amd64.exe') - release.update_release(release.title, release.body, draft=False) + username = getpass.getuser() + host = css + command = "ssh -t {}@{} bash /opt/certbot-misc/css/venv.sh".format(username,host) + + print("SSH into CSS to trigger signing and uploading of Windows installer...") + subprocess.run(command, check=True, universal_newlines=True, shell=True) def assert_logged_into_snapcraft(): @@ -216,23 +168,37 @@ def promote_snaps(version): print(e.stdout) raise +def fetch_version_number(): + """Retrieve version number for release from Azure Pipelines + + :returns: version number + + """ + # Create a connection to the azure org + organization_url = 'https://dev.azure.com/certbot' + connection = Connection(base_url=organization_url) + + # Find the build artifacts + build_client = connection.clients.get_build_client() + get_builds_response = build_client.get_builds('certbot', definitions='3') + build_id = get_builds_response.value[0].id + version = build_client.get_build('certbot', build_id).source_branch.split('v')[1] + return version def main(args): parsed_args = parse_args(args) - github_access_token_file = parsed_args.githubpat - github_access_token = open(github_access_token_file, 'r').read().rstrip() + css = parsed_args.css + version = fetch_version_number() - with tempfile.TemporaryDirectory() as tempdir: - version = download_azure_artifacts(tempdir) - # Once the GitHub release has been published, trying to publish it - # again fails. Publishing the snaps can be done multiple times though - # so we do that first to make it easier to run the script again later - # if something goes wrong. - if parsed_args.publish_snaps: - promote_snaps(version) - if parsed_args.publish_windows: - create_github_release(github_access_token, tempdir, version) + # Once the GitHub release has been published, trying to publish it + # again fails. Publishing the snaps can be done multiple times though + # so we do that first to make it easier to run the script again later + # if something goes wrong. + if parsed_args.publish_snaps: + promote_snaps(version) + if parsed_args.publish_windows: + publish_windows(css) if __name__ == "__main__": main(sys.argv[1:])