mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
141 lines
5.9 KiB
Markdown
141 lines
5.9 KiB
Markdown
# WIP: Offline-root signing
|
|
|
|
Status: implementation paused while we confirm what “generic delegated
|
|
signing” should mean.
|
|
|
|
## What we are trying to protect
|
|
|
|
A Buzz account has a routine key that remains available to the desktop app and
|
|
may also be accessible to agents. That key should continue to sign ordinary
|
|
Buzz events. For a sensitive action such as approving a pull request, we want
|
|
an additional signature from an offline root.
|
|
|
|
The original PR event and its updates are already signed and content-addressed.
|
|
The offline root therefore does not need to sign another copy of the payload or
|
|
participate in a separate request/policy workflow. It needs to sign the exact
|
|
event ID it reviewed.
|
|
|
|
A Nostr event has one author and one signature, and its ID commits to that
|
|
author, its tags, and its content. We cannot append a second signature to an
|
|
existing event without changing it. The root must publish a new signed event
|
|
that references the original event.
|
|
|
|
## Delegation and countersigning are different
|
|
|
|
Tyler's comment that we will probably want this generically for delegated
|
|
signing changes where the primitive should live, but it does not bring back the
|
|
generic approval system.
|
|
|
|
There are two related operations:
|
|
|
|
- **Delegation:** a root authorizes another key to sign some class of future
|
|
events on its behalf.
|
|
- **Countersigning:** a root reviews an event that already exists and signs a
|
|
reference to that exact event.
|
|
|
|
Ordinary delegation alone does not solve the high-assurance problem. If the
|
|
routine key is compromised, an attacker can use whatever authority was
|
|
delegated to it. High-assurance approval requires the second operation: the
|
|
offline root must countersign each exact sensitive event.
|
|
|
|
The two operations can share a generic representation of the relationship
|
|
between an account and its signing authority, but their verification rules and
|
|
security properties must remain distinct.
|
|
|
|
## Proposed minimal primitive
|
|
|
|
The reusable protocol needs only two signed objects in addition to the event
|
|
being approved.
|
|
|
|
First, the routine account publishes a root link. The link contains a root
|
|
signature over the routine pubkey, and the routine profile signs the link in
|
|
turn. This proves that both keys agree on the relationship.
|
|
|
|
Second, the root publishes an endorsement with:
|
|
|
|
- the exact subject event ID;
|
|
- the exact account/root-link event ID;
|
|
- the routine account represented by the root; and
|
|
- a short signed purpose such as `approve`.
|
|
|
|
The generic verifier checks the profile, subject, and endorsement signatures;
|
|
the root-to-account link; the exact references; and the signed purpose. It does
|
|
not know anything about pull requests.
|
|
|
|
The relay may use that same verifier before storing an endorsement. It should
|
|
validate the signing relationship and referenced events, but it should not
|
|
implement PR-specific rules.
|
|
|
|
## Pull requests become a thin consumer
|
|
|
|
For a pull request, the subject is the current signed revision:
|
|
|
|
- the latest trusted kind `1619` update, when one exists; or
|
|
- otherwise the original kind `1618` pull-request event.
|
|
|
|
The PR code treats a valid endorsement with purpose `approve` as an approval by
|
|
the routine account. If a new update is published, its event ID is different,
|
|
so an endorsement of the previous revision no longer counts. No separate
|
|
staleness or payload-digest mechanism is required.
|
|
|
|
The desktop should export the subject event and account link as an offline
|
|
signing package. The root secret remains on the offline device. The desktop
|
|
only imports the resulting public endorsement event.
|
|
|
|
## What Tyler's comment changes
|
|
|
|
The underlying SDK and wire format should use generic event-signing language,
|
|
not PR-specific types. The offline CLI should likewise sign an arbitrary exact
|
|
event package. PR code supplies the subject and interprets `approve`.
|
|
|
|
The current direction is therefore mostly right, but any checks for PR kinds or
|
|
the literal `approve` action belong in the PR feature, not in the generic
|
|
endorsement builder or publisher.
|
|
|
|
This does **not** justify adding:
|
|
|
|
- approval policies;
|
|
- request and decision records;
|
|
- thresholds or quorum calculation;
|
|
- a generic approval inbox;
|
|
- copied payloads and payload digests; or
|
|
- a separate proof-object hierarchy.
|
|
|
|
Those features solve different problems and were responsible for most of the
|
|
earlier size and complexity.
|
|
|
|
## Root rotation and revocation
|
|
|
|
Changing or removing the root must itself require authorization from the
|
|
current root. Otherwise a compromised routine key could remove the protection
|
|
before performing a sensitive action.
|
|
|
|
We still need to decide how rotation affects old endorsements. There are two
|
|
reasonable meanings:
|
|
|
|
- The endorsement proves that the root was valid when it signed. It remains
|
|
valid historical evidence after rotation.
|
|
- An endorsement may authorize a pending action only while its referenced root
|
|
link is current. Rotation immediately prevents old-root endorsements from
|
|
authorizing new execution.
|
|
|
|
For PR admission, the second rule is safer. We can preserve the old event as
|
|
historical evidence while requiring the current account/root link when deciding
|
|
whether the PR may merge.
|
|
|
|
## Questions to settle before continuing
|
|
|
|
1. Did Tyler mean classic future-event delegation, exact-event countersigning,
|
|
or a shared protocol that supports both?
|
|
2. Should the account/root relationship remain a tag on the routine profile,
|
|
or become a dedicated replaceable event reusable by other signing features?
|
|
3. Is the first version intentionally one root per account, or must it support
|
|
multiple scoped delegates now?
|
|
4. Should active authorization always require the currently linked root, while
|
|
preserving older endorsements only as audit history?
|
|
|
|
My recommendation is to ship one root per account and one generic exact-event
|
|
endorsement. Use it first for PR approvals, keep PR interpretation outside the
|
|
generic verifier, and defer policies, quorum, and broader delegation until a
|
|
concrete second consumer requires them.
|