跳到正文
原文
Microsoft Research· Alex Lavaee, Matthai Philipose·· 3 天前AI 评分50

使用 PDD Kit 形式化验证全栈网络应用

Formally verifying agent-written full-stack web apps with PDD Kit

AI 摘要

PDD Kit 是一款工具,它通过将开发者的意图转化为形式化规范,并证明 AI 代理编写的代码符合该规范,从而帮助开发者可靠地审查 AI 代理生成的代码,特别是在全栈网络应用程序等大型项目中,解决了传统人工审查难以扩展的问题。

正文 · 清洗整理版

PDD Kit 帮助将意图转化为形式化规范,并证明代理为每个输入编写的代码符合该规范,同时使用测试来补充证明无法覆盖的部分。 它将形式化方法扩展到没有形式化方法背景的工程师和日常应用程序,如全栈网络应用程序。 随着 AI 代理生成越来越多的代码,彻底的逐行人工审查可能难以扩展。 PDD Kit 与您合作,将您的意图转化为 Verus 中的形式化规范,证明代理的代码符合该规范,并在证明无法覆盖时回退到测试。

在 GitHub Next 的 Chopin 中,我们使用 PDD Kit 对 Rust 店铺 Pet Store 的登录逻辑进行了形式化验证。 Verus 加固了代码并发现了现有错误,证明了相对于规范的登录错误不存在。 开发者审查了意图,从未逐行阅读生成的代码。 计划是代理应该遵循的合同,但没有任何东西约束代理遵循它。 现在,编码代理通常一次性交付整个功能,往往跨越数万或数十万行代码。 因此,阅读每个 pull 请求的行不适用于这种新工作方式。

现在,大多数团队投资于计划和相关测试:向代理描述他们想要什么,来回讨论直到计划和提出的测试看起来正确,然后将它们交给代理进行实现。 这个计划或自然语言规范是代理应该持有的合同。 然而,在实践中,代理可能会偏离它。 它实现了一些略有不同的事情,然后编写了通过其实现而不是您打算编写的代码的测试。 由于低质量和大量测试的泛滥,持续集成 (CI) 在增长,覆盖率看起来很健康,您要求的东西和交付的东西之间的差距直到出现错误报告或恶劣的边缘情况才会显现。 那么,当代理生成越来越多的代码时,如何可靠地扩展审查?

代理代码失败的两种方式是仔细的审查者通常会捕获的:它遗漏了明显必要的东西,或者它做了明显错误的事情。 测试本身无法弥补这个差距,因为它们只执行了程序可以做的事情的一小部分。 弥补它需要不同类型的机制,这就是证明的作用所在。 审查询问“这个看起来对吗? ”证明回答“这个是对的吗? ”数学证明表明代码对于每个输入都符合其规范,包括测试套件可能遗漏的输入。 这比单独测试提供了更强的指定属性保证,尤其是在逐行审查不实用时。 证明过去对日常软件来说太昂贵了。

您需要专家、不熟悉的语言、比代码大得多的证明,并且证明需要花费数年才能开发,但有两件事自那以来发生了变化。 首先,最近的编码代理进步使它们越来越实际地从定义良好的规范中生成形式化证明。 其次,代理现在可以更好地帮助您编写形式化规范。 我们称之为新的软件开发范例“证明驱动开发”(PDD)。 PDD Kit 是我们为此目的的工具包。 PDD Kit 的工作原理 PDD Kit 对于形式化方法大致相当于 Spec Kit 对于 Spec-Driven Development。

它作为 Chopin(GitHub Next 的实时、多人规划环境)内部的合作伙伴运行,团队和代理可以在一个共享文档中规划。

PDDKit decision flowchart on green gradient background

Flow diagram showing the PDD Kit workflow for formally verifying agent-written code. Team members review intent by expressing requirements in plain language, which are formalized in a pdd-plan containing decision cards, intent artifacts, trusted boundaries, and reviewer approvals. The plan generates a formal specification with Verus ensures clauses. Machines then check the code through pdd-prove, which includes Verus proofs, tests for trusted components, and LLM gap review. Verified code and receipts are submitted as a pull request. Dashed feedback loops return specification contradictions and verification gaps to earlier planning and coding stages.

Screenshot of a verification tool evaluating a login authentication requirement. The prompt asks, “Must the right password always get a token?” A flow diagram shows a login request leading to a password check, where matching passwords receive a token and non-matching passwords are refused. Option A, highlighted as recommended, proves both outcomes: the correct password receives a token and an incorrect password is refused. Option B proves only that incorrect passwords are refused, leaving the result for the correct password unspecified.

Three-panel illustration comparing login outcomes. In the first panel, a customer logs in with the correct email and password and receives a “customer” ticket. In the second panel, the same email is paired with an incorrect password and access is refused. In the third panel, an administrator logs in with the correct username and password and receives an “admin” ticket. The diagram uses a ticket-counter analogy to explain authentication and role-based access.

Intent map showing the login authentication flow for issuing a token. If an account exists and bcrypt verifies the correct password, the user receives claims for that account. If the account does not exist or the password is incorrect, the result is “401 Unauthorized.” If the password hash cannot be read, the result is “500 unreadable hash.”

Side-by-side comparison of two authentication policies. The left panel, “Only when,” shows that a token implies the correct password but does not guarantee a token for a correct password. The right panel, “Exactly when,” shows a two-way relationship in which a token is issued if and only if the correct password is provided. The highlighted difference is that denying a token to a user with the correct password is allowed under the first policy but forbidden under the second.

Comparison of two approaches to verifying a login handler. Option A, recommended, keeps the login handler trusted and verifies only the login decision logic, while database lookups and token signing remain tested but trusted components. Option B gives the login handler its own formal specification, proving the orchestration logic but requiring additional trusted wrappers and assumed contracts around database lookups, clocks, and JWT signing.

Diagram showing the proof boundary for a formally verified login system. Functionality outside the proof is either not promised or trusted and validated through human review and testing, including SQLite lookups, bcrypt, the system clock, JWT signing, database error handling, and request parsing. At the center, the formally verified portion consists of the login_flow and its components login_core, lookup_target, decide_login, and issue_token, which are proven by Verus for every input.

Proof map showing how a verified login system is divided between formally proved code and trusted, tested components. Five core functions, including login_flow, login_core, lookup_target, decide_login, and issue_token, are formally verified with Verus. Supporting functions for database queries, password verification, token signing, clock access, and error handling are treated as trusted contracts that are reviewed and tested.

Proof map showing how a verified login system is divided between formally proved code and trusted, tested components. Five core functions, including login_flow, login_core, lookup_target, decide_login, and issue_token, are formally verified with Verus. Supporting functions for database queries, password verification, token signing, clock access, and error handling are treated as trusted contracts that are reviewed and tested.

Screenshot of a test plan for verifying password validation behavior. The section, “check_password_answers_with_bcrypts_verdict,” describes unit tests confirming that password checks return true for the correct password and false for incorrect or empty passwords. Example test cases use bcrypt hashes for customer and administrator accounts.

Annotated code snippet explaining a formal verification clause for login tokens. The clause states that if a login returns a token, then the request names a valid account, the password matches the stored hash, the token contains valid claims, and the token’s subject and role match the authenticated account. Numbered callouts explain each part of the expression.

Traceability diagram showing how formal verification promises are derived from requirements. Statements made by developers and decisions recorded in design cards are mapped to eight specific guarantees in the login_flow specification, covering token issuance, account roles, invalid credentials, missing accounts, malformed requests, and error handling.

Flowchart showing the end-to-end login process. A login request selects an account table based on an email or username, looks up the account, verifies the password, and issues a signed token when authentication succeeds. Error paths return appropriate HTTP responses: 400 for missing credentials, 401 for invalid credentials or missing accounts, and 500 for lookup or password-hash failures.

Diagram comparing how formal verification applies to synchronous and asynchronous functions. For both types, preconditions are checked when the function is called and postconditions are guaranteed when a result is returned. In an asynchronous login flow, the function may pause while awaiting a database lookup, and the specification makes no guarantee about whether or how quickly the operation completes.

Annotated map of the verified/src/login.rs file showing the structure of a formally verified login implementation. The diagram categorizes sections as specification-only definitions, trusted external contracts, data types, and five functions formally proved with Verus: login_flow, login_core, issue_token, lookup_target, and decide_login.

Screenshot of a PDD Kit build plan for a login-token issuance specification. The build workflow contains seven tasks, with the first task focused on making verified/src/login.rs successfully build under Verus while preserving contract meanings. Subsequent tasks cover proving login-related functions, testing trusted wrappers, running end-to-end login tests, and validating token-signing behavior.

来源:Microsoft Research · microsoft.com

00