供应链与依赖治理
正在读取学习记录…
Agent 的“读取笔记”工具依赖一个解析库。即使工具代码没改,解析库升级也可能改变输出格式或增加联网行为。供应链指应用从源代码到运行环境所依赖的一整串输入:第三方库、间接依赖、模型权重、容器基础镜像、构建脚本和发布制品。依赖治理就是把这些输入的来源、版本、用途和更新责任管起来。
正常发布时,团队审核过 notes-adapter 1.2.0 和 text-parser 2.0.0,部署拿到同样两个版本、同样内容,检查通过后才使用。这里有三个独立问题:拿的是哪一版、拿到的字节是否一致、这一版是否适合继续使用。下面把前两个问题落到一个本地校验器。
为什么版本和指纹要一起检查
锁定表示明确写出版本,避免“满足条件的最新版本”在不同时间变成不同内容。指纹是文件内容经过哈希函数得到的摘要;程序采用 SHA-256,同一份字节得到相同摘要,内容改变后摘要通常会完全不同。它适合比较完整性,批准者身份则要靠受保护的审核清单、签名和来源流程确认。
| 输入发生了什么 | 版本检查 | 指纹检查 | 处理 |
|---|---|---|---|
| 两个已批准制品原样使用 | 一致 | 一致 | 继续 |
| 版本仍写1.2.0,内容加一个字节 | 一致 | 不同 | 拒绝该制品 |
| 相同内容标成1.2.1 | 不同 | 一致 | 进入升级审核 |
| 多一个未登记的间接依赖 | 集合不同 | 无批准值 | 补齐清单并审核 |
pip 的安全安装文档要求启用哈希检查时锁定需求,并覆盖全部依赖。实际项目应从可信渠道建立锁定清单,把解析出的间接依赖一起纳入。直接依赖是你主动引用的库;间接依赖是这些库继续引用的其他库,风险同样会进入应用。
把审核清单和候选制品分开
图中蓝色清单是批准输入,绿色候选是准备使用的输入。校验器只读两边并比较,不在校验过程中重算批准清单。如果从候选制品现算一个指纹再立即当批准值,比较会永远通过。
示例用两段短字节表示本地制品,不执行制品内容。APPROVED 是固定的教学基准;真实发布中,批准清单应独立保存并限制修改权限。程序先比较集合,再逐项比较版本和摘要,任何差异都给出具体原因。
在 PowerShell 中建立新文件夹 l8-supply-chain。把下方完整代码分别保存为 verify_supply.py 和 test_verify_supply.py,两个文件放在同一目录。
先在 PowerShell 创建并进入目录,再保存下方两份文件:
New-Item -ItemType Directory -Force l8-supply-chain
cd l8-supply-chainmacOS 终端:
mkdir -p l8-supply-chain
cd l8-supply-chain"""校验固定版本和本地制品指纹,不安装或执行依赖。"""
from hashlib import sha256
# 已审核的制品内容与清单分开保管,清单不会随待检查内容重算。
APPROVED = b"notes-adapter:read-only:v1"
LOCK = {
"notes-adapter": {"version": "1.2.0", "sha256": sha256(APPROVED).hexdigest()},
"text-parser": {"version": "2.0.0", "sha256": sha256(b"text-parser:v2").hexdigest()},
}
ARTIFACTS = {
"notes-adapter": ("1.2.0", APPROVED),
"text-parser": ("2.0.0", b"text-parser:v2"),
}
TAMPER = False
def verify(lock, artifacts):
# 额外依赖和遗漏依赖都破坏审核过的依赖集合。
if set(lock) != set(artifacts):
return ["依赖集合不同"]
errors = []
for name, expected in sorted(lock.items()):
version, payload = artifacts[name]
if version != expected["version"]:
errors.append(f"{name}:版本不符")
if sha256(payload).hexdigest() != expected["sha256"]:
errors.append(f"{name}:指纹不符")
return errors
def main():
candidates = dict(ARTIFACTS)
if TAMPER:
# 改一个字节即可破坏完整性;这些字节始终作为数据处理。
candidates["notes-adapter"] = ("1.2.0", APPROVED + b"!")
errors = verify(LOCK, candidates)
print("依赖数:", len(candidates))
print("校验:", "通过" if not errors else "拒绝")
print("原因:", "、".join(errors) if errors else "集合、版本、指纹一致")
if __name__ == "__main__":
main()测试文件 test_verify_supply.py:
"""覆盖完整性、版本锁定与依赖集合的变化。"""
import unittest
from verify_supply import APPROVED, LOCK, ARTIFACTS, verify
class SupplyTests(unittest.TestCase):
def test_reviewed_artifacts(self):
self.assertEqual(verify(LOCK, ARTIFACTS), [])
def test_changed_byte(self):
changed = dict(ARTIFACTS)
changed["notes-adapter"] = ("1.2.0", APPROVED + b"!")
self.assertEqual(verify(LOCK, changed), ["notes-adapter:指纹不符"])
def test_same_bytes_new_version(self):
changed = dict(ARTIFACTS)
changed["notes-adapter"] = ("1.2.1", APPROVED)
self.assertEqual(verify(LOCK, changed), ["notes-adapter:版本不符"])
def test_missing_and_extra(self):
self.assertEqual(verify(LOCK, {}), ["依赖集合不同"])
self.assertEqual(verify(LOCK, {**ARTIFACTS, "extra": ("1", b"x")}),
["依赖集合不同"])
def test_empty_inventory(self):
self.assertEqual(verify({}, {}), [])
if __name__ == "__main__":
unittest.main()文件保存后,在同一窗口核对文件名并运行:
ls
python -X utf8 verify_supply.py
python -X utf8 -m unittest -v test_verify_supply.pydir应显示这两个文件。运行程序后得到下面输出;测试末尾应显示 OK。
程序输出:
依赖数: 2
校验: 通过
原因: 集合、版本、指纹一致让一个字节触发拒绝
在 verify_supply.py 找到唯一一行 TAMPER = False,改成 TAMPER = True,保存后运行:
python -X utf8 verify_supply.py依赖数仍是2,校验变成“拒绝”,原因是 notes-adapter:指纹不符。变化发生在候选制品的尾部,批准清单没有变。恢复 TAMPER = False,再执行相同命令,应重新通过。
测试中的版本变化、遗漏和额外依赖检查都已给定输入;直接运行测试即可核对。空集合对空集合在算法上通过,发布流程还要单独判断“本应用是否应该存在依赖”,避免把空清单误当成完整物料表。
升级时怎样做决定
出现安全公告时,先定位受影响版本以及是否调用了相关功能,再准备候选升级。比较清单变化,跑工具输出契约和安全回归,审批后替换清单并保留旧制品。回滚时应使用原来批准的版本与内容,临时重新拉“最新版”会让故障复现困难。
软件物料清单(SBOM)记录组成软件的组件、版本和关系,方便查“哪个应用用了受影响的库”。它与漏洞扫描相配合:扫描器把组件版本匹配到已知公告,维护者再判断可达性和修复优先级。哈希一致说明内容与批准基准一致,漏洞是否存在仍需单独检查。
| 具体场景 | 检查入口 | 下一步 |
|---|---|---|
| 指纹不同但文件名相同 | 候选来源与批准清单 | 隔离候选,重新获取并比较 |
| 解析库升级后返回字段消失 | 工具契约测试 | 保持旧版,调整适配器后再发布 |
| 已批准库被披露严重漏洞 | SBOM与安全公告 | 评估影响,升级或暂时关闭功能 |
| 模型权重替换,输出风格改变 | 权重标识与业务回归 | 将权重变化纳入发布审核 |
供应链检查放在构建和启动之前,运行期继续控制工具权限和网络出口。这样,依赖来源、内容完整性和实际执行权限分别有自己的控制位置。
课后练习展开习题收起习题
正在读取本地记录…
不调用模型,不执行代码。简答、代码和场景题仅保存答案并展示自查标准,不生成评分、徽章或认证。输入内容不会自动保存,请点击提交;不要填写个人信息或密钥。
选择题 · 先判断边界
关于“供应链与依赖治理”,哪种做法更稳妥?
对应知识点:L8-supply-chain
简答题 · 解释失败
写出一个失败输入并说明记录字段。
对应知识点:L8-supply-chain
代码题 · 边界测试
补充正常、边界、失败三组输入和预期结果。
对应知识点:L8-supply-chain
场景题 · 结果未知
证据不足时如何设计状态和人工接管?
对应知识点:L8-supply-chain
继续阅读身份、RBAC与ABAC,把“软件由哪些输入组成”接到“谁能执行哪些动作”。
描述会发送给本站维护者,用于修订文章,保存90天。请只填写文章问题,省略个人信息、密钥和内部资料。