{"id":21006216,"url":"https://github.com/derlin/rickroller","last_synced_at":"2025-05-15T01:33:51.010Z","repository":{"id":43666740,"uuid":"475569397","full_name":"derlin/rickroller","owner":"derlin","description":"RickRoll your friends like a pro! Just enter a webpage URL and let the magic happen. Every click on the page will send you to the one and only Rick Astley's iconic hit.","archived":false,"fork":false,"pushed_at":"2024-08-04T17:55:30.000Z","size":5749,"stargazers_count":10,"open_issues_count":3,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-12T13:13:51.969Z","etag":null,"topics":["best-practices","python","rickroll-website","rickrolling"],"latest_commit_sha":null,"homepage":"http://rroll.derlin.ch","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/derlin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-29T18:25:48.000Z","updated_at":"2025-03-20T04:55:18.000Z","dependencies_parsed_at":"2024-08-04T19:24:46.494Z","dependency_job_id":"aad59f7d-3c35-4cae-baa0-dc09707041a8","html_url":"https://github.com/derlin/rickroller","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derlin%2Frickroller","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derlin%2Frickroller/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derlin%2Frickroller/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derlin%2Frickroller/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/derlin","download_url":"https://codeload.github.com/derlin/rickroller/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254256755,"owners_count":22040354,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["best-practices","python","rickroll-website","rickrolling"],"created_at":"2024-11-19T08:49:57.444Z","updated_at":"2025-05-15T01:33:47.173Z","avatar_url":"https://github.com/derlin.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RickRoller\n\n\u003e RickRoller is a dumb (yet funny) project mostly used as a pretext to play with Google Cloud Run,\nGitHub Actions and to try Open Source best practices. Keep reading to know more about what I learned.\n\nTransform any web page into a RickRoller! Test it live\n:point_right: [**https://rroll.derlin.ch**](https://rroll.derlin.ch).\n\n\u003e [!NOTE]  \n\u003e The demo runs on Google Cloud Run and may take a moment to start... Be patient :).\n\u003e \n\u003e *I deployed it initially on [Divio](https://divio.com) (which is awesome, check it out), but some\n\u003e people used it to rickroll their friends with websites that were detected by AWS to be scams,\n\u003e and AWS forced me to take it down.*\n\n\u003c!-- ![big](https://user-images.githubusercontent.com/5463445/163544627-6fcf82e5-caf9-467c-b234-b0a496b93b5c.png) --\u003e\n\u003c!-- generated using https://screely.com --\u003e\n[![preview](https://github.com/derlin/rickroller/assets/5463445/e4568944-eb92-46bb-a0a8-7d6e78a8cd22)](https://tinyurl.eu.aldryn.io)\n\nSimply take a webpage, paste its URL into the box, and BAM! The same webpage will be displayed,\nbut every click will redirect you to the famous Rick Astley video,\n[never gonna give you up](https://www.youtube.com/watch?v=dQw4w9WgXcQ).\n\n:new: To make it even more efficient at trolling your friends, RickRoller can now disguise itself\nas an URL shortener (requires a database)!\nLearn more at [docs/persistence](docs/persistence.md).\n\nTo run RickRoller locally or deploy it using Docker, see [docs/quickstart](docs/quickstart.md).\nTo better understand how the RickRolling works, see [docs/rickrolling](docs/rickrolling.md).\n\n-------------\n\n\u003cp align=\"center\"\u003e\u003cb\u003e ⇓ ᗯᕼᗩT I ᒪEᗩᖇᑎEᗪ (December, 2022) ⇓ \u003c/b\u003e\u003c/p\u003e\n\n------------\n\n\u003e [!CAUTION]\n\u003e This documentation was written in December 2022. As technologies evolve, some of its content may be outdated.\n\u003e I hope though that the generic principles still hold.\n\n# Best practices\n\n\u003c!-- TOC start --\u003e\n- [Conventional Commits](#conventional-commits)\n- [GitHub Repository settings](#github-repository-settings)\n- [Codebase](#codebase)\n  * [Linters and SAST](#linters-and-sast)\n- [Docker images](#docker-images)\n  * [Labels](#labels)\n  * [Multi-stage build](#multi-stage-build)\n  * [HEALTHCHECK and USER](#healthcheck-and-user)\n  * [Multi-platform support](#multi-platform-support)\n- [GitHub CI](#github-ci)\n  * [Building docker images](#building-docker-images)\n  * [Keeping the GitHub Registry clean](#keeping-the-github-registry-clean)\n  * [Pushing docker images to both Docker Hub and GitHub Registry](#pushing-docker-images-to-both-docker-hub-and-github-registry)\n  * [Release automation: release-please](#release-automation-release-please)\n  * [Deploying to Cloud Run With GitHub Action](#deploying-to-cloud-run-with-github-action)\n    + [Google Project setup](#google-project-setup)\n    + [GitHub Action](#github-action)\n- [Other Tips and tricks](#other-tips-and-tricks)\n  * [Keep python dependencies up-to-date](#keep-python-dependencies-up-to-date)\n  * [Avoid SSRFs](#avoid-ssrfs)\n\u003c!-- TOC end --\u003e\n\n\u003c!-- TOC --\u003e\u003ca name=\"conventional-commits\"\u003e\u003c/a\u003e\n## Conventional Commits\n\nThis repository is using [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/).\n\nThis is a simple convention that is both for humans and machines.\nI am currently using the basic tags (`feat:` and `fix:`), plus the ones based on [the Angular conventions](\nhttps://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines)\n(`build:`, `chore:`, `ci:`, `docs:`, `style:`, `refactor:`, `perf:`, `test:`).\n\nThe advantage? By adding a semantic layer to git commits, one can automate lots of tasks such as CHANGELOG\nupdates, releases, version bumps, statistics, etc. There are lots of tools out there that support this convention,\nand it keeps growing!\n\n\u003c!-- TOC --\u003e\u003ca name=\"github-repository-settings\"\u003e\u003c/a\u003e\n## GitHub Repository settings\n\nLots of mistakes and chores can be avoided by properly configuring a GitHub repository.\nI am personally in favor of pull requests and clean linear history (squash and merge).\nBelow are the most important settings for this goal.\n\n**Protect your main branch**: under *Settings* \u003e *Branches*, create a new *Branch protection rule*\nfor your main branch. What you choose here depends on the project, but I would try to always check:\n\n- *require a pull request before merging*: this ensures no one is pushing directly to `main`.\n- *require status checks to pass before merging*: if you have some CI workflows, they should always\n  be green before anything is merged!\n- *include administrators*: this one is tricky. If you do not check it, admins will be able to bypass\n  all rules, meaning you could e.g. force push to `main` by mistake.  \n\n**Enforce a clean history**: this is a highly controversial subject, but I am personally in favor of one\ncommit, one feature (→ squash before merging). To enforce this in GitHub: \n\n* in *Settings* \u003e *General* \u003e *Pull Requests*, only check *Allow squash merging*;\n* in main branch protection, check *require linear history*.\n\n\n**Cleanup**: to limit the number of stale branches, check the following in *Settings* \u003e *General* \u003e *Pull Requests*:\n* *Automatically delete head branches*: branches are automatically deleted after a PR is merged.\n\n\u003c!-- TOC --\u003e\u003ca name=\"codebase\"\u003e\u003c/a\u003e\n## Codebase\n\n\u003c!-- TOC --\u003e\u003ca name=\"linters-and-sast\"\u003e\u003c/a\u003e\n### Linters and SAST\n\nProjects should ALWAYS use linting, code formatting rules, and SAST tools.\nThis eases collaboration and prevents big mistakes.\n\nEach language has its own tools. This specific project (Python + Docker) uses:\n\n* [~~black~~](https://github.com/psf/black) for (automatically) formatting python files (UPDATE 2024: use ruff!),\n* [~~bandit~~](https://bandit.readthedocs.io/) ~~for checking vulnerabilities in python files~~\n* [ruff](https://beta.ruff.rs/docs/) for linting and checking style + vulnerabilities in python files,\n* [checkov](https://checkov.io) for checking vulnerabilities in docker images.\n\nblack and ruff are listed under dev dependencies. To run the checks locally:\n```bash\npoetry run black --line-length 100 --check rickroll\npoetry run ruff rickroll\n```\n\nTo fix the problems automatically (when possible), run:\n```bash\n# formatting\n# automatically fix the formatting issue, if possible\npoetry run black --line-length 100 --experimental-string-processing rickroll\n# automatically fix the issues, if possible\npoetry run ruff --fix rickroll\n```\n\nAs checkov is quite heavy, it is run using a dedicated GitHub action in the CI.\nTo run it locally:\n```bash\npoetry run pip install checkov # install, without adding it to pyproject.toml\npoetry run checkov --framework dockerfile -f Dockerfile\n```\n\n\u003c!-- TOC --\u003e\u003ca name=\"docker-images\"\u003e\u003c/a\u003e\n## Docker images\n\n\u003c!-- TOC --\u003e\u003ca name=\"labels\"\u003e\u003c/a\u003e\n### Labels\n\nThe Docker image uses common labels from [opencontainers](\nhttps://github.com/opencontainers/image-spec/blob/main/annotations.md).\nThose are extracted automatically in the CI using [docker/metadata-action](\nhttps://github.com/docker/metadata-action).\nThey can also be set manually using the `--label` parameter:\n```bash\n# the --label parameter can be repeated as much as needed\ndocker build \\\n  --label org.opencontainers.image.title=rickroller \\\n  --label org.opencontainers.image.url=https://github.com/derlin/rickroller \\\n  -t rroll .\n```\n\nNote that opencontainers labels are supported by GitHub: the description,\netc. you provide will be used and displayed in the *packages* interface of GitHub. \n\n\u003c!-- TOC --\u003e\u003ca name=\"multi-stage-build\"\u003e\u003c/a\u003e\n### Multi-stage build\n\nThe Dockerfile uses [multi-stage build](https://docs.docker.com/develop/develop-images/multistage-build/).\nThe idea is to use multiple `FROM` in a Dockerfile. The first one(s) are there to build the different\nartifacts, which can then be copied into the final `FROM` section (the final image), that only contain\nwhat is needed to run them.\nThis way, the final image is kept at its minimum, which improves performance, storage, and security.\n\nSince the Flask app runs with `gunicorn`, the module doesn't need to be built/installed:\ngunicorn will find it automatically if it is located in the `pwd`.\nHence, I only need to create the virtual env (installing deps using poetry) in my build stage.\nIn the final image, I copy the virtual env from the previous step, and the `rickroll` folder from the\nhost.\n\nIf the module had to be properly installed in the final Docker image, one way to do it is\nto call `poetry build` in the builder. This will create a `*.whl` that can be copied in the\nfinal image and installed with pip.\nAnother way is simply to install it in the venv of the builder, then ensure that the venv is\nactivated in the final image (e.g. in an `entrypoint.sh`).\n\n\u003c!-- TOC --\u003e\u003ca name=\"healthcheck-and-user\"\u003e\u003c/a\u003e\n### HEALTHCHECK and USER\n\nAs checkov told me, Docker containers should provide a [health check\ninstruction](https://docs.docker.com/engine/reference/builder/#healthcheck).\nNote that this healthcheck is not used by Kubernetes, which defines its own, more powerful checks\nthrough `livenessProbe`, `readinessProbe`, and `startupProbe`.\n\nThe most common way to implement a health check is to use cURL (cf the official doc):\n```dockerfile\nHEALTHCHECK --interval=5m --timeout=3s \\\n  CMD curl -f http://localhost/ || exit 1\n```\n\nThis, however, requires `curl` to be installed in the container. As it would be a shame to install\nit (and thus increase the image size) only for the check, I used a python script instead.\nNote that the `requests` package is needed by the app, so I know it is available:\n```dockerfile\nHEALTHCHECK --start-period=5s --interval=1m --timeout=10s CMD python -c 'import requests' \\\n    'try:' \\\n    '  exit(0 if requests.get(\"http://localhost:8080\").status_code == 200 else 1)' \\\n    'except:' \\\n    '  exit(1)'\n```\n\nIn general, I suggest you try to find a way to reuse what you already have available in your image.\n\nDocker containers should also never run as root. Avoiding root is as easy as using `USER xxx`.\nBe careful though: if you copy some files that were generated (e.g. in your builder) using\nthe root user, you may run into permission errors.\n\nThis is why I use the `--chown` option in the Dockerfile:\n```dockerfile\nUSER app\n# ...\nCOPY --chown=app --from=venv /app/.venv .venv\n```\n\n\u003c!-- TOC --\u003e\u003ca name=\"multi-platform-support\"\u003e\u003c/a\u003e\n### Multi-platform support\n\nNow that Apple switched to ARM, it is important to provide images for both AMD and ARM (at the very\nleast). Using buildx (readily available on Docker Desktop for Mac):\n```bash\nexport DOCKER_BUILDKIT=1\ndocker build -t rroll --rm --progress=plain --platform linux/amd64  .\ndocker build -t rroll --rm --progress=plain --platform linux/arm64  .\n```\n\n\u003c!-- TOC --\u003e\u003ca name=\"github-ci\"\u003e\u003c/a\u003e\n## GitHub CI\n\n\u003c!-- TOC --\u003e\u003ca name=\"building-docker-images\"\u003e\u003c/a\u003e\n### Building docker images\n\nOn GitHub, the action [docker/build-push-action](https://github.com/docker/build-push-action)\nshould be used to build docker images. It is very convenient, as it is able to:\n\n* add the proper labels generated by the docker/metadata-action (`with.labels`),\n* optionally publish to GitHub packages (`with.push`), given that you logged in to\n  Docker in a previous step,\n* build Docker images for both arm and amd platform `with.platforms`.\n\nThe last point is important, now that Apple switched to ARM. If you forget this simple\nparameter, Mac users won't be able to pull/use your image!\n\nHere is the relevant part (the full workflow is in `.GitHub/workflows`):\n```yaml\n    # build arm64 requires buildx, but also the QEMU emulator,\n    # since GitHub Actions runners are amd !\n    - name: Set up QEMU\n      uses: docker/setup-qemu-action@v2\n\n    - name: Set up Docker Buildx\n      uses: docker/setup-buildx-action@v2\n\n    - name: Build and push Docker image\n      uses: docker/build-push-action@v3\n      with:\n        context: .\n        platforms: linux/amd64,linux/arm64  # also support the new mac architecture\n        push: true  # push to the Docker registry (assuming you used docker/login in a previous step)\n        # the next two are coming from the docker/metadata-action step (I gave it the id `meta`)\n        tags: ${{ steps.meta.outputs.tags }}\n        labels: ${{ steps.meta.outputs.labels }}\n```\n\n**Layer caching**\n\nDocker layer caching (DLC) is a great feature when building Docker images is a regular part of the CI process.\n\nThe idea is to cache the individual layers of Docker images built in CI jobs, and then reuse unchanged image layers\non subsequent runs, rather than rebuilding the entire images from scratch every time.\n\nThis caching mechanism is a given when building Docker images locally (see Docker's documentation - [leverage build cache](\nhttps://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache)). However, in CI,\na new runner is started each time, so the cache is always empty by default.\n\nThe build-push-action from Docker [supports multiple types of caches](https://github.com/docker/build-push-action/blob/master/docs/advanced/cache.md).\nIn this repo, I use the GitHub cache (`gha`). It is rather straightforward to turn on: simply set the `cache-from` and\n`cache-to` parameters. One important detail is the `mode=max`, which instructs the action to cache **all** layers, and not only the\nones from the final image. It is very important if your Dockerfile is using multi-stage builds.\n\n```yaml\n- name: Build and push Docker image\n  uses: docker/build-push-action@v3\n  with:\n    # ...\n    cache-from: type=gha\n    cache-to: type=gha,mode=max # \u003c-- mode=max will also cache all layers, vs only the ones from the final image\n```\n\nWith DLC, the less the Dockerfiles change from commit to commit, the faster the image-building steps will run.\nIt is thus important to keep this in mind when writing the Dockerfile.\n\n\n**Tags**\n\nThe metadata-action is configured to add tags to Docker images based on the workflow trigger.\n\nUnique tags:\n\n* an image built from a pull request gets tagged `pr-{{N}}`, with `N` the pull request number,\n* an image built from branch *main* creates a tag `main-{{SHA}}`, with `SHA` the short SHA of the commit,\n* an image built from a release is tagged with the full version (`major.minor.patch`, e.g. `1.2.0`)\n\nMoving tags:\n\n* the tag *latest* is added to the latest build on branch *main*,\n* the version tags `{{major}}` and `{{major}}.{{minor}}` are updated on each release, based on the version released.\n  For example, if version `1.2.0` is released, the image will get the tag `1` and `1.2` (as well as the unique tag `1.2.0`).\n\nMoving tags are useful for users, while unique tags are useful for developers when they want to test a specific version of the\ncode. \n\n\u003c!-- TOC --\u003e\u003ca name=\"keeping-the-github-registry-clean\"\u003e\u003c/a\u003e\n### Keeping the GitHub Registry clean\n\nA lot of images will be pushed to the registry from the CI.\n\nTo clean up old tags, a workflow triggered manually is available.\nIt uses the [vlaurin/action-ghcr-prune](https://github.com/vlaurin/action-ghcr-prune/issues/64)\naction to do the dead, which proposes lots of useful options. See their documentation\nfor details.\n\nNote that to be used, this action requires a PAT - **P**ersonal **A**ccess **T**oken\n(it cannot work with the default `GITHUB_TOKEN`), with at least the scopes `repo`\nand `packages:delete`.\n\n\u003c!-- TOC --\u003e\u003ca name=\"pushing-docker-images-to-both-docker-hub-and-github-registry\"\u003e\u003c/a\u003e\n### Pushing docker images to both Docker Hub and GitHub Registry\n\nIn the first iteration of the reusable docker build/push workflow, I only pushed to `ghcr.io`.\nThen came the wish to also push to Docker Hub, but only \"meaningful\" tags: `latest`, and release-related.\nIn other words, tags for ghcr.io and docker.io are **different**.\nI tried multiple approaches and finally came up with a good-enough solution. The idea:\n\n* run the [docker/metadata-action](https://github.com/docker/metadata-action) twice, one for each\n  registry, using different inputs;\n* add a step that concatenates both results into a single environment variable;\n* pass the content of this new environment variable to [docker/build-push-action](docker/build-push-action).\n\nNote that tags must be a multi-line string, with one image per line.\nMulti-line strings are tricky in GitHub Actions, and need to use a *heredoc*:\n```yaml\n- name: Set a multi-line environment variable\n  run: |\n    echo 'ident\u003c\u003cEOF' \u003e\u003e $GitHub_OUTPUT\n    echo -e 'First line\\nSecond line\\n...' \u003e\u003e $GitHub_OUTPUT\n    echo \"EOF\" \u003e\u003e $GitHub_OUTPUT\n```\n\n(See https://github.com/orgs/community/discussions/26288.)\n\n\u003c!-- TOC --\u003e\u003ca name=\"release-automation-release-please\"\u003e\u003c/a\u003e\n### Release automation: release-please\n\nGoogle's release please action simplifies the creation of releases, given your repository uses [conventional commits](\nhttps://www.conventionalcommits.org/en/v1.0.0/).\n\nBasically, [release-please-action](https://github.com/google-GitHub-actions/release-please-action/) is called on each push\nto main, and will create (or update) a PR for the next release. The PR will automatically:\n* bump the version to the next correct semantic one, depending on your commits (breaking changes, fixes, etc);\n* update the CHANGELOG.\n\nOnce ready for release, just merge the PR to main. Release-please will be called again and will create a tag\n(`vX.X.X`) and a GitHub Release. Additional tasks such as building the Docker image for the tag or attaching assets to\nthe GitHub releases are up to us.\n\nThere are some pitfalls though.\n\nFirst, by default release-please uses the default GitHub token to create the tag, and thus won't trigger other workflows\nsupposed to react to tag creation:\n\n\u003e When you use the repository's GitHub_TOKEN to perform tasks, events triggered by the GitHub_TOKEN will not create a new workflow run.\n\u003e This prevents you from accidentally creating recursive workflow runs.\n\u003e [source](https://docs.GitHub.com/en/actions/security-guides/automatic-token-authentication#using-the-GitHub_token-in-a-workflow)\n\n\nSo how can we build the Docker image on release? Two ways:\n1. configure release-please to use a PAT (*P*ersonal *A*ccess *T*oken), and create a workflow triggered by tags `v*`;\n2. use release-please output `release_created` to conditionally run another job after release-please. \n\nI went for 2, and this is why I use a reusable workflow to push Docker images, and call it in both build and release-please.\n\nSecond, Java/Kotlin `-SNAPSHOT` conventions are not supported for now: at any one time, the version in the git repo is the\nlast one released. With Gradle, one way to dirty fix this is to use a `version.txt` at the root managed by release-please,\nand to add some logic in `build.gradle`/`build.gradle.kts`. See [https://github.com/derlin/docker-compose-viz-mermaid](\nhttps://github.com/derlin/docker-compose-viz-mermaid/blob/main/build.gradle.kts#L12) for an example.\n\n\u003c!-- TOC --\u003e\u003ca name=\"deploying-to-cloud-run-with-github-action\"\u003e\u003c/a\u003e\n### Deploying to Cloud Run With GitHub Action\n\n\u003c!-- TOC --\u003e\u003ca name=\"google-project-setup\"\u003e\u003c/a\u003e\n#### Google Project setup\n\n(See https://github.com/google-GitHub-actions/deploy-cloudrun#setup)\n\n1. create project (I used an educational account)\n2. enable *Cloud Run*, *IAM* and *Container Registry* APIs\n3. create a service account with the following roles:\n    * *Cloud Run Admin*: the role which will allow us to create a new Cloud Run deployment;\n    * *Storage Admin*: the role which allows us to upload our Docker images to the GCP’s Container Registry;\n    * *Service Account User*: the role that allows the service account to act as a user.\n4. once created, click on *manage keys* and add a key in JSON format. This will generate a file that you must keep in a safe and secret place.\n\nNow on GitHub Actions, create a new secret with the content of the JSON file: *Settings* \u003e *Secrets* \u003e *Actions*.\nThe name can be `GOOGLE_CREDENTIALS` (will be referenced later in a workflow using `${{ secrets.GOOGLE_CREDENTIALS }}`),\nand the value must be the JSON content.\n\n\u003c!-- TOC --\u003e\u003ca name=\"github-action\"\u003e\u003c/a\u003e\n#### GitHub Action\n\nThe action is triggered manually and supports optional parameters.\n\nMain actions used:\n\n* [setup-gcloud](https://github.com/google-GitHub-actions/setup-gcloud)\n* [deploy-cloud-run](https://github.com/google-GitHub-actions/deploy-cloudrun)\n\nResources:\n\n* [build and push workflow example](https://github.com/google-GitHub-actions/deploy-cloudrun/blob/main/.GitHub/workflows/example-workflow.yaml)\n* [setup gcloud + auth](https://github.com/google-GitHub-actions/setup-gcloud)\n\n\n**NOTES**\n\nOn the first push, a service will be created in Cloud Run that DO NOT allow unauthenticated requests.\nThis may be modified in the Cloud Run Console:\n\n\u003e A Cloud Run product recommendation is that CI/CD systems not set or change settings for allowing unauthenticated invocations.\n\u003e New deployments are automatically private services while deploying a revision of a public (unauthenticated) service will preserve the IAM setting of public (unauthenticated).\n\nTo make it public:\n\n1. Go to Cloud Run Service *Permissions*\n2. Add a new user:\n    * Principal: `allUsers` \n    * Roles: *Cloud Run Invoker*\n\nTo add a custom domain: https://cloud.google.com/run/docs/mapping-custom-domains#map\n\n\u003c!-- TOC --\u003e\u003ca name=\"other-tips-and-tricks\"\u003e\u003c/a\u003e\n## Other Tips and tricks\n\n\u003c!-- TOC --\u003e\u003ca name=\"keep-python-dependencies-up-to-date\"\u003e\u003c/a\u003e\n### Keep python dependencies up-to-date\n\nTo update to the latest versions but still respect the constraints in `pyproject.toml`, use:\n```bash\npoetry update\n```\n\nTo bump the versions in `pyproject.toml` easily, use [poetryup](https://pypi.org/project/poetryup/):\n```bash\npoetryup --latest\n```\n\n\u003c!-- TOC --\u003e\u003ca name=\"avoid-ssrfs\"\u003e\u003c/a\u003e\n### Avoid SSRFs\n\n*S*erver-*S*ide *R*equest *F*orgery (SSRF) is a web security vulnerability that allows an\nattacker to induce the server-side application to make requests to an unintended location.\n\nFor example, the user may supply to RickRoller the address of a service only reachable from\nthe internal network where the RickRoller server is located.\nImagine it being hosted on Amazon, and an internal service being the metadata amazon server\nhosting tokens and login information. An external user cannot access it as its IP is non-routable,\nbut RickRoller can as it is hosted on the same network. If we are not careful, RickRoller\ncould return sensitive information to the user.\n\nMore information can be found online, for example, https://portswigger.net/web-security/ssrf.\n\nThe mitigation implemented in this repo is two-fold:\n1. Before fetching the content from the URL provided, RickRoller resolves the hostname into\n   an IP address. If the latter is private (aka non-routable), it stops and raises an exception.\n2. During the fetch, RickRoller does follow redirects but keeps a list of redirections.\n   Before returning any content, the same checks as in (1) are applied to the full redirection\n   history.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fderlin%2Frickroller","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fderlin%2Frickroller","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fderlin%2Frickroller/lists"}