secagentx 3.0.0__py3-none-any.whl

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 (182) hide show
  1. backend/__init__.py +1 -0
  2. backend/__main__.py +3 -0
  3. backend/_assets/config.yaml +195 -0
  4. backend/_assets/frontend/dist/assets/AgentsView-DFqRplI8.css +1 -0
  5. backend/_assets/frontend/dist/assets/AgentsView-DJTpfQ87.js +1 -0
  6. backend/_assets/frontend/dist/assets/AttackChainView-BVfI-SC6.js +1 -0
  7. backend/_assets/frontend/dist/assets/ChatView-Bg4nIlQ0.css +1 -0
  8. backend/_assets/frontend/dist/assets/ChatView-CRndtmEC.js +38 -0
  9. backend/_assets/frontend/dist/assets/DashboardView-BXs4AWv8.js +1 -0
  10. backend/_assets/frontend/dist/assets/DashboardView-WnHWiqBW.css +1 -0
  11. backend/_assets/frontend/dist/assets/EventDetailView-DQk6Qp7-.js +1 -0
  12. backend/_assets/frontend/dist/assets/EventDetailView-Dj-a-zWr.css +1 -0
  13. backend/_assets/frontend/dist/assets/EventsView-8xh8uKO0.js +1 -0
  14. backend/_assets/frontend/dist/assets/EventsView-BHfFn66K.css +1 -0
  15. backend/_assets/frontend/dist/assets/KnowledgeView-C2N3v9bF.css +1 -0
  16. backend/_assets/frontend/dist/assets/KnowledgeView-D54ODoC9.js +11 -0
  17. backend/_assets/frontend/dist/assets/LoginView-CjvFmo7C.js +1 -0
  18. backend/_assets/frontend/dist/assets/LoginView-D14FzcsP.css +1 -0
  19. backend/_assets/frontend/dist/assets/SettingsView-JOJuoABi.js +1 -0
  20. backend/_assets/frontend/dist/assets/UsersView-DhMXZhir.js +1 -0
  21. backend/_assets/frontend/dist/assets/_plugin-vue_export-helper-BDNMzG2s.js +1 -0
  22. backend/_assets/frontend/dist/assets/index-D9Su3fYY.css +1 -0
  23. backend/_assets/frontend/dist/assets/index-DBEjbyJR.js +4 -0
  24. backend/_assets/frontend/dist/assets/rolldown-runtime-DK3Fl9T5.js +1 -0
  25. backend/_assets/frontend/dist/assets/vendor-charts-Dh1nChzO.js +39 -0
  26. backend/_assets/frontend/dist/assets/vendor-icons-BTNgi7vU.js +1 -0
  27. backend/_assets/frontend/dist/assets/vendor-ui-Cdd65KTN.js +7367 -0
  28. backend/_assets/frontend/dist/assets/vendor-vue-CXKcZAmz.js +1 -0
  29. backend/_assets/frontend/dist/index.html +51 -0
  30. backend/_assets/frontend/index.html +46 -0
  31. backend/_assets/frontend/package-lock.json +2983 -0
  32. backend/_assets/frontend/package.json +37 -0
  33. backend/_assets/frontend/src/App.vue +231 -0
  34. backend/_assets/frontend/src/main.js +12 -0
  35. backend/_assets/frontend/src/router/index.js +117 -0
  36. backend/_assets/frontend/src/stores/chat.js +671 -0
  37. backend/_assets/frontend/src/styles/tokens.css +282 -0
  38. backend/_assets/frontend/src/utils/http.js +191 -0
  39. backend/_assets/frontend/src/views/AgentsView.vue +227 -0
  40. backend/_assets/frontend/src/views/AttackChainView.vue +210 -0
  41. backend/_assets/frontend/src/views/ChatView.vue +1107 -0
  42. backend/_assets/frontend/src/views/DashboardView.vue +514 -0
  43. backend/_assets/frontend/src/views/EventDetailView.vue +387 -0
  44. backend/_assets/frontend/src/views/EventsView.vue +253 -0
  45. backend/_assets/frontend/src/views/KnowledgeView.vue +883 -0
  46. backend/_assets/frontend/src/views/LoginView.vue +314 -0
  47. backend/_assets/frontend/src/views/SettingsView.vue +226 -0
  48. backend/_assets/frontend/src/views/UsersView.vue +235 -0
  49. backend/_assets/frontend/vite.config.js +55 -0
  50. backend/_assets/knowledge_data/compliance/regulations.json +383 -0
  51. backend/_assets/knowledge_data/cve/vulnerabilities.json +70720 -0
  52. backend/_assets/knowledge_data/mitre_attack/techniques.json +14097 -0
  53. backend/_assets/knowledge_data/remediation/remediation.json +574 -0
  54. backend/_assets/knowledge_data/threat_intel/actors.json +1602 -0
  55. backend/_assets/knowledge_data/threat_intel/malware.json +971 -0
  56. backend/agents/__init__.py +1 -0
  57. backend/agents/alert_filter/__init__.py +1 -0
  58. backend/agents/alert_filter/alert_filter_agent.py +88 -0
  59. backend/agents/analyst.py +331 -0
  60. backend/agents/base.py +553 -0
  61. backend/agents/classifier_agent.py +134 -0
  62. backend/agents/cot_engine.py +578 -0
  63. backend/agents/intel.py +46 -0
  64. backend/agents/knowledge/__init__.py +2 -0
  65. backend/agents/knowledge/agentic_rag.py +928 -0
  66. backend/agents/knowledge/knowledge_agent.py +47 -0
  67. backend/agents/registry.py +148 -0
  68. backend/agents/responder.py +51 -0
  69. backend/agents/summary_agent.py +219 -0
  70. backend/auto_ingestor.py +948 -0
  71. backend/auto_patrol.py +452 -0
  72. backend/cli_app.py +523 -0
  73. backend/config/__init__.py +20 -0
  74. backend/config/provider_profiles.py +416 -0
  75. backend/config/runtime_settings.py +84 -0
  76. backend/decision_fusion/__init__.py +32 -0
  77. backend/decision_fusion/base.py +127 -0
  78. backend/decision_fusion/dempster_shafer.py +419 -0
  79. backend/decision_fusion/weighted_average.py +141 -0
  80. backend/email_ingestor.py +588 -0
  81. backend/errors.py +243 -0
  82. backend/escalation.py +453 -0
  83. backend/evaluation/__init__.py +7 -0
  84. backend/evaluation/evaluator.py +197 -0
  85. backend/evaluation/metrics.py +210 -0
  86. backend/federation/__init__.py +22 -0
  87. backend/federation/core.py +743 -0
  88. backend/interface/__init__.py +1 -0
  89. backend/interface/api_server.py +1830 -0
  90. backend/interface/cli.py +671 -0
  91. backend/knowledge/__init__.py +11 -0
  92. backend/knowledge/compliance.py +101 -0
  93. backend/knowledge/cve_db.py +100 -0
  94. backend/knowledge/mitre_attack.py +457 -0
  95. backend/knowledge/remediation.py +84 -0
  96. backend/knowledge/threat_intel_kb.py +246 -0
  97. backend/llm/__init__.py +1 -0
  98. backend/llm/anthropic_compatible.py +191 -0
  99. backend/llm/base.py +81 -0
  100. backend/llm/deepseek.py +221 -0
  101. backend/llm/fallback.py +268 -0
  102. backend/llm/mock.py +204 -0
  103. backend/llm/openai_compatible.py +51 -0
  104. backend/llm/provider.py +217 -0
  105. backend/llm/qwen.py +218 -0
  106. backend/main.py +421 -0
  107. backend/memory/__init__.py +1 -0
  108. backend/memory/episodic_memory.py +132 -0
  109. backend/memory/manager.py +204 -0
  110. backend/memory/semantic_memory.py +156 -0
  111. backend/memory/session_memory.py +102 -0
  112. backend/ml_model/__init__.py +23 -0
  113. backend/ml_model/pipeline.py +191 -0
  114. backend/ml_model/trainer.py +627 -0
  115. backend/models/__init__.py +1 -0
  116. backend/models/event.py +62 -0
  117. backend/models/message.py +58 -0
  118. backend/models/output.py +1216 -0
  119. backend/monitoring/metrics.py +184 -0
  120. backend/orchestrator/__init__.py +17 -0
  121. backend/orchestrator/agent_router.py +145 -0
  122. backend/orchestrator/core.py +159 -0
  123. backend/orchestrator/dynamic_weights.py +287 -0
  124. backend/orchestrator/react_loop.py +1895 -0
  125. backend/orchestrator/risk_model.py +494 -0
  126. backend/orchestrator/risk_scorer.py +356 -0
  127. backend/reasoner/__init__.py +19 -0
  128. backend/reasoner/reasoner.py +316 -0
  129. backend/runtime_assets.py +45 -0
  130. backend/security/__init__.py +24 -0
  131. backend/security/adversarial/__init__.py +13 -0
  132. backend/security/adversarial/guard.py +121 -0
  133. backend/security/adversarial/redteam.py +121 -0
  134. backend/security/adversarial/scanner.py +208 -0
  135. backend/security/audit.py +118 -0
  136. backend/security/auth.py +283 -0
  137. backend/security/circuit_breaker.py +212 -0
  138. backend/security/dispatch.py +18 -0
  139. backend/security/ratelimit.py +237 -0
  140. backend/security/rbac.py +431 -0
  141. backend/security/refresh_sessions.py +193 -0
  142. backend/security/sanitizer.py +32 -0
  143. backend/storage/__init__.py +1 -0
  144. backend/storage/chroma_store.py +79 -0
  145. backend/storage/database.py +296 -0
  146. backend/storage/migrations/env.py +65 -0
  147. backend/storage/migrations/versions/0001_initial_schema.py +101 -0
  148. backend/storage/migrations/versions/0002_add_agent_logs_experiences.py +53 -0
  149. backend/storage/migrations/versions/0003_add_conversation_owner.py +30 -0
  150. backend/storage/models.py +194 -0
  151. backend/storage/repositories/__init__.py +1 -0
  152. backend/storage/repositories/asset_repo.py +86 -0
  153. backend/storage/repositories/conversation_repo.py +216 -0
  154. backend/storage/repositories/event_repo.py +76 -0
  155. backend/storage/repositories/trajectory_repo.py +324 -0
  156. backend/storage/retention.py +117 -0
  157. backend/tools/__init__.py +16 -0
  158. backend/tools/alert_filter.py +208 -0
  159. backend/tools/aliyun_firewall.py +237 -0
  160. backend/tools/aws_firewall.py +369 -0
  161. backend/tools/base.py +445 -0
  162. backend/tools/calling.py +207 -0
  163. backend/tools/cve_search.py +77 -0
  164. backend/tools/execution_engine.py +202 -0
  165. backend/tools/firewall.py +387 -0
  166. backend/tools/geoip.py +168 -0
  167. backend/tools/log_analyzer.py +185 -0
  168. backend/tools/ml_detector.py +226 -0
  169. backend/tools/registry.py +38 -0
  170. backend/tools/tencent_firewall.py +300 -0
  171. backend/tools/threat_intel.py +732 -0
  172. backend/tools/trust_checker.py +76 -0
  173. backend/utils/__init__.py +5 -0
  174. backend/utils/config_loader.py +164 -0
  175. backend/utils/env.py +75 -0
  176. backend/utils/logger.py +150 -0
  177. backend/utils/text.py +32 -0
  178. secagentx-3.0.0.dist-info/METADATA +325 -0
  179. secagentx-3.0.0.dist-info/RECORD +182 -0
  180. secagentx-3.0.0.dist-info/WHEEL +5 -0
  181. secagentx-3.0.0.dist-info/entry_points.txt +2 -0
  182. secagentx-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "secagentx-frontend",
3
+ "version": "2.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "preview": "vite preview",
10
+ "test": "vitest run",
11
+ "test:watch": "vitest",
12
+ "test:coverage": "vitest run --coverage",
13
+ "test:e2e": "playwright test",
14
+ "test:e2e:ui": "playwright test --ui"
15
+ },
16
+ "dependencies": {
17
+ "@vicons/ionicons5": "^0.13.0",
18
+ "echarts": "^6.1.0",
19
+ "marked": "^12.0.0",
20
+ "naive-ui": "^2.38.0",
21
+ "pinia": "^2.1.0",
22
+ "vue": "^3.4.0",
23
+ "vue-router": "^4.3.0"
24
+ },
25
+ "devDependencies": {
26
+ "@playwright/test": "^1.62.0",
27
+ "@vitejs/plugin-vue": "^6.0.8",
28
+ "@vue/test-utils": "^2.4.11",
29
+ "jsdom": "^29.1.1",
30
+ "vite": "^8.2.2",
31
+ "vitest": "^4.1.10"
32
+ },
33
+ "overrides": {
34
+ "nanoid": "^3.3.18",
35
+ "postcss": "^8.5.23"
36
+ }
37
+ }
@@ -0,0 +1,231 @@
1
+ <template>
2
+ <n-config-provider :theme="customTheme" :locale="zhCN" :date-locale="dateZhCN">
3
+ <n-message-provider>
4
+ <n-notification-provider>
5
+ <n-dialog-provider>
6
+ <n-layout position="absolute" style="height: 100vh; background: var(--bg-primary);">
7
+ <!-- 顶部导航栏 -->
8
+ <n-layout-header bordered style="height: var(--header-height); display: flex; align-items: center; padding: 0 20px; background: var(--bg-card); border-bottom: 1px solid var(--border-primary);">
9
+ <!-- Logo 区域 -->
10
+ <div style="display: flex; align-items: center; gap: 10px;">
11
+ <div style="width: 28px; height: 28px; border-radius: 8px; background: var(--accent); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px; color: white; letter-spacing: 1px;">
12
+ SX
13
+ </div>
14
+ <span style="color: var(--accent); font-size: 16px; font-weight: 700; letter-spacing: 1.5px;">SecAgentX</span>
15
+ <span style="color: var(--text-muted); font-size: 11px; font-weight: 400; padding-left: 10px; border-left: 1px solid var(--border-primary);">AI 安全智能体</span>
16
+ </div>
17
+ <div style="flex:1" />
18
+ <!-- 右侧状态区 -->
19
+ <template v-if="!isLoginPage">
20
+ <!-- 连接状态指示灯 - 使用 store 的统一状态 -->
21
+ <div style="display: flex; align-items: center; gap: 6px; margin-right: 16px;">
22
+ <div :style="{
23
+ width: '7px', height: '7px', borderRadius: '50%',
24
+ background: chatStore.wsConnected ? 'var(--success)' : 'var(--error)',
25
+ boxShadow: chatStore.wsConnected ? '0 0 8px rgba(34,197,94,0.5)' : 'none',
26
+ animation: chatStore.wsConnected ? 'pulse-dot 2s infinite' : 'none',
27
+ }"></div>
28
+ <span style="color: var(--text-muted); font-size: 11px; font-weight: 500;">
29
+ {{ chatStore.wsConnected ? '已连接' : '未连接' }}
30
+ </span>
31
+ </div>
32
+ <!-- 用户信息 -->
33
+ <div v-if="currentUser" style="display: flex; align-items: center; gap: 8px; padding: 4px 12px 4px 4px; border-radius: var(--radius-full); background: var(--bg-elevated); border: 1px solid var(--border-primary);">
34
+ <div style="width: 26px; height: 26px; border-radius: 50%; background: linear-gradient(135deg, var(--accent), var(--accent-hover)); display: flex; align-items: center; justify-content: center; color: white; font-size: 11px; font-weight: 700;">
35
+ {{ (currentUser.display_name || currentUser.username).charAt(0).toUpperCase() }}
36
+ </div>
37
+ <span style="color: var(--text-secondary); font-size: 12px; font-weight: 500; line-height: 1;">
38
+ {{ currentUser.display_name || currentUser.username }}
39
+ <span style="color: var(--text-muted); font-weight: 400; font-size: 10px; margin-left: 4px;">{{ currentUser.role }}</span>
40
+ </span>
41
+ </div>
42
+ <n-button text size="small" @click="handleLogout" style="color: var(--text-muted); font-size: 11px; margin-left: 4px;">
43
+ 退出
44
+ </n-button>
45
+ </template>
46
+ </n-layout-header>
47
+
48
+ <!-- 主体区域(登录页不渲染侧边栏菜单,避免"点了跳不走"的困惑) -->
49
+ <n-layout v-if="!isLoginPage" position="absolute" style="top: var(--header-height); bottom: 0; background: var(--bg-primary);" has-sider>
50
+ <n-layout-sider bordered :width="220" :collapsed-width="64" show-trigger="bar" style="background: var(--bg-card); border-right: 1px solid var(--border-primary);">
51
+ <n-menu :value="currentRoute" :options="menuOptions" @update:value="onMenuChange" style="background: var(--bg-card); padding-top: 4px;" />
52
+ </n-layout-sider>
53
+ <n-layout style="background: var(--bg-primary);">
54
+ <!-- 页面过渡动画 - 只用透明度,杜绝 out-in 白帧 -->
55
+ <router-view v-slot="{ Component, route: r }">
56
+ <transition name="fade" mode="default">
57
+ <component :is="Component" :key="r.path" />
58
+ </transition>
59
+ </router-view>
60
+ </n-layout>
61
+ </n-layout>
62
+ <!-- 登录页:主体直接渲染登录视图 -->
63
+ <n-layout v-else position="absolute" style="top: 0; bottom: 0; background: var(--bg-primary);">
64
+ <router-view />
65
+ </n-layout>
66
+ </n-layout>
67
+ </n-dialog-provider>
68
+ </n-notification-provider>
69
+ </n-message-provider>
70
+ </n-config-provider>
71
+ </template>
72
+
73
+ <script setup>
74
+ import { ref, computed, h, onMounted, onUnmounted, watch } from 'vue'
75
+ import { useRouter, useRoute } from 'vue-router'
76
+ import { darkTheme, zhCN, dateZhCN, NConfigProvider, useMessage } from 'naive-ui'
77
+ import { useChatStore } from './stores/chat.js'
78
+ import { buildApiUrl } from './utils/http.js'
79
+ import {
80
+ GridOutline,
81
+ ChatbubblesOutline,
82
+ CubeOutline,
83
+ WarningOutline,
84
+ GitNetworkOutline,
85
+ ShieldCheckmarkOutline,
86
+ BugOutline,
87
+ DocumentTextOutline,
88
+ SettingsOutline,
89
+ PeopleOutline,
90
+ } from '@vicons/ionicons5'
91
+
92
+ const router = useRouter()
93
+ const route = useRoute()
94
+ const chatStore = useChatStore()
95
+
96
+ // useMessage 降级(provider 在子组件中)
97
+ let message
98
+ try {
99
+ message = useMessage()
100
+ } catch (e) {
101
+ message = { error: console.warn, success: console.log, warning: console.warn, info: console.log }
102
+ }
103
+
104
+ const isLoginPage = computed(() => route.path === '/login')
105
+ const currentUser = ref(null)
106
+ const userPermissions = ref([])
107
+
108
+ const currentRoute = computed(() => route.path)
109
+
110
+ function loadUser() {
111
+ try {
112
+ const u = localStorage.getItem('secagentx_user')
113
+ if (u) currentUser.value = JSON.parse(u)
114
+ const p = localStorage.getItem('secagentx_permissions')
115
+ if (p) userPermissions.value = JSON.parse(p)
116
+ } catch (e) {
117
+ currentUser.value = null
118
+ }
119
+ }
120
+
121
+ async function fetchPermissions() {
122
+ try {
123
+ const token = localStorage.getItem('secagentx_token')
124
+ if (!token) return
125
+ const resp = await fetch(buildApiUrl('/api/users/me'), {
126
+ headers: { 'Authorization': `Bearer ${token}` }
127
+ })
128
+ if (resp.ok) {
129
+ const data = await resp.json()
130
+ if (data.permissions) {
131
+ userPermissions.value = data.permissions
132
+ localStorage.setItem('secagentx_permissions', JSON.stringify(data.permissions))
133
+ }
134
+ }
135
+ } catch (e) { /* ignore */ }
136
+ }
137
+
138
+ function hasPermission(perm) {
139
+ return userPermissions.value.includes(perm)
140
+ }
141
+
142
+ loadUser()
143
+
144
+ // 设计系统主题 — 复用 tokens.css 变量
145
+ const customTheme = {
146
+ ...darkTheme,
147
+ common: {
148
+ ...darkTheme.common,
149
+ primaryColor: '#dc2626',
150
+ primaryColorHover: '#ef4444',
151
+ primaryColorPressed: '#b91c1c',
152
+ primaryColorSuppl: '#dc2626',
153
+ bodyColor: '#0f1117',
154
+ cardColor: '#171923',
155
+ modalColor: '#171923',
156
+ popoverColor: '#171923',
157
+ tableColor: '#171923',
158
+ borderColor: '#2a2d38',
159
+ dividerColor: '#2a2d38',
160
+ actionColor: '#171923',
161
+ tabColor: '#171923',
162
+ inputColor: '#171923',
163
+ inputColorDisabled: '#171923',
164
+ hoverColor: '#1f2230',
165
+ closeColor: '#64748b',
166
+ closeColorHover: '#e2e8f0',
167
+ textColor1: '#f1f5f9',
168
+ textColor2: '#cbd5e1',
169
+ textColor3: '#94a3b8',
170
+ textColorDisabled: '#64748b',
171
+ placeholderColor: '#475569',
172
+ invertedColor: '#0f1117',
173
+ progressRailColor: '#2a2d38',
174
+ railColor: '#2a2d38',
175
+ fontWeightStrong: '600',
176
+ },
177
+ }
178
+
179
+ // 带 SVG 图标的菜单 — 使用 ionicons5 渲染
180
+ function renderIcon(icon) {
181
+ return () => h(icon, { style: 'width:18px;height:18px;' })
182
+ }
183
+
184
+ const menuOptions = computed(() => {
185
+ const items = [
186
+ { label: '总览', key: '/dashboard', icon: renderIcon(GridOutline) },
187
+ { label: '对话', key: '/', icon: renderIcon(ChatbubblesOutline) },
188
+ { label: 'Agent 状态', key: '/agents', icon: renderIcon(CubeOutline) },
189
+ { label: '事件', key: '/events', icon: renderIcon(WarningOutline) },
190
+ { label: 'ATT&CK 知识库', key: '/knowledge/mitre', icon: renderIcon(GitNetworkOutline) },
191
+ { label: 'OWASP 知识库', key: '/knowledge/owasp', icon: renderIcon(ShieldCheckmarkOutline) },
192
+ { label: 'CVE 漏洞库', key: '/knowledge/cve', icon: renderIcon(BugOutline) },
193
+ { label: '检测规则', key: '/knowledge/rules', icon: renderIcon(DocumentTextOutline) },
194
+ ]
195
+ if (hasPermission('admin:users')) {
196
+ items.push({ label: '系统设置', key: '/settings', icon: renderIcon(SettingsOutline) })
197
+ items.push({ label: '用户管理', key: '/users', icon: renderIcon(PeopleOutline) })
198
+ }
199
+ return items
200
+ })
201
+
202
+ function onMenuChange(key) {
203
+ router.push(key)
204
+ }
205
+
206
+ function handleLogout() {
207
+ chatStore.disconnectWebSocket()
208
+ localStorage.removeItem('secagentx_token')
209
+ localStorage.removeItem('secagentx_user')
210
+ localStorage.removeItem('secagentx_permissions')
211
+ router.push('/login')
212
+ }
213
+
214
+ // 路由变化时管理 WebSocket 生命周期(登录页断连,其他页连接)
215
+ watch(() => route.path, (newPath) => {
216
+ if (newPath === '/login') {
217
+ chatStore.disconnectWebSocket()
218
+ } else {
219
+ chatStore.connectWebSocket()
220
+ }
221
+ })
222
+
223
+ onMounted(() => {
224
+ const token = localStorage.getItem('secagentx_token')
225
+ if (token) { chatStore.connectWebSocket(); fetchPermissions() }
226
+ })
227
+
228
+ onUnmounted(() => {
229
+ chatStore.disconnectWebSocket()
230
+ })
231
+ </script>
@@ -0,0 +1,12 @@
1
+ import { createApp } from 'vue'
2
+ import { createPinia } from 'pinia'
3
+ import naive from 'naive-ui'
4
+ import router from './router/index.js'
5
+ import App from './App.vue'
6
+ import './styles/tokens.css'
7
+
8
+ const app = createApp(App)
9
+ app.use(createPinia())
10
+ app.use(router)
11
+ app.use(naive)
12
+ app.mount('#app')
@@ -0,0 +1,117 @@
1
+ import { createRouter, createWebHistory } from 'vue-router'
2
+
3
+ /**
4
+ * 路由 base — 运行时自适应(与 http.js 前缀逻辑一致)
5
+ *
6
+ * - OpenIM 集成环境:页面挂在 /secagentx/ 下,路由 base 须为 /secagentx/
7
+ * 否则 SPA 跳转会丢失前缀(如变成 /agents),刷新即被 nginx 拦回 OpenIM 首页
8
+ * - FastAPI 直连:base 为 /
9
+ */
10
+ function resolveRouterBase() {
11
+ const injected = import.meta.env && import.meta.env.VITE_BASE_PATH
12
+ if (injected) return injected
13
+ if (typeof window !== 'undefined' && window.location.pathname.startsWith('/secagentx/')) {
14
+ return '/secagentx/'
15
+ }
16
+ return '/'
17
+ }
18
+
19
+ /**
20
+ * 路由守卫:检查是否已登录
21
+ * 未登录时跳转到 /login,并携带目标路径
22
+ */
23
+ function requireAuth(to, from, next) {
24
+ const token = localStorage.getItem('secagentx_token')
25
+ if (to.meta.requiresAuth !== false && !token) {
26
+ next({ path: '/login', query: { redirect: to.fullPath } })
27
+ } else {
28
+ next()
29
+ }
30
+ }
31
+
32
+ const routes = [
33
+ {
34
+ path: '/login',
35
+ name: 'login',
36
+ component: () => import('../views/LoginView.vue'),
37
+ meta: { requiresAuth: false },
38
+ },
39
+ {
40
+ path: '/',
41
+ name: 'chat',
42
+ component: () => import('../views/ChatView.vue'),
43
+ },
44
+ {
45
+ path: '/agents',
46
+ name: 'agents',
47
+ component: () => import('../views/AgentsView.vue'),
48
+ },
49
+ {
50
+ path: '/events',
51
+ name: 'events',
52
+ component: () => import('../views/EventsView.vue'),
53
+ },
54
+ {
55
+ path: '/knowledge',
56
+ name: 'knowledge',
57
+ component: () => import('../views/KnowledgeView.vue'),
58
+ },
59
+ {
60
+ path: '/knowledge/mitre',
61
+ name: 'knowledge-mitre',
62
+ component: () => import('../views/KnowledgeView.vue'),
63
+ },
64
+ {
65
+ path: '/knowledge/owasp',
66
+ name: 'knowledge-owasp',
67
+ component: () => import('../views/KnowledgeView.vue'),
68
+ },
69
+ {
70
+ path: '/knowledge/cve',
71
+ name: 'knowledge-cve',
72
+ component: () => import('../views/KnowledgeView.vue'),
73
+ },
74
+ {
75
+ path: '/knowledge/rules',
76
+ name: 'knowledge-rules',
77
+ component: () => import('../views/KnowledgeView.vue'),
78
+ },
79
+ {
80
+ path: '/attack-chain',
81
+ name: 'attack-chain',
82
+ component: () => import('../views/AttackChainView.vue'),
83
+ },
84
+ {
85
+ path: '/dashboard',
86
+ name: 'dashboard',
87
+ component: () => import('../views/DashboardView.vue'),
88
+ },
89
+ {
90
+ path: '/events/:id',
91
+ name: 'event-detail',
92
+ component: () => import('../views/EventDetailView.vue'),
93
+ props: true,
94
+ },
95
+ {
96
+ path: '/users',
97
+ name: 'users',
98
+ component: () => import('../views/UsersView.vue'),
99
+ meta: { requiresAuth: true },
100
+ },
101
+ {
102
+ path: '/settings',
103
+ name: 'settings',
104
+ component: () => import('../views/SettingsView.vue'),
105
+ meta: { requiresAuth: true },
106
+ },
107
+ ]
108
+
109
+ const router = createRouter({
110
+ history: createWebHistory(resolveRouterBase()),
111
+ routes,
112
+ })
113
+
114
+ // 注册全局路由守卫
115
+ router.beforeEach(requireAuth)
116
+
117
+ export default router