Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/scripts/actionlint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ readonly SCRIPT_DIR
# To update the actionlint version, replace this file with the updated checksums file from the GitHub release
readonly CHECKSUMS_FILE="$SCRIPT_DIR/actionlint_checksums.txt"
readonly ACTIONLINT_PATH="$SCRIPT_DIR/actionlint"
readonly REPO_ROOT="${REPO_ROOT:-.}"

source "$SCRIPT_DIR/shellUtils.sh"

Expand Down Expand Up @@ -72,16 +73,17 @@ else
# It's only possible to have one exit trap, so we have to update to include both items we wish to remove
trap 'rm -rf "$TMPDIR" "$TARBALL"' EXIT
tar -C "$TMPDIR" -xzf "$TARBALL"
mv "$TMPDIR/actionlint" "$SCRIPT_DIR/actionlint"
mv "$TMPDIR/actionlint" "$ACTIONLINT_PATH"

INSTALLED_VERSION="$("$SCRIPT_DIR/actionlint" -version | head -n 1)"
INSTALLED_VERSION="$("$ACTIONLINT_PATH" -version | head -n 1)"
readonly INSTALLED_VERSION
info "Successfully installed actionlint version $INSTALLED_VERSION" >&2
fi

info "Linting workflows..."
echo
if ! "$SCRIPT_DIR/actionlint" -color; then
cd "$REPO_ROOT" || exit 1
if ! "$ACTIONLINT_PATH" -color; then
error "Workflows did not pass actionlint :("
exit 1
fi
Expand Down
27 changes: 18 additions & 9 deletions .github/scripts/shellUtils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,50 @@

# Check if GREEN has already been defined
if [ -z "${GREEN+x}" ]; then
declare -r GREEN=$'\e[1;32m'
readonly GREEN=$'\e[1;32m'
fi

# Check if YELLOW has already been defined
if [ -z "${YELLOW+x}" ]; then
readonly YELLOW=$'\e[1;33m'
fi

# Check if RED has already been defined
if [ -z "${RED+x}" ]; then
declare -r RED=$'\e[1;31m'
readonly RED=$'\e[1;31m'
fi

# Check if BLUE has already been defined
if [ -z "${BLUE+x}" ]; then
declare -r BLUE=$'\e[1;34m'
readonly BLUE=$'\e[1;34m'
fi

# Check if TITLE has already been defined
if [ -z "${TITLE+x}" ]; then
declare -r TITLE=$'\e[1;4;34m'
readonly TITLE=$'\e[1;4;34m'
fi

# Check if RESET has already been defined
if [ -z "${RESET+x}" ]; then
declare -r RESET=$'\e[0m'
readonly RESET=$'\e[0m'
fi

function success {
function success() {
echo "🎉 $GREEN$1$RESET"
}

function error {
function warning() {
echo "⚠️ $YELLOW$1$RESET"
}

function error() {
echo "💥 $RED$1$RESET"
}

function info {
function info() {
echo "$BLUE$1$RESET"
}

function title {
function title() {
printf "\n%s%s%s\n" "$TITLE" "$1" "$RESET"
}
23 changes: 17 additions & 6 deletions .github/scripts/validateImmutableActionRefs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,31 @@
# Check for unsafe action references #
############################################

GITHUB_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." &>/dev/null && pwd)"
readonly GITHUB_DIR
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
readonly SCRIPT_DIR

source "$GITHUB_DIR/scripts/shellUtils.sh"
readonly REPO_ROOT="${REPO_ROOT:-.}"

source "$SCRIPT_DIR/shellUtils.sh"

title "Checking for mutable action references..."

ACTION_USAGES=""

# Find yaml files - these can be either:
# - workflows, which are always stored in .github/workflows, or
YAML_FILES="$(find "$GITHUB_DIR/workflows" -type f \( -name "*.yml" -o -name "*.yaml" \))"
WORKFLOWS="$(find "$REPO_ROOT/.github/workflows" -type f \( -name "*.yml" -o -name "*.yaml" \))"
if [[ -z "$WORKFLOWS" ]]; then
warning "No workflows found. Did you remember to run this script from the root of a repository?" >&2
fi

# - action metadata files, which can be anywhere in the repo, but must be called action.yml or action.yaml
YAML_FILES+=" $(find "$GITHUB_DIR/.." -type f \( -name "action.yml" -o -name "action.yaml" \))"
ACTIONS="$(find "$REPO_ROOT" -type f \( -name "action.yml" -o -name "action.yaml" \))"
if [[ -z "$ACTIONS" ]]; then
warning "No workflows found. Did you remember to run this script from the root of a repository?" >&2
fi

readonly YAML_FILES="$WORKFLOWS $ACTIONS"

# Find yaml files in the `.github` directory
for FILE in $YAML_FILES; do
Expand Down Expand Up @@ -74,7 +85,7 @@ function check_remote_ref() {
local REPO
REPO="$(echo "$ACTION" | awk -F/ '{print $1 "/" $2}')"

local REPO_URL="git@github.com:${REPO}.git"
local REPO_URL="https://github.com/${REPO}"
if git ls-remote --quiet --tags --heads --exit-code "$REPO_URL" "refs/*/$REF*" ; then
error "Found remote branch or tag that looks like a commit hash! ${ACTION}@${REF}"
return 1
Expand Down
22 changes: 15 additions & 7 deletions .github/scripts/validateWorkflowSchemas.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
# Validate GitHub action and workflow yaml schemas #
##########################################################

GITHUB_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." &>/dev/null && pwd)"
readonly GITHUB_DIR
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
readonly SCRIPT_DIR

source "$GITHUB_DIR/scripts/shellUtils.sh"
source "$SCRIPT_DIR/shellUtils.sh"

readonly REPO_ROOT="${REPO_ROOT:-.}"

title "Validating the Github Actions and workflows using the json schemas provided by (https://www.schemastore.org/json/)"

Expand All @@ -21,7 +23,7 @@ for SCHEMA in github-action.json github-workflow.json; do
if curl "https://json.schemastore.org/$SCHEMA" --output "$TEMP_SCHEMA_DIR/$SCHEMA" --silent; then
success "Successfully downloaded $SCHEMA schema!"
else
error "Failed downloading $SCHEMA schema"
error "Failed downloading $SCHEMA schema" >&2
exit 1
fi
done
Expand All @@ -33,7 +35,10 @@ info "Validating action metadata files against their JSON schema..."
echo

# Get all actions, delimited by -d (data arg for ajv)
ACTIONS="$(find "$GITHUB_DIR/.." -type f \( -name "action.yml" -o -name "action.yaml" \) -exec echo -n " -d "{} \;)"
ACTIONS="$(find "$REPO_ROOT" -type f \( -name "action.yml" -o -name "action.yaml" \) -exec echo -n " -d "{} \;)"
if [[ -z "$ACTIONS" ]]; then
warning "No actions found. Did you remember to run this script from the root of a repo?" >&2
fi

# Disabling shellcheck because we WANT word-splitting on ACTIONS in this case
# shellcheck disable=SC2086
Expand All @@ -46,7 +51,10 @@ info "Validating workflows against their JSON schema..."
echo

# Get all workflows, delimited by -d (data arg for ajv)
WORKFLOWS="$(find "$GITHUB_DIR/workflows" -type f \( -name "*.yml" -o -name "*.yaml" \) -exec echo -n " -d "{} \;)"\
WORKFLOWS="$(find "${REPO_ROOT}/.github/workflows" -type f \( -name "*.yml" -o -name "*.yaml" \) -exec echo -n " -d "{} \;)"
if [[ -z "$WORKFLOWS" ]]; then
warning "No workflows found. Did you remember to run this script from the root of a repo?" >&2
fi

# shellcheck disable=SC2086
if ! npx ajv --strict=false -s "$TEMP_SCHEMA_DIR/github-workflow.json" $WORKFLOWS; then
Expand All @@ -56,7 +64,7 @@ fi
echo

if [[ $EXIT_CODE -ne 0 ]]; then
error "Some actions and/or workflows are invalid"
error "Some actions and/or workflows are invalid" >&2
exit $EXIT_CODE
fi

Expand Down
32 changes: 19 additions & 13 deletions .github/workflows/validateActions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,43 @@ jobs:
validateSchemas:
runs-on: ubuntu-latest
steps:
# v4.2.2
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Checkout repos
id: repo
uses: Expensify/GitHub-Actions/checkoutRepoAndGitHubActions@main

# v4.3.0
- name: Setup Node
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e

# Install node to get the ajv-cli
- name: Install node modules
run: npm ci
run: npm i -g ajv-cli@5.0.0

- name: Validate action and workflow schemas
run: .github/scripts/validateWorkflowSchemas.sh
run: GitHub-Actions/.github/scripts/validateWorkflowSchemas.sh
env:
REPO_ROOT: ${{ steps.repo.outputs.NAME }}

actionlint:
runs-on: ubuntu-latest
steps:
# v4.2.2
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Checkout repos
id: repo
uses: Expensify/GitHub-Actions/checkoutRepoAndGitHubActions@main

- name: Lint workflows with actionlint
run: .github/scripts/actionlint.sh
run: GitHub-Actions/.github/scripts/actionlint.sh
env:
REPO_ROOT: ${{ steps.repo.outputs.NAME }}

validateImmutableActionRefs:
runs-on: ubuntu-latest
steps:
# v4.2.2
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Checkout repos
id: repo
uses: Expensify/GitHub-Actions/checkoutRepoAndGitHubActions@main

- name: Validate actions refs are immutable
run: .github/scripts/validateImmutableActionRefs.sh
run: GitHub-Actions/.github/scripts/validateImmutableActionRefs.sh
env:
REPO_ROOT: ${{ steps.repo.outputs.NAME }}
26 changes: 26 additions & 0 deletions checkoutRepoAndGitHubActions/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Checkout target repo and GitHub Actions repo

outputs:
NAME:
description: The target repo where this workflow is running (repo name w/o org prefix)
value: ${{ steps.repo.outputs.NAME }}

runs:
using: composite
steps:
- name: Get target repo name
id: repo
run: echo "NAME=$(basename ${{ github.repository }})" >> "$GITHUB_OUTPUT"
shell: bash

# v4.2.2
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: ${{ steps.repo.outputs.NAME }}

- name: Checkout Expensify/GitHub-Actions
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
repository: Expensify/GitHub-Actions
path: GitHub-Actions
Loading