196 lines
7.3 KiB
Markdown
196 lines
7.3 KiB
Markdown
|
# .dehub
|
||
|
|
||
|
The `.dehub` directory contains all meta information related to
|
||
|
decentralized repository management and access control.
|
||
|
|
||
|
## config.yml
|
||
|
|
||
|
The `.dehub/config.yml` file takes the following structure:
|
||
|
|
||
|
```yaml
|
||
|
# accounts defines all accounts which are known to the repo.
|
||
|
accounts:
|
||
|
|
||
|
# Each account is an object with an id and at least one identifier. The id
|
||
|
# must be unique for each account.
|
||
|
- id: some_user_id:
|
||
|
|
||
|
# signifiers describes different methods the account might use to
|
||
|
# identify itself. Generally, these will be different public keys which
|
||
|
# commits will be signed with. At least one is required.
|
||
|
signifiers:
|
||
|
- type: "pgp_public_key"
|
||
|
body: "FULL PGP PUBLIC KEY STRING"
|
||
|
|
||
|
- type: "pgp_public_key_file"
|
||
|
path: ".dehub/some_user_id.asc"
|
||
|
|
||
|
- type: "keybase"
|
||
|
user: "some_keybase_user_id"
|
||
|
|
||
|
# access_controls defines under what conditions different files in the repo may
|
||
|
# be modified. For each file modified in a commit, all access control patterns
|
||
|
# are applied sequentially until one matches, and the associated access control
|
||
|
# conditions are checked. A commit is only allowed if the conditions of all
|
||
|
# modified files are met.
|
||
|
access_controls:
|
||
|
|
||
|
# pattern is a glob pattern describing what files this access control
|
||
|
# applies to. Single star matches all characters except path separators,
|
||
|
# double star matches everything.
|
||
|
- pattern: ".dehub/**"
|
||
|
|
||
|
# signature conditions indicate that a commit must be signed by one or
|
||
|
# more accounts to be allowed.
|
||
|
condition:
|
||
|
type: signature
|
||
|
|
||
|
# account_ids lists all accounts whose signature will count towards
|
||
|
# meeting the condition
|
||
|
account_ids:
|
||
|
- some_user_id
|
||
|
|
||
|
# count describes how many signatures are required. It can be either a
|
||
|
# contrete integer (e.g. 2, meaning any 2 accounts listed by
|
||
|
# account_ids) or a percent.
|
||
|
count: 100%
|
||
|
|
||
|
# This catch-all pattern for the rest of the repo requires that changes to
|
||
|
# any files not under `.dehub/` are signed by at least one of the
|
||
|
# defined accounts.
|
||
|
- pattern: "**"
|
||
|
condition:
|
||
|
type: signature
|
||
|
any_account: true # indicates any account defined in accounts is valid
|
||
|
count: 1
|
||
|
```
|
||
|
|
||
|
# Master commit
|
||
|
|
||
|
All new commits being appended to the HEAD of the `master` branch are subject to
|
||
|
the following requirements:
|
||
|
|
||
|
* Must conform to all requirements defined by the `access_controls` section of
|
||
|
the `config.yml`, as found in the HEAD. If the commit is the initial commit of
|
||
|
the repo then it instead uses the `config.yml` found in itself.
|
||
|
|
||
|
* Must not be a merge commit (this may be amended later, but at present it
|
||
|
simplifies implementation).
|
||
|
|
||
|
* The commit message must conform to the format and semantics defined below.
|
||
|
|
||
|
## Master Commit Message
|
||
|
|
||
|
The commit message for a commit being appended to the HEAD of the `master`
|
||
|
branch must conform to the following format: a single line (the message head)
|
||
|
giving a short description of the change, then two newlines, then a body which
|
||
|
is a yaml formatted string:
|
||
|
|
||
|
```yaml
|
||
|
This is the message head. It will be re-iterated within the yaml body.
|
||
|
|
||
|
# Now the yaml body begins
|
||
|
---
|
||
|
message: >
|
||
|
This is the message head. It will be re-iterated within the yaml body.
|
||
|
|
||
|
The rest of this field is for the message body, which corresponds to the
|
||
|
body of a normal commit message which might give a more long-form
|
||
|
explanation of the commit's changes.
|
||
|
|
||
|
Since the message is used in generating the signature it's necessary for it
|
||
|
to be encoded here fully formed, even though the message head is then
|
||
|
duplicated. Otherwise the exact bytes of the message would be ambiguous.
|
||
|
This situation is ugly, but not unbearable.
|
||
|
|
||
|
# See the Commit Signatures section below for how this is computed. The
|
||
|
# change_hash is always recomputed when verifying a commit, but is reproduced in
|
||
|
# the commit message itself for cases of forward compatibility, e.g. if the
|
||
|
algorithm to compute the hash changes.
|
||
|
change_hash: XXX
|
||
|
|
||
|
# Credentials are the set of credentials which count towards requirements
|
||
|
# specified in the `access_controls` section of the `config.yml` file.
|
||
|
credentials:
|
||
|
|
||
|
- type: pgp_signature
|
||
|
account_id: some_user_id
|
||
|
pub_key_id: XXX
|
||
|
body: "base-64 signature body"
|
||
|
```
|
||
|
|
||
|
## Commit Signatures
|
||
|
|
||
|
When a commit is being signed by a signifier there is an expected data format
|
||
|
for the data to be signed. The format is a SHA-256 hash of the following pieces
|
||
|
of data concatenated together (the "change_hash"):
|
||
|
|
||
|
* A uvarint indicating the number of bytes in the commit message.
|
||
|
* The message.
|
||
|
* A uvarint indicating the number of files changed.
|
||
|
* For each file changed in the commit, ordered lexographically-ascending based
|
||
|
on its full relative path within the repo, the following is then written:
|
||
|
* A uvarint indicating the length of the full relative path of the file
|
||
|
within the repo.
|
||
|
* The full relative path of the file within the repo.
|
||
|
* A little-endian uint32 representing the previous file mode of the file (or 0
|
||
|
if the file is being inserted).
|
||
|
* The 20-byte SHA1 hash of the previous version of the file's contents (or 20
|
||
|
0 bytes if the file is being inserted).
|
||
|
* A little-endian uint32 representing the new file mode of the file (or 0
|
||
|
if the file is being deleted).
|
||
|
* The 20-byte SHA1 hash of the new version of the file's contents (or 20
|
||
|
0 bytes if the file is being deleted).
|
||
|
|
||
|
The raw output from the SHA-256 is then prepended with a `0` byte (for forward
|
||
|
compatibility) and signed, and the result used as the signature body.
|
||
|
|
||
|
# Merge Requests
|
||
|
|
||
|
A merge request (MR) may be pushed to the repository as a new branch at any
|
||
|
time. All MR branch names follow the naming convention `DHMR-short-description`.
|
||
|
An MR branch has the following qualities:
|
||
|
|
||
|
* Meta commits (see sub-section) will only contain a commit message head/body,
|
||
|
but no file changes.
|
||
|
|
||
|
* The most recent substantial commit (as opposed to meta commits) should always
|
||
|
contain the full commit message head and body.
|
||
|
|
||
|
## Meta Commits
|
||
|
|
||
|
Meta commits are those which add information about the changes being requested,
|
||
|
but do not modify the changes themselves.
|
||
|
|
||
|
### Signature Commits
|
||
|
|
||
|
Signature commits sign the changes requested in order to count towards their
|
||
|
access control requirements. The message head of these are arbitrary, but the
|
||
|
body must be formatted as such:
|
||
|
|
||
|
```yaml
|
||
|
# This object matches the one found in the `credentials` section of the master
|
||
|
# commit message.
|
||
|
type: pgp_signature
|
||
|
account_id: some_user_id ```
|
||
|
pub_key_id: XXX
|
||
|
body: "base-64 signature body" # see Commit Signatures sub-section.
|
||
|
```
|
||
|
|
||
|
If a signature commit is added to a MR branch, and a substantial commit is
|
||
|
added after it, then that signature commit will no longer be valid, as it was
|
||
|
only signing the the prior changeset. The signer will need to create and push a
|
||
|
new signature commit, if they agree with the new changes.
|
||
|
|
||
|
## Merging MRs
|
||
|
|
||
|
When an MR has accumulated enough meta commits to fulfuill access control
|
||
|
requirements it may be coalesced into a single commit destined for the master
|
||
|
branch. See the Master Commit Message sub-section for details on how commits in
|
||
|
the master branch must be formatted.
|
||
|
|
||
|
# TODO
|
||
|
|
||
|
* access control patterns related to who may push to MR branches, and what types
|
||
|
of commits they can push.
|