Add Ability to Disable Replication Status Endpoints in Listener Configuration (#23547)

* CI: Pre-emptively delete logs dir after cache restore in test-collect-reports (#23600)

* Fix OktaNumberChallenge (#23565)

* remove arg

* changelog

* exclude changelog in verifying doc/ui PRs (#23601)

* Audit: eventlogger sink node reopen on SIGHUP (#23598)

* ensure nodes are asked to reload audit files on SIGHUP

* added changelog

* Capture errors emitted from all nodes during proccessing of audit pipelines (#23582)

* Update security-scan.yml

* Listeners: Redaction only for TCP (#23592)

* redaction should only work for TCP listeners, also fix bug that allowed custom response headers for unix listeners

* fix failing test

* updates from PR feedback

* fix panic when unlocking unlocked user (#23611)

* VAULT-18307: update rotation period for aws static roles on update (#23528)

* add disable_replication_status_endpoints tcp listener config parameter

* add wrapping handler for disabled replication status endpoints setting

* adapt disable_replication_status_endpoints configuration parsing code to refactored parsing code

* refactor configuration parsing code to facilitate testing

* fix a panic when parsing configuration

* update refactored configuration parsing code

* fix merge corruption

* add changelog file

* document new TCP listener configuration parameter

* make sure disable_replication_status_endpoints only has effect on TCP listeners

* use active voice for explanation of disable_replication_status_endpoints

* fix minor merge issue

---------

Co-authored-by: Kuba Wieczorek <kuba.wieczorek@hashicorp.com>
Co-authored-by: Angel Garbarino <Monkeychip@users.noreply.github.com>
Co-authored-by: Hamid Ghaf <83242695+hghaf099@users.noreply.github.com>
Co-authored-by: Peter Wilson <peter.wilson@hashicorp.com>
Co-authored-by: Mark Collao <106274486+mcollao-hc@users.noreply.github.com>
Co-authored-by: davidadeleon <56207066+davidadeleon@users.noreply.github.com>
Co-authored-by: kpcraig <3031348+kpcraig@users.noreply.github.com>
This commit is contained in:
Marc Boudreau
2023-10-11 14:23:21 -04:00
committed by GitHub
parent 6fc1888cf7
commit 01cd9d37bb
6 changed files with 437 additions and 125 deletions

3
changelog/23547.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:feature
config/listener: allow per-listener configuration setting to disable replication status endpoints.
```

View File

@@ -237,20 +237,27 @@ func handler(props *vault.HandlerProperties) http.Handler {
additionalRoutes(mux, core)
}
// Wrap the handler in another handler to trigger all help paths.
helpWrappedHandler := wrapHelpHandler(mux, core)
corsWrappedHandler := wrapCORSHandler(helpWrappedHandler, core)
quotaWrappedHandler := rateLimitQuotaWrapping(corsWrappedHandler, core)
genericWrappedHandler := genericWrapping(core, quotaWrappedHandler, props)
// Build up a chain of wrapping handlers.
wrappedHandler := wrapHelpHandler(mux, core)
wrappedHandler = wrapCORSHandler(wrappedHandler, core)
wrappedHandler = rateLimitQuotaWrapping(wrappedHandler, core)
wrappedHandler = genericWrapping(core, wrappedHandler, props)
// Wrap the handler with PrintablePathCheckHandler to check for non-printable
// characters in the request path.
printablePathCheckHandler := genericWrappedHandler
// Add an extra wrapping handler if the DisablePrintableCheck listener
// setting isn't true that checks for non-printable characters in the
// request path.
if !props.DisablePrintableCheck {
printablePathCheckHandler = cleanhttp.PrintablePathCheckHandler(genericWrappedHandler, nil)
wrappedHandler = cleanhttp.PrintablePathCheckHandler(wrappedHandler, nil)
}
return printablePathCheckHandler
// Add an extra wrapping handler if the DisableReplicationStatusEndpoints
// setting is true that will create a new request with a context that has
// a value indicating that the replication status endpoints are disabled.
if props.ListenerConfig != nil && props.ListenerConfig.DisableReplicationStatusEndpoints {
wrappedHandler = disableReplicationStatusEndpointWrapping(wrappedHandler)
}
return wrappedHandler
}
type copyResponseWriter struct {

View File

@@ -133,6 +133,14 @@ func rateLimitQuotaWrapping(handler http.Handler, core *vault.Core) http.Handler
})
}
func disableReplicationStatusEndpointWrapping(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
request := r.WithContext(context.WithValue(r.Context(), "disable_replication_status_endpoints", true))
h.ServeHTTP(w, request)
})
}
func parseRemoteIPAddress(r *http.Request) string {
ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {

View File

@@ -139,6 +139,10 @@ type Listener struct {
RedactClusterName bool `hcl:"-"`
RedactVersionRaw any `hcl:"redact_version"`
RedactVersion bool `hcl:"-"`
// DisableReplicationStatusEndpoint disables the unauthenticated replication status endpoints
DisableReplicationStatusEndpointsRaw interface{} `hcl:"disable_replication_status_endpoints"`
DisableReplicationStatusEndpoints bool `hcl:"-"`
}
// AgentAPI allows users to select which parts of the Agent API they want enabled.
@@ -252,6 +256,7 @@ func parseListener(item *ast.ObjectItem) (*Listener, error) {
l.parseHTTPHeaderSettings,
l.parseChrootNamespaceSettings,
l.parseRedactionSettings,
l.parseDisableReplicationStatusEndpointSettings,
} {
err := parser()
if err != nil {
@@ -272,22 +277,114 @@ func (t ListenerType) String() string {
return string(t.Normalize())
}
// parseAndClearBool parses a raw setting as a bool configuration parameter. If
// the raw value is successfully parsed, the parsedSetting argument is set to it
// and the rawSetting argument is cleared. Otherwise, the rawSetting argument is
// left unchanged and an error is returned.
func parseAndClearBool(rawSetting *interface{}, parsedSetting *bool) error {
var err error
if *rawSetting != nil {
*parsedSetting, err = parseutil.ParseBool(*rawSetting)
if err != nil {
return err
}
*rawSetting = nil
}
return nil
}
// parseAndClearString parses a raw setting as a string configuration parameter.
// If the raw value is successfully parsed, the parsedSetting argument is set to
// it and the rawSetting argument is cleared. Otherwise, the rawSetting argument
// is left unchanged and an error is returned.
func parseAndClearString(rawSetting *interface{}, parsedSetting *string) error {
var err error
if *rawSetting != nil {
*parsedSetting, err = parseutil.ParseString(*rawSetting)
if err != nil {
return err
}
*rawSetting = nil
}
return nil
}
// parseAndClearInt parses a raw setting as an integer configuration parameter.
// If the raw value is successfully parsed, the parsedSetting argument is set to
// it and the rawSetting argument is cleared. Otherwise, the rawSetting argument
// is left unchanged and an error is returned.
func parseAndClearInt(rawSetting *interface{}, parsedSetting *int64) error {
var err error
if *rawSetting != nil {
*parsedSetting, err = parseutil.ParseInt(*rawSetting)
if err != nil {
return err
}
*rawSetting = nil
}
return nil
}
// parseAndClearDurationSecond parses a raw setting as a time duration
// configuration parameter. If the raw value is successfully parsed, the
// parsedSetting argument is set to it and the rawSetting argument is cleared.
// Otherwise, the rawSetting argument is left unchanged and an error is
// returned.
func parseAndClearDurationSecond(rawSetting *interface{}, parsedSetting *time.Duration) error {
var err error
if *rawSetting != nil {
*parsedSetting, err = parseutil.ParseDurationSecond(*rawSetting)
if err != nil {
return err
}
*rawSetting = nil
}
return nil
}
// parseDisableReplicationStatusEndpointSettings attempts to parse the raw
// disable_replication_status_endpoints setting. The receiving Listener's
// DisableReplicationStatusEndpoints field will be set with the successfully
// parsed value.
func (l *Listener) parseDisableReplicationStatusEndpointSettings() error {
if l.Type != TCP {
return nil
}
if err := parseAndClearBool(&l.DisableReplicationStatusEndpointsRaw, &l.DisableReplicationStatusEndpoints); err != nil {
return fmt.Errorf("invalid value for disable_replication_status_endpoints: %w", err)
}
return nil
}
// parseChrootNamespace attempts to parse the raw listener chroot namespace settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseChrootNamespaceSettings() error {
var err error
var (
err error
setting string
)
// If a valid ChrootNamespace value exists, then canonicalize the namespace value
if l.ChrootNamespaceRaw != nil {
l.ChrootNamespace, err = parseutil.ParseString(l.ChrootNamespaceRaw)
if err != nil {
return fmt.Errorf("invalid value for chroot_namespace: %w", err)
}
l.ChrootNamespace = namespace.Canonicalize(l.ChrootNamespace)
err = parseAndClearString(&l.ChrootNamespaceRaw, &setting)
if err != nil {
return fmt.Errorf("invalid value for chroot_namespace: %w", err)
}
l.ChrootNamespaceRaw = nil
l.ChrootNamespace = namespace.Canonicalize(setting)
return nil
}
@@ -327,13 +424,8 @@ func (l *Listener) parseType(fallback string) error {
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseRequestSettings() error {
if l.MaxRequestSizeRaw != nil {
maxRequestSize, err := parseutil.ParseInt(l.MaxRequestSizeRaw)
if err != nil {
return fmt.Errorf("error parsing max_request_size: %w", err)
}
l.MaxRequestSize = maxRequestSize
if err := parseAndClearInt(&l.MaxRequestSizeRaw, &l.MaxRequestSize); err != nil {
return fmt.Errorf("error parsing max_request_size: %w", err)
}
if l.MaxRequestDurationRaw != nil {
@@ -347,22 +439,13 @@ func (l *Listener) parseRequestSettings() error {
}
l.MaxRequestDuration = maxRequestDuration
l.MaxRequestDurationRaw = nil
}
if l.RequireRequestHeaderRaw != nil {
requireRequestHeader, err := parseutil.ParseBool(l.RequireRequestHeaderRaw)
if err != nil {
return fmt.Errorf("invalid value for require_request_header: %w", err)
}
l.RequireRequestHeader = requireRequestHeader
if err := parseAndClearBool(&l.RequireRequestHeaderRaw, &l.RequireRequestHeader); err != nil {
return fmt.Errorf("invalid value for require_request_header: %w", err)
}
// Clear raw values after successful parsing.
l.MaxRequestSizeRaw = nil
l.MaxRequestDurationRaw = nil
l.RequireRequestHeaderRaw = nil
return nil
}
@@ -370,12 +453,8 @@ func (l *Listener) parseRequestSettings() error {
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseTLSSettings() error {
if l.TLSDisableRaw != nil {
tlsDisable, err := parseutil.ParseBool(l.TLSDisableRaw)
if err != nil {
return fmt.Errorf("invalid value for tls_disable: %w", err)
}
l.TLSDisable = tlsDisable
if err := parseAndClearBool(&l.TLSDisableRaw, &l.TLSDisable); err != nil {
return fmt.Errorf("invalid value for tls_disable: %w", err)
}
if l.TLSCipherSuitesRaw != "" {
@@ -386,27 +465,16 @@ func (l *Listener) parseTLSSettings() error {
l.TLSCipherSuites = tlsCipherSuites
}
if l.TLSRequireAndVerifyClientCertRaw != nil {
tlsRequireAndVerifyClientCert, err := parseutil.ParseBool(l.TLSRequireAndVerifyClientCertRaw)
if err != nil {
return fmt.Errorf("invalid value for tls_require_and_verify_client_cert: %w", err)
}
l.TLSRequireAndVerifyClientCert = tlsRequireAndVerifyClientCert
if err := parseAndClearBool(&l.TLSRequireAndVerifyClientCertRaw, &l.TLSRequireAndVerifyClientCert); err != nil {
return fmt.Errorf("invalid value for tls_require_and_verify_client_cert: %w", err)
}
if l.TLSDisableClientCertsRaw != nil {
tlsDisableClientCerts, err := parseutil.ParseBool(l.TLSDisableClientCertsRaw)
if err != nil {
return fmt.Errorf("invalid value for tls_disable_client_certs: %w", err)
}
l.TLSDisableClientCerts = tlsDisableClientCerts
if err := parseAndClearBool(&l.TLSDisableClientCertsRaw, &l.TLSDisableClientCerts); err != nil {
return fmt.Errorf("invalid value for tls_disable_client_certs: %w", err)
}
// Clear raw values after successful parsing.
l.TLSDisableRaw = nil
l.TLSCipherSuitesRaw = ""
l.TLSRequireAndVerifyClientCertRaw = nil
l.TLSDisableClientCertsRaw = nil
return nil
}
@@ -438,38 +506,22 @@ func (l *Listener) parseHTTPHeaderSettings() error {
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseHTTPTimeoutSettings() error {
var err error
if l.HTTPReadTimeoutRaw != nil {
if l.HTTPReadTimeout, err = parseutil.ParseDurationSecond(l.HTTPReadTimeoutRaw); err != nil {
return fmt.Errorf("error parsing http_read_timeout: %w", err)
}
if err := parseAndClearDurationSecond(&l.HTTPReadTimeoutRaw, &l.HTTPReadTimeout); err != nil {
return fmt.Errorf("error parsing http_read_timeout: %w", err)
}
if l.HTTPReadHeaderTimeoutRaw != nil {
if l.HTTPReadHeaderTimeout, err = parseutil.ParseDurationSecond(l.HTTPReadHeaderTimeoutRaw); err != nil {
return fmt.Errorf("error parsing http_read_header_timeout: %w", err)
}
if err := parseAndClearDurationSecond(&l.HTTPReadHeaderTimeoutRaw, &l.HTTPReadHeaderTimeout); err != nil {
return fmt.Errorf("error parsing http_read_header_timeout: %w", err)
}
if l.HTTPWriteTimeoutRaw != nil {
if l.HTTPWriteTimeout, err = parseutil.ParseDurationSecond(l.HTTPWriteTimeoutRaw); err != nil {
return fmt.Errorf("error parsing http_write_timeout: %w", err)
}
if err := parseAndClearDurationSecond(&l.HTTPWriteTimeoutRaw, &l.HTTPWriteTimeout); err != nil {
return fmt.Errorf("error parsing http_write_timeout: %w", err)
}
if l.HTTPIdleTimeoutRaw != nil {
if l.HTTPIdleTimeout, err = parseutil.ParseDurationSecond(l.HTTPIdleTimeoutRaw); err != nil {
return fmt.Errorf("error parsing http_idle_timeout: %w", err)
}
if err := parseAndClearDurationSecond(&l.HTTPIdleTimeoutRaw, &l.HTTPIdleTimeout); err != nil {
return fmt.Errorf("error parsing http_idle_timeout: %w", err)
}
// Clear raw values after successful parsing.
l.HTTPReadTimeoutRaw = nil
l.HTTPReadHeaderTimeoutRaw = nil
l.HTTPWriteTimeoutRaw = nil
l.HTTPIdleTimeoutRaw = nil
return nil
}
@@ -524,25 +576,20 @@ func (l *Listener) parseForwardedForSettings() error {
if l.XForwardedForHopSkips < 0 {
return fmt.Errorf("x_forwarded_for_hop_skips cannot be negative but set to %d", l.XForwardedForHopSkips)
}
l.XForwardedForHopSkipsRaw = nil
}
if l.XForwardedForRejectNotAuthorizedRaw != nil {
if l.XForwardedForRejectNotAuthorized, err = parseutil.ParseBool(l.XForwardedForRejectNotAuthorizedRaw); err != nil {
return fmt.Errorf("invalid value for x_forwarded_for_reject_not_authorized: %w", err)
}
if err := parseAndClearBool(&l.XForwardedForRejectNotAuthorizedRaw, &l.XForwardedForRejectNotAuthorized); err != nil {
return fmt.Errorf("invalid value for x_forwarded_for_reject_not_authorized: %w", err)
}
if l.XForwardedForRejectNotPresentRaw != nil {
if l.XForwardedForRejectNotPresent, err = parseutil.ParseBool(l.XForwardedForRejectNotPresentRaw); err != nil {
return fmt.Errorf("invalid value for x_forwarded_for_reject_not_present: %w", err)
}
if err := parseAndClearBool(&l.XForwardedForRejectNotPresentRaw, &l.XForwardedForRejectNotPresent); err != nil {
return fmt.Errorf("invalid value for x_forwarded_for_reject_not_present: %w", err)
}
// Clear raw values after successful parsing.
l.XForwardedForAuthorizedAddrsRaw = nil
l.XForwardedForHopSkipsRaw = nil
l.XForwardedForRejectNotAuthorizedRaw = nil
l.XForwardedForRejectNotPresentRaw = nil
return nil
}
@@ -551,16 +598,10 @@ func (l *Listener) parseForwardedForSettings() error {
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseTelemetrySettings() error {
var err error
if l.Telemetry.UnauthenticatedMetricsAccessRaw != nil {
if l.Telemetry.UnauthenticatedMetricsAccess, err = parseutil.ParseBool(l.Telemetry.UnauthenticatedMetricsAccessRaw); err != nil {
return fmt.Errorf("invalid value for telemetry.unauthenticated_metrics_access: %w", err)
}
if err := parseAndClearBool(&l.Telemetry.UnauthenticatedMetricsAccessRaw, &l.Telemetry.UnauthenticatedMetricsAccess); err != nil {
return fmt.Errorf("invalid value for telemetry.unauthenticated_metrics_access: %w", err)
}
l.Telemetry.UnauthenticatedMetricsAccessRaw = nil
return nil
}
@@ -568,16 +609,10 @@ func (l *Listener) parseTelemetrySettings() error {
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseProfilingSettings() error {
var err error
if l.Profiling.UnauthenticatedPProfAccessRaw != nil {
if l.Profiling.UnauthenticatedPProfAccess, err = parseutil.ParseBool(l.Profiling.UnauthenticatedPProfAccessRaw); err != nil {
return fmt.Errorf("invalid value for profiling.unauthenticated_pprof_access: %w", err)
}
if err := parseAndClearBool(&l.Profiling.UnauthenticatedPProfAccessRaw, &l.Profiling.UnauthenticatedPProfAccess); err != nil {
return fmt.Errorf("invalid value for profiling.unauthenticated_pprof_access: %w", err)
}
l.Profiling.UnauthenticatedPProfAccessRaw = nil
return nil
}
@@ -585,16 +620,10 @@ func (l *Listener) parseProfilingSettings() error {
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseInFlightRequestSettings() error {
var err error
if l.InFlightRequestLogging.UnauthenticatedInFlightAccessRaw != nil {
if l.InFlightRequestLogging.UnauthenticatedInFlightAccess, err = parseutil.ParseBool(l.InFlightRequestLogging.UnauthenticatedInFlightAccessRaw); err != nil {
return fmt.Errorf("invalid value for inflight_requests_logging.unauthenticated_in_flight_requests_access: %w", err)
}
if err := parseAndClearBool(&l.InFlightRequestLogging.UnauthenticatedInFlightAccessRaw, &l.InFlightRequestLogging.UnauthenticatedInFlightAccess); err != nil {
return fmt.Errorf("invalid value for inflight_requests_logging.unauthenticated_in_flight_requests_access: %w", err)
}
l.InFlightRequestLogging.UnauthenticatedInFlightAccessRaw = nil
return nil
}
@@ -602,12 +631,8 @@ func (l *Listener) parseInFlightRequestSettings() error {
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseCORSSettings() error {
var err error
if l.CorsEnabledRaw != nil {
if l.CorsEnabled, err = parseutil.ParseBool(l.CorsEnabledRaw); err != nil {
return fmt.Errorf("invalid value for cors_enabled: %w", err)
}
if err := parseAndClearBool(&l.CorsEnabledRaw, &l.CorsEnabled); err != nil {
return fmt.Errorf("invalid value for cors_enabled: %w", err)
}
if strutil.StrListContains(l.CorsAllowedOrigins, "*") && len(l.CorsAllowedOrigins) > 1 {
@@ -620,7 +645,6 @@ func (l *Listener) parseCORSSettings() error {
}
}
l.CorsEnabledRaw = nil
l.CorsAllowedHeadersRaw = nil
return nil

View File

@@ -8,6 +8,7 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -1095,3 +1096,269 @@ func TestListener_parseRedactionSettings(t *testing.T) {
})
}
}
func TestParseAndClearBool(t *testing.T) {
testcases := []struct {
name string
raw interface{}
rawAssertion func(assert.TestingT, any, ...any) bool
expectedParsed bool
errorAssertion func(assert.TestingT, error, ...any) bool
}{
{
name: "valid-true-as-string",
raw: "true",
rawAssertion: assert.Nil,
expectedParsed: true,
errorAssertion: assert.NoError,
},
{
name: "valid-false-as-string",
raw: "false",
rawAssertion: assert.Nil,
expectedParsed: false,
errorAssertion: assert.NoError,
},
{
name: "valid-true-as-bool",
raw: true,
rawAssertion: assert.Nil,
expectedParsed: true,
errorAssertion: assert.NoError,
},
{
name: "valid-false-as-bool",
raw: false,
rawAssertion: assert.Nil,
expectedParsed: false,
errorAssertion: assert.NoError,
},
{
name: "valid-true-as-string-mix-case",
raw: "True",
rawAssertion: assert.Nil,
expectedParsed: true,
errorAssertion: assert.NoError,
},
{
name: "valid-false-as-integer",
raw: 0,
rawAssertion: assert.Nil,
expectedParsed: false,
errorAssertion: assert.NoError,
},
{
name: "valid-true-as-integer",
raw: 2,
rawAssertion: assert.Nil,
expectedParsed: true,
errorAssertion: assert.NoError,
},
{
name: "valid-true-as-float",
raw: 3.14,
rawAssertion: assert.Nil,
expectedParsed: true,
errorAssertion: assert.NoError,
},
{
name: "valid-false-as-float",
raw: 0.0,
rawAssertion: assert.Nil,
expectedParsed: false,
errorAssertion: assert.NoError,
},
{
name: "invalid-as-string",
raw: "0.0.0.0:8200",
rawAssertion: assert.NotNil,
errorAssertion: assert.Error,
},
{
name: "invalid-as-struct",
raw: struct{}{},
rawAssertion: assert.NotNil,
errorAssertion: assert.Error,
},
{
name: "not-set",
raw: nil,
rawAssertion: assert.Nil,
errorAssertion: assert.NoError,
},
}
for _, testcase := range testcases {
var parsed bool
err := parseAndClearBool(&testcase.raw, &parsed)
testcase.errorAssertion(t, err, testcase.name)
assert.Equal(t, testcase.expectedParsed, parsed, testcase.name)
testcase.rawAssertion(t, testcase.raw, testcase.name)
}
}
func TestParseAndClearString(t *testing.T) {
testcases := []struct {
name string
raw any
rawAssertion func(assert.TestingT, any, ...any) bool
expectedParsed string
errorAssertion func(assert.TestingT, error, ...any) bool
}{
{
name: "valid-empty-string",
raw: "",
rawAssertion: assert.Nil,
expectedParsed: "",
errorAssertion: assert.NoError,
},
{
name: "valid-some-string",
raw: "blah blah",
rawAssertion: assert.Nil,
expectedParsed: "blah blah",
errorAssertion: assert.NoError,
},
{
name: "valid-as-integer",
raw: 8,
rawAssertion: assert.Nil,
expectedParsed: "8",
errorAssertion: assert.NoError,
},
{
name: "valid-as-bool",
raw: true,
rawAssertion: assert.Nil,
expectedParsed: "1",
errorAssertion: assert.NoError,
},
{
name: "not-set",
raw: nil,
rawAssertion: assert.Nil,
expectedParsed: "",
errorAssertion: assert.NoError,
},
{
name: "invalid-as-struct",
raw: struct{}{},
rawAssertion: assert.NotNil,
errorAssertion: assert.Error,
},
}
for _, testcase := range testcases {
var parsed string
err := parseAndClearString(&testcase.raw, &parsed)
testcase.errorAssertion(t, err, testcase.name)
assert.Equal(t, testcase.expectedParsed, parsed, testcase.name)
testcase.rawAssertion(t, testcase.raw, testcase.name)
}
}
func TestParseAndClearInt(t *testing.T) {
testcases := []struct {
name string
raw any
rawAssertion func(assert.TestingT, any, ...any) bool
expectedParsed int64
errorAssertion func(assert.TestingT, error, ...any) bool
}{
{
name: "valid-as-int",
raw: 200,
rawAssertion: assert.Nil,
expectedParsed: int64(200),
errorAssertion: assert.NoError,
},
{
name: "valid-as-string",
raw: "53",
rawAssertion: assert.Nil,
expectedParsed: int64(53),
errorAssertion: assert.NoError,
},
{
name: "invalid-as-hex-string",
raw: "0xa",
rawAssertion: assert.NotNil,
errorAssertion: assert.Error,
},
{
name: "not-set",
raw: nil,
rawAssertion: assert.Nil,
errorAssertion: assert.NoError,
},
}
for _, testcase := range testcases {
var parsed int64
err := parseAndClearInt(&testcase.raw, &parsed)
testcase.errorAssertion(t, err, testcase.name)
assert.Equal(t, testcase.expectedParsed, parsed, testcase.name)
testcase.rawAssertion(t, testcase.raw, testcase.name)
}
}
func TestParseAndClearDurationSecond(t *testing.T) {
testcases := []struct {
name string
raw any
rawAssertion func(assert.TestingT, any, ...any) bool
expectedParsed time.Duration
errorAssertion func(assert.TestingT, error, ...any) bool
}{
{
name: "valid-as-string",
raw: "30s",
rawAssertion: assert.Nil,
expectedParsed: time.Duration(30 * time.Second),
errorAssertion: assert.NoError,
},
{
name: "valid-as-string-more-complex",
raw: "29h24m49s",
rawAssertion: assert.Nil,
expectedParsed: time.Duration((29 * time.Hour) + (24 * time.Minute) + (49 * time.Second)),
errorAssertion: assert.NoError,
},
{
name: "invalid-as-string-using-days",
raw: "1d3s",
rawAssertion: assert.NotNil,
errorAssertion: assert.Error,
},
{
name: "valid-as-integer",
raw: 87,
rawAssertion: assert.Nil,
expectedParsed: time.Duration(87 * time.Second),
errorAssertion: assert.NoError,
},
{
name: "not-set",
raw: nil,
rawAssertion: assert.Nil,
errorAssertion: assert.NoError,
},
{
name: "invalid-as-struct",
raw: struct{}{},
rawAssertion: assert.NotNil,
errorAssertion: assert.Error,
},
}
for _, testcase := range testcases {
var parsed time.Duration
err := parseAndClearDurationSecond(&testcase.raw, &parsed)
testcase.errorAssertion(t, err, testcase.name)
assert.Equal(t, testcase.expectedParsed, parsed)
testcase.rawAssertion(t, testcase.raw, testcase.name)
}
}

View File

@@ -202,6 +202,9 @@ default value in the `"/sys/config/ui"` [API endpoint](/vault/api-docs/system/co
there is no X-Forwarded-For header or it is empty, the client address will be
used as-is, rather than the client connection rejected.
- `disable_replication_status_endpoints` `(bool: false)` - Disables replication
status endpoints for the configured listener when set to `true`.
### `telemetry` parameters
- `unauthenticated_metrics_access` `(bool: false)` - If set to true, allows