diff --git a/docs/decisions/0021-what-this-board-publishes.md b/docs/decisions/0021-what-this-board-publishes.md new file mode 100644 index 0000000..bffbd6c --- /dev/null +++ b/docs/decisions/0021-what-this-board-publishes.md @@ -0,0 +1,87 @@ +# 0021. What this board publishes + +## What was decided + +This board publishes downloadable release artefacts. They are signed. The +release notes say, in the notes themselves rather than only here, that the +artefacts exist for checking this board and are not part of what the +organisation ships to users. + +The reason is the independent-verification argument, which is the whole point of +handing somebody a runner at all. The runner's job is reading a checkout and +reporting what it examined, and somebody who has to build that runner from the +repository they are checking is in a weaker position than somebody who downloads +it. Most people who might want to check this board's claims have no toolchain. +Publishing source only would have cost exactly that, and it would have left the +verification argument resting on the reader trusting the build they made from +the tree under examination. + +The tension with the scope this board opened with is real and is not resolved by +being unwritten. That scope excludes anything a user is asked to install. What +separates the two is who the operator is: somebody checking this repository, +rather than somebody using a media server. The release-notes sentence is what +carries that distinction to the person holding the file, and its weakness is +that it depends on being read. Both halves are stated here so that a later +reader meets the residual rather than the assurance. + +The artefacts are signed rather than published with a bare checksum. A checksum +published next to the file it checksums proves the download arrived intact and +says nothing about who built it, which is the claim somebody verifying this +board actually needs. The keys are the ones operations#1609 sets up for the +working accounts, and that is what makes this one key-custody story rather than +two: record 0023 requires a verified signature on a commit from the same keys. +Where those keys are held and how they are rotated belongs to that issue and is +not restated here, because a custody story written twice is a custody story with +two answers. + +What publishing costs, named rather than discovered later. Signing. Checksums. +A bill of materials. A vulnerability surface, which a repository publishing +nothing does not have. And an expectation of continuity, which is the one that +cannot be withdrawn once somebody is running a version. + +## What it applies to + +Every release this board publishes, from the commit this record lands on, and +the issues that build them: the release workflow, the third-party notices and +bill of materials, the smoke run against a published artefact, and the first +release. + +It does not apply to what an experiment produces. An experiment's prototype is +not published, is not something anybody is asked to install, and leaves this +board by promotion, which is +[0005-how-a-result-leaves.md](0005-how-a-result-leaves.md). + +It decides that the artefacts are signed and does not decide what a signature is +checked with, by whom, or what a reader does when the check fails. A published +signature nobody verifies is a file beside a file. + +## What else was considered + +Publishing source only, with the tool run from a checkout. + +Publishing artefacts with a checksum beside each one and no signature. + +Publishing artefacts with no release-notes sentence separating them from what +the organisation ships to users. + +## What each rejected option would have cost + +Source only costs the reader a toolchain, which most people who would want to +check this board do not have, and it weakens the argument the publishing exists +to make. Somebody who builds the tool from the repository they are checking has +verified that the tree builds, not that the tree is what it claims to be. The +option is cheap for this board and expensive for exactly the person it was +supposed to serve. + +A checksum with no signature costs the claim that matters. It proves the bytes +arrived as they left and nothing about where they left from, so anybody who can +place a file can place a checksum beside it. It is also the cheaper option only +until entry seven of the plan is answered, since a signed commit needs a key +held somewhere regardless, and taking it would have meant writing the custody +story once for commits and discovering later that artefacts needed their own. + +Publishing with no separating sentence costs the scope exclusion its meaning. An +artefact with no such note is read as something the organisation ships, which is +the reading the exclusion was written against, and the cost of correcting that +reading arrives after somebody has already deployed against it. The sentence is +weak because it depends on being read; absent, there is nothing to depend on. diff --git a/docs/decisions/0023-signed-commits-on-the-default-branch.md b/docs/decisions/0023-signed-commits-on-the-default-branch.md new file mode 100644 index 0000000..84c3cbb --- /dev/null +++ b/docs/decisions/0023-signed-commits-on-the-default-branch.md @@ -0,0 +1,88 @@ +# 0023. A commit on the default branch carries a verified signature + +## What was decided + +A commit on the default branch of this board has to carry a verified signature. +It becomes effective as the account keys operations#1609 sets up for the working +accounts land, and not before, because a rule that refuses every merge before +anybody holds a key is a rule that gets turned off rather than followed. + +The reason is that two claims are otherwise collapsed into one. That an account +pushed a commit and that a key signed it are different statements, and only the +second survives somebody else holding the account. Not requiring a signature +costs nothing to operate and rests authorship entirely on the account, which is +one credential and one recovery route away from being somebody else's. + +The costs are real, they arrive later than the decision does, and each of them +lands on somebody who did not take it. They are written here rather than +discovered. + +A key has to be held somewhere and rotated eventually. That is the same key +story record 0021 needs for signed release artefacts, which is why the two +answers were taken together: one custody story, written once, in +operations#1609. + +An unsigned commit anywhere in a branch's history refuses the merge rather than +refusing the commit. So the repair is rebuilding the branch rather than adding +one more commit to it, and it lands at the end of the work rather than at the +start, which is the moment it is most expensive and least expected. + +Edits made through the web interface and anything an automation authors are +signed by the platform's key or not at all. That decides what those routes can +still be used for, and it is a consequence rather than a side effect. + +**Earlier history does not become signed.** This covers what arrives after the +day it takes effect, whatever was intended by setting it, so a reader must not +take a signed default branch for a branch that is signed end to end. Stating +that here is the point: the rule buys a property from a date, and a property +from a date read as a property of the whole is worse than no property at all. + +The requirement is a setting on the branch protection rather than anything in +this tree, so nothing here refuses an unsigned commit and this record does not +claim otherwise. Read the live state rather than trusting this paragraph: + + gh api repos/Flowfin/lab/rules/branches/main --jq '.[].type' + +Neither this board nor the board the quality-parity work targets required a +signature when this was decided, so parity settles nothing here and the ruleset +walk points at this record instead of deciding it. + +## What it applies to + +Every commit reaching the default branch of this board from the day the keys +land, whoever authors it, with no bypass for whoever administers the repository. +A gate with an exception for the person most likely to be in a hurry is not a +gate. + +It applies to the ruleset work that configures it and to the quality-parity +document that walks the ruleset. + +It does not apply to a feature branch, which no ruleset covers, and it does not +apply to anything already in history. + +It decides that a signature is required and does not decide what happens to a +contributor who has no key. This board takes experiments from anybody, so that +question is real rather than hypothetical, and the record answering who may run +an experiment here is where it belongs. + +## What else was considered + +Not requiring a signature at all, and resting authorship on the account. + +Requiring one from the first release onward rather than from the day the keys +land. + +## What each rejected option would have cost + +Resting on the account costs the distinction the whole decision is about. It is +free to operate and it is exactly as strong as the weakest recovery route on one +account, which is not a property this board controls or can measure. The cost is +invisible until the day it is total. + +Tying it to the first release costs the same thing the effective date already +costs, and more of it. A history carrying unsigned commits does not become +signed afterwards, so the later the rule starts the more of the branch it does +not cover, and the release is later than the keys. It also splits the key story +from record 0021 by a stretch of calendar for no gain, since the keys that sign +the release artefacts are the keys that sign the commits, and having them +without using them is a cost already paid and not collected.