agent-safe-pipelineSafe
§ · Nested detail page

执行门禁和测试证据 深度解析

SafeExecutor 的价值需要靠测试证明:它必须拒绝换绑、重放、缺授权、参数错误和 forged captured envelope。

§ 00 · IMPORT CHAIN

导入链与契约

packages/pipeline/src/execution/SafeExecutor.ts:35 是执行入口,但真正调用 handler 要等到 packages/pipeline/src/execution/SafeExecutor.ts:77。中间的 packages/pipeline/src/execution/SafeExecutor.ts:39、packages/pipeline/src/execution/SafeExecutor.ts:42、packages/pipeline/src/execution/SafeExecutor.ts:45、packages/pipeline/src/execution/SafeExecutor.ts:48、packages/pipeline/src/execution/SafeExecutor.ts:54 形成多层短路。

src/packages/pipeline/src/execution/SafeExecutor.ts · L35-82TypeScript
35  public async run<TResult = unknown>(
36    captured: CapturedIntent,
37    decision: GateDecision,
38  ): Promise<SafeExecutionResult<TResult>> {
39    if (decision.verdict !== "ALLOW" || decision.failClosed) {
40      return SafeExecutor.blocked("DECISION_NOT_ALLOW");
41    }
42    if (decision.intentHash !== captured.intentHash) {
43      return SafeExecutor.blocked("INTENT_BINDING_MISMATCH");
44    }
45    if (decision.authorization === null) {
46      return SafeExecutor.blocked("AUTHORIZATION_MISSING");
47    }
48    if (!this.intentConforms(captured)) {
49      return SafeExecutor.blocked("INTENT_CONFORMANCE_FAILED");
50    }
51    this.registry.validate(captured);
52    let authorization: VerifiedAuthorization | null;
53    try {
54      authorization = await this.verifier.verifyAndConsume(captured, decision);
55    } catch {
56      return SafeExecutor.blocked("AUTHORIZATION_INVALID");
57    }
58    if (authorization === null) return SafeExecutor.blocked("AUTHORIZATION_INVALID");
59    const authorizationExpiry = Date.parse(authorization.expiresAt);
60    if (
61      authorization.decisionId !== decision.decisionId ||
62      authorization.dossierId !== decision.dossierId ||
63      authorization.grantId.length === 0 ||
64      authorization.intentHash !== captured.intentHash ||
65      Math.floor(authorizationExpiry / 1_000) !==
66        Math.floor(Date.parse(decision.authorization.expiresAt) / 1_000) ||
67      authorizationExpiry <= Date.now() ||
68      authorizationExpiry > Date.parse(captured.intent.expiresAt)
69    ) {
70      return SafeExecutor.blocked("AUTHORIZATION_INVALID");
71    }
72    if (!this.intentConforms(captured)) {
73      return SafeExecutor.blocked("INTENT_CONFORMANCE_FAILED");
74    }
75    let result: TResult;
76    try {
77      result = (await this.registry.execute(captured, authorization)) as TResult;
78    } catch {
79      throw new Error("ACTION_EXECUTION_FAILED");
80    }
81    return { executed: true, result, authorization };
82  }

▸读这页时先看三个不变量

第一,页面里的每个 path:NN 都指向当前源码快照;第二,所有授权都必须绑定到同一个 intentHash;第三,执行端只消费一次性 grant,不接收 agent 自己声明的“我被批准了”。

§ 01 · CORE IMPL

核心实现,逐段拆

▸ActionRegistry 是执行白名单,不是动态路由

packages/pipeline/src/execution/ActionRegistry.ts:21 用 Map 保存 action handler,packages/pipeline/src/execution/ActionRegistry.ts:29 禁止 sealed 后继续注册,packages/pipeline/src/execution/ActionRegistry.ts:44 和 packages/pipeline/src/execution/ActionRegistry.ts:53 分别在 validate 和 execute 阶段检查 sealed、registered action 与参数 schema。

src/packages/pipeline/src/execution/ActionRegistry.ts · L21-64TypeScript
21export class ActionRegistry {
22  private readonly actions = new Map<string, RegisteredAction>();
23  private sealed = false;
24
25  public register<TParameters, TResult>(
26    action: string,
27    handler: ActionHandler<TParameters, TResult>,
28  ): this {
29    if (this.sealed) throw new Error("ACTION_REGISTRY_SEALED");
30    if (this.actions.has(action)) throw new Error("ACTION_ALREADY_REGISTERED");
31    this.actions.set(action, handler as RegisteredAction);
32    return this;
33  }
34
35  public seal(): this {
36    this.sealed = true;
37    return this;
38  }
39
40  public has(action: string): boolean {
41    return this.actions.has(action);
42  }
43
44  public validate(captured: CapturedIntent): void {
45    if (!this.sealed) throw new Error("ACTION_REGISTRY_NOT_SEALED");
46    const handler = this.actions.get(captured.intent.action);
47    if (!handler) throw new Error("ACTION_NOT_REGISTERED");
48    if (!handler.parametersSchema.safeParse(captured.intent.parameters).success) {
49      throw new Error("ACTION_PARAMETERS_INVALID");
50    }
51  }
52
53  public async execute(
54    captured: CapturedIntent,
55    authorization: VerifiedAuthorization,
56  ): Promise<unknown> {
57    if (!this.sealed) throw new Error("ACTION_REGISTRY_NOT_SEALED");
58    const handler = this.actions.get(captured.intent.action);
59    if (!handler) throw new Error("ACTION_NOT_REGISTERED");
60    const result = handler.parametersSchema.safeParse(captured.intent.parameters);
61    if (!result.success) throw new Error("ACTION_PARAMETERS_INVALID");
62    return handler.execute({ intent: captured, parameters: result.data, authorization });
63  }
64}

▸测试覆盖 grant replay 与 envelope 篡改

packages/pipeline/test/execution/SafeExecutor.test.ts:91 拒绝把一个 approved intent 的 decision 套到另一个 intent 上;packages/pipeline/test/execution/SafeExecutor.test.ts:120 枚举 captured envelope mismatch;packages/pipeline/test/execution/SafeExecutor.test.ts:189 则用 100 个并发 run 证明只有一个执行能成功。

src/packages/pipeline/test/execution/SafeExecutor.test.ts · L189-213TypeScript
189  it("allows exactly one execution under one grant across 100 concurrent claims", async () => {
190    const { execute, pair, executor } = setup();
191    const intent = captured();
192    const decision = await pair.authority.evaluate(intent);
193
194    const results = await Promise.all(
195      Array.from({ length: 100 }, async () => executor.run(intent, decision)),
196    );
197
198    expect(results.filter((result) => result.executed)).toHaveLength(1);
199    expect(execute).toHaveBeenCalledTimes(1);
200    expect(
201      results.filter((result) => !result.executed && result.reason === "AUTHORIZATION_INVALID"),
202    ).toHaveLength(99);
203  });
204
205  it("does not consume a grant before action parameters pass the trusted schema", async () => {
206    const { execute, pair, executor } = setup();
207    const invalid = captured(-1);
208    const decision = await pair.authority.evaluate(invalid);
209
210    await expect(executor.run(invalid, decision)).rejects.toThrow("ACTION_PARAMETERS_INVALID");
211    expect(execute).not.toHaveBeenCalled();
212    expect(await pair.verifier.verifyAndConsume(invalid, decision)).not.toBeNull();
213  });
§ 02 · KEY FLOW

关键流程

registry.validate -> verifier.verifyAndConsume -> expiry/hash checks -> registry.execute -> result

测试还暴露了一个设计取舍:packages/pipeline/test/execution/SafeExecutor.test.ts:205 到 packages/pipeline/test/execution/SafeExecutor.test.ts:213 里参数 schema 失败会抛 ACTION_PARAMETERS_INVALID,且测试显示 fixture verifier 仍能消费 grant。这说明生产接入时应该先让 registry.validate 过,再进入远端 consume-token,避免无效参数消耗授权。

§ 03 · EDGE CASES

边界 / 失败模式

  • packages/pipeline/test/execution/SafeExecutor.test.ts:81 BLOCK 和 ESCALATE 都不会执行 handler。
  • packages/pipeline/test/execution/SafeExecutor.test.ts:101 conformance 失败时 verifier 不会被调用。
  • packages/pipeline/test/execution/SafeExecutor.test.ts:156 grant 消费后再篡改 canonicalIntent 仍会被第二次 conformance 拦下。
  • packages/pipeline/test/execution/SafeExecutor.test.ts:215 verifier 抛错或返回不匹配 evidence 都会 AUTHORIZATION_INVALID。