...

Source file src/github.com/letsencrypt/boulder/features/features.go

Documentation: github.com/letsencrypt/boulder/features

     1  //go:generate stringer -type=FeatureFlag
     2  
     3  package features
     4  
     5  import (
     6  	"fmt"
     7  	"strings"
     8  	"sync"
     9  )
    10  
    11  type FeatureFlag int
    12  
    13  const (
    14  	unused FeatureFlag = iota // unused is used for testing
    15  	//   Deprecated features, these can be removed once stripped from production configs
    16  	StoreRevokerInfo
    17  	ROCSPStage6
    18  	ROCSPStage7
    19  	StoreLintingCertificateInsteadOfPrecertificate
    20  	CAAValidationMethods
    21  	CAAAccountURI
    22  	LeaseCRLShards
    23  
    24  	//   Currently in-use features
    25  	// EnforceMultiVA causes the VA to block on remote VA PerformValidation
    26  	// requests in order to make a valid/invalid decision with the results.
    27  	EnforceMultiVA
    28  	// MultiVAFullResults will cause the main VA to wait for all of the remote VA
    29  	// results, not just the threshold required to make a decision.
    30  	MultiVAFullResults
    31  	// ECDSAForAll enables all accounts, regardless of their presence in the CA's
    32  	// ecdsaAllowedAccounts config value, to get issuance from ECDSA issuers.
    33  	ECDSAForAll
    34  	// ServeRenewalInfo exposes the renewalInfo endpoint in the directory and for
    35  	// GET requests. WARNING: This feature is a draft and highly unstable.
    36  	ServeRenewalInfo
    37  	// AllowUnrecognizedFeatures is internal to the features package: if true,
    38  	// skip error when unrecognized feature flag names are passed.
    39  	AllowUnrecognizedFeatures
    40  
    41  	// ExpirationMailerUsesJoin enables using a JOIN query in expiration-mailer
    42  	// rather than a SELECT from certificateStatus followed by thousands of
    43  	// one-row SELECTs from certificates.
    44  	ExpirationMailerUsesJoin
    45  
    46  	// CertCheckerChecksValidations enables an extra query for each certificate
    47  	// checked, to find the relevant authzs. Since this query might be
    48  	// expensive, we gate it behind a feature flag.
    49  	CertCheckerChecksValidations
    50  
    51  	// CertCheckerRequiresValidations causes cert-checker to fail if the
    52  	// query enabled by CertCheckerChecksValidations didn't find corresponding
    53  	// authorizations.
    54  	CertCheckerRequiresValidations
    55  
    56  	// CertCheckerRequiresCorrespondence enables an extra query for each certificate
    57  	// checked, to find the linting precertificate in the `precertificates` table.
    58  	// It then checks that the final certificate "corresponds" to the precertificate
    59  	// using `precert.Correspond`.
    60  	CertCheckerRequiresCorrespondence
    61  
    62  	// AsyncFinalize enables the RA to return approximately immediately from
    63  	// requests to finalize orders. This allows us to take longer getting SCTs,
    64  	// issuing certs, and updating the database; it indirectly reduces the number
    65  	// of issuances that fail due to timeouts during storage. However, it also
    66  	// requires clients to properly implement polling the Order object to wait
    67  	// for the cert URL to appear.
    68  	AsyncFinalize
    69  
    70  	// RequireCommonName defaults to true, and causes the CA to fail to issue a
    71  	// certificate if there is no CommonName in the certificate. When false, the
    72  	// CA will be willing to issue certificates with no CN.
    73  	//
    74  	// According to the BRs Section 7.1.4.2.2(a), the commonName field is
    75  	// Deprecated, and its inclusion is discouraged but not (yet) prohibited.
    76  	RequireCommonName
    77  
    78  	// CAAAfterValidation causes the VA to only kick off CAA checks after the base
    79  	// domain control validation has completed and succeeded. This makes
    80  	// successful validations slower by serializing the DCV and CAA work, but
    81  	// makes unsuccessful validations easier by not doing CAA work at all.
    82  	CAAAfterValidation
    83  )
    84  
    85  // List of features and their default value, protected by fMu
    86  var features = map[FeatureFlag]bool{
    87  	unused:                            false,
    88  	CAAValidationMethods:              false,
    89  	CAAAccountURI:                     false,
    90  	EnforceMultiVA:                    false,
    91  	MultiVAFullResults:                false,
    92  	StoreRevokerInfo:                  false,
    93  	ECDSAForAll:                       false,
    94  	ServeRenewalInfo:                  false,
    95  	AllowUnrecognizedFeatures:         false,
    96  	ROCSPStage6:                       false,
    97  	ROCSPStage7:                       false,
    98  	ExpirationMailerUsesJoin:          false,
    99  	CertCheckerChecksValidations:      false,
   100  	CertCheckerRequiresValidations:    false,
   101  	CertCheckerRequiresCorrespondence: false,
   102  	AsyncFinalize:                     false,
   103  	RequireCommonName:                 true,
   104  	LeaseCRLShards:                    false,
   105  	CAAAfterValidation:                false,
   106  
   107  	StoreLintingCertificateInsteadOfPrecertificate: false,
   108  }
   109  
   110  var fMu = new(sync.RWMutex)
   111  
   112  var initial = map[FeatureFlag]bool{}
   113  
   114  var nameToFeature = make(map[string]FeatureFlag, len(features))
   115  
   116  func init() {
   117  	for f, v := range features {
   118  		nameToFeature[f.String()] = f
   119  		initial[f] = v
   120  	}
   121  }
   122  
   123  // Set accepts a list of features and whether they should
   124  // be enabled or disabled. In the presence of unrecognized
   125  // flags, it will return an error or not depending on the
   126  // value of AllowUnrecognizedFeatures.
   127  func Set(featureSet map[string]bool) error {
   128  	fMu.Lock()
   129  	defer fMu.Unlock()
   130  	var unknown []string
   131  	for n, v := range featureSet {
   132  		f, present := nameToFeature[n]
   133  		if present {
   134  			features[f] = v
   135  		} else {
   136  			unknown = append(unknown, n)
   137  		}
   138  	}
   139  	if len(unknown) > 0 && !features[AllowUnrecognizedFeatures] {
   140  		return fmt.Errorf("unrecognized feature flag names: %s",
   141  			strings.Join(unknown, ", "))
   142  	}
   143  	return nil
   144  }
   145  
   146  // Enabled returns true if the feature is enabled or false
   147  // if it isn't, it will panic if passed a feature that it
   148  // doesn't know.
   149  func Enabled(n FeatureFlag) bool {
   150  	fMu.RLock()
   151  	defer fMu.RUnlock()
   152  	v, present := features[n]
   153  	if !present {
   154  		panic(fmt.Sprintf("feature '%s' doesn't exist", n.String()))
   155  	}
   156  	return v
   157  }
   158  
   159  // Reset resets the features to their initial state
   160  func Reset() {
   161  	fMu.Lock()
   162  	defer fMu.Unlock()
   163  	for k, v := range initial {
   164  		features[k] = v
   165  	}
   166  }
   167  

View as plain text