airomhq/airom

GitHub: airomhq/airom

一款开源的 AI 物料清单(AIBOM)扫描器,能够自动发现并盘点代码、容器和 Kubernetes 中的各类 AI 资产,并生成附带精确代码溯源证据的标准格式报告。

Stars: 4 | Forks: 1

# AIROM **开源 AI 物料清单 (AIBOM) 扫描器。** AIROM 是一款开源扫描器,能够发现 AI 资产——包括模型、prompt、数据集、embedding、向量数据库和 AI 框架——并生成 AI 物料清单 (AIBOM)。它以单个静态二进制文件的形式在文件系统、源码仓库、容器镜像或 Kubernetes 集群上运行,并为每个条目提供 `file:line` 证据。 [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/airomhq/airom/actions/workflows/ci.yml) [![Release](https://img.shields.io/github/v/release/airomhq/airom?include_prereleases)](https://github.com/airomhq/airom/releases) [![Go Report Card](https://goreportcard.com/badge/github.com/airomhq/airom)](https://goreportcard.com/report/github.com/airomhq/airom) [![Go Reference](https://pkg.go.dev/badge/github.com/airomhq/airom.svg)](https://pkg.go.dev/github.com/airomhq/airom) [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE) ## 什么是 AIROM? 迟早会有审计员、客户或你自己的安全团队问这个问题: 大多数 AIBOM 工具无法回答这个问题。它们以注册表为中心——你在 Hugging Face 上指定一个模型,它们就渲染出一张模型卡片——或者它们是专有工具,根本不看你的代码。没有人会去扫描*你实际交付的代码仓库*并展示其工作过程。 AIROM 是**证据优先**的。输出中的每个组件都包含: - **Occurrences(出现位置)** — 每次出现的 `file:line`、匹配的代码片段以及所属的外层符号 - **Detection technique(检测技术)** — 源码分析、二进制头解析、manifest 分析、哈希比对等 - **A calibrated confidence score(校准的置信度分数)** — 背后有客观的推导逻辑,而不是凭空感觉 这些证据会作为 CycloneDX 1.6 的 `evidence.identity[]` + `evidence.occurrences[]` 输出——这是一个规范原生的存储位置,用于记录“在 file:line 处通过技术 T 以置信度 C 发现”的信息——而这些信息**常常被其他 AIBOM 工具留空——此外还会生成 SARIF 投影,以便将相同的发现作为批注显示在 GitHub Code Scanning 中。一次扫描,一张图,任何输出格式都只是它的纯粹投影。 ## AIROM 检测什么 | 类别 | 覆盖范围 | |---|---| | **托管模型 API** | OpenAI、Anthropic、Gemini、AWS Bedrock、Azure OpenAI、Cohere、Mistral、Groq、Ollama — 模型 ID 字面量和 SDK 调用点 | | **本地模型权重** | GGUF、safetensors、ONNX、Torch (pickle-zip)、TensorFlow SavedModel、TensorRT、TFLite、HDF5 — magic bytes + 头部元数据(架构、参数数量、quantization),绝不加载或执行 | | **模型目录与谱系** | Hugging Face 模型目录(`config.json` + 权重 = 一个组件),PEFT/LoRA adapter → `derived-from` 基础模型边 | | **Embedding 模型** | OpenAI、sentence-transformers、BGE/E5/MiniLM、Voyage、Cohere — 托管或本地 | | **框架与 SDK** | LangChain、LlamaIndex、Haystack、DSPy、CrewAI、AutoGen、Semantic Kernel、Transformers、vLLM、MLflow 以及各个提供商的 SDK — 从 manifest *和*实际用法中提取 | | **向量数据库** | Chroma、Milvus、Qdrant、Pinecone、Weaviate、FAISS、pgvector、Redis、Elasticsearch、MongoDB Atlas | | **Prompt** | Prompt 文件、`PromptTemplate`/`ChatPromptTemplate`/`system_prompt` 模式 | | **数据集** | CSV/JSONL/Parquet/Arrow 特征、`load_dataset()`、Kaggle 和 HF 数据集引用 | | **生成参数** | temperature、top_p、top_k、max_tokens、seed、stop、reasoning effort、response format — 绑定到调用点的模型,并附带出处 | | **服务基础设施** | Ollama、vLLM、TGI、Ray Serve、SageMaker、Vertex AI、Azure ML — 包括 Dockerfile/compose/k8s manifest | | **RAG pipeline** | Retriever + 向量存储 + embedder + LLM 被组装成一个合成的 `rag-pipeline` 组合体,包含带类型且有证据支持的边 | **扫描目标:** 文件系统 · git 仓库(本地或 URL)· 容器镜像(目前支持通过 `--input` tarball 或 OCI layout;远程/daemon 拉取将在后续推出)· Kubernetes 工作负载(目前支持离线 `--manifests`;实时集群扫描将在后续推出) **语言:** Python、JavaScript、TypeScript、Go、Java、Rust、C#、Kotlin **输出格式:** 原生 AIBOM JSON(带版本号的 schema)· CycloneDX 1.6 ML-BOM · SARIF 2.1.0 · YAML · 表格 — 一次扫描可输出任意组合。SPDX 3.0.1 AI profile 已为 v2 预留位置。 ## 快速开始 ### 安装 ``` # pip — 无需 Go toolchain。安装 `airom` 命令和 Python SDK。 pip install airom # or: pipx install airom (isolated, always on PATH) # 从源码(需要 Go 1.25+)。解析为最新的 release tag。 go install github.com/airomhq/airom/cmd/airom@latest ``` 然后,在任何目录下执行 `airom --version` 应该都能正常运行。
airom: command not found — 这取决于它是否在 PATH 中。 wheel 安装包会将 `airom` 安装到您运行环境的 `bin/` 目录中,因此 **pip** 会自动将其放入激活的 virtualenv 的 PATH 中(`pipx` 则会全局放入 PATH)。**`go install`** 会将文件写入 `$(go env GOPATH)/bin`,而 Go *不会*自动为您将其添加到 PATH 中: ``` export PATH="$PATH:$(go env GOPATH)/bin" # add to ~/.zshrc or ~/.bashrc ``` 使用 `command -v airom`、`pip show -f airom` 或 `go env GOPATH` 来检查它的安装位置。
所有六个目标平台的预构建、cosign 签名的二进制文件均可在[发布页面](https://github.com/airomhq/airom/releases)获取,每个文件都附有校验和与 SBOM;Homebrew tap 正在计划中。AIROM 以单个静态二进制文件发布(`CGO_ENABLED=0`)——无需 runtime,无需依赖。 ### 扫描 ``` # 自动检测 target:directory、git URL 或 image reference airom scan . # 显式 nouns —— 每种 target 类型一个 subcommand airom fs ./my-service airom repo https://github.com/org/rag-app airom image --input img.tar # docker save -o img.tar nginx:latest airom k8s --manifests ./deploy # offline: enumerate workload images # 一次扫描生成多个输出:table 输出到终端, # CycloneDX 和 SARIF 输出到文件 airom scan . -o table -o cyclonedx=bom.json -o sarif=scan.sarif # 缩小 detector 集合;添加您自己的 rules airom scan . --select "rules,+modelfile/gguf,-dataset/file" --rules extra.yaml ``` **退出代码:** 当扫描成功时,`airom` 会退出,**代码为 0 — 发现的问题本身不代表失败**。是否将其作为阻断条件是可选的 CI 策略: ``` airom scan . --exit-code 1 --fail-on "local-model-file&confidence>=0.9" ``` ## 示例输出 ``` $ airom scan . AI Bill of Materials — /home/you/my-ai-app 7 component(s), 3 relationship(s) KIND NAME VERSION PROVIDER CONF EVIDENCE hosted-llm gpt-4.1 - openai 0.87 12 occ embedding-model text-embedding-3-large - openai 0.85 3 occ local-model-file llama-3-8b-instruct.Q4_K_M - local 0.97 2 occ framework langchain 0.3.14 - 0.95 2 occ vector-db chromadb 0.6.3 - 0.92 4 occ prompt system-prompt.md - local 0.80 1 occ rag-pipeline rag-pipeline#1 - - 0.78 0 occ ``` 以下是 CycloneDX BOM(节选)中针对审计员问题的回答: ``` { "type": "machine-learning-model", "bom-ref": "airom:1f3a9b2c4d5e6f70", "group": "openai", "name": "gpt-4.1", "modelCard": { "modelParameters": { "task": "text-generation" } }, "properties": [ { "name": "airom:model.provider", "value": "openai" }, { "name": "airom:model.id", "value": "gpt-4.1" }, { "name": "airom:confidence", "value": "0.87" }, { "name": "airom:param.temperature", "value": "0.2 @ src/rag.py:88" } ], "evidence": { "identity": [ { "field": "name", "confidence": 0.87, "methods": [ { "technique": "source-code-analysis", "confidence": 0.85, "value": "model=\"gpt-4.1\"" } ] } ], "occurrences": [ { "location": "src/rag.py", "line": 88, "symbol": "answer_question", "additionalContext": "client.chat.completions.create(model=\"gpt-4.1\", temperature=0.2)" }, { "location": "src/summarize.py", "line": 41, "symbol": "summarize" } // …10 more ] } } ``` 注意这里*没有*什么:没有捏造的 `pkg:generic/openai/gpt-4.1` purl。托管 API 模型不是软件包;AIROM 通过 `bom-ref` 和命名空间属性来识别它们,而不是去污染像 Dependency-Track 这样基于 purl 索引的消费者。相反,本地权重文件会获得真实的 purl(`pkg:huggingface/...`、`pkg:generic?checksum=...`)和 SHA-256 哈希值——它们的身份**就是**它们的字节内容,因此位于三个路径下的相同权重会被识别为一个组件,但附带三次出现记录。 置信度绝不是含糊其辞的:单个检测器的命中次数是有上限的(对同一个正则表达式的十二次命中 ≈ 一次命中,仅有轻微增强——重复不能粉饰为确定性),不同的独立检测方法通过 noisy-OR 相互印证,并且所有值都会被截断在 0.99。只有与已知权重的内容哈希匹配才能断言为 1.0。 ## 工作原理 ``` source (fs / repo / image / k8s) → Phase 1 — streaming scan: one bounded pipeline; each file read at most once; a compiled selector index picks interested detectors; the rule engine runs Aho–Corasick keyword prefilters over lexed code/string regions before any regex → Phase 2 — project detectors: cross-file logic (HF model dirs, adapter lineage, config⇄model binding, RAG stitching) over an immutable phase-1 view → Assembler: canonical identity, keep-and-relate merge, confidence calculus, parameter binding — detectors emit claims, never components → Writers: pure functions from one graph to every output format. ``` 使其达到生产级质量的原因是其不变性,而非期望:峰值内存是配置的函数,而不受输入大小的影响;损坏的文件会降级为一条真实的 `Unknown` 记录,而不是导致扫描崩溃;相同的输入在任何并行度下都会产生逐字节相同的输出;容器镜像中一个 40 GB 的 GGUF 文件仅需 32 KB 的头部解析和一次哈希处理——零内存增长,零磁盘占用。随着测试矩阵的完善,这些特性中的每一项都有专门的 CI 强制测试(Phase 8)。 完整的设计——领域模型、检测器框架、并发拓扑、身份与置信度演算、缓存,以及记录了被否决方案的决策日志——都在 **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** 中。 ## 扩展 AIROM 那些需要快速迭代的检测面(例如模型 ID 每周都在变化)被放置在**声明式 YAML 规则包**中,而不是 Go 代码中。添加一个提供商只需发起一个规则 PR,无需等待新版本发布,目标是**在一小时内完成**: 1. `airom dev new-rulepack fireworks` 会生成 `rules/models/fireworks.yaml` 骨架以及测试用例。 2. 编写约 30 行 YAML:关键字(必填——它们控制着 Aho–Corasick 预过滤器,因此你的正则表达式只会在可能匹配的文件上运行)、一两个模式、一个声明模板。添加一个正向测试用例和一个反向测试用例。 3. `airom rules lint && go test ./rules/ -update` 会生成预期的输出。 4. 你的 PR 包含一个 YAML 文件、两个测试用例、一个预期输出。零 Go 代码,零核心修改。Review 标准仅仅是“预期输出看起来对吗”。 规则甚至可以声明关系,并在调用点捕获生成参数——通过 YAML 定义边,无需编码。对于需要真正解析器的检测(二进制头解析、跨文件组装),Go 实现路径也同样简短:基于仅依赖 stdlib 的 `pkg/airom/detect` SDK 实现 `FileDetector`,并使用公开的 `detectortest` 测试套件进行验证——这与内置检测器使用的测试套件完全相同。 - **[docs/plugin-guide.md](docs/plugin-guide.md)** — 两种贡献路径,附带真实的 diff - **[docs/rule-schema.md](docs/rule-schema.md)** — 规则包 YAML 参考 ## 项目状态 AIROM 目前处于 **v0.1.0**,这是其第一个带标签的发布版本:功能已完整实现了 10 阶段计划,架构通过了多代理生产环境审查。作为早期软件——可能会有粗糙之处,请查看下方的“暂缓实现”行,了解其目前刻意不做的事情。真实记录如下: | 领域 | 状态 | |---|---| | 架构、领域模型、决策日志 ([docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)) | **完成** — 已接受的 v1 基线 | | 基于 §4 布局的仓库骨架(包及其契约、构建文件、文档) | **完成** — Phase 2 | | CLI ([docs/cli.md](docs/cli.md)):scan/fs/repo/image/k8s/clean/version,配置分层(flags > env > file > defaults),退出代码契约,`--fail-on` 语法,pprof/trace 引导 | **完成** — Phase 3,外加分组/带样式的帮助信息,以及在脱离终端时优雅退化的实时扫描进度指示器 | | 文件系统扫描器:目录源(嵌套的 `.gitignore`/`.airomignore` 堆栈,默认跳过项,符号链接安全),分类(语言/二进制/magic),一次读取的 tee-hash 文件上下文,阶段一流式 pipeline(有界 channel,钳制的 I/O 预算,panic 隔离,确定性输出) | **完成** — Phase 4 | | 插件框架:公开 SDK(带有 tri-state 字段的 `pkg/airom` 领域图,`pkg/airom/detect` 契约 + 分发索引,`purl` 规范,`detectortest` 测试套件),带有按检测器隔离和统计的调度器,显式目录 + Syft 风格的 `--select`,组装器(CanonicalKey 身份,keep-and-relate 合并,分组的 noisy-OR 置信度,refusal-first 关系),规则引擎编译器(完整的 [rule-schema.md](docs/rule-schema.md) lint 契约,三层合并,自失效的规则集哈希,Aho–Corasick 预过滤器,适用于所有 8 种语言的区域词法分析器),`detectors-gen`,`airom detectors list/explain` | **完成** — Phase 5。如今 `airom fs . --rules pack.yaml` 已能端到端运行用户规则包 | | 检测器与规则包:二进制模型文件解析器(GGUF,safetensors,ONNX,Torch + 静 pickle-opcode 安全扫描,SavedModel,TFLite,HDF5,TensorRT — 经过模糊测试),8 大生态系统的 manifest 检测器,Go AST 检测器,prompt/数据集/infra 检测器,阶段二的项目检测器(HF-dir 组装,adapter 谱系,配置绑定,RAG 合成),涵盖所有 8 个类别的 47 个内置规则包 / 98 条规则,`rules list/lint/test` + `dev` 脚手架 | **完成** — Phase 6。能够将真实的 AI 项目扫描并生成内容丰富的 AIBOM(模型,embedding,向量数据库,框架,权重,prompt,基础设施,RAG pipeline)| | 来源:`repo`(exec-git shallow clone + 本地 worktree),`image`(docker-save/OCI archive + OCI layout — 实时 registry/daemon 拉取将在后续推出),`k8s`(离线 `--manifests` 镜像枚举 — 实时集群扫描将在后续推出) | **完成** — Phase 6(包含上述提到的后续项)| | 输出器:原生 JSON(带版本的、无损的超集 — 经过往返测试),CycloneDX 1.6/1.7 ML-BOM(modelCard + `evidence.occurrences[]`,已通过官方 schema 验证),SARIF 2.1.0(每个检测器一条规则,每次出现一条结果,无行号的 fingerprint),YAML,表格;多输出 `-o fmt=path` | **完成** — Phase 7。`airom scan . -o cyclonedx=bom.json -o sarif=scan.sarif` 在一次扫描中同时输出两者 | | 测试套件:通过端到端测试用例仓库将整个 pipeline 生成为全部五种格式的 golden 测试,官方 CycloneDX/SARIF schema 一致性检查,`docs/mapping.md` 往返强制验证,全扫描确定性(`--parallel 1` vs `16`),混沌降级,以及 P2 RSS 上限回归测试套件 — 所有内容均在 `-race` 下运行,约 74% 的覆盖率 | **完成** — Phase 8 | | 发布自动化:CI(lint/vet/gofmt,在 Linux+macOS 上运行 `-race` 测试,针对所有六个目标平台的 `CGO_ENABLED=0` 交叉编译矩阵,生成代码偏差检查,模糊冒烟测试,CodeQL),goreleaser(静态矩阵构建,校验和,无密钥 cosign 签名,每个发布的 SBOM + 自扫描的 AIBOM),Dependabot,issue/PR 模板,`SECURITY.md`/`CODE_OF_CONDUCT.md`/`CONTRIBUTING.md` | **完成** — Phase 9 | | 生产环境加固:全树对抗性审查(10 个维度,针对每个发现进行验证),发现并修复了 17 个已验证的缺陷 — 包括 OCI layout 路径穿越漏洞,通过 memo/GET 绕过静态 pickle 扫描的漏洞,未连通的 `--fail-on` CI 门禁,P7 堆栈跟踪泄露,YAML int64 损坏,非规范 purl,以及检测器/规则预过滤器的缺口 — 每一个都附带了回归测试。确认了空的 CycloneDX `dependencies[]`(没有实质性的 `depends-on` 边)以及暂缓实现的实时 registry/daemon/集群模式(会优雅地失败)是设计使然,而非缺陷 | **完成** — Phase 10 | | SPDX 3.0.1 AI profile,attestation 验证,分层归属,OCI 规则注册表,实时集群/registry 源模式,根→依赖边合成 | 按设计推迟至 v2(已预留位置 — 参见 [ARCHITECTURE §16](docs/ARCHITECTURE.md))| 已知的差距,每一项不仅在这里列出,也会在受影响标志的 `--help` 中显示:缓存未实现(每次扫描都是冷启动,`--no-cache` 是一个空操作),实时 registry/daemon 镜像拉取不可用(请使用 `airom image --input `),实时集群扫描不可用(请使用 `airom k8s --manifests `)。 ## 对比 没有恐吓营销,只有客观定位——以下工具解决的是不同的问题: | | AIROM | 以注册表为中心的 AIBOM 生成器 | 专有 AI 安全扫描器 | |---|---|---|---| | 输入 | **你的仓库、镜像或集群** | 你指定的注册表条目(例如 HF 仓库) | 各不相同;通常是模型制品或连接了 SaaS 的仓库 | | 能回答“为什么我的 AIBOM 中包含这个?” | **是 — 在 BOM 中提供 file:line 出现位置、技术、置信度** | 否 — 输出描述的是模型本身,而不是你的使用方式 | 通常只给出发现结果,而没有 BOM 原生的证据 | | CycloneDX `evidence.occurrences[]` | **输出** | 不输出 | 不输出 | | 覆盖范围 | 托管 API **和**本地权重**以及**框架、向量数据库、prompt、数据集、参数、基础设施、RAG 图 | 仅限指定的模型 | 通常是模型文件和/或精心挑选的子集 | | 分发方式 | 单个静态 Go 二进制文件,支持离线运行 | Python 包 | Agent 或 SaaS | | 许可证 | Apache 2.0 | 各不相同(通常为开源) | 专有 | 如果你已经明确知道使用的是哪个注册表模型,并且想要获取其模型卡片,那么以注册表为中心的生成器是正确的工具。而当事实依据就是你的代码库且你必须证明这一点时,AIROM 正是你需要的。 ## 安全性 AIROM 是一款安全工具,其解析器需要处理不受信任的字节流,因此进行了相应的加固。以下准则是具有约束力的设计契约([ARCHITECTURE §13](docs/ARCHITECTURE.md));执行这些准则的模糊测试和发布机制将随着测试和发布阶段的落地而上线(参见[项目状态](#project-status)): - **绝不执行模型。** 权重文件仅通过 magic bytes 和有界的头部解析来进行识别——不会进行加载、反序列化为对象或运行任何内容。 - **Pickle opcode 扫描。** Torch 的 `.pt`/`.pkl` 流会在不执行的情况下,通过静态分析扫描可疑的 `GLOBAL` opcode(`os.system`、`subprocess`、`builtins.eval` 等);结果会以 `PickleRisk` 的形式呈现在组件上。 - **经过模糊测试的解析器。** 每一个二进制头部解析器都在 CI 中经过了模糊测试,并且必须返回错误——绝不会引发 panic,也绝不会进行无限制的内存分配。 - **无意外的网络访问。** 文件系统、本地仓库和 `image --input` 扫描不会触及任何网络;`--offline` 会在全局范围内对此进行断言。 - **供应链。** 发布版本采用 `CGO_ENABLED=0`,可复现构建,经 cosign 签名,并附带了 SBOM 进行发布——而且,通过 dogfooding(自身使用),还附带了一份 AIBOM。 包含报告说明的 `SECURITY.md` 将在首次发布前提供;在此之前,请通过该仓库上的 GitHub 安全公告私下报告漏洞,而不是提交公开的 issue。 ## 贡献 请从 [docs/plugin-guide.md](docs/plugin-guide.md) 开始(`CONTRIBUTING.md` 将在首次发布前提供)。让 AIROM 变得更好的最快方式是编写一个规则包:一个 YAML 文件,两个测试用例,一个预期输出——大多数提供商的接入都能在一小时内完成。 ## 许可证 基于 [Apache License 2.0](LICENSE) 授权。© AIROM 贡献者
标签:AIBOM, AI资产发现, EVTX分析, SBOM, 云安全监控, 子域名突变, 日志审计, 硬件无关, 聊天机器人, 请求拦截, 逆向工具, 静态分析