A read-only clone of the dehub project, for until dehub.dev can be brought back online.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
dehub/SPEC.md

7.3 KiB

.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:

# 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:

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:

# 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.