#!/usr/bin/env bash set -euo pipefail [[ -v VERBOSE ]] && set -x ## ********************************* ## * DO NOT USE THIS IN PRODUCTION * ## ********************************* ## ## Digest GitHub Action steps from @ to ## ## For Example: ## actions/checkout@v2 -> actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 ## ## Usage: ## ./gha-digest > ## ## The program prints the modified workflow file to `stdout`. ## Any resolved action is logged to `stderr` for reference. ## ## Please mind that this script does not cover edge cases and was only ## created for a case-study on feasibility. This is by no means considered ## a holistic program and is NOT TO BE USED IN PRODUCTION. ## ## Source: https://github.com/hendrikmaus/github-actions-step-digest ## Author: Hendrik Maus ## # Find 'use: ' statements in a given file and populate an array # # Usage: # find_uses # function find_uses { local -n res="${1}" local target="${2}" # read result into array # grep for lines that start with a pattern # get the second column of the output # remove any single or double quotes around the entries # remove any duplicates # ... not handling any more cases for the sake of simplicity readarray -d '' -t res < <(grep -iE '^?uses: ' "${target}" | awk '{print $2}' | tr -d "'\"" | sort | uniq) } # Get the commit sha of the latest tag in a given owner/repository on GitHub. # Returns the 40 character commit sha without trailing linebreak. # # Usage: # latest_tag_sha "/" # function latest_tag_sha { local repository="${1}" curl -s "https://api.github.com/repos/${repository}/tags?per_page=1" | jq -j '.[].commit.sha' } # Digest all used github actions from their tagged variant to a commit sha # Prints the processed workflow to stdout; prints resolved items to stderr. # # Usage: # run # function run { local target="${1}" local uses find_uses uses "${target}" # mutates `uses` variable echo "Found actions:" >&2 echo "${uses}" >&2 local workflow # mutated in every loop iteration below workflow=$(cat "${target}") echo "Resolving:" >&2 for item in ${uses}; do local repository version IFS='@' read -r repository version <<< "${item}" if [[ $(echo -n "${version}" | wc -m) == 40 ]]; then # let's just assume that a 40 char version is already a commit sha # ... for the sake of simplicity continue fi local commit_sha commit_sha=$(latest_tag_sha "${repository}" ) local resolved_item resolved_item="${repository}@${commit_sha}" echo "${item} -> ${resolved_item}" >&2 workflow=$(echo -n "${workflow}" | sed "s#\<${item}\>#${resolved_item}#") done echo "${workflow}" } # Program main function # function main { local target="${1:-}" run "${target}" } main "$@"