carlos / platform Public

settings-1 task 4: the root-signed pointer digest marker

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 9a0f4b3e28c474f25e0d5c2fc023dc92e2b99abd parent 83a57da
2 files changed, +165 −0
  • internal/release/digestmarker.go +88 −0
  • internal/release/digestmarker_test.go +77 −0
diff --git a/internal/release/digestmarker.go b/internal/release/digestmarker.go
new file mode 100644
index 000000000..fcd99b03d
--- /dev/null
+++ b/internal/release/digestmarker.go
@@ -0,0 +1,88 @@
+package release
+
+import (
+ "context"
+ "crypto/ed25519"
+ "errors"
+ "fmt"
+ "os"
+ "time"
+)
+
+// PointerDigestsKey is the account's emission marker (#253, spec §4.6
+// "Writers before readers"). While it verifies, upgraded writers sign
+// digests into the pointers they write; writers from before #253 do not know
+// it, which is why every writer is upgraded before it is written.
+func PointerDigestsKey(acct string) string { return "releases/" + acct + "/pointer-digests" }
+
+// DigestMarker is the marker's root-signed payload. At is when emission
+// started: a pointer without digests promoted after At came from a writer
+// that was not upgraded (DigestStateOf's straggler).
+type DigestMarker struct {
+ Schema int `json:"schema"`
+ Account string `json:"account"`
+ At time.Time `json:"at"`
+ By string `json:"by,omitempty"`
+}
+
+// WriteDigestMarker turns emission on for acct. Root key only: the marker is
+// deployment control, not channel publication (SignRootEnvelope refuses a
+// scoped signer). A marker that already verifies is left alone, so At stays
+// the first time emission went on.
+func WriteDigestMarker(ctx context.Context, s Store, sg Signer, acct, by string) error {
+ if !ValidAccount(acct) {
+ return fmt.Errorf("pointer digests: invalid account %q", acct)
+ }
+ key := PointerDigestsKey(acct)
+ _, etag, err := s.Get(ctx, key)
+ switch {
+ case errors.Is(err, os.ErrNotExist):
+ etag = ""
+ case err != nil:
+ return err
+ default:
+ if m, verr := ReadDigestMarker(ctx, s, sg.RootPublicKey(), acct); verr == nil && m != nil {
+ return nil
+ }
+ }
+ wire, err := SignRootEnvelope(sg, DigestMarker{Schema: 1, Account: acct, At: time.Now().UTC().Truncate(time.Second), By: by})
+ if err != nil {
+ return fmt.Errorf("pointer digests: the marker needs the deployment's root key: %w", err)
+ }
+ _, err = s.Put(ctx, key, wire, etag)
+ return err
+}
+
+// RemoveDigestMarker suspends emission for acct. It does not clear any box's
+// ratchet: a box that has seen digests for a channel keeps refusing pointers
+// without them (spec §4.6).
+func RemoveDigestMarker(ctx context.Context, s Store, acct string) error {
+ if !ValidAccount(acct) {
+ return fmt.Errorf("pointer digests: invalid account %q", acct)
+ }
+ if err := s.Delete(ctx, PointerDigestsKey(acct)); err != nil && !errors.Is(err, os.ErrNotExist) {
+ return err
+ }
+ return nil
+}
+
+// ReadDigestMarker is (nil, nil) when acct has no marker, the marker when it
+// verifies against the root, and an error for anything else: a marker that is
+// present but cannot be trusted is never read as "off" or as "on".
+func ReadDigestMarker(ctx context.Context, s Store, pub ed25519.PublicKey, acct string) (*DigestMarker, error) {
+ raw, _, err := s.Get(ctx, PointerDigestsKey(acct))
+ if errors.Is(err, os.ErrNotExist) {
+ return nil, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+ var m DigestMarker
+ if err := VerifyRootEnvelope(pub, raw, &m); err != nil {
+ return nil, fmt.Errorf("pointer digest marker for %s: %w", acct, err)
+ }
+ if m.Schema != 1 || m.Account != acct || m.At.IsZero() {
+ return nil, fmt.Errorf("pointer digest marker for %s names account %q, schema %d", acct, m.Account, m.Schema)
+ }
+ return &m, nil
+}
diff --git a/internal/release/digestmarker_test.go b/internal/release/digestmarker_test.go
new file mode 100644
index 000000000..3b9ed045a
--- /dev/null
+++ b/internal/release/digestmarker_test.go
@@ -0,0 +1,77 @@
+package release
+
+import (
+ "context"
+ "crypto/ed25519"
+ "testing"
+ "time"
+)
+
+func markerOn(t *testing.T, s Store, priv ed25519.PrivateKey, acct string) {
+ t.Helper()
+ if err := WriteDigestMarker(context.Background(), s, RootSigner(priv), acct, "test"); err != nil {
+ t.Fatalf("WriteDigestMarker: %v", err)
+ }
+}
+
+func TestDigestMarkerLifecycle(t *testing.T) {
+ s := NewDirStore(t.TempDir())
+ ctx := context.Background()
+ priv, pub := testKeys(t)
+ if m, err := ReadDigestMarker(ctx, s, pub, "bab"); m != nil || err != nil {
+ t.Fatalf("absent marker = %+v, %v; want nil, nil", m, err)
+ }
+ markerOn(t, s, priv, "bab")
+ m, err := ReadDigestMarker(ctx, s, pub, "bab")
+ if err != nil || m == nil || m.Account != "bab" || m.At.IsZero() {
+ t.Fatalf("marker = %+v, %v", m, err)
+ }
+ // Writing it again keeps the first time: moving it later would hide a
+ // straggler written in between.
+ time.Sleep(1100 * time.Millisecond)
+ markerOn(t, s, priv, "bab")
+ again, _ := ReadDigestMarker(ctx, s, pub, "bab")
+ if !again.At.Equal(m.At) {
+ t.Fatalf("a second write moved the marker from %s to %s", m.At, again.At)
+ }
+ if other, err := ReadDigestMarker(ctx, s, pub, "cdf"); other != nil || err != nil {
+ t.Fatalf("the marker is per account: %+v, %v", other, err)
+ }
+ if err := RemoveDigestMarker(ctx, s, "bab"); err != nil {
+ t.Fatal(err)
+ }
+ if m, err := ReadDigestMarker(ctx, s, pub, "bab"); m != nil || err != nil {
+ t.Fatalf("after removal = %+v, %v", m, err)
+ }
+ if err := RemoveDigestMarker(ctx, s, "bab"); err != nil {
+ t.Fatalf("removing an absent marker: %v", err)
+ }
+}
+
+func TestDigestMarkerIsRootOnly(t *testing.T) {
+ s := NewDirStore(t.TempDir())
+ ctx := context.Background()
+ root, pub := testKeys(t)
+ seed, grant, err := MintKeyGrant(root, "ci", []string{"canary"}, time.Hour)
+ if err != nil {
+ t.Fatal(err)
+ }
+ key, err := ParseSigningKey(seed, "test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ sg, err := ScopedSigner(key, grant, pub)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := WriteDigestMarker(ctx, s, sg, "bab", "ci"); err == nil {
+ t.Fatal("a scoped key wrote the marker")
+ }
+ // A marker signed by some other key is present but unverifiable: an
+ // error, never "absent".
+ other, _ := testKeys(t)
+ markerOn(t, s, other, "bab")
+ if m, err := ReadDigestMarker(ctx, s, pub, "bab"); m != nil || err == nil {
+ t.Fatalf("a foreign marker = %+v, %v; want an error", m, err)
+ }
+}