Bring manual up to date and repair links

This commit is contained in:
Tony Garnock-Jones 2023-02-07 13:30:13 +01:00
parent fd8e32d655
commit 3d9b377a62
7 changed files with 116 additions and 77 deletions

View File

@ -307,7 +307,7 @@ language, the Preserves concept of an *embedded value* is used in the SAM to rel
portions of a datum referring to SAM entities. portions of a datum referring to SAM entities.
Concretely, in [Preserves text Concretely, in [Preserves text
syntax](https://preserves.dev/preserves.html#textual-syntax), embedded values syntax](https://preserves.dev/preserves-text.html), embedded values
appear prepended with `#!`. In messages transferred across links using the [Syndicate network appear prepended with `#!`. In messages transferred across links using the [Syndicate network
protocol][], references might appear as `#![0 123]`, `#![1 555]`, etc. etc. protocol][], references might appear as `#![0 123]`, `#![1 555]`, etc. etc.

View File

@ -60,11 +60,11 @@ automatically, losslessly translatable from one syntax to another because Preser
are syntax-independent. are syntax-independent.
The core Preserves specification defines a text-based, human-readable, JSON-like syntax, that The core Preserves specification defines a text-based, human-readable, JSON-like syntax, that
is a syntactic superset of JSON, and a completely equivalent compact binary syntax, crucial to is a syntactic superset of JSON, and a completely equivalent compact machine-oriented syntax,
the definition of [canonical form](#canonical-form) for Preserves values.[^syrup] crucial to the definition of [canonical form](#canonical-form) for Preserves values.[^syrup]
Here are a few example values, written using the text syntax (see [the Here are a few example values, written using the text syntax (see [the
specification](https://preserves.dev/preserves.html#textual-syntax) for the specification](https://preserves.dev/preserves-text.html) for the
grammar): grammar):
Boolean : #t #f Boolean : #t #f
@ -84,10 +84,10 @@ Commas are optional in sequences, sets, and dictionaries.
### Canonical form ### Canonical form
Every Preserves value can be serialized into a *canonical form* using the [binary Every Preserves value can be serialized into a *canonical form* using the [machine-oriented
syntax](https://preserves.dev/preserves.html#compact-binary-syntax) along with syntax](https://preserves.dev/preserves-binary.html) along with [a few simple
[a few simple rules](https://preserves.dev/canonical-binary.html) about rules](https://preserves.dev/canonical-binary.html) about serialization ordering of elements in
serialization ordering of elements in sets and keys in dictionaries. sets and keys in dictionaries.
Having a canonical form means that, for example, a cryptographic hash of a value's canonical Having a canonical form means that, for example, a cryptographic hash of a value's canonical
serialization can be used as a unique fingerprint for the value. serialization can be used as a unique fingerprint for the value.

View File

@ -39,15 +39,15 @@ The following definitions are taken from the
schema. For further detail, see the [reference](../../protocols/syndicate/gatekeeper.md). schema. For further detail, see the [reference](../../protocols/syndicate/gatekeeper.md).
```preserves-schema ```preserves-schema
SturdyRef = <ref @oid any @caveatChain [Attenuation ...] @sig bytes>. SturdyRef = <ref @oid any @caveatChain [Caveat ...] @sig bytes>.
``` ```
Within a `ref` record, the `oid` field is a free-form value that the targeted service chooses Within a `ref` record, the `oid` field is a free-form value that the targeted service chooses
to name itself. The `sig` is an iterated keyed-HMAC construction, just as in [macaroons][]. to name itself. The `sig` is an iterated keyed-HMAC construction, just as in [macaroons][].
First, the service's secret key is used to key an HMAC of the `oid`. Then, the result is used First, the service's secret key is used to key an HMAC of the `oid`. Then, the result is used
to key an HMAC of the first `Attenuation` in `caveatChain`. Each `Attenuation`'s HMAC becomes to key an HMAC of the ([canonical form](../../guide/preserves.md#canonical-form) of the) first
the key for the next in the `caveatChain`. The final result is equal to the `sig` field in a `Caveat` in `caveatChain`. Each `Caveat`'s HMAC becomes the key for the next in the
valid sturdyref. `caveatChain`. The final result is equal to the `sig` field in a valid sturdyref.
### Attenuation of authority ### Attenuation of authority
@ -56,19 +56,13 @@ sturdyref, the `caveatChain` is used to [attenuate](../../glossary.md#attenuatio
authority denoted by the sturdyref by filtering and/or rewriting assertion and message bodies. authority denoted by the sturdyref by filtering and/or rewriting assertion and message bodies.
The `caveatChain` is run *right to left*, with newer rewrites-and-filters at the right-hand end The `caveatChain` is run *right to left*, with newer rewrites-and-filters at the right-hand end
of the chain and older ones at the left-hand end. Of course, an empty `caveatChain` is an of the chain and older ones at the left-hand end. Of course, an empty `caveatChain` is an
unattenuated reference. unattenuated reference. The structure and interpretation of `Caveat`s is described fully in
[the relevant section of the Syndicate network protocol
specification](../../protocol.md#attenuation-of-authority).
```preserves-schema The term "caveat" is shamelessly taken from [macaroons][], though our caveats presently embody
Attenuation = [Caveat ...]. only what in the Macaroons paper are called "first-party caveats" over assertion structure;
``` future versions of the server may add "third-party caveats" and other, richer, predicates over
assertions.
Each individual `Attenuation` in a `caveatChain` is a sequence of `Caveat`s. The term "caveat"
is shamelessly taken from [macaroons][], though our caveats presently embody only what in the
Macaroons paper are called "first-party caveats" over assertion structure; future versions of
the server may add "third-party caveats" and other, richer, predicates over assertions.
Each `Attenuation`'s `Caveat`s are run in *right to left* order. The structure and
interpretation of `Caveat`s is described fully in [the relevant section of the Syndicate
network protocol specification](../../protocol.md#attenuation-of-authority).
[Macaroons]: ../../glossary.md#macaroon [Macaroons]: ../../glossary.md#macaroon

View File

@ -31,13 +31,13 @@ name](#the-active-target).
*Program* = *Instruction* ... *Program* = *Instruction* ...
A configuration source file is a file whose name ends in `.pr` that contains zero or more A configuration source file is a file whose name ends in `.pr` that contains zero or more
Preserves [text-syntax](https://preserves.dev/preserves.html#textual-syntax) Preserves [text-syntax](https://preserves.dev/preserves-text.html)
values, which are together interpreted as a sequence of *Instruction*s. values, which are together interpreted as a sequence of *Instruction*s.
**Comments.** [Preserves **Comments.** [Preserves
comments](https://preserves.dev/conventions.html#comments) are ignored. One comments](https://preserves.dev/conventions.html#comments) are ignored. One
unfortunate wart is that because Preserves comments are really unfortunate wart is that because Preserves comments are really
[annotations](https://preserves.dev/preserves.html#annotations), they are [annotations](https://preserves.dev/preserves-text.html#annotations), they are
required by the Preserves data model to be attached to some other value. Syntactically, this required by the Preserves data model to be attached to some other value. Syntactically, this
manifests as the need for *some non-comment following every comment*. In scripts written to manifests as the need for *some non-comment following every comment*. In scripts written to
date, often an empty *SequencingInstruction* serves to anchor comments at the end of a file: date, often an empty *SequencingInstruction* serves to anchor comments at the end of a file:
@ -182,7 +182,7 @@ facet terminates, *Instruction* is run.
    `dataspace` |     `dataspace` |
    `timestamp` |     `timestamp` |
    `facet` |     `facet` |
`stringify` *ConvenienceExpr* |     `stringify` *ConvenienceExpr* |
    *ValueExpr*     *ValueExpr*
Values can be destructured and new variables introduced into the environment with `let`, which Values can be destructured and new variables introduced into the environment with `let`, which
@ -248,30 +248,47 @@ special syntax for *[attenuated](../glossary.md#attenuation) entity references*,
## Attenuation Expressions ## Attenuation Expressions
*AttenuationExpr* = `<* $`*var*` [`*Rewrite* ...`]>` *AttenuationExpr* = `<* $`*var*` [`*Caveat* ...`]>`
*Caveat* =
    `<or [`*Rewrite* ...`]>` |
    `<reject `*PatternExpr*`>` |
    *Rewrite*
*Rewrite* = *Rewrite* =
    `<filter `*PatternExpr*`>` |     `<accept `*PatternExpr*`>` |
    `<rewrite `*PatternExpr*` `*TemplateExpr*`>`     `<rewrite `*PatternExpr*` `*TemplateExpr*`>`
An attenuation expression looks up *var* in the environment, asserts that it is an entity An attenuation expression looks up *var* in the environment, asserts that it is an entity
reference *orig*, and returns a new entity reference *ref*, like *orig* but reference *orig*, and returns a new entity reference *ref*, like *orig* but
[attenuated](../glossary.md#attenuation) with zero or more *Rewrite*s. The result of evaluation [attenuated](../glossary.md#attenuation) with zero or more *Caveat*s. The result of evaluation
is *ref*, the new attenuated entity reference. is *ref*, the new attenuated entity reference.
When an assertion is published or a message body arrives at *ref*, the sequence of *Rewrite*s When an assertion is published or a message arrives at *ref*, the sequence of *Caveats*s is
is executed left-to-right. If a *Rewrite* succeeds, the value if produces is forwarded on to executed **right-to-left**, transforming and possibly discarding the asserted value or message
*orig*. If all *Rewrite*s fail, the assertion or message is silently ignored. body. If all *Caveat*s succeed, the final transformed value is forwarded on to *orig*. If any
*Caveat* fails, the assertion or message is silently ignored.
A `rewrite` *Rewrite* matches values with *PatternExpr*. If the match fails, the next *Rewrite* A *Caveat* can be one of three possibilities:
is tried; if it succeeds, the resulting bindings are used along with the current environment to
evaluate *TemplateExpr*, and the resulting value is forwarded on to *orig*.
A `filter` *Rewrite* is the same as `<rewrite <?`*v*` `*PatternExpr*`> $`*v*`>`, for some fresh - An `or` of multiple alternative *Rewrite*s. The first *Rewrite* to accept (and possibly
*v*. transform) the input value causes the whole `or` *Caveat* to succeed. If all the *Rewrite*s
in the `or` fail, the `or` itself fails. Supplying a *Caveat* that is an `or` containing
zero *Rewrite*s will reject *all* assertions and messages.
Supplying zero *Rewrite*s will cause the new entity to reject *all* assertions and messages - A `reject`, which allows all values through unchanged except those matching *PatternExpr*.
sent to it.
- A simple *Rewrite*.
A *Rewrite* can be one of two possibilities:
- A `rewrite`, which matches input values with *PatternExpr*. If the match fails, the
*Rewrite* fails. If it succeeds, the resulting bindings are used along with the current
environment to evaluate *TemplateExpr*, and the *Rewrite* succeeds, yielding the resulting
value.
- An `accept`, which is the same as `<rewrite <?`*v*` `*PatternExpr*`> $`*v*`>` for some fresh
*v*.
## Pattern Expressions ## Pattern Expressions
@ -348,10 +365,10 @@ binding the resulting capability to `$sys`. Any `require-service` record publish
rewritten into a `require-core-service` record; other assertions are forwarded unchanged. rewritten into a `require-core-service` record; other assertions are forwarded unchanged.
```preserves ```preserves
let ?sys = <* $config [ let ?sys = <* $config [<or [
<rewrite <require-service ?s> <require-core-service $s>> <rewrite <require-service ?s> <require-core-service $s>>
<filter _> <accept _>
]> ]>]>
``` ```
Then, `$sys` is used to build the initial environment for a [configuration Then, `$sys` is used to build the initial environment for a [configuration

View File

@ -124,10 +124,10 @@ expression](./scripting.md#attenuation-expressions) rewrites `require-service` a
`require-core-service` assertions: `require-core-service` assertions:
```preserves ```preserves
let ?sys = <* $config [ let ?sys = <* $config [<or [
<rewrite <require-service ?s> <require-core-service $s>> <rewrite <require-service ?s> <require-core-service $s>>
<filter _> <accept _>
]> ]>]>
<require-service <config-watcher "/etc/syndicate/core" { <require-service <config-watcher "/etc/syndicate/core" {
config: $sys config: $sys

View File

@ -172,7 +172,7 @@ additional conditions on the receiver's use of its own capability, known as an
An attenuation is a chain of `Caveat`s.[^caveat-terminology-macaroon] A `Caveat` acts as a An attenuation is a chain of `Caveat`s.[^caveat-terminology-macaroon] A `Caveat` acts as a
function that, given a Preserves value representing an assertion or message body, yields either function that, given a Preserves value representing an assertion or message body, yields either
a possibly-rewritten value, or no value at all.[^zero-or-more] In the latter case, the value a possibly-rewritten value, or no value at all.[^affine-caveats] In the latter case, the value
has been *rejected*. In the former case, the rewritten value is used as input to the next has been *rejected*. In the former case, the rewritten value is used as input to the next
`Caveat` in the chain, or as the final assertion or message body for delivery to the entity `Caveat` in the chain, or as the final assertion or message body for delivery to the entity
backing the capability. backing the capability.
@ -183,17 +183,23 @@ leftward `Caveat` in the sequence. If no `Caveat`s are present, the capability i
and inputs are passed through to the backing capability unmodified. and inputs are passed through to the backing capability unmodified.
```preserves-schema ```preserves-schema
Caveat = Rewrite / Alts . Caveat = Rewrite / Alts / Reject / @unknown any .
Rewrite = <rewrite @pattern Pattern @template Template> .
Rewrite = <rewrite @pattern Pattern @template Template>. Reject = <reject @pattern Pattern> .
Alts = <or @alternatives [Rewrite ...]>. Alts = <or @alternatives [Rewrite ...]>.
``` ```
A `Caveat` can be either a single `Rewrite` or a sequence of alternative possible rewrites, A `Caveat` can be:
tried in left-to-right order until one of them accepts the input or there are none left to try.
(A single `Rewrite` *R* is equivalent to `<or [`*R*`]>`.)
A `Rewrite` applies its `Pattern` to the input to the `Caveat`. If it matches, the bindings - a single `Rewrite`[^single-rewrite-meaning], or a sequence of alternative possible rewrites
`Alts`, to be tried in left-to-right order until one of them accepts the input or there are
none left to try;
- a `Reject`, which passes all inputs unmodified except those matching the contained pattern; or
- an `unknown` caveat, which rejects all inputs.
Each `Rewrite` applies its `Pattern` to its input. If the `Pattern` matches, the bindings
captured by the pattern are gathered together and used in instantiation of the `Rewrite`'s captured by the pattern are gathered together and used in instantiation of the `Rewrite`'s
`Template`, yielding the output from the `Caveat`. If the pattern does not match, the `Rewrite` `Template`, yielding the output from the `Caveat`. If the pattern does not match, the `Rewrite`
has rejected the input, and other `alternatives` are tried until none remain, at which point has rejected the input, and other `alternatives` are tried until none remain, at which point
@ -518,6 +524,10 @@ The value is recursively traversed. As the relay comes across each embedded `Wir
- In each case, the `WireSymbol` associated with the OID has its reference count incremented - In each case, the `WireSymbol` associated with the OID has its reference count incremented
(if an `Assert` is being processed). (if an `Assert` is being processed).
In addition, for `Assert` events, the `WireSymbol` (necessarily in the export membrane)
associated with the OID to which the incoming `Assert` is targetted has its reference count
incremented.
### <span id="outbound-rewriting"></span>Rewriting embedded references for transmission ### <span id="outbound-rewriting"></span>Rewriting embedded references for transmission
When transmitting a `Value` *v* in an `Assert` or `Message` event, embedded references in *v* When transmitting a `Value` *v* in an `Assert` or `Message` event, embedded references in *v*
@ -686,13 +696,13 @@ care should be taken in the case of non-cryptographic transport protocols like p
To use such a transport for this protocol, establish a connection and begin transmitting To use such a transport for this protocol, establish a connection and begin transmitting
[`Packet`s](#packet-definitions) encoded as Preserves values using either the Preserves [text [`Packet`s](#packet-definitions) encoded as Preserves values using either the Preserves [text
syntax](https://preserves.dev/preserves.html#textual-syntax) or the Preserves syntax](https://preserves.dev/preserves-text.html) or the Preserves
[binary syntax](https://preserves.dev/preserves.html#compact-binary-syntax). [machine-oriented syntax](https://preserves.dev/preserves-binary.html).
The session starts with the first packet and ends with transport disconnection. If either peer The session starts with the first packet and ends with transport disconnection. If either peer
in a connection detects a syntax error, it MUST disconnect the transport. A responding server in a connection detects a syntax error, it MUST disconnect the transport. A responding server
MUST support the binary syntax, and MAY also support the text syntax. It can autodetect the MUST support the binary syntax, and MAY also support the text syntax. It can autodetect the
syntax variant by following [the rules in the syntax variant by following [the rules in the
specification](https://preserves.dev/preserves.html#appendix-autodetection-of-textual-or-binary-syntax): specification](https://preserves.dev/preserves-binary.html#appendix-autodetection-of-textual-or-binary-syntax):
the first byte of a valid binary-syntax Preserves document is guaranteed not to be the first byte of a valid binary-syntax Preserves document is guaranteed not to be
interpretable as the start of a valid UTF-8 sequence. interpretable as the start of a valid UTF-8 sequence.
@ -771,8 +781,9 @@ version 1 .
Attenuation = [Caveat ...]. Attenuation = [Caveat ...].
Caveat = Rewrite / Alts . Caveat = Rewrite / Alts / Reject / @unknown any .
Rewrite = <rewrite @pattern Pattern @template Template>. Rewrite = <rewrite @pattern Pattern @template Template> .
Reject = <reject @pattern Pattern> .
Alts = <or @alternatives [Rewrite ...]>. Alts = <or @alternatives [Rewrite ...]>.
Oid = int . Oid = int .
@ -793,7 +804,7 @@ PCompound =
/ @dict <dict @entries { any: Pattern ...:... }> . / @dict <dict @entries { any: Pattern ...:... }> .
Template = TAttenuate / TRef / Lit / TCompound . Template = TAttenuate / TRef / Lit / TCompound .
TAttenuate = <attenuate @template Template @attenuation Attenuation>. TAttenuate = <attenuate @template Template @attenuation [Caveat ...]>.
TRef = <ref @binding int>. TRef = <ref @binding int>.
TCompound = TCompound =
/ @rec <rec @label any @fields [Template ...]> / @rec <rec @label any @fields [Template ...]>
@ -806,8 +817,8 @@ TCompound =
### Attenuation ### Attenuation
```python ```python
def attenuate(attenuation, value): def attenuate(caveats, value):
for caveat in reversed(attenuation): for caveat in reversed(caveats):
value = applyCaveat(caveat, value) value = applyCaveat(caveat, value)
if value is None: if value is None:
return None return None
@ -822,6 +833,13 @@ def applyCaveat(caveat, value):
return None return None
if caveat is 'Rewrite' variant: if caveat is 'Rewrite' variant:
return tryRewrite(caveat, value) return tryRewrite(caveat, value)
if caveat is 'Reject' variant:
if applyPattern(caveat.pattern, value) is None:
return value
else:
return None
if caveat is 'unknown' variant:
return None
def tryRewrite(rewrite, value): def tryRewrite(rewrite, value):
bindings = applyPattern(rewrite.pattern, value) bindings = applyPattern(rewrite.pattern, value)
@ -947,10 +965,6 @@ def instantiate(template, bindings):
mechanism. Future versions of this specification may opt to include some of this mechanism. Future versions of this specification may opt to include some of this
generality. generality.
[^zero-or-more]: TODO: It might be better to have a `Caveat` yield *zero or more* values? That [^affine-caveats]: `Caveat`s are thus *affine*.
way they can act as filters. I've sometimes wanted the multiple-value case, though I've so
far been able to work around its lack. TODO: Perhaps it would also make sense to have a [^single-rewrite-meaning]: A single `Rewrite` *R* is equivalent to `<or [`*R*`]>`.
`Caveat` map an *event* to zero or more *events*, rather than to values? Tricky corners
there include ensuring that carried authority isn't misused; macaroons are a very elegant
solution to this problem, of course, so maybe the macaroon design idea could be adapted to
this. For now, `Value`→`Option<Value>` is probably OK.

View File

@ -25,16 +25,28 @@ an overview of `SturdyRef`s, see the [guide to the built-in gatekeeper
entity](../../operation/builtin/gatekeeper.md#sturdyrefs). entity](../../operation/builtin/gatekeeper.md#sturdyrefs).
``` ```
SturdyRef = <ref @oid any @caveatChain [Attenuation ...] @sig bytes>. SturdyRef = <ref @oid any @caveatChain [Caveat ...] @sig bytes>.
``` ```
For detail of the interpretation of `Attenuation`s, `Caveat`s, `Pattern`s, and `Template`s, see The `sig` in a `SturdyRef` is an iterated keyed-HMAC construction, starting from an HMAC of the
the [Syndicate protocol specification](../../protocol.md#capabilities-on-the-wire). ref's *secret key* and its `oid`, following [macaroons][]. The specific function chosen is
[HMAC](https://www.rfc-editor.org/rfc/rfc2104) using
[BLAKE2s-256](https://www.rfc-editor.org/rfc/rfc7693), truncating the output to the first 16
bytes. Let
- *f(k,d)* be `HMAC-BLAKE2s-256`*(k,d)*[0..16),
- *e(v)* yield the canonical machine-oriented serialization of some preserves value *v*, and
- *k* be the original secret key for the ref.
In a valid `SturdyRef`, then, the `sig` will be *f(...f(...f(f(k,e(*`oid`*)),...),e(*`Caveat`*)),...)*.
For detail of the interpretation of `Caveat`s, `Pattern`s, and `Template`s, see the [Syndicate
protocol specification](../../protocol.md#capabilities-on-the-wire).
``` ```
Attenuation = [Caveat ...]. Caveat = Rewrite / Alts / Reject / @unknown any .
Caveat = Rewrite / Alts . Rewrite = <rewrite @pattern Pattern @template Template> .
Rewrite = <rewrite @pattern Pattern @template Template>. Reject = <reject @pattern Pattern> .
Alts = <or @alternatives [Rewrite ...]>. Alts = <or @alternatives [Rewrite ...]>.
Lit = <lit @value any>. Lit = <lit @value any>.
@ -52,10 +64,12 @@ PCompound =
/ @dict <dict @entries { any: Pattern ...:... }> . / @dict <dict @entries { any: Pattern ...:... }> .
Template = TAttenuate / TRef / Lit / TCompound . Template = TAttenuate / TRef / Lit / TCompound .
TAttenuate = <attenuate @template Template @attenuation Attenuation>. TAttenuate = <attenuate @template Template @attenuation [Caveat ...]>.
TRef = <ref @binding int>. TRef = <ref @binding int>.
TCompound = TCompound =
/ @rec <rec @label any @fields [Template ...]> / @rec <rec @label any @fields [Template ...]>
/ @arr <arr @items [Template ...]> / @arr <arr @items [Template ...]>
/ @dict <dict @entries { any: Template ...:... }> . / @dict <dict @entries { any: Template ...:... }> .
``` ```
[Macaroons]: ../../glossary.md#macaroon