feat(approvals): add external verification contract#113517
feat(approvals): add external verification contract#113517Guardiola31337 wants to merge 3 commits into
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 26, 2026, 12:28 AM ET / 04:28 UTC. ClawSweeper reviewWhat this changesThis PR adds sanitized external-verification labels and allow-once/allow-always choices to plugin approval presentations, Gateway protocol schemas, and generated Swift Gateway models without changing current approval resolution. Merge readinessKeep this PR open for maintainer review. The patch is a focused, additive implementation of the accepted external-verification design, but it publishes a new Gateway/native-client approval contract before the companion plugin-SDK and runtime slices land; a maintainer should explicitly confirm that this exact contract is intended to be stable independently. Priority: P2 Review scores
Verification
How this fits togetherPlugins create approval requests that OpenClaw’s host converts into a safe presentation for Gateway clients. This change carries bounded external-verification metadata through that presentation while the host continues to own approval identity, lifecycle, and resolution. flowchart LR
Plugin[Plugin approval request] --> Sanitizer[Host sanitizes external metadata]
Sanitizer --> Presentation[Approval presentation]
Presentation --> Gateway[Gateway protocol snapshot]
Gateway --> Clients[Web and native clients]
Clients --> Host[Existing host approval resolution]
Decision needed
Why: The patch is intentionally inert but exposes generated client-facing protocol data; source review cannot determine whether maintainers want to freeze that public contract independently of the rest of the accepted design. Before merge
Agent review detailsSecurityNone. PR surfaceSource +62, Tests +111, Generated 0, Other +22. Total +195 across 10 files. View PR surface stats
Review metricsNone. Stored data modelPersistent data-model change detected: Root-cause clusterRelationship: Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Land this only after an owner confirms that the bounded Do we have a high-confidence way to reproduce the issue? Not applicable: this PR introduces an additive approval contract rather than repairing a currently broken behavior. Its focused validator and presentation tests provide a clear source-level verification path for the contract. Is this the best way to solve the issue? Unclear pending maintainer intent: the code is a narrow implementation of the accepted design, but publishing its Gateway/native-client shape separately from the SDK and runtime is a product and compatibility-timing choice. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 3f27d76ea7dc. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (13 earlier review cycles; latest 8 shown)
|
8b5aeca to
53495d1
Compare
87ece8b to
33e873f
Compare
|
This is a meaningful implementation — the "first-answer-wins" resolution model with Gateway-owned approval state is the right boundary for plugin-external verification ceremonies. One operational pattern we've found useful running OpenClaw with a persistent agent (Cophy) that has a tiered autonomy model: the The practical challenge we've hit: the agent's task context changes what zone an action falls into. Sending a message is normally yellow, but becomes effectively red if it's the first external message to a new recipient. Does the external verification contract in RFC #15 allow plugins to escalate the required grant level at invocation time? Or does the plugin's verifier only confirm/deny a fixed approval category declared at registration? The reviewer authorization model (signed completion, 401 for unsigned challenge, 200 only over pinned TLS) looks robust — particularly the separation between "who can approve" and "Gateway owns the approval ID." That boundary prevents a class of TOCTOU vulnerabilities where a plugin could issue its own completion. Context: Running OpenClaw as a persistent agent host; approval boundary design is one of the harder operational problems at longer agent session durations. |
33e873f to
8dd9604
Compare
8dd9604 to
af81eb0
Compare
d0bb8a7 to
216261e
Compare
cac2e38 to
66806d7
Compare
|
Yes—the accepted contract allows the plugin to choose the required level at invocation time from the actual For a concrete invocation, the plugin can:
So “first message to a new recipient” can be classified differently from later messages even though the tool name is the same. Core intentionally does not define green/yellow/red policy. The important boundary is that classification happens before the host creates the approval. Once created, the request and selected decision are host-bound and immutable: the verifier can complete only that exact attempt and cannot escalate This focused first PR adds only the bounded contract/projection. The prepared runtime PR lands the |
What Problem This Solves
OpenClaw plugins can request a generic approval, but they cannot present a bounded provider-neutral path for completing that approval through an external ceremony. RFC #15 accepted that separation: core must own the approval and immutable lifecycle while a plugin owns provider policy and proof handling.
Why This Change Was Made
allow-once/allow-alwayschoice model to internal approval requests and Gateway presentation snapshots.Why this is focused
The earlier implementation branch combined 56–96 files depending on the revision. This PR is now the first slice of a prepared stack:
feat/external-verification-state.feat/external-verification-runtime.feat/external-verification-tui.The full stack keeps World-specific policy, proofs, and secrets in the AgentKit plugin. Core receives only the provider-neutral host contract required by the RFC.
Contract boundary
allow-onceandallow-always.Evidence
node scripts/run-vitest.mjs packages/gateway-protocol/src/approvals-validators.test.ts src/infra/approval-presentation.test.tspnpm plugin-sdk:api:checkpnpm deadcode:exportsnode scripts/run-vitest.mjs test/scripts/plugin-sdk-surface-report.test.tsmain.pnpm plugin-sdk:api:checkpassed.pnpm buildpassed, including all 142 public plugin SDK paths and the Control UI performance gate.$autoreview --mode branch --base origin/main: TruffleHog clean; no accepted/actionable findings.git diff --checkpassed.Full-stack behavior proof
The companion AgentKit implementation and prepared core stack were also exercised as a normal user in an isolated OpenClaw home with a physical Pixel 3 and production World App. Allow-once resumed the exact blocked command only after World verification; Deny prevented execution; a failed/expired ceremony could be retried; session trust bypassed the second matching action in the same session; and a new session was gated again. This evidence validates the accepted contract while keeping this first PR reviewably inert.
Behavior addressed: Define the bounded provider-neutral external-resolution metadata that later host-owned attempt and runtime PRs consume.
Real environment tested: This additive contract was tested as part of the full isolated Gateway, TUI, AgentKit, physical Pixel 3, and production World App stack.
Exact steps or command run after this patch: Run the focused contract tests above; on the prepared full stack, ask OpenClaw to execute a protected marker command, select Verify once, scan and approve in World App, then verify terminal output and the proof-free SQLite ledger.
Evidence after fix: Contract tests reject malformed choices and spoofing labels; the full-stack ceremony resumes only the exact host-bound action after successful plugin completion.
Observed result after fix: Existing approval behavior remains unchanged in this PR alone, while the prepared stack successfully provides allow-once, denial, retry, session trust, and cross-session isolation.
What was not tested: No package publish, release, or version bump was performed. This first slice intentionally does not execute an external ceremony by itself; the subsequent focused PRs are required for runtime behavior.