usnistgov/oscal-deep-diff
GitHub: usnistgov/oscal-deep-diff
NIST 开发的 OSCAL 文档深度差异比较工具,通过多种匹配算法实现复杂嵌套 JSON 工件的智能化结构化比对。
Stars: 41 | Forks: 11
# OSCAL Deep Diff
OSCAL Deep Diff 是一个 CLI 应用程序和库,能够生成与 schema 无关的 JSON 工件比较结果。
此工具的目的是比较 [OSCAL](https://pages.nist.gov/OSCAL/) 工件。
这项工作属于美国国家标准与技术研究院 (NIST) [OSCAL](https://pages.nist.gov/OSCAL/) 计划的一部分。
## 公共领域
此项目在全球范围内属于 [公共领域](./LICENSE.md)。
如 [CONTRIBUTING.md](./CONTRIBUTING.md) 中所述。
## 用法
有关端到端的使用示例,请参阅 [`examples/`](./examples/) 目录。
### CLI 安装
```
$ npm install -g @oscal/oscal-deep-diff
```
### 基础比较
OSCAL Deep Diff CLI 需要一个配置文件才能执行比较。
下面提供了一个示例配置文件:
```
leftPath: NIST_SP-800-53_rev5_catalog.json #replace with the JSON documents you want to compare
rightPath: NIST_SP-800-53_rev5_catalog.json
outputPath: output.json
# 这些将在本文档中进一步说明
comparatorConfig: {}
outputConfigs: []
```
此配置文件指示 deep diff 工具比较两个文档并生成一个输出文件 `output.json`。
示例 OSCAL 工件可以在 [这里](https://github.com/usnistgov/oscal-content) 找到。
要执行比较,请使用以下命令:
```
# 将 "config.yaml" 替换为您在上一步中创建的配置文件
$ oscal-deep-diff --config config.yaml
```
### 配置
OSCAL deep diff 的比较行为可以进行更改,以适应您比较的需求。
例如,在比较两个文档时,您可能希望忽略部分更改,比如 `id` 字段,因为它们在文档的多次修订中并不稳定。
有时也可能需要忽略某些字段的大小写,或者忽略文档的整个子集。
JSON 文档可能非常复杂,包含对象的嵌套数组。
deep diff 工具可以匹配对象数组,即使它们的顺序被打乱,但这种行为可以受到限制,以适应您比较的需求。
例如,在比较 [OSCAL Catalog](https://pages.nist.gov/OSCAL/concepts/layer/control/catalog) 的两个修订版时,该工具必须正确地将两个文档中的控制项匹配在一起。
这种匹配行为可以通过多种方式更改,例如直接通过 ID 匹配控制项(`AC-1` 始终映射到 `AC-1`,依此类推),或者通过选择产生最少“子更改”的控制项对。
OSCAL Deep Diff 配置的 `comparatorConfig` 字段控制此行为。
#### 结构解析
比较器配置包含一个指向配置对象的 JSON 指针映射。
下面是一个为 [OSCAL Catalog](https://pages.nist.gov/OSCAL/concepts/layer/control/catalog/) 量身定制的比较器配置示例:
```
comparatorConfig:
'*':
ignoreCase: true
'controls/#':
ignore:
- controls
id:
ignoreCase: false
priority: 1
/catalog:
ignore:
- back-matter
```
在此示例中,比较器将具有以下行为:
- `*`:所有字段都将以不区分大小写的方式进行比较(支持类 glob 语法)。
- `controls/#`:每个控制项的子控制项(增强项)将被忽略。
- `id`:任何 `id` 字段都将区分大小写进行比较,覆盖 `*` 配置。
- `/catalog`:当比较 `/catalog` 时,忽略 `back-matter` 字段。
请注意,配置映射中的每个项目都告诉比较器**如何比较其 JSON 指针匹配该模式的元素**。
此检查适用于所有 JSON 类型、对象(例如 `/catalog`)、基元(例如 `id`)和数组(例如 `controls`)。
#### 对象配置
- `ignore: string[]`:用于忽略与比较无关的对象属性。
#### 基元配置
- `ignoreCase: boolean`:用于对字符串元素进行不区分大小写的比较。
- `stringComparisonMethod: 'jaro-winkler' | 'cosine' | 'absolute'`:对于字符串元素,此设置控制如何使用 [Jaro-Winkler](https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance)、余弦或绝对编辑距离策略对字符串进行加权。
例如,UUID 应该始终进行绝对比较,但在某些情况下,彼此相似的属性中也存在一定意义。
#### 数组配置
- `matcherGenerators: []`:数组比较是一个难以解决的问题,因为匹配是一项开销很大的操作。
OSCAL Deep Diff 通过匹配最小化子更改数量的数组元素来比较数组。
这种匹配可以通过几种方式完成,这些方式各有利弊。
`matcherGenerator` 允许您指定比较数组的方式。
以下是可用的匹配器生成器类型:
- `ObjectPropertyMatcherContainer`:此算法仅通过对象属性来匹配数组项。
例如,可以将比较配置为通过查找具有相同 `id` 属性的对象来匹配对象数组。
此算法产生结果最快,但要求用户根据其正在比较的文档的属性来调整比较。
示例:
matcherGenerators:
- type: ObjectPropertyMatcherContainer
property: id
- `OptimalMatcherContainer`:此算法查找给定对象数组包含的属性,然后使用与 `ObjectPropertyMatcherContainer` 相同的逻辑尝试通过每个属性匹配对象。
产生最少更改数量的属性将被选中。
此容器没有配置选项。
示例:
matcherGenerators:
- type: OptimalMacherContainer
- `HungarianMatcherContainer`:[匈牙利算法](https://en.wikipedia.org/wiki/Hungarian_algorithm) 是一种可用于将项目匹配在一起的算法。
选择此匹配器时,将使用以下方法将数组项匹配在一起:
1. 比较数组项的每种可能组合,生成可能组合及其相关分数的邻接矩阵。
2. 使用代表未匹配元素的附加项扩充邻接矩阵(允许将项目标记为已添加或已删除)。
3. 在邻接矩阵上调用匈牙利算法的实现,生成一个配对数组。
此算法在空间和时间上开销最大。
它也是在无需任何调整的情况下最有可能产生良好结果的选项。
示例:
matcherGenerators:
- type: HungarianMatcherContainer
- `outOfTreeEnabled: boolean`:启用时,可以进行跨树比较。
此选项在处理嵌套的对象数组时很有用,因为对象可能会从一个子数组移动到另一个子数组。
一个很好的例子是 [OSCAL Catalog](https://pages.nist.gov/OSCAL/concepts/layer/control/catalog/) 模型,它具有被组织成组的控制项。
如果在 `control` 上将 `outOfTreeEnabled` 设置为 true,比较器将检查在组之间移动的控制项。
#### 其他配置
- `priority: number`:如果两个指针匹配,则使用优先级来决定应用哪个设置。优先级越高,意味着重叠的设置将优先。
### 输出
进行比较后,输出仅为一个 JSON 文档。
比较文档的根包含 3 个属性:`leftDocument`、`rightDocument` 和 `changes`。
左右文档指的是指定的文档路径。
将 `oscal-deep-diff` 用作库时,这些是手动设置的,并且可以指向 URL。`changes` 属性包含比较器找到的更改列表。
更改类型包括:
- `property_changed`:该属性在两个文档中都存在,但已更改。
- `property_added`:该属性仅存在于右侧文档中。
- `property_deleted`:该属性仅存在于左侧文档中。
- `array_changed`:项数组已更改。此更改类型更复杂,其中包含仅存在于右侧文档中的数组项、仅存在于左侧文档中的数组项,以及存在于两个文档中但子文档中存在差异的数组项。
### 替代输出
比较的 `outputConfigs` 属性用于将原始输出转换为更易于理解的文档。
例如,随着控制项数量的增加,对两个 [OSCAL Catalogs](https://pages.nist.gov/OSCAL/concepts/layer/control/catalog/) 的比较通常变得非常难以处理。
原始输出可以转换为 Excel 文档,该文档会收集所有控制项级别的更改。
```
outputConfigs:
- selection: controls
identifiers:
- 'id'
- 'title'
outputType: excel
outputPath: output.xlsx
```
## 引用
此项目有一个相关的 [DOI](https://www.doi.org/) 条目:[`doi:10.18434/mds2-2727`](https://data.nist.gov/od/id/mds2-2727)。
标签:JSON, MITM代理, OSCAL, 合规管理, 差异比较, 文档结构分析, 暗色界面, 自动化攻击