ChandanaNandi/neuronoc-network-ops-assistant

GitHub: ChandanaNandi/neuronoc-network-ops-assistant

NeuroNOC 是一个安全优先的 AI 辅助网络操作台,用于异常检测、根因分析和修复计划。

Stars: 0 | Forks: 0

# 神经NOC [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/69f96391dd022400.svg)](https://github.com/ChandanaNandi/neuronoc-network-ops-assistant/actions/workflows/ci.yml) NeuroNOC 是一个开源的 AI 辅助网络操作操作台:它从真实实验室(或合成模拟器)收集只读信号,使用确定性规则检测异常,运行多步骤 LangGraph 工作流程来组装事件分析,生成可选的本地 LLM 根因解释,起草结构化修复计划,并在经过身份验证的基于角色的管理员访问权限后进行审批。**永远不会执行修复。** 作为一个 AI-NetOps 思维的组合规模演示:由人参与的闭环,在确定性重要时使用确定性,在值得时使用 LLM,并且明确区分“这是真实实验室数据”和“这是为演示目的而编造的”。 ## 解决了什么问题 NetOps 团队通常盲目行动:遥测数据嘈杂,根本原因隐藏在三层症状之下,对“WAN 边缘 BGP 会话刚刚抖动”的响应通常是缓慢的人类页面线程,因为没有足够信任的自动化工具可以采取行动。NeuroNOC 探索了当整个堆栈从模式开始**以安全第一的原则构建**时,一个小的、有偏见的 NetOps 协作者看起来像什么: - 每个计划在数据库级别都是 `requires_approval=True`。 - 审批绑定到真实的经过身份验证的 `admin` 会话,而不是一个自由文本名称字段。 - 不允许 `app/remediation/`、`app/api/remediation.py`、`app/validation/` 或 `app/telemetry/` 下的任何模块 `import` 远程执行库——如果发生这种情况,AST 扫描会失败构建。 - FRR 实验室收集器只运行 `show *` 命令,只针对允许列表中的容器名称集,并拒绝任何包含 `clear` / `conf t` / `reload` / `delete` / `write` / 等等的 vtysh 调用。 该系统还不是生产 NetOps 工具。它是一个工作组合作品,展示了架构、安全合同以及确定性-LLM 混合代理流端到端在真实(FRR Compose)实验室上的实现。 ## 安全第一原则 每个阶段都保持相同的护栏: 1. **代码中不存在执行路径。** 修复计划器只生成计划;验证预览省略 `proposed_commands` / `proposed_ansible_playbook` 以免被误认为是可操作的工件;实验室收集器只运行 `show` 命令,并针对允许列表中的容器集运行。 2. **审批是经过身份验证和基于角色的。** `POST /api/remediation/recommendations/{id}/approve` 在没有 bearer 令牌时返回 401,在没有 `role=admin` 时返回 403。审计行的 `approved_by` / `approved_by_operator_id` 从会话中获取,而不是从请求体中获取。 3. **AST 安全扫描在 CI 中运行。** 任何在受保护包内部导入 `subprocess` / `paramiko` / `netmiko` / `napalm` / `ansible_runner` / `pysnmp` / `socket` / 等等的操作都会导致构建失败。 4. **Ansible 草稿在 `when: false` 上为每个危险任务设置门控**,加上 `REQUIRES APPROVED CHANGE WINDOW` 注释,因此即使有人手动提取它,文件也无法直接运行。 5. **本地 LLM。** RCA 使用本地 Ollama 或确定性回退;在任何阶段都没有添加云 LLM 依赖。 ## 真实实验室数据与模拟/演示数据 NeuroNOC 携带两个并行数据源。它们都填充相同的 `incidents` / `incident_events` / `incident_evidence` 模式,因此下游代理 / RCA / 计划链以统一的方式处理它们。**它们的来源始终标记在 `summary` 上。** | 来源 | 标签前缀 | 它是什么 | 来自哪里 | |---|---|---|---| | 模拟器(阶段 3) | `[simulator]` | 5 个手写的场景(BGP 下降、接口错误、延迟峰值、路由丢失、ACL 阻塞) | `python -m app.simulator.seed --scenario all` —纯确定性数据 | | FRR 实验室收集器(阶段 8C / 21A / 21E) | `[lab-collector]` | 4 路由 FRR Compose 实验室的只读快照:BGP 状态 + 接口计数器/状态 + 路由表 + 运行配置 | `POST /api/lab/collect/snapshot` —运行 `docker exec` + `vtysh -c "show ..."` 对实验室 | | 手动遥测观察(阶段 22A/B) | 导出 | 操作员提交的(或测试馈送)`TelemetryEvent` 有效负载持久化到 `telemetry_observations`,并可选地关联到事件 | `POST /api/telemetry/observations` + `POST /api/telemetry/observations/{id}/correlate` | **阶段 21E 后真实实验室异常覆盖率:** 8 个规则中有 4 个从真实实验室数据中触发(R001 `bgp_neighbor_down_detected`、R003 `interface_error_spike_detected`、R007 `route_missing_detected`、R008 `link_down_detected`)。其余 4 个规则(R002 路由撤回、R004 数据包丢失、R005 延迟峰值、R006 ACL 否决)仅限于模拟器——FRR 实验室不产生这些信号。 ## 架构 ``` flowchart LR subgraph Console["React + TypeScript operator console (Vite)"] UI[Incident list + detail
Anomaly findings • events • evidence
Agent run inspector
RCA + runbook search
Plan cards + validation preview] LoginUI[Login panel
+ Operator management] TelemUI[Telemetry preview panel
5 fixtures · download · keyboard a11y] end subgraph Backend["FastAPI backend (Python 3.12, uv)"] AuthAPI[Auth API
PBKDF2-SHA256 + bearer tokens] IncidentsAPI[Incidents / events / evidence] AnomalyEngine[Anomaly engine
8 deterministic rules R001-R008] AgentWF[LangGraph workflow
6 deterministic nodes] RCAExp[RCA explainer
+ RAG citations] VectorRAG[Runbook RAG
Sentence Transformers-ready embeddings
FAISS vector search] Planner[Remediation planner
6 templates · plan-only] ValidationAPI[Validation preview API
pre/post checks, rollback, safety notes] TelemetryAPI[Telemetry observations API
persist · list · correlate] LabAPI[Lab snapshot collector API
BGP + interfaces + routes + config] end subgraph DataPlane["Data plane"] PG[(Postgres 16)] Ollama[Local Ollama
qwen2.5:7b-instruct
optional] Lab[FRR v8.4.1 Compose lab
edge-1 · edge-2 · core-1 · branch-1
eBGP fully Established] end Console -- HTTP/JSON via Vite proxy --> Backend AuthAPI --> PG IncidentsAPI --> PG AgentWF --> PG Planner --> PG TelemetryAPI --> PG LabAPI --> PG AnomalyEngine -. reads .-> PG RCAExp -. reads .-> PG RCAExp -. retrieves .-> VectorRAG ValidationAPI -. reads .-> PG RCAExp -. optional .-> Ollama LabAPI -- docker exec + vtysh
show * read-only --> Lab AuthGate{{Admin approval gate
401 unauth · 403 non-admin}} Planner --> AuthGate AuthAPI --> AuthGate AuthGate -- intent only
never executes --> PG ``` ## 主要用户流程 ``` Inject lab fault → Collect lab snapshot → Inspect findings (lab.sh inject ...) (one click in console) (anomaly + events + evidence) ↓ ↓ Approve / reject as admin ← Generate remediation plan ← Generate RCA + cited RAG context (bearer-token + role=admin) (plan-only · requires_approval) (Ollama or deterministic fallback) ``` 每一步都是一次控制台按钮点击;底层 API 响应存储在 Postgres 中,并重新渲染右侧详细窗格。没有后台作业,没有调度程序——每个动作都是显式的操作员请求。 ## 演示说明 针对已播种的模拟器场景的本地运行捕获。每一步都是针对实时 FastAPI 后端的真实按钮点击;没有数据是模拟的。 ### 1. 控制台仪表板 ![控制台仪表板](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/f61e3e258a022401.png) 后端在线 · 播种 5 个事件 · 8 个活跃的异常发现 · 以 `local-operator [admin]` 登录。状态网格、登录面板、操作员面板、运行手册搜索、遥测预览标题和完整的事件列表——全部在一个框架中。 ### 2. BGP 事件——异常发现 ![BGP 事件发现](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/528f9c74f5022402.png) BGP `Established → Idle` 场景触发 3 个确定性异常规则:**R001** `bgp_neighbor_down_detected`、**R002** `route_withdrawal_detected`、**R007** `route_missing_detected`。每个发现都包含严重性、置信度、特定的下一步推荐和引用到原始事件/证据。 ### 3. BGP 事件——原始事件 ![BGP 事件](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/604b561306022403.png) 触发那些发现的 3 个事件行:`route_withdrawal`、`bgp_state_change`、`reachability_loss`。每个事件都带有时戳、归因于其源设备,并携带一个结构化的 JSONB `payload`,代理工作流程会消费它。 ### 4. 代理运行检查器 ![代理运行检查器](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/a7b4cb3970022403.png) 6 节点 LangGraph 工作流程(`load_incident → anomaly_detection → evidence_summary → correlation → validation → report`)在 78 毫秒内完成,每一步的审计都可见。显示了两个运行——检查器支持将连续运行与同一事件进行比较。 ### 5. 最终代理报告(步骤有效负载) ![最终代理报告](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/c8cfbf504f022408.png) 展开 `report` 步骤会显示合成的 `IncidentAnalysisReport` JSON:`suspected_root_cause`、`key_findings`(3 个)、`correlated_signals`、`validation_summary`、`recommended_next_steps`、`requires_human_review: true`。每个步骤的输入+输出都持久化为 JSONB 以供回放和审计。 ### 6. RCA 解释(本地 Ollama) ![RCA 解释](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/02b148177a022409.png) 在第 6 阶段运行针对本地 Ollama(`qwen2.5:7b-instruct`)的 RCA 解释器(当 Ollama 不可达时,确定性回退启动)。输出被限制在 `RCAExplanation` 模式——摘要、可能的原因、推荐的下一步——并且基于事件证据和运行手册片段。 ### 7. 修复计划(草案、已批准) ![修复计划](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/f29f146787022410.png) 根据异常关联自动选择 `bgp_neighbor_recovery` 模板计划。完整的计划以结构化 JSON 的形式发送,带有 `requires_approval: true`、预/后检查、`proposed_commands` 在 `# REQUIRES APPROVAL` 注释后面进行门控,以及一个 Ansible 草案,其中危险任务设置为 `when: false`。此卡片已批准——顶部绿色 `APPROVED` 徽章 + 审计行 `approved by local-operator at …`。**没有执行任何操作。** ### 8. 验证预览(安全射击) ![验证预览](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/4859b6e94b022410.png) 区分屏幕。与 #7 相同的计划 id,但故意更窄的 API 响应:`source: remediation_plan · executable: false`。渲染预检查、后检查、验证标准、回滚步骤和安全注释仅此而已——`proposed_commands` 和 Ansible 草案**故意省略**,因此此视图不会被视为可操作的工件。整个 NeuroNOC 安全论点都在一个屏幕上。 ## 当前功能集 | 阶段 | 表面 | 它做什么 | |---|---|---| | 1–2 | 后端 / Postgres | FastAPI + SQLAlchemy 2 + Alembic;`devices` / `incidents` / `incident_events` / `incident_evidence` / `recommendations` 表 | | 3 | 模拟器 | 5 个确定性场景;CLI + API;外科手术 `--reset` | | 4 | 异常引擎 | 8 个确定性规则(R001–R008),没有机器学习 | | 5 | 代理工作流程 | LangGraph 1.x StateGraph,6 个节点,每一步审计在 `agent_runs` / `agent_steps` 中 | | 6 | RCA | 可选的本地 Ollama (`qwen2.5:7b-instruct`);当 Ollama 不可达时,确定性回退 | | 7 | 修复 | 仅计划,6 个模板,AST 扫描阻止执行库导入 | | 8B/8C | FRR 实验室 + 收集器 | 4 路由 Compose 实验室 + 只读 `docker exec` + vtysh 收集器 | | 9A–9C | 操作员控制台 | React + TS 主/详细,操作按钮,演示流程文档 | | 10A/10B | 审批工作流程 | `approval_status` + 审计列,内联审批表单 | | 11A | 监视循环 | 有限的开发专用 `--watch --iterations N`(≤100,≤3600 秒) | | 12A | Playwright e2e | 针对真实后端 + 真实 Postgres + 真实 Vite 代理的 Chromium 烟雾测试 | | 13A/13B | 操作员 | `operators` 表 + 创建/列出操作员的 UI 面板 | | 14A/14B | CI | GitHub Actions(后端/前端/e2e 作业)+ Playwright 失败跟踪 | | 15A/15B | 代理检查器 | 步骤运行检查器,持续时间,有效负载形状芯片,复制报告 | | 16A/16B | 验证预览 | `GET /api/validation/recommendations/{id}/preview`;UI 块;故意省略命令 | | 17A/17B | 运行手册搜索 | 对捆绑的 Markdown 运行手册进行确定性关键字检索;UI 面板 | | 18A–20B | 遥测预览 | `TelemetryEvent` 模式,验证 + 关联端点(尚未持久化),带有 5 个固定值的 UI 面板,干净的 JSON 导出 | | 21A | 实验室快照收集器 | 伞形 `POST /api/lab/collect/snapshot`:BGP + 接口 + 运行配置 | | 21B | 演示路径 e2e | 端到端测试将实验室快照 → 代理 → RCA → 计划链 | | 21C | 实验室 → 异常 | 实验室事件馈送 R001 / R003 / R008 → 计划器选择特定模板 | | 21D | 实验室故障注入 | `lab.sh inject bgp-down ` / `lab.sh inject iface-down ` + 烟雾测试 | | 21E | 路由表快照 | 实验室收集器读取 `show ip route json`,发出 `lab_route_missing` → R007 | | 22A | 遥测持久化 | `telemetry_observations` 表 + 持久化/获取端点 | | 22B | 遥测 → 事件 | `POST /api/telemetry/observationsid}/correlate` — 确定性、幂等、按需 | | 23 | 身份验证 + RBAC | PBKDF2-SHA256 密码,bearer 令牌会话,基于角色的审批(仅限管理员) | | 24 | 打包 + 文档 | 此 README、演示清单、路线图状态摘要 | | 25 | 运行手册 RAG | Markdown 运行手册分块,使用 FAISS 的嵌入搜索、RCA 引用和检索评估集 | ## 先决条件 - macOS 或 Linux - Docker Desktop(或 Docker Engine + Compose v2) - Python 3.12 和 [uv](https://docs.astral.sh/uv/) - Node 20+ 和 pnpm 10+ - *(可选,用于实时 RCA)* 主机端口 11434 上的 Ollama,已拉取 `qwen2.5:7b-instruct` - *(可选,用于实验室演示)* 缓存在本地 `frrouting/frr:v8.4.1` 映像 ## 本地运行 ### 1. 启动 Postgres ``` docker compose up -d postgres ``` Postgres 监听 `localhost:5433`。开发凭据:`neuronoc / neuronoc_dev_password / neuronoc`。 ### 2. 后端 ``` cd backend uv sync uv run alembic upgrade head # idempotent; current head: 466922adacef (Phase 23) uv run uvicorn app.main:app --host 127.0.0.1 --port 8000 ``` 交互式 API 文档:`http://127.0.0.1:8000/docs`。 ### 3. 播种模拟器数据 + 演示管理员操作员 ``` cd backend uv run python -m app.simulator.seed --reset uv run python -m app.simulator.seed --scenario all uv run python -m app.operators.seed --name local-operator --role admin --password demo-password ``` 种子 CLI 是幂等的——重新运行带有 `--password` 会旋转现有行的哈希。 ### 4. 前端 ``` cd frontend pnpm install pnpm dev ``` 打开 `http://localhost:5173`。Vite 开发服务器代理 `/api/*` 和 `/health` 到 `http://127.0.0.1:8000`,因此不需要 CORS 设置。 ### 5. (可选)启动 FRR 实验室以进行真实数据演示路径 ``` ./infra/lab/scripts/lab.sh up ./infra/lab/scripts/lab.sh bgp all # every session should be Established ``` ## 运行测试 ### 后端 ``` cd backend uv run pytest -q ``` 截至阶段 23,有 268 个测试。每个测试都在一个 savepoint 中运行,在 teardown 时回滚,因此开发数据库保持干净。需要 Postgres 在 `localhost:5433` 上运行。 ### 前端构建(类型检查 + 打包) ``` cd frontend pnpm build # tsc -b && vite build under strict TypeScript ``` ### Playwright e2e(真实后端 + 真实 Postgres + 真实 Vite) ``` cd frontend pnpm exec playwright install chromium # one-time, ~100 MB pnpm test:e2e # headless pnpm test:e2e:headed # watch in a real window ``` 25 个测试,串行,单个工作器,`retries: 0`。工具箱通过 Playwright 的 `webServer` 配置自动启动两个开发服务器。`globalSetup` 重置 + 重新播种模拟器和播种 `local-operator`(使用阶段 23 演示密码);`globalTeardown` 重置模拟器数据,以便开发数据库保持原样。 ### 实验室辅助烟雾(无需 Docker) ``` ./infra/lab/scripts/test_lab.sh ``` 33 个断言在 <1 秒内。假 `docker`-on-PATH 捕获 `lab.sh inject` / `heal` 发射的精确 vtysh / `ip link` 命令字符串。 ### CI(GitHub Actions) `.github/workflows/ci.yml` 在每次推送和 PR 对 Postgres 16 服务容器的推送和 PR 上并行运行后端/前端/e2e 作业。FRR 实验室和 Ollama 在 CI 中不运行(Docker-in-Docker / 无 GPU);e2e RCA 测试接受实时模型行或确定性回退,因此门控始终为绿色。 ## 演示清单(招聘人员面向的说明) 从头到尾运行此清单进行实时演示。每一步都是一条命令或一个点击。 ``` [ ] 1. Start Postgres docker compose up -d postgres [ ] 2. Apply schema + seed simulator + seed the admin operator cd backend uv run alembic upgrade head uv run python -m app.simulator.seed --reset uv run python -m app.simulator.seed --scenario all uv run python -m app.operators.seed --name local-operator --role admin --password demo-password [ ] 3. Start the backend (terminal A) cd backend && uv run uvicorn app.main:app --host 127.0.0.1 --port 8000 [ ] 4. Start the frontend (terminal B) cd frontend && pnpm dev # Open http://localhost:5173 [ ] 5. Start the FRR lab (terminal C) ./infra/lab/scripts/lab.sh up ./infra/lab/scripts/lab.sh bgp all # confirm Established baseline [ ] 6. Inject a real lab fault ./infra/lab/scripts/lab.sh inject bgp-down edge-1 # (or, richer mixed-fault: lab.sh inject iface-down edge-1 eth0) [ ] 7. In the operator console header, click "Collect lab snapshot" → A new Incident appears tagged [lab-collector], incident_type=lab_full_snapshot, severity=medium (or higher). [ ] 8. Click that Incident in the list. The detail pane should show: - Anomaly findings: bgp_neighbor_down_detected (R001), plus link_down_detected (R008) if you injected iface-down. - Events: lab_bgp_peer_not_established, lab_interface_status, and any lab_route_missing if route-table coverage triggered. - Evidence: per-router running_config_snapshot and route_table_snapshot rows. [ ] 9. Click "Run agent analysis" → Phase 5 LangGraph runs 6 deterministic nodes; new agent-run card lists every step; expand any one to see input/output payloads in the inspector. [ ] 10. Click "Generate RCA" → If Ollama is up: "RCA via qwen2.5:7b-instruct". → If not: "RCA (deterministic fallback)". Either is fine. The RCA section persists across re-renders (Phase 9A polish). [ ] 11. Click "Generate remediation plan" → A plan card appears with risk badge + plan_type (specific template, NOT generic_investigation, because Phase 21C maps lab events to specific findings). → Click "Preview validation": only pre-checks / post-checks / validation criteria / rollback steps / safety notes render. proposed_commands and proposed_ansible_playbook are intentionally absent — the response can't be mistaken for an executable artifact. [ ] 12. In the Login panel, log in display_name: local-operator password: demo-password → "Logged in as local-operator [admin]". [ ] 13. Back on the plan card, click "Approve" (or "Reject"). Confirm. The badge flips to approved/rejected; the audit line shows the authenticated operator's display_name + role + timestamp + note. → Backend recorded the approval intent. → Nothing was executed. There is no execution path in code. [ ] 14. (Optional) Show the safety contracts directly cd backend uv run pytest -q tests/test_remediation.py::test_remediation_package_blocks_execution_library_imports uv run pytest -q tests/test_telemetry.py::test_telemetry_package_blocks_network_and_execution_imports [ ] 15. Heal the lab ./infra/lab/scripts/lab.sh heal bgp-down edge-1 sleep 35 # let BGP hold-timer reconverge ./infra/lab/scripts/lab.sh bgp all # back to Established [ ] 16. Tear down ./infra/lab/scripts/lab.sh down cd backend && uv run python -m app.simulator.seed --reset # Ctrl-C the dev servers; docker compose stop postgres if desired. ``` ## 已知限制 - **没有连续遥测管道。** 阶段 8C / 21A 收集器是由 API 调用(或有限的 `--watch` 循环)触发的单次抓取器。没有守护程序,没有调度程序,没有流式传输,没有 SNMP 捕获陷阱监听器,没有 syslog UDP 接收器。 - **没有修复执行。** 按设计,并由 AST 扫描固定。审批仅是意图。 - **本地开发身份验证。** 阶段 23 使用 PBKDF2-SHA256 + 存储在前端 `localStorage` 中的 bearer 令牌。生产应交换为真实的 IdP(SSO / SAML / OAuth)并将令牌移动到 HttpOnly cookie 后面。 - **没有多租户。** 一个操作员池,一个事件命名空间,
标签:AST扫描, DNS解析, Docker 部署, LLM, Unmanaged PE, XML 请求, 人工智能, 代码审查, 修复计划, 基于角色的访问控制, 多代理系统, 安全优先, 安全开发, 安全架构, 实验室数据, 开源项目, 异常检测, 故障排除, 测试用例, 用户模式Hook绕过, 管理员审批, 网络运维, 请求拦截, 逆向工具