Commit 1215d2eb authored by Thomas Boni's avatar Thomas Boni
Browse files

Merge branch '239-add-a-trivy-verification-for-every-docekr-image-in-every-job' into 'latest'

Resolve "Add a trivy verification for every docekr image in every job"

Closes #239

See merge request r2devops/hub!118
parents 2e0ab7a7 9f1a6f66
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
@@ -47,6 +47,79 @@ structure:
    expire_in: 30 days
    when: always

scan_images_dep:
  image: docker:19.03
  stage: static_tests
  services:
    - name: docker:19.03-dind
      entrypoint: ["env", "-u", "DOCKER_HOST"]
      command: ["dockerd-entrypoint.sh"]
  variables:
    PIPENV_PIPFILE: tools/job_image/Pipfile
    JOB_LOGFILE: "job_image.log"
    OUTPUT_DIR: "scan_output"

    TRIVY_EXIT_ON_SEVERITY: ""
    TRIVY_SEVERITY: "LOW,MEDIUM,HIGH,CRITICAL"
    TRIVY_EXIT_CODE: 0
    TRIVY_VULN_TYPE: "os,library"
    TRIVY_NO_PROGRESS: "false"
    TRIVY_OUTPUT: "junit-report.xml"
    TRIVY_IGNOREFILE: .trivyignore
    TRIVY_CACHE_DIR: .trivycache/
    TRIVY_FORMAT: "template"
    TEMPLATE_NAME: "junit.tpl"
    TRIVY_CLEAR_CACHE: "false"
    TRIVY_IGNORE_UNFIXED: "false"
    TRIVY_DEBUG: "false"

    DOCKER_HOST: tcp://docker:2375
    DOCKER_DRIVER: overlay2
    DOCKER_TLS_CERTDIR: ""
    TRIVY_VERSION: "0.9.2"
    TRIVY_REMOTE: ""
    TRIVY_TIMEOUT: ""
    TRIVY_LIGHT: "false"
    TRIVY_DOWNLOAD_DB_ONLY: "false"
    TRIVY_TOKEN: ""
    TRIVY_QUIET: "false"
    TRIVY_SKIP_UPDATE: "false"

  before_script:
    - apk add --no-cache python3 py3-pip
    - pip install --ignore-installed distlib pipenv
    - pipenv install

    - wget https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz
    - tar zxvf trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz
    - wget -O $TEMPLATE_NAME https://github.com/aquasecurity/trivy/raw/v${TRIVY_VERSION}/contrib/junit.tpl

    - mkdir ${OUTPUT_DIR}
  script:
    - for JOB in $(ls jobs); do
    -   IMAGE=$(pipenv run python3 tools/job_image/job_image.py ${JOB})
    -   if [ ! -z ${IMAGE} ]; then
    -     NAME=$(basename ${IMAGE})
    -     ./trivy --template "@${TEMPLATE_NAME}" -o ${OUTPUT_DIR}/${NAME}.${TRIVY_OUTPUT} ${IMAGE}
    -     if [ ! -z ${TRIVY_EXIT_ON_SEVERITY} ]; then
    -       ./trivy --template "@${TEMPLATE_NAME}" --exit-code 1 --severity ${TRIVY_EXIT_ON_SEVERITY} -o ${OUTPUT_DIR}/${NAME}-failed-${TRIVY_OUTPUT} ${IMAGE}
    -     fi
    -   fi
    -   IMAGE=""
    - done
  cache:
    paths:
      - "$TRIVY_CACHE_DIR"
  artifacts:
    paths:
      - "${JOB_LOGFILE}"
      - "${OUTPUT_DIR}/*.xml"
    reports:
      junit:
        - "${OUTPUT_DIR}/*.xml"
    expire_in: 30 days
    when: always

# See https://docs.gitlab.com/ee/api/releases/
# We can only control the link to the hub, the release is still storing the source code
release:
+10 −0
Original line number Diff line number Diff line
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[requires]
python_version = "3"

[packages]
pyyaml = "==5.3.1"
+40 −0
Original line number Diff line number Diff line
{
    "_meta": {
        "hash": {
            "sha256": "393c026ec5df70f675b7d8e3a09d37d15b99d5312608065a0443886c8a752316"
        },
        "pipfile-spec": 6,
        "requires": {
            "python_version": "3"
        },
        "sources": [
            {
                "name": "pypi",
                "url": "https://pypi.org/simple",
                "verify_ssl": true
            }
        ]
    },
    "default": {
        "pyyaml": {
            "hashes": [
                "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97",
                "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76",
                "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2",
                "sha256:6034f55dab5fea9e53f436aa68fa3ace2634918e8b5994d82f3621c04ff5ed2e",
                "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648",
                "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf",
                "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f",
                "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2",
                "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee",
                "sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a",
                "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d",
                "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c",
                "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"
            ],
            "index": "pypi",
            "version": "==5.3.1"
        }
    },
    "develop": {}
}
+71 −0
Original line number Diff line number Diff line
#!/usr/bin/env python3

import os
import sys
import logging
import yaml
import argparse

# Job variables
JOBS_DIR = "jobs"
JOBS_EXTENSION = "yml"
LOGFILE_NAME = os.getenv("JOB_LOGFILE")
EXIT_SUCCESS = 0
EXIT_FAILURE = 1

def argparse_setup():
    """Setup argparse

    Return
    ------
    obj
        Python object with arguments parsed
    """
    parser = argparse.ArgumentParser()
    parser.add_argument("job", help="job name to get the image from")
    return parser.parse_args()

if __name__ == "__main__":
    """Main function, get the name of the image for a job

    Parameters
    ----------
    str
        Job name as argument of the script

    Return
    ------
    0
        If we were able to print that name
    1
        On error
    """
    # Setup argparse
    args = argparse_setup()

    # Setup logging
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s [%(levelname)s] %(message)s",
        handlers=[
            logging.FileHandler(LOGFILE_NAME),
            logging.StreamHandler(sys.stderr)
        ]
    )

    if args.job is None:
        logging.error(f"No argument provided")
        exit(EXIT_FAILURE)
    logging.info(f"Getting the image for job {args.job}")
    with open(f"{JOBS_DIR}/{args.job}/{args.job}.{JOBS_EXTENSION}", 'r') as file:
        data = yaml.load(file, Loader=yaml.FullLoader)
        if "image" in data[args.job].keys():
            if isinstance(data[args.job]['image'], dict):
                print(data[args.job]['image']['name'])
            else:
                print(data[args.job]['image'])
        elif "extends" in data[args.job].keys():
            if isinstance(data[data[args.job]['extends']]['image'], dict):
                print(data[data[args.job]['extends']]['image']['name'])
            else:
                print(data[data[args.job]['extends']]['image'])
 No newline at end of file