人工智能AI Agent网络安全后端前端【免费下载链接】AiSOCOpen-source AI Security Operations Center: alert fusion, LLM-agent triage, MITRE ATTCK investigation, and a replayable decision ledger for every agent step. Self-hostable, runs with no API keys, MIT licensed. Ships an MCP server for Claude, Cursor and Continue.项目地址https://gitcode.com/GitHub_Trending/ai/AiSOC点击查看免费下载本文围绕 AiSOC 的 AI 资产发现AI estate discovery能力展开说明它如何在不新增端点代理的前提下通过 AI 运行时遥测、端点遥测和模型供应商审计日志三条路径把 AI 应用、编码代理、MCP 服务器、IDE 扩展、供应商密钥和 OAuth 授权记录进aisoc_ai_assets表。读完之后你将能够判断每条来源能看见什么、永远看不见什么独立部署aisoc-ai-estateosquery pack并读懂清单页面上一行资产背后的写入链路、风险评分和权限模型。核心设计前提观测值而非声明值AiSOC 的 AI 清单完全建立在已经在采集的遥测之上不需要部署新 agent。三个发现路径分别是你可能已经在路由 AI 流量的 SDK 或网关ai_gateway连接器、packages/aisoc-ai-sdk机群已经在运行的端点 agentFleetDM、osctrl、auditd、Windows 事件转发模型供应商自己的审计日志llm_usage连接器以及 Workspace / Entra 审计流。清单在控制台中位于AI Estate页面落地存储在aisoc_ai_assets表中。它记录的是 AiSOC观测到的事实这与/api/v1/mcp-servers记录运维人员声明的事实刻意区分开。实现上这是一个独立的表services/api/migrations/110_ai_assets.sql 在文件头明确写着aisoc_mcp_servers迁移 069是声明、本表是观测有意思的那一行是存在于本表而不存在于那张表的行。这句话在 AI 治理评审中有直接的操作含义一个没人注册、跑在某台笔记本上、手里还握着供应商密钥的编码代理正是这套清单存在的理由。也正因如此接口层没有提供创建资产的路由——services/api/app/api/v1/endpoints/ai_assets.py 的模块文档说明如果清单可以手工录入它就不再回答有哪些东西在运行而没人告诉我们这个问题要声明请走/api/v1/mcp-servers。每条来源能看见什么、看不见什么这是规划覆盖面之前最值得读的部分。三条来源看到的是真正不同的东西而且盲区并不对称。因此清单页面上某一列空白可能意味着没有人对此负责也可能意味着这条来源从来就无法提供这个信息——只有前者才算一个发现。AI 运行时遥测连接器ai_gateway连接器以及packages/aisoc-ai-sdk投递到ai-runtime/ai-findinginbox 模板的数据。能看见看不见代理的身份与名称设备——除非应用自己上报了 hostname模型与供应商任何未插桩、也不经过网关的代理调用了哪些工具、作用于哪些资源从未调用过模型的进程代理所代理的那个人若存在提示词包含哪些密钥形态而提示词本身从未离开进程表格最后一行的实现依据在 ingest 侧模板里services/ingest/internal/normalizer/templates/ai-runtime.yaml 把prompt_secret_kinds映射到finding.evidence.prompt_secret_kinds并在注释中说明 SDK 在本地计算形态、只发送提示词摘要因此即便在默认的哈希捕获模式下凭证进入提示词的检测依然可用。同一份模板还解释了class_uid: 6003API Activity的选择类别 6 不属于 Findings所以should_promote()要求severity_id 4日常活动留在 ClickHouse 湖里供狩猎使用而护栏违规走ai-finding.yaml类别 2必定提升为告警。端点遥测连接器fleetdm、osctrl、auditd、windows_event。能看见看不见设备调用的是哪个模型二进制及其完整命令行调用了哪些工具代理是否在启动时关闭了权限确认提示词内容MCP 客户端配置文件——服务器被接入的证据任何没有端点 agent 的机器上运行的代理AI IDE 扩展目录含发布者与版本躺在笔记本上的模型供应商凭证文件:::caution EDR 连接器并不提供这些数据crowdstrike、sentinelone、azure_defender轮询的是厂商自己的检测结果不是原始进程遥测。crowdstrike.py读取/detects/queries/detects/v1返回的是判定结论。因此它们被归类为 OCSF Security Findings无法提供进程启动事件。端点发现因此只能来自 osquery经由 FleetDM 或 osctrl、Linux 上的auditd以及 Windows 事件转发。如果你只跑 EDR这一半清单会是空的——那是一个覆盖缺口而不是一片安静的资产面。 :::供应商与目录审计日志连接器llm_usage以及 Workspace / Entra 的审计流。能看见看不见供应商账号与组织任何设备永远谁签发或使用了 API Key是哪个应用使用了该 Key角色、日志与 MFA 变更在受审计组织之外签发的密钥哪个 AI 应用被授予了 OAuth 访问权及其 scope该应用拿到授权后做了什么这三张表在代码里也有一份结构化镜像services/fusion/app/services/ai_asset_recorder.py 中的SOURCE_CAPABILITIES以SourceCapability(sees, cannot_see, connectors)的形式保存了同样的语义并在 docstring 里点明为什么要写看不见这一半——只列能看见什么的表格读起来像完整覆盖而分析师面对空列时真正需要的恰是盲区说明。osquery pack端点侧的五个查询packs/aisoc-ai-estate.yaml 是端点侧的一半。可以像其他 pack 一样分配给租户也可以直接渲染后导入GET /api/v1/osquery/packs/aisoc-ai-estate/render?formatosctrl GET /api/v1/osquery/packs/aisoc-ai-estate/render?formatfleetdm这两个路由由 osquery TLS 服务提供services/osquery-tls/app/api/v1/endpoints/packs.py 中的render_pack接受format参数支持osquery-json、osctrl、fleetdm三种取值分别返回to_osquery_json()、to_osctrl_format()、to_fleetdm_format()的结果见 services/osquery-tls/app/services/pack_loader.py。路由前缀/api/v1/osquery定义在 services/osquery-tls/app/api/v1/init.py。pack 内含五个查询查询间隔回答的问题coding_agent_processes5 分钟哪些编码代理正在运行命令行是什么mcp_server_processes5 分钟哪些本地 MCP 服务器正在运行mcp_client_configurations1 小时配置了哪些 MCP 客户端配置在何处ai_ide_extensions1 小时装了哪些 AI 助手扩展版本是多少provider_key_files1 小时这台笔记本上是否存在模型供应商凭证材料进程查询的 SQL 与显式名单coding_agent_processes: sql: SELECT p.name AS name, p.path AS path, p.cmdline AS cmdline, p.uid AS uid, p.start_time AS start_time, u.username AS username FROM processes p LEFT JOIN users u ON p.uid u.uid WHERE p.name IN ( claude, codex, aider, goose, continue, opencode, gemini, copilot, copilot-language-server, amazonq, cline, claude.exe, codex.exe, aider.exe, gemini.exe, cline.exe ) interval: 300 severity: info mitre: [T1059]MCP 服务器查询则用前缀匹配而非包含匹配mcp_server_processes: sql: SELECT p.name AS name, p.path AS path, p.cmdline AS cmdline, p.uid AS uid, p.start_time AS start_time, u.username AS username FROM processes p LEFT JOIN users u ON p.uid u.uid WHERE p.name LIKE mcp-server%% OR p.name LIKE mcp_server%% OR p.name LIKE mcp-proxy%%文件类查询mcp_client_configurations只SELECT path, directory, filename, uid, mtime, size FROM file覆盖 Claude Desktop、Claude Code、Cursor、Windsurf、VS Code、Continue、Amazon Q、Gemini CLI、Codex CLI 等客户端各自公布的配置路径ai_ide_extensions在.vscode/、.vscode-insiders/、.cursor/、.windsurf/的扩展目录里按命名发布者集合过滤provider_key_files只匹配~/.config/anthropic/%%、~/.openai/%%、~/.config/gcloud/application_default_credentials.json这类路径并且同样只取元数据。三个设计取舍而不是疏漏进程名是一份显式名单不是模式匹配。一句LIKE %agent%会命中半个 EDR 机群而这里的一次误报会把某人的杀毒软件送上安全评审。代价是名单之外的代理对进程查询不可见——不过它仍可能通过 SDK 路径出现如果是编辑器扩展也会被扩展查询捕获。配置文件的内容永不采集。一份 MCP 配置经常携带第三方服务器的 bearer token。文件的存在、路径和 mtime 就是证据清单没有理由持有凭证。每个查询的 severity 都是info。发现某位开发者运行编码代理属于资产盘点而不是一个发现。真正让一行变得有意思的是清单从这一行计算出来的风险——无人负责、权限确认被关闭、来源未经审查——而这个判断只存在一处不被复制进 pack。pack 文件头的注释还给出了一个容易被忽略的工程约束结果经由 fleetdm / osctrl 连接器与 fusion recorder 落进aisoc_ai_assetsrecorder 依据这里选出的列name、path、cmdline、directory对每一行分类悄悄修改被选中的列名会静默破坏分类。因此这些查询刻意多选了 recorder 要读的列而不是只选 osquery 必需的最小集合。让查询真正下发pack 的加载与下发由 osquery TLS 服务负责。pack_loader从repo_root/packs/读取所有 YAML可用AISOC_PACKS_DIR覆盖缓存 TTL 由AISOC_PACKS_CACHE_TTL控制默认 300 秒pack_resolver在租户没有显式分配时回落到默认 pack 集合_DEFAULT_PACK_IDS: list[str] [ aisoc-fim-baseline, aisoc-inventory-baseline, ]这意味着aisoc-ai-estate不在默认集合里需要显式分配。分配接口是POST /api/v1/osquery/tenants/{tenant_id}/packs请求体为{pack_id: aisoc-ai-estate, enabled: true}该接口会先校验 pack 是否存在于目录中再按(tenant_id, pack_id)做 upsert且租户 ID 会与调用者凭证做交叉校验scoped_tenant_or_403。合并进 osquery TLS 配置时查询名会加上{pack_id}__前缀避免多 pack 合并时的名称冲突。另外注意 packs/aisoc-ai-estate.yaml 末尾的file_paths段只列出了 MCP 配置与扩展目录的一个子集其中%%按 packs/README.md 的定义是递归 glob。若你希望 FIM 也覆盖其余客户端需要自行补齐该段。一行资产如何被链接到人和设备每条来源贡献它拥有的那部分而且后一次观测永远不会抹掉前一次学到的内容人来自运行时遥测的actor.user.name、端点事件的操作用户或供应商审计记录中的账号。设备来自端点主机名。运行时遥测只有在被插桩应用主动上报时才提供供应商审计日志则永远不会提供。权限是最近一次观测时有效权限解析器为所链接用户返回结果的快照而不是 join——这样后续的权限变更不会改写历史。当某条来源没有提供链接时控制台会以发现的颜色渲染not learned而不是留一个空白单元格并在 tooltip 里写明该来源对此是盲的。没有任何人负责的资产正是这套清单要暴露出来的那一行。这三点在数据库层的落地方式是CONSTRAINT aisoc_ai_assets_identity UNIQUE NULLS NOT DISTINCT (tenant_id, kind, external_id, device)迁移注释解释了NULLS NOT DISTINCT为什么是承重的在默认语义下 NULL 不等于 NULL于是每一次供应商密钥的观测它没有设备都会插入新行而不是更新旧行清单将按事件数无限增长同时first_seen_at每次都被重置。同一处注释指出这个环境需要 PostgreSQL 15 及以上仓库固定使用 16。观测写入使用ON CONFLICT上的LEAST/GREATESTfirst_seen_at LEAST(aisoc_ai_assets.first_seen_at, EXCLUDED.first_seen_at), last_seen_at GREATEST(aisoc_ai_assets.last_seen_at, EXCLUDED.last_seen_at), observation_count aisoc_ai_assets.observation_count EXCLUDED.observation_count, principal COALESCE(EXCLUDED.principal, aisoc_ai_assets.principal), attributes aisoc_ai_assets.attributes || EXCLUDED.attributes,注释写得很直白重放的 Kafka 批次或迟到的 span不能把first_seen_at往前推因为那会擦掉清单存在的首要事实而后一次没有学到人的观测也不能抹掉前一次学到的。写入链路recorder 如何把事件变成资产services/fusion/app/services/ai_asset_recorder.py 是aisoc_ai_assets的写入方。它挂在 fusion 消费者的原始事件分支上——模块文档解释了原因这是默认 profile 下每一个规范化事件都会经过的路径如果把 recorder 放在开关后面或放在 CORE 不启动的服务里就会得到一张没人写的表和一个对明明有 AI 资产的租户显示『没有 AI 资产』的控制台页面。按 ingest 打的戳分流而不是猜字段classify()是纯函数便于用厂商形状的载荷测试if source_type in (ai-runtime, ai-finding, AI Runtime, AI Guardrail): out.extend(_from_ai_telemetry(tenant_id, ocsf, now)) elif source_type in (llm_usage, AI / LLM Usage Audit): out.extend(_from_provider_audit(tenant_id, ocsf, now)) elif ocsf.get(class_uid) 1007: out.extend(_from_endpoint(tenant_id, ocsf, now))三条分支恰好对应文档里的三条来源AI 运行时 / 网关遥测、供应商审计、以及携带已知编码代理或 MCP 服务器二进制的 OCSF Process Activityclass 1007。每行都记录是哪条来源看见它的因为分析师看到一条没有设备的资产时需要区分链接缺失和这条来源根本不可能提供。端点分支为什么不能读process.name这是最容易踩的坑。services/ingest把连接器自己的规范化字典以JSON 字符串形式放在ocsf[raw_data]下而 OCSF 规范字段映射只携带title、external_id和身份别名别无其他。因此_connector_fields()必须把那个命名空间还原出来raw ocsf.get(raw_data) if isinstance(raw, str) and raw.strip(): parsed json.loads(raw) # 解析失败则返回 {}同一段注释记录了这一处曾经的真实缺陷早期版本读process.name对fleetdm、osctrl、auditd、windows_event全部返回None——也就是本产品所有的端点来源——端点发现永远产不出一行。测试 services/fusion/tests/test_ai_endpoint_discovery.py 用各连接器normalize()真实输出的形状复现并守住了这一点。字段候选顺序是显式元组来自对各连接器normalize()的阅读而非假设PROCESS_FIELDS: tuple[str, ...] (process_name, Image, exe, name, path, process) COMMAND_LINE_FIELDS: tuple[str, ...] (CommandLine, cmdline, cmd_line, command_line, argv) DEVICE_FIELDS: tuple[str, ...] (hostname, host_hostname, computer, Computer, device_name, host) PRINCIPAL_FIELDS: tuple[str, ...] (username, user, actor, TargetUserName, SubjectUserName, user_name)_first()会把列表拍平因此auditd的argv列表会得到拼接后的命令行而不是一个repr。三类端点证据先匹配者胜_from_endpoint()依次尝试已知编码代理二进制 → 本地 MCP 服务器进程 → 文件MCP 客户端配置或 AI IDE 扩展目录。之所以要这个顺序是因为进程路径同时也是文件路径。判定的具体规则编码代理按可执行文件 basename小写、去掉.exe在CODING_AGENT_PROCESSES中查找同时得到供应商映射MCP 服务器按前缀匹配(mcp-server, mcp_server, mcp-proxy)——注释说明mcp作为子串会命中mcpelauncher把游戏启动器送上安全评审命令行中若出现NO_PROMPT_FLAGS之一就写入permission_prompts_disabled: trueNO_PROMPT_FLAGS: tuple[str, ...] ( --dangerously-skip-permissions, --yolo, --auto-approve, --no-confirm, --yes-always, --full-auto, )注释称这是端点来源能提供的信号最强的单一属性也是它唯一出现的地方——这样启动的代理在执行前不会得到任何人工确认。端点分支还有一条刻意的克制绝不设置模型或供应商。端点遥测看不到这两者用默认值填充会让清单断言一个没有任何来源观测到的事实。配置文件与扩展目录的识别MCP_CLIENT_CONFIGS用路径后缀匹配因为每个配置都在各平台形态不同的用户家目录下MCP_CLIENT_CONFIGS: tuple[tuple[str, str], ...] ( (/claude/claude_desktop_config.json, Claude Desktop), (/.claude.json, Claude Code), (/.cursor/mcp.json, Cursor), (/.codeium/windsurf/mcp_config.json, Windsurf), (/code/user/mcp.json, VS Code), (/.vscode/mcp.json, VS Code), (/.continue/config.json, Continue), (/.aws/amazonq/mcp.json, Amazon Q), (/.gemini/settings.json, Gemini CLI), (/.codex/config.toml, Codex CLI), (/.config/zed/settings.json, Zed), )身份键取客户端名而不是文件路径两台笔记本都配置了 Cursor 是两行资产同一台笔记本的文件在版本升级后挪了位置仍是一行。对照 pack 的 SQL 可以看到两侧覆盖并不完全一致——recorder 还认识/.vscode/mcp.json与 Zed 的settings.json而 pack 的file_paths/SQL 未列出后者这意味着这类证据需要由 FIM 或其他采集路径送进来才会被识别。扩展目录的解析用了一个细节正确的正则match re.search(r^(.*?)-(\d[\w.-]*)$, folder)即publisher.name-1.2.3拆成(publisher.name, 1.2.3)。注释解释了为什么按最后一个连字符 数字切分发布者或扩展名本身可能含连字符例如sourcegraph.cody-ai按第一个连字符切会截断标识符。随后只有命中AI_IDE_EXTENSIONS白名单的扩展才会成行——一个编辑器有几百个扩展其中少数才是 AI 助手全部列出会把清单变成包清单。缓冲与失败方向繁忙的代理会为每次工具调用发一个 span。逐 span upsert 等于在部署中每个 AI 事件的热路径上写一次只为更新一个没人按这个粒度读的last_seen_at。因此观测按身份在内存中合并按大小或时长刷写_MAX_PENDING 200 _MAX_AGE_SECONDS 30.0注释说明这个尺寸保证只有一个 agent 的租户也能在第一个 span 到达后一分钟内看到自己的第一条资产。属性中的tools、models、prompt_secret_kinds走集合并集其余键后者覆盖前者。失败方向是单向的Postgres 不可用时丢弃缓冲的观测并记录日志绝不阻塞消费者。理由写在模块文档里——清单是治理面丢一小时可以承受而阻塞告警提升不行丢弃会以warning计数并记录ai_asset_recorder.flush_failed、ai_asset_recorder.no_pool让安静的清单可诊断而不是神秘。风险评分一个数字十个信号一句理由评分只有一个计算点services/api/app/services/ai_inventory.py 的score_risk()。recorder 在写入时调用它并存储结果控制台读存储值任何查询都不重算。迁移注释解释了原因这个仓库已经出现过两个面各自拥有一段 SQL 表达式、从而对同一批行给出不同数字的事故。分值表逐项如下总分上限 100因此新增信号不会静默重标定既有信号信号键分值触发条件unlinked_principal15没有链接到人无人对它的行为负责unlinked_device10无设备且 kind 为coding_agent/ide_extension/mcp_server处置无处落地undeclared20sanctioned为None没人评审过refused30sanctioned为False评审拒绝却仍在运行privileged_permissions25链接用户持有管理员权限prompts_disabled25启动时关闭了权限确认unvetted_source20install_source不在official/vendor/internal之内secret_in_prompt20prompt_secret_kinds非空high_risk_tool15调用过HIGH_RISK_TOOLS中的工具broad_oauth_scope25持有覆盖整个邮箱、云盘或组织的 scopeHIGH_RISK_TOOLS是改变资产面而非只读的工具名集合execute_command、run_shell、write_file、delete_file、send_email、create_user、grant_permission、deploy、terraform_apply、database_writeBROAD_OAUTH_SCOPES里每一条都是供应商参考文档中的真实 scope 字符串例如https://mail.google.com/、Mail.ReadWrite、Files.ReadWrite.All、repo、admin:org。注释强调这些不是自造的分类。两点容易错的语义值得单独记住sanctioned是三态三态分值不同。None表示没人看过适度风险因为未评审即未纳管False表示有人看过并拒绝、但它仍在跑风险最高True表示已批准不加分。_is_privileged()在权限快照为None时返回False。注释称这是诚实的答案把未知当作特权会让没有采集姿态数据的部署里每一项资产都显得严重。recorder 侧的_score()是这份逻辑的镜像差异在于新建观测必然sanctionedNone、也没有权限快照因此它固定记undeclared并且不计算refused与privileged_permissions。两个服务各自打包为顶层app无法互相 import所以 services/fusion/tests/test_ai_asset_recorder.py 用一张共享用例表断言两份实现保持一致——这是让镜像保持为镜像的唯一办法。读取与治理API 与控制台清单的读接口在 services/api/app/api/v1/endpoints/ai_assets.py共三条路由。# 全部资产按最近观测倒序 curl -H Authorization: Bearer $TOKEN \ https://aisoc.example/api/v1/ai-assets?limit50offset0 # 只看编码代理 curl -H Authorization: Bearer $TOKEN \ https://aisoc.example/api/v1/ai-assets?kindcoding_agent # 只看没有人负责的资产——这是评审的起点 curl -H Authorization: Bearer $TOKEN \ https://aisoc.example/api/v1/ai-assets?unlinkedtrue参数约束kind必须是六个 kind 之一否则返回422并在 detail 中列出合法取值limit取值 1–200_MAX_PAGEoffset非负。响应体为items / total / observedSources其中observedSources是显式声明而不是从空列表推断出来的字段——同一份注释指出没有 AI 遥测的租户与 AI 资产面确实为空的租户在行数据上看起来完全一样而只有前者才是需要去排查的理由。单条资产用GET /api/v1/ai-assets/{asset_id}唯一的写操作是治理判定curl -X POST -H Authorization: Bearer $TOKEN -H Content-Type: application/json \ -d {sanctioned: false, note: Unregistered agent on a finance laptop} \ https://aisoc.example/api/v1/ai-assets/asset_id/sanctionsanctioned取true/false/null三者语义不同批准、评审后拒绝、退回未决。该路由会用同一个score_risk()重算风险分并写回——因为治理判定本身就是评分输入之一一个刚被拒绝却仍在运行的资产其暴露程度与没人看过的资产不同。权限模型读取需要ai_estate:read写入需要ai_estate:write。模块文档说明了为什么在大多数读接口只做认证的这个服务里这里要额外要权限这份清单指明了哪台笔记本上哪个编码代理属于哪个人、握着哪个供应商密钥那是一份目标清单能读告警的会话不应该自动获得它。权限词表与角色持有关系见 services/api/app/core/security.py。控制台页面apps/web/src/components/ai-estate/AiEstateView.tsx 是页面实现文件头列出三条渲染决策缺失的人或设备渲染为琥珀色not learned附 tooltip 说明该来源对此盲而非空白格读取失败会明说失败绝不渲染成空资产面——因为你没有影子 AI是这个页面可能说出的最危险的错误陈述不伪造任何数据没有样例行、没有?? MOCK、没有 SWRfallbackData因为编造的 AI 清单会成为读者据以行动的安全面。页面按kind与unlinked过滤30 秒刷新一次展开行会显示逐条风险理由、观测次数、来源说明以及批准/拒绝按钮。SOURCE_LIMITS为五种来源各准备了一句能看见/永远看不见的提示与后端SOURCE_CAPABILITIES语义一致。图谱投影除关系表外AI 资产还有一张图投影。schemas/graph-schema.yaml 定义了AIAsset标签并说明一个标签加kind属性而不是六个标签的理由与关系表完全一致对这份数据提出的每个问题都是跨 kind 提问的这个人跑什么、这台笔记本上跑什么六个标签会把它们变成六路 union。schema 中同时指出持久记录是 Postgres 里的aisoc_ai_assets图只是调查时遍历的投影由extractAIEstate从ai-runtime/ai-finding遥测以及命名已知代理二进制的进程活动写入。上线检查怎么确认这张表真的在被写这套功能最大的失败模式不是报错而是代码能跑、测试能过、页面能渲染但表里没有写入。仓库为此提供了一个专用门禁scripts/check_ai_asset_inventory.py。它用ast与纯文本解析而非 import因为 CI 中它跑在任何服务 venv 之前。它的规则集是RULES ( (MIGRATION, _check_migration), (MODEL, _check_model), (ROUTES, _check_routes), (PERMISSIONS, _check_permissions), (WRITER, _check_writer), (KINDS, _check_kinds), (GRAPH, _check_graph), (CONSOLE, _check_console), )其中WRITER是承重规则它要求三件事同时成立RECORDER_PATH存在且文本中出现了表名fusion 消费者的_process_message函数体内真的调用了_ai_assets.observe用 AST 限定在单函数内因为顶部 import、只在开关分支里调用正是那个缺陷services/fusion/app/main.py真的构造了AiAssetRecorder(否则消费者的引用为None每个调用点都会静默跳过。第三点在 services/fusion/app/main.py 中是以可调用对象传入的ai_assets AiAssetRecorder(lambda: sink._pool) if sink is not None else None注释解释了为什么传 lambda 而不是直接传sink._pool连接池是在worker.start()期间由sink.start()打开的提前捕获会拿到None从而在整个进程生命周期里静默丢弃每一次观测。消费者的调用点分布在三处见 services/fusion/app/workers/consumer.py主循环中await self._ai_assets.flush_if_stale()、收尾时await self._ai_assets.flush()、以及消息处理中累加ai_assets_observed指标。单元测试证明不了写入路径通着所以还有一套针对真实 PostgreSQL 的隔离测试tests/isolation/test_ai_estate_live.py。它的完成标准直接取自计划——用一台编码代理、一个 MCP 服务器和一个供应商密钥组成的夹具资产面三者在清单页面上都出现并链接到正确的人与设备。该套件必须连真库因为它验证的都是 PostgreSQL 的性质UNIQUE NULLS NOT DISTINCT的合并语义、LEAST/GREATEST阻止重放批次推进first_seen_at、以及只有以aisoc_app仅 DML角色连接时 RLS 才真正生效。运行方式ISOLATION_AI_ESTATE_DSNpostgresql://aisoc_app:...localhost:5432/aisoc \ pytest tests/isolation/test_ai_estate_live.py文件头明确变量设置后测试失败是硬失败绝不跳过——会跳过的在线套件只是在一无所有之上盖了一个绿勾。覆盖规划与排障要点清单为空先查来源不要下结论。页面对读了但失败和没有资产给出不同文案API 的observedSources会告诉你究竟有哪些来源在工作。若列表为空且observedSources也为空说明三条采集路径都没接通而不是资产面干净。只跑 EDR 会得到半张表。crowdstrike/sentinelone/azure_defender返回的是厂商判定无法提供进程启动。要端点侧证据需要 osqueryFleetDM 或 osctrl、Linuxauditd或 Windows 事件转发。osquery pack 要显式分配。默认 pack 集合只含aisoc-fim-baseline与aisoc-inventory-baseline。分配后可用GET /api/v1/osquery/packs/aisoc-ai-estate/render?formatosctrl核对查询是否如预期下发。not learned是发现不是缺数据。先看discoverySourceai_runtime天生没有设备、provider_audit天生没有设备这两类的空设备列属于盲区说明而一台端点侧观测到的编码代理没有人才是需要处理的问责缺口。调风险分先看riskReasons。分数是暴露度而非定性结论展开行能看到每条理由评审应当反驳一句话而不是反驳一个数字。未评审的资产必然带undeclared的 20 分把它降下来的正确方式是做出sanctioned判定而不是改评分逻辑。改 pack 的 SELECT 列要小心。name、path、cmdline、directory是 recorder 分类所依赖的列改名会静默破坏分类而不是报错。小结AiSOC 的 AI 资产发现没有引入任何新组件它把AI 治理这个通常停留在问卷层面的问题还原成了三条各有明确盲区的遥测路径加一张有主键约束的表ai-runtime告诉你代理是谁、用了什么模型和工具端点告诉你哪台机器上跑着哪个二进制以及是否关闭了权限确认供应商审计告诉你谁签发了哪把密钥以及谁授予了什么 scope。三者以(tenant_id, kind, external_id, device)为身份在NULLS NOT DISTINCT下合并缺失的链接以 not learned 显式呈现风险分由唯一一处函数在写入时计算并附带可反驳的理由。剩下的工作属于使用者把 pack 分配给租户观察observedSources然后从没有人负责的那一列开始处理。赞分享人工智能AI Agent网络安全后端前端【免费下载链接】AiSOCOpen-source AI Security Operations Center: alert fusion, LLM-agent triage, MITRE ATTCK investigation, and a replayable decision ledger for every agent step. Self-hostable, runs with no API keys, MIT licensed. Ships an MCP server for Claude, Cursor and Continue.项目地址https://gitcode.com/GitHub_Trending/ai/AiSOC点击查看免费下载相关推荐akshare数据目录建立可发现的金融数据资产清单akshare数据目录建立可发现的金融数据资产清单 AKShare作为基于Python的开源财经数据接口库为数据科学家和金融从业者提供了全面丰富的金融数据获金融科技网页爬虫Impeccable 方向合成与资产生产指南从三张 Comp 到可测度的构建规格Impeccable 方向合成与资产生产指南从三张 Comp 到可测度的构建规格 本指南基于 Impeccable 技能体系中 visualize 参考文档AI 技能前端设计系统AI 插件godot-open-rpg 第三方资产清单与 CC0 许可使用指南godot open rpg 第三方资产清单与 CC0 许可使用指南 godot open rpg 是一个用于学习在 Godot 4 中制作经典回合制 RPG游戏开发示例工程上一篇Llama-Guard-3-1B性能实测M1到M4 Ultra芯片183-549 tokens/s速度大揭秘下一篇InternVL3-2B-Pretrained 推理进阶批量推理、流式输出的 3 种实现方法详解创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
零基础 30 分钟出片:用万通 Animate 把角色设定变成可复用的动画素材 零基础 30 分钟出片:用万通 Animate 把角色设定变成可复用的动画素材
做账号的朋友应该都踩过这个坑:
你想让"同一个角色"出现在每条视频里,结果每次生成,脸变了、衣服变了、连发色都对不上。观众看两集就认不出是谁了&… · 2026/11/3 10:27:54
LinkSwift 网盘直链下载助手:三步装好,九大网盘直链推送 IDM、Aria2、cURL LinkSwift 网盘直链下载助手:三步装好,九大网盘直链推送 IDM、Aria2、cURL 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / … · 2026/11/3 10:27:54
REA Agent实战:从npx初始化到应用分析闭环 1. 先把REA这件事想明白,再动手敲命令
1.1 一次“应用分析”为什么需要Agent而不是一段Prompt 很多人第一次听到“应用分析”,脑子里浮现的是丢一段长提示词给大模型,让它输出一份功能清单、用户反馈和竞品对比。这种玩法在Demo阶段确实爽&a… · 2026/11/3 11:23:00
CAD2027部署全流程解析:环境评估、安装排错与批量部署 装 CAD 这件事,我原以为早就没什么新鲜感了,直到上周帮同事在一台新机器上部署 CAD2027。他照着网上搜到的一篇所谓“超详细图文教程”一步步点下去,结果卡在安装进度 87% 一动不动四十分钟,最后弹了个错误码了事。我接手之后发现… · 2026/11/3 11:23:00
零成本接入13个模型:统一入口、多渠道路由与降级实践 零预算跑通十几个模型能力,这件事我做过不止一次。标题里那个词说得很直白,本质上就是 把能零成本调用的模型能力,全部收拢到一个统一入口 。dsh-our-free-model 2.0 是我给这套东西起的代号,它不是一个产品,而是一份… · 2026/11/3 11:23:00
GPU驱动安全架构:UMD与KMD权限边界设计解析 1. GPU驱动架构中的权限边界设计在GPU驱动开发领域,UMD(User Mode Driver)与KMD(Kernel Mode Driver)的分层架构设计是现代图形系统的核心安全机制。这种设计源于操作系统对硬件资源访问的基本安全要求——用户态程序不… · 2026/11/3 11:23:00
rea命令安装全解析:curl脚本与npm全局安装对比及PATH排查 1. 先把 rea 是什么、两种装法到底在装什么讲清楚 rea 命令在我的日常工具箱里属于那种"装一次就再也离不开"的角色——它是一个命令行工具,跑在终端里,干的是项目初始化、资源构建、批量任务编排这类活儿,常见的调用形态就是 rea… · 2026/11/3 11:23:00
支付系统架构设计:核心挑战与高并发解决方案 1. 支付系统架构的本质挑战 支付系统作为现代商业基础设施的核心组件,其设计复杂度往往被严重低估。表面上看只是完成资金转移,实则涉及金融安全、交易一致性、系统容灾等十余个专业领域的交叉协同。从业十余年,我见过太多团队在初期只关注功… · 2026/11/3 11:21:58
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46