基于Gitlab、Sonarqube和jenkins的代码静态扫描

基于Gitlab、Sonarqube和jenkins的代码静态扫描_第1张图片

日常工作中,用gitlab做代码管理,sonarqube做代码静态扫描,是质量保障的常见方式。具体落地实践过程中,需要解决如下几个问题:

  • 从gitlab中获取需要做静态扫描的项目信息,包括地址、分支等
  • sonarqube中访问扫描结果的权限问题
  • sonarqube扫描结果的报告汇总

获取需要扫描的项目信息

此处实现的方式方法较多,比如:

  • 使用gitlab4j的api从gitlab中拉取项目列表和分支信息,如果不需要扫描所有的项目和分支,可以对需要进行扫描的项目和分支进行约定,比如基于group或者项目名称或者分支名称等等
  • 另外一种方式就是提供白名单,只扫描白名单中的项目,比如:

基于Gitlab、Sonarqube和jenkins的代码静态扫描

 

sonarqube中访问扫描结果的权限

如果采用sonarqube本身提供的web界面去访问bug等信息,那么需要注意代码安全问题,保证非项目组成员不能查看项目和代码,此处具体落地过程中采用如下方式:

  • 首先,修改项目模板,将项目的默认访问权限改为private:

基于Gitlab、Sonarqube和jenkins的代码静态扫描_第2张图片

 

如此扫描任务完成之后,扫描结果无法直接访问

  • 然后从gitlab中获取该项目的访问权限列表,包括group和member的,然后采用定时任务调用sonarqube的api,添加group和member的访问权限给该扫描结果,如此进行基本权限控

sonarqube扫描结果的报告汇总

扫描结果的汇总,主要通过sonarqube的api获取,具体的api列表可以通过访问http://****:9000/web_api,访问方法如下:

  • 首先在MyAccount页面生成token
  • 然后使用api列表中指明的GET/POST等方法调用相应的接口进行请求,注意sonar采用HTTP Basic Auth的方式进行身份验证,此处的username为token,密码为空,比如我们采用Unirest进行请求的代码如下:
Unirest.get(sonarUrl + uri).basicAuth(sonarToken, "")
 .asString().getBody();
  • 扫描结果的获取,主要使用badges/measure这个API,获取的度量包括bug数、代码行数等,关键代码如下:
@Slf4j
public class SonarBadgesApi extends SonarBaseApi {
 public SonarBadgesApi(String sonarUrl, String sonarToken){
 super(sonarUrl, sonarToken);
 }
 static final String MEASURE_URI = "api/badges/measure";
 static final Pattern PATTERN = Pattern.compile("(.*?)");
 /**
 * 获取所有需要的measure
 * @param key
 * @return
 */
 public String measures(String key){
 Map map = new HashMap();
 String[] metrics = {"bugs", "ncloc", "duplicated_lines_density", "code_smells", "bugs", "vulnerabilities", "sqale_debt_ratio"};
 for(String metric : metrics){
 try {
 map.put(metric, measure(key, metric));
 } catch (Exception e) {
 log.error(e.getMessage(), e);
 continue;
 }
 }
 return JSON.toJSONString(map);
 }
 public String measure(String key, String metric) throws Exception{
 String uriFormat = MEASURE_URI + "?key=%s&metric=%s";
 String uri = String.format(uriFormat, key, metric);
 String content = getToString(uri).toString();
 //值在最后一个text中
 Matcher matcher = PATTERN.matcher(content);
 String value = "";
 while(matcher.find()){
 value = matcher.group(1);
 }
 return value;
 }
}

比较简单,就不解释了。

结合jenkins做持续集成

前文解决了扫描谁、谁能看、怎么看的问题,另外一个关键问题是怎么扫的问题。一个落地方法是结合jenkins做持续集成,需要对jenkins做基于参数的构建:

基于Gitlab、Sonarqube和jenkins的代码静态扫描_第3张图片

 

可以看到,其中的几个参数即为我们在第一步中指明的那些参数,如果从jenkins执行,指明参数即可;如果从平台执行,则需要调用jenkins 的api,关键代码如下:

public void sonarJob(JenkinsSonarJobEntity entity) throws Exception{
 log.info("提交{}开始执行代码扫描...", entity.getRepo());
 Map params = new HashMap<>();
 params.put("REPO", entity.getRepo());
 params.put("PROJECT_NAME", entity.getProjectName());
 params.put("SONAR_PROJECT_NAME", Utils.gitlabProjectToSonarProject(entity.getProjectName()));//sonar的project名字不支持/
 params.put("BRANCH", entity.getBranch());
 params.put("SONAR_BRANCH", Utils.gitlabProjectToSonarProject(entity.getBranch()));//分支不支持/
 params.put("SOURCE", fixForJenkinsEnv(entity.getSource()));
 params.put("TARGET", fixForJenkinsEnv(entity.getTarget()));
 params.put("EXCLUSIONS", fixForJenkinsEnv(entity.getExclusions()));
 String queue = jenkinsServer.getJob("SonarScan").build(params, false).getQueueItemUrlPart();
 log.info("提交完成:{}", queue);
}

此处用到如下包:


 com.offbytwo.jenkins
 jenkins-client
 0.3.8
  • jenkins需要安装sonarqube的插件:

基于Gitlab、Sonarqube和jenkins的代码静态扫描_第4张图片

 

综上,介绍了一个基于gitlab、sonarqube和jenkins的可以落地的静态代码扫描方法,后续在此基础上集成到质量平台时,可以做:

  • 质量大盘
  • 质量报告生成与告警

关注:测试领域专家(头条&微信)获取第一时间文章更新。

你可能感兴趣的:(持续集成)