コンテンツにスキップ

GitLab CI/CD との統合

gitlab-ci-cd

このガイドでは、プッシュのたびに Mayhem が自動的にコードまたは API をテストできるよう GitLab CI/CD パイプラインをセットアップする方法を説明します。

GitLab CI/CD パイプラインで Mayhem を実行するには、以下が必要です

  1. Mayhem API トークン を作成します。
  2. 作成したトークンを MAYHEM_TOKEN という名前の「シークレット変数」としてパイプランの変数に追加します。

GitLab CI/CD と Mayhem を連携するためのパイプライン構成

GitLab CI/CD パイプラインを構成してコードまたは API をテストするには、.gitlab-ci.yml ファイルを作成します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
services:
  - "docker:dind"

variables:
  # Set env vars, unable to use cmd substitution here, see https://gitlab.com/gitlab-org/gitlab/-/issues/17251
  REGISTRY: "registry.gitlab.com"
  REPO_SLUG: "${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}"

stages:
  - build
  - test

build-job:
  stage: build
  image: docker:stable
  before_script:
    # Set <username>/<repo> to lowercase
    - LOWER_REPO_SLUG=$(echo $REPO_SLUG | tr '[:upper:]' '[:lower:]')
  script:
    # Build and push Docker image to registry
    - echo $CI_REGISTRY_PASSWORD | docker login $REGISTRY -u $CI_REGISTRY_USER --password-stdin
    - docker build --platform=linux/amd64 -t ${REGISTRY}/${LOWER_REPO_SLUG}:${CI_COMMIT_REF_NAME} .
    - docker push ${REGISTRY}/${LOWER_REPO_SLUG}:${CI_COMMIT_REF_NAME}

mcode-test-job:
  stage: test
  image: debian:bullseye
  before_script:
    # Get GitLab username and set <username>/<repo> to lowercase
    - GITLAB_USERNAME=$(echo $REPO_SLUG | cut -d '/' -f1)
    - LOWER_REPO_SLUG=$(echo $REPO_SLUG | tr '[:upper:]' '[:lower:]')
  script:
    # Download Mayhem CLI and log in to the Mayhem server
    - apt-get update && apt-get install -y curl jq
    - mkdir -p ~/bin
    - export PATH=${PATH}:~/bin
    - curl --no-progress-meter -Lo ~/bin/mayhem ${MAYHEM_URL}/cli/Linux/mayhem  && chmod +x ~/bin/mayhem
    - MAYHEM_PROMPT=1 mayhem login --url ${MAYHEM_URL} --token ${MAYHEM_TOKEN}
    # Execute Mayhem run and fail if no run was executed
    - run=$(mayhem --verbosity info run . --project $LOWER_REPO_SLUG --owner andrew5194 --image ${REGISTRY}/${LOWER_REPO_SLUG}:${CI_COMMIT_REF_NAME} --file ${MAYHEMFILE} --duration 60 --branch-name ${CI_COMMIT_REF_NAME} --revision ${CI_COMMIT_SHA} --ci-url ${CI_PIPELINE_URL} 2>/dev/null);
    - if [ -z "${run}" ]; then exit 1; fi
    # Otherwise, determine run name and wait for job to complete and artifacts to be ready
    - runName=$(echo ${run} | awk -F / '{ print $(NF-1) }');
    - mayhem --verbosity info wait $run --owner $GITLAB_USERNAME --sarif sarif-${runName}.sarif --junit junit-${runName}.xml;
    - status=$(mayhem --verbosity info show --owner $GITLAB_USERNAME --format json $run | jq '.[0].status')
    - if [[ ${status} == *"stopped"* || ${status} == *"failed"* ]]; then exit 2; fi
    # Fail if defects were found
    - defects=$(mayhem --verbosity info show --owner $GITLAB_USERNAME --format json ${run} | jq '.[0].defects|tonumber')
    - if [[ ${defects} -gt 0 ]]; then echo "${defects} defects found!"; exit 3; fi
  parallel:
    matrix:
      # Specify one or more Mayhemfiles for testing
      - MAYHEMFILE: ['mayhem/Mayhemfile.lighttpd', 'mayhem/Mayhemfile.mayhemit']
  artifacts:
    when: always
    paths:
      - 'sarif-*.sarif'
      - 'junit-*.xml'
    reports:
      junit: 'junit-*.xml'
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
image: python:3.9

cache:
  paths:
    - .cache/pip
    - .coverage

before_script:
  - pip install --cache-dir .cache/pip -r requirements.txt

stages:
  - test
  - coverage

test-job:
  stage: test
  script:
    - FASTAPI_ENV=test python3 -m coverage run -m uvicorn src.main:app &
    - curl -Lo mapi $MAYHEM_URL/cli/mapi/linux-musl/latest/mapi && chmod +x mapi
    - ./mapi login $MAPI_TOKEN
    - ./mapi run forallsecure/mapi-action-examples/fastapi auto "http://localhost:8000/openapi.json" --url "http://localhost:8000/" --junit junit.xml --sarif mapi.sarif --html mapi.html
    - pgrep python3 | xargs kill || true
  artifacts:
    when: always
    paths:
      - junit.xml
      - mapi.html
      - mapi.sarif
    reports:
      junit: junit.xml

coverage-report:
  stage: coverage
  when: always
  script:
    - python3 -m coverage report
    - python3 -m coverage xml
    - python3 -m coverage html -d coverage_html_report
  coverage: '/TOTAL.*\s+(\d+\%)$/' # regex to extract coverage percentage
  artifacts:
    when: always
    paths:
      - coverage_html_report/
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml

GitLab CI/CD と Mayhem の統合

Mayhem と GitLab CI/CD を適切に統合するのに必要な .gitlab-ci.yml について説明したので、次は、動作するサンプルを確認します。

Info

このサンプルでは、mcode-action-examples にあるアセットをフォークし、ターゲットの GitLab CI/CD パイプラインに Mayhem を統合しています。

gitlab-repo

GitLab で構成を動作させるには、まず、シークレット変数を設定する必要があります。このサンプルでは、次のパイプライン変数が設定されています。

  1. MAYHEM_TOKEN: ユーザー生成の Mayhem API トークンです。
  2. MAYHEM_URL: Mayhem サーバーの URL です。https://app.mayhem.security を設定します。

secret-variables

さらに、上記の .gitlab-ci.yml 構成では、Docker イメージをビルドして GitLab Container Registry にプッシュします。そのため、プロジェクトの可視性が Public に設定されていることを確認し、Mayhem が GitLab Container Registry からリポジトリの Docker イメージをプルできるようにします。

repo-visibility

上記の手順を完了すると、GitLab CI/CD パイプラインを実行できるようになります。パイプラインはターゲットに対して Mayhem ランを実行し、脆弱性をテストします。

successful-pipeline