diff --git a/.markdownlint.yaml b/.markdownlint.yaml index fbb5761..d0315a1 100644 --- a/.markdownlint.yaml +++ b/.markdownlint.yaml @@ -25,4 +25,7 @@ "MD046": false # We need inline HTML to embed YouTube videos -"MD033": false \ No newline at end of file +"MD033": false + +# Allow the use of links based on our common-links snippets +"MD052": false \ No newline at end of file diff --git a/docs/blog/posts/changelog/added-pixelfed.md b/docs/blog/posts/changelog/added-pixelfed.md index eb360c8..c8758b4 100644 --- a/docs/blog/posts/changelog/added-pixelfed.md +++ b/docs/blog/posts/changelog/added-pixelfed.md @@ -10,7 +10,7 @@ links: # New Recipe: Pixelfed - Federated image sharing. Think "looks like instagram, works like Mastodon" -New recipe - Pixelfed, like Instagram on the Fediverse. Check it out [here](/docs/recipes/pixelfed.md) +New recipe - Pixelfed, like Instagram on the Fediverse. Check it out [here](/docs/recipes/pixelfed/) diff --git a/docs/blog/posts/changelog/review-immich.md b/docs/blog/posts/changelog/review-immich.md index ee14f82..931c72d 100644 --- a/docs/blog/posts/changelog/review-immich.md +++ b/docs/blog/posts/changelog/review-immich.md @@ -10,7 +10,7 @@ links: # New Review: Immich -New recipe - Pixelfed, like Instagram on the Fediverse. Check it out [here](/docs/recipes/pixelfed.md) +New recipe - Pixelfed, like Instagram on the Fediverse. Check it out [here](/docs/recipes/pixelfed/) diff --git a/docs/blog/posts/changelog/review-pixelfed.md b/docs/blog/posts/changelog/review-pixelfed.md deleted file mode 100644 index 974adb7..0000000 --- a/docs/blog/posts/changelog/review-pixelfed.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -date: 2022-11-10 -categories: - - CHANGELOG -tags: - - pixelfed -links: - - Get Support!: support.md ---- - -# New Review: Pixelfed - -New recipe - Pixelfed, like Instagram on the Fediverse. Check it out [here](/docs/recipes/pixelfed.md) - - - -[Pixelfed](https://pixelfed.org) is a free and ethical, open-source, federated (*i.e., decentralized*) social image sharing platform. As [Mastodon][mastodon] is to Twitter, so Pixelfed is to Instagram. Pixelfed uses the ActivityPub protocol, allowing users to interact with other users (*on other servers*) within the protocol, such as Mastodon, PeerTube, and Friendica, making Pixelfed a part of the Fediverse. - -Much like Mastodon, Pixelfed implements chronological timelines with no implementation of content manipulation algorithms and is privacy-focused with no third party analytics or tracking. It only allows users over 16 years old to use. - ---8<-- "common-links.md" \ No newline at end of file diff --git a/docs/community/contribute.md b/docs/community/contribute.md index c4303fb..fb1ceb8 100644 --- a/docs/community/contribute.md +++ b/docs/community/contribute.md @@ -59,8 +59,8 @@ The process is basically: 1. [Fork the repo](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) 2. Clone your forked repo locally 3. Make a new branch for your recipe (*not strictly necessary, but it helps to differentiate multiple in-flight recipes*) -4. Create your new recipe as a markdown file within the existing structure of the [manuscript folder](https://github.com/geek-cookbook/geek-cookbook/tree/master/manuscript) -5. Add your recipe to the navigation by editing [mkdocs.yml](https://github.com/geek-cookbook/geek-cookbook/blob/master/mkdocs.yml#L32) +4. Create your new recipe as a markdown file within the existing structure of the [docs folder](https://github.com/geek-cookbook/geek-cookbook/tree/main/docs) +5. Add your recipe to the navigation by editing [mkdocs.yml](https://github.com/geek-cookbook/geek-cookbook/blob/main/mkdocs.yml#L32) 6. Test locally by running `./scripts/serve.sh` in the repo folder (*this launches a preview in Docker*), and navigating to 7. Rinse and repeat until you're ready to submit a PR 8. Create a pull request via the GitHub UI diff --git a/docs/docker-swarm/authelia.md b/docs/docker-swarm/authelia.md index 60d9cc6..7144fcd 100644 --- a/docs/docker-swarm/authelia.md +++ b/docs/docker-swarm/authelia.md @@ -18,7 +18,7 @@ Features include * Lockout users after too many failed login attempts * Highly Customizable Access Control using rules to match criteria such as subdomain, username, groups the user is in, and Network * Authelia [Community](https://discord.authelia.com/) Support -* Full list of features can be viewed [here](https://www.authelia.com/docs/features/) +* Full list of features can be viewed [here](https://www.authelia.com/) ## Authelia requirements @@ -42,7 +42,7 @@ mkdir /var/data/config/authelia ### Create Authelia config file -Authelia configurations are defined in `/var/data/config/authelia/configuration.yml`. Some are required and some are optional. The following is a variation of the default example config file. Optional configuration settings can be viewed on in [Authelia's documentation](https://www.authelia.com/docs/configuration/) +Authelia configurations are defined in `/var/data/config/authelia/configuration.yml`. Some are required and some are optional. The following is a variation of the default example config file. Optional configuration settings can be viewed on in [Authelia's documentation](https://www.authelia.com/configuration/prologue/introduction/) !!! warning Your variables may vary significantly from what's illustrated below, and it's best to read up and understand exactly what each option does. diff --git a/docs/docker-swarm/traefik-forward-auth/dex-static.md b/docs/docker-swarm/traefik-forward-auth/dex-static.md index 3092085..21a98b7 100644 --- a/docs/docker-swarm/traefik-forward-auth/dex-static.md +++ b/docs/docker-swarm/traefik-forward-auth/dex-static.md @@ -180,7 +180,7 @@ Once you redeploy traefik-forward-auth with the above, it **should** use dex as ### Test -Browse to (*obviously, customized for your domain and having created a DNS record*), and all going according to plan, you'll be redirected to a CoreOS Dex login. Once successfully logged in, you'll be directed to the basic whoami page :thumbsup: +Browse to `https://whoami.example.com` (*obviously, customized for your domain and having created a DNS record*), and all going according to plan, you'll be redirected to a CoreOS Dex login. Once successfully logged in, you'll be directed to the basic whoami page :thumbsup: ### Protect services diff --git a/docs/docker-swarm/traefik-forward-auth/google.md b/docs/docker-swarm/traefik-forward-auth/google.md index a98a841..c6ebcde 100644 --- a/docs/docker-swarm/traefik-forward-auth/google.md +++ b/docs/docker-swarm/traefik-forward-auth/google.md @@ -18,7 +18,7 @@ This recipe will illustrate how to point Traefik Forward Auth to Google, confirm Log into , create a new project then search for and select "**Credentials**" in the search bar. - Fill out the "OAuth Consent Screen" tab, and then click, "**Create Credentials**" > "**OAuth client ID**". Select "**Web Application**", fill in the name of your app, skip "**Authorized JavaScript origins**" and fill "**Authorized redirect URIs**" with either all the domains you will allow authentication from, appended with the url-path (*e.g. , , etc*), or if you don't like frustration, use a "auth host" URL instead, like "**" (*see below for details*) + Fill out the "OAuth Consent Screen" tab, and then click, "**Create Credentials**" > "**OAuth client ID**". Select "**Web Application**", fill in the name of your app, skip "**Authorized JavaScript origins**" and fill "**Authorized redirect URIs**" with either all the domains you will allow authentication from, appended with the url-path (*e.g. `https://radarr.example.com/_oauth`, `https://radarr.example.com/_oauth`, etc*), or if you don't like frustration, use a "auth host" URL instead, like "`https://auth.example.com/_oauth`" (*see below for details*) #### Monkey see, monkey do 🙈 @@ -38,9 +38,11 @@ SECRET= # comment out AUTH_HOST if you'd rather use individual redirect_uris (slightly less complicated but more work) AUTH_HOST=auth.example.com COOKIE_DOMAINS=example.com -WHITELIST=you@yourdomain.com, me@mydomain.com +WHITELIST=you@yourdomain.com, me@mydomain.com # (1)! ``` +1. Whitelist should match your Google account email address(es) [^1] + ### Prepare the docker service config Create `/var/data/config/traefik-forward-auth/traefik-forward-auth.yml` as per the following example: @@ -118,7 +120,7 @@ Deploy traefik-forward-auth with ```docker stack deploy traefik-forward-auth -c ### Test -Browse to (*obviously, customized for your domain and having created a DNS record*), and all going according to plan, you should be redirected to a Google login. Once successfully logged in, you'll be directed to the basic whoami page. +Browse to `https://whoami.example.com` (*obviously, customized for your domain and having created a DNS record*), and all going according to plan, you should be redirected to a Google login. Once successfully logged in, you'll be directed to the basic whoami page. ## Summary diff --git a/docs/docker-swarm/traefik-forward-auth/index.md b/docs/docker-swarm/traefik-forward-auth/index.md index e26c6b8..e0aaba4 100644 --- a/docs/docker-swarm/traefik-forward-auth/index.md +++ b/docs/docker-swarm/traefik-forward-auth/index.md @@ -20,7 +20,7 @@ This is the role of Traefik Forward Auth. **Normally**, Traefik proxies web requests directly to individual web apps running in containers. The user talks directly to the webapp, and the webapp is responsible for ensuring appropriate authentication. -When employing Traefik Forward Auth as "[middleware](https://doc.traefik.io/traefik/middlewares/forwardauth/)", the forward-auth process sits in the middle of this transaction - traefik receives the incoming request, "checks in" with the auth server to determine whether or not further authentication is required. If the user is authenticated, the auth server returns a 200 response code, and Traefik is authorized to forward the request to the backend. If not, traefik passes the auth server response back to the user - this process will usually direct the user to an authentication provider (*[Google][tfa-google], [Keycloak][tfa-keycloak], and [Dex][tfa-dex-static] are common examples*), so that they can perform a login. +When employing Traefik Forward Auth as "[middleware](https://doc.traefik.io/traefik/middlewares/http/forwardauth/)", the forward-auth process sits in the middle of this transaction - traefik receives the incoming request, "checks in" with the auth server to determine whether or not further authentication is required. If the user is authenticated, the auth server returns a 200 response code, and Traefik is authorized to forward the request to the backend. If not, traefik passes the auth server response back to the user - this process will usually direct the user to an authentication provider (*[Google][tfa-google], [Keycloak][tfa-keycloak], and [Dex][tfa-dex-static] are common examples*), so that they can perform a login. Illustrated below: ![Traefik Forward Auth](/images/traefik-forward-auth.png){ loading=lazy } @@ -35,9 +35,9 @@ Under normal Oauth2 / OIDC auth, you have to tell your auth provider which URLs ### How does it work? -Say for example, you're protecting **radarr.example.com**. When you first browse to ****, Traefik forwards your session to traefik-forward-auth, to be authenticated. Traefik-forward-auth redirects you to your OIDC provider's login, but instructs the OIDC provider to redirect a successfully authenticated session **back** to ****, rather than to ****. +Say for example, you're protecting **radarr.example.com**. When you first browse to `https://radarr.example.com`, Traefik forwards your session to traefik-forward-auth, to be authenticated. Traefik-forward-auth redirects you to your OIDC provider's login, but instructs the OIDC provider to redirect a successfully authenticated session **back** to `https://auth.example.com/_oauth`, rather than to `https://radarr.example.com/_oauth`. -When you successfully authenticate against the OIDC provider, you are redirected to the "_redirect_uri_" of . Again, your request hits Traefik, which forwards the session to traefik-forward-auth, which **knows** that you've just been authenticated (*cookies have a role to play here*). Traefik-forward-auth also knows the URL of your **original** request (*thanks to the X-Forwarded-Host header*). Traefik-forward-auth redirects you to your original destination, and everybody is happy. +When you successfully authenticate against the OIDC provider, you are redirected to the "_redirect_uri_" of `https://auth.example.com`. Again, your request hits Traefik, which forwards the session to traefik-forward-auth, which **knows** that you've just been authenticated (*cookies have a role to play here*). Traefik-forward-auth also knows the URL of your **original** request (*thanks to the X-Forwarded-Host header*). Traefik-forward-auth redirects you to your original destination, and everybody is happy. This clever workaround only works under 2 conditions: diff --git a/docs/docker-swarm/traefik-forward-auth/keycloak.md b/docs/docker-swarm/traefik-forward-auth/keycloak.md index fc61238..1e65329 100644 --- a/docs/docker-swarm/traefik-forward-auth/keycloak.md +++ b/docs/docker-swarm/traefik-forward-auth/keycloak.md @@ -71,7 +71,7 @@ Redeploy traefik with `docker stack deploy traefik-app -c /var/data/traefik/trae ### Test -Browse to (_obviously, customized for your domain and having created a DNS record_), and all going according to plan, you'll be redirected to a Keycloak login. Once successfully logged in, you'll be directed to the basic whoami page. +Browse to `https://whoami.example.com` (_obviously, customized for your domain and having created a DNS record_), and all going according to plan, you'll be redirected to a Keycloak login. Once successfully logged in, you'll be directed to the basic whoami page. ### Protect services diff --git a/docs/index.md b/docs/index.md index 324bdfd..e449acd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -79,7 +79,7 @@ So if you're familiar enough with the concepts above, and you've done self-hosti I have no hesitation in recommending him for your project, and I'll certainly be calling on him again in the future. - -- John McDowall, Founder, [kiso.io](https://kiso.io) + -- John McDowall, Founder, kiso.io (*since defunct, not my fault!*) ## Who made this? @@ -94,7 +94,7 @@ I want your [support](https://github.com/sponsors/funkypenguin), either in the [ #### Get in touch 💬 - Come and say hi to me and the friendly geeks in the [Discord](http://chat.funkypenguin.co.nz) chat or the [Discourse](https://forum.funkypenguin.co.nz/) forums - say hi, ask a question, or suggest a new recipe! -- Toot me up, I'm [@funkypenguin](https://so.fnky.nz/@funkypengui)! 🐘 +- Toot me up, I'm [@funkypenguin](https://so.fnky.nz/@funkypenguin)! 🐘 - [Contact me](https://www.funkypenguin.co.nz/contact/) by a variety of channels #### [Sponsor](https://github.com/sponsors/funkypenguin) me ❤️ diff --git a/docs/kubernetes/backup/index.md b/docs/kubernetes/backup/index.md index 8514984..bde1b86 100644 --- a/docs/kubernetes/backup/index.md +++ b/docs/kubernetes/backup/index.md @@ -12,7 +12,7 @@ I've [reviewed Miniflux in detail on my blog](https://www.funkypenguin.co.nz/rev * Use the Bookmarklet to subscribe to a website directly from any browsers !!! abstract "2.0+ is a bit different" - [Some things changed](https://docs.miniflux.net/en/latest/migration.html) when Miniflux 2.0 was released. For one thing, the only supported database is now postgresql (_no more SQLite_). External themes are gone, as is PHP (_in favor of golang_). It's been a controversial change, but I'm keen on minimal and single-purpose, so I'm still very happy with the direction of development. The developer has laid out his [opinions](https://docs.miniflux.net/en/latest/opinionated.html) re the decisions he's made in the course of development. + [Some things changed](https://miniflux.app/docs/migration.html) when Miniflux 2.0 was released. For one thing, the only supported database is now postgresql (_no more SQLite_). External themes are gone, as is PHP (_in favor of golang_). It's been a controversial change, but I'm keen on minimal and single-purpose, so I'm still very happy with the direction of development. The developer has laid out his [opinions](https://miniflux.app/docs/opionated.html) re the decisions he's made in the course of development. ## Ingredients @@ -305,7 +305,7 @@ app miniflux.funkypenguin.co.nz 80 55d ### Access Miniflux -At this point, you should be able to access your instance on your chosen DNS name (*i.e. *) +At this point, you should be able to access your instance on your chosen DNS name (*i.e. `https://miniflux.example.com`) ### Troubleshooting diff --git a/docs/kubernetes/cluster/digitalocean.md b/docs/kubernetes/cluster/digitalocean.md index f1814da..b0154ad 100644 --- a/docs/kubernetes/cluster/digitalocean.md +++ b/docs/kubernetes/cluster/digitalocean.md @@ -72,6 +72,6 @@ festive-merkle-8n9e Ready 58s v1.13.1 That's it. You have a beautiful new kubernetes cluster ready for some action! -[^1]: Do you live in the CLI? Install the kubectl autocompletion for [bash](https://kubernetes.io/docs/tasks/tools/included/optional-kubectl-configs-bash-linux/) or [zsh](https://kubernetes.io/docs/tasks/tools/included/optional-kubectl-configs-zsh/) to make your life much easier! +[^1]: Do you live in the CLI? Install the kubectl autocompletion for [bash or zsh](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/) to make your life much easier! --8<-- "recipe-footer.md" diff --git a/docs/kubernetes/cluster/k3s.md b/docs/kubernetes/cluster/k3s.md index d7a559d..d74984e 100644 --- a/docs/kubernetes/cluster/k3s.md +++ b/docs/kubernetes/cluster/k3s.md @@ -152,7 +152,7 @@ k3s will have saved your kubeconfig file on the masters to `/etc/rancher/k3s/k3s Cuddle your beautiful new cluster by running `kubectl cluster-info` [^1] - if that doesn't work, check your k3s logs[^2]. -[^1]: Do you live in the CLI? Install the kubectl autocompletion for [bash](https://kubernetes.io/docs/tasks/tools/included/optional-kubectl-configs-bash-linux/) or [zsh](https://kubernetes.io/docs/tasks/tools/included/optional-kubectl-configs-zsh/) to make your life much easier! +[^1]: Do you live in the CLI? Install the kubectl autocompletion for [bash or zsh](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/) to make your life much easier! [^2]: Looking for your k3s logs? Under Ubuntu LTS, run `journalctl -u k3s` to show your logs [^3]: k3s is not the only "lightweight kubernetes" game in town. Minikube (*virtualization-based*) and mikrok8s (*possibly better for Ubuntu users since it's installed in a "snap" - haha*) are also popular options. One day I'll write a "mikrok8s vs k3s" review, but it doesn't really matter for our cluster operations - as I understand it, microk8s makes HA clustering slightly easire than k3s, but you get slightly less "out-of-the-box" in return, so mikrok8s may be more suitable for experience users / production edge deployments. diff --git a/docs/kubernetes/index.md b/docs/kubernetes/index.md index 0fd5c07..24f3d4a 100644 --- a/docs/kubernetes/index.md +++ b/docs/kubernetes/index.md @@ -17,7 +17,7 @@ Sorry to say, but from where I sit, there's no innovation or development happeni Yes, I know, after Docker Inc [sold its platform business to Mirantis in Nov 2019](https://www.mirantis.com/blog/mirantis-acquires-docker-enterprise-platform-business/), in Feb 2020 Mirantis [back-tracked](https://www.mirantis.com/blog/mirantis-will-continue-to-support-and-develop-docker-swarm/) on their original plan to sunset swarm after 2 years, and stated that they'd continue to invest in swarm. But seriously, look around. Nobody is interested in swarm right now... -... Not even Mirantis! As of Nov 2021, the Mirantis blog tag "[kubernetes](https://www.mirantis.com/tag/kubernetes/)" had 8 posts within the past month. The tag "[docker](https://www.mirantis.com/tag/docker/)" has 8 posts in the past **2 years**, the 8th being the original announcement of the Docker aquisition. The tag "[docker swarm](https://www.mirantis.com/tag/docker-swarm/)" has only 2 posts, **ever**. +... Not even Mirantis! As of Nov 2021, the Mirantis blog tag "[kubernetes](https://www.mirantis.com/blog/tag/kubernetes/)" had 8 posts within the past month. The tag "[docker](https://www.mirantis.com/blog/tag/docker/)" has 8 posts in the past **2 years**, the 8th being the original announcement of the Docker aquisition. The tag "[docker swarm](https://www.mirantis.com/blog/tag/docker-swarm/)" has only 2 posts, **ever**. Dead. [Extinct. Like the doodoo](https://youtu.be/NxnZC9L_YXE?t=47). diff --git a/docs/kubernetes/ingress/index.md b/docs/kubernetes/ingress/index.md index cd68c66..dacbac5 100644 --- a/docs/kubernetes/ingress/index.md +++ b/docs/kubernetes/ingress/index.md @@ -3,7 +3,7 @@ description: What is a Kubernetes Ingress? --- # Ingresses -In Kubernetes, an Ingress is a way to describe how to route traffic coming **into** the cluster, so that (*for example*) will end up on a [Radarr][radarr] pod, but will end up on a [Sonarr][sonarr] pod. +In Kubernetes, an Ingress is a way to describe how to route traffic coming **into** the cluster, so that (*for example*) `https://radarr.example.com` will end up on a [Radarr][radarr] pod, but `https://sonarr.example.com` will end up on a [Sonarr][sonarr] pod. ![Ingress illustration](/images/ingress.jpg) diff --git a/docs/kubernetes/monitoring/index.md b/docs/kubernetes/monitoring/index.md index 8514984..309165c 100644 --- a/docs/kubernetes/monitoring/index.md +++ b/docs/kubernetes/monitoring/index.md @@ -305,7 +305,7 @@ app miniflux.funkypenguin.co.nz 80 55d ### Access Miniflux -At this point, you should be able to access your instance on your chosen DNS name (*i.e. *) +At this point, you should be able to access your instance on your chosen DNS name (*i.e. `https://miniflux.example.com`) ### Troubleshooting diff --git a/docs/recipes/kavita.md b/docs/recipes/kavita.md index 0397051..41d27e8 100644 --- a/docs/recipes/kavita.md +++ b/docs/recipes/kavita.md @@ -9,7 +9,7 @@ So you've just watched a bunch of superhero movies, and you're suddenly inspired ![Kavita Screenshot](/images/kavita.png){ loading=lazy } -[Kavita Reader](https://www.kavitareader.com) is a "*rocket fueled self-hosted digital library which supports a vast array of file formats*". Primarily used for cosuming Manga (*but quite capable of managing ebooks too*), Kavita's killer feature is an OPDS server for integration with other mobile apps such as [Chunky on iPad](http://chunkyreader.com/), and the ability to save your reading position across multiple devices. +[Kavita Reader](https://www.kavitareader.com) is a "*rocket fueled self-hosted digital library which supports a vast array of file formats*". Primarily used for cosuming Manga (*but quite capable of managing ebooks too*), Kavita's killer feature is an OPDS server for integration with other mobile apps such as [Chunky on iPad](https://apps.apple.com/us/app/chunky-comic-reader/id663567628), and the ability to save your reading position across multiple devices. There's a [public demo available](https://www.kavitareader.com/#demo) too! diff --git a/docs/recipes/komga.md b/docs/recipes/komga.md index a870aef..81ad8c5 100644 --- a/docs/recipes/komga.md +++ b/docs/recipes/komga.md @@ -9,7 +9,7 @@ So you've just watched a bunch of superhero movies, and you're suddenly inspired ![Komga Screenshot](../images/komga.png){ loading=lazy } -[Komga](https://komga.org/) is a media server with a beautifully slick interface, allowing you to read your comics / manga in CBZ, CBR, PDF and epub format. Komga includes an integrated web reader, as well as a [Tachiyomi](https://tachiyomi.org/) plugin and an OPDS server for integration with other mobile apps such as [Chunky on iPad](http://chunkyreader.com/). +[Komga](https://komga.org/) is a media server with a beautifully slick interface, allowing you to read your comics / manga in CBZ, CBR, PDF and epub format. Komga includes an integrated web reader, as well as a [Tachiyomi](https://tachiyomi.org/) plugin and an OPDS server for integration with other mobile apps such as [Chunky on iPad](https://apps.apple.com/us/app/chunky-comic-reader/id663567628). ## Ingredients diff --git a/mkdocs.yml b/mkdocs.yml index dbb4870..e6bc9e9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -40,12 +40,12 @@ plugins: autolinks: macros: verbose: true - # htmlproofer: - # raise_error: True - # raise_error_excludes: - # 504: ['https://www.mkdocs.org/'] - # 404: ['https://github.com/manuzhang/mkdocs-htmlproofer-plugin'] - # 400: ['*'] + htmlproofer: + raise_error: false + raise_error_excludes: + 504: ['https://www.mkdocs.org/'] + 404: ['https://github.com/manuzhang/mkdocs-htmlproofer-plugin'] + 400: ['*'] # git-committers: # This seems to create double-ups # repository: geek-cookbook/geek-cookbook # token: !ENV GH_TOKEN