refactor SPEC, plus some small changes to INTRODUCTION

message: refactor SPEC, plus some small changes to INTRODUCTION
change_hash: AH0PC1GwyLaVEQ0xwI3IxE5xTUmOE5o/bdH2PoNgKAA7
credentials:
- type: pgp_signature
  pub_key_id: 95C46FA6A41148AC
  body: iQIzBAABAgAdFiEEJ6tQKp6olvZKJ0lwlcRvpqQRSKwFAl5PFygACgkQlcRvpqQRSKyqYg/+MWE24B1rJDqQudlmuZXDYDRpQE1jsvknbLRA+IF7Ky4PYthZLAOc2RNGOE0gsKtyB353tx5cQITHycNqX2XJoEX7iR5qBKlAWQlc5YcNSg1ChtylDXTl7zw96mPKzCpo0dFxCabHJokjgCO+bKaVPZ3I0A+jaEfnkeCaamzVjgCNeMe3SZMMSS0/uUK6b91BlcpNuLT6ZBhwS8JInhLXfteOtO2GBlkurLGvi3E9qAsNGE8VPSoF9yXOua9v8eEzubx62HxkfzsULkS2FgHnB+57sEdXK4VRxokD5twLOcAgF22NzzA/VMw+inFGxgpcxgEDLx9JujEKhWlbUY2OGjgOEwL9faxz21JpMl4PwN1Hj2S6CqIqs9gcTv3id8R4CZM6UmUKN5ReHmdF8MHKlGbuLkQATNGs9We5iH3zgcZffI6mbCWn1aWUoWfruP7XEJxEM/0xJnyN9cxj6KtqHl+IPZB8bnUm5q9UDJgVHjEJ9l3bwza4PBNSU1mcvT2e2oiyCq8Lq8zsMt8V8I6vdnKCXomNY/RDagPRMn3bmfJdT9SbvBVMn4XrEb4uNL0cYBPyBoQJoDSCyNuSP32aMHe8f/yIAaaQ4zWmoEVgfvMk4Nm36Ls5vb4DdhVtvBH706JgAhhY2nnk7zxqJZ2ZzqgwaCEZQ2B69fVK7e2Cf4c=
  account: mediocregopher
This commit is contained in:
mediocregopher 2020-02-20 16:33:03 -07:00
parent b565d26d1f
commit 492e7242c6
2 changed files with 164 additions and 112 deletions

View File

@ -37,6 +37,12 @@ By embedding project meta-information into git messages, as yaml encoded data
structures, dehub is able to incept all the features generally provided by git structures, dehub is able to incept all the features generally provided by git
platforms into the git history itself, including dehub's own configuration. platforms into the git history itself, including dehub's own configuration.
By doing this, the server-side git component can be reduced to a mere
pre-receive hook (if anything at all). This opens the door for much more
lightweight and flexible hosting of git projects, and even more radical
solutions like hosting git projects on completely decentralized platforms like
IPFS.
### Example ### Example
MyProject wants to ensure that at least 2 of the 3 maintainers sign off on a MyProject wants to ensure that at least 2 of the 3 maintainers sign off on a
@ -64,6 +70,7 @@ A commit in the `trunk` branch would have a message with the following form:
``` ```
This is the first line of the commit message. It remains human readable This is the first line of the commit message. It remains human readable
---
type: change type: change
message: | message: |
This is the first line of the commit message. It remains human readable This is the first line of the commit message. It remains human readable
@ -93,23 +100,25 @@ The `credentials` contains signatures of both the commit message and its
changes, allowing it to be added to the `trunk`. A simple git hook is all that's changes, allowing it to be added to the `trunk`. A simple git hook is all that's
needed to verify commits in `trunk` when they are pushed or pulled. needed to verify commits in `trunk` when they are pushed or pulled.
## dehub Branches ## dehub Thread Branches
The `trunk` branch is the project's source-of-truth; all commits in it must have The `trunk` branch is the project's source-of-truth; all commits in it must have
dehub encoded message bodies with acceptable credentials. Other branches are dehub encoded message bodies with acceptable credentials. Other branches, called
used to coordinate new changes, and then coalesce those changes into a commit threads, are used to coordinate new changes, and then coalesce those changes
suitable for `trunk`. into a commit suitable for `trunk`.
### Example ### Example
Alice creates and pushes a branch on the git repo called `featureBranch`, and Alice creates and pushes a thread branch on the git repo called `featureBranch`,
pushes to it a commit with the following commit message: and pushes to it a commit with the following commit message:
``` ```
This commit adds some really cool features This commit adds some really cool features
---
type: change type: change
message: This commit adds some really cool features message: This commit adds some really cool features
change_hash: SOMECHANGEHASH
credentials: credentials:
- type: pgp_signature - type: pgp_signature
pub_key_id: 01234 pub_key_id: 01234
@ -120,12 +129,13 @@ credentials:
# trunk branch. # trunk branch.
``` ```
Bob sees the new branch and looks through it. He pushes the following commit Bob sees the new thread branch and looks through it. He pushes the following
(with no file changes): commit (with no file changes):
``` ```
A small comment A small comment
---
type: comment type: comment
message: | message: |
A small comment A small comment
@ -143,18 +153,20 @@ credentials:
``` ```
Alice sees Bob's comment, and agrees with his suggestion. She pushes a new Alice sees Bob's comment, and agrees with his suggestion. She pushes a new
commit, which contains a slight modification of the original commit message plus commit to the thread, which contains a slight modification of the original
the suggested changes: commit message plus the suggested changes:
``` ```
This commit adds some really cool features This commit adds some really cool features
---
type: change type: change
message: | message: |
This commit adds some really cool features This commit adds some really cool features
The pattern used at file:line was suggested by Bob. Thanks Bob! The pattern used at file:line was suggested by Bob. Thanks Bob!
change_hash: NEWCHANGEHASH
credentials: credentials:
- type: pgp_signature - type: pgp_signature
pub_key_id: 01234 pub_key_id: 01234
@ -165,25 +177,29 @@ credentials:
# trunk branch. # trunk branch.
``` ```
Bob, happy with these changes, pushes a commit to `featureBranch` which adds his Bob, happy with these changes, pushes a commit to the thread which adds his own
own signature for the latest commit message and all file changes in the branch: signature for the latest commit message and all file changes in the branch:
``` ```
bob's signature for this branch's changes bob's signature for this branch's changes
type: pgp_signature ---
pub_key_id: 01234 type: credential
change_hash: NEWCHANGEHASH
credentials:
- type: pgp_signature
pub_key_id: 56789
body: SIGNATUREBODY body: SIGNATUREBODY
account: bob account: bob
``` ```
_Finally_ the feature branch is ready to be coalesced, which is a step anyone _Finally_ the thread branch is ready to be coalesced, which is a step anyone
can do once all the required credentials are available. can do once all the required credentials are available.
To coalesce, the following is done: All changes in the branch are squashed into To coalesce, the following is done: All file changes in the branch are squashed
a single commit, using the latest commit message which was pushed by Alice. into a single change commit, using the latest commit message which was pushed by Alice.
Bob's signature is added to the commit structure as a credential. The commit can Bob's signature is added to the change commit message as a credential. The
then be pushed to `trunk` (because it now has two credentials) and commit can then be pushed to `trunk` (because it now has two credentials) and
`featureBranch` can be deleted. `featureBranch` can be deleted.
## Pre-emptively Answered Questions ## Pre-emptively Answered Questions

218
SPEC.md
View File

@ -65,65 +65,11 @@ access_controls:
count: 1 count: 1
``` ```
# Trunk Commit # Change Hash
All new commits being appended to the HEAD of the `trunk` branch are subject to When a change commit (see Commits section) is being signed by a signifier there
the following requirements: 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):
* 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 branch 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.
## Trunk Commit Message
The commit message for a commit being appended to the HEAD of the `trunk`
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. * A uvarint indicating the number of bytes in the commit message.
* The message. * The message.
@ -143,51 +89,141 @@ of data concatenated together (the "change_hash"):
0 bytes if the file is being deleted). 0 bytes if the file is being deleted).
The raw output from the SHA-256 is then prepended with a `0` byte (for forward 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. compatibility). The result is the raw change hash.
# Merge Requests # Credentials
A merge request (MR) may be pushed to the repository as a new branch at any All file changes need to have some kind of credential to be accepted into the
time. All MR branch names follow the naming convention `DHMR-short-description`. `trunk` branch (see Trunk Branch section). Each credential is encoded as a yaml
An MR branch has the following qualities: object with a `type` field.
* Meta commits (see sub-section) will only contain a commit message head/body, All credentials contain enough information to correspond them to a specific
but no file changes. signifier in the `config.yml`, so as to be able to verify them.
* The most recent substantial commit (as opposed to meta commits) should always ## PGP Signature Credential
contain the full commit message head and body.
## Meta Commits Currently there is only a single credential type, the `pgp_signature`, which
signs a raw change hash (which is communicated out-of-band of the object):
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 trunk
# commit message.
type: pgp_signature type: pgp_signature
account_id: some_user_id ``` account_id: some_user_id
pub_key_id: XXX pub_key_id: XXX
body: "base-64 signature body" # see Commit Signatures sub-section. body: "base-64 signature body"
``` ```
If a signature commit is added to a MR branch, and a substantial commit is # Commits
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 All commit messages in dehub repositories are expected to follow the following
template (newlines included, yaml comments start with `#` and are only for
informational purposes):
When an MR has accumulated enough meta commits to fulfill access control ```
requirements it may be coalesced into a single commit destined for the `trunk` Human readable message head
branch. See the Trunk Commit Message sub-section for details on how commit
messages in the `trunk` branch must be formatted. ---
# Three dashes indicate the start of the yaml body. Everything after must be
# valid yaml.
type: type of the commit # Always required
fieldA: valueA
fieldB: valueB
```
## Change Commits
Commits of type `change` correspond to the standard git commit; they encompass a
set of file changes as well as a message describing the changes which occurred.
They extend the standard git commit with a few dehub specific features, such as
the change hash and credentials.
`change` commits are, currently, the _only_ commit type which are allowed to
have file changes.
Example change commit message:
```
This is the message head. It will be re-iterated within the message field
---
type: change
message: >
This is the message head. It will be re-iterated within the message field
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.
# The change_hash is able to be computed from the commit's message and changed
# files, but is reproduced in the commit message for forward compatibility, e.g.
# if the algorithm to compute the hash changes.
change_hash: XXX
# Credentials are the set of credentials which indicate approval of the change
credentials:
- type: pgp_signature
account_id: some_user_id
pub_key_id: XXX
body: "base-64 signature body"
```
## Credential Commits
Commits of type `credential` contain one or more credentials for some set of
changes, and the change hash to which those credentials apply. The commit
message head is not spec'd, but should be a human-readable description of "who
is crediting what, and how".
Example credential commit message:
```
some_user_id pgp sig of commits AAA..BBB with key CCC
---
change_hash: XXX
credentials:
- type: pgp_signature
account_id: some_user_id
pub_key_id: CCC
body: "base-64 signature body"
```
# Branches
dehub branches correspond 1-to-1 with branches in the underlying git repo. All
commits in a dehub branch should contain an encoded message as specified in the
Commits section of this document, and possibly file changes as appropriate.
## Trunk Branch
The "primary" branch of a dehub repo is the `trunk` branch. All new commits
being appended to the HEAD of the `trunk` branch are subject to the following
requirements:
* Must be `change` commits.
* Must conform to all requirements defined by the `access_controls` section of
the `config.yml`, as found in the current HEAD. If the commit is the initial
commit of the branch then it instead uses the `config.yml` found in itself.
* Must be a "fast-forward" commit (this may be amended later, but at present it
simplifies implementation).
## Thread Branches
Branches which are not the `trunk` branch are referred to as "threads", and have
much less stringent requirements than the `trunk` branch:
* They can contain commits of any type, as long as the commits come from those
with an account defined in the `config.yml`.
* `change` commits are not subject `access_controls` requirements.
# TODO # TODO