From 3423fd12e0d4ef09ab91fdd0f6448697e8c90492 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 9 Jun 2024 15:35:28 -0400 Subject: [PATCH] Generating Minisign key before content generation Regenerating a package is easier when the Minisign key is generated before the content, as the content will contain the actual key value rather than a placeholder. --- .gitignore | 3 ++ .../package/cookiecutter.json | 5 +-- .../package/cookiecutter_prompts.yaml | 15 +++++++-- .../package/hooks/post_gen_project.py | 33 ++----------------- .../package/hooks/pre_gen_project.py | 2 ++ .../.github/workflows/standard.yaml | 2 +- .../.python_project_bootstrapper_config.yml | 2 +- .../{{ cookiecutter.__empty_dir }}/README.md | 11 +++---- 8 files changed, 29 insertions(+), 44 deletions(-) diff --git a/.gitignore b/.gitignore index 46374ed..7768bca 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ Deactivate*.sh build/** dist/** src/PythonProjectBootstrapper.egg-info/** + +key.pri +key.pub diff --git a/src/PythonProjectBootstrapper/package/cookiecutter.json b/src/PythonProjectBootstrapper/package/cookiecutter.json index 0d735b6..2a489e0 100644 --- a/src/PythonProjectBootstrapper/package/cookiecutter.json +++ b/src/PythonProjectBootstrapper/package/cookiecutter.json @@ -20,7 +20,8 @@ "gist_id": "", "gist_username": "{{ cookiecutter.github_username }}", - "sign_binaries": true, + "minisign_public_key": "", + "openssf_best_practices_badge_id": "__openssf_badge_id__", "create_docker_image": false, @@ -39,7 +40,7 @@ "pypi_project_name": "\n\nPlease enter the name of your project as it will appear on PyPI (https://pypi.org). This name cannot be associated with any other project on PyPI.\n\n", "gist_id": "\n\nPlease enter the GitHub gist id for use with this project.\n\nGitHub defines a gist as \"a simple way to share snippets and pastes with others.\" The generated python project will use a gist to store information dynamically generated during the build (for example code coverage information) that can be retrieved at a later time (for example, to display a code coverage badge in the project's README.md file). To create a gist:\n 1. Go to https://gist.github.com/\n 2. Enter the following values in their respective fields:\n\n Gist description...: Gist used by GitHub Action workflows to store and retrieve dynamic information (oftentimes used to create and display badges).\n Filename including extension...: README.md\n File contents: Gist used by GitHub Action workflows to store and retrieve dynamic information (oftentimes used to create and display badges).\n\n 3. Click the \"Create secret gist\" button\n 4. Copy the gist id (this will be the hex string at the end of the url associated with the gist\n that was just created). It will look something like:\n\n https://gist.github.com//4c10281ff1abc26cafcb9a5f9a8a443e\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n This is the gist id\n\n", "gist_username": "\n\nPlease enter the username associated with your gist_id. In most cases, this will be the same as your GitHub username.\n\n", - "sign_binaries": "\n\nWould you like the GitHub Action workflows to sign binaries produced by the project?\n\nA signed binary can be validated against its signature to ensure that changes have not been made to it after it was created. This is especially useful when distributing software to others and is highly recommended.\n\n", + "minisign_public_key": "\n\nPlease enter your Minisign public key for use with this project or \"none\" if you do not want to sign binaries (this is not recommended).\n\nMinisign is a dead simple tool to sign files and verify signatures. It is a secure tool that uses the Ed25519 public-key signature system. More information is available at https://jedisct1.github.io/minisign/.\n\nNote that these steps rely on docker (docker.com), so please make sure that docker is installed and working properly on your machine.\nAdditional information is available at https://docs.docker.com/engine/install/.\n\nTo create a Minisign key pair for use with this project:\n 1. Run 'docker run -i --rm -v \".:/host\" jedisct1/minisign -G -p /host/key.pub -s /host/key.pri -W'\n 2. Ensure that the file 'key.pri' exists (this file will be used later).\n 3. Open the file 'key.pub' and copy the key from the file; the key will be the last line of the file.\n 4. Paste the copied key here.\n\n", "openssf_best_practices_badge_id": "\n\nEnter the OpenSSF Best Practices Badge ID to display in your README.md file. Keep this default value if you do not have an OpenSSF Best Practices Badge ID but would like to create one (this is highly recommended). Enter the value 'none' if you do not want to display this badge in your README.md file.\n\nThe Open Source Security Foundation (OpenSSF) Best Practices badge is a way for Free/Libre and Open Source Software (FLOSS) projects to show that they follow best practices. Additional information is available at https://www.bestpractices.dev/.\n\nThis script will automatically generate scaffolding to achieve a 63% score. Completing your project's documentation and following development best practices will raise your score to 100%. Participation in the OpenSSF Best Practices Badge program is highly recommended.\n\n", "create_docker_image": "\n\nWould you like the GitHub Action workflows to create docker images of the development environment? These images can be used to produce exact results across different commits made to the repository over time (which is especially valuable when writing scientific software).\n\n" }, diff --git a/src/PythonProjectBootstrapper/package/cookiecutter_prompts.yaml b/src/PythonProjectBootstrapper/package/cookiecutter_prompts.yaml index f2ceed6..d4cc562 100644 --- a/src/PythonProjectBootstrapper/package/cookiecutter_prompts.yaml +++ b/src/PythonProjectBootstrapper/package/cookiecutter_prompts.yaml @@ -78,10 +78,19 @@ gist_id: |- gist_username: |- Please enter the username associated with your gist_id. In most cases, this will be the same as your GitHub username. -sign_binaries: |- - Would you like the GitHub Action workflows to sign binaries produced by the project? +minisign_public_key: |- + Please enter your Minisign public key for use with this project or "none" if you do not want to sign binaries (this is not recommended). - A signed binary can be validated against its signature to ensure that changes have not been made to it after it was created. This is especially useful when distributing software to others and is highly recommended. + Minisign is a dead simple tool to sign files and verify signatures. It is a secure tool that uses the Ed25519 public-key signature system. More information is available at https://jedisct1.github.io/minisign/. + + Note that these steps rely on docker (docker.com), so please make sure that docker is installed and working properly on your machine. + Additional information is available at https://docs.docker.com/engine/install/. + + To create a Minisign key pair for use with this project: + 1. Run 'docker run -i --rm -v ".:/host" jedisct1/minisign -G -p /host/key.pub -s /host/key.pri -W' + 2. Ensure that the file 'key.pri' exists (this file will be used later). + 3. Open the file 'key.pub' and copy the key from the file; the key will be the last line of the file. + 4. Paste the copied key here. openssf_best_practices_badge_id: |- Enter the OpenSSF Best Practices Badge ID to display in your README.md file. Keep this default value if you do not have an OpenSSF Best Practices Badge ID but would like to create one (this is highly recommended). Enter the value 'none' if you do not want to display this badge in your README.md file. diff --git a/src/PythonProjectBootstrapper/package/hooks/post_gen_project.py b/src/PythonProjectBootstrapper/package/hooks/post_gen_project.py index 1bc5a3a..d8c2957 100644 --- a/src/PythonProjectBootstrapper/package/hooks/post_gen_project.py +++ b/src/PythonProjectBootstrapper/package/hooks/post_gen_project.py @@ -101,25 +101,12 @@ def SavePrompts() -> None: """, ) -{% if cookiecutter.sign_binaries %} - prompts["Create a Minisign Key"] = textwrap.dedent( - f"""\ - In this step, we will create a Minisign (https://jedisct1.github.io/minisign/) key that is used to sign the binaries generated by GitHub Actions. - - Note that these steps rely on docker (docker.com), so please make sure that docker is installed and working properly on your machine. - Additional information is available at https://docs.docker.com/engine/install/. - - 1. Run 'docker run -i --rm -v "{Path.cwd()}:/host" jedisct1/minisign -G -p /host/key.pub -s /host/key.pri -W' - 2. Ensure that the file '{Path.cwd() / "key.pub"}' exists. - 3. Ensure that the file '{Path.cwd() / "key.pri"}' exists. - """, - ) - +{% if cookiecutter.minisign_public_key != 'none' %} prompts["Save the Minisign Private Key"] = textwrap.dedent( f"""\ In this step, we will save the Minisign private key as a GitHub Action Secret. - 1. Open '{Path.cwd() / "key.pri"}' in a text editor. + 1. Open 'key.pri' in a text editor. 2. Copy the contents of the file. 3. Visit {{ cookiecutter.github_url }}/{{ cookiecutter.github_username }}/{{ cookiecutter.github_project_name }}/settings/secrets/actions 4. In the "Repository secrets" section... @@ -128,23 +115,9 @@ def SavePrompts() -> None: Name: MINISIGN_PRIVATE_KEY Secret: 7. Click the "Save" button - 8. Save '{Path.cwd() / "key.pri"}' in a safe place. + 8. Save 'key.pri' in a safe place. """, ) - - prompts["Save the Minisign Public Key"] = textwrap.dedent( - f"""\ - In this step, we will update README.md with the Minisign public key. - - 1. Open '{Path.cwd() / "key.pub"}' in a text editor. - 2. Copy the contents of the file. - 3. Edit 'README.md'. - 4. Search for '' and replace all instances with the contents of key.pub copied in step #2. - 5. Save 'README.md'. - 6. Delete '{Path.cwd() / "key.pub"}'. - """, - ) - {% endif %} prompts["Commit and Push the Repository"] = textwrap.dedent( diff --git a/src/PythonProjectBootstrapper/package/hooks/pre_gen_project.py b/src/PythonProjectBootstrapper/package/hooks/pre_gen_project.py index cbb0da5..3b92425 100644 --- a/src/PythonProjectBootstrapper/package/hooks/pre_gen_project.py +++ b/src/PythonProjectBootstrapper/package/hooks/pre_gen_project.py @@ -19,6 +19,8 @@ errors.append('''github_project_name ("{{ cookiecutter.github_project_name }}")''') if "{{ cookiecutter.gist_id | escape_double_quotes }}".startswith("<") and "{{ cookiecutter.gist_id | escape_double_quotes }}".endswith(">"): errors.append('''gist_id ("{{ cookiecutter.gist_id }}")''') +if "{{ cookiecutter.minisign_public_key | escape_double_quotes }}".startswith("<") and "{{ cookiecutter.minisign_public_key | escape_double_quotes }}".endswith(">"): + errors.append('''minisign_public_key ("{{ cookiecutter.minisign_public_key }}")''') # fmt: on if errors: diff --git a/src/PythonProjectBootstrapper/package/{{ cookiecutter.__empty_dir }}/.github/workflows/standard.yaml b/src/PythonProjectBootstrapper/package/{{ cookiecutter.__empty_dir }}/.github/workflows/standard.yaml index 6cae1da..3565b66 100644 --- a/src/PythonProjectBootstrapper/package/{{ cookiecutter.__empty_dir }}/.github/workflows/standard.yaml +++ b/src/PythonProjectBootstrapper/package/{{ cookiecutter.__empty_dir }}/.github/workflows/standard.yaml @@ -232,6 +232,6 @@ jobs: release_sources_configuration_filename: .github/release_sources.yaml secrets: PYPI_TOKEN: {% raw %}${{ secrets.PYPI_TOKEN }}{% endraw %} -{% if cookiecutter.sign_binaries %} +{% if cookiecutter.minisign_public_key != 'none' %} MINISIGN_PRIVATE_KEY: {% raw %}${{ secrets.MINISIGN_PRIVATE_KEY }}{% endraw %} {% endif %} diff --git a/src/PythonProjectBootstrapper/package/{{ cookiecutter.__empty_dir }}/.python_project_bootstrapper_config.yml b/src/PythonProjectBootstrapper/package/{{ cookiecutter.__empty_dir }}/.python_project_bootstrapper_config.yml index ed41752..83ac77b 100644 --- a/src/PythonProjectBootstrapper/package/{{ cookiecutter.__empty_dir }}/.python_project_bootstrapper_config.yml +++ b/src/PythonProjectBootstrapper/package/{{ cookiecutter.__empty_dir }}/.python_project_bootstrapper_config.yml @@ -17,6 +17,6 @@ default_context: pypi_project_name: {{ cookiecutter.pypi_project_name }} gist_id: {{ cookiecutter.gist_id }} gist_username: {{ cookiecutter.gist_username }} - sign_binaries: {{ cookiecutter.sign_binaries }} + minisign_public_key: {{ cookiecutter.minisign_public_key }} openssf_best_practices_badge_id: {{ cookiecutter.openssf_best_practices_badge_id }} create_docker_image: {{ cookiecutter.create_docker_image }} diff --git a/src/PythonProjectBootstrapper/package/{{ cookiecutter.__empty_dir }}/README.md b/src/PythonProjectBootstrapper/package/{{ cookiecutter.__empty_dir }}/README.md index bf30bb4..bbe4b21 100644 --- a/src/PythonProjectBootstrapper/package/{{ cookiecutter.__empty_dir }}/README.md +++ b/src/PythonProjectBootstrapper/package/{{ cookiecutter.__empty_dir }}/README.md @@ -48,19 +48,16 @@ Download an executable for Linux, MacOS, or Windows to use the functionality pro 1. Download the archive for the latest release [here]({{ cookiecutter.github_url }}/{{ cookiecutter.github_username }}/{{ cookiecutter.github_project_name }}/releases/latest); the files will begin with `exe.` and contain the name of your operating system. 2. Decompress the archive -{% if cookiecutter.sign_binaries %} +{% if cookiecutter.minisign_public_key != 'none' %} #### Verifying Signed Executables Executables are signed and validated using [Minisign](https://jedisct1.github.io/minisign/). -The public key for executables in this repository is ``. +The public key for executables in this repository is `{{ cookiecutter.minisign_public_key }}`. -To verify that the executable is valid, download the corresponding `.minisig` file [here]({{ cookiecutter.github_url }}/{{ cookiecutter.github_username }}/{{ cookiecutter.github_project_name }}/releases/latest) and run the command corresponding to your operating system, replacing `` with the name of your file. +To verify that the executable is valid, download the corresponding `.minisig` file [here]({{ cookiecutter.github_url }}/{{ cookiecutter.github_username }}/{{ cookiecutter.github_project_name }}/releases/latest) and run this command, replacing `` with the name of your file. -| Operating System | Command | -| --- | --- | -| Linux / MacOS | `docker run -i --rm -v "$(pwd):/host" jedisct1/minisign -V -P -m /host/` | -| Windows | `docker run -i --rm -v "%CD%:/host" jedisct1/minisign -V -P -m /host/` | +`docker run -i --rm -v .:/host jedisct1/minisign -V -P {{ cookiecutter.minisign_public_key }} -m /host/` Instructions for installing [docker](https://docker.com) are available at https://docs.docker.com/engine/install/.