Jenkins CI との統合
このガイドでは、プッシュのたびに Mayhem が自動的に API をテストできるよう Jenkins Pipeline をセットアップする方法を説明します。
Jenkins と Mayhem を連携するためのパイプライン構成
コードまたは API をテストして JUnit レポートとして結果を収集するよう Jenkinsスクリプト パイプライン を構成するには、Jenkinsfile
を作成します。
コード テスト
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 pipeline {
agent any
stages {
stage ( 'Setup' ) {
steps {
echo 'Setting up..'
withCredentials ([ usernamePassword ( credentialsId: 'MAYHEM_CREDENTIALS' , usernameVariable: 'MAYHEM_USERNAME' , passwordVariable: 'MAYHEM_TOKEN' )]) {
sh """
# Setup aarch64 (preinstalled) and x86_64 (download to install)
mkdir -p ~/bin
export PATH=\${PATH}:~/bin
curl -Lo ~/bin/mayhem-x86_64 ${MAYHEM_URL}/cli/Linux/mayhem && chmod +x ~/bin/mayhem-x86_64
# Login to mayhem and docker
mayhem-\$(arch) login --url ${MAYHEM_URL} --token ${MAYHEM_TOKEN}
REGISTRY=\$(mayhem-\$(arch) docker-registry)
echo "${MAYHEM_TOKEN}" | docker login -u ${MAYHEM_USERNAME} --password-stdin \${REGISTRY}
"""
}
}
}
stage ( 'Build' ) {
steps {
echo 'Building..'
sh """
echo "Compiling the code..."
export PATH=\${PATH}:~/bin
REGISTRY=\$(mayhem-\$(arch) docker-registry)
docker build --platform=linux/amd64 -t \${REGISTRY}/lighttpd:${env.BRANCH_NAME} .
docker push \${REGISTRY}/lighttpd:${env.BRANCH_NAME}
echo "Compile complete."
"""
}
}
stage ( 'Mayhem for Code' ) {
matrix {
agent any
axes {
axis {
name 'TARGET'
values 'lighttpd' , 'mayhemit'
}
}
stages {
stage ( 'Mayhem for Code' ) {
steps {
echo 'Scanning..'
sh """#!/bin/bash
export PATH=\${PATH}:~/bin
REGISTRY=\$(mayhem-\$(arch) docker-registry)
# Run Mayhem
echo "mayhem-\$(arch) --verbosity info run . --project forallsecure/mcode-action-examples --owner forallsecure --image \${REGISTRY}/lighttpd:${env.BRANCH_NAME} --file mayhem/Mayhemfile.${TARGET} --duration 60 --branch-name ${env.BRANCH_NAME} --revision ${env.GIT_COMMIT} 2>/dev/null"
run=\$(mayhem-\$(arch) --verbosity info run . --project forallsecure/mcode-action-examples --owner forallsecure --image \${REGISTRY}/lighttpd:${env.BRANCH_NAME} --file mayhem/Mayhemfile.${TARGET} --duration 60 --branch-name ${env.BRANCH_NAME} --revision ${env.GIT_COMMIT} 2>/dev/null);
# Fail if no output was given
if [ -z "\${run}" ]; then exit 1; fi
# Determine run name
runName=\$(echo \${run} | awk -F / '{ print \$(NF-1) }');
# Wait for job to complete and artifacts to be ready
mayhem-\$(arch) --verbosity info wait \${run} --owner forallsecure --sarif sarif-\${runName}.sarif --junit junit-\${runName}.xml;
status=\$(mayhem-\$(arch) --verbosity info show --owner forallsecure --format json \${run} | jq '.[0].status')
if [[ \${status} == *"stopped"* || \${status} == *"failed"* ]]; then exit 2; fi
defects=\$(mayhem-\$(arch) --verbosity info show --owner forallsecure --format json \${run} | jq '.[0].defects|tonumber')
if [[ \${defects} -gt 0 ]]; then echo "\${defects} defects found!"; exit 3; fi
"""
}
}
}
post {
always {
echo 'Archive....'
archiveArtifacts artifacts: 'junit-*.xml, sarif-*.sarif' ,
allowEmptyArchive: true ,
fingerprint: true ,
onlyIfSuccessful: false
junit 'junit-*.xml'
recordIssues (
enabledForFailure: true ,
tool: sarif ( id: "sarif-${TARGET}" , pattern: 'sarif-*.sarif' )
)
}
}
}
}
}
}
API テスト
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 // Run the build on a node with the 'docker' label
node ( "docker" ) {
checkout scm
// MAPI_TOKEN - The API Token secret text added to Credentials
withCredentials ([
string ( credentialsId: "${MAPI_TOKEN}" , variable: "MAPI_TOKEN" )
]) {
//
// 1. BUILD AND TEST YOUR API HERE
//
stage ( "Run Mayhem" ) {
//
// 2. Start your API
// eg. http://localhost:8080/api
//
//
// 3. Download the CLI (or use Jenkins Tools
// see: https://github.com/jenkinsci/custom-tools-plugin/blob/master/README.md)
// Replace $(MAYHEM_URL) with your instance's URL, e.g., https://app.mayhem.security
//
sh '''
curl -Lo mapi $(MAYHEM_URL)/cli/mapi/linux-musl/latest/mapi \
&& chmod +x mapi
'''
//
// 4. Check your API
//
sh '''
mapi run my-api auto <path_to_openapi_spec> \
--url 'http://localhost:8080/api' \
--junit results.xml
'''
//
// 5. Collect junit results
//
junit testResults: 'results.xml'
}
}
}
Mayhem と Jenkins の統合
Mayhem と Jenkins を適切に統合するのに必要な Jenkinsfile
について説明したので、次は、動作するサンプルを確認します。
Jenkins で構成を動作させるには、Jenkins で次の認証情報を設定する必要があります。このサンプルでは、次のパイプライン変数が設定されています。
MAYHEM_CREDENTIALS
: ユーザー名とパスワードを受け取ります。ユーザー名は Mayhem ユーザーであり、パスワードは Mayhem API トークンです。
MAYHEM_URL
: Mayhem サーバーの URL です。https://app.mayhem.security
を設定します。
さらに、上記の Jenkinsfile
構成では、Docker イメージをビルドして GitHub Container Registry にプッシュします。そのため、プロジェクトの可視性が Public
に設定されていることを確認し、Mayhem が GitHub Container Registry からリポジトリの Docker イメージをプルできるようにします。
上記の手順を完了すると、Jenkins パイプラインを実行できるようになります。パイプラインはターゲットに対して Mayhem ランを実行し、脆弱性をテストします。