Allow reading incident rows with NULL columns (#6961)
Fixes https://github.com/letsencrypt/boulder/issues/6960
This commit is contained in:
parent
08017e436e
commit
bd29cc430f
|
|
@ -850,10 +850,10 @@ func incidentModelToPB(i incidentModel) sapb.Incident {
|
|||
|
||||
// incidentSerialModel represents a row in an 'incident_*' table.
|
||||
type incidentSerialModel struct {
|
||||
Serial string `db:"serial"`
|
||||
RegistrationID int64 `db:"registrationID"`
|
||||
OrderID int64 `db:"orderID"`
|
||||
LastNoticeSent time.Time `db:"lastNoticeSent"`
|
||||
Serial string `db:"serial"`
|
||||
RegistrationID *int64 `db:"registrationID"`
|
||||
OrderID *int64 `db:"orderID"`
|
||||
LastNoticeSent *time.Time `db:"lastNoticeSent"`
|
||||
}
|
||||
|
||||
// crlEntryModel has just the certificate status fields necessary to construct
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/letsencrypt/boulder/db"
|
||||
"github.com/letsencrypt/boulder/grpc"
|
||||
"github.com/letsencrypt/boulder/probs"
|
||||
"github.com/letsencrypt/boulder/test/vars"
|
||||
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
corepb "github.com/letsencrypt/boulder/core/proto"
|
||||
|
|
@ -346,3 +347,52 @@ func makeKey() rsa.PrivateKey {
|
|||
q := bigIntFromB64("uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc=")
|
||||
return rsa.PrivateKey{PublicKey: rsa.PublicKey{N: n, E: e}, D: d, Primes: []*big.Int{p, q}}
|
||||
}
|
||||
|
||||
func TestIncidentSerialModel(t *testing.T) {
|
||||
testIncidentsDbMap, err := DBMapForTest(vars.DBConnIncidentsFullPerms)
|
||||
test.AssertNotError(t, err, "Couldn't create test dbMap")
|
||||
defer test.ResetIncidentsTestDatabase(t)
|
||||
|
||||
// Inserting and retrieving a row with only the serial populated should work.
|
||||
_, err = testIncidentsDbMap.Exec(
|
||||
"INSERT INTO incident_foo (serial) VALUES (?)",
|
||||
"1337",
|
||||
)
|
||||
test.AssertNotError(t, err, "inserting row with only serial")
|
||||
|
||||
var res1 incidentSerialModel
|
||||
err = testIncidentsDbMap.SelectOne(
|
||||
&res1,
|
||||
"SELECT * FROM incident_foo WHERE serial = ?",
|
||||
"1337",
|
||||
)
|
||||
test.AssertNotError(t, err, "selecting row with only serial")
|
||||
|
||||
test.AssertEquals(t, res1.Serial, "1337")
|
||||
test.AssertBoxedNil(t, res1.RegistrationID, "registrationID should be NULL")
|
||||
test.AssertBoxedNil(t, res1.OrderID, "orderID should be NULL")
|
||||
test.AssertBoxedNil(t, res1.LastNoticeSent, "lastNoticeSent should be NULL")
|
||||
|
||||
// Inserting and retrieving a row with all columns populated should work.
|
||||
_, err = testIncidentsDbMap.Exec(
|
||||
"INSERT INTO incident_foo (serial, registrationID, orderID, lastNoticeSent) VALUES (?, ?, ?, ?)",
|
||||
"1338",
|
||||
1,
|
||||
2,
|
||||
time.Date(2023, 06, 29, 16, 9, 00, 00, time.UTC),
|
||||
)
|
||||
test.AssertNotError(t, err, "inserting row with only serial")
|
||||
|
||||
var res2 incidentSerialModel
|
||||
err = testIncidentsDbMap.SelectOne(
|
||||
&res2,
|
||||
"SELECT * FROM incident_foo WHERE serial = ?",
|
||||
"1338",
|
||||
)
|
||||
test.AssertNotError(t, err, "selecting row with only serial")
|
||||
|
||||
test.AssertEquals(t, res2.Serial, "1338")
|
||||
test.AssertEquals(t, *res2.RegistrationID, int64(1))
|
||||
test.AssertEquals(t, *res2.OrderID, int64(2))
|
||||
test.AssertEquals(t, *res2.LastNoticeSent, time.Date(2023, 06, 29, 16, 9, 00, 00, time.UTC))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2351,9 +2351,9 @@ type IncidentSerial struct {
|
|||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Serial string `protobuf:"bytes,1,opt,name=serial,proto3" json:"serial,omitempty"`
|
||||
RegistrationID int64 `protobuf:"varint,2,opt,name=registrationID,proto3" json:"registrationID,omitempty"`
|
||||
OrderID int64 `protobuf:"varint,3,opt,name=orderID,proto3" json:"orderID,omitempty"`
|
||||
LastNoticeSent int64 `protobuf:"varint,4,opt,name=lastNoticeSent,proto3" json:"lastNoticeSent,omitempty"` // Unix timestamp (nanoseconds)
|
||||
RegistrationID int64 `protobuf:"varint,2,opt,name=registrationID,proto3" json:"registrationID,omitempty"` // May be 0 (NULL)
|
||||
OrderID int64 `protobuf:"varint,3,opt,name=orderID,proto3" json:"orderID,omitempty"` // May be 0 (NULL)
|
||||
LastNoticeSent int64 `protobuf:"varint,4,opt,name=lastNoticeSent,proto3" json:"lastNoticeSent,omitempty"` // Unix timestamp (nanoseconds), may be 0 (NULL)
|
||||
}
|
||||
|
||||
func (x *IncidentSerial) Reset() {
|
||||
|
|
|
|||
|
|
@ -334,9 +334,9 @@ message SerialsForIncidentRequest {
|
|||
|
||||
message IncidentSerial {
|
||||
string serial = 1;
|
||||
int64 registrationID = 2;
|
||||
int64 orderID = 3;
|
||||
int64 lastNoticeSent = 4; // Unix timestamp (nanoseconds)
|
||||
int64 registrationID = 2; // May be 0 (NULL)
|
||||
int64 orderID = 3; // May be 0 (NULL)
|
||||
int64 lastNoticeSent = 4; // Unix timestamp (nanoseconds), may be 0 (NULL)
|
||||
}
|
||||
|
||||
message GetRevokedCertsRequest {
|
||||
|
|
|
|||
|
|
@ -2926,6 +2926,8 @@ func TestIncidentsForSerial(t *testing.T) {
|
|||
test.AssertNotError(t, err, "Couldn't create test dbMap")
|
||||
defer test.ResetIncidentsTestDatabase(t)
|
||||
|
||||
weekAgo := sa.clk.Now().Add(-time.Hour * 24 * 7)
|
||||
|
||||
// Add a disabled incident.
|
||||
err = testSADbMap.Insert(&incidentModel{
|
||||
SerialTable: "incident_foo",
|
||||
|
|
@ -2950,11 +2952,12 @@ func TestIncidentsForSerial(t *testing.T) {
|
|||
test.AssertNotError(t, err, "Failed to insert enabled incident")
|
||||
|
||||
// Add a row to the incident table with serial '1338'.
|
||||
one := int64(1)
|
||||
affectedCertA := incidentSerialModel{
|
||||
Serial: "1338",
|
||||
RegistrationID: 1,
|
||||
OrderID: 1,
|
||||
LastNoticeSent: sa.clk.Now().Add(time.Hour * 24 * 7),
|
||||
RegistrationID: &one,
|
||||
OrderID: &one,
|
||||
LastNoticeSent: &weekAgo,
|
||||
}
|
||||
_, err = testIncidentsDbMap.Exec(
|
||||
fmt.Sprintf("INSERT INTO incident_bar (%s) VALUES ('%s', %d, %d, '%s')",
|
||||
|
|
@ -2973,11 +2976,12 @@ func TestIncidentsForSerial(t *testing.T) {
|
|||
test.AssertEquals(t, len(result.Incidents), 0)
|
||||
|
||||
// Add a row to the incident table with serial '1337'.
|
||||
two := int64(2)
|
||||
affectedCertB := incidentSerialModel{
|
||||
Serial: "1337",
|
||||
RegistrationID: 2,
|
||||
OrderID: 2,
|
||||
LastNoticeSent: sa.clk.Now().Add(time.Hour * 24 * 7),
|
||||
RegistrationID: &two,
|
||||
OrderID: &two,
|
||||
LastNoticeSent: &weekAgo,
|
||||
}
|
||||
_, err = testIncidentsDbMap.Exec(
|
||||
fmt.Sprintf("INSERT INTO incident_bar (%s) VALUES ('%s', %d, %d, '%s')",
|
||||
|
|
|
|||
25
sa/saro.go
25
sa/saro.go
|
|
@ -1205,7 +1205,9 @@ func (ssa *SQLStorageAuthority) IncidentsForSerial(ctx context.Context, req *sap
|
|||
// SerialsForIncident queries the provided incident table and returns the
|
||||
// resulting rows as a stream of `*sapb.IncidentSerial`s. An `io.EOF` error
|
||||
// signals that there are no more serials to send. If the incident table in
|
||||
// question contains zero rows, only an `io.EOF` error is returned.
|
||||
// question contains zero rows, only an `io.EOF` error is returned. The
|
||||
// IncidentSerial messages returned may have the zero-value for their OrderID,
|
||||
// RegistrationID, and LastNoticeSent fields, if those are NULL in the database.
|
||||
func (ssa *SQLStorageAuthorityRO) SerialsForIncident(req *sapb.SerialsForIncidentRequest, stream sapb.StorageAuthorityReadOnly_SerialsForIncidentServer) error {
|
||||
if req.IncidentTable == "" {
|
||||
return errIncompleteRequest
|
||||
|
|
@ -1235,13 +1237,20 @@ func (ssa *SQLStorageAuthorityRO) SerialsForIncident(req *sapb.SerialsForInciden
|
|||
return err
|
||||
}
|
||||
|
||||
err = stream.Send(
|
||||
&sapb.IncidentSerial{
|
||||
Serial: ism.Serial,
|
||||
RegistrationID: ism.RegistrationID,
|
||||
OrderID: ism.OrderID,
|
||||
LastNoticeSent: ism.LastNoticeSent.UnixNano(),
|
||||
})
|
||||
ispb := &sapb.IncidentSerial{
|
||||
Serial: ism.Serial,
|
||||
}
|
||||
if ism.RegistrationID != nil {
|
||||
ispb.RegistrationID = *ism.RegistrationID
|
||||
}
|
||||
if ism.OrderID != nil {
|
||||
ispb.OrderID = *ism.OrderID
|
||||
}
|
||||
if ism.LastNoticeSent != nil {
|
||||
ispb.LastNoticeSent = ism.LastNoticeSent.UnixNano()
|
||||
}
|
||||
|
||||
err = stream.Send(ispb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue