software-architecture-spec/sam
GitHub: software-architecture-spec/sam
SAM 是一份生产者签名的机器可读清单规范,用于声明软件的架构意图和运行包络,填补 SBOM 和 SLSA 无法覆盖的「软件被设计为什么」这一信息空白。
Stars: 1 | Forks: 0
# 软件架构清单 (SAM)
- [GitHub 仓库](https://github.com/software-architecture-spec/sam)
一份由生产者签名的、机器可读的声明,阐明了软件的设计目标以及为其设计的运行包络。
SBOM 告诉你软件里面有什么。SLSA 告诉你它是如何构建的。OpenSSF Scorecard 告诉你是否遵循了良好的实践。**SAM 告诉你生产者将其设计为什么。**
当前版本为 **v0.3**。请参阅 [`v0.3/SPECIFICATION.md`](v0.3/SPECIFICATION.md)。根据 `SPECIFICATION.md §6.3`(同 MAJOR 版本向后兼容),v0.1 和 v0.2 已被冻结,并仍保留在其 URI 处有效。未来版本将一同发布(v0.4、v0.5、……),并固定在各自的 URI 处.
## 为什么需要
在 AI 时代,一个凭直觉编码出的周末原型与一个经过强化的生产服务在视觉上是无法区分的:相同的 React 前端、相同的 Postgres、相同的 Dockerfile、相同的部署流水线。过去放在共享驱动器上的 Access 数据库会自动暴露其自身的脆弱性。而现代的等同物却不会。
SAM 恢复了这种信号。一份诚实声明了 `audience: single_user`、`scaling: none`、`observability: unspecified`、`tenancy: none` 的清单,*就是*现代版的 `.mdb` 文件,它在宣告自己的本质——而没有从技术栈选择中进行推断的歧义。
## SAM 是什么——以及它不是什么
**SAM 是**一份由生产者签名的关于*软件架构事实*的声明:意图、运行包络(包括第三方运营依赖项)、带有行业标准交叉引用的 ISO/IEC 25010:2023 质量声明,以及在跨属性冲突上所选择的立场。受众:任何需要评估软件设计目标的消费者——采购、安全、SRE、审计、AI agent、下游开发者。
**SAM 不是:**
- **合规框架**。SAM 不满足 DORA、NIS2、SOC 2、HIPAA、FedRAMP 或任何其他制度。受这些制度约束的消费者阅读 SAM 是为了填充他们自己的合规产物;SAM 的职责是作为架构输入层。
- **物料清单**。SBOM(CycloneDX、SPDX)列出了软件内部的组件;SAM 声明了软件被设计为什么。通过 `subject.sbomRef` 引用 SBOM。
- **构建证明**。SLSA / in-toto 涵盖了来源——即软件是如何构建的。SAM 是通过相同的信封签名的同级 predicate。
- **漏洞披露**。CSAF / VEX 涵盖了这一点。
- **许可证声明**。属于 SBOM 的领域。
- **法律合同**或**服务级别协议**。SAM 不具有自动的法律效力;单独的合同可以通过引用纳入 SAM 的声明。
- **测试或尽职调查的替代品**。证据 URI 引用了验证产物;阅读 SAM 并不能免除消费者根据自身的风险承受能力评估生产者声明的责任。
完整的规范范围请参见 [`SPECIFICATION.md §1`](v0.3/SPECIFICATION.md)。
## 层级 — 清单描述的内容
相同的问题(“它如何扩展”、“它以什么权限运行”、“它是多租户的吗”)在三个不同的层级会得到不同的答案,并由三种不同的受众阅读。SAM 通过 `subject.layer` 显式声明其层级:
| 层级 | 粒度 | 受众 | 备注 |
|---|---|---|---|
| `artifact` | 单个容器镜像、二进制文件或包 | AI agent、构建/SLSA、SBOM 工具 | 签名的粒度。必须提供 `digest`。匹配 in-toto subject 约定。 |
| `service` | 拥有 SLO 的逻辑单元(1 个或多个 artifact) | SRE、on-call、运维 | SLO 和事件响应实际存在的地方。`digest` 可选;使用 `components[]` 指向组成它的 artifact SAM。 |
| `product` | 合同/面向客户的层面 | 采购、审计、客户 | 被销售的产品。`components[]` 指向组成它的 service SAM。 |
一个小型项目可能只需要在 `artifact` 层拥有一个 SAM。一个真正的产品通常三层都有,每一层的清单都通过 `subject.components[]` 引用其组成部分。组合是显式的;没有什么是推断出来的。
## 等级 — 清单向你提供多少信息
一个 SAM 要么符合规范,要么不符合。但生产者和消费者也需要一套词汇表,以表达 SAM 向他们提供了*多少*信息。SAM 等级(`SPECIFICATION.md §9`)定义了四个层级:
| 等级 | 含义 | 受众成本 | 合规姿态 |
|---|---|---|---|
| **L0** | 不存在 SAM | 不适用 | 需要逆向工程 |
| **L1** | 符合规范的 SAM(根据 §5.1)已签名并绑定到其 subject | 中等吸收成本 | 可进行初步评估 |
| **L2** | L1 + 每个非平凡声明都有 `industryRefs[]` | 审计员自动化 | 足以应对许多第三方风险流程 |
| **L3** | L2 + 每个 `verified` 声明都有 `evidence[]`;冲突已声明;`validFor` 是最新的 | 映射到严格合规 | 在受监管的环境中,可在很大程度上替代直接的尽职调查 |
等级关乎*可评估性*,而非*质量*。一份声明“P95 延迟为 30 秒”的 L3 清单是符合 L3 规范的;至于 30 秒是否可接受,这属于消费者的判断,不在 SAM 的范围内。
## 结构
```
manifest
├── manifestVersion schema version (v0.3)
├── subject what this manifest describes
│ ├── layer artifact | service | product (granularity declaration)
│ ├── name, version
│ ├── digest required at layer=artifact, optional at service/product
│ ├── sbomRef optional pointer to SBOM
│ └── components[] lower-layer subjects (for service/product manifests)
├── intent purpose, audience, tenancy, out-of-scope
│ ├── tenancy model + isolationGuarantees + dataResidency[]
│ ├── deliveryForm saas | self_hosted_service | library | cli_tool | desktop_app | mobile_app | browser_extension | infrastructure | appliance (new in v0.3)
│ ├── architecturalStyle monolith | modular_monolith | microservices | serverless | event_driven | actor | hybrid (new in v0.3)
│ └── architecturalPatterns[] well-known patterns — circuit_breaker, saga, cqrs, … (registry/patterns.json) (new in v0.3)
├── envelope operational design target (the "what was it built for")
│ ├── throughput target/max RPS, latency SLOs, concurrency
│ ├── scaling axis (horizontal/vertical/none), statefulness
│ ├── instantiation mode + coordination + ordering / idempotency / conflictResolution (detail new in v0.3)
│ ├── privilege root_required / unprivileged / capability_scoped
│ ├── network isolated / egress_only / ingress_only / bidirectional
│ ├── dependencies[] third-party ICT services; deliveryForm + role (split from 'type' in v0.3)
│ ├── serviceLevels SLA / SLO bucket — service/product layer only
│ └── persistence stores + replication / consistency / backup / encryption (detail new in v0.3)
├── qualityAttributes ISO/IEC 25010:2023 — 9 characteristics + sub-characteristics
│ (defined in our own words at SPECIFICATION.md §10)
├── extensions quality concerns ISO 25010 doesn't cover cleanly
│ ├── observability (folds awkwardly under maintainability.analysability)
│ ├── dataLifecycle retention, deletion, archival
│ └── internationalization
├── tensionsDeclared which side of CAP/observability-cost/etc. did you pick?
└── producer issuer + contact + issuedAt + validFor
industryRefs[] entries gain optional auditor / auditPeriod / dateAttested in v0.2.
x-* extension keys are permitted on:
qualityAttributeClaim, qualityAttributes characteristic objects,
tensionsDeclared[] items, industryRefs[] items, evidence[] items,
producer, subject.components[] items.
```
### 声明状态
每个质量属性声明都具有以下四种状态之一:
- `unspecified` — 生产者不作声明。(诚实的缺失胜过虚假的保证。)
- `declared` — 生产者作出声明但不提供证据。(凭他们的一面之词。)
- `verified` — 生产者作出声明并指向证据(负载测试、安全扫描、审计、CI 运行)。
- `not_applicable` — 生产者声称此属性与此 artifact 无关。
这种三轨模型(declared / verified / unspecified)反映了 SBOM 标准随着时间的推移是如何增加证明通道的。v0.x 对仅包含声明的清单很友好;v1 将为 `verified` 轨道定义更严格的证明要求。SAM 等级(§9)在这些状态之上进行叠加,以表达清单中有多少内容是经过锚定和提供证据的。
## 标准对齐
SAM 对每个声明使用两个引用层:
- **`industryRefs[]`** — *规范性*。审计员和采购团队认可的行业标准锚点。在清单中作为一等公民存在,因为它们比任何单一的主机或供应商都更持久。
- **`informationalRefs[]`** — *非规范性*。指向设计上下文资源(模式目录、内部文档、知识库)的 https URI,这些资源辅助了生产者的推理。对于想要深入了解逻辑依据的 AI agent 和人类很有用;但不是审计员所依赖的锚点。
### 顶级标准
| 层级 | 标准 | 所在位置 |
|---|---|---|
| 软件供应链(内容) | SBOM (CycloneDX / SPDX) | `subject.sbomRef` |
| 构建出处 | SLSA / in-toto | 外部证明;SAM 是同级 predicate |
| 质量模型骨架 | **ISO/IEC 25010:2023** | `qualityAttributes` 键 = 9 项特征 |
| 运营第三方风险 | EU DORA Art. 28, NIS2, ISO/IEC 27036, NIST SP 800-161 | `envelope.dependencies[]` |
### 各部分的行业锚点(用作 `industryRefs[]`)
| 部分 | 推荐锚点 |
|---|---|
| `qualityAttributes.security.*` | NIST SP 800-218 (SSDF), OWASP ASVS L1/L2/L3, ISO/IEC 27001, SOC 2, NIST SP 800-53, **CIS Benchmarks**, **NIST SP 800-190** (containers) |
| `qualityAttributes.interactionCapability.inclusivity` | WCAG 2.2 (A / AA / AAA), EN 301 549, Section 508 |
| `qualityAttributes.compatibility.interoperability` | OpenAPI 3.x, AsyncAPI, SCIM, SAML, OAuth 2.x, OIDC |
| `qualityAttributes.flexibility.installability` | OCI Image Spec, Helm chart schema |
| `qualityAttributes.safety`(特定领域) | ISO 26262 (automotive), IEC 62304 (medical), DO-178C (aviation), IEC 61508 (industrial) |
| `qualityAttributes.functionalSuitability` | ISO/IEC 25010:2023 (correctness/completeness/appropriateness) |
| `envelope.dependencies[]` | EU DORA Art. 28, NIS2, ISO/IEC 27036, NIST SP 800-161 |
| `extensions.observability` | OpenTelemetry semantic conventions |
| `extensions.dataLifecycle` | ISO/IEC 25012, GDPR articles, CCPA, HIPAA, SOX §802, PCI DSS, **NIST SP 800-88 Rev. 1** (deletion side) |
| `extensions.internationalization` | Unicode CLDR, ICU MessageFormat, BCP 47 |
| 构建/供应链(顶级) | SLSA build level (L0–L3, where L0 = no claim), in-toto attestation, CycloneDX/SPDX |
这些只是起点,并非详尽无遗的列表。生产者使用其审计/采购上下文实际认可的任何标准填充 `industryRefs[]`。schema 没有将 `standard` 字段限制为枚举;`/registry/standards.json` 配套产物提供了规范的拼写作为指导性建议。
### 为什么选择 ISO 25010,但不仅限于此
ISO 25010:2023 被采用作为 `qualityAttributes` 的规范键集,因为它是采购、审计和认证已经使用的正式质量模型。生产者可以为粗略的清单按特征填充 `overall` 声明,或者深入到 `subCharacteristics` 进行细粒度填充。
ISO 25010 存在空白。可观测性没有一等公民的位置(它被折叠在 `maintainability.analysability` 下);数据生命周期和 i18n 根本没有正式的位置。这些存在于 `extensions` 中。
运营 `envelope`(租户、实例化模式、权限、网络姿态、依赖项)故意不作为 `qualityAttributes` 的一部分——这些是部署/运营信号,而不是质量声明。它们回答了“它是为什么而设计的”,正式的质量模型将其视为输入而不是输出。
## 签名
清单是一个 **predicate** — 意图的声明。签名将其包装在 DSSE 信封或 sigstore bundle 中,与今天签署 SBOM 和 SLSA 证明的方式相同。
```
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [{ "name": "metrics-dashboard-api", "digest": { "sha256": "..." } }],
"predicateType": "https://software-architecture-spec.github.io/sam/v0.3",
"predicate": { ...the manifest body... }
}
```
这意味着 cosign、sigstore 以及任何感知 in-toto 的工具都可以对 SAM 进行签名和验证,而无需发明新的密钥系统。通过 `subject.digest` 将清单绑定到 artifact。
## 文件
### 版本化(`v0.3/` — 当前)
- [`v0.3/SPECIFICATION.md`](v0.3/SPECIFICATION.md) — 规范性文档(§§1–10;`§6.6` 列出了 v0.3 的更改)
- [`v0.3/schema.json`](v0.3/schema.json) — JSON Schema (Draft 2020-12),增加了 `intent.deliveryForm`、`intent.architecturalStyle`、`intent.architecturalPatterns[]`,`envelope.persistence` 上的存储细节,`envelope.instantiation` 上的并发细节,以及 `dependencies[].type` → `deliveryForm` + `role` 的拆分
- [`v0.3/examples/saas.manifest.json`](v0.3/examples/saas.manifest.json) — 多租户 SaaS API(公有云形态)
- [`v0.3/examples/internal-enterprise.manifest.json`](v0.3/examples/internal-enterprise.manifest.json) — 内部员工入职门户(企业内部形态:SSO、无公有暴露、合规留存、WCAG 2.2 AA)
- [`v0.3/examples/caddy.manifest.json`](v0.3/examples/caddy.manifest.json) — 针对真实 OSS Web 服务器 [Caddy](https://caddyserver.com/) 的说明性 artifact 层清单。*不是*来自 Caddy 项目的真实生产者签名清单;作为教学材料包含在内。
- [`v0.3/conformance/`](v0.3/conformance/) — 由 `manifest.json` 索引的测试语料库;包含 `§5.1` 中的正反面案例以及针对 v0.3 字段的案例。
### 已冻结的历史版本
- [`v0.2/`](v0.2/) — 字节完全一致,并根据 `§6.3` 同 MAJOR 版本向后性解析在其 URI 处。
- [`v0.1/`](v0.1/) — 首个公开草案。字节完全一致,并根据 `§6.3` 解析在其 URI 处。
未来版本将一同发布(`v0.3/`、`v0.4/`、……),并且不会干扰已发布的 URI。
### 配套注册表(`registry/` — 独立进行版本控制)
- [`registry/standards.json`](registry/standards.json) — `industryRefs.standard` 的规范拼写(SPDX List 模式;建议性)
- [`registry/tensions.json`](registry/tensions.json) — `tensionsDeclared[].tension` 的知名 ID(来自 §5.1.11 的五个)
- [`registry/README.md`](registry/README.md) — 注册表结构、版本控制和贡献模型
### 验证
```
# 运行所有检查:schema、metaschema、每个版本的 examples、conformance corpus、registries。
python3 tools/validate.py
```
验证器(`tools/validate.py`)是标准的入口点。它运行于:
- **在每次推送到 `main` 的推送和 pull request 时进行 CI** 通过 [`.github/workflows/validate.yml`](.github/workflows/validate.yml) — 对所有提议的更改强制执行。
- **作为 pre-commit hook 在本地运行**,如果你选择开启:
git config core.hooksPath .githooks
pip install jsonschema # 一次性操作
在此之后,`git commit` 会在任何涉及 `sam/`、`registry/`、验证器本身或 CI 工作流的更改上运行验证器。只有在你明白自己要跳过什么的情况下,才使用 `git commit --no-verify` 绕过。
要在不使用完整语料库的情况下对单个示例进行临时验证:
```
check-jsonschema --schemafile v0.3/schema.json v0.3/examples/saas.manifest.json
```
## 状态
v0.3 — 当前版本。当 `MAJOR` 为 `0` 时,仍可能发生破坏性更改(根据 `SPECIFICATION.md §6.1`)。v0 的目标是确定正确的字段集,而不是锁定格式。除了 §6.1 允许的一项更改外,v0.3 相比 v0.2 是增加性的:`dependencies[].type` 枚举被拆分为 `deliveryForm` + `role`(参见 `§6.6`)。v0.1 和 v0.2 清单在各自冻结的 URI 下仍然符合规范。
### v0.3 约定
- **允许 `x-*` 扩展** 在 `qualityAttributeClaim`、`qualityAttributes` 特征对象、`tensionsDeclared[]` 项目、`industryRefs[]` 项目、`evidence[]` 项目、`producer` 和 `subject.components[]` 项目上。在顶级清单、`subject` 根节点、`manifestVersion`、`intent`(以及 `tenancy`)、`qualityAttributes` 父节点和所有 `envelope` 的子块上禁止使用。参见 `SPECIFICATION.md §7`。
- **稳定性注释** 在每个字段的 `description` 上(`Stability: stable | experimental`),并在稳定字段上添加 `x-sam-stability` 关键字。参见 `SPECIFICATION.md §8`。
- **开放枚举** 用于 `tensionsDeclared.tension`、`industryRefs.standard` 和 `intent.architecturalPatterns[]` — `/registry/tensions.json`、`/registry/standards.json` 和 `/registry/patterns.json` 提供建议性的规范 ID。**封闭枚举** 用于 `intent.deliveryForm`、`intent.architecturalStyle` 和新的 `envelope` 存储/并发字段;`/registry/delivery-forms.json` 记录了交付形式。
- **`informationalRefs[]` 需要 URI。**使用 https。
### 待解决问题
- 针对 ISO 25010 子特征键的按特征枚举约束(目前出于易用性考虑为任意字符串)。
- 条件性的 `if/then`,使得 `status: verified` 时需要 `evidence`,且 `status: declared|verified` 时需要 `summary`(目前仅由规范强制执行 §5.1.6/§5.1.7,并在一致性语料库中呈现)。
- `tensionsDeclared` 是否应该是必需的(目前:可选)。
- 证据验证:schema 是否应该要求证据 URI 本身是已签名的证明?
- 是否要添加 `lifecycle` 部分(active、maintenance、deprecated、abandoned),还是将其留给包元数据。
- 对于非 artifact 层的感知 subject 的 DSSE 绑定 — service 和 product 层清单具有可选的 `subject.digest`;将它们绑定到没有 digest 的 subject 标识符目前尚不明确。
### v0.3 之后的计划
- **编写指南** — 为生产者提供关于如何按属性填充内容以及如何编写诚实摘要的实用指南。
- **验证指南** — 为消费者提供关于如何在不同决策上下文中评估 SAM 的实用指南。
- **生命周期策略** — 重新发布、撤销、替代。
- **冲突和标准注册表的增长** — 版本控制、贡献工作流、别名管理。
- **`x-sam-stability` 验证行为** — 目前是描述性的;未来版本可能会赋予其语义(例如,消费者拒绝承诺为 `stable` 却使用 `experimental` 字段的清单)。
## 许可证
该项目采用双重许可。
- **代码、schema、示例、一致性语料库和注册表**(`sam/**/schema.json`、`sam/**/examples/*`、`sam/**/conformance/*`、`registry/*.json`、未来的工具)采用 [Apache-2.0](LICENSE) 许可。这里首选 Apache-2.0 而不是 MIT,因为它包含明确的专利授权——这对于在签名和验证流程方面具有潜在专利面的标准非常重要。
- **规范文本和其他散文**(`README.md`、`sam/**/SPECIFICATION.md`、`registry/README.md`、`sam/**/conformance/README.md`)采用 [知识共享署名 4.0 国际许可协议 (CC-BY-4.0)](LICENSE-DOCS) 许可。这遵循了 SLSA 和 SPDX(较新版本)对于规范文本使用的惯例:只要声明出处,即允许衍生文档。
本仓库的意图是在声明出处的情况下进行广泛重用。
标签:元数据, 数据管道, 架构规范, 标准规范, 用户代理, 跌倒检测, 软件供应链, 软件工程, 软件物料清单