diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1211ae7..74d6644 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -103,7 +103,7 @@ jobs: results: ${{ steps.hadolint5.outputs.results }} run: echo "$results" - - name: Run integration test 7 - set recursive + - name: Run integration test 7 - set recursive matching *Dockerfile (warning/info) # This step will never fail, but will print out rule violations # for all the Dockerfiles in repository. uses: ./ @@ -120,14 +120,31 @@ jobs: # format: sarif # output-file: report.sarif - - name: Run integration test 9 - run with no Dockerfiles + - name: Run integration test 9 - set recursive with one matching file (good) + # This step will never fail, but will print out rule violations + # for all the Dockerfiles in repository. + uses: ./ + with: + dockerfile: "*Dockerfile" + recursive: true + working-directory: testdata/test_good_single_file/ + + - name: Run integration test 10 - set recursive with non-matching files + # This step will never fail, but will print out rule violations + # for all the Dockerfiles in repository. + uses: ./ + with: + dockerfile: "*Dockerfile_non_existent" + recursive: true + + - name: Run integration test 11 - run with no Dockerfiles # This should not fail if no Dockerfiles are found in the path # especially if git change deletes Dockerfile - uses: testdata/test_empty_dir + uses: ./ with: - dockerfile: "" - failure-threshold: error + dockerfile: "*Dockerfile" recursive: true + working-directory: testdata/test_empty_dir/ release: if: github.event_name == 'push' && github.ref == 'refs/heads/master' diff --git a/action.yml b/action.yml index e1c9fba..d80a8f5 100644 --- a/action.yml +++ b/action.yml @@ -73,6 +73,10 @@ inputs: required: false description: 'A comma separated list of trusted registry urls' default: + working-directory: + required: false + description: 'Path where you want to start scanning for Dockerfiles' + default: runs: using: 'docker' @@ -91,6 +95,7 @@ runs: HADOLINT_OVERRIDE_STYLE: ${{ inputs.override-style }} HADOLINT_IGNORE: ${{ inputs.ignore }} HADOLINT_TRUSTED_REGISTRIES: ${{ inputs.trusted-registries }} + HADOLINT_WORKING_DIRECTORY: ${{ inputs.working-directory }} HADOLINT_CONFIG: ${{ inputs.config }} HADOLINT_RECURSIVE: ${{ inputs.recursive }} diff --git a/hadolint.sh b/hadolint.sh index d28035d..9fce960 100755 --- a/hadolint.sh +++ b/hadolint.sh @@ -3,9 +3,22 @@ # checkout (outside the Docker container running hadolint). We copy # problem-matcher.json to the home folder. +# unset certain env vars to empty values +RESULTS='' +# shellcheck disable=SC2034 +HADOLINT_RESULTS='' + +# disable cheks for undefined env vars, in here mostly githu env vars +# shellcheck disable=SC2154 + +if [[ -n "${HADOLINT_WORKING_DIRECTORY}" ]]; then + cd "${HADOLINT_WORKING_DIRECTORY}" \ + || { echo "Error: failed to change path to ${HADOLINT_WORKING_DIRECTORY}, check if exists, if is a directory directory permissions etc"; exit 1; } +fi + PROBLEM_MATCHER_FILE="/problem-matcher.json" -if [ -f "$PROBLEM_MATCHER_FILE" ]; then - cp "$PROBLEM_MATCHER_FILE" "$HOME/" +if [[ -f "${PROBLEM_MATCHER_FILE}" ]]; then + cp "${PROBLEM_MATCHER_FILE}" "${HOME}/" fi # After the run has finished we remove the problem-matcher.json from # the repository so we don't leave the checkout dirty. We also remove @@ -16,52 +29,73 @@ cleanup() { } trap cleanup EXIT -echo "::add-matcher::$HOME/problem-matcher.json" +echo "::add-matcher::${HOME}/problem-matcher.json" -if [ -n "$HADOLINT_CONFIG" ]; then +if [[ -n "${HADOLINT_CONFIG}" ]]; then HADOLINT_CONFIG="-c ${HADOLINT_CONFIG}" fi -if [ -z "$HADOLINT_TRUSTED_REGISTRIES" ]; then +if [[ -z "${HADOLINT_TRUSTED_REGISTRIES}" ]]; then unset HADOLINT_TRUSTED_REGISTRIES fi -COMMAND="hadolint $HADOLINT_CONFIG" +COMMAND="hadolint ${HADOLINT_CONFIG}" -if [ "$HADOLINT_RECURSIVE" = "true" ]; then +if [[ "${HADOLINT_RECURSIVE}" = "true" ]]; then shopt -s globstar - filename="${!#}" flags="${*:1:$#-1}" - RESULTS=$(eval "$COMMAND $flags" -- **/"$filename") + files_found=false + # try to find files to scan but do not end with eror if no files found + # notice that $filename can contain glob char so we add exception here + # shellcheck disable=SC2231 + for file in **/${filename} + do + if [[ -e "${file}" ]] + then + files_found=true + break + fi + done + + if [[ "${files_found}" = "true" ]]; then + # notice that $filename can contain glob char so we add exception here + # shellcheck disable=SC2086,SC2231,SC2248 + RESULTS=$(eval "${COMMAND} ${flags}" -- **/${filename}) + else + RESULTS='' + echo "No Dockerfiles detected, skipping processing"; + fi + else flags=$* - RESULTS=$(eval "$COMMAND" "$flags") + RESULTS=$(eval "${COMMAND}" "${flags}") fi FAILED=$? -if [ -n "$HADOLINT_OUTPUT" ]; then - if [ -f "$HADOLINT_OUTPUT" ]; then - HADOLINT_OUTPUT="$TMP_FOLDER/$HADOLINT_OUTPUT" +if [[ -n "${HADOLINT_OUTPUT}" ]]; then + if [[ -f "${HADOLINT_OUTPUT}" ]]; then + HADOLINT_OUTPUT="${TMP_FOLDER}/${HADOLINT_OUTPUT}" fi - echo "$RESULTS" >"$HADOLINT_OUTPUT" + echo "${RESULTS}" >"${HADOLINT_OUTPUT}" fi RESULTS="${RESULTS//$'\\n'/''}" { echo "results<>"$GITHUB_OUTPUT" +} >>"${GITHUB_OUTPUT}" { echo "HADOLINT_RESULTS<>"$GITHUB_ENV" +} >>"${GITHUB_ENV}" -[ -z "$HADOLINT_OUTPUT" ] || echo "Hadolint output saved to: $HADOLINT_OUTPUT" +[[ -z "${HADOLINT_OUTPUT}" ]] || echo "Hadolint output saved to: ${HADOLINT_OUTPUT}" -exit $FAILED +# shellcheck disable=SC2248 +exit ${FAILED} diff --git a/testdata/test_empty_dir/README.md b/testdata/test_empty_dir/README.md new file mode 100644 index 0000000..68ebc4e --- /dev/null +++ b/testdata/test_empty_dir/README.md @@ -0,0 +1,4 @@ +This directory is intentionally empty. + +It is used by the test suite to verify that hadolint action is not executed +if processed directory does not contain any Dockerfile. diff --git a/testdata/test_good_single_file/Dockerfile b/testdata/test_good_single_file/Dockerfile new file mode 100644 index 0000000..fca6156 --- /dev/null +++ b/testdata/test_good_single_file/Dockerfile @@ -0,0 +1,3 @@ +FROM alpine:3.10 + +RUN echo "Hello"