From 0ae04b401802964f03819951fe74036dbed2ac87 Mon Sep 17 00:00:00 2001 From: Andrew Hobson Date: Tue, 13 Apr 2021 16:40:11 +0000 Subject: [PATCH 1/8] Add hadolint hook that downloads binary on run --- .pre-commit-hooks.yaml | 6 ++++++ README.md | 4 ++++ pre-commit-hadolint | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100755 pre-commit-hadolint diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 54d16a5..0c5a471 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -47,3 +47,9 @@ entry: /usr/bin/sort -u -o .spelling .spelling language: script pass_filenames: false + +- id: hadolint + name: Run hadolint Dockerfile linter + description: Run hadolint Dockerfile linter + entry: pre-commit-hadolint + language: script diff --git a/README.md b/README.md index 43689a5..bbde904 100644 --- a/README.md +++ b/README.md @@ -55,3 +55,7 @@ will ignore words listed in a `.spelling` file in your repo. ## spelling-sort Run `sort` on the `.spelling` file used by the `markdown-spellcheck` tool. This keeps the file tidy as it is used. + +## hadolint + +Run the [hadolint](https://github.com/hadolint/hadolint) Dockerfile linter diff --git a/pre-commit-hadolint b/pre-commit-hadolint new file mode 100755 index 0000000..1bd12c6 --- /dev/null +++ b/pre-commit-hadolint @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +set -euo pipefail + +HADOLINT_PREFIX_URL="https://github.com/hadolint/hadolint/releases/download" +HADOLINT_VERSION="v2.1.0" +OS=$(uname -s) +ARCH=$(uname -m) +HADOLINT_BINARY="hadolint-${OS}-${ARCH}" + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +LOCAL_BINARY="${DIR}/${HADOLINT_BINARY}-${HADOLINT_VERSION}" + +# Download the binary if it doesn't already exist +if [[ ! -x ${LOCAL_BINARY} ]]; then + curl -o "${LOCAL_BINARY}" \ + -L -sSf "${HADOLINT_PREFIX_URL}/${HADOLINT_VERSION}/${HADOLINT_BINARY}" + chmod 755 "${LOCAL_BINARY}" +fi + +files=() + +# only run hadolint if it looks like a Dockerfile +for f in "$@"; do + case $f in + (Dockerfile*|*/Dockerfile*) + files+=( "${f}" ) + ;; + esac +done + +if [[ "${#files[@]}" -gt 0 ]]; then + exec "${LOCAL_BINARY}" "${files[@]}" +fi From 989bee35ba04248a16a0781f3965ee904059ef0c Mon Sep 17 00:00:00 2001 From: Andrew Hobson Date: Wed, 14 Apr 2021 07:17:19 -0400 Subject: [PATCH 2/8] Try to work around CircleCI craziness --- pre-commit-hadolint | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pre-commit-hadolint b/pre-commit-hadolint index 1bd12c6..c8228ea 100755 --- a/pre-commit-hadolint +++ b/pre-commit-hadolint @@ -16,6 +16,12 @@ if [[ ! -x ${LOCAL_BINARY} ]]; then curl -o "${LOCAL_BINARY}" \ -L -sSf "${HADOLINT_PREFIX_URL}/${HADOLINT_VERSION}/${HADOLINT_BINARY}" chmod 755 "${LOCAL_BINARY}" + if [[ -n "${CIRCLECI+x}" ]]; then + # oh CircleCI, you so funny + # Text file busy error makes is likely you are using aufs and + # so we need to + sync + fi fi files=() From 90fdab1c9f60e30b9d95d5a01459651143adcfa5 Mon Sep 17 00:00:00 2001 From: Andrew Hobson Date: Wed, 14 Apr 2021 07:25:43 -0400 Subject: [PATCH 3/8] Download hadolint to temp file to prevent Text file busy --- pre-commit-hadolint | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/pre-commit-hadolint b/pre-commit-hadolint index c8228ea..f365909 100755 --- a/pre-commit-hadolint +++ b/pre-commit-hadolint @@ -13,15 +13,11 @@ LOCAL_BINARY="${DIR}/${HADOLINT_BINARY}-${HADOLINT_VERSION}" # Download the binary if it doesn't already exist if [[ ! -x ${LOCAL_BINARY} ]]; then - curl -o "${LOCAL_BINARY}" \ + # download to temp location and rename to prevent Text file busy + curl -o "${LOCAL_BINARY}.new" \ -L -sSf "${HADOLINT_PREFIX_URL}/${HADOLINT_VERSION}/${HADOLINT_BINARY}" - chmod 755 "${LOCAL_BINARY}" - if [[ -n "${CIRCLECI+x}" ]]; then - # oh CircleCI, you so funny - # Text file busy error makes is likely you are using aufs and - # so we need to - sync - fi + chmod 755 "${LOCAL_BINARY}.new" + mv "${LOCAL_BINARY}.new" "${LOCAL_BINARY}" fi files=() From 1c4860d2ee66e66ee041e6ae161a1da89374de18 Mon Sep 17 00:00:00 2001 From: Andrew Hobson Date: Wed, 14 Apr 2021 07:29:47 -0400 Subject: [PATCH 4/8] Ensure hadolint success if no files match --- pre-commit-hadolint | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pre-commit-hadolint b/pre-commit-hadolint index f365909..5685c76 100755 --- a/pre-commit-hadolint +++ b/pre-commit-hadolint @@ -34,3 +34,6 @@ done if [[ "${#files[@]}" -gt 0 ]]; then exec "${LOCAL_BINARY}" "${files[@]}" fi + +# if no files, exit successfully +exit 0 From 543e87ac37c12943c8a619068bd9582301ed4df0 Mon Sep 17 00:00:00 2001 From: Andrew Hobson Date: Wed, 14 Apr 2021 13:17:06 +0000 Subject: [PATCH 5/8] Try more hoops for CircleCI hadolint --- pre-commit-hadolint | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pre-commit-hadolint b/pre-commit-hadolint index 5685c76..08a62c7 100755 --- a/pre-commit-hadolint +++ b/pre-commit-hadolint @@ -13,11 +13,14 @@ LOCAL_BINARY="${DIR}/${HADOLINT_BINARY}-${HADOLINT_VERSION}" # Download the binary if it doesn't already exist if [[ ! -x ${LOCAL_BINARY} ]]; then + tmp_local_binary="${LOCAL_BINARY}.new" # download to temp location and rename to prevent Text file busy - curl -o "${LOCAL_BINARY}.new" \ + curl -o "${tmp_local_binary}" \ -L -sSf "${HADOLINT_PREFIX_URL}/${HADOLINT_VERSION}/${HADOLINT_BINARY}" - chmod 755 "${LOCAL_BINARY}.new" - mv "${LOCAL_BINARY}.new" "${LOCAL_BINARY}" + # ensure the file is synced on CIRCLECI + [ -n "${CIRCLECI+x}" ] && sync + chmod 755 "${tmp_local_binary}" + mv "${tmp_local_binary}" "${LOCAL_BINARY}" fi files=() From ade5e561d2bc1ac48d4a8de0a0b141753c2a324e Mon Sep 17 00:00:00 2001 From: Andrew Hobson Date: Wed, 14 Apr 2021 13:48:06 +0000 Subject: [PATCH 6/8] Ugh, try mkdir locking --- pre-commit-hadolint | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/pre-commit-hadolint b/pre-commit-hadolint index 08a62c7..3375552 100755 --- a/pre-commit-hadolint +++ b/pre-commit-hadolint @@ -7,20 +7,22 @@ HADOLINT_VERSION="v2.1.0" OS=$(uname -s) ARCH=$(uname -m) HADOLINT_BINARY="hadolint-${OS}-${ARCH}" +HADOLINT_URL="${HADOLINT_PREFIX_URL}/${HADOLINT_VERSION}/${HADOLINT_BINARY}" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" LOCAL_BINARY="${DIR}/${HADOLINT_BINARY}-${HADOLINT_VERSION}" # Download the binary if it doesn't already exist if [[ ! -x ${LOCAL_BINARY} ]]; then - tmp_local_binary="${LOCAL_BINARY}.new" - # download to temp location and rename to prevent Text file busy - curl -o "${tmp_local_binary}" \ - -L -sSf "${HADOLINT_PREFIX_URL}/${HADOLINT_VERSION}/${HADOLINT_BINARY}" - # ensure the file is synced on CIRCLECI - [ -n "${CIRCLECI+x}" ] && sync - chmod 755 "${tmp_local_binary}" - mv "${tmp_local_binary}" "${LOCAL_BINARY}" + # use mkdir as a lock so only single download happens + # can't use flock as that doesn't exist on macOS + if mkdir "${LOCAL_BINARY}.lock" 2>/dev/null; then + curl -o "${LOCAL_BINARY}" -L -sSf "${HADOLINT_URL}" + chmod 755 "${LOCAL_BINARY}" + else + # another process is downloading, give it time to complete + sleep 5 + fi fi files=() From add6fda3c16d324376b471cce872d1bdfa21ec88 Mon Sep 17 00:00:00 2001 From: Andrew Hobson Date: Wed, 14 Apr 2021 14:28:08 +0000 Subject: [PATCH 7/8] Use flock if available, otherwise use perl(!) --- pre-commit-hadolint | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/pre-commit-hadolint b/pre-commit-hadolint index 3375552..402f06f 100755 --- a/pre-commit-hadolint +++ b/pre-commit-hadolint @@ -12,18 +12,25 @@ HADOLINT_URL="${HADOLINT_PREFIX_URL}/${HADOLINT_VERSION}/${HADOLINT_BINARY}" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" LOCAL_BINARY="${DIR}/${HADOLINT_BINARY}-${HADOLINT_VERSION}" +function mylock() { + # *sigh* + # macOS does not have flock so fall back to perl(!) if it's not + # available + if command -v flock &>/dev/null; then + flock -x 200 + else + perl -e 'use Fcntl qw(:flock); open($fh, "<&=", 200) || die "Cannot open"; flock($fh, LOCK_EX) || die "Cannot lock"' + fi +} + # Download the binary if it doesn't already exist -if [[ ! -x ${LOCAL_BINARY} ]]; then - # use mkdir as a lock so only single download happens - # can't use flock as that doesn't exist on macOS - if mkdir "${LOCAL_BINARY}.lock" 2>/dev/null; then +( + mylock + if [[ ! -x ${LOCAL_BINARY} ]]; then curl -o "${LOCAL_BINARY}" -L -sSf "${HADOLINT_URL}" chmod 755 "${LOCAL_BINARY}" - else - # another process is downloading, give it time to complete - sleep 5 fi -fi +) 200> "${LOCAL_BINARY}.lock" files=() From b1000fce7da998841c0ba67eaf8bd011eeaa4a6c Mon Sep 17 00:00:00 2001 From: Andrew Hobson Date: Wed, 14 Apr 2021 15:54:41 +0000 Subject: [PATCH 8/8] Include comment on locking pattern for hadolint --- pre-commit-hadolint | 1 + 1 file changed, 1 insertion(+) diff --git a/pre-commit-hadolint b/pre-commit-hadolint index 402f06f..18baa34 100755 --- a/pre-commit-hadolint +++ b/pre-commit-hadolint @@ -24,6 +24,7 @@ function mylock() { } # Download the binary if it doesn't already exist +# use the locking pattern from https://linux.die.net/man/1/flock ( mylock if [[ ! -x ${LOCAL_BINARY} ]]; then