-
Notifications
You must be signed in to change notification settings - Fork 2
docs: UCAN Command Definitions RFC #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Peeja
wants to merge
1
commit into
main
Choose a base branch
from
command-definitions
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,190 @@ | ||
| # RFC: UCAN Command Definitions | ||
| Status: Proposed Standard | ||
|
|
||
| ## Introduction | ||
|
|
||
| This RFC proposes a definition and formal documentation format for UCAN Commands, to replace the manually created and inconsistently structured specification documents we currently use. | ||
|
|
||
| This is largely a proposal for UCAN itself, but as it's motivated by needs arising in Storacha, it will at least begin as a draft RFC here for initial feedback. It is fully compatible with the existing UCAN 1.0 specifications, and could be adopted by UCAN itself or live on top of it. However, its utility is limited if it is not adopted outside of a single organization. | ||
|
|
||
| ### Notation | ||
|
|
||
| *Several elements of the proposal below will be illustrated with examples displayed in DAG-JSON. The canonical representations of such elements, however, is DAG-CBOR.* | ||
|
|
||
| *Comments such as `// "/": "bafy..` denote the CIDs of objects.* | ||
|
|
||
| ## Problem | ||
|
|
||
| Understanding a UCAN document requires a great deal of implicit context. UCAN provides strict semantics for determining whether an invocation of a Command was issued with authority, and should therefore be executed. It does not, however, provide strict semantics for what that execution should consist of. | ||
|
|
||
| Consider the following scenario. Alice has some files in a home directory on a server. She'd like Bob to be able to access those files. Alice trusts Bob fully with the contents of this home directory, and so issues the following delegation: | ||
|
|
||
| ```json5 | ||
| { | ||
| // "/": "bafy..accessdel", | ||
| "iss": "did:example:alice", | ||
| "aud": "did:example:bob", | ||
| "sub": "did:example:alice", | ||
| "cmd": "/home/access", | ||
| "nonce": "…", | ||
| "exp": null, | ||
| } | ||
| ``` | ||
|
|
||
| But Bob, whether out of malice or misunderstanding, then issues the following invocation: | ||
|
|
||
| ```json5 | ||
| { | ||
| "iss": "did:example:bob", | ||
| "aud": "did:example:alices-front-door", | ||
| "sub": "did:example:alice", | ||
| "cmd": "/home/access", | ||
| "nonce": "…", | ||
| "exp": null, | ||
| "prf": [{"/": "bafy..accessdel"}] | ||
| } | ||
| ``` | ||
|
|
||
| `did:example:alices-front-door` is the smart lock on Alice's front door. Seeing that Bob has authority from Alice to "access" her "home", it accordingly unlocks and lets Bob in, where he has a very different kind of access than what Alice intended to delegate. | ||
|
|
||
| This is a kind of [confused deputy problem](https://en.wikipedia.org/wiki/Confused_deputy_problem). The issue lies in two related problems with UCAN Commands as so far defined in the UCAN specifications: | ||
|
|
||
| * UCAN Commands are not namespaced, so a Command name built from everyday words is likely to be ambiguously defined by unrelated specifications. | ||
| * UCAN Commands are not explicitly connected to any sort of documentation or specification, so any interpreter must correctly know the specification out-of-band. | ||
|
|
||
| [The UCAN specification states](https://github.com/ucan-wg/spec#33-command): | ||
|
|
||
| > Commands are concrete messages ("verbs") that MUST be unambiguously interpretable by the Subject of a UCAN. Commands are REQUIRED in invocations. Some examples include `/msg/send`, `/crud/read`, and `/ucan/revoke`. | ||
|
|
||
| However, while the *Subject* may unambiguously understand the Command, it is the *Executor* who must ultimately understand it, and the Executor may not know anything about the Subject other than that it has granted some authority to some other principal. | ||
|
|
||
| ## Proposal | ||
|
|
||
| ### Namespacing | ||
|
|
||
| The first part of the proposal is simple: a UCAN-based specification SHOULD namespace its Commands using a DID it controls. Thus, these may be two different Commands: | ||
|
|
||
| ```json5 | ||
| { | ||
| // ... | ||
| "cmd": "/did:web:ezhosting.example/home/access" | ||
| } | ||
|
|
||
| { | ||
| // ... | ||
| "cmd": "/did:web:smartlocksrus.example/home/access" | ||
| } | ||
| ``` | ||
|
|
||
| These DIDs both use the `web` method, and this is likely to be a common choice, but it is not required in this proposal. Any DID which the definer controls will do. | ||
|
|
||
| These Commands are valid under the base UCAN specification. They also parallel that specification's reservation of a `/ucan` namespace for Commands defined in UCAN specifications. | ||
|
|
||
| ### Definition and Schema | ||
|
|
||
| Namespacing Commands resolves the ambiguity, but because it connects each Command with an authoritative Principal it also gives us the opportunity to specify and document Commands more clearly. | ||
|
|
||
| The following is a definition for a Command which publishes a blog post using a protocol defined by `did:example:blog`, a blogging service: | ||
|
|
||
| ```json5 | ||
| { | ||
| // "/": "bafy..pubdef", | ||
| "cmd": "/did:example:blog/post/publish", | ||
| "description": "Publish a new blog post", | ||
| "sub": "The blog where the post will be published", | ||
| "args": { | ||
| "article": { | ||
| "type": "object", | ||
| "properties": { | ||
| "title": { | ||
| "type": "string", | ||
| "description": "The title of the article" | ||
| }, | ||
| "author": { | ||
| "type": "string", | ||
| "description": "The DID of the article's author" | ||
| }, | ||
| "content": { | ||
| "type": "string", | ||
| "description": "The text content of the article" | ||
| } | ||
| }, | ||
| "required": ["title", "author", "content"], | ||
| }, | ||
| }, | ||
| "out": { | ||
| "ok": { | ||
| "type": "object", | ||
| "properties": { | ||
| "postId": { | ||
| "type": "string", | ||
| "description": "The identifier of the published post", | ||
| }, | ||
| "publishedAt": { | ||
| "type": "string", | ||
| "format": "date-time", | ||
| "description": "The time and date when the post published." | ||
| }, | ||
| }, | ||
| "required": ["postId", "publishedAt"], | ||
| }, | ||
| }, | ||
| } | ||
| ``` | ||
|
|
||
| This provides a number of useful pieces of information: | ||
|
|
||
| * The Command has a human-language definition (here, in English) for the action it will perform. | ||
| * The Command has a human-language definition for the role the Subject plays in the action. | ||
| * The arguments to the Command are fully specified and defined, using JSON Schema. | ||
| * The out-value expected in the Receipt is fully specified and defined, using JSON Schema. | ||
|
|
||
| This level of definition opens several new opportunities: | ||
|
|
||
| * Generic UCAN tools which can help a user manually create a Delegation or Invocation. | ||
| * Generic UCAN validation tools, either standalone or within UCAN libraries. | ||
| * Automatic, standard documentation generation. | ||
| * Static code generation of types in multiple programming languages. | ||
|
|
||
| ### Assertion of Definition | ||
|
|
||
| The Command definition form given above may be used today to replace or supplement existing protocol documentation for existing Commands. Just as documentation today must be trusted by the reader according to out-of-band information (such as knowing that it's stored in a repo controlled by the same people who implemented the eventual Executor of the Command), these machine-readable definitions may also be asserted without cryptographic proof, and be useful. | ||
|
|
||
| However, if a Command is namespaced by a Principal's DID, as described above, that Principal can also meaningfully assert that a particular definition is correct. Such an assertion could look like this: | ||
|
|
||
| ```json5 | ||
| { | ||
| "iss": "did:example:blog", | ||
| "sub": "did:example:blog", | ||
| "cmd": "/ucan/command/define", | ||
| "args": { | ||
| "def": { | ||
| "/": "bafy..pubdef", | ||
| }, | ||
| }, | ||
| "nonce": "…", | ||
| "exp": null, | ||
| } | ||
| ``` | ||
|
|
||
| Because this assertion is signed by `did:example:blog`, it serves as proof that `bafy..pubdef` is the correct definition of the Command. | ||
|
|
||
| ## Conclusion | ||
|
|
||
| The proposal offers three ideas: | ||
|
|
||
| * A convention of namespacing Commands with a DID controlled by the definer. | ||
| * A formal definition schema for Commands, including documentation. | ||
| * A Command for asserting the correctness of a particular definition of a Command controlled by the Subject. | ||
|
|
||
| The first two can be used independently. The third ties the first two together to make them more useful in a truly decentralized environment. | ||
|
|
||
| ## Not yet addressed | ||
|
|
||
| * Sometimes the authority to invoke one command implies the authority to invoke another. This is partly handled by the Command name structure, as the authority to `/foo` implies the authority to `/foo/bar` and to `/foo/baz`. However, some desired authority derivation is more complex than this. Currently, Ucanto allows the server to define derivation logic, but it's up to each server to do so correctly. What's proposed already provides a signed document which could describe that logic in human language. However, it may be valuable to include a machine-readable definition of that logic which any compliant service could implement automatically. | ||
|
|
||
| * Sometimes we update a Command's Argument schema. Currently, we don't have a great solution for versioning our Commands/Abilities, and this proposal does nothing to improve that situation. | ||
|
|
||
| * This proposal makes no particular effort to allow for documentation in multiple human languages, as JSON Schema itself does not support multiple languages. However, there are proposals for JSON Schema which could be incorporated if adopted. | ||
|
|
||
| * Many technical details are currently elided, as they're unnecessary at this early stage. The definition assertion, in particular, is a very rough-draft proof of concept. | ||
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the subject differentiate here? You're not accessing "alice", you're accessing the alice's house. The house should have a DID, as should the server space - this is the subject of the invocation.