# Authenticating Commits

When Bob adds a commit to Frob's repository, he can check that it is
allowed by the policy using `sq-git log` like so:

```shell
{{#include ../examples/frob-50-bob-adds-a-commit.txt}}
```

`sq-git log` checks that there is a path from the trust root to the
current commit, and that each commit can be authenticated by its
parent.

<div class="warning">

If there are merge commits, there may be multiple paths.  In this
case, only one path needs to be authenticated: when the parent
authenticates the merge commit, it implicitly authenticates the
changes added by the other parents.

</div>

The `--trust-root` argument specifies the start of the path.  By using
`HEAD^`, Bob is asking if the current commit is allowed by the parent
commit's policy.

<div class="warning">

`sq-git` authenticates a range of commits.  The **trust root** is the
start of the range.  We call it the trust root, because this is what
the user trusts; the authentication status of the target commit is
derived from the trust root.

</div>

`sq-git` requires each user to select their own trust root; for
security reasons, this cannot be delegated to the project.

Consider Dave.  When deciding whether to use a project, he first does
some due diligence.  He looks at the code, researches the project and
its maintainers, and examines the most recent commit's signing policy.
If he is happy, he uses that commit as his trust root for that
project.  Alternatively, if the project has been audited, he might
decide to rely on the auditors, and use the commit that they reviewed
as his trust root.  Or, Dave might [*yolo*] it, and set the trust root
to the current commit.  This is like trust on first use ([TOFU]):
`sq-git log` will alert him to future changes that violate the singing
policy, which is less secure, but still helpful.

  [*yolo*]: https://en.wikipedia.org/wiki/YOLO_(aphorism)
  [TOFU]: https://en.wikipedia.org/wiki/Trust_on_first_use

Dave records the trust root in his local checkout by setting git's
`sequoia.trustRoot` configuration key to the hash of the commit that
he audited:

```shell
{{#include ../examples/frob-60-dave-sets-a-trust-root.txt}}
```

It's important to use a hash and not use a branch or a tag, as these
may be changed by a third party when you pull from an upstream
repository.

When Dave fetches updates from the upstream repository, he can use
`sq-git` to check that there is an authenticated path from his trust
root to the latest commit.

To illustrate, let's say that Bob adds a few commits:

```shell
{{#include ../examples/frob-70-bob-adds-a-commit.txt}}
```

Later, Dave updates his local repository, and authenticates the
changes:

```shell
{{#include ../examples/frob-80-dave-checks.txt}}
```

Since Dave set the trust root in his `git` configuration to
`{{#include ../examples/frob-55-dave-trust-root.txt}}`, he doesn't have
to pass the `--trust-root` argument.

In this case, `sq-git` didn't complain, which means that it found a
path from the trust root to the current commit.

Let's say that Carol adds a commit:

```shell
{{#include ../examples/frob-90-carol-adds-a-commit.txt}}
```

If Dave were to pull her changes and try to authenticate them, he
would see that he can't authenticate Carol's commit:

```shell
{{#include ../examples/frob-100-dave-checks-carols-commit.txt}}
```

`sq-git` correctly identify that the commit was not authorized.  The
missing key error message means that the certificate used to sign the
commit was not found in the parent commit's policy file.  This is
exactly what we expect and want: the parent commit does not authorize
Carol to add commits.

There are two main reasons for unauthorized commits.  First, it may be
that the maintainers made a mistake.  For instance, Alice accidentally
merged Carol's commit without first verifying that the commit is
authorized by the policy.  Second, an attacker added a commit.  This
could happen if an the attacker compromised the upstream repository by
gaining access to the server, or by convincing the operator of the
forge to give them access to the repository.  The latter is sometimes
reasonable if the original maintainer has abandoned the project.
`sq-git` is not able to distinguish these different cases.  So, it is
up to the user to investigate what happened, and decide what to do.

Let's imagine that Carol sees that `sq-git log` is unhappy with her
commit, and she tries to fix it by adding herself to the signing
policy.

```shell
{{#include ../examples/frob-110-carol-adds-herself-to-the-policy.txt}}
```

Now, `sq-git log` can authenticate Carol's commit!  So, she pushes her
branch, and thinks that everything is okay.  When Dave tries to
authenticate it, however, he still sees an error:

```shell
{{#include ../examples/frob-120-dave-checks-carols-new-commits.txt}}
```

This is because although `sq-git log` can authenticate the commit with
Carol's functional change, it correctly rejects the commit where she
adds herself to the signing policy: the parent commit doesn't
authorize that, and Dave's trust root comes earlier.

If Bob is happy with Carol's functional change, he can merge it:

```shell
{{#include ../examples/frob-130-bob-merges-carols-commit.txt}}
```

Notice that Bob uses the `--no-ff` switch to force a merge commit.
This results in the following history:

```shell
{{#include ../examples/frob-140-git-log.txt}}
```

The merge commit has two parent's: Carol's commit, and Bob's commit.
Although Bob's commit can still not authenticate Carol's commit, it
can authenticate Bob's merge commit.  Therefore there is an unbroken
path from Dave's trust root to Bob's merge commit.  Now, when Dave
runs `sq-git` with his trust root, he can again authenticate the
changes:

```shell
{{#include ../examples/frob-150-dave-checks-merge-commit.txt}}
```

Note that the Carol's commit, `{{#include
../examples/frob-95-carol-commit-cherry-picked.txt}}`, still can't be
authenticated.  But because there is an alternate path to the trust
root, `sq-git` is happy.

Instead of using an empty merge commit, Bob could have re-signed
Carol's commit using his certificate:

```shell
{{#include ../examples/frob-160-bob-signs-carols-commit.txt}}
```

This preserves the Carol's authorship information, but replaces the
signature, and updates the committer.  Now there is an authenticated
path from Dave's trust root to the branch's tip:

```shell
{{#include ../examples/frob-170-dave-checks-resign.txt}}
```

