From c7bb8f85f49822d3c76ddcd7b3ab249fe0ec9175 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Fri, 21 Aug 2026 13:39:16 -0700 Subject: [PATCH] mtca/publisher: make MirrorID nullable This field is null when a checkpoint is first created. Represent it as a `*string`. This fixes a unittest error I was seeing locally: --- FAIL: TestPublish (0.01s) mtpublisher_test.go:190: p.Publish(): selecting the latest checkpoint: failed to select one *mtpublisher.checkpointEntry (unknown table): sql: Scan error on column index 3, name "mirrorID": converting NULL to string is unsupported --- mtca/mtca.go | 25 +++++++++++++++---------- mtpublisher/mtpublisher.go | 14 +++++++------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/mtca/mtca.go b/mtca/mtca.go index 60a4e10a9aa..d41c248e37a 100644 --- a/mtca/mtca.go +++ b/mtca/mtca.go @@ -22,6 +22,8 @@ import ( "github.com/jmhodges/clock" "github.com/letsencrypt/borp" + "golang.org/x/mod/sumdb/tlog" + "github.com/letsencrypt/boulder/db" "github.com/letsencrypt/boulder/identifier" "github.com/letsencrypt/boulder/issuance" @@ -31,7 +33,6 @@ import ( "github.com/letsencrypt/boulder/trees/entry" "github.com/letsencrypt/boulder/trees/issuancelog" "github.com/letsencrypt/boulder/trees/tiles" - "golang.org/x/mod/sumdb/tlog" ) var ErrIssuanceLogAlreadyInitialized = errors.New("issuance log already initialized") @@ -486,7 +487,7 @@ func (m *mtca) sequence(ctx context.Context) error { ID: 0, MTCLogID: m.logID.String(), MTCASignature: nil, - MirrorID: "", + MirrorID: nil, MirrorSignature: nil, TreeSize: candidate.TreeSize(), RootHash: newRootHash[:], @@ -594,13 +595,13 @@ func (m *mtca) sequence(ctx context.Context) error { // // For signing, the TreeSize and RootHash fields are incorporated into a `cosigned.Message`. type checkpoint struct { - ID int64 `db:"id"` - MTCLogID string `db:"mtcLogID"` - MTCASignature []byte `db:"mtcaSignature"` - MirrorID string `db:"mirrorID"` - MirrorSignature []byte `db:"mirrorSignature"` - TreeSize int64 `db:"treeSize"` - RootHash []byte `db:"rootHash"` + ID int64 `db:"id"` + MTCLogID string `db:"mtcLogID"` + MTCASignature []byte `db:"mtcaSignature"` + MirrorID *string `db:"mirrorID"` + MirrorSignature []byte `db:"mirrorSignature"` + TreeSize int64 `db:"treeSize"` + RootHash []byte `db:"rootHash"` } func (c *checkpoint) valid() error { @@ -634,8 +635,12 @@ func (c *checkpoint) String() string { if len(c.MirrorSignature) > 0 { mirrorSig = "non-empty" } + var mirrorID string + if c.MirrorID != nil { + mirrorID = *c.MirrorID + } return fmt.Sprintf("ID:%d MTCLogID:%s MTCASignature:%s MirrorID:%s MirrorSignature:%s TreeSize:%d RootHash:%x", - c.ID, c.MTCLogID, caSig, c.MirrorID, mirrorSig, c.TreeSize, c.RootHash) + c.ID, c.MTCLogID, caSig, mirrorID, mirrorSig, c.TreeSize, c.RootHash) } func (m *mtca) latestCheckpoint(ctx context.Context) (*checkpoint, error) { diff --git a/mtpublisher/mtpublisher.go b/mtpublisher/mtpublisher.go index 6319193bf9b..b0734a93f54 100644 --- a/mtpublisher/mtpublisher.go +++ b/mtpublisher/mtpublisher.go @@ -82,13 +82,13 @@ func New(dbMap *db.WrappedMap, interval time.Duration, logID issuancelog.ID, mir } type checkpointEntry struct { - ID int64 `db:"id"` - MTCLogID string `db:"mtcLogID"` - MTCASignature []byte `db:"mtcaSignature"` - MirrorID string `db:"mirrorID"` - MirrorSignature []byte `db:"mirrorSignature"` - TreeSize int64 `db:"treeSize"` - RootHash []byte `db:"rootHash"` + ID int64 `db:"id"` + MTCLogID string `db:"mtcLogID"` + MTCASignature []byte `db:"mtcaSignature"` + MirrorID *string `db:"mirrorID"` + MirrorSignature []byte `db:"mirrorSignature"` + TreeSize int64 `db:"treeSize"` + RootHash []byte `db:"rootHash"` } // cosign cosigns the checkpoint described by tree as the mirror and returns the