{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "796ddf67",
   "metadata": {},
   "source": [
    "# Signing GitHub Commits\n",
    "\n",
    "## Overview\n",
    "The OpenMDAO `master` branch now only accepts __verified__ commits to be confident that the changes come from a trusted source. To be verified, a commit must be signed with a certificate recognized by GitHub.\n",
    "\n",
    "These instructions cover creating a GPG key, copying it to GitHub, and setting up `git` to sign commits.\n",
    "\n",
    "Although it's possible to use S/MIME to sign commits with an X.509 certificate (e.g. as found on a smartcard), the certificate must be signed by an authority already trusted by GitHub. The list of trusted CAs is the same as the one [trusted by the Mozilla browser](https://ccadb-public.secure.force.com/mozilla/IncludedCACertificateReport). Note: The certificates on NASA PIV badges are __not__ signed by a CA currently trusted by GitHub.\n",
    "<br>\n",
    "\n",
    "## Setting up your GPG Key with Git and GitHub\n",
    "\n",
    "The process is [documented in detail by GitHub](https://docs.github.com/en/github/authenticating-to-github/managing-commit-signature-verification/about-commit-signature-verification). Here are the highlights:\n",
    "\n",
    "1. Install GPG if necessary\n",
    "    - Source and binary releases are available at [gnupg.org](https://gnupg.org/download/)\n",
    "    - Also available through many OS package managers. Examples:\n",
    "        - MacOS: `brew install gpg`\n",
    "        - RPM-based Linux distro: `sudo yum install gnupg2` or `sudo dnf install gnupg2`\n",
    "        - DEB-based Linux distro: `sudo apt install gnupg`\n",
    "        - Windows: `scoop bucket add nonportable`, then `scoop install gpg-np` ([Obtain Scoop](https://scoop.sh/))\n",
    "2. [Generate a new GPG key](https://docs.github.com/en/github/authenticating-to-github/managing-commit-signature-verification/generating-a-new-gpg-key)\n",
    "    - It's important to note that the email address used for the key must be identical to your GitHub commit email address\n",
    "        - Run `git config --global user.email` to find this if you're unsure\n",
    "        - [Additional information](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-user-account/managing-email-preferences/setting-your-commit-email-address) on setting your commit email address, including using a `no-reply` address\n",
    "    - At the end of this process, you'll have your new GPG key copied to your clipboard\n",
    "3. [Add the GPG key to your GitHub account](https://docs.github.com/en/github/authenticating-to-github/managing-commit-signature-verification/adding-a-new-gpg-key-to-your-github-account)\n",
    "    - Summary:\n",
    "        - Complete the [instructions](https://docs.github.com/en/github/authenticating-to-github/managing-commit-signature-verification/adding-a-new-gpg-key-to-your-github-account) to find your key's ID and configure `git` with it\n",
    "        - Profile photo &#8594; Settings &#8594; SSH and GPG keys &#8594; New GPG key\n",
    "        - Paste the key\n",
    "        - Click `Add GPG key`\n",
    "4. [Tell Git about your GPG key](https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key)\n",
    "    - Summary:\n",
    "        - Run `gpg --list-secret-keys --keyid-format=long`\n",
    "        - From that output, copy the long ID (16 hexadecimal digits) from the `sec` line of the key you just generated (or existing one you want to use), e.g. <pre>...<br>sec   ed25519/<i><b>A0B1C2D3E4F56789</b></i> 2021-09-07 [SC]<br>...</pre>\n",
    "        - Set your signing key: <pre>git config --global user.signingkey <i><b>A0B1C2D3E4F56789</b></i></pre>\n",
    "<br>\n",
    "\n",
    "## Signing Commits\n",
    "\n",
    "### Sign all commits by default:\n",
    "`git config --global commit.gpgsign true`\n",
    "\n",
    "### Sign only commits for the current local repository by default:\n",
    "`git config --local commit.gpgsign true`\n",
    "\n",
    "### Sign an individual commit:\n",
    "`git commit -S -m \"commit message here\"`\n",
    "\n",
    "GitHub has [additional documentation](https://docs.github.com/en/github/authenticating-to-github/managing-commit-signature-verification/signing-commits) on signing commits.\n",
    "<br>\n",
    "\n",
    "## Configuring gpg-agent\n",
    "It can be inconvenient to have to enter your GPG key passphrase for every commit. Invoking `gpg` automatically starts the `gpg-agent` program, which caches the key for a configurable amount of time. The `$HOME/.gnupg/gpg-agent.conf` file contains options for `gpg-agent`. [Here](https://www.gnupg.org/documentation/manuals/gnupg/Agent-Options.html#Agent-Options) is the complete list of `gpg-agent` options.\n",
    "\n",
    "Example config file with some useful options:\n",
    "***\n",
    "```\n",
    "# Set the time a cache entry is valid to 600 seconds. Each time a\n",
    "# cache entry is accessed, the entry’s timer is reset.\n",
    "default-cache-ttl 600\n",
    "\n",
    "# Set the maximum time a cache entry is valid to 7200 seconds. After\n",
    "# this a cache entry will be expired even if it has been accessed recently.\n",
    "max-cache-ttl 7200\n",
    "\n",
    "# MacOS only: Connect gpg-agent to the keychain via the pinentry program\n",
    "# from GPGtools. Run \"brew install pinentry-mac\" to install.\n",
    "pinentry-program /usr/local/bin/pinentry-mac\n",
    "```\n",
    "***\n",
    "<br>\n",
    "\n",
    "## Pull-requesting a branch with unverified commits\n",
    "\n",
    "If you attempt to PR a branch containing unsigned/unverified commits, merging will be blocked.\n",
    "\n",
    "![An example of a PR with unverified commits](images/github_unsigned_pr.png)\n",
    "\n",
    "To fix this problem, you'll need to overwrite the unverified commits.\n",
    "1. Start by recommitting from the local repository of your development branch: `git rebase -i <commit before first problematic commit>`\n",
    "2. Your text editor will open up. Change every `pick` to `edit`.\n",
    "3. Save the file and exit the editor.\n",
    "4. Run `git commit --amend -S`, followed by `git rebase --continue`. Repeat until you get a message like `Successfully rebased and updated refs/heads/<branchname>`.\n",
    "5. Run `git push --force-with-lease`\n",
    "\n",
    "*Adapted from [stackoverflow](https://stackoverflow.com/questions/59351257/unverified-commits-in-github)*\n"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "plaintext"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
