From 7f38cae9dc6fabbe015b492229743a0eac61e5ed Mon Sep 17 00:00:00 2001 From: Jacob Hummer Date: Fri, 9 Jun 2023 15:55:12 -0500 Subject: [PATCH 1/3] Move github.ttoken stuff to new page --- wiki/Home.md | 123 ------------------------------------------- wiki/github.token.md | 121 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 123 deletions(-) create mode 100644 wiki/github.token.md diff --git a/wiki/Home.md b/wiki/Home.md index 035ea31..e69de29 100644 --- a/wiki/Home.md +++ b/wiki/Home.md @@ -1,123 +0,0 @@ - - -## How `${{ github.token }}` works - -When you interact with GitHub stuff, you need to be authenticated. In a GitHub -Action, this means using the `${{ github.token }}`. - -The `${{ github.token }}` is a special access token that you can use to -authenticate on behalf of GitHub Actions. GitHub automatically creates -a `${{ github.token }}` secret for you to use in your workflow, and you can use -it to authenticate in a workflow run. - -The way this works is that when you enable GitHub Actions in a repository, -GitHub installs a GitHub App on your repository. -The `${{ github.token }}` secret is a GitHub App installation access token. You -can use the installation access token to authenticate on behalf of the GitHub -App installed on your repository. The token's permissions are limited to the -repository that contains your workflow. - -Before each job begins, GitHub fetches an installation access token for the -job. The `${{ github.token }}` expires when a job finishes or after a maximum of -24 hours. - -The token is also available as the `$GITHUB_TOKEN` env variable in most places -without needing to be explicitly passed around. - -### Best practices - -You can use the `${{ github.token }}` by using the standard syntax for -referencing secrets: `${{ secrets.GITHUB_TOKEN }}`. You can pass the token as an -input to an action, or use it to make an authenticated GitHub API request. If -you are using a custom PAT, you should also avoid hardcoding the token value in -your workflow file or scripts. Instead, use `${{ secrets.MY_PAT }}`. - -Modern GitHub Actions will also default to using the current workflow's -`${{ github.token }}` value if non is provided by the user. This implicit token -passing makes workflows drasticly simpler. As a good security practice, you -should always make sure that actions only have the minimum access they require -by limiting the permissions granted to the `${{ github.token }}`. - -### How it's generated - -The `${{ github.token }}` is not a personal access token. It is a GitHub App -installation access token that is automatically created by GitHub when you -enable GitHub Actions in a repository. - -You do not need to create or manage the token yourself. You also do not need to -renew or rotate the token, as GitHub does that for you before each job. - -### Permissions - -| Scope | Permissive | Restricted | Max fork perms | -| ------------------- | ---------- | ---------- | -------------- | -| actions | read/write | | read | -| checks | read/write | | read | -| contents | read/write | read | read | -| deployments | read/write | | read | -| id-token | | | read | -| issues | read/write | | read | -| metadata | read | read | read | -| packages | read/write | read | read | -| pages | read/write | | read | -| pull-requests | read/write | | read | -| repository-projects | read/write | | read | -| security-events | read/write | | read | -| statuses | read/write | | read | - -You can change any of these permissions using the `permissions:` option in your -workflow `.yml` files. - -```yaml -permissions: - issues: write - contents: read -``` - -### Authentication - -You can use the `${{ github.token }}` to authenticate on the command line when -cloning a repository. You can enter the token instead of your password when -performing Git operations over HTTPS. - -For example, on the command line you would enter the following: - -```sh -git clone https://github.com/username/repo.git -``` - -``` -Username: your_username -Password: your_token -``` - -You can also use the token as part of the URL, like this: - -```sh -git clone https://your_username:your_token@github.com/username/repo.git -``` - -However, this is less secure and not recommended, as the token may be exposed in -plain text or in your shell history. - -If you are not prompted for your username and password, your credentials may be -cached on your computer. You can update your credentials in the Keychain or -Credential Manager to replace your old password with the token. - -Alternatively, you can use a credential helper to cache your token with a Git -client. - -```sh -gh auth setup-git -``` - -You can use the runner builtin `gh` CLI to configure `git` to use GitHub CLI as -a credential helper for all authenticated hosts. Alternatively, you can use -the `--hostname` flag to specify a single host to be configured. - -📚 Further reading: [Git - gitcredentials Documentation] - -[Git - gitcredentials Documentation]: https://git-scm.com/docs/gitcredentials diff --git a/wiki/github.token.md b/wiki/github.token.md new file mode 100644 index 0000000..a56f90c --- /dev/null +++ b/wiki/github.token.md @@ -0,0 +1,121 @@ + + +When you interact with GitHub stuff, you need to be authenticated. In a GitHub +Action, this means using the `${{ github.token }}`. + +The `${{ github.token }}` is a special access token that you can use to +authenticate on behalf of GitHub Actions. GitHub automatically creates +a `${{ github.token }}` secret for you to use in your workflow, and you can use +it to authenticate in a workflow run. + +The way this works is that when you enable GitHub Actions in a repository, +GitHub installs a GitHub App on your repository. +The `${{ github.token }}` secret is a GitHub App installation access token. You +can use the installation access token to authenticate on behalf of the GitHub +App installed on your repository. The token's permissions are limited to the +repository that contains your workflow. + +Before each job begins, GitHub fetches an installation access token for the +job. The `${{ github.token }}` expires when a job finishes or after a maximum of +24 hours. + +The token is also available as the `$GITHUB_TOKEN` env variable in most places +without needing to be explicitly passed around. + +## Best practices + +You can use the `${{ github.token }}` by using the standard syntax for +referencing secrets: `${{ secrets.GITHUB_TOKEN }}`. You can pass the token as an +input to an action, or use it to make an authenticated GitHub API request. If +you are using a custom PAT, you should also avoid hardcoding the token value in +your workflow file or scripts. Instead, use `${{ secrets.MY_PAT }}`. + +Modern GitHub Actions will also default to using the current workflow's +`${{ github.token }}` value if non is provided by the user. This implicit token +passing makes workflows drasticly simpler. As a good security practice, you +should always make sure that actions only have the minimum access they require +by limiting the permissions granted to the `${{ github.token }}`. + +## How it's generated + +The `${{ github.token }}` is not a personal access token. It is a GitHub App +installation access token that is automatically created by GitHub when you +enable GitHub Actions in a repository. + +You do not need to create or manage the token yourself. You also do not need to +renew or rotate the token, as GitHub does that for you before each job. + +## Permissions + +| Scope | Permissive | Restricted | Max fork perms | +| ------------------- | ---------- | ---------- | -------------- | +| actions | read/write | | read | +| checks | read/write | | read | +| contents | read/write | read | read | +| deployments | read/write | | read | +| id-token | | | read | +| issues | read/write | | read | +| metadata | read | read | read | +| packages | read/write | read | read | +| pages | read/write | | read | +| pull-requests | read/write | | read | +| repository-projects | read/write | | read | +| security-events | read/write | | read | +| statuses | read/write | | read | + +You can change any of these permissions using the `permissions:` option in your +workflow `.yml` files. + +```yaml +permissions: + issues: write + contents: read +``` + +## Authentication + +You can use the `${{ github.token }}` to authenticate on the command line when +cloning a repository. You can enter the token instead of your password when +performing Git operations over HTTPS. + +For example, on the command line you would enter the following: + +```sh +git clone https://github.com/username/repo.git +``` + +``` +Username: your_username +Password: your_token +``` + +You can also use the token as part of the URL, like this: + +```sh +git clone https://your_username:your_token@github.com/username/repo.git +``` + +However, this is less secure and not recommended, as the token may be exposed in +plain text or in your shell history. + +If you are not prompted for your username and password, your credentials may be +cached on your computer. You can update your credentials in the Keychain or +Credential Manager to replace your old password with the token. + +Alternatively, you can use a credential helper to cache your token with a Git +client. + +```sh +gh auth setup-git +``` + +You can use the runner builtin `gh` CLI to configure `git` to use GitHub CLI as +a credential helper for all authenticated hosts. Alternatively, you can use +the `--hostname` flag to specify a single host to be configured. + +📚 Further reading: [Git - gitcredentials Documentation] + +[Git - gitcredentials Documentation]: https://git-scm.com/docs/gitcredentials From 2e4d66cbc6ef8570b9b44e3e7450dffc63a59129 Mon Sep 17 00:00:00 2001 From: Jacob Hummer Date: Fri, 9 Jun 2023 16:08:50 -0500 Subject: [PATCH 2/3] Move most comments to wiki page --- src/clone.sh | 80 +-------------------------------- src/init.sh | 45 ------------------- wiki/How-it-works.md | 104 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 124 deletions(-) create mode 100644 wiki/How-it-works.md diff --git a/src/clone.sh b/src/clone.sh index cedd2f4..24e7606 100755 --- a/src/clone.sh +++ b/src/clone.sh @@ -1,107 +1,34 @@ #!/bin/bash # Copyright 2023 Jacob Hummer # SPDX-License-Identifier: Apache-2.0 - -# Remember, this enables fail-fast mode! We want this for scripts. If a command -# returns a non-zero exit code, this -e makes us exit then-and-there. set -e -# When a job fails, you can re-run it with debug mode enabled. This is exposed -# to scripts via the ${{ runner.debug }} or $RUNNER_DEBUG variable. Here, we -# use the -n test to see if the $RUNNER_DEBUG exists. If so, we use the -x flag -# to print a '+ cmd arg1 arg2' of each command that's run in the script. This -# helps with debugging what commands and $VAR expansions are actually happening. if [[ -n $RUNNER_DEBUG ]]; then set -x fi -# We overwrite the $GITHUB_* environment variables with user-provided ones. -# GitHub Actions normally provides a bunch of $GITHUB_* env vars. These can -# be used in scripts to tailor them to the current GitHub thing (repo, issue, -# etc). Here, we want to use these same variables, but with our custom -# user-provided values instead. We overwrite the originals (in this process; -# we can't affect our parent process) with the user-provided (or default) -# values so that we can use the same $GITHUB_REPOSITORY semantics to refer to -# the current repo that the action is on (the default) or the user-provided -# repo that we want to use instead. We use the same var names to make it -# familiar. export GITHUB_TOKEN="$INPUT_TOKEN" export GITHUB_SERVER_URL="$INPUT_GITHUB_SERVER_URL" export GITHUB_REPOSITORY="$INPUT_REPOSITORY" -# This is the default host that gh uses for clones and commands without a repo -# context (a .git folder). We use Bash string magic to get the github.com part -# from a full origin (no pathname) like https://github.com => github.com. The -# '#*//' operation removes '*//' from the start of the string. That's the -# 'https://' chunk. With that gone, we are left with 'github.company.com' or -# something similar. export GH_HOST="${GITHUB_SERVER_URL#*//}" -# We configure some special $GIT_* environment variables to make it so that -# we can have our special .git folder (you know, the one that holds all the -# critical repo information & history?) in a completely different location -# from our working tree! Normally, $GIT_DIR is automagically determined by -# walking up the folders from your $PWD until '.git/' is found. In this case, -# we want that in a temp folder. Then, we use $GIT_WORK_TREE to control what -# the base folder or "root" of the $GIT_DIR's repo should be. Normally, this -# would be the $PWD, but we want to set it to the $INPUT_PATH which is -# probably a subfolder of the project somwhere! export GIT_DIR && GIT_DIR=$(mktemp -d) export GIT_WORK_TREE="$INPUT_PATH" -# This is just good practice to clean up after yourself. It's not needed per-se. -# This is a one-off Actions runner that will delete every part of itself after -# completion. It's a good habit nonetheless. trap 'rm -rf "$GIT_DIR"' SIGINT SIGTERM ERR EXIT -# This setup-git is a command is what makes it so that we can be authorized to -# do normal 'git clone' and 'git push' operations without using the gh CLI. It -# auto-adds the credentials for the host in $GH_HOST and any additional --host -# options passed to it. We need this to make it so that our 'git push' at the -# end of this script works! gh auth setup-git -# We also need to preemptively mark the $GIT_DIR as safe to use. Normally Git -# will protect you against doing insecure stuff in untrusted areas, and that's -# a good thing! In this case, though, we know that what we are doing in this -# temp folder is OK. git config --global --add safe.directory "$GIT_DIR" -# We clone the $GITHUB_REPOSITORY.wiki Git repo into a temp folder. This is -# a special Git repository that holds a flat file structure of markup files -# that are rendered on the Wiki tab in the GitHub web UI. We clone this repo -# into the aforementioned $GIT_DIR folder. We use the --bare option to make -# the underlying 'git clone' command that's run create just a .git folder -# without pulling out all the initial files (which is the default behaviour). -# So, we'll have a .git-like folder sitting in /tmp/id.1234 which we want to -# use as our .git folder that we commit to and use for the rest of the Git -# stuff. The $GIT_WORK_TREE is already set to use the $INPUT_PATH (likely a -# folder like 'wiki/'). git clone "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY.wiki.git" "$GIT_DIR" --bare -# This is a trick to make the git CLI think that there should be a worktree too! -# By default, --bare Git repos are pretty inert. We unset this and then use our -# previously configured $GIT_WORK_TREE. git config --unset core.bare -# We are using .gitignore syntax for the 'ignore' option. Here's where we put it -# to good use! We then immediately add everything verbosely to "apply" it. echo "$INPUT_IGNORE" >>"$GIT_DIR/info/exclude" git add -Av -# This sets the default author & committer for the Git commit that we make. If -# you want to change this, you can! You can set the $GIT_AUTHOR_* and -# $GIT_COMMITTER_* env vars in your workflow and they should pass down to this -# 'git commit' operation. These values are from one of the popular Git commit -# actions: stefanzweifel/git-auto-commit-action [1] -# -# [1]: https://github.com/stefanzweifel/git-auto-commit-action/blob/master/action.yml#L35-L42 +# https://github.com/stefanzweifel/git-auto-commit-action/blob/master/action.yml#L35-L42 git config user.name github-actions[bot] git config user.email 41898282+github-actions[bot]@users.noreply.github.com -# Allowing an empty commit is way easier than detecting empty commits! This also -# makes semantic sense. If you run this action, it adds a commit to your wiki. -# How large that commit is comes down to your changes. 0 change = commit with 0. -# This works well with the default "Update wiki ${{ github.sha }}" message so -# that even if the commit is empty, the message has the SHA there. git commit --allow-empty -m "$INPUT_COMMIT_MESSAGE" -# If we are given 'dry-run: true', then we want to just print changes and stop -# without pushing. This is only used in testing right now. if [[ $INPUT_DRY_RUN == true ]]; then echo 'Dry run' git remote show origin @@ -109,9 +36,4 @@ if [[ $INPUT_DRY_RUN == true ]]; then exit 0 fi -# This is the pushing operation! The origin remote looks something like: -# "https://github.com/octocat/awesome.wiki.git" with no token attached. That -# 'gh auth setup-git' is what makes the username & password automagically attach -# to that 'github.com' hostname! We aren't using -u or -f here since there -# shouldn't be a need. git push origin master diff --git a/src/init.sh b/src/init.sh index 4466ac8..ec26683 100755 --- a/src/init.sh +++ b/src/init.sh @@ -1,66 +1,21 @@ #!/bin/bash # Copyright 2023 Jacob Hummer # SPDX-License-Identifier: Apache-2.0 - -# Remember, this enables fail-fast mode! We want this for scripts. If a command -# returns a non-zero exit code, this -e makes us exit then-and-there. set -e -# When a job fails, you can re-run it with debug mode enabled. This is exposed -# to scripts via the ${{ runner.debug }} or $RUNNER_DEBUG variable. Here, we -# use the -n test to see if the $RUNNER_DEBUG exists. If so, we use the -x flag -# to print a '+ cmd arg1 arg2' of each command that's run in the script. This -# helps with debugging what commands and $VAR expansions are actually happening. if [[ -n $RUNNER_DEBUG ]]; then set -x fi -# We overwrite the $GITHUB_* environment variables with user-provided ones. -# GitHub Actions normally provides a bunch of $GITHUB_* env vars. These can -# be used in scripts to tailor them to the current GitHub thing (repo, issue, -# etc). Here, we want to use these same variables, but with our custom -# user-provided values instead. We overwrite the originals (in this process; -# we can't affect our parent process) with the user-provided (or default) -# values so that we can use the same $GITHUB_REPOSITORY semantics to refer to -# the current repo that the action is on (the default) or the user-provided -# repo that we want to use instead. We use the same var names to make it -# familiar. export GITHUB_TOKEN="$INPUT_TOKEN" export GITHUB_SERVER_URL="$INPUT_GITHUB_SERVER_URL" export GITHUB_REPOSITORY="$INPUT_REPOSITORY" -# This is the default host that gh uses for clones and commands without a repo -# context (a .git folder). We use Bash string magic to get the github.com part -# from a full origin (no pathname) like https://github.com => github.com. The -# '#*//' operation removes '*//' from the start of the string. That's the -# 'https://' chunk. With that gone, we are left with 'github.company.com' or -# something similar. export GH_HOST="${GITHUB_SERVER_URL#*//}" -# We configure some special $GIT_* environment variables to make it so that -# we can have our special .git folder (you know, the one that holds all the -# critical repo information & history?) in a completely different location -# from our working tree! Normally, $GIT_DIR is automagically determined by -# walking up the folders from your $PWD until '.git/' is found. In this case, -# we want that in a temp folder. Then, we use $GIT_WORK_TREE to control what -# the base folder or "root" of the $GIT_DIR's repo should be. Normally, this -# would be the $PWD, but we want to set it to the $INPUT_PATH which is -# probably a subfolder of the project somwhere! export GIT_DIR && GIT_DIR=$(mktemp -d) export GIT_WORK_TREE="$INPUT_PATH" -# This is just good practice to clean up after yourself. It's not needed per-se. -# This is a one-off Actions runner that will delete every part of itself after -# completion. It's a good habit nonetheless. trap 'rm -rf "$GIT_DIR"' SIGINT SIGTERM ERR EXIT -# This setup-git is a command is what makes it so that we can be authorized to -# do normal 'git clone' and 'git push' operations without using the gh CLI. It -# auto-adds the credentials for the host in $GH_HOST and any additional --host -# options passed to it. We need this to make it so that our 'git push' at the -# end of this script works! gh auth setup-git -# We also need to preemptively mark the $GIT_DIR as safe to use. Normally Git -# will protect you against doing insecure stuff in untrusted areas, and that's -# a good thing! In this case, though, we know that what we are doing in this -# temp folder is OK. git config --global --add safe.directory "$GIT_DIR" git init -b master diff --git a/wiki/How-it-works.md b/wiki/How-it-works.md new file mode 100644 index 0000000..f612bd8 --- /dev/null +++ b/wiki/How-it-works.md @@ -0,0 +1,104 @@ +**Quick Bash recap:** Remember that `if [[ -n $VAR ]]` means "if var is non-zero +length" and `if [[ -z $VAR ]]` means "if var is zero length". We use this to +check for the presence of variables too. + +At the top of the file, we first `set -e` like good programmers to make sure +that errors _do propogate_ instead of being swallowed. Then, we conditionally +`set -x` to debug log only if the current Job is in debug mode. + +When a job fails, you can re-run it with debug mode enabled. This is exposed +to scripts via the `${{ runner.debug }}` or `$RUNNER_DEBUG` variable. Here, we +use the -n test to see if the $RUNNER_DEBUG exists. If so, we use the `-x` flag +to print a `+ cmd arg1 arg2` of each command that's run in the script. This +helps with debugging what commands and `$VAR` expansions are actually happening. + +We use a convention of overwriting the existing `GITHUB_*` env vars with our own +equivalent settings that we recieved from the user in the `github-server-url:` +and `token:` inputs. This is just a convention so that we can continue to use +`$GITHUB_TOKEN`. + +```sh +# This is the default host that gh uses for clones and commands without a repo +# context (a .git folder). We use Bash string magic to get the github.com part +# from a full origin (no pathname) like https://github.com => github.com. The +# '#*//' operation removes '*//' from the start of the string. That's the +# 'https://' chunk. With that gone, we are left with 'github.company.com' or +# something similar. +export GH_HOST="${GITHUB_SERVER_URL#*//}" +``` + +```sh +# We configure some special $GIT_* environment variables to make it so that +# we can have our special .git folder (you know, the one that holds all the +# critical repo information & history?) in a completely different location +# from our working tree! Normally, $GIT_DIR is automagically determined by +# walking up the folders from your $PWD until '.git/' is found. In this case, +# we want that in a temp folder. Then, we use $GIT_WORK_TREE to control what +# the base folder or "root" of the $GIT_DIR's repo should be. Normally, this +# would be the $PWD, but we want to set it to the $INPUT_PATH which is +# probably a subfolder of the project somwhere! +export GIT_DIR && GIT_DIR=$(mktemp -d) +export GIT_WORK_TREE="$INPUT_PATH" +``` + +This `setup-git` is a command is what makes it so that we can be authorized to +do normal `git clone` and `git push` operations without using the gh CLI. It +auto-adds the credentials for the host in `$GH_HOST` and any additional `--host` +options passed to it. We need this to make it so that our `git push` at the +end of this script works! + +```sh +gh auth setup-git +``` + +We also need to preemptively mark the $GIT_DIR as safe to use. Normally Git +will protect you against doing insecure stuff in untrusted areas, and that's +a good thing! In this case, though, we know that what we are doing in this +temp folder is OK. + +## `clone.sh`-specific + +```sh +# We clone the $GITHUB_REPOSITORY.wiki Git repo into a temp folder. This is +# a special Git repository that holds a flat file structure of markup files +# that are rendered on the Wiki tab in the GitHub web UI. We clone this repo +# into the aforementioned $GIT_DIR folder. We use the --bare option to make +# the underlying 'git clone' command that's run create just a .git folder +# without pulling out all the initial files (which is the default behaviour). +# So, we'll have a .git-like folder sitting in /tmp/id.1234 which we want to +# use as our .git folder that we commit to and use for the rest of the Git +# stuff. The $GIT_WORK_TREE is already set to use the $INPUT_PATH (likely a +# folder like 'wiki/'). +git clone "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY.wiki.git" "$GIT_DIR" --bare +# This is a trick to make the git CLI think that there should be a worktree too! +# By default, --bare Git repos are pretty inert. We unset this and then use our +# previously configured $GIT_WORK_TREE. +git config --unset core.bare +``` + +```sh +# This sets the default author & committer for the Git commit that we make. If +# you want to change this, you can! You can set the $GIT_AUTHOR_* and +# $GIT_COMMITTER_* env vars in your workflow and they should pass down to this +# 'git commit' operation. These values are from one of the popular Git commit +# actions: stefanzweifel/git-auto-commit-action [1] +# +# [1]: https://github.com/stefanzweifel/git-auto-commit-action/blob/master/action.yml#L35-L42 +git config user.name github-actions[bot] +git config user.email 41898282+github-actions[bot]@users.noreply.github.com +``` + +Allowing an empty commit is way easier than detecting empty commits! This also +makes semantic sense. If you run this action, it adds a commit to your wiki. +How large that commit is comes down to your changes. 0 change = commit with 0. +This works well with the default `Update wiki ${{ github.sha }}` message so +that even if the commit is empty, the message has the SHA there. + +```sh +# This is the pushing operation! The origin remote looks something like: +# "https://github.com/octocat/awesome.wiki.git" with no token attached. That +# 'gh auth setup-git' is what makes the username & password automagically attach +# to that 'github.com' hostname! We aren't using -u or -f here since there +# shouldn't be a need. +git push origin master +``` From 249e3190fea366069d1c8fd677ec426061aa9768 Mon Sep 17 00:00:00 2001 From: Jacob Hummer Date: Fri, 9 Jun 2023 16:08:55 -0500 Subject: [PATCH 3/3] Add nice landing page --- wiki/Home.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/wiki/Home.md b/wiki/Home.md index e69de29..f3ead93 100644 --- a/wiki/Home.md +++ b/wiki/Home.md @@ -0,0 +1,15 @@ + + +👋 Hello! Welcome to our dual-purpose test wiki & dev wiki! If you're seeing +this in the Wiki tab, then the GitHub Action successfully pushed the +contents of the `wiki/` folder to the GitHub wiki. 🥳 + +To learn more about how this action works, check out the [How it works] page. +If you're more interested in using this action, head back to the [README] to get +started using it in your own repository! 🚀 + +[How it works]: How-it-works +[README]: https://github.com/Andrew-Chen-Wang/github-wiki-action#readme