Module Conex_repository

module Conex_repository: sig .. end
Repository state and validation logic

The repository keeps track of valid resources, which are added after successful verification of an author. The only configuration element is the quorum: how many janitors have to sign off a change.

The only resource which is signed with an asymmetric cryptographic operation is the author, which contains a list of resources the author vouches for. To validate a resource, first the authorised authors have to be validated. Once they are approved, resource validation is a lookup of a computed hash in a map which is part of the repository.

This module contains the program logic to validate the different resources, which have different rules:

Monotonicity requirements are as follows:




Repository type, constructor, predicates


type t 
The repository type
val repository : ?quorum:int ->
(Conex_resource.Wire.t -> Conex_resource.Digest.t) ->
unit -> t
repository ~quorum ~strict digest () is a fresh empty repository.
val digestf : t -> Conex_resource.Wire.t -> Conex_resource.Digest.t
val quorum : t -> int
quorum repo is the configured quorum.
val find_team : t -> Conex_resource.identifier -> Conex_utils.S.t option
find_team repo id returns the members of the team id or None if there is no such team.
val id_loaded : t -> Conex_resource.identifier -> bool
id_loaded repo id is true if id has been loaded.
val authorised : t ->
Conex_resource.Authorisation.t -> Conex_resource.identifier -> bool
authorised repo auth id is true if id is a member of auth or member of a team which is authorised.
val contains : ?queued:bool ->
t ->
Conex_resource.Author.t ->
Conex_resource.name -> Conex_resource.typ -> Conex_resource.Wire.t -> bool
contains ~queued author name typ data is true if data named name of typ is a member in the list of resources of author. If queued is true, membership of the resource in the queued list of resources is sufficient.

Validation


type conflict = [ `NameConflict of Conex_resource.name * Conex_resource.Author.r
| `TypConflict of Conex_resource.typ * Conex_resource.Author.r ]
The variant of a conflict in the digest map.
val pp_conflict : conflict Conex_utils.fmt
pp_conflict is a pretty printer for Conex_repository.conflict.
val pp_ok : [< `Approved of Conex_resource.identifier
| `Both of Conex_resource.identifier * Conex_utils.S.t
| `Quorum of Conex_utils.S.t ]
Conex_utils.fmt
pp_ok pretty prints validation success
type base_error = [ `InvalidName of Conex_resource.name * Conex_resource.name
| `InvalidResource of
Conex_resource.name * Conex_resource.typ * Conex_resource.typ
| `NotApproved of Conex_resource.name * Conex_resource.typ * Conex_utils.S.t ]
Errors which can occur during any validation.
val pp_error : [< `AuthRelMismatch of Conex_resource.name * Conex_resource.name
| `AuthorWithoutKeys of Conex_resource.identifier
| `ChecksumsDiff of
Conex_resource.name * Conex_resource.name list *
Conex_resource.name list *
(Conex_resource.Release.c * Conex_resource.Release.c) list
| `IdNotPresent of Conex_resource.name * Conex_utils.S.t
| `InsufficientQuorum of
Conex_resource.name * Conex_resource.typ * Conex_utils.S.t * int
| `InvalidName of Conex_resource.name * Conex_resource.name
| `InvalidReleases of
Conex_resource.name * Conex_utils.S.t * Conex_utils.S.t
| `InvalidResource of
Conex_resource.name * Conex_resource.typ * Conex_resource.typ
| `MemberNotPresent of Conex_resource.identifier * Conex_utils.S.t
| `NameConflict of Conex_resource.name * Conex_resource.Author.r
| `NoSharedPrefix of Conex_resource.name * Conex_utils.S.t
| `NotApproved of Conex_resource.name * Conex_resource.typ * Conex_utils.S.t
| `NotInReleases of Conex_resource.name * Conex_utils.S.t
| `TypConflict of Conex_resource.typ * Conex_resource.Author.r ]
Conex_utils.fmt
pp_error prints validation errors.
val validate_author : t ->
Conex_resource.Author.t ->
(t,
[> `AuthorWithoutKeys of Conex_resource.identifier
| `InsufficientQuorum of
Conex_resource.name * Conex_resource.typ * Conex_utils.S.t * int
| `InvalidName of Conex_resource.name * Conex_resource.name
| `InvalidResource of
Conex_resource.name * Conex_resource.typ * Conex_resource.typ
| `NameConflict of Conex_resource.name * Conex_resource.Author.r
| `NotApproved of
Conex_resource.name * Conex_resource.typ * Conex_utils.S.t
| `TypConflict of Conex_resource.typ * Conex_resource.Author.r ])
Pervasives.result
validate_author repo author validates author: at least one public key must be approved by a quorum of janitors or the resource list is empty and it is approved by a quorum of janitors. The valid resource list is added to the repository (using Conex_repository.add_index).
val validate_account : t ->
Conex_resource.Author.t ->
Conex_resource.Author.account ->
([ `Both of Conex_resource.identifier * Conex_utils.S.t ],
[> `InsufficientQuorum of
Conex_resource.name * Conex_resource.typ * Conex_utils.S.t * int
| `InvalidName of Conex_resource.name * Conex_resource.name
| `InvalidResource of
Conex_resource.name * Conex_resource.typ * Conex_resource.typ
| `NotApproved of
Conex_resource.name * Conex_resource.typ * Conex_utils.S.t ])
Pervasives.result
validate_account repo author account validates account of author: a quorum of janitors have to approve an account.
val validate_key : t ->
Conex_resource.identifier ->
Conex_resource.Key.t ->
([ `Both of Conex_resource.identifier * Conex_utils.S.t ],
[> `InsufficientQuorum of
Conex_resource.name * Conex_resource.typ * Conex_utils.S.t * int
| `InvalidName of Conex_resource.name * Conex_resource.name
| `InvalidResource of
Conex_resource.name * Conex_resource.typ * Conex_resource.typ
| `NotApproved of
Conex_resource.name * Conex_resource.typ * Conex_utils.S.t ])
Pervasives.result
validate_key repo id key validates key of id: a quorum of janitors have to approve a key.
val validate_team : t ->
Conex_resource.Team.t ->
(t * [ `Quorum of Conex_utils.S.t ],
[> `InsufficientQuorum of
Conex_resource.name * Conex_resource.typ * Conex_utils.S.t * int
| `InvalidName of Conex_resource.name * Conex_resource.name
| `InvalidResource of
Conex_resource.name * Conex_resource.typ * Conex_resource.typ
| `MemberNotPresent of Conex_resource.identifier * Conex_utils.S.t
| `NotApproved of
Conex_resource.name * Conex_resource.typ * Conex_utils.S.t ])
Pervasives.result
validate_team repo team validates team: a quorum of janitors have to approve a team, and all team members must be in the repository. If valid, the team is added to repo (using Conex_repository.add_team).
val validate_authorisation : t ->
Conex_resource.Authorisation.t ->
([ `Quorum of Conex_utils.S.t ],
[> `IdNotPresent of Conex_resource.name * Conex_utils.S.t
| `InsufficientQuorum of
Conex_resource.name * Conex_resource.typ * Conex_utils.S.t * int
| `InvalidName of Conex_resource.name * Conex_resource.name
| `InvalidResource of
Conex_resource.name * Conex_resource.typ * Conex_resource.typ
| `NotApproved of
Conex_resource.name * Conex_resource.typ * Conex_utils.S.t ])
Pervasives.result
validate_authorisation repo auth validates auth: a quorum of janitors have to approve an authorisation, and all authorised ids have to be present in repo.
val validate_package : t ->
?on_disk:Conex_resource.Package.t ->
Conex_resource.Authorisation.t ->
Conex_resource.Package.t ->
([ `Approved of Conex_resource.identifier
| `Both of Conex_resource.identifier * Conex_utils.S.t
| `Quorum of Conex_utils.S.t ],
[> `AuthRelMismatch of Conex_resource.name * Conex_resource.name
| `InvalidName of Conex_resource.name * Conex_resource.name
| `InvalidReleases of
Conex_resource.name * Conex_utils.S.t * Conex_utils.S.t
| `InvalidResource of
Conex_resource.name * Conex_resource.typ * Conex_resource.typ
| `NoSharedPrefix of Conex_resource.name * Conex_utils.S.t
| `NotApproved of
Conex_resource.name * Conex_resource.typ * Conex_utils.S.t ])
Pervasives.result
validate_package repo ~on_disk auth package validates package: an Conex_repository.authorised identity must approve the package in repo, all releases must be prefixed with the package name, and if on_disk is given, the list of releases have to be identical.
val validate_release : t ->
?on_disk:Conex_resource.Release.t ->
Conex_resource.Authorisation.t ->
Conex_resource.Package.t ->
Conex_resource.Release.t ->
([ `Approved of Conex_resource.identifier
| `Both of Conex_resource.identifier * Conex_utils.S.t
| `Quorum of Conex_utils.S.t ],
[> `AuthRelMismatch of Conex_resource.name * Conex_resource.name
| `ChecksumsDiff of
Conex_resource.name * Conex_resource.name list *
Conex_resource.name list *
(Conex_resource.Release.c * Conex_resource.Release.c) list
| `InvalidName of Conex_resource.name * Conex_resource.name
| `InvalidResource of
Conex_resource.name * Conex_resource.typ * Conex_resource.typ
| `NotApproved of
Conex_resource.name * Conex_resource.typ * Conex_utils.S.t
| `NotInReleases of Conex_resource.name * Conex_utils.S.t ])
Pervasives.result
validate_release repo ~on_disk auth package release validates release: an Conex_repository.authorised (using auth) identity must approve the release in repo, it must be part of the releases of package, and if on_disk is given, the files listed must be equal, as well as their checksums.

Monotonicity


type m_err = [ `Deleted of Conex_resource.typ * Conex_resource.name
| `Msg of Conex_resource.typ * string
| `NotIncreased of Conex_resource.typ * Conex_resource.name ]
The variant of monotonicity errors.
val pp_m_err : m_err Conex_utils.fmt
pp_m_err is a pretty printer for Conex_repository.m_err.
val monoton_author : ?old:Conex_resource.Author.t ->
?now:Conex_resource.Author.t ->
t -> (unit, m_err) Pervasives.result
monoton_author ~old ~now repo checks that the counter increased.
val monoton_team : ?old:Conex_resource.Team.t ->
?now:Conex_resource.Team.t ->
t -> (unit, m_err) Pervasives.result
monoton_team ~old ~now repo checks that the counter increased.
val monoton_authorisation : ?old:Conex_resource.Authorisation.t ->
?now:Conex_resource.Authorisation.t ->
t -> (unit, m_err) Pervasives.result
monoton_authorisation ~old ~now repo checks that the counter increased.
val monoton_package : ?old:Conex_resource.Package.t ->
?now:Conex_resource.Package.t ->
t -> (unit, m_err) Pervasives.result
monoton_package ~old ~now repo checks that the counter increased.
val monoton_release : ?old:Conex_resource.Release.t ->
?now:Conex_resource.Release.t ->
t -> (unit, m_err) Pervasives.result
monoton_release ~old ~now repo checks that the counter increased.

Unsafe operations



These operations extend which resources are trusted. Usually you should not need them, but use Conex_repository.validate_author and Conex_repository.validate_team instead.
val add_valid_resource : Conex_resource.identifier ->
t ->
Conex_resource.Author.r ->
(t, conflict) Pervasives.result
add_valid_resource id repo r marks resource r valid under id in repo. If the digest of r is already present for a different resource, an error will be returned.
val add_index : t ->
Conex_resource.Author.t ->
(t, conflict) Pervasives.result
add_index repo author applies Conex_repository.add_valid_resource to each member of the resource list from author.
val add_team : t -> Conex_resource.Team.t -> t
add_team repo team adds the team to the repo.
val add_id : t -> Conex_resource.identifier -> t
add_id repo id adds the id to the repo.