diff --git a/cmd/boulder-ca/main.go b/cmd/boulder-ca/main.go index 99e4c69ff36..d7ab60ccec3 100644 --- a/cmd/boulder-ca/main.go +++ b/cmd/boulder-ca/main.go @@ -4,7 +4,6 @@ import ( "context" "flag" "os" - "reflect" "strconv" "time" @@ -39,11 +38,6 @@ type Config struct { // configured certificate profile or boulder-ca will fail to start. DefaultCertificateProfileName string `validate:"omitempty,alphanum,min=1,max=32"` - // TODO(#7414) Remove this deprecated field. - // Deprecated: Use CertProfiles instead. Profile implicitly takes - // the internal Boulder default value of ca.DefaultCertProfileName. - Profile issuance.ProfileConfig `validate:"required_without=CertProfiles,structonly"` - // One of the profile names must match the value of // DefaultCertificateProfileName or boulder-ca will fail to start. CertProfiles map[string]*issuance.ProfileConfig `validate:"dive,keys,alphanum,min=1,max=32,endkeys,required_without=Profile,structonly"` @@ -51,24 +45,8 @@ type Config struct { // TODO(#7159): Make this required once all live configs are using it. CRLProfile issuance.CRLProfileConfig `validate:"-"` Issuers []issuance.IssuerConfig `validate:"min=1,dive"` - - // LintConfig is a path to a zlint config file. - // Deprecated: Use CertProfiles.LintConfig instead. - LintConfig string - // IgnoredLints is a list of lint names for which any errors should be - // ignored. - // Deprecated: Use CertProfiles.IgnoredLints instead. - IgnoredLints []string } - // How long issued certificates are valid for. - // Deprecated: Use Issuance.CertProfiles.MaxValidityPeriod instead. - Expiry config.Duration - - // How far back certificates should be backdated. - // Deprecated: Use Issuance.CertProfiles.MaxValidityBackdate instead. - Backdate config.Duration - // What digits we should prepend to serials after randomly generating them. // Deprecated: Use SerialPrefixHex instead. SerialPrefix int `validate:"required_without=SerialPrefixHex,omitempty,min=1,max=127"` @@ -94,12 +72,6 @@ type Config struct { // Section 4.9.10, it MUST NOT be more than 10 days. Default 96h. LifespanOCSP config.Duration - // LifespanCRL is how long CRLs are valid for. It should be longer than the - // `period` field of the CRL Updater. Per the BRs, Section 4.9.7, it MUST - // NOT be more than 10 days. - // Deprecated: Use Config.CA.Issuance.CRLProfile.ValidityInterval instead. - LifespanCRL config.Duration `validate:"-"` - // GoodKey is an embedded config stanza for the goodkey library. GoodKey goodkey.Config @@ -179,15 +151,6 @@ func main() { c.CA.LifespanOCSP.Duration = 96 * time.Hour } - // TODO(#7159): Remove these fallbacks once all live configs are setting the - // CRL validity interval inside the Issuance.CRLProfile Config. - if c.CA.Issuance.CRLProfile.ValidityInterval.Duration == 0 && c.CA.LifespanCRL.Duration != 0 { - c.CA.Issuance.CRLProfile.ValidityInterval = c.CA.LifespanCRL - } - if c.CA.Issuance.CRLProfile.MaxBackdate.Duration == 0 && c.CA.Backdate.Duration != 0 { - c.CA.Issuance.CRLProfile.MaxBackdate = c.CA.Backdate - } - scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.CA.DebugAddr) defer oTelShutdown(context.Background()) logger.Info(cmd.VersionString()) @@ -226,27 +189,8 @@ func main() { } logger.Infof("Configured default certificate profile name set to: %s", c.CA.Issuance.DefaultCertificateProfileName) - // TODO(#7414) Remove this check. - if !reflect.ValueOf(c.CA.Issuance.Profile).IsZero() && len(c.CA.Issuance.CertProfiles) > 0 { - cmd.Fail("Only one of Issuance.Profile or Issuance.CertProfiles can be configured") - } - - // If no individual cert profiles are configured, pretend that the deprecated - // top-level profile as the only individual profile instead. - // TODO(#7414) Remove this fallback. if len(c.CA.Issuance.CertProfiles) == 0 { - c.CA.Issuance.CertProfiles = make(map[string]*issuance.ProfileConfig, 0) - c.CA.Issuance.CertProfiles[c.CA.Issuance.DefaultCertificateProfileName] = &c.CA.Issuance.Profile - } - - // If any individual cert profile doesn't have its own lint configuration, - // instead copy in the deprecated top-level lint configuration. - // TODO(#7414): Remove this fallback. - for _, prof := range c.CA.Issuance.CertProfiles { - if prof.LintConfig == "" && len(prof.IgnoredLints) == 0 { - prof.LintConfig = c.CA.Issuance.LintConfig - prof.IgnoredLints = c.CA.Issuance.IgnoredLints - } + cmd.Fail("At least one profile must be configured") } tlsConfig, err := c.CA.TLS.Load(scope) diff --git a/features/features.go b/features/features.go index 1db2f59f69f..8c29f906e34 100644 --- a/features/features.go +++ b/features/features.go @@ -16,10 +16,11 @@ import ( // package's global Config. type Config struct { // Deprecated flags. - IncrementRateLimits bool - UseKvLimitsForNewOrder bool - DisableLegacyLimitWrites bool - InsertAuthzsIndividually bool + IncrementRateLimits bool + UseKvLimitsForNewOrder bool + DisableLegacyLimitWrites bool + MultipleCertificateProfiles bool + InsertAuthzsIndividually bool // ServeRenewalInfo exposes the renewalInfo endpoint in the directory and for // GET requests. WARNING: This feature is a draft and highly unstable. @@ -56,14 +57,6 @@ type Config struct { // make a valid/invalid decision with the results. EnforceMultiCAA bool - // MultipleCertificateProfiles, when enabled, triggers the following - // behavior: - // - SA.NewOrderAndAuthzs: upon receiving a NewOrderRequest with a - // `certificateProfileName` value, will add that value to the database's - // `orders.certificateProfileName` column. Values in this column are - // allowed to be empty. - MultipleCertificateProfiles bool - // CheckIdentifiersPaused checks if any of the identifiers in the order are // currently paused at NewOrder time. If any are paused, an error is // returned to the Subscriber indicating that the order cannot be processed diff --git a/ra/ra_test.go b/ra/ra_test.go index 98832a05648..b4008a05c97 100644 --- a/ra/ra_test.go +++ b/ra/ra_test.go @@ -15,7 +15,6 @@ import ( "fmt" "math/big" mrand "math/rand/v2" - "os" "regexp" "strconv" "strings" @@ -1389,8 +1388,9 @@ func TestNewOrder_OrderReusex(t *testing.T) { // Create an initial order with regA and names names := []string{"zombo.com", "welcome.to.zombo.com"} orderReq := &rapb.NewOrderRequest{ - RegistrationID: Registration.Id, - DnsNames: names, + RegistrationID: Registration.Id, + DnsNames: names, + CertificateProfileName: "test", } firstOrder, err := ra.NewOrder(context.Background(), orderReq) test.AssertNotError(t, err, "Adding an initial order for regA failed") @@ -1406,12 +1406,14 @@ func TestNewOrder_OrderReusex(t *testing.T) { Name string RegistrationID int64 DnsNames []string + Profile string ExpectReuse bool }{ { Name: "Duplicate order, same regID", RegistrationID: Registration.Id, DnsNames: names, + Profile: "test", // We expect reuse since the order matches firstOrder ExpectReuse: true, }, @@ -1419,6 +1421,7 @@ func TestNewOrder_OrderReusex(t *testing.T) { Name: "Subset of order names, same regID", RegistrationID: Registration.Id, DnsNames: names[:1], + Profile: "test", // We do not expect reuse because the order names don't match firstOrder ExpectReuse: false, }, @@ -1426,13 +1429,30 @@ func TestNewOrder_OrderReusex(t *testing.T) { Name: "Superset of order names, same regID", RegistrationID: Registration.Id, DnsNames: append(names, "blog.zombo.com"), + Profile: "test", // We do not expect reuse because the order names don't match firstOrder ExpectReuse: false, }, + { + Name: "Missing profile, same regID", + RegistrationID: Registration.Id, + DnsNames: append(names, "blog.zombo.com"), + // We do not expect reuse because the profile is missing + ExpectReuse: false, + }, + { + Name: "Missing profile, same regID", + RegistrationID: Registration.Id, + DnsNames: append(names, "blog.zombo.com"), + Profile: "different", + // We do not expect reuse because a different profile is specified + ExpectReuse: false, + }, { Name: "Duplicate order, different regID", RegistrationID: secondReg.Id, DnsNames: names, + Profile: "test", // We do not expect reuse because the order regID differs from firstOrder ExpectReuse: false, }, @@ -1443,8 +1463,9 @@ func TestNewOrder_OrderReusex(t *testing.T) { t.Run(tc.Name, func(t *testing.T) { // Add the order for the test request order, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ - RegistrationID: tc.RegistrationID, - DnsNames: tc.DnsNames, + RegistrationID: tc.RegistrationID, + DnsNames: tc.DnsNames, + CertificateProfileName: tc.Profile, }) test.AssertNotError(t, err, "NewOrder returned an unexpected error") test.AssertNotNil(t, order.Id, "NewOrder returned an order with a nil Id") @@ -1462,50 +1483,6 @@ func TestNewOrder_OrderReusex(t *testing.T) { } } -// TestNewOrder_OrderReuse_Profile tests that order reuse respects profiles. -// This is not simply a test case in TestNewOrder_OrderReuse because it relies -// on feature-flag gated behavior. It should be unified with that function when -// the feature flag is removed. -func TestNewOrder_OrderReuse_Profile(t *testing.T) { - // TODO(#7324): Integrate these cases into TestNewOrder_OrderReuse. - if !strings.Contains(os.Getenv("BOULDER_CONFIG_DIR"), "test/config-next") { - t.Skip("this test requires the db to have the certificateProfileName column in the orders table") - } - - _, _, ra, _, _, cleanUp := initAuthorities(t) - defer cleanUp() - - features.Set(features.Config{MultipleCertificateProfiles: true}) - defer features.Reset() - - // Create an initial order with a profile name. - extant, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ - RegistrationID: Registration.Id, - CertificateProfileName: "test", - DnsNames: []string{"a.com", "b.com"}, - }) - test.AssertNotError(t, err, "creating test order") - - // Creating an identical order should reuse the first one. - new, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ - RegistrationID: Registration.Id, - CertificateProfileName: "test", - DnsNames: []string{"a.com", "b.com"}, - }) - test.AssertNotError(t, err, "creating test order") - test.AssertEquals(t, new.Id, extant.Id) - - // Creating a new order for the same names but a different profile should not - // reuse the first one. - new, err = ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ - RegistrationID: Registration.Id, - CertificateProfileName: "test2", - DnsNames: []string{"a.com", "b.com"}, - }) - test.AssertNotError(t, err, "creating test order") - test.AssertNotEquals(t, new.Id, extant.Id) -} - // TestNewOrder_OrderReuse_Expired tests that expired orders are not reused. // This is not simply a test case in TestNewOrder_OrderReuse because it has // side effects. diff --git a/sa/database.go b/sa/database.go index 886f4dbd994..bb6c7f5650c 100644 --- a/sa/database.go +++ b/sa/database.go @@ -271,8 +271,7 @@ func initTables(dbMap *borp.DbMap) { dbMap.AddTableWithName(core.Certificate{}, "certificates").SetKeys(true, "ID") dbMap.AddTableWithName(core.CertificateStatus{}, "certificateStatus").SetKeys(true, "ID") dbMap.AddTableWithName(core.FQDNSet{}, "fqdnSets").SetKeys(true, "ID") - dbMap.AddTableWithName(orderModelv2{}, "orders").SetKeys(true, "ID") - dbMap.AddTableWithName(orderModelv1{}, "orders").SetKeys(true, "ID") + dbMap.AddTableWithName(orderModel{}, "orders").SetKeys(true, "ID") dbMap.AddTableWithName(orderToAuthzModel{}, "orderToAuthz").SetKeys(false, "OrderID", "AuthzID") dbMap.AddTableWithName(orderFQDNSet{}, "orderFqdnSets").SetKeys(true, "ID") dbMap.AddTableWithName(authzModel{}, "authz2").SetKeys(true, "ID") diff --git a/sa/db-next/boulder_sa/20240304000000_CertificateProfiles.sql b/sa/db-next/boulder_sa/20240304000000_CertificateProfiles.sql deleted file mode 100644 index 583a106d6b8..00000000000 --- a/sa/db-next/boulder_sa/20240304000000_CertificateProfiles.sql +++ /dev/null @@ -1,9 +0,0 @@ --- +migrate Up --- SQL in section 'Up' is executed when this migration is applied - -ALTER TABLE `orders` ADD COLUMN `certificateProfileName` varchar(32) DEFAULT NULL; - --- +migrate Down --- SQL section 'Down' is executed when this migration is rolled back - -ALTER TABLE `orders` DROP COLUMN `certificateProfileName`; diff --git a/sa/db-next/boulder_sa/20240304000000_CertificateProfiles.sql b/sa/db-next/boulder_sa/20240304000000_CertificateProfiles.sql new file mode 120000 index 00000000000..f837842abdd --- /dev/null +++ b/sa/db-next/boulder_sa/20240304000000_CertificateProfiles.sql @@ -0,0 +1 @@ +../../db/boulder_sa/20240304000000_CertificateProfiles.sql \ No newline at end of file diff --git a/sa/db/boulder_sa/20240304000000_CertificateProfiles.sql b/sa/db/boulder_sa/20240304000000_CertificateProfiles.sql new file mode 100644 index 00000000000..583a106d6b8 --- /dev/null +++ b/sa/db/boulder_sa/20240304000000_CertificateProfiles.sql @@ -0,0 +1,9 @@ +-- +migrate Up +-- SQL in section 'Up' is executed when this migration is applied + +ALTER TABLE `orders` ADD COLUMN `certificateProfileName` varchar(32) DEFAULT NULL; + +-- +migrate Down +-- SQL section 'Down' is executed when this migration is rolled back + +ALTER TABLE `orders` DROP COLUMN `certificateProfileName`; diff --git a/sa/model.go b/sa/model.go index 1bb671eab3e..b91b5bf12e3 100644 --- a/sa/model.go +++ b/sa/model.go @@ -370,20 +370,9 @@ type lintingCertModel struct { Expires time.Time } -// TODO(#7324) orderModelv1 is deprecated, use orderModelv2 moving forward. -type orderModelv1 struct { - ID int64 - RegistrationID int64 - Expires time.Time - Created time.Time - Error []byte - CertificateSerial string - BeganProcessing bool -} - -// orderModelv2 represents one row in the orders table. The -// CertificateProfileName column is a pointer because the column is NULL-able. -type orderModelv2 struct { +// orderModel represents one row in the orders table. The CertificateProfileName +// column is a pointer because the column is NULL-able. +type orderModel struct { ID int64 RegistrationID int64 Expires time.Time @@ -399,59 +388,11 @@ type orderToAuthzModel struct { AuthzID int64 } -// TODO(#7324) orderToModelv1 is deprecated, use orderModelv2 moving forward. -func orderToModelv1(order *corepb.Order) (*orderModelv1, error) { - om := &orderModelv1{ - ID: order.Id, - RegistrationID: order.RegistrationID, - Expires: order.Expires.AsTime(), - Created: order.Created.AsTime(), - BeganProcessing: order.BeganProcessing, - CertificateSerial: order.CertificateSerial, - } - - if order.Error != nil { - errJSON, err := json.Marshal(order.Error) - if err != nil { - return nil, err - } - if len(errJSON) > mediumBlobSize { - return nil, fmt.Errorf("Error object is too large to store in the database") - } - om.Error = errJSON - } - return om, nil -} - -// TODO(#7324) modelToOrderv1 is deprecated, use orderModelv2 moving forward. -func modelToOrderv1(om *orderModelv1) (*corepb.Order, error) { - order := &corepb.Order{ - Id: om.ID, - RegistrationID: om.RegistrationID, - Expires: timestamppb.New(om.Expires), - Created: timestamppb.New(om.Created), - CertificateSerial: om.CertificateSerial, - BeganProcessing: om.BeganProcessing, - } - if len(om.Error) > 0 { - var problem corepb.ProblemDetails - err := json.Unmarshal(om.Error, &problem) - if err != nil { - return &corepb.Order{}, badJSONError( - "failed to unmarshal order model's error", - om.Error, - err) - } - order.Error = &problem - } - return order, nil -} - -func orderToModelv2(order *corepb.Order) (*orderModelv2, error) { +func orderToModel(order *corepb.Order) (*orderModel, error) { // Make a local copy so we can take a reference to it below. profile := order.CertificateProfileName - om := &orderModelv2{ + om := &orderModel{ ID: order.Id, RegistrationID: order.RegistrationID, Expires: order.Expires.AsTime(), @@ -474,7 +415,7 @@ func orderToModelv2(order *corepb.Order) (*orderModelv2, error) { return om, nil } -func modelToOrderv2(om *orderModelv2) (*corepb.Order, error) { +func modelToOrder(om *orderModel) (*corepb.Order, error) { profile := "" if om.CertificateProfileName != nil { profile = *om.CertificateProfileName diff --git a/sa/model_test.go b/sa/model_test.go index b2ba57a3766..0a4a97be398 100644 --- a/sa/model_test.go +++ b/sa/model_test.go @@ -237,7 +237,7 @@ func TestAuthzModel(t *testing.T) { // validation error JSON field to an Order produces the expected bad JSON error. func TestModelToOrderBadJSON(t *testing.T) { badJSON := []byte(`{`) - _, err := modelToOrderv2(&orderModelv2{ + _, err := modelToOrder(&orderModel{ Error: badJSON, }) test.AssertError(t, err, "expected error from modelToOrderv2") @@ -250,21 +250,6 @@ func TestOrderModelThereAndBackAgain(t *testing.T) { clk := clock.New() now := clk.Now() order := &corepb.Order{ - Id: 0, - RegistrationID: 2016, - Expires: timestamppb.New(now.Add(24 * time.Hour)), - Created: timestamppb.New(now), - Error: nil, - CertificateSerial: "1", - BeganProcessing: true, - } - model1, err := orderToModelv1(order) - test.AssertNotError(t, err, "orderToModelv1 should not have errored") - returnOrder, err := modelToOrderv1(model1) - test.AssertNotError(t, err, "modelToOrderv1 should not have errored") - test.AssertDeepEquals(t, order, returnOrder) - - anotherOrder := &corepb.Order{ Id: 1, RegistrationID: 2024, Expires: timestamppb.New(now.Add(24 * time.Hour)), @@ -274,11 +259,11 @@ func TestOrderModelThereAndBackAgain(t *testing.T) { BeganProcessing: true, CertificateProfileName: "phljny", } - model2, err := orderToModelv2(anotherOrder) + model, err := orderToModel(order) test.AssertNotError(t, err, "orderToModelv2 should not have errored") - returnOrder, err = modelToOrderv2(model2) + returnOrder, err := modelToOrder(model) test.AssertNotError(t, err, "modelToOrderv2 should not have errored") - test.AssertDeepEquals(t, anotherOrder, returnOrder) + test.AssertDeepEquals(t, order, returnOrder) } // TestPopulateAttemptedFieldsBadJSON tests that populating a challenge from an diff --git a/sa/sa.go b/sa/sa.go index a83b3930432..0cf6a9ea9e0 100644 --- a/sa/sa.go +++ b/sa/sa.go @@ -531,30 +531,18 @@ func (ssa *SQLStorageAuthority) NewOrderAndAuthzs(ctx context.Context, req *sapb } // Second, insert the new order. - var orderID int64 - var err error created := ssa.clk.Now() - if features.Get().MultipleCertificateProfiles { - omv2 := orderModelv2{ - RegistrationID: req.NewOrder.RegistrationID, - Expires: req.NewOrder.Expires.AsTime(), - Created: created, - CertificateProfileName: &req.NewOrder.CertificateProfileName, - } - err = tx.Insert(ctx, &omv2) - orderID = omv2.ID - } else { - omv1 := orderModelv1{ - RegistrationID: req.NewOrder.RegistrationID, - Expires: req.NewOrder.Expires.AsTime(), - Created: created, - } - err = tx.Insert(ctx, &omv1) - orderID = omv1.ID + om := orderModel{ + RegistrationID: req.NewOrder.RegistrationID, + Expires: req.NewOrder.Expires.AsTime(), + Created: created, + CertificateProfileName: &req.NewOrder.CertificateProfileName, } + err := tx.Insert(ctx, &om) if err != nil { return nil, err } + orderID := om.ID // Third, insert all of the orderToAuthz relations. // Have to combine the already-associated and newly-created authzs. @@ -676,7 +664,7 @@ func (ssa *SQLStorageAuthority) SetOrderError(ctx context.Context, req *sapb.Set return nil, errIncompleteRequest } _, overallError := db.WithTransaction(ctx, ssa.dbMap, func(tx db.Executor) (interface{}, error) { - om, err := orderToModelv2(&corepb.Order{ + om, err := orderToModel(&corepb.Order{ Id: req.Id, Error: req.Error, }) diff --git a/sa/sa_test.go b/sa/sa_test.go index 21e80ac1ff5..bc4874fb800 100644 --- a/sa/sa_test.go +++ b/sa/sa_test.go @@ -17,7 +17,6 @@ import ( "math/bits" mrand "math/rand/v2" "net" - "os" "reflect" "slices" "strings" @@ -1126,7 +1125,7 @@ func TestFinalizeOrder(t *testing.T) { test.AssertEquals(t, updatedOrder.Status, string(core.StatusValid)) } -func TestOrderWithOrderModelv1(t *testing.T) { +func TestOrder(t *testing.T) { sa, fc, cleanup := initSA(t) defer cleanup() @@ -1182,17 +1181,10 @@ func TestOrderWithOrderModelv1(t *testing.T) { test.AssertDeepEquals(t, storedOrder, expectedOrder) } -func TestOrderWithOrderModelv2(t *testing.T) { - if !strings.Contains(os.Getenv("BOULDER_CONFIG_DIR"), "test/config-next") { - t.Skip("Test requires 20240304000000_CertificateProfiles.sql migration to have run") - } - +func TestOrderWithProfile(t *testing.T) { sa, fc, cleanup := initSA(t) defer cleanup() - features.Set(features.Config{MultipleCertificateProfiles: true}) - defer features.Reset() - reg := createWorkingRegistration(t, sa) authzExpires := fc.Now().Add(time.Hour) authzID := createPendingAuthorization(t, sa, "example.com", authzExpires) @@ -1246,130 +1238,6 @@ func TestOrderWithOrderModelv2(t *testing.T) { storedOrder, err := sa.GetOrder(context.Background(), &sapb.OrderRequest{Id: order.Id}) test.AssertNotError(t, err, "sa.GetOrder failed") test.AssertDeepEquals(t, storedOrder, expectedOrder) - - // - // Test that an order without a certificate profile name, but with the - // MultipleCertificateProfiles feature flag enabled works as expected. - // - - inputOrderNoName := &corepb.Order{ - RegistrationID: reg.Id, - Expires: timestamppb.New(expires), - DnsNames: []string{"example.com"}, - V2Authorizations: []int64{authzID}, - } - - // Create the order - orderNoName, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{ - NewOrder: &sapb.NewOrderRequest{ - RegistrationID: inputOrderNoName.RegistrationID, - Expires: inputOrderNoName.Expires, - DnsNames: inputOrderNoName.DnsNames, - V2Authorizations: inputOrderNoName.V2Authorizations, - CertificateProfileName: inputOrderNoName.CertificateProfileName, - }, - }) - test.AssertNotError(t, err, "sa.NewOrderAndAuthzs failed") - - // The Order from GetOrder should match the following expected order - created = sa.clk.Now() - expectedOrderNoName := &corepb.Order{ - // The registration ID, authorizations, expiry, and names should match the - // input to NewOrderAndAuthzs - RegistrationID: inputOrderNoName.RegistrationID, - V2Authorizations: inputOrderNoName.V2Authorizations, - DnsNames: inputOrderNoName.DnsNames, - Expires: inputOrderNoName.Expires, - // The ID should have been set to 2 by the SA - Id: 2, - // The status should be pending - Status: string(core.StatusPending), - // The serial should be empty since this is a pending order - CertificateSerial: "", - // We should not be processing it - BeganProcessing: false, - // The created timestamp should have been set to the current time - Created: timestamppb.New(created), - } - - // Fetch the order by its ID and make sure it matches the expected - storedOrderNoName, err := sa.GetOrder(context.Background(), &sapb.OrderRequest{Id: orderNoName.Id}) - test.AssertNotError(t, err, "sa.GetOrder failed") - test.AssertDeepEquals(t, storedOrderNoName, expectedOrderNoName) -} - -func TestOrderModelMigration(t *testing.T) { - if !strings.Contains(os.Getenv("BOULDER_CONFIG_DIR"), "test/config-next") { - t.Skip("Test requires 20240304000000_CertificateProfiles.sql migration to have run") - } - - sa, fc, cleanup := initSA(t) - defer cleanup() - - reg := createWorkingRegistration(t, sa) - - // Create an order using the v1 model - authzID := createPendingAuthorization(t, sa, "example.com", fc.Now().Add(time.Hour)) - order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{ - NewOrder: &sapb.NewOrderRequest{ - RegistrationID: reg.Id, - Expires: timestamppb.New(fc.Now().Add(2 * time.Hour)), - DnsNames: []string{"example.com"}, - V2Authorizations: []int64{authzID}, - }, - }) - if err != nil { - t.Fatalf("failed to insert order using orderModelv1: %s", err) - } - - // Retrieve that order using the v2 model - features.Set(features.Config{MultipleCertificateProfiles: true}) - defer features.Reset() - storedOrder, err := sa.GetOrder(context.Background(), &sapb.OrderRequest{Id: order.Id}) - if err != nil { - t.Fatalf("failed to retrieve order using orderModelv2: %s", err) - } - if storedOrder.CertificateProfileName != "" { - t.Errorf("order inserted with v1 schema should have empty profilename, instead got %q", storedOrder.CertificateProfileName) - } -} - -func TestOrderModelMigrationRollback(t *testing.T) { - if !strings.Contains(os.Getenv("BOULDER_CONFIG_DIR"), "test/config-next") { - t.Skip("Test requires 20240304000000_CertificateProfiles.sql migration to have run") - } - - sa, fc, cleanup := initSA(t) - defer cleanup() - - reg := createWorkingRegistration(t, sa) - - // Create an order using the v2 model - features.Set(features.Config{MultipleCertificateProfiles: true}) - defer features.Reset() - authzID := createPendingAuthorization(t, sa, "example.com", fc.Now().Add(time.Hour)) - order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{ - NewOrder: &sapb.NewOrderRequest{ - RegistrationID: reg.Id, - Expires: timestamppb.New(fc.Now().Add(2 * time.Hour)), - DnsNames: []string{"example.com"}, - V2Authorizations: []int64{authzID}, - CertificateProfileName: "asdf", - }, - }) - if err != nil { - t.Fatalf("failed to insert order using orderModelv2: %s", err) - } - - // Retrieve that order using the v1 model - features.Reset() - storedOrder, err := sa.GetOrder(context.Background(), &sapb.OrderRequest{Id: order.Id}) - if err != nil { - t.Fatalf("failed to retrieve order using orderModelv1: %s", err) - } - if storedOrder.CertificateProfileName != "" { - t.Errorf("order retrieved with v1 schema should have empty profilename, instead got %q", storedOrder.CertificateProfileName) - } } // TestGetAuthorization2NoRows ensures that the GetAuthorization2 function returns diff --git a/sa/saro.go b/sa/saro.go index 57f0ffa338a..e26f1229450 100644 --- a/sa/saro.go +++ b/sa/saro.go @@ -22,7 +22,6 @@ import ( corepb "github.com/letsencrypt/boulder/core/proto" "github.com/letsencrypt/boulder/db" berrors "github.com/letsencrypt/boulder/errors" - "github.com/letsencrypt/boulder/features" bgrpc "github.com/letsencrypt/boulder/grpc" "github.com/letsencrypt/boulder/identifier" blog "github.com/letsencrypt/boulder/log" @@ -410,13 +409,7 @@ func (ssa *SQLStorageAuthorityRO) GetOrder(ctx context.Context, req *sapb.OrderR } txn := func(tx db.Executor) (interface{}, error) { - var omObj interface{} - var err error - if features.Get().MultipleCertificateProfiles { - omObj, err = tx.Get(ctx, orderModelv2{}, req.Id) - } else { - omObj, err = tx.Get(ctx, orderModelv1{}, req.Id) - } + omObj, err := tx.Get(ctx, orderModel{}, req.Id) if err != nil { if db.IsNoRows(err) { return nil, berrors.NotFoundError("no order found for ID %d", req.Id) @@ -427,12 +420,7 @@ func (ssa *SQLStorageAuthorityRO) GetOrder(ctx context.Context, req *sapb.OrderR return nil, berrors.NotFoundError("no order found for ID %d", req.Id) } - var order *corepb.Order - if features.Get().MultipleCertificateProfiles { - order, err = modelToOrderv2(omObj.(*orderModelv2)) - } else { - order, err = modelToOrderv1(omObj.(*orderModelv1)) - } + order, err := modelToOrder(omObj.(*orderModel)) if err != nil { return nil, err } diff --git a/test/config-next/sa.json b/test/config-next/sa.json index 13242a803c6..b6b878bca46 100644 --- a/test/config-next/sa.json +++ b/test/config-next/sa.json @@ -48,9 +48,7 @@ } }, "healthCheckInterval": "4s", - "features": { - "MultipleCertificateProfiles": true - } + "features": {} }, "syslog": { "stdoutlevel": 6, diff --git a/test/config/ca.json b/test/config/ca.json index 809d626ac34..07a086b1a3e 100644 --- a/test/config/ca.json +++ b/test/config/ca.json @@ -44,18 +44,35 @@ "hostOverride": "sa.boulder" }, "issuance": { - "profile": { - "allowMustStaple": true, - "allowCTPoison": true, - "allowSCTList": true, - "allowCommonName": true, - "policies": [ - { - "oid": "2.23.140.1.2.1" - } - ], - "maxValidityPeriod": "7776000s", - "maxValidityBackdate": "1h5m" + "defaultCertificateProfileName": "legacy", + "certProfiles": { + "legacy": { + "allowMustStaple": true, + "maxValidityPeriod": "7776000s", + "maxValidityBackdate": "1h5m", + "lintConfig": "test/config-next/zlint.toml", + "ignoredLints": [ + "w_subject_common_name_included", + "w_ext_subject_key_identifier_not_recommended_subscriber" + ] + }, + "modern": { + "allowMustStaple": true, + "omitCommonName": true, + "omitKeyEncipherment": true, + "omitClientAuth": true, + "omitSKID": true, + "maxValidityPeriod": "583200s", + "maxValidityBackdate": "1h5m", + "lintConfig": "test/config-next/zlint.toml", + "ignoredLints": [ + "w_ext_subject_key_identifier_missing_sub_cert" + ] + } + }, + "crlProfile": { + "validityInterval": "216h", + "maxBackdate": "1h5m" }, "issuers": [ { @@ -124,19 +141,11 @@ "numSessions": 2 } } - ], - "lintConfig": "test/config/zlint.toml", - "ignoredLints": [ - "w_subject_common_name_included", - "w_ext_subject_key_identifier_not_recommended_subscriber" ] }, - "expiry": "7776000s", - "backdate": "1h", "serialPrefix": 127, "maxNames": 100, "lifespanOCSP": "96h", - "lifespanCRL": "216h", "goodkey": { "fermatRounds": 100 }, diff --git a/test/config/sa.json b/test/config/sa.json index 928e2da4e8b..23f703aab84 100644 --- a/test/config/sa.json +++ b/test/config/sa.json @@ -49,6 +49,7 @@ }, "features": { "UseKvLimitsForNewOrder": true, + "MultipleCertificateProfiles": true, "InsertAuthzsIndividually": true } },