Skip to content

Instantly share code, notes, and snippets.

@seantrane
Last active February 21, 2025 19:29
Show Gist options
  • Save seantrane/05074184cf35467af08248bf07c176c8 to your computer and use it in GitHub Desktop.
Save seantrane/05074184cf35467af08248bf07c176c8 to your computer and use it in GitHub Desktop.
MegaLinter Usage

MegaLinter Usage

MegaLinter via Docker CLI

NOTE: When using Trivy, it will download a Vulnerability DB, Java Index DB, and Checks Bundle during every run. This quickly triggers rate-limiting errors. The script below will pre-cache the DB's every 24 hours, to ensure that excessive MegaLinter scans do not trigger rate-limiting.

bin/megalinter:

#!/usr/bin/env bash
#
# MegaLinter via Docker CLI
# https://megalinter.io/latest/install-docker/
#
# Run in directory with mega-linter.yml: megalinter
# Run a specific version of MegaLinter: megalinter v8
#
# shellcheck disable=SC2034

export MEGALINTER_IMAGE="${MEGALINTER_IMAGE:-"oxsecurity/megalinter"}"
export MEGALINTER_VERSION="${MEGALINTER_VERSION:-"v8"}"

trivy_cache_primer() {
  TRIVY_CACHE_DIR="${HOME:-/tmp/lint}/.cache/trivy"
  _CACHE_TIMER="_cache-timer"
  _TRIVY_DB_REPO="public.ecr.aws/aquasecurity/trivy-db:2"
  _TRIVY_JAVA_DB_REPO="public.ecr.aws/aquasecurity/trivy-java-db:1"
  _TRIVY_CHECKS_REPO="ghcr.io/aquasecurity/trivy-checks:1"
  _TRIVY_DB_CACHE_PATH="${TRIVY_CACHE_DIR}/db"
  _TRIVY_JAVA_DB_CACHE_PATH="${TRIVY_CACHE_DIR}/java-db"
  _TRIVY_CHECKS_CACHE_PATH="${TRIVY_CACHE_DIR}/checks"
  # Create cache directory, if it doesn't exist.
  [[ ! -d "$TRIVY_CACHE_DIR" ]] && mkdir -p "$TRIVY_CACHE_DIR"
  # Delete outdated cache-timers.
  find "$TRIVY_CACHE_DIR" -name "*$_CACHE_TIMER" -type f -mmin +1440 -delete
  # Trivy Vulnerability DB
  # If cache-timer doesn't exist, or cache is empty, prime the cache.
  if [[ ! -e "${_TRIVY_DB_CACHE_PATH}${_CACHE_TIMER}" ]] || [[ -z "$(ls -A "$_TRIVY_DB_CACHE_PATH")" ]]; then
    rm -rf "$_TRIVY_DB_CACHE_PATH" "${_TRIVY_DB_CACHE_PATH}${_CACHE_TIMER}"
    mkdir -p "$_TRIVY_DB_CACHE_PATH"
    (
      cd "$TRIVY_CACHE_DIR" || echo ""
      echo "Pulling Trivy Vulnerability DB and storing in cache."
      oras pull "$_TRIVY_DB_REPO" &&
        tar -xzf db.tar.gz -C "$_TRIVY_DB_CACHE_PATH" &&
        rm -f db.tar.gz
    )
    # Reset the cache-timer, if cache is not empty.
    [[ -n "$(ls -A "$_TRIVY_DB_CACHE_PATH")" ]] && touch "${_TRIVY_DB_CACHE_PATH}${_CACHE_TIMER}"
  fi
  # Trivy Java Index DB
  # If cache-timer doesn't exist, or cache is empty, prime the cache.
  if [[ ! -e "${_TRIVY_JAVA_DB_CACHE_PATH}${_CACHE_TIMER}" ]] || [[ -z "$(ls -A "$_TRIVY_JAVA_DB_CACHE_PATH")" ]]; then
    rm -rf "$_TRIVY_JAVA_DB_CACHE_PATH" "${_TRIVY_JAVA_DB_CACHE_PATH}${_CACHE_TIMER}"
    mkdir -p "$_TRIVY_JAVA_DB_CACHE_PATH"
    (
      cd "$TRIVY_CACHE_DIR" || echo ""
      echo "Pulling Trivy Java Index DB and storing in cache."
      oras pull "$_TRIVY_JAVA_DB_REPO" &&
        tar -xzf javadb.tar.gz -C "$_TRIVY_JAVA_DB_CACHE_PATH" &&
        rm -f javadb.tar.gz
    )
    # Reset the cache-timer, if cache is not empty.
    [[ -n "$(ls -A "$_TRIVY_JAVA_DB_CACHE_PATH")" ]] && touch "${_TRIVY_JAVA_DB_CACHE_PATH}${_CACHE_TIMER}"
  fi
  # Trivy Checks Bundle
  # If cache-timer doesn't exist, or cache is empty, prime the cache.
  if [[ ! -e "${_TRIVY_CHECKS_CACHE_PATH}${_CACHE_TIMER}" ]] || [[ -z "$(ls -A "$_TRIVY_CHECKS_CACHE_PATH")" ]]; then
    rm -rf "$_TRIVY_CHECKS_CACHE_PATH" "${_TRIVY_CHECKS_CACHE_PATH}${_CACHE_TIMER}"
    mkdir -p "$_TRIVY_CHECKS_CACHE_PATH"
    (
      cd "$TRIVY_CACHE_DIR" || echo ""
      echo "Pulling Trivy Checks Bundle and storing in cache."
      oras pull "$_TRIVY_CHECKS_REPO" &&
        tar -xzf bundle.tar.gz -C "$_TRIVY_CHECKS_CACHE_PATH" &&
        rm -f bundle.tar.gz
    )
    # Reset the cache-timer, if cache is not empty.
    [[ -n "$(ls -A "$_TRIVY_CHECKS_CACHE_PATH")" ]] && touch "${_TRIVY_CHECKS_CACHE_PATH}${_CACHE_TIMER}"
  fi
  # output cache file list for debugging.
  echo "Contents of Trivy cache directory: $TRIVY_CACHE_DIR"
  ls -lahF "$TRIVY_CACHE_DIR"
}

main() {
  if [ "$(whoami)" == "runner" ]; then
    : #  echo "Don't execute in GitHub Actions workflow runs."
  else
    trivy_cache_primer
    # Clean up previous reports directory.
    [[ -d "$(pwd)/megalinter-reports" ]] && rm -rf "$(pwd)/megalinter-reports"
    # Run MegaLinter with cache enabled.
    local OPTS=()
    OPTS+=(--rm)
    # OPTS+=(-q)
    [[ -t 0 ]] && OPTS+=(-it) # terminal
    [[ -e ~/.ssh/config_shared ]] && OPTS+=(-v ~/.ssh/config_shared:/root/.ssh/config)
    [[ -e ~/.ssh/id_rsa_shared ]] && OPTS+=(-v ~/.ssh/id_rsa_shared:/root/.ssh/id_rsa_shared)
    OPTS+=(-v /var/run/docker.sock:/var/run/docker.sock:rw)
    OPTS+=(-v "$(pwd):/tmp/lint:rw")
    OPTS+=(-v "$HOME/.cache/trivy:/tmp/megalinter/.cache/trivy:rw")
    OPTS+=(-e "TRIVY_CACHE_DIR=/tmp/megalinter/.cache/trivy")
    OPTS+=(-e "TRIVY_SKIP_DB_UPDATE=true")
    OPTS+=(-e "TRIVY_SKIP_JAVA_DB_UPDATE=true")
    OPTS+=(-e "TRIVY_SKIP_CHECK_UPDATE=true")
    OPTS+=(--name "${PWD##*/}-megalinter-${MEGALINTER_VERSION}")
    docker run "${OPTS[@]}" "${MEGALINTER_IMAGE}:${MEGALINTER_VERSION}" "$@"
  fi
}

main "$@"

MegaLinter Configuration

.mega-linter.yml:

---
# Configuration file for MegaLinter
# See all available variables at https://megalinter.io/configuration/ and in linters documentation

# Activates formatting and auto-fixing
APPLY_FIXES: none
# https://megalinter.io/latest/supported-linters/
# If you use ENABLE variable, all other languages/formats/tooling formats will be disabled by default
ENABLE:
  - BASH
  # - CLOUDFORMATION
  # - CSS
  - DOCKERFILE
  - ENV
  # - GHERKIN
  # - HTML
  - JAVASCRIPT
  - JSON
  # - KUBERNETES
  - MARKDOWN
  # - OPENAPI
  - PYTHON
  - REPOSITORY
  - TERRAFORM
  # - XML
  - YAML
DISABLE_LINTERS:
  - JAVASCRIPT_STANDARD
  - JSON_PRETTIER
  - KUBERNETES_KUBEVAL
  - MARKDOWN_MARKDOWN_LINK_CHECK
  - MARKDOWN_REMARK_LINT
  # - PYTHON_BLACK
  - PYTHON_FLAKE8
  - PYTHON_ISORT
  - PYTHON_MYPY
  - PYTHON_PYRIGHT
  - PYTHON_RUFF
  # - REPOSITORY_CHECKOV
  - REPOSITORY_DEVSKIM
  - REPOSITORY_DUSTILOCK
  - REPOSITORY_GOODCHECK
  - REPOSITORY_GRYPE
  # - REPOSITORY_KICS
  - REPOSITORY_SEMGREP
  - REPOSITORY_SYFT
  - REPOSITORY_TRUFFLEHOG
  - TERRAFORM_TERRASCAN
BASH_EXEC_FILE_EXTENSIONS: ['']
BASH_EXEC_FILTER_REGEX_INCLUDE: '(bin/*|scripts/*)'
BASH_SHELLCHECK_FILE_EXTENSIONS: ['', '.sh', '.bash', '.dash', '.ksh']
BASH_SHELLCHECK_FILTER_REGEX_EXCLUDE: '.gitkeep'
BASH_SHELLCHECK_FILTER_REGEX_INCLUDE: '(bin/*|scripts/*)'
BASH_SHFMT_FILE_EXTENSIONS: ['', '.sh', '.bash', '.dash', '.ksh']
BASH_SHFMT_FILTER_REGEX_EXCLUDE: '.gitkeep'
BASH_SHFMT_FILTER_REGEX_INCLUDE: '(bin/*|scripts/*)'
EXCLUDED_DIRECTORIES: ['.git', '.terraform', 'megalinter-reports', 'node_modules']
FLAVOR_SUGGESTIONS: false
FORMATTERS_DISABLE_ERRORS: false
JSON_JSONLINT_FILTER_REGEX_EXCLUDE: '(\.devcontainer/|\.vscode/)'
MARKDOWN_MARKDOWN_LINK_CHECK_DISABLE_ERRORS: true
MARKDOWN_MARKDOWNLINT_FILTER_REGEX_EXCLUDE: '(CHANGELOG.md)'
PRINT_ALL_FILES: false
PRINT_ALPACA: false
PYTHON_PYLINT_CONFIG_FILE: pyproject.toml
PYTHON_PYLINT_ARGUMENTS: '--fail-under=0 --fail-on=E'
PYTHON_BANDIT_CONFIG_FILE: pyproject.toml
PYTHON_BANDIT_PRE_COMMANDS:
  - command: 'pip install bandit[toml]'
    cwd: 'workspace'
REPORTERS_MARKDOWN_TYPE: simple
REPOSITORY_CHECKOV_ARGUMENTS: ['--check', 'HIGH', '--skip-check', 'MEDIUM']
REPOSITORY_KICS_ARGUMENTS: '--exclude-severities info,low'
REPOSITORY_TRIVY_ARGUMENTS:
  - '--db-repository'
  - 'public.ecr.aws/aquasecurity/trivy-db:2'
  - '--java-db-repository'
  - 'public.ecr.aws/aquasecurity/trivy-java-db:1'
  - '--skip-dirs'
  - '.devcontainer'
  - '--skip-dirs'
  - '.terraform'
  - '--skip-dirs'
  - 'megalinter-reports'
  - '--skip-dirs'
  - 'node_modules'
SHOW_ELAPSED_TIME: true
SHOW_SKIPPED_LINTERS: false
YAML_PRETTIER_FILTER_REGEX_EXCLUDE: '(\.github/workflows)'
YAML_YAMLLINT_FILTER_REGEX_EXCLUDE: '(\.github/workflows)'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment