diff --git a/modules/module-ci-machine/pom.xml b/modules/module-ci-machine/pom.xml
new file mode 100644
index 00000000..e36adc39
--- /dev/null
+++ b/modules/module-ci-machine/pom.xml
@@ -0,0 +1,33 @@
+
+
+ 4.0.0
+
+ cd.casic.boot
+ modules
+ ${revision}
+
+
+ module-ci-machine
+
+ jar
+ ${revision}
+ ${project.artifactId}
+
+
+
+ cd.casic.boot
+ commons
+
+
+
+ cd.casic.boot
+ spring-boot-starter-security
+
+
+ com.antherd
+ sm-crypto
+ 0.3.2.1-RELEASE
+
+
+
diff --git a/modules/module-ci-machine/src/main/java/cd/casic/module/machine/contants/MachineErrorCodeConstants.java b/modules/module-ci-machine/src/main/java/cd/casic/module/machine/contants/MachineErrorCodeConstants.java
new file mode 100644
index 00000000..a526d9e5
--- /dev/null
+++ b/modules/module-ci-machine/src/main/java/cd/casic/module/machine/contants/MachineErrorCodeConstants.java
@@ -0,0 +1,37 @@
+package cd.casic.module.machine.contants;
+
+import cd.casic.framework.commons.exception.ErrorCode;
+
+/**
+ * 机器报错
+ */
+public interface MachineErrorCodeConstants {
+ // ========== 机器基础信息模块 1-003-000-000 ==========
+ ErrorCode MACHINE_INFO_NULL = new ErrorCode(1_003_000_000, "机器信息为空");
+ ErrorCode MACHINE_INFO_HOST_IP_NULL = new ErrorCode(1_003_000_001, "机器主机IP为空");
+ ErrorCode MACHINE_INFO_USER_NAME_NULL = new ErrorCode(1_003_000_002, "机器用户名为空");
+ ErrorCode MACHINE_INFO_TYPE_NULL = new ErrorCode(1_003_000_003, "机器类型为空");
+ ErrorCode MACHINE_INFO_TYPE_NOT_EXISTS = new ErrorCode(1_003_000_004, "机器类型不存在");
+ ErrorCode MACHINE_INFO_TAG_NULL = new ErrorCode(1_003_000_005, "机器唯一标识为空");
+ ErrorCode MACHINE_INFO_TAG_EXISTS = new ErrorCode(1_003_000_006, "机器唯一标识已存在");
+ ErrorCode MACHINE_INFO_AUTHENTICATION_TYPE_NULL = new ErrorCode(1_003_000_007, "机器认证类型为空");
+ ErrorCode MACHINE_INFO_AUTHENTICATION_TYPE_NOT_EXISTS = new ErrorCode(1_003_000_008, "机器认证类型不存在");
+ ErrorCode MACHINE_ENABLE = new ErrorCode(1_003_000_009, "机器启用中");
+
+ // ========== 机器环境变量模块 1-003-002-000 ==========
+ ErrorCode MACHINE_ENV_NULL = new ErrorCode(1_003_002_000, "机器环境变量为空");
+ ErrorCode MACHINE_ENV_NOT_EXISTS = new ErrorCode(1_003_002_001, "机器不存在");
+ ErrorCode MACHINE_ENV_KEY_ILLEGAL = new ErrorCode(1_003_002_002, "机器环境变量键不合法");
+
+ // ========== 机器代理模块 1-003-003-000 ==========
+ ErrorCode MACHINE_PROXY_HOST_IP_NULL = new ErrorCode(1_003_003_000, "机器代理主机地址为空");
+ ErrorCode MACHINE_PROXY_USER_NAME_NULL = new ErrorCode(1_003_003_001, "机器代理用户名为空");
+ ErrorCode MACHINE_PROXY_NOT_EXISTS = new ErrorCode(1_003_003_002, "机器代理不存在");
+ ErrorCode MACHINE_PROXY_TYPE_NOT_EXISTS = new ErrorCode(1_003_003_003, "机器代理类型不存在");
+ ErrorCode MACHINE_PROXY_IS_ONLINE = new ErrorCode(1_003_003_004, "机器代理在线,不能删除");
+
+ // ========== 密钥模块 1-003-004-000 ==========
+ ErrorCode SECRET_KEY_NULL = new ErrorCode(1_003_004_000, "密钥为空");
+ ErrorCode SECRET_KEY_NOT_EXISTS = new ErrorCode(1_003_004_001, "密钥不存在");
+ ErrorCode ENCRYPT_OR_DECRYPT_FAIL = new ErrorCode(1_003_004_002, "加密/解密失败");
+}
diff --git a/modules/module-ci-machine/src/main/java/cd/casic/module/machine/controller/MachineEnvController.java b/modules/module-ci-machine/src/main/java/cd/casic/module/machine/controller/MachineEnvController.java
new file mode 100644
index 00000000..d7ca1c20
--- /dev/null
+++ b/modules/module-ci-machine/src/main/java/cd/casic/module/machine/controller/MachineEnvController.java
@@ -0,0 +1,84 @@
+package cd.casic.module.machine.controller;
+
+import cd.casic.framework.commons.pojo.CommonResult;
+import cd.casic.framework.commons.pojo.PageResult;
+import cd.casic.framework.commons.util.object.BeanUtils;
+import cd.casic.module.machine.dal.dataobject.MachineEnvDO;
+import cd.casic.module.machine.service.MachineEnvService;
+import cd.casic.module.machine.controller.vo.MachineEnvVO;
+import cn.hutool.core.collection.CollUtil;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+
+import static cd.casic.framework.commons.pojo.CommonResult.success;
+
+/**
+ * 环境变量控制器
+ */
+@Tag(name = "环境变量管理")
+@RestController
+@RequestMapping("/ci/machineEnv")
+@Validated
+public class MachineEnvController {
+
+ @Resource
+ private MachineEnvService machineEnvService;
+
+ @PostMapping("/create")
+ @Operation(summary = "新增环境变量")
+ @PreAuthorize("@ss.hasPermission('ci:machineEnv:create')")
+ public CommonResult createEnv(@Valid @RequestBody MachineEnvVO machineEnvVO) {
+ Long id = machineEnvService.createEnv(machineEnvVO);
+ return success(id);
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "修改环境变量")
+ @PreAuthorize("@ss.hasPermission('ci:machineEnv:update')")
+ public CommonResult updateEnv(@Valid @RequestBody MachineEnvVO machineEnvVO) {
+ machineEnvService.updateEnv(machineEnvVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除机器的环境变量")
+ @PreAuthorize("@ss.hasPermission('ci:machineEnv:delete')")
+ public CommonResult deleteEnv(@RequestParam("id") Long id) {
+ machineEnvService.deleteEnv(id);
+ return success(true);
+ }
+
+ @DeleteMapping("/deleteList")
+ @Operation(summary = "批量删除机器环境变量")
+ @PreAuthorize("@ss.hasPermission('ci:machineEnv:delete')")
+ public CommonResult deleteEnvList(@RequestParam("ids") String ids) {
+ machineEnvService.deleteEnvList(ids);
+ return success(true);
+ }
+
+ @GetMapping("/getEnv")
+ @Operation(summary = "获取机器的环境变量")
+ public CommonResult getEnv(@RequestParam("id") Long id) {
+ MachineEnvVO machineEnvVO = machineEnvService.getEnv(id);
+ return success(machineEnvVO);
+ }
+
+
+ @PostMapping("/list")
+ @Operation(summary = "获取环境变量列表")
+ public CommonResult> getEnvPage(@Valid @RequestBody MachineEnvVO machineEnvVO) {
+ PageResult pageResult = machineEnvService.getEnvPage(machineEnvVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(new PageResult<>(pageResult.getTotal()));
+ }
+ return success(BeanUtils.toBean(pageResult, MachineEnvVO.class));
+ }
+}
+
diff --git a/modules/module-ci-machine/src/main/java/cd/casic/module/machine/controller/MachineInfoController.java b/modules/module-ci-machine/src/main/java/cd/casic/module/machine/controller/MachineInfoController.java
new file mode 100644
index 00000000..e0abd893
--- /dev/null
+++ b/modules/module-ci-machine/src/main/java/cd/casic/module/machine/controller/MachineInfoController.java
@@ -0,0 +1,83 @@
+package cd.casic.module.machine.controller;
+
+import cd.casic.framework.commons.pojo.CommonResult;
+import cd.casic.framework.commons.pojo.PageResult;
+import cd.casic.framework.commons.util.object.BeanUtils;
+import cd.casic.module.machine.controller.vo.SecretKeyVO;
+import cd.casic.module.machine.dal.dataobject.MachineInfoDO;
+import cd.casic.module.machine.service.MachineInfoService;
+import cd.casic.module.machine.controller.vo.MachineInfoVO;
+import cn.hutool.core.collection.CollUtil;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import static cd.casic.framework.commons.pojo.CommonResult.success;
+
+@RestController
+@Tag(name = "机器信息管理")
+@RequestMapping("/ci/machineInfo")
+@Validated
+public class MachineInfoController {
+ @Resource
+ private MachineInfoService machineInfoService;
+
+ @PostMapping("/create")
+ @Operation(summary = "新增机器信息")
+// @PreAuthorize("@ss.hasPermission('ci:machineInfo:create')")
+ public CommonResult createMachine(@Valid @RequestBody MachineInfoVO machineInfoVO) {
+ Long id = machineInfoService.createMachine(machineInfoVO);
+ return success(id);
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "编辑机器信息")
+// @PreAuthorize("@ss.hasPermission('ci:machineInfo:update')")
+ public CommonResult updateMachineInfo(@Valid @RequestBody MachineInfoVO machineInfoVO) {
+ machineInfoService.updateMachineInfo(machineInfoVO);
+ return success(true);
+ }
+
+ @PutMapping("/updateStatus")
+ @Operation(summary = "机器启用/停用")
+// @PreAuthorize("@ss.hasPermission('ci:machineInfo:status')")
+ public CommonResult updateStatus(@Valid @RequestBody MachineInfoVO machineInfoVO) {
+ Integer newStatus = machineInfoService.updateStatus(machineInfoVO);
+ return success(newStatus);
+ }
+
+ @PostMapping("/list")
+ @Operation(summary = "获取机器信息列表")
+ public CommonResult> list(@Valid @RequestBody MachineInfoVO machineInfoVO) {
+ PageResult pageResult = machineInfoService.listMachineInfo(machineInfoVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(new PageResult<>(pageResult.getTotal()));
+ }
+ return success(BeanUtils.toBean(pageResult, MachineInfoVO.class));
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "机器信息删除")
+// @PreAuthorize("@ss.hasPermission('ci:machineInfo:delete')")
+ public CommonResult deleteMachineInfo(@RequestParam("machineInfoId") Long machineInfoId) {
+ machineInfoService.deleteMachineInfo(machineInfoId);
+ return success(true);
+ }
+
+ @DeleteMapping("/deleteList")
+ @Operation(summary = "批量删除机器信息")
+// @PreAuthorize("@ss.hasPermission('ci:machineInfo:delete')")
+ public CommonResult deleteMachineInfoList(@RequestParam("machineInfoIds") String ids) {
+ machineInfoService.deleteMachineInfoList(ids);
+ return success(true);
+ }
+
+ @PutMapping("/bindingSecretKey")
+ @Operation(summary = "绑定/解绑密钥")
+ public void bindingSecretKey(@RequestBody SecretKeyVO secretKeyVO) {
+ machineInfoService.bindingSecretKey(secretKeyVO);
+ }
+}
diff --git a/modules/module-ci-machine/src/main/java/cd/casic/module/machine/controller/MachineProxyController.java b/modules/module-ci-machine/src/main/java/cd/casic/module/machine/controller/MachineProxyController.java
new file mode 100644
index 00000000..83082ee5
--- /dev/null
+++ b/modules/module-ci-machine/src/main/java/cd/casic/module/machine/controller/MachineProxyController.java
@@ -0,0 +1,81 @@
+package cd.casic.module.machine.controller;
+
+import cd.casic.framework.commons.pojo.CommonResult;
+import cd.casic.framework.commons.pojo.PageResult;
+import cd.casic.framework.commons.util.object.BeanUtils;
+import cd.casic.module.machine.controller.vo.MachineProxyVO;
+import cd.casic.module.machine.dal.dataobject.MachineProxyDO;
+import cd.casic.module.machine.service.MachineProxyService;
+import cn.hutool.core.collection.CollUtil;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static cd.casic.framework.commons.pojo.CommonResult.success;
+
+/**
+ * 机器代理控制器
+ */
+@RestController
+@RequestMapping("/ci/machineProxy")
+@Tag(name = "机器代理管理")
+@Validated
+public class MachineProxyController {
+
+ @Resource
+ private MachineProxyService machineProxyService;
+
+ @PostMapping("/create")
+ @Operation(summary = "注册新的机器代理")
+// @PreAuthorize("@ss.hasPermission('ci:machineProxy:create')")
+ public CommonResult createProxy(@Valid @RequestBody MachineProxyVO machineProxyVO) {
+ Long id = machineProxyService.createProxy(machineProxyVO);
+ return success(id);
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "修改代理")
+// @PreAuthorize("@ss.hasPermission('ci:machineProxy:update')")
+ public CommonResult updateProxy(@Valid @RequestBody MachineProxyVO machineProxyVO) {
+ machineProxyService.updateProxy(machineProxyVO);
+ return success(true);
+ }
+
+ @PostMapping("/list")
+ @Operation(summary = "获取代理列表")
+ public CommonResult> getProxyPage(@Valid @RequestBody MachineProxyVO machineProxyVO) {
+ PageResult pageResult = machineProxyService.getProxyPage(machineProxyVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(new PageResult<>(pageResult.getTotal()));
+ }
+ return success(BeanUtils.toBean(pageResult, MachineProxyVO.class));
+ }
+
+ @GetMapping("/allStatus")
+ @Operation(summary = "获取所有代理的状态统计")
+ public CommonResult