Giter Club home page Giter Club logo

hadolint-gh-action's Introduction

hadolint-gh-action

A stable, well-tested, highly configurable way of checking your Dockerfile(s) with hadolint.

Usage

Verify your dockerfiles with hadolint for pull requests:

name: Lint
on: pull_request

jobs:
  hadolint:
    runs-on: ubuntu-22.04
    name: Hadolint
    steps:
      - uses: actions/checkout@v4
      - uses: jbergstroem/hadolint-gh-action@v1

More usage examples can be found in USAGE.md.

Parameters

Variable Default Description
dockerfile ./Dockerfile Path to Dockerfile(s). Accepts shell expansions (**/Dockerfile)
config_file Path to optional config (hadolint defaults to read ./hadolint.yml if it exists)
error_level 0 Fail CI based on hadolint output (-1: never, 0: error, 1: warning, 2: info)
annotate true Annotate code inline in the github PR viewer (true/false)
output_format Set output format (choose between tty, json, checkstyle, codeclimate, gitlab_codeclimate, gnu, codacy, sonarqube and sarif)
hadolint_path Absolute path to hadolint binary. If unset, it is assumed to exist in $PATH
version 2.12.0 Use a specific version of Hadolint

Hadolint version

The github action accepts an input - version - to switch/pin to a different version of hadolint.

The output variable hadolint_version will always contain what version the action is running. This can be useful in debugging scenarios where things "break" from one day to the other due to the action being updated.

The shell scripts are developed against the latest version available (which is the default value for the input).

Output

You can control the behavior of how hadolint presents its findings by configuring:

  • annotate: let feedback show inline in your code review
  • output_format: store the output in a variable you can pass on to other processing tools

If output_format is set, the github action variable hadolint_output will contain the output. You can choose what format you prefer depending on how you want to process the results.

These output variables are always populated:

  • hadolint_version: the version of hadolint used while running the action
  • hadolint_gh_action_version: the version of this action while running it

Robustness

Also known as "can I run this in production". The action itself is tested via CI for all its use cases as well as unit tests for each function. Additionally, shellcheck is run against all shell scripts. Releases are cut manually (for now) and the action will strictly follow semver with regards to breaking functionality or options.

Performance

Due to staying with bash we can avoid Docker-related performance penalties. Yet to be benchmarked, but it is likely on par or faster than other hadolint actions.

hadolint-gh-action's People

Contributors

dependabot[bot] avatar jbergstroem avatar khancyr avatar renovate[bot] avatar smoraisansys avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

hadolint-gh-action's Issues

Pass custom hadolint version to action

Like many other github actions, this repo should also support passing a custom version of the binary for use. This would be implemented in the action itself, so testing needs to be consiered properly (currently, testing is done via a second repository triggered while landing to the main branch).

Document cutting a new release

Updating hadolint

  1. edit action.yml (or let renovate manage it)
  2. update README.md (cannot be done by renovate unless self-hosted with postupdate scripts) to update default value #116

Updating the action

  1. update lib/hadolint.sh and commit said change
  2. draft a new release (autodraft suggests changelog and a new tag)
  3. review
  4. release

Improve test for catching glob expansion properly

The upcoming approach basically assumes that the glob works, but that's it. A better test would be to verify that the files that are tested are the ones we expect by checking output from hadolint and matching the filenames.

Refs: #82.

Test the action itself on PR

If there are changes to action.yml, these needs to be tested to make sure that it doesn't break (see it as e2e via the action environment).

Explore using sarif as output format

Sarif is a json format that provides a finer grained way of showing errors, warnings and so on. The issues found are also shown on the security page which might interest a fair amount of people.

Based on a JSON template there might be a not-so-painful way of having jq emit a sarif-friendly document that github can consume.

Shell expansion **/Dockerfile not finding file recursively

For a repo with collection of Dockerfile-s structured like this:

/a/x/Dockerfile
/a/y/Dockerfile
/a/z/Dockerfile

the following workflow with shell expansion

jobs:
  hadolint:
    name: Dockerfiles
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - uses: jbergstroem/hadolint-gh-action@v1
      with:
        dockerfile: "**/Dockerfile"

fails with

hadolint: **/Dockerfile: openBinaryFile: does not exist (No such file or directory)

image

Is the recursive look-up for multiple Dockerfile-s even supported?
I failed to find any note on that in the docs.

Support custom path to hadolint and jq

Instead of overriding the path in a shell environment, we can allow the user to pass custom direct paths to hadolint and jq instead. This makes it easier to work in stricter environment where there may be limits to what can be overridden or changed.

Always use latest available version?

I initially considered seeing this as ABI breaking but I'm on the fence since I've been more or less emulating the same behavior.

It could backfire if upstream decides to change things radically (output formats, flags, ..). Will keep this open for a bit and see what others thinl.

hadolint_output is empty

- uses: jbergstroem/hadolint-gh-action@v1
  id: hadolint
  with:
    dockerfile: ./Dockerfile
    #output_format: sarif

- name: Debug
  shell: bash
  run: |
    echo "${{ steps.hadolint.outputs.hadolint_version }}"
    echo "${{ steps.hadolint.outputs.hadolint_gh_action_version }}"
    echo "${{ steps.hadolint.outputs.hadolint_output }}"

Produces:
Run echo "2.12.0"
echo "2.12.0"
echo "1.12.0"
echo ""

In other words: the hadolint_output output variable is empty, no matter which output_format is specified.
It looks like it's being caused by:

echo "hadolint_output=${OUTPUT//$'\n'/'%0A'} >> \$GITHUB_OUTPUT"

Possible solution:
change
echo "hadolint_output=${OUTPUT//$'\n'/'%0A'} >> \$GITHUB_OUTPUT"
to
echo "hadolint_output=${OUTPUT//$'\n'/'%0A'}" >> "${GITHUB_OUTPUT}"

Switch to renovatebot

Reasoning:

  • no need to manually maintain github relases for dependencies
  • simpler to use and manage compared to dependabot

Silence unecessary output in test suite

This bugs me:

Running tests in test/e2e.sh
	Running test_annotate ... SUCCESS ✓
	Running test_bash_glob_expansion ... SUCCESS ✓
	Running test_custom_config ... SUCCESS ✓
	Running test_custom_dockerfile_path ... SUCCESS ✓
	Running test_custom_hadolint_path ... SUCCESS ✓
	Running test_custom_output_format ... SUCCESS ✓
	Running test_default_hadolint_config ... SUCCESS ✓
	Running test_default_path ... SUCCESS ✓
	Running test_default_path_with_dockerfile ... SUCCESS ✓
	Running test_disable_annotate ... SUCCESS ✓
	Running test_multiple_dockerfiles ... SUCCESS ✓
	Running test_output_with_nonzero_exit ... SUCCESS ✓
	Running test_override_errorlevel ... SUCCESS ✓
	Running test_version_output ... ::add-matcher::~/.github/problem-matcher.json

SUCCESS ✓
Running tests in test/unit.sh
	Running test_output_hadolint_version ... SUCCESS ✓
	Running test_validate_annotate ... SUCCESS ✓
	Running test_validate_error_level ... SUCCESS ✓
	Running test_validate_invalid_annotate ... SUCCESS ✓
	Running test_validate_invalid_error_level ... SUCCESS ✓
	Running test_validate_invalid_output_format ... SUCCESS ✓
	Running test_validate_output_format ... SUCCESS ✓
Overall result: SUCCESS ✓

The issue is how stdout is managed since I redirect output to emulate the CI environment.

error_level: 2 always exits non-zero

It seems like error_level: 2 always bails:

$ dockerfile=../mariadb-alpine/Dockerfile error_level=2 ./hadolint.sh
::set-output name=hadolint_version::2.4.0-no-git
$ echo $?
1

Extract hadolint version from file

It would likely look cleaner to extract hadolint version from a file instead of inline in a github action. That way, bumps are more visible to a user.

Document versioning

Mention that we aim to follow upstream semver plus our own, ultimately leading to a consistent experience for the user (being able to pin to major, min & patch)

Support file filters based on changed files in PRs

We have a single repository with multiple Dockerfiles, and our pipeline only builds those files that are modified.

My understanding is that running this tool would result on all Dockerfiles being scanned in a pull request, regardless of whether they belong to the PR or not. If that's the case, it would be good if this tool had support to specify a filter; that is, to allow us to specify whether to scan every Dockerfile in the repo, or only those that are part of the PR (added, modified, copied, renamed, and / or changed).

We are currently using reviewdog/action-hadolint@v1 which has its own filtering options, but it scans everything / has an issue excluding files such as .json files, which causes a bit of noise for us:

https://github.com/reviewdog/reviewdog#file

We'd like to switch to this action in any case as the output format options look interesting.

Error when trying to use the action in multiple steps

I'm currently using this wonderful action and I'm encountering a minor bug.

To design an action for a group of projects, I wanted to use hadolint-gh-action in two different steps where the first works on directory docker and the second on .devcontainer. However, if one wants to use the action twice, there is an issue because of mkdir ${{ github.action_path }}/bin in the action.yml file. Since it already exists, you end up with the following error mkdir: cannot create directory ‘/home/runner/work/_actions/jbergstroem/hadolint-gh-action/v1/bin’: File exists.

A quick fix would be to use option -p of mkdir to avoid throwing an error is the path exists.

Idiomatic way to print hadolint report?

I'm trying to simple print all lint failures into the CI log rather than using annotations, mostly for consistency.

But whatever I do I can't seem to get the output to work:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Docker Lint
        id: docker-lint
        uses: jbergstroem/hadolint-gh-action@v1
        with:
          annotate: false
          error_level: 2
          output_format: tty
          dockerfile: "**/Dockerfile"
      - name: Docker Lint Output
        if: always()
        run: echo ${{ env.OUTPUT }}
        env:
          OUTPUT: ${{ steps.docker-lint.outputs.hadolint_output }} # also tried using outputs directly in echo

Can you let me know if I am using this as designed or if I'm missing something here?

Btw it would be nice if the default behavior (with annotations off and no output format set) for the action to print all errors into the log rather than hiding it.

Install fails with: mv: cannot move '/tmp/hadolint' to '/usr/local/bin/hadolint': Permission denied

Since version 2.12.0 this action always fails on our self-hosted runners with the following output:

> Run jbergstroem/hadolint-gh-action@v1
  with:
    dockerfile: ./Dockerfile
    error_level: 0
    annotate: true
    version: 2.12.0
> Run /runner/_work/_actions/jbergstroem/hadolint-gh-action/v1/install.sh
  /runner/_work/_actions/jbergstroem/hadolint-gh-action/v1/install.sh
  shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
  env:
    version: 2.12.0
mv: cannot move '/tmp/hadolint' to '/usr/local/bin/hadolint': Permission denied
1
Error: Process completed with exit code 1.

For context, the self-hosted runner is using this Docker image:
summerwind/actions-runner-dind:v2.312.0-ubuntu-22.04

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.