diff --git a/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/LocalAflCrashesController.java b/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/LocalAflCrashesController.java new file mode 100644 index 00000000..1567609e --- /dev/null +++ b/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/LocalAflCrashesController.java @@ -0,0 +1,40 @@ +package cd.casic.ci.api; + + +import cd.casic.ci.process.dto.req.localAflCrashes.LocalAflCrashesQueryReq; +import cd.casic.ci.process.dto.req.localAflCrashes.LocalAflCrashesSaveReq; +import cd.casic.ci.process.dto.resp.localAflCrashes.LocalAflCrashesResp; +import cd.casic.ci.process.process.service.localAflCrashes.LocalAflCrashesService; +import cd.casic.ci.process.util.SftpUploadUtil; +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.framework.commons.pojo.PageResult; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/LocalAflCrashes") +public class LocalAflCrashesController { + @Resource + private LocalAflCrashesService localAflCrashesService; + + @PostMapping(path="/saveLocalAflCrashesInfo") + public CommonResult saveLocalAflCrashesInfo(@RequestBody @Valid LocalAflCrashesSaveReq req) throws SftpUploadUtil.SftpUploadException { + + localAflCrashesService.saveLocalAflCrashesInfo(req); + + return CommonResult.success(); + } + + /** + *分页模糊查询漏洞信息 + */ + @PostMapping("/search") + public CommonResult> getLocalAflCrashesSearch(@RequestBody LocalAflCrashesQueryReq req) { + PageResult search = localAflCrashesService.getLocalAflCrashesSearch(req); + return CommonResult.success(search); + } +} diff --git a/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/VulInfoController.java b/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/VulInfoController.java new file mode 100644 index 00000000..7a92816a --- /dev/null +++ b/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/VulInfoController.java @@ -0,0 +1,37 @@ +package cd.casic.ci.api; + +import cd.casic.ci.process.dto.req.vulInfo.SearchDto; +import cd.casic.ci.process.dto.req.vulInfo.VulInfoDto; +import cd.casic.ci.process.process.dataObject.volumnInfo.VulInfo; +import cd.casic.ci.process.process.service.vulInfo.VulInfoService; +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.framework.commons.pojo.PageResult; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/vulInfo") +public class VulInfoController { + @Resource + private VulInfoService vulInfoService; + + /** + *上传漏洞信息 + */ + @PostMapping("/upload") + public CommonResult uploadVulInfo(@RequestBody VulInfo vulInfo) { + vulInfoService.upload(vulInfo); + return CommonResult.success(); + } + + /** + *分页模糊查询漏洞信息 + */ + @PostMapping("/search") + public CommonResult> getVulInfoSearch(@RequestBody SearchDto searchDto) { + return CommonResult.success(vulInfoService.getSearch(searchDto)); + } +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/localAflCrashes/LocalAflCrashesQueryReq.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/localAflCrashes/LocalAflCrashesQueryReq.java new file mode 100644 index 00000000..0a781ba2 --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/localAflCrashes/LocalAflCrashesQueryReq.java @@ -0,0 +1,72 @@ +package cd.casic.ci.process.dto.req.localAflCrashes; + +import cd.casic.framework.commons.pojo.PageParam; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @ClassName PipelineQueryReq + * @Author hopeli + * @Date 2025/5/10 9:54 + * @Version 1.0 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class LocalAflCrashesQueryReq extends PageParam { + private String id; + /** + * 流水线id + */ + private String pipelineId; + + /** + * 流水线历史记录id + */ + private String pipelineHistoryId; + + /** + * 任务节点id + */ + private String taskId; + + /** + * 流水线节点类型 + */ + private String taskType; + + /** + * 分组标识 + */ + private String groupIdentifier; + + /** + * 文件信息 + */ + private byte[] fileContent; + + /** + * 流水线执行记录id + */ + private String instanceId; + + /** + * 发现的目标漏洞类型,源码,二进制,固件 + */ + private String targetType; + + /** + * 目标名称 + */ + private String targetName; + + /** + * 城市 + */ + private String city; + + /** + * 崩溃文件名称 + */ + private String crashesName; + +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/localAflCrashes/LocalAflCrashesSaveReq.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/localAflCrashes/LocalAflCrashesSaveReq.java new file mode 100644 index 00000000..262307c1 --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/localAflCrashes/LocalAflCrashesSaveReq.java @@ -0,0 +1,76 @@ +package cd.casic.ci.process.dto.req.localAflCrashes; + +import lombok.Data; + +@Data +public class LocalAflCrashesSaveReq { + /** + * 流水线id + */ + private String pipelineId; + + /** + * 流水线历史记录id + */ + private String pipelineHistoryId; + + /** + * 任务节点id + */ + private String taskId; + + /** + * 流水线节点类型 + */ + private String taskType; + + /** + * 分组标识 + */ + private String groupIdentifier; + + /** + * 文件信息 + */ + private byte[] fileContent; + + /** + * 流水线执行记录id + */ + private String instanceId; + + /** + * 发现的目标漏洞类型,源码,二进制,固件 + */ + private String targetType; + + /** + * 目标名称 + */ + private String targetName; + + /** + * 城市 + */ + private String city; + + /** + * 崩溃文件名称 + */ + private String crashesName; + + /** + * 崩溃文件生成时间 + */ + private String crashesCreateTime; + + /** + * 崩溃文件大小 + */ + private Integer crashesLength; + + /** + * 崩溃文件描述 + */ + private String crashesRemark; +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/vulInfo/SearchDto.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/vulInfo/SearchDto.java new file mode 100644 index 00000000..acb60825 --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/vulInfo/SearchDto.java @@ -0,0 +1,29 @@ +package cd.casic.ci.process.dto.req.vulInfo; + +import cd.casic.framework.commons.pojo.PageParam; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class SearchDto extends PageParam { + private String vulId; + + private String vulTitle; + + private List cwes; + + private String affectProjectId; + + private String verifyStatus; + + private String targetName; + + private String unaffectedVersions; + + private String affectProductName; + + private String localAflCrashesId; +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/vulInfo/VulInfoDto.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/vulInfo/VulInfoDto.java new file mode 100644 index 00000000..1043648b --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/vulInfo/VulInfoDto.java @@ -0,0 +1,113 @@ +package cd.casic.ci.process.dto.req.vulInfo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.Date; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(callSuper = false) +public class VulInfoDto { + + /** + * 记录的唯一标识 ID,数据库中为主键,自增长 + */ + private Long id; + + /** + * 创建时间,自动生成 + */ + private Date createTime; + + /** + * 修改时间,自动生成,修改时间就是审核时间 + */ + private Date modifyTime; + + /** + * 漏洞状态,未审核、审核中,审核完 + */ + private String verifyStatus; + + /** + * 内部漏洞id,不需要输入,根据类型+日期随机生成,类型分为源码、固件、二进制 ,根据target_type 漏洞目标相关 + */ + private String vulId; + + /** + * 是否开源,选项框,对勾,源码时候才会有这个概念 + */ + private String isOpenSource; + + /** + * 中文标题 + */ + private String vulTitle; + + /** + * 中文描述 + */ + private String vulDescription; + + /** + * 危险等级,高中低三种 + */ + private String severity; + + /** + * 中文修复方案 + */ + private String solution; + + /** + * 暂时修复的缓解措施 + */ + private String relieve; + + /** + * 目标的名称 + */ + private String targetName; + + /** + * 漏洞类型 + */ + private List cwes; + + /** + * 利用级别,可利用和不可利用,默认不要利用 + */ + private String level; + + /** + * 发现的漏洞目标类型,源码,二进制,固件三种 + */ + private String targetType; + + /** + * 目标的链接,来自于人机协同系统,就是一个下载地址的url + */ + private String targetUrl; + + /** + * 受影响的目标,用户自己输入 + */ + private String affectProjectId; + + /** + * 类型是源码的情况才有这个概念,安全分支列表,如果类型是源码的,这个是可选项,比如master分支,dev分支等 + */ + private String unaffectedVersions; + + /** + * 受影响产品名 + */ + private String affectProductName; + + private String localAflCrashesId; +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/resp/localAflCrashes/LocalAflCrashesResp.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/resp/localAflCrashes/LocalAflCrashesResp.java new file mode 100644 index 00000000..cfef6ec4 --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/resp/localAflCrashes/LocalAflCrashesResp.java @@ -0,0 +1,106 @@ +package cd.casic.ci.process.dto.resp.localAflCrashes; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * @ClassName ReportResp + * @Author hopeli + * @Date 2025/5/10 10:53 + * @Version 1.0 + */ +@Data +public class LocalAflCrashesResp { + private String id; + /** + * 流水线id + */ + private String pipelineId; + + /** + * 流水线历史记录id + */ + private String pipelineHistoryId; + + /** + * 任务节点id + */ + private String taskId; + + /** + * 流水线节点类型 + */ + private String taskType; + + /** + * 分组标识 + */ + private String groupIdentifier; + + /** + * 文件信息 + */ + private byte[] fileContent; + + /** + * 流水线执行记录id + */ + private String instanceId; + + /** + * 发现的目标漏洞类型,源码,二进制,固件 + */ + private String targetType; + + /** + * 目标名称 + */ + private String targetName; + + /** + * 城市 + */ + private String city; + + /** + * 崩溃文件名称 + */ + private String crashesName; + + /** + * 崩溃文件生成时间 + */ + private String crashesCreateTime; + + /** + * 崩溃文件大小 + */ + private Integer crashesLength; + + /** + * 崩溃文件描述 + */ + private String crashesRemark; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + /** + * 最后更新时间 + */ + private LocalDateTime updateTime; + /** + * 创建者,目前使用 SysUser 的 id 编号 + * + * 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。 + */ + private String creator; + /** + * 更新者,目前使用 SysUser 的 id 编号 + * + * 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。 + */ + private String updater; +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/converter/LocalAflCrashesConverter.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/converter/LocalAflCrashesConverter.java new file mode 100644 index 00000000..574ce00e --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/converter/LocalAflCrashesConverter.java @@ -0,0 +1,22 @@ +package cd.casic.ci.process.process.converter; + +import cd.casic.ci.process.dto.resp.localAflCrashes.LocalAflCrashesResp; +import cd.casic.ci.process.process.dataObject.localAflCrashes.LocalAflCrashesInfo; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * @author HopeLi + * @version v1.0 + * @ClassName PipelineConverter + * @Date: 2025/5/13 14:39 + * @Description: + */ +@Mapper(componentModel = "spring") +public interface LocalAflCrashesConverter { + LocalAflCrashesConverter INSTANCE = Mappers.getMapper(LocalAflCrashesConverter.class); + + List toRespList(List records); +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dao/localAflCrashes/LocalAflCrashesDao.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dao/localAflCrashes/LocalAflCrashesDao.java new file mode 100644 index 00000000..16808c6a --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dao/localAflCrashes/LocalAflCrashesDao.java @@ -0,0 +1,14 @@ +package cd.casic.ci.process.process.dao.localAflCrashes; + +import cd.casic.ci.process.process.dataObject.localAflCrashes.LocalAflCrashesInfo; +import cd.casic.framework.mybatis.core.mapper.BaseMapperX; + +/** + * @author HopeLi + * @version v1.0 + * @ClassName LocalAflCrashesDao + * @Date: 2025/5/13 14:39 + * @Description: + */ +public interface LocalAflCrashesDao extends BaseMapperX { +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/localAflCrashes/LocalAflCrashesInfo.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/localAflCrashes/LocalAflCrashesInfo.java new file mode 100644 index 00000000..cb66588e --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/localAflCrashes/LocalAflCrashesInfo.java @@ -0,0 +1,88 @@ +package cd.casic.ci.process.process.dataObject.localAflCrashes; + +import cd.casic.ci.process.process.dataObject.base.PipBaseElement; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author HopeLi + * @version v1.0 + * @ClassName LocalAflCrashesInfo + * @Date: 2025/7/30 11:22 + * @Description: + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName(value = "local_afl_crashes_info") +public class LocalAflCrashesInfo extends PipBaseElement { + /** + * 流水线id + */ + private String pipelineId; + + /** + * 流水线历史记录id + */ + private String pipelineHistoryId; + + /** + * 任务节点id + */ + private String taskId; + + /** + * 流水线节点类型 + */ + private String taskType; + + /** + * 分组标识 + */ + private String groupIdentifier; + + /** + * 文件信息 + */ + private byte[] fileContent; + + /** + * 流水线执行记录id + */ + private String instanceId; + + /** + * 发现的目标漏洞类型,源码,二进制,固件 + */ + private String targetType; + + /** + * 目标名称 + */ + private String targetName; + + /** + * 城市 + */ + private String city; + + /** + * 崩溃文件名称 + */ + private String crashesName; + + /** + * 崩溃文件生成时间 + */ + private String crashesCreateTime; + + /** + * 崩溃文件大小 + */ + private Integer crashesLength; + + /** + * 崩溃文件描述 + */ + private String crashesRemark; +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/volumnInfo/VulInfo.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/volumnInfo/VulInfo.java index 0b11df44..f10eadb3 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/volumnInfo/VulInfo.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/volumnInfo/VulInfo.java @@ -1,6 +1,5 @@ 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; @@ -8,7 +7,6 @@ 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; @@ -131,4 +129,6 @@ public class VulInfo { * 节点类型 * */ private String taskType; + + private String localAflCrashesId; } diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/localAflCrashes/LocalAflCrashesService.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/localAflCrashes/LocalAflCrashesService.java new file mode 100644 index 00000000..6e1eee83 --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/localAflCrashes/LocalAflCrashesService.java @@ -0,0 +1,23 @@ +package cd.casic.ci.process.process.service.localAflCrashes; + +import cd.casic.ci.process.dto.req.localAflCrashes.LocalAflCrashesQueryReq; +import cd.casic.ci.process.dto.req.localAflCrashes.LocalAflCrashesSaveReq; +import cd.casic.ci.process.dto.resp.localAflCrashes.LocalAflCrashesResp; +import cd.casic.ci.process.process.dataObject.localAflCrashes.LocalAflCrashesInfo; +import cd.casic.framework.commons.pojo.PageResult; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.validation.Valid; + +/** + * @author HopeLi + * @version v1.0 + * @ClassName LocalAflCrashesService + * @Date: 2025/5/17 10:20 + * @Description: + */ +public interface LocalAflCrashesService extends IService { + + void saveLocalAflCrashesInfo(@Valid LocalAflCrashesSaveReq req); + + PageResult getLocalAflCrashesSearch(LocalAflCrashesQueryReq req); +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/localAflCrashes/impl/LocalAflCrashesServiceImpl.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/localAflCrashes/impl/LocalAflCrashesServiceImpl.java new file mode 100644 index 00000000..8d86a1e4 --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/localAflCrashes/impl/LocalAflCrashesServiceImpl.java @@ -0,0 +1,218 @@ +package cd.casic.ci.process.process.service.localAflCrashes.impl; + +import cd.casic.ci.process.dto.req.localAflCrashes.LocalAflCrashesQueryReq; +import cd.casic.ci.process.dto.req.localAflCrashes.LocalAflCrashesSaveReq; +import cd.casic.ci.process.dto.resp.localAflCrashes.LocalAflCrashesResp; +import cd.casic.ci.process.dto.resp.resource.ResourceDetailResp; +import cd.casic.ci.process.engine.constant.PipelineVariableConstant; +import cd.casic.ci.process.engine.manager.RunContextManager; +import cd.casic.ci.process.engine.runContext.BaseRunContext; +import cd.casic.ci.process.process.converter.LocalAflCrashesConverter; +import cd.casic.ci.process.process.dao.localAflCrashes.LocalAflCrashesDao; +import cd.casic.ci.process.process.dataObject.localAflCrashes.LocalAflCrashesInfo; +import cd.casic.ci.process.process.service.localAflCrashes.LocalAflCrashesService; +import cd.casic.ci.process.process.service.resource.ResourceManagerService; +import cd.casic.ci.process.util.SftpUploadUtil; +import cd.casic.framework.commons.exception.ServiceException; +import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants; +import cd.casic.framework.commons.pojo.PageResult; +import cd.casic.module.machine.dal.dataobject.MachineInfoDO; +import cd.casic.module.machine.utils.CryptogramUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author HopeLi + * @version v1.0 + * @ClassName TargetVersionServiceImpl + * @Date: 2025/5/17 15:20 + * @Description: + */ +@Service +@Slf4j +public class LocalAflCrashesServiceImpl extends ServiceImpl implements LocalAflCrashesService { + + private static final String remoteFilePath = "/home/casic/706/yunqi/"; + private static final String crashesFilePath = "/ai_afl/default/crashes/"; + + @Resource + private RunContextManager runContextManager; + @Resource + private ResourceManagerService resourceManagerService; + + + + @Override + public void saveLocalAflCrashesInfo(LocalAflCrashesSaveReq req) { + List aflCrashesInfos = new ArrayList<>(0); + + if (StringUtils.isEmpty(req.getPipelineId()) || StringUtils.isEmpty(req.getTaskId())){ + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"pipelineId或者taskId不能为空"); + } + String uuid = req.getGroupIdentifier(); + BaseRunContext runContext = runContextManager.getContext(req.getPipelineId()); + if (ObjectUtils.isEmpty(runContext)){ + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到运行上下文"); + } + String resourceId = runContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY) instanceof String ? ((String) runContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY)) : null; + if (StringUtils.isEmpty(resourceId)){ + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到资源"); + } + + ResourceDetailResp resourceById = resourceManagerService.findResourceDetailById(resourceId); + if (resourceById == null || resourceById.getMachineInfo() == null || resourceById.getMachineInfo().getAuthenticationType()!=1) { + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"资源信息错误"); + } + + MachineInfoDO resourceMachine = resourceById.getMachineInfo(); + String password = CryptogramUtil.doDecrypt(resourceMachine.getPassword()); + resourceMachine.setPassword(password); + + try { + // 步骤1:使用自定义sql获取崩溃文件的创建时间 + //查询创建时间 + List resultList = SftpUploadUtil.findCreateTimeByCommand( + resourceMachine.getHostIp(), + resourceMachine.getSshPort(), + resourceMachine.getUsername(), + resourceMachine.getPassword(), null, remoteFilePath + "PIP_" + req.getPipelineId() + crashesFilePath); + + if (!CollectionUtils.isEmpty(resultList)){ + //解析文件名和创建时间 + for (String o : resultList) { + String[] lineParts = o.split("\\s+创建时间:\\s+"); + if (lineParts.length < 2) { + System.err.println("无效格式: " + o); + break; + } + LocalAflCrashesInfo aflCrashesInfo = new LocalAflCrashesInfo(); + + String fileName = lineParts[0].substring(2).trim(); // 文件信息部分 + String createTime = lineParts[1].trim(); // 创建时间 + aflCrashesInfo.setCrashesName(fileName); + aflCrashesInfo.setCrashesCreateTime(createTime); + + aflCrashesInfos.add(aflCrashesInfo); + } + } + + + + // 步驟2.查询文件大小 + List fileResultList = SftpUploadUtil.findFileByteByCommand( + resourceMachine.getHostIp(), + resourceMachine.getSshPort(), + resourceMachine.getUsername(), + resourceMachine.getPassword(), null, remoteFilePath + "PIP_" + req.getPipelineId() + crashesFilePath); + + if (!CollectionUtils.isEmpty(fileResultList) && !CollectionUtils.isEmpty(aflCrashesInfos)){ + //解析文件名和文件大小 + for (String o : fileResultList) { + // 按空白字符分割 + String[] parts = o.trim().split("\\s+"); + + String fileName = parts[0]; // 文件名称 + Integer fileLength = Integer.parseInt(parts[1]); // 文件大小 + for (LocalAflCrashesInfo aflCrashesInfo : aflCrashesInfos) { + if (aflCrashesInfo.getCrashesName().equals(fileName)) { + aflCrashesInfo.setCrashesLength(fileLength); + } + aflCrashesInfo.setPipelineId(req.getPipelineId()); + if (!StringUtils.isEmpty(req.getTaskId())){ + aflCrashesInfo.setTaskId(req.getTaskId()); + } + if (!StringUtils.isEmpty(req.getPipelineHistoryId())){ + aflCrashesInfo.setPipelineHistoryId(req.getPipelineHistoryId()); + } + aflCrashesInfo.setGroupIdentifier(uuid); + } + } + } + + + + // 步骤3:列出源目录下的所有文件 + List files = SftpUploadUtil.listFilesInRemoteDirectory( + resourceMachine.getHostIp(), resourceMachine.getSshPort(), resourceMachine.getUsername(), resourceMachine.getPassword(), null, remoteFilePath + "PIP_" + req.getPipelineId() + crashesFilePath); + + if (!CollectionUtils.isEmpty(files)) { + // 步骤4:批量下载文件流与文件绑定 + Map copiedFiles = SftpUploadUtil.copyRemoteFilesToByteArray( + resourceMachine.getHostIp(), resourceMachine.getSshPort(), resourceMachine.getUsername(), resourceMachine.getPassword(), null, files); + System.out.println("共复制 " + copiedFiles.size() + " 个文件"); + + //绑定对应的文件流 + if (!CollectionUtils.isEmpty(copiedFiles)){ + for (Map.Entry entry : copiedFiles.entrySet()) { + if (!CollectionUtils.isEmpty(aflCrashesInfos)){ + for (LocalAflCrashesInfo aflCrashesInfo : aflCrashesInfos) { + if (aflCrashesInfo.getCrashesName().equals(entry.getKey())) { + aflCrashesInfo.setFileContent(entry.getValue()); + } + aflCrashesInfo.setPipelineId(req.getPipelineId()); + if (!StringUtils.isEmpty(req.getTaskId())){ + aflCrashesInfo.setTaskId(req.getTaskId()); + } + aflCrashesInfo.setPipelineHistoryId(req.getPipelineHistoryId()); + aflCrashesInfo.setTaskType("AFL"); + aflCrashesInfo.setInstanceId(req.getInstanceId()); + aflCrashesInfo.setTargetType(req.getTargetType()); + aflCrashesInfo.setTargetName(req.getTargetName()); + aflCrashesInfo.setCity(req.getCity()); + } + } + } + + //新增数据到crashes表中 + baseMapper.insertBatch(aflCrashesInfos); + } + } + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"crashes入库失败"); + } + } + + @Override + public PageResult getLocalAflCrashesSearch(LocalAflCrashesQueryReq req) { + QueryWrapper wrapper = new QueryWrapper<>(); + if (!ObjectUtils.isEmpty(req.getId())){ + wrapper.eq("id",req.getId()); + } + if (!ObjectUtils.isEmpty(req.getPipelineId())){ + wrapper.eq("pipeline_id",req.getPipelineId()); + } + if (!ObjectUtils.isEmpty(req.getPipelineHistoryId())){ + wrapper.eq("pipeline_history_id",req.getPipelineHistoryId()); + } + if (!ObjectUtils.isEmpty(req.getTaskId())){ + wrapper.eq("task_id",req.getTaskId()); + } + if (!ObjectUtils.isEmpty(req.getGroupIdentifier())){ + wrapper.eq("group_identifier",req.getGroupIdentifier()); + } + + Page localAflCrashesInfoPage = baseMapper.selectPage(new Page<>(req.getPageNo(), req.getPageSize()), wrapper); + + if (ObjectUtils.isEmpty(localAflCrashesInfoPage)){ + return new PageResult<>(); + } + + List respList = LocalAflCrashesConverter.INSTANCE.toRespList(localAflCrashesInfoPage.getRecords()); + PageResult result = new PageResult<>(respList, localAflCrashesInfoPage.getTotal(), localAflCrashesInfoPage.getCurrent(), localAflCrashesInfoPage.getSize()); + return result; + } + + +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/vulInfo/VulInfoService.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/vulInfo/VulInfoService.java index 5699ca57..2f2ae6e5 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/vulInfo/VulInfoService.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/vulInfo/VulInfoService.java @@ -1,11 +1,11 @@ package cd.casic.ci.process.process.service.vulInfo; +import cd.casic.ci.process.dto.req.vulInfo.SearchDto; +import cd.casic.ci.process.dto.req.vulInfo.VulInfoDto; 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 cd.casic.framework.commons.pojo.PageResult; import com.baomidou.mybatisplus.extension.service.IService; -import jakarta.annotation.Resource; -import org.springframework.stereotype.Service; import java.security.KeyManagementException; import java.security.KeyStoreException; @@ -16,4 +16,8 @@ public interface VulInfoService extends IService { 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 scaVulListGet(Integer scaTaskId) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException; + + void upload(VulInfo vulInfo); + + PageResult getSearch(SearchDto searchDto); } diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/vulInfo/impl/VulInfoServiceImpl.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/vulInfo/impl/VulInfoServiceImpl.java index c1e0e6ca..354d34ce 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/vulInfo/impl/VulInfoServiceImpl.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/vulInfo/impl/VulInfoServiceImpl.java @@ -1,15 +1,23 @@ package cd.casic.ci.process.process.service.vulInfo.impl; import cd.casic.ci.process.dto.req.report.ReportAssetTaskReq; +import cd.casic.ci.process.dto.req.vulInfo.SearchDto; +import cd.casic.ci.process.dto.req.vulInfo.VulInfoDto; 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 cd.casic.ci.process.util.vulInfo.BeanUtil; +import cd.casic.ci.process.util.vulInfo.TimeUtils; +import cd.casic.framework.commons.exception.ServiceException; +import cd.casic.framework.commons.pojo.PageResult; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -21,7 +29,7 @@ import java.nio.charset.StandardCharsets; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -114,6 +122,61 @@ public class VulInfoServiceImpl extends ServiceImpl implemen return List.of(); } + + public void upload(VulInfo vulInfo) { + vulInfo.setVulId(vulInfo.getTargetType() + TimeUtils.ConvertTimeToStringUtils()); + try { + save(vulInfo); + } catch (Exception e) { + throw new ServiceException(500, e.getMessage()); + } + } + + + @Override + public PageResult getSearch(SearchDto searchDto) { + Page page = new Page<>(searchDto.getPageNo(), searchDto.getPageSize()); + String cwes = null; + if (searchDto.getCwes() != null && !searchDto.getCwes().isEmpty()) { + cwes = JSONObject.toJSONString(searchDto.getCwes()); + } + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (searchDto.getVulId() != null && !searchDto.getVulId().isEmpty()) { + queryWrapper.like("vul_id", searchDto.getVulId()); + } + if (searchDto.getVulTitle() != null && !searchDto.getVulTitle().isEmpty()) { + queryWrapper.like("vul_title", searchDto.getVulTitle()); + } + if (cwes != null && !cwes.isEmpty()) { + queryWrapper.like("cwes", cwes); + } + if (searchDto.getAffectProjectId() != null && !searchDto.getAffectProjectId().isEmpty()) { + queryWrapper.like("affect_project_id", searchDto.getAffectProjectId()); + } + if (searchDto.getVerifyStatus() != null && !searchDto.getVerifyStatus().isEmpty()) { + queryWrapper.like("verify_status", searchDto.getVerifyStatus()); + } + if (searchDto.getTargetName() != null && !searchDto.getTargetName().isEmpty()) { + queryWrapper.like("target_name", searchDto.getTargetName()); + } + if (searchDto.getUnaffectedVersions() != null && !searchDto.getUnaffectedVersions().isEmpty()) { + queryWrapper.like("unaffected_versions", searchDto.getUnaffectedVersions()); + } + if (searchDto.getAffectProductName() != null && !searchDto.getAffectProductName().isEmpty()) { + queryWrapper.like("affect_product_name", searchDto.getAffectProductName()); + } + Page vulInfoPage = baseMapper.selectPage(page, queryWrapper); + List records = vulInfoPage.getRecords(); + List vulInfoDtos = new ArrayList<>(); + if (records != null && !records.isEmpty()) { + //VulInfo转VulInfoDto + for (VulInfo vulInfo : records) { + vulInfoDtos.add(BeanUtil.ConvertVulInfoToVulInfoDto(vulInfo)); + } + } + return new PageResult<>(vulInfoDtos,vulInfoPage.getTotal(),vulInfoPage.getCurrent(),vulInfoPage.getSize()); + } + private HttpHeaders createHeaders() { HttpHeaders headers = new HttpHeaders(); headers.add("OpenApiUserToken", ConstantContextHolder.getScaToken()); diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/SftpUploadUtil.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/SftpUploadUtil.java index 36e78def..c758d510 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/SftpUploadUtil.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/SftpUploadUtil.java @@ -1524,6 +1524,123 @@ public class SftpUploadUtil { } + /** + * 从远程服务器下载文件并直接返回文件的二进制流 + * + * @param remoteHost 远程服务器地址 + * @param remotePort 远程服务器端口 + * @param username 远程服务器用户名 + * @param password 远程服务器密码 + * @param sshKeyPath SSH密钥路径 + * @param remoteFilePaths 远程文件路径列表 + * @return Map 文件名和对应的二进制流 + * @throws SftpUploadException 如果下载文件过程中发生错误 + */ + public static Map copyRemoteFilesToByteArray(String remoteHost, + Integer remotePort, + String username, + String password, + String sshKeyPath, + List remoteFilePaths) throws SftpUploadException { + + Map fileByteArrays = new HashMap<>(); + + Session session = null; + Channel channel = null; + ChannelSftp channelSftp = null; + + try { + JSch jsch = new JSch(); + + // 1. 添加身份认证信息 (密码或密钥) + if (sshKeyPath != null && !sshKeyPath.trim().isEmpty()) { + // 使用 SSH Key 认证 + File sshKeyFile = new File(sshKeyPath); + if (!sshKeyFile.exists() || !sshKeyFile.isFile()) { + throw new SftpUploadException("SSH Key 文件不存在或不是一个有效文件: " + sshKeyPath); + } + jsch.addIdentity(sshKeyPath); + System.out.println("使用 SSH Key 认证: " + sshKeyPath); + } else if (password == null || password.trim().isEmpty()) { + // 如果没有提供密码或密钥路径,则认证信息不全 + throw new SftpUploadException("必须提供密码或 SSH Key 路径进行 SFTP 认证."); + } + + // 2. 获取 Session + int port = (remotePort != null && remotePort > 0) ? remotePort : DEFAULT_SFTP_PORT; + session = jsch.getSession(username, remoteHost, port); + System.out.println("尝试连接 SFTP 服务器: " + username + "@" + remoteHost + ":" + port); + + // 如果使用密码认证且提供了密码 + if (password != null && !password.trim().isEmpty() && (sshKeyPath == null || sshKeyPath.trim().isEmpty())) { + session.setPassword(password); + System.out.println("使用密码认证."); + } + + // 设置连接不进行主机密钥检查 + java.util.Properties config = new java.util.Properties(); + config.put("StrictHostKeyChecking", "no"); + session.setConfig(config); + + // 3. 连接 Session + session.connect(); + System.out.println("SFTP Session 连接成功."); + + // 4. 打开 SFTP Channel + channel = session.openChannel("sftp"); + channel.connect(); + System.out.println("SFTP Channel 打开成功."); + + channelSftp = (ChannelSftp) channel; + + // 遍历远程文件路径并下载 + for (String remoteFile : remoteFilePaths) { + String chmodDir = remoteFile.substring(0, remoteFile.indexOf("default")); + log.info("分配权限路径,{}", chmodDir); + // 切换目录并列出内容用于调试 + sudoChmodORwx(session, chmodDir, password); + + String fileName = new File(remoteFile).getName(); + + try (InputStream in = channelSftp.get(remoteFile); + ByteArrayOutputStream out = new ByteArrayOutputStream()) { + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = in.read(buffer)) > 0) { + out.write(buffer, 0, bytesRead); + } + fileByteArrays.put(fileName, out.toByteArray()); // 添加文件名和二进制数据 + } catch (Exception e) { + throw new SftpUploadException("文件读取失败: " + remoteFile, e); + } + } + return fileByteArrays; + } catch (JSchException e) { + throw new SftpUploadException("SFTP 连接或认证失败: " + e.getMessage(), e); + } catch (SftpUploadException e) { + // 重新抛出自定义异常 + throw e; + } catch (Exception e) { + // 捕获其他未知异常 + throw new SftpUploadException("SFTP 上传过程中发生未知异常: " + e.getMessage(), e); + } finally { + // 关闭资源 (确保在任何情况下都关闭) + if (channelSftp != null) { + channelSftp.disconnect(); + System.out.println("SFTP Channel 已断开."); + } + if (channel != null) { + channel.disconnect(); + System.out.println("SFTP Channel 资源已释放."); + } + if (session != null) { + session.disconnect(); + System.out.println("SFTP Session 已断开."); + } + } + } + + /** * 从远程服务器下载文件并返回文件输入流,并设置AflInfo对象 * diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/vulInfo/BeanUtil.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/vulInfo/BeanUtil.java new file mode 100644 index 00000000..9ec24549 --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/vulInfo/BeanUtil.java @@ -0,0 +1,32 @@ +package cd.casic.ci.process.util.vulInfo; + + +import cd.casic.ci.process.dto.req.vulInfo.VulInfoDto; +import cd.casic.ci.process.process.dataObject.volumnInfo.VulInfo; +import org.springframework.beans.BeanUtils; + +public class BeanUtil { + + public static VulInfoDto ConvertVulInfoToVulInfoDto(VulInfo vulInfo) { + VulInfoDto vulInfoDto = new VulInfoDto(); + BeanUtils.copyProperties(vulInfo,vulInfoDto); + if (vulInfo.getIsOpenSource()){ + vulInfoDto.setIsOpenSource("开源"); + }else { + vulInfoDto.setIsOpenSource("非开源"); + } + vulInfoDto.setSeverity( + (vulInfo.getSeverity() == 3)? "高" : + ((vulInfo.getSeverity() == 2)? "中" : + ((vulInfo.getSeverity() == 1)? "低" : null)) + ); + if (vulInfo.getLevel()){ + vulInfoDto.setIsOpenSource("可利用"); + }else { + vulInfoDto.setIsOpenSource("不可利用"); + } + + vulInfoDto.setTargetType(vulInfo.getTargetType()); + return vulInfoDto; + } +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/vulInfo/TimeUtils.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/vulInfo/TimeUtils.java new file mode 100644 index 00000000..2d71de77 --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/vulInfo/TimeUtils.java @@ -0,0 +1,12 @@ +package cd.casic.ci.process.util.vulInfo; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class TimeUtils { + + public static String ConvertTimeToStringUtils() { + return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + } + +}