跳到正文

18 · generate_fixtures

返回:Agent 安全 · 不可变原始文件

原课程脚本 · 未联网执行

保留原始框架与完整代码。依赖、变量、入口以脚本及其相邻 README 为准;本页为代码导读,未声称所有外部服务均已验证。

链式记录:核对前序收据的规范字节哈希,并另外验证各签名;链头需要可信外部锚点才能发现整段截断。

签名操作:私钥仅用于签名,验签必须使用独立信任的公钥;不要把收据自带的公钥直接当成可信身份。

输出观察:print 展示应用可观察结果;预存输出和现场结果可能不同,它不是模型内部思考记录。

python
"""
Generate the three sample receipt fixtures in this directory.

Uses a fixed Ed25519 signing key and a fixed timestamp so the output is
byte-reproducible. Run this from the repo root or from within this folder.

Output:
  01_valid_receipt.json
  02_tampered_receipt.json
  03_chain_three_receipts.json
"""
import copy
import hashlib
import json
import base64
from pathlib import Path

from nacl import signing
from jcs import canonicalize


# Fixed key for byte-reproducible fixtures. NEVER reuse in production.
FIXED_SK_HEX = "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
FIXED_TS = "2026-04-25T14:30:00Z"


def b64url_nopad(data: bytes) -> str:
    return base64.urlsafe_b64encode(data).decode("ascii").rstrip("=")


def sha256_canonical(obj) -> str:
    canonical = canonicalize(obj)
    return f"sha256:{hashlib.sha256(canonical).hexdigest()}"


def sign_receipt(payload: dict, signing_key, verify_key) -> dict:
    canonical = canonicalize(payload)
    sig_bytes = signing_key.sign(canonical).signature
    return {
        **payload,
        "signature": {
            "alg": "EdDSA",
            "sig": b64url_nopad(sig_bytes),
            "public_key": b64url_nopad(bytes(verify_key)),
        },
    }


def receipt_hash(receipt: dict) -> str:
    canonical = canonicalize(receipt)
    return f"sha256:{hashlib.sha256(canonical).hexdigest()}"


def make_receipt(tool_name, tool_args, tool_result, sequence,
                 previous_receipt_hash, signing_key, verify_key,
                 timestamp=FIXED_TS):
    payload = {
        "type": "agent.tool_call.v1",
        "agent_id": "contoso-travel-bot",
        "tool_name": tool_name,
        "tool_args_hash": sha256_canonical(tool_args),
        "result_hash": sha256_canonical(tool_result),
        "policy_id": "contoso-travel-policy-v3",
        "timestamp": timestamp,
        "sequence": sequence,
        "previous_receipt_hash": previous_receipt_hash,
    }
    return sign_receipt(payload, signing_key, verify_key)


def main():
    here = Path(__file__).parent
    sk = signing.SigningKey(bytes.fromhex(FIXED_SK_HEX))
    vk = sk.verify_key

    # Fixture 1: a valid receipt
    valid = make_receipt(
        tool_name="lookup_flights",
        tool_args={"origin": "SYD", "destination": "LAX",
                   "departure_date": "2026-06-15", "passengers": 2},
        tool_result=[
            {"flight": "QF11", "price": 1850, "stops": 0},
            {"flight": "UA864", "price": 1620, "stops": 1},
        ],
        sequence=0,
        previous_receipt_hash=None,
        signing_key=sk,
        verify_key=vk,
    )
    (here / "01_valid_receipt.json").write_text(
        json.dumps(valid, indent=2) + "\n"
    )

    # Fixture 2: tamper with one field after signing
    tampered = copy.deepcopy(valid)
    tampered["policy_id"] = "contoso-travel-policy-PERMISSIVE"
    (here / "02_tampered_receipt.json").write_text(
        json.dumps(tampered, indent=2) + "\n"
    )

    # Fixture 3: chain of three receipts
    r0 = make_receipt(
        tool_name="lookup_flights",
        tool_args={"origin": "SYD", "destination": "LAX"},
        tool_result=[{"flight": "QF11", "price": 1850}],
        sequence=0,
        previous_receipt_hash=None,
        signing_key=sk,
        verify_key=vk,
    )
    r1 = make_receipt(
        tool_name="hold_seat",
        tool_args={"flight": "QF11", "seat": "14A", "hold_minutes": 30},
        tool_result={"hold_id": "H8472", "expires_at": "2026-06-15T15:00:00Z"},
        sequence=1,
        previous_receipt_hash=receipt_hash(r0),
        signing_key=sk,
        verify_key=vk,
    )
    r2 = make_receipt(
        tool_name="confirm_booking",
        tool_args={"hold_id": "H8472", "payment_token": "tok_redacted"},
        tool_result={"booking_ref": "CT-09182", "status": "confirmed"},
        sequence=2,
        previous_receipt_hash=receipt_hash(r1),
        signing_key=sk,
        verify_key=vk,
    )
    (here / "03_chain_three_receipts.json").write_text(
        json.dumps([r0, r1, r2], indent=2) + "\n"
    )

    print(f"Wrote three fixtures to {here}")


if __name__ == "__main__":
    main()

基于 Microsoft AI Agents for Beginners · 非官方中文学习版

100%