最近做了 Black Duck 与 Jenkins 的集成,目标是给测试和开发提供定制化、定时的对各个开发代码仓库的进行源码扫描。
为什么要做源码扫描
在产品开发中经常需要引入一些开源组件,但这些开源的代码会给产品风险。因此我们在发布自己产品的时候需要对这些开源组件的漏洞和许可信息进行评估。
Black Duck(黑鸭)是一款对源代码进行扫描、审计和代码管理的软件工具(同类型的工具还有 JFrog Xray)。能够搜索安全的开源代码,检测产品的开源代码使用情况,以检查外来代码的开源代码使用情况和风险情况。
如果不能及时的进行代码扫描,在产品发布快要发布才进行扫描,如果发现问题这时候再去解决就会变得非常被动,因此团队需要尽早发现并解决问题,将 CI 工具进行集成,进行每日、每周、每月扫描就变得十分重要。
Black Duck 手动执行一般步骤
- 手动下载指定 Git 仓库及分支代码
- 去掉不相关的代码(也可以通过 Black Duck 参数去指定要扫描的特定文件或文件夹)
- 手动执行 Black Duck 扫描命令
- 扫描成功后,结果传到内部 Black Duck 网站供相关人员进行审查
Black Duck 与 Jenkins 的集成目标
- 一个流水线支持定制化仓库的代码下载
- 给开发和测试提供简单的、可随时可以执行源码扫描的界面
- 支持定期自动扫描,以及与其他 Jenkins 任务联动执行
Black Duck 参数介绍
--blackduck.url --blackduck.username --blackduck.api.token --detect.project.name --detect.project.version.name --detect.source.path --logging.level.com.synopsys.integration --blackduck.trust.cert=TRUE --detect.blackduck.signature.scanner.snippet.matching
|
更多其他参数可以参照官方的 CI 集成文档 Synopsys Detect for Jenkins
Black Duck 配置
首先,安装 Black Duck 插件 Synopsys Detect 到 Jenkins
然后,配置 Synopsys Detect 插件
- Jenkins -> Confiruration(系统配置)
- Black Duck URL: 公司内部的 Black Duck 网址,例如 https://yourcompany.blackducksoftware.com
- Black Duck credentials: 注意要选择 credentials 类型为 Secret text, Secret 填写你用户的 Token
- 配置完成后点击 Test connections to Black Duck,显示 Connection successful 表示配置成功。
Black Duck 流水线任务效果
Black Duck 流水线代码
pipeline{ agent { node { label 'black-duck' customWorkspace "/agent/workspace/blackduck" } }
parameters { choice( name: 'VERSION', choices: ['MVSURE_v1.1', 'MVSURE_v1.2', 'MVSURE_v2.2'], description: 'Which version do you want scan on black duck? MVSURE_v1.1, MVSURE_v1.2 or others?') choice( name: 'REPO', choices: ['blog-server', 'blog-client', 'blog-docker'], description: 'Which repository code does above VERSION belong to?') string( name: 'BRANCH', defaultValue: 'develop', description: 'Which branch does above VERSION belong to?') choice( name: 'SNIPPET-MODES', choices: ['SNIPPET_MATCHING', 'SNIPPET_MATCHING_ONLY', 'FULL_SNIPPET_MATCHING', 'FULL_SNIPPET_MATCHING_ONLY', 'NONE'], description: 'What snippet scan mode do you want to choose?') }
environment { ROBOT = credentials("d1cbab74-823d-41aa-abb7-858485121212") hub_detect = 'https://blackducksoftware.github.io/hub-detect/hub-detect.sh' blackduck_url = 'https://yourcompany.blackducksoftware.com' blackduck_user = 'robot@yourcompany.com' detect_project = 'GITHUB' detect_project_version = '${VERSION}' detect_source_path = '${WORKSPACE}/${REPO}/src' }
options {buildDiscarder(logRotator(numToKeepStr:'10'))}
stages { stage("git clone"){ steps{ sh ''' if [ -d ${REPO} ]; then rm -rf ${REPO} fi git clone -b ${BRANCH} --depth 1 https://$ROBOT_USR:"$ROBOT_PSW"@git.yourcompany.com/scm/github/${REPO}.git ''' } } stage("black duck scan"){ steps { withCredentials([string(credentialsId: 'robot-black-duck-scan', variable: 'TOKEN')]) { synopsys_detect 'bash <(curl -s ${hub_detect}) --blackduck.url=${blackduck_url} --blackduck.username=${blackduck_user} --blackduck.api.token=${TOKEN} --detect.project.name=${detect_project} --detect.project.version.name=${detect_project_version} --detect.source.path=${detect_source_path} --logging.level.com.synopsys.integration=debug --blackduck.trust.cert=TRUE --detect.blackduck.signature.scanner.snippet.matching=${SNIPPET-MODES}' } } } } post { always { script { def email = load "vars/email.groovy" wrap([$class: 'BuildUser']) { def user = env.BUILD_USER_ID email.build(currentBuild.result, "${user}") } } } success { echo "success, cleanup blackduck workspace" cleanWs() } } }
|