SAST修改,sca漏洞入库逻辑添加

This commit is contained in:
even 2025-07-29 18:49:10 +08:00
parent 56ef0b77dc
commit d5bb9b1404
21 changed files with 942 additions and 23 deletions

View File

@ -1,9 +1,6 @@
package cd.casic.ci.api;
import cd.casic.ci.process.dto.req.sast.SastApplicationCreateReq;
import cd.casic.ci.process.dto.req.sast.SastEngineConfigReq;
import cd.casic.ci.process.dto.req.sast.SastIdentifiedLanguageTaskReq;
import cd.casic.ci.process.dto.req.sast.SastReportCreateReq;
import cd.casic.ci.process.dto.req.sast.*;
import cd.casic.ci.process.dto.resp.sast.*;
import cd.casic.ci.process.process.service.sast.SastService;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
@ -97,8 +94,8 @@ public class SastController {
* sast上传 应用创建或者更新
* */
@PostMapping("/applicationCreateOrUpdate")
public CommonResult<SastApplicationCreateResp> applicationCreateOrUpdate(@RequestBody SastApplicationCreateReq req){
SastApplicationCreateResp sastApplicationCreateResp = sastService.applicationCreate(req);
public CommonResult<SastApplicationCreateResp> applicationCreateOrUpdate(@RequestBody SastApplicationStashReq req){
SastApplicationCreateResp sastApplicationCreateResp = sastService.applicationStash(req);
return CommonResult.success(sastApplicationCreateResp);
}
/**

View File

@ -10,6 +10,7 @@ public class SastUrlConstant {
public static final String engineConfig = "/invoke/engine/config";
public static final String detectionConfig = "/invoke/project/setting/getDetectionConfig";
public static final String applicationCreate = "/invoke/application/create";
public static final String applicationStash = "/invoke/application/stash";
public static final String getApplicationEcho = "/invoke/application/getApplicationEcho";
public static final String reportIndex = "/api/report/index";
public static final String reportDownload = "/api/report/index/download";
@ -19,4 +20,6 @@ public class SastUrlConstant {
public static final String getApplicationStatus = "/invoke/application/getStatus/";
public static final String jsonReportDownload = "/api/report/index/downloadReport";
public static final String getReportInfo = "/api/report/index/getReportInfo";
public static final String stashScan = "/invoke/application/stash/scan/";
public static final String engineLog = "/invoke/engine/%s/log";
}

View File

@ -0,0 +1,64 @@
package cd.casic.ci.process.dto.req.sast;
import lombok.Data;
import java.util.List;
@Data
public class SastApplicationStashReq {
/**
* 项目Id
* */
private String projectId;
/**
* 应用名称
* */
private String applicationName;
/**
* 源代码ONLINE 或者字节码COMPRESS_FILE
* */
private String codeSourceFrom;
/**
* GITLABGITEEGITHUBLOCAL (本地)
* */
private String codeRepoType;
/**
* git连接状态 目前不用git 固定传false
* */
private Boolean connectionStatus;
/**
* 语言和模板配置是否开启编译模式目前不开启传false
* */
private List<SastApplicationConfig> config;
/**
* 传接口获取到的引擎id
* */
private List<String> openEngine;
/**
* 传上传文件接口返回的文件id
* */
private List<String> fileId;
/**
* 编辑时使用 applicationId
* */
private String applicationId;
/**
* 是否开启缺陷自动研判
* */
private Boolean autoAudit;
/**
* 函数过滤内容
* */
private String functionFilter;
@Data
public static class SastApplicationConfig{
private String languageId;
private String templateId;
private String version;
private String compileTool;
private String compileCommand;
private boolean compile;
private boolean isCompile;
}
}

View File

@ -0,0 +1,148 @@
package cd.casic.ci.process.dto.resp;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class ScaVulInfoResp {
/**
* 漏洞UID
*/
private String vulUid;
/**
* CVE编号
*/
private String cve;
/**
* CNNVD编号
*/
private String cnnvd;
/**
* CNVD编号
*/
private String cnvd;
/**
* CWE编号
*/
private String cwe;
/**
* 漏洞名称
*/
private String vulName;
/**
* 漏洞类型
*/
private String vulType;
/**
* 攻击类型
*/
private String attackType;
/**
* 是否可利用
*/
private String isExploit;
/**
* 安全等级
*/
private String securityLevel;
/**
* CVSS4评分
*/
private Double cvss4;
/**
* 发布时间
*/
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate releaseDate;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate updateDate;
/**
* 漏洞描述
*/
private String vulDescription;
/**
* 修复建议
*/
private String suggestion;
/**
* 检测时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime detectionTime;
/**
* 影响组件数量
*/
private Integer influenceComponentNum;
/**
* 影响包数量
*/
private Integer influencePackageNum;
/**
* 影响组件
*/
private String influenceComponent;
/**
* 影响组件镜像
*/
private String influenceComponentImage;
/**
* 漏洞状态
*/
private String vulStatus;
/**
* 审计状态
*/
private String auditStatus;
/**
* 可达类型字符串
*/
private String reachTypeStr;
/**
* 是否可修复
*/
private String fixAvailable;
/**
* 是否隐藏
*/
private Integer isHide;
/**
* CVSS2评分
*/
private String cvss2;
/**
* CVSS3评分
*/
private String cvss3;
}

View File

@ -0,0 +1,19 @@
package cd.casic.ci.process.dto.resp.sast;
import lombok.Data;
@Data
public class SastApplicationStashResp {
private String applicationId;
private String applicationName;
private String taskId;
private String fileId;
private String jobAddBy;
private String jobStatus;
private String checkStartTime;
private String checkEndTime;
private String codeQualityMetric;
private String engineType;
private String progress;
private String type;
}

View File

@ -0,0 +1,18 @@
package cd.casic.ci.process.dto.resp.sast;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class SastEngineLogResp {
private String taskId;
private LocalDateTime createTime;
private String serverFrom;
private String ipFrom;
private String containerId;
private String stageInfo;
private String message;
private String infoLevel;
private String prettyPrint;
}

View File

@ -7,8 +7,8 @@ import lombok.Data;
@Data
@AllArgsConstructor
public abstract class ExecuteTaskPostHandler {
private String taskId;
private String pipelineId;
protected String taskId;
protected String pipelineId;
/**
* 流水线执行结束需要执行的操作

View File

@ -153,6 +153,8 @@ public class TestCaseGenerationWorker extends DockerWorker {
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
sftp = (ChannelSftp) session.openChannel("sftp");
sftp.connect();
@ -167,6 +169,7 @@ public class TestCaseGenerationWorker extends DockerWorker {
String binaryId = JSON.parseObject(targetUploadRes).getString("id");
append(context,"开始创建测试用例生成task");
sftp.disconnect();
// 创建task
TestCaseAITaskCreateReq req = new TestCaseAITaskCreateReq();
req.setBinaryId(binaryId);
@ -186,8 +189,10 @@ public class TestCaseGenerationWorker extends DockerWorker {
} else {
String logRes = aiGeneratorService.getTaskLog(taskId);
String logStr = JSON.parseObject(logRes).getString("log");
if (StringUtils.isNotEmpty(logStr)) {
append(context,logStr);
}
}
// append(context,"task当前执行状态"+taskStatusRes);
}
append(context,"开始下载生成的测试用例文件");

View File

@ -4,10 +4,7 @@ package cd.casic.ci.process.engine.worker.sast;
import cd.casic.ci.process.common.WorkAtom;
import cd.casic.ci.process.dto.req.sast.SastApplicationCreateReq;
import cd.casic.ci.process.dto.req.sast.SastReportCreateReq;
import cd.casic.ci.process.dto.resp.sast.SastApplicationCreateResp;
import cd.casic.ci.process.dto.resp.sast.SastApplicationEchoResp;
import cd.casic.ci.process.dto.resp.sast.SastApplicationStatusResp;
import cd.casic.ci.process.dto.resp.sast.SastReportStatusResp;
import cd.casic.ci.process.dto.resp.sast.*;
import cd.casic.ci.process.engine.constant.SastConstant;
import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.engine.worker.base.BaseWorker;
@ -24,6 +21,7 @@ import com.alibaba.fastjson.JSONObject;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -58,17 +56,18 @@ public class SastWorker extends BaseWorker {
append(context,"当前任务正在运行中");
// toBadEnding();
} else{
SastApplicationCreateReq sastApplicationCreateReq = converter.converter(applicationEcho);
List<String> list = applicationEcho.getLodeFiles().stream().map(SastApplicationEchoResp.LodeFile::getFileId).toList();
sastApplicationCreateReq.setFileId(list);
append(context,"开始启动SAST任务,检测文件信息:{}"+JSON.toJSONString(applicationEcho.getLodeFiles()));
log.info("SAST启动任务入参:{}",JSON.toJSONString(sastApplicationCreateReq));
SastApplicationCreateResp sastApplicationCreateResp = sastService.applicationCreate(sastApplicationCreateReq);
// SastApplicationCreateReq sastApplicationCreateReq = converter.converter(applicationEcho);
// List<String> list = applicationEcho.getLodeFiles().stream().map(SastApplicationEchoResp.LodeFile::getFileId).toList();
// sastApplicationCreateReq.setFileId(list);
// append(context,"开始启动SAST任务,检测文件信息:{}"+JSON.toJSONString(applicationEcho.getLodeFiles()));
// log.info("SAST启动任务入参:{}",JSON.toJSONString(sastApplicationCreateReq));
SastApplicationStashResp sastApplicationCreateResp = sastService.stashScan(applicationId);
log.info("SAST启动任务返回值:{}",JSON.toJSONString(sastApplicationCreateResp));
append(context,"启动任务完毕");
}
// 检测状态是否完毕
applicationStatus = sastService.getApplicationStatus(applicationId);
List<SastEngineLogResp> oldLogList = new ArrayList<>();
int repeat = 0;
while (!SastConstant.STATUS_JOB_DONE.equals(applicationStatus.getJobStatus())) {
try {
@ -92,6 +91,14 @@ public class SastWorker extends BaseWorker {
append(context,"任务被取消");
toBadEnding();
}
List<SastEngineLogResp> logList = sastService.engineLog(applicationId);
if (logList.size()>oldLogList.size()) {
for (int i = oldLogList.size(); i < logList.size(); i++) {
SastEngineLogResp logResp = logList.get(i);
append(context,logResp.getPrettyPrint());
}
oldLogList = logList;
}
repeat = 0;
}
JSONObject reportJSON = getReportJSON(applicationId, SastConstant.REPORT_MODE_DETAILS,context);

View File

@ -5,18 +5,21 @@ import cd.casic.ci.process.common.WorkAtom;
import cd.casic.ci.process.dto.req.report.ReportAssetTaskReq;
import cd.casic.ci.process.dto.resp.report.ReportResp;
import cd.casic.ci.process.engine.context.ConstantContextHolder;
import cd.casic.ci.process.engine.postHandler.ExecuteTaskPostHandler;
import cd.casic.ci.process.engine.runContext.BaseRunContext;
import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.engine.worker.base.HttpWorker;
import cd.casic.ci.process.process.dao.pipeline.PipTaskDao;
import cd.casic.ci.process.process.dataObject.base.BaseIdReq;
import cd.casic.ci.process.process.dataObject.base.PipBaseElement;
import cd.casic.ci.process.process.dataObject.history.PipPipelineHisInstance;
import cd.casic.ci.process.process.dataObject.pipeline.PipPipeline;
import cd.casic.ci.process.process.dataObject.target.TargetVersion;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.ci.process.process.service.pipeline.PipelineService;
import cd.casic.ci.process.process.service.report.impl.ReportServiceImpl;
import cd.casic.ci.process.process.service.target.impl.TargetVersionServiceImpl;
import cd.casic.ci.process.process.service.vulInfo.VulInfoService;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import cn.hutool.core.util.ObjectUtil;
@ -38,6 +41,8 @@ import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import static cd.casic.ci.process.engine.constant.AFLConstant.GROUP_ID;
/**
* @author HopeLi
* @version v1.0
@ -62,6 +67,8 @@ public class ApplicationWorker extends HttpWorker {
@Resource
private ReportServiceImpl reportService;
@Resource
private VulInfoService vulInfoService;
@Override
@ -112,6 +119,14 @@ public class ApplicationWorker extends HttpWorker {
log.error("==================SCA-应用包审查分析节点执行失败=================",e);
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"SCA-应用包审查分析节点执行失败");
}
Integer scaTaskId = pipTask.getTaskProperties().get("scaTaskId") instanceof Integer ? ((Integer) pipTask.getTaskProperties().get("scaTaskId")) : null;
String fileName = targetVersion.getFileName();
postHandlerManager.registerPostHandler(new ExecuteTaskPostHandler(pipTask.getId(),pipelineId) {
@Override
public void executeAfterDone(PipPipelineHisInstance pipPipelineHisInstance) {
vulInfoService.scaToVulInfoSave(scaTaskId,pipeline.getTargetType(),fileName,"长沙",pipPipelineHisInstance.getId(),taskId,"APPLICATION");
}
});
}
localVariables.put("statusCode", statusCode + "");
}
@ -291,5 +306,4 @@ public class ApplicationWorker extends HttpWorker {
}
return 0;
}
}

View File

@ -5,18 +5,21 @@ import cd.casic.ci.process.common.WorkAtom;
import cd.casic.ci.process.dto.req.report.ReportAssetTaskReq;
import cd.casic.ci.process.dto.resp.report.ReportResp;
import cd.casic.ci.process.engine.context.ConstantContextHolder;
import cd.casic.ci.process.engine.postHandler.ExecuteTaskPostHandler;
import cd.casic.ci.process.engine.runContext.BaseRunContext;
import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.engine.worker.base.HttpWorker;
import cd.casic.ci.process.process.dao.pipeline.PipTaskDao;
import cd.casic.ci.process.process.dataObject.base.BaseIdReq;
import cd.casic.ci.process.process.dataObject.base.PipBaseElement;
import cd.casic.ci.process.process.dataObject.history.PipPipelineHisInstance;
import cd.casic.ci.process.process.dataObject.pipeline.PipPipeline;
import cd.casic.ci.process.process.dataObject.target.TargetVersion;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.ci.process.process.service.pipeline.PipelineService;
import cd.casic.ci.process.process.service.report.impl.ReportServiceImpl;
import cd.casic.ci.process.process.service.target.impl.TargetVersionServiceImpl;
import cd.casic.ci.process.process.service.vulInfo.VulInfoService;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import cn.hutool.core.util.ObjectUtil;
@ -63,7 +66,8 @@ public class ScaBinaryWorker extends HttpWorker {
@Resource
private ReportServiceImpl reportService;
@Resource
private VulInfoService vulInfoService;
@Override
public void execute(TaskRunContext context) {
int statusCode = 0;
@ -117,6 +121,14 @@ public class ScaBinaryWorker extends HttpWorker {
log.error("==================SCA-BINARY节点执行失败=================",e);
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"SCA-SBOM节点执行失败");
}
Integer scaTaskId = pipTask.getTaskProperties().get("scaTaskId") instanceof Integer ? ((Integer) pipTask.getTaskProperties().get("scaTaskId")) : null;
String fileName = targetVersion.getFileName();
postHandlerManager.registerPostHandler(new ExecuteTaskPostHandler(pipTask.getId(),pipelineId) {
@Override
public void executeAfterDone(PipPipelineHisInstance pipPipelineHisInstance) {
vulInfoService.scaToVulInfoSave(scaTaskId,pipeline.getTargetType(),fileName,"长沙",pipPipelineHisInstance.getId(),taskId,"APPLICATION");
}
});
}
localVariables.put("statusCode", statusCode + "");

View File

@ -5,18 +5,21 @@ import cd.casic.ci.process.common.WorkAtom;
import cd.casic.ci.process.dto.req.report.ReportAssetTaskReq;
import cd.casic.ci.process.dto.resp.report.ReportResp;
import cd.casic.ci.process.engine.context.ConstantContextHolder;
import cd.casic.ci.process.engine.postHandler.ExecuteTaskPostHandler;
import cd.casic.ci.process.engine.runContext.BaseRunContext;
import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.engine.worker.base.HttpWorker;
import cd.casic.ci.process.process.dao.pipeline.PipTaskDao;
import cd.casic.ci.process.process.dataObject.base.BaseIdReq;
import cd.casic.ci.process.process.dataObject.base.PipBaseElement;
import cd.casic.ci.process.process.dataObject.history.PipPipelineHisInstance;
import cd.casic.ci.process.process.dataObject.pipeline.PipPipeline;
import cd.casic.ci.process.process.dataObject.target.TargetVersion;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.ci.process.process.service.pipeline.PipelineService;
import cd.casic.ci.process.process.service.report.impl.ReportServiceImpl;
import cd.casic.ci.process.process.service.target.impl.TargetVersionServiceImpl;
import cd.casic.ci.process.process.service.vulInfo.VulInfoService;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import cn.hutool.core.util.ObjectUtil;
@ -60,7 +63,8 @@ public class ScaMirrorWorker extends HttpWorker {
@Resource
private PipTaskDao pipTaskDao;
@Resource
private VulInfoService vulInfoService;
@Resource
private ReportServiceImpl reportService;
@ -115,6 +119,14 @@ public class ScaMirrorWorker extends HttpWorker {
log.error("==================SCA-MIRROR节点执行失败=================",e);
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"SCA-MIRROR节点执行失败");
}
Integer scaTaskId = pipTask.getTaskProperties().get("scaTaskId") instanceof Integer ? ((Integer) pipTask.getTaskProperties().get("scaTaskId")) : null;
String fileName = targetVersion.getFileName();
postHandlerManager.registerPostHandler(new ExecuteTaskPostHandler(pipTask.getId(),pipelineId) {
@Override
public void executeAfterDone(PipPipelineHisInstance pipPipelineHisInstance) {
vulInfoService.scaToVulInfoSave(scaTaskId,pipeline.getTargetType(),fileName,"长沙",pipPipelineHisInstance.getId(),taskId,"APPLICATION");
}
});
}
localVariables.put("statusCode", statusCode + "");

View File

@ -5,18 +5,21 @@ import cd.casic.ci.process.common.WorkAtom;
import cd.casic.ci.process.dto.req.report.ReportAssetTaskReq;
import cd.casic.ci.process.dto.resp.report.ReportResp;
import cd.casic.ci.process.engine.context.ConstantContextHolder;
import cd.casic.ci.process.engine.postHandler.ExecuteTaskPostHandler;
import cd.casic.ci.process.engine.runContext.BaseRunContext;
import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.engine.worker.base.HttpWorker;
import cd.casic.ci.process.process.dao.pipeline.PipTaskDao;
import cd.casic.ci.process.process.dataObject.base.BaseIdReq;
import cd.casic.ci.process.process.dataObject.base.PipBaseElement;
import cd.casic.ci.process.process.dataObject.history.PipPipelineHisInstance;
import cd.casic.ci.process.process.dataObject.pipeline.PipPipeline;
import cd.casic.ci.process.process.dataObject.target.TargetVersion;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.ci.process.process.service.pipeline.PipelineService;
import cd.casic.ci.process.process.service.report.impl.ReportServiceImpl;
import cd.casic.ci.process.process.service.target.impl.TargetVersionServiceImpl;
import cd.casic.ci.process.process.service.vulInfo.VulInfoService;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import cn.hutool.core.util.ObjectUtil;
@ -64,7 +67,8 @@ public class ScaSbomWorker extends HttpWorker {
@Resource
private ReportServiceImpl reportService;
@Resource
private VulInfoService vulInfoService;
@Override
public void execute(TaskRunContext context) {
int statusCode = 0;
@ -113,6 +117,14 @@ public class ScaSbomWorker extends HttpWorker {
log.error("==================SCA-SBOM节点执行失败=================",e);
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"SCA-SBOM节点执行失败");
}
Integer scaTaskId = pipTask.getTaskProperties().get("scaTaskId") instanceof Integer ? ((Integer) pipTask.getTaskProperties().get("scaTaskId")) : null;
String fileName = targetVersion.getFileName();
postHandlerManager.registerPostHandler(new ExecuteTaskPostHandler(pipTask.getId(),pipelineId) {
@Override
public void executeAfterDone(PipPipelineHisInstance pipPipelineHisInstance) {
vulInfoService.scaToVulInfoSave(scaTaskId,pipeline.getTargetType(),fileName,"长沙",pipPipelineHisInstance.getId(),taskId,"APPLICATION");
}
});
}
localVariables.put("statusCode", statusCode + "");

View File

@ -0,0 +1,200 @@
package cd.casic.ci.process.process.converter;
import cd.casic.ci.process.dto.resp.ScaVulInfoResp;
import cd.casic.ci.process.process.dataObject.volumnInfo.VulInfo;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
@Mapper(componentModel = "spring")
public interface VulInfoConverter {
VulInfoConverter INSTANCE = Mappers.getMapper(VulInfoConverter.class);
/**
* JSON数据转换为数据库实体
*/
@Mappings({
@Mapping(target = "id", ignore = true),
@Mapping(target = "createTime", source = "releaseDate", qualifiedByName = "dateToDateTime"),
@Mapping(target = "modifyTime", source = "updateDate", qualifiedByName = "dateToDateTime"),
@Mapping(target = "verifyStatus", source = "auditStatus"),
@Mapping(target = "vulId", source = "vulUid"),
@Mapping(target = "isOpenSource", ignore = true),
@Mapping(target = "vulTitle", source = "vulName"),
@Mapping(target = "vulDescription", source = "vulDescription"),
@Mapping(target = "severity", source = "securityLevel", qualifiedByName = "securityLevelToSeverity"),
@Mapping(target = "solution", source = "suggestion"),
@Mapping(target = "relieve", ignore = true),
@Mapping(target = "targetName", source = "influenceComponent"),
@Mapping(target = "cwes", source = "cwe", qualifiedByName = "cweToCwes"),
@Mapping(target = "level", source = "isExploit", qualifiedByName = "exploitToLevel"),
@Mapping(target = "targetType", ignore = true),
@Mapping(target = "targetUrl", ignore = true),
@Mapping(target = "affectProjectId", ignore = true),
@Mapping(target = "unaffectedVersions", ignore = true),
@Mapping(target = "affectProductName", source = "influenceComponent")
})
VulInfo scaToVulInfo(ScaVulInfoResp vulJsonData);
List<VulInfo> scaToVulInfo(List<ScaVulInfoResp> vulJsonData);
/**
* 数据库实体转换为JSON数据
*/
@Mappings({
@Mapping(target = "vulUid", source = "vulId"),
@Mapping(target = "cve", ignore = true),
@Mapping(target = "cnnvd", ignore = true),
@Mapping(target = "cnvd", ignore = true),
@Mapping(target = "cwe", source = "cwes", qualifiedByName = "cwesToCwe"),
@Mapping(target = "vulName", source = "vulTitle"),
@Mapping(target = "vulType", ignore = true),
@Mapping(target = "attackType", ignore = true),
@Mapping(target = "isExploit", source = "level", qualifiedByName = "levelToExploit"),
@Mapping(target = "securityLevel", source = "severity", qualifiedByName = "severityToSecurityLevel"),
@Mapping(target = "cvss4", ignore = true),
@Mapping(target = "releaseDate", source = "createTime", qualifiedByName = "dateTimeToDate"),
@Mapping(target = "updateDate", source = "modifyTime", qualifiedByName = "dateTimeToDate"),
@Mapping(target = "vulDescription", source = "vulDescription"),
@Mapping(target = "suggestion", source = "solution"),
@Mapping(target = "detectionTime", ignore = true),
@Mapping(target = "influenceComponentNum", ignore = true),
@Mapping(target = "influencePackageNum", ignore = true),
@Mapping(target = "influenceComponent", source = "targetName"),
@Mapping(target = "influenceComponentImage", source = "targetName"),
@Mapping(target = "vulStatus", ignore = true),
@Mapping(target = "auditStatus", source = "verifyStatus"),
@Mapping(target = "reachTypeStr", ignore = true),
@Mapping(target = "fixAvailable", ignore = true),
@Mapping(target = "isHide", ignore = true),
@Mapping(target = "cvss2", ignore = true),
@Mapping(target = "cvss3", ignore = true)
})
ScaVulInfoResp vulInfoToSca(VulInfo vulInfo);
/**
* LocalDate转换为LocalDateTime
*/
@Named("dateToDateTime")
default LocalDateTime dateToDateTime(LocalDate date) {
if (date == null) {
return LocalDateTime.now();
}
return date.atStartOfDay();
}
/**
* LocalDateTime转换为LocalDate
*/
@Named("dateTimeToDate")
default LocalDate dateTimeToDate(LocalDateTime dateTime) {
if (dateTime == null) {
return LocalDate.now();
}
return dateTime.toLocalDate();
}
/**
* CWE转换为CWE列表
*/
@Named("cweToCwes")
default List<String> cweToCwes(String cwe) {
if (cwe == null || cwe.trim().isEmpty()) {
return Arrays.asList();
}
return Arrays.asList(cwe.split(","));
}
/**
* CWE列表转换为CWE字符串
*/
@Named("cwesToCwe")
default String cwesToCwe(List<String> cwes) {
if (cwes == null || cwes.isEmpty()) {
return "";
}
return String.join(",", cwes);
}
/**
* 利用难度转换为利用级别
*/
@Named("exploitToLevel")
default Boolean exploitToLevel(String isExploit) {
if (isExploit == null) {
return false;
}
// 映射规则容易 -> true, 困难 -> false, 一般 -> true
switch (isExploit) {
case "容易":
case "一般":
return true;
case "困难":
default:
return false;
}
}
/**
* 利用级别转换为利用难度
*/
@Named("levelToExploit")
default String levelToExploit(Boolean level) {
if (level == null) {
return "困难";
}
return level ? "容易" : "困难";
}
/**
* 安全等级转换为危险等级
*/
@Named("securityLevelToSeverity")
default Integer securityLevelToSeverity(String securityLevel) {
if (securityLevel == null) {
return 0;
}
// 映射规则严重 -> 1, 高危 -> 2, 中危 -> 3, 低危 -> 4
switch (securityLevel) {
case "严重":
return 1;
case "高危":
return 2;
case "中危":
return 3;
case "低危":
return 4;
default:
return 0;
}
}
/**
* 危险等级转换为安全等级
*/
@Named("severityToSecurityLevel")
default String severityToSecurityLevel(Integer severity) {
if (severity == null) {
return "未知";
}
// 映射规则1 -> 严重, 2 -> 高危, 3 -> 中危, 4 -> 低危
switch (severity) {
case 1:
return "严重";
case 2:
return "高危";
case 3:
return "中危";
case 4:
return "低危";
default:
return "未知";
}
}
}

View File

@ -0,0 +1,7 @@
package cd.casic.ci.process.process.dao.vulInfo;
import cd.casic.ci.process.process.dataObject.volumnInfo.VulInfo;
import cd.casic.framework.mybatis.core.mapper.BaseMapperX;
public interface VulInfoDao extends BaseMapperX<VulInfo> {
}

View File

@ -0,0 +1,134 @@
package cd.casic.ci.process.process.dataObject.volumnInfo;
import cd.casic.framework.mybatis.core.type.EncryptTypeHandler;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.ibatis.type.JdbcType;
import java.time.LocalDateTime;
import java.util.List;
@Data
@TableName(value = "vul_info",autoResultMap = true)
public class VulInfo {
/**
* 主键ID自动生成
*/
@TableId(type = IdType.ASSIGN_ID)
private Long id;
/**
* 创建时间自动生成
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
/**
* 修改时间自动生成修改时间就是审核时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime modifyTime;
/**
* 漏洞状态枚举未审核审核中审核完
*/
private String verifyStatus;
/**
* 内部漏洞id不需要输入根据类型+日期随机生成
*/
private String vulId;
/**
* 是否开源选项框对勾源码时候才会有这个概念
*/
private Boolean isOpenSource;
/**
* 中文标题
*/
private String vulTitle;
/**
* 中文描述
*/
private String vulDescription;
/**
* 危险等级,高中低三种
*/
private Integer severity;
/**
* 中文修复方案
*/
private String solution;
/**
* 暂时修复的缓解措施
*/
private String relieve;
/**
* 目标的名称
*/
private String targetName;
/**
* 漏洞类型
*/
@TableField(typeHandler = JacksonTypeHandler.class,jdbcType = JdbcType.VARCHAR)
private List<String> cwes;
/**
* 利用级别可利用和不可利用默认不要利用
*/
private Boolean level;
/**
* 发现的漏洞目标类型源码二进制固件三种
*/
private String targetType;
/**
* 目标的链接来自于人机协同系统就是一个下载地址的url
*/
private String targetUrl;
/**
* 受影响的目标用户自己输入
*/
private String affectProjectId;
/**
* 类型是源码的情况才有这个概念安全分支列表
*/
private String unaffectedVersions;
/**
* 受影响产品名
*/
private String affectProductName;
/**
* 城市
* */
private String city;
/**
* 关联的流水线执行记录id
* */
private String instanceId;
/**
* 流水线节点id
* */
private String taskId;
/**
* 节点类型
* */
private String taskType;
}

View File

@ -1,6 +1,7 @@
package cd.casic.ci.process.process.service.sast;
import cd.casic.ci.process.dto.req.sast.SastApplicationCreateReq;
import cd.casic.ci.process.dto.req.sast.SastApplicationStashReq;
import cd.casic.ci.process.dto.req.sast.SastIdentifiedLanguageTaskReq;
import cd.casic.ci.process.dto.req.sast.SastReportCreateReq;
import cd.casic.ci.process.dto.resp.sast.*;
@ -22,6 +23,7 @@ public interface SastService {
List<SastEngineConfigResp> engineConfig(List<String> languageIdList);
SastDetectionConfigResp detectionConfig(String languageId);
SastApplicationCreateResp applicationCreate(SastApplicationCreateReq req);
SastApplicationCreateResp applicationStash(SastApplicationStashReq req);
SastApplicationEchoResp getApplicationEcho(String applicationId);
String reportIndex(SastReportCreateReq req);
public String reportDownload(String reportId);
@ -34,4 +36,6 @@ public interface SastService {
public JSONObject jsonReportDownload(String reportId);
public SastReportStatusResp getReportStatus(String reportId);
SastApplicationStashResp stashScan(String applicationId);
List<SastEngineLogResp> engineLog(String applicationId);
}

View File

@ -1,6 +1,7 @@
package cd.casic.ci.process.process.service.sast.impl;
import cd.casic.ci.process.dto.req.sast.SastApplicationCreateReq;
import cd.casic.ci.process.dto.req.sast.SastApplicationStashReq;
import cd.casic.ci.process.dto.req.sast.SastIdentifiedLanguageTaskReq;
import cd.casic.ci.process.dto.req.sast.SastReportCreateReq;
import cd.casic.ci.process.dto.resp.report.ReportResp;
@ -165,6 +166,15 @@ public class SastServiceImpl implements SastService {
return body;
}
@Override
public SastApplicationCreateResp applicationStash(SastApplicationStashReq req) {
HttpHeaders httpHeaders = getHeaders();
HttpEntity<SastApplicationStashReq> entity = new HttpEntity<>(req,httpHeaders);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<SastApplicationCreateResp> exchange = restTemplate.exchange(sastProperties.getBaseUrl() +applicationStash, HttpMethod.POST,entity,SastApplicationCreateResp.class,new HashMap<>());
SastApplicationCreateResp body = exchange.getBody();
return body;
}
@Override
public SastApplicationEchoResp getApplicationEcho(String applicationId){
HttpHeaders httpHeaders = getHeaders();
Map<String, String> entityMap = new HashMap<>();
@ -267,6 +277,28 @@ public class SastServiceImpl implements SastService {
return exchange.getBody();
}
@Override
public SastApplicationStashResp stashScan(String applicationId) {
HttpHeaders httpHeaders = getHeaders();
Map<String, String> entityMap = new HashMap<>();
HttpEntity<Map<String, String>> entity = new HttpEntity<>(entityMap,httpHeaders);
String uriString=sastProperties.getBaseUrl()+stashScan+applicationId;
log.info("sast 开始任务url:{}",uriString);
ResponseEntity<SastApplicationStashResp> exchange = restTemplate.exchange(uriString, HttpMethod.POST,entity, SastApplicationStashResp.class,new HashMap<>());
return exchange.getBody();
}
@Override
public List<SastEngineLogResp> engineLog(String applicationId) {
HttpHeaders httpHeaders = getHeaders();
Map<String, String> entityMap = new HashMap<>();
HttpEntity<Map<String, String>> entity = new HttpEntity<>(entityMap,httpHeaders);
String uriString=sastProperties.getBaseUrl()+engineLog;
uriString=String.format(uriString,applicationId);
log.info("sast 开始任务url:{}",uriString);
ResponseEntity<String> exchange = restTemplate.exchange(uriString, HttpMethod.GET,entity, String.class,new HashMap<>());
return JSONArray.parseArray(exchange.getBody(), SastEngineLogResp.class);
}
private HttpHeaders getHeaders(){
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set(TOKEN_HEADER_KEY,TOKEN_PREFIX+getToken());

View File

@ -0,0 +1,19 @@
package cd.casic.ci.process.process.service.vulInfo;
import cd.casic.ci.process.dto.resp.ScaVulInfoResp;
import cd.casic.ci.process.process.dao.vulInfo.VulInfoDao;
import cd.casic.ci.process.process.dataObject.volumnInfo.VulInfo;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
public interface VulInfoService extends IService<VulInfo> {
void scaToVulInfoSave(Integer scaTaskId,String targetType,String targetName,String city,String instanceId,String taskId,String taskType);
Integer scaVulCountGet(Integer scaTaskId) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException;
List<ScaVulInfoResp> scaVulListGet(Integer scaTaskId) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException;
}

View File

@ -0,0 +1,147 @@
package cd.casic.ci.process.process.service.vulInfo.impl;
import cd.casic.ci.process.dto.req.report.ReportAssetTaskReq;
import cd.casic.ci.process.dto.resp.ScaVulInfoResp;
import cd.casic.ci.process.engine.context.ConstantContextHolder;
import cd.casic.ci.process.process.converter.VulInfoConverter;
import cd.casic.ci.process.process.dao.vulInfo.VulInfoDao;
import cd.casic.ci.process.process.dataObject.volumnInfo.VulInfo;
import cd.casic.ci.process.process.service.vulInfo.VulInfoService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import static cd.casic.ci.process.engine.worker.base.HttpWorker.getRestTemplateWithoutSANCheck;
@Service
@Slf4j
public class VulInfoServiceImpl extends ServiceImpl<VulInfoDao,VulInfo> implements VulInfoService {
@Resource
private VulInfoConverter converter;
@Resource
private VulInfoDao vulInfoDao;
@Override
public void scaToVulInfoSave(Integer scaTaskId,String targetType,String targetName,String city,String instanceId,String taskId,String taskType) {
List<ScaVulInfoResp> scaVulInfoResps = null;
try {
scaVulInfoResps = scaVulListGet(scaTaskId);
} catch (Exception e) {
return;
}
System.out.println(scaVulInfoResps.size());
System.out.println(scaVulInfoResps);
List<VulInfo> vulInfos = converter.scaToVulInfo(scaVulInfoResps);
vulInfos.forEach(item->{
item.setTargetType(targetType);
item.setTargetName(targetName);
item.setCity(city);
item.setInstanceId(instanceId);
item.setTaskId(taskId);
item.setTaskType(taskType);
});
saveBatch(vulInfos);
}
@Override
public Integer scaVulCountGet(Integer scaTaskId) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
RestTemplate restTemplate= getRestTemplateWithoutSANCheck();
String url = ConstantContextHolder.getScaIp() + "/openapi/v1/task/vul/list";
JSONObject json = new JSONObject();
json.put("taskId", scaTaskId);
json.put("pageNo", 1);
json.put("pageSize", 1);
String body = json.toJSONString();
HttpEntity<String> entity = new HttpEntity<>(body,createHeaders());
ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, entity, String.class, new HashMap<>());
String res = exchange.getBody();
return JSONObject.parseObject(res).getInteger("total");
}
@Override
public List<ScaVulInfoResp> scaVulListGet(Integer scaTaskId) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
HttpHeaders headers = createHeaders();
RestTemplate restTemplate = getRestTemplateWithoutSANCheck();
JSONObject json = new JSONObject();
ReportAssetTaskReq req = new ReportAssetTaskReq();
//报告维度 5-组件默认为5-组件
json.put("dimension", req.getDimension());
json.put("reportTemplateId", req.getReportTemplateId());
json.put("type", 4);
json.put("reportName", req.getReportName());
json.put("scaTaskId", scaTaskId);
String generateUrl = ConstantContextHolder.getScaIp()+"/openapi/v1/asset/report/task";
HttpEntity<String> entity = new HttpEntity<>(json.toJSONString(),headers);
// 生成报告
ResponseEntity<String> exchange = restTemplate.exchange(generateUrl, HttpMethod.POST, entity, String.class, new HashMap<>());
String generateRes = exchange.getBody();
JSONObject generateResObj = JSON.parseObject(generateRes);
if ("success".equals(generateResObj.getString("message"))) {
Integer id = generateResObj.getInteger("data");
// 检查报告状态
if (!checkScaReportStatus(id,restTemplate,headers)) {
return List.of();
}
// 下载报告
String downloadUrl = ConstantContextHolder.getScaIp()+"/openapi/v1/asset/report/downLoadReport/batch";
JSONObject downloadBody = new JSONObject();
downloadBody.put("reportIds", Collections.singletonList(id));
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> downloadEntity = new HttpEntity<>(downloadBody.toJSONString(),headers);
ResponseEntity<byte[]> downloadExchange = restTemplate.exchange(downloadUrl, HttpMethod.POST, downloadEntity, byte[].class, new HashMap<>());
byte[] downloadRes = downloadExchange.getBody();
String reportString = new String(downloadRes, StandardCharsets.UTF_8);
JSONObject reportObj = JSONObject.parseObject(reportString);
// 解析报告
String vulInfo = reportObj.getString("vulInfo");
return JSONArray.parseArray(vulInfo, ScaVulInfoResp.class);
}
return List.of();
}
private HttpHeaders createHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.add("OpenApiUserToken", ConstantContextHolder.getScaToken());
return headers;
}
private Boolean checkScaReportStatus(Integer reporterId,RestTemplate restTemplate,HttpHeaders headers){
HttpEntity<String> checkEntity = new HttpEntity<>("",headers);
String checkUrl = ConstantContextHolder.getScaIp()+"/openapi/v1/asset/report/status/"+reporterId;
while (true){
ResponseEntity<String> exchange = restTemplate.exchange(checkUrl, HttpMethod.POST, checkEntity, String.class, new HashMap<>());
JSONObject res = JSONObject.parseObject(exchange.getBody());
JSONObject data = res.getJSONObject("data");
Integer status = data.getInteger("status");
log.info("报告生成状态 -1-排队中 0-生成中 1-已生成 2-生成失败:{}",status);
//报告状态 -1-排队中 0-生成中 1-已生成 2-生成失败
if (status==null) {
break;
}
if (status.equals(1)) {
return true;
}else if (status.equals(2)) {
return false;
}
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
}
}
return false;
}
}

View File

@ -0,0 +1,65 @@
package cd.casic.server;
import cd.casic.ci.process.constant.PipelineTargetTypeConstant;
import cd.casic.ci.process.dto.req.testCase.TestCaseAITaskCreateReq;
import cd.casic.ci.process.dto.resp.ScaVulInfoResp;
import cd.casic.ci.process.process.converter.VulInfoConverter;
import cd.casic.ci.process.process.dataObject.target.TargetVersion;
import cd.casic.ci.process.process.dataObject.volumnInfo.VulInfo;
import cd.casic.ci.process.process.service.testCase.TestCaseAIGeneratorService;
import cd.casic.ci.process.process.service.vulInfo.VulInfoService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.web.WebAppConfiguration;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
@SpringBootTest(classes = {OpsServerApplication.class})
@ActiveProfiles("local")
@Slf4j
@WebAppConfiguration
public class VulInfoTest {
@Resource
private VulInfoService vulInfoService;
@Resource
private VulInfoConverter converter;
@Test
public void test() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
System.out.println(vulInfoService.scaVulCountGet(681));
}
@Test
public void scaVulListGet() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
String targetType = PipelineTargetTypeConstant.SOURCE_CODE;
Integer scaTaskId = 681;
String targetName="测试目标名称";
String city = "长沙";
String instanceId = "instanceId";
String taskId = "taskId";
String taskType ="taskType";
List<ScaVulInfoResp> scaVulInfoResps = vulInfoService.scaVulListGet(scaTaskId);
System.out.println(scaVulInfoResps.size());
System.out.println(scaVulInfoResps);
List<VulInfo> vulInfos = converter.scaToVulInfo(scaVulInfoResps);
vulInfos.forEach(item->{
item.setTargetType(targetType);
item.setTargetName(targetName);
item.setCity(city);
item.setInstanceId(instanceId);
item.setTaskId(taskId);
item.setTaskType(taskType);
});
vulInfoService.saveBatch(vulInfos);
}
}