AgentDepthAgent 工程学习指南
输入概念或问题,检索正文和待编写目录。
第一次学习?从 L0 总览开始 →

供应链与依赖治理

我的学习 →

正在读取学习记录…

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 创建并进入目录,再保存下方两份文件:

PowerShell
New-Item -ItemType Directory -Force l8-supply-chain
cd l8-supply-chain

macOS 终端:

Bash
mkdir -p l8-supply-chain
cd l8-supply-chain
Python
"""校验固定版本和本地制品指纹,不安装或执行依赖。"""
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:

Python
"""覆盖完整性、版本锁定与依赖集合的变化。"""
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()

文件保存后,在同一窗口核对文件名并运行:

Bash
ls
python -X utf8 verify_supply.py
python -X utf8 -m unittest -v test_verify_supply.py

dir应显示这两个文件。运行程序后得到下面输出;测试末尾应显示 OK。

程序输出:

TXT
依赖数: 2
校验: 通过
原因: 集合、版本、指纹一致

让一个字节触发拒绝

在 verify_supply.py 找到唯一一行 TAMPER = False,改成 TAMPER = True,保存后运行:

Bash
python -X utf8 verify_supply.py

依赖数仍是2,校验变成“拒绝”,原因是 notes-adapter:指纹不符。变化发生在候选制品的尾部,批准清单没有变。恢复 TAMPER = False,再执行相同命令,应重新通过。

测试中的版本变化、遗漏和额外依赖检查都已给定输入;直接运行测试即可核对。空集合对空集合在算法上通过,发布流程还要单独判断“本应用是否应该存在依赖”,避免把空清单误当成完整物料表。

升级时怎样做决定

出现安全公告时,先定位受影响版本以及是否调用了相关功能,再准备候选升级。比较清单变化,跑工具输出契约和安全回归,审批后替换清单并保留旧制品。回滚时应使用原来批准的版本与内容,临时重新拉“最新版”会让故障复现困难。

软件物料清单(SBOM)记录组成软件的组件、版本和关系,方便查“哪个应用用了受影响的库”。它与漏洞扫描相配合:扫描器把组件版本匹配到已知公告,维护者再判断可达性和修复优先级。哈希一致说明内容与批准基准一致,漏洞是否存在仍需单独检查。

具体场景检查入口下一步
指纹不同但文件名相同候选来源与批准清单隔离候选,重新获取并比较
解析库升级后返回字段消失工具契约测试保持旧版,调整适配器后再发布
已批准库被披露严重漏洞SBOM与安全公告评估影响,升级或暂时关闭功能
模型权重替换,输出风格改变权重标识与业务回归将权重变化纳入发布审核

供应链检查放在构建和启动之前,运行期继续控制工具权限和网络出口。这样,依赖来源、内容完整性和实际执行权限分别有自己的控制位置。

课后练习展开习题收起习题

4 道练习 · 客观题规则评分 · 其余题目待批改

正在读取本地记录…

不调用模型,不执行代码。简答、代码和场景题仅保存答案并展示自查标准,不生成评分、徽章或认证。输入内容不会自动保存,请点击提交;不要填写个人信息或密钥。

练习 1 / 4 · v1.0.1

选择题 · 先判断边界

关于“供应链与依赖治理”,哪种做法更稳妥?

对应知识点:L8-supply-chain

选择一个答案
练习 2 / 4 · v1.0.0

简答题 · 解释失败

写出一个失败输入并说明记录字段。

对应知识点:L8-supply-chain

练习 3 / 4 · v1.0.0

代码题 · 边界测试

补充正常、边界、失败三组输入和预期结果。

对应知识点:L8-supply-chain

练习 4 / 4 · v1.0.0

场景题 · 结果未知

证据不足时如何设计状态和人工接管?

对应知识点:L8-supply-chain

继续阅读身份、RBAC与ABAC,把“软件由哪些输入组成”接到“谁能执行哪些动作”。

图片查看器
100%

文章配图 · 按 Esc 关闭