feat: builder writes under write-grants (Write API demo slice) - #226
Open
volod-vana wants to merge 3 commits into
Open
feat: builder writes under write-grants (Write API demo slice)#226volod-vana wants to merge 3 commits into
volod-vana wants to merge 3 commits into
Conversation
Write API demo slice, authorization layer over the existing ingest path: - policy/data-write.ts: verifyDataWritePolicy mirrors the read policy but only honors write:-prefixed grant scope entries, so a read-grant never confers write and a write-grant never confers read. Includes a WriteFeeVerifierPort seam (default free; fee mechanics undecided). - write/session.ts: write-session store + createWriteSession handshake, same shape as the self-signing MCP session (prove key control once via Web3Signed, short-lived bearer after). PS keeps signing AddData as the owner; the builder never holds the owner key. - write/attribution.ts: per-write builder-signed payload proof (X-Vana-Write-Signature, Web3Signed over the request incl. bodyHash), stored with the record inside envelope data under the reserved $writtenBy key (same in-data marker idiom as $binary) so it travels the unchanged encrypt/upload/register path. On-chain shape untouched. - api/index.ts: optional authorizeWrite on PersonalServerApiAuthPort; POST /v1/data/:scope stays owner-only unless the port supports write sessions. Builder writes are stamped with attribution and logged to the access log with action write. - contracts/data.ts: ingest contracts accept the attribution and reject payloads that carry the reserved key. Claude-Session: https://claude.ai/code/session_018omZb8Q4JpPf4DvSUJfePY
- routes/write-session.ts: POST /v1/write/session, a Web3Signed handshake
(builder key + write-grant id in the proof) mints a short-lived bearer
bound to {builder, grant}, with the same replay guard discipline as the
MCP session route.
- api-auth.ts: authorizeWrite redeems write-session bearers on the ingest
endpoint, re-running the write policy against the LIVE grant per write
and verifying the X-Vana-Write-Signature attribution proof; any other
credential falls through to the unchanged owner path.
- app.ts: one shared in-memory session store wired into both the handshake
route and the data routes (overridable via AppDeps for persistence).
Claude-Session: https://claude.ai/code/session_018omZb8Q4JpPf4DvSUJfePY
- tests/e2e/write-api.e2e.test.ts: full slice against a booted server -- handshake, delegated write with attribution, read-back denied under the write-grant, read-back served under a separate read-grant. - tests/e2e/helpers/mock-gateway.ts: grants are now seedable (setGrant). - scripts/e2e-write-api.ts (npm run e2e:write-api): in-process demo with an injected mock gateway; verifies the stored attribution signature recovers to the builder over the original body bytes. Claude-Session: https://claude.ai/code/session_018omZb8Q4JpPf4DvSUJfePY
Codex Review
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builders can now write into a user's PS under a write-grant. The owner key never leaves the PS: the server keeps signing AddData as the owner, the builder authenticates with its own key plus a grant. Implements the Write API tech design, demo slice scope.
How it works:
write:prefix (write:notes.entries,write:chatgpt.*). Read policy matches entries verbatim, so a write-grant never grants read and a read-grant never grants write. Zero gateway changes.POST /v1/write/session: Web3Signed handshake carrying the grantId, replay-guarded, mints a short-lived bearer. Same shape as the feat(mcp): chatbot-first self-signing MCP session + x402 pay-per-read #212 MCP session.POST /v1/data/:scopeaccepts that bearer. Every write re-checks the live grant (revoke wins immediately, not at token expiry) and verifiesX-Vana-Write-Signaturerecovers to the session builder.$writtenBy(same idiom as$binary), so it rides the unchanged encrypt/upload/register path. A payload that brings its own$writtenByis a 400, a session write without the signature header is a 401.WriteFeeVerifierPortseam, default free until the PRD settles who pays. Real delete is a separate workstream.Everything downstream of the auth gate is the untouched owner ingest path. PS-Lite and all existing surfaces are unaffected:
authorizeWriteis an optional port, anything that is not a write-session bearer falls through to the old behavior.Open question before merge: the
write:prefix vs a first-class permissions field on the grant. The prefix needs zero DP RPC / EIP-712 changes, which is why v1 uses it. Raised in #eng_protocol.Testing: