coroboros/skillward
GitHub: coroboros/skillward
一个将九个确定性安全扫描器融合为单一离线判定的 agent skill 供应链安全审计与 CI 门控工具。
Stars: 0 | Forks: 0

# skillward
**在安装前拆解 agent skill —— 一套完整的确定性扫描器集合,融合为一个离线判定。**
skillward 会运行所有维护中的离线扫描器,对不受信任的 skill 添加独特的检测维度,将它们重叠的发现融合成一份去重报告,并为 CI 返回 `--fail-on` 判定。这些扫描器位于一个从源码构建的 Docker 包中;Rust 二进制文件负责编排、融合和门控。
[](https://crates.io/crates/skillward)
[](https://github.com/coroboros/skillward/actions/workflows/ci.yml)
[](https://opensource.org/licenses/MIT)
[](https://github.com/coroboros/skillward)
[](https://github.com/coroboros/agent-skills)
[](https://coroboros.com)
## 目录
- [环境要求](#requirements)
- [安装](#install)
- [用法](#usage)
- [为何开发此工具](#why-this-exists)
- [工作原理](#how-it-works)
- [扫描器](#scanners)
- [确定性与隔离](#determinism-and-isolation)
- [目标](#targets)
- [选项](#options)
- [输出格式](#output-formats)
- [Agents](#agents)
- [退出代码](#exit-codes)
- [局限性](#limitations)
- [与替代方案比较](#compared-to-alternatives)
- [贡献](#contributing)
- [许可证](#license)
## 环境要求
- macOS (Apple Silicon 或 Intel)、Linux 或 Windows。
- **Docker** 用于默认沙箱 —— skillward 在加固的容器中运行扫描器包。`--sandbox host` 会取消此要求,改为使用本地安装的扫描器。
- 首次运行 `skillward install` 会从 GitHub Container Registry (`ghcr.io/coroboros/skillward-bundle`) 拉取扫描器包,该镜像同步至 Docker Hub (`coroboros/skillward-bundle`) —— 这是一个数百 MB 的多架构镜像(Python、semgrep、trivy DB),经过容器扫描并由 cosign 签名。它会被缓存;随后的扫描均为离线进行。
## 安装
```
cargo binstall skillward # prebuilt binary via cargo
brew install coroboros/tap/skillward
npx @coroboros/skillward # Node toolchains
```
从源码安装:
```
cargo install --path .
```
然后拉取一次扫描器包:
```
skillward install
```
## 用法
```
skillward ./my-skill # one skill
skillward ./skills # a directory of skills, scanned in parallel
skillward https://github.com/owner/skill # a remote repo, cloned and hardened
skillward ./my-skill --fail-on critical # only critical findings fail the gate
skillward ./my-skill --format json -o report.json
skillward ./my-skill --without cisco,semgrep # trim the ensemble
skillward ./my-skill --sandbox host # use locally-installed scanners, no Docker
skillward install # pull the bundle
skillward update # re-pull the pinned bundle
```
运行 `skillward --help` 获取完整的 flag 列表。
## 为何开发此工具
手动审查不受信任的 skill 意味着要运行多个扫描器,每一个都有各自的
flag 和输出格式,然后还要相信它们都没有悄悄连接网络,并且
一个也没被漏掉。skillward 一次性运行整套维护中的扫描器,并将结果
浓缩为一个单一的判定。
- **完整性胜过任何单一工具。** 没有任何单一扫描器能捕获所有问题,因此 skillward
运行九者的并集,并让它们的重叠部分转化为信号:被四个工具标记的同一个位置
是置信度提升的一次发现,而不是四行噪音。
- **离线且确定。** 默认沙箱在每次扫描时切断网络,因此
工具可选的 LLM 或 CVE 查找调用无法连出,并且相同的 skill 每次运行
都会得出相同的判定。
- **大声报错,从不沉默。** 崩溃、超时或缺失的扫描器会变成可见的
`tool-error`,而完全失效的引擎会以非零值退出 —— 降级的运行
绝不会显示为干净的 skill。
- **是一个门控,而不是一堵输出的墙。** 每个 skill 一个 `--fail-on` 判定和一个稳定的退出
代码,因此无需解析即可接入 CI。
- **继承的检测。** 规则来自上游工具,通过按计划从源码重建
包来刷新;skillward 负责编排、融合和门控 — 它
绝不自行编写检测。
## 工作原理
出于安全考虑,覆盖的完整性是必需的:没有单一扫描器能捕获
所有问题,因此 skillward 运行并集并使重叠部分被解读为信号
而不是噪音。
1. **解析** 目标 —— 一个 skill 文件夹、一个包含多个 skill 的目录,或一个远程 URL
(克隆到一个加固的、一次性的 checkout 中)。
2. **运行** 完整的集合扫描每个 skill,每个工具都在各自独立的
容器中并行运行。
3. **标准化** 每个工具的 SARIF 为统一的发现模型,具有统一的严重性
级别和规则类别分类。
4. **融合** —— 通过 (类别, 文件, 行) 去重,跨工具关联(被四个工具标记的同一个位置
变成一个引用所有四个工具的发现,且置信度提升),
并进行排序,使相互印证的关键问题排在前面。
5. **门控** —— 每个 skill 的判定;当任何发现达到 `--fail-on` 时退出 `20`。
这里绝不编写检测规则。它们继承自上游工具,
并通过按计划从源码重建包来刷新,包位于其自身的
事实来源代码库,
[coroboros/infrastructure/skillward-bundle](https://gitlab.com/coroboros/infrastructure/skillward-bundle)
—— 多架构、经过容器扫描,并使用 CycloneDX SBOM 进行 cosign 签名。
## 扫描器
默认集合 —— 每个维护中的确定性扫描器都添加了独特的
检测维度,均具备离线能力。`--without` 会精简它;`--with` 会重新添加被 `--without` 排除的工具。
九个扫描器及其检测维度
| 工具 | 语言 | 许可证 | 检测维度 |
| --- | --- | --- | --- |
| [skillspector](https://github.com/NVIDIA/SkillSpector) | Python | Apache-2.0 | 最深层的 `SKILL.md` 污染 → 执行 |
| [cc-audit](https://github.com/ryo-ebata/cc-audit) | Rust | MIT | Claude Skills / Hooks / MCP 配置审计 |
| [aguara](https://github.com/garagon/aguara) | Go | Apache-2.0 | 跨 9 个生态系统的供应链 + agent 内容 |
| [cisco skill-scanner](https://github.com/cisco-ai-defense/skill-scanner) | Python | Apache-2.0 | 多引擎静态分析 —— YAML、YARA、字节码、pipeline 污染 |
| [agent-audit](https://github.com/HeadyZhang/agent-audit) | Python | MIT | OWASP Agentic Top 10、工具边界污染 |
| [ramparts](https://github.com/highflame-ai/ramparts) | Rust | Apache-2.0 | MCP server + agent skill,静态 |
| [semgrep](https://github.com/semgrep/semgrep) | — | LGPL-2.1 | 带有 OWASP-LLM 规则集的 AST/dataflow |
| [trivy](https://github.com/aquasecurity/trivy) | Go | Apache-2.0 | SCA + 配置错误 + secrets |
| [gitleaks](https://github.com/gitleaks/gitleaks) | Go | MIT | Secrets —— 正则表达式 + 熵 |
## 确定性与隔离
确定性在沙箱层面强制执行,而不是信任每个工具。每个扫描器都在
包镜像内运行,使用:
```
--network=none --read-only --cap-drop=ALL --security-opt=no-new-privileges
--pids-limit=512 --memory=2g
```
网络被切断,因此工具可选的 LLM 或 CVE 查找阶段无法
连出 —— 离线 DB(trivy 的漏洞 DB、semgrep 规则集)被预构建在镜像中。
相同的输入产生相同的报告。崩溃、超时或不输出任何内容的工具
会在报告中变成 `tool-error`,而不是中止运行 —— 并且
完全失效的引擎(所有工具都失败)会以退出代码 `12` 大声报错,绝不会静默 PASS。
远程目标在禁用 hooks 的情况下以 depth-1 方式克隆,不获取 submodules 和 LFS,
并且符号链接以惰性方式写入;在此基础上会运行一次转义符号链接扫描,
而扫描本身发生在 `--network=none --read-only` 容器内。
## 目标
三种目标类型
| 目标 | 行为 |
| --- | --- |
| 一个 skill 文件夹(存在 `SKILL.md`) | 作为一个 skill 扫描。 |
| 一个包含多个 skill 的目录 | 发现每个 `SKILL.md` 根目录并并行扫描。 |
| 一个远程 https Git URL | 克隆到加固的临时 checkout 中,然后如上所述进行发现。 |
`--offline` 拒绝远程目标;无论何种情况,默认的 Docker 沙箱都会在每次扫描时切断网络。
## 选项
所有 flag;`skillward --help` 打印相同的内容。
所有 flag 及其默认值
| 选项 | 默认值 | 描述 |
| --- | --- | --- |
| `...` | *(必填)* | Skill 文件夹、包含多个 skill 的目录或 https Git URL。参见 [目标](#targets)。 |
| `--fail-on ` | `high` | 在达到或高于此严重性时失败(退出 20):`none`、`low`、`medium`、`high`、`critical`。 |
| `--format ` | `terminal` | 报告格式:`terminal`、`markdown`、`json`、`sarif`。参见 [输出格式](#output-formats)。 |
| `--output `, `-o` | stdout | 将报告写入文件而不是 stdout(去除颜色)。 |
| `--without ` | none | 要从集合中剔除的工具,以逗号分隔。参见 [扫描器](#scanners)。 |
| `--with ` | none | 要重新添加的工具(例如被 `--without` 剔除的工具),以逗号分隔。 |
| `--sandbox ` | `docker` | 扫描器运行的位置:`docker`(加固包)或 `host`(本地二进制文件)。 |
| `--jobs `, `-j` | 感知设备 | 扫描的工作线程;skill 及其工具共享该池。 |
| `--offline` | `false` | 拒绝远程目标;Docker 沙箱在每次扫描时已经切断了网络。 |
| `--no-color` | `false` | 禁用彩色输出。 |
子命令
| 命令 | 描述 |
| --- | --- |
| `install` | 拉取扫描器包镜像(一次性,需要 Docker)。 |
| `update` | 重新拉取固定的包镜像。 |
| `skills list` · `skills get [name]` | 列出或打印内置的 agent skill。参见 [Agents](#agents)。 |
### 环境变量
覆盖默认值的变量
| 变量 | 默认值 | 描述 |
| --- | --- | --- |
| `SKILLWARD_BUNDLE_IMAGE` | 固定的引用 | 覆盖扫描器包镜像 —— 标签或 `@sha256:` 摘要,用于字节级可复现或气隙扫描。 |
## 输出格式
四种报告格式
| `--format` | 内容 |
| --- | --- |
| `terminal` | 彩色摘要 —— 判定、印证、每个发现的单独行(默认)。 |
| `markdown` | Markdown 报告,每个 skill 带有一个发现表格。 |
| `json` | 用于工具的版本化 schema —— 判定、融合的发现、来源、tool-errors。 |
| `sarif` | SARIF 2.1.0,每个贡献工具有一次运行,适用于代码扫描消费者。 |
`-o
` 将报告写入文件(去除颜色);否则打印到
stdout,计划横幅和状态在 stderr 上。
## Agents
skillward 附带了一个 agent skill —— 它自己的用法与分诊指南 —— 用于编码 agent。将其安装到 agent 中:
```
npx skills add coroboros/skillward
```
或者不安装直接内联阅读:
```
skillward skills get skillward # print the bundled skill to stdout
skillward skills list # list bundled skills
```
`skillward --help` 带有 `Agents:` 页脚,包含相同的指引。该 skill 驱动 CLI 扫描 skill、包含多个 skill 的目录或远程 URL,然后将报告分诊为安装 / 不安装 / 修复的决定。同一份 Markdown 是唯一的来源 —— 为 `skills get` 嵌入二进制文件,并为 `npx skills add` 发布。
## 退出代码
跨版本稳定 —— 只增不改,绝不重新编号。
退出代码约定
| 代码 | 含义 |
| --- | --- |
| `0` | 干净,或所有均低于 `--fail-on` |
| `1` | 意外错误(例如未能写入报告) |
| `2` | 用法错误(错误的 flag 或值,无目标) |
| `10` | 未找到目标 |
| `11` | 远程克隆失败、不支持的传输方式 (http/ssh/git/file),或在 `--offline` 下被拒绝 |
| `12` | 扫描引擎故障(Docker 不可用,或没有扫描器产生输出) |
| `13` | 扫描器包镜像不可用(未拉取,或拉取失败) |
| `14` | 被拒绝:`--sandbox host` 目标具有逃逸出 skill 根目录的符号链接 |
| `20` | 发现达到或高于 `--fail-on` |
## 局限性
- **默认使用 Docker。** 完整的集合以容器镜像形式提供;
首次拉取的数据量很大。`--sandbox host` 则运行本地安装的扫描器。
- **静态、只读。** skillward 绝不执行被扫描的 skill —— 它无法捕获
仅在 runtime 才显现的威胁。
- **检测是继承的。** 覆盖范围完全是内置工具能检测到的;
skillward 增加了完整性、融合和稳定的门控,而不是新规则。
## 与替代方案比较
大多数审查 agent skill 的工具都是单一的扫描器:一个引擎,一种检测
理念,直接在文件上运行。有几个工具编排了多个扫描器,但每一个
都舍弃了 skillward 保留的某些东西:隔离、离线操作、交叉印证或门控。
| 工具 | 方法 | 多个外部工具 | 沙箱扫描 | 离线 | 跨工具印证 | 稳定的 CI 门控 |
| --- | --- | :---: | :---: | :---: | :---: | :---: |
| **skillward** | 9 个确定性扫描器,已融合 | 是 | 是 | 是 | 是 | 是 |
| [SkillSpector](https://github.com/NVIDIA/SkillSpector) | 正则表达式 + AST + 可选 LLM | 否 | 否 | 基本上是 | 否 | — |
| [ramparts](https://github.com/highflame-ai/ramparts) | YARA + LLM + OWASP-MCP 标签 | 否 | 否 | 否 | 否 | 部分 |
| [cc-audit](https://github.com/ryo-ebata/cc-audit) | 无 AI 的正则表达式规则 | 否 | 否 | 是 | 否 | 是 |
| [agent-audit](https://github.com/HeadyZhang/agent-audit) | AST + 污染 + secrets | 否 | 否 | 是 | 否 | — |
| [Cisco skill-scanner](https://github.com/cisco-ai-defense/skill-scanner) | 8 个内部引擎 + 元分析器 | 内部 | 否 | 否 | 是 | — |
| [shield-claude-skill](https://github.com/alissonlinneker/shield-claude-skill) | 封装 Semgrep + gitleaks + Trivy | 是 | 否 | 否 | 仅去重 | 否 |
| semgrep / gitleaks / trivy,单独使用 | 单个引擎,手动运行 | 否 | 否 | 是 | 否 | 每个工具单独 |
单元格反映了每个工具自己的文档和来源;`—` 表示该属性未由其
主要来源确定,并非确认的“否”。具体细节:SkillSpector 的 LLM 阶段是
可选的,其确定性核心是离线的;ramparts 连接到实时的 MCP endpoint
和 LLM;Cisco 的 LLM、VirusTotal 和 AI-Defense 层需要 API 密钥和网络,
并且它的八个引擎是内部模块,而不是独立的工具;shield-claude-skill
按 `(文件, 行, 工具)` 去重,所以来自两个工具的相同问题永远不会被合并
或提升置信度,并且它不提供隔离和退出代码门控。
skillward 的定位是它们都没有占据的交集:多个确定性
外部扫描器,每一个都在加固的 `--network=none` 容器中运行,离线
融合并带有跨工具印证,位于具有稳定退出的 `--fail-on` 门控之后。
## 贡献
欢迎提交 Bug 报告和 PR。
- 在提交非平凡的 PR 之前先开启一个 issue。
- 提交遵循 [Conventional Commits](https://www.conventionalcommits.org/)。
- 在推送之前运行 `cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo test`。
- 新的扫描器必须确定且离线运行,并添加集合中尚不存在的维度;
添加其适配器并在包代码库的 `smoke-test.sh`
(`coroboros/infrastructure/skillward-bundle`) 中镜像其 argv。
- 以 `main` 分支为目标。
## 许可证
[MIT](LICENSE.md)标签:AI代理, Docker, Rust, 可视化界面, 安全防御评估, 文档安全, 日志审计, 网络流量审计, 请求拦截, 逆向工具, 通知系统, 静态扫描