union-ark-web 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/PROJECT_OVERVIEW.md +405 -0
  2. package/README.md +177 -0
  3. package/ark-control/pom.xml +142 -0
  4. package/ark-control/src/local-mock/java/com/epcc/commons/securityproxy/api/SecurityResult.java +14 -0
  5. package/ark-control/src/local-mock/java/com/epcc/commons/securityproxy/api/SymmetricalSecurityService.java +11 -0
  6. package/ark-control/src/local-mock/java/com/epcc/dubbo/result/Result.java +29 -0
  7. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/annotation/EnDecryptField.java +16 -0
  8. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/annotation/EnDecryptFieldLong.java +17 -0
  9. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/annotation/EnDecryptFieldWithTag.java +16 -0
  10. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/exception/BaseDataErrorCode.java +26 -0
  11. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/exception/CheckException.java +33 -0
  12. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/exception/ErrorCode.java +9 -0
  13. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/redis/RedisCacheService.java +131 -0
  14. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/util/Constant.java +24 -0
  15. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/util/ResultUtil.java +9 -0
  16. package/ark-control/src/local-mock/java/com/union/control/local/sensitive/LocalMockSensitiveProxy.java +40 -0
  17. package/ark-control/src/local-mock/java/com/union/control/local/sensitive/LocalRedisCacheService.java +45 -0
  18. package/ark-control/src/local-mock/java/com/union/control/local/sensitive/LocalSensitiveHostConfiguration.java +27 -0
  19. package/ark-control/src/local-mock/java/com/union/control/local/sensitive/LocalSensitiveProxyConfiguration.java +16 -0
  20. package/ark-control/src/main/java/com/union/control/ArkControlApplication.java +17 -0
  21. package/ark-control/src/main/java/com/union/control/dubbo/ProviderAccessLogFilter.java +45 -0
  22. package/ark-control/src/main/java/com/union/control/mapper/AgentExecutionMapper.java +35 -0
  23. package/ark-control/src/main/java/com/union/control/mapper/ConversationMapper.java +44 -0
  24. package/ark-control/src/main/java/com/union/control/mapper/MemoryStoreMapper.java +41 -0
  25. package/ark-control/src/main/java/com/union/control/mapper/ScheduledTaskMapper.java +96 -0
  26. package/ark-control/src/main/java/com/union/control/mapper/SensitiveAddressBookDemo.java +31 -0
  27. package/ark-control/src/main/java/com/union/control/mapper/SensitiveDataDemoMapper.java +24 -0
  28. package/ark-control/src/main/java/com/union/control/mapper/interceptor/AESInterceptor.java +265 -0
  29. package/ark-control/src/main/java/com/union/control/mapper/interceptor/AddressBookHandler.java +105 -0
  30. package/ark-control/src/main/java/com/union/control/schedule/ScheduledExecutionToken.java +55 -0
  31. package/ark-control/src/main/java/com/union/control/schedule/ScheduledTaskScheduler.java +206 -0
  32. package/ark-control/src/main/java/com/union/control/service/impl/AgentExecutionServiceImpl.java +212 -0
  33. package/ark-control/src/main/java/com/union/control/service/impl/AgentProxyServiceImpl.java +143 -0
  34. package/ark-control/src/main/java/com/union/control/service/impl/ConversationServiceImpl.java +245 -0
  35. package/ark-control/src/main/java/com/union/control/service/impl/MemoryStoreServiceImpl.java +252 -0
  36. package/ark-control/src/main/java/com/union/control/service/impl/RunningAnalysisMockServiceImpl.java +301 -0
  37. package/ark-control/src/main/java/com/union/control/service/impl/ScheduledTaskServiceImpl.java +576 -0
  38. package/ark-control/src/main/java/com/union/control/service/impl/SensitiveDataDemoServiceImpl.java +144 -0
  39. package/ark-control/src/main/java/com/union/control/service/sensitive/RedisRevealTokenStore.java +90 -0
  40. package/ark-control/src/main/java/com/union/control/service/sensitive/SensitiveRevealProcessor.java +319 -0
  41. package/ark-control/src/main/java/com/union/control/service/sensitive/SensitiveRevealServiceImpl.java +72 -0
  42. package/ark-control/src/main/java/com/union/control/utils/AgentSupport.java +103 -0
  43. package/ark-control/src/main/java/com/union/control/utils/security/SymmetricalSecurityUtils.java +160 -0
  44. package/ark-control/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter +1 -0
  45. package/ark-control/src/main/resources/application.properties +4 -0
  46. package/ark-control/src/main/resources/application.yml +32 -0
  47. package/ark-control/src/main/resources/dubbo-provider.xml +20 -0
  48. package/ark-control/src/main/resources/mapper/AgentExecutionMapper.xml +75 -0
  49. package/ark-control/src/main/resources/mapper/ConversationMapper.xml +110 -0
  50. package/ark-control/src/main/resources/mapper/MemoryStoreMapper.xml +74 -0
  51. package/ark-control/src/main/resources/mapper/ScheduledTaskMapper.xml +286 -0
  52. package/ark-control/src/main/resources/mapper/SensitiveDataDemoMapper.xml +55 -0
  53. package/ark-control/src/main/resources/schema.sql +146 -0
  54. package/ark-control/src/test/java/com/union/control/AgentExecutionServiceTest.java +170 -0
  55. package/ark-control/src/test/java/com/union/control/ArkControlStructureContractTest.java +107 -0
  56. package/ark-control/src/test/java/com/union/control/ConversationServiceTest.java +89 -0
  57. package/ark-control/src/test/java/com/union/control/MemoryStoreServiceTest.java +26 -0
  58. package/ark-control/src/test/java/com/union/control/PydanticAiControlContractTest.java +52 -0
  59. package/ark-control/src/test/java/com/union/control/TestJson.java +45 -0
  60. package/ark-control/src/test/java/com/union/control/dubbo/ProviderAccessLogFilterTest.java +53 -0
  61. package/ark-control/src/test/java/com/union/control/local/sensitive/LocalSensitiveProxyConfigurationTest.java +23 -0
  62. package/ark-control/src/test/java/com/union/control/mapper/interceptor/AESInterceptorCompatibilityTest.java +505 -0
  63. package/ark-control/src/test/java/com/union/control/schedule/ScheduledExecutionTokenTest.java +27 -0
  64. package/ark-control/src/test/java/com/union/control/schedule/ScheduledTaskSchedulerTest.java +51 -0
  65. package/ark-control/src/test/java/com/union/control/service/AgentProxyServiceTest.java +111 -0
  66. package/ark-control/src/test/java/com/union/control/service/ScheduledTaskServiceTest.java +483 -0
  67. package/ark-control/src/test/java/com/union/control/service/impl/SensitiveDataDemoServiceImplTest.java +104 -0
  68. package/ark-control/src/test/java/com/union/control/service/sensitive/RedisRevealTokenStoreTest.java +65 -0
  69. package/ark-control/src/test/java/com/union/control/service/sensitive/SensitiveRevealBoundaryTest.java +99 -0
  70. package/ark-control/src/test/java/com/union/control/service/sensitive/SensitiveRevealProcessorCodecTest.java +111 -0
  71. package/ark-control/src/test/java/com/union/control/service/sensitive/SensitiveRevealProcessorTest.java +111 -0
  72. package/ark-control/src/test/java/com/union/control/utils/security/SymmetricalSecurityUtilsCompatibilityTest.java +87 -0
  73. package/ark-control-facade/pom.xml +16 -0
  74. package/ark-control-facade/src/main/java/com/union/control/service/AgentExecutionService.java +8 -0
  75. package/ark-control-facade/src/main/java/com/union/control/service/AgentProxyService.java +7 -0
  76. package/ark-control-facade/src/main/java/com/union/control/service/AgentResponse.java +22 -0
  77. package/ark-control-facade/src/main/java/com/union/control/service/ConversationService.java +12 -0
  78. package/ark-control-facade/src/main/java/com/union/control/service/MemoryStoreService.java +12 -0
  79. package/ark-control-facade/src/main/java/com/union/control/service/RunningAnalysisMockService.java +10 -0
  80. package/ark-control-facade/src/main/java/com/union/control/service/ScheduledTaskService.java +40 -0
  81. package/ark-control-facade/src/main/java/com/union/control/service/SensitiveDataDemoService.java +13 -0
  82. package/ark-control-facade/src/main/java/com/union/control/service/sensitive/SensitiveRevealService.java +18 -0
  83. package/ark-web/README.md +80 -0
  84. package/ark-web/pom.xml +105 -0
  85. package/ark-web/src/local-mock/java/com/epcc/arkweb/mock/ArkAuthServiceMock.java +105 -0
  86. package/ark-web/src/local-mock/java/com/epcc/arkweb/mock/LocalKaptchaConfiguration.java +26 -0
  87. package/ark-web/src/main/java/com/epcc/arkweb/Application.java +13 -0
  88. package/ark-web/src/main/java/com/epcc/arkweb/config/InterceptorConfig.java +20 -0
  89. package/ark-web/src/main/java/com/epcc/arkweb/config/Realm.java +64 -0
  90. package/ark-web/src/main/java/com/epcc/arkweb/config/ShiroConfig.java +129 -0
  91. package/ark-web/src/main/java/com/epcc/arkweb/filter/LoginFormFilter.java +43 -0
  92. package/ark-web/src/main/java/com/epcc/arkweb/helper/AuthContextHolder.java +39 -0
  93. package/ark-web/src/main/java/com/epcc/arkweb/helper/AuthenticatedRequest.java +91 -0
  94. package/ark-web/src/main/java/com/epcc/arkweb/model/ShiroUser.java +21 -0
  95. package/ark-web/src/main/java/com/epcc/arkweb/utils/ResultMsg.java +19 -0
  96. package/ark-web/src/main/java/com/epcc/arkweb/vo/llm/ScheduledTaskCommandVO.java +30 -0
  97. package/ark-web/src/main/java/com/epcc/arkweb/vo/llm/ScheduledTaskQueryVO.java +20 -0
  98. package/ark-web/src/main/java/com/epcc/arkweb/web/CommonController.java +25 -0
  99. package/ark-web/src/main/java/com/epcc/arkweb/web/llm/AgentAuthorizationInterceptor.java +229 -0
  100. package/ark-web/src/main/java/com/epcc/arkweb/web/llm/AgentController.java +165 -0
  101. package/ark-web/src/main/java/com/epcc/arkweb/web/llm/AgentPermission.java +13 -0
  102. package/ark-web/src/main/java/com/epcc/arkweb/web/llm/LlmController.java +209 -0
  103. package/ark-web/src/main/java/com/epcc/arkweb/web/llm/ScheduledTaskController.java +160 -0
  104. package/ark-web/src/main/java/com/epcc/arkweb/web/sensitive/reveal/SensitiveCaptchaService.java +146 -0
  105. package/ark-web/src/main/java/com/epcc/arkweb/web/sensitive/reveal/SensitiveRevealController.java +163 -0
  106. package/ark-web/src/main/resources/application.properties +1 -0
  107. package/ark-web/src/main/resources/application.yml +23 -0
  108. package/ark-web/src/main/resources/dubbo-consumer.xml +19 -0
  109. package/ark-web/src/production-overlay/java/com/epcc/arkweb/config/CasShiroConfig.java +229 -0
  110. package/ark-web/src/production-overlay/java/com/epcc/arkweb/config/InterceptorConfig.java +35 -0
  111. package/ark-web/src/production-overlay/java/com/epcc/arkweb/config/ShiroConfig.java +161 -0
  112. package/ark-web/src/test/java/com/epcc/arkweb/ArkWebStructureContractTest.java +290 -0
  113. package/ark-web/src/test/java/com/epcc/arkweb/ShiroTestSupport.java +32 -0
  114. package/ark-web/src/test/java/com/epcc/arkweb/config/LocalShiroIntegrationTest.java +121 -0
  115. package/ark-web/src/test/java/com/epcc/arkweb/helper/AuthenticatedRequestTest.java +131 -0
  116. package/ark-web/src/test/java/com/epcc/arkweb/local/LocalArkAuthServiceMockTest.java +17 -0
  117. package/ark-web/src/test/java/com/epcc/arkweb/web/llm/AgentAuthorizationInterceptorTest.java +134 -0
  118. package/ark-web/src/test/java/com/epcc/arkweb/web/llm/AgentControllerAuthorizationTest.java +97 -0
  119. package/ark-web/src/test/java/com/epcc/arkweb/web/llm/LlmControllerTest.java +113 -0
  120. package/ark-web/src/test/java/com/epcc/arkweb/web/sensitive/reveal/SensitiveRevealControllerTest.java +273 -0
  121. package/package.json +18 -0
  122. package/pom.xml +16 -0
@@ -0,0 +1,103 @@
1
+ package com.union.control.utils;
2
+
3
+ import com.fasterxml.jackson.core.type.TypeReference;
4
+ import com.fasterxml.jackson.databind.ObjectMapper;
5
+
6
+ import java.util.LinkedHashMap;
7
+ import java.util.Map;
8
+ import java.util.regex.Pattern;
9
+
10
+ public final class AgentSupport {
11
+ private static final Pattern ID = Pattern.compile("[A-Za-z0-9._:@-]{1,64}");
12
+
13
+ private AgentSupport() {}
14
+
15
+ public static Map<String, Object> request(ObjectMapper json, String input) {
16
+ if (input == null) throw new IllegalArgumentException("请求参数非法");
17
+ try {
18
+ Map<String, Object> value = json.readValue(
19
+ input, new TypeReference<Map<String, Object>>() {});
20
+ if (value == null) throw new IllegalArgumentException("请求参数非法");
21
+ return value;
22
+ } catch (IllegalArgumentException error) {
23
+ throw error;
24
+ } catch (Exception error) {
25
+ throw new IllegalArgumentException("请求参数不是合法 JSON", error);
26
+ }
27
+ }
28
+
29
+ public static String userId(Map<String, Object> request) {
30
+ return identity(request, "userId");
31
+ }
32
+
33
+ public static String identity(Map<String, Object> request, String field) {
34
+ String value = text(request, field, 64, true);
35
+ if (value == null || value.trim().isEmpty())
36
+ throw new IllegalArgumentException(field + " 非法");
37
+ return value;
38
+ }
39
+
40
+ public static void requireId(String value) {
41
+ if (value == null || !ID.matcher(value).matches())
42
+ throw new IllegalArgumentException("conversationId 非法");
43
+ }
44
+
45
+ public static void requireExecutionToken(String value) {
46
+ if (value == null || !ID.matcher(value).matches())
47
+ throw new IllegalArgumentException("runId 非法");
48
+ }
49
+
50
+ public static int integer(Map<String, Object> values, String key, int min, int max) {
51
+ Object raw = values.get(key);
52
+ if (!(raw instanceof Number)) throw new IllegalArgumentException(key + " 非法");
53
+ int value = ((Number) raw).intValue();
54
+ requireRange(value, min, max, key);
55
+ return value;
56
+ }
57
+
58
+ public static long number(Object value) {
59
+ return value instanceof Number
60
+ ? ((Number) value).longValue()
61
+ : Long.parseLong(String.valueOf(value));
62
+ }
63
+
64
+ public static String optionalText(Map<String, Object> values, String key, int max) {
65
+ return text(values, key, max, false);
66
+ }
67
+
68
+ public static String text(Map<?, ?> values, String key, int max, boolean required) {
69
+ Object raw = values.get(key);
70
+ if (raw != null && !(raw instanceof String))
71
+ throw new IllegalArgumentException(key + " 非法");
72
+ String value = raw == null ? null : ((String) raw).trim();
73
+ if (value != null && value.isEmpty()) value = null;
74
+ if ((required && value == null) || (value != null && value.length() > max))
75
+ throw new IllegalArgumentException(key + " 非法");
76
+ return value;
77
+ }
78
+
79
+ public static void requireRange(int value, int min, int max, String name) {
80
+ if (value < min || value > max)
81
+ throw new IllegalArgumentException(name + " 超出范围");
82
+ }
83
+
84
+ public static String likePrefix(String prefix) {
85
+ return prefix.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_") + "%";
86
+ }
87
+
88
+ public static boolean same(String left, String right) {
89
+ return left == null ? right == null : left.equals(right);
90
+ }
91
+
92
+ public static Map<String, Object> success() {
93
+ Map<String, Object> response = new LinkedHashMap<>();
94
+ response.put("success", true);
95
+ return response;
96
+ }
97
+
98
+ public static Map<String, Object> ok(Object data) {
99
+ Map<String, Object> response = success();
100
+ response.put("data", data);
101
+ return response;
102
+ }
103
+ }
@@ -0,0 +1,160 @@
1
+ package com.union.control.utils.security;
2
+
3
+ import com.epcc.commons.securityproxy.api.SecurityResult;
4
+ import com.epcc.commons.securityproxy.api.SymmetricalSecurityService;
5
+ import com.epcc.dubbo.result.Result;
6
+ import com.nucc.channel.ark.common.exception.BaseDataErrorCode;
7
+ import com.nucc.channel.ark.common.exception.CheckException;
8
+ import org.apache.commons.codec.binary.Base64;
9
+ import org.slf4j.Logger;
10
+ import org.slf4j.LoggerFactory;
11
+ import org.springframework.stereotype.Component;
12
+
13
+ import javax.annotation.Resource;
14
+ import java.nio.charset.StandardCharsets;
15
+ import java.util.ArrayList;
16
+ import java.util.List;
17
+ import java.util.regex.Matcher;
18
+ import java.util.regex.Pattern;
19
+
20
+ import static com.nucc.channel.ark.common.util.Constant.ENCRYPT_END;
21
+ import static com.nucc.channel.ark.common.util.Constant.ENCRYPT_START;
22
+ import static com.nucc.channel.ark.common.util.Constant.REGEX_DECRYPT_TAG;
23
+ import static com.nucc.channel.ark.common.util.Constant.REGEX_EMAIL;
24
+ import static com.nucc.channel.ark.common.util.Constant.REGEX_MOBILE;
25
+ import static com.nucc.channel.ark.common.util.Constant.REGEX_TELEPHONE;
26
+
27
+ /** Production-equivalent crypto utility; cryptography remains behind sensitiveProxy. */
28
+ @Component
29
+ public class SymmetricalSecurityUtils {
30
+ private static final Logger LOG = LoggerFactory.getLogger(SymmetricalSecurityUtils.class);
31
+ private static final Pattern MOBILE = Pattern.compile(REGEX_MOBILE);
32
+ private static final Pattern EMAIL = Pattern.compile(REGEX_EMAIL);
33
+ private static final Pattern TELEPHONE = Pattern.compile(REGEX_TELEPHONE);
34
+ private static final Pattern DECRYPT_TAG = Pattern.compile(REGEX_DECRYPT_TAG);
35
+
36
+ @Resource(name = "sensitiveProxy")
37
+ private SymmetricalSecurityService symmetricalSecurityService;
38
+
39
+ public SymmetricalSecurityUtils() {}
40
+
41
+ public SymmetricalSecurityUtils(SymmetricalSecurityService symmetricalSecurityService) {
42
+ this.symmetricalSecurityService = symmetricalSecurityService;
43
+ }
44
+
45
+ public String encryptLongString(String plaintext, int chunkSize) throws CheckException {
46
+ if (chunkSize == 0) return encryptByFixKey(plaintext);
47
+ List<String> chunks = new ArrayList<>();
48
+ for (int i = 0; i < plaintext.length(); i += chunkSize) {
49
+ chunks.add(encryptByFixKey(plaintext.substring(i, Math.min(plaintext.length(), i + chunkSize))));
50
+ }
51
+ return join(chunks, "|");
52
+ }
53
+
54
+ public String encryptWithTag(String plaintext) throws CheckException {
55
+ if (isBlank(plaintext)) return "";
56
+ String value = replaceEncrypted(MOBILE, plaintext);
57
+ value = replaceEncrypted(EMAIL, value);
58
+ return replaceEncrypted(TELEPHONE, value);
59
+ }
60
+
61
+ public String decryptLongString(String ciphertext) throws CheckException {
62
+ String[] chunks = ciphertext.split("\\|");
63
+ StringBuilder result = new StringBuilder();
64
+ for (String chunk : chunks) result.append(decryptWithCheckNoLog(chunk));
65
+ return result.toString();
66
+ }
67
+
68
+ public String decryptWithTag(String ciphertext) throws CheckException {
69
+ if (isBlank(ciphertext)) return "";
70
+ StringBuilder value = new StringBuilder(ciphertext);
71
+ Matcher matcher = DECRYPT_TAG.matcher(value);
72
+ while (matcher.find()) {
73
+ value.replace(matcher.start(), matcher.end(), decryptWithCheckNoLog(matcher.group(1)));
74
+ matcher.reset(value);
75
+ }
76
+ return value.toString();
77
+ }
78
+
79
+ public String encryptWithCheck(String plaintext) throws CheckException {
80
+ return isBlank(plaintext) ? plaintext : encryptByFixKey(plaintext);
81
+ }
82
+
83
+ public String decryptWithCheck(String ciphertext) {
84
+ if (isBlank(ciphertext)) return ciphertext;
85
+ try {
86
+ return decryptByFixKey(ciphertext);
87
+ } catch (CheckException error) {
88
+ LOG.error("decryptWithCheck failed error_type={}", error.getClass().getSimpleName());
89
+ return ciphertext;
90
+ }
91
+ }
92
+
93
+ public String decryptWithCheckNoLog(String ciphertext) throws CheckException {
94
+ return isBlank(ciphertext) ? ciphertext : decryptByFixKey(ciphertext);
95
+ }
96
+
97
+ private String replaceEncrypted(Pattern pattern, String plaintext) throws CheckException {
98
+ StringBuilder value = new StringBuilder(plaintext);
99
+ Matcher matcher = pattern.matcher(value);
100
+ while (matcher.find()) {
101
+ value.replace(matcher.start(), matcher.end(),
102
+ ENCRYPT_START + encryptByFixKey(matcher.group()) + ENCRYPT_END);
103
+ matcher.reset(value);
104
+ }
105
+ return value.toString();
106
+ }
107
+
108
+ private String encryptByFixKey(String plaintext) throws CheckException {
109
+ long started = System.currentTimeMillis();
110
+ Result<SecurityResult> result = symmetricalSecurityService.encryptByFixedKey(
111
+ SymmetricalSecurityService.Algorithm.AES256,
112
+ plaintext.getBytes(StandardCharsets.UTF_8));
113
+ if (!result.isSuccess()) throw remoteFailure(result);
114
+ debug("encryptByFixKey", started);
115
+ return Base64.encodeBase64String(result.getResult().getContent());
116
+ }
117
+
118
+ private String decryptByFixKey(String ciphertext) throws CheckException {
119
+ long started = System.currentTimeMillis();
120
+ final byte[] decoded;
121
+ try {
122
+ decoded = Base64.decodeBase64(ciphertext);
123
+ } catch (IllegalArgumentException error) {
124
+ throw new CheckException(BaseDataErrorCode.SYSTEM_INNER_ERROR, "Invalid ciphertext");
125
+ }
126
+ Result<SecurityResult> result = symmetricalSecurityService.decryptByFixedKey(
127
+ SymmetricalSecurityService.Algorithm.AES256, decoded);
128
+ if (!result.isSuccess()) throw remoteFailure(result);
129
+ String plaintext = new String(result.getResult().getContent(), StandardCharsets.UTF_8);
130
+ debug("decryptByFixKey", started);
131
+ return plaintext;
132
+ }
133
+
134
+ private void debug(String operation, long started) {
135
+ if (LOG.isDebugEnabled()) LOG.debug("SymmetricalSecurityUtils.{} elapsedMs={}",
136
+ operation, System.currentTimeMillis() - started);
137
+ }
138
+
139
+ private static CheckException remoteFailure(Result<SecurityResult> result) {
140
+ return new CheckException(BaseDataErrorCode.SYSTEM_INNER_ERROR,
141
+ result.getErrorCode() + "|" + result.getErrorMsg());
142
+ }
143
+
144
+ private static boolean isBlank(String value) {
145
+ if (value == null || value.isEmpty()) return true;
146
+ for (int i = 0; i < value.length(); i++) {
147
+ if (!Character.isWhitespace(value.charAt(i))) return false;
148
+ }
149
+ return true;
150
+ }
151
+
152
+ private static String join(List<String> values, String delimiter) {
153
+ StringBuilder result = new StringBuilder();
154
+ for (String value : values) {
155
+ if (result.length() > 0) result.append(delimiter);
156
+ result.append(value);
157
+ }
158
+ return result.toString();
159
+ }
160
+ }
@@ -0,0 +1 @@
1
+ providerAccessLog=com.union.control.dubbo.ProviderAccessLogFilter
@@ -0,0 +1,4 @@
1
+ sensitive.reveal.enabled=${SENSITIVE_REVEAL_ENABLED:true}
2
+ sensitive.reveal.strict_mode=${SENSITIVE_REVEAL_STRICT_MODE:true}
3
+ sensitive.reveal.ttl-seconds=${SENSITIVE_REVEAL_TTL_SECONDS:300}
4
+ sensitive.address-book.plaintext-roles=${SENSITIVE_ADDRESS_BOOK_PLAINTEXT_ROLES:001,002,003}
@@ -0,0 +1,32 @@
1
+ agent:
2
+ py-app-base-url: ${PY_APP_BASE_URL:http://127.0.0.1:8083}
3
+ scheduled-enabled: ${SCHEDULED_TASK_ENABLED:true}
4
+ scheduled-worker-threads: ${SCHEDULED_TASK_WORKER_THREADS:2}
5
+ scheduled-max-run-seconds: ${SCHEDULED_TASK_MAX_RUN_SECONDS:930}
6
+ scheduled-token-ttl-seconds: ${SCHEDULED_TASK_TOKEN_TTL_SECONDS:960}
7
+
8
+ dubbo:
9
+ application:
10
+ name: ark-control
11
+ registry:
12
+ address: ${DUBBO_REGISTRY_ADDRESS:zookeeper://127.0.0.1:2181}
13
+ protocol:
14
+ port: ${DUBBO_PROTOCOL_PORT:20880}
15
+
16
+ spring:
17
+ main:
18
+ web-environment: false
19
+ datasource:
20
+ url: ${MYSQL_URL:jdbc:mysql://127.0.0.1:3306/union_control?createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC}
21
+ username: ${MYSQL_USER:root}
22
+ password: ${MYSQL_PASSWORD:mmls@HW902}
23
+ driver-class-name: com.mysql.cj.jdbc.Driver
24
+ initialize: true
25
+ redis:
26
+ host: ${REDIS_HOST:127.0.0.1}
27
+ port: ${REDIS_PORT:6379}
28
+ password: ${REDIS_PASSWORD:mmls@HW902}
29
+ timeout: ${REDIS_TIMEOUT_MS:2000}
30
+
31
+ mybatis:
32
+ mapper-locations: classpath*:mapper/*.xml
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <beans xmlns="http://www.springframework.org/schema/beans"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
5
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
6
+ http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
7
+ <dubbo:application name="${dubbo.application.name}"/>
8
+ <dubbo:registry address="${dubbo.registry.address}"/>
9
+ <dubbo:protocol name="dubbo" port="${dubbo.protocol.port}" transporter="netty4"/>
10
+ <dubbo:provider filter="providerAccessLog"/>
11
+
12
+ <dubbo:service interface="com.union.control.service.AgentExecutionService" ref="agentExecutionService"/>
13
+ <dubbo:service interface="com.union.control.service.AgentProxyService" ref="agentProxyService"/>
14
+ <dubbo:service interface="com.union.control.service.ConversationService" ref="conversationService"/>
15
+ <dubbo:service interface="com.union.control.service.MemoryStoreService" ref="memoryStoreService"/>
16
+ <dubbo:service interface="com.union.control.service.RunningAnalysisMockService" ref="runningAnalysisMockService"/>
17
+ <dubbo:service interface="com.union.control.service.ScheduledTaskService" ref="scheduledTaskService"/>
18
+ <dubbo:service interface="com.union.control.service.SensitiveDataDemoService" ref="sensitiveDataDemoService"/>
19
+ <dubbo:service interface="com.union.control.service.sensitive.SensitiveRevealService" ref="sensitiveRevealService"/>
20
+ </beans>
@@ -0,0 +1,75 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <!DOCTYPE mapper
3
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
4
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
5
+ <mapper namespace="com.union.control.mapper.AgentExecutionMapper">
6
+
7
+ <update id="softDeleteExecutions">
8
+ UPDATE ai_agent_execution
9
+ SET delete_flag=0,updated_at=CURRENT_TIMESTAMP
10
+ WHERE conversation_id=#{conversationId} AND user_id=#{userId} AND delete_flag=1
11
+ </update>
12
+
13
+ <insert id="insertRootExecution">
14
+ INSERT INTO ai_agent_execution
15
+ (run_id,conversation_id,user_id,parent_execution_id,agent_name,status,delete_flag)
16
+ VALUES (#{runId},#{conversationId},#{userId},NULL,NULL,'running',1)
17
+ </insert>
18
+
19
+ <insert id="insertCompletedRootExecution" parameterType="map"
20
+ useGeneratedKeys="true" keyProperty="id">
21
+ INSERT INTO ai_agent_execution
22
+ (run_id,conversation_id,user_id,parent_execution_id,agent_name,status,
23
+ finished_at,delete_flag,created_at,updated_at)
24
+ VALUES (#{runId},#{conversationId},#{userId},NULL,#{agentName},'completed',
25
+ CURRENT_TIMESTAMP,1,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)
26
+ </insert>
27
+
28
+ <update id="updateRootAgent">
29
+ UPDATE ai_agent_execution
30
+ SET agent_name=#{agentName},updated_at=CURRENT_TIMESTAMP
31
+ WHERE id=#{id} AND delete_flag=1
32
+ </update>
33
+
34
+ <insert id="insertChildExecution">
35
+ INSERT INTO ai_agent_execution
36
+ (run_id,conversation_id,user_id,parent_execution_id,agent_name,
37
+ delegation_tool_call_id,task,status,delete_flag)
38
+ VALUES (#{runId},#{conversationId},#{userId},#{parentExecutionId},#{agentName},
39
+ #{delegationCallId},#{task},'running',1)
40
+ </insert>
41
+
42
+ <select id="findExecutions" resultType="map">
43
+ SELECT e.id,e.run_id AS runId,e.conversation_id AS conversationId,
44
+ e.parent_execution_id AS parentExecutionId,p.run_id AS parentRunId,
45
+ e.agent_name AS agentName,e.delegation_tool_call_id AS delegationToolCallId,
46
+ e.task,e.status,e.error_code AS errorCode,
47
+ DATE_FORMAT(e.finished_at,'%Y-%m-%dT%H:%i:%s') AS finishedAt,
48
+ DATE_FORMAT(e.created_at,'%Y-%m-%dT%H:%i:%s') AS createdAt
49
+ FROM ai_agent_execution e
50
+ LEFT JOIN ai_agent_execution p ON p.id=e.parent_execution_id
51
+ WHERE e.user_id=#{userId} AND e.conversation_id=#{conversationId} AND e.delete_flag=1
52
+ ORDER BY e.created_at,e.id
53
+ </select>
54
+
55
+ <select id="findExecution" resultType="map">
56
+ SELECT e.id,e.run_id AS runId,e.conversation_id AS conversationId,
57
+ e.parent_execution_id AS parentExecutionId,p.run_id AS parentRunId,
58
+ e.agent_name AS agentName,e.delegation_tool_call_id AS delegationToolCallId,
59
+ e.task,e.status,e.error_code AS errorCode,
60
+ DATE_FORMAT(e.finished_at,'%Y-%m-%dT%H:%i:%s') AS finishedAt,
61
+ DATE_FORMAT(e.created_at,'%Y-%m-%dT%H:%i:%s') AS createdAt
62
+ FROM ai_agent_execution e
63
+ LEFT JOIN ai_agent_execution p ON p.id=e.parent_execution_id
64
+ WHERE e.user_id=#{userId} AND e.conversation_id=#{conversationId}
65
+ AND e.run_id=#{runId} AND e.delete_flag=1
66
+ <if test="lock">FOR UPDATE</if>
67
+ </select>
68
+
69
+ <update id="finishExecution">
70
+ UPDATE ai_agent_execution
71
+ SET status=#{status},error_code=#{errorCode},
72
+ finished_at=CURRENT_TIMESTAMP,updated_at=CURRENT_TIMESTAMP
73
+ WHERE id=#{id} AND delete_flag=1
74
+ </update>
75
+ </mapper>
@@ -0,0 +1,110 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <!DOCTYPE mapper
3
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
4
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
5
+ <mapper namespace="com.union.control.mapper.ConversationMapper">
6
+
7
+ <select id="findConversations" resultType="map">
8
+ SELECT c.conversation_id AS conversationId,c.title,c.status,
9
+ DATE_FORMAT(c.created_at,'%Y-%m-%dT%H:%i:%s') AS createdAt,
10
+ DATE_FORMAT(c.updated_at,'%Y-%m-%dT%H:%i:%s') AS updatedAt,
11
+ (SELECT e.status FROM ai_agent_execution e
12
+ WHERE e.conversation_id=c.conversation_id AND e.user_id=c.user_id
13
+ AND e.parent_execution_id IS NULL AND e.delete_flag=1
14
+ ORDER BY e.created_at DESC,e.id DESC LIMIT 1) AS executionStatus
15
+ FROM ai_conversation c
16
+ WHERE c.user_id=#{userId} AND c.delete_flag=1
17
+ AND c.status='active'
18
+ ORDER BY c.created_at DESC,c.id DESC
19
+ LIMIT #{limit}
20
+ </select>
21
+
22
+ <select id="findConversation" resultType="map">
23
+ SELECT c.conversation_id AS conversationId,c.title,c.status,
24
+ DATE_FORMAT(c.created_at,'%Y-%m-%dT%H:%i:%s') AS createdAt,
25
+ DATE_FORMAT(c.updated_at,'%Y-%m-%dT%H:%i:%s') AS updatedAt,
26
+ (SELECT e.status FROM ai_agent_execution e
27
+ WHERE e.conversation_id=c.conversation_id AND e.user_id=c.user_id
28
+ AND e.parent_execution_id IS NULL AND e.delete_flag=1
29
+ ORDER BY e.created_at DESC,e.id DESC LIMIT 1) AS executionStatus
30
+ FROM ai_conversation c
31
+ WHERE c.conversation_id=#{conversationId}
32
+ AND c.user_id=#{userId} AND c.delete_flag=1
33
+ </select>
34
+
35
+ <update id="updateConversationTitle">
36
+ UPDATE ai_conversation
37
+ SET title=#{title},updated_at=CURRENT_TIMESTAMP
38
+ WHERE conversation_id=#{conversationId} AND user_id=#{userId} AND delete_flag=1
39
+ </update>
40
+
41
+ <update id="softDeleteMessages">
42
+ UPDATE ai_conversation_message
43
+ SET delete_flag=0,updated_at=CURRENT_TIMESTAMP
44
+ WHERE conversation_id=#{conversationId} AND user_id=#{userId} AND delete_flag=1
45
+ </update>
46
+
47
+ <update id="softDeleteConversation">
48
+ UPDATE ai_conversation
49
+ SET delete_flag=0,updated_at=CURRENT_TIMESTAMP
50
+ WHERE conversation_id=#{conversationId} AND user_id=#{userId} AND delete_flag=1
51
+ </update>
52
+
53
+ <insert id="insertConversation">
54
+ INSERT INTO ai_conversation
55
+ (conversation_id,user_id,title,delete_flag)
56
+ VALUES (#{conversationId},#{userId},#{title},1)
57
+ </insert>
58
+
59
+ <select id="currentMessageSequence" resultType="long">
60
+ SELECT COALESCE(MAX(sequence_no),0)
61
+ FROM ai_conversation_message
62
+ WHERE conversation_id=#{conversationId}
63
+ </select>
64
+
65
+ <insert id="insertMessage">
66
+ INSERT INTO ai_conversation_message
67
+ (conversation_id,user_id,message_id,agent_execution_id,role,sequence_no,payload,delete_flag)
68
+ VALUES (#{conversationId},#{userId},#{messageId},#{executionId},#{role},#{sequence},#{payload},1)
69
+ </insert>
70
+
71
+ <update id="touchConversation">
72
+ UPDATE ai_conversation
73
+ SET updated_at=CURRENT_TIMESTAMP
74
+ WHERE conversation_id=#{conversationId} AND user_id=#{userId} AND delete_flag=1
75
+ </update>
76
+
77
+ <select id="findRootMessages" resultType="map">
78
+ SELECT m.message_id AS messageId,m.role,m.payload
79
+ FROM ai_conversation_message m
80
+ JOIN ai_agent_execution e ON e.id=m.agent_execution_id
81
+ WHERE m.conversation_id=#{conversationId} AND m.user_id=#{userId} AND m.delete_flag=1
82
+ AND e.delete_flag=1 AND e.parent_execution_id IS NULL
83
+ ORDER BY m.sequence_no
84
+ </select>
85
+
86
+ <select id="findBrowserMessages" resultType="map">
87
+ SELECT m.message_id AS messageId,m.role,m.payload,e.run_id AS runId,
88
+ e.parent_execution_id AS parentExecutionId
89
+ FROM ai_conversation_message m
90
+ JOIN ai_agent_execution e ON e.id=m.agent_execution_id
91
+ WHERE m.conversation_id=#{conversationId} AND m.user_id=#{userId} AND m.delete_flag=1
92
+ AND e.delete_flag=1
93
+ ORDER BY m.sequence_no
94
+ </select>
95
+
96
+ <select id="requireOwnedActive" resultType="long">
97
+ SELECT id
98
+ FROM ai_conversation
99
+ WHERE conversation_id=#{conversationId} AND user_id=#{userId}
100
+ AND status='active' AND delete_flag=1
101
+ </select>
102
+
103
+ <select id="requireOwned" resultType="long">
104
+ SELECT id
105
+ FROM ai_conversation
106
+ WHERE conversation_id=#{conversationId} AND user_id=#{userId} AND delete_flag=1
107
+ <if test="lock">FOR UPDATE</if>
108
+ </select>
109
+ </mapper>
110
+
@@ -0,0 +1,74 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <!DOCTYPE mapper
3
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
4
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
5
+ <mapper namespace="com.union.control.mapper.MemoryStoreMapper">
6
+
7
+ <select id="readMemory" resultType="map">
8
+ SELECT content,version,last_operation_id AS operationId
9
+ FROM ai_memory_file
10
+ WHERE user_id=#{userId} AND path=#{path} AND delete_flag=1
11
+ </select>
12
+
13
+ <select id="listMemoryPaths" resultType="string">
14
+ SELECT path
15
+ FROM ai_memory_file
16
+ WHERE user_id=#{userId} AND delete_flag=1 AND path LIKE #{prefix}
17
+ ORDER BY path
18
+ LIMIT #{limit}
19
+ </select>
20
+
21
+ <select id="findMemoryOperation" resultType="map">
22
+ SELECT fingerprint,result_version AS resultVersion,existed
23
+ FROM ai_memory_operation
24
+ WHERE user_id=#{userId} AND operation_id=#{operationId}
25
+ <if test="lock">FOR UPDATE</if>
26
+ </select>
27
+
28
+ <select id="currentMemoryVersion" resultType="long">
29
+ SELECT COALESCE(MAX(version),0)
30
+ FROM ai_memory_file
31
+ WHERE user_id=#{userId} AND path=#{path}
32
+ </select>
33
+
34
+ <update id="updateMemoryFile">
35
+ UPDATE ai_memory_file
36
+ SET content=#{content},version=#{version},last_operation_id=#{operationId},
37
+ updated_at=CURRENT_TIMESTAMP
38
+ WHERE id=#{id} AND delete_flag=1
39
+ </update>
40
+
41
+ <insert id="insertMemoryFile">
42
+ INSERT INTO ai_memory_file
43
+ (user_id,path,content,version,last_operation_id,delete_flag)
44
+ VALUES (#{userId},#{path},#{content},#{version},#{operationId},1)
45
+ </insert>
46
+
47
+ <update id="softDeleteMemoryFile">
48
+ UPDATE ai_memory_file
49
+ SET delete_flag=0,updated_at=CURRENT_TIMESTAMP
50
+ WHERE id=#{id} AND delete_flag=1
51
+ </update>
52
+
53
+ <select id="searchMemory" resultType="map">
54
+ SELECT path,content
55
+ FROM ai_memory_file
56
+ WHERE user_id=#{userId} AND delete_flag=1 AND path LIKE #{prefix}
57
+ ORDER BY path
58
+ LIMIT #{limit}
59
+ </select>
60
+
61
+ <select id="findMemoryRow" resultType="map">
62
+ SELECT id,version
63
+ FROM ai_memory_file
64
+ WHERE user_id=#{userId} AND path=#{path} AND delete_flag=1
65
+ FOR UPDATE
66
+ </select>
67
+
68
+ <insert id="insertMemoryOperation">
69
+ INSERT INTO ai_memory_operation
70
+ (user_id,operation_id,fingerprint,result_version,existed,delete_flag)
71
+ VALUES (#{userId},#{operationId},#{fingerprint},#{version},#{existed},1)
72
+ </insert>
73
+ </mapper>
74
+