From 53040690a2bb89a71b723cd888411182295abcd6 Mon Sep 17 00:00:00 2001
From: Steven Clark
Date: Mon, 20 Nov 2023 10:32:05 -0500
Subject: [PATCH 01/74] PKI: Do not set NextUpdate OCSP field when ocsp_expiry
is 0 (#24192)
* Do not set NextUpdate OCSP field when ocsp_expiry is 0
* Add cl
---
builtin/logical/pki/path_ocsp.go | 5 ++-
builtin/logical/pki/path_ocsp_test.go | 60 +++++++++++++++++++------
changelog/24192.txt | 3 ++
website/content/api-docs/secret/pki.mdx | 5 ++-
4 files changed, 56 insertions(+), 17 deletions(-)
create mode 100644 changelog/24192.txt
diff --git a/builtin/logical/pki/path_ocsp.go b/builtin/logical/pki/path_ocsp.go
index 98adcc5fe4f2..6dac24d5cd7f 100644
--- a/builtin/logical/pki/path_ocsp.go
+++ b/builtin/logical/pki/path_ocsp.go
@@ -510,11 +510,14 @@ func genResponse(cfg *crlConfig, caBundle *certutil.ParsedCertBundle, info *ocsp
Status: info.ocspStatus,
SerialNumber: info.serialNumber,
ThisUpdate: curTime,
- NextUpdate: curTime.Add(duration),
ExtraExtensions: []pkix.Extension{},
SignatureAlgorithm: revSigAlg,
}
+ if duration > 0 {
+ template.NextUpdate = curTime.Add(duration)
+ }
+
if info.ocspStatus == ocsp.Revoked {
template.RevokedAt = *info.revocationTimeUTC
template.RevocationReason = ocsp.Unspecified
diff --git a/builtin/logical/pki/path_ocsp_test.go b/builtin/logical/pki/path_ocsp_test.go
index b62e7d4b5a17..20f706fa42f8 100644
--- a/builtin/logical/pki/path_ocsp_test.go
+++ b/builtin/logical/pki/path_ocsp_test.go
@@ -15,6 +15,7 @@ import (
"strconv"
"strings"
"testing"
+ "time"
"github.com/hashicorp/go-secure-stdlib/parseutil"
vaulthttp "github.com/hashicorp/vault/http"
@@ -467,6 +468,18 @@ func TestOcsp_HigherLevel(t *testing.T) {
require.Equal(t, certToRevoke.SerialNumber, ocspResp.SerialNumber)
}
+// TestOcsp_NextUpdate make sure that we are setting the appropriate values
+// for the NextUpdate field within our responses.
+func TestOcsp_NextUpdate(t *testing.T) {
+ // Within the runOcspRequestTest, with a ocspExpiry of 0,
+ // we will validate that NextUpdate was not set in the response
+ runOcspRequestTest(t, "POST", "ec", 0, 0, crypto.SHA256, 0)
+
+ // Within the runOcspRequestTest, with a ocspExpiry of 24 hours, we will validate
+ // that NextUpdate is set and has a time 24 hours larger than ThisUpdate
+ runOcspRequestTest(t, "POST", "ec", 0, 0, crypto.SHA256, 24*time.Hour)
+}
+
func TestOcsp_ValidRequests(t *testing.T) {
type caKeyConf struct {
keyType string
@@ -506,13 +519,15 @@ func TestOcsp_ValidRequests(t *testing.T) {
localTT.reqHash)
t.Run(testName, func(t *testing.T) {
runOcspRequestTest(t, localTT.reqType, localTT.keyConf.keyType, localTT.keyConf.keyBits,
- localTT.keyConf.sigBits, localTT.reqHash)
+ localTT.keyConf.sigBits, localTT.reqHash, 12*time.Hour)
})
}
}
-func runOcspRequestTest(t *testing.T, requestType string, caKeyType string, caKeyBits int, caKeySigBits int, requestHash crypto.Hash) {
- b, s, testEnv := setupOcspEnvWithCaKeyConfig(t, caKeyType, caKeyBits, caKeySigBits)
+func runOcspRequestTest(t *testing.T, requestType string, caKeyType string,
+ caKeyBits int, caKeySigBits int, requestHash crypto.Hash, ocspExpiry time.Duration,
+) {
+ b, s, testEnv := setupOcspEnvWithCaKeyConfig(t, caKeyType, caKeyBits, caKeySigBits, ocspExpiry)
// Non-revoked cert
resp, err := SendOcspRequest(t, b, s, requestType, testEnv.leafCertIssuer1, testEnv.issuer1, requestHash)
@@ -574,17 +589,28 @@ func runOcspRequestTest(t *testing.T, requestType string, caKeyType string, caKe
require.Equal(t, testEnv.leafCertIssuer2.SerialNumber, ocspResp.SerialNumber)
// Verify that our thisUpdate and nextUpdate fields are updated as expected
- thisUpdate := ocspResp.ThisUpdate
- nextUpdate := ocspResp.NextUpdate
- require.True(t, thisUpdate.Before(nextUpdate),
- fmt.Sprintf("thisUpdate %s, should have been before nextUpdate: %s", thisUpdate, nextUpdate))
- nextUpdateDiff := nextUpdate.Sub(thisUpdate)
- expectedDiff, err := parseutil.ParseDurationSecond(defaultCrlConfig.OcspExpiry)
+ resp, err = CBRead(b, s, "config/crl")
+ requireSuccessNonNilResponse(t, resp, err, "failed reading from config/crl")
+ requireFieldsSetInResp(t, resp, "ocsp_expiry")
+ ocspExpiryRaw := resp.Data["ocsp_expiry"].(string)
+ expectedDiff, err := parseutil.ParseDurationSecond(ocspExpiryRaw)
require.NoError(t, err, "failed to parse default ocsp expiry value")
- require.Equal(t, expectedDiff, nextUpdateDiff,
- fmt.Sprintf("the delta between thisUpdate %s and nextUpdate: %s should have been around: %s but was %s",
- thisUpdate, nextUpdate, defaultCrlConfig.OcspExpiry, nextUpdateDiff))
+ thisUpdate := ocspResp.ThisUpdate
+ require.Less(t, time.Since(thisUpdate), 10*time.Second, "expected ThisUpdate field to be within the last 10 seconds")
+ if expectedDiff != 0 {
+ nextUpdate := ocspResp.NextUpdate
+ require.False(t, nextUpdate.IsZero(), "nextUpdate field value should have been a non-zero time")
+ require.True(t, thisUpdate.Before(nextUpdate),
+ fmt.Sprintf("thisUpdate %s, should have been before nextUpdate: %s", thisUpdate, nextUpdate))
+ nextUpdateDiff := nextUpdate.Sub(thisUpdate)
+ require.Equal(t, expectedDiff, nextUpdateDiff,
+ fmt.Sprintf("the delta between thisUpdate %s and nextUpdate: %s should have been around: %s but was %s",
+ thisUpdate, nextUpdate, defaultCrlConfig.OcspExpiry, nextUpdateDiff))
+ } else {
+ // With the config value set to 0, we shouldn't have a NextUpdate field set
+ require.True(t, ocspResp.NextUpdate.IsZero(), "nextUpdate value was not zero as expected was: %v", ocspResp.NextUpdate)
+ }
requireOcspSignatureAlgoForKey(t, testEnv.issuer2.SignatureAlgorithm, ocspResp.SignatureAlgorithm)
requireOcspResponseSignedBy(t, ocspResp, testEnv.issuer2)
}
@@ -610,16 +636,22 @@ type ocspTestEnv struct {
}
func setupOcspEnv(t *testing.T, keyType string) (*backend, logical.Storage, *ocspTestEnv) {
- return setupOcspEnvWithCaKeyConfig(t, keyType, 0, 0)
+ return setupOcspEnvWithCaKeyConfig(t, keyType, 0, 0, 12*time.Hour)
}
-func setupOcspEnvWithCaKeyConfig(t *testing.T, keyType string, caKeyBits int, caKeySigBits int) (*backend, logical.Storage, *ocspTestEnv) {
+func setupOcspEnvWithCaKeyConfig(t *testing.T, keyType string, caKeyBits int, caKeySigBits int, ocspExpiry time.Duration) (*backend, logical.Storage, *ocspTestEnv) {
b, s := CreateBackendWithStorage(t)
var issuerCerts []*x509.Certificate
var leafCerts []*x509.Certificate
var issuerIds []issuerID
var keyIds []keyID
+ resp, err := CBWrite(b, s, "config/crl", map[string]interface{}{
+ "ocsp_enable": true,
+ "ocsp_expiry": fmt.Sprintf("%ds", int(ocspExpiry.Seconds())),
+ })
+ requireSuccessNonNilResponse(t, resp, err, "config/crl failed")
+
for i := 0; i < 2; i++ {
resp, err := CBWrite(b, s, "root/generate/internal", map[string]interface{}{
"key_type": keyType,
diff --git a/changelog/24192.txt b/changelog/24192.txt
new file mode 100644
index 000000000000..97a26746bd0f
--- /dev/null
+++ b/changelog/24192.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+secrets/pki: Do not set nextUpdate field in OCSP responses when ocsp_expiry is 0
+```
diff --git a/website/content/api-docs/secret/pki.mdx b/website/content/api-docs/secret/pki.mdx
index 28f7fba484e5..6a87cf51685c 100644
--- a/website/content/api-docs/secret/pki.mdx
+++ b/website/content/api-docs/secret/pki.mdx
@@ -4199,8 +4199,9 @@ the CRL.
- `ocsp_disable` `(bool: false)` - Disables or enables the OCSP responder in Vault.
- `ocsp_expiry` `(string: "12h")` - The amount of time an OCSP response can be cached for,
- (controls the NextUpdate field), useful for OCSP stapling refresh durations. Setting to 0
- should effectively disable caching in third party systems.
+ (controls the NextUpdate field), useful for OCSP stapling refresh durations. If set to 0
+ the NextUpdate field is not set, indicating newer revocation information is available
+ all the time.
- `auto_rebuild` `(bool: false)` - Enables or disables periodic rebuilding of
the CRL upon expiry.
From d2afea92a111f94c0586d99a7902937f29ad750a Mon Sep 17 00:00:00 2001
From: Violet Hynes
Date: Mon, 20 Nov 2023 10:45:36 -0500
Subject: [PATCH 02/74] VAULT-22030 update error message when from entity isn't
found as part of automated entity merge (#24188)
* VAULT-22030 update error message when from entity isn't found as part of automated entity merge
* VAULT-22030 add extra info
---
vault/identity_store_entities.go | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/vault/identity_store_entities.go b/vault/identity_store_entities.go
index bf890c57f2b0..f59457f95098 100644
--- a/vault/identity_store_entities.go
+++ b/vault/identity_store_entities.go
@@ -883,6 +883,15 @@ func (i *IdentityStore) mergeEntity(ctx context.Context, txn *memdb.Txn, toEntit
}
if fromEntity == nil {
+ // If forceMergeAliases is true, and we didn't find a fromEntity, then something
+ // is wrong with storage. This function was called as part of an automated
+ // merge from CreateOrFetchEntity or Invalidate to repatriate an alias with its 'true'
+ // entity. As a result, the entity _should_ exist, but we can't find it.
+ // MemDb may be in a bad state, because fromEntity should be non-nil in the
+ // automated merge case.
+ if forceMergeAliases {
+ return fmt.Errorf("fromEntity %s was not found in memdb as part of an automated entity merge into %s; storage/memdb may be in a bad state", fromEntityID, toEntity.ID), nil, nil
+ }
return errors.New("entity id to merge from is invalid"), nil, nil
}
@@ -995,6 +1004,15 @@ func (i *IdentityStore) mergeEntity(ctx context.Context, txn *memdb.Txn, toEntit
}
if fromEntity == nil {
+ // If forceMergeAliases is true, and we didn't find a fromEntity, then something
+ // is wrong with storage. This function was called as part of an automated
+ // merge from CreateOrFetchEntity or Invalidate to repatriate an alias with its 'true'
+ // entity. As a result, the entity _should_ exist, but we can't find it.
+ // MemDb may be in a bad state, because fromEntity should be non-nil in the
+ // automated merge case.
+ if forceMergeAliases {
+ return fmt.Errorf("fromEntity %s was not found in memdb as part of an automated entity merge into %s; storage/memdb may be in a bad state", fromEntityID, toEntity.ID), nil, nil
+ }
return errors.New("entity id to merge from is invalid"), nil, nil
}
From bcbd45b380d2cf776cb3cd920f03291301cee998 Mon Sep 17 00:00:00 2001
From: Steven Clark
Date: Mon, 20 Nov 2023 10:51:03 -0500
Subject: [PATCH 03/74] Handle expired OCSP responses from server (#24193)
* Handle expired OCSP responses from server
- If a server replied with what we considered an expired OCSP response (nextUpdate is now or in the past), and it was our only response we would panic due to missing error handling logic.
* Add cl
---
changelog/24193.txt | 3 ++
sdk/helper/ocsp/client.go | 11 ++++-
sdk/helper/ocsp/ocsp_test.go | 89 ++++++++++++++++++++++++++++++++++++
3 files changed, 102 insertions(+), 1 deletion(-)
create mode 100644 changelog/24193.txt
diff --git a/changelog/24193.txt b/changelog/24193.txt
new file mode 100644
index 000000000000..67ea1d0ae974
--- /dev/null
+++ b/changelog/24193.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+auth/cert: Handle errors related to expired OCSP server responses
+```
diff --git a/sdk/helper/ocsp/client.go b/sdk/helper/ocsp/client.go
index c1b9c2fbc37a..8bd9cea4ee8f 100644
--- a/sdk/helper/ocsp/client.go
+++ b/sdk/helper/ocsp/client.go
@@ -517,6 +517,11 @@ func (c *Client) GetRevocationStatus(ctx context.Context, subject, issuer *x509.
}
if isValidOCSPStatus(ret.code) {
ocspStatuses[i] = ret
+ } else if ret.err != nil {
+ // This check needs to occur after the isValidOCSPStatus as the unknown
+ // status also sets an err value within ret.
+ errors[i] = ret.err
+ return ret.err
}
return nil
}
@@ -568,8 +573,12 @@ func (c *Client) GetRevocationStatus(ctx context.Context, subject, issuer *x509.
if (ret == nil || ret.code == ocspStatusUnknown) && firstError != nil {
return nil, firstError
}
- // otherwise ret should contain a response for the overall request
+ // An extra safety in case ret and firstError are both nil
+ if ret == nil {
+ return nil, fmt.Errorf("failed to extract a known response code or error from the OCSP server")
+ }
+ // otherwise ret should contain a response for the overall request
if !isValidOCSPStatus(ret.code) {
return ret, nil
}
diff --git a/sdk/helper/ocsp/ocsp_test.go b/sdk/helper/ocsp/ocsp_test.go
index 2f3f1976d2a8..677dfa85aa5e 100644
--- a/sdk/helper/ocsp/ocsp_test.go
+++ b/sdk/helper/ocsp/ocsp_test.go
@@ -6,14 +6,20 @@ import (
"bytes"
"context"
"crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
"crypto/tls"
"crypto/x509"
+ "crypto/x509/pkix"
"errors"
"fmt"
"io"
"io/ioutil"
+ "math/big"
"net"
"net/http"
+ "net/http/httptest"
"net/url"
"testing"
"time"
@@ -21,6 +27,7 @@ import (
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-retryablehttp"
lru "github.com/hashicorp/golang-lru"
+ "github.com/stretchr/testify/require"
"golang.org/x/crypto/ocsp"
)
@@ -201,6 +208,88 @@ func TestUnitCheckOCSPResponseCache(t *testing.T) {
}
}
+func TestUnitExpiredOCSPResponse(t *testing.T) {
+ rootCaKey, rootCa, leafCert := createCaLeafCerts(t)
+
+ expiredOcspResponse := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ now := time.Now()
+ ocspRes := ocsp.Response{
+ SerialNumber: big.NewInt(2),
+ ThisUpdate: now.Add(-1 * time.Hour),
+ NextUpdate: now.Add(-30 * time.Minute),
+ Status: ocsp.Good,
+ }
+ response, err := ocsp.CreateResponse(rootCa, rootCa, ocspRes, rootCaKey)
+ if err != nil {
+ _, _ = w.Write(ocsp.InternalErrorErrorResponse)
+ t.Fatalf("failed generating OCSP response: %v", err)
+ }
+ _, _ = w.Write(response)
+ })
+ ts := httptest.NewServer(expiredOcspResponse)
+ defer ts.Close()
+
+ logFactory := func() hclog.Logger {
+ return hclog.NewNullLogger()
+ }
+ client := New(logFactory, 100)
+
+ ctx := context.Background()
+
+ config := &VerifyConfig{
+ OcspEnabled: true,
+ OcspServersOverride: []string{ts.URL},
+ OcspFailureMode: FailOpenFalse,
+ QueryAllServers: false,
+ }
+
+ status, err := client.GetRevocationStatus(ctx, leafCert, rootCa, config)
+ require.ErrorContains(t, err, "invalid validity",
+ "Expected error got response: %v, %v", status, err)
+}
+
+func createCaLeafCerts(t *testing.T) (*ecdsa.PrivateKey, *x509.Certificate, *x509.Certificate) {
+ rootCaKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ require.NoError(t, err, "failed generated root key for CA")
+
+ // Validate we reject CSRs that contain CN that aren't in the original order
+ cr := &x509.Certificate{
+ Subject: pkix.Name{CommonName: "Root Cert"},
+ SerialNumber: big.NewInt(1),
+ IsCA: true,
+ BasicConstraintsValid: true,
+ SignatureAlgorithm: x509.ECDSAWithSHA256,
+ NotBefore: time.Now().Add(-1 * time.Second),
+ NotAfter: time.Now().AddDate(1, 0, 0),
+ KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageOCSPSigning},
+ }
+ rootCaBytes, err := x509.CreateCertificate(rand.Reader, cr, cr, &rootCaKey.PublicKey, rootCaKey)
+ require.NoError(t, err, "failed generating root ca")
+
+ rootCa, err := x509.ParseCertificate(rootCaBytes)
+ require.NoError(t, err, "failed parsing root ca")
+
+ leafKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ require.NoError(t, err, "failed generated leaf key")
+
+ cr = &x509.Certificate{
+ Subject: pkix.Name{CommonName: "Leaf Cert"},
+ SerialNumber: big.NewInt(2),
+ SignatureAlgorithm: x509.ECDSAWithSHA256,
+ NotBefore: time.Now().Add(-1 * time.Second),
+ NotAfter: time.Now().AddDate(1, 0, 0),
+ KeyUsage: x509.KeyUsageDigitalSignature,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+ }
+ leafCertBytes, err := x509.CreateCertificate(rand.Reader, cr, rootCa, &leafKey.PublicKey, rootCaKey)
+ require.NoError(t, err, "failed generating root ca")
+
+ leafCert, err := x509.ParseCertificate(leafCertBytes)
+ require.NoError(t, err, "failed parsing root ca")
+ return rootCaKey, rootCa, leafCert
+}
+
func TestUnitValidateOCSP(t *testing.T) {
ocspRes := &ocsp.Response{}
ost, err := validateOCSP(ocspRes)
From 4cf837d56a7ec639d3bedf4b585d961c69f59458 Mon Sep 17 00:00:00 2001
From: Alex
Date: Mon, 20 Nov 2023 18:00:03 +0000
Subject: [PATCH 04/74] UI: HDS adoption replace footer element (#24191)
* Replace footer with `Hds::AppFooter`
* Remove unused `.footer` styles
* Add changelog entry
* Use `doc-link` helper for 'Documentation' link
---
changelog/24191.txt | 3 +++
ui/app/styles/core.scss | 1 -
ui/app/styles/core/footer.scss | 20 -----------------
ui/app/templates/vault.hbs | 39 +++++++++++++---------------------
4 files changed, 18 insertions(+), 45 deletions(-)
create mode 100644 changelog/24191.txt
delete mode 100644 ui/app/styles/core/footer.scss
diff --git a/changelog/24191.txt b/changelog/24191.txt
new file mode 100644
index 000000000000..2fe98e926d05
--- /dev/null
+++ b/changelog/24191.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: Implement Helios Design System footer component
+```
diff --git a/ui/app/styles/core.scss b/ui/app/styles/core.scss
index 92d50091f681..eefc125be3cb 100644
--- a/ui/app/styles/core.scss
+++ b/ui/app/styles/core.scss
@@ -30,7 +30,6 @@
@import './core/control';
@import './core/field';
@import './core/file';
-@import './core/footer';
@import './core/inputs';
@import './core/json-diff-patch';
@import './core/label';
diff --git a/ui/app/styles/core/footer.scss b/ui/app/styles/core/footer.scss
deleted file mode 100644
index c3a193c309e5..000000000000
--- a/ui/app/styles/core/footer.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: BUSL-1.1
- */
-
-.footer {
- background-color: transparent;
- border-top: $base-border;
- padding: $spacing-24 $spacing-20;
- margin-top: auto;
-
- span:not(:first-child) {
- display: inline-block;
- padding: 0 0.5rem;
-
- @include until($mobile) {
- display: none;
- }
- }
-}
diff --git a/ui/app/templates/vault.hbs b/ui/app/templates/vault.hbs
index 0c3fd74bc253..3a72ea2d85ac 100644
--- a/ui/app/templates/vault.hbs
+++ b/ui/app/templates/vault.hbs
@@ -4,32 +4,23 @@
~}}
{{outlet}}
-
+
+ Documentation
+
+
+
+
{{#if (eq this.env "development")}}
From b833b30315fe24f3249dd83422eb86be96f73de8 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
Date: Mon, 20 Nov 2023 13:21:00 -0600
Subject: [PATCH 05/74] UI: always send capabilities-self request in user's
root namespace (#24168)
* Add getRelativePath helper and use to calculate relativeNamespace
* Always request capabilities-self on users root ns and prefix body with relative path
* Update capabilities adapter with test
* add changelog
* Simplify getRelativePath logic
* test update
---
changelog/24168.txt | 3 ++
ui/app/adapters/capabilities.js | 16 +++++++-
ui/app/services/namespace.js | 8 ++++
ui/lib/core/addon/utils/sanitize-path.js | 20 ++++++++++
ui/lib/core/app/utils/sanitize-path.js | 2 +-
ui/tests/unit/adapters/capabilities-test.js | 41 +++++++++++++++++++++
ui/tests/unit/utils/sanitize-path-test.js | 11 +++++-
7 files changed, 98 insertions(+), 3 deletions(-)
create mode 100644 changelog/24168.txt
diff --git a/changelog/24168.txt b/changelog/24168.txt
new file mode 100644
index 000000000000..09f34ce8621c
--- /dev/null
+++ b/changelog/24168.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: capabilities-self is always called in the user's root namespace
+```
\ No newline at end of file
diff --git a/ui/app/adapters/capabilities.js b/ui/app/adapters/capabilities.js
index de54824bbb0f..8eee53c3e27b 100644
--- a/ui/app/adapters/capabilities.js
+++ b/ui/app/adapters/capabilities.js
@@ -6,14 +6,28 @@
import AdapterError from '@ember-data/adapter/error';
import { set } from '@ember/object';
import ApplicationAdapter from './application';
+import { sanitizePath } from 'core/utils/sanitize-path';
export default ApplicationAdapter.extend({
pathForType() {
return 'capabilities-self';
},
+ formatPaths(path) {
+ const { relativeNamespace } = this.namespaceService;
+ if (!relativeNamespace) {
+ return [path];
+ }
+ // ensure original path doesn't have leading slash
+ return [`${relativeNamespace}/${path.replace(/^\//, '')}`];
+ },
+
findRecord(store, type, id) {
- return this.ajax(this.buildURL(type), 'POST', { data: { paths: [id] } }).catch((e) => {
+ const paths = this.formatPaths(id);
+ return this.ajax(this.buildURL(type), 'POST', {
+ data: { paths },
+ namespace: sanitizePath(this.namespaceService.userRootNamespace),
+ }).catch((e) => {
if (e instanceof AdapterError) {
set(e, 'policyPath', 'sys/capabilities-self');
}
diff --git a/ui/app/services/namespace.js b/ui/app/services/namespace.js
index 07802320a031..cd8e65e67e05 100644
--- a/ui/app/services/namespace.js
+++ b/ui/app/services/namespace.js
@@ -7,6 +7,7 @@ import { alias, equal } from '@ember/object/computed';
import Service, { inject as service } from '@ember/service';
import { task } from 'ember-concurrency';
import { computed } from '@ember/object';
+import { getRelativePath } from 'core/utils/sanitize-path';
const ROOT_NAMESPACE = '';
export default Service.extend({
@@ -28,6 +29,13 @@ export default Service.extend({
return parts[parts.length - 1];
}),
+ relativeNamespace: computed('path', 'userRootNamespace', function () {
+ // relative namespace is the current namespace minus the user's root.
+ // so if we're in app/staging/group1 but the user's root is app, the
+ // relative namespace is staging/group
+ return getRelativePath(this.path, this.userRootNamespace);
+ }),
+
setNamespace(path) {
if (!path) {
this.set('path', '');
diff --git a/ui/lib/core/addon/utils/sanitize-path.js b/ui/lib/core/addon/utils/sanitize-path.js
index bfd200a362d5..7ca66c651de6 100644
--- a/ui/lib/core/addon/utils/sanitize-path.js
+++ b/ui/lib/core/addon/utils/sanitize-path.js
@@ -4,6 +4,7 @@
*/
export function sanitizePath(path) {
+ if (!path) return '';
//remove whitespace + remove trailing and leading slashes
return path.trim().replace(/^\/+|\/+$/g, '');
}
@@ -11,3 +12,22 @@ export function sanitizePath(path) {
export function ensureTrailingSlash(path) {
return path.replace(/(\w+[^/]$)/g, '$1/');
}
+
+/**
+ * getRelativePath is for removing matching segments of a subpath from the front of a full path.
+ * This method assumes that the full path starts with all of the root path.
+ * @param {string} fullPath eg apps/prod/app_1/test
+ * @param {string} rootPath eg apps/prod
+ * @returns the leftover segment, eg app_1/test
+ */
+export function getRelativePath(fullPath = '', rootPath = '') {
+ const root = sanitizePath(rootPath);
+ const full = sanitizePath(fullPath);
+
+ if (!root) {
+ return full;
+ } else if (root === full) {
+ return '';
+ }
+ return sanitizePath(full.substring(root.length));
+}
diff --git a/ui/lib/core/app/utils/sanitize-path.js b/ui/lib/core/app/utils/sanitize-path.js
index 58a60b33d422..27a0db30e1c6 100644
--- a/ui/lib/core/app/utils/sanitize-path.js
+++ b/ui/lib/core/app/utils/sanitize-path.js
@@ -3,4 +3,4 @@
* SPDX-License-Identifier: BUSL-1.1
*/
-export { ensureTrailingSlash, sanitizePath } from 'core/utils/sanitize-path';
+export { ensureTrailingSlash, sanitizePath, getRelativePath } from 'core/utils/sanitize-path';
diff --git a/ui/tests/unit/adapters/capabilities-test.js b/ui/tests/unit/adapters/capabilities-test.js
index bcd1f055b551..2e0bb0f33092 100644
--- a/ui/tests/unit/adapters/capabilities-test.js
+++ b/ui/tests/unit/adapters/capabilities-test.js
@@ -24,4 +24,45 @@ module('Unit | Adapter | capabilities', function (hooks) {
assert.deepEqual({ paths: ['foo'] }, options.data, 'data params OK');
assert.strictEqual(method, 'POST', 'method OK');
});
+
+ test('enterprise calls the correct url within namespace when userRoot = root', function (assert) {
+ const namespaceSvc = this.owner.lookup('service:namespace');
+ namespaceSvc.setNamespace('admin');
+
+ let url, method, options;
+ const adapter = this.owner.factoryFor('adapter:capabilities').create({
+ ajax: (...args) => {
+ [url, method, options] = args;
+ return resolve();
+ },
+ });
+
+ adapter.findRecord(null, 'capabilities', 'foo');
+ assert.strictEqual(url, '/v1/sys/capabilities-self', 'calls the correct URL');
+ assert.deepEqual({ paths: ['admin/foo'] }, options.data, 'data params prefix paths with namespace');
+ assert.strictEqual(options.namespace, '', 'sent with root namespace');
+ assert.strictEqual(method, 'POST', 'method OK');
+ });
+
+ test('enterprise calls the correct url within namespace when userRoot is not root', function (assert) {
+ const namespaceSvc = this.owner.lookup('service:namespace');
+ namespaceSvc.setNamespace('admin/bar/baz');
+ namespaceSvc.reopen({
+ userRootNamespace: 'admin/bar',
+ });
+
+ let url, method, options;
+ const adapter = this.owner.factoryFor('adapter:capabilities').create({
+ ajax: (...args) => {
+ [url, method, options] = args;
+ return resolve();
+ },
+ });
+
+ adapter.findRecord(null, 'capabilities', 'foo');
+ assert.strictEqual(url, '/v1/sys/capabilities-self', 'calls the correct URL');
+ assert.deepEqual({ paths: ['baz/foo'] }, options.data, 'data params prefix path with relative namespace');
+ assert.strictEqual(options.namespace, 'admin/bar', 'sent with root namespace');
+ assert.strictEqual(method, 'POST', 'method OK');
+ });
});
diff --git a/ui/tests/unit/utils/sanitize-path-test.js b/ui/tests/unit/utils/sanitize-path-test.js
index cdde888100c9..7107d737f2c5 100644
--- a/ui/tests/unit/utils/sanitize-path-test.js
+++ b/ui/tests/unit/utils/sanitize-path-test.js
@@ -4,7 +4,7 @@
*/
import { module, test } from 'qunit';
-import { ensureTrailingSlash, sanitizePath } from 'core/utils/sanitize-path';
+import { ensureTrailingSlash, getRelativePath, sanitizePath } from 'core/utils/sanitize-path';
module('Unit | Utility | sanitize-path', function () {
test('it removes spaces and slashes from either side', function (assert) {
@@ -14,10 +14,19 @@ module('Unit | Utility | sanitize-path', function () {
'removes spaces and slashes on either side'
);
assert.strictEqual(sanitizePath('//foo/bar/baz/'), 'foo/bar/baz', 'removes more than one slash');
+ assert.strictEqual(sanitizePath(undefined), '', 'handles falsey values');
});
test('#ensureTrailingSlash', function (assert) {
assert.strictEqual(ensureTrailingSlash('foo/bar'), 'foo/bar/', 'adds trailing slash');
assert.strictEqual(ensureTrailingSlash('baz/'), 'baz/', 'keeps trailing slash if there is one');
});
+
+ test('#getRelativePath', function (assert) {
+ assert.strictEqual(getRelativePath('/', undefined), '', 'works with minimal inputs');
+ assert.strictEqual(getRelativePath('/baz/bar/', undefined), 'baz/bar', 'sanitizes the output');
+ assert.strictEqual(getRelativePath('recipes/cookies/choc-chip/', 'recipes/'), 'cookies/choc-chip');
+ assert.strictEqual(getRelativePath('/recipes/cookies/choc-chip/', 'recipes/cookies'), 'choc-chip');
+ assert.strictEqual(getRelativePath('/admin/bop/boop/admin_foo/baz/', 'admin'), 'bop/boop/admin_foo/baz');
+ });
});
From c0014c9640fb4b13abdce9818bfa923d9e94e34c Mon Sep 17 00:00:00 2001
From: Victor Rodriguez
Date: Tue, 21 Nov 2023 08:56:58 -0500
Subject: [PATCH 06/74] Augment testCore_Rekey_Update_Common to test for
RekeyUpdate errors. (#24206)
---
vault/rekey_test.go | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/vault/rekey_test.go b/vault/rekey_test.go
index c0857a6f94b6..a7278b037f26 100644
--- a/vault/rekey_test.go
+++ b/vault/rekey_test.go
@@ -151,6 +151,10 @@ func TestCore_Rekey_Update(t *testing.T) {
}
func testCore_Rekey_Update_Common(t *testing.T, c *Core, keys [][]byte, root string, recovery bool) {
+ testCore_Rekey_Update_Common_Error(t, c, keys, root, recovery, false)
+}
+
+func testCore_Rekey_Update_Common_Error(t *testing.T, c *Core, keys [][]byte, root string, recovery bool, wantRekeyUpdateError bool) {
var err error
// Start a rekey
var expType string
@@ -184,12 +188,19 @@ func testCore_Rekey_Update_Common(t *testing.T, c *Core, keys [][]byte, root str
for _, key := range keys {
result, err = c.RekeyUpdate(context.Background(), key, rkconf.Nonce, recovery)
if err != nil {
- t.Fatalf("err: %v", err)
+ if !wantRekeyUpdateError {
+ t.Fatalf("err: %v", err)
+ } else {
+ return
+ }
}
if result != nil {
break
}
}
+ if wantRekeyUpdateError {
+ t.Fatal("expected and error during RekeyUpdate")
+ }
if result == nil {
t.Fatal("nil result after update")
}
From 1bf366ccdc3032f4451d6fead0bf58205de4c37b Mon Sep 17 00:00:00 2001
From: Nick Cabatoff
Date: Tue, 21 Nov 2023 10:08:18 -0500
Subject: [PATCH 07/74] Use our fork of bbolt to improve freelist performance
(#24010)
---
changelog/24010.txt | 3 +
.../cache/cacheboltdb/bolt.go | 2 +-
.../cache/cacheboltdb/bolt_test.go | 2 +-
go.mod | 3 +-
go.sum | 18 +++++
physical/raft/fsm.go | 2 +-
physical/raft/raft.go | 66 ++++++++++++++++++-
physical/raft/raft_test.go | 2 +-
physical/raft/snapshot.go | 2 +-
9 files changed, 91 insertions(+), 9 deletions(-)
create mode 100644 changelog/24010.txt
diff --git a/changelog/24010.txt b/changelog/24010.txt
new file mode 100644
index 000000000000..aa72bc977912
--- /dev/null
+++ b/changelog/24010.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+storage/raft: Upgrade to bbolt 1.3.8, along with an extra patch to reduce time scanning large freelist maps.
+```
diff --git a/command/agentproxyshared/cache/cacheboltdb/bolt.go b/command/agentproxyshared/cache/cacheboltdb/bolt.go
index 6100ef896298..05d5ad93637a 100644
--- a/command/agentproxyshared/cache/cacheboltdb/bolt.go
+++ b/command/agentproxyshared/cache/cacheboltdb/bolt.go
@@ -12,10 +12,10 @@ import (
"time"
"github.com/golang/protobuf/proto"
+ bolt "github.com/hashicorp-forge/bbolt"
"github.com/hashicorp/go-hclog"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/go-multierror"
- bolt "go.etcd.io/bbolt"
)
const (
diff --git a/command/agentproxyshared/cache/cacheboltdb/bolt_test.go b/command/agentproxyshared/cache/cacheboltdb/bolt_test.go
index dbfafdce7bb4..06a31780b5ad 100644
--- a/command/agentproxyshared/cache/cacheboltdb/bolt_test.go
+++ b/command/agentproxyshared/cache/cacheboltdb/bolt_test.go
@@ -14,11 +14,11 @@ import (
"time"
"github.com/golang/protobuf/proto"
+ bolt "github.com/hashicorp-forge/bbolt"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/command/agentproxyshared/cache/keymanager"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- bolt "go.etcd.io/bbolt"
)
func getTestKeyManager(t *testing.T) keymanager.KeyManager {
diff --git a/go.mod b/go.mod
index e2a005ae2182..ca8ab3deab56 100644
--- a/go.mod
+++ b/go.mod
@@ -75,6 +75,7 @@ require (
github.com/google/go-github v17.0.0+incompatible
github.com/google/go-metrics-stackdriver v0.2.0
github.com/google/tink/go v1.7.0
+ github.com/hashicorp-forge/bbolt v1.3.8-hc3
github.com/hashicorp/cap v0.3.4
github.com/hashicorp/cap/ldap v0.0.0-20230914221201-c4eecc7e31f7
github.com/hashicorp/consul-template v0.33.0
@@ -203,7 +204,6 @@ require (
github.com/sethvargo/go-limiter v0.7.1
github.com/shirou/gopsutil/v3 v3.22.6
github.com/stretchr/testify v1.8.4
- go.etcd.io/bbolt v1.3.7
go.etcd.io/etcd/client/pkg/v3 v3.5.7
go.etcd.io/etcd/client/v2 v2.305.5
go.etcd.io/etcd/client/v3 v3.5.7
@@ -507,6 +507,7 @@ require (
github.com/yusufpapurcu/wmi v1.2.2 // indirect
github.com/zclconf/go-cty v1.12.1 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
+ go.etcd.io/bbolt v1.3.7 // indirect
go.etcd.io/etcd/api/v3 v3.5.7 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel/metric v1.16.0 // indirect
diff --git a/go.sum b/go.sum
index e575e7c7184a..f32079238fa6 100644
--- a/go.sum
+++ b/go.sum
@@ -954,10 +954,13 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aov
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1 h1:UPeCRD+XY7QlaGQte2EVI2iOcWvUYA2XY8w5T/8v0NQ=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1/go.mod h1:oGV6NlB0cvi1ZbYRR2UN44QHxWFyGk+iylgD0qaMXjA=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E=
+github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2/go.mod h1:FbdwsQ2EzwvXxOPcMFYO8ogEc9uMMIj3YkmCdXdAFmk=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups v1.0.0 h1:pPvTJ1dY0sA35JOeFq6TsY2xj6Z85Yo23Pj4wCCvu4o=
+github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups v1.0.0/go.mod h1:mLfWfj8v3jfWKsL9G4eoBoXVcsqcIUTapmdKy7uGOp0=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.1.0 h1:Q707jfTFqfunSnh73YkCBDXR3GQJKno3chPRxXw//ho=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.1.0/go.mod h1:vjoxsjVnPwhjHZw4PuuhpgYlcxWl5tyNedLHUl0ulFA=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.0.0 h1:nBy98uKOIfun5z6wx6jwWLrULcM0+cjBalBFZlEZ7CA=
+github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.0.0/go.mod h1:243D9iHbcQXoFUtgHJwL7gl2zx1aDuDMjvBZVGr2uW0=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 h1:7CBQ+Ei8SP2c6ydQTGCCrS35bDxgTMfoP2miAwK++OU=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1/go.mod h1:c/wcGeGx5FUPbM/JltUYHZcKmigwyVLJlDq+4HdtXaw=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 h1:u/LLAOFgsMv7HmNL4Qufg58y+qElGOt5qv0z1mURkRY=
@@ -1125,6 +1128,7 @@ github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
+github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220418222510-f25a4f6275ed/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
@@ -1576,6 +1580,7 @@ github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQx
github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0=
+github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
@@ -1637,6 +1642,7 @@ github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM
github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU=
github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
+github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
@@ -1663,6 +1669,7 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
+github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
@@ -1681,6 +1688,7 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmS
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
+github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
github.com/go-git/go-git/v5 v5.7.0 h1:t9AudWVLmqzlo+4bqdf7GY+46SUuRsx59SboFxkq2aE=
github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhcZd8Fodw8=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@@ -1838,6 +1846,7 @@ github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
@@ -2101,6 +2110,7 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI=
+github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
@@ -2115,6 +2125,8 @@ github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
+github.com/hashicorp-forge/bbolt v1.3.8-hc3 h1:iTWR3RDPj0TGChAvJ8QjHFcNFWAUVgNQV73IE6gAX4E=
+github.com/hashicorp-forge/bbolt v1.3.8-hc3/go.mod h1:sQBu5UIJ+rcUFU4Fo9rpTHNV935jwmGWS3dQ/MV8810=
github.com/hashicorp/cap v0.3.4 h1:RoqWYqr6LaDLuvnBCpod1sZtvuEhehIhu0GncmoHW40=
github.com/hashicorp/cap v0.3.4/go.mod h1:dHTmyMIVbzT981XxRoci5G//dfWmd/HhuNiCH6J5+IA=
github.com/hashicorp/cap/ldap v0.0.0-20230914221201-c4eecc7e31f7 h1:jgVdtp5YMn++PxnYhAFfrURfLf+nlqzBeddbvRG+tTg=
@@ -2126,6 +2138,7 @@ github.com/hashicorp/consul/api v1.23.0 h1:L6e4v1AfoumqAHq/Rrsmuulev+nd7vltM3k8H
github.com/hashicorp/consul/api v1.23.0/go.mod h1:SfvUIT74b0EplDuNgAJQ/FVqSO6KyK2ia80UI39/Ye8=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/consul/sdk v0.14.0 h1:Hly+BMNMssVzoWddbBnBFi3W+Fzytvm0haSkihhj3GU=
+github.com/hashicorp/consul/sdk v0.14.0/go.mod h1:gHYeuDa0+0qRAD6Wwr6yznMBvBwHKoxSBoW5l73+saE=
github.com/hashicorp/cronexpr v1.1.1 h1:NJZDd87hGXjoZBdvyCF9mX4DCq5Wy7+A/w+A7q0wn6c=
github.com/hashicorp/cronexpr v1.1.1/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -2143,6 +2156,7 @@ github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/S
github.com/hashicorp/go-discover v0.0.0-20210818145131-c573d69da192 h1:eje2KOX8Sf7aYPiAsLnpWdAIrGRMcpFjN/Go/Exb7Zo=
github.com/hashicorp/go-discover v0.0.0-20210818145131-c573d69da192/go.mod h1:3/4dzY4lR1Hzt9bBqMhBzG7lngZ0GKx/nL6G/ad62wE=
github.com/hashicorp/go-gatedio v0.5.0 h1:Jm1X5yP4yCqqWj5L1TgW7iZwCVPGtVc+mro5r/XX7Tg=
+github.com/hashicorp/go-gatedio v0.5.0/go.mod h1:Lr3t8L6IyxD3DAeaUxGcgl2JnRUpWMCsmBl4Omu/2t4=
github.com/hashicorp/go-gcp-common v0.8.0 h1:/2vGAbCU1v+BZ3YHXTCzTvxqma9WOJHYtADTfhZixLo=
github.com/hashicorp/go-gcp-common v0.8.0/go.mod h1:Q7zYRy9ue9SuaEN2s9YLIQs4SoKHdoRmKRcImY3SLgs=
github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
@@ -2442,6 +2456,7 @@ github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4=
github.com/jarcoal/httpmock v1.0.7 h1:d1a2VFpSdm5gtjhCPWsQHSnx8+5V3ms5431YwvmkuNk=
+github.com/jarcoal/httpmock v1.0.7/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
@@ -2809,6 +2824,7 @@ github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkA
github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw=
github.com/onsi/ginkgo/v2 v2.6.1/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE=
+github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -2829,6 +2845,7 @@ github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
+github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/open-policy-agent/opa v0.42.2/go.mod h1:MrmoTi/BsKWT58kXlVayBb+rYVeaMwuBm3nYAN3923s=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -3057,6 +3074,7 @@ github.com/sethvargo/go-limiter v0.7.1/go.mod h1:C0kbSFbiriE5k2FFOe18M1YZbAR2Fiw
github.com/shirou/gopsutil/v3 v3.22.6 h1:FnHOFOh+cYAM0C30P+zysPISzlknLC5Z1G4EAElznfQ=
github.com/shirou/gopsutil/v3 v3.22.6/go.mod h1:EdIubSnZhbAvBS1yJ7Xi+AShB/hxwLHOMz4MCYz7yMs=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
+github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
diff --git a/physical/raft/fsm.go b/physical/raft/fsm.go
index abc5e87a0fc8..3323f987df8b 100644
--- a/physical/raft/fsm.go
+++ b/physical/raft/fsm.go
@@ -20,6 +20,7 @@ import (
"github.com/armon/go-metrics"
"github.com/golang/protobuf/proto"
+ bolt "github.com/hashicorp-forge/bbolt"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-raftchunking"
@@ -28,7 +29,6 @@ import (
"github.com/hashicorp/vault/sdk/helper/jsonutil"
"github.com/hashicorp/vault/sdk/physical"
"github.com/hashicorp/vault/sdk/plugin/pb"
- bolt "go.etcd.io/bbolt"
)
const (
diff --git a/physical/raft/raft.go b/physical/raft/raft.go
index ecfdb92c01d7..c6ca8a789b40 100644
--- a/physical/raft/raft.go
+++ b/physical/raft/raft.go
@@ -20,6 +20,7 @@ import (
"github.com/armon/go-metrics"
"github.com/golang/protobuf/proto"
+ bolt "github.com/hashicorp-forge/bbolt"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-raftchunking"
"github.com/hashicorp/go-secure-stdlib/parseutil"
@@ -37,7 +38,7 @@ import (
"github.com/hashicorp/vault/sdk/physical"
"github.com/hashicorp/vault/vault/cluster"
"github.com/hashicorp/vault/version"
- bolt "go.etcd.io/bbolt"
+ etcdbolt "go.etcd.io/bbolt"
)
const (
@@ -400,7 +401,7 @@ func NewRaftBackend(conf map[string]string, logger log.Logger) (physical.Backend
// Create the backend raft store for logs and stable storage.
dbPath := filepath.Join(path, "raft.db")
- opts := boltOptions(dbPath)
+ opts := etcdboltOptions(dbPath)
raftOptions := raftboltdb.Options{
Path: dbPath,
BoltOptions: opts,
@@ -631,7 +632,7 @@ func (b *RaftBackend) CollectMetrics(sink *metricsutil.ClusterMetricSink) {
stats = b.raft.Stats()
}
b.l.RUnlock()
- b.collectMetricsWithStats(logstoreStats, sink, "logstore")
+ b.collectEtcdBoltMetricsWithStats(logstoreStats, sink, "logstore")
b.collectMetricsWithStats(fsmStats, sink, "fsm")
labels := []metrics.Label{
{
@@ -672,6 +673,29 @@ func (b *RaftBackend) collectMetricsWithStats(stats bolt.Stats, sink *metricsuti
sink.IncrCounterWithLabels([]string{"raft_storage", "bolt", "write", "time"}, float32(txstats.GetWriteTime().Milliseconds()), labels)
}
+func (b *RaftBackend) collectEtcdBoltMetricsWithStats(stats etcdbolt.Stats, sink *metricsutil.ClusterMetricSink, database string) {
+ txstats := stats.TxStats
+ labels := []metricsutil.Label{{"database", database}}
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "freelist", "free_pages"}, float32(stats.FreePageN), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "freelist", "pending_pages"}, float32(stats.PendingPageN), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "freelist", "allocated_bytes"}, float32(stats.FreeAlloc), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "freelist", "used_bytes"}, float32(stats.FreelistInuse), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "transaction", "started_read_transactions"}, float32(stats.TxN), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "transaction", "currently_open_read_transactions"}, float32(stats.OpenTxN), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "page", "count"}, float32(txstats.GetPageCount()), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "page", "bytes_allocated"}, float32(txstats.GetPageAlloc()), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "cursor", "count"}, float32(txstats.GetCursorCount()), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "node", "count"}, float32(txstats.GetNodeCount()), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "node", "dereferences"}, float32(txstats.GetNodeDeref()), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "rebalance", "count"}, float32(txstats.GetRebalance()), labels)
+ sink.AddSampleWithLabels([]string{"raft_storage", "bolt", "rebalance", "time"}, float32(txstats.GetRebalanceTime().Milliseconds()), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "split", "count"}, float32(txstats.GetSplit()), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "spill", "count"}, float32(txstats.GetSpill()), labels)
+ sink.AddSampleWithLabels([]string{"raft_storage", "bolt", "spill", "time"}, float32(txstats.GetSpillTime().Milliseconds()), labels)
+ sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "write", "count"}, float32(txstats.GetWrite()), labels)
+ sink.IncrCounterWithLabels([]string{"raft_storage", "bolt", "write", "time"}, float32(txstats.GetWriteTime().Milliseconds()), labels)
+}
+
// RaftServer has information about a server in the Raft configuration
type RaftServer struct {
// NodeID is the name of the server
@@ -1916,3 +1940,39 @@ func boltOptions(path string) *bolt.Options {
return o
}
+
+func etcdboltOptions(path string) *etcdbolt.Options {
+ o := &etcdbolt.Options{
+ Timeout: 1 * time.Second,
+ FreelistType: etcdbolt.FreelistMapType,
+ NoFreelistSync: true,
+ MmapFlags: getMmapFlags(path),
+ }
+
+ if os.Getenv("VAULT_RAFT_FREELIST_TYPE") == "array" {
+ o.FreelistType = etcdbolt.FreelistArrayType
+ }
+
+ if os.Getenv("VAULT_RAFT_FREELIST_SYNC") != "" {
+ o.NoFreelistSync = false
+ }
+
+ // By default, we want to set InitialMmapSize to 100GB, but only on 64bit platforms.
+ // Otherwise, we set it to whatever the value of VAULT_RAFT_INITIAL_MMAP_SIZE
+ // is, assuming it can be parsed as an int. Bolt itself sets this to 0 by default,
+ // so if users are wanting to turn this off, they can also set it to 0. Setting it
+ // to a negative value is the same as not setting it at all.
+ if os.Getenv("VAULT_RAFT_INITIAL_MMAP_SIZE") == "" {
+ o.InitialMmapSize = initialMmapSize
+ } else {
+ imms, err := strconv.Atoi(os.Getenv("VAULT_RAFT_INITIAL_MMAP_SIZE"))
+
+ // If there's an error here, it means they passed something that's not convertible to
+ // a number. Rather than fail startup, just ignore it.
+ if err == nil && imms > 0 {
+ o.InitialMmapSize = imms
+ }
+ }
+
+ return o
+}
diff --git a/physical/raft/raft_test.go b/physical/raft/raft_test.go
index cc3594f0f12d..e7532b992a99 100644
--- a/physical/raft/raft_test.go
+++ b/physical/raft/raft_test.go
@@ -21,13 +21,13 @@ import (
"github.com/go-test/deep"
"github.com/golang/protobuf/proto"
+ bolt "github.com/hashicorp-forge/bbolt"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-secure-stdlib/base62"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/raft"
"github.com/hashicorp/vault/sdk/helper/jsonutil"
"github.com/hashicorp/vault/sdk/physical"
- bolt "go.etcd.io/bbolt"
)
func connectPeers(nodes ...*RaftBackend) {
diff --git a/physical/raft/snapshot.go b/physical/raft/snapshot.go
index 3eb818574958..adcfac4e1c44 100644
--- a/physical/raft/snapshot.go
+++ b/physical/raft/snapshot.go
@@ -18,10 +18,10 @@ import (
"time"
"github.com/golang/protobuf/proto"
+ bolt "github.com/hashicorp-forge/bbolt"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/sdk/plugin/pb"
"github.com/rboyer/safeio"
- bolt "go.etcd.io/bbolt"
"go.uber.org/atomic"
"github.com/hashicorp/raft"
From 66b3e439d80c7cb991ec31cd84d652c1001aa3f6 Mon Sep 17 00:00:00 2001
From: Scott Miller
Date: Tue, 21 Nov 2023 09:53:41 -0600
Subject: [PATCH 08/74] wordsmithing (#24205)
---
website/content/docs/enterprise/fips/fips1402.mdx | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/website/content/docs/enterprise/fips/fips1402.mdx b/website/content/docs/enterprise/fips/fips1402.mdx
index ce9fa97904e2..4d46dfa46daa 100644
--- a/website/content/docs/enterprise/fips/fips1402.mdx
+++ b/website/content/docs/enterprise/fips/fips1402.mdx
@@ -88,8 +88,12 @@ reasons:
of say, a Root CA involves a concerted, non-Vault effort to accomplish
and must be done thoughtfully.
-Combined, we suggest leaving the existing cluster in place, and carefully
-consider migration of specific workloads to the FIPS-backed cluster.
+As such Hashicorp cannot provide support for workloads that are affected
+either technically or via non-compliance that results from converting
+existing cluster workloads to the FIPS 140-2 Inside binary.
+
+Instead, we suggest leaving the existing cluster in place, and carefully
+consider migration of specific workloads to the FIPS-backed cluster.
#### Entropy augmentation restrictions
From 68fbb17b9c252869be38b9b87447b51b240cdeb0 Mon Sep 17 00:00:00 2001
From: Steven Clark
Date: Tue, 21 Nov 2023 10:58:44 -0500
Subject: [PATCH 09/74] TestTransitImport: Generate Transit wrapping key with a
longer context (#24212)
- Instead of relying on the initial call to import to generate the
wrapping key, generate it within the test setup with a longer
dedicated timeout.
- This hopefully is enough of a timeout for the 32 bit nightly runner
---
command/transit_import_key_test.go | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/command/transit_import_key_test.go b/command/transit_import_key_test.go
index 6bcf0237df5c..21884c0799ca 100644
--- a/command/transit_import_key_test.go
+++ b/command/transit_import_key_test.go
@@ -5,11 +5,13 @@ package command
import (
"bytes"
+ "context"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"testing"
+ "time"
"github.com/hashicorp/vault/api"
@@ -29,6 +31,15 @@ func TestTransitImport(t *testing.T) {
t.Fatalf("transit mount error: %#v", err)
}
+ // Force the generation of the Transit wrapping key now with a longer context
+ // to help the 32bit nightly tests. This creates a 4096-bit RSA key which can take
+ // a while on an overloaded system
+ genWrappingKeyCtx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
+ defer cancel()
+ if _, err := client.Logical().ReadWithContext(genWrappingKeyCtx, "transit/wrapping_key"); err != nil {
+ t.Fatalf("transit failed generating wrapping key: %#v", err)
+ }
+
rsa1, rsa2, aes128, aes256 := generateKeys(t)
type testCase struct {
From f60c643aa8c15083fd7dec38416396ef79bbee27 Mon Sep 17 00:00:00 2001
From: Angel Garbarino
Date: Tue, 21 Nov 2023 09:06:45 -0700
Subject: [PATCH 10/74] UI: HDS adoption replace in lib/replication
(#24161)
* replication directory components update
* need to wait for another pr to merge for revoke and fixing a one off in distribute:
* clean up
* amend revoke with new ConfirmAction work.
* some PR comments
* remove wrapping LinkTo
* Update ui/lib/replication/addon/templates/mode/secondaries/revoke.hbs
Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
---------
Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
---
.../components/keymgmt/distribute.hbs | 30 ++++++----------
.../components/replication-summary.hbs | 19 +++++-----
.../addon/templates/mode/secondaries/add.hbs | 19 ++++------
.../mode/secondaries/config-create.hbs | 17 +++------
.../mode/secondaries/config-edit.hbs | 19 +++-------
.../templates/mode/secondaries/revoke.hbs | 35 +++++++++----------
6 files changed, 52 insertions(+), 87 deletions(-)
diff --git a/ui/app/templates/components/keymgmt/distribute.hbs b/ui/app/templates/components/keymgmt/distribute.hbs
index ec9fdbc06392..c9c54a33320e 100644
--- a/ui/app/templates/components/keymgmt/distribute.hbs
+++ b/ui/app/templates/components/keymgmt/distribute.hbs
@@ -151,24 +151,16 @@
-
-
-
- {{#if this.createDistribution.isRunning}}
-
- {{else}}
- {{if (or (not @key) this.isNewKey) "Add key" "Distribute key"}}
- {{/if}}
-
-
-
-
-
-
+
+
+
+
+
{{/if}}
\ No newline at end of file
diff --git a/ui/lib/replication/addon/templates/components/replication-summary.hbs b/ui/lib/replication/addon/templates/components/replication-summary.hbs
index c32a365a53e6..3750ad2c5aea 100644
--- a/ui/lib/replication/addon/templates/components/replication-summary.hbs
+++ b/ui/lib/replication/addon/templates/components/replication-summary.hbs
@@ -278,11 +278,12 @@
)
}}
-
-
- Enable Replication
-
-
+
{{/if}}
@@ -315,9 +316,7 @@
{{#if this.submit.isRunning}}
{{else}}
-
-
-
+
{{/if}}
{{else}}
@@ -329,9 +328,7 @@
Performance
-
-
-
+
{{/if}}
{{/if}}
diff --git a/ui/lib/replication/addon/templates/mode/secondaries/add.hbs b/ui/lib/replication/addon/templates/mode/secondaries/add.hbs
index 838af13f4442..c6a6cbaabd2f 100644
--- a/ui/lib/replication/addon/templates/mode/secondaries/add.hbs
+++ b/ui/lib/replication/addon/templates/mode/secondaries/add.hbs
@@ -25,7 +25,7 @@
name="activation-token-id"
id="activation-token-id"
@value={{this.id}}
- data-test-replication-secondary-id={{true}}
+ data-test-replication-secondary-id
/>
@@ -45,18 +45,11 @@
{{#if (eq this.replicationMode "performance")}}
{{/if}}
-
-
-
- Generate token
-
-
-
-
- Cancel
-
-
-
+
+
+
+
+
{{#if this.isModalActive}}
diff --git a/ui/lib/replication/addon/templates/mode/secondaries/config-create.hbs b/ui/lib/replication/addon/templates/mode/secondaries/config-create.hbs
index 3fbf861065d3..1858da83be36 100644
--- a/ui/lib/replication/addon/templates/mode/secondaries/config-create.hbs
+++ b/ui/lib/replication/addon/templates/mode/secondaries/config-create.hbs
@@ -11,16 +11,9 @@
\ No newline at end of file
diff --git a/ui/lib/replication/addon/templates/mode/secondaries/config-edit.hbs b/ui/lib/replication/addon/templates/mode/secondaries/config-edit.hbs
index 77a4b57f33d4..03b5dbd18de0 100644
--- a/ui/lib/replication/addon/templates/mode/secondaries/config-edit.hbs
+++ b/ui/lib/replication/addon/templates/mode/secondaries/config-edit.hbs
@@ -12,18 +12,9 @@
\ No newline at end of file
diff --git a/ui/lib/replication/addon/templates/mode/secondaries/revoke.hbs b/ui/lib/replication/addon/templates/mode/secondaries/revoke.hbs
index fa52a6becde6..1143f5170a5e 100644
--- a/ui/lib/replication/addon/templates/mode/secondaries/revoke.hbs
+++ b/ui/lib/replication/addon/templates/mode/secondaries/revoke.hbs
@@ -20,21 +20,20 @@
The secondary id to revoke; given initially to generate a secondary token.
-
-
-
-
-
- {{#unless this.isRevoking}}
-
- Cancel
-
- {{/unless}}
-
-
\ No newline at end of file
+
+
+
+
+
\ No newline at end of file
From 913481fb1f438888fafc15f1131d6091ef8d7c9d Mon Sep 17 00:00:00 2001
From: Scott Miller
Date: Tue, 21 Nov 2023 10:25:01 -0600
Subject: [PATCH 11/74] OSS fixes (#24200)
---
command/server.go | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/command/server.go b/command/server.go
index 3c1861099047..9cf3f73bdb3e 100644
--- a/command/server.go
+++ b/command/server.go
@@ -2567,10 +2567,16 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
Priority: 1,
Name: "shamir",
})
- case 1:
- // If there's only one seal and it's disabled assume they want to
+ default:
+ allSealsDisabled := true
+ for _, c := range config.Seals {
+ if !c.Disabled {
+ allSealsDisabled = false
+ }
+ }
+ // If all seals are disabled assume they want to
// migrate to a shamir seal and simply didn't provide it
- if config.Seals[0].Disabled {
+ if allSealsDisabled {
config.Seals = append(config.Seals, &configutil.KMS{
Type: vault.SealConfigTypeShamir.String(),
Priority: 1,
From b7dff9777db22512fe11d53b28d3ff2ec4dd212a Mon Sep 17 00:00:00 2001
From: Steven Clark
Date: Tue, 21 Nov 2023 14:36:49 -0500
Subject: [PATCH 12/74] Allow backends to extract credentials from payloads and
trigger an authentication workflow (#23924)
* wip
* Work on the tuneable allowance and some bugs
* Call handleCancellableRequest instead, which gets the audit order more correct and includes the preauth response
* Get rid of no longer needed operation
* Phew, this wasn't necessary
* Add auth error handling by the backend, and fix a bug with handleInvalidCredentials
* Cleanup req/resp naming
* Use the new form, and data
* Discovered that tokens werent really being checked because isLoginRequest returns true for the re-request into the backend, when it shouldnt
* Add a few more checks in the delegated request handler for bad inputs
- Protect the delegated handler from bad inputs from the backend such
as an empty accessor, a path that isn't registered as a login request
- Add similar protections for bad auth results as we do in the normal
login request paths. Technically not 100% needed but if somehow the
handleCancelableRequest doesn't use the handleLoginRequest code path
we could get into trouble in the future
- Add delegated-auth-accessors flag to the secrets tune command and
api-docs
* Unit tests and some small fixes
* Remove transit preauth test, rely on unit tests
* Cleanup and add a little more commentary in tests
* Fix typos, add another failure use-case which we reference a disabled auth mount
* PR Feedback
- Use router to lookup mount instead of defining a new lookup method
- Enforce auth table types and namespace when mount is found
- Define a type alias for the handleInvalidCreds
- Fix typos/grammar
- Clean up globals in test
* Additional PR feedback
- Add test for delegated auth handler
- Force batch token usage
- Add a test to validate failures if a non-batch token is used
- Check for Data member being nil in test cases
* Update failure error message around requiring batch tokens
* Trap MFA requests
* Reword some error messages
* Add test and fixes for delegated response wrapping
* Move MFA test to dedicated mount
- If the delegated auth tests were running in parallel, the MFA test
case might influence the other tests, so move the MFA to a dedicated
mount
* PR feedback: use textproto.CanonicalMIMEHeaderKey
- Change the X-Vault-Wrap-Ttl constant to X-Vault-Wrap-TTL
and use textproto.CanonicalMIMEHeaderKey to format it
within the delete call.
- This protects the code around changes of the constant typing
* PR feedback
- Append Error to RequestDelegatedAuth
- Force error interface impl through explicit nil var assignment on
RequestDelegatedAuthError
- Clean up test factory and leverage NewTestSoloCluster
- Leverage newer maps.Clone as this is 1.16 only
---------
Co-authored-by: Scott G. Miller
---
api/sys_mounts.go | 3 +
command/commands.go | 3 +
command/secrets_tune.go | 13 +
helper/testhelpers/testhelpers.go | 11 +-
sdk/helper/consts/consts.go | 4 +
sdk/logical/error.go | 46 +-
sdk/logical/request.go | 1 +
.../delegated_auth/delegated_auth_test.go | 530 ++++++++++++++++++
vault/logical_system.go | 33 ++
vault/logical_system_paths.go | 9 +
vault/mount.go | 8 +
vault/request_handling.go | 135 ++++-
website/content/api-docs/system/mounts.mdx | 6 +
13 files changed, 795 insertions(+), 7 deletions(-)
create mode 100644 vault/external_tests/delegated_auth/delegated_auth_test.go
diff --git a/api/sys_mounts.go b/api/sys_mounts.go
index a6c2a0f5412e..16aedcce4750 100644
--- a/api/sys_mounts.go
+++ b/api/sys_mounts.go
@@ -271,6 +271,7 @@ type MountConfigInput struct {
AllowedManagedKeys []string `json:"allowed_managed_keys,omitempty" mapstructure:"allowed_managed_keys"`
PluginVersion string `json:"plugin_version,omitempty"`
UserLockoutConfig *UserLockoutConfigInput `json:"user_lockout_config,omitempty"`
+ DelegatedAuthAccessors []string `json:"delegated_auth_accessors,omitempty" mapstructure:"delegated_auth_accessors"`
// Deprecated: This field will always be blank for newer server responses.
PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"`
}
@@ -303,6 +304,8 @@ type MountConfigOutput struct {
TokenType string `json:"token_type,omitempty" mapstructure:"token_type"`
AllowedManagedKeys []string `json:"allowed_managed_keys,omitempty" mapstructure:"allowed_managed_keys"`
UserLockoutConfig *UserLockoutConfigOutput `json:"user_lockout_config,omitempty"`
+ DelegatedAuthAccessors []string `json:"delegated_auth_accessors,omitempty" mapstructure:"delegated_auth_accessors"`
+
// Deprecated: This field will always be blank for newer server responses.
PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"`
}
diff --git a/command/commands.go b/command/commands.go
index b1867e428da3..1a52e121a1df 100644
--- a/command/commands.go
+++ b/command/commands.go
@@ -161,6 +161,9 @@ const (
// flagNameLogLevel is used to specify the log level applied to logging
// Supported log levels: Trace, Debug, Error, Warn, Info
flagNameLogLevel = "log-level"
+ // flagNameDelegatedAuthAccessors allows operators to specify the allowed mount accessors a backend can delegate
+ // authentication
+ flagNameDelegatedAuthAccessors = "delegated-auth-accessors"
)
var (
diff --git a/command/secrets_tune.go b/command/secrets_tune.go
index 66a409fc9602..eef9e577c2f4 100644
--- a/command/secrets_tune.go
+++ b/command/secrets_tune.go
@@ -35,6 +35,7 @@ type SecretsTuneCommand struct {
flagVersion int
flagPluginVersion string
flagAllowedManagedKeys []string
+ flagDelegatedAuthAccessors []string
}
func (c *SecretsTuneCommand) Synopsis() string {
@@ -158,6 +159,14 @@ func (c *SecretsTuneCommand) Flags() *FlagSets {
"the plugin catalog, and will not start running until the plugin is reloaded.",
})
+ f.StringSliceVar(&StringSliceVar{
+ Name: flagNameDelegatedAuthAccessors,
+ Target: &c.flagDelegatedAuthAccessors,
+ Usage: "A list of permitted authentication accessors this backend can delegate authentication to. " +
+ "Note that multiple values may be specified by providing this option multiple times, " +
+ "each time with 1 accessor.",
+ })
+
return set
}
@@ -242,6 +251,10 @@ func (c *SecretsTuneCommand) Run(args []string) int {
if fl.Name == flagNamePluginVersion {
mountConfigInput.PluginVersion = c.flagPluginVersion
}
+
+ if fl.Name == flagNameDelegatedAuthAccessors {
+ mountConfigInput.DelegatedAuthAccessors = c.flagDelegatedAuthAccessors
+ }
})
if err := client.Sys().TuneMount(mountPath, mountConfigInput); err != nil {
diff --git a/helper/testhelpers/testhelpers.go b/helper/testhelpers/testhelpers.go
index 261e03b6fcb9..c3499b8b6b0c 100644
--- a/helper/testhelpers/testhelpers.go
+++ b/helper/testhelpers/testhelpers.go
@@ -811,9 +811,15 @@ func RetryUntil(t testing.T, timeout time.Duration, f func() error) {
t.Fatalf("did not complete before deadline, err: %v", err)
}
-// CreateEntityAndAlias clones an existing client and creates an entity/alias.
+// CreateEntityAndAlias clones an existing client and creates an entity/alias, uses userpass mount path
// It returns the cloned client, entityID, and aliasID.
func CreateEntityAndAlias(t testing.T, client *api.Client, mountAccessor, entityName, aliasName string) (*api.Client, string, string) {
+ return CreateEntityAndAliasWithinMount(t, client, mountAccessor, "userpass", entityName, aliasName)
+}
+
+// CreateEntityAndAliasWithinMount clones an existing client and creates an entity/alias, within the specified mountPath
+// It returns the cloned client, entityID, and aliasID.
+func CreateEntityAndAliasWithinMount(t testing.T, client *api.Client, mountAccessor, mountPath, entityName, aliasName string) (*api.Client, string, string) {
t.Helper()
userClient, err := client.Clone()
if err != nil {
@@ -841,7 +847,8 @@ func CreateEntityAndAlias(t testing.T, client *api.Client, mountAccessor, entity
if aliasID == "" {
t.Fatal("Alias ID not present in response")
}
- _, err = client.Logical().WriteWithContext(context.Background(), fmt.Sprintf("auth/userpass/users/%s", aliasName), map[string]interface{}{
+ path := fmt.Sprintf("auth/%s/users/%s", mountPath, aliasName)
+ _, err = client.Logical().WriteWithContext(context.Background(), path, map[string]interface{}{
"password": "testpassword",
})
if err != nil {
diff --git a/sdk/helper/consts/consts.go b/sdk/helper/consts/consts.go
index 036ccf55d425..ccc7494a281c 100644
--- a/sdk/helper/consts/consts.go
+++ b/sdk/helper/consts/consts.go
@@ -19,6 +19,10 @@ const (
// SSRF protection.
RequestHeaderName = "X-Vault-Request"
+ // WrapTTLHeaderName is the name of the header containing a directive to
+ // wrap the response
+ WrapTTLHeaderName = "X-Vault-Wrap-TTL"
+
// PerformanceReplicationALPN is the negotiated protocol used for
// performance replication.
PerformanceReplicationALPN = "replication_v1"
diff --git a/sdk/logical/error.go b/sdk/logical/error.go
index 5605784b3e13..95445afac537 100644
--- a/sdk/logical/error.go
+++ b/sdk/logical/error.go
@@ -3,7 +3,10 @@
package logical
-import "errors"
+import (
+ "context"
+ "errors"
+)
var (
// ErrUnsupportedOperation is returned if the operation is not supported
@@ -61,6 +64,47 @@ var (
ErrPathFunctionalityRemoved = errors.New("functionality on this path has been removed")
)
+type DelegatedAuthErrorHandler func(ctx context.Context, initiatingRequest, authRequest *Request, authResponse *Response, err error) (*Response, error)
+
+var _ error = &RequestDelegatedAuthError{}
+
+// RequestDelegatedAuthError Special error indicating the backend wants to delegate authentication elsewhere
+type RequestDelegatedAuthError struct {
+ mountAccessor string
+ path string
+ data map[string]interface{}
+ errHandler DelegatedAuthErrorHandler
+}
+
+func NewDelegatedAuthenticationRequest(mountAccessor, path string, data map[string]interface{}, errHandler DelegatedAuthErrorHandler) *RequestDelegatedAuthError {
+ return &RequestDelegatedAuthError{
+ mountAccessor: mountAccessor,
+ path: path,
+ data: data,
+ errHandler: errHandler,
+ }
+}
+
+func (d *RequestDelegatedAuthError) Error() string {
+ return "authentication delegation requested"
+}
+
+func (d *RequestDelegatedAuthError) MountAccessor() string {
+ return d.mountAccessor
+}
+
+func (d *RequestDelegatedAuthError) Path() string {
+ return d.path
+}
+
+func (d *RequestDelegatedAuthError) Data() map[string]interface{} {
+ return d.data
+}
+
+func (d *RequestDelegatedAuthError) AuthErrorHandler() DelegatedAuthErrorHandler {
+ return d.errHandler
+}
+
type HTTPCodedError interface {
Error() string
Code() int
diff --git a/sdk/logical/request.go b/sdk/logical/request.go
index 4b617dbc100e..a4850e0eb504 100644
--- a/sdk/logical/request.go
+++ b/sdk/logical/request.go
@@ -56,6 +56,7 @@ const (
NoClientToken ClientTokenSource = iota
ClientTokenFromVaultHeader
ClientTokenFromAuthzHeader
+ ClientTokenFromInternalAuth
)
type WALState struct {
diff --git a/vault/external_tests/delegated_auth/delegated_auth_test.go b/vault/external_tests/delegated_auth/delegated_auth_test.go
new file mode 100644
index 000000000000..c50077ffe5f9
--- /dev/null
+++ b/vault/external_tests/delegated_auth/delegated_auth_test.go
@@ -0,0 +1,530 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: BUSL-1.1
+
+package delegated_auth
+
+import (
+ "context"
+ "fmt"
+ paths "path"
+ "testing"
+
+ "github.com/hashicorp/vault/api"
+ "github.com/hashicorp/vault/builtin/credential/userpass"
+ "github.com/hashicorp/vault/builtin/logical/totp"
+ "github.com/hashicorp/vault/helper/testhelpers"
+ "github.com/hashicorp/vault/helper/testhelpers/minimal"
+ "github.com/hashicorp/vault/sdk/framework"
+ "github.com/hashicorp/vault/sdk/logical"
+ "github.com/hashicorp/vault/vault"
+ "github.com/stretchr/testify/require"
+)
+
+func buildDaError(defaults map[string]string, d *framework.FieldData) *logical.RequestDelegatedAuthError {
+ fieldDataOrDefault := func(field string, d *framework.FieldData) string {
+ if val, ok := d.GetOk(field); ok {
+ return val.(string)
+ }
+
+ return defaults[field]
+ }
+
+ accessor := fieldDataOrDefault("accessor", d)
+ path := fieldDataOrDefault("path", d)
+ username := fieldDataOrDefault("username", d)
+ password := fieldDataOrDefault("password", d)
+ var errorHandler logical.DelegatedAuthErrorHandler
+ if handleErrorRaw, ok := d.GetOk("handle_error"); ok {
+ if handleErrorRaw.(bool) {
+ errorHandler = func(ctx context.Context, initiatingRequest, authRequest *logical.Request, authResponse *logical.Response, err error) (*logical.Response, error) {
+ return logical.ErrorResponse(fmt.Sprintf("my custom handler: %v", err)), nil
+ }
+ }
+ }
+
+ loginPath := paths.Join(path, username)
+ data := map[string]interface{}{"password": password}
+
+ return logical.NewDelegatedAuthenticationRequest(accessor, loginPath, data, errorHandler)
+}
+
+func buildDelegatedAuthFactory(defaults map[string]string) logical.Factory {
+ opHandler := func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
+ daError := buildDaError(defaults, d)
+ if req.ClientToken == "" || req.ClientTokenSource != logical.ClientTokenFromInternalAuth {
+ return nil, daError
+ }
+
+ if req.Operation == logical.ListOperation {
+ return logical.ListResponse([]string{"success", req.ClientToken}), nil
+ }
+
+ if d.Get("loop").(bool) {
+ return nil, daError
+ }
+
+ if d.Get("perform_write").(bool) {
+ entry, err := logical.StorageEntryJSON("test", map[string]string{"test": "value"})
+ if err != nil {
+ return nil, err
+ }
+ if err = req.Storage.Put(ctx, entry); err != nil {
+ return nil, err
+ }
+ }
+
+ return &logical.Response{
+ Data: map[string]interface{}{
+ "success": true,
+ "token": req.ClientToken,
+ },
+ }, nil
+ }
+
+ return func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) {
+ b := new(framework.Backend)
+ b.BackendType = logical.TypeLogical
+ b.Paths = []*framework.Path{
+ {
+ Pattern: "preauth-test/list/?",
+ Operations: map[logical.Operation]framework.OperationHandler{
+ logical.ListOperation: &framework.PathOperation{Callback: opHandler},
+ },
+ },
+ {
+ Pattern: "preauth-test",
+ Operations: map[logical.Operation]framework.OperationHandler{
+ logical.ReadOperation: &framework.PathOperation{Callback: opHandler},
+ logical.PatchOperation: &framework.PathOperation{Callback: opHandler},
+ logical.UpdateOperation: &framework.PathOperation{Callback: opHandler},
+ logical.DeleteOperation: &framework.PathOperation{Callback: opHandler},
+ },
+ Fields: map[string]*framework.FieldSchema{
+ "accessor": {Type: framework.TypeString},
+ "path": {Type: framework.TypeString},
+ "username": {Type: framework.TypeString},
+ "password": {Type: framework.TypeString},
+ "loop": {Type: framework.TypeBool},
+ "perform_write": {Type: framework.TypeBool},
+ "handle_error": {Type: framework.TypeBool},
+ },
+ },
+ }
+ b.PathsSpecial = &logical.Paths{Unauthenticated: []string{"preauth-test", "preauth-test/*"}}
+ err := b.Setup(ctx, config)
+ return b, err
+ }
+}
+
+func TestDelegatedAuth(t *testing.T) {
+ t.Parallel()
+
+ // A map of success values to be populated once and used in request
+ // operations that can't pass in values
+ delegatedReqDefaults := map[string]string{
+ "username": "allowed-est",
+ "password": "test",
+ "path": "login",
+ }
+
+ delegatedAuthFactory := buildDelegatedAuthFactory(delegatedReqDefaults)
+ coreConfig := &vault.CoreConfig{
+ CredentialBackends: map[string]logical.Factory{
+ "userpass": userpass.Factory,
+ },
+ LogicalBackends: map[string]logical.Factory{
+ "delegateauthtest": delegatedAuthFactory,
+ "totp": totp.Factory,
+ },
+ }
+
+ cluster := minimal.NewTestSoloCluster(t, coreConfig)
+ cluster.Start()
+ defer cluster.Cleanup()
+
+ client := testhelpers.WaitForActiveNode(t, cluster).Client
+
+ // Setup two users, one with an allowed policy, another without a policy within userpass
+ err := client.Sys().PutPolicy("allow-est",
+ `path "dat/preauth-test" { capabilities = ["read", "create", "update", "patch", "delete"] }
+ path "dat/preauth-test/*" { capabilities = ["read","list"] }`)
+ require.NoError(t, err, "Failed to write policy allow-est")
+
+ err = client.Sys().EnableAuthWithOptions("userpass", &api.EnableAuthOptions{
+ Type: "userpass",
+ })
+ require.NoError(t, err, "failed mounting userpass endpoint")
+
+ _, err = client.Logical().Write("auth/userpass/users/allowed-est", map[string]interface{}{
+ "password": "test",
+ "policies": "allow-est",
+ "token_type": "batch",
+ })
+ require.NoError(t, err, "failed to create allowed-est user")
+
+ _, err = client.Logical().Write("auth/userpass/users/not-allowed-est", map[string]interface{}{
+ "password": "test",
+ "token_type": "batch",
+ })
+ require.NoError(t, err, "failed to create not-allowed-est user")
+
+ _, err = client.Logical().Write("auth/userpass/users/bad-token-type-est", map[string]interface{}{
+ "password": "test",
+ "token_type": "service",
+ })
+ require.NoError(t, err, "failed to create bad-token-type-est user")
+
+ // Setup another auth mount so we can test multiple accessors in mount tuning works later
+ err = client.Sys().EnableAuthWithOptions("userpass2", &api.EnableAuthOptions{
+ Type: "userpass",
+ })
+ require.NoError(t, err, "failed mounting userpass2")
+
+ _, err = client.Logical().Write("auth/userpass2/users/allowed-est-2", map[string]interface{}{
+ "password": "test",
+ "policies": "allow-est",
+ "token_type": "batch",
+ })
+ require.NoError(t, err, "failed to create allowed-est-2 user")
+
+ // Setup a dedicated mount for MFA purposes
+ err = client.Sys().EnableAuthWithOptions("userpass-mfa", &api.EnableAuthOptions{
+ Type: "userpass",
+ })
+ require.NoError(t, err, "failed mounting userpass-mfa")
+
+ // Fetch the userpass auth accessors
+ resp, err := client.Logical().Read("/sys/mounts/auth/userpass")
+ require.NoError(t, err, "failed to query for mount accessor")
+ require.NotNil(t, resp, "received nil response from mount accessor query")
+ require.NotNil(t, resp.Data, "received response with nil Data")
+ require.NotEmpty(t, resp.Data["accessor"], "Accessor field was empty: %v", resp)
+ upAccessor := resp.Data["accessor"].(string)
+
+ resp, err = client.Logical().Read("/sys/mounts/auth/userpass2")
+ require.NoError(t, err, "failed to query for mount accessor for userpass2")
+ require.NotNil(t, resp, "received nil response from mount accessor query for userpass2")
+ require.NotNil(t, resp.Data, "received response with nil Data")
+ require.NotEmpty(t, resp.Data["accessor"], "Accessor field was empty: %v", resp)
+ upAccessor2 := resp.Data["accessor"].(string)
+
+ resp, err = client.Logical().Read("/sys/mounts/auth/userpass-mfa")
+ require.NoError(t, err, "failed to query for MFA mount accessor")
+ require.NotNil(t, resp, "received nil response from MFA mount accessor query")
+ require.NotNil(t, resp.Data, "received response with nil Data for MFA mount accessor query")
+ require.NotEmpty(t, resp.Data["accessor"], "MFA mount Accessor field was empty: %v", resp)
+ upAccessorMFA := resp.Data["accessor"].(string)
+
+ resp, err = client.Logical().Read("/sys/mounts/cubbyhole")
+ require.NoError(t, err, "failed to query for mount accessor for cubbyhole")
+ require.NotNil(t, resp, "received nil response from mount accessor query for cubbyhole")
+ require.NotNil(t, resp.Data, "received response with nil Data")
+ require.NotEmpty(t, resp.Data["accessor"], "Accessor field was empty: %v", resp)
+ cubbyAccessor := resp.Data["accessor"].(string)
+
+ // Set up our backend mount that will delegate its auth to the userpass mount
+ err = client.Sys().Mount("dat", &api.MountInput{
+ Type: "delegateauthtest",
+ Config: api.MountConfigInput{
+ DelegatedAuthAccessors: []string{
+ upAccessor, upAccessorMFA, "an-accessor-that-does-not-exist",
+ cubbyAccessor,
+ },
+ },
+ })
+ require.NoError(t, err, "failed mounting delegated auth endpoint")
+
+ delegatedReqDefaults["accessor"] = upAccessor
+
+ // We want a client without any previous tokens set to make sure we aren't using
+ // the other token.
+ clientNoToken, err := client.Clone()
+ require.NoError(t, err, "failed cloning client")
+ clientNoToken.ClearToken()
+
+ // Happy path test for the various operation types we want to support, make sure
+ // for each one that we don't error out and we get back a token value from the backend
+ // call.
+ for _, test := range []string{"delete", "read", "list", "write"} {
+ t.Run("op-"+test, func(st *testing.T) {
+ switch test {
+ case "delete":
+ resp, err = clientNoToken.Logical().Delete("dat/preauth-test")
+ case "read":
+ resp, err = clientNoToken.Logical().Read("dat/preauth-test")
+ case "list":
+ resp, err = clientNoToken.Logical().List("dat/preauth-test/list/")
+ case "write":
+ resp, err = clientNoToken.Logical().Write("dat/preauth-test", map[string]interface{}{
+ "accessor": delegatedReqDefaults["accessor"],
+ "path": delegatedReqDefaults["path"],
+ "username": delegatedReqDefaults["username"],
+ "password": delegatedReqDefaults["password"],
+ })
+ }
+
+ require.NoErrorf(st, err, "failed making %s pre-auth call with allowed-est", test)
+ require.NotNilf(st, resp, "pre-auth %s call returned nil", test)
+ require.NotNil(t, resp.Data, "received response with nil Data")
+ if test != "list" {
+ require.Equalf(st, true, resp.Data["success"], "Got an incorrect response from %s call in success field", test)
+ require.NotEmptyf(st, resp.Data["token"], "no token returned by %s handler", test)
+ } else {
+ require.NotEmpty(st, resp.Data["keys"], "list operation did not contain keys in response")
+ keys := resp.Data["keys"].([]interface{})
+ require.Equal(st, 2, len(keys), "keys field did not contain expected 2 elements")
+ require.Equal(st, "success", keys[0], "the first keys field did not contain expected value")
+ require.NotEmpty(st, keys[1], "the second keys field did not contain a token")
+ }
+ })
+ }
+
+ // Test various failure scenarios
+ failureTests := []struct {
+ name string
+ accessor string
+ path string
+ username string
+ password string
+ errorContains string
+ forceLoop bool
+ }{
+ {
+ name: "policy-denies-user",
+ accessor: upAccessor,
+ path: "login",
+ username: "not-allowed-est",
+ password: "test",
+ errorContains: "permission denied",
+ },
+ {
+ name: "bad-password",
+ accessor: upAccessor,
+ path: "login",
+ username: "allowed-est",
+ password: "bad-password",
+ errorContains: "invalid credentials",
+ },
+ {
+ name: "unknown-user",
+ accessor: upAccessor,
+ path: "login",
+ username: "non-existant-user",
+ password: "test",
+ errorContains: "invalid username or password",
+ },
+ {
+ name: "missing-user",
+ accessor: upAccessor,
+ path: "login",
+ username: "",
+ password: "test",
+ errorContains: "was not considered a login request",
+ },
+ {
+ name: "missing-password",
+ accessor: upAccessor,
+ path: "login",
+ username: "allowed-est",
+ password: "",
+ errorContains: "missing password",
+ },
+ {
+ name: "bad-path-within-delegated-auth-error",
+ accessor: upAccessor,
+ path: "not-the-login-path",
+ username: "allowed-est",
+ password: "test",
+ errorContains: "was not considered a login request",
+ },
+ {
+ name: "empty-path-within-delegated-auth-error",
+ accessor: upAccessor,
+ path: "",
+ username: "allowed-est",
+ password: "test",
+ errorContains: "was not considered a login request",
+ },
+ {
+ name: "empty-accessor-within-delegated-auth-error",
+ accessor: "",
+ path: "login",
+ username: "allowed-est",
+ password: "test",
+ errorContains: "backend returned an invalid mount accessor",
+ },
+ {
+ name: "accessor-does-not-exist-within-delegated-auth-error",
+ accessor: "an-accessor-that-does-not-exist",
+ path: "login",
+ username: "allowed-est",
+ password: "test",
+ errorContains: "requested delegate authentication accessor 'an-accessor-that-does-not-exist' was not found",
+ },
+ {
+ name: "non-allowed-accessor-within-delegated-auth-error",
+ accessor: upAccessor2,
+ path: "login",
+ username: "allowed-est-2",
+ password: "test",
+ errorContains: fmt.Sprintf("delegated auth to accessor %s not permitted", upAccessor2),
+ },
+ {
+ name: "force-constant-login-request-loop",
+ accessor: upAccessor,
+ path: "login",
+ username: "allowed-est",
+ password: "test",
+ forceLoop: true,
+ errorContains: "delegated authentication requested but authentication token present",
+ },
+ {
+ name: "non-auth-mount-accessor",
+ accessor: cubbyAccessor,
+ path: "login",
+ username: "allowed-est",
+ password: "test",
+ errorContains: fmt.Sprintf("requested delegate authentication mount '%s' was not an auth mount", cubbyAccessor),
+ },
+ {
+ name: "fails-on-non-batch-token",
+ accessor: upAccessor,
+ path: "login",
+ username: "bad-token-type-est",
+ password: "test",
+ errorContains: "delegated auth requests must be configured to issue batch tokens",
+ },
+ }
+ for _, test := range failureTests {
+ t.Run(test.name, func(st *testing.T) {
+ resp, err = clientNoToken.Logical().Write("dat/preauth-test", map[string]interface{}{
+ "accessor": test.accessor,
+ "path": test.path,
+ "username": test.username,
+ "password": test.password,
+ "loop": test.forceLoop,
+ })
+ if test.errorContains != "" {
+ require.ErrorContains(st, err, test.errorContains,
+ "pre-auth call should have failed due to policy restriction got resp: %v err: %v", resp, err)
+ } else {
+ require.Error(st, err, "Expected failure got resp: %v err: %v", resp, err)
+ }
+ })
+ }
+
+ // Make sure we can add an accessor to the mount that previously failed above,
+ // and the request handling code does use both accessor values.
+ t.Run("multiple-accessors", func(st *testing.T) {
+ err = client.Sys().TuneMount("dat", api.MountConfigInput{DelegatedAuthAccessors: []string{upAccessor, upAccessor2, upAccessorMFA}})
+ require.NoError(t, err, "Failed to tune mount to update delegated auth accessors")
+
+ resp, err = clientNoToken.Logical().Write("dat/preauth-test", map[string]interface{}{
+ "accessor": upAccessor2,
+ "path": "login",
+ "username": "allowed-est-2",
+ "password": "test",
+ })
+
+ require.NoError(st, err, "failed making pre-auth call with allowed-est-2")
+ require.NotNil(st, resp, "pre-auth %s call returned nil with allowed-est-2")
+ require.NotNil(t, resp.Data, "received response with nil Data")
+ require.Equal(st, true, resp.Data["success"], "Got an incorrect response from call in success field with allowed-est-2")
+ require.NotEmpty(st, resp.Data["token"], "no token returned with allowed-est-2 user")
+ })
+
+ // Test we can delegate a permission denied error back to the originating
+ // backend for processing/response to the client
+ t.Run("backend-handles-permission-denied", func(st *testing.T) {
+ resp, err = clientNoToken.Logical().Write("dat/preauth-test", map[string]interface{}{
+ "accessor": upAccessor,
+ "path": "login",
+ "username": "allowed-est",
+ "password": "test2",
+ "handle_error": true,
+ })
+
+ require.ErrorContains(st, err, "my custom handler: invalid credentials")
+ })
+
+ // Test we can delegate a permission denied error back to the originating
+ // backend for processing/response to the client
+ t.Run("mfa-request-is-denied", func(st *testing.T) {
+ // Mount the totp secrets engine
+ testhelpers.SetupTOTPMount(st, client)
+
+ // Create a test entity and alias
+ totpUser := "test-totp"
+ testhelpers.CreateEntityAndAliasWithinMount(st, client, upAccessorMFA, "userpass-mfa", "entity1", totpUser)
+
+ // Configure a default TOTP method
+ methodID := testhelpers.SetupTOTPMethod(st, client, map[string]interface{}{
+ "issuer": "yCorp",
+ "period": 5,
+ "algorithm": "SHA256",
+ "digits": 6,
+ "skew": 1,
+ "key_size": 20,
+ "qr_size": 200,
+ "max_validation_attempts": 5,
+ "method_name": "foo",
+ })
+
+ // Configure a login enforcement specific to the MFA userpass mount to avoid conflicts on others.
+ enforcementConfig := map[string]interface{}{
+ "auth_method_accessors": []string{upAccessorMFA},
+ "name": methodID[0:4],
+ "mfa_method_ids": []string{methodID},
+ }
+
+ testhelpers.SetupMFALoginEnforcement(st, client, enforcementConfig)
+
+ _, err = clientNoToken.Logical().Write("dat/preauth-test", map[string]interface{}{
+ "accessor": upAccessorMFA,
+ "path": "login",
+ "username": totpUser,
+ "password": "testpassword",
+ "handle_error": false,
+ })
+
+ require.ErrorContains(st, err, "delegated auth request requiring MFA is not supported")
+ })
+
+ // Test the behavior around receiving a request asking for response wrapping and
+ // being delegated to the secondary query we do
+ t.Run("response-wrapping-test", func(st *testing.T) {
+ resWrapClient, err := client.Clone()
+ require.NoError(st, err, "failed cloning client for response wrapping")
+
+ resWrapClient.SetWrappingLookupFunc(func(operation, path string) string {
+ if path == "dat/preauth-test" {
+ return "15s"
+ }
+ return ""
+ })
+
+ resp, err = resWrapClient.Logical().Write("dat/preauth-test", map[string]interface{}{
+ "accessor": upAccessor,
+ "path": "login",
+ "username": "allowed-est",
+ "password": "test",
+ })
+ require.NoError(st, err, "failed calling preauth-test api with response wrapping")
+ require.NotNil(st, resp, "Got nil, nil response from preauth-test api with response wrapping")
+ require.NotNil(st, resp.WrapInfo, "response object didn't contain wrapped info")
+
+ unwrapClient, err := client.Clone()
+ require.NoError(st, err, "failed cloning client for lookups")
+ wrapToken := resp.WrapInfo.Token
+ unwrapClient.SetToken(wrapToken)
+
+ unwrapResp, err := unwrapClient.Logical().Write("sys/wrapping/unwrap", map[string]interface{}{})
+ require.NoError(st, err, "failed unwrap call")
+ require.NotNil(st, unwrapResp, "unwrap response was nil")
+ require.NotNil(st, unwrapResp.Data, "unwrap response did not contain Data")
+ require.Contains(st, unwrapResp.Data, "success", "unwrap response data did not contain success field")
+ require.Contains(st, unwrapResp.Data, "token", "unwrap response data did not contain token field")
+ require.Equal(st, true, unwrapResp.Data["success"], "Got an incorrect response in success field within unwrap call")
+ require.NotEmptyf(st, unwrapResp.Data["token"], "no token returned by handler within unwrap call")
+ })
+}
diff --git a/vault/logical_system.go b/vault/logical_system.go
index e978095a1908..564e0e971593 100644
--- a/vault/logical_system.go
+++ b/vault/logical_system.go
@@ -1426,6 +1426,9 @@ func (b *SystemBackend) handleMount(ctx context.Context, req *logical.Request, d
if len(apiConfig.AllowedManagedKeys) > 0 {
config.AllowedManagedKeys = apiConfig.AllowedManagedKeys
}
+ if len(apiConfig.DelegatedAuthAccessors) > 0 {
+ config.DelegatedAuthAccessors = apiConfig.DelegatedAuthAccessors
+ }
// Create the mount entry
me := &MountEntry{
@@ -2370,6 +2373,32 @@ func (b *SystemBackend) handleTuneWriteCommon(ctx context.Context, path string,
}
}
+ if rawVal, ok := data.GetOk("delegated_auth_accessors"); ok {
+ delegatedAuthAccessors := rawVal.([]string)
+
+ oldVal := mountEntry.Config.DelegatedAuthAccessors
+ mountEntry.Config.DelegatedAuthAccessors = delegatedAuthAccessors
+
+ // Update the mount table
+ var err error
+ switch {
+ case strings.HasPrefix(path, "auth/"):
+ err = b.Core.persistAuth(ctx, b.Core.auth, &mountEntry.Local)
+ default:
+ err = b.Core.persistMounts(ctx, b.Core.mounts, &mountEntry.Local)
+ }
+ if err != nil {
+ mountEntry.Config.DelegatedAuthAccessors = oldVal
+ return handleError(err)
+ }
+
+ mountEntry.SyncCache()
+
+ if b.Core.logger.IsInfo() {
+ b.Core.logger.Info("mount tuning of delegated_auth_accessors successful", "path", path)
+ }
+ }
+
var err error
var resp *logical.Response
var options map[string]string
@@ -6409,4 +6438,8 @@ This path responds to the following HTTP methods.
Returns the available and enabled experiments.
`,
},
+ "delegated_auth_accessors": {
+ "A list of auth accessors that the mount is allowed to delegate authentication too",
+ "",
+ },
}
diff --git a/vault/logical_system_paths.go b/vault/logical_system_paths.go
index 5f4df09ecb31..637f77bf5859 100644
--- a/vault/logical_system_paths.go
+++ b/vault/logical_system_paths.go
@@ -4427,6 +4427,10 @@ func (b *SystemBackend) mountPaths() []*framework.Path {
Type: framework.TypeCommaStringSlice,
Description: strings.TrimSpace(sysHelp["tune_allowed_managed_keys"][0]),
},
+ "delegated_auth_accessors": {
+ Type: framework.TypeCommaStringSlice,
+ Description: strings.TrimSpace(sysHelp["allowed_delegated_auth_accessors"][0]),
+ },
"plugin_version": {
Type: framework.TypeString,
Description: strings.TrimSpace(sysHelp["plugin-catalog_version"][0]),
@@ -4477,6 +4481,11 @@ func (b *SystemBackend) mountPaths() []*framework.Path {
Description: strings.TrimSpace(sysHelp["tune_allowed_managed_keys"][0]),
Required: false,
},
+ "delegated_auth_accessors": {
+ Type: framework.TypeCommaStringSlice,
+ Description: strings.TrimSpace(sysHelp["delegated_auth_accessors"][0]),
+ Required: false,
+ },
"allowed_response_headers": {
Type: framework.TypeCommaStringSlice,
Description: strings.TrimSpace(sysHelp["allowed_response_headers"][0]),
diff --git a/vault/mount.go b/vault/mount.go
index b72e22a054b1..d06c331ea12a 100644
--- a/vault/mount.go
+++ b/vault/mount.go
@@ -364,6 +364,7 @@ type MountConfig struct {
TokenType logical.TokenType `json:"token_type,omitempty" structs:"token_type" mapstructure:"token_type"`
AllowedManagedKeys []string `json:"allowed_managed_keys,omitempty" mapstructure:"allowed_managed_keys"`
UserLockoutConfig *UserLockoutConfig `json:"user_lockout_config,omitempty" mapstructure:"user_lockout_config"`
+ DelegatedAuthAccessors []string `json:"delegated_auth_accessors,omitempty" mapstructure:"delegated_auth_accessors"`
// PluginName is the name of the plugin registered in the catalog.
//
@@ -399,6 +400,7 @@ type APIMountConfig struct {
AllowedManagedKeys []string `json:"allowed_managed_keys,omitempty" mapstructure:"allowed_managed_keys"`
UserLockoutConfig *UserLockoutConfig `json:"user_lockout_config,omitempty" mapstructure:"user_lockout_config"`
PluginVersion string `json:"plugin_version,omitempty" mapstructure:"plugin_version"`
+ DelegatedAuthAccessors []string `json:"delegated_auth_accessors,omitempty" mapstructure:"delegated_auth_accessors"`
// PluginName is the name of the plugin registered in the catalog.
//
@@ -500,6 +502,12 @@ func (e *MountEntry) SyncCache() {
} else {
e.synthesizedConfigCache.Store("allowed_managed_keys", e.Config.AllowedManagedKeys)
}
+
+ if len(e.Config.DelegatedAuthAccessors) == 0 {
+ e.synthesizedConfigCache.Delete("delegated_auth_accessors")
+ } else {
+ e.synthesizedConfigCache.Store("delegated_auth_accessors", e.Config.DelegatedAuthAccessors)
+ }
}
func (entry *MountEntry) Deserialize() map[string]interface{} {
diff --git a/vault/request_handling.go b/vault/request_handling.go
index 1330b94688f5..b8296f34f115 100644
--- a/vault/request_handling.go
+++ b/vault/request_handling.go
@@ -9,7 +9,11 @@ import (
"encoding/base64"
"errors"
"fmt"
+ "maps"
+ "net/textproto"
"os"
+ paths "path"
+ "slices"
"strconv"
"strings"
"time"
@@ -767,7 +771,7 @@ func (c *Core) handleCancelableRequest(ctx context.Context, req *logical.Request
walState := &logical.WALState{}
ctx = logical.IndexStateContext(ctx, walState)
var auth *logical.Auth
- if c.isLoginRequest(ctx, req) {
+ if c.isLoginRequest(ctx, req) && req.ClientTokenSource != logical.ClientTokenFromInternalAuth {
resp, auth, err = c.handleLoginRequest(ctx, req)
} else {
resp, auth, err = c.handleRequest(ctx, req)
@@ -1379,6 +1383,10 @@ func (c *Core) handleRequest(ctx context.Context, req *logical.Request) (retResp
// Return the response and error
if routeErr != nil {
+ if _, ok := routeErr.(*logical.RequestDelegatedAuthError); ok {
+ routeErr = fmt.Errorf("delegated authentication requested but authentication token present")
+ }
+
retErr = multierror.Append(retErr, routeErr)
}
@@ -1496,15 +1504,23 @@ func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (re
// Route the request
resp, routeErr := c.doRouting(ctx, req)
- // if routeErr has invalid credentials error, update the userFailedLoginMap
- if routeErr != nil && routeErr == logical.ErrInvalidCredentials {
+ handleInvalidCreds := func(err error) (*logical.Response, *logical.Auth, error) {
if !isUserLockoutDisabled {
err := c.failedUserLoginProcess(ctx, entry, req)
if err != nil {
return nil, nil, err
}
}
- return resp, nil, routeErr
+ return resp, nil, err
+ }
+
+ if routeErr != nil {
+ // if routeErr has invalid credentials error, update the userFailedLoginMap
+ if routeErr == logical.ErrInvalidCredentials {
+ return handleInvalidCreds(routeErr)
+ } else if da, ok := routeErr.(*logical.RequestDelegatedAuthError); ok {
+ return c.handleDelegatedAuth(ctx, req, da, entry, handleInvalidCreds)
+ }
}
if resp != nil {
@@ -1837,6 +1853,117 @@ func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (re
return resp, auth, routeErr
}
+type invalidCredentialHandler func(err error) (*logical.Response, *logical.Auth, error)
+
+// handleDelegatedAuth when a backend request returns logical.RequestDelegatedAuthError, it is requesting that
+// an authentication workflow of its choosing be implemented prior to it being able to accept it. Normally
+// this is used for standard protocols that communicate the credential information in a non-standard Vault way
+func (c *Core) handleDelegatedAuth(ctx context.Context, origReq *logical.Request, da *logical.RequestDelegatedAuthError, entry *MountEntry, invalidCredHandler invalidCredentialHandler) (*logical.Response, *logical.Auth, error) {
+ // Make sure we didn't get into a routing loop.
+ if origReq.ClientTokenSource == logical.ClientTokenFromInternalAuth {
+ return nil, nil, fmt.Errorf("%w: original request had delegated auth token, "+
+ "forbidding another delegated request from path '%s'", ErrInternalError, origReq.Path)
+ }
+
+ // Backend has requested internally delegated authentication
+ requestedAccessor := da.MountAccessor()
+ if strings.TrimSpace(requestedAccessor) == "" {
+ return nil, nil, fmt.Errorf("%w: backend returned an invalid mount accessor '%s'", ErrInternalError, requestedAccessor)
+ }
+ // First, is this allowed by the mount tunable?
+ if !slices.Contains(entry.Config.DelegatedAuthAccessors, requestedAccessor) {
+ return nil, nil, fmt.Errorf("delegated auth to accessor %s not permitted", requestedAccessor)
+ }
+
+ reqNamespace, err := namespace.FromContext(ctx)
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed looking up namespace from context: %w", err)
+ }
+
+ mount := c.router.MatchingMountByAccessor(requestedAccessor)
+ if mount == nil {
+ return nil, nil, fmt.Errorf("%w: requested delegate authentication accessor '%s' was not found", logical.ErrPermissionDenied, requestedAccessor)
+ }
+ if mount.Table != credentialTableType {
+ return nil, nil, fmt.Errorf("%w: requested delegate authentication mount '%s' was not an auth mount", logical.ErrPermissionDenied, requestedAccessor)
+ }
+ if mount.NamespaceID != reqNamespace.ID {
+ return nil, nil, fmt.Errorf("%w: requested delegate authentication mount was in a different namespace than request", logical.ErrPermissionDenied)
+ }
+
+ // Found it, now form the login path and issue the request
+ path := paths.Join("auth", mount.Path, da.Path())
+ authReq, err := origReq.Clone()
+ if err != nil {
+ return nil, nil, err
+ }
+ authReq.MountAccessor = requestedAccessor
+ authReq.Path = path
+ authReq.Operation = logical.UpdateOperation
+
+ // filter out any response wrapping headers, for our embedded login request
+ delete(authReq.Headers, textproto.CanonicalMIMEHeaderKey(consts.WrapTTLHeaderName))
+ authReq.WrapInfo = nil
+
+ // Insert the data fields from the delegated auth error in our auth request
+ authReq.Data = maps.Clone(da.Data())
+
+ // Make sure we are going to perform a login request and not expose other backend types to this request
+ if !c.isLoginRequest(ctx, authReq) {
+ return nil, nil, fmt.Errorf("delegated path '%s' was not considered a login request", authReq.Path)
+ }
+
+ authResp, err := c.handleCancelableRequest(ctx, authReq)
+ if err != nil || authResp.IsError() {
+ // see if the backend wishes to handle the failed auth
+ if da.AuthErrorHandler() != nil {
+ resp, err := da.AuthErrorHandler()(ctx, origReq, authReq, authResp, err)
+ return resp, nil, err
+ }
+ switch err {
+ case nil:
+ return authResp, nil, nil
+ case logical.ErrInvalidCredentials:
+ return invalidCredHandler(err)
+ default:
+ return authResp, nil, err
+ }
+ }
+ if authResp == nil {
+ return nil, nil, fmt.Errorf("%w: delegated auth request returned empty response for request_path: %s", ErrInternalError, authReq.Path)
+ }
+ // A login request should never return a secret!
+ if authResp.Secret != nil {
+ return nil, nil, fmt.Errorf("%w: unexpected Secret response for login path for request_path: %s", ErrInternalError, authReq.Path)
+ }
+ if authResp.Auth == nil {
+ return nil, nil, fmt.Errorf("%w: Auth response was nil for request_path: %s", ErrInternalError, authReq.Path)
+ }
+ if authResp.Auth.ClientToken == "" {
+ if authResp.Auth.MFARequirement != nil {
+ return nil, nil, fmt.Errorf("%w: delegated auth request requiring MFA is not supported: %s", logical.ErrPermissionDenied, authReq.Path)
+ }
+ return nil, nil, fmt.Errorf("%w: delegated auth request did not return a client token for login path: %s", ErrInternalError, authReq.Path)
+ }
+
+ // Delegated auth tokens should only be batch tokens, as we don't want to incur
+ // the cost of storage/tidying for protocols that will be generating a token per
+ // request.
+ if !IsBatchToken(authResp.Auth.ClientToken) {
+ return nil, nil, fmt.Errorf("%w: delegated auth requests must be configured to issue batch tokens", logical.ErrPermissionDenied)
+ }
+
+ // Authentication successful, use the resulting ClientToken to reissue the original request
+ secondReq, err := origReq.Clone()
+ if err != nil {
+ return nil, nil, err
+ }
+ secondReq.ClientToken = authResp.Auth.ClientToken
+ secondReq.ClientTokenSource = logical.ClientTokenFromInternalAuth
+ resp, err := c.handleCancelableRequest(ctx, secondReq)
+ return resp, nil, err
+}
+
// LoginCreateToken creates a token as a result of a login request.
// If MFA is enforced, mfa/validate endpoint calls this functions
// after successful MFA validation to generate the token.
diff --git a/website/content/api-docs/system/mounts.mdx b/website/content/api-docs/system/mounts.mdx
index 3bee236c5ce4..5486e9f70251 100644
--- a/website/content/api-docs/system/mounts.mdx
+++ b/website/content/api-docs/system/mounts.mdx
@@ -174,6 +174,9 @@ This endpoint enables a new secrets engine at the given path.
- `allowed_managed_keys` `(array: [])` - List of managed key registry entry names
that the mount in question is allowed to access.
+ - `delegated_auth_accessors` `(array: [])` - List of allowed authentication mount
+ accessors the backend can request delegated authentication for.
+
- `options` `(map: nil)` - Specifies mount type specific options
that are passed to the backend.
@@ -382,6 +385,9 @@ This endpoint tunes configuration parameters for a given mount point.
- `plugin_version` `(string: "")` – Specifies the semantic version of the plugin
to use, e.g. "v1.0.0". Changes will not take effect until the mount is reloaded.
+- `delegated_auth_accessors` `(array: [])` - List of allowed authentication mount
+ accessors the backend can request delegated authentication for.
+
### Sample payload
```json
From 18e6385e0589895c354e0d2aed95e8321f1ee84f Mon Sep 17 00:00:00 2001
From: Mike Palmiotto
Date: Tue, 21 Nov 2023 15:45:07 -0500
Subject: [PATCH 13/74] Consistently use OperationHandler for entity paths
(#24225)
---
vault/identity_store_entities.go | 30 ++++++++++++++++++++----------
1 file changed, 20 insertions(+), 10 deletions(-)
diff --git a/vault/identity_store_entities.go b/vault/identity_store_entities.go
index f59457f95098..05c83c7bd2b0 100644
--- a/vault/identity_store_entities.go
+++ b/vault/identity_store_entities.go
@@ -68,8 +68,10 @@ func entityPaths(i *IdentityStore) []*framework.Path {
},
Fields: entityPathFields(),
- Callbacks: map[logical.Operation]framework.OperationFunc{
- logical.UpdateOperation: i.handleEntityUpdateCommon(),
+ Operations: map[logical.Operation]framework.OperationHandler{
+ logical.UpdateOperation: &framework.PathOperation{
+ Callback: i.handleEntityUpdateCommon(),
+ },
},
HelpSynopsis: strings.TrimSpace(entityHelp["entity"][0]),
@@ -158,8 +160,10 @@ func entityPaths(i *IdentityStore) []*framework.Path {
},
},
- Callbacks: map[logical.Operation]framework.OperationFunc{
- logical.UpdateOperation: i.handleEntityBatchDelete(),
+ Operations: map[logical.Operation]framework.OperationHandler{
+ logical.UpdateOperation: &framework.PathOperation{
+ Callback: i.handleEntityBatchDelete(),
+ },
},
HelpSynopsis: strings.TrimSpace(entityHelp["batch-delete"][0]),
@@ -173,8 +177,10 @@ func entityPaths(i *IdentityStore) []*framework.Path {
OperationSuffix: "by-name",
},
- Callbacks: map[logical.Operation]framework.OperationFunc{
- logical.ListOperation: i.pathEntityNameList(),
+ Operations: map[logical.Operation]framework.OperationHandler{
+ logical.ListOperation: &framework.PathOperation{
+ Callback: i.pathEntityNameList(),
+ },
},
HelpSynopsis: strings.TrimSpace(entityHelp["entity-name-list"][0]),
@@ -188,8 +194,10 @@ func entityPaths(i *IdentityStore) []*framework.Path {
OperationSuffix: "by-id",
},
- Callbacks: map[logical.Operation]framework.OperationFunc{
- logical.ListOperation: i.pathEntityIDList(),
+ Operations: map[logical.Operation]framework.OperationHandler{
+ logical.ListOperation: &framework.PathOperation{
+ Callback: i.pathEntityIDList(),
+ },
},
HelpSynopsis: strings.TrimSpace(entityHelp["entity-id-list"][0]),
@@ -221,8 +229,10 @@ func entityPaths(i *IdentityStore) []*framework.Path {
Description: "Setting this will follow the 'mine' strategy for merging MFA secrets. If there are secrets of the same type both in entities that are merged from and in entity into which all others are getting merged, secrets in the destination will be unaltered. If not set, this API will throw an error containing all the conflicts.",
},
},
- Callbacks: map[logical.Operation]framework.OperationFunc{
- logical.UpdateOperation: i.pathEntityMergeID(),
+ Operations: map[logical.Operation]framework.OperationHandler{
+ logical.UpdateOperation: &framework.PathOperation{
+ Callback: i.pathEntityMergeID(),
+ },
},
HelpSynopsis: strings.TrimSpace(entityHelp["entity-merge-id"][0]),
From 82ca52d44763f8be6cc2885f4aada68fee05e55e Mon Sep 17 00:00:00 2001
From: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
Date: Tue, 21 Nov 2023 15:11:14 -0600
Subject: [PATCH 14/74] UI: Fix KV v2 json editor (#24224)
* Fix JSON editor in KVv2 unable to paste. Fixes #23940
* Default to JSON view on edit with secret is complex
* Add changelog
---
changelog/24224.txt | 3 +++
ui/lib/kv/addon/components/kv-data-fields.hbs | 2 +-
ui/lib/kv/addon/components/kv-data-fields.js | 12 ++++++++----
ui/lib/kv/addon/components/page/secret/edit.hbs | 9 +++++++--
ui/lib/kv/addon/components/page/secret/edit.js | 5 +++++
.../backend/kv/kv-v2-workflow-edge-cases-test.js | 15 +++++++++++++++
.../components/kv/kv-data-fields-test.js | 2 +-
7 files changed, 40 insertions(+), 8 deletions(-)
create mode 100644 changelog/24224.txt
diff --git a/changelog/24224.txt b/changelog/24224.txt
new file mode 100644
index 000000000000..040b42d94da8
--- /dev/null
+++ b/changelog/24224.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+ui: Fix JSON editor in KV V2 unable to handle pasted values
+```
diff --git a/ui/lib/kv/addon/components/kv-data-fields.hbs b/ui/lib/kv/addon/components/kv-data-fields.hbs
index 76c5c2dfd3a0..b384d3e4c2e3 100644
--- a/ui/lib/kv/addon/components/kv-data-fields.hbs
+++ b/ui/lib/kv/addon/components/kv-data-fields.hbs
@@ -15,7 +15,7 @@
{{#if @showJson}}
{{#if (or @modelValidations.secretData.errors this.lintingErrors)}}
diff --git a/ui/lib/kv/addon/components/kv-data-fields.js b/ui/lib/kv/addon/components/kv-data-fields.js
index bb1f759810d1..663df063e4c9 100644
--- a/ui/lib/kv/addon/components/kv-data-fields.js
+++ b/ui/lib/kv/addon/components/kv-data-fields.js
@@ -6,7 +6,7 @@
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
-import KVObject from 'vault/lib/kv-object';
+import { stringify } from 'core/helpers/stringify';
/**
* @module KvDataFields is used for rendering the fields associated with kv secret data, it hides/shows a json editor and renders validation errors for the json editor
@@ -28,10 +28,13 @@ import KVObject from 'vault/lib/kv-object';
export default class KvDataFields extends Component {
@tracked lintingErrors;
+ @tracked codeMirrorString;
- get emptyJson() {
- // if secretData is null, this specially formats a blank object and renders a nice initial state for the json editor
- return KVObject.create({ content: [{ name: '', value: '' }] }).toJSONString(true);
+ constructor() {
+ super(...arguments);
+ this.codeMirrorString = this.args.secret?.secretData
+ ? stringify([this.args.secret.secretData], {})
+ : '{ "": "" }';
}
@action
@@ -41,5 +44,6 @@ export default class KvDataFields extends Component {
if (!this.lintingErrors) {
this.args.secret.secretData = JSON.parse(value);
}
+ this.codeMirrorString = value;
}
}
diff --git a/ui/lib/kv/addon/components/page/secret/edit.hbs b/ui/lib/kv/addon/components/page/secret/edit.hbs
index 34a0365d1608..8a5be5646996 100644
--- a/ui/lib/kv/addon/components/page/secret/edit.hbs
+++ b/ui/lib/kv/addon/components/page/secret/edit.hbs
@@ -5,7 +5,12 @@
<:toolbarFilters>
-
+
JSON
@@ -38,7 +43,7 @@
0) {
+ // Dumb way to check if there's a nested object in the secret
+ this.secretDataIsAdvanced = true;
+ }
}
get showOldVersionAlert() {
diff --git a/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-edge-cases-test.js b/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-edge-cases-test.js
index c92914102ba9..87aad84cc2c0 100644
--- a/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-edge-cases-test.js
+++ b/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-edge-cases-test.js
@@ -24,6 +24,7 @@ import {
} from 'vault/tests/helpers/policy-generator/kv';
import { clearRecords, writeSecret, writeVersionedSecret } from 'vault/tests/helpers/kv/kv-run-commands';
import { FORM, PAGE } from 'vault/tests/helpers/kv/kv-selectors';
+import codemirror from 'vault/tests/helpers/codemirror';
/**
* This test set is for testing edge cases, such as specific bug fixes or reported user workflows
@@ -269,6 +270,20 @@ module('Acceptance | kv-v2 workflow | edge cases', function (hooks) {
await click(PAGE.breadcrumbAtIdx(2));
assert.dom(PAGE.list.item()).exists({ count: 2 }, 'two secrets are listed');
});
+
+ test('complex values default to JSON display', async function (assert) {
+ await visit(`/vault/secrets/${this.backend}/kv/create`);
+ await fillIn(FORM.inputByAttr('path'), 'complex');
+
+ await click(FORM.toggleJson);
+ assert.strictEqual(codemirror().getValue(), '{ "": "" }');
+ codemirror().setValue('{ "foo3": { "name": "bar3" } }');
+ await click(FORM.saveBtn);
+ // Future: test that json is automatic on details too
+ await click(PAGE.detail.createNewVersion);
+ assert.dom(FORM.toggleJson).isDisabled();
+ assert.dom(FORM.toggleJson).isChecked();
+ });
});
// NAMESPACE TESTS
diff --git a/ui/tests/integration/components/kv/kv-data-fields-test.js b/ui/tests/integration/components/kv/kv-data-fields-test.js
index 954e4d0e1fa7..44ed1c9a2b1c 100644
--- a/ui/tests/integration/components/kv/kv-data-fields-test.js
+++ b/ui/tests/integration/components/kv/kv-data-fields-test.js
@@ -43,7 +43,7 @@ module('Integration | Component | kv-v2 | KvDataFields', function (hooks) {
assert.strictEqual(
codemirror().getValue(' '),
- `{ \"\": \"\" }`, // eslint-disable-line no-useless-escape
+ `{ \"\": \"\" }`, // eslint-disable-line no-useless-escape
'json editor initializes with empty object'
);
await fillIn(`${FORM.jsonEditor} textarea`, 'blah');
From 8e8bc82a5ac384748f1928e1825958be3c18000f Mon Sep 17 00:00:00 2001
From: Marccio Silva
Date: Tue, 21 Nov 2023 22:36:58 +0100
Subject: [PATCH 15/74] Update go-jose dependency to 3.0.1 (#24226)
---
api/go.mod | 2 +-
api/go.sum | 4 ++--
go.mod | 4 ++--
go.sum | 3 ++-
4 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/api/go.mod b/api/go.mod
index 20fb4617af23..184b9e4d03b9 100644
--- a/api/go.mod
+++ b/api/go.mod
@@ -9,7 +9,7 @@ go 1.19
require (
github.com/cenkalti/backoff/v3 v3.0.0
- github.com/go-jose/go-jose/v3 v3.0.0
+ github.com/go-jose/go-jose/v3 v3.0.1
github.com/go-test/deep v1.0.2
github.com/hashicorp/errwrap v1.1.0
github.com/hashicorp/go-cleanhttp v0.5.2
diff --git a/api/go.sum b/api/go.sum
index e8f5f1811f8f..bb993047e5ca 100644
--- a/api/go.sum
+++ b/api/go.sum
@@ -7,8 +7,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
-github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
+github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA=
+github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw=
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
diff --git a/go.mod b/go.mod
index ca8ab3deab56..ce7b32a48ea8 100644
--- a/go.mod
+++ b/go.mod
@@ -62,7 +62,7 @@ require (
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
github.com/go-errors/errors v1.5.0
github.com/go-git/go-git/v5 v5.7.0
- github.com/go-jose/go-jose/v3 v3.0.0
+ github.com/go-jose/go-jose/v3 v3.0.1
github.com/go-ldap/ldap/v3 v3.4.4
github.com/go-sql-driver/mysql v1.7.1
github.com/go-test/deep v1.1.0
@@ -204,6 +204,7 @@ require (
github.com/sethvargo/go-limiter v0.7.1
github.com/shirou/gopsutil/v3 v3.22.6
github.com/stretchr/testify v1.8.4
+ go.etcd.io/bbolt v1.3.7
go.etcd.io/etcd/client/pkg/v3 v3.5.7
go.etcd.io/etcd/client/v2 v2.305.5
go.etcd.io/etcd/client/v3 v3.5.7
@@ -507,7 +508,6 @@ require (
github.com/yusufpapurcu/wmi v1.2.2 // indirect
github.com/zclconf/go-cty v1.12.1 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
- go.etcd.io/bbolt v1.3.7 // indirect
go.etcd.io/etcd/api/v3 v3.5.7 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel/metric v1.16.0 // indirect
diff --git a/go.sum b/go.sum
index f32079238fa6..13ebf88ef11b 100644
--- a/go.sum
+++ b/go.sum
@@ -1696,8 +1696,9 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-ini/ini v1.66.6/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
-github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
+github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA=
+github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
From 39762174206ee353e8cb2d1eab2c544723b91c2d Mon Sep 17 00:00:00 2001
From: Peter Wilson
Date: Wed, 22 Nov 2023 19:54:47 +0000
Subject: [PATCH 16/74] Audit: logging a response uses a separate 5 second
timeout (#24238)
* added a 5s timeout to attempts to process nodes in the audit pipeline for logging a response
* added changelog
* ensure we supply namespace to the new context
---
changelog/24238.txt | 3 +++
vault/audit_broker.go | 19 ++++++++++++++++++-
2 files changed, 21 insertions(+), 1 deletion(-)
create mode 100644 changelog/24238.txt
diff --git a/changelog/24238.txt b/changelog/24238.txt
new file mode 100644
index 000000000000..207a61d60952
--- /dev/null
+++ b/changelog/24238.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+core/audit: Audit logging a Vault response will now use a 5 second context timeout, separate from the original request.
+```
\ No newline at end of file
diff --git a/vault/audit_broker.go b/vault/audit_broker.go
index 7fcce78e29f7..7ad214513e0f 100644
--- a/vault/audit_broker.go
+++ b/vault/audit_broker.go
@@ -10,6 +10,8 @@ import (
"sync"
"time"
+ "github.com/hashicorp/vault/helper/namespace"
+
"github.com/hashicorp/vault/internal/observability/event"
metrics "github.com/armon/go-metrics"
@@ -297,7 +299,22 @@ func (a *AuditBroker) LogResponse(ctx context.Context, in *logical.LogInput, hea
e.Data = in
- status, err := a.broker.Send(ctx, eventlogger.EventType(event.AuditType.String()), e)
+ // In cases where we are trying to audit the response, we detach
+ // ourselves from the original context (keeping only the namespace).
+ // This is so that we get a fair run at writing audit entries if Vault
+ // Took up a lot of time handling the request before audit (response)
+ // is triggered. Pipeline nodes may check for a cancelled context and
+ // refuse to process the nodes further.
+ ns, err := namespace.FromContext(ctx)
+ if err != nil {
+ retErr = multierror.Append(retErr, fmt.Errorf("namespace missing from context: %w", err))
+ return retErr.ErrorOrNil()
+ }
+
+ auditContext, auditCancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer auditCancel()
+ auditContext = namespace.ContextWithNamespace(auditContext, ns)
+ status, err := a.broker.Send(auditContext, eventlogger.EventType(event.AuditType.String()), e)
if err != nil {
retErr = multierror.Append(retErr, multierror.Append(err, status.Warnings...))
}
From 511ce92852eea274f0a72a8b718c3217de47dbcb Mon Sep 17 00:00:00 2001
From: Peter Wilson
Date: Fri, 24 Nov 2023 09:30:10 +0000
Subject: [PATCH 17/74] fix import formatting (#24248)
---
vault/audit_broker.go | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/vault/audit_broker.go b/vault/audit_broker.go
index 7ad214513e0f..342a4387008e 100644
--- a/vault/audit_broker.go
+++ b/vault/audit_broker.go
@@ -10,15 +10,13 @@ import (
"sync"
"time"
- "github.com/hashicorp/vault/helper/namespace"
-
- "github.com/hashicorp/vault/internal/observability/event"
-
metrics "github.com/armon/go-metrics"
"github.com/hashicorp/eventlogger"
log "github.com/hashicorp/go-hclog"
multierror "github.com/hashicorp/go-multierror"
"github.com/hashicorp/vault/audit"
+ "github.com/hashicorp/vault/helper/namespace"
+ "github.com/hashicorp/vault/internal/observability/event"
"github.com/hashicorp/vault/sdk/logical"
)
From 904c08e1e4ffc7bade5ed2f606cb3a1490ea515b Mon Sep 17 00:00:00 2001
From: Christopher Swenson
Date: Mon, 27 Nov 2023 09:11:01 -0800
Subject: [PATCH 18/74] Remove runtime patch for SHA1 support in X.509 certs
(#24243)
This code only executes when the Vault version is <1.11,
so is now dead code and can be removed safely.
---
builtin/credential/aws/pkcs7/sign.go | 6 ---
internal/go118_sha1_patch.go | 59 ----------------------------
main.go | 6 ---
3 files changed, 71 deletions(-)
delete mode 100644 internal/go118_sha1_patch.go
diff --git a/builtin/credential/aws/pkcs7/sign.go b/builtin/credential/aws/pkcs7/sign.go
index 72b99388548e..b64fcb11da47 100644
--- a/builtin/credential/aws/pkcs7/sign.go
+++ b/builtin/credential/aws/pkcs7/sign.go
@@ -12,14 +12,8 @@ import (
"fmt"
"math/big"
"time"
-
- "github.com/hashicorp/vault/internal"
)
-func init() {
- internal.PatchSha1()
-}
-
// SignedData is an opaque data structure for creating signed data payloads
type SignedData struct {
sd signedData
diff --git a/internal/go118_sha1_patch.go b/internal/go118_sha1_patch.go
deleted file mode 100644
index bce531889681..000000000000
--- a/internal/go118_sha1_patch.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) HashiCorp, Inc.
-// SPDX-License-Identifier: BUSL-1.1
-
-package internal
-
-import (
- "fmt"
- "os"
- "sync"
- _ "unsafe" // for go:linkname
-
- goversion "github.com/hashicorp/go-version"
- "github.com/hashicorp/vault/version"
-)
-
-const sha1PatchVersionsBefore = "1.12.0"
-
-var patchSha1 sync.Once
-
-//go:linkname debugAllowSHA1 crypto/x509.debugAllowSHA1
-var debugAllowSHA1 bool
-
-// PatchSha1 patches Go 1.18+ to allow certificates with signatures containing SHA-1 hashes to be allowed.
-// It is safe to call this function multiple times.
-// This is necessary to allow Vault 1.10 and 1.11 to work with Go 1.18+ without breaking backwards compatibility
-// with these certificates. See https://go.dev/doc/go1.18#sha1 and
-// https://developer.hashicorp.com/vault/docs/deprecation/faq#q-what-is-the-impact-of-removing-support-for-x-509-certificates-with-signatures-that-use-sha-1
-// for more details.
-// TODO: remove when Vault <=1.11 is no longer supported
-func PatchSha1() {
- patchSha1.Do(func() {
- // for Go 1.19.4 and later
- godebug := os.Getenv("GODEBUG")
- if godebug != "" {
- godebug += ","
- }
- godebug += "x509sha1=1"
- os.Setenv("GODEBUG", godebug)
-
- // for Go 1.19.3 and earlier, patch the variable
- patchBefore, err := goversion.NewSemver(sha1PatchVersionsBefore)
- if err != nil {
- panic(err)
- }
-
- patch := false
- v, err := goversion.NewSemver(version.GetVersion().Version)
- if err == nil {
- patch = v.LessThan(patchBefore)
- } else {
- fmt.Fprintf(os.Stderr, "Cannot parse version %s; going to apply SHA-1 deprecation patch workaround\n", version.GetVersion().Version)
- patch = true
- }
-
- if patch {
- debugAllowSHA1 = true
- }
- })
-}
diff --git a/main.go b/main.go
index a48e21b6942c..35d2f584ee96 100644
--- a/main.go
+++ b/main.go
@@ -7,14 +7,8 @@ import (
"os"
"github.com/hashicorp/vault/command"
- "github.com/hashicorp/vault/internal"
)
-func init() {
- // this is a good place to patch SHA-1 support back into x509
- internal.PatchSha1()
-}
-
func main() {
os.Exit(command.Run(os.Args[1:]))
}
From 0ca6135f6895bbaeef27c685b5217f4a3c5cfe28 Mon Sep 17 00:00:00 2001
From: Angel Garbarino
Date: Mon, 27 Nov 2023 10:21:35 -0700
Subject: [PATCH 19/74] Glimmerize Splash Page (#24104)
* make splash page view only block content
* change invocation of component
* address some of the pr comments
* add test coverage
* remove conditional because of issue with it always showing
* solve for mfa errors
* move altcontent outside
---
ui/app/components/splash-page.hbs | 21 ++
ui/app/components/splash-page.js | 34 ---
.../components/splash-page/splash-content.js | 10 -
.../components/splash-page/splash-footer.js | 10 -
.../components/splash-page/splash-header.js | 10 -
ui/app/templates/components/splash-page.hbs | 26 --
ui/app/templates/vault/cluster/auth.hbs | 240 +++++++++---------
ui/app/templates/vault/cluster/init.hbs | 38 ++-
ui/app/templates/vault/cluster/mfa-setup.hbs | 10 +-
ui/app/templates/vault/cluster/unseal.hbs | 16 +-
.../components/splash-page-test.js | 37 +++
11 files changed, 211 insertions(+), 241 deletions(-)
create mode 100644 ui/app/components/splash-page.hbs
delete mode 100644 ui/app/components/splash-page.js
delete mode 100644 ui/app/components/splash-page/splash-content.js
delete mode 100644 ui/app/components/splash-page/splash-footer.js
delete mode 100644 ui/app/components/splash-page/splash-header.js
delete mode 100644 ui/app/templates/components/splash-page.hbs
create mode 100644 ui/tests/integration/components/splash-page-test.js
diff --git a/ui/app/components/splash-page.hbs b/ui/app/components/splash-page.hbs
new file mode 100644
index 000000000000..187687ac4071
--- /dev/null
+++ b/ui/app/components/splash-page.hbs
@@ -0,0 +1,21 @@
+{{!
+ Copyright (c) HashiCorp, Inc.
+ SPDX-License-Identifier: BUSL-1.1
+~}}
+
+
+
+
+
+
+
+ {{yield to="content"}}
+
+ {{yield to="footer"}}
+
+
+
\ No newline at end of file
diff --git a/ui/app/components/splash-page.js b/ui/app/components/splash-page.js
deleted file mode 100644
index ec1634e6d521..000000000000
--- a/ui/app/components/splash-page.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: BUSL-1.1
- */
-
-/**
- * @module SplashPage
- * SplashPage component is used as a landing page with a box horizontally and center aligned on the page. It's used as the login landing page.
- *
- *
- * @example
- * ```js
- *
- * content here
- *
-
-
-
-
-
- {{yield (hash content=(component "splash-page/splash-content"))}}
-
- {{yield (hash footer=(component "splash-page/splash-content"))}}
-
-
-
-{{/if}}
\ No newline at end of file
diff --git a/ui/app/templates/vault/cluster/auth.hbs b/ui/app/templates/vault/cluster/auth.hbs
index 4d75b44acc01..13d291f2a24f 100644
--- a/ui/app/templates/vault/cluster/auth.hbs
+++ b/ui/app/templates/vault/cluster/auth.hbs
@@ -3,126 +3,130 @@
SPDX-License-Identifier: BUSL-1.1
~}}
-
-
-
-
-
-
-
-
-
- {{#if this.oidcProvider}}
-
-
-
- {{else}}
-
-
-
+{{#if this.mfaErrors}}
+
+
+
+
+
+{{else}}
+
+ <:header>
+ {{#if this.oidcProvider}}
+
+
-
-
- {{#if this.mfaAuthData}}
-
- {{else if this.waitingForOktaNumberChallenge}}
-
- {{/if}}
-
- {{if (or this.mfaAuthData this.waitingForOktaNumberChallenge) "Authenticate" "Sign in to Vault"}}
-
-
- {{/if}}
-
- {{#unless this.mfaAuthData}}
- {{#if (has-feature "Namespaces")}}
-
-
-
-
- Namespace
-
- {{#if this.managedNamespaceRoot}}
-
-
/{{this.managedNamespaceRoot}}
+ {{else}}
+
+
+ {{#if this.mfaAuthData}}
+
+ {{else if this.waitingForOktaNumberChallenge}}
+
+ {{/if}}
+
+ {{if (or this.mfaAuthData this.waitingForOktaNumberChallenge) "Authenticate" "Sign in to Vault"}}
+
+
+ {{/if}}
+
+
+ <:subHeader>
+ {{#if (has-feature "Namespaces")}}
+ {{#unless this.mfaAuthData}}
+
+
+
+ Namespace
- {{/if}}
-
-
-
-
+ {{#if this.managedNamespaceRoot}}
+
+ /{{this.managedNamespaceRoot}}
+
+ {{/if}}
+
-
-
-
- {{/if}}
- {{/unless}}
-
- {{#if this.mfaAuthData}}
-
- {{else}}
-
- {{/if}}
-
-
-
-
- {{#if this.oidcProvider}}
- Once you log in, you will be redirected back to your application. If you require login credentials, contact your
- administrator.
- {{else}}
- Contact your administrator for login credentials
- {{/if}}
-
-
-
-
\ No newline at end of file
+
+ {{/unless}}
+ {{/if}}
+
+
+ <:content>
+ {{#if this.mfaAuthData}}
+
+ {{else}}
+
+ {{/if}}
+
+
+ <:footer>
+
+
+ {{#if this.oidcProvider}}
+ Once you log in, you will be redirected back to your application. If you require login credentials, contact your
+ administrator.
+ {{else}}
+ Contact your administrator for login credentials.
+ {{/if}}
+
+
+
+
+{{/if}}
\ No newline at end of file
diff --git a/ui/app/templates/vault/cluster/init.hbs b/ui/app/templates/vault/cluster/init.hbs
index 70d44deb8e90..172f8c0668de 100644
--- a/ui/app/templates/vault/cluster/init.hbs
+++ b/ui/app/templates/vault/cluster/init.hbs
@@ -3,18 +3,13 @@
SPDX-License-Identifier: BUSL-1.1
~}}
-
- {{#if (and this.model.usingRaft (not this.prefersInit))}}
-
+
+ <:header>
+ {{#if (and this.model.usingRaft (not this.prefersInit))}}
Raft Storage
-
-
-
-
- {{else if this.keyData}}
-
+ {{else if this.keyData}}
{{#let (or this.keyData.recovery_keys this.keyData.keys) as |keyArray|}}
Vault has been initialized!
@@ -26,8 +21,16 @@
{{/if}}
{{/let}}
-
-
+ {{else}}
+
+ Let's set up the initial set of root keys that you will need in case of an emergency.
+
+ {{/if}}
+
+ <:content>
+ {{#if (and this.model.usingRaft (not this.prefersInit))}}
+
+ {{else if this.keyData}}
-
- {{else}}
-
-
- Let's set up the initial set of root keys that you’ll need in case of an emergency
-
-
-
+ {{else}}
-
- {{/if}}
+ {{/if}}
+
\ No newline at end of file
diff --git a/ui/app/templates/vault/cluster/mfa-setup.hbs b/ui/app/templates/vault/cluster/mfa-setup.hbs
index b4d3419f356f..3c203179fe37 100644
--- a/ui/app/templates/vault/cluster/mfa-setup.hbs
+++ b/ui/app/templates/vault/cluster/mfa-setup.hbs
@@ -3,11 +3,11 @@
SPDX-License-Identifier: BUSL-1.1
~}}
-
-
+
+ <:header>
MFA setup
-
-
+
+ <:content>
-
+
\ No newline at end of file
diff --git a/ui/app/templates/vault/cluster/unseal.hbs b/ui/app/templates/vault/cluster/unseal.hbs
index ed9a02983d4b..ebaca1beae08 100644
--- a/ui/app/templates/vault/cluster/unseal.hbs
+++ b/ui/app/templates/vault/cluster/unseal.hbs
@@ -23,13 +23,14 @@
{{else}}
-
-
+
+ <:header>
Unseal Vault
-
-
+
+
+ <:content>
{{capitalize this.model.name}}
@@ -57,8 +58,9 @@
/>
{{/if}}
-
-
+
+
+ <:footer>
-
+
{{/if}}
\ No newline at end of file
diff --git a/ui/tests/integration/components/splash-page-test.js b/ui/tests/integration/components/splash-page-test.js
new file mode 100644
index 000000000000..82ddef0c9e93
--- /dev/null
+++ b/ui/tests/integration/components/splash-page-test.js
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | splash-page', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it should render', async function (assert) {
+ assert.expect(4);
+ await render(hbs`
+ <:header>
+ Header here
+
+ <:subHeader>
+ sub header
+
+ <:content>
+ content
+
+ <:footer>
+ footer
+
+
+
+ `);
+ assert.dom('[data-test-splash-page-header]').includesText('Header here', 'Header renders');
+ assert.dom('[data-test-splash-page-sub-header]').includesText('sub header', 'SubHeader renders');
+ assert.dom('[data-test-splash-page-content]').includesText('content', 'Content renders');
+ assert.dom('[data-test-footer]').includesText('footer', 'Footer renders');
+ });
+});
From e69b0b2bcf88c7498565aaf6ca27384bc5b08758 Mon Sep 17 00:00:00 2001
From: Raymond Ho
Date: Mon, 27 Nov 2023 09:46:20 -0800
Subject: [PATCH 20/74] add custom permissions for azurekv (#23298)
---
website/content/docs/sync/azurekv.mdx | 44 +++++++++++++++++++++++++--
1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/website/content/docs/sync/azurekv.mdx b/website/content/docs/sync/azurekv.mdx
index 8266420d0143..d86ec901388c 100644
--- a/website/content/docs/sync/azurekv.mdx
+++ b/website/content/docs/sync/azurekv.mdx
@@ -27,8 +27,9 @@ Prerequisites:
1. Once the service principal is created, the next step is to
[grant the service principal](https://learn.microsoft.com/en-us/azure/key-vault/general/rbac-guide?tabs=azure-cli)
- access to Azure Key Vault. We recommend using the "Key Vault Secrets Officer" built-in role,
- which gives sufficient access to manage secrets.
+ access to Azure Key Vault. To quickly get started, we recommend using the "Key Vault Secrets Officer" built-in role,
+ which gives sufficient access to manage secrets. For more information, see the [Permissions](#permissions) section.
+
1. Configure a sync destination with the service principal credentials and Key Vault URI created in the previous steps.
@@ -127,6 +128,45 @@ Moving forward, any modification on the Vault secret will be propagated in near
counterpart. Creating a new secret version in Vault will create a new version in Azure Key Vault. Deleting the secret
or the association in Vault will delete the secret in your Azure Key Vault as well.
+
+## Permissions
+
+For a more minimal set of permissions, you can create a
+[custom role](https://learn.microsoft.com/en-us/azure/role-based-access-control/custom-roles#steps-to-create-a-custom-role)
+using the following JSON role definition. Be sure to replace the subscription id placeholder.
+
+```json
+{
+ "properties": {
+ "roleName": "Key Vault Secrets Reader Writer",
+ "description": "Custom role for reading and updating Azure Key Vault secrets.",
+ "permissions": [
+ {
+ "actions": [
+ "Microsoft.KeyVault/vaults/secrets/read",
+ "Microsoft.KeyVault/vaults/secrets/write"
+ ],
+ "notActions": [],
+ "dataActions": [
+ "Microsoft.KeyVault/vaults/secrets/delete",
+ "Microsoft.KeyVault/vaults/secrets/backup/action",
+ "Microsoft.KeyVault/vaults/secrets/purge/action",
+ "Microsoft.KeyVault/vaults/secrets/recover/action",
+ "Microsoft.KeyVault/vaults/secrets/restore/action",
+ "Microsoft.KeyVault/vaults/secrets/readMetadata/action",
+ "Microsoft.KeyVault/vaults/secrets/getSecret/action",
+ "Microsoft.KeyVault/vaults/secrets/setSecret/action"
+ ],
+ "notDataActions": []
+ }
+ ],
+ "assignableScopes": [
+ "/subscriptions/{subscriptionId}/"
+ ]
+ }
+}
+```
+
## API
Please see the [secrets sync API](/vault/api-docs/system/secrets-sync) for more details.
From 9b7d06839f9c18de00f2fc2958a1fb6f210c2f2e Mon Sep 17 00:00:00 2001
From: kpcraig <3031348+kpcraig@users.noreply.github.com>
Date: Mon, 27 Nov 2023 15:48:16 -0500
Subject: [PATCH 21/74] Add a /config/rotate-root path to the ldap auth backend
(#24099)
---
builtin/credential/ldap/backend.go | 9 +-
builtin/credential/ldap/path_config.go | 19 +++
.../ldap/path_config_rotate_root.go | 115 ++++++++++++++++++
.../ldap/path_config_rotate_root_test.go | 66 ++++++++++
changelog/24099.txt | 3 +
5 files changed, 210 insertions(+), 2 deletions(-)
create mode 100644 builtin/credential/ldap/path_config_rotate_root.go
create mode 100644 builtin/credential/ldap/path_config_rotate_root_test.go
create mode 100644 changelog/24099.txt
diff --git a/builtin/credential/ldap/backend.go b/builtin/credential/ldap/backend.go
index d938a4fea9f0..3f203fb13bb0 100644
--- a/builtin/credential/ldap/backend.go
+++ b/builtin/credential/ldap/backend.go
@@ -7,6 +7,7 @@ import (
"context"
"fmt"
"strings"
+ "sync"
"github.com/hashicorp/cap/ldap"
"github.com/hashicorp/go-secure-stdlib/strutil"
@@ -17,8 +18,9 @@ import (
)
const (
- operationPrefixLDAP = "ldap"
- errUserBindFailed = "ldap operation failed: failed to bind as user"
+ operationPrefixLDAP = "ldap"
+ errUserBindFailed = "ldap operation failed: failed to bind as user"
+ defaultPasswordLength = 64 // length to use for configured root password on rotations by default
)
func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
@@ -51,6 +53,7 @@ func Backend() *backend {
pathUsers(&b),
pathUsersList(&b),
pathLogin(&b),
+ pathConfigRotateRoot(&b),
},
AuthRenew: b.pathLoginRenew,
@@ -62,6 +65,8 @@ func Backend() *backend {
type backend struct {
*framework.Backend
+
+ mu sync.RWMutex
}
func (b *backend) Login(ctx context.Context, req *logical.Request, username string, password string, usernameAsAlias bool) (string, []string, *logical.Response, []string, error) {
diff --git a/builtin/credential/ldap/path_config.go b/builtin/credential/ldap/path_config.go
index f6e7a152dfa4..e24d04b295c7 100644
--- a/builtin/credential/ldap/path_config.go
+++ b/builtin/credential/ldap/path_config.go
@@ -48,6 +48,12 @@ func pathConfig(b *backend) *framework.Path {
tokenutil.AddTokenFields(p.Fields)
p.Fields["token_policies"].Description += ". This will apply to all tokens generated by this auth method, in addition to any configured for specific users/groups."
+
+ p.Fields["password_policy"] = &framework.FieldSchema{
+ Type: framework.TypeString,
+ Description: "Password policy to use to rotate the root password",
+ }
+
return p
}
@@ -118,6 +124,9 @@ func (b *backend) Config(ctx context.Context, req *logical.Request) (*ldapConfig
}
func (b *backend) pathConfigRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
+ b.mu.RLock()
+ defer b.mu.RUnlock()
+
cfg, err := b.Config(ctx, req)
if err != nil {
return nil, err
@@ -128,6 +137,7 @@ func (b *backend) pathConfigRead(ctx context.Context, req *logical.Request, d *f
data := cfg.PasswordlessMap()
cfg.PopulateTokenData(data)
+ data["password_policy"] = cfg.PasswordPolicy
resp := &logical.Response{
Data: data,
@@ -164,6 +174,9 @@ func (b *backend) checkConfigUserFilter(cfg *ldapConfigEntry) []string {
}
func (b *backend) pathConfigWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
+ b.mu.Lock()
+ defer b.mu.Unlock()
+
cfg, err := b.Config(ctx, req)
if err != nil {
return nil, err
@@ -194,6 +207,10 @@ func (b *backend) pathConfigWrite(ctx context.Context, req *logical.Request, d *
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
}
+ if passwordPolicy, ok := d.GetOk("password_policy"); ok {
+ cfg.PasswordPolicy = passwordPolicy.(string)
+ }
+
entry, err := logical.StorageEntryJSON("config", cfg)
if err != nil {
return nil, err
@@ -234,6 +251,8 @@ func (b *backend) getConfigFieldData() (*framework.FieldData, error) {
type ldapConfigEntry struct {
tokenutil.TokenParams
*ldaputil.ConfigEntry
+
+ PasswordPolicy string `json:"password_policy"`
}
const pathConfigHelpSyn = `
diff --git a/builtin/credential/ldap/path_config_rotate_root.go b/builtin/credential/ldap/path_config_rotate_root.go
new file mode 100644
index 000000000000..1aa008f4ddc3
--- /dev/null
+++ b/builtin/credential/ldap/path_config_rotate_root.go
@@ -0,0 +1,115 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: BUSL-2.0
+
+package ldap
+
+import (
+ "context"
+
+ "github.com/go-ldap/ldap/v3"
+
+ "github.com/hashicorp/vault/sdk/helper/base62"
+ "github.com/hashicorp/vault/sdk/helper/ldaputil"
+
+ "github.com/hashicorp/vault/sdk/framework"
+ "github.com/hashicorp/vault/sdk/logical"
+)
+
+func pathConfigRotateRoot(b *backend) *framework.Path {
+ return &framework.Path{
+ Pattern: "config/rotate-root",
+
+ DisplayAttrs: &framework.DisplayAttributes{
+ OperationPrefix: operationPrefixLDAP,
+ OperationVerb: "rotate",
+ OperationSuffix: "root-credentials",
+ },
+
+ Operations: map[logical.Operation]framework.OperationHandler{
+ logical.UpdateOperation: &framework.PathOperation{
+ Callback: b.pathConfigRotateRootUpdate,
+ ForwardPerformanceSecondary: true,
+ ForwardPerformanceStandby: true,
+ },
+ },
+
+ HelpSynopsis: pathConfigRotateRootHelpSyn,
+ HelpDescription: pathConfigRotateRootHelpDesc,
+ }
+}
+
+func (b *backend) pathConfigRotateRootUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
+ // lock the backend's state - really just the config state - for mutating
+ b.mu.Lock()
+ defer b.mu.Unlock()
+
+ cfg, err := b.Config(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ if cfg == nil {
+ return logical.ErrorResponse("attempted to rotate root on an undefined config"), nil
+ }
+
+ u, p := cfg.BindDN, cfg.BindPassword
+ if u == "" || p == "" {
+ return logical.ErrorResponse("auth is not using authenticated search, no root to rotate"), nil
+ }
+
+ // grab our ldap client
+ client := ldaputil.Client{
+ Logger: b.Logger(),
+ LDAP: ldaputil.NewLDAP(),
+ }
+
+ conn, err := client.DialLDAP(cfg.ConfigEntry)
+ if err != nil {
+ return nil, err
+ }
+
+ err = conn.Bind(u, p)
+ if err != nil {
+ return nil, err
+ }
+
+ lreq := &ldap.ModifyRequest{
+ DN: cfg.BindDN,
+ }
+
+ var newPassword string
+ if cfg.PasswordPolicy != "" {
+ newPassword, err = b.System().GeneratePasswordFromPolicy(ctx, cfg.PasswordPolicy)
+ } else {
+ newPassword, err = base62.Random(defaultPasswordLength)
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ lreq.Replace("userPassword", []string{newPassword})
+
+ err = conn.Modify(lreq)
+ if err != nil {
+ return nil, err
+ }
+ // update config with new password
+ cfg.BindPassword = newPassword
+ entry, err := logical.StorageEntryJSON("config", cfg)
+ if err != nil {
+ return nil, err
+ }
+ if err := req.Storage.Put(ctx, entry); err != nil {
+ // we might have to roll-back the password here?
+ return nil, err
+ }
+
+ return nil, nil
+}
+
+const pathConfigRotateRootHelpSyn = `
+Request to rotate the LDAP credentials used by Vault
+`
+
+const pathConfigRotateRootHelpDesc = `
+This path attempts to rotate the LDAP bindpass used by Vault for this mount.
+`
diff --git a/builtin/credential/ldap/path_config_rotate_root_test.go b/builtin/credential/ldap/path_config_rotate_root_test.go
new file mode 100644
index 000000000000..65073472ca00
--- /dev/null
+++ b/builtin/credential/ldap/path_config_rotate_root_test.go
@@ -0,0 +1,66 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: BUSL-2.0
+
+package ldap
+
+import (
+ "context"
+ "os"
+ "testing"
+
+ "github.com/hashicorp/vault/helper/testhelpers/ldap"
+ logicaltest "github.com/hashicorp/vault/helper/testhelpers/logical"
+ "github.com/hashicorp/vault/sdk/logical"
+)
+
+// This test relies on a docker ldap server with a suitable person object (cn=admin,dc=planetexpress,dc=com)
+// with bindpassword "admin". `PrepareTestContainer` does this for us. - see the backend_test for more details
+func TestRotateRoot(t *testing.T) {
+ if os.Getenv(logicaltest.TestEnvVar) == "" {
+ t.Skip("skipping rotate root tests because VAULT_ACC is unset")
+ }
+ ctx := context.Background()
+
+ b, store := createBackendWithStorage(t)
+ cleanup, cfg := ldap.PrepareTestContainer(t, "latest")
+ defer cleanup()
+ // set up auth config
+ req := &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "config",
+ Storage: store,
+ Data: map[string]interface{}{
+ "url": cfg.Url,
+ "binddn": cfg.BindDN,
+ "bindpass": cfg.BindPassword,
+ "userdn": cfg.UserDN,
+ },
+ }
+
+ resp, err := b.HandleRequest(ctx, req)
+ if err != nil {
+ t.Fatalf("failed to initialize ldap auth config: %s", err)
+ }
+ if resp != nil && resp.IsError() {
+ t.Fatalf("failed to initialize ldap auth config: %s", resp.Data["error"])
+ }
+
+ req = &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "config/rotate-root",
+ Storage: store,
+ }
+
+ _, err = b.HandleRequest(ctx, req)
+ if err != nil {
+ t.Fatalf("failed to rotate password: %s", err)
+ }
+
+ newCFG, err := b.Config(ctx, req)
+ if newCFG.BindDN != cfg.BindDN {
+ t.Fatalf("a value in config that should have stayed the same changed: %s", cfg.BindDN)
+ }
+ if newCFG.BindPassword == cfg.BindPassword {
+ t.Fatalf("the password should have changed, but it didn't")
+ }
+}
diff --git a/changelog/24099.txt b/changelog/24099.txt
new file mode 100644
index 000000000000..bc33a184f988
--- /dev/null
+++ b/changelog/24099.txt
@@ -0,0 +1,3 @@
+```release-note:feature
+**Rotate Root for LDAP auth**: Rotate root operations are now supported for the LDAP auth engine.
+```
From c329ed8d3b02b92dfded30065317c82648d3cae3 Mon Sep 17 00:00:00 2001
From: Steven Clark
Date: Mon, 27 Nov 2023 15:50:41 -0500
Subject: [PATCH 22/74] api/leader: fix deadlock when namespace is set on
leader calls (#24256)
* api/leader: fix deadlock when namespace is set on leader calls
* Add cl
---
changelog/24256.txt | 4 ++++
vault/ha.go | 23 ++++++++++++++++-------
vault/logical_system.go | 17 ++++++++++++-----
vault/raft.go | 3 +++
4 files changed, 35 insertions(+), 12 deletions(-)
create mode 100644 changelog/24256.txt
diff --git a/changelog/24256.txt b/changelog/24256.txt
new file mode 100644
index 000000000000..74124710b8a8
--- /dev/null
+++ b/changelog/24256.txt
@@ -0,0 +1,4 @@
+```release-note:bug
+api: Fix deadlock on calls to sys/leader with a namespace configured
+on the request.
+```
diff --git a/vault/ha.go b/vault/ha.go
index 8ef86b0fefcb..15d6f180f7cb 100644
--- a/vault/ha.go
+++ b/vault/ha.go
@@ -150,30 +150,41 @@ func (c *Core) Leader() (isLeader bool, leaderAddr, clusterAddr string, err erro
if c.Sealed() {
return false, "", "", consts.ErrSealed
}
-
c.stateLock.RLock()
+ defer c.stateLock.RUnlock()
+
+ return c.LeaderLocked()
+}
+
+func (c *Core) LeaderLocked() (isLeader bool, leaderAddr, clusterAddr string, err error) {
+ // Check if HA enabled. We don't need the lock for this check as it's set
+ // on startup and never modified
+ if c.ha == nil {
+ return false, "", "", ErrHANotEnabled
+ }
+
+ // Check if sealed
+ if c.Sealed() {
+ return false, "", "", consts.ErrSealed
+ }
// Check if we are the leader
if !c.standby {
- c.stateLock.RUnlock()
return true, c.redirectAddr, c.ClusterAddr(), nil
}
// Initialize a lock
lock, err := c.ha.LockWith(CoreLockPath, "read")
if err != nil {
- c.stateLock.RUnlock()
return false, "", "", err
}
// Read the value
held, leaderUUID, err := lock.Value()
if err != nil {
- c.stateLock.RUnlock()
return false, "", "", err
}
if !held {
- c.stateLock.RUnlock()
return false, "", "", nil
}
@@ -188,13 +199,11 @@ func (c *Core) Leader() (isLeader bool, leaderAddr, clusterAddr string, err erro
// If the leader hasn't changed, return the cached value; nothing changes
// mid-leadership, and the barrier caches anyways
if leaderUUID == localLeaderUUID && localRedirectAddr != "" {
- c.stateLock.RUnlock()
return false, localRedirectAddr, localClusterAddr, nil
}
c.logger.Trace("found new active node information, refreshing")
- defer c.stateLock.RUnlock()
c.leaderParamsLock.Lock()
defer c.leaderParamsLock.Unlock()
diff --git a/vault/logical_system.go b/vault/logical_system.go
index 564e0e971593..30ffdf0e3e47 100644
--- a/vault/logical_system.go
+++ b/vault/logical_system.go
@@ -5150,8 +5150,15 @@ type LeaderResponse struct {
}
func (core *Core) GetLeaderStatus() (*LeaderResponse, error) {
+ core.stateLock.RLock()
+ defer core.stateLock.RUnlock()
+
+ return core.GetLeaderStatusLocked()
+}
+
+func (core *Core) GetLeaderStatusLocked() (*LeaderResponse, error) {
haEnabled := true
- isLeader, address, clusterAddr, err := core.Leader()
+ isLeader, address, clusterAddr, err := core.LeaderLocked()
if errwrap.Contains(err, ErrHANotEnabled.Error()) {
haEnabled = false
err = nil
@@ -5165,10 +5172,10 @@ func (core *Core) GetLeaderStatus() (*LeaderResponse, error) {
IsSelf: isLeader,
LeaderAddress: address,
LeaderClusterAddress: clusterAddr,
- PerfStandby: core.PerfStandby(),
+ PerfStandby: core.perfStandby,
}
if isLeader {
- resp.ActiveTime = core.ActiveTime()
+ resp.ActiveTime = core.activeTime
}
if resp.PerfStandby {
resp.PerfStandbyLastRemoteWAL = core.EntLastRemoteWAL()
@@ -5176,7 +5183,7 @@ func (core *Core) GetLeaderStatus() (*LeaderResponse, error) {
resp.LastWAL = core.EntLastWAL()
}
- resp.RaftCommittedIndex, resp.RaftAppliedIndex = core.GetRaftIndexes()
+ resp.RaftCommittedIndex, resp.RaftAppliedIndex = core.GetRaftIndexesLocked()
return resp, nil
}
@@ -5200,7 +5207,7 @@ func (b *SystemBackend) handleSealStatus(ctx context.Context, req *logical.Reque
}
func (b *SystemBackend) handleLeaderStatus(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
- status, err := b.Core.GetLeaderStatus()
+ status, err := b.Core.GetLeaderStatusLocked()
if err != nil {
return nil, err
}
diff --git a/vault/raft.go b/vault/raft.go
index 9e4df481d9ce..b2b26496d12f 100644
--- a/vault/raft.go
+++ b/vault/raft.go
@@ -70,7 +70,10 @@ func (c *Core) GetRaftNodeID() string {
func (c *Core) GetRaftIndexes() (committed uint64, applied uint64) {
c.stateLock.RLock()
defer c.stateLock.RUnlock()
+ return c.GetRaftIndexesLocked()
+}
+func (c *Core) GetRaftIndexesLocked() (committed uint64, applied uint64) {
raftStorage, ok := c.underlyingPhysical.(*raft.RaftBackend)
if !ok {
return 0, 0
From 5781891292c6beb4cd07fbf565469ac04fa4d86a Mon Sep 17 00:00:00 2001
From: Steven Clark
Date: Mon, 27 Nov 2023 15:50:54 -0500
Subject: [PATCH 23/74] PKI: Address some errors that were not wrapped properly
(#24118)
---
builtin/logical/pki/acme_challenges.go | 2 +-
builtin/logical/pki/path_resign_crls.go | 4 ++--
builtin/logical/pki/test_helpers.go | 24 ++++++++++++++++++++++++
3 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/builtin/logical/pki/acme_challenges.go b/builtin/logical/pki/acme_challenges.go
index 290c8ec78c7f..85c051c86e0e 100644
--- a/builtin/logical/pki/acme_challenges.go
+++ b/builtin/logical/pki/acme_challenges.go
@@ -311,7 +311,7 @@ func ValidateTLSALPN01Challenge(domain string, token string, thumbprint string,
// checks for the parent certificate having the IsCA basic constraint set.
err := cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature)
if err != nil {
- return fmt.Errorf("server under test returned a non-self-signed certificate: %v", err)
+ return fmt.Errorf("server under test returned a non-self-signed certificate: %w", err)
}
if !bytes.Equal(cert.RawSubject, cert.RawIssuer) {
diff --git a/builtin/logical/pki/path_resign_crls.go b/builtin/logical/pki/path_resign_crls.go
index 6113010dc8c5..23e1a0b0ed43 100644
--- a/builtin/logical/pki/path_resign_crls.go
+++ b/builtin/logical/pki/path_resign_crls.go
@@ -252,7 +252,7 @@ func (b *backend) pathUpdateResignCrlsHandler(ctx context.Context, request *logi
if deltaCrlBaseNumber > -1 {
ext, err := certutil.CreateDeltaCRLIndicatorExt(int64(deltaCrlBaseNumber))
if err != nil {
- return nil, fmt.Errorf("could not create crl delta indicator extension: %v", err)
+ return nil, fmt.Errorf("could not create crl delta indicator extension: %w", err)
}
template.ExtraExtensions = []pkix.Extension{ext}
}
@@ -325,7 +325,7 @@ func (b *backend) pathUpdateSignRevocationListHandler(ctx context.Context, reque
if deltaCrlBaseNumber > -1 {
ext, err := certutil.CreateDeltaCRLIndicatorExt(int64(deltaCrlBaseNumber))
if err != nil {
- return nil, fmt.Errorf("could not create crl delta indicator extension: %v", err)
+ return nil, fmt.Errorf("could not create crl delta indicator extension: %w", err)
}
crlExtensions = append(crlExtensions, ext)
}
diff --git a/builtin/logical/pki/test_helpers.go b/builtin/logical/pki/test_helpers.go
index 1cdc98795e71..c80856b661c5 100644
--- a/builtin/logical/pki/test_helpers.go
+++ b/builtin/logical/pki/test_helpers.go
@@ -436,3 +436,27 @@ func performOcspPost(t *testing.T, cert *x509.Certificate, issuerCert *x509.Cert
require.NoError(t, err, "parsing ocsp get response")
return ocspResp
}
+
+func requireCertMissingFromStorage(t *testing.T, client *api.Client, cert *x509.Certificate) {
+ serial := serialFromCert(cert)
+ requireSerialMissingFromStorage(t, client, serial)
+}
+
+func requireSerialMissingFromStorage(t *testing.T, client *api.Client, serial string) {
+ resp, err := client.Logical().ReadWithContext(context.Background(), "pki/cert/"+serial)
+ require.NoErrorf(t, err, "failed reading certificate with serial %s", serial)
+ require.Nilf(t, resp, "expected a nil response looking up serial %s got: %v", serial, resp)
+}
+
+func requireCertInStorage(t *testing.T, client *api.Client, cert *x509.Certificate) {
+ serial := serialFromCert(cert)
+ requireSerialInStorage(t, client, serial)
+}
+
+func requireSerialInStorage(t *testing.T, client *api.Client, serial string) {
+ resp, err := client.Logical().ReadWithContext(context.Background(), "pki/cert/"+serial)
+ require.NoErrorf(t, err, "failed reading certificate with serial %s", serial)
+ require.NotNilf(t, resp, "reading certificate returned a nil response for serial: %s", serial)
+ require.NotNilf(t, resp.Data, "reading certificate returned a nil data response for serial: %s", serial)
+ require.NotEmpty(t, resp.Data["certificate"], "certificate field was empty for serial: %s", serial)
+}
From 83a6ffcff6d1190c7c6432c43431bc33122b2e5b Mon Sep 17 00:00:00 2001
From: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
Date: Mon, 27 Nov 2023 15:51:46 -0600
Subject: [PATCH 24/74] UI: Replace instances of with
(#24257)
* Remove and replace InfoTable on replication-secondary-card
* Raft storage table update
* Known secondaries table replace
* remove vlt-table class and styles
* Fix tests
---
ui/app/styles/components/vlt-table.scss | 63 --------
ui/app/styles/core.scss | 1 -
.../components/raft-storage-overview.hbs | 145 +++++++-----------
.../core/addon/components/confirm-action.hbs | 1 +
ui/lib/core/addon/components/info-table.hbs | 28 ----
ui/lib/core/addon/components/info-table.js | 29 ----
.../components/replication-secondary-card.hbs | 36 +++--
ui/lib/core/app/components/info-table.js | 6 -
.../components/known-secondaries-card.hbs | 10 +-
.../components/known-secondaries-table.hbs | 84 ++++------
ui/tests/acceptance/raft-storage-test.js | 2 +-
.../components/confirm-action-test.js | 6 +-
.../integration/components/info-table-test.js | 42 -----
.../components/known-secondaries-card-test.js | 4 +-
.../known-secondaries-table-test.js | 48 +++---
.../replication-secondary-card-test.js | 8 +-
16 files changed, 155 insertions(+), 358 deletions(-)
delete mode 100644 ui/app/styles/components/vlt-table.scss
delete mode 100644 ui/lib/core/addon/components/info-table.hbs
delete mode 100644 ui/lib/core/addon/components/info-table.js
delete mode 100644 ui/lib/core/app/components/info-table.js
delete mode 100644 ui/tests/integration/components/info-table-test.js
diff --git a/ui/app/styles/components/vlt-table.scss b/ui/app/styles/components/vlt-table.scss
deleted file mode 100644
index 1d397c0db77c..000000000000
--- a/ui/app/styles/components/vlt-table.scss
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: BUSL-1.1
- */
-
-.vlt-table {
- .is-collapsed {
- visibility: collapse;
- height: 0;
- }
-
- &.sticky-header {
- thead th {
- position: sticky;
- background: #fff;
- box-shadow: 0 1px 0px 0px rgba($grey-dark, 0.3);
- top: 0;
- }
- }
-
- table {
- border-collapse: collapse;
- border-spacing: 0;
- }
-
- th,
- td {
- padding: $spacing-12;
- }
-
- th {
- color: $grey-dark;
- font-weight: 500;
- font-size: $size-8;
- text-align: left;
- vertical-align: top;
- }
-
- tbody th {
- font-size: $size-7;
- }
-
- tr {
- border-bottom: 1px solid $grey-light;
- }
-
- td {
- color: $grey-darkest;
- }
-
- td.middle {
- vertical-align: middle;
- }
-
- td.no-padding {
- padding: 0;
- }
-
- code {
- font-size: $size-7;
- color: $black;
- }
-}
diff --git a/ui/app/styles/core.scss b/ui/app/styles/core.scss
index eefc125be3cb..1c8dcc675d65 100644
--- a/ui/app/styles/core.scss
+++ b/ui/app/styles/core.scss
@@ -113,4 +113,3 @@
@import './components/unseal-warning';
// @import './components/ui-wizard'; // remove, see PR https://github.com/hashicorp/vault/pull/19220
@import './components/vault-loading';
-@import './components/vlt-table';
diff --git a/ui/app/templates/components/raft-storage-overview.hbs b/ui/app/templates/components/raft-storage-overview.hbs
index 006566b775e8..7c4e00100fc3 100644
--- a/ui/app/templates/components/raft-storage-overview.hbs
+++ b/ui/app/templates/components/raft-storage-overview.hbs
@@ -3,98 +3,67 @@
SPDX-License-Identifier: BUSL-1.1
~}}
-
-
-
- Raft Storage
-
-
-
-
-
-
-
- Snapshots
-
-
-
-
-
-
-
-
+
+ Raft Storage
+
+
+
+ {{#if this.useServiceWorker}}
+
+ {{else}}
+
+ {{/if}}
+
+
+
+
-
- Raft servers
-
-
- Address
- Voter
-
-
-
-
+
+ <:head as |H|>
+
+ Address
+ Leader
+ Voter
+ Actions
+
+
+ <:body as |B|>
{{#each @model as |server|}}
-
-
- {{server.address}}
- {{#if server.leader}}
- Leader
+
+ {{server.address}}
+ {{#if server.leader}}
+
+ {{else}}
+
{{/if}}
-
-
-
+
+
{{#if server.voter}}
-
+
{{else}}
-
+
{{/if}}
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
{{/each}}
-
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/ui/lib/core/addon/components/confirm-action.hbs b/ui/lib/core/addon/components/confirm-action.hbs
index 3e5cd5021a0a..2c22eedd8ea8 100644
--- a/ui/lib/core/addon/components/confirm-action.hbs
+++ b/ui/lib/core/addon/components/confirm-action.hbs
@@ -27,6 +27,7 @@
{{#if this.showConfirmModal}}
-
-
- {{this.title}}
-
-
-
-
- {{@header}}
-
-
-
-
- {{#each @items as |item|}}
-
-
-
-
-
- {{/each}}
-
-
-
\ No newline at end of file
diff --git a/ui/lib/core/addon/components/info-table.js b/ui/lib/core/addon/components/info-table.js
deleted file mode 100644
index 00eb57bfedb8..000000000000
--- a/ui/lib/core/addon/components/info-table.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: BUSL-1.1
- */
-
-import Component from '@glimmer/component';
-
-/**
- * @module InfoTable
- * InfoTable components are a table with a single column and header. They are used to render a list of InfoTableRow components.
- *
- * @example
- * ```js
- *
- * ```
- * @param {String} [title=Info Table] - The title of the table. Used for accessibility purposes.
- * @param {String} header=null - The column header.
- * @param {Array} items=null - An array of strings which will be used as the InfoTableRow value.
- */
-
-export default class InfoTable extends Component {
- get title() {
- return this.args.title || 'Info Table';
- }
-}
diff --git a/ui/lib/core/addon/templates/components/replication-secondary-card.hbs b/ui/lib/core/addon/templates/components/replication-secondary-card.hbs
index 317ea44a7247..053188128d6b 100644
--- a/ui/lib/core/addon/templates/components/replication-secondary-card.hbs
+++ b/ui/lib/core/addon/templates/components/replication-secondary-card.hbs
@@ -107,16 +107,34 @@
{{#if (is-empty this.knownPrimaryClusterAddrs)}}
-
-
- Learn more
-
-
+
+
+
+
+
+
+
{{else}}
-
+
+ <:head as |H|>
+
+ cluster_addr
+
+
+ <:body as |B|>
+ {{#each this.knownPrimaryClusterAddrs as |item|}}
+
+ {{item}}
+
+ {{/each}}
+
+
{{/if}}
{{/if}}
diff --git a/ui/lib/core/app/components/info-table.js b/ui/lib/core/app/components/info-table.js
deleted file mode 100644
index f7ced1e2b209..000000000000
--- a/ui/lib/core/app/components/info-table.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: BUSL-1.1
- */
-
-export { default } from 'core/components/info-table';
diff --git a/ui/lib/replication/addon/templates/components/known-secondaries-card.hbs b/ui/lib/replication/addon/templates/components/known-secondaries-card.hbs
index 5cd2c244200e..b25504e3c41b 100644
--- a/ui/lib/replication/addon/templates/components/known-secondaries-card.hbs
+++ b/ui/lib/replication/addon/templates/components/known-secondaries-card.hbs
@@ -17,10 +17,12 @@
{{#if this.replicationAttrs.secondaries}}
{{else}}
-
+
+
+
+
{{/if}}
{{#if this.cluster.canAddSecondary}}
diff --git a/ui/lib/replication/addon/templates/components/known-secondaries-table.hbs b/ui/lib/replication/addon/templates/components/known-secondaries-table.hbs
index 39479f3b54a1..b447dd29bf3c 100644
--- a/ui/lib/replication/addon/templates/components/known-secondaries-table.hbs
+++ b/ui/lib/replication/addon/templates/components/known-secondaries-table.hbs
@@ -3,54 +3,36 @@
SPDX-License-Identifier: BUSL-1.1
~}}
-
\ No newline at end of file
+
+ <:head as |H|>
+
+ Secondary ID
+ URL
+ Connected?
+
+
+ <:body as |B|>
+ {{#each this.secondaries as |secondary|}}
+
+ {{secondary.node_id}}
+
+ {{#if secondary.api_address}}
+
+ {{else}}
+ URL unavailable
+ {{/if}}
+
+
+
+ {{secondary.connection_status}}
+
+
+
+ {{/each}}
+
+
\ No newline at end of file
diff --git a/ui/tests/acceptance/raft-storage-test.js b/ui/tests/acceptance/raft-storage-test.js
index 35ddc099aa87..56c2aa7ec931 100644
--- a/ui/tests/acceptance/raft-storage-test.js
+++ b/ui/tests/acceptance/raft-storage-test.js
@@ -66,7 +66,7 @@ module('Acceptance | raft storage', function (hooks) {
await visit('/vault/storage/raft');
assert.dom('[data-raft-row]').exists({ count: 2 }, '2 raft peers render in table');
- await click('[data-raft-row]:nth-child(2) [data-test-popup-menu-trigger]');
+ await click('[data-raft-row]:nth-child(2) [data-test-raft-actions] button');
await click('[data-test-confirm-action-trigger]');
await click('[data-test-confirm-button]');
assert.dom('[data-raft-row]').exists({ count: 1 }, 'Raft peer successfully removed');
diff --git a/ui/tests/integration/components/confirm-action-test.js b/ui/tests/integration/components/confirm-action-test.js
index 839840e5f3ed..139bc100162b 100644
--- a/ui/tests/integration/components/confirm-action-test.js
+++ b/ui/tests/integration/components/confirm-action-test.js
@@ -36,7 +36,7 @@ module('Integration | Component | confirm-action', function (hooks) {
// hasClass assertion wasn't working so this is the workaround
assert.strictEqual(
find('#confirm-action-modal').className,
- 'hds-modal hds-modal--size-small hds-modal--color-critical',
+ 'hds-modal hds-modal--size-small hds-modal--color-critical has-text-left',
'renders critical modal color by default'
);
assert.strictEqual(
@@ -110,7 +110,7 @@ module('Integration | Component | confirm-action', function (hooks) {
await click(SELECTORS.modalToggle);
assert.strictEqual(
find('#confirm-action-modal').className,
- 'hds-modal hds-modal--size-small hds-modal--color-neutral',
+ 'hds-modal hds-modal--size-small hds-modal--color-neutral has-text-left',
'renders critical modal color by default'
);
assert.dom(SELECTORS.title).hasText('Not allowed', 'renders disabled title');
@@ -144,7 +144,7 @@ module('Integration | Component | confirm-action', function (hooks) {
await click(SELECTORS.modalToggle);
assert.strictEqual(
find('#confirm-action-modal').className,
- 'hds-modal hds-modal--size-small hds-modal--color-warning',
+ 'hds-modal hds-modal--size-small hds-modal--color-warning has-text-left',
'renders warning modal'
);
assert.strictEqual(
diff --git a/ui/tests/integration/components/info-table-test.js b/ui/tests/integration/components/info-table-test.js
deleted file mode 100644
index 96e3e5ec27ec..000000000000
--- a/ui/tests/integration/components/info-table-test.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: BUSL-1.1
- */
-
-import { module, test } from 'qunit';
-import { setupRenderingTest } from 'ember-qunit';
-import { render } from '@ember/test-helpers';
-import hbs from 'htmlbars-inline-precompile';
-
-const TITLE = 'My Table';
-const HEADER = 'Cool Header';
-const ITEMS = ['https://127.0.0.1:8201', 'hello', '3'];
-
-module('Integration | Component | InfoTable', function (hooks) {
- setupRenderingTest(hooks);
-
- hooks.beforeEach(function () {
- this.set('title', TITLE);
- this.set('header', HEADER);
- this.set('items', ITEMS);
- });
-
- test('it renders', async function (assert) {
- assert.expect(6);
- await render(hbs` `);
-
- assert.dom('[data-test-info-table]').exists();
- assert.dom('[data-test-info-table] th').includesText(HEADER, `shows the table header`);
-
- const rows = document.querySelectorAll('.info-table-row');
- assert.strictEqual(rows.length, ITEMS.length, 'renders an InfoTableRow for each item');
-
- rows.forEach((row, i) => {
- assert.strictEqual(row.innerText, ITEMS[i], 'handles strings and numbers as row values');
- });
- });
-});
diff --git a/ui/tests/integration/components/known-secondaries-card-test.js b/ui/tests/integration/components/known-secondaries-card-test.js
index 40fcf2b6048b..ac343147659e 100644
--- a/ui/tests/integration/components/known-secondaries-card-test.js
+++ b/ui/tests/integration/components/known-secondaries-card-test.js
@@ -58,8 +58,8 @@ module('Integration | Component | replication known-secondaries-card', function
.dom('[data-test-known-secondaries-table]')
.doesNotExist('does not show the known secondaries table');
assert
- .dom('.empty-state')
- .includesText('No known dr secondary clusters', 'has a message with the replication mode');
+ .dom('.hds-application-state')
+ .includesText('No known dr secondary clusters', 'empty state has a message with the replication mode');
});
test('it renders an Add secondary link if user has capabilites', async function (assert) {
diff --git a/ui/tests/integration/components/known-secondaries-table-test.js b/ui/tests/integration/components/known-secondaries-table-test.js
index 0a4fee2421cc..e0c9f8ebb8cf 100644
--- a/ui/tests/integration/components/known-secondaries-table-test.js
+++ b/ui/tests/integration/components/known-secondaries-table-test.js
@@ -32,37 +32,31 @@ module('Integration | Component | replication known-secondaries-table', function
});
test('it shows the secondary URL and connection_status', async function (assert) {
- assert.expect(9);
+ assert.expect(13);
await render(hbs` `, this.context);
SECONDARIES.forEach((secondary) => {
- assert.strictEqual(
- this.element.querySelector(`[data-test-secondaries=row-for-${secondary.node_id}]`).innerHTML.trim(),
- secondary.node_id,
- 'shows a table row and ID for each known secondary'
- );
-
- if (secondary.api_address) {
- const expectedUrl = `${secondary.api_address}/ui/`;
-
- assert.strictEqual(
- this.element.querySelector(`[data-test-secondaries=api-address-for-${secondary.node_id}]`).href,
- expectedUrl,
- 'renders a URL to the secondary UI'
- );
- } else {
- assert.notOk(
- this.element.querySelector(`[data-test-secondaries=api-address-for-${secondary.node_id}]`)
- );
- }
+ assert
+ .dom(`[data-test-secondaries-node="${secondary.node_id}"]`)
+ .hasText(secondary.node_id, 'shows a table row and ID for each known secondary');
+ const expectedAPIAddr = secondary.api_address || 'URL unavailable';
+ const expectedTag = secondary.api_address ? 'a' : 'p';
+ assert.dom(`[data-test-secondaries-api-address="${secondary.node_id}"]`).hasText(expectedAPIAddr);
+ assert
+ .dom(`[data-test-secondaries-api-address="${secondary.node_id}"] ${expectedTag}`)
+ .exists('has correct tag');
+
+ assert
+ .dom(`[data-test-secondaries-connection-status="${secondary.node_id}"]`)
+ .hasText(secondary.connection_status, 'shows the connection status');
+ });
- assert.strictEqual(
- this.element
- .querySelector(`[data-test-secondaries=connection-status-for-${secondary.node_id}]`)
- .innerHTML.trim(),
- secondary.connection_status,
- 'shows the connection status'
+ assert
+ .dom(`[data-test-secondaries-api-address="secondary-1"] a`)
+ .hasAttribute(
+ 'href',
+ 'https://127.0.0.1:52304/ui/',
+ 'secondary with API address has correct href attribute'
);
- });
});
});
diff --git a/ui/tests/integration/components/replication-secondary-card-test.js b/ui/tests/integration/components/replication-secondary-card-test.js
index d89d9a2a4c8f..1c8261a90173 100644
--- a/ui/tests/integration/components/replication-secondary-card-test.js
+++ b/ui/tests/integration/components/replication-secondary-card-test.js
@@ -48,10 +48,10 @@ module('Integration | Component | replication-secondary-card', function (hooks)
assert.dom('[data-test-info-table]').exists('it shows the known primary cluster details');
- const url = this.element.querySelector('[data-test-primary-link]').href;
const expectedUrl = `${REPLICATION_DETAILS.primaries[0].api_address}/ui/`;
-
- assert.strictEqual(url, expectedUrl, 'it renders a link to the primary cluster UI');
+ assert
+ .dom('[data-test-primary-link]')
+ .hasAttribute('href', expectedUrl, 'it renders a link to the primary cluster UI');
});
test('it does not render a link to the primary cluster UI when the primary api address or known primaries are unknown', async function (assert) {
@@ -68,7 +68,7 @@ module('Integration | Component | replication-secondary-card', function (hooks)
await render(
hbs` `
);
- assert.dom('[data-test-component="empty-state"]').exists();
+ assert.dom('[data-test-empty-state]').exists('shows empty state');
});
test('it renders tooltip with check-circle-outline when state is stream-wals', async function (assert) {
From 3726d8fb1d86670580d2d5fcccfe9b901144cb96 Mon Sep 17 00:00:00 2001
From: Robert <17119716+robmonte@users.noreply.github.com>
Date: Mon, 27 Nov 2023 16:10:37 -0600
Subject: [PATCH 25/74] Add configuration section to sync API docs (#24179)
* Add configuration section
* Add restricted root namespace alert
---
.../content/api-docs/system/secrets-sync.mdx | 50 +++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/website/content/api-docs/system/secrets-sync.mdx b/website/content/api-docs/system/secrets-sync.mdx
index b258a8082ceb..beb52f137fa2 100644
--- a/website/content/api-docs/system/secrets-sync.mdx
+++ b/website/content/api-docs/system/secrets-sync.mdx
@@ -11,6 +11,56 @@ The `/sys/sync` endpoints are used to configure destinations and associate secre
Each destination type has its own endpoint for creation & update operations, but share the same endpoints for read &
delete operations.
+## Configuration
+
+The `sys/sync/config` endpoint is used to set configuration parameters for the sync system as a whole.
+
+@include 'alerts/restricted-root.mdx'
+
+| Method | Path |
+|:--------|:------------------|
+| `PATCH` | `sys/sync/config` |
+
+### Parameters
+
+- `disabled` `(bool: false)` - Disables sync operations from sending secrets in Vault to external destinations when
+set to true. While disabled, actions performed in Vault which trigger a sync operation will instead get queued to be
+processed once syncing is reactivated. Queued operations will have a status of `PENDING` until they are completed.
+This is provided as a safety mechanism for emergencies.
+
+### Sample payload
+```json
+{
+ "disabled": "true"
+}
+```
+
+### Sample request
+
+```shell-session
+$ curl \
+ --header "X-Vault-Token: ..." \
+ --request PATCH \
+ --data @payload.json
+ http://127.0.0.1:8200/v1/sys/sync/config
+```
+
+### Sample response
+
+```json
+{
+ "request_id": "uuid",
+ "lease_id": "",
+ "lease_duration": 0,
+ "renewable": false,
+ "data": {
+ "disabled": true
+ },
+ "warnings": null,
+ "mount_type": "system"
+}
+```
+
## List destinations
This endpoint lists all configured sync destination names regrouped by destination type.
From 030bba4e68751ddffaf9734853da3dfb395d2f28 Mon Sep 17 00:00:00 2001
From: Tom Proctor
Date: Tue, 28 Nov 2023 14:07:07 +0000
Subject: [PATCH 26/74] Support rootless plugin containers (#24236)
* Pulls in github.com/go-secure-stdlib/plugincontainer@v0.3.0 which exposes a new `Config.Rootless` option to opt in to extra container configuration options that allow establishing communication with a non-root plugin within a rootless container runtime.
* Adds a new "rootless" option for plugin runtimes, so Vault needs to be explicitly told whether the container runtime on the machine is rootless or not. It defaults to false as rootless installs are not the default.
* Updates `run_config.go` to use the new option when the plugin runtime is rootless.
* Adds new `-rootless` flag to `vault plugin runtime register`, and `rootless` API option to the register API.
* Adds rootless Docker installation to CI to support tests for the new functionality.
* Minor test refactor to minimise the number of test Vault cores that need to be made for the external plugin container tests.
* Documentation for the new rootless configuration and the new (reduced) set of restrictions for plugin containers.
* As well as adding rootless support, we've decided to drop explicit support for podman for now, but there's no barrier other than support burden to adding it back again in future so it will depend on demand.
---
.github/workflows/test-go.yml | 32 +++-
api/sys_plugins_runtimes.go | 1 +
changelog/24236.txt | 3 +
command/plugin_runtime_register.go | 11 ++
command/plugin_runtime_register_test.go | 8 +-
go.mod | 5 +-
go.sum | 16 +-
sdk/go.mod | 5 +-
sdk/go.sum | 11 +-
sdk/helper/pluginruntimeutil/config.go | 1 +
sdk/helper/pluginutil/run_config.go | 6 +-
vault/external_plugin_container_test.go | 140 +++++++++---------
vault/external_plugin_test.go | 8 +-
.../plugin/external_plugin_test.go | 24 +--
vault/logical_system.go | 8 +
vault/logical_system_paths.go | 9 ++
vault/logical_system_test.go | 3 +
vault/testdata/Dockerfile | 4 +
vault/testing.go | 38 ++---
.../system/plugins-runtimes-catalog.mdx | 4 +
.../docs/commands/plugin/runtime/register.mdx | 4 +
.../docs/plugins/containerized-plugins.mdx | 38 ++---
22 files changed, 236 insertions(+), 143 deletions(-)
create mode 100644 changelog/24236.txt
diff --git a/.github/workflows/test-go.yml b/.github/workflows/test-go.yml
index 2b498be4d011..24825b5272b6 100644
--- a/.github/workflows/test-go.yml
+++ b/.github/workflows/test-go.yml
@@ -286,14 +286,37 @@ jobs:
"runsc": {
"path": "/usr/local/bin/runsc",
"runtimeArgs": [
- "--host-uds=all",
- "--host-fifo=open"
+ "--host-uds=create"
]
}
}
}
EOF
sudo systemctl reload docker
+ - name: Install rootless Docker
+ # Enterprise repo runners do not allow sudo, so can't system packages there yet.
+ if: ${{ !inputs.enterprise }}
+ run: |
+ sudo apt-get install -y uidmap dbus-user-session
+ export FORCE_ROOTLESS_INSTALL=1
+ curl -fsSL https://get.docker.com/rootless | sh
+ mkdir -p ~/.config/docker/
+ tee ~/.config/docker/daemon.json <)` – Part of the request URL. Specifies the plugin runtime name.
Use the runtime name to look up plugin runtimes in the catalog.
+- `rootless` `(bool: false)` - Whether the container runtime is running as a
+ non-privileged user. Must be set if plugin container images are also configured
+ to run as a non-root user.
+
- `oci_runtime` `(string: )` – Specifies OCI-compliant container runtime to use.
Default is "runsc", gVisor's OCI runtime.
diff --git a/website/content/docs/commands/plugin/runtime/register.mdx b/website/content/docs/commands/plugin/runtime/register.mdx
index 698ee318db6f..75119d4e7268 100644
--- a/website/content/docs/commands/plugin/runtime/register.mdx
+++ b/website/content/docs/commands/plugin/runtime/register.mdx
@@ -45,6 +45,10 @@ flags](/vault/docs/commands) included on all commands.
- `-type` `(string: )` - Plugin runtime type. Vault currently only
supports `container` as a runtime type.
+- `-rootless` `(bool: false)` - Whether the container runtime is running as a
+ non-privileged user. Must be set if plugin container images are also configured
+ to run as a non-root user.
+
- `-cgroup_parent` `(string: "")` - Parent cgroup to set for each container.
Use `cgroup_parent` to control the total resource usage for a group of plugins.
diff --git a/website/content/docs/plugins/containerized-plugins.mdx b/website/content/docs/plugins/containerized-plugins.mdx
index 1bd4cb2de797..748d6d680923 100644
--- a/website/content/docs/plugins/containerized-plugins.mdx
+++ b/website/content/docs/plugins/containerized-plugins.mdx
@@ -39,7 +39,7 @@ increases the isolation between plugins, and between plugins and Vault.
All plugins have the following basic requirements to be containerized:
-- **Your plugin must be built with at least v1.5.0 of the HashiCorp
+- **Your plugin must be built with at least v1.6.0 of the HashiCorp
[`go-plugin`](https://github.com/hashicorp/go-plugin) library**.
- **The image entrypoint should run the plugin binary**.
@@ -52,39 +52,39 @@ in [supported configurations](#supported-configurations).
Vault's containerized plugins are compatible with a variety of configurations.
In particular, it has been tested with the following:
-- Docker and Podman.
-- Default and rootless container engine.
-- OCI runtimes runsc and runc.
-- Plugin container images with root and non-root users.
+- Default and [rootless](https://docs.docker.com/engine/security/rootless/) Docker.
+- OCI-compatible runtimes `runsc` and `runc`.
+- Plugin container images running as root and non-root users.
- [Mlock](/vault/docs/configuration#disable_mlock) disabled or enabled.
Not all combinations work and some have additional requirements, listed below.
If you use a configuration that matches multiple headings, you should combine
the requirements from each matching heading.
-### Rootless installation with non-root container user
+### `runsc` runtime
-Not currently supported. We are hoping to provide support in future.
+- You must pass an additional `--host-uds=create` flag to the `runsc` runtime.
-### runsc runtime
+### Rootless Docker with `runsc` runtime
-- You must pass an additional `--host-uds=all` flag to the `runsc` runtime.
+- You must pass an additional `--ignore-cgroups` flag to the `runsc` runtime.
+ - Cgroup limits are not currently supported for this configuration.
-### Rootless installation with `runsc`
+### Rootless Docker with non-root container user
-- Does not currently support cgroup limits.
-- You must pass an additional `--ignore-cgroups` flag to the `runsc` runtime.
+- You must use a container plugin runtime with
+ [`rootless`](/vault/docs/commands/plugin/runtime/register#rootless) enabled.
+- Your filesystem must have Posix 1e ACL support, available by default in most
+ modern Linux file systems.
+- Only supported for gVisor's `runsc` runtime.
-### Non-root container user with mlock enabled
+### Rootless Docker with mlock enabled
-- You must set the IPC_LOCK capability on the plugin binary.
+- Only supported for gVisor's `runsc` runtime.
-### Rootless container engine with mlock enabled
+### Non-root container user with mlock enabled
-- You must set the IPC_LOCK capability on the container engine's binary.
-- You do not need to set the IPC_LOCK capability if running with Docker and runsc.
- The `runsc` runtime supports mlock syscalls in rootless Docker without needing
- IPC_LOCK itself.
+- You must set the `IPC_LOCK` capability on the plugin binary.
## Container lifecycle and metadata
From 51d99fc7cfeafe7dd95e6c1c633d81c1f05c42f3 Mon Sep 17 00:00:00 2001
From: Tom Proctor
Date: Tue, 28 Nov 2023 14:13:26 +0000
Subject: [PATCH 27/74] cli: Improve error handling for plugin commands
(#24250)
* Stop supporting vault plugin info and deregister without a type argument
* Make a best-effort attempt to report whether a plugin was actually deregistered and give more descriptive errors
* Fix error message for vault plugin reload
---
changelog/24250.txt | 6 ++++
command/plugin_deregister.go | 48 +++++++++++++++++++++++++------
command/plugin_deregister_test.go | 31 +++++++++++++++++---
command/plugin_info.go | 20 ++++++-------
command/plugin_info_test.go | 6 ++++
command/plugin_reload.go | 8 ++++--
command/plugin_reload_test.go | 6 ++--
7 files changed, 95 insertions(+), 30 deletions(-)
create mode 100644 changelog/24250.txt
diff --git a/changelog/24250.txt b/changelog/24250.txt
new file mode 100644
index 000000000000..e6aca7096ac3
--- /dev/null
+++ b/changelog/24250.txt
@@ -0,0 +1,6 @@
+```release-note:change
+cli: `vault plugin info` and `vault plugin deregister` now require 2 positional arguments instead of accepting either 1 or 2.
+```
+```release-note:improvement
+cli: Improved error messages for `vault plugin` sub-commands.
+```
diff --git a/command/plugin_deregister.go b/command/plugin_deregister.go
index 4b9de504db84..5355a951576d 100644
--- a/command/plugin_deregister.go
+++ b/command/plugin_deregister.go
@@ -4,7 +4,9 @@
package command
import (
+ "context"
"fmt"
+ "net/http"
"strings"
semver "github.com/hashicorp/go-version"
@@ -83,18 +85,16 @@ func (c *PluginDeregisterCommand) Run(args []string) int {
var pluginNameRaw, pluginTypeRaw string
args = f.Args()
- switch len(args) {
- case 0:
- c.UI.Error("Not enough arguments (expected 1, or 2, got 0)")
+ positionalArgsCount := len(args)
+ switch positionalArgsCount {
+ case 0, 1:
+ c.UI.Error(fmt.Sprintf("Not enough arguments (expected 2, got %d)", positionalArgsCount))
return 1
- case 1:
- pluginTypeRaw = "unknown"
- pluginNameRaw = args[0]
case 2:
pluginTypeRaw = args[0]
pluginNameRaw = args[1]
default:
- c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, or 2, got %d)", len(args)))
+ c.UI.Error(fmt.Sprintf("Too many arguments (expected 2, got %d)", positionalArgsCount))
return 1
}
@@ -118,7 +118,33 @@ func (c *PluginDeregisterCommand) Run(args []string) int {
}
}
- if err := client.Sys().DeregisterPlugin(&api.DeregisterPluginInput{
+ // The deregister endpoint returns 200 if the plugin doesn't exist, so first
+ // try fetching the plugin to help improve info printed to the user.
+ // 404 => Return early with a descriptive message.
+ // Other error => Continue attempting to deregister the plugin anyway.
+ // Plugin exists but is builtin => Error early.
+ // Otherwise => If deregister succeeds, we can report that the plugin really
+ // was deregistered (and not just already absent).
+ var pluginExists bool
+ if info, err := client.Sys().GetPluginWithContext(context.Background(), &api.GetPluginInput{
+ Name: pluginName,
+ Type: pluginType,
+ Version: c.flagPluginVersion,
+ }); err != nil {
+ if respErr, ok := err.(*api.ResponseError); ok && respErr.StatusCode == http.StatusNotFound {
+ c.UI.Output(fmt.Sprintf("Plugin %q (type: %q, version %q) does not exist in the catalog", pluginName, pluginType, c.flagPluginVersion))
+ return 0
+ }
+ // Best-effort check, continue trying to deregister.
+ } else if info != nil {
+ if info.Builtin {
+ c.UI.Error(fmt.Sprintf("Plugin %q (type: %q) is a builtin plugin and cannot be deregistered", pluginName, pluginType))
+ return 2
+ }
+ pluginExists = true
+ }
+
+ if err := client.Sys().DeregisterPluginWithContext(context.Background(), &api.DeregisterPluginInput{
Name: pluginName,
Type: pluginType,
Version: c.flagPluginVersion,
@@ -127,6 +153,10 @@ func (c *PluginDeregisterCommand) Run(args []string) int {
return 2
}
- c.UI.Output(fmt.Sprintf("Success! Deregistered plugin (if it was registered): %s", pluginName))
+ if pluginExists {
+ c.UI.Output(fmt.Sprintf("Success! Deregistered %s plugin: %s", pluginType, pluginName))
+ } else {
+ c.UI.Output(fmt.Sprintf("Success! Deregistered %s plugin (if it was registered): %s", pluginType, pluginName))
+ }
return 0
}
diff --git a/command/plugin_deregister_test.go b/command/plugin_deregister_test.go
index f23c8b6c433c..b5bf4f7be92c 100644
--- a/command/plugin_deregister_test.go
+++ b/command/plugin_deregister_test.go
@@ -35,7 +35,7 @@ func TestPluginDeregisterCommand_Run(t *testing.T) {
}{
{
"not_enough_args",
- nil,
+ []string{"foo"},
"Not enough arguments",
1,
},
@@ -109,7 +109,7 @@ func TestPluginDeregisterCommand_Run(t *testing.T) {
t.Errorf("expected %d to be %d", code, exp)
}
- expected := "Success! Deregistered plugin (if it was registered): "
+ expected := "Success! Deregistered auth plugin: "
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
if !strings.Contains(combined, expected) {
t.Errorf("expected %q to contain %q", combined, expected)
@@ -159,7 +159,7 @@ func TestPluginDeregisterCommand_Run(t *testing.T) {
t.Errorf("expected %d to be %d", code, exp)
}
- expected := "Success! Deregistered plugin (if it was registered): "
+ expected := "Success! Deregistered auth plugin: "
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
if !strings.Contains(combined, expected) {
t.Errorf("expected %q to contain %q", combined, expected)
@@ -206,7 +206,7 @@ func TestPluginDeregisterCommand_Run(t *testing.T) {
t.Errorf("expected %d to be %d", code, exp)
}
- expected := "Success! Deregistered plugin (if it was registered): "
+ expected := "does not exist in the catalog"
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
if !strings.Contains(combined, expected) {
t.Errorf("expected %q to contain %q", combined, expected)
@@ -230,6 +230,29 @@ func TestPluginDeregisterCommand_Run(t *testing.T) {
}
})
+ t.Run("deregister builtin", func(t *testing.T) {
+ t.Parallel()
+
+ pluginDir, cleanup := corehelpers.MakeTestPluginDir(t)
+ defer cleanup(t)
+
+ client, _, closer := testVaultServerPluginDir(t, pluginDir)
+ defer closer()
+
+ ui, cmd := testPluginDeregisterCommand(t)
+ cmd.client = client
+
+ expected := "is a builtin plugin"
+ if code := cmd.Run([]string{
+ consts.PluginTypeCredential.String(),
+ "github",
+ }); code != 2 {
+ t.Errorf("expected %d to be %d", code, 2)
+ } else if !strings.Contains(ui.ErrorWriter.String(), expected) {
+ t.Errorf("expected %q to contain %q", ui.ErrorWriter.String(), expected)
+ }
+ })
+
t.Run("communication_failure", func(t *testing.T) {
t.Parallel()
diff --git a/command/plugin_info.go b/command/plugin_info.go
index b1cf7acb04a2..0211555027e2 100644
--- a/command/plugin_info.go
+++ b/command/plugin_info.go
@@ -77,23 +77,19 @@ func (c *PluginInfoCommand) Run(args []string) int {
var pluginNameRaw, pluginTypeRaw string
args = f.Args()
+ positionalArgsCount := len(args)
switch {
- case len(args) < 1:
- c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1 or 2, got %d)", len(args)))
+ case positionalArgsCount < 2:
+ c.UI.Error(fmt.Sprintf("Not enough arguments (expected 2, got %d)", positionalArgsCount))
return 1
- case len(args) > 2:
- c.UI.Error(fmt.Sprintf("Too many arguments (expected 1 or 2, got %d)", len(args)))
+ case positionalArgsCount > 2:
+ c.UI.Error(fmt.Sprintf("Too many arguments (expected 2, got %d)", positionalArgsCount))
return 1
-
- // These cases should come after invalid cases have been checked
- case len(args) == 1:
- pluginTypeRaw = "unknown"
- pluginNameRaw = args[0]
- case len(args) == 2:
- pluginTypeRaw = args[0]
- pluginNameRaw = args[1]
}
+ pluginTypeRaw = args[0]
+ pluginNameRaw = args[1]
+
client, err := c.Client()
if err != nil {
c.UI.Error(err.Error())
diff --git a/command/plugin_info_test.go b/command/plugin_info_test.go
index 367124301671..3ffaa6972010 100644
--- a/command/plugin_info_test.go
+++ b/command/plugin_info_test.go
@@ -34,6 +34,12 @@ func TestPluginInfoCommand_Run(t *testing.T) {
out string
code int
}{
+ {
+ "not_enough_args",
+ []string{"foo"},
+ "Not enough arguments",
+ 1,
+ },
{
"too_many_args",
[]string{"foo", "bar", "fizz"},
diff --git a/command/plugin_reload.go b/command/plugin_reload.go
index 4ec7acb99c83..22cd91275d16 100644
--- a/command/plugin_reload.go
+++ b/command/plugin_reload.go
@@ -90,12 +90,16 @@ func (c *PluginReloadCommand) Run(args []string) int {
return 1
}
+ positionalArgs := len(f.Args())
switch {
+ case positionalArgs != 0:
+ c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", positionalArgs))
+ return 1
case c.plugin == "" && len(c.mounts) == 0:
- c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1, got %d)", len(args)))
+ c.UI.Error("No plugins specified, must specify exactly one of -plugin or -mounts")
return 1
case c.plugin != "" && len(c.mounts) > 0:
- c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
+ c.UI.Error("Must specify exactly one of -plugin or -mounts")
return 1
case c.scope != "" && c.scope != "global":
c.UI.Error(fmt.Sprintf("Invalid reload scope: %s", c.scope))
diff --git a/command/plugin_reload_test.go b/command/plugin_reload_test.go
index cf9f2d149c54..7ae082ed840b 100644
--- a/command/plugin_reload_test.go
+++ b/command/plugin_reload_test.go
@@ -46,13 +46,13 @@ func TestPluginReloadCommand_Run(t *testing.T) {
{
"not_enough_args",
nil,
- "Not enough arguments",
+ "No plugins specified, must specify exactly one of -plugin or -mounts",
1,
},
{
"too_many_args",
[]string{"-plugin", "foo", "-mounts", "bar"},
- "Too many arguments",
+ "Must specify exactly one of -plugin or -mounts",
1,
},
}
@@ -147,7 +147,7 @@ func TestPluginReloadStatusCommand_Run(t *testing.T) {
client, closer := testVaultServer(t)
defer closer()
- ui, cmd := testPluginReloadCommand(t)
+ ui, cmd := testPluginReloadStatusCommand(t)
cmd.client = client
args := append([]string{}, tc.args...)
From 8f064b90ecd27587f6cd8c0f263ccd398db4b093 Mon Sep 17 00:00:00 2001
From: Kuba Wieczorek
Date: Tue, 28 Nov 2023 14:22:33 +0000
Subject: [PATCH 28/74] [VAULT-22270] API: add enterprise field to the response
from /sys/health/ endpoint (#24270)
---
changelog/24270.txt | 3 +++
http/sys_health.go | 3 +++
http/sys_health_test.go | 7 +++++++
3 files changed, 13 insertions(+)
create mode 100644 changelog/24270.txt
diff --git a/changelog/24270.txt b/changelog/24270.txt
new file mode 100644
index 000000000000..eb8e4c04fb7c
--- /dev/null
+++ b/changelog/24270.txt
@@ -0,0 +1,3 @@
+```release-note:change
+api: add the `enterprise` parameter to the `/sys/health` endpoint
+```
diff --git a/http/sys_health.go b/http/sys_health.go
index d0c4362a8ab6..b5e92961d150 100644
--- a/http/sys_health.go
+++ b/http/sys_health.go
@@ -12,6 +12,7 @@ import (
"time"
"github.com/hashicorp/go-secure-stdlib/parseutil"
+ "github.com/hashicorp/vault/helper/constants"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/vault"
"github.com/hashicorp/vault/version"
@@ -204,6 +205,7 @@ func getSysHealth(core *vault.Core, r *http.Request) (int, *HealthResponse, erro
ReplicationDRMode: replicationState.GetDRString(),
ServerTimeUTC: time.Now().UTC().Unix(),
Version: version.GetVersion().VersionNumber(),
+ Enterprise: constants.IsEnterprise,
ClusterName: clusterName,
ClusterID: clusterID,
}
@@ -245,6 +247,7 @@ type HealthResponse struct {
ReplicationDRMode string `json:"replication_dr_mode"`
ServerTimeUTC int64 `json:"server_time_utc"`
Version string `json:"version"`
+ Enterprise bool `json:"enterprise"`
ClusterName string `json:"cluster_name,omitempty"`
ClusterID string `json:"cluster_id,omitempty"`
LastWAL uint64 `json:"last_wal,omitempty"`
diff --git a/http/sys_health_test.go b/http/sys_health_test.go
index 48caa6e1ca41..83ec63db0010 100644
--- a/http/sys_health_test.go
+++ b/http/sys_health_test.go
@@ -10,6 +10,7 @@ import (
"reflect"
"testing"
+ "github.com/hashicorp/vault/helper/constants"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/vault"
)
@@ -26,6 +27,7 @@ func TestSysHealth_get(t *testing.T) {
var actual map[string]interface{}
expected := map[string]interface{}{
+ "enterprise": constants.IsEnterprise,
"replication_performance_mode": consts.ReplicationUnknown.GetPerformanceString(),
"replication_dr_mode": consts.ReplicationUnknown.GetDRString(),
"initialized": false,
@@ -60,6 +62,7 @@ func TestSysHealth_get(t *testing.T) {
actual = map[string]interface{}{}
expected = map[string]interface{}{
+ "enterprise": constants.IsEnterprise,
"replication_performance_mode": consts.ReplicationUnknown.GetPerformanceString(),
"replication_dr_mode": consts.ReplicationUnknown.GetDRString(),
"initialized": true,
@@ -98,6 +101,7 @@ func TestSysHealth_get(t *testing.T) {
actual = map[string]interface{}{}
expected = map[string]interface{}{
+ "enterprise": constants.IsEnterprise,
"replication_performance_mode": consts.ReplicationPerformanceDisabled.GetPerformanceString(),
"replication_dr_mode": consts.ReplicationDRDisabled.GetDRString(),
"initialized": true,
@@ -141,6 +145,7 @@ func TestSysHealth_customcodes(t *testing.T) {
var actual map[string]interface{}
expected := map[string]interface{}{
+ "enterprise": constants.IsEnterprise,
"replication_performance_mode": consts.ReplicationUnknown.GetPerformanceString(),
"replication_dr_mode": consts.ReplicationUnknown.GetDRString(),
"initialized": false,
@@ -176,6 +181,7 @@ func TestSysHealth_customcodes(t *testing.T) {
actual = map[string]interface{}{}
expected = map[string]interface{}{
+ "enterprise": constants.IsEnterprise,
"replication_performance_mode": consts.ReplicationUnknown.GetPerformanceString(),
"replication_dr_mode": consts.ReplicationUnknown.GetDRString(),
"initialized": true,
@@ -215,6 +221,7 @@ func TestSysHealth_customcodes(t *testing.T) {
actual = map[string]interface{}{}
expected = map[string]interface{}{
+ "enterprise": constants.IsEnterprise,
"replication_performance_mode": consts.ReplicationPerformanceDisabled.GetPerformanceString(),
"replication_dr_mode": consts.ReplicationDRDisabled.GetDRString(),
"initialized": true,
From 2e54ae0d6155fac13d9596ee1a8a5d30a159c933 Mon Sep 17 00:00:00 2001
From: Victor Rodriguez
Date: Tue, 28 Nov 2023 09:56:39 -0500
Subject: [PATCH 29/74] Check that multi-seal wrappers provide unique key IDs
(#24266)
* Remove duplicate function NewToggleableTestSeal.
NewToggleableTestSeal is almost the same as NewTestSeal, so remove it and adapt
the callers to use the duplicated function.
* Remove unnecessary function CreateTestSealWrappers.
The only caller of CreateTestSealWrappers can use NewTestSeal instead and
obtain the wrappers from the seal Access object instead.
* Ensure NewTestSeal does not generate "duplicate" wrappers.
NewTestSeal uses TestWrappers to create multi-seal Access objects. However, the
default behaviour for TestWrapper is to reverse the byte slice, which means that
two different wrappers will be identical, which is a problem for testing since
one wrapper will be able do "decrypt" another wrapper's encryption.
To fix this problem, NewTestSeal now creates TestWrappers with a different
secret for each one.
* Make NewTestSeal give unique Key IDs to its test wrappers.
* Fix some typos.
* Detect multi-seal wrappers producing duplicate Key IDs.
The Access object relies on all the encryption wrappers generating distinct key
IDs, so guard against this happening.
If a duplicate key ID is detected, do not use the encrypted value produced by
the wrappers that generated it. Return an error instead.
---
vault/external_tests/raft/raft_test.go | 4 +-
vault/seal/seal.go | 44 ++++++++--
vault/seal/seal_test.go | 47 +++++++++++
vault/seal/seal_testing.go | 106 ++++++++-----------------
vault/seal_autoseal_test.go | 10 +--
vault/seal_testing_util.go | 26 ++++++
6 files changed, 150 insertions(+), 87 deletions(-)
diff --git a/vault/external_tests/raft/raft_test.go b/vault/external_tests/raft/raft_test.go
index efe209c44e89..73eab754bfb7 100644
--- a/vault/external_tests/raft/raft_test.go
+++ b/vault/external_tests/raft/raft_test.go
@@ -514,7 +514,7 @@ func TestRaft_SnapshotAPI_MidstreamFailure(t *testing.T) {
// defer goleak.VerifyNone(t)
t.Parallel()
- seal, setErr := vaultseal.NewToggleableTestSeal(nil)
+ seal, wrappers := vaultseal.NewTestSeal(nil)
autoSeal := vault.NewAutoSeal(seal)
cluster, _ := raftCluster(t, &RaftClusterOpts{
NumCores: 1,
@@ -547,7 +547,7 @@ func TestRaft_SnapshotAPI_MidstreamFailure(t *testing.T) {
wg.Done()
}()
- setErr[0](errors.New("seal failure"))
+ wrappers[0].SetError(errors.New("seal failure"))
// Take a snapshot
err := leaderClient.Sys().RaftSnapshot(w)
w.Close()
diff --git a/vault/seal/seal.go b/vault/seal/seal.go
index 3786f37c866f..cd49f052edc4 100644
--- a/vault/seal/seal.go
+++ b/vault/seal/seal.go
@@ -203,13 +203,13 @@ func haveCommonSeal(existingSealKmsConfigs, newSealKmsConfigs []*configutil.KMS)
}
func findRenamedDisabledSeals(configs []*configutil.KMS) []*configutil.KMS {
- diabledSeals := []*configutil.KMS{}
+ disabledSeals := []*configutil.KMS{}
for _, seal := range configs {
if seal.Disabled && strings.HasSuffix(seal.Name, configutil.KmsRenameDisabledSuffix) {
- diabledSeals = append(diabledSeals, seal)
+ disabledSeals = append(disabledSeals, seal)
}
}
- return diabledSeals
+ return disabledSeals
}
func compareKMSConfigByNameAndType() cmp.Option {
@@ -468,7 +468,10 @@ func (a *access) Init(ctx context.Context, options ...wrapping.Option) error {
a.logger.Warn("cannot determine key ID for seal", "seal", sealWrapper.Name, "err", err)
return fmt.Errorf("cannod determine key ID for seal %s: %w", sealWrapper.Name, err)
}
- keyIds = append(keyIds, keyId)
+ if keyId != "" {
+ // Some wrappers may not yet know their key id. For emample, see gcpkms.Wrapper.
+ keyIds = append(keyIds, keyId)
+ }
}
}
a.keyIdSet.setIds(keyIds)
@@ -477,7 +480,7 @@ func (a *access) Init(ctx context.Context, options ...wrapping.Option) error {
func (a *access) IsUpToDate(ctx context.Context, value *MultiWrapValue, forceKeyIdRefresh bool) (bool, error) {
// Note that we don't compare generations when the value is transitory, since all single-blobInfo
- // values are unmarshalled as transitory values.
+ // values (i.e. not yet upgraded to MultiWrapValues) are unmarshalled as transitory values.
if value.Generation != 0 && value.Generation != a.Generation() {
return false, nil
}
@@ -558,6 +561,34 @@ GATHER_RESULTS:
}
}
+ {
+ // Check for duplicate Key IDs.
+ // If any wrappers produce duplicated IDs, their BlobInfo will be replaced by an error.
+
+ keyIdToSealWrapperNameMap := make(map[string]string)
+ for _, sealWrapper := range enabledWrappersByPriority {
+ wrapperName := sealWrapper.Name
+ if result, ok := results[wrapperName]; ok {
+ if result.err != nil {
+ continue
+ }
+ if result.ciphertext.KeyInfo == nil {
+ // Can this really happen? Probably not?
+ continue
+ }
+ keyId := result.ciphertext.KeyInfo.KeyId
+ duplicateWrapperName, isDuplicate := keyIdToSealWrapperNameMap[keyId]
+ if isDuplicate {
+ for _, name := range []string{wrapperName, duplicateWrapperName} {
+ results[name].err = fmt.Errorf("seal %s has returned duplicate key ID %s, key IDs must be unique", name, keyId)
+ results[name].ciphertext = nil
+ }
+ }
+ keyIdToSealWrapperNameMap[keyId] = wrapperName
+ }
+ }
+ }
+
// Sort out the successful results from the errors
var slots []*wrapping.BlobInfo
errs := make(map[string]error)
@@ -587,6 +618,7 @@ GATHER_RESULTS:
a.logger.Trace("successfully encrypted value", "encryption seal wrappers", len(slots), "total enabled seal wrappers",
len(a.GetEnabledSealWrappersByPriority()))
+
ret := &MultiWrapValue{
Generation: a.Generation(),
Slots: slots,
@@ -748,7 +780,7 @@ GATHER_RESULTS:
return nil, false, errors.New("context timeout exceeded")
}
-// tryDecrypt returns the plaintext and a flad indicating whether the decryption was done by the "unwrapSeal" (see
+// tryDecrypt returns the plaintext and a flag indicating whether the decryption was done by the "unwrapSeal" (see
// sealWrapMigration.Decrypt).
func (a *access) tryDecrypt(ctx context.Context, sealWrapper *SealWrapper, ciphertextByKeyId map[string]*wrapping.BlobInfo, options []wrapping.Option) ([]byte, bool, error) {
now := time.Now()
diff --git a/vault/seal/seal_test.go b/vault/seal/seal_test.go
index 07abe465dba1..c5bc5224136a 100644
--- a/vault/seal/seal_test.go
+++ b/vault/seal/seal_test.go
@@ -4,6 +4,9 @@
package seal
import (
+ "context"
+ "fmt"
+ "github.com/stretchr/testify/require"
"testing"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
@@ -95,3 +98,47 @@ func Test_keyIdSet(t *testing.T) {
runTest(tt.name+".setIDs", useSetIds)
}
}
+
+// Test_Encrypt_duplicate_keyIds verifies that if two seal wrappers produce the same Key ID, an error
+// will be returned for both.
+func Test_Encrypt_duplicate_keyIds(t *testing.T) {
+ ctx := context.Background()
+
+ setId := func(w *SealWrapper, keyId string) {
+ testWrapper := w.Wrapper.(*ToggleableWrapper).Wrapper.(*wrapping.TestWrapper)
+ testWrapper.SetKeyId(keyId)
+ }
+
+ getId := func(w *SealWrapper) string {
+ id, err := w.Wrapper.KeyId(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return id
+ }
+
+ access, _ := NewTestSeal(&TestSealOpts{WrapperCount: 3})
+
+ // Set up - make the key IDs the same for the last two wrappers
+ wrappers := access.GetAllSealWrappersByPriority()
+ setId(wrappers[1], "this-key-is-duplicated")
+ setId(wrappers[2], "this-key-is-duplicated")
+
+ // Some sanity checks
+ require.NotEqual(t, wrappers[0].Name, wrappers[1].Name)
+ require.NotEqual(t, wrappers[1].Name, wrappers[2].Name)
+ require.NotEqual(t, getId(wrappers[0]), getId(wrappers[1]))
+ require.Equal(t, getId(wrappers[1]), getId(wrappers[2]))
+
+ // Encrypt a value
+ mwv, errorMap := access.Encrypt(ctx, []byte("Rinconete y Cortadillo"))
+
+ // Assertions
+ require.NotNilf(t, mwv, "seal 0 should have succeeded")
+
+ requireDuplicateErr := func(w *SealWrapper) {
+ require.ErrorContains(t, errorMap[w.Name], fmt.Sprintf("seal %v has returned duplicate key ID", w.Name))
+ }
+ requireDuplicateErr(wrappers[1])
+ requireDuplicateErr(wrappers[2])
+}
diff --git a/vault/seal/seal_testing.go b/vault/seal/seal_testing.go
index 56a7bcb46cfb..f376564c2053 100644
--- a/vault/seal/seal_testing.go
+++ b/vault/seal/seal_testing.go
@@ -6,6 +6,7 @@ package seal
import (
"context"
"fmt"
+ UUID "github.com/hashicorp/go-uuid"
"sync"
"github.com/hashicorp/vault/sdk/helper/logging"
@@ -17,7 +18,7 @@ import (
type TestSealOpts struct {
Logger hclog.Logger
StoredKeys StoredKeysSupport
- Secret []byte
+ Secrets [][]byte
Name wrapping.WrapperType
WrapperCount int
Generation uint64
@@ -37,6 +38,29 @@ func NewTestSealOpts(opts *TestSealOpts) *TestSealOpts {
// we might at some point need to allow Generation == 0
opts.Generation = 1
}
+ switch len(opts.Secrets) {
+ case opts.WrapperCount:
+ // all good, each wrapper has its own secret
+
+ case 0:
+ if opts.WrapperCount == 1 {
+ // If there is only one wrapper, the default TestWrapper behaviour of reversing
+ // the bytes slice is fine.
+ opts.Secrets = [][]byte{nil}
+ } else {
+ // If there is more than one wrapper, each one needs a different secret
+ for i := 0; i < opts.WrapperCount; i++ {
+ uuid, err := UUID.GenerateUUID()
+ if err != nil {
+ panic(fmt.Sprintf("error generating secret: %v", err))
+ }
+ opts.Secrets = append(opts.Secrets, []byte(uuid))
+ }
+ }
+
+ default:
+ panic(fmt.Sprintf("wrong number of secrets %d vs %d wrappers", len(opts.Secrets), opts.WrapperCount))
+ }
return opts
}
@@ -46,7 +70,12 @@ func NewTestSeal(opts *TestSealOpts) (Access, []*ToggleableWrapper) {
sealWrappers := make([]*SealWrapper, opts.WrapperCount)
ctx := context.Background()
for i := 0; i < opts.WrapperCount; i++ {
- wrappers[i] = &ToggleableWrapper{Wrapper: wrapping.NewTestWrapper(opts.Secret)}
+ wrapperName := fmt.Sprintf("%s-%d", opts.Name, i+1)
+ wrappers[i] = &ToggleableWrapper{Wrapper: wrapping.NewTestWrapper(opts.Secrets[i])}
+ _, err := wrappers[i].Wrapper.SetConfig(context.Background(), wrapping.WithKeyId(wrapperName))
+ if err != nil {
+ panic(err)
+ }
wrapperType, err := wrappers[i].Type(ctx)
if err != nil {
panic(err)
@@ -54,7 +83,7 @@ func NewTestSeal(opts *TestSealOpts) (Access, []*ToggleableWrapper) {
sealWrappers[i] = NewSealWrapper(
wrappers[i],
i+1,
- fmt.Sprintf("%s-%d", opts.Name, i+1),
+ wrapperName,
wrapperType.String(),
false,
true,
@@ -75,77 +104,6 @@ type TestSealWrapperOpts struct {
WrapperCount int
}
-func CreateTestSealWrapperOpts(opts *TestSealWrapperOpts) *TestSealWrapperOpts {
- if opts == nil {
- opts = new(TestSealWrapperOpts)
- }
- if opts.WrapperCount == 0 {
- opts.WrapperCount = 1
- }
- if opts.Logger == nil {
- opts.Logger = logging.NewVaultLogger(hclog.Debug)
- }
- return opts
-}
-
-func CreateTestSealWrappers(opts *TestSealWrapperOpts) []*SealWrapper {
- opts = CreateTestSealWrapperOpts(opts)
- wrappers := make([]*ToggleableWrapper, opts.WrapperCount)
- sealWrappers := make([]*SealWrapper, opts.WrapperCount)
- ctx := context.Background()
- for i := 0; i < opts.WrapperCount; i++ {
- wrappers[i] = &ToggleableWrapper{Wrapper: wrapping.NewTestWrapper(opts.Secret)}
- wrapperType, err := wrappers[i].Type(ctx)
- if err != nil {
- panic(err)
- }
- sealWrappers[i] = NewSealWrapper(
- wrappers[i],
- i+1,
- fmt.Sprintf("%s-%d", opts.Name, i+1),
- wrapperType.String(),
- false,
- true,
- )
- }
-
- return sealWrappers
-}
-
-func NewToggleableTestSeal(opts *TestSealOpts) (Access, []func(error)) {
- opts = NewTestSealOpts(opts)
-
- wrappers := make([]*ToggleableWrapper, opts.WrapperCount)
- sealWrappers := make([]*SealWrapper, opts.WrapperCount)
- funcs := make([]func(error), opts.WrapperCount)
- ctx := context.Background()
- for i := 0; i < opts.WrapperCount; i++ {
- w := &ToggleableWrapper{Wrapper: wrapping.NewTestWrapper(opts.Secret)}
- wrapperType, err := w.Type(ctx)
- if err != nil {
- panic(err)
- }
-
- wrappers[i] = w
- sealWrappers[i] = NewSealWrapper(
- wrappers[i],
- i+1,
- fmt.Sprintf("%s-%d", opts.Name, i+1),
- wrapperType.String(),
- false,
- true,
- )
- funcs[i] = w.SetError
- }
-
- sealAccess, err := NewAccessFromSealWrappers(nil, opts.Generation, true, sealWrappers)
- if err != nil {
- panic(err)
- }
-
- return sealAccess, funcs
-}
-
type ToggleableWrapper struct {
wrapping.Wrapper
wrapperType *wrapping.WrapperType
diff --git a/vault/seal_autoseal_test.go b/vault/seal_autoseal_test.go
index d4f52ecc182e..e070471a35e3 100644
--- a/vault/seal_autoseal_test.go
+++ b/vault/seal_autoseal_test.go
@@ -183,7 +183,7 @@ func TestAutoSeal_HealthCheck(t *testing.T) {
metrics.NewGlobal(metricsConf, inmemSink)
pBackend := newTestBackend(t)
- testSealAccess, setErrs := seal.NewToggleableTestSeal(&seal.TestSealOpts{Name: "health-test"})
+ testSealAccess, wrappers := seal.NewTestSeal(&seal.TestSealOpts{Name: "health-test"})
core, _, _ := TestCoreUnsealedWithConfig(t, &CoreConfig{
MetricSink: metricsutil.NewClusterMetricSink("", inmemSink),
Physical: pBackend,
@@ -195,7 +195,7 @@ func TestAutoSeal_HealthCheck(t *testing.T) {
core.seal = autoSeal
autoSeal.StartHealthCheck()
defer autoSeal.StopHealthCheck()
- setErrs[0](errors.New("disconnected"))
+ wrappers[0].SetError(errors.New("disconnected"))
tries := 10
for tries = 10; tries > 0; tries-- {
@@ -208,7 +208,7 @@ func TestAutoSeal_HealthCheck(t *testing.T) {
t.Fatalf("Expected to detect unhealthy seals")
}
- setErrs[0](nil)
+ wrappers[0].SetError(nil)
time.Sleep(50 * time.Millisecond)
if !autoSeal.Healthy() {
t.Fatal("Expected seals to be healthy")
@@ -216,8 +216,8 @@ func TestAutoSeal_HealthCheck(t *testing.T) {
}
func TestAutoSeal_BarrierSealConfigType(t *testing.T) {
- singleWrapperAccess, _ := seal.NewToggleableTestSeal(&seal.TestSealOpts{WrapperCount: 1})
- multipleWrapperAccess, _ := seal.NewToggleableTestSeal(&seal.TestSealOpts{WrapperCount: 2})
+ singleWrapperAccess, _ := seal.NewTestSeal(&seal.TestSealOpts{WrapperCount: 1})
+ multipleWrapperAccess, _ := seal.NewTestSeal(&seal.TestSealOpts{WrapperCount: 2})
require.Equalf(t, singleWrapperAccess.GetAllSealWrappersByPriority()[0].SealConfigType, NewAutoSeal(singleWrapperAccess).BarrierSealConfigType().String(),
"autoseals that have a single seal wrapper report that wrapper's as the barrier seal type")
diff --git a/vault/seal_testing_util.go b/vault/seal_testing_util.go
index 6139ed25ebee..ea735b087505 100644
--- a/vault/seal_testing_util.go
+++ b/vault/seal_testing_util.go
@@ -10,6 +10,8 @@ import (
testing "github.com/mitchellh/go-testing-interface"
)
+// NewTestSeal creates a new seal for testing. If you want to use the same seal multiple times, such as for
+// a cluster, use NewTestSealFunc instead.
func NewTestSeal(t testing.T, opts *seal.TestSealOpts) Seal {
t.Helper()
opts = seal.NewTestSealOpts(opts)
@@ -50,3 +52,27 @@ func NewTestSeal(t testing.T, opts *seal.TestSealOpts) Seal {
return NewAutoSeal(access)
}
}
+
+// NewTestSealFunc returns a function that creates seals. All such seals will have TestWrappers that
+// share the same secret, thus making them equivalent.
+func NewTestSealFunc(t testing.T, opts *seal.TestSealOpts) func() Seal {
+ testSeal := NewTestSeal(t, opts)
+
+ return func() Seal {
+ return cloneTestSeal(t, testSeal)
+ }
+}
+
+// CloneTestSeal creates a new test seal that shares the same seal wrappers as `testSeal`.
+func cloneTestSeal(t testing.T, testSeal Seal) Seal {
+ logger := corehelpers.NewTestLogger(t).Named("sealAccess")
+
+ access, err := seal.NewAccessFromSealWrappers(logger, testSeal.GetAccess().Generation(), testSeal.GetAccess().GetSealGenerationInfo().IsRewrapped(), testSeal.GetAccess().GetAllSealWrappersByPriority())
+ if err != nil {
+ t.Fatal("error cloning seal %v", err)
+ }
+ if testSeal.StoredKeysSupported() == seal.StoredKeysNotSupported {
+ return NewDefaultSeal(access)
+ }
+ return NewAutoSeal(access)
+}
From 625cb00b61539cb265e79bce6d9e9c9cbb7de094 Mon Sep 17 00:00:00 2001
From: Victor Rodriguez
Date: Tue, 28 Nov 2023 10:37:28 -0500
Subject: [PATCH 30/74] Run make fmt. (#24272)
---
vault/seal/seal_test.go | 3 ++-
vault/seal/seal_testing.go | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/vault/seal/seal_test.go b/vault/seal/seal_test.go
index c5bc5224136a..75562431823a 100644
--- a/vault/seal/seal_test.go
+++ b/vault/seal/seal_test.go
@@ -6,9 +6,10 @@ package seal
import (
"context"
"fmt"
- "github.com/stretchr/testify/require"
"testing"
+ "github.com/stretchr/testify/require"
+
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
)
diff --git a/vault/seal/seal_testing.go b/vault/seal/seal_testing.go
index f376564c2053..db3a77ee79bb 100644
--- a/vault/seal/seal_testing.go
+++ b/vault/seal/seal_testing.go
@@ -6,9 +6,10 @@ package seal
import (
"context"
"fmt"
- UUID "github.com/hashicorp/go-uuid"
"sync"
+ UUID "github.com/hashicorp/go-uuid"
+
"github.com/hashicorp/vault/sdk/helper/logging"
"github.com/hashicorp/go-hclog"
From a823fdb3ef43cd2926a7f195e9890c16052fbf59 Mon Sep 17 00:00:00 2001
From: Tom Proctor
Date: Tue, 28 Nov 2023 17:35:00 +0000
Subject: [PATCH 31/74] testfix: Skip runsc test earlier (#24274)
---
vault/external_plugin_container_test.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/vault/external_plugin_container_test.go b/vault/external_plugin_container_test.go
index aeebd50e47f5..03aca4ca6d1a 100644
--- a/vault/external_plugin_container_test.go
+++ b/vault/external_plugin_container_test.go
@@ -74,12 +74,12 @@ func TestExternalPluginInContainer_MountAndUnmount(t *testing.T) {
})
t.Run("rootless runsc", func(t *testing.T) {
- t.Setenv("DOCKER_HOST", fmt.Sprintf("unix:///run/user/%d/docker.sock", os.Getuid()))
- c, plugins := testClusterWithContainerPlugins(t, []consts.PluginType{consts.PluginTypeCredential})
-
if _, err := exec.LookPath("runsc"); err != nil {
t.Skip("Skipping test as runsc not found on path")
}
+
+ t.Setenv("DOCKER_HOST", fmt.Sprintf("unix:///run/user/%d/docker.sock", os.Getuid()))
+ c, plugins := testClusterWithContainerPlugins(t, []consts.PluginType{consts.PluginTypeCredential})
mountAndUnmountContainerPlugin_WithRuntime(t, c, plugins[0], "runsc", true)
})
}
From e9f7c5bcefddc33aa06ae8a055c7d58afbfa30be Mon Sep 17 00:00:00 2001
From: Angel Garbarino
Date: Tue, 28 Nov 2023 10:56:33 -0700
Subject: [PATCH 32/74] Fix failing LDAP test with new attribute (#24273)
* add in new attribute to fix failing api test
* fix replication test failures
---
.../addon/templates/components/known-secondaries-card.hbs | 5 ++++-
ui/tests/acceptance/enterprise-replication-test.js | 2 +-
ui/tests/helpers/openapi/auth-model-attributes.js | 6 ++++++
3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/ui/lib/replication/addon/templates/components/known-secondaries-card.hbs b/ui/lib/replication/addon/templates/components/known-secondaries-card.hbs
index b25504e3c41b..f190d43ff5e1 100644
--- a/ui/lib/replication/addon/templates/components/known-secondaries-card.hbs
+++ b/ui/lib/replication/addon/templates/components/known-secondaries-card.hbs
@@ -18,7 +18,10 @@
{{else}}
-
+
diff --git a/ui/tests/acceptance/enterprise-replication-test.js b/ui/tests/acceptance/enterprise-replication-test.js
index ea70e3b97639..9a89204d587f 100644
--- a/ui/tests/acceptance/enterprise-replication-test.js
+++ b/ui/tests/acceptance/enterprise-replication-test.js
@@ -123,7 +123,7 @@ module('Acceptance | Enterprise | replication', function (hooks) {
await click('[data-test-replication-link="details"]');
assert
- .dom(`[data-test-secondaries=row-for-${secondaryName}]`)
+ .dom(`[data-test-secondaries-node=${secondaryName}]`)
.exists('shows a table row the recently added secondary');
// nav to DR
diff --git a/ui/tests/helpers/openapi/auth-model-attributes.js b/ui/tests/helpers/openapi/auth-model-attributes.js
index 50c86000057d..ec455509f736 100644
--- a/ui/tests/helpers/openapi/auth-model-attributes.js
+++ b/ui/tests/helpers/openapi/auth-model-attributes.js
@@ -822,6 +822,12 @@ const ldap = {
fieldGroup: 'default',
type: 'number',
},
+ passwordPolicy: {
+ editType: 'string',
+ fieldGroup: 'default',
+ helpText: 'Password policy to use to rotate the root password',
+ type: 'string',
+ },
requestTimeout: {
editType: 'ttl',
helpText:
From 78d756acdb98b7c9c7bcd8c4c1a7792c85545365 Mon Sep 17 00:00:00 2001
From: Scott Miller
Date: Tue, 28 Nov 2023 12:03:24 -0600
Subject: [PATCH 33/74] Provide a more reasonable error message for disabled
Shamir seals (#24275)
---
command/server.go | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/command/server.go b/command/server.go
index 9cf3f73bdb3e..3f5b78964ea9 100644
--- a/command/server.go
+++ b/command/server.go
@@ -2572,6 +2572,8 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
for _, c := range config.Seals {
if !c.Disabled {
allSealsDisabled = false
+ } else if c.Type == vault.SealConfigTypeShamir.String() {
+ return nil, errors.New("shamir seals cannot be set disabled (they should simply not be set)")
}
}
// If all seals are disabled assume they want to
@@ -2722,9 +2724,6 @@ func setSeal(c *ServerCommand, config *server.Config, infoKeys []string, info ma
return nil, errors.Join(sealConfigWarning, errors.New("no enabled Seals in configuration"))
case configuredSeals == 0:
return nil, errors.Join(sealConfigWarning, errors.New("no seals were successfully initialized"))
- case containsShamir(enabledSealWrappers) && containsShamir(disabledSealWrappers):
- return nil, errors.Join(sealConfigWarning, errors.New("shamir seals cannot be set disabled (they should simply not be set)"))
-
case len(enabledSealWrappers) == 1 && containsShamir(enabledSealWrappers):
// The barrier seal is Shamir. If there are any disabled seals, then we put them all in the same
// autoSeal.
From ef14ae87a5f0086b15de1b22f50a7ec6949bd65a Mon Sep 17 00:00:00 2001
From: Angel Garbarino
Date: Tue, 28 Nov 2023 14:00:28 -0700
Subject: [PATCH 34/74] Fix KV "View secret" or "View list" HDS button styling
(#24278)
* wip
* remove is-flex and put input on same different row
* remove wide
---
ui/lib/kv/addon/components/page/list.hbs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ui/lib/kv/addon/components/page/list.hbs b/ui/lib/kv/addon/components/page/list.hbs
index b0ce8be7dbe9..a7b5bb5d41fc 100644
--- a/ui/lib/kv/addon/components/page/list.hbs
+++ b/ui/lib/kv/addon/components/page/list.hbs
@@ -29,7 +29,7 @@
@cardTitle="View secret"
@subText="Type the path of the secret you want to view. Include a trailing slash to navigate to the list view."
>
-
\ No newline at end of file
diff --git a/ui/lib/kv/addon/components/kv-version-dropdown.hbs b/ui/lib/kv/addon/components/kv-version-dropdown.hbs
index f8170a1eb4b1..a5557d4ea69f 100644
--- a/ui/lib/kv/addon/components/kv-version-dropdown.hbs
+++ b/ui/lib/kv/addon/components/kv-version-dropdown.hbs
@@ -15,7 +15,7 @@
{{#each @metadata.sortedVersions as |versionData|}}
{{#if @onSelect}}
- {{! TODO Hds::Button manual update }}
+ {{! TODO use Hds::Dropdown instead https://helios.hashicorp.design/components/dropdown }}
Date: Thu, 30 Nov 2023 09:49:22 -0800
Subject: [PATCH 42/74] events: Add filters to keep track of local and other
subscriptions (#24201)
This adds a very basic implementation of a list of namespace+eventType
combinations that each node is interested in by just running the
glob operations in for-loops. Some parallelization is possible, but
not enabled by default.
It only wires up keeping track of what the local event bus is interested
in for now (but doesn't use it yet to filter messages).
Also updates the cloudevents source URL to indicate the Vault node that generated the event.
Co-authored-by: Tom Proctor
---
changelog/24201.txt | 3 +
vault/core.go | 6 +-
vault/eventbus/bus.go | 71 +++++++++++---------
vault/eventbus/bus_test.go | 29 +++++---
vault/eventbus/filter.go | 120 ++++++++++++++++++++++++++++++++++
vault/eventbus/filter_test.go | 31 +++++++++
6 files changed, 218 insertions(+), 42 deletions(-)
create mode 100644 changelog/24201.txt
create mode 100644 vault/eventbus/filter.go
create mode 100644 vault/eventbus/filter_test.go
diff --git a/changelog/24201.txt b/changelog/24201.txt
new file mode 100644
index 000000000000..9253e44ab8c0
--- /dev/null
+++ b/changelog/24201.txt
@@ -0,0 +1,3 @@
+```release-note:change
+events: Source URL is now `vault://{vault node}`
+```
diff --git a/vault/core.go b/vault/core.go
index 73a29f03ccfe..eff0e9cb1a43 100644
--- a/vault/core.go
+++ b/vault/core.go
@@ -1261,7 +1261,11 @@ func NewCore(conf *CoreConfig) (*Core, error) {
eventsLogger := conf.Logger.Named("events")
c.allLoggers = append(c.allLoggers, eventsLogger)
// start the event system
- events, err := eventbus.NewEventBus(eventsLogger)
+ nodeID, err := c.LoadNodeID()
+ if err != nil {
+ return nil, err
+ }
+ events, err := eventbus.NewEventBus(nodeID, eventsLogger)
if err != nil {
return nil, err
}
diff --git a/vault/eventbus/bus.go b/vault/eventbus/bus.go
index 0185e9fbadf4..fd5102ad8f6d 100644
--- a/vault/eventbus/bus.go
+++ b/vault/eventbus/bus.go
@@ -35,9 +35,8 @@ const (
)
var (
- ErrNotStarted = errors.New("event broker has not been started")
- cloudEventsFormatterFilter *cloudevents.FormatterFilter
- subscriptions atomic.Int64 // keeps track of event subscription count in all event buses
+ ErrNotStarted = errors.New("event broker has not been started")
+ subscriptions atomic.Int64 // keeps track of event subscription count in all event buses
// these metadata fields will have the plugin mount path prepended to them
metadataPrependPathFields = []string{
@@ -49,11 +48,13 @@ var (
// EventBus contains the main logic of running an event broker for Vault.
// Start() must be called before the EventBus will accept events for sending.
type EventBus struct {
- logger hclog.Logger
- broker *eventlogger.Broker
- started atomic.Bool
- formatterNodeID eventlogger.NodeID
- timeout time.Duration
+ logger hclog.Logger
+ broker *eventlogger.Broker
+ started atomic.Bool
+ formatterNodeID eventlogger.NodeID
+ timeout time.Duration
+ filters *Filters
+ cloudEventsFormatterFilter *cloudevents.FormatterFilter
}
type pluginEventBus struct {
@@ -72,6 +73,7 @@ type asyncChanNode struct {
closeOnce sync.Once
cancelFunc context.CancelFunc
pipelineID eventlogger.PipelineID
+ removeFilter func()
removePipeline func(ctx context.Context, t eventlogger.EventType, id eventlogger.PipelineID) (bool, error)
}
@@ -162,21 +164,7 @@ func (bus *pluginEventBus) SendEvent(ctx context.Context, eventType logical.Even
return bus.bus.SendEventInternal(ctx, bus.namespace, bus.pluginInfo, eventType, data)
}
-func init() {
- // TODO: maybe this should relate to the Vault core somehow?
- sourceUrl, err := url.Parse("https://vaultproject.io/")
- if err != nil {
- panic(err)
- }
- cloudEventsFormatterFilter = &cloudevents.FormatterFilter{
- Source: sourceUrl,
- Predicate: func(_ context.Context, e interface{}) (bool, error) {
- return true, nil
- },
- }
-}
-
-func NewEventBus(logger hclog.Logger) (*EventBus, error) {
+func NewEventBus(localNodeID string, logger hclog.Logger) (*EventBus, error) {
broker, err := eventlogger.NewBroker()
if err != nil {
return nil, err
@@ -192,11 +180,25 @@ func NewEventBus(logger hclog.Logger) (*EventBus, error) {
logger = hclog.Default().Named("events")
}
+ sourceUrl, err := url.Parse("vault://" + localNodeID)
+ if err != nil {
+ return nil, err
+ }
+
+ cloudEventsFormatterFilter := &cloudevents.FormatterFilter{
+ Source: sourceUrl,
+ Predicate: func(_ context.Context, e interface{}) (bool, error) {
+ return true, nil
+ },
+ }
+
return &EventBus{
- logger: logger,
- broker: broker,
- formatterNodeID: formatterNodeID,
- timeout: defaultTimeout,
+ logger: logger,
+ broker: broker,
+ formatterNodeID: formatterNodeID,
+ timeout: defaultTimeout,
+ cloudEventsFormatterFilter: cloudEventsFormatterFilter,
+ filters: NewFilters(localNodeID),
}, nil
}
@@ -215,7 +217,7 @@ func (bus *EventBus) SubscribeMultipleNamespaces(ctx context.Context, namespaceP
return nil, nil, err
}
- err = bus.broker.RegisterNode(bus.formatterNodeID, cloudEventsFormatterFilter)
+ err = bus.broker.RegisterNode(bus.formatterNodeID, bus.cloudEventsFormatterFilter)
if err != nil {
return nil, nil, err
}
@@ -240,7 +242,12 @@ func (bus *EventBus) SubscribeMultipleNamespaces(ctx context.Context, namespaceP
}
ctx, cancel := context.WithCancel(ctx)
- asyncNode := newAsyncNode(ctx, bus.logger, bus.broker)
+
+ bus.filters.addPattern(bus.filters.self, namespacePathPatterns, pattern)
+
+ asyncNode := newAsyncNode(ctx, bus.logger, bus.broker, func() {
+ bus.filters.removePattern(bus.filters.self, namespacePathPatterns, pattern)
+ })
err = bus.broker.RegisterNode(eventlogger.NodeID(sinkNodeID), asyncNode)
if err != nil {
defer cancel()
@@ -301,7 +308,7 @@ func newFilterNode(namespacePatterns []string, pattern string, bexprFilter strin
}
}
- // Filter for correct event type, including wildcards.
+ // NodeFilter for correct event type, including wildcards.
if !glob.Glob(pattern, eventRecv.EventType) {
return false, nil
}
@@ -315,11 +322,12 @@ func newFilterNode(namespacePatterns []string, pattern string, bexprFilter strin
}, nil
}
-func newAsyncNode(ctx context.Context, logger hclog.Logger, broker *eventlogger.Broker) *asyncChanNode {
+func newAsyncNode(ctx context.Context, logger hclog.Logger, broker *eventlogger.Broker, removeFilter func()) *asyncChanNode {
return &asyncChanNode{
ctx: ctx,
ch: make(chan *eventlogger.Event),
logger: logger,
+ removeFilter: removeFilter,
removePipeline: broker.RemovePipelineAndNodes,
}
}
@@ -328,6 +336,7 @@ func newAsyncNode(ctx context.Context, logger hclog.Logger, broker *eventlogger.
func (node *asyncChanNode) Close(ctx context.Context) {
node.closeOnce.Do(func() {
defer node.cancelFunc()
+ node.removeFilter()
removed, err := node.removePipeline(ctx, eventTypeAll, node.pipelineID)
switch {
diff --git a/vault/eventbus/bus_test.go b/vault/eventbus/bus_test.go
index d6e5c9c9cbaf..0255f7fe8678 100644
--- a/vault/eventbus/bus_test.go
+++ b/vault/eventbus/bus_test.go
@@ -23,7 +23,7 @@ import (
// TestBusBasics tests that basic event sending and subscribing function.
func TestBusBasics(t *testing.T) {
- bus, err := NewEventBus(nil)
+ bus, err := NewEventBus("", nil)
if err != nil {
t.Fatal(err)
}
@@ -78,7 +78,7 @@ func TestBusBasics(t *testing.T) {
// TestBusIgnoresSendContext tests that the context is ignored when sending to an event,
// so that we do not give up too quickly.
func TestBusIgnoresSendContext(t *testing.T) {
- bus, err := NewEventBus(nil)
+ bus, err := NewEventBus("", nil)
if err != nil {
t.Fatal(err)
}
@@ -119,7 +119,7 @@ func TestBusIgnoresSendContext(t *testing.T) {
// TestSubscribeNonRootNamespace verifies that events for non-root namespaces
// aren't filtered out by the bus.
func TestSubscribeNonRootNamespace(t *testing.T) {
- bus, err := NewEventBus(nil)
+ bus, err := NewEventBus("", nil)
if err != nil {
t.Fatal(err)
}
@@ -162,7 +162,7 @@ func TestSubscribeNonRootNamespace(t *testing.T) {
// TestNamespaceFiltering verifies that events for other namespaces are filtered out by the bus.
func TestNamespaceFiltering(t *testing.T) {
- bus, err := NewEventBus(nil)
+ bus, err := NewEventBus("", nil)
if err != nil {
t.Fatal(err)
}
@@ -222,7 +222,7 @@ func TestNamespaceFiltering(t *testing.T) {
// TestBus2Subscriptions verifies that events of different types are successfully routed to the correct subscribers.
func TestBus2Subscriptions(t *testing.T) {
- bus, err := NewEventBus(nil)
+ bus, err := NewEventBus("", nil)
if err != nil {
t.Fatal(err)
}
@@ -293,7 +293,7 @@ func TestBusSubscriptionsCancel(t *testing.T) {
for _, tc := range testCases {
t.Run(fmt.Sprintf("cancel=%v", tc.cancel), func(t *testing.T) {
subscriptions.Store(0)
- bus, err := NewEventBus(nil)
+ bus, err := NewEventBus("", nil)
if err != nil {
t.Fatal(err)
}
@@ -396,7 +396,7 @@ func waitFor(t *testing.T, maxWait time.Duration, f func() bool) {
// TestBusWildcardSubscriptions tests that a single subscription can receive
// multiple event types using * for glob patterns.
func TestBusWildcardSubscriptions(t *testing.T) {
- bus, err := NewEventBus(nil)
+ bus, err := NewEventBus("", nil)
if err != nil {
t.Fatal(err)
}
@@ -471,7 +471,7 @@ func TestBusWildcardSubscriptions(t *testing.T) {
// TestDataPathIsPrependedWithMount tests that "data_path", if present in the
// metadata, is prepended with the plugin's mount.
func TestDataPathIsPrependedWithMount(t *testing.T) {
- bus, err := NewEventBus(nil)
+ bus, err := NewEventBus("", nil)
if err != nil {
t.Fatal(err)
}
@@ -591,7 +591,7 @@ func TestDataPathIsPrependedWithMount(t *testing.T) {
// TestBexpr tests go-bexpr filters are evaluated on an event.
func TestBexpr(t *testing.T) {
- bus, err := NewEventBus(nil)
+ bus, err := NewEventBus("", nil)
if err != nil {
t.Fatal(err)
}
@@ -671,7 +671,7 @@ func TestBexpr(t *testing.T) {
// TestPipelineCleanedUp ensures pipelines are properly cleaned up after
// subscriptions are closed.
func TestPipelineCleanedUp(t *testing.T) {
- bus, err := NewEventBus(nil)
+ bus, err := NewEventBus("", nil)
if err != nil {
t.Fatal(err)
}
@@ -683,6 +683,10 @@ func TestPipelineCleanedUp(t *testing.T) {
if err != nil {
t.Fatal(err)
}
+ // check that the filters are set
+ if !bus.filters.anyMatch(namespace.RootNamespace, eventType) {
+ t.Fatal()
+ }
if !bus.broker.IsAnyPipelineRegistered(eventTypeAll) {
cancel()
t.Fatal()
@@ -693,4 +697,9 @@ func TestPipelineCleanedUp(t *testing.T) {
if bus.broker.IsAnyPipelineRegistered(eventTypeAll) {
t.Fatal()
}
+
+ // and that the filters are cleaned up
+ if bus.filters.anyMatch(namespace.RootNamespace, eventType) {
+ t.Fatal()
+ }
}
diff --git a/vault/eventbus/filter.go b/vault/eventbus/filter.go
new file mode 100644
index 000000000000..7d4268aacfe8
--- /dev/null
+++ b/vault/eventbus/filter.go
@@ -0,0 +1,120 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package eventbus
+
+import (
+ "slices"
+ "sort"
+ "sync"
+
+ "github.com/hashicorp/vault/helper/namespace"
+ "github.com/hashicorp/vault/sdk/logical"
+ "github.com/ryanuber/go-glob"
+)
+
+// Filters keeps track of all the event patterns that each node is interested in.
+type Filters struct {
+ lock sync.RWMutex
+ self nodeID
+ filters map[nodeID]*NodeFilter
+}
+
+// nodeID is used to syntactically indicate that the string is a node's name identifier.
+type nodeID string
+
+// pattern is used to represent one or more combinations of patterns
+type pattern struct {
+ eventTypePattern string
+ namespacePatterns []string
+}
+
+// NodeFilter keeps track of all patterns that a particular node is interested in.
+type NodeFilter struct {
+ patterns []pattern
+}
+
+func (nf *NodeFilter) match(ns *namespace.Namespace, eventType logical.EventType) bool {
+ if nf == nil {
+ return false
+ }
+ for _, p := range nf.patterns {
+ if glob.Glob(p.eventTypePattern, string(eventType)) {
+ for _, nsp := range p.namespacePatterns {
+ if glob.Glob(nsp, ns.Path) {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
+// NewFilters creates an empty set of filters to keep track of each node's pattern interests.
+func NewFilters(self string) *Filters {
+ return &Filters{
+ self: nodeID(self),
+ filters: map[nodeID]*NodeFilter{},
+ }
+}
+
+// addPattern adds a pattern to a node's list.
+func (f *Filters) addPattern(node nodeID, namespacePatterns []string, eventTypePattern string) {
+ f.lock.Lock()
+ defer f.lock.Unlock()
+ if _, ok := f.filters[node]; !ok {
+ f.filters[node] = &NodeFilter{}
+ }
+ nsPatterns := slices.Clone(namespacePatterns)
+ sort.Strings(nsPatterns)
+ f.filters[node].patterns = append(f.filters[node].patterns, pattern{eventTypePattern: eventTypePattern, namespacePatterns: nsPatterns})
+}
+
+func (f *Filters) addNsPattern(node nodeID, ns *namespace.Namespace, eventTypePattern string) {
+ f.addPattern(node, []string{ns.Path}, eventTypePattern)
+}
+
+// removePattern removes a pattern from a node's list.
+func (f *Filters) removePattern(node nodeID, namespacePatterns []string, eventTypePattern string) {
+ nsPatterns := slices.Clone(namespacePatterns)
+ sort.Strings(nsPatterns)
+ check := pattern{eventTypePattern: eventTypePattern, namespacePatterns: nsPatterns}
+ f.lock.Lock()
+ defer f.lock.Unlock()
+ filters, ok := f.filters[node]
+ if !ok {
+ return
+ }
+ filters.patterns = slices.DeleteFunc(filters.patterns, func(m pattern) bool {
+ return m.eventTypePattern == check.eventTypePattern &&
+ slices.Equal(m.namespacePatterns, check.namespacePatterns)
+ })
+}
+
+func (f *Filters) removeNsPattern(node nodeID, ns *namespace.Namespace, eventTypePattern string) {
+ f.removePattern(node, []string{ns.Path}, eventTypePattern)
+}
+
+// anyMatch returns true if any node's pattern list matches the arguments.
+func (f *Filters) anyMatch(ns *namespace.Namespace, eventType logical.EventType) bool {
+ f.lock.RLock()
+ defer f.lock.RUnlock()
+ for _, nf := range f.filters {
+ if nf.match(ns, eventType) {
+ return true
+ }
+ }
+ return false
+}
+
+// nodeMatch returns true if the given node's pattern list matches the arguments.
+func (f *Filters) nodeMatch(node nodeID, ns *namespace.Namespace, eventType logical.EventType) bool {
+ f.lock.RLock()
+ defer f.lock.RUnlock()
+ return f.filters[node].match(ns, eventType)
+}
+
+// localMatch returns true if the local node's pattern list matches the arguments.
+func (f *Filters) localMatch(ns *namespace.Namespace, eventType logical.EventType) bool {
+ return f.nodeMatch(f.self, ns, eventType)
+}
diff --git a/vault/eventbus/filter_test.go b/vault/eventbus/filter_test.go
new file mode 100644
index 000000000000..034fb74f95a6
--- /dev/null
+++ b/vault/eventbus/filter_test.go
@@ -0,0 +1,31 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package eventbus
+
+import (
+ "testing"
+
+ "github.com/hashicorp/vault/helper/namespace"
+ "github.com/stretchr/testify/assert"
+)
+
+// TestFilters_AddRemoveMatchLocal checks that basic matching, adding, and removing of patterns all work.
+func TestFilters_AddRemoveMatchLocal(t *testing.T) {
+ f := NewFilters("self")
+ ns := &namespace.Namespace{
+ ID: "ns1",
+ Path: "ns1",
+ }
+
+ assert.False(t, f.localMatch(ns, "abc"))
+ assert.False(t, f.anyMatch(ns, "abc"))
+ f.addNsPattern("self", ns, "abc")
+ assert.True(t, f.localMatch(ns, "abc"))
+ assert.False(t, f.localMatch(ns, "abcd"))
+ assert.True(t, f.anyMatch(ns, "abc"))
+ assert.False(t, f.anyMatch(ns, "abcd"))
+ f.removeNsPattern("self", ns, "abc")
+ assert.False(t, f.localMatch(ns, "abc"))
+ assert.False(t, f.anyMatch(ns, "abc"))
+}
From 3ae669df34c7789a394ff81d935203b9dc30bc14 Mon Sep 17 00:00:00 2001
From: Peter Wilson
Date: Thu, 30 Nov 2023 19:30:31 +0000
Subject: [PATCH 43/74] Bump the `node` version (#24304)
* make node happy
* Updated package-lock.json for website
---
website/.nvmrc | 2 +-
website/package-lock.json | 2 +-
website/package.json | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/website/.nvmrc b/website/.nvmrc
index 958b5a36e1fa..3f430af82b3d 100644
--- a/website/.nvmrc
+++ b/website/.nvmrc
@@ -1 +1 @@
-v14
+v18
diff --git a/website/package-lock.json b/website/package-lock.json
index 79339e660dbc..ccdff66fdbaa 100644
--- a/website/package-lock.json
+++ b/website/package-lock.json
@@ -17,7 +17,7 @@
"simple-git-hooks": "^2.6.1"
},
"engines": {
- "node": ">=12.0.0 <= 16.x",
+ "node": ">=12.0.0 <= 18.x",
"npm": ">=7.0.0"
}
},
diff --git a/website/package.json b/website/package.json
index 3e8666fe3e40..5e85e591969a 100644
--- a/website/package.json
+++ b/website/package.json
@@ -13,7 +13,7 @@
},
"engines": {
"npm": ">=7.0.0",
- "node": ">=12.0.0 <= 16.x"
+ "node": ">=12.0.0 <= 18.x"
},
"repository": {
"type": "git",
From f5622a677a502c156c8cdb6f0d37c9b8fad5c96c Mon Sep 17 00:00:00 2001
From: Raymond Ho
Date: Thu, 30 Nov 2023 12:05:25 -0800
Subject: [PATCH 44/74] bump eventlogger dependency to v0.2.7 (#24305)
---
changelog/24305.txt | 3 +++
go.mod | 2 +-
go.sum | 2 ++
3 files changed, 6 insertions(+), 1 deletion(-)
create mode 100644 changelog/24305.txt
diff --git a/changelog/24305.txt b/changelog/24305.txt
new file mode 100644
index 000000000000..5fcde924fae2
--- /dev/null
+++ b/changelog/24305.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+eventlogger: Update library to v0.2.7 to address race condition
+```
diff --git a/go.mod b/go.mod
index af061c00cf87..47b75c30ae6b 100644
--- a/go.mod
+++ b/go.mod
@@ -81,7 +81,7 @@ require (
github.com/hashicorp/consul-template v0.33.0
github.com/hashicorp/consul/api v1.23.0
github.com/hashicorp/errwrap v1.1.0
- github.com/hashicorp/eventlogger v0.2.5
+ github.com/hashicorp/eventlogger v0.2.7
github.com/hashicorp/go-bexpr v0.1.12
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/hashicorp/go-discover v0.0.0-20210818145131-c573d69da192
diff --git a/go.sum b/go.sum
index e3cc17821671..deed96295782 100644
--- a/go.sum
+++ b/go.sum
@@ -2147,6 +2147,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/eventlogger v0.2.5 h1:Z2hqgJDNHAewz/kmluhpOWuC2Ts5JzF3mXt6N5MTr6U=
github.com/hashicorp/eventlogger v0.2.5/go.mod h1://CHt6/j+Q2lc0NlUB5af4aS2M0c0aVBg9/JfcpAyhM=
+github.com/hashicorp/eventlogger v0.2.7 h1:6Y0lpWa7UUbVTsldIQNAeHfgs12iZJmEVapkPbYBEFE=
+github.com/hashicorp/eventlogger v0.2.7/go.mod h1://CHt6/j+Q2lc0NlUB5af4aS2M0c0aVBg9/JfcpAyhM=
github.com/hashicorp/go-bexpr v0.1.12 h1:XrdVhmwu+9iYxIUWxsGVG7NQwrhzJZ0vR6nbN5bLgrA=
github.com/hashicorp/go-bexpr v0.1.12/go.mod h1:ACktpcSySkFNpcxWSClFrut7wicd9WzisnvHuw+g9K8=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
From 9ddc33ab98c2c4f5a6cf875bea0457525a15cc76 Mon Sep 17 00:00:00 2001
From: Angel Garbarino
Date: Thu, 30 Nov 2023 13:46:39 -0700
Subject: [PATCH 45/74] Fixes redirects to KV engine when secret is a directory
(#24281)
* fix
* changelog
* Update 24281.txt
* add test coverage
* dont make assumptions about list
---
changelog/24281.txt | 3 +++
ui/app/components/dashboard/quick-actions-card.js | 2 +-
ui/app/routes/vault/cluster/secrets/backend/list.js | 4 ++++
.../secrets/backend/kv/kv-v2-workflow-navigation-test.js | 7 +++++++
4 files changed, 15 insertions(+), 1 deletion(-)
create mode 100644 changelog/24281.txt
diff --git a/changelog/24281.txt b/changelog/24281.txt
new file mode 100644
index 000000000000..7d24c296a1f2
--- /dev/null
+++ b/changelog/24281.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+ui: Correctly handle directory redirects from pre 1.15.0 Kv v2 list view urls.
+```
diff --git a/ui/app/components/dashboard/quick-actions-card.js b/ui/app/components/dashboard/quick-actions-card.js
index 57a524c3adc8..6247790f757a 100644
--- a/ui/app/components/dashboard/quick-actions-card.js
+++ b/ui/app/components/dashboard/quick-actions-card.js
@@ -140,7 +140,7 @@ export default class DashboardQuickActionsCard extends Component {
@action
navigateToPage() {
let route = this.searchSelectParams.route;
- // If search-select falls back to stringInput, paramVlue is a string not object
+ // If search-select falls back to stringInput, paramValue is a string not object
let param = this.paramValue.id || this.paramValue;
// kv has a special use case where if the paramValue ends in a '/' you should
diff --git a/ui/app/routes/vault/cluster/secrets/backend/list.js b/ui/app/routes/vault/cluster/secrets/backend/list.js
index 85feb1662f79..c1db7504a545 100644
--- a/ui/app/routes/vault/cluster/secrets/backend/list.js
+++ b/ui/app/routes/vault/cluster/secrets/backend/list.js
@@ -11,6 +11,7 @@ import { allEngines, isAddonEngine } from 'vault/helpers/mountable-secret-engine
import { inject as service } from '@ember/service';
import { normalizePath } from 'vault/utils/path-encoding-helpers';
import { assert } from '@ember/debug';
+import { pathIsDirectory } from 'kv/utils/kv-breadcrumbs';
const SUPPORTED_BACKENDS = supportedSecretBackends();
@@ -77,6 +78,9 @@ export default Route.extend({
return this.router.replaceWith('vault.cluster.secrets.backend.list', secret + '/');
}
if (isAddonEngine(type, secretEngine.version)) {
+ if (engineRoute === 'kv.list' && pathIsDirectory(secret)) {
+ return this.router.transitionTo('vault.cluster.secrets.backend.kv.list-directory', backend, secret);
+ }
return this.router.transitionTo(`vault.cluster.secrets.backend.${engineRoute}`, backend);
}
const modelType = this.getModelType(backend, tab);
diff --git a/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-navigation-test.js b/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-navigation-test.js
index 54327e8d350c..24586a99e5ad 100644
--- a/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-navigation-test.js
+++ b/ui/tests/acceptance/secrets/backend/kv/kv-v2-workflow-navigation-test.js
@@ -207,6 +207,13 @@ module('Acceptance | kv-v2 workflow | navigation', function (hooks) {
await click(PAGE.breadcrumbAtIdx(1));
assert.ok(currentURL().startsWith(`/vault/secrets/${backend}/kv/list`), 'links back to list root');
});
+ test('is redirects to nested secret using old non-engine url (a)', async function (assert) {
+ // Reported bug, backported fix https://github.com/hashicorp/vault/pull/24281
+ assert.expect(1);
+ const backend = this.backend;
+ await visit(`/vault/secrets/${backend}/list/app/`);
+ assert.strictEqual(currentURL(), `/vault/secrets/${backend}/kv/list/app/`);
+ });
test('versioned secret nav, tabs, breadcrumbs (a)', async function (assert) {
assert.expect(45);
const backend = this.backend;
From 638522ebac23446c9482c3c61c8ef37a05edc7a6 Mon Sep 17 00:00:00 2001
From: Rachel Culpepper <84159930+rculpepper@users.noreply.github.com>
Date: Thu, 30 Nov 2023 16:08:13 -0500
Subject: [PATCH 46/74] Vault-18638: add seal reload on SIGHUP (#23571)
* reload seals on SIGHUP
* add lock in SetSeals
* move lock
* use stubmaker and change wrapper finalize call
* change finalize logic so that old seals will be finalized after new seals are configured
* add changelog
* run make fmt
* fix fmt
* fix panic when reloading seals errors out
---
changelog/23571.txt | 4 ++
command/server.go | 146 +++++++++++++++++++++++++++-------------
command/server_test.go | 48 +++++++++++++
vault/core.go | 43 ++++++++++++
vault/core_stubs_oss.go | 11 ++-
vault/core_test.go | 42 ++++++++++++
6 files changed, 247 insertions(+), 47 deletions(-)
create mode 100644 changelog/23571.txt
diff --git a/changelog/23571.txt b/changelog/23571.txt
new file mode 100644
index 000000000000..62185d25b4d5
--- /dev/null
+++ b/changelog/23571.txt
@@ -0,0 +1,4 @@
+```release-note:feature
+**Reload seal configuration on SIGHUP**: Seal configuration is reloaded on SIGHUP so that seal configuration can
+be changed without shutting down vault
+```
diff --git a/command/server.go b/command/server.go
index 3f5b78964ea9..066b0859ad9e 100644
--- a/command/server.go
+++ b/command/server.go
@@ -1238,58 +1238,15 @@ func (c *ServerCommand) Run(args []string) int {
}
ctx := context.Background()
- existingSealGenerationInfo, err := vault.PhysicalSealGenInfo(ctx, backend)
- if err != nil {
- c.UI.Error(fmt.Sprintf("Error getting seal generation info: %v", err))
- return 1
- }
- hasPartialPaths, err := hasPartiallyWrappedPaths(ctx, backend)
- if err != nil {
- c.UI.Error(fmt.Sprintf("Cannot determine if there are partially seal wrapped entries in storage: %v", err))
- return 1
- }
- setSealResponse, err := setSeal(c, config, infoKeys, info, existingSealGenerationInfo, hasPartialPaths)
+ setSealResponse, secureRandomReader, err := c.configureSeals(ctx, config, backend, infoKeys, info)
if err != nil {
c.UI.Error(err.Error())
return 1
}
- if setSealResponse.sealConfigWarning != nil {
- c.UI.Warn(fmt.Sprintf("Warnings during seal configuration: %v", setSealResponse.sealConfigWarning))
- }
- for _, seal := range setSealResponse.getCreatedSeals() {
- seal := seal // capture range variable
- // Ensure that the seal finalizer is called, even if using verify-only
- defer func(seal *vault.Seal) {
- err = (*seal).Finalize(ctx)
- if err != nil {
- c.UI.Error(fmt.Sprintf("Error finalizing seals: %v", err))
- }
- }(seal)
- }
-
- if setSealResponse.barrierSeal == nil {
- c.UI.Error("Could not create barrier seal! Most likely proper Seal configuration information was not set, but no error was generated.")
- return 1
- }
-
- // prepare a secure random reader for core
- entropyAugLogger := c.logger.Named("entropy-augmentation")
- var entropySources []*configutil.EntropySourcerInfo
- for _, sealWrapper := range setSealResponse.barrierSeal.GetAccess().GetEnabledSealWrappersByPriority() {
- if s, ok := sealWrapper.Wrapper.(entropy.Sourcer); ok {
- entropySources = append(entropySources, &configutil.EntropySourcerInfo{
- Sourcer: s,
- Name: sealWrapper.Name,
- })
- }
- }
- secureRandomReader, err := configutil.CreateSecureRandomReaderFunc(config.SharedConfig, entropySources, entropyAugLogger)
- if err != nil {
- c.UI.Error(err.Error())
- return 1
- }
+ currentSeals := setSealResponse.getCreatedSeals()
+ defer c.finalizeSeals(ctx, ¤tSeals)
coreConfig := createCoreConfig(c, config, backend, configSR, setSealResponse.barrierSeal, setSealResponse.unwrapSeal, metricsHelper, metricSink, secureRandomReader)
if c.flagDevThreeNode {
@@ -1680,6 +1637,18 @@ func (c *ServerCommand) Run(args []string) int {
c.logger.Warn(cErr.String())
}
+ if !cmp.Equal(core.GetCoreConfigInternal().Seals, config.Seals) {
+ setSealResponse, err = c.reloadSeals(ctx, core, config)
+ if err != nil {
+ c.UI.Error(fmt.Errorf("error reloading seal config: %s", err).Error())
+ config.Seals = core.GetCoreConfigInternal().Seals
+ } else {
+ // finalize the old seals and set the new seals as the current ones
+ c.finalizeSeals(ctx, ¤tSeals)
+ currentSeals = setSealResponse.getCreatedSeals()
+ }
+ }
+
core.SetConfig(config)
// reloading custom response headers to make sure we have
@@ -1836,6 +1805,57 @@ func (c *ServerCommand) Run(args []string) int {
return retCode
}
+func (c *ServerCommand) configureSeals(ctx context.Context, config *server.Config, backend physical.Backend, infoKeys []string, info map[string]string) (*SetSealResponse, io.Reader, error) {
+ existingSealGenerationInfo, err := vault.PhysicalSealGenInfo(ctx, backend)
+ if err != nil {
+ return nil, nil, fmt.Errorf("Error getting seal generation info: %v", err)
+ }
+
+ hasPartialPaths, err := hasPartiallyWrappedPaths(ctx, backend)
+ if err != nil {
+ return nil, nil, fmt.Errorf("Cannot determine if there are partially seal wrapped entries in storage: %v", err)
+ }
+ setSealResponse, err := setSeal(c, config, infoKeys, info, existingSealGenerationInfo, hasPartialPaths)
+ if err != nil {
+ return nil, nil, err
+ }
+ if setSealResponse.sealConfigWarning != nil {
+ c.UI.Warn(fmt.Sprintf("Warnings during seal configuration: %v", setSealResponse.sealConfigWarning))
+ }
+
+ if setSealResponse.barrierSeal == nil {
+ return nil, nil, errors.New("Could not create barrier seal! Most likely proper Seal configuration information was not set, but no error was generated.")
+ }
+
+ // prepare a secure random reader for core
+ entropyAugLogger := c.logger.Named("entropy-augmentation")
+ var entropySources []*configutil.EntropySourcerInfo
+ for _, sealWrapper := range setSealResponse.barrierSeal.GetAccess().GetEnabledSealWrappersByPriority() {
+ if s, ok := sealWrapper.Wrapper.(entropy.Sourcer); ok {
+ entropySources = append(entropySources, &configutil.EntropySourcerInfo{
+ Sourcer: s,
+ Name: sealWrapper.Name,
+ })
+ }
+ }
+ secureRandomReader, err := configutil.CreateSecureRandomReaderFunc(config.SharedConfig, entropySources, entropyAugLogger)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return setSealResponse, secureRandomReader, nil
+}
+
+func (c *ServerCommand) finalizeSeals(ctx context.Context, seals *[]*vault.Seal) {
+ for _, seal := range *seals {
+ // Ensure that the seal finalizer is called, even if using verify-only
+ err := (*seal).Finalize(ctx)
+ if err != nil {
+ c.UI.Error(fmt.Sprintf("Error finalizing seals: %v", err))
+ }
+ }
+}
+
// configureLogging takes the configuration and attempts to parse config values into 'log' friendly configuration values
// If all goes to plan, a logger is created and setup.
func (c *ServerCommand) configureLogging(config *server.Config) (hclog.InterceptLogger, error) {
@@ -3294,6 +3314,40 @@ func startHttpServers(c *ServerCommand, core *vault.Core, config *server.Config,
return nil
}
+func (c *ServerCommand) reloadSeals(ctx context.Context, core *vault.Core, config *server.Config) (*SetSealResponse, error) {
+ if len(config.Seals) == 1 && config.Seals[0].Disabled {
+ return nil, errors.New("moving from autoseal to shamir requires seal migration")
+ }
+
+ if core.SealAccess().BarrierSealConfigType() == vault.SealConfigTypeShamir {
+ return nil, errors.New("moving from shamir to autoseal requires seal migration")
+ }
+
+ infoKeysReload := make([]string, 0)
+ infoReload := make(map[string]string)
+
+ setSealResponse, secureRandomReader, err := c.configureSeals(ctx, config, core.PhysicalAccess(), infoKeysReload, infoReload)
+ if err != nil {
+ return nil, err
+ }
+ if setSealResponse.sealConfigError != nil {
+ return nil, err
+ }
+
+ err = core.SetSeals(setSealResponse.barrierSeal, secureRandomReader)
+ if err != nil {
+ return nil, fmt.Errorf("error setting seal: %s", err)
+ }
+
+ newGen := setSealResponse.barrierSeal.GetAccess().GetSealGenerationInfo()
+
+ if err := core.SetPhysicalSealGenInfo(ctx, newGen); err != nil {
+ c.logger.Warn("could not update seal information in storage", "err", err)
+ }
+
+ return setSealResponse, nil
+}
+
func SetStorageMigration(b physical.Backend, active bool) error {
if !active {
return b.Delete(context.Background(), storageMigrationLock)
diff --git a/command/server_test.go b/command/server_test.go
index 677705176bb4..62e2a99e2ac6 100644
--- a/command/server_test.go
+++ b/command/server_test.go
@@ -11,6 +11,7 @@
package command
import (
+ "context"
"crypto/tls"
"crypto/x509"
"fmt"
@@ -21,8 +22,13 @@ import (
"testing"
"time"
+ "github.com/hashicorp/vault/command/server"
+ "github.com/hashicorp/vault/helper/testhelpers/corehelpers"
+ "github.com/hashicorp/vault/internalshared/configutil"
"github.com/hashicorp/vault/sdk/physical"
physInmem "github.com/hashicorp/vault/sdk/physical/inmem"
+ "github.com/hashicorp/vault/vault"
+ "github.com/hashicorp/vault/vault/seal"
"github.com/mitchellh/cli"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -400,3 +406,45 @@ func TestConfigureDevTLS(t *testing.T) {
})
}
}
+
+func TestConfigureSeals(t *testing.T) {
+ testConfig := server.Config{SharedConfig: &configutil.SharedConfig{}}
+ _, testCommand := testServerCommand(t)
+
+ logger := corehelpers.NewTestLogger(t)
+ backend, err := physInmem.NewInmem(nil, logger)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testCommand.logger = logger
+
+ setSealResponse, _, err := testCommand.configureSeals(context.Background(), &testConfig, backend, []string{}, map[string]string{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(setSealResponse.barrierSeal.GetAccess().GetAllSealWrappersByPriority()) != 1 {
+ t.Fatalf("expected 1 seal, got %d", len(setSealResponse.barrierSeal.GetAccess().GetAllSealWrappersByPriority()))
+ }
+
+ if setSealResponse.barrierSeal.BarrierSealConfigType() != vault.SealConfigTypeShamir {
+ t.Fatalf("expected shamir seal, got seal type %s", setSealResponse.barrierSeal.BarrierSealConfigType())
+ }
+}
+
+func TestReloadSeals(t *testing.T) {
+ testCore := vault.TestCoreWithSeal(t, vault.NewTestSeal(t, &seal.TestSealOpts{StoredKeys: seal.StoredKeysSupportedShamirRoot}), false)
+ _, testCommand := testServerCommand(t)
+ testConfig := server.Config{SharedConfig: &configutil.SharedConfig{}}
+
+ _, err := testCommand.reloadSeals(context.Background(), testCore, &testConfig)
+ if err == nil {
+ t.Fatal("expected error, got nil")
+ }
+
+ testConfig = server.Config{SharedConfig: &configutil.SharedConfig{Seals: []*configutil.KMS{{Disabled: true}}}}
+ _, err = testCommand.reloadSeals(context.Background(), testCore, &testConfig)
+ if err == nil {
+ t.Fatal("expected error, got nil")
+ }
+}
diff --git a/vault/core.go b/vault/core.go
index eff0e9cb1a43..cd61111a40b4 100644
--- a/vault/core.go
+++ b/vault/core.go
@@ -4235,6 +4235,49 @@ func (c *Core) Events() *eventbus.EventBus {
return c.events
}
+func (c *Core) SetSeals(barrierSeal Seal, secureRandomReader io.Reader) error {
+ ctx, _ := c.GetContext()
+
+ c.stateLock.Lock()
+ defer c.stateLock.Unlock()
+
+ currentSealBarrierConfig, err := c.SealAccess().BarrierConfig(ctx)
+ if err != nil {
+ return fmt.Errorf("error retrieving barrier config: %s", err)
+ }
+
+ barrierConfigCopy := currentSealBarrierConfig.Clone()
+ barrierConfigCopy.Type = barrierSeal.BarrierSealConfigType().String()
+
+ barrierSeal.SetCore(c)
+
+ rootKey, err := c.seal.GetStoredKeys(ctx)
+ if err != nil {
+ return err
+ }
+
+ if len(rootKey) < 1 {
+ return errors.New("root key not found")
+ }
+
+ barrierConfigCopy.Type = barrierSeal.BarrierSealConfigType().String()
+ err = barrierSeal.SetBarrierConfig(ctx, barrierConfigCopy)
+ if err != nil {
+ return fmt.Errorf("error setting barrier config for new seal: %s", err)
+ }
+
+ err = barrierSeal.SetStoredKeys(ctx, rootKey)
+ if err != nil {
+ return fmt.Errorf("error setting root key in new seal: %s", err)
+ }
+
+ c.seal = barrierSeal
+
+ c.reloadSealsEnt(secureRandomReader, barrierSeal.GetAccess(), c.logger)
+
+ return nil
+}
+
func (c *Core) GetWellKnownRedirect(ctx context.Context, path string) (string, error) {
if c.WellKnownRedirects == nil {
return "", nil
diff --git a/vault/core_stubs_oss.go b/vault/core_stubs_oss.go
index 6ffdb4b2a581..a89fe42af17b 100644
--- a/vault/core_stubs_oss.go
+++ b/vault/core_stubs_oss.go
@@ -5,7 +5,13 @@
package vault
-import "context"
+import (
+ "context"
+ "io"
+
+ "github.com/hashicorp/go-hclog"
+ "github.com/hashicorp/vault/vault/seal"
+)
//go:generate go run github.com/hashicorp/vault/tools/stubmaker
@@ -96,3 +102,6 @@ func (c *Core) entLastRemoteUpstreamWAL() uint64 {
func (c *Core) EntWaitUntilWALShipped(ctx context.Context, index uint64) bool {
return true
}
+
+func (c *Core) reloadSealsEnt(secureRandomReader io.Reader, sealAccess seal.Access, logger hclog.Logger) {
+}
diff --git a/vault/core_test.go b/vault/core_test.go
index 983235a24036..6ecc40af3140 100644
--- a/vault/core_test.go
+++ b/vault/core_test.go
@@ -41,6 +41,7 @@ import (
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/sdk/physical"
"github.com/hashicorp/vault/sdk/physical/inmem"
+ "github.com/hashicorp/vault/vault/seal"
"github.com/hashicorp/vault/version"
"github.com/sasha-s/go-deadlock"
)
@@ -3362,6 +3363,47 @@ func InduceDeadlock(t *testing.T, vaultcore *Core, expected uint32) {
}
}
+func TestSetSeals(t *testing.T) {
+ oldSeal := NewTestSeal(t, &seal.TestSealOpts{
+ StoredKeys: seal.StoredKeysSupportedGeneric,
+ Name: "old-seal",
+ WrapperCount: 1,
+ Generation: 1,
+ })
+ testCore := TestCoreWithSeal(t, oldSeal, false)
+ _, keys, _ := TestCoreInitClusterWrapperSetup(t, testCore, nil)
+ for _, key := range keys {
+ if _, err := TestCoreUnseal(testCore, key); err != nil {
+ t.Fatalf("error unsealing core: %s", err)
+ }
+ }
+
+ if testCore.Sealed() {
+ t.Fatal("expected core to be unsealed, but it is sealed")
+ }
+
+ newSeal := NewTestSeal(t, &seal.TestSealOpts{
+ StoredKeys: seal.StoredKeysSupportedGeneric,
+ Name: "new-seal",
+ WrapperCount: 1,
+ Generation: 2,
+ })
+
+ err := testCore.SetSeals(newSeal, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ wrappers := testCore.seal.GetAccess().GetAllSealWrappersByPriority()
+ if len(wrappers) != 1 {
+ t.Fatalf("expected 1 wrapper in seal access, got %d", len(wrappers))
+ }
+
+ if wrappers[0].Name != "new-seal-1" {
+ t.Fatalf("unexpected seal name: got %s, expected new-seal-1", wrappers[0].Name)
+ }
+}
+
func TestExpiration_DeadlockDetection(t *testing.T) {
testCore := TestCore(t)
testCoreUnsealed(t, testCore)
From db1170576f9d8f02212a32860fd55bfaa96e80ad Mon Sep 17 00:00:00 2001
From: Hamid Ghaf <83242695+hghaf099@users.noreply.github.com>
Date: Thu, 30 Nov 2023 14:47:38 -0800
Subject: [PATCH 47/74] only update license changes in ui related files in ui
precommit hook (#24313)
---
.hooks/pre-commit | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.hooks/pre-commit b/.hooks/pre-commit
index 0b4d6e0c94fa..33aef779ba13 100755
--- a/.hooks/pre-commit
+++ b/.hooks/pre-commit
@@ -115,7 +115,7 @@ ui_copywrite() {
# run the copywrite tool
# if a --path option is added we could apply the headers to only the staged files much easier
# as of the latest version 0.16.6 there is only support for --dirPath
- STAGED_FILES=($(git diff --name-only --cached))
+ STAGED_FILES=($(git diff --name-only --cached -- $DIR/))
rm -rf $BINARY_DIR/.staged
mkdir $BINARY_DIR/.staged
From 61ee28ba3bac1e0f0b48ccad4510263706fe4060 Mon Sep 17 00:00:00 2001
From: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
Date: Thu, 30 Nov 2023 18:57:32 -0600
Subject: [PATCH 48/74] UI: HDS adoption update component to use
Hds::Alert (#24299)
* replace paddingTop with clas
* use hds alert for AlertInline component
* remve isSmall arg
* add test selector back
* remove mimicRefresh arg
* update assertion for alert inline component
* update string-list
* use alert inline for string-list
* add changelog
* update block instances of alert inline
* remove p tags from test selectors
* minor cleanup
---
changelog/24299.txt | 3 +
ui/app/components/auth-saml.hbs | 3 +-
ui/app/styles/components/doc-link.scss | 9 --
.../components/auth-form-options.hbs | 3 +-
ui/app/templates/components/auth-form.hbs | 3 +-
ui/app/templates/components/auth-jwt.hbs | 3 +-
.../components/clients/attribution.hbs | 27 ++--
ui/app/templates/components/date-dropdown.hbs | 2 +-
.../components/keymgmt/distribute.hbs | 57 ++++++---
ui/app/templates/components/mfa/mfa-form.hbs | 2 +-
.../components/mount-backend-form.hbs | 2 +-
.../components/oidc/assignment-form.hbs | 2 +-
.../templates/components/oidc/client-form.hbs | 2 +-
ui/app/templates/components/oidc/key-form.hbs | 2 +-
.../components/oidc/provider-form.hbs | 2 +-
.../templates/components/oidc/scope-form.hbs | 2 +-
.../components/secret-create-or-update.hbs | 14 +--
ui/lib/core/addon/components/alert-inline.hbs | 24 ++--
ui/lib/core/addon/components/alert-inline.js | 76 +++++------
.../addon/components/kv-object-editor.hbs | 2 +-
ui/lib/core/addon/components/string-list.hbs | 12 +-
ui/lib/core/addon/components/text-file.hbs | 2 +-
.../addon/templates/components/edit-form.hbs | 2 +-
.../addon/components/page/configure.hbs | 7 +-
.../components/page/role/create-and-edit.hbs | 2 +-
ui/lib/kv/addon/components/kv-data-fields.hbs | 16 +--
.../kv/addon/components/page/secret/edit.hbs | 1 -
.../components/page/secret/metadata/edit.hbs | 3 +-
.../addon/components/page/secrets/create.hbs | 1 -
.../ldap/addon/components/page/configure.hbs | 3 +-
.../page/library/create-and-edit.hbs | 3 +-
.../components/page/role/create-and-edit.hbs | 3 +-
.../page/pki-configuration-edit.hbs | 3 +-
.../addon/components/page/pki-issuer-edit.hbs | 7 +-
.../page/pki-issuer-rotate-root.hbs | 3 +-
.../pki/addon/components/pki-generate-csr.hbs | 2 +-
.../addon/components/pki-generate-root.hbs | 3 +-
ui/lib/pki/addon/components/pki-key-form.hbs | 3 +-
.../pki/addon/components/pki-key-import.hbs | 3 +-
ui/lib/pki/addon/components/pki-role-form.hbs | 4 +-
.../addon/components/pki-role-generate.hbs | 2 +-
.../components/pki-sign-intermediate-form.hbs | 8 +-
ui/lib/pki/addon/components/pki-tidy-form.hbs | 2 +-
.../components/alert-inline-test.js | 119 ++++++++++--------
.../kubernetes/page/configure-test.js | 4 +-
.../components/ldap/page/configure-test.js | 2 +-
.../ldap/page/library/create-and-edit-test.js | 6 +-
47 files changed, 234 insertions(+), 232 deletions(-)
create mode 100644 changelog/24299.txt
diff --git a/changelog/24299.txt b/changelog/24299.txt
new file mode 100644
index 000000000000..1b295b985687
--- /dev/null
+++ b/changelog/24299.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: Update AlertInline component to use Helios Design System Alert component
+```
diff --git a/ui/app/components/auth-saml.hbs b/ui/app/components/auth-saml.hbs
index f555bd92a186..8d69fe8759ce 100644
--- a/ui/app/components/auth-saml.hbs
+++ b/ui/app/components/auth-saml.hbs
@@ -22,8 +22,7 @@
/>
diff --git a/ui/app/styles/components/doc-link.scss b/ui/app/styles/components/doc-link.scss
index 3e8a7345c0be..20edb9d62dc8 100644
--- a/ui/app/styles/components/doc-link.scss
+++ b/ui/app/styles/components/doc-link.scss
@@ -11,12 +11,3 @@
text-decoration: underline !important;
}
}
-
-.doc-link-subtle {
- color: inherit;
- text-decoration: underline;
- font-weight: inherit;
- &:hover {
- color: inherit;
- }
-}
diff --git a/ui/app/templates/components/auth-form-options.hbs b/ui/app/templates/components/auth-form-options.hbs
index 3505b8e262c2..ace2085cfb28 100644
--- a/ui/app/templates/components/auth-form-options.hbs
+++ b/ui/app/templates/components/auth-form-options.hbs
@@ -23,8 +23,7 @@
/>
diff --git a/ui/app/templates/components/auth-form.hbs b/ui/app/templates/components/auth-form.hbs
index 35506c5cb3c5..8d06e36dcd86 100644
--- a/ui/app/templates/components/auth-form.hbs
+++ b/ui/app/templates/components/auth-form.hbs
@@ -191,8 +191,7 @@
/>
{{#if (and this.delayAuthMessageReminder.isIdle this.showLoading)}}
diff --git a/ui/app/templates/components/clients/attribution.hbs b/ui/app/templates/components/clients/attribution.hbs
index 7cea4fe50ecb..5418b26b5b27 100644
--- a/ui/app/templates/components/clients/attribution.hbs
+++ b/ui/app/templates/components/clients/attribution.hbs
@@ -112,17 +112,24 @@
{{#if @upgradeExplanation}}
-
-
- Your data contains an upgrade.
-
+
+ Your data contains an upgrade.
+ {{@upgradeExplanation}}
+ Visit our
+
- Learn more here.
-
-
-
{{@upgradeExplanation}}
-
+ Client count FAQ
+
+ for more information.
+
+
{{/if}}
diff --git a/ui/app/templates/components/date-dropdown.hbs b/ui/app/templates/components/date-dropdown.hbs
index 4e87843a2a10..d154886f6a46 100644
--- a/ui/app/templates/components/date-dropdown.hbs
+++ b/ui/app/templates/components/date-dropdown.hbs
@@ -34,5 +34,5 @@
/>
{{#if this.invalidDate}}
-
+
{{/if}}
\ No newline at end of file
diff --git a/ui/app/templates/components/keymgmt/distribute.hbs b/ui/app/templates/components/keymgmt/distribute.hbs
index c9c54a33320e..06439b8a5a0f 100644
--- a/ui/app/templates/components/keymgmt/distribute.hbs
+++ b/ui/app/templates/components/keymgmt/distribute.hbs
@@ -28,11 +28,20 @@
@disallowNewItems={{false}}
>
{{#if (and this.validMatchError.key (not this.isNewKey))}}
-
- {{this.validMatchError.key}}
- To check compatibility,
- refer to this table .
-
+
+
+ {{this.validMatchError.key}}
+ To check compatibility,
+
+ refer to this table
+ .
+
+
{{/if}}
@@ -62,11 +71,20 @@
{{#if this.validMatchError.key}}
-
- {{this.validMatchError.key}}
- To check compatibility,
- refer to this table .
-
+
+
+ {{this.validMatchError.key}}
+ To check compatibility,
+
+ refer to this table
+ .
+
+
{{/if}}
@@ -89,11 +107,20 @@
data-test-keymgmt-dist-provider
>
{{#if this.validMatchError.provider}}
-
- {{this.validMatchError.provider}}
- To check compatibility,
- refer to this table .
-
+
+
+ {{this.validMatchError.provider}}
+ To check compatibility,
+
+ refer to this table
+ .
+
+
{{/if}}
diff --git a/ui/app/templates/components/mfa/mfa-form.hbs b/ui/app/templates/components/mfa/mfa-form.hbs
index 5ec07b60a172..a2587b47b3ab 100644
--- a/ui/app/templates/components/mfa/mfa-form.hbs
+++ b/ui/app/templates/components/mfa/mfa-form.hbs
@@ -58,7 +58,7 @@
{{#if this.newCodeDelay.isRunning}}
{{/if}}
{{#if this.invalidFormAlert}}
{{/if}}
diff --git a/ui/app/templates/components/oidc/assignment-form.hbs b/ui/app/templates/components/oidc/assignment-form.hbs
index 8ce86f21687a..13ff8044f6db 100644
--- a/ui/app/templates/components/oidc/assignment-form.hbs
+++ b/ui/app/templates/components/oidc/assignment-form.hbs
@@ -63,7 +63,7 @@
data-test-oidc-assignment-cancel
/>
{{#if this.modelValidations.targets.errors}}
-
+
{{/if}}
\ No newline at end of file
diff --git a/ui/app/templates/components/oidc/client-form.hbs b/ui/app/templates/components/oidc/client-form.hbs
index e2c0a9def19b..d789ad92873f 100644
--- a/ui/app/templates/components/oidc/client-form.hbs
+++ b/ui/app/templates/components/oidc/client-form.hbs
@@ -97,7 +97,7 @@
{{#if this.invalidFormAlert}}
{{/if}}
diff --git a/ui/app/templates/components/oidc/key-form.hbs b/ui/app/templates/components/oidc/key-form.hbs
index 9ea41100b07e..77e983fd1d8f 100644
--- a/ui/app/templates/components/oidc/key-form.hbs
+++ b/ui/app/templates/components/oidc/key-form.hbs
@@ -98,7 +98,7 @@
{{#if this.invalidFormAlert}}
{{/if}}
diff --git a/ui/app/templates/components/oidc/provider-form.hbs b/ui/app/templates/components/oidc/provider-form.hbs
index b51e0d1e86eb..b09ca7a2cf7f 100644
--- a/ui/app/templates/components/oidc/provider-form.hbs
+++ b/ui/app/templates/components/oidc/provider-form.hbs
@@ -125,7 +125,7 @@
{{#if this.invalidFormAlert}}
{{/if}}
diff --git a/ui/app/templates/components/oidc/scope-form.hbs b/ui/app/templates/components/oidc/scope-form.hbs
index 76541045a80c..f6e3667982a8 100644
--- a/ui/app/templates/components/oidc/scope-form.hbs
+++ b/ui/app/templates/components/oidc/scope-form.hbs
@@ -73,7 +73,7 @@
{{#if this.invalidFormAlert}}
{{/if}}
diff --git a/ui/app/templates/components/secret-create-or-update.hbs b/ui/app/templates/components/secret-create-or-update.hbs
index fbb491677eba..8650d73fdab7 100644
--- a/ui/app/templates/components/secret-create-or-update.hbs
+++ b/ui/app/templates/components/secret-create-or-update.hbs
@@ -26,12 +26,7 @@
/>
{{#if (get this.validationMessages "path")}}
-
+
{{/if}}
{{#if @modelForData.isFolder}}
@@ -104,12 +99,7 @@
{{#if this.validationMessages.key}}
-
+
{{/if}}
{{/each}}
diff --git a/ui/lib/core/addon/components/alert-inline.hbs b/ui/lib/core/addon/components/alert-inline.hbs
index f0637176cb91..0496ce57d621 100644
--- a/ui/lib/core/addon/components/alert-inline.hbs
+++ b/ui/lib/core/addon/components/alert-inline.hbs
@@ -3,22 +3,16 @@
SPDX-License-Identifier: BUSL-1.1
~}}
-
- {{#if this.isRefreshing}}
-
- {{else}}
-
-
- {{#if (has-block)}}
- {{yield}}
- {{else}}
- {{@message}}
- {{/if}}
-
- {{/if}}
-
\ No newline at end of file
+ {{#unless this.isRefreshing}}
+ {{@message}}
+ {{/unless}}
+
\ No newline at end of file
diff --git a/ui/lib/core/addon/components/alert-inline.js b/ui/lib/core/addon/components/alert-inline.js
index 6fac080fba47..8a25a6fc286b 100644
--- a/ui/lib/core/addon/components/alert-inline.js
+++ b/ui/lib/core/addon/components/alert-inline.js
@@ -7,62 +7,62 @@ import Component from '@glimmer/component';
import { action } from '@ember/object';
import { later } from '@ember/runloop';
import { tracked } from '@glimmer/tracking';
-import { messageTypes } from 'core/helpers/message-types';
+import { assert } from '@ember/debug';
/**
* @module AlertInline
- * `AlertInline` components are used to inform users of important messages.
+ * * Use Hds::Alert @type="compact" for displaying alert messages.
+ * This component renders a compact Hds::Alert that displays a loading icon if the
+ * @message arg changes and then re-renders the updated @message text.
+ * (Example: submitting a form and displaying the number of errors because on re-submit the number may change)
*
* @example
- * ```js
- *
+ * ```
+ *
* ```
*
- * @param {string} type=null - The alert type passed to the message-types helper.
- * @param {string} [message=null] - The message to display within the alert.
- * @param {boolean} [paddingTop=false] - Whether or not to add padding above component.
- * @param {boolean} [isMarginless=false] - Whether or not to remove margin bottom below component.
- * @param {boolean} [sizeSmall=false] - Whether or not to display a small font with padding below of alert message.
- * @param {boolean} [mimicRefresh=false] - If true will display a loading icon when attributes change (e.g. when a form submits and the alert message changes).
+ * @deprecated {string} type - color getter maps type to the Hds::Alert @color
+ * @param {string} color - Styles alert color and icon, can be one of: critical, warning, success, highlight, neutral
+ * @param {string} message - The message to display within the alert.
*/
export default class AlertInlineComponent extends Component {
@tracked isRefreshing = false;
- get mimicRefresh() {
- return this.args.mimicRefresh || false;
- }
-
- get paddingTop() {
- return this.args.paddingTop ? ' padding-top' : '';
- }
-
- get isMarginless() {
- return this.args.isMarginless ? ' is-marginless' : '';
- }
-
- get sizeSmall() {
- return this.args.sizeSmall ? ' size-small' : '';
- }
-
- get textClass() {
- if (this.args.type === 'danger') {
- return this.alertType.glyphClass;
+ constructor() {
+ super(...arguments);
+ assert('@type arg is deprecated, pass @color="critical" instead', this.args.type !== 'critical');
+ if (this.args.color) {
+ const possibleColors = ['critical', 'warning', 'success', 'highlight', 'neutral'];
+ assert(
+ `${this.args.color} is not a valid color. @color must be one of: ${possibleColors.join(', ')}`,
+ possibleColors.includes(this.args.color)
+ );
}
- return null;
}
- get alertType() {
- return messageTypes([this.args.type]);
+ get color() {
+ if (this.args.color) return this.args.color;
+ // @type arg is deprecated, this is for backward compatibility of old implementation
+ switch (this.args.type) {
+ case 'danger':
+ return 'critical';
+ case 'success':
+ return 'success';
+ case 'warning':
+ return 'warning';
+ case 'info':
+ return 'highlight';
+ default:
+ return 'neutral';
+ }
}
@action
refresh() {
- if (this.mimicRefresh) {
- this.isRefreshing = true;
- later(() => {
- this.isRefreshing = false;
- }, 200);
- }
+ this.isRefreshing = true;
+ later(() => {
+ this.isRefreshing = false;
+ }, 200);
}
}
diff --git a/ui/lib/core/addon/components/kv-object-editor.hbs b/ui/lib/core/addon/components/kv-object-editor.hbs
index 74cb0d63e9b7..eac26ede34cc 100644
--- a/ui/lib/core/addon/components/kv-object-editor.hbs
+++ b/ui/lib/core/addon/components/kv-object-editor.hbs
@@ -13,7 +13,7 @@
/>
{{#if @validationError}}
{{/if}}
{{#if this.kvData}}
diff --git a/ui/lib/core/addon/components/string-list.hbs b/ui/lib/core/addon/components/string-list.hbs
index 3c654eecd252..b838f29efdf9 100644
--- a/ui/lib/core/addon/components/string-list.hbs
+++ b/ui/lib/core/addon/components/string-list.hbs
@@ -53,15 +53,15 @@
{{/if}}
{{#if (includes index this.indicesWithComma)}}
-
+
{{/if}}
{{/each}}
{{#if this.indicesWithComma}}
-
+
+
+ Input contains a comma. Please separate values into individual rows.
+
+
{{/if}}
\ No newline at end of file
diff --git a/ui/lib/core/addon/components/text-file.hbs b/ui/lib/core/addon/components/text-file.hbs
index e3fd0ec46864..6572357e82da 100644
--- a/ui/lib/core/addon/components/text-file.hbs
+++ b/ui/lib/core/addon/components/text-file.hbs
@@ -57,7 +57,7 @@
{{/if}}
diff --git a/ui/lib/core/addon/templates/components/edit-form.hbs b/ui/lib/core/addon/templates/components/edit-form.hbs
index 02f0b12a0e73..2ca2fb583b89 100644
--- a/ui/lib/core/addon/templates/components/edit-form.hbs
+++ b/ui/lib/core/addon/templates/components/edit-form.hbs
@@ -30,7 +30,7 @@
>
<:error>
{{#if this.invalidFormAlert}}
-
+
{{/if}}
diff --git a/ui/lib/kubernetes/addon/components/page/configure.hbs b/ui/lib/kubernetes/addon/components/page/configure.hbs
index b623c2a2a975..45795fa15cb8 100644
--- a/ui/lib/kubernetes/addon/components/page/configure.hbs
+++ b/ui/lib/kubernetes/addon/components/page/configure.hbs
@@ -78,7 +78,8 @@
-
+
+
{{#if this.alert}}
-
+
{{/if}}
-
+
{{#if this.showConfirm}}
diff --git a/ui/lib/kubernetes/addon/components/page/role/create-and-edit.hbs b/ui/lib/kubernetes/addon/components/page/role/create-and-edit.hbs
index 5d0d0bb6b6bf..9fc5770458e1 100644
--- a/ui/lib/kubernetes/addon/components/page/role/create-and-edit.hbs
+++ b/ui/lib/kubernetes/addon/components/page/role/create-and-edit.hbs
@@ -130,7 +130,7 @@
{{/if}}
{{#if this.invalidFormAlert}}
{{/if}}
diff --git a/ui/lib/kv/addon/components/kv-data-fields.hbs b/ui/lib/kv/addon/components/kv-data-fields.hbs
index f981b2b8c412..554c4cbdd1f2 100644
--- a/ui/lib/kv/addon/components/kv-data-fields.hbs
+++ b/ui/lib/kv/addon/components/kv-data-fields.hbs
@@ -20,13 +20,15 @@
@readOnly={{eq @type "details"}}
/>
{{#if (or @modelValidations.secretData.errors this.lintingErrors)}}
-
- {{#if @modelValidations.secretData.errors}}
- {{@modelValidations.secretData.errors}}
- {{else}}
- JSON is unparsable. Fix linting errors to avoid data discrepancies.
- {{/if}}
-
+
{{/if}}
{{else if (eq @type "details")}}
{{#each-in @secret.secretData as |key value|}}
diff --git a/ui/lib/kv/addon/components/page/secret/edit.hbs b/ui/lib/kv/addon/components/page/secret/edit.hbs
index 28ba62d89f78..6f10886b6c40 100644
--- a/ui/lib/kv/addon/components/page/secret/edit.hbs
+++ b/ui/lib/kv/addon/components/page/secret/edit.hbs
@@ -94,7 +94,6 @@
class="has-top-padding-s"
@type="danger"
@message={{this.invalidFormAlert}}
- @mimicRefresh={{true}}
/>
{{/if}}
diff --git a/ui/lib/kv/addon/components/page/secret/metadata/edit.hbs b/ui/lib/kv/addon/components/page/secret/metadata/edit.hbs
index 9d1bd4188244..9d8bcb7b045a 100644
--- a/ui/lib/kv/addon/components/page/secret/metadata/edit.hbs
+++ b/ui/lib/kv/addon/components/page/secret/metadata/edit.hbs
@@ -38,9 +38,8 @@
{{/if}}
diff --git a/ui/lib/kv/addon/components/page/secrets/create.hbs b/ui/lib/kv/addon/components/page/secrets/create.hbs
index 4eefecf19854..47933c341a90 100644
--- a/ui/lib/kv/addon/components/page/secrets/create.hbs
+++ b/ui/lib/kv/addon/components/page/secrets/create.hbs
@@ -62,7 +62,6 @@
class="has-top-padding-s"
@type="danger"
@message={{this.invalidFormAlert}}
- @mimicRefresh={{true}}
/>
{{/if}}
diff --git a/ui/lib/ldap/addon/components/page/configure.hbs b/ui/lib/ldap/addon/components/page/configure.hbs
index b0b1bec2fef9..393b8eb51e99 100644
--- a/ui/lib/ldap/addon/components/page/configure.hbs
+++ b/ui/lib/ldap/addon/components/page/configure.hbs
@@ -70,9 +70,8 @@
{{#if this.invalidFormMessage}}
{{/if}}
diff --git a/ui/lib/ldap/addon/components/page/library/create-and-edit.hbs b/ui/lib/ldap/addon/components/page/library/create-and-edit.hbs
index 8535400cf7ba..7f8b77c00bd0 100644
--- a/ui/lib/ldap/addon/components/page/library/create-and-edit.hbs
+++ b/ui/lib/ldap/addon/components/page/library/create-and-edit.hbs
@@ -43,9 +43,8 @@
{{#if this.invalidFormMessage}}
{{/if}}
diff --git a/ui/lib/ldap/addon/components/page/role/create-and-edit.hbs b/ui/lib/ldap/addon/components/page/role/create-and-edit.hbs
index 8c5b3e54bfb6..c90601480d18 100644
--- a/ui/lib/ldap/addon/components/page/role/create-and-edit.hbs
+++ b/ui/lib/ldap/addon/components/page/role/create-and-edit.hbs
@@ -67,9 +67,8 @@
{{#if this.invalidFormMessage}}
{{/if}}
diff --git a/ui/lib/pki/addon/components/page/pki-configuration-edit.hbs b/ui/lib/pki/addon/components/page/pki-configuration-edit.hbs
index 713f9c46ffbe..e1c890a0b313 100644
--- a/ui/lib/pki/addon/components/page/pki-configuration-edit.hbs
+++ b/ui/lib/pki/addon/components/page/pki-configuration-edit.hbs
@@ -146,9 +146,8 @@
diff --git a/ui/lib/pki/addon/components/page/pki-issuer-edit.hbs b/ui/lib/pki/addon/components/page/pki-issuer-edit.hbs
index 80d682355be4..2c763dd69907 100644
--- a/ui/lib/pki/addon/components/page/pki-issuer-edit.hbs
+++ b/ui/lib/pki/addon/components/page/pki-issuer-edit.hbs
@@ -68,12 +68,7 @@
{{#if this.error}}
{{/if}}
\ No newline at end of file
diff --git a/ui/lib/pki/addon/components/page/pki-issuer-rotate-root.hbs b/ui/lib/pki/addon/components/page/pki-issuer-rotate-root.hbs
index e84330f80c32..137e0cafb14a 100644
--- a/ui/lib/pki/addon/components/page/pki-issuer-rotate-root.hbs
+++ b/ui/lib/pki/addon/components/page/pki-issuer-rotate-root.hbs
@@ -173,9 +173,8 @@
diff --git a/ui/lib/pki/addon/components/pki-generate-csr.hbs b/ui/lib/pki/addon/components/pki-generate-csr.hbs
index b363631dcda5..1b4a38f8bd90 100644
--- a/ui/lib/pki/addon/components/pki-generate-csr.hbs
+++ b/ui/lib/pki/addon/components/pki-generate-csr.hbs
@@ -67,7 +67,7 @@
{{#if this.alert}}
{{/if}}
diff --git a/ui/lib/pki/addon/components/pki-generate-root.hbs b/ui/lib/pki/addon/components/pki-generate-root.hbs
index f94cfb58e4ed..8980ef11462b 100644
--- a/ui/lib/pki/addon/components/pki-generate-root.hbs
+++ b/ui/lib/pki/addon/components/pki-generate-root.hbs
@@ -104,9 +104,8 @@
diff --git a/ui/lib/pki/addon/components/pki-key-form.hbs b/ui/lib/pki/addon/components/pki-key-form.hbs
index 9dcd62dc264b..881492a512bf 100644
--- a/ui/lib/pki/addon/components/pki-key-form.hbs
+++ b/ui/lib/pki/addon/components/pki-key-form.hbs
@@ -55,9 +55,8 @@
diff --git a/ui/lib/pki/addon/components/pki-key-import.hbs b/ui/lib/pki/addon/components/pki-key-import.hbs
index aa3859b946e8..882149985a7b 100644
--- a/ui/lib/pki/addon/components/pki-key-import.hbs
+++ b/ui/lib/pki/addon/components/pki-key-import.hbs
@@ -37,9 +37,8 @@
diff --git a/ui/lib/pki/addon/components/pki-role-form.hbs b/ui/lib/pki/addon/components/pki-role-form.hbs
index 2b8d2cbdff6b..150086a7ea6d 100644
--- a/ui/lib/pki/addon/components/pki-role-form.hbs
+++ b/ui/lib/pki/addon/components/pki-role-form.hbs
@@ -134,11 +134,11 @@
/>
{{#if this.modelValidations.targets.errors}}
-
+
{{/if}}
{{#if this.invalidFormAlert}}
{{/if}}
\ No newline at end of file
diff --git a/ui/lib/pki/addon/components/pki-role-generate.hbs b/ui/lib/pki/addon/components/pki-role-generate.hbs
index e1bebc7e31d8..a5db88ff6557 100644
--- a/ui/lib/pki/addon/components/pki-role-generate.hbs
+++ b/ui/lib/pki/addon/components/pki-role-generate.hbs
@@ -44,7 +44,7 @@
{{#if this.invalidFormAlert}}
{{/if}}
diff --git a/ui/lib/pki/addon/components/pki-sign-intermediate-form.hbs b/ui/lib/pki/addon/components/pki-sign-intermediate-form.hbs
index c49c9471993d..157ba3d16c61 100644
--- a/ui/lib/pki/addon/components/pki-sign-intermediate-form.hbs
+++ b/ui/lib/pki/addon/components/pki-sign-intermediate-form.hbs
@@ -73,13 +73,7 @@
{{#if this.inlineFormAlert}}
{{/if}}
diff --git a/ui/lib/pki/addon/components/pki-tidy-form.hbs b/ui/lib/pki/addon/components/pki-tidy-form.hbs
index e5daca47cfd6..e45483b68710 100644
--- a/ui/lib/pki/addon/components/pki-tidy-form.hbs
+++ b/ui/lib/pki/addon/components/pki-tidy-form.hbs
@@ -75,7 +75,7 @@
{{#if this.invalidFormAlert}}
{{/if}}
\ No newline at end of file
diff --git a/ui/tests/integration/components/alert-inline-test.js b/ui/tests/integration/components/alert-inline-test.js
index 87c0059d4bf6..a992257ede3f 100644
--- a/ui/tests/integration/components/alert-inline-test.js
+++ b/ui/tests/integration/components/alert-inline-test.js
@@ -8,71 +8,84 @@ import { setupRenderingTest } from 'ember-qunit';
import { render, settled, find, waitUntil } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
+const SHARED_STYLES = {
+ success: {
+ icon: 'check-circle-fill',
+ class: 'hds-alert--color-success',
+ },
+ warning: {
+ icon: 'alert-triangle-fill',
+ class: 'hds-alert--color-warning',
+ },
+};
module('Integration | Component | alert-inline', function (hooks) {
setupRenderingTest(hooks);
- hooks.beforeEach(function () {
- this.set('message', 'some very important alert');
- this.set('type', 'warning');
- });
+ test('it renders alert message for each @color arg', async function (assert) {
+ const COLORS = {
+ ...SHARED_STYLES,
+ neutral: {
+ icon: 'info-fill',
+ class: 'hds-alert--color-neutral',
+ },
+ highlight: {
+ icon: 'info-fill',
+ class: 'hds-alert--color-highlight',
+ },
+ critical: {
+ icon: 'alert-diamond-fill',
+ class: 'hds-alert--color-critical',
+ },
+ };
- test('it renders alert message with correct class args', async function (assert) {
- await render(hbs`
-
- `);
+ const { neutral } = COLORS; // default color
+ await render(hbs` `);
assert.dom('[data-test-inline-error-message]').hasText('some very important alert');
- assert
- .dom('[data-test-inline-alert]')
- .hasAttribute('class', 'is-flex-center padding-top is-marginless size-small');
- });
+ assert.dom(`[data-test-icon="${neutral.icon}"]`).exists('renders default icon');
+ assert.dom('[data-test-inline-alert]').hasClass(neutral.class, 'renders default class');
- test('it yields to block text', async function (assert) {
- await render(hbs`
-
- A much more important alert
-
- `);
- assert.dom('[data-test-inline-error-message]').hasText('A much more important alert');
+ // assert deprecated @type arg values map to expected color
+ for (const type in COLORS) {
+ this.color = type;
+ const color = COLORS[type];
+ await render(hbs` `);
+ assert.dom(`[data-test-icon="${color.icon}"]`).exists(`@color="${type}" renders icon: ${color.icon}`);
+ assert
+ .dom('[data-test-inline-alert]')
+ .hasClass(color.class, `@color="${type}" renders class: ${color.class}`);
+ }
});
- test('it renders correctly for type=danger', async function (assert) {
- this.set('type', 'danger');
- await render(hbs`
-
- `);
- assert
- .dom('[data-test-inline-error-message]')
- .hasAttribute('class', 'has-text-danger', 'has danger text');
- assert.dom('[data-test-icon="x-square-fill"]').exists('danger icon exists');
- });
-
- test('it renders correctly for type=warning', async function (assert) {
- await render(hbs`
-
- `);
- assert.dom('[data-test-inline-error-message]').doesNotHaveAttribute('class', 'does not have styled text');
- assert.dom('[data-test-icon="alert-triangle-fill"]').exists('warning icon exists');
+ test('it renders alert color for each deprecated @type arg', async function (assert) {
+ const OLD_TYPES = {
+ ...SHARED_STYLES,
+ info: {
+ icon: 'info-fill',
+ class: 'hds-alert--color-highlight',
+ },
+ danger: {
+ icon: 'alert-diamond-fill',
+ class: 'hds-alert--color-critical',
+ },
+ };
+ // assert deprecated @type arg values map to expected color
+ for (const type in OLD_TYPES) {
+ this.type = type;
+ const color = OLD_TYPES[type];
+ await render(hbs` `);
+ assert
+ .dom(`[data-test-icon="${color.icon}"]`)
+ .exists(`deprecated @type="${type}" renders icon: ${color.icon}`);
+ assert
+ .dom('[data-test-inline-alert]')
+ .hasClass(color.class, `deprecated @type="${type}" renders class: ${color.class}`);
+ }
});
test('it mimics loading when message changes', async function (assert) {
+ this.message = 'some very important alert';
await render(hbs`
-
+
`);
assert
.dom('[data-test-inline-error-message]')
diff --git a/ui/tests/integration/components/kubernetes/page/configure-test.js b/ui/tests/integration/components/kubernetes/page/configure-test.js
index 7d1b922e837a..8c41a3431a78 100644
--- a/ui/tests/integration/components/kubernetes/page/configure-test.js
+++ b/ui/tests/integration/components/kubernetes/page/configure-test.js
@@ -222,9 +222,9 @@ module('Integration | Component | kubernetes | Page::Configure', function (hooks
await click('[data-test-config-save]');
assert
- .dom('[data-test-inline-error-message]')
+ .dom('[data-test-field-validation="kubernetesHost"] [data-test-inline-error-message]')
.hasText('Kubernetes host is required', 'Error renders for required field');
- assert.dom('[data-test-alert] p').hasText('There is an error with this form.', 'Alert renders');
+ assert.dom('[data-test-alert]').hasText('There is an error with this form.', 'Alert renders');
});
test('it should save inferred config', async function (assert) {
diff --git a/ui/tests/integration/components/ldap/page/configure-test.js b/ui/tests/integration/components/ldap/page/configure-test.js
index f81ad8b491bd..a479656adc4d 100644
--- a/ui/tests/integration/components/ldap/page/configure-test.js
+++ b/ui/tests/integration/components/ldap/page/configure-test.js
@@ -85,7 +85,7 @@ module('Integration | Component | ldap | Page::Configure', function (hooks) {
.dom('[data-test-field="bindpass"] [data-test-inline-error-message]')
.hasText('Administrator password is required.', 'Validation message renders for bindpass');
assert
- .dom('[data-test-invalid-form-message] p')
+ .dom('[data-test-invalid-form-message]')
.hasText('There are 2 errors with this form.', 'Invalid form message renders');
});
diff --git a/ui/tests/integration/components/ldap/page/library/create-and-edit-test.js b/ui/tests/integration/components/ldap/page/library/create-and-edit-test.js
index 67c8721ce25e..7003c8bcea03 100644
--- a/ui/tests/integration/components/ldap/page/library/create-and-edit-test.js
+++ b/ui/tests/integration/components/ldap/page/library/create-and-edit-test.js
@@ -87,13 +87,13 @@ module('Integration | Component | ldap | Page::Library::CreateAndEdit', function
await click('[data-test-save]');
assert
- .dom('[data-test-field-validation="name"] p')
+ .dom('[data-test-field-validation="name"]')
.hasText('Library name is required.', 'Name validation error renders');
assert
- .dom('[data-test-field-validation="service_account_names"] p')
+ .dom('[data-test-field-validation="service_account_names"]')
.hasText('At least one service account is required.', 'Service account name validation error renders');
assert
- .dom('[data-test-invalid-form-message] p')
+ .dom('[data-test-invalid-form-message]')
.hasText('There are 2 errors with this form.', 'Invalid form message renders');
});
From 96281c43103465af9f294e7297f7b640b1f0e8c8 Mon Sep 17 00:00:00 2001
From: miagilepner
Date: Fri, 1 Dec 2023 11:41:02 +0100
Subject: [PATCH 49/74] split out reloadSealsEnt (#24320)
---
vault/core_stubs_oss.go | 7 -------
vault/reload_seal_stubs_oss.go | 18 ++++++++++++++++++
2 files changed, 18 insertions(+), 7 deletions(-)
create mode 100644 vault/reload_seal_stubs_oss.go
diff --git a/vault/core_stubs_oss.go b/vault/core_stubs_oss.go
index a89fe42af17b..2fb05416b164 100644
--- a/vault/core_stubs_oss.go
+++ b/vault/core_stubs_oss.go
@@ -7,10 +7,6 @@ package vault
import (
"context"
- "io"
-
- "github.com/hashicorp/go-hclog"
- "github.com/hashicorp/vault/vault/seal"
)
//go:generate go run github.com/hashicorp/vault/tools/stubmaker
@@ -102,6 +98,3 @@ func (c *Core) entLastRemoteUpstreamWAL() uint64 {
func (c *Core) EntWaitUntilWALShipped(ctx context.Context, index uint64) bool {
return true
}
-
-func (c *Core) reloadSealsEnt(secureRandomReader io.Reader, sealAccess seal.Access, logger hclog.Logger) {
-}
diff --git a/vault/reload_seal_stubs_oss.go b/vault/reload_seal_stubs_oss.go
new file mode 100644
index 000000000000..3528840aa6ac
--- /dev/null
+++ b/vault/reload_seal_stubs_oss.go
@@ -0,0 +1,18 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: BUSL-1.1
+
+//go:build !enterprise
+
+package vault
+
+import (
+ "io"
+
+ "github.com/hashicorp/go-hclog"
+ "github.com/hashicorp/vault/vault/seal"
+)
+
+//go:generate go run github.com/hashicorp/vault/tools/stubmaker
+
+func (c *Core) reloadSealsEnt(secureRandomReader io.Reader, sealAccess seal.Access, logger hclog.Logger) {
+}
From 06b9325bb9e6616789c4fe5e7778459ba98a14ab Mon Sep 17 00:00:00 2001
From: Peter Wilson
Date: Fri, 1 Dec 2023 11:30:34 +0000
Subject: [PATCH 50/74] fix `-log-file` so that it uses the correct name and
only adds timestamps on rotation (#24297)
* fix -log-file so that it uses the correct name and only adds timestamps on rotation
* added some tests for naming/rotation
* changelog
* revert to previous way of getting created time
* remove unused stat
* comment shuffle
* Update changelog/24297.txt
Co-authored-by: Violet Hynes
* Update website/content/docs/agent-and-proxy/agent/index.mdx
Update 'agent' docs page
Co-authored-by: Sarah Chavis <62406755+schavis@users.noreply.github.com>
* Update website/content/docs/agent-and-proxy/proxy/index.mdx
Update 'proxy' docs page
Co-authored-by: Sarah Chavis <62406755+schavis@users.noreply.github.com>
* Update website/content/docs/commands/server.mdx
Update 'server' docs page
Co-authored-by: Sarah Chavis <62406755+schavis@users.noreply.github.com>
* fix typos
---------
Co-authored-by: Violet Hynes
Co-authored-by: Sarah Chavis <62406755+schavis@users.noreply.github.com>
---
changelog/24297.txt | 2 +
command/agent.go | 23 +--
command/proxy.go | 21 ++-
command/server.go | 21 +--
helper/logging/logfile.go | 31 +++-
helper/logging/logger.go | 49 ++++--
helper/logging/logger_test.go | 161 ++++++++++++------
.../docs/agent-and-proxy/agent/index.mdx | 19 ++-
.../docs/agent-and-proxy/proxy/index.mdx | 19 ++-
website/content/docs/commands/server.mdx | 21 ++-
10 files changed, 239 insertions(+), 128 deletions(-)
create mode 100644 changelog/24297.txt
diff --git a/changelog/24297.txt b/changelog/24297.txt
new file mode 100644
index 000000000000..d1433cfcd1f9
--- /dev/null
+++ b/changelog/24297.txt
@@ -0,0 +1,2 @@
+```release-note:change
+logging: Vault server, Agent and Proxy now honor log file value and only add a timestamp on rotation.
\ No newline at end of file
diff --git a/command/agent.go b/command/agent.go
index b410da8c8a35..94db44c86d58 100644
--- a/command/agent.go
+++ b/command/agent.go
@@ -20,7 +20,7 @@ import (
systemd "github.com/coreos/go-systemd/daemon"
ctconfig "github.com/hashicorp/consul-template/config"
- hclog "github.com/hashicorp/go-hclog"
+ "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-secure-stdlib/gatedwriter"
"github.com/hashicorp/go-secure-stdlib/parseutil"
@@ -31,7 +31,7 @@ import (
"github.com/hashicorp/vault/command/agent/template"
"github.com/hashicorp/vault/command/agentproxyshared"
"github.com/hashicorp/vault/command/agentproxyshared/auth"
- cache "github.com/hashicorp/vault/command/agentproxyshared/cache"
+ "github.com/hashicorp/vault/command/agentproxyshared/cache"
"github.com/hashicorp/vault/command/agentproxyshared/sink"
"github.com/hashicorp/vault/command/agentproxyshared/sink/file"
"github.com/hashicorp/vault/command/agentproxyshared/sink/inmem"
@@ -62,6 +62,7 @@ const (
// flagNameAgentExitAfterAuth is used as an Agent specific flag to indicate
// that agent should exit after a single successful auth
flagNameAgentExitAfterAuth = "exit-after-auth"
+ nameAgent = "agent"
)
type AgentCommand struct {
@@ -1129,15 +1130,17 @@ func (c *AgentCommand) newLogger() (hclog.InterceptLogger, error) {
return nil, errs
}
- logCfg := &logging.LogConfig{
- Name: "agent",
- LogLevel: logLevel,
- LogFormat: logFormat,
- LogFilePath: c.config.LogFile,
- LogRotateDuration: logRotateDuration,
- LogRotateBytes: c.config.LogRotateBytes,
- LogRotateMaxFiles: c.config.LogRotateMaxFiles,
+ logCfg, err := logging.NewLogConfig(nameAgent)
+ if err != nil {
+ return nil, err
}
+ logCfg.Name = nameAgent
+ logCfg.LogLevel = logLevel
+ logCfg.LogFormat = logFormat
+ logCfg.LogFilePath = c.config.LogFile
+ logCfg.LogRotateDuration = logRotateDuration
+ logCfg.LogRotateBytes = c.config.LogRotateBytes
+ logCfg.LogRotateMaxFiles = c.config.LogRotateMaxFiles
l, err := logging.Setup(logCfg, c.logWriter)
if err != nil {
diff --git a/command/proxy.go b/command/proxy.go
index 55dc555fb290..28753128ef96 100644
--- a/command/proxy.go
+++ b/command/proxy.go
@@ -27,7 +27,7 @@ import (
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/command/agentproxyshared"
"github.com/hashicorp/vault/command/agentproxyshared/auth"
- cache "github.com/hashicorp/vault/command/agentproxyshared/cache"
+ "github.com/hashicorp/vault/command/agentproxyshared/cache"
"github.com/hashicorp/vault/command/agentproxyshared/sink"
"github.com/hashicorp/vault/command/agentproxyshared/sink/file"
"github.com/hashicorp/vault/command/agentproxyshared/sink/inmem"
@@ -59,6 +59,7 @@ const (
// flagNameProxyExitAfterAuth is used as a Proxy specific flag to indicate
// that proxy should exit after a single successful auth
flagNameProxyExitAfterAuth = "exit-after-auth"
+ nameProxy = "proxy"
)
type ProxyCommand struct {
@@ -1040,15 +1041,17 @@ func (c *ProxyCommand) newLogger() (log.InterceptLogger, error) {
return nil, errors
}
- logCfg := &logging.LogConfig{
- Name: "proxy",
- LogLevel: logLevel,
- LogFormat: logFormat,
- LogFilePath: c.config.LogFile,
- LogRotateDuration: logRotateDuration,
- LogRotateBytes: c.config.LogRotateBytes,
- LogRotateMaxFiles: c.config.LogRotateMaxFiles,
+ logCfg, err := logging.NewLogConfig(nameProxy)
+ if err != nil {
+ return nil, err
}
+ logCfg.Name = nameProxy
+ logCfg.LogLevel = logLevel
+ logCfg.LogFormat = logFormat
+ logCfg.LogFilePath = c.config.LogFile
+ logCfg.LogRotateDuration = logRotateDuration
+ logCfg.LogRotateBytes = c.config.LogRotateBytes
+ logCfg.LogRotateMaxFiles = c.config.LogRotateMaxFiles
l, err := logging.Setup(logCfg, c.logWriter)
if err != nil {
diff --git a/command/server.go b/command/server.go
index 066b0859ad9e..93604ccb03a5 100644
--- a/command/server.go
+++ b/command/server.go
@@ -25,12 +25,11 @@ import (
"sync"
"time"
- "github.com/google/go-cmp/cmp"
- "github.com/hashicorp/go-kms-wrapping/entropy/v2"
-
systemd "github.com/coreos/go-systemd/daemon"
+ "github.com/google/go-cmp/cmp"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/go-hclog"
+ "github.com/hashicorp/go-kms-wrapping/entropy/v2"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
aeadwrapper "github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2"
"github.com/hashicorp/go-multierror"
@@ -1875,14 +1874,16 @@ func (c *ServerCommand) configureLogging(config *server.Config) (hclog.Intercept
return nil, err
}
- logCfg := &loghelper.LogConfig{
- LogLevel: logLevel,
- LogFormat: logFormat,
- LogFilePath: config.LogFile,
- LogRotateDuration: logRotateDuration,
- LogRotateBytes: config.LogRotateBytes,
- LogRotateMaxFiles: config.LogRotateMaxFiles,
+ logCfg, err := loghelper.NewLogConfig("vault")
+ if err != nil {
+ return nil, err
}
+ logCfg.LogLevel = logLevel
+ logCfg.LogFormat = logFormat
+ logCfg.LogFilePath = config.LogFile
+ logCfg.LogRotateDuration = logRotateDuration
+ logCfg.LogRotateBytes = config.LogRotateBytes
+ logCfg.LogRotateMaxFiles = config.LogRotateMaxFiles
return loghelper.Setup(logCfg, c.logWriter)
}
diff --git a/helper/logging/logfile.go b/helper/logging/logfile.go
index fa4d5d0e7b4e..2f2eb8fbc46d 100644
--- a/helper/logging/logfile.go
+++ b/helper/logging/logfile.go
@@ -57,7 +57,8 @@ func (l *LogFile) Write(b []byte) (n int, err error) {
if err := l.openNew(); err != nil {
return 0, err
}
- } else if err := l.rotate(); err != nil { // Check for the last contact and rotate if necessary
+ }
+ if err := l.rotate(); err != nil { // Check for the last contact and rotate if necessary
return 0, err
}
@@ -82,21 +83,20 @@ func (l *LogFile) fileNamePattern() string {
}
func (l *LogFile) openNew() error {
- fileNamePattern := l.fileNamePattern()
-
- createTime := now()
- newFileName := fmt.Sprintf(fileNamePattern, strconv.FormatInt(createTime.UnixNano(), 10))
+ newFileName := l.fileName
newFilePath := filepath.Join(l.logPath, newFileName)
- // Try creating a file. We truncate the file because we are the only authority to write the logs
- filePointer, err := os.OpenFile(newFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o640)
+ // Try creating or opening the active log file. Since the active log file
+ // always has the same name, append log entries to prevent overwriting
+ // previous log data.
+ filePointer, err := os.OpenFile(newFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o640)
if err != nil {
return err
}
- // New file, new 'bytes' tracker, new creation time :) :)
+ // New file, new bytes tracker, new creation time :)
l.fileInfo = filePointer
- l.lastCreated = createTime
+ l.lastCreated = now()
l.bytesWritten = 0
return nil
}
@@ -109,6 +109,9 @@ func (l *LogFile) rotate() error {
if err := l.fileInfo.Close(); err != nil {
return err
}
+ if err := l.renameCurrentFile(); err != nil {
+ return err
+ }
if err := l.pruneFiles(); err != nil {
return err
}
@@ -148,3 +151,13 @@ func removeFiles(files []string) (err error) {
}
return err
}
+
+func (l *LogFile) renameCurrentFile() error {
+ fileNamePattern := l.fileNamePattern()
+ createTime := now()
+ currentFilePath := filepath.Join(l.logPath, l.fileName)
+ oldFileName := fmt.Sprintf(fileNamePattern, strconv.FormatInt(createTime.UnixNano(), 10))
+ oldFilePath := filepath.Join(l.logPath, oldFileName)
+
+ return os.Rename(currentFilePath, oldFilePath)
+}
diff --git a/helper/logging/logger.go b/helper/logging/logger.go
index 8b21bdfa5106..b37134b93cb4 100644
--- a/helper/logging/logger.go
+++ b/helper/logging/logger.go
@@ -11,7 +11,7 @@ import (
"strings"
"time"
- log "github.com/hashicorp/go-hclog"
+ "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-multierror"
)
@@ -32,7 +32,7 @@ type LogConfig struct {
Name string
// LogLevel is the minimum level to be logged.
- LogLevel log.Level
+ LogLevel hclog.Level
// LogFormat is the log format to use, supported formats are 'standard' and 'json'.
LogFormat LogFormat
@@ -48,10 +48,27 @@ type LogConfig struct {
// LogRotateMaxFiles is the maximum number of past archived log files to keep
LogRotateMaxFiles int
+
+ // DefaultFileName should be set to the value to be used if the LogFilePath
+ // ends in a path separator such as '/var/log/'
+ // Examples of the default name are as follows: 'vault', 'agent' or 'proxy.
+ // The creator of this struct *must* ensure that it is assigned before doing
+ // anything with LogConfig!
+ DefaultFileName string
+}
+
+// NewLogConfig should be used to initialize the LogConfig struct.
+func NewLogConfig(defaultFileName string) (*LogConfig, error) {
+ defaultFileName = strings.TrimSpace(defaultFileName)
+ if defaultFileName == "" {
+ return nil, errors.New("default file name is required")
+ }
+
+ return &LogConfig{DefaultFileName: defaultFileName}, nil
}
func (c *LogConfig) isLevelInvalid() bool {
- return c.LogLevel == log.NoLevel || c.LogLevel == log.Off || c.LogLevel.String() == "unknown"
+ return c.LogLevel == hclog.NoLevel || c.LogLevel == hclog.Off || c.LogLevel.String() == "unknown"
}
func (c *LogConfig) isFormatJson() bool {
@@ -104,7 +121,7 @@ func parseFullPath(fullPath string) (directory, fileName string, err error) {
}
// Setup creates a new logger with the specified configuration and writer
-func Setup(config *LogConfig, w io.Writer) (log.InterceptLogger, error) {
+func Setup(config *LogConfig, w io.Writer) (hclog.InterceptLogger, error) {
// Validate the log level
if config.isLevelInvalid() {
return nil, fmt.Errorf("invalid log level: %v", config.LogLevel)
@@ -121,7 +138,9 @@ func Setup(config *LogConfig, w io.Writer) (log.InterceptLogger, error) {
if err != nil {
return nil, err
}
-
+ if fileName == "" {
+ fileName = fmt.Sprintf("%s.log", config.DefaultFileName)
+ }
if config.LogRotateDuration == 0 {
config.LogRotateDuration = defaultRotateDuration
}
@@ -142,7 +161,7 @@ func Setup(config *LogConfig, w io.Writer) (log.InterceptLogger, error) {
writers = append(writers, logFile)
}
- logger := log.NewInterceptLogger(&log.LoggerOptions{
+ logger := hclog.NewInterceptLogger(&hclog.LoggerOptions{
Name: config.Name,
Level: config.LogLevel,
IndependentLevels: true,
@@ -169,21 +188,21 @@ func ParseLogFormat(format string) (LogFormat, error) {
// ParseLogLevel returns the hclog.Level that corresponds with the provided level string.
// This differs hclog.LevelFromString in that it supports additional level strings.
-func ParseLogLevel(logLevel string) (log.Level, error) {
- var result log.Level
+func ParseLogLevel(logLevel string) (hclog.Level, error) {
+ var result hclog.Level
logLevel = strings.ToLower(strings.TrimSpace(logLevel))
switch logLevel {
case "trace":
- result = log.Trace
+ result = hclog.Trace
case "debug":
- result = log.Debug
+ result = hclog.Debug
case "notice", "info", "":
- result = log.Info
+ result = hclog.Info
case "warn", "warning":
- result = log.Warn
+ result = hclog.Warn
case "err", "error":
- result = log.Error
+ result = hclog.Error
default:
return -1, errors.New(fmt.Sprintf("unknown log level: %s", logLevel))
}
@@ -192,11 +211,11 @@ func ParseLogLevel(logLevel string) (log.Level, error) {
}
// TranslateLoggerLevel returns the string that corresponds with logging level of the hclog.Logger.
-func TranslateLoggerLevel(logger log.Logger) (string, error) {
+func TranslateLoggerLevel(logger hclog.Logger) (string, error) {
logLevel := logger.GetLevel()
switch logLevel {
- case log.Trace, log.Debug, log.Info, log.Warn, log.Error:
+ case hclog.Trace, hclog.Debug, hclog.Info, hclog.Warn, hclog.Error:
return logLevel.String(), nil
default:
return "", fmt.Errorf("unknown log level")
diff --git a/helper/logging/logger_test.go b/helper/logging/logger_test.go
index 20538101c7a3..c5f7ec50d9bc 100644
--- a/helper/logging/logger_test.go
+++ b/helper/logging/logger_test.go
@@ -8,15 +8,17 @@ import (
"encoding/json"
"errors"
"os"
+ "path/filepath"
"testing"
- log "github.com/hashicorp/go-hclog"
+ "github.com/hashicorp/go-hclog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestLogger_SetupBasic(t *testing.T) {
- cfg := &LogConfig{Name: "test-system", LogLevel: log.Info}
+ cfg := newTestLogConfig(t)
+ cfg.LogLevel = hclog.Info
logger, err := Setup(cfg, nil)
require.NoError(t, err)
@@ -26,16 +28,15 @@ func TestLogger_SetupBasic(t *testing.T) {
}
func TestLogger_SetupInvalidLogLevel(t *testing.T) {
- cfg := &LogConfig{}
+ cfg := newTestLogConfig(t)
_, err := Setup(cfg, nil)
assert.Containsf(t, err.Error(), "invalid log level", "expected error %s", err)
}
func TestLogger_SetupLoggerErrorLevel(t *testing.T) {
- cfg := &LogConfig{
- LogLevel: log.Error,
- }
+ cfg := newTestLogConfig(t)
+ cfg.LogLevel = hclog.Error
var buf bytes.Buffer
@@ -48,15 +49,16 @@ func TestLogger_SetupLoggerErrorLevel(t *testing.T) {
output := buf.String()
- require.Contains(t, output, "[ERROR] test error msg")
- require.NotContains(t, output, "[INFO] test info msg")
+ require.Contains(t, output, "[ERROR] test-system: test error msg")
+ require.NotContains(t, output, "[INFO] test-system: test info msg")
}
func TestLogger_SetupLoggerDebugLevel(t *testing.T) {
- cfg := LogConfig{LogLevel: log.Debug}
+ cfg := newTestLogConfig(t)
+ cfg.LogLevel = hclog.Debug
var buf bytes.Buffer
- logger, err := Setup(&cfg, &buf)
+ logger, err := Setup(cfg, &buf)
require.NoError(t, err)
require.NotNil(t, logger)
@@ -65,15 +67,14 @@ func TestLogger_SetupLoggerDebugLevel(t *testing.T) {
output := buf.String()
- require.Contains(t, output, "[INFO] test info msg")
- require.Contains(t, output, "[DEBUG] test debug msg")
+ require.Contains(t, output, "[INFO] test-system: test info msg")
+ require.Contains(t, output, "[DEBUG] test-system: test debug msg")
}
-func TestLogger_SetupLoggerWithName(t *testing.T) {
- cfg := &LogConfig{
- LogLevel: log.Debug,
- Name: "test-system",
- }
+func TestLogger_SetupLoggerWithoutName(t *testing.T) {
+ cfg := newTestLogConfig(t)
+ cfg.Name = ""
+ cfg.LogLevel = hclog.Info
var buf bytes.Buffer
logger, err := Setup(cfg, &buf)
@@ -82,15 +83,13 @@ func TestLogger_SetupLoggerWithName(t *testing.T) {
logger.Warn("test warn msg")
- require.Contains(t, buf.String(), "[WARN] test-system: test warn msg")
+ require.Contains(t, buf.String(), "[WARN] test warn msg")
}
func TestLogger_SetupLoggerWithJSON(t *testing.T) {
- cfg := &LogConfig{
- LogLevel: log.Debug,
- LogFormat: JSONFormat,
- Name: "test-system",
- }
+ cfg := newTestLogConfig(t)
+ cfg.LogLevel = hclog.Debug
+ cfg.LogFormat = JSONFormat
var buf bytes.Buffer
logger, err := Setup(cfg, &buf)
@@ -108,13 +107,68 @@ func TestLogger_SetupLoggerWithJSON(t *testing.T) {
require.Equal(t, jsonOutput["@message"], "test warn msg")
}
-func TestLogger_SetupLoggerWithValidLogPath(t *testing.T) {
+func TestLogger_SetupLoggerWithValidLogPathMissingFileName(t *testing.T) {
tmpDir := t.TempDir()
+ cfg := newTestLogConfig(t)
+ cfg.LogLevel = hclog.Info
+ cfg.LogFilePath = tmpDir + "/" // add the trailing slash to the temp dir
+ var buf bytes.Buffer
- cfg := &LogConfig{
- LogLevel: log.Info,
- LogFilePath: tmpDir, //+ "/",
- }
+ logger, err := Setup(cfg, &buf)
+ require.NoError(t, err)
+ require.NotNil(t, logger)
+
+ logger.Info("juan?")
+
+ m, err := filepath.Glob(cfg.LogFilePath + "*")
+ require.NoError(t, err)
+ require.Truef(t, len(m) == 1, "no files were found")
+}
+
+func TestLogger_SetupLoggerWithValidLogPathFileName(t *testing.T) {
+ tmpDir := t.TempDir()
+ cfg := newTestLogConfig(t)
+ cfg.LogLevel = hclog.Info
+ cfg.LogFilePath = filepath.Join(tmpDir, "juan.log")
+ var buf bytes.Buffer
+
+ logger, err := Setup(cfg, &buf)
+ require.NoError(t, err)
+ require.NotNil(t, logger)
+
+ logger.Info("juan?")
+ f, err := os.Stat(cfg.LogFilePath)
+ require.NoError(t, err)
+ require.NotNil(t, f)
+}
+
+func TestLogger_SetupLoggerWithValidLogPathFileNameRotate(t *testing.T) {
+ tmpDir := t.TempDir()
+ cfg := newTestLogConfig(t)
+ cfg.LogLevel = hclog.Info
+ cfg.LogFilePath = filepath.Join(tmpDir, "juan.log")
+ cfg.LogRotateBytes = 1 // set a tiny number of bytes to force rotation
+ var buf bytes.Buffer
+
+ logger, err := Setup(cfg, &buf)
+ require.NoError(t, err)
+ require.NotNil(t, logger)
+
+ logger.Info("juan?")
+ logger.Info("john?")
+ f, err := os.Stat(cfg.LogFilePath)
+ require.NoError(t, err)
+ require.NotNil(t, f)
+ m, err := filepath.Glob(tmpDir + "/juan-*") // look for juan-{timestamp}.log
+ require.NoError(t, err)
+ require.Truef(t, len(m) == 1, "no files were found")
+}
+
+func TestLogger_SetupLoggerWithValidLogPath(t *testing.T) {
+ tmpDir := t.TempDir()
+ cfg := newTestLogConfig(t)
+ cfg.LogLevel = hclog.Info
+ cfg.LogFilePath = tmpDir + "/" // add the trailing slash to the temp dir
var buf bytes.Buffer
logger, err := Setup(cfg, &buf)
@@ -123,10 +177,10 @@ func TestLogger_SetupLoggerWithValidLogPath(t *testing.T) {
}
func TestLogger_SetupLoggerWithInValidLogPath(t *testing.T) {
- cfg := &LogConfig{
- LogLevel: log.Info,
- LogFilePath: "nonexistentdir/",
- }
+ cfg := newTestLogConfig(t)
+ cfg.LogLevel = hclog.Info
+ cfg.LogLevel = hclog.Info
+ cfg.LogFilePath = "nonexistentdir/"
var buf bytes.Buffer
logger, err := Setup(cfg, &buf)
@@ -142,10 +196,9 @@ func TestLogger_SetupLoggerWithInValidLogPathPermission(t *testing.T) {
assert.NoError(t, err, "unexpected error testing with invalid log path permission")
defer os.RemoveAll(tmpDir)
- cfg := &LogConfig{
- LogLevel: log.Info,
- LogFilePath: tmpDir + "/",
- }
+ cfg := newTestLogConfig(t)
+ cfg.LogLevel = hclog.Info
+ cfg.LogFilePath = tmpDir + "/"
var buf bytes.Buffer
logger, err := Setup(cfg, &buf)
@@ -188,10 +241,10 @@ func TestLogger_SetupLoggerWithInvalidLogFilePath(t *testing.T) {
for name, tc := range cases {
name := name
tc := tc
- cfg := &LogConfig{
- LogLevel: log.Info,
- LogFilePath: tc.path,
- }
+ cfg := newTestLogConfig(t)
+ cfg.LogLevel = hclog.Info
+ cfg.LogFilePath = tc.path
+
_, err := Setup(cfg, &bytes.Buffer{})
assert.Error(t, err, "%s: expected error due to *", name)
assert.Contains(t, err.Error(), tc.message, "%s: error message does not match: %s", name, err.Error())
@@ -199,26 +252,34 @@ func TestLogger_SetupLoggerWithInvalidLogFilePath(t *testing.T) {
}
func TestLogger_ChangeLogLevels(t *testing.T) {
- cfg := &LogConfig{
- LogLevel: log.Debug,
- Name: "test-system",
- }
+ cfg := newTestLogConfig(t)
+ cfg.LogLevel = hclog.Debug
var buf bytes.Buffer
logger, err := Setup(cfg, &buf)
require.NoError(t, err)
require.NotNil(t, logger)
- assert.Equal(t, log.Debug, logger.GetLevel())
+ assert.Equal(t, hclog.Debug, logger.GetLevel())
// Create new named loggers from the base logger and change the levels
logger2 := logger.Named("test2")
logger3 := logger.Named("test3")
- logger2.SetLevel(log.Info)
- logger3.SetLevel(log.Error)
+ logger2.SetLevel(hclog.Info)
+ logger3.SetLevel(hclog.Error)
+
+ assert.Equal(t, hclog.Debug, logger.GetLevel())
+ assert.Equal(t, hclog.Info, logger2.GetLevel())
+ assert.Equal(t, hclog.Error, logger3.GetLevel())
+}
+
+func newTestLogConfig(t *testing.T) *LogConfig {
+ t.Helper()
+
+ cfg, err := NewLogConfig("test")
+ require.NoError(t, err)
+ cfg.Name = "test-system"
- assert.Equal(t, log.Debug, logger.GetLevel())
- assert.Equal(t, log.Info, logger2.GetLevel())
- assert.Equal(t, log.Error, logger3.GetLevel())
+ return cfg
}
diff --git a/website/content/docs/agent-and-proxy/agent/index.mdx b/website/content/docs/agent-and-proxy/agent/index.mdx
index 5fae0df52500..7ce716eb6384 100644
--- a/website/content/docs/agent-and-proxy/agent/index.mdx
+++ b/website/content/docs/agent-and-proxy/agent/index.mdx
@@ -83,14 +83,17 @@ See the [caching](/vault/docs/agent-and-proxy/agent/caching#api) page for detail
are `standard` and `json`. This can also be specified via the
`VAULT_LOG_FORMAT` environment variable.
-- `-log-file` ((#\_log_file)) - writes all the Vault agent log messages
- to a file. This value is used as a prefix for the log file name. The current timestamp
- is appended to the file name. If the value ends in a path separator, `vault-agent`
- will be appended to the value. If the file name is missing an extension, `.log`
- is appended. For example, setting `log-file` to `/var/log/` would result in a log
- file path of `/var/log/vault-agent-{timestamp}.log`. `log-file` can be combined with
- [`-log-rotate-bytes`](#_log_rotate_bytes) and [`-log-rotate-duration`](#_log_rotate_duration)
- for a fine-grained log rotation experience.
+- `-log-file` ((#\_log_file)) - the absolute path where Vault Agent should save
+ log messages. Paths that end with a path separator use the default file name,
+ `agent.log`. Paths that do not end with a file extension use the default
+ `.log` extension. If the log file rotates, Vault Agent appends the current
+ timestamp to the file name at the time of rotation. For example:
+
+ `log-file` | Full log file | Rotated log file
+ ---------- | ------------- | ----------------
+ `/var/log` | `/var/log/agent.log` | `/var/log/agent-{timestamp}.log`
+ `/var/log/my-diary` | `/var/log/my-diary.log` | `/var/log/my-diary-{timestamp}.log`
+ `/var/log/my-diary.txt` | `/var/log/my-diary.txt` | `/var/log/my-diary-{timestamp}.txt`
- `-log-rotate-bytes` ((#\_log_rotate_bytes)) - to specify the number of
bytes that should be written to a log before it needs to be rotated. Unless specified,
diff --git a/website/content/docs/agent-and-proxy/proxy/index.mdx b/website/content/docs/agent-and-proxy/proxy/index.mdx
index fdaae8ab8178..086ff87eddde 100644
--- a/website/content/docs/agent-and-proxy/proxy/index.mdx
+++ b/website/content/docs/agent-and-proxy/proxy/index.mdx
@@ -75,14 +75,17 @@ also be specified via the `VAULT_LOG_LEVEL` environment variable.
are `standard` and `json`. This can also be specified via the
`VAULT_LOG_FORMAT` environment variable.
-- `-log-file` ((#\_log_file)) - writes all the Vault proxy log messages
-to a file. This value is used as a prefix for the log file name. The current timestamp
-is appended to the file name. If the value ends in a path separator, `vault-proxy`
-will be appended to the value. If the file name is missing an extension, `.log`
-is appended. For example, setting `log-file` to `/var/log/` would result in a log
-file path of `/var/log/vault-proxy-{timestamp}.log`. `log-file` can be combined with
-[`-log-rotate-bytes`](#_log_rotate_bytes) and [`-log-rotate-duration`](#_log_rotate_duration)
-for a fine-grained log rotation experience.
+- `-log-file` ((#\_log_file)) - the absolute path where Vault Proxy should save
+ log messages. Paths that end with a path separator use the default file name,
+ `proxy.log`. Paths that do not end with a file extension use the default
+ `.log` extension. If the log file rotates, Vault Proxy appends the current
+ timestamp to the file name at the time of rotation. For example:
+
+ `log-file` | Full log file | Rotated log file
+ ---------- | ------------- | ----------------
+ `/var/log` | `/var/log/proxy.log` | `/var/log/proxy-{timestamp}.log`
+ `/var/log/my-diary` | `/var/log/my-diary.log` | `/var/log/my-diary-{timestamp}.log`
+ `/var/log/my-diary.txt` | `/var/log/my-diary.txt` | `/var/log/my-diary-{timestamp}.txt`
- `-log-rotate-bytes` ((#\_log_rotate_bytes)) - to specify the number of
bytes that should be written to a log before it needs to be rotated. Unless specified,
diff --git a/website/content/docs/commands/server.mdx b/website/content/docs/commands/server.mdx
index 8c9f08f05d0d..8a12a738aa23 100644
--- a/website/content/docs/commands/server.mdx
+++ b/website/content/docs/commands/server.mdx
@@ -60,15 +60,18 @@ flags](/vault/docs/commands) included on all commands.
are `standard` and `json`. This can also be specified via the
`VAULT_LOG_FORMAT` environment variable.
-- `-log-file` ((#\_log_file)) - writes all the Vault log messages
- to a file. This value is used as a prefix for the log file name. The current timestamp
- is appended to the file name. If the value ends in a path separator, `vault`
- will be appended to the value. If the file name is missing an extension, `.log`
- is appended. For example, setting `log-file` to `/var/log/` would result in a log
- file path of `/var/log/vault-{timestamp}.log`. `log-file` can be combined with
- [`-log-rotate-bytes`](#_log_rotate_bytes) and [`-log-rotate-duration`](#_log_rotate_duration)
- for a fine-grained log rotation experience. This output operates in addition to existing
- outputs, meaning logs will continue to be written to journald / stdout (where appropriate).
+- `-log-file` ((#\_log_file)) - the absolute path where Vault should save log
+ messages in addition to other, existing outputs like journald / stdout. Paths
+ that end with a path separator use the default file name, `vault.log`. Paths
+ that do not end with a file extension use the default `.log` extension. If the
+ log file rotates, Vault appends the current timestamp to the file name
+ at the time of rotation. For example:
+
+ `log-file` | Full log file | Rotated log file
+ ---------- | ------------- | ----------------
+ `/var/log` | `/var/log/vault.log` | `/var/log/vault-{timestamp}.log`
+ `/var/log/my-diary` | `/var/log/my-diary.log` | `/var/log/my-diary-{timestamp}.log`
+ `/var/log/my-diary.txt` | `/var/log/my-diary.txt` | `/var/log/my-diary-{timestamp}.txt`
- `-log-rotate-bytes` ((#\_log_rotate_bytes)) - to specify the number of
bytes that should be written to a log before it needs to be rotated. Unless specified,
From 4a7bee5a02db880d543692386ccd597f33e29624 Mon Sep 17 00:00:00 2001
From: Mike Palmiotto
Date: Fri, 1 Dec 2023 09:47:32 -0500
Subject: [PATCH 51/74] Always forward entity merge requests from perfStandby
(#24325)
Update requests to /sys/identity/entity/merge perform merges on perfStandby nodes in memory and skip the persist call.
This commit changes the behavior for the merge endpoint, forcing it to be forwarded from the standby to the active node. This change is specifically scoped to manual merges, as automatic merges are not isolated to a specific endpoint and require careful consideration for all callers.
---
changelog/24325.txt | 4 ++++
vault/identity_store_entities.go | 3 ++-
2 files changed, 6 insertions(+), 1 deletion(-)
create mode 100644 changelog/24325.txt
diff --git a/changelog/24325.txt b/changelog/24325.txt
new file mode 100644
index 000000000000..ab5ce613c404
--- /dev/null
+++ b/changelog/24325.txt
@@ -0,0 +1,4 @@
+```release-note:change
+identity (enterprise): POST requests to the `/identity/entity/merge` endpoint
+are now always forwarded from standbys to the active node.
+```
\ No newline at end of file
diff --git a/vault/identity_store_entities.go b/vault/identity_store_entities.go
index 05c83c7bd2b0..6094339c4e84 100644
--- a/vault/identity_store_entities.go
+++ b/vault/identity_store_entities.go
@@ -231,7 +231,8 @@ func entityPaths(i *IdentityStore) []*framework.Path {
},
Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{
- Callback: i.pathEntityMergeID(),
+ Callback: i.pathEntityMergeID(),
+ ForwardPerformanceStandby: true,
},
},
From 73f46fca3ea00cfafccb4607fb13e4510f9f11dd Mon Sep 17 00:00:00 2001
From: Raymond Ho
Date: Fri, 1 Dec 2023 11:30:58 -0800
Subject: [PATCH 52/74] optimize NewTestCluster (#24300)
---
.../external_tests/api/sys_rekey_ext_test.go | 7 +-
.../sealmigration/testshared.go | 3 +-
vault/testing.go | 71 ++++++++++---------
3 files changed, 43 insertions(+), 38 deletions(-)
diff --git a/vault/external_tests/api/sys_rekey_ext_test.go b/vault/external_tests/api/sys_rekey_ext_test.go
index f1a63ed83920..2661987f14ce 100644
--- a/vault/external_tests/api/sys_rekey_ext_test.go
+++ b/vault/external_tests/api/sys_rekey_ext_test.go
@@ -9,6 +9,7 @@ import (
"testing"
"github.com/hashicorp/go-hclog"
+
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/testhelpers"
vaulthttp "github.com/hashicorp/vault/http"
@@ -143,7 +144,7 @@ func testSysRekey_Verification(t *testing.T, recovery bool, legacyShamir bool) {
// Sealing should clear state, so after this we should be able to perform
// the above again
cluster.EnsureCoresSealed(t)
- if err := cluster.UnsealCoresWithError(recovery); err != nil {
+ if err := cluster.UnsealCoresWithError(t, recovery); err != nil {
t.Fatal(err)
}
doRekeyInitialSteps()
@@ -259,7 +260,7 @@ func testSysRekey_Verification(t *testing.T, recovery bool, legacyShamir bool) {
cluster.Start()
defer cluster.Cleanup()
- if err := cluster.UnsealCoresWithError(false); err == nil {
+ if err := cluster.UnsealCoresWithError(t, false); err == nil {
t.Fatal("expected error")
}
@@ -273,7 +274,7 @@ func testSysRekey_Verification(t *testing.T, recovery bool, legacyShamir bool) {
newKeyBytes = append(newKeyBytes, val)
}
cluster.BarrierKeys = newKeyBytes
- if err := cluster.UnsealCoresWithError(false); err != nil {
+ if err := cluster.UnsealCoresWithError(t, false); err != nil {
t.Fatal(err)
}
} else {
diff --git a/vault/external_tests/sealmigration/testshared.go b/vault/external_tests/sealmigration/testshared.go
index a50acced19d3..f6ec26ddf27d 100644
--- a/vault/external_tests/sealmigration/testshared.go
+++ b/vault/external_tests/sealmigration/testshared.go
@@ -13,6 +13,7 @@ import (
"github.com/go-test/deep"
"github.com/hashicorp/go-hclog"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
+
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/helper/testhelpers"
@@ -801,7 +802,7 @@ func runAutoseal(t *testing.T, logger hclog.Logger, storage teststorage.Reusable
t.Fatal(err)
}
} else {
- if err := cluster.UnsealCoresWithError(true); err != nil {
+ if err := cluster.UnsealCoresWithError(t, true); err != nil {
t.Fatal(err)
}
}
diff --git a/vault/testing.go b/vault/testing.go
index 9f8f2881da1a..ec3088e5b994 100644
--- a/vault/testing.go
+++ b/vault/testing.go
@@ -37,6 +37,11 @@ import (
"github.com/hashicorp/go-secure-stdlib/reloadutil"
raftlib "github.com/hashicorp/raft"
kv "github.com/hashicorp/vault-plugin-secrets-kv"
+ "github.com/mitchellh/copystructure"
+ "github.com/mitchellh/go-testing-interface"
+ "golang.org/x/crypto/ed25519"
+ "golang.org/x/net/http2"
+
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/audit"
auditFile "github.com/hashicorp/vault/builtin/audit/file"
@@ -59,10 +64,6 @@ import (
backendplugin "github.com/hashicorp/vault/sdk/plugin"
"github.com/hashicorp/vault/vault/cluster"
"github.com/hashicorp/vault/vault/seal"
- "github.com/mitchellh/copystructure"
- "github.com/mitchellh/go-testing-interface"
- "golang.org/x/crypto/ed25519"
- "golang.org/x/net/http2"
)
// This file contains a number of methods that are useful for unit
@@ -873,7 +874,7 @@ func (c *TestCluster) start(t testing.T) {
activeCore := -1
WAITACTIVE:
- for i := 0; i < 60; i++ {
+ for i := 0; i < 600; i++ {
for i, core := range c.Cores {
if standby, _ := core.Core.Standby(); !standby {
activeCore = i
@@ -881,7 +882,7 @@ WAITACTIVE:
}
}
- time.Sleep(time.Second)
+ time.Sleep(100 * time.Millisecond)
}
if activeCore == -1 {
t.Fatalf("no core became active")
@@ -917,12 +918,12 @@ WAITACTIVE:
// UnsealCores uses the cluster barrier keys to unseal the test cluster cores
func (c *TestCluster) UnsealCores(t testing.T) {
t.Helper()
- if err := c.UnsealCoresWithError(false); err != nil {
+ if err := c.UnsealCoresWithError(t, false); err != nil {
t.Fatal(err)
}
}
-func (c *TestCluster) UnsealCoresWithError(useStoredKeys bool) error {
+func (c *TestCluster) UnsealCoresWithError(t testing.T, useStoredKeys bool) error {
unseal := func(core *Core) error {
for _, key := range c.BarrierKeys {
if _, err := core.Unseal(TestKeyCopy(key)); err != nil {
@@ -959,19 +960,21 @@ func (c *TestCluster) UnsealCoresWithError(useStoredKeys bool) error {
}
// Let them come fully up to standby
- time.Sleep(2 * time.Second)
-
- // Ensure cluster connection info is populated.
- // Other cores should not come up as leaders.
- for i := 1; i < len(c.Cores); i++ {
- isLeader, _, _, err := c.Cores[i].Leader()
- if err != nil {
- return err
- }
- if isLeader {
- return fmt.Errorf("core[%d] should not be leader", i)
+ corehelpers.RetryUntil(t, 2*time.Second, func() error {
+ // Ensure cluster connection info is populated.
+ // Other cores should not come up as leaders.
+ for i := 1; i < len(c.Cores); i++ {
+ isLeader, _, _, err := c.Cores[i].Leader()
+ if err != nil {
+ return err
+ }
+ if isLeader {
+ return fmt.Errorf("core[%d] should not be leader", i)
+ }
}
- }
+
+ return nil
+ })
return nil
}
@@ -1109,8 +1112,6 @@ func (c *TestCluster) Cleanup() {
os.RemoveAll(c.TempDir)
}
- // Give time to actually shut down/clean up before the next test
- time.Sleep(time.Second)
if c.CleanupFunc != nil {
c.CleanupFunc()
}
@@ -2177,19 +2178,21 @@ func (tc *TestCluster) initCores(t testing.T, opts *TestClusterOptions, addAudit
}
// Let them come fully up to standby
- time.Sleep(2 * time.Second)
-
- // Ensure cluster connection info is populated.
- // Other cores should not come up as leaders.
- for i := 1; i < numCores; i++ {
- isLeader, _, _, err := tc.Cores[i].Core.Leader()
- if err != nil {
- t.Fatal(err)
- }
- if isLeader {
- t.Fatalf("core[%d] should not be leader", i)
+ corehelpers.RetryUntil(t, 2*time.Second, func() error {
+ // Ensure cluster connection info is populated.
+ // Other cores should not come up as leaders.
+ for i := 1; i < numCores; i++ {
+ isLeader, _, _, err := tc.Cores[i].Core.Leader()
+ if err != nil {
+ return err
+ }
+ if isLeader {
+ return fmt.Errorf("core[%d] should not be leader", i)
+ }
}
- }
+
+ return nil
+ })
}
//
From 22cbf23f47dd89e77c2cabd4f5f39c45ac5d5f29 Mon Sep 17 00:00:00 2001
From: Meggie
Date: Fri, 1 Dec 2023 16:21:39 -0500
Subject: [PATCH 53/74] changelog++ (#24329)
---
CHANGELOG.md | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cc17febcfa35..2bccb7febdf4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,41 @@
- [v1.0.0 - v1.9.10](CHANGELOG-pre-v1.10.md)
- [v0.11.6 and earlier](CHANGELOG-v0.md)
+## 1.15.3
+### November 30, 2023
+
+CHANGES:
+
+* core: Bump Go version to 1.21.4.
+
+IMPROVEMENTS:
+
+* core (enterprise): Speed up unseal when using namespaces
+* core: update sys/seal-status (and CLI vault status) to report the type of
+the seal when unsealed, as well as the type of the recovery seal if an
+auto-seal. [[GH-23022](https://github.com/hashicorp/vault/pull/23022)]
+* secrets/pki: do not check TLS validity on ACME requests redirected to https [[GH-22521](https://github.com/hashicorp/vault/pull/22521)]
+* ui: Sort list view of entities and aliases alphabetically using the item name [[GH-24103](https://github.com/hashicorp/vault/pull/24103)]
+* ui: capabilities-self is always called in the user's root namespace [[GH-24168](https://github.com/hashicorp/vault/pull/24168)]
+
+BUG FIXES:
+
+* activity log (enterprise): De-duplicate client count estimates for license utilization reporting.
+* auth/cert: Handle errors related to expired OCSP server responses [[GH-24193](https://github.com/hashicorp/vault/pull/24193)]
+* core (Enterprise): Treat multiple disabled HA seals as a migration to Shamir.
+* core/audit: Audit logging a Vault response will now use a 5 second context timeout, separate from the original request. [[GH-24238](https://github.com/hashicorp/vault/pull/24238)]
+* core/config: Use correct HCL config value when configuring `log_requests_level`. [[GH-24059](https://github.com/hashicorp/vault/pull/24059)]
+* core/quotas: Close rate-limit blocked client purge goroutines when sealing [[GH-24108](https://github.com/hashicorp/vault/pull/24108)]
+* core: Fix an error that resulted in the wrong seal type being returned by sys/seal-status while
+Vault is in seal migration mode. [[GH-24165](https://github.com/hashicorp/vault/pull/24165)]
+* replication (enterprise): disallow configuring paths filter for a mount path that does not exist
+* secrets-sync (enterprise): Fix panic when setting usage_gauge_period to none
+* secrets/pki: Do not set nextUpdate field in OCSP responses when ocsp_expiry is 0 [[GH-24192](https://github.com/hashicorp/vault/pull/24192)]
+* secrets/transit: Fix a panic when attempting to export a public RSA key [[GH-24054](https://github.com/hashicorp/vault/pull/24054)]
+* ui: Fix JSON editor in KV V2 unable to handle pasted values [[GH-24224](https://github.com/hashicorp/vault/pull/24224)]
+* ui: Fix error when tuning token auth configuration within namespace [[GH-24147](https://github.com/hashicorp/vault/pull/24147)]
+* ui: show error from API when seal fails [[GH-23921](https://github.com/hashicorp/vault/pull/23921)]
+
## 1.15.2
### November 09, 2023
@@ -336,6 +371,31 @@ sdk/ldaputil: use EscapeLDAPValue implementation from cap/ldap [[GH-22249](https
* ui: fixes model defaults overwriting input value when user tries to clear form input [[GH-22458](https://github.com/hashicorp/vault/pull/22458)]
* ui: fixes text readability issue in revoke token confirmation dialog [[GH-22390](https://github.com/hashicorp/vault/pull/22390)]
+## 1.14.7
+### November 30, 2023
+
+CHANGES:
+
+* core: Bump Go version to 1.20.11.
+
+IMPROVEMENTS:
+
+* core (enterprise): Speed up unseal when using namespaces
+* secrets/pki: do not check TLS validity on ACME requests redirected to https [[GH-22521](https://github.com/hashicorp/vault/pull/22521)]
+* ui: Sort list view of entities and aliases alphabetically using the item name [[GH-24103](https://github.com/hashicorp/vault/pull/24103)]
+* ui: Update flat, shell-quote and swagger-ui-dist packages. Remove swagger-ui styling overrides. [[GH-23700](https://github.com/hashicorp/vault/pull/23700)]
+
+BUG FIXES:
+
+* activity log (enterprise): De-duplicate client count estimates for license utilization reporting.
+* auth/cert: Handle errors related to expired OCSP server responses [[GH-24193](https://github.com/hashicorp/vault/pull/24193)]
+* core/config: Use correct HCL config value when configuring `log_requests_level`. [[GH-24058](https://github.com/hashicorp/vault/pull/24058)]
+* core/quotas: Close rate-limit blocked client purge goroutines when sealing [[GH-24108](https://github.com/hashicorp/vault/pull/24108)]
+* replication (enterprise): disallow configuring paths filter for a mount path that does not exist
+* secrets/pki: Do not set nextUpdate field in OCSP responses when ocsp_expiry is 0 [[GH-24192](https://github.com/hashicorp/vault/pull/24192)]
+* secrets/transit: Fix a panic when attempting to export a public RSA key [[GH-24054](https://github.com/hashicorp/vault/pull/24054)]
+* ui: Fix error when tuning token auth configuration within namespace [[GH-24147](https://github.com/hashicorp/vault/pull/24147)]
+
## 1.14.6
### November 09, 2023
@@ -802,6 +862,28 @@ with a new entity alias to be incorrectly forwarded from perf standbys. [[GH-211
* ui: fixes key_bits and signature_bits reverting to default values when editing a pki role [[GH-20907](https://github.com/hashicorp/vault/pull/20907)]
* ui: wait for wanted message event during OIDC callback instead of using the first message event [[GH-18521](https://github.com/hashicorp/vault/pull/18521)]
+## 1.13.11
+### November 30, 2023
+
+CHANGES:
+
+* core: Bump Go version to 1.20.11.
+
+IMPROVEMENTS:
+
+* core (enterprise): Speed up unseal when using namespaces
+* ui: Sort list view of entities and aliases alphabetically using the item name [[GH-24103](https://github.com/hashicorp/vault/pull/24103)]
+
+BUG FIXES:
+
+* activity log (enterprise): De-duplicate client count estimates for license utilization reporting.
+* auth/cert: Handle errors related to expired OCSP server responses [[GH-24193](https://github.com/hashicorp/vault/pull/24193)]
+* core/config: Use correct HCL config value when configuring `log_requests_level`. [[GH-24057](https://github.com/hashicorp/vault/pull/24057)]
+* core/quotas: Close rate-limit blocked client purge goroutines when sealing [[GH-24108](https://github.com/hashicorp/vault/pull/24108)]
+* replication (enterprise): disallow configuring paths filter for a mount path that does not exist
+* secrets/pki: Do not set nextUpdate field in OCSP responses when ocsp_expiry is 0 [[GH-24192](https://github.com/hashicorp/vault/pull/24192)]
+* ui: Fix error when tuning token auth configuration within namespace [[GH-24147](https://github.com/hashicorp/vault/pull/24147)]
+
## 1.13.10
### November 09, 2023
From 73df860e906cc1d8810ec66f434dd2e3925f4b5d Mon Sep 17 00:00:00 2001
From: Rachel Culpepper <84159930+rculpepper@users.noreply.github.com>
Date: Fri, 1 Dec 2023 17:07:44 -0500
Subject: [PATCH 54/74] Vault-14651: add function for restarting cluster nodes
(#24335)
* add function for restarting cluster nodes
* fix import
---
sdk/helper/testcluster/docker/environment.go | 49 ++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/sdk/helper/testcluster/docker/environment.go b/sdk/helper/testcluster/docker/environment.go
index 6ce2b1613423..801ee924ac7c 100644
--- a/sdk/helper/testcluster/docker/environment.go
+++ b/sdk/helper/testcluster/docker/environment.go
@@ -16,6 +16,7 @@ import (
"encoding/hex"
"encoding/json"
"encoding/pem"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -25,12 +26,14 @@ import (
"net/http"
"os"
"path/filepath"
+ "strconv"
"strings"
"sync"
"testing"
"time"
"github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/volume"
docker "github.com/docker/docker/client"
"github.com/hashicorp/go-cleanhttp"
@@ -864,6 +867,52 @@ func (n *DockerClusterNode) Pause(ctx context.Context) error {
return n.DockerAPI.ContainerPause(ctx, n.Container.ID)
}
+func (n *DockerClusterNode) Restart(ctx context.Context) error {
+ timeout := 5
+ err := n.DockerAPI.ContainerRestart(ctx, n.Container.ID, container.StopOptions{Timeout: &timeout})
+ if err != nil {
+ return err
+ }
+
+ resp, err := n.DockerAPI.ContainerInspect(ctx, n.Container.ID)
+ if err != nil {
+ return fmt.Errorf("error inspecting container after restart: %s", err)
+ }
+
+ var port int
+ if len(resp.NetworkSettings.Ports) > 0 {
+ for key, binding := range resp.NetworkSettings.Ports {
+ if len(binding) < 1 {
+ continue
+ }
+
+ if key == "8200/tcp" {
+ port, err = strconv.Atoi(binding[0].HostPort)
+ }
+ }
+ }
+
+ if port == 0 {
+ return fmt.Errorf("failed to find container port after restart")
+ }
+
+ hostPieces := strings.Split(n.HostPort, ":")
+ if len(hostPieces) < 2 {
+ return errors.New("could not parse node hostname")
+ }
+
+ n.HostPort = fmt.Sprintf("%s:%d", hostPieces[0], port)
+
+ client, err := n.newAPIClient()
+ if err != nil {
+ return err
+ }
+ client.SetToken(n.Cluster.rootToken)
+ n.client = client
+
+ return nil
+}
+
func (n *DockerClusterNode) AddNetworkDelay(ctx context.Context, delay time.Duration, targetIP string) error {
ip := net.ParseIP(targetIP)
if ip == nil {
From 699fc035e05f8ebfe24f7077ab481f241e549c2e Mon Sep 17 00:00:00 2001
From: Sarah Thompson
Date: Sun, 3 Dec 2023 10:38:45 +0000
Subject: [PATCH 55/74] Remove release-engineering as codeowners (#24237)
---
CODEOWNERS | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/CODEOWNERS b/CODEOWNERS
index 364e143c95d1..2332eea289ce 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -42,8 +42,8 @@
/ui/app/routes/vault/cluster/oidc-*.js @hashicorp/vault-ecosystem-applications
# Release config; service account is required for automation tooling.
-/.release/ @hashicorp/release-engineering @hashicorp/github-secure-vault-core @hashicorp/quality-team
-/.github/workflows/build.yml @hashicorp/release-engineering @hashicorp/github-secure-vault-core @hashicorp/quality-team
+/.release/ @hashicorp/github-secure-vault-core @hashicorp/quality-team
+/.github/workflows/build.yml @hashicorp/github-secure-vault-core @hashicorp/quality-team
# Quality engineering
/.github/ @hashicorp/quality-team
From 85b3dba3102eaf993a33a7342294cec285cbee51 Mon Sep 17 00:00:00 2001
From: Nick Cabatoff
Date: Mon, 4 Dec 2023 08:34:25 -0500
Subject: [PATCH 56/74] Rework sys/health tests to use structs and cmp (#24324)
---
api/sys_health.go | 1 +
http/sys_health_test.go | 249 ++++++++++++++--------------------------
2 files changed, 90 insertions(+), 160 deletions(-)
diff --git a/api/sys_health.go b/api/sys_health.go
index 13fd8d4d3743..17fb4fc10d66 100644
--- a/api/sys_health.go
+++ b/api/sys_health.go
@@ -49,4 +49,5 @@ type HealthResponse struct {
ClusterName string `json:"cluster_name,omitempty"`
ClusterID string `json:"cluster_id,omitempty"`
LastWAL uint64 `json:"last_wal,omitempty"`
+ Enterprise bool `json:"enterprise"`
}
diff --git a/http/sys_health_test.go b/http/sys_health_test.go
index 83ec63db0010..bd64ea853232 100644
--- a/http/sys_health_test.go
+++ b/http/sys_health_test.go
@@ -7,9 +7,11 @@ import (
"io/ioutil"
"net/http"
"net/url"
- "reflect"
"testing"
+ "github.com/google/go-cmp/cmp"
+ "github.com/google/go-cmp/cmp/cmpopts"
+ "github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/constants"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/vault"
@@ -20,73 +22,54 @@ func TestSysHealth_get(t *testing.T) {
ln, addr := TestServer(t, core)
defer ln.Close()
- resp, err := http.Get(addr + "/v1/sys/health")
+ // Test without the client first since we want to verify the response code
+ raw, err := http.Get(addr + "/v1/sys/health")
if err != nil {
t.Fatalf("err: %s", err)
}
+ testResponseStatus(t, raw, 501)
- var actual map[string]interface{}
- expected := map[string]interface{}{
- "enterprise": constants.IsEnterprise,
- "replication_performance_mode": consts.ReplicationUnknown.GetPerformanceString(),
- "replication_dr_mode": consts.ReplicationUnknown.GetDRString(),
- "initialized": false,
- "sealed": true,
- "standby": true,
- "performance_standby": false,
+ // Test with the client because it's a bit easier to work with structs
+ config := api.DefaultConfig()
+ config.Address = addr
+ client, err := api.NewClient(config)
+ if err != nil {
+ t.Fatal(err)
}
- testResponseStatus(t, resp, 501)
- testResponseBody(t, resp, &actual)
- expected["server_time_utc"] = actual["server_time_utc"]
- expected["version"] = actual["version"]
- if actual["cluster_name"] == nil {
- delete(expected, "cluster_name")
- } else {
- expected["cluster_name"] = actual["cluster_name"]
+
+ resp, err := client.Sys().Health()
+ if err != nil {
+ t.Fatalf("err: %s", err)
}
- if actual["cluster_id"] == nil {
- delete(expected, "cluster_id")
- } else {
- expected["cluster_id"] = actual["cluster_id"]
+
+ expected := &api.HealthResponse{
+ Enterprise: constants.IsEnterprise,
+ Initialized: false,
+ Sealed: true,
+ Standby: true,
+ PerformanceStandby: false,
+ ReplicationPerformanceMode: consts.ReplicationUnknown.GetPerformanceString(),
+ ReplicationDRMode: consts.ReplicationUnknown.GetDRString(),
}
- delete(actual, "license")
- if !reflect.DeepEqual(actual, expected) {
- t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
+ ignore := cmpopts.IgnoreFields(*expected, "ClusterName", "ClusterID", "ServerTimeUTC", "Version")
+ if diff := cmp.Diff(resp, expected, ignore); len(diff) > 0 {
+ t.Fatal(diff)
}
keys, _ := vault.TestCoreInit(t, core)
- resp, err = http.Get(addr + "/v1/sys/health")
+ raw, err = http.Get(addr + "/v1/sys/health")
if err != nil {
t.Fatalf("err: %s", err)
}
+ testResponseStatus(t, raw, 503)
- actual = map[string]interface{}{}
- expected = map[string]interface{}{
- "enterprise": constants.IsEnterprise,
- "replication_performance_mode": consts.ReplicationUnknown.GetPerformanceString(),
- "replication_dr_mode": consts.ReplicationUnknown.GetDRString(),
- "initialized": true,
- "sealed": true,
- "standby": true,
- "performance_standby": false,
- }
- testResponseStatus(t, resp, 503)
- testResponseBody(t, resp, &actual)
- expected["server_time_utc"] = actual["server_time_utc"]
- expected["version"] = actual["version"]
- if actual["cluster_name"] == nil {
- delete(expected, "cluster_name")
- } else {
- expected["cluster_name"] = actual["cluster_name"]
- }
- if actual["cluster_id"] == nil {
- delete(expected, "cluster_id")
- } else {
- expected["cluster_id"] = actual["cluster_id"]
+ resp, err = client.Sys().Health()
+ if err != nil {
+ t.Fatalf("err: %s", err)
}
- delete(actual, "license")
- if !reflect.DeepEqual(actual, expected) {
- t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
+ expected.Initialized = true
+ if diff := cmp.Diff(resp, expected, ignore); len(diff) > 0 {
+ t.Fatal(diff)
}
for _, key := range keys {
@@ -94,38 +77,22 @@ func TestSysHealth_get(t *testing.T) {
t.Fatalf("unseal err: %s", err)
}
}
- resp, err = http.Get(addr + "/v1/sys/health")
+ raw, err = http.Get(addr + "/v1/sys/health")
if err != nil {
t.Fatalf("err: %s", err)
}
+ testResponseStatus(t, raw, 200)
- actual = map[string]interface{}{}
- expected = map[string]interface{}{
- "enterprise": constants.IsEnterprise,
- "replication_performance_mode": consts.ReplicationPerformanceDisabled.GetPerformanceString(),
- "replication_dr_mode": consts.ReplicationDRDisabled.GetDRString(),
- "initialized": true,
- "sealed": false,
- "standby": false,
- "performance_standby": false,
- }
- testResponseStatus(t, resp, 200)
- testResponseBody(t, resp, &actual)
- expected["server_time_utc"] = actual["server_time_utc"]
- expected["version"] = actual["version"]
- if actual["cluster_name"] == nil {
- delete(expected, "cluster_name")
- } else {
- expected["cluster_name"] = actual["cluster_name"]
- }
- if actual["cluster_id"] == nil {
- delete(expected, "cluster_id")
- } else {
- expected["cluster_id"] = actual["cluster_id"]
+ resp, err = client.Sys().Health()
+ if err != nil {
+ t.Fatalf("err: %s", err)
}
- delete(actual, "license")
- if !reflect.DeepEqual(actual, expected) {
- t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
+ expected.Sealed = false
+ expected.Standby = false
+ expected.ReplicationPerformanceMode = consts.ReplicationPerformanceDisabled.GetPerformanceString()
+ expected.ReplicationDRMode = consts.ReplicationDRDisabled.GetDRString()
+ if diff := cmp.Diff(resp, expected, ignore); len(diff) > 0 {
+ t.Fatal(diff)
}
}
@@ -138,75 +105,53 @@ func TestSysHealth_customcodes(t *testing.T) {
if err != nil {
t.Fatalf("err: %s", err)
}
- resp, err := http.Get(queryurl.String())
+ raw, err := http.Get(queryurl.String())
if err != nil {
t.Fatalf("err: %s", err)
}
+ testResponseStatus(t, raw, 581)
- var actual map[string]interface{}
- expected := map[string]interface{}{
- "enterprise": constants.IsEnterprise,
- "replication_performance_mode": consts.ReplicationUnknown.GetPerformanceString(),
- "replication_dr_mode": consts.ReplicationUnknown.GetDRString(),
- "initialized": false,
- "sealed": true,
- "standby": true,
- "performance_standby": false,
+ // Test with the client because it's a bit easier to work with structs
+ config := api.DefaultConfig()
+ config.Address = addr
+ client, err := api.NewClient(config)
+ if err != nil {
+ t.Fatal(err)
}
- testResponseStatus(t, resp, 581)
- testResponseBody(t, resp, &actual)
- expected["server_time_utc"] = actual["server_time_utc"]
- expected["version"] = actual["version"]
- if actual["cluster_name"] == nil {
- delete(expected, "cluster_name")
- } else {
- expected["cluster_name"] = actual["cluster_name"]
+ resp, err := client.Sys().Health()
+ if err != nil {
+ t.Fatalf("err: %s", err)
}
- if actual["cluster_id"] == nil {
- delete(expected, "cluster_id")
- } else {
- expected["cluster_id"] = actual["cluster_id"]
+
+ expected := &api.HealthResponse{
+ Enterprise: constants.IsEnterprise,
+ Initialized: false,
+ Sealed: true,
+ Standby: true,
+ PerformanceStandby: false,
+ ReplicationPerformanceMode: consts.ReplicationUnknown.GetPerformanceString(),
+ ReplicationDRMode: consts.ReplicationUnknown.GetDRString(),
}
- delete(actual, "license")
- if !reflect.DeepEqual(actual, expected) {
- t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
+ ignore := cmpopts.IgnoreFields(*expected, "ClusterName", "ClusterID", "ServerTimeUTC", "Version")
+ if diff := cmp.Diff(resp, expected, ignore); len(diff) > 0 {
+ t.Fatal(diff)
}
keys, _ := vault.TestCoreInit(t, core)
- resp, err = http.Get(queryurl.String())
+ raw, err = http.Get(queryurl.String())
if err != nil {
t.Fatalf("err: %s", err)
}
+ testResponseStatus(t, raw, 523)
- actual = map[string]interface{}{}
- expected = map[string]interface{}{
- "enterprise": constants.IsEnterprise,
- "replication_performance_mode": consts.ReplicationUnknown.GetPerformanceString(),
- "replication_dr_mode": consts.ReplicationUnknown.GetDRString(),
- "initialized": true,
- "sealed": true,
- "standby": true,
- "performance_standby": false,
- }
- testResponseStatus(t, resp, 523)
- testResponseBody(t, resp, &actual)
-
- expected["server_time_utc"] = actual["server_time_utc"]
- expected["version"] = actual["version"]
- if actual["cluster_name"] == nil {
- delete(expected, "cluster_name")
- } else {
- expected["cluster_name"] = actual["cluster_name"]
- }
- if actual["cluster_id"] == nil {
- delete(expected, "cluster_id")
- } else {
- expected["cluster_id"] = actual["cluster_id"]
+ resp, err = client.Sys().Health()
+ if err != nil {
+ t.Fatalf("err: %s", err)
}
- delete(actual, "license")
- if !reflect.DeepEqual(actual, expected) {
- t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
+ expected.Initialized = true
+ if diff := cmp.Diff(resp, expected, ignore); len(diff) > 0 {
+ t.Fatal(diff)
}
for _, key := range keys {
@@ -214,38 +159,22 @@ func TestSysHealth_customcodes(t *testing.T) {
t.Fatalf("unseal err: %s", err)
}
}
- resp, err = http.Get(queryurl.String())
+ raw, err = http.Get(queryurl.String())
if err != nil {
t.Fatalf("err: %s", err)
}
+ testResponseStatus(t, raw, 202)
- actual = map[string]interface{}{}
- expected = map[string]interface{}{
- "enterprise": constants.IsEnterprise,
- "replication_performance_mode": consts.ReplicationPerformanceDisabled.GetPerformanceString(),
- "replication_dr_mode": consts.ReplicationDRDisabled.GetDRString(),
- "initialized": true,
- "sealed": false,
- "standby": false,
- "performance_standby": false,
- }
- testResponseStatus(t, resp, 202)
- testResponseBody(t, resp, &actual)
- expected["server_time_utc"] = actual["server_time_utc"]
- expected["version"] = actual["version"]
- if actual["cluster_name"] == nil {
- delete(expected, "cluster_name")
- } else {
- expected["cluster_name"] = actual["cluster_name"]
- }
- if actual["cluster_id"] == nil {
- delete(expected, "cluster_id")
- } else {
- expected["cluster_id"] = actual["cluster_id"]
+ resp, err = client.Sys().Health()
+ if err != nil {
+ t.Fatalf("err: %s", err)
}
- delete(actual, "license")
- if !reflect.DeepEqual(actual, expected) {
- t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
+ expected.Sealed = false
+ expected.Standby = false
+ expected.ReplicationPerformanceMode = consts.ReplicationPerformanceDisabled.GetPerformanceString()
+ expected.ReplicationDRMode = consts.ReplicationDRDisabled.GetDRString()
+ if diff := cmp.Diff(resp, expected, ignore); len(diff) > 0 {
+ t.Fatal(diff)
}
}
From 31ccb2667a6a4c21571cb65c9d8ac767a1ec4e23 Mon Sep 17 00:00:00 2001
From: Nick Cabatoff
Date: Mon, 4 Dec 2023 09:31:16 -0500
Subject: [PATCH 57/74] Ensure that Autopilot sees all nodes in KnownServers at
outset (#24246)
---
changelog/24246.txt | 3 +++
vault/raft.go | 21 ++++++++++++---------
2 files changed, 15 insertions(+), 9 deletions(-)
create mode 100644 changelog/24246.txt
diff --git a/changelog/24246.txt b/changelog/24246.txt
new file mode 100644
index 000000000000..424a006f2da3
--- /dev/null
+++ b/changelog/24246.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+storage/raft: Fix a race whereby a new leader may present inconsistent node data to Autopilot.
+```
\ No newline at end of file
diff --git a/vault/raft.go b/vault/raft.go
index b2b26496d12f..76dcf4fa0de0 100644
--- a/vault/raft.go
+++ b/vault/raft.go
@@ -314,14 +314,6 @@ func (c *Core) setupRaftActiveNode(ctx context.Context) error {
c.logger.Info("starting raft active node")
raftBackend.SetEffectiveSDKVersion(c.effectiveSDKVersion)
- autopilotConfig, err := c.loadAutopilotConfiguration(ctx)
- if err != nil {
- c.logger.Error("failed to load autopilot config from storage when setting up cluster; continuing since autopilot falls back to default config", "error", err)
- }
- disableAutopilot := c.disableAutopilot
-
- raftBackend.SetupAutopilot(c.activeContext, autopilotConfig, c.raftFollowerStates, disableAutopilot)
-
c.pendingRaftPeers = &sync.Map{}
// Reload the raft TLS keys to ensure we are using the latest version.
@@ -334,7 +326,18 @@ func (c *Core) setupRaftActiveNode(ctx context.Context) error {
if err := c.monitorUndoLogs(); err != nil {
return err
}
- return c.startPeriodicRaftTLSRotate(ctx)
+
+ if err := c.startPeriodicRaftTLSRotate(ctx); err != nil {
+ return err
+ }
+
+ autopilotConfig, err := c.loadAutopilotConfiguration(ctx)
+ if err != nil {
+ c.logger.Error("failed to load autopilot config from storage when setting up cluster; continuing since autopilot falls back to default config", "error", err)
+ }
+ disableAutopilot := c.disableAutopilot
+ raftBackend.SetupAutopilot(c.activeContext, autopilotConfig, c.raftFollowerStates, disableAutopilot)
+ return nil
}
func (c *Core) stopRaftActiveNode() {
From 9082ebc99646167e73c83d443ee26d85d7acfddb Mon Sep 17 00:00:00 2001
From: Meggie
Date: Mon, 4 Dec 2023 10:55:10 -0500
Subject: [PATCH 58/74] Update LICENSE for 1.15.3 (#24346)
---
LICENSE | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/LICENSE b/LICENSE
index ae14f271d418..83ffd142556b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -4,7 +4,7 @@ License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved.
Parameters
Licensor: HashiCorp, Inc.
-Licensed Work: Vault 1.15.2. The Licensed Work is (c) 2023 HashiCorp, Inc.
+Licensed Work: Vault 1.15.3. The Licensed Work is (c) 2023 HashiCorp, Inc.
Additional Use Grant: You may make production use of the Licensed Work, provided
Your use does not include offering the Licensed Work to third
parties on a hosted or embedded basis in order to compete with
From af3901e256600ec5e1f2a48b21c284960474ce94 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
Date: Mon, 4 Dec 2023 10:40:34 -0600
Subject: [PATCH 59/74] UI: Update replication nav (#24283)
* replication gets its own subnav
* glimmerize replication-summary-card
* Simplify replication-summary-card
* update replication subnav + tests
* replication action block uses HDS card
* add/update test selectors
* test coverage
* Add changelog
* Update defaults on replication-summary-card
* test that the view updates between replication types
* typo
---
changelog/24283.txt | 3 +
ui/app/app.js | 12 +-
ui/app/components/sidebar/nav/cluster.hbs | 33 +----
ui/app/models/cluster.js | 4 +-
ui/app/styles/components/action-block.scss | 5 +-
.../components/replication-summary-card.hbs | 40 ++++++
.../components/replication-summary-card.js | 44 +++---
.../components/replication-actions.hbs | 14 +-
.../components/replication-header.hbs | 2 +-
.../components/replication-mode-summary.hbs | 17 +--
.../components/replication-summary-card.hbs | 63 ---------
ui/lib/replication/addon/engine.js | 13 +-
.../addon/templates/application.hbs | 28 ++++
.../components/replication-summary.hbs | 5 +-
.../enterprise-replication-modes-test.js | 130 ++++++++++++++++++
.../acceptance/enterprise-replication-test.js | 2 +-
...enterprise-replication-unsupported-test.js | 33 -----
.../acceptance/enterprise-sidebar-nav-test.js | 13 +-
ui/tests/helpers/replication.js | 60 ++++++++
.../replication-summary-card-test.js | 40 +++++-
.../components/sidebar/nav/cluster-test.js | 4 +-
21 files changed, 378 insertions(+), 187 deletions(-)
create mode 100644 changelog/24283.txt
create mode 100644 ui/lib/core/addon/components/replication-summary-card.hbs
delete mode 100644 ui/lib/core/addon/templates/components/replication-summary-card.hbs
create mode 100644 ui/tests/acceptance/enterprise-replication-modes-test.js
delete mode 100644 ui/tests/acceptance/enterprise-replication-unsupported-test.js
diff --git a/changelog/24283.txt b/changelog/24283.txt
new file mode 100644
index 000000000000..f8f885f3e11e
--- /dev/null
+++ b/changelog/24283.txt
@@ -0,0 +1,3 @@
+```release-note:change
+ui: add subnav for replication items
+```
diff --git a/ui/app/app.js b/ui/app/app.js
index 5e55eb51628c..2fe614d04c53 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -20,9 +20,19 @@ export default class App extends Application {
},
replication: {
dependencies: {
- services: ['auth', 'flash-messages', 'namespace', 'replication-mode', 'router', 'store', 'version'],
+ services: [
+ 'auth',
+ 'flash-messages',
+ 'namespace',
+ 'replication-mode',
+ 'router',
+ 'store',
+ 'version',
+ '-portal',
+ ],
externalRoutes: {
replication: 'vault.cluster.replication.index',
+ vault: 'vault.cluster',
},
},
},
diff --git a/ui/app/components/sidebar/nav/cluster.hbs b/ui/app/components/sidebar/nav/cluster.hbs
index c16c55780972..6668bade2e02 100644
--- a/ui/app/components/sidebar/nav/cluster.hbs
+++ b/ui/app/components/sidebar/nav/cluster.hbs
@@ -42,32 +42,6 @@
/>
{{/if}}
- {{#if
- (and
- this.version.isEnterprise
- this.namespace.inRootNamespace
- this.cluster.anyReplicationEnabled
- (has-permission "status" routeParams="replication")
- )
- }}
- Replication
-
-
- {{#if (has-feature "Performance Replication")}}
-
- {{/if}}
- {{/if}}
-
{{#if
(or
(and
@@ -79,7 +53,12 @@
Monitoring
{{/if}}
{{#if (and this.version.isEnterprise this.namespace.inRootNamespace (has-permission "status" routeParams="replication"))}}
-
+
{{/if}}
{{#if (and this.cluster.usingRaft this.namespace.inRootNamespace (has-permission "status" routeParams="raft"))}}
+ {{@title}}
+
+
+
+
+
last_dr_wal
+
+ Index of last WAL entry written on local storage. Updates every ten seconds.
+
+
+
+
known_secondaries
+
Number of secondaries connected to this primary.
+
+ {{format-number this.lastWAL}}
+ {{format-number this.knownSecondariesCount}}
+
+
merkle_root
+
A snapshot of the merkle tree's root hash.
+
{{this.merkleRoot}}
+
+
\ No newline at end of file
diff --git a/ui/lib/core/addon/components/replication-summary-card.js b/ui/lib/core/addon/components/replication-summary-card.js
index df25cac695a6..21a15ec89670 100644
--- a/ui/lib/core/addon/components/replication-summary-card.js
+++ b/ui/lib/core/addon/components/replication-summary-card.js
@@ -3,9 +3,8 @@
* SPDX-License-Identifier: BUSL-1.1
*/
-import Component from '@ember/component';
-import { computed } from '@ember/object';
-import layout from '../templates/components/replication-summary-card';
+import { get } from '@ember/object';
+import Component from '@glimmer/component';
/**
* @module ReplicationSummaryCard
@@ -22,28 +21,17 @@ import layout from '../templates/components/replication-summary-card';
* @param {Object} replicationDetails=null - An Ember data object computed off the Ember Model. It combines the Model.dr and Model.performance objects into one and contains details specific to the mode replication.
*/
-export default Component.extend({
- layout,
- title: null,
- replicationDetails: null,
- lastDrWAL: computed('replicationDetails.dr.lastWAL', function () {
- return this.replicationDetails.dr.lastWAL || 0;
- }),
- lastPerformanceWAL: computed('replicationDetails.performance.lastWAL', function () {
- return this.replicationDetails.performance.lastWAL || 0;
- }),
- merkleRootDr: computed('replicationDetails.dr.merkleRoot', function () {
- return this.replicationDetails.dr.merkleRoot || '';
- }),
- merkleRootPerformance: computed('replicationDetails.performance.merkleRoot', function () {
- return this.replicationDetails.performance.merkleRoot || '';
- }),
- knownSecondariesDr: computed('replicationDetails.dr.knownSecondaries', function () {
- const knownSecondaries = this.replicationDetails.dr.knownSecondaries;
- return knownSecondaries.length;
- }),
- knownSecondariesPerformance: computed('replicationDetails.performance.knownSecondaries', function () {
- const knownSecondaries = this.replicationDetails.performance.knownSecondaries;
- return knownSecondaries.length;
- }),
-});
+export default class ReplicationSummaryCard extends Component {
+ get key() {
+ return this.args.title === 'Performance' ? 'performance' : 'dr';
+ }
+ get lastWAL() {
+ return get(this.args.replicationDetails, `${this.key}.lastWAL`) || 0;
+ }
+ get merkleRoot() {
+ return get(this.args.replicationDetails, `${this.key}.merkleRoot`) || 'no hash found';
+ }
+ get knownSecondariesCount() {
+ return get(this.args.replicationDetails, `${this.key}.knownSecondaries.length`) || 0;
+ }
+}
diff --git a/ui/lib/core/addon/templates/components/replication-actions.hbs b/ui/lib/core/addon/templates/components/replication-actions.hbs
index 05b4b8c677ef..718ad28a151f 100644
--- a/ui/lib/core/addon/templates/components/replication-actions.hbs
+++ b/ui/lib/core/addon/templates/components/replication-actions.hbs
@@ -13,12 +13,14 @@
as |replicationAction|
}}
- {{component
- (concat "replication-action-" replicationAction)
- onSubmit=(action "onSubmit")
- replicationMode=this.replicationMode
- model=this.model
- }}
+
+ {{component
+ (concat "replication-action-" replicationAction)
+ onSubmit=(action "onSubmit")
+ replicationMode=this.replicationMode
+ model=this.model
+ }}
+
{{/each}}
diff --git a/ui/lib/core/addon/templates/components/replication-header.hbs b/ui/lib/core/addon/templates/components/replication-header.hbs
index b8e0f0afc6bc..286a636841ee 100644
--- a/ui/lib/core/addon/templates/components/replication-header.hbs
+++ b/ui/lib/core/addon/templates/components/replication-header.hbs
@@ -20,7 +20,7 @@
{{/unless}}
-
+
{{this.title}}
{{#if this.data.anyReplicationEnabled}}
diff --git a/ui/lib/core/addon/templates/components/replication-mode-summary.hbs b/ui/lib/core/addon/templates/components/replication-mode-summary.hbs
index e1b7fa65254a..bd2eec9950c7 100644
--- a/ui/lib/core/addon/templates/components/replication-mode-summary.hbs
+++ b/ui/lib/core/addon/templates/components/replication-mode-summary.hbs
@@ -110,16 +110,13 @@
- {{#if this.replicationDisabled}}
-
- {{else}}
-
- {{/if}}
+
{{/if}}
\ No newline at end of file
diff --git a/ui/lib/core/addon/templates/components/replication-summary-card.hbs b/ui/lib/core/addon/templates/components/replication-summary-card.hbs
deleted file mode 100644
index f4562b523625..000000000000
--- a/ui/lib/core/addon/templates/components/replication-summary-card.hbs
+++ /dev/null
@@ -1,63 +0,0 @@
-{{!
- Copyright (c) HashiCorp, Inc.
- SPDX-License-Identifier: BUSL-1.1
-~}}
-
-
- {{! Check if DR or Performance Card }}
- {{#if (eq this.title "Disaster Recovery")}}
- {{this.title}}
-
-
- Details
-
-
-
-
last_dr_wal
-
- Index of last WAL entry written on local storage. Updates every ten seconds.
-
-
-
-
known_secondaries
-
Number of secondaries connected to this primary.
-
- {{format-number this.lastDrWAL}}
- {{format-number this.knownSecondariesDr}}
-
-
merkle_root
-
A snapshot of the merkle tree's root hash.
-
{{this.merkleRootDr}}
-
- {{else}}
- {{this.title}}
-
-
- Details
-
-
-
-
last_performance_wal
-
- Index of last WAL entry written on local storage. Updates every ten seconds.
-
-
-
-
known_secondaries
-
Number of secondaries connected to this primary.
-
- {{format-number this.lastPerformanceWAL}}
-
- {{format-number this.knownSecondariesPerformance}}
-
-
-
merkle_root
-
A snapshot of the merkle tree's root hash.
-
{{this.merkleRootPerformance}}
-
- {{/if}}
-
\ No newline at end of file
diff --git a/ui/lib/replication/addon/engine.js b/ui/lib/replication/addon/engine.js
index 2347738d9366..f3ddb560ea47 100644
--- a/ui/lib/replication/addon/engine.js
+++ b/ui/lib/replication/addon/engine.js
@@ -14,8 +14,17 @@ const Eng = Engine.extend({
modulePrefix,
Resolver,
dependencies: {
- services: ['auth', 'flash-messages', 'namespace', 'replication-mode', 'router', 'store', 'version'],
- externalRoutes: ['replication'],
+ services: [
+ 'auth',
+ 'flash-messages',
+ 'namespace',
+ 'replication-mode',
+ 'router',
+ 'store',
+ 'version',
+ '-portal',
+ ],
+ externalRoutes: ['replication', 'vault'],
},
});
diff --git a/ui/lib/replication/addon/templates/application.hbs b/ui/lib/replication/addon/templates/application.hbs
index 11a06fba0089..1e8c8ad0b3ff 100644
--- a/ui/lib/replication/addon/templates/application.hbs
+++ b/ui/lib/replication/addon/templates/application.hbs
@@ -3,4 +3,32 @@
SPDX-License-Identifier: BUSL-1.1
~}}
+
+
+
+ Replication
+
+ {{#if (not-eq this.model.mode "unsupported")}}
+ {{#if (has-feature "DR Replication")}}
+
+ {{/if}}
+ {{#if (has-feature "Performance Replication")}}
+
+ {{/if}}
+ {{/if}}
+
+
{{outlet}}
\ No newline at end of file
diff --git a/ui/lib/replication/addon/templates/components/replication-summary.hbs b/ui/lib/replication/addon/templates/components/replication-summary.hbs
index 3750ad2c5aea..7fa582ffcb1a 100644
--- a/ui/lib/replication/addon/templates/components/replication-summary.hbs
+++ b/ui/lib/replication/addon/templates/components/replication-summary.hbs
@@ -8,7 +8,7 @@
{{else if (or this.cluster.allReplicationDisabled this.cluster.replicationAttrs.replicationDisabled)}}
-
+
{{#if this.initialReplicationMode}}
{{#if (eq this.initialReplicationMode "dr")}}
Enable Disaster Recovery Replication
@@ -36,6 +36,7 @@
replicationMode=this.replicationMode
)
}}
+ data-test-replication-enable-form
>
@@ -291,7 +292,7 @@
{{#if (not (and this.cluster.dr.replicationEnabled this.cluster.performance.replicationEnabled))}}
-
+
Replication
diff --git a/ui/tests/acceptance/enterprise-replication-modes-test.js b/ui/tests/acceptance/enterprise-replication-modes-test.js
new file mode 100644
index 000000000000..c06c7181acd8
--- /dev/null
+++ b/ui/tests/acceptance/enterprise-replication-modes-test.js
@@ -0,0 +1,130 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+import { module, test } from 'qunit';
+import { setupApplicationTest } from 'ember-qunit';
+import { setupMirage } from 'ember-cli-mirage/test-support';
+import { click, visit } from '@ember/test-helpers';
+import authPage from 'vault/tests/pages/auth';
+import { STATUS_DISABLED_RESPONSE, mockReplicationBlock } from 'vault/tests/helpers/replication';
+
+const s = {
+ navLink: (title) => `[data-test-sidebar-nav-link="${title}"]`,
+ title: '[data-test-replication-title]',
+ detailLink: (mode) => `[data-test-replication-details-link="${mode}"]`,
+ summaryCard: '[data-test-replication-summary-card]',
+ dashboard: '[data-test-replication-dashboard]',
+ enableForm: '[data-test-replication-enable-form]',
+ knownSecondary: (name) => `[data-test-secondaries-node="${name}"]`,
+};
+
+module('Acceptance | Enterprise | replication modes', function (hooks) {
+ setupApplicationTest(hooks);
+ setupMirage(hooks);
+
+ hooks.beforeEach(async function () {
+ this.setupMocks = (payload) => {
+ this.server.get('sys/replication/status', () => ({
+ data: payload,
+ }));
+ return authPage.login();
+ };
+ });
+
+ test('replication page when unsupported', async function (assert) {
+ await this.setupMocks({
+ data: {
+ mode: 'unsupported',
+ },
+ });
+ await visit('/vault/replication');
+ assert.dom(s.title).hasText('Replication unsupported', 'it shows the unsupported view');
+
+ // Nav links
+ assert.dom(s.navLink('Performance')).doesNotExist('hides performance link');
+ assert.dom(s.navLink('Disaster Recovery')).doesNotExist('hides dr link');
+ });
+
+ test('replication page when disabled', async function (assert) {
+ await this.setupMocks(STATUS_DISABLED_RESPONSE);
+ await visit('/vault/replication');
+ assert.dom(s.title).hasText('Enable Replication', 'it shows the enable view');
+
+ // Nav links
+ assert.dom(s.navLink('Performance')).exists('shows performance link');
+ assert.dom(s.navLink('Disaster Recovery')).exists('shows dr link');
+
+ await click(s.navLink('Performance'));
+ assert.dom(s.title).hasText('Enable Performance Replication', 'it shows the enable view for performance');
+
+ await click(s.navLink('Disaster Recovery'));
+ assert.dom(s.title).hasText('Enable Disaster Recovery Replication', 'it shows the enable view for dr');
+ });
+
+ ['primary', 'secondary'].forEach((mode) => {
+ test(`replication page when perf ${mode} only`, async function (assert) {
+ await this.setupMocks({
+ dr: mockReplicationBlock(),
+ performance: mockReplicationBlock(mode),
+ });
+ await visit('/vault/replication');
+
+ assert.dom(s.title).hasText('Replication', 'it shows default view');
+ assert.dom(s.detailLink('performance')).hasText('Details', 'CTA to see performance details');
+ assert.dom(s.detailLink('dr')).hasText('Enable', 'CTA to enable dr');
+
+ // Nav links
+ assert.dom(s.navLink('Performance')).exists('shows performance link');
+ assert.dom(s.navLink('Disaster Recovery')).exists('shows dr link');
+
+ await click(s.navLink('Performance'));
+ assert.dom(s.title).hasText(`Performance ${mode}`, `it shows the performance title`);
+ assert.dom(s.dashboard).exists(`it shows the replication dashboard`);
+
+ await click(s.navLink('Disaster Recovery'));
+ assert.dom(s.title).hasText('Enable Disaster Recovery Replication', 'it shows the dr title');
+ assert.dom(s.enableForm).exists('it shows the enable view for dr');
+ });
+ });
+ // DR secondary mode is a whole other thing, test primary only here
+ test(`replication page when dr primary only`, async function (assert) {
+ await this.setupMocks({
+ dr: mockReplicationBlock('primary'),
+ performance: mockReplicationBlock(),
+ });
+ await visit('/vault/replication');
+ assert.dom(s.title).hasText('Replication', 'it shows default view');
+ assert.dom(s.detailLink('performance')).hasText('Enable', 'CTA to enable performance');
+ assert.dom(s.detailLink('dr')).hasText('Details', 'CTA to see dr details');
+
+ // Nav links
+ assert.dom(s.navLink('Performance')).exists('shows performance link');
+ assert.dom(s.navLink('Disaster Recovery')).exists('shows dr link');
+
+ await click(s.navLink('Performance'));
+ assert.dom(s.title).hasText(`Enable Performance Replication`, `it shows the performance title`);
+ assert.dom(s.enableForm).exists('it shows the enable view for performance');
+
+ await click(s.navLink('Disaster Recovery'));
+ assert.dom(s.title).hasText(`Disaster Recovery primary`, 'it shows the dr title');
+ assert.dom(s.dashboard).exists(`it shows the replication dashboard`);
+ });
+
+ test(`replication page both primary`, async function (assert) {
+ await this.setupMocks({
+ dr: mockReplicationBlock('primary'),
+ performance: mockReplicationBlock('primary'),
+ });
+ await visit('/vault/replication');
+ assert.dom(s.title).hasText('Disaster Recovery & Performance primary', 'it shows primary view');
+ assert.dom(s.summaryCard).exists({ count: 2 }, 'shows 2 summary cards');
+
+ await click(s.navLink('Performance'));
+ assert.dom(s.title).hasText(`Performance primary`, `it shows the performance mode details`);
+
+ await click(s.navLink('Disaster Recovery'));
+ assert.dom(s.title).hasText(`Disaster Recovery primary`, 'it shows the dr mode details');
+ });
+});
diff --git a/ui/tests/acceptance/enterprise-replication-test.js b/ui/tests/acceptance/enterprise-replication-test.js
index 9a89204d587f..8d46ad0d9f9d 100644
--- a/ui/tests/acceptance/enterprise-replication-test.js
+++ b/ui/tests/acceptance/enterprise-replication-test.js
@@ -306,7 +306,7 @@ module('Acceptance | Enterprise | replication', function (hooks) {
.doesNotExist(`does not render replication summary card when both modes are not enabled as primary`);
// enable DR primary replication
- await click('[data-test-replication-promote-secondary]');
+ await click('[data-test-replication-details-link="dr"]');
await click('[data-test-replication-enable]');
await pollCluster(this.owner);
diff --git a/ui/tests/acceptance/enterprise-replication-unsupported-test.js b/ui/tests/acceptance/enterprise-replication-unsupported-test.js
deleted file mode 100644
index cfcb2a73c273..000000000000
--- a/ui/tests/acceptance/enterprise-replication-unsupported-test.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: BUSL-1.1
- */
-
-import { module, test } from 'qunit';
-import { setupApplicationTest } from 'ember-qunit';
-import { setupMirage } from 'ember-cli-mirage/test-support';
-import authPage from 'vault/tests/pages/auth';
-import { visit } from '@ember/test-helpers';
-
-module('Acceptance | Enterprise | replication unsupported', function (hooks) {
- setupApplicationTest(hooks);
- setupMirage(hooks);
-
- hooks.beforeEach(async function () {
- this.server.get('/sys/replication/status', function () {
- return {
- data: {
- mode: 'unsupported',
- },
- };
- });
- return authPage.login();
- });
-
- test('replication page when unsupported', async function (assert) {
- await visit('/vault/replication');
- assert
- .dom('[data-test-replication-title]')
- .hasText('Replication unsupported', 'it shows the unsupported view');
- });
-});
diff --git a/ui/tests/acceptance/enterprise-sidebar-nav-test.js b/ui/tests/acceptance/enterprise-sidebar-nav-test.js
index 28e7671296dd..73246bea8291 100644
--- a/ui/tests/acceptance/enterprise-sidebar-nav-test.js
+++ b/ui/tests/acceptance/enterprise-sidebar-nav-test.js
@@ -5,7 +5,7 @@
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
-import { click, currentURL, fillIn } from '@ember/test-helpers';
+import { click, currentURL } from '@ember/test-helpers';
import { setupMirage } from 'ember-cli-mirage/test-support';
import authPage from 'vault/tests/pages/auth';
@@ -22,11 +22,15 @@ module('Acceptance | Enterprise | sidebar navigation', function (hooks) {
// common links are tested in the sidebar-nav test and will not be covered here
test('it should render enterprise only navigation links', async function (assert) {
+ assert.expect(12);
assert.dom(panel('Cluster')).exists('Cluster nav panel renders');
await click(link('Replication'));
assert.strictEqual(currentURL(), '/vault/replication', 'Replication route renders');
- await click('[data-test-replication-enable]');
+ assert.dom(panel('Replication')).exists(`Replication nav panel renders`);
+ assert.dom(link('Overview')).hasClass('active', 'Overview link is active');
+ assert.dom(link('Performance')).exists('Performance link exists');
+ assert.dom(link('Disaster Recovery')).exists('DR link exists');
await click(link('Performance'));
assert.strictEqual(
@@ -37,11 +41,6 @@ module('Acceptance | Enterprise | sidebar navigation', function (hooks) {
await click(link('Disaster Recovery'));
assert.strictEqual(currentURL(), '/vault/replication/dr', 'Replication dr route renders');
- // disable replication now that we have checked the links
- await click('[data-test-replication-link="manage"]');
- await click('[data-test-replication-action-trigger]');
- await fillIn('[data-test-confirmation-modal-input="Disable Replication?"]', 'Disaster Recovery');
- await click('[data-test-confirm-button="Disable Replication?"]');
await click(link('Client Count'));
assert.strictEqual(currentURL(), '/vault/clients/dashboard', 'Client counts route renders');
diff --git a/ui/tests/helpers/replication.js b/ui/tests/helpers/replication.js
index be3cc8ab0d32..3024ee9d0e82 100644
--- a/ui/tests/helpers/replication.js
+++ b/ui/tests/helpers/replication.js
@@ -34,3 +34,63 @@ export const disableReplication = async (type, assert) => {
await settled();
}
};
+
+export const STATUS_DISABLED_RESPONSE = {
+ dr: mockReplicationBlock(),
+ performance: mockReplicationBlock(),
+};
+
+/**
+ * Mock replication block returns the expected payload for a given replication type
+ * @param {string} mode disabled | primary | secondary
+ * @param {string} status connected | disconnected
+ * @returns expected object for a single replication type, eg dr or performance values
+ */
+export function mockReplicationBlock(mode = 'disabled', status = 'connected') {
+ switch (mode) {
+ case 'primary':
+ return {
+ cluster_id: '5f20f5ab-acea-0481-787e-71ec2ff5a60b',
+ known_secondaries: ['4'],
+ last_wal: 455,
+ merkle_root: 'aaaaaabbbbbbbccccccccddddddd',
+ mode: 'primary',
+ primary_cluster_addr: '',
+ secondaries: [
+ {
+ api_address: 'https://127.0.0.1:49277',
+ cluster_address: 'https://127.0.0.1:49281',
+ connection_status: status,
+ last_heartbeat: '2020-06-10T15:40:46-07:00',
+ node_id: '4',
+ },
+ ],
+ state: 'stream-wals',
+ };
+ case 'secondary':
+ return {
+ cluster_id: '5f20f5ab-acea-0481-787e-71ec2ff5a60b',
+ known_primary_cluster_addrs: ['https://127.0.0.1:8201'],
+ last_remote_wal: 291,
+ merkle_root: 'aaaaaabbbbbbbccccccccddddddd',
+ corrupted_merkle_tree: false,
+ last_corruption_check_epoch: '1694456090',
+ mode: 'secondary',
+ primaries: [
+ {
+ api_address: 'https://127.0.0.1:49244',
+ cluster_address: 'https://127.0.0.1:8201',
+ connection_status: status,
+ last_heartbeat: '2020-06-10T15:40:46-07:00',
+ },
+ ],
+ primary_cluster_addr: 'https://127.0.0.1:8201',
+ secondary_id: '2',
+ state: 'stream-wals',
+ };
+ default:
+ return {
+ mode: 'disabled',
+ };
+ }
+}
diff --git a/ui/tests/integration/components/replication-summary-card-test.js b/ui/tests/integration/components/replication-summary-card-test.js
index a8ca8dafdc0b..86e98ed98cf2 100644
--- a/ui/tests/integration/components/replication-summary-card-test.js
+++ b/ui/tests/integration/components/replication-summary-card-test.js
@@ -5,7 +5,7 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
-import { render } from '@ember/test-helpers';
+import { render, settled } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
const TITLE = 'Disaster Recovery';
@@ -15,11 +15,13 @@ const REPLICATION_DETAILS = {
state: 'running',
lastWAL: 10,
knownSecondaries: ['https://127.0.0.1:8201', 'https://127.0.0.1:8202'],
+ merkleRoot: 'zzzzzzzyyyyyyyxxxxxxxwwwwww',
},
performance: {
state: 'running',
lastWAL: 20,
knownSecondaries: ['https://127.0.0.1:8201'],
+ merkleRoot: 'aaaaaabbbbbbbbccccccccdddddd',
},
};
@@ -44,6 +46,9 @@ module('Integration | Component | replication-summary-card', function (hooks) {
assert
.dom('[data-test-known-secondaries]')
.includesText(knownSecondaries, `shows the correct computed value of the known secondaries count`);
+ assert
+ .dom('[data-test-merkle-root]')
+ .includesText(REPLICATION_DETAILS.dr.merkleRoot, `shows the correct merkle root value`);
});
test('it shows the correct lastWAL and knownSecondaries when title is Performance', async function (assert) {
@@ -58,5 +63,38 @@ module('Integration | Component | replication-summary-card', function (hooks) {
assert
.dom('[data-test-known-secondaries]')
.includesText(knownSecondaries, `shows the correct computed value of the known secondaries count`);
+ assert
+ .dom('[data-test-merkle-root]')
+ .includesText(REPLICATION_DETAILS.performance.merkleRoot, `shows the correct merkle root value`);
+ });
+
+ test('it shows reasonable defaults', async function (assert) {
+ const data = {
+ dr: {
+ mode: 'disabled',
+ },
+ performance: {
+ mode: 'disabled',
+ },
+ };
+ this.set('replicationDetails', data);
+ await render(
+ hbs` `
+ );
+ assert.dom('[data-test-lastWAL]').includesText('0', `shows the correct lastWAL value`);
+ assert
+ .dom('[data-test-known-secondaries]')
+ .includesText('0', `shows the correct default value of the known secondaries count`);
+ assert.dom('[data-test-merkle-root]').includesText('', `shows the correct merkle root value`);
+
+ await this.set('title', 'Performance');
+ await settled();
+ assert.dom('[data-test-lastWAL]').includesText('0', `shows the correct lastWAL value`);
+ assert
+ .dom('[data-test-known-secondaries]')
+ .includesText('0', `shows the correct default value of the known secondaries count`);
+ assert
+ .dom('[data-test-merkle-root]')
+ .includesText('no hash found', `shows the correct merkle root value`);
});
});
diff --git a/ui/tests/integration/components/sidebar/nav/cluster-test.js b/ui/tests/integration/components/sidebar/nav/cluster-test.js
index ccb9be3bcbf5..b0a477744629 100644
--- a/ui/tests/integration/components/sidebar/nav/cluster-test.js
+++ b/ui/tests/integration/components/sidebar/nav/cluster-test.js
@@ -21,7 +21,7 @@ module('Integration | Component | sidebar-nav-cluster', function (hooks) {
setupRenderingTest(hooks);
test('it should render nav headings', async function (assert) {
- const headings = ['Vault', 'Replication', 'Monitoring'];
+ const headings = ['Vault', 'Monitoring'];
stubFeaturesAndPermissions(this.owner, true, true);
await renderComponent();
@@ -52,8 +52,6 @@ module('Integration | Component | sidebar-nav-cluster', function (hooks) {
'Access',
'Policies',
'Tools',
- 'Disaster Recovery',
- 'Performance',
'Replication',
'Raft Storage',
'Client Count',
From 02eadb8ecb648977968ed43a161d2dd607cf18fa Mon Sep 17 00:00:00 2001
From: hc-github-team-es-release-engineering
<82989873+hc-github-team-es-release-engineering@users.noreply.github.com>
Date: Mon, 4 Dec 2023 08:57:30 -0800
Subject: [PATCH 60/74] Update LICENSE (#24264)
* Update LICENSE
* Update LICENSE
---------
Co-authored-by: Meggie
---
LICENSE | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/LICENSE b/LICENSE
index 83ffd142556b..0731bd030f72 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,32 +1,33 @@
License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved.
-“Business Source License” is a trademark of MariaDB Corporation Ab.
+"Business Source License" is a trademark of MariaDB Corporation Ab.
Parameters
Licensor: HashiCorp, Inc.
-Licensed Work: Vault 1.15.3. The Licensed Work is (c) 2023 HashiCorp, Inc.
+Licensed Work: Vault Version 1.15.0 or later. The Licensed Work is (c) 2023
+ HashiCorp, Inc.
Additional Use Grant: You may make production use of the Licensed Work, provided
Your use does not include offering the Licensed Work to third
parties on a hosted or embedded basis in order to compete with
- HashiCorp’s paid version(s) of the Licensed Work. For purposes
+ HashiCorp's paid version(s) of the Licensed Work. For purposes
of this license:
- A “competitive offering” is a Product that is offered to third
+ A "competitive offering" is a Product that is offered to third
parties on a paid basis, including through paid support
arrangements, that significantly overlaps with the capabilities
- of HashiCorp’s paid version(s) of the Licensed Work. If Your
+ of HashiCorp's paid version(s) of the Licensed Work. If Your
Product is not a competitive offering when You first make it
generally available, it will not become a competitive offering
later due to HashiCorp releasing a new version of the Licensed
Work with additional capabilities. In addition, Products that
are not provided on a paid basis are not competitive.
- “Product” means software that is offered to end users to manage
+ "Product" means software that is offered to end users to manage
in their own environments or offered as a service on a hosted
basis.
- “Embedded” means including the source code or executable code
- from the Licensed Work in a competitive offering. “Embedded”
+ "Embedded" means including the source code or executable code
+ from the Licensed Work in a competitive offering. "Embedded"
also means packaging the competitive offering in such a way
that the Licensed Work must be accessed or downloaded for the
competitive offering to operate.
@@ -85,7 +86,7 @@ Licensor or its affiliates (provided that you may use a trademark or logo of
Licensor as expressly required by this License).
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
-AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
+AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
TITLE.
From b8f531142b35dccc9dd9b86ae318976e7cf9d671 Mon Sep 17 00:00:00 2001
From: Nick Cabatoff
Date: Mon, 4 Dec 2023 12:04:38 -0500
Subject: [PATCH 61/74] Use our heartbeat echo RPCs to estimate clock skew,
expose it in status APIs (#24343)
---
api/replication_status.go | 12 +-
api/sys_hastatus.go | 18 +-
api/sys_health.go | 2 +
changelog/24343.txt | 5 +
http/sys_health.go | 4 +
scripts/protocversioncheck.sh | 2 +-
sdk/helper/testcluster/util.go | 62 ++++
vault/cluster/simulations.go | 19 +-
vault/core.go | 45 ++-
vault/external_tests/standby/standby_test.go | 114 +++++++
vault/ha.go | 16 +-
vault/logical_system.go | 18 +-
vault/request_forwarding_rpc.go | 54 +++-
vault/request_forwarding_service.pb.go | 305 +++++++++++--------
vault/request_forwarding_service.proto | 9 +
15 files changed, 497 insertions(+), 188 deletions(-)
create mode 100644 changelog/24343.txt
create mode 100644 vault/external_tests/standby/standby_test.go
diff --git a/api/replication_status.go b/api/replication_status.go
index 1668daf19c12..9bc02d53935d 100644
--- a/api/replication_status.go
+++ b/api/replication_status.go
@@ -19,11 +19,13 @@ const (
)
type ClusterInfo struct {
- APIAddr string `json:"api_address,omitempty" mapstructure:"api_address"`
- ClusterAddress string `json:"cluster_address,omitempty" mapstructure:"cluster_address"`
- ConnectionStatus string `json:"connection_status,omitempty" mapstructure:"connection_status"`
- LastHeartBeat string `json:"last_heartbeat,omitempty" mapstructure:"last_heartbeat"`
- NodeID string `json:"node_id,omitempty" mapstructure:"node_id"`
+ APIAddr string `json:"api_address,omitempty" mapstructure:"api_address"`
+ ClusterAddress string `json:"cluster_address,omitempty" mapstructure:"cluster_address"`
+ ConnectionStatus string `json:"connection_status,omitempty" mapstructure:"connection_status"`
+ LastHeartBeat string `json:"last_heartbeat,omitempty" mapstructure:"last_heartbeat"`
+ LastHeartBeatDurationMillis string `json:"last_heartbeat_duration_ms,omitempty" mapstructure:"last_heartbeat_duration_ms"`
+ ClockSkewMillis string `json:"clock_skew_ms,omitempty" mapstructure:"clock_skew_ms"`
+ NodeID string `json:"node_id,omitempty" mapstructure:"node_id"`
}
type ReplicationStatusGenericResponse struct {
diff --git a/api/sys_hastatus.go b/api/sys_hastatus.go
index 2b2aa7c3e980..58a73b89cbb7 100644
--- a/api/sys_hastatus.go
+++ b/api/sys_hastatus.go
@@ -35,12 +35,14 @@ type HAStatusResponse struct {
}
type HANode struct {
- Hostname string `json:"hostname"`
- APIAddress string `json:"api_address"`
- ClusterAddress string `json:"cluster_address"`
- ActiveNode bool `json:"active_node"`
- LastEcho *time.Time `json:"last_echo"`
- Version string `json:"version"`
- UpgradeVersion string `json:"upgrade_version,omitempty"`
- RedundancyZone string `json:"redundancy_zone,omitempty"`
+ Hostname string `json:"hostname"`
+ APIAddress string `json:"api_address"`
+ ClusterAddress string `json:"cluster_address"`
+ ActiveNode bool `json:"active_node"`
+ LastEcho *time.Time `json:"last_echo"`
+ EchoDurationMillis int64 `json:"echo_duration_ms"`
+ ClockSkewMillis int64 `json:"clock_skew_ms"`
+ Version string `json:"version"`
+ UpgradeVersion string `json:"upgrade_version,omitempty"`
+ RedundancyZone string `json:"redundancy_zone,omitempty"`
}
diff --git a/api/sys_health.go b/api/sys_health.go
index 17fb4fc10d66..0dc849885ff4 100644
--- a/api/sys_health.go
+++ b/api/sys_health.go
@@ -50,4 +50,6 @@ type HealthResponse struct {
ClusterID string `json:"cluster_id,omitempty"`
LastWAL uint64 `json:"last_wal,omitempty"`
Enterprise bool `json:"enterprise"`
+ EchoDurationMillis int64 `json:"echo_duration_ms"`
+ ClockSkewMillis int64 `json:"clock_skew_ms"`
}
diff --git a/changelog/24343.txt b/changelog/24343.txt
new file mode 100644
index 000000000000..b77b3afc1938
--- /dev/null
+++ b/changelog/24343.txt
@@ -0,0 +1,5 @@
+```release-note:improvement
+api: sys/health and sys/ha-status now expose information about how long
+the last heartbeat took, and the estimated clock skew between standby and
+active node based on that heartbeat duration.
+```
\ No newline at end of file
diff --git a/http/sys_health.go b/http/sys_health.go
index b5e92961d150..0e1f0ff24728 100644
--- a/http/sys_health.go
+++ b/http/sys_health.go
@@ -208,6 +208,8 @@ func getSysHealth(core *vault.Core, r *http.Request) (int, *HealthResponse, erro
Enterprise: constants.IsEnterprise,
ClusterName: clusterName,
ClusterID: clusterID,
+ ClockSkewMillis: core.ActiveNodeClockSkewMillis(),
+ EchoDurationMillis: core.EchoDuration().Milliseconds(),
}
licenseState, err := core.EntGetLicenseState()
@@ -252,4 +254,6 @@ type HealthResponse struct {
ClusterID string `json:"cluster_id,omitempty"`
LastWAL uint64 `json:"last_wal,omitempty"`
License *HealthResponseLicense `json:"license,omitempty"`
+ EchoDurationMillis int64 `json:"echo_duration_ms"`
+ ClockSkewMillis int64 `json:"clock_skew_ms"`
}
diff --git a/scripts/protocversioncheck.sh b/scripts/protocversioncheck.sh
index ecd67233fc5c..db82ec148180 100755
--- a/scripts/protocversioncheck.sh
+++ b/scripts/protocversioncheck.sh
@@ -9,7 +9,7 @@ PROTOC_CMD=${PROTOC_CMD:-protoc}
PROTOC_VERSION_EXACT="$1"
echo "==> Checking that protoc is at version $1..."
-PROTOC_VERSION=$($PROTOC_CMD --version | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+')
+PROTOC_VERSION=$($PROTOC_CMD --version | grep -o '[0-9]\+\.[0-9]\+\(\.[0-9]\+\)\?')
if [ "$PROTOC_VERSION" == "$PROTOC_VERSION_EXACT" ]; then
echo "Using protoc version $PROTOC_VERSION"
diff --git a/sdk/helper/testcluster/util.go b/sdk/helper/testcluster/util.go
index 883cd69926bf..b2a123556cd7 100644
--- a/sdk/helper/testcluster/util.go
+++ b/sdk/helper/testcluster/util.go
@@ -209,6 +209,68 @@ func WaitForActiveNode(ctx context.Context, cluster VaultCluster) (int, error) {
return -1, ctx.Err()
}
+func WaitForStandbyNode(ctx context.Context, cluster VaultCluster, nodeIdx int) error {
+ if nodeIdx >= len(cluster.Nodes()) {
+ return fmt.Errorf("invalid nodeIdx %d for cluster", nodeIdx)
+ }
+ node := cluster.Nodes()[nodeIdx]
+ client := node.APIClient()
+
+ var err error
+ for ctx.Err() == nil {
+ var resp *api.LeaderResponse
+
+ resp, err = client.Sys().LeaderWithContext(ctx)
+ switch {
+ case err != nil:
+ case resp.IsSelf:
+ return fmt.Errorf("waiting for standby but node is leader")
+ case resp.LeaderAddress == "":
+ err = fmt.Errorf("node doesn't know leader address")
+ default:
+ return nil
+ }
+
+ time.Sleep(100 * time.Millisecond)
+ }
+ if err == nil {
+ err = ctx.Err()
+ }
+ return err
+}
+
+func WaitForActiveNodeAndStandbys(ctx context.Context, cluster VaultCluster) (int, error) {
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+
+ leaderIdx, err := WaitForActiveNode(ctx, cluster)
+ if err != nil {
+ return 0, err
+ }
+
+ if len(cluster.Nodes()) == 1 {
+ return 0, nil
+ }
+
+ errs := make(chan error)
+ for i := range cluster.Nodes() {
+ if i == leaderIdx {
+ continue
+ }
+ go func(i int) {
+ errs <- WaitForStandbyNode(ctx, cluster, i)
+ }(i)
+ }
+
+ var merr *multierror.Error
+ expectedStandbys := len(cluster.Nodes()) - 1
+ for i := 0; i < expectedStandbys; i++ {
+ merr = multierror.Append(merr, <-errs)
+ }
+
+ return leaderIdx, merr.ErrorOrNil()
+}
+
func WaitForActiveNodeAndPerfStandbys(ctx context.Context, cluster VaultCluster) error {
logger := cluster.NamedLogger("WaitForActiveNodeAndPerfStandbys")
// This WaitForActiveNode was added because after a Raft cluster is sealed
diff --git a/vault/cluster/simulations.go b/vault/cluster/simulations.go
index 4e4896090dce..7a24b2f5bdb5 100644
--- a/vault/cluster/simulations.go
+++ b/vault/cluster/simulations.go
@@ -7,6 +7,8 @@ import (
"io"
"net"
"time"
+
+ uberAtomic "go.uber.org/atomic"
)
type delayedConn struct {
@@ -15,12 +17,13 @@ type delayedConn struct {
}
func newDelayedConn(conn net.Conn, delay time.Duration) net.Conn {
+ dr := &delayedReader{
+ r: conn,
+ delay: uberAtomic.NewDuration(delay),
+ }
return &delayedConn{
+ dr: dr,
Conn: conn,
- dr: &delayedReader{
- r: conn,
- delay: delay,
- },
}
}
@@ -29,18 +32,18 @@ func (conn *delayedConn) Read(data []byte) (int, error) {
}
func (conn *delayedConn) SetDelay(delay time.Duration) {
- conn.dr.delay = delay
+ conn.dr.delay.Store(delay)
}
type delayedReader struct {
r io.Reader
- delay time.Duration
+ delay *uberAtomic.Duration
}
func (dr *delayedReader) Read(data []byte) (int, error) {
// Sleep for the delay period prior to reading
- if dr.delay > 0 {
- time.Sleep(dr.delay)
+ if delay := dr.delay.Load(); delay != 0 {
+ time.Sleep(delay)
}
return dr.r.Read(data)
diff --git a/vault/core.go b/vault/core.go
index cd61111a40b4..1d7573c1b8ef 100644
--- a/vault/core.go
+++ b/vault/core.go
@@ -698,6 +698,17 @@ type Core struct {
WellKnownRedirects *wellKnownRedirectRegistry // RFC 5785
// Config value for "detect_deadlocks".
detectDeadlocks []string
+
+ echoDuration *uberAtomic.Duration
+ activeNodeClockSkewMillis *uberAtomic.Int64
+}
+
+func (c *Core) ActiveNodeClockSkewMillis() int64 {
+ return c.activeNodeClockSkewMillis.Load()
+}
+
+func (c *Core) EchoDuration() time.Duration {
+ return c.echoDuration.Load()
}
// c.stateLock needs to be held in read mode before calling this function.
@@ -1045,6 +1056,8 @@ func CreateCore(conf *CoreConfig) (*Core, error) {
impreciseLeaseRoleTracking: conf.ImpreciseLeaseRoleTracking,
WellKnownRedirects: NewWellKnownRedirects(),
detectDeadlocks: detectDeadlocks,
+ echoDuration: uberAtomic.NewDuration(0),
+ activeNodeClockSkewMillis: uberAtomic.NewInt64(0),
}
c.standbyStopCh.Store(make(chan struct{}))
@@ -3919,13 +3932,15 @@ func (c *Core) ReloadIntrospectionEndpointEnabled() {
}
type PeerNode struct {
- Hostname string `json:"hostname"`
- APIAddress string `json:"api_address"`
- ClusterAddress string `json:"cluster_address"`
- Version string `json:"version"`
- LastEcho time.Time `json:"last_echo"`
- UpgradeVersion string `json:"upgrade_version,omitempty"`
- RedundancyZone string `json:"redundancy_zone,omitempty"`
+ Hostname string `json:"hostname"`
+ APIAddress string `json:"api_address"`
+ ClusterAddress string `json:"cluster_address"`
+ Version string `json:"version"`
+ LastEcho time.Time `json:"last_echo"`
+ UpgradeVersion string `json:"upgrade_version,omitempty"`
+ RedundancyZone string `json:"redundancy_zone,omitempty"`
+ EchoDuration time.Duration `json:"echo_duration"`
+ ClockSkewMillis int64 `json:"clock_skew_millis"`
}
// GetHAPeerNodesCached returns the nodes that've sent us Echo requests recently.
@@ -3934,13 +3949,15 @@ func (c *Core) GetHAPeerNodesCached() []PeerNode {
for itemClusterAddr, item := range c.clusterPeerClusterAddrsCache.Items() {
info := item.Object.(nodeHAConnectionInfo)
nodes = append(nodes, PeerNode{
- Hostname: info.nodeInfo.Hostname,
- APIAddress: info.nodeInfo.ApiAddr,
- ClusterAddress: itemClusterAddr,
- LastEcho: info.lastHeartbeat,
- Version: info.version,
- UpgradeVersion: info.upgradeVersion,
- RedundancyZone: info.redundancyZone,
+ Hostname: info.nodeInfo.Hostname,
+ APIAddress: info.nodeInfo.ApiAddr,
+ ClusterAddress: itemClusterAddr,
+ LastEcho: info.lastHeartbeat,
+ Version: info.version,
+ UpgradeVersion: info.upgradeVersion,
+ RedundancyZone: info.redundancyZone,
+ EchoDuration: info.echoDuration,
+ ClockSkewMillis: info.clockSkewMillis,
})
}
return nodes
diff --git a/vault/external_tests/standby/standby_test.go b/vault/external_tests/standby/standby_test.go
new file mode 100644
index 000000000000..3ce3fb96bb3b
--- /dev/null
+++ b/vault/external_tests/standby/standby_test.go
@@ -0,0 +1,114 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: BUSL-1.1
+
+package standby
+
+import (
+ "context"
+ "fmt"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/hashicorp/vault/helper/constants"
+ "github.com/hashicorp/vault/helper/testhelpers/corehelpers"
+ "github.com/hashicorp/vault/helper/testhelpers/teststorage"
+ "github.com/hashicorp/vault/sdk/helper/testcluster"
+ "github.com/hashicorp/vault/vault"
+ "github.com/hashicorp/vault/vault/cluster"
+)
+
+// Test_Echo_Duration_Skew tests that the sys/health and sys/ha-status endpoints
+// report reasonable values for echo duration and clock skew.
+func Test_Echo_Duration_Skew(t *testing.T) {
+ t.Parallel()
+ cases := []struct {
+ name string
+ perfstandby bool
+ }{
+ {"standby", false},
+ {"perfstandby", true},
+ }
+ for i := range cases {
+ perfstandby := cases[i].perfstandby
+ if perfstandby && !constants.IsEnterprise {
+ continue
+ }
+ t.Run(cases[i].name, func(t *testing.T) {
+ t.Parallel()
+ conf, opts := teststorage.ClusterSetup(nil, nil, nil)
+ name := strings.Replace(t.Name(), "/", "_", -1)
+ logger := corehelpers.NewTestLogger(t)
+ layers, err := cluster.NewInmemLayerCluster(name, 3, logger)
+ if err != nil {
+ t.Fatal(err)
+ }
+ opts.ClusterLayers = layers
+ opts.Logger = logger
+ conf.DisablePerformanceStandby = !perfstandby
+ cluster := vault.NewTestCluster(t, conf, opts)
+ defer cluster.Cleanup()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+ leaderIdx, err := testcluster.WaitForActiveNodeAndStandbys(ctx, cluster)
+ if err != nil {
+ t.Fatal(err)
+ }
+ leader := cluster.Nodes()[leaderIdx]
+
+ // The delay applies in both directions, hence a 0.25s delay implies a 0.5s roundtrip delay
+ layers.SetReaderDelay(time.Second / 4)
+
+ check := func(echoDuration int64, clockSkew int64) error {
+ if echoDuration < time.Second.Milliseconds()/2 {
+ return fmt.Errorf("echo duration must exceed 0.5s, got: %dms", echoDuration)
+ }
+ // Because we're using the same clock for all nodes, any clock skew will
+ // be negative, as it's based on the delta of server time across both nodes,
+ // but it doesn't factor in the round-trip time of the echo request.
+ if clockSkew == 0 || -clockSkew < time.Second.Milliseconds()/2 {
+ return fmt.Errorf("clock skew must be nonzero and exceed -0.5s, got: %dms", clockSkew)
+ }
+
+ return nil
+ }
+
+ // We need to wait for at least 2 heartbeats to happen (2s intervals)
+ corehelpers.RetryUntil(t, 5*time.Second, func() error {
+ haStatus, err := leader.APIClient().Sys().HAStatus()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(haStatus.Nodes) < 3 {
+ return fmt.Errorf("expected 3 nodes, got %d", len(haStatus.Nodes))
+ }
+ for _, node := range haStatus.Nodes {
+ if node.ActiveNode {
+ continue
+ }
+
+ if err := check(node.EchoDurationMillis, node.ClockSkewMillis); err != nil {
+ return fmt.Errorf("ha-status node %s: %w", node.Hostname, err)
+ }
+ }
+
+ for i, node := range cluster.Nodes() {
+ if i == leaderIdx {
+ continue
+ }
+
+ h, err := node.APIClient().Sys().Health()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if err := check(h.EchoDurationMillis, h.ClockSkewMillis); err != nil {
+ return fmt.Errorf("health node %s: %w", node.APIClient().Address(), err)
+ }
+ }
+ return nil
+ })
+ })
+ }
+}
diff --git a/vault/ha.go b/vault/ha.go
index 15d6f180f7cb..9468538a6609 100644
--- a/vault/ha.go
+++ b/vault/ha.go
@@ -118,13 +118,15 @@ func (c *Core) getHAMembers() ([]HAStatusNode, error) {
for _, peerNode := range c.GetHAPeerNodesCached() {
lastEcho := peerNode.LastEcho
nodes = append(nodes, HAStatusNode{
- Hostname: peerNode.Hostname,
- APIAddress: peerNode.APIAddress,
- ClusterAddress: peerNode.ClusterAddress,
- LastEcho: &lastEcho,
- Version: peerNode.Version,
- UpgradeVersion: peerNode.UpgradeVersion,
- RedundancyZone: peerNode.RedundancyZone,
+ Hostname: peerNode.Hostname,
+ APIAddress: peerNode.APIAddress,
+ ClusterAddress: peerNode.ClusterAddress,
+ LastEcho: &lastEcho,
+ Version: peerNode.Version,
+ UpgradeVersion: peerNode.UpgradeVersion,
+ RedundancyZone: peerNode.RedundancyZone,
+ EchoDurationMillis: peerNode.EchoDuration.Milliseconds(),
+ ClockSkewMillis: peerNode.ClockSkewMillis,
})
}
diff --git a/vault/logical_system.go b/vault/logical_system.go
index 8a6e292af6d8..67b674105d7b 100644
--- a/vault/logical_system.go
+++ b/vault/logical_system.go
@@ -5288,14 +5288,16 @@ func (b *SystemBackend) handleHAStatus(ctx context.Context, req *logical.Request
}
type HAStatusNode struct {
- Hostname string `json:"hostname"`
- APIAddress string `json:"api_address"`
- ClusterAddress string `json:"cluster_address"`
- ActiveNode bool `json:"active_node"`
- LastEcho *time.Time `json:"last_echo"`
- Version string `json:"version"`
- UpgradeVersion string `json:"upgrade_version,omitempty"`
- RedundancyZone string `json:"redundancy_zone,omitempty"`
+ Hostname string `json:"hostname"`
+ APIAddress string `json:"api_address"`
+ ClusterAddress string `json:"cluster_address"`
+ ActiveNode bool `json:"active_node"`
+ LastEcho *time.Time `json:"last_echo"`
+ Version string `json:"version"`
+ UpgradeVersion string `json:"upgrade_version,omitempty"`
+ RedundancyZone string `json:"redundancy_zone,omitempty"`
+ EchoDurationMillis int64 `json:"echo_duration_ms"`
+ ClockSkewMillis int64 `json:"clock_skew_ms"`
}
func (b *SystemBackend) handleVersionHistoryList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
diff --git a/vault/request_forwarding_rpc.go b/vault/request_forwarding_rpc.go
index 92dad79aefe9..8b82b767d02d 100644
--- a/vault/request_forwarding_rpc.go
+++ b/vault/request_forwarding_rpc.go
@@ -16,6 +16,8 @@ import (
"github.com/hashicorp/vault/physical/raft"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/vault/replication"
+ "google.golang.org/protobuf/types/known/durationpb"
+ "google.golang.org/protobuf/types/known/timestamppb"
)
type forwardedRequestRPCServer struct {
@@ -72,20 +74,26 @@ func (s *forwardedRequestRPCServer) ForwardRequest(ctx context.Context, freq *fo
}
type nodeHAConnectionInfo struct {
- nodeInfo *NodeInformation
- lastHeartbeat time.Time
- version string
- upgradeVersion string
- redundancyZone string
+ nodeInfo *NodeInformation
+ lastHeartbeat time.Time
+ version string
+ upgradeVersion string
+ redundancyZone string
+ localTime time.Time
+ echoDuration time.Duration
+ clockSkewMillis int64
}
func (s *forwardedRequestRPCServer) Echo(ctx context.Context, in *EchoRequest) (*EchoReply, error) {
incomingNodeConnectionInfo := nodeHAConnectionInfo{
- nodeInfo: in.NodeInfo,
- lastHeartbeat: time.Now(),
- version: in.SdkVersion,
- upgradeVersion: in.RaftUpgradeVersion,
- redundancyZone: in.RaftRedundancyZone,
+ nodeInfo: in.NodeInfo,
+ lastHeartbeat: time.Now(),
+ version: in.SdkVersion,
+ upgradeVersion: in.RaftUpgradeVersion,
+ redundancyZone: in.RaftRedundancyZone,
+ localTime: in.Now.AsTime(),
+ echoDuration: in.LastRoundtripTime.AsDuration(),
+ clockSkewMillis: in.ClockSkewMillis,
}
if in.ClusterAddr != "" {
s.core.clusterPeerClusterAddrsCache.Set(in.ClusterAddr, incomingNodeConnectionInfo, 0)
@@ -106,6 +114,7 @@ func (s *forwardedRequestRPCServer) Echo(ctx context.Context, in *EchoRequest) (
reply := &EchoReply{
Message: "pong",
ReplicationState: uint32(s.core.ReplicationState()),
+ Now: timestamppb.Now(),
}
if raftBackend := s.core.getRaftBackend(); raftBackend != nil {
@@ -134,15 +143,19 @@ func (c *forwardingClient) startHeartbeat() {
Hostname: hostname,
Mode: "standby",
}
+ var echoDuration time.Duration
+ var serverTimeDelta int64
tick := func() {
labels := make([]metrics.Label, 0, 1)
defer metrics.MeasureSinceWithLabels([]string{"ha", "rpc", "client", "echo"}, time.Now(), labels)
req := &EchoRequest{
- Message: "ping",
- ClusterAddr: clusterAddr,
- NodeInfo: &ni,
- SdkVersion: c.core.effectiveSDKVersion,
+ Message: "ping",
+ ClusterAddr: clusterAddr,
+ NodeInfo: &ni,
+ SdkVersion: c.core.effectiveSDKVersion,
+ LastRoundtripTime: durationpb.New(echoDuration),
+ ClockSkewMillis: serverTimeDelta,
}
if raftBackend := c.core.getRaftBackend(); raftBackend != nil {
@@ -155,9 +168,22 @@ func (c *forwardingClient) startHeartbeat() {
labels = append(labels, metrics.Label{Name: "peer_id", Value: raftBackend.NodeID()})
}
+ start := time.Now()
+ req.Now = timestamppb.New(start)
ctx, cancel := context.WithTimeout(c.echoContext, 2*time.Second)
resp, err := c.RequestForwardingClient.Echo(ctx, req)
cancel()
+
+ now := time.Now()
+ if err == nil {
+ serverTimeDelta = resp.Now.AsTime().UnixMilli() - now.UnixMilli()
+ } else {
+ serverTimeDelta = 0
+ }
+ echoDuration = now.Sub(start)
+ c.core.echoDuration.Store(echoDuration)
+ c.core.activeNodeClockSkewMillis.Store(serverTimeDelta)
+
if err != nil {
metrics.IncrCounter([]string{"ha", "rpc", "client", "echo", "errors"}, 1)
c.core.logger.Debug("forwarding: error sending echo request to active node", "error", err)
diff --git a/vault/request_forwarding_service.pb.go b/vault/request_forwarding_service.pb.go
index 4b5cb8b28a35..2f0d206bf786 100644
--- a/vault/request_forwarding_service.pb.go
+++ b/vault/request_forwarding_service.pb.go
@@ -13,6 +13,8 @@ import (
forwarding "github.com/hashicorp/vault/helper/forwarding"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ durationpb "google.golang.org/protobuf/types/known/durationpb"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
)
@@ -35,15 +37,20 @@ type EchoRequest struct {
ClusterAddr string `protobuf:"bytes,2,opt,name=cluster_addr,json=clusterAddr,proto3" json:"cluster_addr,omitempty"`
// ClusterAddrs is used to send up a list of cluster addresses to a dr
// primary from a dr secondary
- ClusterAddrs []string `protobuf:"bytes,3,rep,name=cluster_addrs,json=clusterAddrs,proto3" json:"cluster_addrs,omitempty"`
- RaftAppliedIndex uint64 `protobuf:"varint,4,opt,name=raft_applied_index,json=raftAppliedIndex,proto3" json:"raft_applied_index,omitempty"`
- RaftNodeID string `protobuf:"bytes,5,opt,name=raft_node_id,json=raftNodeId,proto3" json:"raft_node_id,omitempty"`
- NodeInfo *NodeInformation `protobuf:"bytes,6,opt,name=node_info,json=nodeInfo,proto3" json:"node_info,omitempty"`
- RaftTerm uint64 `protobuf:"varint,7,opt,name=raft_term,json=raftTerm,proto3" json:"raft_term,omitempty"`
- RaftDesiredSuffrage string `protobuf:"bytes,8,opt,name=raft_desired_suffrage,json=raftDesiredSuffrage,proto3" json:"raft_desired_suffrage,omitempty"`
- RaftUpgradeVersion string `protobuf:"bytes,9,opt,name=raft_upgrade_version,json=raftUpgradeVersion,proto3" json:"raft_upgrade_version,omitempty"`
- RaftRedundancyZone string `protobuf:"bytes,10,opt,name=raft_redundancy_zone,json=raftRedundancyZone,proto3" json:"raft_redundancy_zone,omitempty"`
- SdkVersion string `protobuf:"bytes,11,opt,name=sdk_version,json=sdkVersion,proto3" json:"sdk_version,omitempty"`
+ ClusterAddrs []string `protobuf:"bytes,3,rep,name=cluster_addrs,json=clusterAddrs,proto3" json:"cluster_addrs,omitempty"`
+ RaftAppliedIndex uint64 `protobuf:"varint,4,opt,name=raft_applied_index,json=raftAppliedIndex,proto3" json:"raft_applied_index,omitempty"`
+ RaftNodeID string `protobuf:"bytes,5,opt,name=raft_node_id,json=raftNodeId,proto3" json:"raft_node_id,omitempty"`
+ NodeInfo *NodeInformation `protobuf:"bytes,6,opt,name=node_info,json=nodeInfo,proto3" json:"node_info,omitempty"`
+ RaftTerm uint64 `protobuf:"varint,7,opt,name=raft_term,json=raftTerm,proto3" json:"raft_term,omitempty"`
+ RaftDesiredSuffrage string `protobuf:"bytes,8,opt,name=raft_desired_suffrage,json=raftDesiredSuffrage,proto3" json:"raft_desired_suffrage,omitempty"`
+ RaftUpgradeVersion string `protobuf:"bytes,9,opt,name=raft_upgrade_version,json=raftUpgradeVersion,proto3" json:"raft_upgrade_version,omitempty"`
+ RaftRedundancyZone string `protobuf:"bytes,10,opt,name=raft_redundancy_zone,json=raftRedundancyZone,proto3" json:"raft_redundancy_zone,omitempty"`
+ SdkVersion string `protobuf:"bytes,11,opt,name=sdk_version,json=sdkVersion,proto3" json:"sdk_version,omitempty"`
+ Now *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=now,proto3" json:"now,omitempty"`
+ // last_roundtrip_time is the time taken for the last echo request
+ LastRoundtripTime *durationpb.Duration `protobuf:"bytes,13,opt,name=last_roundtrip_time,json=lastRoundtripTime,proto3" json:"last_roundtrip_time,omitempty"`
+ // clock_skew_millis is the server time minus the local time
+ ClockSkewMillis int64 `protobuf:"varint,14,opt,name=clock_skew_millis,json=clockSkewMillis,proto3" json:"clock_skew_millis,omitempty"`
}
func (x *EchoRequest) Reset() {
@@ -155,6 +162,27 @@ func (x *EchoRequest) GetSdkVersion() string {
return ""
}
+func (x *EchoRequest) GetNow() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Now
+ }
+ return nil
+}
+
+func (x *EchoRequest) GetLastRoundtripTime() *durationpb.Duration {
+ if x != nil {
+ return x.LastRoundtripTime
+ }
+ return nil
+}
+
+func (x *EchoRequest) GetClockSkewMillis() int64 {
+ if x != nil {
+ return x.ClockSkewMillis
+ }
+ return 0
+}
+
type EchoReply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -166,6 +194,8 @@ type EchoReply struct {
RaftAppliedIndex uint64 `protobuf:"varint,4,opt,name=raft_applied_index,json=raftAppliedIndex,proto3" json:"raft_applied_index,omitempty"`
RaftNodeID string `protobuf:"bytes,5,opt,name=raft_node_id,json=raftNodeId,proto3" json:"raft_node_id,omitempty"`
NodeInfo *NodeInformation `protobuf:"bytes,6,opt,name=node_info,json=nodeInfo,proto3" json:"node_info,omitempty"`
+ // now is the time on the server
+ Now *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=now,proto3" json:"now,omitempty"`
}
func (x *EchoReply) Reset() {
@@ -242,6 +272,13 @@ func (x *EchoReply) GetNodeInfo() *NodeInformation {
return nil
}
+func (x *EchoReply) GetNow() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Now
+ }
+ return nil
+}
+
type NodeInformation struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -531,105 +568,122 @@ var file_vault_request_forwarding_service_proto_rawDesc = []byte{
0x0a, 0x26, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f,
0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x1a,
- 0x1d, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x2f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69,
- 0x6e, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xca,
- 0x03, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18,
- 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73,
- 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
- 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x63,
- 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03,
- 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x73,
- 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x66, 0x74, 0x5f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64,
- 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x72, 0x61,
- 0x66, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x20,
- 0x0a, 0x0c, 0x72, 0x61, 0x66, 0x74, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x61, 0x66, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x64,
- 0x12, 0x33, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x4e, 0x6f, 0x64, 0x65,
- 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6e, 0x6f, 0x64,
- 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x61, 0x66, 0x74, 0x5f, 0x74, 0x65,
- 0x72, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x61, 0x66, 0x74, 0x54, 0x65,
- 0x72, 0x6d, 0x12, 0x32, 0x0a, 0x15, 0x72, 0x61, 0x66, 0x74, 0x5f, 0x64, 0x65, 0x73, 0x69, 0x72,
- 0x65, 0x64, 0x5f, 0x73, 0x75, 0x66, 0x66, 0x72, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x13, 0x72, 0x61, 0x66, 0x74, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x53, 0x75,
- 0x66, 0x66, 0x72, 0x61, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x61, 0x66, 0x74, 0x5f, 0x75,
- 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, 0x61, 0x66, 0x74, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64,
- 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x61, 0x66, 0x74,
- 0x5f, 0x72, 0x65, 0x64, 0x75, 0x6e, 0x64, 0x61, 0x6e, 0x63, 0x79, 0x5f, 0x7a, 0x6f, 0x6e, 0x65,
- 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, 0x61, 0x66, 0x74, 0x52, 0x65, 0x64, 0x75,
- 0x6e, 0x64, 0x61, 0x6e, 0x63, 0x79, 0x5a, 0x6f, 0x6e, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x64,
- 0x6b, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x0a, 0x73, 0x64, 0x6b, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xfc, 0x01, 0x0a, 0x09,
- 0x45, 0x63, 0x68, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73,
- 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73,
- 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x61,
- 0x64, 0x64, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x75, 0x73,
- 0x74, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x70, 0x6c,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20,
- 0x01, 0x28, 0x0d, 0x52, 0x10, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x66, 0x74, 0x5f, 0x61, 0x70,
- 0x70, 0x6c, 0x69, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28,
- 0x04, 0x52, 0x10, 0x72, 0x61, 0x66, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x49, 0x6e,
- 0x64, 0x65, 0x78, 0x12, 0x20, 0x0a, 0x0c, 0x72, 0x61, 0x66, 0x74, 0x5f, 0x6e, 0x6f, 0x64, 0x65,
- 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x61, 0x66, 0x74, 0x4e,
- 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x33, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e,
- 0x66, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x76, 0x61, 0x75, 0x6c, 0x74,
- 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0xc5, 0x01, 0x0a, 0x0f, 0x4e,
- 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21,
- 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x64, 0x64,
- 0x72, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x69, 0x41, 0x64, 0x64, 0x72, 0x12, 0x12, 0x0a, 0x04,
- 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65,
- 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x70,
- 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x05,
- 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61,
- 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61,
- 0x6d, 0x65, 0x22, 0x49, 0x0a, 0x09, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12,
- 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74,
- 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x01, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01,
- 0x78, 0x12, 0x0c, 0x0a, 0x01, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x79, 0x12,
- 0x0c, 0x0a, 0x01, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x64, 0x22, 0x1a, 0x0a,
- 0x18, 0x50, 0x65, 0x72, 0x66, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79, 0x45, 0x6c, 0x65, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x22, 0xe9, 0x01, 0x0a, 0x1b, 0x50, 0x65,
- 0x72, 0x66, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79, 0x45, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f,
- 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75,
- 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63,
- 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x70, 0x72, 0x69, 0x6d,
- 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72,
- 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x43,
- 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x61,
- 0x5f, 0x63, 0x65, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x61, 0x43,
- 0x65, 0x72, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x65,
- 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
- 0x43, 0x65, 0x72, 0x74, 0x12, 0x2f, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6b,
- 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x61, 0x75, 0x6c, 0x74,
- 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x09, 0x63, 0x6c, 0x69, 0x65,
- 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x32, 0xf0, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x3d, 0x0a, 0x0e, 0x46,
- 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x13, 0x2e,
- 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
- 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x2e,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2e, 0x0a, 0x04, 0x45, 0x63,
- 0x68, 0x6f, 0x12, 0x12, 0x2e, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x45,
- 0x63, 0x68, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x21, 0x50, 0x65,
- 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79,
- 0x45, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x1f, 0x2e, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x53, 0x74, 0x61, 0x6e,
- 0x64, 0x62, 0x79, 0x45, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74,
- 0x1a, 0x22, 0x2e, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x53, 0x74, 0x61,
- 0x6e, 0x64, 0x62, 0x79, 0x45, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x42, 0x22, 0x5a, 0x20, 0x67, 0x69, 0x74, 0x68,
- 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
- 0x2f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x62, 0x06, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x33,
+ 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+ 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
+ 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+ 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x1a, 0x1d, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x2f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64,
+ 0x69, 0x6e, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
+ 0xef, 0x04, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75,
+ 0x73, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x23, 0x0a, 0x0d,
+ 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x03, 0x20,
+ 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72,
+ 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x66, 0x74, 0x5f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65,
+ 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x72,
+ 0x61, 0x66, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12,
+ 0x20, 0x0a, 0x0c, 0x72, 0x61, 0x66, 0x74, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18,
+ 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x61, 0x66, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49,
+ 0x64, 0x12, 0x33, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x4e, 0x6f, 0x64,
+ 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6e, 0x6f,
+ 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x61, 0x66, 0x74, 0x5f, 0x74,
+ 0x65, 0x72, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x61, 0x66, 0x74, 0x54,
+ 0x65, 0x72, 0x6d, 0x12, 0x32, 0x0a, 0x15, 0x72, 0x61, 0x66, 0x74, 0x5f, 0x64, 0x65, 0x73, 0x69,
+ 0x72, 0x65, 0x64, 0x5f, 0x73, 0x75, 0x66, 0x66, 0x72, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x13, 0x72, 0x61, 0x66, 0x74, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x53,
+ 0x75, 0x66, 0x66, 0x72, 0x61, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x61, 0x66, 0x74, 0x5f,
+ 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
+ 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, 0x61, 0x66, 0x74, 0x55, 0x70, 0x67, 0x72, 0x61,
+ 0x64, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x61, 0x66,
+ 0x74, 0x5f, 0x72, 0x65, 0x64, 0x75, 0x6e, 0x64, 0x61, 0x6e, 0x63, 0x79, 0x5f, 0x7a, 0x6f, 0x6e,
+ 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, 0x61, 0x66, 0x74, 0x52, 0x65, 0x64,
+ 0x75, 0x6e, 0x64, 0x61, 0x6e, 0x63, 0x79, 0x5a, 0x6f, 0x6e, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73,
+ 0x64, 0x6b, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x0a, 0x73, 0x64, 0x6b, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x03,
+ 0x6e, 0x6f, 0x77, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
+ 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x6e, 0x6f, 0x77, 0x12, 0x49, 0x0a, 0x13, 0x6c, 0x61,
+ 0x73, 0x74, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x5f, 0x74, 0x69, 0x6d,
+ 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x52, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69,
+ 0x70, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73,
+ 0x6b, 0x65, 0x77, 0x5f, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03,
+ 0x52, 0x0f, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x6b, 0x65, 0x77, 0x4d, 0x69, 0x6c, 0x6c, 0x69,
+ 0x73, 0x22, 0xaa, 0x02, 0x0a, 0x09, 0x45, 0x63, 0x68, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12,
+ 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, 0x75,
+ 0x73, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
+ 0x52, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x73, 0x12, 0x2b,
+ 0x0a, 0x11, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74,
+ 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x72, 0x65, 0x70, 0x6c, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x72,
+ 0x61, 0x66, 0x74, 0x5f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65,
+ 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x72, 0x61, 0x66, 0x74, 0x41, 0x70, 0x70,
+ 0x6c, 0x69, 0x65, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x20, 0x0a, 0x0c, 0x72, 0x61, 0x66,
+ 0x74, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x0a, 0x72, 0x61, 0x66, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x33, 0x0a, 0x09, 0x6e,
+ 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,
+ 0x2e, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72,
+ 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f,
+ 0x12, 0x2c, 0x0a, 0x03, 0x6e, 0x6f, 0x77, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+ 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x6e, 0x6f, 0x77, 0x22, 0xc5,
+ 0x01, 0x0a, 0x0f, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64,
+ 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65,
+ 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x61, 0x64, 0x64,
+ 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x69, 0x41, 0x64, 0x64, 0x72,
+ 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+ 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18,
+ 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x2b, 0x0a,
+ 0x11, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61,
+ 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f,
+ 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f,
+ 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x49, 0x0a, 0x09, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
+ 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x01, 0x78, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x0c, 0x52, 0x01, 0x78, 0x12, 0x0c, 0x0a, 0x01, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,
+ 0x52, 0x01, 0x79, 0x12, 0x0c, 0x0a, 0x01, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01,
+ 0x64, 0x22, 0x1a, 0x0a, 0x18, 0x50, 0x65, 0x72, 0x66, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79,
+ 0x45, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x22, 0xe9, 0x01,
+ 0x0a, 0x1b, 0x50, 0x65, 0x72, 0x66, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79, 0x45, 0x6c, 0x65,
+ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a,
+ 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a,
+ 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14,
+ 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f,
+ 0x61, 0x64, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x70, 0x72, 0x69, 0x6d,
+ 0x61, 0x72, 0x79, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x17,
+ 0x0a, 0x07, 0x63, 0x61, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52,
+ 0x06, 0x63, 0x61, 0x43, 0x65, 0x72, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+ 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6c,
+ 0x69, 0x65, 0x6e, 0x74, 0x43, 0x65, 0x72, 0x74, 0x12, 0x2f, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65,
+ 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76,
+ 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x09,
+ 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x32, 0xf0, 0x01, 0x0a, 0x11, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x12,
+ 0x3d, 0x0a, 0x0e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x12, 0x13, 0x2e, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64,
+ 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2e,
+ 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x12, 0x2e, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x45,
+ 0x63, 0x68, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x76, 0x61, 0x75,
+ 0x6c, 0x74, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x6c,
+ 0x0a, 0x21, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x61,
+ 0x6e, 0x64, 0x62, 0x79, 0x45, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x50, 0x65, 0x72, 0x66,
+ 0x53, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79, 0x45, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49,
+ 0x6e, 0x70, 0x75, 0x74, 0x1a, 0x22, 0x2e, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x50, 0x65, 0x72,
+ 0x66, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79, 0x45, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x42, 0x22, 0x5a, 0x20,
+ 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69,
+ 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2f, 0x76, 0x61, 0x75, 0x6c, 0x74,
+ 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -652,24 +706,29 @@ var file_vault_request_forwarding_service_proto_goTypes = []interface{}{
(*ClientKey)(nil), // 3: vault.ClientKey
(*PerfStandbyElectionInput)(nil), // 4: vault.PerfStandbyElectionInput
(*PerfStandbyElectionResponse)(nil), // 5: vault.PerfStandbyElectionResponse
- (*forwarding.Request)(nil), // 6: forwarding.Request
- (*forwarding.Response)(nil), // 7: forwarding.Response
+ (*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp
+ (*durationpb.Duration)(nil), // 7: google.protobuf.Duration
+ (*forwarding.Request)(nil), // 8: forwarding.Request
+ (*forwarding.Response)(nil), // 9: forwarding.Response
}
var file_vault_request_forwarding_service_proto_depIDxs = []int32{
2, // 0: vault.EchoRequest.node_info:type_name -> vault.NodeInformation
- 2, // 1: vault.EchoReply.node_info:type_name -> vault.NodeInformation
- 3, // 2: vault.PerfStandbyElectionResponse.client_key:type_name -> vault.ClientKey
- 6, // 3: vault.RequestForwarding.ForwardRequest:input_type -> forwarding.Request
- 0, // 4: vault.RequestForwarding.Echo:input_type -> vault.EchoRequest
- 4, // 5: vault.RequestForwarding.PerformanceStandbyElectionRequest:input_type -> vault.PerfStandbyElectionInput
- 7, // 6: vault.RequestForwarding.ForwardRequest:output_type -> forwarding.Response
- 1, // 7: vault.RequestForwarding.Echo:output_type -> vault.EchoReply
- 5, // 8: vault.RequestForwarding.PerformanceStandbyElectionRequest:output_type -> vault.PerfStandbyElectionResponse
- 6, // [6:9] is the sub-list for method output_type
- 3, // [3:6] is the sub-list for method input_type
- 3, // [3:3] is the sub-list for extension type_name
- 3, // [3:3] is the sub-list for extension extendee
- 0, // [0:3] is the sub-list for field type_name
+ 6, // 1: vault.EchoRequest.now:type_name -> google.protobuf.Timestamp
+ 7, // 2: vault.EchoRequest.last_roundtrip_time:type_name -> google.protobuf.Duration
+ 2, // 3: vault.EchoReply.node_info:type_name -> vault.NodeInformation
+ 6, // 4: vault.EchoReply.now:type_name -> google.protobuf.Timestamp
+ 3, // 5: vault.PerfStandbyElectionResponse.client_key:type_name -> vault.ClientKey
+ 8, // 6: vault.RequestForwarding.ForwardRequest:input_type -> forwarding.Request
+ 0, // 7: vault.RequestForwarding.Echo:input_type -> vault.EchoRequest
+ 4, // 8: vault.RequestForwarding.PerformanceStandbyElectionRequest:input_type -> vault.PerfStandbyElectionInput
+ 9, // 9: vault.RequestForwarding.ForwardRequest:output_type -> forwarding.Response
+ 1, // 10: vault.RequestForwarding.Echo:output_type -> vault.EchoReply
+ 5, // 11: vault.RequestForwarding.PerformanceStandbyElectionRequest:output_type -> vault.PerfStandbyElectionResponse
+ 9, // [9:12] is the sub-list for method output_type
+ 6, // [6:9] is the sub-list for method input_type
+ 6, // [6:6] is the sub-list for extension type_name
+ 6, // [6:6] is the sub-list for extension extendee
+ 0, // [0:6] is the sub-list for field type_name
}
func init() { file_vault_request_forwarding_service_proto_init() }
diff --git a/vault/request_forwarding_service.proto b/vault/request_forwarding_service.proto
index bb54b7189bf6..f564e807dcde 100644
--- a/vault/request_forwarding_service.proto
+++ b/vault/request_forwarding_service.proto
@@ -5,6 +5,8 @@ syntax = "proto3";
package vault;
+import "google/protobuf/duration.proto";
+import "google/protobuf/timestamp.proto";
import "helper/forwarding/types.proto";
option go_package = "github.com/hashicorp/vault/vault";
@@ -26,6 +28,11 @@ message EchoRequest {
string raft_upgrade_version = 9;
string raft_redundancy_zone = 10;
string sdk_version = 11;
+ google.protobuf.Timestamp now = 12;
+ // last_roundtrip_time is the time taken for the last echo request
+ google.protobuf.Duration last_roundtrip_time = 13;
+ // clock_skew_millis is the server time minus the local time
+ int64 clock_skew_millis = 14;
}
message EchoReply {
@@ -35,6 +42,8 @@ message EchoReply {
uint64 raft_applied_index = 4;
string raft_node_id = 5;
NodeInformation node_info = 6;
+ // now is the time on the server
+ google.protobuf.Timestamp now = 7;
}
message NodeInformation {
From 91ec1a788b46c0bf12a3351e5e3339474400eee9 Mon Sep 17 00:00:00 2001
From: Scott Miller
Date: Mon, 4 Dec 2023 12:36:55 -0600
Subject: [PATCH 62/74] Only use the short persistKeyring timeout for
encryption count tracking (#24336)
* Only use the short persistKeyring timeout for encryption count tracking
* changelog
* accidental paste
---
changelog/24336.txt | 3 +++
vault/barrier_aes_gcm.go | 33 ++++++++++++++++++++++++---------
2 files changed, 27 insertions(+), 9 deletions(-)
create mode 100644 changelog/24336.txt
diff --git a/changelog/24336.txt b/changelog/24336.txt
new file mode 100644
index 000000000000..63594dc6cee0
--- /dev/null
+++ b/changelog/24336.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+core: Fix a timeout initializing Vault by only using a short timeout persisting barrier keyring encryption counts.
+```
diff --git a/vault/barrier_aes_gcm.go b/vault/barrier_aes_gcm.go
index 5145146b66b6..bb4c455b4805 100644
--- a/vault/barrier_aes_gcm.go
+++ b/vault/barrier_aes_gcm.go
@@ -37,6 +37,8 @@ const (
autoRotateCheckInterval = 5 * time.Minute
legacyRotateReason = "legacy rotation"
+ // The keyring is persisted before the root key.
+ keyringTimeout = 1 * time.Second
)
// Versions of the AESGCM storage methodology
@@ -211,11 +213,18 @@ func (b *AESGCMBarrier) Initialize(ctx context.Context, key []byte, sealKey []by
// persistKeyring is used to write out the keyring using the
// root key to encrypt it.
func (b *AESGCMBarrier) persistKeyring(ctx context.Context, keyring *Keyring) error {
- const (
- // The keyring is persisted before the root key.
- keyringTimeout = 1 * time.Second
- )
+ return b.persistKeyringInternal(ctx, keyring, false)
+}
+
+// persistKeyringBestEffort is like persistKeyring but 'best effort', ie times out early
+// for non critical keyring writes (encryption/rotation tracking)
+func (b *AESGCMBarrier) persistKeyringBestEffort(ctx context.Context, keyring *Keyring) error {
+ return b.persistKeyringInternal(ctx, keyring, true)
+}
+// persistKeyring is used to write out the keyring using the
+// root key to encrypt it.
+func (b *AESGCMBarrier) persistKeyringInternal(ctx context.Context, keyring *Keyring, bestEffort bool) error {
// Create the keyring entry
keyringBuf, err := keyring.Serialize()
defer memzero(keyringBuf)
@@ -241,10 +250,16 @@ func (b *AESGCMBarrier) persistKeyring(ctx context.Context, keyring *Keyring) er
Value: value,
}
- // We reduce the timeout on the initial 'put' but if this succeeds we will
- // allow longer later on when we try to persist the root key .
- ctxKeyring, cancelKeyring := context.WithTimeout(ctx, keyringTimeout)
- defer cancelKeyring()
+ ctxKeyring := ctx
+
+ if bestEffort {
+ // We reduce the timeout on the initial 'put' but if this succeeds we will
+ // allow longer later on when we try to persist the root key .
+ var cancelKeyring func()
+ ctxKeyring, cancelKeyring = context.WithTimeout(ctx, keyringTimeout)
+ defer cancelKeyring()
+ }
+
if err := b.backend.Put(ctxKeyring, pe); err != nil {
return fmt.Errorf("failed to persist keyring: %w", err)
}
@@ -1231,7 +1246,7 @@ func (b *AESGCMBarrier) persistEncryptions(ctx context.Context) error {
newEncs := upe + 1
activeKey.Encryptions += uint64(newEncs)
newKeyring := b.keyring.Clone()
- err := b.persistKeyring(ctx, newKeyring)
+ err := b.persistKeyringBestEffort(ctx, newKeyring)
if err != nil {
return err
}
From 6ed8b88f5ff2402f10e85e36424aafe71c76f0e6 Mon Sep 17 00:00:00 2001
From: Christopher Swenson
Date: Mon, 4 Dec 2023 11:05:02 -0800
Subject: [PATCH 63/74] Switch from mitchellh/cli to hashicorp/cli (#24239)
@mitchellh suggested we fork `cli` and switch to that.
Since we primarily use the interfaces in `cli`, and the new
fork has not changed those, this is (mostly) a drop-in replacement.
A small fix will be necessary for Vault Enterprise, I believe.
---
command/agent.go | 2 +-
command/agent_generate_config.go | 2 +-
command/agent_test.go | 2 +-
command/audit.go | 2 +-
command/audit_disable.go | 2 +-
command/audit_disable_test.go | 2 +-
command/audit_enable.go | 2 +-
command/audit_enable_test.go | 2 +-
command/audit_list.go | 2 +-
command/audit_list_test.go | 2 +-
command/auth.go | 2 +-
command/auth_disable.go | 2 +-
command/auth_disable_test.go | 2 +-
command/auth_enable.go | 2 +-
command/auth_enable_test.go | 2 +-
command/auth_help.go | 2 +-
command/auth_help_test.go | 2 +-
command/auth_list.go | 2 +-
command/auth_list_test.go | 2 +-
command/auth_move.go | 2 +-
command/auth_move_test.go | 2 +-
command/auth_test.go | 2 +-
command/auth_tune.go | 2 +-
command/auth_tune_test.go | 2 +-
command/base.go | 2 +-
command/command_stubs_oss.go | 2 +-
command/command_test.go | 2 +-
command/commands.go | 2 +-
command/debug.go | 2 +-
command/debug_test.go | 2 +-
command/delete.go | 2 +-
command/delete_test.go | 2 +-
command/events.go | 2 +-
command/events_test.go | 2 +-
command/format.go | 2 +-
command/kv.go | 2 +-
command/kv_delete.go | 2 +-
command/kv_destroy.go | 2 +-
command/kv_enable_versioning.go | 2 +-
command/kv_get.go | 2 +-
command/kv_helpers.go | 2 +-
command/kv_list.go | 2 +-
command/kv_metadata.go | 2 +-
command/kv_metadata_delete.go | 2 +-
command/kv_metadata_get.go | 2 +-
command/kv_metadata_patch.go | 2 +-
command/kv_metadata_patch_test.go | 2 +-
command/kv_metadata_put.go | 2 +-
command/kv_metadata_put_test.go | 2 +-
command/kv_patch.go | 2 +-
command/kv_put.go | 2 +-
command/kv_rollback.go | 2 +-
command/kv_test.go | 2 +-
command/kv_undelete.go | 2 +-
command/lease.go | 2 +-
command/lease_lookup.go | 2 +-
command/lease_lookup_test.go | 2 +-
command/lease_renew.go | 2 +-
command/lease_renew_test.go | 2 +-
command/lease_revoke.go | 2 +-
command/lease_revoke_test.go | 2 +-
command/list.go | 2 +-
command/list_test.go | 2 +-
command/login_test.go | 2 +-
command/main.go | 2 +-
command/monitor.go | 2 +-
command/monitor_test.go | 2 +-
command/namespace.go | 2 +-
command/namespace_api_lock.go | 2 +-
command/namespace_api_unlock.go | 2 +-
command/namespace_create.go | 2 +-
command/namespace_delete.go | 2 +-
command/namespace_list.go | 2 +-
command/namespace_lookup.go | 2 +-
command/namespace_patch.go | 2 +-
command/operator.go | 2 +-
command/operator_diagnose.go | 2 +-
command/operator_diagnose_test.go | 2 +-
command/operator_generate_root.go | 2 +-
command/operator_generate_root_test.go | 2 +-
command/operator_init.go | 2 +-
command/operator_init_test.go | 2 +-
command/operator_key_status.go | 2 +-
command/operator_key_status_test.go | 2 +-
command/operator_members.go | 2 +-
command/operator_migrate.go | 2 +-
command/operator_raft.go | 2 +-
command/operator_raft_autopilot_get_config.go | 2 +-
command/operator_raft_autopilot_set_config.go | 2 +-
command/operator_raft_autopilot_state.go | 2 +-
command/operator_raft_join.go | 2 +-
command/operator_raft_listpeers.go | 2 +-
command/operator_raft_remove_peer.go | 2 +-
command/operator_raft_snapshot.go | 2 +-
command/operator_raft_snapshot_inspect.go | 2 +-
.../operator_raft_snapshot_inspect_test.go | 2 +-
command/operator_raft_snapshot_restore.go | 2 +-
command/operator_raft_snapshot_save.go | 2 +-
command/operator_rekey.go | 2 +-
command/operator_rekey_test.go | 2 +-
command/operator_seal.go | 2 +-
command/operator_seal_test.go | 2 +-
command/operator_step_down.go | 2 +-
command/operator_step_down_test.go | 2 +-
command/operator_unseal.go | 2 +-
command/operator_unseal_test.go | 2 +-
command/operator_usage.go | 2 +-
command/patch.go | 2 +-
command/patch_test.go | 2 +-
command/path_help.go | 2 +-
command/path_help_test.go | 2 +-
command/pki.go | 2 +-
command/pki_health_check.go | 2 +-
command/pki_health_check_test.go | 2 +-
command/plugin.go | 2 +-
command/plugin_deregister.go | 2 +-
command/plugin_deregister_test.go | 2 +-
command/plugin_info.go | 2 +-
command/plugin_info_test.go | 2 +-
command/plugin_list.go | 2 +-
command/plugin_list_test.go | 2 +-
command/plugin_register.go | 2 +-
command/plugin_register_test.go | 2 +-
command/plugin_reload.go | 2 +-
command/plugin_reload_status.go | 2 +-
command/plugin_reload_test.go | 2 +-
command/plugin_runtime.go | 2 +-
command/plugin_runtime_deregister.go | 2 +-
command/plugin_runtime_deregister_test.go | 2 +-
command/plugin_runtime_info.go | 2 +-
command/plugin_runtime_info_test.go | 2 +-
command/plugin_runtime_list.go | 2 +-
command/plugin_runtime_list_test.go | 2 +-
command/plugin_runtime_register.go | 2 +-
command/plugin_runtime_register_test.go | 2 +-
command/policy.go | 2 +-
command/policy_delete.go | 2 +-
command/policy_delete_test.go | 2 +-
command/policy_fmt.go | 2 +-
command/policy_fmt_test.go | 2 +-
command/policy_list.go | 2 +-
command/policy_list_test.go | 2 +-
command/policy_read.go | 2 +-
command/policy_read_test.go | 2 +-
command/policy_write.go | 2 +-
command/policy_write_test.go | 2 +-
command/print.go | 2 +-
command/print_token.go | 2 +-
command/proxy.go | 2 +-
command/proxy_test.go | 2 +-
command/read.go | 2 +-
command/read_test.go | 2 +-
command/rotate.go | 2 +-
command/rotate_test.go | 2 +-
command/secrets.go | 2 +-
command/secrets_disable.go | 2 +-
command/secrets_disable_test.go | 2 +-
command/secrets_enable.go | 2 +-
command/secrets_enable_test.go | 2 +-
command/secrets_list.go | 2 +-
command/secrets_list_test.go | 2 +-
command/secrets_move.go | 2 +-
command/secrets_move_test.go | 2 +-
command/secrets_tune.go | 2 +-
command/secrets_tune_test.go | 2 +-
command/server.go | 2 +-
command/server/listener.go | 2 +-
command/server/listener_tcp.go | 2 +-
command/server/listener_tcp_test.go | 2 +-
command/server/listener_unix.go | 2 +-
command/server/listener_unix_test.go | 2 +-
command/server_test.go | 2 +-
command/ssh.go | 2 +-
command/ssh_test.go | 2 +-
command/status.go | 2 +-
command/status_test.go | 2 +-
command/token.go | 2 +-
command/token/testing.go | 2 +-
command/token_capabilities.go | 2 +-
command/token_capabilities_test.go | 2 +-
command/token_create.go | 2 +-
command/token_create_test.go | 2 +-
command/token_lookup.go | 2 +-
command/token_lookup_test.go | 2 +-
command/token_renew.go | 2 +-
command/token_renew_test.go | 2 +-
command/token_revoke.go | 2 +-
command/token_revoke_test.go | 2 +-
command/transform.go | 2 +-
command/transform_import_key.go | 2 +-
command/transform_import_key_version.go | 2 +-
command/transit.go | 2 +-
command/transit_import_key.go | 2 +-
command/transit_import_key_version.go | 2 +-
command/unwrap.go | 2 +-
command/unwrap_test.go | 2 +-
command/util.go | 2 +-
command/version.go | 2 +-
command/version_history.go | 2 +-
command/version_history_test.go | 2 +-
command/version_test.go | 2 +-
command/write.go | 2 +-
command/write_test.go | 2 +-
go.mod | 8 ++++----
go.sum | 20 ++++++++-----------
internalshared/configutil/telemetry.go | 2 +-
internalshared/listenerutil/listener.go | 2 +-
207 files changed, 217 insertions(+), 221 deletions(-)
diff --git a/command/agent.go b/command/agent.go
index 94db44c86d58..a3d46a32edc9 100644
--- a/command/agent.go
+++ b/command/agent.go
@@ -19,6 +19,7 @@ import (
"time"
systemd "github.com/coreos/go-systemd/daemon"
+ "github.com/hashicorp/cli"
ctconfig "github.com/hashicorp/consul-template/config"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-multierror"
@@ -45,7 +46,6 @@ import (
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/version"
"github.com/kr/pretty"
- "github.com/mitchellh/cli"
"github.com/oklog/run"
"github.com/posener/complete"
"golang.org/x/text/cases"
diff --git a/command/agent_generate_config.go b/command/agent_generate_config.go
index f2ff1abf9559..31bbcd255c4e 100644
--- a/command/agent_generate_config.go
+++ b/command/agent_generate_config.go
@@ -13,10 +13,10 @@ import (
"strings"
"unicode"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/hcl/v2/hclwrite"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/mitchellh/go-homedir"
"github.com/posener/complete"
)
diff --git a/command/agent_test.go b/command/agent_test.go
index 3ab66b462389..8d12f6584d3d 100644
--- a/command/agent_test.go
+++ b/command/agent_test.go
@@ -20,6 +20,7 @@ import (
"testing"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-hclog"
vaultjwt "github.com/hashicorp/vault-plugin-auth-jwt"
logicalKv "github.com/hashicorp/vault-plugin-secrets-kv"
@@ -35,7 +36,6 @@ import (
"github.com/hashicorp/vault/sdk/helper/pointerutil"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault"
- "github.com/mitchellh/cli"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
diff --git a/command/audit.go b/command/audit.go
index 67f5b194daaa..1c59140a9a98 100644
--- a/command/audit.go
+++ b/command/audit.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*AuditCommand)(nil)
diff --git a/command/audit_disable.go b/command/audit_disable.go
index 0e99da438d7b..79914ea5d993 100644
--- a/command/audit_disable.go
+++ b/command/audit_disable.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/audit_disable_test.go b/command/audit_disable_test.go
index ec28f70ddfc0..786140ee326e 100644
--- a/command/audit_disable_test.go
+++ b/command/audit_disable_test.go
@@ -7,8 +7,8 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testAuditDisableCommand(tb testing.TB) (*cli.MockUi, *AuditDisableCommand) {
diff --git a/command/audit_enable.go b/command/audit_enable.go
index c77fe277d1f3..a163f471cc4f 100644
--- a/command/audit_enable.go
+++ b/command/audit_enable.go
@@ -9,8 +9,8 @@ import (
"os"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/audit_enable_test.go b/command/audit_enable_test.go
index 58dca872e640..6c0c769e23ed 100644
--- a/command/audit_enable_test.go
+++ b/command/audit_enable_test.go
@@ -9,7 +9,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testAuditEnableCommand(tb testing.TB) (*cli.MockUi, *AuditEnableCommand) {
diff --git a/command/audit_list.go b/command/audit_list.go
index a7793fcee493..cf3a16f0f079 100644
--- a/command/audit_list.go
+++ b/command/audit_list.go
@@ -8,8 +8,8 @@ import (
"sort"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/audit_list_test.go b/command/audit_list_test.go
index bc41c13d603c..43ddbacf91f2 100644
--- a/command/audit_list_test.go
+++ b/command/audit_list_test.go
@@ -7,8 +7,8 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testAuditListCommand(tb testing.TB) (*cli.MockUi, *AuditListCommand) {
diff --git a/command/auth.go b/command/auth.go
index 76919ed2084f..57489a186f1d 100644
--- a/command/auth.go
+++ b/command/auth.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*AuthCommand)(nil)
diff --git a/command/auth_disable.go b/command/auth_disable.go
index 775f7fabc7fd..1476b71d0f07 100644
--- a/command/auth_disable.go
+++ b/command/auth_disable.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/auth_disable_test.go b/command/auth_disable_test.go
index 1cf429876070..f9da8a7d770c 100644
--- a/command/auth_disable_test.go
+++ b/command/auth_disable_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testAuthDisableCommand(tb testing.TB) (*cli.MockUi, *AuthDisableCommand) {
diff --git a/command/auth_enable.go b/command/auth_enable.go
index cd47d2f35f92..912f410e8285 100644
--- a/command/auth_enable.go
+++ b/command/auth_enable.go
@@ -10,8 +10,8 @@ import (
"strings"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/auth_enable_test.go b/command/auth_enable_test.go
index 93c685819e44..0cdaf0fc79dd 100644
--- a/command/auth_enable_test.go
+++ b/command/auth_enable_test.go
@@ -11,10 +11,10 @@ import (
"github.com/go-test/deep"
"github.com/google/go-cmp/cmp"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/helper/builtinplugins"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/helper/strutil"
- "github.com/mitchellh/cli"
)
func testAuthEnableCommand(tb testing.TB) (*cli.MockUi, *AuthEnableCommand) {
diff --git a/command/auth_help.go b/command/auth_help.go
index 5e971ebbac41..68365e737c3b 100644
--- a/command/auth_help.go
+++ b/command/auth_help.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/auth_help_test.go b/command/auth_help_test.go
index d87832c8920f..e437f29199e3 100644
--- a/command/auth_help_test.go
+++ b/command/auth_help_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
credUserpass "github.com/hashicorp/vault/builtin/credential/userpass"
)
diff --git a/command/auth_list.go b/command/auth_list.go
index e1a8771d7f5b..d095156e155b 100644
--- a/command/auth_list.go
+++ b/command/auth_list.go
@@ -9,8 +9,8 @@ import (
"strconv"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/auth_list_test.go b/command/auth_list_test.go
index 8e019f1b8fa9..087010a8ce35 100644
--- a/command/auth_list_test.go
+++ b/command/auth_list_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testAuthListCommand(tb testing.TB) (*cli.MockUi, *AuthListCommand) {
diff --git a/command/auth_move.go b/command/auth_move.go
index e91d9d82fb83..3ede5fc49fc9 100644
--- a/command/auth_move.go
+++ b/command/auth_move.go
@@ -8,7 +8,7 @@ import (
"strings"
"time"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/auth_move_test.go b/command/auth_move_test.go
index 095c3ae9daab..0b585e7e0031 100644
--- a/command/auth_move_test.go
+++ b/command/auth_move_test.go
@@ -7,8 +7,8 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testAuthMoveCommand(tb testing.TB) (*cli.MockUi, *AuthMoveCommand) {
diff --git a/command/auth_test.go b/command/auth_test.go
index 4eb7d4ee3e07..9071c0c157a0 100644
--- a/command/auth_test.go
+++ b/command/auth_test.go
@@ -6,7 +6,7 @@ package command
import (
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/command/token"
)
diff --git a/command/auth_tune.go b/command/auth_tune.go
index 65b3070666d9..10e7f9fe4113 100644
--- a/command/auth_tune.go
+++ b/command/auth_tune.go
@@ -10,8 +10,8 @@ import (
"strings"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/auth_tune_test.go b/command/auth_tune_test.go
index ea0449b9d5c2..4bc8ddf46596 100644
--- a/command/auth_tune_test.go
+++ b/command/auth_tune_test.go
@@ -8,9 +8,9 @@ import (
"testing"
"github.com/go-test/deep"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
- "github.com/mitchellh/cli"
)
func testAuthTuneCommand(tb testing.TB) (*cli.MockUi, *AuthTuneCommand) {
diff --git a/command/base.go b/command/base.go
index 10be15b636cb..c2657e7fd8cc 100644
--- a/command/base.go
+++ b/command/base.go
@@ -15,11 +15,11 @@ import (
"sync"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/command/token"
"github.com/hashicorp/vault/helper/namespace"
"github.com/mattn/go-isatty"
- "github.com/mitchellh/cli"
"github.com/pkg/errors"
"github.com/posener/complete"
)
diff --git a/command/command_stubs_oss.go b/command/command_stubs_oss.go
index bc90a1585aaf..d1de67e4def6 100644
--- a/command/command_stubs_oss.go
+++ b/command/command_stubs_oss.go
@@ -8,9 +8,9 @@ package command
//go:generate go run github.com/hashicorp/vault/tools/stubmaker
import (
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/command/server"
"github.com/hashicorp/vault/vault"
- "github.com/mitchellh/cli"
)
func entInitCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions, commands map[string]cli.CommandFactory) {
diff --git a/command/command_test.go b/command/command_test.go
index 34bd3b453355..5ef880b78742 100644
--- a/command/command_test.go
+++ b/command/command_test.go
@@ -12,6 +12,7 @@ import (
"testing"
"time"
+ "github.com/hashicorp/cli"
log "github.com/hashicorp/go-hclog"
kv "github.com/hashicorp/vault-plugin-secrets-kv"
"github.com/hashicorp/vault/api"
@@ -25,7 +26,6 @@ import (
"github.com/hashicorp/vault/sdk/physical/inmem"
"github.com/hashicorp/vault/vault"
"github.com/hashicorp/vault/vault/seal"
- "github.com/mitchellh/cli"
auditFile "github.com/hashicorp/vault/builtin/audit/file"
credUserpass "github.com/hashicorp/vault/builtin/credential/userpass"
diff --git a/command/commands.go b/command/commands.go
index 1a52e121a1df..aac2d57bc73f 100644
--- a/command/commands.go
+++ b/command/commands.go
@@ -8,12 +8,12 @@ import (
"os/signal"
"syscall"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/audit"
"github.com/hashicorp/vault/builtin/plugin"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/sdk/physical"
"github.com/hashicorp/vault/version"
- "github.com/mitchellh/cli"
/*
The builtinplugins package is initialized here because it, in turn,
diff --git a/command/debug.go b/command/debug.go
index 941249657a94..09df88fb4d60 100644
--- a/command/debug.go
+++ b/command/debug.go
@@ -17,6 +17,7 @@ import (
"sync"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-secure-stdlib/gatedwriter"
"github.com/hashicorp/go-secure-stdlib/strutil"
@@ -26,7 +27,6 @@ import (
"github.com/hashicorp/vault/sdk/helper/logging"
"github.com/hashicorp/vault/version"
"github.com/mholt/archiver/v3"
- "github.com/mitchellh/cli"
"github.com/oklog/run"
"github.com/posener/complete"
)
diff --git a/command/debug_test.go b/command/debug_test.go
index 80576311dde8..279c48f0a5ac 100644
--- a/command/debug_test.go
+++ b/command/debug_test.go
@@ -16,9 +16,9 @@ import (
"testing"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
"github.com/mholt/archiver/v3"
- "github.com/mitchellh/cli"
)
func testDebugCommand(tb testing.TB) (*cli.MockUi, *DebugCommand) {
diff --git a/command/delete.go b/command/delete.go
index 58005e95b261..6986a84ec343 100644
--- a/command/delete.go
+++ b/command/delete.go
@@ -9,7 +9,7 @@ import (
"os"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/delete_test.go b/command/delete_test.go
index 3c08bc685b0b..6da1d1d7fa91 100644
--- a/command/delete_test.go
+++ b/command/delete_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testDeleteCommand(tb testing.TB) (*cli.MockUi, *DeleteCommand) {
diff --git a/command/events.go b/command/events.go
index acc68b117f9c..48f1fdd22681 100644
--- a/command/events.go
+++ b/command/events.go
@@ -11,8 +11,8 @@ import (
"os"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
"nhooyr.io/websocket"
)
diff --git a/command/events_test.go b/command/events_test.go
index 336dc0a34225..dfeb12d706b2 100644
--- a/command/events_test.go
+++ b/command/events_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testEventsSubscribeCommand(tb testing.TB) (*cli.MockUi, *EventsSubscribeCommands) {
diff --git a/command/format.go b/command/format.go
index 4b12771d98d1..548a9a089c85 100644
--- a/command/format.go
+++ b/command/format.go
@@ -14,8 +14,8 @@ import (
"time"
"github.com/ghodss/yaml"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/ryanuber/columnize"
)
diff --git a/command/kv.go b/command/kv.go
index 9a7e9eaee15d..f17baf5d3ab7 100644
--- a/command/kv.go
+++ b/command/kv.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*KVCommand)(nil)
diff --git a/command/kv_delete.go b/command/kv_delete.go
index acb4abecaf41..67cc56ac4e77 100644
--- a/command/kv_delete.go
+++ b/command/kv_delete.go
@@ -8,8 +8,8 @@ import (
"path"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/kv_destroy.go b/command/kv_destroy.go
index bc73021fff82..0299be4cea87 100644
--- a/command/kv_destroy.go
+++ b/command/kv_destroy.go
@@ -8,7 +8,7 @@ import (
"path"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/kv_enable_versioning.go b/command/kv_enable_versioning.go
index 1b522269034b..921c286e3aae 100644
--- a/command/kv_enable_versioning.go
+++ b/command/kv_enable_versioning.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/kv_get.go b/command/kv_get.go
index d852a722b48e..e31c8a32a5c7 100644
--- a/command/kv_get.go
+++ b/command/kv_get.go
@@ -8,7 +8,7 @@ import (
"path"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/kv_helpers.go b/command/kv_helpers.go
index 844af21848d2..ed3bc38118e5 100644
--- a/command/kv_helpers.go
+++ b/command/kv_helpers.go
@@ -12,9 +12,9 @@ import (
"sort"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func kvReadRequest(client *api.Client, path string, params map[string]string) (*api.Secret, error) {
diff --git a/command/kv_list.go b/command/kv_list.go
index d4733a137f59..4e19d9d7ae3b 100644
--- a/command/kv_list.go
+++ b/command/kv_list.go
@@ -8,7 +8,7 @@ import (
"path"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/kv_metadata.go b/command/kv_metadata.go
index 8c0d2ca59274..14e1b5bfa3a5 100644
--- a/command/kv_metadata.go
+++ b/command/kv_metadata.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*KVMetadataCommand)(nil)
diff --git a/command/kv_metadata_delete.go b/command/kv_metadata_delete.go
index 8163cc6bde8e..6f672fc6aeac 100644
--- a/command/kv_metadata_delete.go
+++ b/command/kv_metadata_delete.go
@@ -8,7 +8,7 @@ import (
"path"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/kv_metadata_get.go b/command/kv_metadata_get.go
index 54d73c0b3a22..2722c330efe0 100644
--- a/command/kv_metadata_get.go
+++ b/command/kv_metadata_get.go
@@ -10,7 +10,7 @@ import (
"strconv"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/kv_metadata_patch.go b/command/kv_metadata_patch.go
index 74c46476d0de..ff59c12fb7c7 100644
--- a/command/kv_metadata_patch.go
+++ b/command/kv_metadata_patch.go
@@ -11,7 +11,7 @@ import (
"strings"
"time"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/kv_metadata_patch_test.go b/command/kv_metadata_patch_test.go
index a8dc583780c5..1dc0e123773e 100644
--- a/command/kv_metadata_patch_test.go
+++ b/command/kv_metadata_patch_test.go
@@ -10,8 +10,8 @@ import (
"testing"
"github.com/go-test/deep"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testKVMetadataPatchCommand(tb testing.TB) (*cli.MockUi, *KVMetadataPatchCommand) {
diff --git a/command/kv_metadata_put.go b/command/kv_metadata_put.go
index 1cd8375320a1..5b8124229de9 100644
--- a/command/kv_metadata_put.go
+++ b/command/kv_metadata_put.go
@@ -10,7 +10,7 @@ import (
"strings"
"time"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/kv_metadata_put_test.go b/command/kv_metadata_put_test.go
index a4068e23c886..edd0b6bf2e92 100644
--- a/command/kv_metadata_put_test.go
+++ b/command/kv_metadata_put_test.go
@@ -9,8 +9,8 @@ import (
"testing"
"github.com/go-test/deep"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testKVMetadataPutCommand(tb testing.TB) (*cli.MockUi, *KVMetadataPutCommand) {
diff --git a/command/kv_patch.go b/command/kv_patch.go
index da96088d112f..7eaf710ebecb 100644
--- a/command/kv_patch.go
+++ b/command/kv_patch.go
@@ -11,8 +11,8 @@ import (
"path"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/kv_put.go b/command/kv_put.go
index d450b4415ccc..b51705791f51 100644
--- a/command/kv_put.go
+++ b/command/kv_put.go
@@ -10,7 +10,7 @@ import (
"path"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/kv_rollback.go b/command/kv_rollback.go
index 798e4a898846..a0544b69d79a 100644
--- a/command/kv_rollback.go
+++ b/command/kv_rollback.go
@@ -9,7 +9,7 @@ import (
"path"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/kv_test.go b/command/kv_test.go
index e8abba0b1d56..c5ca555be6be 100644
--- a/command/kv_test.go
+++ b/command/kv_test.go
@@ -11,8 +11,8 @@ import (
"testing"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testKVPutCommand(tb testing.TB) (*cli.MockUi, *KVPutCommand) {
diff --git a/command/kv_undelete.go b/command/kv_undelete.go
index abc90879e6b8..7d438387193b 100644
--- a/command/kv_undelete.go
+++ b/command/kv_undelete.go
@@ -8,7 +8,7 @@ import (
"path"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/lease.go b/command/lease.go
index 5e8f46afe1bb..3e0817ffd0d8 100644
--- a/command/lease.go
+++ b/command/lease.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*LeaseCommand)(nil)
diff --git a/command/lease_lookup.go b/command/lease_lookup.go
index 8c38c1cfd7df..51b7aab60415 100644
--- a/command/lease_lookup.go
+++ b/command/lease_lookup.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/lease_lookup_test.go b/command/lease_lookup_test.go
index bc0019428097..2c9b81caf5fa 100644
--- a/command/lease_lookup_test.go
+++ b/command/lease_lookup_test.go
@@ -7,8 +7,8 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testLeaseLookupCommand(tb testing.TB) (*cli.MockUi, *LeaseLookupCommand) {
diff --git a/command/lease_renew.go b/command/lease_renew.go
index 0918d8ed4b75..b0671c379682 100644
--- a/command/lease_renew.go
+++ b/command/lease_renew.go
@@ -8,7 +8,7 @@ import (
"strings"
"time"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/lease_renew_test.go b/command/lease_renew_test.go
index 40719d1f0a55..eac098fe4634 100644
--- a/command/lease_renew_test.go
+++ b/command/lease_renew_test.go
@@ -7,8 +7,8 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testLeaseRenewCommand(tb testing.TB) (*cli.MockUi, *LeaseRenewCommand) {
diff --git a/command/lease_revoke.go b/command/lease_revoke.go
index 751cce97449d..59a09de597e8 100644
--- a/command/lease_revoke.go
+++ b/command/lease_revoke.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/lease_revoke_test.go b/command/lease_revoke_test.go
index ece8d31f0601..aeb9987e7ddd 100644
--- a/command/lease_revoke_test.go
+++ b/command/lease_revoke_test.go
@@ -7,8 +7,8 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testLeaseRevokeCommand(tb testing.TB) (*cli.MockUi, *LeaseRevokeCommand) {
diff --git a/command/list.go b/command/list.go
index 1f300cb459e6..6505f76af8c3 100644
--- a/command/list.go
+++ b/command/list.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/list_test.go b/command/list_test.go
index 60467647a055..e7a870d7ffb6 100644
--- a/command/list_test.go
+++ b/command/list_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testListCommand(tb testing.TB) (*cli.MockUi, *ListCommand) {
diff --git a/command/login_test.go b/command/login_test.go
index deb96be18871..b8afeffbf2f6 100644
--- a/command/login_test.go
+++ b/command/login_test.go
@@ -10,7 +10,7 @@ import (
"testing"
"time"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
credToken "github.com/hashicorp/vault/builtin/credential/token"
diff --git a/command/main.go b/command/main.go
index 22dde07fa745..359ae471edfc 100644
--- a/command/main.go
+++ b/command/main.go
@@ -15,10 +15,10 @@ import (
"text/tabwriter"
"github.com/fatih/color"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/command/token"
colorable "github.com/mattn/go-colorable"
- "github.com/mitchellh/cli"
)
type VaultUI struct {
diff --git a/command/monitor.go b/command/monitor.go
index acfbc24be761..f39ca72a360a 100644
--- a/command/monitor.go
+++ b/command/monitor.go
@@ -8,8 +8,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-secure-stdlib/strutil"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/monitor_test.go b/command/monitor_test.go
index 8c2c288d841a..fd1b288fd243 100644
--- a/command/monitor_test.go
+++ b/command/monitor_test.go
@@ -9,7 +9,7 @@ import (
"testing"
"time"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testMonitorCommand(tb testing.TB) (*cli.MockUi, *MonitorCommand) {
diff --git a/command/namespace.go b/command/namespace.go
index 4bc6cfa1c776..c47b26648c89 100644
--- a/command/namespace.go
+++ b/command/namespace.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*NamespaceCommand)(nil)
diff --git a/command/namespace_api_lock.go b/command/namespace_api_lock.go
index 22a3169304e7..4193508ec4fe 100644
--- a/command/namespace_api_lock.go
+++ b/command/namespace_api_lock.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/helper/namespace"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/namespace_api_unlock.go b/command/namespace_api_unlock.go
index fa05d43ca561..0c9cd22eadd9 100644
--- a/command/namespace_api_unlock.go
+++ b/command/namespace_api_unlock.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/helper/namespace"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/namespace_create.go b/command/namespace_create.go
index 20dc639ad605..6499bf2a25c9 100644
--- a/command/namespace_create.go
+++ b/command/namespace_create.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/namespace_delete.go b/command/namespace_delete.go
index f034ec4771af..e7704ca5cd85 100644
--- a/command/namespace_delete.go
+++ b/command/namespace_delete.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/namespace_list.go b/command/namespace_list.go
index 8bb30ed9bb3a..e8581670edb7 100644
--- a/command/namespace_list.go
+++ b/command/namespace_list.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/namespace_lookup.go b/command/namespace_lookup.go
index 480da0b914fa..376a0adc419e 100644
--- a/command/namespace_lookup.go
+++ b/command/namespace_lookup.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/namespace_patch.go b/command/namespace_patch.go
index 40c1d05f9d73..d3868c6134fe 100644
--- a/command/namespace_patch.go
+++ b/command/namespace_patch.go
@@ -9,8 +9,8 @@ import (
"net/http"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/operator.go b/command/operator.go
index 94b02994d807..8d918f3492ac 100644
--- a/command/operator.go
+++ b/command/operator.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*OperatorCommand)(nil)
diff --git a/command/operator_diagnose.go b/command/operator_diagnose.go
index 360feb287be3..a3f02fba97d0 100644
--- a/command/operator_diagnose.go
+++ b/command/operator_diagnose.go
@@ -18,6 +18,7 @@ import (
"golang.org/x/term"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/consul/api"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-secure-stdlib/reloadutil"
@@ -36,7 +37,6 @@ import (
"github.com/hashicorp/vault/vault/diagnose"
"github.com/hashicorp/vault/vault/hcp_link"
"github.com/hashicorp/vault/version"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_diagnose_test.go b/command/operator_diagnose_test.go
index 31b38f1c50ed..8b15cc8b1d24 100644
--- a/command/operator_diagnose_test.go
+++ b/command/operator_diagnose_test.go
@@ -15,8 +15,8 @@ import (
"github.com/hashicorp/vault/command/server"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/vault/diagnose"
- "github.com/mitchellh/cli"
)
func testOperatorDiagnoseCommand(tb testing.TB) *OperatorDiagnoseCommand {
diff --git a/command/operator_generate_root.go b/command/operator_generate_root.go
index e660a6e1c145..b7518aa91c5d 100644
--- a/command/operator_generate_root.go
+++ b/command/operator_generate_root.go
@@ -10,11 +10,11 @@ import (
"os"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-secure-stdlib/password"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/pgpkeys"
"github.com/hashicorp/vault/sdk/helper/roottoken"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_generate_root_test.go b/command/operator_generate_root_test.go
index 4db2262cad1b..e27592d856a7 100644
--- a/command/operator_generate_root_test.go
+++ b/command/operator_generate_root_test.go
@@ -13,9 +13,9 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/sdk/helper/xor"
"github.com/hashicorp/vault/vault"
- "github.com/mitchellh/cli"
)
func testOperatorGenerateRootCommand(tb testing.TB) (*cli.MockUi, *OperatorGenerateRootCommand) {
diff --git a/command/operator_init.go b/command/operator_init.go
index 4b0f26bb4aa8..576f7fe2dc5d 100644
--- a/command/operator_init.go
+++ b/command/operator_init.go
@@ -9,9 +9,9 @@ import (
"runtime"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/pgpkeys"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
consulapi "github.com/hashicorp/consul/api"
diff --git a/command/operator_init_test.go b/command/operator_init_test.go
index 917686543223..73fe4ff59e93 100644
--- a/command/operator_init_test.go
+++ b/command/operator_init_test.go
@@ -13,10 +13,10 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/pgpkeys"
"github.com/hashicorp/vault/vault"
- "github.com/mitchellh/cli"
)
func testOperatorInitCommand(tb testing.TB) (*cli.MockUi, *OperatorInitCommand) {
diff --git a/command/operator_key_status.go b/command/operator_key_status.go
index 866b7d7e7eb8..015bd891f75f 100644
--- a/command/operator_key_status.go
+++ b/command/operator_key_status.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_key_status_test.go b/command/operator_key_status_test.go
index db92eb9e9b70..ccaac3883081 100644
--- a/command/operator_key_status_test.go
+++ b/command/operator_key_status_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testOperatorKeyStatusCommand(tb testing.TB) (*cli.MockUi, *OperatorKeyStatusCommand) {
diff --git a/command/operator_members.go b/command/operator_members.go
index c280f315bf9c..83d7a2d4301e 100644
--- a/command/operator_members.go
+++ b/command/operator_members.go
@@ -8,7 +8,7 @@ import (
"strings"
"time"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_migrate.go b/command/operator_migrate.go
index 2e956046f3f7..3af73e696382 100644
--- a/command/operator_migrate.go
+++ b/command/operator_migrate.go
@@ -14,6 +14,7 @@ import (
"strings"
"time"
+ "github.com/hashicorp/cli"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/hcl"
@@ -23,7 +24,6 @@ import (
"github.com/hashicorp/vault/sdk/helper/logging"
"github.com/hashicorp/vault/sdk/physical"
"github.com/hashicorp/vault/vault"
- "github.com/mitchellh/cli"
"github.com/pkg/errors"
"github.com/posener/complete"
"golang.org/x/sync/errgroup"
diff --git a/command/operator_raft.go b/command/operator_raft.go
index 9e02371dcbd6..deaff14cdf2d 100644
--- a/command/operator_raft.go
+++ b/command/operator_raft.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*OperatorRaftCommand)(nil)
diff --git a/command/operator_raft_autopilot_get_config.go b/command/operator_raft_autopilot_get_config.go
index 81ee3b6b885a..bdeeed6f8c08 100644
--- a/command/operator_raft_autopilot_get_config.go
+++ b/command/operator_raft_autopilot_get_config.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_raft_autopilot_set_config.go b/command/operator_raft_autopilot_set_config.go
index 3ac287cc7494..39b9b2ddcb6d 100644
--- a/command/operator_raft_autopilot_set_config.go
+++ b/command/operator_raft_autopilot_set_config.go
@@ -8,7 +8,7 @@ import (
"strings"
"time"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_raft_autopilot_state.go b/command/operator_raft_autopilot_state.go
index a5b31a34139b..4fc4ca4445e8 100644
--- a/command/operator_raft_autopilot_state.go
+++ b/command/operator_raft_autopilot_state.go
@@ -8,8 +8,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_raft_join.go b/command/operator_raft_join.go
index 74fc7f487f7f..aaaaf2891e10 100644
--- a/command/operator_raft_join.go
+++ b/command/operator_raft_join.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_raft_listpeers.go b/command/operator_raft_listpeers.go
index 434fcc0eecd7..b92ab8f0b517 100644
--- a/command/operator_raft_listpeers.go
+++ b/command/operator_raft_listpeers.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_raft_remove_peer.go b/command/operator_raft_remove_peer.go
index 1f9c33ba1ce3..fabd9ce30d39 100644
--- a/command/operator_raft_remove_peer.go
+++ b/command/operator_raft_remove_peer.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_raft_snapshot.go b/command/operator_raft_snapshot.go
index c78ef8d4e74e..02fc4c2b8a43 100644
--- a/command/operator_raft_snapshot.go
+++ b/command/operator_raft_snapshot.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*OperatorRaftSnapshotCommand)(nil)
diff --git a/command/operator_raft_snapshot_inspect.go b/command/operator_raft_snapshot_inspect.go
index a64c5ba347a9..43c3fb0e4a13 100644
--- a/command/operator_raft_snapshot_inspect.go
+++ b/command/operator_raft_snapshot_inspect.go
@@ -20,11 +20,11 @@ import (
"strings"
"text/tabwriter"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/raft"
protoio "github.com/hashicorp/vault/physical/raft"
"github.com/hashicorp/vault/sdk/plugin/pb"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_raft_snapshot_inspect_test.go b/command/operator_raft_snapshot_inspect_test.go
index de306595e5a3..d70037695606 100644
--- a/command/operator_raft_snapshot_inspect_test.go
+++ b/command/operator_raft_snapshot_inspect_test.go
@@ -10,9 +10,9 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/physical/raft"
"github.com/hashicorp/vault/sdk/physical"
- "github.com/mitchellh/cli"
)
func testOperatorRaftSnapshotInspectCommand(tb testing.TB) (*cli.MockUi, *OperatorRaftSnapshotInspectCommand) {
diff --git a/command/operator_raft_snapshot_restore.go b/command/operator_raft_snapshot_restore.go
index 56c24b61b58f..516fba522fe8 100644
--- a/command/operator_raft_snapshot_restore.go
+++ b/command/operator_raft_snapshot_restore.go
@@ -8,7 +8,7 @@ import (
"os"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_raft_snapshot_save.go b/command/operator_raft_snapshot_save.go
index 95ecae87c09d..38580ed5e1f5 100644
--- a/command/operator_raft_snapshot_save.go
+++ b/command/operator_raft_snapshot_save.go
@@ -9,7 +9,7 @@ import (
"os"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_rekey.go b/command/operator_rekey.go
index 415b634a07ad..9b4841568281 100644
--- a/command/operator_rekey.go
+++ b/command/operator_rekey.go
@@ -11,10 +11,10 @@ import (
"strings"
"github.com/fatih/structs"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-secure-stdlib/password"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/pgpkeys"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_rekey_test.go b/command/operator_rekey_test.go
index f06ac561346e..b21d9c367b32 100644
--- a/command/operator_rekey_test.go
+++ b/command/operator_rekey_test.go
@@ -14,8 +14,8 @@ import (
"github.com/hashicorp/vault/sdk/helper/roottoken"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testOperatorRekeyCommand(tb testing.TB) (*cli.MockUi, *OperatorRekeyCommand) {
diff --git a/command/operator_seal.go b/command/operator_seal.go
index e8f55805b0c8..f390972f2045 100644
--- a/command/operator_seal.go
+++ b/command/operator_seal.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_seal_test.go b/command/operator_seal_test.go
index 7a8e5c35ed78..6208d6396328 100644
--- a/command/operator_seal_test.go
+++ b/command/operator_seal_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testOperatorSealCommand(tb testing.TB) (*cli.MockUi, *OperatorSealCommand) {
diff --git a/command/operator_step_down.go b/command/operator_step_down.go
index b9350ee08817..e8b93acf0759 100644
--- a/command/operator_step_down.go
+++ b/command/operator_step_down.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_step_down_test.go b/command/operator_step_down_test.go
index 376f4ef2e6ae..8cb108be98c9 100644
--- a/command/operator_step_down_test.go
+++ b/command/operator_step_down_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testOperatorStepDownCommand(tb testing.TB) (*cli.MockUi, *OperatorStepDownCommand) {
diff --git a/command/operator_unseal.go b/command/operator_unseal.go
index 18bd5f4a02a5..a667f209dcba 100644
--- a/command/operator_unseal.go
+++ b/command/operator_unseal.go
@@ -9,9 +9,9 @@ import (
"os"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-secure-stdlib/password"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/operator_unseal_test.go b/command/operator_unseal_test.go
index 8e45978c0beb..42f603e4882c 100644
--- a/command/operator_unseal_test.go
+++ b/command/operator_unseal_test.go
@@ -11,7 +11,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testOperatorUnsealCommand(tb testing.TB) (*cli.MockUi, *OperatorUnsealCommand) {
diff --git a/command/operator_usage.go b/command/operator_usage.go
index fda1caf29a82..8fa0f8f41518 100644
--- a/command/operator_usage.go
+++ b/command/operator_usage.go
@@ -11,8 +11,8 @@ import (
"strings"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
"github.com/ryanuber/columnize"
)
diff --git a/command/patch.go b/command/patch.go
index f2092f3eba4a..f7b006f0f125 100644
--- a/command/patch.go
+++ b/command/patch.go
@@ -10,7 +10,7 @@ import (
"os"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/patch_test.go b/command/patch_test.go
index a8476722e28a..357257937309 100644
--- a/command/patch_test.go
+++ b/command/patch_test.go
@@ -8,8 +8,8 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testPatchCommand(tb testing.TB) (*cli.MockUi, *PatchCommand) {
diff --git a/command/path_help.go b/command/path_help.go
index 3525f2ededc5..335de684008f 100644
--- a/command/path_help.go
+++ b/command/path_help.go
@@ -8,7 +8,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/path_help_test.go b/command/path_help_test.go
index 0bce2c788f81..33c06b4fe553 100644
--- a/command/path_help_test.go
+++ b/command/path_help_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testPathHelpCommand(tb testing.TB) (*cli.MockUi, *PathHelpCommand) {
diff --git a/command/pki.go b/command/pki.go
index 63655da5ca6f..8b90a6aa7b38 100644
--- a/command/pki.go
+++ b/command/pki.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*PKICommand)(nil)
diff --git a/command/pki_health_check.go b/command/pki_health_check.go
index a06a8eccf8fc..0ae44499fb96 100644
--- a/command/pki_health_check.go
+++ b/command/pki_health_check.go
@@ -12,7 +12,7 @@ import (
"github.com/hashicorp/vault/command/healthcheck"
"github.com/ghodss/yaml"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
"github.com/ryanuber/columnize"
)
diff --git a/command/pki_health_check_test.go b/command/pki_health_check_test.go
index b3b2dfb8c830..5f86b3b97f7e 100644
--- a/command/pki_health_check_test.go
+++ b/command/pki_health_check_test.go
@@ -15,7 +15,7 @@ import (
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/command/healthcheck"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/stretchr/testify/require"
)
diff --git a/command/plugin.go b/command/plugin.go
index 49e5635db1ba..862b55bb046b 100644
--- a/command/plugin.go
+++ b/command/plugin.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*PluginCommand)(nil)
diff --git a/command/plugin_deregister.go b/command/plugin_deregister.go
index 5355a951576d..1f1e4360acd5 100644
--- a/command/plugin_deregister.go
+++ b/command/plugin_deregister.go
@@ -9,9 +9,9 @@ import (
"net/http"
"strings"
+ "github.com/hashicorp/cli"
semver "github.com/hashicorp/go-version"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/plugin_deregister_test.go b/command/plugin_deregister_test.go
index b5bf4f7be92c..d80ed9f3fe48 100644
--- a/command/plugin_deregister_test.go
+++ b/command/plugin_deregister_test.go
@@ -7,10 +7,10 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
"github.com/hashicorp/vault/sdk/helper/consts"
- "github.com/mitchellh/cli"
)
func testPluginDeregisterCommand(tb testing.TB) (*cli.MockUi, *PluginDeregisterCommand) {
diff --git a/command/plugin_info.go b/command/plugin_info.go
index 0211555027e2..e47a23c66519 100644
--- a/command/plugin_info.go
+++ b/command/plugin_info.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/plugin_info_test.go b/command/plugin_info_test.go
index 3ffaa6972010..f0e66d8be52c 100644
--- a/command/plugin_info_test.go
+++ b/command/plugin_info_test.go
@@ -7,11 +7,11 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
"github.com/hashicorp/vault/helper/versions"
"github.com/hashicorp/vault/sdk/helper/consts"
- "github.com/mitchellh/cli"
)
func testPluginInfoCommand(tb testing.TB) (*cli.MockUi, *PluginInfoCommand) {
diff --git a/command/plugin_list.go b/command/plugin_list.go
index a325264eaf9e..28714adf4f5b 100644
--- a/command/plugin_list.go
+++ b/command/plugin_list.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/plugin_list_test.go b/command/plugin_list_test.go
index 395167e45f12..4ad37868b2c9 100644
--- a/command/plugin_list_test.go
+++ b/command/plugin_list_test.go
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testPluginListCommand(tb testing.TB) (*cli.MockUi, *PluginListCommand) {
diff --git a/command/plugin_register.go b/command/plugin_register.go
index e8cb406b400d..d124b38b8917 100644
--- a/command/plugin_register.go
+++ b/command/plugin_register.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/plugin_register_test.go b/command/plugin_register_test.go
index e2c3ce3e7020..ed46a16caa35 100644
--- a/command/plugin_register_test.go
+++ b/command/plugin_register_test.go
@@ -11,10 +11,10 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
"github.com/hashicorp/vault/sdk/helper/consts"
- "github.com/mitchellh/cli"
)
func testPluginRegisterCommand(tb testing.TB) (*cli.MockUi, *PluginRegisterCommand) {
diff --git a/command/plugin_reload.go b/command/plugin_reload.go
index 22cd91275d16..57e32a57f14d 100644
--- a/command/plugin_reload.go
+++ b/command/plugin_reload.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/plugin_reload_status.go b/command/plugin_reload_status.go
index 83c8f8a86a91..c653955978aa 100644
--- a/command/plugin_reload_status.go
+++ b/command/plugin_reload_status.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/plugin_reload_test.go b/command/plugin_reload_test.go
index 7ae082ed840b..f3af275eb4af 100644
--- a/command/plugin_reload_test.go
+++ b/command/plugin_reload_test.go
@@ -7,9 +7,9 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
- "github.com/mitchellh/cli"
)
func testPluginReloadCommand(tb testing.TB) (*cli.MockUi, *PluginReloadCommand) {
diff --git a/command/plugin_runtime.go b/command/plugin_runtime.go
index 38781a724879..ce15bb31fdbf 100644
--- a/command/plugin_runtime.go
+++ b/command/plugin_runtime.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*PluginRuntimeCommand)(nil)
diff --git a/command/plugin_runtime_deregister.go b/command/plugin_runtime_deregister.go
index dfadc20a0972..47b790f2cc03 100644
--- a/command/plugin_runtime_deregister.go
+++ b/command/plugin_runtime_deregister.go
@@ -8,8 +8,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/plugin_runtime_deregister_test.go b/command/plugin_runtime_deregister_test.go
index 5cd411d5f700..1569fceb3f11 100644
--- a/command/plugin_runtime_deregister_test.go
+++ b/command/plugin_runtime_deregister_test.go
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testPluginRuntimeDeregisterCommand(tb testing.TB) (*cli.MockUi, *PluginRuntimeDeregisterCommand) {
diff --git a/command/plugin_runtime_info.go b/command/plugin_runtime_info.go
index b22af6c50119..22c95a233570 100644
--- a/command/plugin_runtime_info.go
+++ b/command/plugin_runtime_info.go
@@ -8,8 +8,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/plugin_runtime_info_test.go b/command/plugin_runtime_info_test.go
index cf1a5aee7c14..40166b094bf9 100644
--- a/command/plugin_runtime_info_test.go
+++ b/command/plugin_runtime_info_test.go
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testPluginRuntimeInfoCommand(tb testing.TB) (*cli.MockUi, *PluginRuntimeInfoCommand) {
diff --git a/command/plugin_runtime_list.go b/command/plugin_runtime_list.go
index 9fca07da6de6..64cca1805f63 100644
--- a/command/plugin_runtime_list.go
+++ b/command/plugin_runtime_list.go
@@ -8,8 +8,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/plugin_runtime_list_test.go b/command/plugin_runtime_list_test.go
index 50ba6a6112ad..cd67ece564ee 100644
--- a/command/plugin_runtime_list_test.go
+++ b/command/plugin_runtime_list_test.go
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testPluginRuntimeListCommand(tb testing.TB) (*cli.MockUi, *PluginRuntimeListCommand) {
diff --git a/command/plugin_runtime_register.go b/command/plugin_runtime_register.go
index d2bbaa65309a..175be302f519 100644
--- a/command/plugin_runtime_register.go
+++ b/command/plugin_runtime_register.go
@@ -8,8 +8,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/plugin_runtime_register_test.go b/command/plugin_runtime_register_test.go
index 74d520bf8ae4..3b28587cf62a 100644
--- a/command/plugin_runtime_register_test.go
+++ b/command/plugin_runtime_register_test.go
@@ -10,9 +10,9 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/sdk/helper/consts"
- "github.com/mitchellh/cli"
)
func testPluginRuntimeRegisterCommand(tb testing.TB) (*cli.MockUi, *PluginRuntimeRegisterCommand) {
diff --git a/command/policy.go b/command/policy.go
index 64fe14a75ebb..5e5f61bb2d72 100644
--- a/command/policy.go
+++ b/command/policy.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*PolicyCommand)(nil)
diff --git a/command/policy_delete.go b/command/policy_delete.go
index c4ee61059bd9..d5c3b8aabc11 100644
--- a/command/policy_delete.go
+++ b/command/policy_delete.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/policy_delete_test.go b/command/policy_delete_test.go
index 7c96d241571c..6b3bd01e3f32 100644
--- a/command/policy_delete_test.go
+++ b/command/policy_delete_test.go
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testPolicyDeleteCommand(tb testing.TB) (*cli.MockUi, *PolicyDeleteCommand) {
diff --git a/command/policy_fmt.go b/command/policy_fmt.go
index 219ce1f75b9f..ea3dd2ab9958 100644
--- a/command/policy_fmt.go
+++ b/command/policy_fmt.go
@@ -8,10 +8,10 @@ import (
"io/ioutil"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/hcl/hcl/printer"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/vault"
- "github.com/mitchellh/cli"
homedir "github.com/mitchellh/go-homedir"
"github.com/posener/complete"
)
diff --git a/command/policy_fmt_test.go b/command/policy_fmt_test.go
index 7830b2a034ce..41de53c9e6c8 100644
--- a/command/policy_fmt_test.go
+++ b/command/policy_fmt_test.go
@@ -9,7 +9,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testPolicyFmtCommand(tb testing.TB) (*cli.MockUi, *PolicyFmtCommand) {
diff --git a/command/policy_list.go b/command/policy_list.go
index 3800b584627a..147efb971672 100644
--- a/command/policy_list.go
+++ b/command/policy_list.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/policy_list_test.go b/command/policy_list_test.go
index 0626f3a1b678..c603d310fcd2 100644
--- a/command/policy_list_test.go
+++ b/command/policy_list_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testPolicyListCommand(tb testing.TB) (*cli.MockUi, *PolicyListCommand) {
diff --git a/command/policy_read.go b/command/policy_read.go
index d8b749ee784c..dd7a698de65c 100644
--- a/command/policy_read.go
+++ b/command/policy_read.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/policy_read_test.go b/command/policy_read_test.go
index 84ec9f9cf64b..e18298e5115e 100644
--- a/command/policy_read_test.go
+++ b/command/policy_read_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testPolicyReadCommand(tb testing.TB) (*cli.MockUi, *PolicyReadCommand) {
diff --git a/command/policy_write.go b/command/policy_write.go
index d4b5256b0cac..193c94968809 100644
--- a/command/policy_write.go
+++ b/command/policy_write.go
@@ -10,7 +10,7 @@ import (
"os"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/policy_write_test.go b/command/policy_write_test.go
index 57ace717ddab..64f67eb2a8b4 100644
--- a/command/policy_write_test.go
+++ b/command/policy_write_test.go
@@ -12,7 +12,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testPolicyWriteCommand(tb testing.TB) (*cli.MockUi, *PolicyWriteCommand) {
diff --git a/command/print.go b/command/print.go
index 72e653855c4e..d5e3b2a5529b 100644
--- a/command/print.go
+++ b/command/print.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/print_token.go b/command/print_token.go
index 904a41f240a2..9402e8a15238 100644
--- a/command/print_token.go
+++ b/command/print_token.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/proxy.go b/command/proxy.go
index 28753128ef96..89cc77d9835b 100644
--- a/command/proxy.go
+++ b/command/proxy.go
@@ -18,6 +18,7 @@ import (
"time"
systemd "github.com/coreos/go-systemd/daemon"
+ "github.com/hashicorp/cli"
ctconfig "github.com/hashicorp/consul-template/config"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-multierror"
@@ -42,7 +43,6 @@ import (
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/version"
"github.com/kr/pretty"
- "github.com/mitchellh/cli"
"github.com/oklog/run"
"github.com/posener/complete"
"golang.org/x/text/cases"
diff --git a/command/proxy_test.go b/command/proxy_test.go
index c8feb3e53e2d..391bee40a0ff 100644
--- a/command/proxy_test.go
+++ b/command/proxy_test.go
@@ -17,6 +17,7 @@ import (
"testing"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-hclog"
vaultjwt "github.com/hashicorp/vault-plugin-auth-jwt"
logicalKv "github.com/hashicorp/vault-plugin-secrets-kv"
@@ -30,7 +31,6 @@ import (
"github.com/hashicorp/vault/sdk/helper/logging"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault"
- "github.com/mitchellh/cli"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
diff --git a/command/read.go b/command/read.go
index c205718f89e7..742e03676381 100644
--- a/command/read.go
+++ b/command/read.go
@@ -10,7 +10,7 @@ import (
"os"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/read_test.go b/command/read_test.go
index 6f33a1ef2b74..fe8961afb669 100644
--- a/command/read_test.go
+++ b/command/read_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testReadCommand(tb testing.TB) (*cli.MockUi, *ReadCommand) {
diff --git a/command/rotate.go b/command/rotate.go
index 5ed97354c95d..2a17e41f9b5e 100644
--- a/command/rotate.go
+++ b/command/rotate.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/rotate_test.go b/command/rotate_test.go
index b591b5f73e15..927812934c3f 100644
--- a/command/rotate_test.go
+++ b/command/rotate_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testOperatorRotateCommand(tb testing.TB) (*cli.MockUi, *OperatorRotateCommand) {
diff --git a/command/secrets.go b/command/secrets.go
index f3a6d9074327..a205aae17443 100644
--- a/command/secrets.go
+++ b/command/secrets.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*SecretsCommand)(nil)
diff --git a/command/secrets_disable.go b/command/secrets_disable.go
index b99e3c7193ef..163af4a785c7 100644
--- a/command/secrets_disable.go
+++ b/command/secrets_disable.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/secrets_disable_test.go b/command/secrets_disable_test.go
index 40058ec2f0fa..253107136430 100644
--- a/command/secrets_disable_test.go
+++ b/command/secrets_disable_test.go
@@ -7,8 +7,8 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testSecretsDisableCommand(tb testing.TB) (*cli.MockUi, *SecretsDisableCommand) {
diff --git a/command/secrets_enable.go b/command/secrets_enable.go
index 2388234c5f4c..9e06392b2d39 100644
--- a/command/secrets_enable.go
+++ b/command/secrets_enable.go
@@ -10,8 +10,8 @@ import (
"strings"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/secrets_enable_test.go b/command/secrets_enable_test.go
index 488d25d369df..10fd0c5c9c80 100644
--- a/command/secrets_enable_test.go
+++ b/command/secrets_enable_test.go
@@ -13,10 +13,10 @@ import (
"github.com/go-test/deep"
"github.com/google/go-cmp/cmp"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/vault/helper/builtinplugins"
"github.com/hashicorp/vault/sdk/helper/consts"
- "github.com/mitchellh/cli"
)
func testSecretsEnableCommand(tb testing.TB) (*cli.MockUi, *SecretsEnableCommand) {
diff --git a/command/secrets_list.go b/command/secrets_list.go
index 7ce6dde457be..2819e2a1d390 100644
--- a/command/secrets_list.go
+++ b/command/secrets_list.go
@@ -9,8 +9,8 @@ import (
"strconv"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/secrets_list_test.go b/command/secrets_list_test.go
index 544e7196c8de..dcc51eb01892 100644
--- a/command/secrets_list_test.go
+++ b/command/secrets_list_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testSecretsListCommand(tb testing.TB) (*cli.MockUi, *SecretsListCommand) {
diff --git a/command/secrets_move.go b/command/secrets_move.go
index c3d8d730a7b2..bd4062969a49 100644
--- a/command/secrets_move.go
+++ b/command/secrets_move.go
@@ -8,7 +8,7 @@ import (
"strings"
"time"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/secrets_move_test.go b/command/secrets_move_test.go
index 6e7a0d796e54..ed7a5a5c629c 100644
--- a/command/secrets_move_test.go
+++ b/command/secrets_move_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testSecretsMoveCommand(tb testing.TB) (*cli.MockUi, *SecretsMoveCommand) {
diff --git a/command/secrets_tune.go b/command/secrets_tune.go
index eef9e577c2f4..7dcf3feb9293 100644
--- a/command/secrets_tune.go
+++ b/command/secrets_tune.go
@@ -10,8 +10,8 @@ import (
"strings"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/secrets_tune_test.go b/command/secrets_tune_test.go
index 8146dec92467..5c1670db92d7 100644
--- a/command/secrets_tune_test.go
+++ b/command/secrets_tune_test.go
@@ -8,9 +8,9 @@ import (
"testing"
"github.com/go-test/deep"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
- "github.com/mitchellh/cli"
)
func testSecretsTuneCommand(tb testing.TB) (*cli.MockUi, *SecretsTuneCommand) {
diff --git a/command/server.go b/command/server.go
index 93604ccb03a5..0b760bd86646 100644
--- a/command/server.go
+++ b/command/server.go
@@ -27,6 +27,7 @@ import (
systemd "github.com/coreos/go-systemd/daemon"
"github.com/google/go-cmp/cmp"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-kms-wrapping/entropy/v2"
@@ -62,7 +63,6 @@ import (
"github.com/hashicorp/vault/vault/hcp_link"
vaultseal "github.com/hashicorp/vault/vault/seal"
"github.com/hashicorp/vault/version"
- "github.com/mitchellh/cli"
"github.com/mitchellh/go-testing-interface"
"github.com/posener/complete"
"github.com/sasha-s/go-deadlock"
diff --git a/command/server/listener.go b/command/server/listener.go
index 7e308a0ccb79..c003a6289dc1 100644
--- a/command/server/listener.go
+++ b/command/server/listener.go
@@ -12,10 +12,10 @@ import (
// We must import sha512 so that it registers with the runtime so that
// certificates that use it can be parsed.
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-secure-stdlib/reloadutil"
"github.com/hashicorp/vault/helper/proxyutil"
"github.com/hashicorp/vault/internalshared/configutil"
- "github.com/mitchellh/cli"
)
// ListenerFactory is the factory function to create a listener.
diff --git a/command/server/listener_tcp.go b/command/server/listener_tcp.go
index 11c145b3eec4..6c121ec403e2 100644
--- a/command/server/listener_tcp.go
+++ b/command/server/listener_tcp.go
@@ -12,10 +12,10 @@ import (
"strings"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-secure-stdlib/reloadutil"
"github.com/hashicorp/vault/internalshared/configutil"
"github.com/hashicorp/vault/internalshared/listenerutil"
- "github.com/mitchellh/cli"
)
func tcpListenerFactory(l *configutil.Listener, _ io.Writer, ui cli.Ui) (net.Listener, map[string]string, reloadutil.ReloadFunc, error) {
diff --git a/command/server/listener_tcp_test.go b/command/server/listener_tcp_test.go
index fe96548317fe..42da6c0d21a6 100644
--- a/command/server/listener_tcp_test.go
+++ b/command/server/listener_tcp_test.go
@@ -14,9 +14,9 @@ import (
"testing"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-sockaddr"
"github.com/hashicorp/vault/internalshared/configutil"
- "github.com/mitchellh/cli"
"github.com/pires/go-proxyproto"
)
diff --git a/command/server/listener_unix.go b/command/server/listener_unix.go
index 0b70a046935d..35306d166699 100644
--- a/command/server/listener_unix.go
+++ b/command/server/listener_unix.go
@@ -7,10 +7,10 @@ import (
"io"
"net"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-secure-stdlib/reloadutil"
"github.com/hashicorp/vault/internalshared/configutil"
"github.com/hashicorp/vault/internalshared/listenerutil"
- "github.com/mitchellh/cli"
)
func unixListenerFactory(l *configutil.Listener, _ io.Writer, ui cli.Ui) (net.Listener, map[string]string, reloadutil.ReloadFunc, error) {
diff --git a/command/server/listener_unix_test.go b/command/server/listener_unix_test.go
index 9d156bbc1350..72f21bb471cd 100644
--- a/command/server/listener_unix_test.go
+++ b/command/server/listener_unix_test.go
@@ -8,8 +8,8 @@ import (
"path/filepath"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/internalshared/configutil"
- "github.com/mitchellh/cli"
)
func TestUnixListener(t *testing.T) {
diff --git a/command/server_test.go b/command/server_test.go
index 62e2a99e2ac6..e46d5bedba3f 100644
--- a/command/server_test.go
+++ b/command/server_test.go
@@ -22,6 +22,7 @@ import (
"testing"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/command/server"
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
"github.com/hashicorp/vault/internalshared/configutil"
@@ -29,7 +30,6 @@ import (
physInmem "github.com/hashicorp/vault/sdk/physical/inmem"
"github.com/hashicorp/vault/vault"
"github.com/hashicorp/vault/vault/seal"
- "github.com/mitchellh/cli"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
diff --git a/command/ssh.go b/command/ssh.go
index edc8b4cd6637..cd39ad45782d 100644
--- a/command/ssh.go
+++ b/command/ssh.go
@@ -14,9 +14,9 @@ import (
"strings"
"syscall"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/builtin/logical/ssh"
- "github.com/mitchellh/cli"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/posener/complete"
diff --git a/command/ssh_test.go b/command/ssh_test.go
index 32f16f79e6e5..b6dfd563d242 100644
--- a/command/ssh_test.go
+++ b/command/ssh_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testSSHCommand(tb testing.TB) (*cli.MockUi, *SSHCommand) {
diff --git a/command/status.go b/command/status.go
index 5a979e7c7780..9f7c7010f86d 100644
--- a/command/status.go
+++ b/command/status.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/status_test.go b/command/status_test.go
index b423edb6840a..47a2803d66cb 100644
--- a/command/status_test.go
+++ b/command/status_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testStatusCommand(tb testing.TB) (*cli.MockUi, *StatusCommand) {
diff --git a/command/token.go b/command/token.go
index 5ccec004a885..eb430b48daa0 100644
--- a/command/token.go
+++ b/command/token.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*TokenCommand)(nil)
diff --git a/command/token/testing.go b/command/token/testing.go
index acfc84338e7a..24dc3258e511 100644
--- a/command/token/testing.go
+++ b/command/token/testing.go
@@ -9,7 +9,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
// Test is a public function that can be used in other tests to
diff --git a/command/token_capabilities.go b/command/token_capabilities.go
index 246619011f74..fc149b9611f7 100644
--- a/command/token_capabilities.go
+++ b/command/token_capabilities.go
@@ -8,7 +8,7 @@ import (
"sort"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/token_capabilities_test.go b/command/token_capabilities_test.go
index 6dffae53f58d..a3e5b9525a7f 100644
--- a/command/token_capabilities_test.go
+++ b/command/token_capabilities_test.go
@@ -7,8 +7,8 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testTokenCapabilitiesCommand(tb testing.TB) (*cli.MockUi, *TokenCapabilitiesCommand) {
diff --git a/command/token_create.go b/command/token_create.go
index 56e182b73903..3e49bb2ca72b 100644
--- a/command/token_create.go
+++ b/command/token_create.go
@@ -8,8 +8,8 @@ import (
"strings"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/token_create_test.go b/command/token_create_test.go
index 9991afb3625a..3acd2dd1474e 100644
--- a/command/token_create_test.go
+++ b/command/token_create_test.go
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testTokenCreateCommand(tb testing.TB) (*cli.MockUi, *TokenCreateCommand) {
diff --git a/command/token_lookup.go b/command/token_lookup.go
index 78bfd0f98f2e..afb622372b1e 100644
--- a/command/token_lookup.go
+++ b/command/token_lookup.go
@@ -7,8 +7,8 @@ import (
"fmt"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/token_lookup_test.go b/command/token_lookup_test.go
index db6807300e66..6a351f781c5a 100644
--- a/command/token_lookup_test.go
+++ b/command/token_lookup_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testTokenLookupCommand(tb testing.TB) (*cli.MockUi, *TokenLookupCommand) {
diff --git a/command/token_renew.go b/command/token_renew.go
index 488ff76364bf..c354b4e6a506 100644
--- a/command/token_renew.go
+++ b/command/token_renew.go
@@ -8,8 +8,8 @@ import (
"strings"
"time"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/token_renew_test.go b/command/token_renew_test.go
index 70ec46e99e4b..4fc469995b05 100644
--- a/command/token_renew_test.go
+++ b/command/token_renew_test.go
@@ -9,7 +9,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testTokenRenewCommand(tb testing.TB) (*cli.MockUi, *TokenRenewCommand) {
diff --git a/command/token_revoke.go b/command/token_revoke.go
index 0aa9d0abd851..c9f6a2b7f22f 100644
--- a/command/token_revoke.go
+++ b/command/token_revoke.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/token_revoke_test.go b/command/token_revoke_test.go
index 70aa8a08c6a1..3cdf13d615e8 100644
--- a/command/token_revoke_test.go
+++ b/command/token_revoke_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
func testTokenRevokeCommand(tb testing.TB) (*cli.MockUi, *TokenRevokeCommand) {
diff --git a/command/transform.go b/command/transform.go
index a85229bddbf4..46129cd32e29 100644
--- a/command/transform.go
+++ b/command/transform.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*TransformCommand)(nil)
diff --git a/command/transform_import_key.go b/command/transform_import_key.go
index e582abd28ac3..d01100acea04 100644
--- a/command/transform_import_key.go
+++ b/command/transform_import_key.go
@@ -8,7 +8,7 @@ import (
"regexp"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/transform_import_key_version.go b/command/transform_import_key_version.go
index 38e677b30b05..61a6db45b674 100644
--- a/command/transform_import_key_version.go
+++ b/command/transform_import_key_version.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/transit.go b/command/transit.go
index a74ff505881c..9b988d7e3c70 100644
--- a/command/transit.go
+++ b/command/transit.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
)
var _ cli.Command = (*TransitCommand)(nil)
diff --git a/command/transit_import_key.go b/command/transit_import_key.go
index d8dd60b07492..350821b07612 100644
--- a/command/transit_import_key.go
+++ b/command/transit_import_key.go
@@ -20,7 +20,7 @@ import (
"github.com/google/tink/go/kwp/subtle"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/transit_import_key_version.go b/command/transit_import_key_version.go
index 364481fd36ae..cf248554f779 100644
--- a/command/transit_import_key_version.go
+++ b/command/transit_import_key_version.go
@@ -6,7 +6,7 @@ package command
import (
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/unwrap.go b/command/unwrap.go
index f852845cfb58..a671071c15a0 100644
--- a/command/unwrap.go
+++ b/command/unwrap.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
)
diff --git a/command/unwrap_test.go b/command/unwrap_test.go
index 41b03095ab27..518d32fb12d6 100644
--- a/command/unwrap_test.go
+++ b/command/unwrap_test.go
@@ -7,8 +7,8 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testUnwrapCommand(tb testing.TB) (*cli.MockUi, *UnwrapCommand) {
diff --git a/command/util.go b/command/util.go
index 0ace16191477..717191025d24 100644
--- a/command/util.go
+++ b/command/util.go
@@ -12,11 +12,11 @@ import (
"time"
"github.com/fatih/color"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/command/config"
"github.com/hashicorp/vault/command/token"
- "github.com/mitchellh/cli"
)
// DefaultTokenHelper returns the token helper that is configured for Vault.
diff --git a/command/version.go b/command/version.go
index 1e3dce16a759..8b54511c099a 100644
--- a/command/version.go
+++ b/command/version.go
@@ -6,8 +6,8 @@ package command
import (
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/version"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/version_history.go b/command/version_history.go
index 8f7fe1318d93..7326bffdeddf 100644
--- a/command/version_history.go
+++ b/command/version_history.go
@@ -7,7 +7,7 @@ import (
"fmt"
"strings"
- "github.com/mitchellh/cli"
+ "github.com/hashicorp/cli"
"github.com/posener/complete"
"github.com/ryanuber/columnize"
)
diff --git a/command/version_history_test.go b/command/version_history_test.go
index b6467b8fcb97..8d2e18445107 100644
--- a/command/version_history_test.go
+++ b/command/version_history_test.go
@@ -9,8 +9,8 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/version"
- "github.com/mitchellh/cli"
)
func testVersionHistoryCommand(tb testing.TB) (*cli.MockUi, *VersionHistoryCommand) {
diff --git a/command/version_test.go b/command/version_test.go
index be40377c1c75..abacfd3662c0 100644
--- a/command/version_test.go
+++ b/command/version_test.go
@@ -7,8 +7,8 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/version"
- "github.com/mitchellh/cli"
)
func testVersionCommand(tb testing.TB) (*cli.MockUi, *VersionCommand) {
diff --git a/command/write.go b/command/write.go
index cd3301b8f274..33ee3be0f242 100644
--- a/command/write.go
+++ b/command/write.go
@@ -9,8 +9,8 @@ import (
"os"
"strings"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
"github.com/posener/complete"
)
diff --git a/command/write_test.go b/command/write_test.go
index 24521311ba42..2e7a32833fa1 100644
--- a/command/write_test.go
+++ b/command/write_test.go
@@ -8,8 +8,8 @@ import (
"strings"
"testing"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/vault/api"
- "github.com/mitchellh/cli"
)
func testWriteCommand(tb testing.TB) (*cli.MockUi, *WriteCommand) {
diff --git a/go.mod b/go.mod
index 47b75c30ae6b..8cf6506e5829 100644
--- a/go.mod
+++ b/go.mod
@@ -55,7 +55,7 @@ require (
github.com/denisenkom/go-mssqldb v0.12.3
github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74
github.com/dustin/go-humanize v1.0.1
- github.com/fatih/color v1.15.0
+ github.com/fatih/color v1.16.0
github.com/fatih/structs v1.1.0
github.com/favadi/protoc-go-inject-tag v1.4.0
github.com/gammazero/workerpool v1.1.3
@@ -78,6 +78,7 @@ require (
github.com/hashicorp-forge/bbolt v1.3.8-hc3
github.com/hashicorp/cap v0.3.4
github.com/hashicorp/cap/ldap v0.0.0-20230914221201-c4eecc7e31f7
+ github.com/hashicorp/cli v1.1.6
github.com/hashicorp/consul-template v0.33.0
github.com/hashicorp/consul/api v1.23.0
github.com/hashicorp/errwrap v1.1.0
@@ -171,11 +172,10 @@ require (
github.com/kr/pretty v0.3.1
github.com/kr/text v0.2.0
github.com/mattn/go-colorable v0.1.13
- github.com/mattn/go-isatty v0.0.19
+ github.com/mattn/go-isatty v0.0.20
github.com/mholt/archiver/v3 v3.5.1
github.com/michaelklishin/rabbit-hole/v2 v2.12.0
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a
- github.com/mitchellh/cli v1.1.5
github.com/mitchellh/copystructure v1.2.0
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/go-testing-interface v1.14.1
@@ -220,7 +220,7 @@ require (
golang.org/x/net v0.17.0
golang.org/x/oauth2 v0.11.0
golang.org/x/sync v0.3.0
- golang.org/x/sys v0.13.0
+ golang.org/x/sys v0.14.0
golang.org/x/term v0.13.0
golang.org/x/text v0.13.0
golang.org/x/tools v0.10.0
diff --git a/go.sum b/go.sum
index deed96295782..b792c5584466 100644
--- a/go.sum
+++ b/go.sum
@@ -1046,7 +1046,6 @@ github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
-github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
@@ -1620,8 +1619,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
-github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
-github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
+github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
+github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/favadi/protoc-go-inject-tag v1.4.0 h1:K3KXxbgRw5WT4f43LbglARGz/8jVsDOS7uMjG4oNvXY=
@@ -2131,6 +2130,8 @@ github.com/hashicorp/cap v0.3.4 h1:RoqWYqr6LaDLuvnBCpod1sZtvuEhehIhu0GncmoHW40=
github.com/hashicorp/cap v0.3.4/go.mod h1:dHTmyMIVbzT981XxRoci5G//dfWmd/HhuNiCH6J5+IA=
github.com/hashicorp/cap/ldap v0.0.0-20230914221201-c4eecc7e31f7 h1:jgVdtp5YMn++PxnYhAFfrURfLf+nlqzBeddbvRG+tTg=
github.com/hashicorp/cap/ldap v0.0.0-20230914221201-c4eecc7e31f7/go.mod h1:q+c9XV1VqloZFZMu+zdvfb0cm7UrvKbvtmTF5wX5Q9o=
+github.com/hashicorp/cli v1.1.6 h1:CMOV+/LJfL1tXCOKrgAX0uRKnzjj/mpmqNXloRSy2K8=
+github.com/hashicorp/cli v1.1.6/go.mod h1:MPon5QYlgjjo0BSoAiN0ESeT5fRzDjVRp+uioJ0piz4=
github.com/hashicorp/consul-template v0.33.0 h1:UNyf7V/nFeh8edh5X6pP8f+9LZVn+DG9uNLLcTpLsFc=
github.com/hashicorp/consul-template v0.33.0/go.mod h1:3RayddSLvOGQwdifbbe4doVwamgJU4QvxTtf5DNeclw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
@@ -2376,8 +2377,6 @@ github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKe
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
@@ -2643,8 +2642,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
-github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
@@ -2701,8 +2700,6 @@ github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
-github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng=
-github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
@@ -3446,10 +3443,8 @@ golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
@@ -3873,8 +3868,9 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
+golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
diff --git a/internalshared/configutil/telemetry.go b/internalshared/configutil/telemetry.go
index e10812276f23..964e03f0b9c8 100644
--- a/internalshared/configutil/telemetry.go
+++ b/internalshared/configutil/telemetry.go
@@ -18,11 +18,11 @@ import (
"github.com/armon/go-metrics/prometheus"
stackdriver "github.com/google/go-metrics-stackdriver"
stackdrivervault "github.com/google/go-metrics-stackdriver/vault"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/hcl"
"github.com/hashicorp/hcl/hcl/ast"
"github.com/hashicorp/vault/helper/metricsutil"
- "github.com/mitchellh/cli"
"google.golang.org/api/option"
)
diff --git a/internalshared/listenerutil/listener.go b/internalshared/listenerutil/listener.go
index 76b80860e4fd..1f8afe717650 100644
--- a/internalshared/listenerutil/listener.go
+++ b/internalshared/listenerutil/listener.go
@@ -13,12 +13,12 @@ import (
osuser "os/user"
"strconv"
+ "github.com/hashicorp/cli"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/go-secure-stdlib/reloadutil"
"github.com/hashicorp/go-secure-stdlib/tlsutil"
"github.com/hashicorp/vault/internalshared/configutil"
"github.com/jefferai/isbadcipher"
- "github.com/mitchellh/cli"
)
type Listener struct {
From e3aa18c7f7f1952d05d2044bf9b1191a5e016ee6 Mon Sep 17 00:00:00 2001
From: Scott Miller
Date: Mon, 4 Dec 2023 13:31:05 -0600
Subject: [PATCH 64/74] Make it possible to skip the seal re-wrap in progress
check (#24351)
---
vault/seal/seal.go | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/vault/seal/seal.go b/vault/seal/seal.go
index cd49f052edc4..5d3c41c3dd73 100644
--- a/vault/seal/seal.go
+++ b/vault/seal/seal.go
@@ -8,21 +8,19 @@ import (
"encoding/json"
"errors"
"fmt"
+ "os"
"reflect"
"sort"
"strings"
"sync/atomic"
"time"
+ metrics "github.com/armon/go-metrics"
"github.com/google/go-cmp/cmp"
-
"github.com/hashicorp/go-hclog"
-
- "github.com/hashicorp/vault/internalshared/configutil"
-
- metrics "github.com/armon/go-metrics"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/go-kms-wrapping/v2/aead"
+ "github.com/hashicorp/vault/internalshared/configutil"
)
type StoredKeysSupport int
@@ -102,7 +100,7 @@ func (sgi *SealGenerationInfo) Validate(existingSgi *SealGenerationInfo, hasPart
}
}
- if !previousShamirConfigured && (!existingSgi.IsRewrapped() || hasPartiallyWrappedPaths) {
+ if !previousShamirConfigured && (!existingSgi.IsRewrapped() || hasPartiallyWrappedPaths) && os.Getenv("VAULT_SEAL_REWRAP_SAFETY") != "disable" {
return errors.New("cannot make seal config changes while seal re-wrap is in progress, please revert any seal configuration changes")
}
From cb217388d463c2514a96f48dc11d5587fd257e02 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
Date: Mon, 4 Dec 2023 14:28:16 -0600
Subject: [PATCH 65/74] UI: handle reduced disclosure endpoints (#24262)
* Create app-footer component with tests
* glimmerize vault route + controller
* Add dev mode badge to new footer
* Fix version on dashboard
* update app-footer tests
* update version title component
* Handle case for chroot namespace fail on health check
* cleanup
* fix ent tests
* add missing headers
* extra version fetch on login success, clear version on logout and seal
* Add coverage for clearing version on seal
* rename isOSS to isCommunity
* remove is-version helper
* test version in footer on unseal flow
* fix enterprise test
* VAULT-21399 test coverage
* VAULT-21400 test coverage
---
ui/app/adapters/cluster.js | 12 +-
ui/app/components/app-footer.hbs | 31 ++++
ui/app/components/app-footer.js | 16 ++
.../dashboard/vault-version-title.js | 9 +-
ui/app/components/logo-edition.hbs | 2 +-
ui/app/controllers/vault.js | 17 +--
ui/app/controllers/vault/cluster/auth.js | 4 +-
.../vault/cluster/settings/seal.js | 6 +-
ui/app/controllers/vault/cluster/unseal.js | 4 +-
ui/app/routes/vault.js | 27 ++--
ui/app/routes/vault/cluster.js | 3 +-
ui/app/routes/vault/cluster/license.js | 5 +-
ui/app/routes/vault/cluster/logout.js | 2 +
ui/app/routes/vault/cluster/policies/index.js | 2 +-
ui/app/services/control-group.js | 4 +-
ui/app/services/version.js | 45 ++++--
ui/app/styles/components/env-banner.scss | 6 +-
.../dashboard/vault-version-title.hbs | 3 +-
ui/app/templates/vault.hbs | 26 +---
ui/lib/core/addon/helpers/is-version.js | 24 ---
ui/lib/core/app/helpers/is-version.js | 6 -
ui/mirage/handlers/base.js | 1 +
.../enterprise-license-banner-test.js | 1 +
.../enterprise-reduced-disclosure-test.js | 137 ++++++++++++++++++
.../acceptance/enterprise-sidebar-nav-test.js | 1 -
.../integration/components/app-footer-test.js | 47 ++++++
.../components/dashboard/overview-test.js | 4 +
.../components/license-banners-test.js | 1 +
.../components/link-status-test.js | 5 +-
.../mount-backend/type-form-test.js | 2 +-
.../page/pki-configuration-details-test.js | 4 +-
.../pki/page/pki-configuration-edit-test.js | 4 +-
.../components/pki/pki-tidy-form-test.js | 6 +-
.../components/sidebar/frame-test.js | 2 +-
ui/tests/pages/auth.js | 4 +-
ui/tests/unit/adapters/kv/data-test.js | 2 +-
ui/tests/unit/services/control-group-test.js | 21 +--
ui/tests/unit/services/version-test.js | 19 +--
38 files changed, 359 insertions(+), 156 deletions(-)
create mode 100644 ui/app/components/app-footer.hbs
create mode 100644 ui/app/components/app-footer.js
delete mode 100644 ui/lib/core/addon/helpers/is-version.js
delete mode 100644 ui/lib/core/app/helpers/is-version.js
create mode 100644 ui/tests/acceptance/enterprise-reduced-disclosure-test.js
create mode 100644 ui/tests/integration/components/app-footer-test.js
diff --git a/ui/app/adapters/cluster.js b/ui/app/adapters/cluster.js
index 7469e062cdff..131d143e84cd 100644
--- a/ui/app/adapters/cluster.js
+++ b/ui/app/adapters/cluster.js
@@ -5,7 +5,6 @@
import AdapterError from '@ember-data/adapter/error';
import { inject as service } from '@ember/service';
-import { assign } from '@ember/polyfills';
import { hash, resolve } from 'rsvp';
import { assert } from '@ember/debug';
import { pluralize } from 'ember-inflector';
@@ -22,6 +21,7 @@ const ENDPOINTS = [
'init',
'capabilities-self',
'license',
+ 'internal/ui/version',
];
const REPLICATION_ENDPOINTS = {
@@ -55,12 +55,12 @@ export default ApplicationAdapter.extend({
id,
name: snapshot.attr('name'),
};
- ret = assign(ret, health);
+ ret = Object.assign(ret, health);
if (sealStatus instanceof AdapterError === false) {
- ret = assign(ret, { nodes: [sealStatus] });
+ ret = Object.assign(ret, { nodes: [sealStatus] });
}
if (replicationStatus && replicationStatus instanceof AdapterError === false) {
- ret = assign(ret, replicationStatus.data);
+ ret = Object.assign(ret, replicationStatus.data);
}
return resolve(ret);
});
@@ -94,6 +94,10 @@ export default ApplicationAdapter.extend({
});
},
+ fetchVersion() {
+ return this.ajax(`${this.urlFor('internal/ui/version')}`, 'GET').catch(() => ({}));
+ },
+
sealStatus() {
return this.ajax(this.urlFor('seal-status'), 'GET', { unauthenticated: true });
},
diff --git a/ui/app/components/app-footer.hbs b/ui/app/components/app-footer.hbs
new file mode 100644
index 000000000000..616feb27d332
--- /dev/null
+++ b/ui/app/components/app-footer.hbs
@@ -0,0 +1,31 @@
+{{!
+ Copyright (c) HashiCorp, Inc.
+ SPDX-License-Identifier: BUSL-1.1
+~}}
+
+
+
+ {{#if this.isDevelopment}}
+
+
+
+ Local development
+
+
+
+ {{/if}}
+
+
+ Vault
+ {{this.version.version}}
+
+ {{#if this.version.isCommunity}}
+
+ Upgrade to Vault Enterprise
+
+ {{/if}}
+
+ Documentation
+
+
+
\ No newline at end of file
diff --git a/ui/app/components/app-footer.js b/ui/app/components/app-footer.js
new file mode 100644
index 000000000000..2a64928d1d67
--- /dev/null
+++ b/ui/app/components/app-footer.js
@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+import { service } from '@ember/service';
+import Component from '@glimmer/component';
+import ENV from 'vault/config/environment';
+
+export default class AppFooterComponent extends Component {
+ @service version;
+
+ get isDevelopment() {
+ return ENV.environment === 'development';
+ }
+}
diff --git a/ui/app/components/dashboard/vault-version-title.js b/ui/app/components/dashboard/vault-version-title.js
index 1462844740ac..5c5cd075569d 100644
--- a/ui/app/components/dashboard/vault-version-title.js
+++ b/ui/app/components/dashboard/vault-version-title.js
@@ -12,17 +12,10 @@ import { inject as service } from '@ember/service';
*
* @example
* ```js
- *
+ *
* ```
*/
export default class DashboardVaultVersionTitle extends Component {
- @service version;
@service namespace;
-
- get versionHeader() {
- return this.version.isEnterprise
- ? `Vault v${this.version.version.slice(0, this.version.version.indexOf('+'))}`
- : `Vault v${this.version.version}`;
- }
}
diff --git a/ui/app/components/logo-edition.hbs b/ui/app/components/logo-edition.hbs
index 4c2651f6bff3..b57e23451980 100644
--- a/ui/app/components/logo-edition.hbs
+++ b/ui/app/components/logo-edition.hbs
@@ -15,7 +15,7 @@
d="M69.7218638,30.2482468 L63.2587814,8.45301543 L58,8.45301543 L65.9885305,34.6072931 L73.4551971,34.6072931 L81.4437276,8.45301543 L76.1849462,8.45301543 L69.7218638,30.2482468 Z M97.6329749,22.0014025 C97.6329749,17.2103787 95.8265233,15.0897616 89.6845878,15.0897616 C87.5168459,15.0897616 84.8272401,15.4431978 82.9806452,15.9929874 L83.5827957,19.6451613 C85.3089606,19.2917251 87.2358423,19.056101 89.0021505,19.056101 C92.1333333,19.056101 92.7354839,19.802244 92.7354839,21.9228612 L92.7354839,23.9256662 L88.0387097,23.9256662 C84.0645161,23.9256662 82.3383513,25.4179523 82.3383513,29.3057504 C82.3383513,32.6044881 83.8637993,35 87.4365591,35 C89.4035842,35 91.4910394,34.4502104 93.2573477,33.3113604 L93.618638,34.6072931 L97.6329749,34.6072931 L97.6329749,22.0014025 Z M92.7354839,30.2089762 C91.8121864,30.7194951 90.4874552,31.1907433 89.0422939,31.1907433 C87.5168459,31.1907433 87.0752688,30.601683 87.0752688,29.2664797 C87.0752688,27.8134642 87.5168459,27.3814867 89.1225806,27.3814867 L92.7354839,27.3814867 L92.7354839,30.2089762 Z M102.421505,15.4824684 L102.421505,29.345021 C102.421505,32.7615708 103.585663,35 106.837276,35 C109.125448,35 112.216487,34.1753156 114.665233,32.997195 L115.146953,34.6072931 L118.880287,34.6072931 L118.880287,15.4824684 L113.982796,15.4824684 L113.982796,28.7559607 C112.216487,29.6591865 110.088889,30.3660589 108.884588,30.3660589 C107.760573,30.3660589 107.318996,29.85554 107.318996,28.8345021 L107.318996,15.4824684 L102.421505,15.4824684 Z M129.168459,34.6072931 L129.168459,7 L124.270968,7.66760168 L124.270968,34.6072931 L129.168459,34.6072931 Z M144.394265,30.601683 C143.551254,30.8373072 142.6681,30.9943899 141.94552,30.9943899 C140.660932,30.9943899 140.179211,30.3267882 140.179211,29.3057504 L140.179211,19.2917251 L144.875986,19.2917251 L145.197133,15.4824684 L140.179211,15.4824684 L140.179211,10.0631136 L135.28172,10.7307153 L135.28172,15.4824684 L132.351254,15.4824684 L132.351254,19.2917251 L135.28172,19.2917251 L135.28172,29.9340813 C135.28172,33.3506311 137.088172,35 140.660932,35 C141.905376,35 143.912545,34.6858345 144.956272,34.2538569 L144.394265,30.601683 Z"
>
- {{#if (is-version "Enterprise")}}
+ {{#if this.version.isEnterprise}}
{
this.model.cluster.get('leaderNode').set('sealed', true);
this.auth.deleteCurrentToken();
- return this.transitionToRoute('vault.cluster.unseal');
+ // Reset version so it doesn't show on footer
+ this.version.version = null;
+ return this.router.transitionTo('vault.cluster.unseal');
});
},
},
diff --git a/ui/app/controllers/vault/cluster/unseal.js b/ui/app/controllers/vault/cluster/unseal.js
index 4441493c8969..c01f8ce00627 100644
--- a/ui/app/controllers/vault/cluster/unseal.js
+++ b/ui/app/controllers/vault/cluster/unseal.js
@@ -4,14 +4,16 @@
*/
import Controller from '@ember/controller';
+import { inject as service } from '@ember/service';
export default Controller.extend({
+ router: service(),
showLicenseError: false,
actions: {
transitionToCluster() {
return this.model.reload().then(() => {
- return this.transitionToRoute('vault.cluster', this.model.name);
+ return this.router.transitionTo('vault.cluster', this.model.name);
});
},
diff --git a/ui/app/routes/vault.js b/ui/app/routes/vault.js
index bc67466c3ae1..f71dc7c3943b 100644
--- a/ui/app/routes/vault.js
+++ b/ui/app/routes/vault.js
@@ -8,18 +8,21 @@ import { Promise } from 'rsvp';
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import Ember from 'ember';
-/* eslint-disable ember/no-ember-testing-in-module-scope */
-const SPLASH_DELAY = Ember.testing ? 0 : 300;
-export default Route.extend({
- store: service(),
- version: service(),
+const SPLASH_DELAY = 300;
+
+export default class VaultRoute extends Route {
+ @service router;
+ @service store;
+ @service version;
beforeModel() {
- return this.version.fetchVersion();
- },
+ // So we can know what type (Enterprise/Community) we're running
+ return this.version.fetchType();
+ }
model() {
+ const delay = Ember.testing ? 0 : SPLASH_DELAY;
// hardcode single cluster
const fixture = {
data: {
@@ -34,13 +37,13 @@ export default Route.extend({
return new Promise((resolve) => {
later(() => {
resolve(this.store.peekAll('cluster'));
- }, SPLASH_DELAY);
+ }, delay);
});
- },
+ }
redirect(model, transition) {
if (model.get('length') === 1 && transition.targetName === 'vault.index') {
- return this.transitionTo('vault.cluster', model.get('firstObject.name'));
+ return this.router.transitionTo('vault.cluster', model.get('firstObject.name'));
}
- },
-});
+ }
+}
diff --git a/ui/app/routes/vault/cluster.js b/ui/app/routes/vault/cluster.js
index 2908592c21bf..7d55d33b90ad 100644
--- a/ui/app/routes/vault/cluster.js
+++ b/ui/app/routes/vault/cluster.js
@@ -58,7 +58,7 @@ export default Route.extend(ModelBoundaryRoute, ClusterRoute, {
const managedRoot = this.featureFlagService.managedNamespaceRoot;
assert(
'Cannot use VAULT_CLOUD_ADMIN_NAMESPACE flag with non-enterprise Vault version',
- !(managedRoot && this.version.isOSS)
+ !(managedRoot && this.version.isCommunity)
);
if (!namespace && currentTokenName && !Ember.testing) {
// if no namespace queryParam and user authenticated,
@@ -80,6 +80,7 @@ export default Route.extend(ModelBoundaryRoute, ClusterRoute, {
if (id) {
this.auth.setCluster(id);
if (this.auth.currentToken) {
+ this.version.fetchVersion();
await this.permissions.getPaths.perform();
}
return this.version.fetchFeatures();
diff --git a/ui/app/routes/vault/cluster/license.js b/ui/app/routes/vault/cluster/license.js
index 33682c5334bc..66e219523c78 100644
--- a/ui/app/routes/vault/cluster/license.js
+++ b/ui/app/routes/vault/cluster/license.js
@@ -10,10 +10,11 @@ import { inject as service } from '@ember/service';
export default Route.extend(ClusterRoute, {
store: service(),
version: service(),
+ router: service(),
beforeModel() {
- if (this.version.isOSS) {
- this.transitionTo('vault.cluster');
+ if (this.version.isCommunity) {
+ this.router.transitionTo('vault.cluster');
}
},
diff --git a/ui/app/routes/vault/cluster/logout.js b/ui/app/routes/vault/cluster/logout.js
index b7b71016081f..8fa567ada49c 100644
--- a/ui/app/routes/vault/cluster/logout.js
+++ b/ui/app/routes/vault/cluster/logout.js
@@ -17,6 +17,7 @@ export default Route.extend(ModelBoundaryRoute, {
permissions: service(),
namespaceService: service('namespace'),
router: service(),
+ version: service(),
modelTypes: computed(function () {
return ['secret', 'secret-engine'];
@@ -32,6 +33,7 @@ export default Route.extend(ModelBoundaryRoute, {
this.console.clearLog(true);
this.flashMessages.clearMessages();
this.permissions.reset();
+ this.version.version = null;
queryParams.with = authType;
if (ns) {
diff --git a/ui/app/routes/vault/cluster/policies/index.js b/ui/app/routes/vault/cluster/policies/index.js
index a983115827c7..1a3a8b167bb0 100644
--- a/ui/app/routes/vault/cluster/policies/index.js
+++ b/ui/app/routes/vault/cluster/policies/index.js
@@ -13,7 +13,7 @@ export default Route.extend(ClusterRoute, ListRoute, {
version: service(),
shouldReturnEmptyModel(policyType, version) {
- return policyType !== 'acl' && (version.get('isOSS') || !version.get('hasSentinel'));
+ return policyType !== 'acl' && (version.get('isCommunity') || !version.get('hasSentinel'));
},
model(params) {
diff --git a/ui/app/services/control-group.js b/ui/app/services/control-group.js
index 5713e6b27152..7ea218fbfbe9 100644
--- a/ui/app/services/control-group.js
+++ b/ui/app/services/control-group.js
@@ -73,7 +73,7 @@ export default Service.extend({
},
tokenForUrl(url) {
- if (this.version.isOSS) {
+ if (this.version.isCommunity) {
return null;
}
let pathForUrl = parseURL(url).pathname;
@@ -89,7 +89,7 @@ export default Service.extend({
checkForControlGroup(callbackArgs, response, wasWrapTTLRequested) {
const creationPath = response && response?.wrap_info?.creation_path;
if (
- this.version.isOSS ||
+ this.version.isCommunity ||
wasWrapTTLRequested ||
!response ||
(creationPath && WRAPPED_RESPONSE_PATHS.includes(creationPath)) ||
diff --git a/ui/app/services/version.js b/ui/app/services/version.js
index cf99b759c7a8..7e3c7a2278ce 100644
--- a/ui/app/services/version.js
+++ b/ui/app/services/version.js
@@ -11,7 +11,17 @@ export default class VersionService extends Service {
@service store;
@tracked features = [];
@tracked version = null;
+ @tracked type = null;
+ get isEnterprise() {
+ return this.type === 'enterprise';
+ }
+
+ get isCommunity() {
+ return !this.isEnterprise;
+ }
+
+ /* Features */
get hasPerfReplication() {
return this.features.includes('Performance Replication');
}
@@ -32,26 +42,35 @@ export default class VersionService extends Service {
return this.features.includes('Control Groups');
}
- get isEnterprise() {
- if (!this.version) return false;
- return this.version.includes('+');
+ get versionDisplay() {
+ if (!this.version) {
+ return '';
+ }
+ return this.isEnterprise ? `v${this.version.slice(0, this.version.indexOf('+'))}` : `v${this.version}`;
}
- get isOSS() {
- return !this.isEnterprise;
+ @task({ drop: true })
+ *getVersion() {
+ if (this.version) return;
+ const response = yield this.store.adapterFor('cluster').fetchVersion();
+ this.version = response.data?.version;
}
@task
- *getVersion() {
- if (this.version) return;
- const response = yield this.store.adapterFor('cluster').sealStatus();
- this.version = response.version;
- return;
+ *getType() {
+ if (this.type !== null) return;
+ const response = yield this.store.adapterFor('cluster').health();
+ if (response.has_chroot_namespace) {
+ // chroot_namespace feature is only available in enterprise
+ this.type = 'enterprise';
+ return;
+ }
+ this.type = response.enterprise ? 'enterprise' : 'community';
}
@keepLatestTask
*getFeatures() {
- if (this.features?.length || this.isOSS) {
+ if (this.features?.length || this.isCommunity) {
return;
}
try {
@@ -67,6 +86,10 @@ export default class VersionService extends Service {
return this.getVersion.perform();
}
+ fetchType() {
+ return this.getType.perform();
+ }
+
fetchFeatures() {
return this.getFeatures.perform();
}
diff --git a/ui/app/styles/components/env-banner.scss b/ui/app/styles/components/env-banner.scss
index 86895dc2e3c1..cda5d646cf47 100644
--- a/ui/app/styles/components/env-banner.scss
+++ b/ui/app/styles/components/env-banner.scss
@@ -4,7 +4,7 @@
*/
.env-banner {
- align-self: center;
+ font-size: 0.8rem;
border-radius: 3rem;
background: linear-gradient(
135deg,
@@ -13,8 +13,6 @@
); // only use case for purple in the app. define here instead of utils/color_var
animation: env-banner-color-rotate 8s infinite linear alternate;
color: $white;
- margin-top: -20px;
- margin-bottom: 6px;
.hs-icon {
margin: 0;
@@ -22,7 +20,7 @@
.notification {
background-color: transparent;
- line-height: 1.66;
+ line-height: 2;
padding: 0 $spacing-12;
}
}
diff --git a/ui/app/templates/components/dashboard/vault-version-title.hbs b/ui/app/templates/components/dashboard/vault-version-title.hbs
index 194a1ae5f5fa..8509f23eb088 100644
--- a/ui/app/templates/components/dashboard/vault-version-title.hbs
+++ b/ui/app/templates/components/dashboard/vault-version-title.hbs
@@ -6,7 +6,8 @@
- {{this.versionHeader}}
+ Vault
+ {{@version.versionDisplay}}
{{#if @version.isEnterprise}}
{{/if}}
diff --git a/ui/app/templates/vault.hbs b/ui/app/templates/vault.hbs
index 3a72ea2d85ac..b26997c65a5d 100644
--- a/ui/app/templates/vault.hbs
+++ b/ui/app/templates/vault.hbs
@@ -5,28 +5,4 @@
{{outlet}}
-
-
- Vault
- {{this.auth.activeCluster.leaderNode.version}}
-
- {{#if (is-version "OSS")}}
-
- Upgrade to Vault Enterprise
-
- {{/if}}
-
- Documentation
-
-
-
-
-{{#if (eq this.env "development")}}
-
-
-
- Local development
-
-
-
-{{/if}}
\ No newline at end of file
+
\ No newline at end of file
diff --git a/ui/lib/core/addon/helpers/is-version.js b/ui/lib/core/addon/helpers/is-version.js
deleted file mode 100644
index 88c6da62c751..000000000000
--- a/ui/lib/core/addon/helpers/is-version.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: BUSL-1.1
- */
-
-/* eslint-disable ember/no-observers */
-import { inject as service } from '@ember/service';
-import { assert } from '@ember/debug';
-import Helper from '@ember/component/helper';
-import { observer } from '@ember/object';
-
-export default Helper.extend({
- version: service(),
- onFeaturesChange: observer('version.version', function () {
- this.recompute();
- }),
- compute([sku]) {
- if (sku !== 'OSS' && sku !== 'Enterprise') {
- assert(`${sku} is not one of the available values for Vault versions.`, false);
- return false;
- }
- return this.get(`version.is${sku}`);
- },
-});
diff --git a/ui/lib/core/app/helpers/is-version.js b/ui/lib/core/app/helpers/is-version.js
deleted file mode 100644
index 0386f00a8a69..000000000000
--- a/ui/lib/core/app/helpers/is-version.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: BUSL-1.1
- */
-
-export { default } from 'core/helpers/is-version';
diff --git a/ui/mirage/handlers/base.js b/ui/mirage/handlers/base.js
index 2693f4a7592b..52a7ff996a5c 100644
--- a/ui/mirage/handlers/base.js
+++ b/ui/mirage/handlers/base.js
@@ -18,6 +18,7 @@ export default function (server) {
server.get('/sys/health', function () {
return {
+ enterprise: true,
initialized: true,
sealed: false,
standby: false,
diff --git a/ui/tests/acceptance/enterprise-license-banner-test.js b/ui/tests/acceptance/enterprise-license-banner-test.js
index d7c252c7e52d..9d84c71e7dc9 100644
--- a/ui/tests/acceptance/enterprise-license-banner-test.js
+++ b/ui/tests/acceptance/enterprise-license-banner-test.js
@@ -26,6 +26,7 @@ const generateHealthResponse = (now, state) => {
break;
}
return {
+ enterprise: true,
initialized: true,
sealed: false,
standby: false,
diff --git a/ui/tests/acceptance/enterprise-reduced-disclosure-test.js b/ui/tests/acceptance/enterprise-reduced-disclosure-test.js
new file mode 100644
index 000000000000..ccce7369953a
--- /dev/null
+++ b/ui/tests/acceptance/enterprise-reduced-disclosure-test.js
@@ -0,0 +1,137 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+import { module, test } from 'qunit';
+import { setupApplicationTest } from 'ember-qunit';
+import { setupMirage } from 'ember-cli-mirage/test-support';
+import { settled, visit } from '@ember/test-helpers';
+import authPage from 'vault/tests/pages/auth';
+import { createTokenCmd, runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/commands';
+import { pollCluster } from 'vault/tests/helpers/poll-cluster';
+import VAULT_KEYS from 'vault/tests/helpers/vault-keys';
+import ENV from 'vault/config/environment';
+
+const { unsealKeys } = VAULT_KEYS;
+const SELECTORS = {
+ footerVersion: `[data-test-footer-version]`,
+ dashboardTitle: `[data-test-dashboard-card-header="Vault version"]`,
+};
+
+module('Acceptance | Enterprise | reduced disclosure test', function (hooks) {
+ setupApplicationTest(hooks);
+ setupMirage(hooks);
+
+ hooks.before(function () {
+ ENV['ember-cli-mirage'].handler = 'mfaConfig';
+ });
+ hooks.beforeEach(function () {
+ this.versionSvc = this.owner.lookup('service:version');
+ return authPage.logout();
+ });
+ hooks.after(function () {
+ ENV['ember-cli-mirage'].handler = null;
+ });
+
+ test('it works when reduced disclosure enabled', async function (assert) {
+ const namespace = 'reduced-disclosure';
+ assert.dom(SELECTORS.footerVersion).hasText(`Vault`, 'shows Vault without version when logged out');
+ await authPage.login();
+
+ // Ensure it shows version on dashboard
+ assert.dom(SELECTORS.dashboardTitle).includesText(`Vault v1.`);
+ assert
+ .dom(SELECTORS.footerVersion)
+ .hasText(`Vault ${this.versionSvc.version}`, 'shows Vault version after login');
+
+ await runCmd(`write sys/namespaces/${namespace} -f`, false);
+ await authPage.loginNs(namespace);
+
+ assert
+ .dom(SELECTORS.footerVersion)
+ .hasText(`Vault ${this.versionSvc.version}`, 'shows Vault version within namespace');
+
+ const token = await runCmd(createTokenCmd('default'));
+
+ await authPage.logout();
+ assert.dom(SELECTORS.footerVersion).hasText(`Vault`, 'no vault version after logout');
+
+ await authPage.loginNs(namespace, token);
+ assert
+ .dom(SELECTORS.footerVersion)
+ .hasText(`Vault ${this.versionSvc.version}`, 'shows Vault version for default policy in namespace');
+ });
+
+ test('it works for user accessing child namespace', async function (assert) {
+ const namespace = 'reduced-disclosure';
+ await authPage.login();
+
+ await runCmd(`write sys/namespaces/${namespace} -f`, false);
+ const token = await runCmd(
+ tokenWithPolicyCmd(
+ 'child-ns-access',
+ `
+ path "${namespace}/sys/*" {
+ capabilities = ["read"]
+ }
+ `
+ )
+ );
+
+ await authPage.logout();
+ await authPage.login(token);
+ assert
+ .dom(SELECTORS.footerVersion)
+ .hasText(`Vault ${this.versionSvc.version}`, 'shows Vault version for default policy in namespace');
+
+ // navigate to child namespace
+ await visit(`/vault/dashboard?namespace=${namespace}`);
+ assert
+ .dom(SELECTORS.footerVersion)
+ .hasText(
+ `Vault ${this.versionSvc.version}`,
+ 'shows Vault version for default policy in child namespace'
+ );
+ assert.dom(SELECTORS.dashboardTitle).includesText('Vault v1.');
+ });
+
+ test('shows correct version on unseal flow', async function (assert) {
+ await authPage.login();
+
+ const versionSvc = this.owner.lookup('service:version');
+ await visit('/vault/settings/seal');
+ assert
+ .dom('[data-test-footer-version]')
+ .hasText(`Vault ${versionSvc.version}`, 'shows version on seal page');
+ assert.strictEqual(currentURL(), '/vault/settings/seal');
+
+ // seal
+ await click('[data-test-seal]');
+
+ await click('[data-test-confirm-button]');
+
+ await pollCluster(this.owner);
+ await settled();
+ assert.strictEqual(currentURL(), '/vault/unseal', 'vault is on the unseal page');
+ assert.dom('[data-test-footer-version]').hasText(`Vault`, 'Clears version on unseal');
+
+ // unseal
+ for (const key of unsealKeys) {
+ await fillIn('[data-test-shamir-key-input]', key);
+
+ await click('button[type="submit"]');
+
+ await pollCluster(this.owner);
+ await settled();
+ }
+
+ assert.dom('[data-test-cluster-status]').doesNotExist('ui does not show sealed warning');
+ assert.strictEqual(currentRouteName(), 'vault.cluster.auth', 'vault is ready to authenticate');
+ assert.dom('[data-test-footer-version]').hasText(`Vault`, 'Version is still not shown before auth');
+ await authPage.login();
+ assert
+ .dom('[data-test-footer-version]')
+ .hasText(`Vault ${versionSvc.version}`, 'Version is shown after login');
+ });
+});
diff --git a/ui/tests/acceptance/enterprise-sidebar-nav-test.js b/ui/tests/acceptance/enterprise-sidebar-nav-test.js
index 73246bea8291..de95fd704dc0 100644
--- a/ui/tests/acceptance/enterprise-sidebar-nav-test.js
+++ b/ui/tests/acceptance/enterprise-sidebar-nav-test.js
@@ -22,7 +22,6 @@ module('Acceptance | Enterprise | sidebar navigation', function (hooks) {
// common links are tested in the sidebar-nav test and will not be covered here
test('it should render enterprise only navigation links', async function (assert) {
- assert.expect(12);
assert.dom(panel('Cluster')).exists('Cluster nav panel renders');
await click(link('Replication'));
diff --git a/ui/tests/integration/components/app-footer-test.js b/ui/tests/integration/components/app-footer-test.js
new file mode 100644
index 000000000000..cc9ee5555101
--- /dev/null
+++ b/ui/tests/integration/components/app-footer-test.js
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'vault/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+const selectors = {
+ versionDisplay: '[data-test-footer-version]',
+ upgradeLink: '[data-test-footer-upgrade-link]',
+ docsLink: '[data-test-footer-documentation-link]',
+};
+
+module('Integration | Component | app-footer', function (hooks) {
+ setupRenderingTest(hooks);
+
+ hooks.beforeEach(function () {
+ this.versionSvc = this.owner.lookup('service:version');
+ });
+
+ test('it renders a sane default', async function (assert) {
+ await render(hbs` `);
+ assert.dom(selectors.versionDisplay).hasText('Vault', 'Vault without version by default');
+ assert.dom(selectors.upgradeLink).hasText('Upgrade to Vault Enterprise', 'upgrade link shows');
+ assert.dom(selectors.docsLink).hasText('Documentation', 'displays docs link');
+ });
+
+ test('it renders for community version', async function (assert) {
+ this.versionSvc.version = '1.15.1';
+ this.versionSvc.type = 'community';
+ await render(hbs` `);
+ assert.dom(selectors.versionDisplay).hasText('Vault 1.15.1', 'Vault shows version when available');
+ assert.dom(selectors.upgradeLink).hasText('Upgrade to Vault Enterprise', 'upgrade link shows');
+ assert.dom(selectors.docsLink).hasText('Documentation', 'displays docs link');
+ });
+ test('it renders for ent version', async function (assert) {
+ this.versionSvc.version = '1.15.1+hsm';
+ this.versionSvc.type = 'enterprise';
+ await render(hbs` `);
+ assert.dom(selectors.versionDisplay).hasText('Vault 1.15.1+hsm', 'shows version when available');
+ assert.dom(selectors.upgradeLink).doesNotExist('upgrade link not shown');
+ assert.dom(selectors.docsLink).hasText('Documentation', 'displays docs link');
+ });
+});
diff --git a/ui/tests/integration/components/dashboard/overview-test.js b/ui/tests/integration/components/dashboard/overview-test.js
index 9e661595c574..50e9fa687308 100644
--- a/ui/tests/integration/components/dashboard/overview-test.js
+++ b/ui/tests/integration/components/dashboard/overview-test.js
@@ -114,6 +114,7 @@ module('Integration | Component | dashboard/overview', function (hooks) {
test('it should show client count on enterprise w/ license', async function (assert) {
this.version = this.owner.lookup('service:version');
this.version.version = '1.13.1+ent';
+ this.version.type = 'enterprise';
this.license = {
autoloaded: {
license_id: '7adbf1f4-56ef-35cd-3a6c-50ef2627865d',
@@ -142,6 +143,7 @@ module('Integration | Component | dashboard/overview', function (hooks) {
test('it should hide client count on enterprise w/o license ', async function (assert) {
this.version = this.owner.lookup('service:version');
this.version.version = '1.13.1+ent';
+ this.version.type = 'enterprise';
this.isRootNamespace = true;
await render(
@@ -168,6 +170,7 @@ module('Integration | Component | dashboard/overview', function (hooks) {
test('it should hide replication on enterprise not on root namespace', async function (assert) {
this.version = this.owner.lookup('service:version');
this.version.version = '1.13.1+ent';
+ this.version.type = 'enterprise';
this.isRootNamespace = false;
this.license = {
autoloaded: {
@@ -217,6 +220,7 @@ module('Integration | Component | dashboard/overview', function (hooks) {
test('shows the learn more card on enterprise', async function (assert) {
this.version = this.owner.lookup('service:version');
this.version.version = '1.13.1+ent';
+ this.version.type = 'enterprise';
this.version.features = [
'Performance Replication',
'DR Replication',
diff --git a/ui/tests/integration/components/license-banners-test.js b/ui/tests/integration/components/license-banners-test.js
index 3a3d2caa2b4a..2df72bebf686 100644
--- a/ui/tests/integration/components/license-banners-test.js
+++ b/ui/tests/integration/components/license-banners-test.js
@@ -28,6 +28,7 @@ module('Integration | Component | license-banners', function (hooks) {
this.tomorrow = addDays(mockNow, 1);
this.version = this.owner.lookup('service:version');
this.version.version = '1.13.1+ent';
+ this.version.type = 'enterprise';
});
hooks.after(function () {
timestamp.now.restore();
diff --git a/ui/tests/integration/components/link-status-test.js b/ui/tests/integration/components/link-status-test.js
index 04bd942b9b4a..815384a20728 100644
--- a/ui/tests/integration/components/link-status-test.js
+++ b/ui/tests/integration/components/link-status-test.js
@@ -24,7 +24,7 @@ module('Integration | Component | link-status', function (hooks) {
// this can be removed once feature is released for OSS
hooks.beforeEach(function () {
- this.owner.lookup('service:version').set('version', '1.13.0+ent');
+ this.owner.lookup('service:version').set('type', 'enterprise');
this.statuses = statuses;
});
@@ -37,7 +37,7 @@ module('Integration | Component | link-status', function (hooks) {
});
test('it does not render banner in oss version', async function (assert) {
- this.owner.lookup('service:version').set('version', '1.13.0');
+ this.owner.lookup('service:version').set('type', 'community');
await render(hbs`
@@ -50,7 +50,6 @@ module('Integration | Component | link-status', function (hooks) {
await render(hbs`
`);
-
assert.dom(SELECTORS.bannerConnected).exists('Success banner renders for connected state');
assert
.dom('[data-test-link-status]')
diff --git a/ui/tests/integration/components/mount-backend/type-form-test.js b/ui/tests/integration/components/mount-backend/type-form-test.js
index 9ab5b06a12c0..d67841c371b9 100644
--- a/ui/tests/integration/components/mount-backend/type-form-test.js
+++ b/ui/tests/integration/components/mount-backend/type-form-test.js
@@ -50,7 +50,7 @@ module('Integration | Component | mount-backend/type-form', function (hooks) {
module('Enterprise', function (hooks) {
hooks.beforeEach(function () {
this.version = this.owner.lookup('service:version');
- this.version.version = '1.12.1+ent';
+ this.version.type = 'enterprise';
});
test('it renders correct items for enterprise secrets', async function (assert) {
diff --git a/ui/tests/integration/components/pki/page/pki-configuration-details-test.js b/ui/tests/integration/components/pki/page/pki-configuration-details-test.js
index 3ee97db4c54e..9e5aaff4483d 100644
--- a/ui/tests/integration/components/pki/page/pki-configuration-details-test.js
+++ b/ui/tests/integration/components/pki/page/pki-configuration-details-test.js
@@ -151,7 +151,7 @@ module('Integration | Component | Page::PkiConfigurationDetails', function (hook
test('it renders enterprise params in crl section', async function (assert) {
this.version = this.owner.lookup('service:version');
- this.version.version = '1.13.1+ent';
+ this.version.type = 'enterprise';
await render(
hbs` ,`,
{ owner: this.engine }
@@ -166,7 +166,7 @@ module('Integration | Component | Page::PkiConfigurationDetails', function (hook
test('it does not render enterprise params in crl section', async function (assert) {
this.version = this.owner.lookup('service:version');
- this.version.version = '1.13.1';
+ this.version.type = 'community';
await render(
hbs` ,`,
{ owner: this.engine }
diff --git a/ui/tests/integration/components/pki/page/pki-configuration-edit-test.js b/ui/tests/integration/components/pki/page/pki-configuration-edit-test.js
index 30cf39d0aca6..cc8644921ec8 100644
--- a/ui/tests/integration/components/pki/page/pki-configuration-edit-test.js
+++ b/ui/tests/integration/components/pki/page/pki-configuration-edit-test.js
@@ -276,7 +276,7 @@ module('Integration | Component | page/pki-configuration-edit', function (hooks)
test('it renders enterprise only params', async function (assert) {
assert.expect(6);
this.version = this.owner.lookup('service:version');
- this.version.version = '1.13.1+ent';
+ this.version.type = 'enterprise';
this.server.post(`/${this.backend}/config/acme`, () => {});
this.server.post(`/${this.backend}/config/cluster`, () => {});
this.server.post(`/${this.backend}/config/crl`, (schema, req) => {
@@ -327,7 +327,7 @@ module('Integration | Component | page/pki-configuration-edit', function (hooks)
test('it does not render enterprise only params for OSS', async function (assert) {
assert.expect(9);
this.version = this.owner.lookup('service:version');
- this.version.version = '1.13.1';
+ this.version.type = 'community';
this.server.post(`/${this.backend}/config/acme`, () => {});
this.server.post(`/${this.backend}/config/cluster`, () => {});
this.server.post(`/${this.backend}/config/crl`, (schema, req) => {
diff --git a/ui/tests/integration/components/pki/pki-tidy-form-test.js b/ui/tests/integration/components/pki/pki-tidy-form-test.js
index f13ff9f6e8a3..a3acc912574f 100644
--- a/ui/tests/integration/components/pki/pki-tidy-form-test.js
+++ b/ui/tests/integration/components/pki/pki-tidy-form-test.js
@@ -19,7 +19,7 @@ module('Integration | Component | pki tidy form', function (hooks) {
hooks.beforeEach(function () {
this.store = this.owner.lookup('service:store');
this.version = this.owner.lookup('service:version');
- this.version.version = '1.14.1+ent';
+ this.version.type = 'enterprise';
this.server.post('/sys/capabilities-self', () => {});
this.onSave = () => {};
this.onCancel = () => {};
@@ -33,7 +33,6 @@ module('Integration | Component | pki tidy form', function (hooks) {
test('it hides or shows fields depending on auto-tidy toggle', async function (assert) {
assert.expect(37);
- this.version.version = '1.14.1+ent';
const sectionHeaders = [
'Universal operations',
'ACME operations',
@@ -82,7 +81,6 @@ module('Integration | Component | pki tidy form', function (hooks) {
test('it renders all attribute fields, including enterprise', async function (assert) {
assert.expect(25);
- this.version.version = '1.14.1+ent';
this.autoTidy.enabled = true;
const skipFields = ['enabled', 'tidyAcme', 'intervalDuration']; // combined with duration ttl or asserted separately
await render(
@@ -123,7 +121,7 @@ module('Integration | Component | pki tidy form', function (hooks) {
test('it hides enterprise fields for OSS', async function (assert) {
assert.expect(7);
- this.version.version = '1.14.1';
+ this.version.type = 'community';
this.autoTidy.enabled = true;
const enterpriseFields = [
diff --git a/ui/tests/integration/components/sidebar/frame-test.js b/ui/tests/integration/components/sidebar/frame-test.js
index e310988a3f6f..4df34374b720 100644
--- a/ui/tests/integration/components/sidebar/frame-test.js
+++ b/ui/tests/integration/components/sidebar/frame-test.js
@@ -27,7 +27,7 @@ module('Integration | Component | sidebar-frame', function (hooks) {
const currentCluster = this.owner.lookup('service:currentCluster');
currentCluster.setCluster({ hcpLinkStatus: 'connected' });
const version = this.owner.lookup('service:version');
- version.version = '1.13.0-dev1+ent';
+ version.type = 'enterprise';
await render(hbs`
diff --git a/ui/tests/pages/auth.js b/ui/tests/pages/auth.js
index f1e2cad69e46..66c53c47e785 100644
--- a/ui/tests/pages/auth.js
+++ b/ui/tests/pages/auth.js
@@ -45,7 +45,7 @@ export default create({
await this.usernameInput(username);
return this.passwordInput(password).submit();
},
- loginNs: async function (ns) {
+ loginNs: async function (ns, token = rootToken) {
// make sure we're always logged out and logged back in
await this.logout();
await settled();
@@ -55,7 +55,7 @@ export default create({
await settled();
await this.namespaceInput(ns);
await settled();
- await this.tokenInput(rootToken).submit();
+ await this.tokenInput(token).submit();
return;
},
clickLogout: async function (clearNamespace = false) {
diff --git a/ui/tests/unit/adapters/kv/data-test.js b/ui/tests/unit/adapters/kv/data-test.js
index ae67ccd3079e..01edae328ff7 100644
--- a/ui/tests/unit/adapters/kv/data-test.js
+++ b/ui/tests/unit/adapters/kv/data-test.js
@@ -79,7 +79,7 @@ module('Unit | Adapter | kv/data', function (hooks) {
hooks.beforeEach(function () {
this.store = this.owner.lookup('service:store');
this.version = this.owner.lookup('service:version');
- this.version.version = 'example+ent'; // Required for testing control-group flow
+ this.version.type = 'enterprise'; // Required for testing control-group flow
this.secretMountPath = this.owner.lookup('service:secret-mount-path');
this.backend = 'my/kv-back&end';
this.secretMountPath.currentPath = this.backend;
diff --git a/ui/tests/unit/services/control-group-test.js b/ui/tests/unit/services/control-group-test.js
index 6a477846702c..b0c9089681d2 100644
--- a/ui/tests/unit/services/control-group-test.js
+++ b/ui/tests/unit/services/control-group-test.js
@@ -51,8 +51,8 @@ module('Unit | Service | control group', function (hooks) {
hooks.afterEach(function () {});
- const isOSS = (context) => set(context, 'version.isOSS', true);
- const isEnt = (context) => set(context, 'version.isOSS', false);
+ const isCommunity = (context) => set(context, 'version.type', 'community');
+ const isEnt = (context) => set(context, 'version.type', 'enterprise');
const resolvesArgs = (assert, result, expectedArgs) => {
return result.then((...args) => {
return assert.deepEqual(args, expectedArgs, 'resolves with the passed args');
@@ -61,31 +61,31 @@ module('Unit | Service | control group', function (hooks) {
[
[
- 'it resolves isOSS:true, wrapTTL: true, response: has wrap_info',
- isOSS,
+ 'it resolves isCommunity:true, wrapTTL: true, response: has wrap_info',
+ isCommunity,
[[{ one: 'two', three: 'four' }], { wrap_info: { token: 'foo', accessor: 'bar' } }, true],
(assert, result) => resolvesArgs(assert, result, [{ one: 'two', three: 'four' }]),
],
[
- 'it resolves isOSS:true, wrapTTL: false, response: has no wrap_info',
- isOSS,
+ 'it resolves isCommunity:true, wrapTTL: false, response: has no wrap_info',
+ isCommunity,
[[{ one: 'two', three: 'four' }], { wrap_info: null }, false],
(assert, result) => resolvesArgs(assert, result, [{ one: 'two', three: 'four' }]),
],
[
- 'it resolves isOSS: false and wrapTTL:true response: has wrap_info',
+ 'it resolves isCommunity: false and wrapTTL:true response: has wrap_info',
isEnt,
[[{ one: 'two', three: 'four' }], { wrap_info: { token: 'foo', accessor: 'bar' } }, true],
(assert, result) => resolvesArgs(assert, result, [{ one: 'two', three: 'four' }]),
],
[
- 'it resolves isOSS: false and wrapTTL:false response: has no wrap_info',
+ 'it resolves isCommunity: false and wrapTTL:false response: has no wrap_info',
isEnt,
[[{ one: 'two', three: 'four' }], { wrap_info: null }, false],
(assert, result) => resolvesArgs(assert, result, [{ one: 'two', three: 'four' }]),
],
[
- 'it rejects isOSS: false, wrapTTL:false, response: has wrap_info',
+ 'it rejects isCommunity: false, wrapTTL:false, response: has wrap_info',
isEnt,
[
[{ one: 'two', three: 'four' }],
@@ -107,7 +107,8 @@ module('Unit | Service | control group', function (hooks) {
],
].forEach(function ([name, setup, args, expectation]) {
test(`checkForControlGroup: ${name}`, function (assert) {
- const assertCount = name === 'it rejects isOSS: false, wrapTTL:false, response: has wrap_info' ? 2 : 1;
+ const assertCount =
+ name === 'it rejects isCommunity: false, wrapTTL:false, response: has wrap_info' ? 2 : 1;
assert.expect(assertCount);
if (setup) {
setup(this);
diff --git a/ui/tests/unit/services/version-test.js b/ui/tests/unit/services/version-test.js
index 1bc1ca4d7785..f7ebf7b2f2fd 100644
--- a/ui/tests/unit/services/version-test.js
+++ b/ui/tests/unit/services/version-test.js
@@ -9,24 +9,17 @@ import { setupTest } from 'ember-qunit';
module('Unit | Service | version', function (hooks) {
setupTest(hooks);
- test('setting version computes isOSS properly', function (assert) {
+ test('setting type computes isCommunity properly', function (assert) {
const service = this.owner.lookup('service:version');
- service.version = '0.9.5';
- assert.true(service.isOSS);
+ service.type = 'community';
+ assert.true(service.isCommunity);
assert.false(service.isEnterprise);
});
- test('setting version computes isEnterprise properly', function (assert) {
+ test('setting type computes isEnterprise properly', function (assert) {
const service = this.owner.lookup('service:version');
- service.version = '0.9.5+ent';
- assert.false(service.isOSS);
- assert.true(service.isEnterprise);
- });
-
- test('setting version with hsm ending computes isEnterprise properly', function (assert) {
- const service = this.owner.lookup('service:version');
- service.version = '0.9.5+ent.hsm';
- assert.false(service.isOSS);
+ service.type = 'enterprise';
+ assert.false(service.isCommunity);
assert.true(service.isEnterprise);
});
From aeb817dfba95ebe6f7f0577d144510ff19648d0a Mon Sep 17 00:00:00 2001
From: Hamid Ghaf <83242695+hghaf099@users.noreply.github.com>
Date: Mon, 4 Dec 2023 13:22:22 -0800
Subject: [PATCH 66/74] Buffer body read up to MaxRequestSize (#24354)
---
helper/forwarding/util.go | 16 +--------
http/handler.go | 40 +--------------------
http/handler_test.go | 59 +++++++++++++++++++++++++++++++
http/util.go | 68 ++++++++++++++++++++++++++++++------
sdk/logical/request.go | 44 +++++++----------------
sdk/logical/request_test.go | 66 ----------------------------------
vault/core.go | 37 +++++++++++++-------
vault/logical_system_raft.go | 5 +--
vault/request_handling.go | 4 +++
9 files changed, 162 insertions(+), 177 deletions(-)
diff --git a/helper/forwarding/util.go b/helper/forwarding/util.go
index 1bc1c5e68fc3..e9d06de04854 100644
--- a/helper/forwarding/util.go
+++ b/helper/forwarding/util.go
@@ -7,9 +7,7 @@ import (
"bytes"
"crypto/tls"
"crypto/x509"
- "errors"
"io"
- "io/ioutil"
"net/http"
"net/url"
"os"
@@ -17,7 +15,6 @@ import (
"github.com/golang/protobuf/proto"
"github.com/hashicorp/vault/sdk/helper/compressutil"
"github.com/hashicorp/vault/sdk/helper/jsonutil"
- "github.com/hashicorp/vault/sdk/logical"
)
type bufCloser struct {
@@ -64,18 +61,7 @@ func GenerateForwardedHTTPRequest(req *http.Request, addr string) (*http.Request
func GenerateForwardedRequest(req *http.Request) (*Request, error) {
var reader io.Reader = req.Body
- ctx := req.Context()
- if logical.ContextContainsMaxRequestSize(ctx) {
- max, ok := logical.ContextMaxRequestSizeValue(ctx)
- if !ok {
- return nil, errors.New("could not parse max request size from request context")
- }
- if max > 0 {
- reader = io.LimitReader(req.Body, max)
- }
- }
-
- body, err := ioutil.ReadAll(reader)
+ body, err := io.ReadAll(reader)
if err != nil {
return nil, err
}
diff --git a/http/handler.go b/http/handler.go
index 37e769aa5e3e..c3f49d32b62b 100644
--- a/http/handler.go
+++ b/http/handler.go
@@ -242,6 +242,7 @@ func handler(props *vault.HandlerProperties) http.Handler {
wrappedHandler = wrapCORSHandler(wrappedHandler, core)
wrappedHandler = rateLimitQuotaWrapping(wrappedHandler, core)
wrappedHandler = entWrapGenericHandler(core, wrappedHandler, props)
+ wrappedHandler = wrapMaxRequestSizeHandler(wrappedHandler, props)
// Add an extra wrapping handler if the DisablePrintableCheck listener
// setting isn't true that checks for non-printable characters in the
@@ -332,18 +333,12 @@ func handleAuditNonLogical(core *vault.Core, h http.Handler) http.Handler {
// are performed.
func wrapGenericHandler(core *vault.Core, h http.Handler, props *vault.HandlerProperties) http.Handler {
var maxRequestDuration time.Duration
- var maxRequestSize int64
if props.ListenerConfig != nil {
maxRequestDuration = props.ListenerConfig.MaxRequestDuration
- maxRequestSize = props.ListenerConfig.MaxRequestSize
}
if maxRequestDuration == 0 {
maxRequestDuration = vault.DefaultMaxRequestDuration
}
- if maxRequestSize == 0 {
- maxRequestSize = DefaultMaxRequestSize
- }
-
// Swallow this error since we don't want to pollute the logs and we also don't want to
// return an HTTP error here. This information is best effort.
hostname, _ := os.Hostname()
@@ -378,11 +373,6 @@ func wrapGenericHandler(core *vault.Core, h http.Handler, props *vault.HandlerPr
ctx, cancelFunc = context.WithTimeout(ctx, maxRequestDuration)
}
- // if maxRequestSize < 0, no need to set context value
- // Add a size limiter if desired
- if maxRequestSize > 0 {
- ctx = logical.CreateContextMaxRequestSize(ctx, maxRequestSize)
- }
ctx = logical.CreateContextOriginalRequestPath(ctx, r.URL.Path)
r = r.WithContext(ctx)
r = r.WithContext(namespace.ContextWithNamespace(r.Context(), namespace.RootNamespace))
@@ -738,24 +728,6 @@ func parseJSONRequest(perfStandby bool, r *http.Request, w http.ResponseWriter,
// Limit the maximum number of bytes to MaxRequestSize to protect
// against an indefinite amount of data being read.
reader := r.Body
- ctx := r.Context()
- if logical.ContextContainsMaxRequestSize(ctx) {
- max, ok := logical.ContextMaxRequestSizeValue(ctx)
- if !ok {
- return nil, errors.New("could not parse max request size from request context")
- }
- if max > 0 {
- // MaxBytesReader won't do all the internal stuff it must unless it's
- // given a ResponseWriter that implements the internal http interface
- // requestTooLarger. So we let it have access to the underlying
- // ResponseWriter.
- inw := w
- if myw, ok := inw.(logical.WrappingResponseWriter); ok {
- inw = myw.Wrapped()
- }
- reader = http.MaxBytesReader(inw, r.Body, max)
- }
- }
var origBody io.ReadWriter
@@ -779,16 +751,6 @@ func parseJSONRequest(perfStandby bool, r *http.Request, w http.ResponseWriter,
//
// A nil map will be returned if the format is empty or invalid.
func parseFormRequest(r *http.Request) (map[string]interface{}, error) {
- if logical.ContextContainsMaxRequestSize(r.Context()) {
- max, ok := logical.ContextMaxRequestSizeValue(r.Context())
- if !ok {
- return nil, errors.New("could not parse max request size from request context")
- }
- if max > 0 {
- r.Body = io.NopCloser(io.LimitReader(r.Body, max))
- }
- }
-
if err := r.ParseForm(); err != nil {
return nil, err
}
diff --git a/http/handler_test.go b/http/handler_test.go
index a669672b60fb..92e1eacc4680 100644
--- a/http/handler_test.go
+++ b/http/handler_test.go
@@ -4,6 +4,7 @@
package http
import (
+ "bytes"
"context"
"crypto/tls"
"encoding/json"
@@ -14,10 +15,12 @@ import (
"net/textproto"
"net/url"
"reflect"
+ "runtime"
"strings"
"testing"
"github.com/hashicorp/vault/internalshared/configutil"
+ "github.com/stretchr/testify/require"
"github.com/go-test/deep"
"github.com/hashicorp/go-cleanhttp"
@@ -892,3 +895,59 @@ func TestHandler_Parse_Form(t *testing.T) {
t.Fatal(diff)
}
}
+
+// TestHandler_MaxRequestSize verifies that a request larger than the
+// MaxRequestSize fails
+func TestHandler_MaxRequestSize(t *testing.T) {
+ t.Parallel()
+ cluster := vault.NewTestCluster(t, &vault.CoreConfig{}, &vault.TestClusterOptions{
+ DefaultHandlerProperties: vault.HandlerProperties{
+ ListenerConfig: &configutil.Listener{
+ MaxRequestSize: 1024,
+ },
+ },
+ HandlerFunc: Handler,
+ NumCores: 1,
+ })
+ cluster.Start()
+ defer cluster.Cleanup()
+
+ client := cluster.Cores[0].Client
+ _, err := client.KVv2("secret").Put(context.Background(), "foo", map[string]interface{}{
+ "bar": strings.Repeat("a", 1025),
+ })
+
+ require.ErrorContains(t, err, "error parsing JSON")
+}
+
+// TestHandler_MaxRequestSize_Memory sets the max request size to 1024 bytes,
+// and creates a 1MB request. The test verifies that less than 1MB of memory is
+// allocated when the request is sent. This test shouldn't be run in parallel,
+// because it modifies GOMAXPROCS
+func TestHandler_MaxRequestSize_Memory(t *testing.T) {
+ ln, addr := TestListener(t)
+ core, _, token := vault.TestCoreUnsealed(t)
+ TestServerWithListenerAndProperties(t, ln, addr, core, &vault.HandlerProperties{
+ Core: core,
+ ListenerConfig: &configutil.Listener{
+ Address: addr,
+ MaxRequestSize: 1024,
+ },
+ })
+ defer ln.Close()
+
+ data := bytes.Repeat([]byte{0x1}, 1024*1024)
+
+ req, err := http.NewRequest("POST", addr+"/v1/sys/unseal", bytes.NewReader(data))
+ require.NoError(t, err)
+ req.Header.Set(consts.AuthHeaderName, token)
+
+ client := cleanhttp.DefaultClient()
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+ var start, end runtime.MemStats
+ runtime.GC()
+ runtime.ReadMemStats(&start)
+ client.Do(req)
+ runtime.ReadMemStats(&end)
+ require.Less(t, end.TotalAlloc-start.TotalAlloc, uint64(1024*1024))
+}
diff --git a/http/util.go b/http/util.go
index abf03b29efe8..4de8f8132646 100644
--- a/http/util.go
+++ b/http/util.go
@@ -6,13 +6,13 @@ package http
import (
"bytes"
"context"
- "errors"
"fmt"
- "io/ioutil"
+ "io"
"net"
"net/http"
"strings"
+ "github.com/hashicorp/go-multierror"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/helper/namespace"
@@ -22,6 +22,27 @@ import (
var nonVotersAllowed = false
+func wrapMaxRequestSizeHandler(handler http.Handler, props *vault.HandlerProperties) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ var maxRequestSize int64
+ if props.ListenerConfig != nil {
+ maxRequestSize = props.ListenerConfig.MaxRequestSize
+ }
+ if maxRequestSize == 0 {
+ maxRequestSize = DefaultMaxRequestSize
+ }
+ ctx := r.Context()
+ originalBody := r.Body
+ if maxRequestSize > 0 {
+ r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
+ }
+ ctx = logical.CreateContextOriginalBody(ctx, originalBody)
+ r = r.WithContext(ctx)
+
+ handler.ServeHTTP(w, r)
+ })
+}
+
func rateLimitQuotaWrapping(handler http.Handler, core *vault.Core) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ns, err := namespace.FromContext(r.Context())
@@ -40,14 +61,6 @@ func rateLimitQuotaWrapping(handler http.Handler, core *vault.Core) http.Handler
}
mountPath := strings.TrimPrefix(core.MatchingMount(r.Context(), path), ns.Path)
- // Clone body, so we do not close the request body reader
- bodyBytes, err := ioutil.ReadAll(r.Body)
- if err != nil {
- respondError(w, http.StatusInternalServerError, errors.New("failed to read request body"))
- return
- }
- r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
-
quotaReq := "as.Request{
Type: quotas.TypeRateLimit,
Path: path,
@@ -67,7 +80,18 @@ func rateLimitQuotaWrapping(handler http.Handler, core *vault.Core) http.Handler
// If any role-based quotas are enabled for this namespace/mount, just
// do the role resolution once here.
if requiresResolveRole {
- role := core.DetermineRoleFromLoginRequestFromBytes(r.Context(), mountPath, bodyBytes)
+ buf := bytes.Buffer{}
+ teeReader := io.TeeReader(r.Body, &buf)
+ role := core.DetermineRoleFromLoginRequestFromReader(r.Context(), mountPath, teeReader)
+
+ // Reset the body if it was read
+ if buf.Len() > 0 {
+ r.Body = io.NopCloser(&buf)
+ originalBody, ok := logical.ContextOriginalBodyValue(r.Context())
+ if ok {
+ r = r.WithContext(logical.CreateContextOriginalBody(r.Context(), newMultiReaderCloser(&buf, originalBody)))
+ }
+ }
// add an entry to the context to prevent recalculating request role unnecessarily
r = r.WithContext(context.WithValue(r.Context(), logical.CtxKeyRequestRole{}, role))
quotaReq.Role = role
@@ -134,3 +158,25 @@ func parseRemoteIPAddress(r *http.Request) string {
return ip
}
+
+type multiReaderCloser struct {
+ readers []io.Reader
+ io.Reader
+}
+
+func newMultiReaderCloser(readers ...io.Reader) *multiReaderCloser {
+ return &multiReaderCloser{
+ readers: readers,
+ Reader: io.MultiReader(readers...),
+ }
+}
+
+func (m *multiReaderCloser) Close() error {
+ var err error
+ for _, r := range m.readers {
+ if c, ok := r.(io.Closer); ok {
+ err = multierror.Append(err, c.Close())
+ }
+ }
+ return err
+}
diff --git a/sdk/logical/request.go b/sdk/logical/request.go
index a4850e0eb504..176b7013a3f0 100644
--- a/sdk/logical/request.go
+++ b/sdk/logical/request.go
@@ -6,6 +6,7 @@ package logical
import (
"context"
"fmt"
+ "io"
"net/http"
"strings"
"time"
@@ -483,38 +484,6 @@ func CreateContextDisableReplicationStatusEndpoints(parent context.Context, valu
return context.WithValue(parent, ctxKeyDisableReplicationStatusEndpoints{}, value)
}
-// CtxKeyMaxRequestSize is a custom type used as a key in context.Context to
-// store the value of the max_request_size set for the listener through which
-// a request was received.
-type ctxKeyMaxRequestSize struct{}
-
-// String returns a string representation of the receiver type.
-func (c ctxKeyMaxRequestSize) String() string {
- return "max_request_size"
-}
-
-// ContextMaxRequestSizeValue examines the provided context.Context for the max
-// request size value and returns it as an int64 value if it's found along with
-// the ok value set to true; otherwise the ok return value is false.
-func ContextMaxRequestSizeValue(ctx context.Context) (value int64, ok bool) {
- value, ok = ctx.Value(ctxKeyMaxRequestSize{}).(int64)
-
- return
-}
-
-// CreateContextMaxRequestSize creates a new context.Context based on the
-// provided parent that also includes the provided max request size value for
-// the ctxKeyMaxRequestSize key.
-func CreateContextMaxRequestSize(parent context.Context, value int64) context.Context {
- return context.WithValue(parent, ctxKeyMaxRequestSize{}, value)
-}
-
-// ContextContainsMaxRequestSize returns a bool value that indicates if the
-// provided Context contains a value for the ctxKeyMaxRequestSize key.
-func ContextContainsMaxRequestSize(ctx context.Context) bool {
- return ctx.Value(ctxKeyMaxRequestSize{}) != nil
-}
-
// CtxKeyOriginalRequestPath is a custom type used as a key in context.Context
// to store the original request path.
type ctxKeyOriginalRequestPath struct{}
@@ -539,3 +508,14 @@ func ContextOriginalRequestPathValue(ctx context.Context) (value string, ok bool
func CreateContextOriginalRequestPath(parent context.Context, value string) context.Context {
return context.WithValue(parent, ctxKeyOriginalRequestPath{}, value)
}
+
+type ctxKeyOriginalBody struct{}
+
+func ContextOriginalBodyValue(ctx context.Context) (io.ReadCloser, bool) {
+ value, ok := ctx.Value(ctxKeyOriginalBody{}).(io.ReadCloser)
+ return value, ok
+}
+
+func CreateContextOriginalBody(parent context.Context, body io.ReadCloser) context.Context {
+ return context.WithValue(parent, ctxKeyOriginalBody{}, body)
+}
diff --git a/sdk/logical/request_test.go b/sdk/logical/request_test.go
index 1b07cc1b50a5..4e05471035ef 100644
--- a/sdk/logical/request_test.go
+++ b/sdk/logical/request_test.go
@@ -76,72 +76,6 @@ func TestCreateContextDisableReplicationStatusEndpoints(t *testing.T) {
assert.Equal(t, false, value.(bool))
}
-func TestContextMaxRequestSizeValue(t *testing.T) {
- testcases := []struct {
- name string
- ctx context.Context
- expectedValue int64
- expectedOk bool
- }{
- {
- name: "without-value",
- ctx: context.Background(),
- expectedValue: 0,
- expectedOk: false,
- },
- {
- name: "with-nil",
- ctx: context.WithValue(context.Background(), ctxKeyMaxRequestSize{}, nil),
- expectedValue: 0,
- expectedOk: false,
- },
- {
- name: "with-incompatible-value",
- ctx: context.WithValue(context.Background(), ctxKeyMaxRequestSize{}, "6666"),
- expectedValue: 0,
- expectedOk: false,
- },
- {
- name: "with-int64-8888",
- ctx: context.WithValue(context.Background(), ctxKeyMaxRequestSize{}, int64(8888)),
- expectedValue: 8888,
- expectedOk: true,
- },
- {
- name: "with-int64-zero",
- ctx: context.WithValue(context.Background(), ctxKeyMaxRequestSize{}, int64(0)),
- expectedValue: 0,
- expectedOk: true,
- },
- }
-
- for _, testcase := range testcases {
- value, ok := ContextMaxRequestSizeValue(testcase.ctx)
- assert.Equal(t, testcase.expectedValue, value, testcase.name)
- assert.Equal(t, testcase.expectedOk, ok, testcase.name)
- }
-}
-
-func TestCreateContextMaxRequestSize(t *testing.T) {
- ctx := CreateContextMaxRequestSize(context.Background(), int64(8888))
-
- value := ctx.Value(ctxKeyMaxRequestSize{})
-
- assert.NotNil(t, ctx)
- assert.NotNil(t, value)
- assert.IsType(t, int64(0), value)
- assert.Equal(t, int64(8888), value.(int64))
-
- ctx = CreateContextMaxRequestSize(context.Background(), int64(0))
-
- value = ctx.Value(ctxKeyMaxRequestSize{})
-
- assert.NotNil(t, ctx)
- assert.NotNil(t, value)
- assert.IsType(t, int64(0), value)
- assert.Equal(t, int64(0), value.(int64))
-}
-
func TestContextOriginalRequestPathValue(t *testing.T) {
testcases := []struct {
name string
diff --git a/vault/core.go b/vault/core.go
index 1d7573c1b8ef..e02e53a82e39 100644
--- a/vault/core.go
+++ b/vault/core.go
@@ -3999,22 +3999,24 @@ func (c *Core) LoadNodeID() (string, error) {
return hostname, nil
}
-// DetermineRoleFromLoginRequestFromBytes will determine the role that should be applied to a quota for a given
-// login request, accepting a byte payload
-func (c *Core) DetermineRoleFromLoginRequestFromBytes(ctx context.Context, mountPoint string, payload []byte) string {
- data := make(map[string]interface{})
- err := jsonutil.DecodeJSON(payload, &data)
- if err != nil {
- // Cannot discern a role from a request we cannot parse
+// DetermineRoleFromLoginRequest will determine the role that should be applied to a quota for a given
+// login request
+func (c *Core) DetermineRoleFromLoginRequest(ctx context.Context, mountPoint string, data map[string]interface{}) string {
+ c.authLock.RLock()
+ defer c.authLock.RUnlock()
+ matchingBackend := c.router.MatchingBackend(ctx, mountPoint)
+ if matchingBackend == nil || matchingBackend.Type() != logical.TypeCredential {
+ // Role based quotas do not apply to this request
return ""
}
-
- return c.DetermineRoleFromLoginRequest(ctx, mountPoint, data)
+ return c.doResolveRoleLocked(ctx, mountPoint, matchingBackend, data)
}
-// DetermineRoleFromLoginRequest will determine the role that should be applied to a quota for a given
-// login request
-func (c *Core) DetermineRoleFromLoginRequest(ctx context.Context, mountPoint string, data map[string]interface{}) string {
+// DetermineRoleFromLoginRequestFromReader will determine the role that should
+// be applied to a quota for a given login request. The reader will only be
+// consumed if the matching backend for the mount point exists and is a secret
+// backend
+func (c *Core) DetermineRoleFromLoginRequestFromReader(ctx context.Context, mountPoint string, reader io.Reader) string {
c.authLock.RLock()
defer c.authLock.RUnlock()
matchingBackend := c.router.MatchingBackend(ctx, mountPoint)
@@ -4023,6 +4025,17 @@ func (c *Core) DetermineRoleFromLoginRequest(ctx context.Context, mountPoint str
return ""
}
+ data := make(map[string]interface{})
+ err := jsonutil.DecodeJSONFromReader(reader, &data)
+ if err != nil {
+ return ""
+ }
+ return c.doResolveRoleLocked(ctx, mountPoint, matchingBackend, data)
+}
+
+// doResolveRoleLocked does a login and resolve role request on the matching
+// backend. Callers should have a read lock on c.authLock
+func (c *Core) doResolveRoleLocked(ctx context.Context, mountPoint string, matchingBackend logical.Backend, data map[string]interface{}) string {
resp, err := matchingBackend.HandleRequest(ctx, &logical.Request{
MountPoint: mountPoint,
Path: "login",
diff --git a/vault/logical_system_raft.go b/vault/logical_system_raft.go
index d270d1d39bfd..7b254076051a 100644
--- a/vault/logical_system_raft.go
+++ b/vault/logical_system_raft.go
@@ -570,7 +570,8 @@ func (b *SystemBackend) handleStorageRaftSnapshotWrite(force bool, makeSealer fu
if !ok {
return logical.ErrorResponse("raft storage is not in use"), logical.ErrInvalidRequest
}
- if req.HTTPRequest == nil || req.HTTPRequest.Body == nil {
+ body, ok := logical.ContextOriginalBodyValue(ctx)
+ if !ok {
return nil, errors.New("no reader for request")
}
@@ -583,7 +584,7 @@ func (b *SystemBackend) handleStorageRaftSnapshotWrite(force bool, makeSealer fu
// don't have to hold the full snapshot in memory. We also want to do
// the restore in two parts so we can restore the snapshot while the
// stateLock is write locked.
- snapFile, cleanup, metadata, err := raftStorage.WriteSnapshotToTemp(req.HTTPRequest.Body, sealer)
+ snapFile, cleanup, metadata, err := raftStorage.WriteSnapshotToTemp(body, sealer)
switch {
case err == nil:
case strings.Contains(err.Error(), "failed to open the sealed hashes"):
diff --git a/vault/request_handling.go b/vault/request_handling.go
index b8296f34f115..034146b5c002 100644
--- a/vault/request_handling.go
+++ b/vault/request_handling.go
@@ -581,6 +581,10 @@ func (c *Core) switchedLockHandleRequest(httpCtx context.Context, req *logical.R
if disable_repl_status, ok := logical.ContextDisableReplicationStatusEndpointsValue(httpCtx); ok {
ctx = logical.CreateContextDisableReplicationStatusEndpoints(ctx, disable_repl_status)
}
+ body, ok := logical.ContextOriginalBodyValue(httpCtx)
+ if ok {
+ ctx = logical.CreateContextOriginalBody(ctx, body)
+ }
resp, err = c.handleCancelableRequest(ctx, req)
req.SetTokenEntry(nil)
cancel()
From aa9b02307d847ca0db960c3b4672018a8db6399d Mon Sep 17 00:00:00 2001
From: Milena Zlaticanin <60530402+Zlaticanin@users.noreply.github.com>
Date: Mon, 4 Dec 2023 15:41:25 -0700
Subject: [PATCH 67/74] Update Azure Secrets docs (#24279)
---
website/content/api-docs/secret/azure.mdx | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/website/content/api-docs/secret/azure.mdx b/website/content/api-docs/secret/azure.mdx
index f0ced9b035ca..2124e64b4958 100644
--- a/website/content/api-docs/secret/azure.mdx
+++ b/website/content/api-docs/secret/azure.mdx
@@ -212,6 +212,9 @@ information about roles.
suffixed strings ("1h") or an integer number of seconds. Defaults to the system/engine max TTL time.
- `permanently_delete` (`bool: false`) - Specifies whether to permanently delete Applications and Service Principals that are dynamically
created by Vault. If `application_object_id` is present, `permanently_delete` must be `false`.
+- `sign_in_audience` (`string: ""`) - Specifies the security principal types that are allowed to sign in to the application.
+ Valid values are: AzureADMyOrg, AzureADMultipleOrgs, AzureADandPersonalMicrosoftAccount, PersonalMicrosoftAccount.
+- `tags` (`string: ""`) - A comma-separated string of Azure tags to attach to an application.
### Sample payload
@@ -229,6 +232,8 @@ information about roles.
]",
"ttl": 3600,
"max_ttl": "24h"
+ "sign_in_audience": "AzureADMyOrg"
+ "tags": "team:engineering","environment:development"
}
```
From 6e020e38e008f489da5d454eee64d291bdf926f8 Mon Sep 17 00:00:00 2001
From: divyaac
Date: Mon, 4 Dec 2023 14:51:44 -0800
Subject: [PATCH 68/74] Add_Chroot_Namespace_In_Response (#24355)
---
http/handler.go | 22 +++++++++++++---------
http/logical.go | 19 ++++++++++---------
http/logical_test.go | 8 ++++----
http/sys_seal.go | 4 ++--
sdk/logical/request.go | 3 +++
vault/logical_system.go | 2 ++
vault/logical_system_integ_test.go | 3 ++-
vault/logical_system_paths.go | 4 ++++
8 files changed, 40 insertions(+), 25 deletions(-)
diff --git a/http/handler.go b/http/handler.go
index c3f49d32b62b..2e1db26aa0af 100644
--- a/http/handler.go
+++ b/http/handler.go
@@ -151,6 +151,10 @@ func handler(props *vault.HandlerProperties) http.Handler {
// Create the muxer to handle the actual endpoints
mux := http.NewServeMux()
+ var chrootNamespace string
+ if props.ListenerConfig != nil {
+ chrootNamespace = props.ListenerConfig.ChrootNamespace
+ }
switch {
case props.RecoveryMode:
@@ -161,8 +165,8 @@ func handler(props *vault.HandlerProperties) http.Handler {
mux.Handle("/v1/sys/generate-recovery-token/update", handleSysGenerateRootUpdate(core, strategy))
default:
// Handle non-forwarded paths
- mux.Handle("/v1/sys/config/state/", handleLogicalNoForward(core))
- mux.Handle("/v1/sys/host-info", handleLogicalNoForward(core))
+ mux.Handle("/v1/sys/config/state/", handleLogicalNoForward(core, chrootNamespace))
+ mux.Handle("/v1/sys/host-info", handleLogicalNoForward(core, chrootNamespace))
mux.Handle("/v1/sys/init", handleSysInit(core))
mux.Handle("/v1/sys/seal-status", handleSysSealStatus(core,
@@ -177,7 +181,7 @@ func handler(props *vault.HandlerProperties) http.Handler {
mux.Handle("/v1/sys/health", handleSysHealth(core,
WithRedactClusterName(props.ListenerConfig.RedactClusterName),
WithRedactVersion(props.ListenerConfig.RedactVersion)))
- mux.Handle("/v1/sys/monitor", handleLogicalNoForward(core))
+ mux.Handle("/v1/sys/monitor", handleLogicalNoForward(core, chrootNamespace))
mux.Handle("/v1/sys/generate-root/attempt", handleRequestForwarding(core,
handleAuditNonLogical(core, handleSysGenerateRootAttempt(core, vault.GenerateStandardRootTokenStrategy))))
mux.Handle("/v1/sys/generate-root/update", handleRequestForwarding(core,
@@ -193,10 +197,10 @@ func handler(props *vault.HandlerProperties) http.Handler {
mux.Handle("/v1/sys/internal/ui/feature-flags", handleSysInternalFeatureFlags(core))
for _, path := range injectDataIntoTopRoutes {
- mux.Handle(path, handleRequestForwarding(core, handleLogicalWithInjector(core)))
+ mux.Handle(path, handleRequestForwarding(core, handleLogicalWithInjector(core, chrootNamespace)))
}
- mux.Handle("/v1/sys/", handleRequestForwarding(core, handleLogical(core)))
- mux.Handle("/v1/", handleRequestForwarding(core, handleLogical(core)))
+ mux.Handle("/v1/sys/", handleRequestForwarding(core, handleLogical(core, chrootNamespace)))
+ mux.Handle("/v1/", handleRequestForwarding(core, handleLogical(core, chrootNamespace)))
if core.UIEnabled() {
if uiBuiltIn {
mux.Handle("/ui/", http.StripPrefix("/ui/", gziphandler.GzipHandler(handleUIHeaders(core, handleUI(http.FileServer(&UIAssetWrapper{FileSystem: assetFS()}))))))
@@ -213,7 +217,7 @@ func handler(props *vault.HandlerProperties) http.Handler {
if props.ListenerConfig != nil && props.ListenerConfig.Telemetry.UnauthenticatedMetricsAccess {
mux.Handle("/v1/sys/metrics", handleMetricsUnauthenticated(core))
} else {
- mux.Handle("/v1/sys/metrics", handleLogicalNoForward(core))
+ mux.Handle("/v1/sys/metrics", handleLogicalNoForward(core, chrootNamespace))
}
if props.ListenerConfig != nil && props.ListenerConfig.Profiling.UnauthenticatedPProfAccess {
@@ -226,13 +230,13 @@ func handler(props *vault.HandlerProperties) http.Handler {
mux.Handle("/v1/sys/pprof/symbol", http.HandlerFunc(pprof.Symbol))
mux.Handle("/v1/sys/pprof/trace", http.HandlerFunc(pprof.Trace))
} else {
- mux.Handle("/v1/sys/pprof/", handleLogicalNoForward(core))
+ mux.Handle("/v1/sys/pprof/", handleLogicalNoForward(core, chrootNamespace))
}
if props.ListenerConfig != nil && props.ListenerConfig.InFlightRequestLogging.UnauthenticatedInFlightAccess {
mux.Handle("/v1/sys/in-flight-req", handleUnAuthenticatedInFlightRequest(core))
} else {
- mux.Handle("/v1/sys/in-flight-req", handleLogicalNoForward(core))
+ mux.Handle("/v1/sys/in-flight-req", handleLogicalNoForward(core, chrootNamespace))
}
entAdditionalRoutes(mux, core)
}
diff --git a/http/logical.go b/http/logical.go
index c76c0462c068..6ef1daa7a694 100644
--- a/http/logical.go
+++ b/http/logical.go
@@ -257,11 +257,12 @@ func buildLogicalPath(r *http.Request) (string, int, error) {
return path, 0, nil
}
-func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Request) (*logical.Request, io.ReadCloser, int, error) {
+func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Request, chrootNamespace string) (*logical.Request, io.ReadCloser, int, error) {
req, origBody, status, err := buildLogicalRequestNoAuth(core.PerfStandby(), core.RouterAccess(), w, r)
if err != nil || status != 0 {
return nil, nil, status, err
}
+ req.ChrootNamespace = chrootNamespace
req.SetRequiredState(r.Header.Values(VaultIndexHeaderName))
requestAuth(r, req)
@@ -290,22 +291,22 @@ func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Reques
// - Perf standby and token with limited use count.
// - Perf standby and token re-validation needed (e.g. due to invalid token).
// - Perf standby and control group error.
-func handleLogical(core *vault.Core) http.Handler {
- return handleLogicalInternal(core, false, false)
+func handleLogical(core *vault.Core, chrootNamespace string) http.Handler {
+ return handleLogicalInternal(core, false, false, chrootNamespace)
}
// handleLogicalWithInjector returns a handler for processing logical requests
// that also have their logical response data injected at the top-level payload.
// All forwarding behavior remains the same as `handleLogical`.
-func handleLogicalWithInjector(core *vault.Core) http.Handler {
- return handleLogicalInternal(core, true, false)
+func handleLogicalWithInjector(core *vault.Core, chrootNamespace string) http.Handler {
+ return handleLogicalInternal(core, true, false, chrootNamespace)
}
// handleLogicalNoForward returns a handler for processing logical local-only
// requests. These types of requests never forwarded, and return an
// `vault.ErrCannotForwardLocalOnly` error if attempted to do so.
-func handleLogicalNoForward(core *vault.Core) http.Handler {
- return handleLogicalInternal(core, false, true)
+func handleLogicalNoForward(core *vault.Core, chrootNamespace string) http.Handler {
+ return handleLogicalInternal(core, false, true, chrootNamespace)
}
func handleLogicalRecovery(raw *vault.RawBackend, token *atomic.String) http.Handler {
@@ -338,9 +339,9 @@ func handleLogicalRecovery(raw *vault.RawBackend, token *atomic.String) http.Han
// handleLogicalInternal is a common helper that returns a handler for
// processing logical requests. The behavior depends on the various boolean
// toggles. Refer to usage on functions for possible behaviors.
-func handleLogicalInternal(core *vault.Core, injectDataIntoTopLevel bool, noForward bool) http.Handler {
+func handleLogicalInternal(core *vault.Core, injectDataIntoTopLevel bool, noForward bool, chrootNamespace string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- req, origBody, statusCode, err := buildLogicalRequest(core, w, r)
+ req, origBody, statusCode, err := buildLogicalRequest(core, w, r, chrootNamespace)
if err != nil || statusCode != 0 {
respondError(w, statusCode, err)
return
diff --git a/http/logical_test.go b/http/logical_test.go
index cc85967774b9..e5b0caf222d6 100644
--- a/http/logical_test.go
+++ b/http/logical_test.go
@@ -323,7 +323,7 @@ func TestLogical_ListSuffix(t *testing.T) {
req = req.WithContext(namespace.RootContext(nil))
req.Header.Add(consts.AuthHeaderName, rootToken)
- lreq, _, status, err := buildLogicalRequest(core, nil, req)
+ lreq, _, status, err := buildLogicalRequest(core, nil, req, "")
if err != nil {
t.Fatal(err)
}
@@ -338,7 +338,7 @@ func TestLogical_ListSuffix(t *testing.T) {
req = req.WithContext(namespace.RootContext(nil))
req.Header.Add(consts.AuthHeaderName, rootToken)
- lreq, _, status, err = buildLogicalRequest(core, nil, req)
+ lreq, _, status, err = buildLogicalRequest(core, nil, req, "")
if err != nil {
t.Fatal(err)
}
@@ -358,7 +358,7 @@ func TestLogical_ListSuffix(t *testing.T) {
t.Fatal(err)
}
- lreq, _, status, err = buildLogicalRequest(core, nil, req)
+ lreq, _, status, err = buildLogicalRequest(core, nil, req, "")
if err != nil {
t.Fatal(err)
}
@@ -517,7 +517,7 @@ func TestLogical_ListWithQueryParameters(t *testing.T) {
req = req.WithContext(namespace.RootContext(nil))
req.Header.Add(consts.AuthHeaderName, rootToken)
- lreq, _, status, err := buildLogicalRequest(core, nil, req)
+ lreq, _, status, err := buildLogicalRequest(core, nil, req, "")
if err != nil {
t.Fatal(err)
}
diff --git a/http/sys_seal.go b/http/sys_seal.go
index 14bfa41b0015..a17c6eb660b2 100644
--- a/http/sys_seal.go
+++ b/http/sys_seal.go
@@ -18,7 +18,7 @@ import (
func handleSysSeal(core *vault.Core) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- req, _, statusCode, err := buildLogicalRequest(core, w, r)
+ req, _, statusCode, err := buildLogicalRequest(core, w, r, "")
if err != nil || statusCode != 0 {
respondError(w, statusCode, err)
return
@@ -48,7 +48,7 @@ func handleSysSeal(core *vault.Core) http.Handler {
func handleSysStepDown(core *vault.Core) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- req, _, statusCode, err := buildLogicalRequest(core, w, r)
+ req, _, statusCode, err := buildLogicalRequest(core, w, r, "")
if err != nil || statusCode != 0 {
respondError(w, statusCode, err)
return
diff --git a/sdk/logical/request.go b/sdk/logical/request.go
index 176b7013a3f0..4f75bbd6d8e3 100644
--- a/sdk/logical/request.go
+++ b/sdk/logical/request.go
@@ -248,6 +248,9 @@ type Request struct {
// When a request has been forwarded, contains information of the host the request was forwarded 'from'
ForwardedFrom string `json:"forwarded_from,omitempty"`
+
+ // Name of the chroot namespace for the listener that the request was made against
+ ChrootNamespace string `json:"chroot_namespace,omitempty"`
}
// Clone returns a deep copy of the request by using copystructure
diff --git a/vault/logical_system.go b/vault/logical_system.go
index 67b674105d7b..bd5c93e22742 100644
--- a/vault/logical_system.go
+++ b/vault/logical_system.go
@@ -4708,6 +4708,8 @@ func (b *SystemBackend) pathInternalUIResultantACL(ctx context.Context, req *log
},
}
+ resp.Data["chroot_namespace"] = req.ChrootNamespace
+
if acl.root {
resp.Data["root"] = true
return resp, nil
diff --git a/vault/logical_system_integ_test.go b/vault/logical_system_integ_test.go
index d1ff71d10251..644aaec0a688 100644
--- a/vault/logical_system_integ_test.go
+++ b/vault/logical_system_integ_test.go
@@ -144,7 +144,8 @@ func TestSystemBackend_InternalUIResultantACL(t *testing.T) {
},
},
},
- "root": false,
+ "root": false,
+ "chroot_namespace": "",
}
if diff := deep.Equal(resp.Data, exp); diff != nil {
diff --git a/vault/logical_system_paths.go b/vault/logical_system_paths.go
index db0b52583ee9..60e56d31824c 100644
--- a/vault/logical_system_paths.go
+++ b/vault/logical_system_paths.go
@@ -2642,6 +2642,10 @@ func (b *SystemBackend) internalPaths() []*framework.Path {
Type: framework.TypeMap,
Required: false,
},
+ "chroot_namespace": {
+ Type: framework.TypeString,
+ Required: true,
+ },
},
}},
},
From 9e063f31d7c29481c6b3d632947ed7a58017a5da Mon Sep 17 00:00:00 2001
From: Ben Ash <32777270+benashz@users.noreply.github.com>
Date: Mon, 4 Dec 2023 20:29:31 -0500
Subject: [PATCH 69/74] Update VSO docs for v0.4.1 (#24356)
---
website/content/docs/platform/k8s/vso/helm.mdx | 5 ++---
.../content/docs/platform/k8s/vso/installation.mdx | 14 +++++++-------
.../content/docs/platform/k8s/vso/openshift.mdx | 4 ++--
3 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/website/content/docs/platform/k8s/vso/helm.mdx b/website/content/docs/platform/k8s/vso/helm.mdx
index 864c6b4c6943..957db87aa30a 100644
--- a/website/content/docs/platform/k8s/vso/helm.mdx
+++ b/website/content/docs/platform/k8s/vso/helm.mdx
@@ -119,7 +119,7 @@ Use these links to navigate to a particular top-level stanza.
- `repository` ((#v-controller-manager-image-repository)) (`string: hashicorp/vault-secrets-operator`)
- - `tag` ((#v-controller-manager-image-tag)) (`string: 0.4.0`)
+ - `tag` ((#v-controller-manager-image-tag)) (`string: 0.4.1`)
- `clientCache` ((#v-controller-manager-clientcache)) - Configures the client cache which is used by the controller to cache (and potentially persist) vault tokens that
are the result of using the VaultAuthMethod. This enables re-use of Vault Tokens
@@ -262,8 +262,7 @@ Use these links to navigate to a particular top-level stanza.
headers:
X-vault-something1: "foo"
- - `maxConcurrentReconciles` ((#v-controller-manager-maxconcurrentreconciles)) (`integer: ""`) - Defines the maximum number of concurrent reconciles by the controller.
- NOTE: Currently this is only used by the reconciliation logic of dynamic secrets.
+ - `maxConcurrentReconciles` ((#v-controller-manager-maxconcurrentreconciles)) (`integer: ""`) - Defines the maximum number of concurrent reconciles for each controller.
default: 100
diff --git a/website/content/docs/platform/k8s/vso/installation.mdx b/website/content/docs/platform/k8s/vso/installation.mdx
index b99861c7b979..34b6ad402c7f 100644
--- a/website/content/docs/platform/k8s/vso/installation.mdx
+++ b/website/content/docs/platform/k8s/vso/installation.mdx
@@ -30,13 +30,13 @@ $ helm repo add hashicorp https://helm.releases.hashicorp.com
```shell-session
$ helm search repo hashicorp/vault-secrets-operator
NAME CHART VERSION APP VERSION DESCRIPTION
-hashicorp/vault-secrets-operator 0.4.0 0.4.0 Official HashiCorp Vault Secrets Operator Chart
+hashicorp/vault-secrets-operator 0.4.1 0.4.1 Official HashiCorp Vault Secrets Operator Chart
```
Then install the Operator:
```shell-session
-$ helm install --version 0.4.0 --create-namespace --namespace vault-secrets-operator vault-secrets-operator hashicorp/vault-secrets-operator
+$ helm install --version 0.4.1 --create-namespace --namespace vault-secrets-operator vault-secrets-operator hashicorp/vault-secrets-operator
```
@@ -65,10 +65,10 @@ $ helm show crds --version hashicorp/vault-secrets-operator
$ helm upgrade --version --namespace vault-secrets-operator vault-secrets-operator hashicorp/vault-secrets-operator
```
-For example, if you are upgrading to VSO 0.4.0:
+For example, if you are upgrading to VSO 0.4.1:
```shell-session
-$ helm show crds --version 0.4.0 hashicorp/vault-secrets-operator | kubectl apply -f -
-$ helm upgrade --version 0.4.0 --namespace vault-secrets-operator vault-secrets-operator hashicorp/vault-secrets-operator
+$ helm show crds --version 0.4.1 hashicorp/vault-secrets-operator | kubectl apply -f -
+$ helm upgrade --version 0.4.1 --namespace vault-secrets-operator vault-secrets-operator hashicorp/vault-secrets-operator
```
## Updating CRDs
@@ -83,9 +83,9 @@ To update the VSO CRDs, replace `` with the VSO version you
$ helm show crds --version hashicorp/vault-secrets-operator | kubectl apply -f -
```
-For example, if you are upgrading to VSO 0.4.0:
+For example, if you are upgrading to VSO 0.4.1:
```shell-session
-$ helm show crds --version 0.4.0 hashicorp/vault-secrets-operator | kubectl apply -f -
+$ helm show crds --version 0.4.1 hashicorp/vault-secrets-operator | kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/hcpauths.secrets.hashicorp.com created
customresourcedefinition.apiextensions.k8s.io/hcpvaultsecretsapps.secrets.hashicorp.com created
diff --git a/website/content/docs/platform/k8s/vso/openshift.mdx b/website/content/docs/platform/k8s/vso/openshift.mdx
index a05f68ff982b..465c5f1bc7bd 100644
--- a/website/content/docs/platform/k8s/vso/openshift.mdx
+++ b/website/content/docs/platform/k8s/vso/openshift.mdx
@@ -23,7 +23,7 @@ The Vault Secrets Operator may also be installed in OpenShift using the Helm cha
$ helm install vault-secrets-operator hashicorp/vault-secrets-operator \
--create-namespace \
--namespace vault-secrets-operator \
- --version 0.4.0 \
+ --version 0.4.1 \
--values values.yaml
```
@@ -56,7 +56,7 @@ controller:
manager:
image:
repository: registry.connect.redhat.com/hashicorp/vault-secrets-operator
- tag: 0.4.0-ubi
+ tag: 0.4.1-ubi
resources:
limits:
memory: 256Mi
From fcbdd5bd2208bdfe8745a980b04797bbe775a037 Mon Sep 17 00:00:00 2001
From: Peter Wilson
Date: Tue, 5 Dec 2023 11:28:11 +0000
Subject: [PATCH 70/74] Adjust TestSudoPaths to remove audit (#24357)
---
vault/external_tests/api/sudo_paths_test.go | 26 ++++++++++-----------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/vault/external_tests/api/sudo_paths_test.go b/vault/external_tests/api/sudo_paths_test.go
index 5d9e7516bbbd..50cccf8579ad 100644
--- a/vault/external_tests/api/sudo_paths_test.go
+++ b/vault/external_tests/api/sudo_paths_test.go
@@ -9,8 +9,11 @@ import (
"testing"
"github.com/hashicorp/vault/api"
+ "github.com/hashicorp/vault/builtin/logical/pki"
"github.com/hashicorp/vault/helper/builtinplugins"
+ "github.com/hashicorp/vault/helper/testhelpers/minimal"
"github.com/hashicorp/vault/sdk/helper/jsonutil"
+ "github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault"
)
@@ -24,19 +27,17 @@ func TestSudoPaths(t *testing.T) {
EnableRaw: true,
EnableIntrospection: true,
BuiltinRegistry: builtinplugins.Registry,
+ LogicalBackends: map[string]logical.Factory{
+ "pki": pki.Factory,
+ },
}
- client, _, closer := testVaultServerCoreConfig(t, coreConfig)
- defer closer()
- // At present there are no auth methods with sudo paths, except for the automatically mounted token backend
- for _, credBackendName := range []string{} {
- err := client.Sys().EnableAuthWithOptions(credBackendName, &api.EnableAuthOptions{
- Type: credBackendName,
- })
- if err != nil {
- t.Fatalf("error enabling auth backend for test: %v", err)
- }
- }
+ cluster := minimal.NewTestSoloCluster(t, coreConfig)
+ client := cluster.Cores[0].Client
+
+ // NOTE: At present there are no auth methods with sudo paths, except for the
+ // automatically mounted token backend. If this changes this test should be
+ // updated to iterate over the auth methods and test them as we are doing below.
// Each secrets engine that contains sudo paths (other than automatically mounted ones) must be mounted here
for _, logicalBackendName := range []string{"pki"} {
@@ -80,8 +81,7 @@ func TestSudoPaths(t *testing.T) {
}
func getSudoPathsFromSpec(client *api.Client) (map[string]struct{}, error) {
- r := client.NewRequest("GET", "/v1/sys/internal/specs/openapi")
- resp, err := client.RawRequest(r)
+ resp, err := client.Logical().ReadRaw("sys/internal/specs/openapi")
if err != nil {
return nil, fmt.Errorf("unable to retrieve sudo endpoints: %v", err)
}
From 807aa51d7d9e1d9c38a190f87f0cfb340a3cc0a4 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
Date: Tue, 5 Dec 2023 12:04:33 -0600
Subject: [PATCH 71/74] UI: fix ent tests (#24375)
---
ui/tests/acceptance/enterprise-reduced-disclosure-test.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ui/tests/acceptance/enterprise-reduced-disclosure-test.js b/ui/tests/acceptance/enterprise-reduced-disclosure-test.js
index ccce7369953a..93976d204d9d 100644
--- a/ui/tests/acceptance/enterprise-reduced-disclosure-test.js
+++ b/ui/tests/acceptance/enterprise-reduced-disclosure-test.js
@@ -6,7 +6,7 @@
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
-import { settled, visit } from '@ember/test-helpers';
+import { click, currentRouteName, currentURL, fillIn, settled, visit } from '@ember/test-helpers';
import authPage from 'vault/tests/pages/auth';
import { createTokenCmd, runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/commands';
import { pollCluster } from 'vault/tests/helpers/poll-cluster';
@@ -24,7 +24,7 @@ module('Acceptance | Enterprise | reduced disclosure test', function (hooks) {
setupMirage(hooks);
hooks.before(function () {
- ENV['ember-cli-mirage'].handler = 'mfaConfig';
+ ENV['ember-cli-mirage'].handler = 'reducedDisclosure';
});
hooks.beforeEach(function () {
this.versionSvc = this.owner.lookup('service:version');
From a41852379b5b5424bb5d508e702c7ec2a8295820 Mon Sep 17 00:00:00 2001
From: Steven Clark
Date: Tue, 5 Dec 2023 15:26:03 -0500
Subject: [PATCH 72/74] Document and augment tests that PKI accepts 8192 bit
RSA keys (#24364)
- Noticed that our documentation was out of date, we allow 8192
bit RSA keys to be used as an argument to the various PKI
issuer/key creation APIs.
- Augument some unit tests to verify this continues to work
---
builtin/logical/pki/backend_test.go | 2 +-
builtin/logical/pki/fields.go | 5 ++---
builtin/logical/pki/path_manage_keys.go | 5 ++---
builtin/logical/pki/path_manage_keys_test.go | 2 +-
website/content/api-docs/secret/pki.mdx | 20 ++++++++++----------
5 files changed, 16 insertions(+), 18 deletions(-)
diff --git a/builtin/logical/pki/backend_test.go b/builtin/logical/pki/backend_test.go
index 824d3cf8110d..d84cd64cadca 100644
--- a/builtin/logical/pki/backend_test.go
+++ b/builtin/logical/pki/backend_test.go
@@ -1220,7 +1220,7 @@ func generateRoleSteps(t *testing.T, useCSRs bool) []logicaltest.TestStep {
}
getRandCsr := func(keyType string, errorOk bool, csrTemplate *x509.CertificateRequest) csrPlan {
- rsaKeyBits := []int{2048, 3072, 4096}
+ rsaKeyBits := []int{2048, 3072, 4096, 8192}
ecKeyBits := []int{224, 256, 384, 521}
plan := csrPlan{errorOk: errorOk}
diff --git a/builtin/logical/pki/fields.go b/builtin/logical/pki/fields.go
index e637ac27fa90..117497893b8d 100644
--- a/builtin/logical/pki/fields.go
+++ b/builtin/logical/pki/fields.go
@@ -324,9 +324,8 @@ is required. Ignored for other types.`,
Type: framework.TypeInt,
Default: 0,
Description: `The number of bits to use. Allowed values are
-0 (universal default); with rsa key_type: 2048 (default), 3072, or
-4096; with ec key_type: 224, 256 (default), 384, or 521; ignored with
-ed25519.`,
+0 (universal default); with rsa key_type: 2048 (default), 3072, 4096 or 8192;
+with ec key_type: 224, 256 (default), 384, or 521; ignored with ed25519.`,
DisplayAttrs: &framework.DisplayAttributes{
Value: 0,
},
diff --git a/builtin/logical/pki/path_manage_keys.go b/builtin/logical/pki/path_manage_keys.go
index 63e8ac668a58..0b1f932f8bb7 100644
--- a/builtin/logical/pki/path_manage_keys.go
+++ b/builtin/logical/pki/path_manage_keys.go
@@ -44,9 +44,8 @@ func pathGenerateKey(b *backend) *framework.Path {
Type: framework.TypeInt,
Default: 0,
Description: `The number of bits to use. Allowed values are
-0 (universal default); with rsa key_type: 2048 (default), 3072, or
-4096; with ec key_type: 224, 256 (default), 384, or 521; ignored with
-ed25519.`,
+0 (universal default); with rsa key_type: 2048 (default), 3072, 4096 or 8192;
+with ec key_type: 224, 256 (default), 384, or 521; ignored with ed25519.`,
},
"managed_key_name": {
Type: framework.TypeString,
diff --git a/builtin/logical/pki/path_manage_keys_test.go b/builtin/logical/pki/path_manage_keys_test.go
index 68d31ef862f2..7480b2ed3ff9 100644
--- a/builtin/logical/pki/path_manage_keys_test.go
+++ b/builtin/logical/pki/path_manage_keys_test.go
@@ -31,7 +31,7 @@ func TestPKI_PathManageKeys_GenerateInternalKeys(t *testing.T) {
wantLogicalErr bool
}{
{"all-defaults", "", []int{0}, false},
- {"rsa", "rsa", []int{0, 2048, 3072, 4096}, false},
+ {"rsa", "rsa", []int{0, 2048, 3072, 4096, 8192}, false},
{"ec", "ec", []int{0, 224, 256, 384, 521}, false},
{"ed25519", "ed25519", []int{0}, false},
{"error-rsa", "rsa", []int{-1, 343444}, true},
diff --git a/website/content/api-docs/secret/pki.mdx b/website/content/api-docs/secret/pki.mdx
index 6a87cf51685c..44a3b072a566 100644
--- a/website/content/api-docs/secret/pki.mdx
+++ b/website/content/api-docs/secret/pki.mdx
@@ -751,8 +751,8 @@ engine override the issuer as necessary.
- `key_bits` `(int: 0)` - Specifies the number of bits to use for the
generated keys. Allowed values are 0 (universal default); with
- `key_type=rsa`, allowed values are: 2048 (default), 3072, or
- 4096; with `key_type=ec`, allowed values are: 224, 256 (default),
+ `key_type=rsa`, allowed values are: 2048 (default), 3072, 4096 or 8192;
+ with `key_type=ec`, allowed values are: 224, 256 (default),
384, or 521; ignored with `key_type=ed25519`.
- `private_key_format` `(string: "der")` - Specifies the format for marshaling
@@ -2194,8 +2194,8 @@ used.
- `key_bits` `(int: 0)` - Specifies the number of bits to use for the
generated keys. Allowed values are 0 (universal default); with
- `key_type=rsa`, allowed values are: 2048 (default), 3072, or
- 4096; with `key_type=ec`, allowed values are: 224, 256 (default),
+ `key_type=rsa`, allowed values are: 2048 (default), 3072, 4096 or 8192;
+ with `key_type=ec`, allowed values are: 224, 256 (default),
384, or 521; ignored with `key_type=ed25519`.
#### Managed keys parameters
@@ -2341,8 +2341,8 @@ use the values set via `config/urls`.
- `key_bits` `(int: 0)` - Specifies the number of bits to use for the
generated keys. Allowed values are 0 (universal default); with
- `key_type=rsa`, allowed values are: 2048 (default), 3072, or
- 4096; with `key_type=ec`, allowed values are: 224, 256 (default),
+ `key_type=rsa`, allowed values are: 2048 (default), 3072, 4096 or 8192;
+ with `key_type=ec`, allowed values are: 224, 256 (default),
384, or 521; ignored with `key_type=ed25519`.
- `max_path_length` `(int: -1)` - Specifies the maximum path length to encode in
@@ -2541,8 +2541,8 @@ generated depending on the `type` request parameter.
- `key_bits` `(int: 0)` - Specifies the number of bits to use for the
generated keys. Allowed values are 0 (universal default); with
- `key_type=rsa`, allowed values are: 2048 (default), 3072, or
- 4096; with `key_type=ec`, allowed values are: 224, 256 (default),
+ `key_type=rsa`, allowed values are: 2048 (default), 3072, 4096, or 8192;
+ with `key_type=ec`, allowed values are: 224, 256 (default),
384, or 521; ignored with `key_type=ed25519`. Not suitable for
`type=existing` requests.
@@ -3449,8 +3449,8 @@ request is denied.
- `key_bits` `(int: 0)` - Specifies the number of bits to use for the
generated keys. Allowed values are 0 (universal default); with
- `key_type=rsa`, allowed values are: 2048 (default), 3072, or
- 4096; with `key_type=ec`, allowed values are: 224, 256 (default),
+ `key_type=rsa`, allowed values are: 2048 (default), 3072, 4096 or 8192;
+ with `key_type=ec`, allowed values are: 224, 256 (default),
384, or 521; ignored with `key_type=ed25519` or in signing operations
when `key_type=any`.
From 588dd73fe0539d372de68ceae2b742fabfd7b40b Mon Sep 17 00:00:00 2001
From: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
Date: Tue, 5 Dec 2023 14:31:29 -0600
Subject: [PATCH 73/74] UI: handle reduced disclosure on replication endpoints
(#24379)
* add replicationRedacted attribute to cluster model
* disallow access to replication pages if repl endpoints are redacted
* hide replicatio nav item
* Hide replication card on dashboard
---
ui/app/adapters/cluster.js | 6 ++++++
ui/app/components/sidebar/nav/cluster.hbs | 9 ++++++++-
ui/app/models/cluster.js | 4 +++-
ui/app/routes/vault/cluster/dashboard.js | 13 +++++++------
ui/app/templates/components/dashboard/overview.hbs | 4 +++-
ui/lib/replication/addon/routes/application.js | 5 +++++
ui/mirage/handlers/reduced-disclosure.js | 10 +++++++---
.../enterprise-reduced-disclosure-test.js | 13 +++++++++++++
8 files changed, 52 insertions(+), 12 deletions(-)
diff --git a/ui/app/adapters/cluster.js b/ui/app/adapters/cluster.js
index 131d143e84cd..19f7682f7127 100644
--- a/ui/app/adapters/cluster.js
+++ b/ui/app/adapters/cluster.js
@@ -61,6 +61,12 @@ export default ApplicationAdapter.extend({
}
if (replicationStatus && replicationStatus instanceof AdapterError === false) {
ret = Object.assign(ret, replicationStatus.data);
+ } else if (
+ replicationStatus instanceof AdapterError &&
+ replicationStatus?.errors.find((err) => err === 'disabled path')
+ ) {
+ // set redacted if result is an error which only happens when redacted
+ ret = Object.assign(ret, { replication_redacted: true });
}
return resolve(ret);
});
diff --git a/ui/app/components/sidebar/nav/cluster.hbs b/ui/app/components/sidebar/nav/cluster.hbs
index 6668bade2e02..bb3c142de081 100644
--- a/ui/app/components/sidebar/nav/cluster.hbs
+++ b/ui/app/components/sidebar/nav/cluster.hbs
@@ -52,7 +52,14 @@
}}
Monitoring
{{/if}}
- {{#if (and this.version.isEnterprise this.namespace.inRootNamespace (has-permission "status" routeParams="replication"))}}
+ {{#if
+ (and
+ this.version.isEnterprise
+ this.namespace.inRootNamespace
+ (not this.cluster.replicationRedacted)
+ (has-permission "status" routeParams="replication")
+ )
+ }}
{{/if}}
- {{#if (and @isRootNamespace (has-permission "status" routeParams="replication"))}}
+ {{#if
+ (and @isRootNamespace (has-permission "status" routeParams="replication") (not (is-empty-value @replication)))
+ }}
{
return this._super(...arguments);
});
diff --git a/ui/mirage/handlers/reduced-disclosure.js b/ui/mirage/handlers/reduced-disclosure.js
index c0be1b072bfb..73fc189d36c2 100644
--- a/ui/mirage/handlers/reduced-disclosure.js
+++ b/ui/mirage/handlers/reduced-disclosure.js
@@ -4,6 +4,7 @@
*/
import modifyPassthroughResponse from '../helpers/modify-passthrough-response';
+import { Response } from 'miragejs';
export default function (server) {
server.get('/sys/health', (schema, req) =>
@@ -12,7 +13,10 @@ export default function (server) {
server.get('/sys/seal-status', (schema, req) =>
modifyPassthroughResponse(req, { version: '', cluster_name: '', build_date: '' })
);
- server.get('sys/replication/status', () => new Response(404));
- server.get('sys/replication/dr/status', () => new Response(404));
- server.get('sys/replication/performance/status', () => new Response(404));
+ server.get('sys/replication/status', () => new Response(404, {}, { errors: ['disabled path'] }));
+ server.get('sys/replication/dr/status', () => new Response(404, {}, { errors: ['disabled path'] }));
+ server.get(
+ 'sys/replication/performance/status',
+ () => new Response(404, {}, { errors: ['disabled path'] })
+ );
}
diff --git a/ui/tests/acceptance/enterprise-reduced-disclosure-test.js b/ui/tests/acceptance/enterprise-reduced-disclosure-test.js
index 93976d204d9d..ad5b8c332a1b 100644
--- a/ui/tests/acceptance/enterprise-reduced-disclosure-test.js
+++ b/ui/tests/acceptance/enterprise-reduced-disclosure-test.js
@@ -134,4 +134,17 @@ module('Acceptance | Enterprise | reduced disclosure test', function (hooks) {
.dom('[data-test-footer-version]')
.hasText(`Vault ${versionSvc.version}`, 'Version is shown after login');
});
+
+ test('does not allow access to replication pages', async function (assert) {
+ await authPage.login();
+ assert.dom('[data-test-sidebar-nav-link="Replication"]').doesNotExist('hides replication nav item');
+
+ await visit(`/vault/replication/dr`);
+ assert.strictEqual(
+ currentRouteName(),
+ 'vault.cluster.dashboard',
+ 'redirects to dashboard if replication access attempted'
+ );
+ assert.dom('[data-test-card="replication"]').doesNotExist('hides replication card on dashboard');
+ });
});
From 8f69e495926231f2be3b862adbba4da7c8485169 Mon Sep 17 00:00:00 2001
From: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
Date: Tue, 5 Dec 2023 13:49:36 -0800
Subject: [PATCH 74/74] UI: HDS Adoption upgrade to design-system-components:
3.3.0 and ember-flight-icons: 4.0.4 (#24366)
* upgrade to 3.1.0
* VAULT-22471 upgrade to latest version
* fix other selectors
* fix pki tests
* fix copy dropdown
* rename selectors to be consistent
---
ui/app/components/sidebar/user-menu.hbs | 1 +
ui/app/styles/helper-classes/layout.scss | 2 +-
.../addon/components/certificate-card.hbs | 6 +-
ui/lib/core/addon/components/code-snippet.hbs | 1 +
.../addon/components/copy-secret-dropdown.hbs | 2 +-
.../core/addon/components/info-table-row.hbs | 4 +-
ui/lib/core/addon/components/json-editor.hbs | 2 +-
ui/lib/core/addon/components/masked-input.hbs | 2 +-
.../kv/addon/components/page/secret/paths.hbs | 8 +-
ui/package.json | 4 +-
.../acceptance/pki/pki-cross-sign-test.js | 10 +-
.../components/certificate-card-test.js | 3 +-
.../components/copy-secret-dropdown-test.js | 6 +-
.../components/info-table-row-test.js | 2 +-
.../kv/page/kv-page-secret-paths-test.js | 10 +-
.../components/oidc/scope-form-test.js | 6 +-
.../components/pki/pki-generate-csr-test.js | 11 +-
.../components/sidebar/user-menu-test.js | 2 +-
ui/yarn.lock | 1683 +++++++++++++++--
19 files changed, 1538 insertions(+), 227 deletions(-)
diff --git a/ui/app/components/sidebar/user-menu.hbs b/ui/app/components/sidebar/user-menu.hbs
index fc8592a54f1f..b391b2d736e4 100644
--- a/ui/app/components/sidebar/user-menu.hbs
+++ b/ui/app/components/sidebar/user-menu.hbs
@@ -54,6 +54,7 @@
@container="#container"
class="in-dropdown link is-flex-start"
{{on "click" (fn (set-flash-message "Token copied!"))}}
+ data-test-copy-button={{this.auth.currentToken}}
/>
{{#if (is-before (now interval=1000) this.auth.tokenExpirationDate)}}
diff --git a/ui/app/styles/helper-classes/layout.scss b/ui/app/styles/helper-classes/layout.scss
index 4fa01150b685..83f778ef3ccf 100644
--- a/ui/app/styles/helper-classes/layout.scss
+++ b/ui/app/styles/helper-classes/layout.scss
@@ -68,7 +68,7 @@
}
.is-medium-width {
- width: $desktop / 3;
+ width: calc($desktop / 3);
}
.is-medium-height {
diff --git a/ui/lib/core/addon/components/certificate-card.hbs b/ui/lib/core/addon/components/certificate-card.hbs
index a089650e8f38..044067b817e1 100644
--- a/ui/lib/core/addon/components/certificate-card.hbs
+++ b/ui/lib/core/addon/components/certificate-card.hbs
@@ -20,13 +20,13 @@
{{@data}}
-
+
\ No newline at end of file
diff --git a/ui/lib/core/addon/components/code-snippet.hbs b/ui/lib/core/addon/components/code-snippet.hbs
index edd1e492f825..c5be6d878c33 100644
--- a/ui/lib/core/addon/components/code-snippet.hbs
+++ b/ui/lib/core/addon/components/code-snippet.hbs
@@ -15,5 +15,6 @@
@textToCopy={{or @clipboardCode @codeBlock}}
@isIconOnly={{@isIconOnly}}
@container={{@container}}
+ data-test-copy-button={{or @clipboardCode @codeBlock}}
/>
\ No newline at end of file
diff --git a/ui/lib/core/addon/components/copy-secret-dropdown.hbs b/ui/lib/core/addon/components/copy-secret-dropdown.hbs
index 0e50926c5e85..0818adddc5d6 100644
--- a/ui/lib/core/addon/components/copy-secret-dropdown.hbs
+++ b/ui/lib/core/addon/components/copy-secret-dropdown.hbs
@@ -19,7 +19,7 @@
@isFullWidth={{true}}
class="in-dropdown link is-flex-start"
{{on "click" (action (set-flash-message "JSON Copied!"))}}
- data-test-copy-button
+ data-test-copy-button={{@clipboardText}}
/>
diff --git a/ui/lib/core/addon/components/info-table-row.hbs b/ui/lib/core/addon/components/info-table-row.hbs
index 4a7d7c95b942..a79b00821694 100644
--- a/ui/lib/core/addon/components/info-table-row.hbs
+++ b/ui/lib/core/addon/components/info-table-row.hbs
@@ -41,7 +41,7 @@
@isIconOnly={{true}}
@textToCopy={{@value}}
class="transparent has-padding-xxs"
- data-test-copy-button
+ data-test-copy-button={{@value}}
/>
{{/if}}
{{#if (has-block)}}
@@ -95,7 +95,7 @@
@isIconOnly={{true}}
@textToCopy={{@tooltipText}}
class="transparent white-icon"
- data-test-tooltip-copy
+ data-test-tooltip-copy={{@tooltipText}}
/>
{{/if}}
diff --git a/ui/lib/core/addon/components/json-editor.hbs b/ui/lib/core/addon/components/json-editor.hbs
index b7b15e3b72e6..c3a29b72335b 100644
--- a/ui/lib/core/addon/components/json-editor.hbs
+++ b/ui/lib/core/addon/components/json-editor.hbs
@@ -32,7 +32,7 @@
@isIconOnly={{true}}
@textToCopy={{@value}}
class="transparent"
- data-test-copy-button
+ data-test-copy-button={{@value}}
/>
diff --git a/ui/lib/core/addon/components/masked-input.hbs b/ui/lib/core/addon/components/masked-input.hbs
index 221e6b0fbb8c..ae34e9289ab5 100644
--- a/ui/lib/core/addon/components/masked-input.hbs
+++ b/ui/lib/core/addon/components/masked-input.hbs
@@ -40,7 +40,7 @@
@isIconOnly={{true}}
@textToCopy={{@value}}
class="transparent has-padding-xxs"
- data-test-copy-button
+ data-test-copy-button={{or @value true}}
/>
{{/if}}
{{#if @allowDownload}}
diff --git a/ui/lib/kv/addon/components/page/secret/paths.hbs b/ui/lib/kv/addon/components/page/secret/paths.hbs
index eca19d362676..fd9a400d23bf 100644
--- a/ui/lib/kv/addon/components/page/secret/paths.hbs
+++ b/ui/lib/kv/addon/components/page/secret/paths.hbs
@@ -21,7 +21,13 @@
{{#each this.paths as |path|}}
-
+
{{path.snippet}}
diff --git a/ui/package.json b/ui/package.json
index 7e199ccd3df3..f82c2c3b15c7 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -247,8 +247,8 @@
]
},
"dependencies": {
- "@hashicorp/design-system-components": "^2.13.0",
- "@hashicorp/ember-flight-icons": "^3.1.3",
+ "@hashicorp/design-system-components": "^3.3.0",
+ "@hashicorp/ember-flight-icons": "^4.0.4",
"handlebars": "4.7.7",
"highlight.js": "^10.4.1",
"node-notifier": "^8.0.1",
diff --git a/ui/tests/acceptance/pki/pki-cross-sign-test.js b/ui/tests/acceptance/pki/pki-cross-sign-test.js
index 6403cc0bcb32..5ed81e6cf057 100644
--- a/ui/tests/acceptance/pki/pki-cross-sign-test.js
+++ b/ui/tests/acceptance/pki/pki-cross-sign-test.js
@@ -47,13 +47,13 @@ module('Acceptance | pki/pki cross sign', function (hooks) {
await fillIn(SELECTORS.inputByName('type'), 'internal');
await fillIn(SELECTORS.inputByName('commonName'), 'Short-Lived Int R1');
await click('[data-test-save]');
- const csr = find(SELECTORS.copyButton('CSR')).getAttribute('data-clipboard-text');
+ const csr = find(SELECTORS.copyButton('CSR')).getAttribute('data-test-copy-button');
await visit(`vault/secrets/${this.parentMountPath}/pki/issuers/${this.oldParentIssuerName}/sign`);
await fillIn(SELECTORS.inputByName('csr'), csr);
await fillIn(SELECTORS.inputByName('format'), 'pem_bundle');
await click('[data-test-pki-sign-intermediate-save]');
const pemBundle = find(SELECTORS.copyButton('CA Chain'))
- .getAttribute('data-clipboard-text')
+ .getAttribute('data-test-copy-button')
.replace(/,/, '\n');
await visit(`vault/secrets/${this.intMountPath}/pki/configuration/create`);
await click(SELECTORS.configure.optionByKey('import'));
@@ -64,7 +64,7 @@ module('Acceptance | pki/pki cross sign', function (hooks) {
await click('[data-test-is-default]');
// name default issuer of intermediate
const oldIntIssuerId = find(SELECTORS.rowValue('Issuer ID')).innerText;
- const oldIntCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-clipboard-text');
+ const oldIntCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-test-copy-button');
await click(SELECTORS.details.configure);
await fillIn(SELECTORS.inputByName('issuerName'), this.intIssuerName);
await click('[data-test-save]');
@@ -84,7 +84,7 @@ module('Acceptance | pki/pki cross sign', function (hooks) {
// get certificate data of newly signed issuer
await click(`${SELECTORS.signedIssuerCol('newCrossSignedIssuer')} a`);
- const newIntCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-clipboard-text');
+ const newIntCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-test-copy-button');
// verify cross-sign was accurate by creating a role to issue a leaf certificate
const myRole = 'some-role';
@@ -98,7 +98,7 @@ module('Acceptance | pki/pki cross sign', function (hooks) {
await fillIn(SELECTORS.inputByName('commonName'), 'my-leaf');
await fillIn('[data-test-ttl-value="TTL"]', '3600');
await click('[data-test-pki-generate-button]');
- const myLeafCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-clipboard-text');
+ const myLeafCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-test-copy-button');
// see comments in utils/parse-pki-cert.js for step-by-step explanation of of verifyCertificates method
assert.true(
diff --git a/ui/tests/integration/components/certificate-card-test.js b/ui/tests/integration/components/certificate-card-test.js
index e54fcbb3d08a..3d16b68cff8d 100644
--- a/ui/tests/integration/components/certificate-card-test.js
+++ b/ui/tests/integration/components/certificate-card-test.js
@@ -15,6 +15,7 @@ const SELECTORS = {
value: '[data-test-certificate-value]',
icon: '[data-test-certificate-icon]',
copyButton: '[data-test-copy-button]',
+ copyIcon: '[data-test-icon="clipboard-copy"]',
};
module('Integration | Component | certificate-card', function (hooks) {
@@ -26,7 +27,7 @@ module('Integration | Component | certificate-card', function (hooks) {
assert.dom(SELECTORS.label).hasNoText('There is no label because there is no value');
assert.dom(SELECTORS.value).hasNoText('There is no value because none was provided');
assert.dom(SELECTORS.icon).exists('The certificate icon exists');
- assert.dom(SELECTORS.copyButton).exists('The copy button exists');
+ assert.dom(SELECTORS.copyIcon).exists('The copy icon renders');
});
test('it renders with an example PEM Certificate', async function (assert) {
diff --git a/ui/tests/integration/components/copy-secret-dropdown-test.js b/ui/tests/integration/components/copy-secret-dropdown-test.js
index 26c88dd9c4bd..3729c07e7d12 100644
--- a/ui/tests/integration/components/copy-secret-dropdown-test.js
+++ b/ui/tests/integration/components/copy-secret-dropdown-test.js
@@ -11,7 +11,7 @@ import { hbs } from 'ember-cli-htmlbars';
const SELECTORS = {
dropdown: '[data-test-copy-menu-trigger]',
copyButton: '[data-test-copy-button]',
- clipboard: 'data-clipboard-text',
+ clipboard: 'data-test-copy-button',
wrapButton: '[data-test-wrap-button]',
masked: '[data-test-masked-input]',
};
@@ -44,7 +44,7 @@ module('Integration | Component | copy-secret-dropdown', function (hooks) {
assert.dom(SELECTORS.wrapButton).hasText('Wrap secret');
assert
.dom(SELECTORS.copyButton)
- .hasAttribute('data-clipboard-text', `${this.data}`, 'it renders copyable data');
+ .hasAttribute('data-test-copy-button', `${this.data}`, 'it renders copyable data');
await click(SELECTORS.wrapButton);
await click(SELECTORS.dropdown);
@@ -88,6 +88,6 @@ module('Integration | Component | copy-secret-dropdown', function (hooks) {
await click(SELECTORS.dropdown);
assert
.dom(`${SELECTORS.masked} ${SELECTORS.copyButton}`)
- .hasAttribute('data-clipboard-text', this.wrappedData, 'it renders wrapped data');
+ .hasAttribute('data-test-copy-button', this.wrappedData, 'it renders wrapped data');
});
});
diff --git a/ui/tests/integration/components/info-table-row-test.js b/ui/tests/integration/components/info-table-row-test.js
index 238c019e2dd3..d6ba44a25ee0 100644
--- a/ui/tests/integration/components/info-table-row-test.js
+++ b/ui/tests/integration/components/info-table-row-test.js
@@ -96,7 +96,7 @@ module('Integration | Component | InfoTableRow', function (hooks) {
assert.dom('[data-test-tooltip-copy]').exists('Tooltip has copy button');
assert
.dom('[data-test-tooltip-copy]')
- .hasAttribute('data-clipboard-text', 'Foo bar', 'Copy button will copy the tooltip text');
+ .hasAttribute('data-test-tooltip-copy', 'Foo bar', 'Copy button will copy the tooltip text');
});
test('it renders a string with no link if isLink is true and the item type is not an array.', async function (assert) {
diff --git a/ui/tests/integration/components/kv/page/kv-page-secret-paths-test.js b/ui/tests/integration/components/kv/page/kv-page-secret-paths-test.js
index 342e7e90e6c2..5e6fe4a449bd 100644
--- a/ui/tests/integration/components/kv/page/kv-page-secret-paths-test.js
+++ b/ui/tests/integration/components/kv/page/kv-page-secret-paths-test.js
@@ -25,7 +25,7 @@ module('Integration | Component | kv-v2 | Page::Secret::Paths', function (hooks)
];
this.assertClipboard = (assert, element, expected) => {
- assert.dom(element).hasAttribute('data-clipboard-text', expected);
+ assert.dom(element).hasAttribute('data-test-copy-button', expected);
};
});
@@ -110,9 +110,9 @@ module('Integration | Component | kv-v2 | Page::Secret::Paths', function (hooks)
);
assert.dom(PAGE.paths.codeSnippet('cli')).hasText(expected.cli);
- assert.dom(PAGE.paths.snippetCopy('cli')).hasAttribute('data-clipboard-text', expected.cli);
+ assert.dom(PAGE.paths.snippetCopy('cli')).hasAttribute('data-test-copy-button', expected.cli);
assert.dom(PAGE.paths.codeSnippet('api')).hasText(expected.apiDisplay);
- assert.dom(PAGE.paths.snippetCopy('api')).hasAttribute('data-clipboard-text', expected.apiCopy);
+ assert.dom(PAGE.paths.snippetCopy('api')).hasAttribute('data-test-copy-button', expected.apiCopy);
});
test('it renders copyable encoded mount and path commands', async function (assert) {
@@ -141,8 +141,8 @@ module('Integration | Component | kv-v2 | Page::Secret::Paths', function (hooks)
);
assert.dom(PAGE.paths.codeSnippet('cli')).hasText(expected.cli);
- assert.dom(PAGE.paths.snippetCopy('cli')).hasAttribute('data-clipboard-text', expected.cli);
+ assert.dom(PAGE.paths.snippetCopy('cli')).hasAttribute('data-test-copy-button', expected.cli);
assert.dom(PAGE.paths.codeSnippet('api')).hasText(expected.apiDisplay);
- assert.dom(PAGE.paths.snippetCopy('api')).hasAttribute('data-clipboard-text', expected.apiCopy);
+ assert.dom(PAGE.paths.snippetCopy('api')).hasAttribute('data-test-copy-button', expected.apiCopy);
});
});
diff --git a/ui/tests/integration/components/oidc/scope-form-test.js b/ui/tests/integration/components/oidc/scope-form-test.js
index 866861428e34..40d960de3a25 100644
--- a/ui/tests/integration/components/oidc/scope-form-test.js
+++ b/ui/tests/integration/components/oidc/scope-form-test.js
@@ -177,7 +177,11 @@ module('Integration | Component | oidc/scope-form', function (hooks) {
assert.dom(MODAL('text')).hasText('Example of a JSON template for scopes:', 'Modal text renders');
assert
.dom('#scope-template-modal [data-test-copy-button]')
- .hasAttribute('data-clipboard-text', exampleTemplate, 'Modal copy button copies the example template');
+ .hasAttribute(
+ 'data-test-copy-button',
+ exampleTemplate,
+ 'Modal copy button copies the example template'
+ );
assert.dom('.cm-string').hasText('"username"', 'Example template json renders');
await click('[data-test-close-modal]');
assert.dom('.hds#scope-template-modal').doesNotExist('Modal is hidden');
diff --git a/ui/tests/integration/components/pki/pki-generate-csr-test.js b/ui/tests/integration/components/pki/pki-generate-csr-test.js
index 6f4706a5b410..4245a2128747 100644
--- a/ui/tests/integration/components/pki/pki-generate-csr-test.js
+++ b/ui/tests/integration/components/pki/pki-generate-csr-test.js
@@ -112,15 +112,16 @@ module('Integration | Component | pki-generate-csr', function (hooks) {
'Next steps Copy the CSR below for a parent issuer to sign and then import the signed certificate back into this mount. The private_key is only available once. Make sure you copy and save it now.',
'renders Next steps alert banner'
);
+
assert
.dom('[data-test-value-div="CSR"] [data-test-certificate-card] button')
- .hasAttribute('data-clipboard-text', this.model.csr, 'it renders copyable csr');
+ .hasAttribute('data-test-copy-button', this.model.csr, 'it renders copyable csr');
assert
.dom('[data-test-value-div="Key ID"] button')
- .hasAttribute('data-clipboard-text', this.model.keyId, 'it renders copyable key_id');
+ .hasAttribute('data-test-copy-button', this.model.keyId, 'it renders copyable key_id');
assert
.dom('[data-test-value-div="Private key"] [data-test-certificate-card] button')
- .hasAttribute('data-clipboard-text', this.model.privateKey, 'it renders copyable private_key');
+ .hasAttribute('data-test-copy-button', this.model.privateKey, 'it renders copyable private_key');
assert
.dom('[data-test-value-div="Private key type"]')
.hasText(this.model.privateKeyType, 'renders private_key_type');
@@ -145,10 +146,10 @@ module('Integration | Component | pki-generate-csr', function (hooks) {
);
assert
.dom('[data-test-value-div="CSR"] [data-test-certificate-card] button')
- .hasAttribute('data-clipboard-text', this.model.csr, 'it renders copyable csr');
+ .hasAttribute('data-test-copy-button', this.model.csr, 'it renders copyable csr');
assert
.dom('[data-test-value-div="Key ID"] button')
- .hasAttribute('data-clipboard-text', this.model.keyId, 'it renders copyable key_id');
+ .hasAttribute('data-test-copy-button', this.model.keyId, 'it renders copyable key_id');
assert.dom('[data-test-value-div="Private key"]').hasText('internal', 'does not render private key');
assert
.dom('[data-test-value-div="Private key type"]')
diff --git a/ui/tests/integration/components/sidebar/user-menu-test.js b/ui/tests/integration/components/sidebar/user-menu-test.js
index 0b5b0dfc382c..f43a948c26b3 100644
--- a/ui/tests/integration/components/sidebar/user-menu-test.js
+++ b/ui/tests/integration/components/sidebar/user-menu-test.js
@@ -35,7 +35,7 @@ module('Integration | Component | sidebar-user-menu', function (hooks) {
assert.dom('.menu-label').hasText('Token', 'Auth data display name renders');
assert.dom('li').exists({ count: 2 }, 'Correct number of menu items render');
- assert.dom('[data-clipboard-text="root"]').exists('Copy token action renders');
+ assert.dom('[data-test-copy-button="root"]').exists('Copy token action renders');
assert.dom('#logout').hasText('Log out', 'Log out action renders');
});
diff --git a/ui/yarn.lock b/ui/yarn.lock
index ee60cec2407d..85a24bfdc034 100644
--- a/ui/yarn.lock
+++ b/ui/yarn.lock
@@ -67,6 +67,16 @@ __metadata:
languageName: node
linkType: hard
+"@babel/code-frame@npm:^7.22.13":
+ version: 7.23.5
+ resolution: "@babel/code-frame@npm:7.23.5"
+ dependencies:
+ "@babel/highlight": ^7.23.4
+ chalk: ^2.4.2
+ checksum: d90981fdf56a2824a9b14d19a4c0e8db93633fd488c772624b4e83e0ceac6039a27cd298a247c3214faa952bf803ba23696172ae7e7235f3b97f43ba278c569a
+ languageName: node
+ linkType: hard
+
"@babel/code-frame@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/code-frame@npm:7.22.5"
@@ -104,6 +114,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.3, @babel/compat-data@npm:^7.23.5":
+ version: 7.23.5
+ resolution: "@babel/compat-data@npm:7.23.5"
+ checksum: 06ce244cda5763295a0ea924728c09bae57d35713b675175227278896946f922a63edf803c322f855a3878323d48d0255a2a3023409d2a123483c8a69ebb4744
+ languageName: node
+ linkType: hard
+
"@babel/compat-data@npm:^7.22.9":
version: 7.22.9
resolution: "@babel/compat-data@npm:7.22.9"
@@ -375,6 +392,15 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.22.15":
+ version: 7.22.15
+ resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.22.15"
+ dependencies:
+ "@babel/types": ^7.22.15
+ checksum: 639c697a1c729f9fafa2dd4c9af2e18568190299b5907bd4c2d0bc818fcbd1e83ffeecc2af24327a7faa7ac4c34edd9d7940510a5e66296c19bad17001cf5c7a
+ languageName: node
+ linkType: hard
+
"@babel/helper-compilation-targets@npm:^7.12.0, @babel/helper-compilation-targets@npm:^7.13.0, @babel/helper-compilation-targets@npm:^7.13.16, @babel/helper-compilation-targets@npm:^7.13.8, @babel/helper-compilation-targets@npm:^7.16.0":
version: 7.16.3
resolution: "@babel/helper-compilation-targets@npm:7.16.3"
@@ -431,6 +457,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-compilation-targets@npm:^7.20.7, @babel/helper-compilation-targets@npm:^7.22.15, @babel/helper-compilation-targets@npm:^7.22.6":
+ version: 7.22.15
+ resolution: "@babel/helper-compilation-targets@npm:7.22.15"
+ dependencies:
+ "@babel/compat-data": ^7.22.9
+ "@babel/helper-validator-option": ^7.22.15
+ browserslist: ^4.21.9
+ lru-cache: ^5.1.1
+ semver: ^6.3.1
+ checksum: ce85196769e091ae54dd39e4a80c2a9df1793da8588e335c383d536d54f06baf648d0a08fc873044f226398c4ded15c4ae9120ee18e7dfd7c639a68e3cdc9980
+ languageName: node
+ linkType: hard
+
"@babel/helper-compilation-targets@npm:^7.22.9":
version: 7.22.9
resolution: "@babel/helper-compilation-targets@npm:7.22.9"
@@ -513,6 +552,25 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-create-class-features-plugin@npm:^7.21.0, @babel/helper-create-class-features-plugin@npm:^7.22.15, @babel/helper-create-class-features-plugin@npm:^7.23.5":
+ version: 7.23.5
+ resolution: "@babel/helper-create-class-features-plugin@npm:7.23.5"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.22.5
+ "@babel/helper-environment-visitor": ^7.22.20
+ "@babel/helper-function-name": ^7.23.0
+ "@babel/helper-member-expression-to-functions": ^7.23.0
+ "@babel/helper-optimise-call-expression": ^7.22.5
+ "@babel/helper-replace-supers": ^7.22.20
+ "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5
+ "@babel/helper-split-export-declaration": ^7.22.6
+ semver: ^6.3.1
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: fe7c6c0baca1838bba76ac1330df47b661d932354115ea9e2ea65b179f80b717987d3c3da7e1525fd648e5f2d86c620efc959cabda4d7562b125a27c3ac780d0
+ languageName: node
+ linkType: hard
+
"@babel/helper-create-class-features-plugin@npm:^7.22.6":
version: 7.22.9
resolution: "@babel/helper-create-class-features-plugin@npm:7.22.9"
@@ -584,6 +642,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.22.15, @babel/helper-create-regexp-features-plugin@npm:^7.22.5":
+ version: 7.22.15
+ resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.15"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.22.5
+ regexpu-core: ^5.3.1
+ semver: ^6.3.1
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 0243b8d4854f1dc8861b1029a46d3f6393ad72f366a5a08e36a4648aa682044f06da4c6e87a456260e1e1b33c999f898ba591a0760842c1387bcc93fbf2151a6
+ languageName: node
+ linkType: hard
+
"@babel/helper-define-polyfill-provider@npm:^0.2.2":
version: 0.2.3
resolution: "@babel/helper-define-polyfill-provider@npm:0.2.3"
@@ -656,6 +727,21 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-define-polyfill-provider@npm:^0.4.3":
+ version: 0.4.3
+ resolution: "@babel/helper-define-polyfill-provider@npm:0.4.3"
+ dependencies:
+ "@babel/helper-compilation-targets": ^7.22.6
+ "@babel/helper-plugin-utils": ^7.22.5
+ debug: ^4.1.1
+ lodash.debounce: ^4.0.8
+ resolve: ^1.14.2
+ peerDependencies:
+ "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
+ checksum: 5d21e3f47b320e4b5b644195ec405e7ebc3739e48e65899efc808c5fa9c3bf5b06ce0d8ff5246ca99d1411e368f4557bc66730196c5781a5c4e986ee703bee79
+ languageName: node
+ linkType: hard
+
"@babel/helper-environment-visitor@npm:^7.16.7":
version: 7.16.7
resolution: "@babel/helper-environment-visitor@npm:7.16.7"
@@ -679,6 +765,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-environment-visitor@npm:^7.22.20":
+ version: 7.22.20
+ resolution: "@babel/helper-environment-visitor@npm:7.22.20"
+ checksum: d80ee98ff66f41e233f36ca1921774c37e88a803b2f7dca3db7c057a5fea0473804db9fb6729e5dbfd07f4bed722d60f7852035c2c739382e84c335661590b69
+ languageName: node
+ linkType: hard
+
"@babel/helper-environment-visitor@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/helper-environment-visitor@npm:7.22.5"
@@ -756,6 +849,16 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-function-name@npm:^7.23.0":
+ version: 7.23.0
+ resolution: "@babel/helper-function-name@npm:7.23.0"
+ dependencies:
+ "@babel/template": ^7.22.15
+ "@babel/types": ^7.23.0
+ checksum: e44542257b2d4634a1f979244eb2a4ad8e6d75eb6761b4cfceb56b562f7db150d134bc538c8e6adca3783e3bc31be949071527aa8e3aab7867d1ad2d84a26e10
+ languageName: node
+ linkType: hard
+
"@babel/helper-get-function-arity@npm:^7.16.0":
version: 7.16.0
resolution: "@babel/helper-get-function-arity@npm:7.16.0"
@@ -837,6 +940,15 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-member-expression-to-functions@npm:^7.22.15, @babel/helper-member-expression-to-functions@npm:^7.23.0":
+ version: 7.23.0
+ resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0"
+ dependencies:
+ "@babel/types": ^7.23.0
+ checksum: 494659361370c979ada711ca685e2efe9460683c36db1b283b446122596602c901e291e09f2f980ecedfe6e0f2bd5386cb59768285446530df10c14df1024e75
+ languageName: node
+ linkType: hard
+
"@babel/helper-member-expression-to-functions@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/helper-member-expression-to-functions@npm:7.22.5"
@@ -873,6 +985,15 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-module-imports@npm:^7.22.15":
+ version: 7.22.15
+ resolution: "@babel/helper-module-imports@npm:7.22.15"
+ dependencies:
+ "@babel/types": ^7.22.15
+ checksum: ecd7e457df0a46f889228f943ef9b4a47d485d82e030676767e6a2fdcbdaa63594d8124d4b55fd160b41c201025aec01fc27580352b1c87a37c9c6f33d116702
+ languageName: node
+ linkType: hard
+
"@babel/helper-module-imports@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/helper-module-imports@npm:7.22.5"
@@ -961,6 +1082,21 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-module-transforms@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/helper-module-transforms@npm:7.23.3"
+ dependencies:
+ "@babel/helper-environment-visitor": ^7.22.20
+ "@babel/helper-module-imports": ^7.22.15
+ "@babel/helper-simple-access": ^7.22.5
+ "@babel/helper-split-export-declaration": ^7.22.6
+ "@babel/helper-validator-identifier": ^7.22.20
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 5d0895cfba0e16ae16f3aa92fee108517023ad89a855289c4eb1d46f7aef4519adf8e6f971e1d55ac20c5461610e17213f1144097a8f932e768a9132e2278d71
+ languageName: node
+ linkType: hard
+
"@babel/helper-optimise-call-expression@npm:^7.12.13, @babel/helper-optimise-call-expression@npm:^7.16.0":
version: 7.16.0
resolution: "@babel/helper-optimise-call-expression@npm:7.16.0"
@@ -1025,7 +1161,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-plugin-utils@npm:^7.22.5":
+"@babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/helper-plugin-utils@npm:7.22.5"
checksum: c0fc7227076b6041acd2f0e818145d2e8c41968cc52fb5ca70eed48e21b8fe6dd88a0a91cbddf4951e33647336eb5ae184747ca706817ca3bef5e9e905151ff5
@@ -1054,6 +1190,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-remap-async-to-generator@npm:^7.22.20":
+ version: 7.22.20
+ resolution: "@babel/helper-remap-async-to-generator@npm:7.22.20"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.22.5
+ "@babel/helper-environment-visitor": ^7.22.20
+ "@babel/helper-wrap-function": ^7.22.20
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 2fe6300a6f1b58211dffa0aed1b45d4958506d096543663dba83bd9251fe8d670fa909143a65b45e72acb49e7e20fbdb73eae315d9ddaced467948c3329986e7
+ languageName: node
+ linkType: hard
+
"@babel/helper-replace-supers@npm:^7.13.12, @babel/helper-replace-supers@npm:^7.16.0":
version: 7.16.0
resolution: "@babel/helper-replace-supers@npm:7.16.0"
@@ -1105,6 +1254,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-replace-supers@npm:^7.22.20":
+ version: 7.22.20
+ resolution: "@babel/helper-replace-supers@npm:7.22.20"
+ dependencies:
+ "@babel/helper-environment-visitor": ^7.22.20
+ "@babel/helper-member-expression-to-functions": ^7.22.15
+ "@babel/helper-optimise-call-expression": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: a0008332e24daedea2e9498733e3c39b389d6d4512637e000f96f62b797e702ee24a407ccbcd7a236a551590a38f31282829a8ef35c50a3c0457d88218cae639
+ languageName: node
+ linkType: hard
+
"@babel/helper-replace-supers@npm:^7.22.5, @babel/helper-replace-supers@npm:^7.22.9":
version: 7.22.9
resolution: "@babel/helper-replace-supers@npm:7.22.9"
@@ -1238,6 +1400,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-string-parser@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/helper-string-parser@npm:7.23.4"
+ checksum: c0641144cf1a7e7dc93f3d5f16d5327465b6cf5d036b48be61ecba41e1eece161b48f46b7f960951b67f8c3533ce506b16dece576baef4d8b3b49f8c65410f90
+ languageName: node
+ linkType: hard
+
"@babel/helper-validator-identifier@npm:^7.14.0, @babel/helper-validator-identifier@npm:^7.15.7":
version: 7.15.7
resolution: "@babel/helper-validator-identifier@npm:7.15.7"
@@ -1266,6 +1435,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-validator-identifier@npm:^7.22.20":
+ version: 7.22.20
+ resolution: "@babel/helper-validator-identifier@npm:7.22.20"
+ checksum: 136412784d9428266bcdd4d91c32bcf9ff0e8d25534a9d94b044f77fe76bc50f941a90319b05aafd1ec04f7d127cd57a179a3716009ff7f3412ef835ada95bdc
+ languageName: node
+ linkType: hard
+
"@babel/helper-validator-identifier@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/helper-validator-identifier@npm:7.22.5"
@@ -1294,6 +1470,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-validator-option@npm:^7.22.15, @babel/helper-validator-option@npm:^7.23.5":
+ version: 7.23.5
+ resolution: "@babel/helper-validator-option@npm:7.23.5"
+ checksum: 537cde2330a8aede223552510e8a13e9c1c8798afee3757995a7d4acae564124fe2bf7e7c3d90d62d3657434a74340a274b3b3b1c6f17e9a2be1f48af29cb09e
+ languageName: node
+ linkType: hard
+
"@babel/helper-validator-option@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/helper-validator-option@npm:7.22.5"
@@ -1325,6 +1508,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-wrap-function@npm:^7.22.20":
+ version: 7.22.20
+ resolution: "@babel/helper-wrap-function@npm:7.22.20"
+ dependencies:
+ "@babel/helper-function-name": ^7.22.5
+ "@babel/template": ^7.22.15
+ "@babel/types": ^7.22.19
+ checksum: 221ed9b5572612aeb571e4ce6a256f2dee85b3c9536f1dd5e611b0255e5f59a3d0ec392d8d46d4152149156a8109f92f20379b1d6d36abb613176e0e33f05fca
+ languageName: node
+ linkType: hard
+
"@babel/helpers@npm:^7.14.0, @babel/helpers@npm:^7.16.0":
version: 7.16.3
resolution: "@babel/helpers@npm:7.16.3"
@@ -1424,6 +1618,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/highlight@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/highlight@npm:7.23.4"
+ dependencies:
+ "@babel/helper-validator-identifier": ^7.22.20
+ chalk: ^2.4.2
+ js-tokens: ^4.0.0
+ checksum: 643acecdc235f87d925979a979b539a5d7d1f31ae7db8d89047269082694122d11aa85351304c9c978ceeb6d250591ccadb06c366f358ccee08bb9c122476b89
+ languageName: node
+ linkType: hard
+
"@babel/parser@npm:^7.12.3, @babel/parser@npm:^7.4.5":
version: 7.14.0
resolution: "@babel/parser@npm:7.14.0"
@@ -1469,6 +1674,15 @@ __metadata:
languageName: node
linkType: hard
+"@babel/parser@npm:^7.22.15":
+ version: 7.23.5
+ resolution: "@babel/parser@npm:7.23.5"
+ bin:
+ parser: ./bin/babel-parser.js
+ checksum: ea763629310f71580c4a3ea9d3705195b7ba994ada2cc98f9a584ebfdacf54e92b2735d351672824c2c2b03c7f19206899f4d95650d85ce514a822b19a8734c7
+ languageName: node
+ linkType: hard
+
"@babel/parser@npm:^7.22.5, @babel/parser@npm:^7.22.7":
version: 7.22.7
resolution: "@babel/parser@npm:7.22.7"
@@ -1500,6 +1714,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: ddbaf2c396b7780f15e80ee01d6dd790db076985f3dfeb6527d1a8d4cacf370e49250396a3aa005b2c40233cac214a106232f83703d5e8491848bde273938232
+ languageName: node
+ linkType: hard
+
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.13.12":
version: 7.16.0
resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.16.0"
@@ -1539,6 +1764,31 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5
+ "@babel/plugin-transform-optional-chaining": ^7.23.3
+ peerDependencies:
+ "@babel/core": ^7.13.0
+ checksum: 434b9d710ae856fa1a456678cc304fbc93915af86d581ee316e077af746a709a741ea39d7e1d4f5b98861b629cc7e87f002d3138f5e836775632466d4c74aef2
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.23.3"
+ dependencies:
+ "@babel/helper-environment-visitor": ^7.22.20
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 4690123f0ef7c11d6bf1a9579e4f463ce363563b75ec3f6ca66cf68687e39d8d747a82c833847653962f79da367eca895d9095c60d8ebb224a1d4277003acc11
+ languageName: node
+ linkType: hard
+
"@babel/plugin-proposal-async-generator-functions@npm:^7.13.15":
version: 7.16.4
resolution: "@babel/plugin-proposal-async-generator-functions@npm:7.16.4"
@@ -1694,6 +1944,21 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-proposal-decorators@npm:^7.20.13":
+ version: 7.23.5
+ resolution: "@babel/plugin-proposal-decorators@npm:7.23.5"
+ dependencies:
+ "@babel/helper-create-class-features-plugin": ^7.23.5
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/helper-replace-supers": ^7.22.20
+ "@babel/helper-split-export-declaration": ^7.22.6
+ "@babel/plugin-syntax-decorators": ^7.23.3
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: e925fe7a82c03aa372b92b312e69a05453d55aaaf2fd48336c88f4fe2b7e81bf9e8e52b93d4f785a02f2b8deedee6964054153566b40c92886dcf795843a243e
+ languageName: node
+ linkType: hard
+
"@babel/plugin-proposal-decorators@npm:^7.21.0":
version: 7.22.7
resolution: "@babel/plugin-proposal-decorators@npm:7.22.7"
@@ -2060,6 +2325,15 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2":
+ version: 7.21.0-placeholder-for-preset-env.2
+ resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2"
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: d97745d098b835d55033ff3a7fb2b895b9c5295b08a5759e4f20df325aa385a3e0bc9bd5ad8f2ec554a44d4e6525acfc257b8c5848a1345cb40f26a30e277e91
+ languageName: node
+ linkType: hard
+
"@babel/plugin-proposal-private-property-in-object@npm:^7.14.0":
version: 7.16.0
resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.16.0"
@@ -2102,6 +2376,20 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-proposal-private-property-in-object@npm:^7.20.5":
+ version: 7.21.11
+ resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.11"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.18.6
+ "@babel/helper-create-class-features-plugin": ^7.21.0
+ "@babel/helper-plugin-utils": ^7.20.2
+ "@babel/plugin-syntax-private-property-in-object": ^7.14.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 1b880543bc5f525b360b53d97dd30807302bb82615cd42bf931968f59003cac75629563d6b104868db50abd22235b3271fdf679fea5db59a267181a99cc0c265
+ languageName: node
+ linkType: hard
+
"@babel/plugin-proposal-unicode-property-regex@npm:^7.12.13, @babel/plugin-proposal-unicode-property-regex@npm:^7.4.4":
version: 7.16.0
resolution: "@babel/plugin-proposal-unicode-property-regex@npm:7.16.0"
@@ -2215,6 +2503,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-syntax-decorators@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-syntax-decorators@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 07f6e488df0a061428e02629af9a1908b2e8abdcac2e5cfaa267be66dc30897be6e29df7c7f952d33f3679f9585ac9fcf6318f9c827790ab0b0928d5514305cd
+ languageName: node
+ linkType: hard
+
"@babel/plugin-syntax-dynamic-import@npm:^7.8.3":
version: 7.8.3
resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3"
@@ -2248,6 +2547,39 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-syntax-import-assertions@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-syntax-import-assertions@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 883e6b35b2da205138caab832d54505271a3fee3fc1e8dc0894502434fc2b5d517cbe93bbfbfef8068a0fb6ec48ebc9eef3f605200a489065ba43d8cddc1c9a7
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-syntax-import-attributes@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-syntax-import-attributes@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 9aed7661ffb920ca75df9f494757466ca92744e43072e0848d87fa4aa61a3f2ee5a22198ac1959856c036434b5614a8f46f1fb70298835dbe28220cdd1d4c11e
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-syntax-import-meta@npm:^7.10.4":
+ version: 7.10.4
+ resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.10.4
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 166ac1125d10b9c0c430e4156249a13858c0366d38844883d75d27389621ebe651115cb2ceb6dc011534d5055719fa1727b59f39e1ab3ca97820eef3dcab5b9b
+ languageName: node
+ linkType: hard
+
"@babel/plugin-syntax-json-strings@npm:^7.8.3":
version: 7.8.3
resolution: "@babel/plugin-syntax-json-strings@npm:7.8.3"
@@ -2380,6 +2712,29 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-syntax-typescript@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-syntax-typescript@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: abfad3a19290d258b028e285a1f34c9b8a0cbe46ef79eafed4ed7ffce11b5d0720b5e536c82f91cbd8442cde35a3dd8e861fa70366d87ff06fdc0d4756e30876
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-syntax-unicode-sets-regex@npm:^7.18.6":
+ version: 7.18.6
+ resolution: "@babel/plugin-syntax-unicode-sets-regex@npm:7.18.6"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin": ^7.18.6
+ "@babel/helper-plugin-utils": ^7.18.6
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: a651d700fe63ff0ddfd7186f4ebc24447ca734f114433139e3c027bc94a900d013cf1ef2e2db8430425ba542e39ae160c3b05f06b59fd4656273a3df97679e9c
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-arrow-functions@npm:^7.13.0":
version: 7.16.0
resolution: "@babel/plugin-transform-arrow-functions@npm:7.16.0"
@@ -2413,6 +2768,31 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-arrow-functions@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-arrow-functions@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 1e99118176e5366c2636064d09477016ab5272b2a92e78b8edb571d20bc3eaa881789a905b20042942c3c2d04efc530726cf703f937226db5ebc495f5d067e66
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-async-generator-functions@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/plugin-transform-async-generator-functions@npm:7.23.4"
+ dependencies:
+ "@babel/helper-environment-visitor": ^7.22.20
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/helper-remap-async-to-generator": ^7.22.20
+ "@babel/plugin-syntax-async-generators": ^7.8.4
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: e2fc132c9033711d55209f4781e1fc73f0f4da5e0ca80a2da73dec805166b73c92a6e83571a8994cd2c893a28302e24107e90856202b24781bab734f800102bb
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-async-to-generator@npm:^7.13.0":
version: 7.16.0
resolution: "@babel/plugin-transform-async-to-generator@npm:7.16.0"
@@ -2452,6 +2832,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-async-to-generator@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-async-to-generator@npm:7.23.3"
+ dependencies:
+ "@babel/helper-module-imports": ^7.22.15
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/helper-remap-async-to-generator": ^7.22.20
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 2e9d9795d4b3b3d8090332104e37061c677f29a1ce65bcbda4099a32d243e5d9520270a44bbabf0fb1fb40d463bd937685b1a1042e646979086c546d55319c3c
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-block-scoped-functions@npm:^7.12.13":
version: 7.16.0
resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.16.0"
@@ -2474,6 +2867,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-block-scoped-functions@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: e63b16d94ee5f4d917e669da3db5ea53d1e7e79141a2ec873c1e644678cdafe98daa556d0d359963c827863d6b3665d23d4938a94a4c5053a1619c4ebd01d020
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-block-scoping@npm:^7.12.1":
version: 7.13.16
resolution: "@babel/plugin-transform-block-scoping@npm:7.13.16"
@@ -2529,6 +2933,42 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-block-scoping@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/plugin-transform-block-scoping@npm:7.23.4"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: fc4b2100dd9f2c47d694b4b35ae8153214ccb4e24ef545c259a9db17211b18b6a430f22799b56db8f6844deaeaa201af45a03331d0c80cc28b0c4e3c814570e4
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-class-properties@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-class-properties@npm:7.23.3"
+ dependencies:
+ "@babel/helper-create-class-features-plugin": ^7.22.15
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 9c6f8366f667897541d360246de176dd29efc7a13d80a5b48361882f7173d9173be4646c3b7d9b003ccc0e01e25df122330308f33db921fa553aa17ad544b3fc
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-class-static-block@npm:^7.22.11, @babel/plugin-transform-class-static-block@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/plugin-transform-class-static-block@npm:7.23.4"
+ dependencies:
+ "@babel/helper-create-class-features-plugin": ^7.22.15
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/plugin-syntax-class-static-block": ^7.14.5
+ peerDependencies:
+ "@babel/core": ^7.12.0
+ checksum: c8bfaba19a674fc2eb54edad71e958647360474e3163e8226f1acd63e4e2dbec32a171a0af596c1dc5359aee402cc120fea7abd1fb0e0354b6527f0fc9e8aa1e
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-classes@npm:^7.13.0":
version: 7.16.0
resolution: "@babel/plugin-transform-classes@npm:7.16.0"
@@ -2582,6 +3022,25 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-classes@npm:^7.23.5":
+ version: 7.23.5
+ resolution: "@babel/plugin-transform-classes@npm:7.23.5"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.22.5
+ "@babel/helper-compilation-targets": ^7.22.15
+ "@babel/helper-environment-visitor": ^7.22.20
+ "@babel/helper-function-name": ^7.23.0
+ "@babel/helper-optimise-call-expression": ^7.22.5
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/helper-replace-supers": ^7.22.20
+ "@babel/helper-split-export-declaration": ^7.22.6
+ globals: ^11.1.0
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 6d0dd3b0828e84a139a51b368f33f315edee5688ef72c68ba25e0175c68ea7357f9c8810b3f61713e368a3063cdcec94f3a2db952e453b0b14ef428a34aa8169
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-computed-properties@npm:^7.13.0":
version: 7.16.0
resolution: "@babel/plugin-transform-computed-properties@npm:7.16.0"
@@ -2615,6 +3074,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-computed-properties@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-computed-properties@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/template": ^7.22.15
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 80452661dc25a0956f89fe98cb562e8637a9556fb6c00d312c57653ce7df8798f58d138603c7e1aad96614ee9ccd10c47e50ab9ded6b6eded5adeb230d2a982e
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-destructuring@npm:^7.13.17":
version: 7.16.0
resolution: "@babel/plugin-transform-destructuring@npm:7.16.0"
@@ -2648,6 +3119,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-destructuring@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-destructuring@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 9e015099877272501162419bfe781689aec5c462cd2aec752ee22288f209eec65969ff11b8fdadca2eaddea71d705d3bba5b9c60752fcc1be67874fcec687105
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-dotall-regex@npm:^7.12.13, @babel/plugin-transform-dotall-regex@npm:^7.4.4":
version: 7.16.0
resolution: "@babel/plugin-transform-dotall-regex@npm:7.16.0"
@@ -2672,6 +3154,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-dotall-regex@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-dotall-regex@npm:7.23.3"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin": ^7.22.15
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: a2dbbf7f1ea16a97948c37df925cb364337668c41a3948b8d91453f140507bd8a3429030c7ce66d09c299987b27746c19a2dd18b6f17dcb474854b14fd9159a3
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-duplicate-keys@npm:^7.12.13":
version: 7.16.0
resolution: "@babel/plugin-transform-duplicate-keys@npm:7.16.0"
@@ -2705,6 +3199,29 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-duplicate-keys@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-duplicate-keys@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: c2a21c34dc0839590cd945192cbc46fde541a27e140c48fe1808315934664cdbf18db64889e23c4eeb6bad9d3e049482efdca91d29de5734ffc887c4fbabaa16
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-dynamic-import@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/plugin-transform-dynamic-import@npm:7.23.4"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/plugin-syntax-dynamic-import": ^7.8.3
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 57a722604c430d9f3dacff22001a5f31250e34785d4969527a2ae9160fa86858d0892c5b9ff7a06a04076f8c76c9e6862e0541aadca9c057849961343aab0845
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-exponentiation-operator@npm:^7.12.13":
version: 7.16.0
resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.16.0"
@@ -2729,6 +3246,30 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-exponentiation-operator@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.23.3"
+ dependencies:
+ "@babel/helper-builder-binary-assignment-operator-visitor": ^7.22.15
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 00d05ab14ad0f299160fcf9d8f55a1cc1b740e012ab0b5ce30207d2365f091665115557af7d989cd6260d075a252d9e4283de5f2b247dfbbe0e42ae586e6bf66
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-export-namespace-from@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/plugin-transform-export-namespace-from@npm:7.23.4"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/plugin-syntax-export-namespace-from": ^7.8.3
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 9f770a81bfd03b48d6ba155d452946fd56d6ffe5b7d871e9ec2a0b15e0f424273b632f3ed61838b90015b25bbda988896b7a46c7d964fbf8f6feb5820b309f93
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-for-of@npm:^7.13.0":
version: 7.16.0
resolution: "@babel/plugin-transform-for-of@npm:7.16.0"
@@ -2762,6 +3303,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-for-of@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-for-of@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: a6288122a5091d96c744b9eb23dc1b2d4cce25f109ac1e26a0ea03c4ea60330e6f3cc58530b33ba7369fa07163b71001399a145238b7e92bff6270ef3b9c32a0
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-function-name@npm:^7.12.13":
version: 7.16.0
resolution: "@babel/plugin-transform-function-name@npm:7.16.0"
@@ -2787,6 +3339,31 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-function-name@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-function-name@npm:7.23.3"
+ dependencies:
+ "@babel/helper-compilation-targets": ^7.22.15
+ "@babel/helper-function-name": ^7.23.0
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 355c6dbe07c919575ad42b2f7e020f320866d72f8b79181a16f8e0cd424a2c761d979f03f47d583d9471b55dcd68a8a9d829b58e1eebcd572145b934b48975a6
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-json-strings@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/plugin-transform-json-strings@npm:7.23.4"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/plugin-syntax-json-strings": ^7.8.3
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: f9019820233cf8955d8ba346df709a0683c120fe86a24ed1c9f003f2db51197b979efc88f010d558a12e1491210fc195a43cd1c7fee5e23b92da38f793a875de
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-literals@npm:^7.12.13":
version: 7.16.0
resolution: "@babel/plugin-transform-literals@npm:7.16.0"
@@ -2820,6 +3397,29 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-literals@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-literals@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 519a544cd58586b9001c4c9b18da25a62f17d23c48600ff7a685d75ca9eb18d2c5e8f5476f067f0a8f1fea2a31107eff950b9864833061e6076dcc4bdc3e71ed
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-logical-assignment-operators@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.23.4"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 2ae1dc9b4ff3bf61a990ff3accdecb2afe3a0ca649b3e74c010078d1cdf29ea490f50ac0a905306a2bcf9ac177889a39ac79bdcc3a0fdf220b3b75fac18d39b5
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-member-expression-literals@npm:^7.12.13":
version: 7.16.0
resolution: "@babel/plugin-transform-member-expression-literals@npm:7.16.0"
@@ -2842,6 +3442,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-member-expression-literals@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-member-expression-literals@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 95cec13c36d447c5aa6b8e4c778b897eeba66dcb675edef01e0d2afcec9e8cb9726baf4f81b4bbae7a782595aed72e6a0d44ffb773272c3ca180fada99bf92db
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-modules-amd@npm:^7.13.0, @babel/plugin-transform-modules-amd@npm:^7.14.0":
version: 7.16.0
resolution: "@babel/plugin-transform-modules-amd@npm:7.16.0"
@@ -2893,6 +3504,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-modules-amd@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-modules-amd@npm:7.23.3"
+ dependencies:
+ "@babel/helper-module-transforms": ^7.23.3
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: d163737b6a3d67ea579c9aa3b83d4df4b5c34d9dcdf25f415f027c0aa8cded7bac2750d2de5464081f67a042ad9e1c03930c2fab42acd79f9e57c00cf969ddff
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-modules-commonjs@npm:^7.14.0":
version: 7.16.0
resolution: "@babel/plugin-transform-modules-commonjs@npm:7.16.0"
@@ -2935,6 +3558,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-modules-commonjs@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-modules-commonjs@npm:7.23.3"
+ dependencies:
+ "@babel/helper-module-transforms": ^7.23.3
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/helper-simple-access": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 720a231ceade4ae4d2632478db4e7fecf21987d444942b72d523487ac8d715ca97de6c8f415c71e939595e1a4776403e7dc24ed68fe9125ad4acf57753c9bff7
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-modules-systemjs@npm:^7.13.8":
version: 7.16.0
resolution: "@babel/plugin-transform-modules-systemjs@npm:7.16.0"
@@ -2980,6 +3616,20 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-modules-systemjs@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-modules-systemjs@npm:7.23.3"
+ dependencies:
+ "@babel/helper-hoist-variables": ^7.22.5
+ "@babel/helper-module-transforms": ^7.23.3
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/helper-validator-identifier": ^7.22.20
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 0d2fdd993c785aecac9e0850cd5ed7f7d448f0fbb42992a950cc0590167144df25d82af5aac9a5c99ef913d2286782afa44e577af30c10901c5ee8984910fa1f
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-modules-umd@npm:^7.14.0":
version: 7.16.0
resolution: "@babel/plugin-transform-modules-umd@npm:7.16.0"
@@ -3016,6 +3666,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-modules-umd@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-modules-umd@npm:7.23.3"
+ dependencies:
+ "@babel/helper-module-transforms": ^7.23.3
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 586a7a2241e8b4e753a37af9466a9ffa8a67b4ba9aa756ad7500712c05d8fa9a8c1ed4f7bd25fae2a8265e6cf8fe781ec85a8ee885dd34cf50d8955ee65f12dc
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.12.13":
version: 7.16.0
resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.16.0"
@@ -3050,36 +3712,98 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-new-target@npm:^7.12.13":
- version: 7.16.0
- resolution: "@babel/plugin-transform-new-target@npm:7.16.0"
+"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.22.5":
+ version: 7.22.5
+ resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.22.5"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin": ^7.22.5
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 3ee564ddee620c035b928fdc942c5d17e9c4b98329b76f9cefac65c111135d925eb94ed324064cd7556d4f5123beec79abea1d4b97d1c8a2a5c748887a2eb623
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-new-target@npm:^7.12.13":
+ version: 7.16.0
+ resolution: "@babel/plugin-transform-new-target@npm:7.16.0"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.14.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: c741ba3e84c182f1af3174cb7f00c4e434080ff882e72c7b2743d1d636eebcf12c865772be051a323c823bd4ebdfbae19cb78e95218d6b14c338f27a64608e31
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-new-target@npm:^7.16.7":
+ version: 7.16.7
+ resolution: "@babel/plugin-transform-new-target@npm:7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.16.7
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 7410c3e68abc835f87a98d40269e65fb1a05c131decbb6721a80ed49a01bd0c53abb6b8f7f52d5055815509022790e1accca32e975c02f2231ac3cf13d8af768
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-new-target@npm:^7.17.12":
+ version: 7.17.12
+ resolution: "@babel/plugin-transform-new-target@npm:7.17.12"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.17.12
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: bec26350fa49c9a9431d23b4ff234f8eb60554b8cdffca432a94038406aae5701014f343568c0e0cc8afae6f95d492f6bae0d0e2c101c1a484fb20eec75b2c07
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-new-target@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-new-target@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: e5053389316fce73ad5201b7777437164f333e24787fbcda4ae489cd2580dbbbdfb5694a7237bad91fabb46b591d771975d69beb1c740b82cb4761625379f00b
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.23.4"
dependencies:
- "@babel/helper-plugin-utils": ^7.14.5
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: c741ba3e84c182f1af3174cb7f00c4e434080ff882e72c7b2743d1d636eebcf12c865772be051a323c823bd4ebdfbae19cb78e95218d6b14c338f27a64608e31
+ checksum: a27d73ea134d3d9560a6b2e26ab60012fba15f1db95865aa0153c18f5ec82cfef6a7b3d8df74e3c2fca81534fa5efeb6cacaf7b08bdb7d123e3dafdd079886a3
languageName: node
linkType: hard
-"@babel/plugin-transform-new-target@npm:^7.16.7":
- version: 7.16.7
- resolution: "@babel/plugin-transform-new-target@npm:7.16.7"
+"@babel/plugin-transform-numeric-separator@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/plugin-transform-numeric-separator@npm:7.23.4"
dependencies:
- "@babel/helper-plugin-utils": ^7.16.7
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/plugin-syntax-numeric-separator": ^7.10.4
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 7410c3e68abc835f87a98d40269e65fb1a05c131decbb6721a80ed49a01bd0c53abb6b8f7f52d5055815509022790e1accca32e975c02f2231ac3cf13d8af768
+ checksum: 6ba0e5db3c620a3ec81f9e94507c821f483c15f196868df13fa454cbac719a5449baf73840f5b6eb7d77311b24a2cf8e45db53700d41727f693d46f7caf3eec3
languageName: node
linkType: hard
-"@babel/plugin-transform-new-target@npm:^7.17.12":
- version: 7.17.12
- resolution: "@babel/plugin-transform-new-target@npm:7.17.12"
+"@babel/plugin-transform-object-rest-spread@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/plugin-transform-object-rest-spread@npm:7.23.4"
dependencies:
- "@babel/helper-plugin-utils": ^7.17.12
+ "@babel/compat-data": ^7.23.3
+ "@babel/helper-compilation-targets": ^7.22.15
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/plugin-syntax-object-rest-spread": ^7.8.3
+ "@babel/plugin-transform-parameters": ^7.23.3
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: bec26350fa49c9a9431d23b4ff234f8eb60554b8cdffca432a94038406aae5701014f343568c0e0cc8afae6f95d492f6bae0d0e2c101c1a484fb20eec75b2c07
+ checksum: 73fec495e327ca3959c1c03d07a621be09df00036c69fff0455af9a008291677ee9d368eec48adacdc6feac703269a649747568b4af4c4e9f134aa71cc5b378d
languageName: node
linkType: hard
@@ -3107,6 +3831,43 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-object-super@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-object-super@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/helper-replace-supers": ^7.22.20
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: e495497186f621fa79026e183b4f1fbb172fd9df812cbd2d7f02c05b08adbe58012b1a6eb6dd58d11a30343f6ec80d0f4074f9b501d70aa1c94df76d59164c53
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-optional-catch-binding@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.23.4"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/plugin-syntax-optional-catch-binding": ^7.8.3
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: d50b5ee142cdb088d8b5de1ccf7cea85b18b85d85b52f86618f6e45226372f01ad4cdb29abd4fd35ea99a71fefb37009e0107db7a787dcc21d4d402f97470faf
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-optional-chaining@npm:^7.23.3, @babel/plugin-transform-optional-chaining@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/plugin-transform-optional-chaining@npm:7.23.4"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5
+ "@babel/plugin-syntax-optional-chaining": ^7.8.3
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: e7a4c08038288057b7a08d68c4d55396ada9278095509ca51ed8dfb72a7f13f26bdd7c5185de21079fe0a9d60d22c227cb32e300d266c1bda40f70eee9f4bc1e
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-parameters@npm:^7.13.0, @babel/plugin-transform-parameters@npm:^7.16.0":
version: 7.16.3
resolution: "@babel/plugin-transform-parameters@npm:7.16.3"
@@ -3140,6 +3901,43 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-parameters@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-parameters@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: a735b3e85316d17ec102e3d3d1b6993b429bdb3b494651c9d754e3b7d270462ee1f1a126ccd5e3d871af5e683727e9ef98c9d34d4a42204fffaabff91052ed16
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-private-methods@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-private-methods@npm:7.23.3"
+ dependencies:
+ "@babel/helper-create-class-features-plugin": ^7.22.15
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: cedc1285c49b5a6d9a3d0e5e413b756ac40b3ac2f8f68bdfc3ae268bc8d27b00abd8bb0861c72756ff5dd8bf1eb77211b7feb5baf4fdae2ebbaabe49b9adc1d0
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-private-property-in-object@npm:^7.23.4":
+ version: 7.23.4
+ resolution: "@babel/plugin-transform-private-property-in-object@npm:7.23.4"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.22.5
+ "@babel/helper-create-class-features-plugin": ^7.22.15
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/plugin-syntax-private-property-in-object": ^7.14.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: fb7adfe94ea97542f250a70de32bddbc3e0b802381c92be947fec83ebffda57e68533c4d0697152719a3496fdd3ebf3798d451c024cd4ac848fc15ac26b70aa7
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-property-literals@npm:^7.12.13":
version: 7.16.0
resolution: "@babel/plugin-transform-property-literals@npm:7.16.0"
@@ -3162,6 +3960,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-property-literals@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-property-literals@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 16b048c8e87f25095f6d53634ab7912992f78e6997a6ff549edc3cf519db4fca01c7b4e0798530d7f6a05228ceee479251245cdd850a5531c6e6f404104d6cc9
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-regenerator@npm:^7.13.15":
version: 7.16.0
resolution: "@babel/plugin-transform-regenerator@npm:7.16.0"
@@ -3196,6 +4005,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-regenerator@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-regenerator@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ regenerator-transform: ^0.15.2
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 7fdacc7b40008883871b519c9e5cdea493f75495118ccc56ac104b874983569a24edd024f0f5894ba1875c54ee2b442f295d6241c3280e61c725d0dd3317c8e6
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-reserved-words@npm:^7.12.13":
version: 7.16.0
resolution: "@babel/plugin-transform-reserved-words@npm:7.16.0"
@@ -3229,6 +4050,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-reserved-words@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-reserved-words@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 298c4440ddc136784ff920127cea137168e068404e635dc946ddb5d7b2a27b66f1dd4c4acb01f7184478ff7d5c3e7177a127279479926519042948fb7fa0fa48
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-runtime@npm:^7.12.1":
version: 7.13.15
resolution: "@babel/plugin-transform-runtime@npm:7.13.15"
@@ -3283,6 +4115,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-shorthand-properties@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-shorthand-properties@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 5d677a03676f9fff969b0246c423d64d77502e90a832665dc872a5a5e05e5708161ce1effd56bb3c0f2c20a1112fca874be57c8a759d8b08152755519281f326
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-spread@npm:^7.13.0":
version: 7.16.0
resolution: "@babel/plugin-transform-spread@npm:7.16.0"
@@ -3319,6 +4162,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-spread@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-spread@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 8fd5cac201e77a0b4825745f4e07a25f923842f282f006b3a79223c00f61075c8868d12eafec86b2642cd0b32077cdd32314e27bcb75ee5e6a68c0144140dcf2
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-sticky-regex@npm:^7.12.13":
version: 7.16.0
resolution: "@babel/plugin-transform-sticky-regex@npm:7.16.0"
@@ -3341,6 +4196,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-sticky-regex@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-sticky-regex@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 53e55eb2575b7abfdb4af7e503a2bf7ef5faf8bf6b92d2cd2de0700bdd19e934e5517b23e6dfed94ba50ae516b62f3f916773ef7d9bc81f01503f585051e2949
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-template-literals@npm:^7.13.0":
version: 7.16.0
resolution: "@babel/plugin-transform-template-literals@npm:7.16.0"
@@ -3374,6 +4240,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-template-literals@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-template-literals@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: b16c5cb0b8796be0118e9c144d15bdc0d20a7f3f59009c6303a6e9a8b74c146eceb3f05186f5b97afcba7cfa87e34c1585a22186e3d5b22f2fd3d27d959d92b2
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-typeof-symbol@npm:^7.12.13":
version: 7.16.0
resolution: "@babel/plugin-transform-typeof-symbol@npm:7.16.0"
@@ -3407,6 +4284,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-typeof-symbol@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-typeof-symbol@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 0af7184379d43afac7614fc89b1bdecce4e174d52f4efaeee8ec1a4f2c764356c6dba3525c0685231f1cbf435b6dd4ee9e738d7417f3b10ce8bbe869c32f4384
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-typescript@npm:^7.13.0":
version: 7.16.1
resolution: "@babel/plugin-transform-typescript@npm:7.16.1"
@@ -3433,6 +4321,20 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-typescript@npm:^7.20.13":
+ version: 7.23.5
+ resolution: "@babel/plugin-transform-typescript@npm:7.23.5"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.22.5
+ "@babel/helper-create-class-features-plugin": ^7.23.5
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/plugin-syntax-typescript": ^7.23.3
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: d77b5cc22cf48fe461de07e4f058dc9c0d8c4e3ca49de0e3a336a94ab39bfa4f4732598e36c479bec0dd1bf4aff9154bc2dcbfbe3145a751e4771ccae5afaaf8
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-typescript@npm:~7.4.0":
version: 7.4.5
resolution: "@babel/plugin-transform-typescript@npm:7.4.5"
@@ -3493,6 +4395,29 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-unicode-escapes@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-unicode-escapes@npm:7.23.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 561c429183a54b9e4751519a3dfba6014431e9cdc1484fad03bdaf96582dfc72c76a4f8661df2aeeae7c34efd0fa4d02d3b83a2f63763ecf71ecc925f9cc1f60
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-unicode-property-regex@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.23.3"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin": ^7.22.15
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 2298461a194758086d17c23c26c7de37aa533af910f9ebf31ebd0893d4aa317468043d23f73edc782ec21151d3c46cf0ff8098a83b725c49a59de28a1d4d6225
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-unicode-regex@npm:^7.12.13":
version: 7.16.0
resolution: "@babel/plugin-transform-unicode-regex@npm:7.16.0"
@@ -3517,6 +4442,30 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-unicode-regex@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-unicode-regex@npm:7.23.3"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin": ^7.22.15
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: c5f835d17483ba899787f92e313dfa5b0055e3deab332f1d254078a2bba27ede47574b6599fcf34d3763f0c048ae0779dc21d2d8db09295edb4057478dc80a9a
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-unicode-sets-regex@npm:^7.23.3":
+ version: 7.23.3
+ resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.23.3"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin": ^7.22.15
+ "@babel/helper-plugin-utils": ^7.22.5
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 79d0b4c951955ca68235c87b91ab2b393c96285f8aeaa34d6db416d2ddac90000c9bd6e8c4d82b60a2b484da69930507245035f28ba63c6cae341cf3ba68fdef
+ languageName: node
+ linkType: hard
+
"@babel/polyfill@npm:^7.11.5":
version: 7.12.1
resolution: "@babel/polyfill@npm:7.12.1"
@@ -3779,6 +4728,109 @@ __metadata:
languageName: node
linkType: hard
+"@babel/preset-env@npm:^7.20.2":
+ version: 7.23.5
+ resolution: "@babel/preset-env@npm:7.23.5"
+ dependencies:
+ "@babel/compat-data": ^7.23.5
+ "@babel/helper-compilation-targets": ^7.22.15
+ "@babel/helper-plugin-utils": ^7.22.5
+ "@babel/helper-validator-option": ^7.23.5
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.23.3
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.23.3
+ "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ^7.23.3
+ "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2
+ "@babel/plugin-syntax-async-generators": ^7.8.4
+ "@babel/plugin-syntax-class-properties": ^7.12.13
+ "@babel/plugin-syntax-class-static-block": ^7.14.5
+ "@babel/plugin-syntax-dynamic-import": ^7.8.3
+ "@babel/plugin-syntax-export-namespace-from": ^7.8.3
+ "@babel/plugin-syntax-import-assertions": ^7.23.3
+ "@babel/plugin-syntax-import-attributes": ^7.23.3
+ "@babel/plugin-syntax-import-meta": ^7.10.4
+ "@babel/plugin-syntax-json-strings": ^7.8.3
+ "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4
+ "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3
+ "@babel/plugin-syntax-numeric-separator": ^7.10.4
+ "@babel/plugin-syntax-object-rest-spread": ^7.8.3
+ "@babel/plugin-syntax-optional-catch-binding": ^7.8.3
+ "@babel/plugin-syntax-optional-chaining": ^7.8.3
+ "@babel/plugin-syntax-private-property-in-object": ^7.14.5
+ "@babel/plugin-syntax-top-level-await": ^7.14.5
+ "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6
+ "@babel/plugin-transform-arrow-functions": ^7.23.3
+ "@babel/plugin-transform-async-generator-functions": ^7.23.4
+ "@babel/plugin-transform-async-to-generator": ^7.23.3
+ "@babel/plugin-transform-block-scoped-functions": ^7.23.3
+ "@babel/plugin-transform-block-scoping": ^7.23.4
+ "@babel/plugin-transform-class-properties": ^7.23.3
+ "@babel/plugin-transform-class-static-block": ^7.23.4
+ "@babel/plugin-transform-classes": ^7.23.5
+ "@babel/plugin-transform-computed-properties": ^7.23.3
+ "@babel/plugin-transform-destructuring": ^7.23.3
+ "@babel/plugin-transform-dotall-regex": ^7.23.3
+ "@babel/plugin-transform-duplicate-keys": ^7.23.3
+ "@babel/plugin-transform-dynamic-import": ^7.23.4
+ "@babel/plugin-transform-exponentiation-operator": ^7.23.3
+ "@babel/plugin-transform-export-namespace-from": ^7.23.4
+ "@babel/plugin-transform-for-of": ^7.23.3
+ "@babel/plugin-transform-function-name": ^7.23.3
+ "@babel/plugin-transform-json-strings": ^7.23.4
+ "@babel/plugin-transform-literals": ^7.23.3
+ "@babel/plugin-transform-logical-assignment-operators": ^7.23.4
+ "@babel/plugin-transform-member-expression-literals": ^7.23.3
+ "@babel/plugin-transform-modules-amd": ^7.23.3
+ "@babel/plugin-transform-modules-commonjs": ^7.23.3
+ "@babel/plugin-transform-modules-systemjs": ^7.23.3
+ "@babel/plugin-transform-modules-umd": ^7.23.3
+ "@babel/plugin-transform-named-capturing-groups-regex": ^7.22.5
+ "@babel/plugin-transform-new-target": ^7.23.3
+ "@babel/plugin-transform-nullish-coalescing-operator": ^7.23.4
+ "@babel/plugin-transform-numeric-separator": ^7.23.4
+ "@babel/plugin-transform-object-rest-spread": ^7.23.4
+ "@babel/plugin-transform-object-super": ^7.23.3
+ "@babel/plugin-transform-optional-catch-binding": ^7.23.4
+ "@babel/plugin-transform-optional-chaining": ^7.23.4
+ "@babel/plugin-transform-parameters": ^7.23.3
+ "@babel/plugin-transform-private-methods": ^7.23.3
+ "@babel/plugin-transform-private-property-in-object": ^7.23.4
+ "@babel/plugin-transform-property-literals": ^7.23.3
+ "@babel/plugin-transform-regenerator": ^7.23.3
+ "@babel/plugin-transform-reserved-words": ^7.23.3
+ "@babel/plugin-transform-shorthand-properties": ^7.23.3
+ "@babel/plugin-transform-spread": ^7.23.3
+ "@babel/plugin-transform-sticky-regex": ^7.23.3
+ "@babel/plugin-transform-template-literals": ^7.23.3
+ "@babel/plugin-transform-typeof-symbol": ^7.23.3
+ "@babel/plugin-transform-unicode-escapes": ^7.23.3
+ "@babel/plugin-transform-unicode-property-regex": ^7.23.3
+ "@babel/plugin-transform-unicode-regex": ^7.23.3
+ "@babel/plugin-transform-unicode-sets-regex": ^7.23.3
+ "@babel/preset-modules": 0.1.6-no-external-plugins
+ babel-plugin-polyfill-corejs2: ^0.4.6
+ babel-plugin-polyfill-corejs3: ^0.8.5
+ babel-plugin-polyfill-regenerator: ^0.5.3
+ core-js-compat: ^3.31.0
+ semver: ^6.3.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: adddd58d14fc1b2e5f8cf90995f522879362a0543e316afe9e5783f1bd715bb1e92300cd49d7ce3a95c64a96d60788d0089651e2cf4cac937f5469aac1087bb1
+ languageName: node
+ linkType: hard
+
+"@babel/preset-modules@npm:0.1.6-no-external-plugins":
+ version: 0.1.6-no-external-plugins
+ resolution: "@babel/preset-modules@npm:0.1.6-no-external-plugins"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.0.0
+ "@babel/types": ^7.4.4
+ esutils: ^2.0.2
+ peerDependencies:
+ "@babel/core": ^7.0.0-0 || ^8.0.0-0 <8.0.0
+ checksum: 4855e799bc50f2449fb5210f78ea9e8fd46cf4f242243f1e2ed838e2bd702e25e73e822e7f8447722a5f4baa5e67a8f7a0e403f3e7ce04540ff743a9c411c375
+ languageName: node
+ linkType: hard
+
"@babel/preset-modules@npm:^0.1.4, @babel/preset-modules@npm:^0.1.5":
version: 0.1.5
resolution: "@babel/preset-modules@npm:0.1.5"
@@ -3794,6 +4846,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/regjsgen@npm:^0.8.0":
+ version: 0.8.0
+ resolution: "@babel/regjsgen@npm:0.8.0"
+ checksum: 89c338fee774770e5a487382170711014d49a68eb281e74f2b5eac88f38300a4ad545516a7786a8dd5702e9cf009c94c2f582d200f077ac5decd74c56b973730
+ languageName: node
+ linkType: hard
+
"@babel/runtime@npm:7.12.18":
version: 7.12.18
resolution: "@babel/runtime@npm:7.12.18"
@@ -3890,6 +4949,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/template@npm:^7.22.15":
+ version: 7.22.15
+ resolution: "@babel/template@npm:7.22.15"
+ dependencies:
+ "@babel/code-frame": ^7.22.13
+ "@babel/parser": ^7.22.15
+ "@babel/types": ^7.22.15
+ checksum: 1f3e7dcd6c44f5904c184b3f7fe280394b191f2fed819919ffa1e529c259d5b197da8981b6ca491c235aee8dbad4a50b7e31304aa531271cb823a4a24a0dd8fd
+ languageName: node
+ linkType: hard
+
"@babel/template@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/template@npm:7.22.5"
@@ -4068,6 +5138,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.23.0":
+ version: 7.23.5
+ resolution: "@babel/types@npm:7.23.5"
+ dependencies:
+ "@babel/helper-string-parser": ^7.23.4
+ "@babel/helper-validator-identifier": ^7.22.20
+ to-fast-properties: ^2.0.0
+ checksum: 3d21774480a459ef13b41c2e32700d927af649e04b70c5d164814d8e04ab584af66a93330602c2925e1a6925c2b829cc153418a613a4e7d79d011be1f29ad4b2
+ languageName: node
+ linkType: hard
+
"@babel/types@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/types@npm:7.22.5"
@@ -4422,7 +5503,7 @@ __metadata:
languageName: node
linkType: hard
-"@ember/string@npm:^3.0.1":
+"@ember/string@npm:^3.0.1, @ember/string@npm:^3.1.1":
version: 3.1.1
resolution: "@ember/string@npm:3.1.1"
dependencies:
@@ -4461,15 +5542,25 @@ __metadata:
languageName: node
linkType: hard
-"@ember/test-waiters@npm:^3.0.2":
- version: 3.0.2
- resolution: "@ember/test-waiters@npm:3.0.2"
+"@ember/test-waiters@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "@ember/test-waiters@npm:3.1.0"
dependencies:
calculate-cache-key-for-tree: ^2.0.0
ember-cli-babel: ^7.26.6
ember-cli-version-checker: ^5.1.2
semver: ^7.3.5
- checksum: 4ad673fd6c2edc45d7fe378c318dd7f86eabb74eabded5e36b073baa580e2fa2cbb74b52037a2af94a2de98777335129d236b9a33bd33efd30927b0f5e706eaf
+ checksum: f5d8c75ec060f01d038c4f8f419f844e50928b9d7af518b00318844238b43a7b740fc2ec941f45c61fdf698977f2f8a47b34898faa7da2d09e3a38a8137ac8cf
+ languageName: node
+ linkType: hard
+
+"@embroider/addon-shim@npm:1.8.3":
+ version: 1.8.3
+ resolution: "@embroider/addon-shim@npm:1.8.3"
+ dependencies:
+ "@embroider/shared-internals": ^1.8.3
+ semver: ^7.3.5
+ checksum: 11dfdb956631179656727599eb6d6223369f6a04f0e28ac04b793064338c577a89a77c59254a4a665acc46e174cf87196d0f335ab8049be7fe8a2c71ef695974
languageName: node
linkType: hard
@@ -4567,6 +5658,22 @@ __metadata:
languageName: node
linkType: hard
+"@embroider/shared-internals@npm:^1.8.3":
+ version: 1.8.3
+ resolution: "@embroider/shared-internals@npm:1.8.3"
+ dependencies:
+ babel-import-util: ^1.1.0
+ ember-rfc176-data: ^0.3.17
+ fs-extra: ^9.1.0
+ js-string-escape: ^1.0.1
+ lodash: ^4.17.21
+ resolve-package-path: ^4.0.1
+ semver: ^7.3.5
+ typescript-memoize: ^1.0.1
+ checksum: de636225b3e85379caad5bf4cb3c4f8cc8d95d1c9fab05668faf55654ae2cfe1ca2632c5cc4b81f0b52781d4fc5b80879e6cd143801976de46c591430957040f
+ languageName: node
+ linkType: hard
+
"@embroider/shared-internals@npm:^2.0.0":
version: 2.0.0
resolution: "@embroider/shared-internals@npm:2.0.0"
@@ -4981,31 +6088,33 @@ __metadata:
languageName: node
linkType: hard
-"@hashicorp/design-system-components@npm:^2.13.0":
- version: 2.13.0
- resolution: "@hashicorp/design-system-components@npm:2.13.0"
+"@hashicorp/design-system-components@npm:^3.3.0":
+ version: 3.3.0
+ resolution: "@hashicorp/design-system-components@npm:3.3.0"
dependencies:
"@ember/render-modifiers": ^2.0.5
- "@ember/test-waiters": ^3.0.2
+ "@ember/string": ^3.1.1
+ "@ember/test-waiters": ^3.1.0
"@hashicorp/design-system-tokens": ^1.9.0
- "@hashicorp/ember-flight-icons": ^3.1.3
+ "@hashicorp/ember-flight-icons": ^4.0.4
dialog-polyfill: ^0.5.6
ember-a11y-refocus: ^3.0.2
ember-auto-import: ^2.6.3
- ember-cached-decorator-polyfill: ^0.1.4
- ember-cli-babel: ^7.26.11
- ember-cli-clipboard: ^1.0.0
- ember-cli-htmlbars: ^6.2.0
- ember-cli-sass: ^10.0.1
- ember-composable-helpers: ^4.5.0
- ember-focus-trap: ^1.0.2
- ember-keyboard: ^8.2.0
+ ember-cached-decorator-polyfill: ^1.0.2
+ ember-cli-babel: ^8.2.0
+ ember-cli-htmlbars: ^6.3.0
+ ember-cli-sass: ^11.0.1
+ ember-composable-helpers: ^5.0.0
+ ember-element-helper: ^0.8.5
+ ember-focus-trap: ^1.1.0
+ ember-keyboard: ^8.2.1
ember-stargate: ^0.4.3
ember-style-modifier: ^3.0.1
ember-truth-helpers: ^3.1.1
- sass: ^1.62.1
+ prismjs: ^1.29.0
+ sass: ^1.69.5
tippy.js: ^6.3.7
- checksum: 20171b9c3f581214b36205a7a0f5b4a1e37866058a7bfd9d07d51269bcf413da551bcd0738a248de881671e918a32717ebbfd8bedb7534b11de96b5284e3beb9
+ checksum: 47b3262ec9a31e03110309c80833e1b504baa126851106328b0f5668b7c4f312116e35a9f876aedea80ed71de7a32ee8b530498a947adc8f1fe3db8102a6a227
languageName: node
linkType: hard
@@ -5016,22 +6125,23 @@ __metadata:
languageName: node
linkType: hard
-"@hashicorp/ember-flight-icons@npm:^3.1.3":
- version: 3.1.3
- resolution: "@hashicorp/ember-flight-icons@npm:3.1.3"
+"@hashicorp/ember-flight-icons@npm:^4.0.4":
+ version: 4.0.4
+ resolution: "@hashicorp/ember-flight-icons@npm:4.0.4"
dependencies:
- "@hashicorp/flight-icons": ^2.20.0
+ "@hashicorp/flight-icons": ^2.23.0
ember-auto-import: ^2.6.3
- ember-cli-babel: ^7.26.11
- ember-cli-htmlbars: ^6.2.0
- checksum: 196dec75deb983cbfeae6738c5bba7482f645d8ad419b1ab79c0f12f64d0f06e9c7ffb01ce13540e80aabb5ceb490c05c6cd56a7b25ceb3413ebe8274889a298
+ ember-cli-babel: ^8.2.0
+ ember-cli-htmlbars: ^6.3.0
+ ember-get-config: ^2.1.1
+ checksum: fb0a0f26feb80d1dc663b6fd4e1b6849b8c93e4607f8d790f2fa646cee96b4f3df339951b8adddbf85c39052c72fdf54fc4b910baf2fd64c188d660635c8ba73
languageName: node
linkType: hard
-"@hashicorp/flight-icons@npm:^2.20.0":
- version: 2.20.0
- resolution: "@hashicorp/flight-icons@npm:2.20.0"
- checksum: 4ec750e46cd780f007a5046e4cd2cf9e69f946ef131d30b3090c24616c2c0a407f327d0135ebbb0af6578cfdbbb65ab59b18c6ab95599ec04ed2a04827aa24ec
+"@hashicorp/flight-icons@npm:^2.23.0":
+ version: 2.23.0
+ resolution: "@hashicorp/flight-icons@npm:2.23.0"
+ checksum: 0a216a868244bcb3220e13061e5353fd16a0296c1aa9f7444ba2a7148e78532698e7c36a1318573b8ec7fe0283c68c93e7bfbd79a19eb24b2f0006ab78d3b191
languageName: node
linkType: hard
@@ -7941,6 +9051,19 @@ __metadata:
languageName: node
linkType: hard
+"babel-plugin-module-resolver@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "babel-plugin-module-resolver@npm:5.0.0"
+ dependencies:
+ find-babel-config: ^2.0.0
+ glob: ^8.0.3
+ pkg-up: ^3.1.0
+ reselect: ^4.1.7
+ resolve: ^1.22.1
+ checksum: d6880e49fc8e7bac509a2c183b4303ee054a47a80032a59a6f7844bb468ebe5e333b5dc5378443afdab5839e2da2b31a6c8d9a985a0047cd076b82bb9161cc78
+ languageName: node
+ linkType: hard
+
"babel-plugin-polyfill-corejs2@npm:^0.2.0":
version: 0.2.3
resolution: "babel-plugin-polyfill-corejs2@npm:0.2.3"
@@ -7967,6 +9090,19 @@ __metadata:
languageName: node
linkType: hard
+"babel-plugin-polyfill-corejs2@npm:^0.4.6":
+ version: 0.4.6
+ resolution: "babel-plugin-polyfill-corejs2@npm:0.4.6"
+ dependencies:
+ "@babel/compat-data": ^7.22.6
+ "@babel/helper-define-polyfill-provider": ^0.4.3
+ semver: ^6.3.1
+ peerDependencies:
+ "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
+ checksum: 08896811df31530be6a9bcdd630cb9fd4b5ae5181039d18db3796efbc54e38d57a42af460845c10a04434e1bc45c0d47743c7e6c860383cc6b141083cde22030
+ languageName: node
+ linkType: hard
+
"babel-plugin-polyfill-corejs3@npm:^0.2.0":
version: 0.2.5
resolution: "babel-plugin-polyfill-corejs3@npm:0.2.5"
@@ -7995,11 +9131,23 @@ __metadata:
version: 0.5.2
resolution: "babel-plugin-polyfill-corejs3@npm:0.5.2"
dependencies:
- "@babel/helper-define-polyfill-provider": ^0.3.1
- core-js-compat: ^3.21.0
+ "@babel/helper-define-polyfill-provider": ^0.3.1
+ core-js-compat: ^3.21.0
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 2f3184c73f80f00ac876a5ebcad945fd8d2ae70e5f85b7ab6cc3bc69bc74025f4f7070de7abbb2a7274c78e130bd34fc13f4c85342da28205930364a1ef0aa21
+ languageName: node
+ linkType: hard
+
+"babel-plugin-polyfill-corejs3@npm:^0.8.5":
+ version: 0.8.6
+ resolution: "babel-plugin-polyfill-corejs3@npm:0.8.6"
+ dependencies:
+ "@babel/helper-define-polyfill-provider": ^0.4.3
+ core-js-compat: ^3.33.1
peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 2f3184c73f80f00ac876a5ebcad945fd8d2ae70e5f85b7ab6cc3bc69bc74025f4f7070de7abbb2a7274c78e130bd34fc13f4c85342da28205930364a1ef0aa21
+ "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
+ checksum: 36951c2edac42ac0f05b200502e90d77bf66ccee5b52e2937d23496c6ef2372cce31b8c64144da374b77bd3eb65e2721703a52eac56cad16a152326c092cbf77
languageName: node
linkType: hard
@@ -8025,6 +9173,17 @@ __metadata:
languageName: node
linkType: hard
+"babel-plugin-polyfill-regenerator@npm:^0.5.3":
+ version: 0.5.3
+ resolution: "babel-plugin-polyfill-regenerator@npm:0.5.3"
+ dependencies:
+ "@babel/helper-define-polyfill-provider": ^0.4.3
+ peerDependencies:
+ "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
+ checksum: 2bb546582cda1870d19e646a7183baeb2cccd56e0ef3e4eaeabd28e120daf17cb87399194a9ccdcf32506bcaa68d23e73440fc8ab990a7a0f8c5a77c12d5d4bc
+ languageName: node
+ linkType: hard
+
"babel-plugin-syntax-async-functions@npm:^6.8.0":
version: 6.13.0
resolution: "babel-plugin-syntax-async-functions@npm:6.13.0"
@@ -8837,6 +9996,24 @@ __metadata:
languageName: node
linkType: hard
+"broccoli-babel-transpiler@npm:^8.0.0":
+ version: 8.0.0
+ resolution: "broccoli-babel-transpiler@npm:8.0.0"
+ dependencies:
+ broccoli-persistent-filter: ^3.0.0
+ clone: ^2.1.2
+ hash-for-dep: ^1.4.7
+ heimdalljs: ^0.2.1
+ heimdalljs-logger: ^0.1.9
+ json-stable-stringify: ^1.0.1
+ rsvp: ^4.8.4
+ workerpool: ^6.0.2
+ peerDependencies:
+ "@babel/core": ^7.17.9
+ checksum: 5ca5f6664e5ef37e0927501256312ba66d0362180edcdbd9bf23fae2cf057294cc33e5c60e314c6d705c5f2c2dca5f5319b3fc1f1089589c7b16724a6f80e190
+ languageName: node
+ linkType: hard
+
"broccoli-builder@npm:^0.18.14":
version: 0.18.14
resolution: "broccoli-builder@npm:0.18.14"
@@ -9248,6 +10425,25 @@ __metadata:
languageName: node
linkType: hard
+"broccoli-persistent-filter@npm:^3.0.0":
+ version: 3.1.3
+ resolution: "broccoli-persistent-filter@npm:3.1.3"
+ dependencies:
+ async-disk-cache: ^2.0.0
+ async-promise-queue: ^1.0.3
+ broccoli-plugin: ^4.0.3
+ fs-tree-diff: ^2.0.0
+ hash-for-dep: ^1.5.0
+ heimdalljs: ^0.2.1
+ heimdalljs-logger: ^0.1.7
+ promise-map-series: ^0.2.1
+ rimraf: ^3.0.0
+ symlink-or-copy: ^1.0.1
+ sync-disk-cache: ^2.0.0
+ checksum: c3d23e641d15fbb715b730d8f1b69fe5d6c4c66afdee7a57fb77aba3406d4d9026242ffcec6520fdfc55108d72ebcec411948721d8dc8be5d8bdb9c8c10a14ad
+ languageName: node
+ linkType: hard
+
"broccoli-persistent-filter@npm:^3.1.2":
version: 3.1.2
resolution: "broccoli-persistent-filter@npm:3.1.2"
@@ -9826,6 +11022,20 @@ __metadata:
languageName: node
linkType: hard
+"browserslist@npm:^4.22.1":
+ version: 4.22.2
+ resolution: "browserslist@npm:4.22.2"
+ dependencies:
+ caniuse-lite: ^1.0.30001565
+ electron-to-chromium: ^1.4.601
+ node-releases: ^2.0.14
+ update-browserslist-db: ^1.0.13
+ bin:
+ browserslist: cli.js
+ checksum: 33ddfcd9145220099a7a1ac533cecfe5b7548ffeb29b313e1b57be6459000a1f8fa67e781cf4abee97268ac594d44134fcc4a6b2b4750ceddc9796e3a22076d9
+ languageName: node
+ linkType: hard
+
"bser@npm:2.1.1":
version: 2.1.1
resolution: "bser@npm:2.1.1"
@@ -10083,6 +11293,13 @@ __metadata:
languageName: node
linkType: hard
+"caniuse-lite@npm:^1.0.30001565":
+ version: 1.0.30001566
+ resolution: "caniuse-lite@npm:1.0.30001566"
+ checksum: 0f9084bf9f7d5c0a9ddb200c2baddb25dd2ad5a2f205f01e7b971f3e98e9a7bb23c2d86bae48237e9bc9782b682cffaaf3406d936937ab9844987dbe2a6401f2
+ languageName: node
+ linkType: hard
+
"capture-exit@npm:^2.0.0":
version: 2.0.0
resolution: "capture-exit@npm:2.0.0"
@@ -10473,17 +11690,6 @@ __metadata:
languageName: node
linkType: hard
-"clipboard@npm:^2.0.11":
- version: 2.0.11
- resolution: "clipboard@npm:2.0.11"
- dependencies:
- good-listener: ^1.2.2
- select: ^1.1.2
- tiny-emitter: ^2.0.0
- checksum: 413055a6038e43898e0e895216b58ed54fbf386f091cb00188875ef35b186cefbd258acdf4cb4b0ac87cbc00de936f41b45dde9fe1fd1a57f7babb28363b8748
- languageName: node
- linkType: hard
-
"cliui@npm:^5.0.0":
version: 5.0.0
resolution: "cliui@npm:5.0.0"
@@ -10957,6 +12163,15 @@ __metadata:
languageName: node
linkType: hard
+"core-js-compat@npm:^3.31.0, core-js-compat@npm:^3.33.1":
+ version: 3.33.3
+ resolution: "core-js-compat@npm:3.33.3"
+ dependencies:
+ browserslist: ^4.22.1
+ checksum: cb121e83f0f5f18b2b75428cdfb19524936a18459f1e0358f9124c8ff8b75d6a5901495cb996560cfde3a416103973f78eb5947777bb8b2fd877cdf84471465d
+ languageName: node
+ linkType: hard
+
"core-js-compat@npm:^3.9.0":
version: 3.19.1
resolution: "core-js-compat@npm:3.19.1"
@@ -11923,13 +13138,6 @@ __metadata:
languageName: node
linkType: hard
-"delegate@npm:^3.1.2":
- version: 3.2.0
- resolution: "delegate@npm:3.2.0"
- checksum: d943058fe05897228b158cbd1bab05164df28c8f54127873231d6b03b0a5acc1b3ee1f98ac70ccc9b79cd84aa47118a7de111fee2923753491583905069da27d
- languageName: node
- linkType: hard
-
"delegates@npm:^1.0.0":
version: 1.0.0
resolution: "delegates@npm:1.0.0"
@@ -12318,6 +13526,13 @@ __metadata:
languageName: node
linkType: hard
+"electron-to-chromium@npm:^1.4.601":
+ version: 1.4.602
+ resolution: "electron-to-chromium@npm:1.4.602"
+ checksum: a3e30fee47f377f180a99db26f1067acb72891fab720b6800221d74de0c962ac2f595bd977d1f1fd265e0b7f7258b4524c8f9053d17620d01bb8cfa2c0ae32de
+ languageName: node
+ linkType: hard
+
"electron-to-chromium@npm:^1.4.84":
version: 1.4.99
resolution: "electron-to-chromium@npm:1.4.99"
@@ -12350,20 +13565,6 @@ __metadata:
languageName: node
linkType: hard
-"ember-arg-types@npm:^1.0.0":
- version: 1.1.0
- resolution: "ember-arg-types@npm:1.1.0"
- dependencies:
- "@embroider/macros": ^1.8.1
- ember-auto-import: ^2.4.2
- ember-cli-babel: ^7.26.11
- ember-cli-typescript: ^5.1.1
- ember-get-config: ^2.1.1
- prop-types: ^15.8.1
- checksum: f31733f7749c51f1751673afd450106faac3cad61cc0406abc0ef2938d7623416e35794a80636f02a082aac047e4321a037c5f61796ec30baaf156216ba6d87b
- languageName: node
- linkType: hard
-
"ember-asset-loader@npm:^0.6.1":
version: 0.6.1
resolution: "ember-asset-loader@npm:0.6.1"
@@ -12574,21 +13775,25 @@ __metadata:
languageName: node
linkType: hard
-"ember-cached-decorator-polyfill@npm:^0.1.4":
- version: 0.1.4
- resolution: "ember-cached-decorator-polyfill@npm:0.1.4"
+"ember-cached-decorator-polyfill@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "ember-cached-decorator-polyfill@npm:1.0.1"
dependencies:
- "@glimmer/tracking": ^1.0.4
+ "@embroider/macros": ^1.8.3
+ "@glimmer/tracking": ^1.1.2
+ babel-import-util: ^1.2.2
ember-cache-primitive-polyfill: ^1.0.1
- ember-cli-babel: ^7.21.0
+ ember-cli-babel: ^7.26.11
ember-cli-babel-plugin-helpers: ^1.1.1
- checksum: 8f8228e8fe578a78045c00cfd9ffc124dd287e45908e912dba9823ba48a14c1cb7e15fce64f4a034b68edcf6987c51c0500fbab7825e982ea4708672b019780a
+ peerDependencies:
+ ember-source: ^3.13.0 || ^4.0.0
+ checksum: b2589490d897da9f560abc1858c2090fc027a54267dfaa5780ee376e00cec1183b84400df9125f6c25bd7d2b465818d63abb98bb07b3eec0a18b3206a918b804
languageName: node
linkType: hard
-"ember-cached-decorator-polyfill@npm:^1.0.1":
- version: 1.0.1
- resolution: "ember-cached-decorator-polyfill@npm:1.0.1"
+"ember-cached-decorator-polyfill@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "ember-cached-decorator-polyfill@npm:1.0.2"
dependencies:
"@embroider/macros": ^1.8.3
"@glimmer/tracking": ^1.1.2
@@ -12597,8 +13802,8 @@ __metadata:
ember-cli-babel: ^7.26.11
ember-cli-babel-plugin-helpers: ^1.1.1
peerDependencies:
- ember-source: ^3.13.0 || ^4.0.0
- checksum: b2589490d897da9f560abc1858c2090fc027a54267dfaa5780ee376e00cec1183b84400df9125f6c25bd7d2b465818d63abb98bb07b3eec0a18b3206a918b804
+ ember-source: ^3.13.0 || ^4.0.0 || >= 5.0.0
+ checksum: bbfaeafdf89a7ab834d85502829d604e3eb439cb154652b21683492e3e59a918bbaf49d39703f1a896016521d7cf03dc05e89cf5cf06de88fd1489b8e00ef8bb
languageName: node
linkType: hard
@@ -12678,19 +13883,40 @@ __metadata:
languageName: node
linkType: hard
-"ember-cli-clipboard@npm:^1.0.0":
- version: 1.1.0
- resolution: "ember-cli-clipboard@npm:1.1.0"
+"ember-cli-babel@npm:^8.2.0":
+ version: 8.2.0
+ resolution: "ember-cli-babel@npm:8.2.0"
dependencies:
- "@embroider/macros": ^1.10.0
- clipboard: ^2.0.11
- ember-arg-types: ^1.0.0
- ember-auto-import: ^2.4.2
- ember-cli-babel: ^7.26.11
- ember-cli-htmlbars: ^6.1.0
- ember-modifier: ^3.2.7 || ^4.1.0
- prop-types: ^15.8.1
- checksum: 8977ddf744de59662012421feed13e2cd14f6658bc2742504dd5972d0c1181abd8be30085f8dfaaa4f8478fac162eb6ede912ef5c69159d03dac9cb5a6c0bd31
+ "@babel/helper-compilation-targets": ^7.20.7
+ "@babel/plugin-proposal-class-properties": ^7.16.5
+ "@babel/plugin-proposal-decorators": ^7.20.13
+ "@babel/plugin-proposal-private-methods": ^7.16.5
+ "@babel/plugin-proposal-private-property-in-object": ^7.20.5
+ "@babel/plugin-transform-class-static-block": ^7.22.11
+ "@babel/plugin-transform-modules-amd": ^7.20.11
+ "@babel/plugin-transform-runtime": ^7.13.9
+ "@babel/plugin-transform-typescript": ^7.20.13
+ "@babel/preset-env": ^7.20.2
+ "@babel/runtime": 7.12.18
+ amd-name-resolver: ^1.3.1
+ babel-plugin-debug-macros: ^0.3.4
+ babel-plugin-ember-data-packages-polyfill: ^0.1.2
+ babel-plugin-ember-modules-api-polyfill: ^3.5.0
+ babel-plugin-module-resolver: ^5.0.0
+ broccoli-babel-transpiler: ^8.0.0
+ broccoli-debug: ^0.6.4
+ broccoli-funnel: ^3.0.8
+ broccoli-source: ^3.0.1
+ calculate-cache-key-for-tree: ^2.0.0
+ clone: ^2.1.2
+ ember-cli-babel-plugin-helpers: ^1.1.1
+ ember-cli-version-checker: ^5.1.2
+ ensure-posix-path: ^1.0.2
+ resolve-package-path: ^4.0.3
+ semver: ^7.3.8
+ peerDependencies:
+ "@babel/core": ^7.12.0
+ checksum: 26a5abd3107ddfc76221894141b68cab79fb9cdf79ea0fa9646efe47c42f18bda49b854878118f8b57b3ebf5014828cf0ad640e77ffc209e3565f7eb792d1ef5
languageName: node
linkType: hard
@@ -12892,6 +14118,28 @@ __metadata:
languageName: node
linkType: hard
+"ember-cli-htmlbars@npm:^6.3.0":
+ version: 6.3.0
+ resolution: "ember-cli-htmlbars@npm:6.3.0"
+ dependencies:
+ "@ember/edition-utils": ^1.2.0
+ babel-plugin-ember-template-compilation: ^2.0.0
+ babel-plugin-htmlbars-inline-precompile: ^5.3.0
+ broccoli-debug: ^0.6.5
+ broccoli-persistent-filter: ^3.1.2
+ broccoli-plugin: ^4.0.3
+ ember-cli-version-checker: ^5.1.2
+ fs-tree-diff: ^2.0.1
+ hash-for-dep: ^1.5.1
+ heimdalljs-logger: ^0.1.10
+ js-string-escape: ^1.0.1
+ semver: ^7.3.4
+ silent-error: ^1.1.1
+ walk-sync: ^2.2.0
+ checksum: 30639ab2afd4cdf4edf677d6dfdef61865ee1be46449b123917c12a3119346f769573f55897ec3bb2a2dd05bd0e3a645ecc0090453d53545902fd21fbce3d057
+ languageName: node
+ linkType: hard
+
"ember-cli-inject-live-reload@npm:^2.1.0":
version: 2.1.0
resolution: "ember-cli-inject-live-reload@npm:2.1.0"
@@ -13004,7 +14252,7 @@ __metadata:
languageName: node
linkType: hard
-"ember-cli-sass@npm:11.0.1":
+"ember-cli-sass@npm:11.0.1, ember-cli-sass@npm:^11.0.1":
version: 11.0.1
resolution: "ember-cli-sass@npm:11.0.1"
dependencies:
@@ -13016,18 +14264,6 @@ __metadata:
languageName: node
linkType: hard
-"ember-cli-sass@npm:^10.0.1":
- version: 10.0.1
- resolution: "ember-cli-sass@npm:10.0.1"
- dependencies:
- broccoli-funnel: ^2.0.1
- broccoli-merge-trees: ^3.0.1
- broccoli-sass-source-maps: ^4.0.0
- ember-cli-version-checker: ^2.1.0
- checksum: 99eb9045b19c82851a90435df14b4ab4108ee0fd57a9e78d085c225a9d3dfb72bae8118707cf2f1a2d4d37abc2c40ad0dd95c0079f43d051ec90526448189ac3
- languageName: node
- linkType: hard
-
"ember-cli-sri@meirish/ember-cli-sri#rooturl":
version: 2.1.0
resolution: "ember-cli-sri@https://github.com/meirish/ember-cli-sri.git#commit=1c0ff776a61f09121d1ea69ce16e4653da5e1efa"
@@ -13190,7 +14426,7 @@ __metadata:
languageName: node
linkType: hard
-"ember-cli-typescript@npm:^5.1.1, ember-cli-typescript@npm:^5.2.1":
+"ember-cli-typescript@npm:^5.2.1":
version: 5.2.1
resolution: "ember-cli-typescript@npm:5.2.1"
dependencies:
@@ -13390,7 +14626,7 @@ __metadata:
languageName: node
linkType: hard
-"ember-composable-helpers@npm:5.0.0":
+"ember-composable-helpers@npm:5.0.0, ember-composable-helpers@npm:^5.0.0":
version: 5.0.0
resolution: "ember-composable-helpers@npm:5.0.0"
dependencies:
@@ -13402,18 +14638,6 @@ __metadata:
languageName: node
linkType: hard
-"ember-composable-helpers@npm:^4.5.0":
- version: 4.5.0
- resolution: "ember-composable-helpers@npm:4.5.0"
- dependencies:
- "@babel/core": ^7.0.0
- broccoli-funnel: 2.0.1
- ember-cli-babel: ^7.26.3
- resolve: ^1.10.0
- checksum: 39bc86701eee2c8afde0cd912b757fd7f26b06c25df182fc6bc833722bea86a2c4cc4e51659c489dfdcea5630ed87794010584e68b4c52e6049aee8a8c87808b
- languageName: node
- linkType: hard
-
"ember-concurrency-decorators@npm:^2.0.0":
version: 2.0.3
resolution: "ember-concurrency-decorators@npm:2.0.3"
@@ -13537,6 +14761,18 @@ __metadata:
languageName: node
linkType: hard
+"ember-element-helper@npm:^0.8.5":
+ version: 0.8.5
+ resolution: "ember-element-helper@npm:0.8.5"
+ dependencies:
+ "@embroider/addon-shim": 1.8.3
+ "@embroider/util": ^1.0.0
+ peerDependencies:
+ ember-source: ^3.8 || ^4.0.0 || >= 5.0.0
+ checksum: 7be5fa71b172dc74f24bd10bdc179d9e9dcbaaeab5c78763a24dd6f6d384768d6835291771839c6b530940c3ddd259bd7fdc8242576c9cc31e74d6bb35df435b
+ languageName: node
+ linkType: hard
+
"ember-engines@npm:0.8.23":
version: 0.8.23
resolution: "ember-engines@npm:0.8.23"
@@ -13588,7 +14824,7 @@ __metadata:
languageName: node
linkType: hard
-"ember-focus-trap@npm:^1.0.2":
+"ember-focus-trap@npm:^1.1.0":
version: 1.1.0
resolution: "ember-focus-trap@npm:1.1.0"
dependencies:
@@ -13642,7 +14878,7 @@ __metadata:
languageName: node
linkType: hard
-"ember-keyboard@npm:^8.2.0":
+"ember-keyboard@npm:^8.2.1":
version: 8.2.1
resolution: "ember-keyboard@npm:8.2.1"
dependencies:
@@ -13712,7 +14948,7 @@ __metadata:
languageName: node
linkType: hard
-"ember-modifier@npm:^2.1.2 || ^3.1.0 || ^4.0.0, ember-modifier@npm:^3.2.7 || ^4.0.0, ember-modifier@npm:^3.2.7 || ^4.1.0, ember-modifier@npm:^4.1.0":
+"ember-modifier@npm:^2.1.2 || ^3.1.0 || ^4.0.0, ember-modifier@npm:^3.2.7 || ^4.0.0, ember-modifier@npm:^4.1.0":
version: 4.1.0
resolution: "ember-modifier@npm:4.1.0"
dependencies:
@@ -15547,6 +16783,16 @@ __metadata:
languageName: node
linkType: hard
+"find-babel-config@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "find-babel-config@npm:2.0.0"
+ dependencies:
+ json5: ^2.1.1
+ path-exists: ^4.0.0
+ checksum: d110308b02fe6a6411a0cfb7fd50af6740fbf5093eada3d6ddacf99b07fc8eea4aa3475356484710a0032433029a21ce733bb3ef88fda1d6e35c29a3e4983014
+ languageName: node
+ linkType: hard
+
"find-cache-dir@npm:^2.1.0":
version: 2.1.0
resolution: "find-cache-dir@npm:2.1.0"
@@ -16563,15 +17809,6 @@ __metadata:
languageName: node
linkType: hard
-"good-listener@npm:^1.2.2":
- version: 1.2.2
- resolution: "good-listener@npm:1.2.2"
- dependencies:
- delegate: ^3.1.2
- checksum: f39fb82c4e41524f56104cfd2d7aef1a88e72f3f75139115fbdf98cc7d844e0c1b39218b2e83438c6188727bf904ed78c7f0f2feff67b32833bc3af7f0202b33
- languageName: node
- linkType: hard
-
"gopd@npm:^1.0.1":
version: 1.0.1
resolution: "gopd@npm:1.0.1"
@@ -18368,6 +19605,15 @@ __metadata:
languageName: node
linkType: hard
+"json5@npm:^2.1.1, json5@npm:^2.2.2":
+ version: 2.2.3
+ resolution: "json5@npm:2.2.3"
+ bin:
+ json5: lib/cli.js
+ checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349
+ languageName: node
+ linkType: hard
+
"json5@npm:^2.1.2":
version: 2.2.0
resolution: "json5@npm:2.2.0"
@@ -18388,15 +19634,6 @@ __metadata:
languageName: node
linkType: hard
-"json5@npm:^2.2.2":
- version: 2.2.3
- resolution: "json5@npm:2.2.3"
- bin:
- json5: lib/cli.js
- checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349
- languageName: node
- linkType: hard
-
"jsondiffpatch@npm:^0.4.1":
version: 0.4.1
resolution: "jsondiffpatch@npm:0.4.1"
@@ -19227,7 +20464,7 @@ __metadata:
languageName: node
linkType: hard
-"loose-envify@npm:^1.0.0, loose-envify@npm:^1.4.0":
+"loose-envify@npm:^1.0.0":
version: 1.4.0
resolution: "loose-envify@npm:1.4.0"
dependencies:
@@ -20539,6 +21776,13 @@ __metadata:
languageName: node
linkType: hard
+"node-releases@npm:^2.0.14":
+ version: 2.0.14
+ resolution: "node-releases@npm:2.0.14"
+ checksum: 59443a2f77acac854c42d321bf1b43dea0aef55cd544c6a686e9816a697300458d4e82239e2d794ea05f7bbbc8a94500332e2d3ac3f11f52e4b16cbe638b3c41
+ languageName: node
+ linkType: hard
+
"node-releases@npm:^2.0.2":
version: 2.0.2
resolution: "node-releases@npm:2.0.2"
@@ -21861,6 +23105,13 @@ __metadata:
languageName: node
linkType: hard
+"prismjs@npm:^1.21.0":
+ version: 1.29.0
+ resolution: "prismjs@npm:1.29.0"
+ checksum: 007a8869d4456ff8049dc59404e32d5666a07d99c3b0e30a18bd3b7676dfa07d1daae9d0f407f20983865fd8da56de91d09cb08e6aa61f5bc420a27c0beeaf93
+ languageName: node
+ linkType: hard
+
"private@npm:^0.1.6, private@npm:^0.1.8":
version: 0.1.8
resolution: "private@npm:0.1.8"
@@ -21949,17 +23200,6 @@ __metadata:
languageName: node
linkType: hard
-"prop-types@npm:^15.8.1":
- version: 15.8.1
- resolution: "prop-types@npm:15.8.1"
- dependencies:
- loose-envify: ^1.4.0
- object-assign: ^4.1.1
- react-is: ^16.13.1
- checksum: c056d3f1c057cb7ff8344c645450e14f088a915d078dcda795041765047fa080d38e5d626560ccaac94a4e16e3aa15f3557c1a9a8d1174530955e992c675e459
- languageName: node
- linkType: hard
-
"proper-lockfile@npm:^4.1.2":
version: 4.1.2
resolution: "proper-lockfile@npm:4.1.2"
@@ -22218,13 +23458,6 @@ __metadata:
languageName: node
linkType: hard
-"react-is@npm:^16.13.1":
- version: 16.13.1
- resolution: "react-is@npm:16.13.1"
- checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f
- languageName: node
- linkType: hard
-
"read-pkg-up@npm:^8.0.0":
version: 8.0.0
resolution: "read-pkg-up@npm:8.0.0"
@@ -22366,6 +23599,15 @@ __metadata:
languageName: node
linkType: hard
+"regenerate-unicode-properties@npm:^10.1.0":
+ version: 10.1.1
+ resolution: "regenerate-unicode-properties@npm:10.1.1"
+ dependencies:
+ regenerate: ^1.4.2
+ checksum: b80958ef40f125275824c2c47d5081dfaefebd80bff26c76761e9236767c748a4a95a69c053fe29d2df881177f2ca85df4a71fe70a82360388b31159ef19adcf
+ languageName: node
+ linkType: hard
+
"regenerate-unicode-properties@npm:^9.0.0":
version: 9.0.0
resolution: "regenerate-unicode-properties@npm:9.0.0"
@@ -22446,6 +23688,15 @@ __metadata:
languageName: node
linkType: hard
+"regenerator-transform@npm:^0.15.2":
+ version: 0.15.2
+ resolution: "regenerator-transform@npm:0.15.2"
+ dependencies:
+ "@babel/runtime": ^7.8.4
+ checksum: 20b6f9377d65954980fe044cfdd160de98df415b4bff38fbade67b3337efaf078308c4fed943067cd759827cc8cfeca9cb28ccda1f08333b85d6a2acbd022c27
+ languageName: node
+ linkType: hard
+
"regex-not@npm:^1.0.0, regex-not@npm:^1.0.2":
version: 1.0.2
resolution: "regex-not@npm:1.0.2"
@@ -22530,6 +23781,20 @@ __metadata:
languageName: node
linkType: hard
+"regexpu-core@npm:^5.3.1":
+ version: 5.3.2
+ resolution: "regexpu-core@npm:5.3.2"
+ dependencies:
+ "@babel/regjsgen": ^0.8.0
+ regenerate: ^1.4.2
+ regenerate-unicode-properties: ^10.1.0
+ regjsparser: ^0.9.1
+ unicode-match-property-ecmascript: ^2.0.0
+ unicode-match-property-value-ecmascript: ^2.1.0
+ checksum: 95bb97088419f5396e07769b7de96f995f58137ad75fac5811fb5fe53737766dfff35d66a0ee66babb1eb55386ef981feaef392f9df6d671f3c124812ba24da2
+ languageName: node
+ linkType: hard
+
"regjsgen@npm:^0.2.0":
version: 0.2.0
resolution: "regjsgen@npm:0.2.0"
@@ -22584,6 +23849,17 @@ __metadata:
languageName: node
linkType: hard
+"regjsparser@npm:^0.9.1":
+ version: 0.9.1
+ resolution: "regjsparser@npm:0.9.1"
+ dependencies:
+ jsesc: ~0.5.0
+ bin:
+ regjsparser: bin/parser
+ checksum: 5e1b76afe8f1d03c3beaf9e0d935dd467589c3625f6d65fb8ffa14f224d783a0fed4bf49c2c1b8211043ef92b6117313419edf055a098ed8342e340586741afc
+ languageName: node
+ linkType: hard
+
"remark-footnotes@npm:^3.0.0":
version: 3.0.0
resolution: "remark-footnotes@npm:3.0.0"
@@ -22773,6 +24049,13 @@ __metadata:
languageName: node
linkType: hard
+"reselect@npm:^4.1.7":
+ version: 4.1.8
+ resolution: "reselect@npm:4.1.8"
+ checksum: a4ac87cedab198769a29be92bc221c32da76cfdad6911eda67b4d3e7136dca86208c3b210e31632eae31ebd2cded18596f0dd230d3ccc9e978df22f233b5583e
+ languageName: node
+ linkType: hard
+
"resolve-dir@npm:^1.0.0, resolve-dir@npm:^1.0.1":
version: 1.0.1
resolution: "resolve-dir@npm:1.0.1"
@@ -23280,16 +24563,16 @@ __metadata:
languageName: node
linkType: hard
-"sass@npm:^1.62.1":
- version: 1.68.0
- resolution: "sass@npm:1.68.0"
+"sass@npm:^1.69.5":
+ version: 1.69.5
+ resolution: "sass@npm:1.69.5"
dependencies:
chokidar: ">=3.0.0 <4.0.0"
immutable: ^4.0.0
source-map-js: ">=0.6.2 <2.0.0"
bin:
sass: sass.js
- checksum: 65ccede83c96768beeb8dcaf67957b7c76b12ff1276bfd2849d7be151d46ba1400048a67717e6e5e4969bc75e87348e5530f5f272833f2e60a891c21a33d8ab0
+ checksum: c66f4f02882e7aa7aa49703824dadbb5a174dcd05e3cd96f17f73687889aab6027d078b518e2c04b594dfd89b2f574824bf935c7aee46c770aa6be9aafcc49f2
languageName: node
linkType: hard
@@ -23354,13 +24637,6 @@ __metadata:
languageName: node
linkType: hard
-"select@npm:^1.1.2":
- version: 1.1.2
- resolution: "select@npm:1.1.2"
- checksum: 4346151e94f226ea6131e44e68e6d837f3fdee64831b756dd657cc0b02f4cb5107f867cb34a1d1216ab7737d0bf0645d44546afb030bbd8d64e891f5e4c4814e
- languageName: node
- linkType: hard
-
"semver-compare@npm:^1.0.0":
version: 1.0.0
resolution: "semver-compare@npm:1.0.0"
@@ -25020,13 +26296,6 @@ __metadata:
languageName: node
linkType: hard
-"tiny-emitter@npm:^2.0.0":
- version: 2.1.0
- resolution: "tiny-emitter@npm:2.1.0"
- checksum: fbcfb5145751a0e3b109507a828eb6d6d4501352ab7bb33eccef46e22e9d9ad3953158870a6966a59e57ab7c3f9cfac7cab8521db4de6a5e757012f4677df2dd
- languageName: node
- linkType: hard
-
"tiny-glob@npm:0.2.9":
version: 0.2.9
resolution: "tiny-glob@npm:0.2.9"
@@ -25544,6 +26813,13 @@ __metadata:
languageName: node
linkType: hard
+"unicode-match-property-value-ecmascript@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "unicode-match-property-value-ecmascript@npm:2.1.0"
+ checksum: 8d6f5f586b9ce1ed0e84a37df6b42fdba1317a05b5df0c249962bd5da89528771e2d149837cad11aa26bcb84c35355cb9f58a10c3d41fa3b899181ece6c85220
+ languageName: node
+ linkType: hard
+
"unicode-property-aliases-ecmascript@npm:^2.0.0":
version: 2.0.0
resolution: "unicode-property-aliases-ecmascript@npm:2.0.0"
@@ -25723,6 +26999,20 @@ __metadata:
languageName: node
linkType: hard
+"update-browserslist-db@npm:^1.0.13":
+ version: 1.0.13
+ resolution: "update-browserslist-db@npm:1.0.13"
+ dependencies:
+ escalade: ^3.1.1
+ picocolors: ^1.0.0
+ peerDependencies:
+ browserslist: ">= 4.21.0"
+ bin:
+ update-browserslist-db: cli.js
+ checksum: 1e47d80182ab6e4ad35396ad8b61008ae2a1330221175d0abd37689658bdb61af9b705bfc41057fd16682474d79944fb2d86767c5ed5ae34b6276b9bed353322
+ languageName: node
+ linkType: hard
+
"update-section@npm:^0.3.3":
version: 0.3.3
resolution: "update-section@npm:0.3.3"
@@ -25910,8 +27200,8 @@ __metadata:
"@ember/test-waiters": ^3.0.0
"@glimmer/component": ^1.1.2
"@glimmer/tracking": ^1.1.2
- "@hashicorp/design-system-components": ^2.13.0
- "@hashicorp/ember-flight-icons": ^3.1.3
+ "@hashicorp/design-system-components": ^3.3.0
+ "@hashicorp/ember-flight-icons": ^4.0.4
"@hashicorp/structure-icons": ^1.3.0
"@icholy/duration": ^5.1.0
"@tsconfig/ember": ^1.0.1
@@ -26576,6 +27866,13 @@ __metadata:
languageName: node
linkType: hard
+"workerpool@npm:^6.0.2":
+ version: 6.5.1
+ resolution: "workerpool@npm:6.5.1"
+ checksum: f86d13f9139c3a57c5a5867e81905cd84134b499849405dec2ffe5b1acd30dabaa1809f6f6ee603a7c65e1e4325f21509db6b8398eaf202c8b8f5809e26a2e16
+ languageName: node
+ linkType: hard
+
"workerpool@npm:^6.4.0":
version: 6.4.0
resolution: "workerpool@npm:6.4.0"