diff --git a/CHANGELOG.md b/CHANGELOG.md index f680750853f8..48e1dbebaa26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -174,7 +174,7 @@ for write requests as a GA feature (enabled by default) for Integrated Storage. * **Audit Entry Exclusion (enterprise)**: Audit devices support excluding fields from entries being written to them, with expression-based rules (powered by go-bexpr) to determine when the specific fields are excluded. * **Workload Identity Federation UI for AWS (enterprise)**: Add WIF fields to AWS secrets engine. [[GH-28148](https://github.com/hashicorp/vault/pull/28148)] * **KV v2 Patch/Subkey (enterprise)**: Adds GUI support to read the subkeys of a KV v2 secret and patch (partially update) secret data. [[GH-28212](https://github.com/hashicorp/vault/pull/28212)] -* **Self-Managed Static Roles**: Self-Managed Static Roles are now supported for select SQL database engines (Postgres, Oracle). Requires Vault Enterprise. [[GH-28199](https://github.com/hashicorp/vault/pull/28199)] +* **Self-Managed Static Roles**: Self-Managed Static Roles are now supported for the Postgres SQL database engine. Requires Vault Enterprise. [[GH-28199](https://github.com/hashicorp/vault/pull/28199)] * **Vault Minimal Version**: Add the ability to build a minimal version of Vault with only core features using the BUILD_MINIMAL environment variable. [[GH-27394](https://github.com/hashicorp/vault/pull/27394)] * **Vault PKI 3GPP CMPv2 Server (Enterprise)**: Support for the PKI 3GPP CMPv2 certificate management protocol has been added to the Vault PKI Plugin. This allows standard CMPv2 clients to request certificates from a Vault server with no knowledge of Vault APIs. diff --git a/builtin/credential/cert/test-fixtures/keys/cert.pem b/builtin/credential/cert/test-fixtures/keys/cert.pem index 942d26698b12..5b7fa1aed069 100644 --- a/builtin/credential/cert/test-fixtures/keys/cert.pem +++ b/builtin/credential/cert/test-fixtures/keys/cert.pem @@ -1,22 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIDtTCCAp2gAwIBAgIUf+jhKTFBnqSs34II0WS1L4QsbbAwDQYJKoZIhvcNAQEL -BQAwFjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTYwMjI5MDIyNzQxWhcNMjUw -MTA1MTAyODExWjAbMRkwFwYDVQQDExBjZXJ0LmV4YW1wbGUuY29tMIIBIjANBgkq -hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsZx0Svr82YJpFpIy4fJNW5fKA6B8mhxS -TRAVnygAftetT8puHflY0ss7Y6X2OXjsU0PRn+1PswtivhKi+eLtgWkUF9cFYFGn -SgMld6ZWRhNheZhA6ZfQmeM/BF2pa5HK2SDF36ljgjL9T+nWrru2Uv0BCoHzLAmi -YYMiIWplidMmMO5NTRG3k+3AN0TkfakB6JVzjLGhTcXdOcVEMXkeQVqJMAuGouU5 -donyqtnaHuIJGuUdy54YDnX86txhOQhAv6r7dHXzZxS4pmLvw8UI1rsSf/GLcUVG -B+5+AAGF5iuHC3N2DTl4xz3FcN4Cb4w9pbaQ7+mCzz+anqiJfyr2nwIDAQABo4H1 -MIHyMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUm++e -HpyM3p708bgZJuRYEdX1o+UwHwYDVR0jBBgwFoAUncSzT/6HMexyuiU9/7EgHu+o -k5swOwYIKwYBBQUHAQEELzAtMCsGCCsGAQUFBzAChh9odHRwOi8vMTI3LjAuMC4x -OjgyMDAvdjEvcGtpL2NhMCEGA1UdEQQaMBiCEGNlcnQuZXhhbXBsZS5jb22HBH8A -AAEwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDovLzEyNy4wLjAuMTo4MjAwL3YxL3Br -aS9jcmwwDQYJKoZIhvcNAQELBQADggEBABsuvmPSNjjKTVN6itWzdQy+SgMIrwfs -X1Yb9Lefkkwmp9ovKFNQxa4DucuCuzXcQrbKwWTfHGgR8ct4rf30xCRoA7dbQWq4 -aYqNKFWrRaBRAaaYZ/O1ApRTOrXqRx9Eqr0H1BXLsoAq+mWassL8sf6siae+CpwA -KqBko5G0dNXq5T4i2LQbmoQSVetIrCJEeMrU+idkuqfV2h1BQKgSEhFDABjFdTCN -QDAHsEHsi2M4/jRW9fqEuhHSDfl2n7tkFUI8wTHUUCl7gXwweJ4qtaSXIwKXYzNj -xqKHA8Purc1Yfybz4iE1JCROi9fInKlzr5xABq8nb9Qc/J9DIQM+Xmk= +MIIC2zCCAcOgAwIBAgIJAJIiPq+77hewMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNV +BAMTC2V4YW1wbGUuY29tMCAXDTI1MDEwNjE0MzgzMloYDzIwNTAwMTA3MTQzODMy +WjAbMRkwFwYDVQQDExBjZXJ0LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAsZx0Svr82YJpFpIy4fJNW5fKA6B8mhxSTRAVnygAftet +T8puHflY0ss7Y6X2OXjsU0PRn+1PswtivhKi+eLtgWkUF9cFYFGnSgMld6ZWRhNh +eZhA6ZfQmeM/BF2pa5HK2SDF36ljgjL9T+nWrru2Uv0BCoHzLAmiYYMiIWplidMm +MO5NTRG3k+3AN0TkfakB6JVzjLGhTcXdOcVEMXkeQVqJMAuGouU5donyqtnaHuIJ +GuUdy54YDnX86txhOQhAv6r7dHXzZxS4pmLvw8UI1rsSf/GLcUVGB+5+AAGF5iuH +C3N2DTl4xz3FcN4Cb4w9pbaQ7+mCzz+anqiJfyr2nwIDAQABoyUwIzAhBgNVHREE +GjAYghBjZXJ0LmV4YW1wbGUuY29thwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQB/ +0M2jZ8cZJW23s1xpMDS5u2ScrW4QdpVsPbuBu5dxi3SNx7MK0CbvcNVUEZE0WV6b +rCYvYS0+SBi0skudHRV7IeRADPcvzbXY/AdFktWt0adtQ/5B/DKeZIRrnhGtlzhD +m8b3TTnKLoGdV7iS5HO8emvlzaihY/5PjObkztLRLLDRmBAOwYv4z/xBhEqZJRV1 +Ztywy/Qy5srNJug+sHmj8JlBldob/Ohk7Eon04XvXMuCIBptPG/QytnmgGbDGghD +WO/HpCWBh6GHrwzQtof8y7Upxi16i5DSiFbRwNXgRyST4W/ChpZoggvOJ/RI4o2g +5serAZLPfBGztdRbTef2 -----END CERTIFICATE----- diff --git a/builtin/credential/cert/test-fixtures/keys/rebuild-cert.md b/builtin/credential/cert/test-fixtures/keys/rebuild-cert.md new file mode 100644 index 000000000000..6a69ff78e460 --- /dev/null +++ b/builtin/credential/cert/test-fixtures/keys/rebuild-cert.md @@ -0,0 +1,6 @@ +To rebuild the cert.pem within this folder run the following commands + +```shell +$ openssl x509 -in cert.pem -signkey key.pem -x509toreq -out cert.csr +$ openssl x509 -req -in cert.csr -CA ../root/rootcacert.pem -CAkey ../root/rootcakey.pem -CAcreateserial -out cert.pem -days 9132 -sha256 -extensions v3_req -extfile <(echo "[v3_req]\nsubjectAltName=DNS:cert.example.com,IP:127.0.0.1") +``` diff --git a/builtin/credential/ldap/backend.go b/builtin/credential/ldap/backend.go index 6993eb06fc00..9bdb6f567311 100644 --- a/builtin/credential/ldap/backend.go +++ b/builtin/credential/ldap/backend.go @@ -121,14 +121,12 @@ func (b *backend) Login(ctx context.Context, req *logical.Request, username stri if b.Logger().IsDebug() { b.Logger().Debug(errString) } - ldapResponse.AddWarning(errString) } for _, warning := range c.Warnings { if b.Logger().IsDebug() { b.Logger().Debug(string(warning)) } - ldapResponse.AddWarning(string(warning)) } var allGroups []string diff --git a/builtin/credential/ldap/backend_test.go b/builtin/credential/ldap/backend_test.go index c791cb4cf795..c1b84c82a9cd 100644 --- a/builtin/credential/ldap/backend_test.go +++ b/builtin/credential/ldap/backend_test.go @@ -1183,8 +1183,8 @@ func testAccStepLoginNoGroupDN(t *testing.T, user string, pass string) logicalte // Verifies a search without defined GroupDN returns a warning rather than failing Check: func(resp *logical.Response) error { - if len(resp.Warnings) != 1 { - return fmt.Errorf("expected a warning due to no group dn, got: %#v", resp.Warnings) + if len(resp.Warnings) != 0 { + return fmt.Errorf("expected a no warnings, got: %#v", resp.Warnings) } return logicaltest.TestCheckAuth([]string{"bar", "default"})(resp) diff --git a/builtin/logical/aws/backend.go b/builtin/logical/aws/backend.go index 85ff7aa994bc..2313561201a2 100644 --- a/builtin/logical/aws/backend.go +++ b/builtin/logical/aws/backend.go @@ -10,6 +10,8 @@ import ( "sync" "time" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/iam/iamiface" "github.com/aws/aws-sdk-go/service/sts/stsiface" "github.com/hashicorp/vault/sdk/framework" @@ -74,6 +76,91 @@ func Backend(_ *logical.BackendConfig) *backend { } return nil }, + RotateCredential: func(ctx context.Context, req *logical.Request) error { + // the following code is a modified version of the rotate-root method + client, err := b.clientIAM(ctx, req.Storage) + if err != nil { + return err + } + if client == nil { + return fmt.Errorf("nil IAM client") + } + + b.clientMutex.Lock() + defer b.clientMutex.Unlock() + + rawRootConfig, err := req.Storage.Get(ctx, "config/root") + if err != nil { + return err + } + if rawRootConfig == nil { + return fmt.Errorf("no configuration found for config/root") + } + var config rootConfig + if err := rawRootConfig.DecodeJSON(&config); err != nil { + return fmt.Errorf("error reading root configuration: %w", err) + } + + if config.AccessKey == "" || config.SecretKey == "" { + return fmt.Errorf("cannot call config/rotate-root when either access_key or secret_key is empty") + } + + var getUserInput iam.GetUserInput // empty input means get current user + getUserRes, err := client.GetUserWithContext(ctx, &getUserInput) + if err != nil { + return fmt.Errorf("error calling GetUser: %w", err) + } + if getUserRes == nil { + return fmt.Errorf("nil response from GetUser") + } + if getUserRes.User == nil { + return fmt.Errorf("nil user returned from GetUser") + } + if getUserRes.User.UserName == nil { + return fmt.Errorf("nil UserName returned from GetUser") + } + + createAccessKeyInput := iam.CreateAccessKeyInput{ + UserName: getUserRes.User.UserName, + } + createAccessKeyRes, err := client.CreateAccessKeyWithContext(ctx, &createAccessKeyInput) + if err != nil { + return fmt.Errorf("error calling CreateAccessKey: %w", err) + } + if createAccessKeyRes.AccessKey == nil { + return fmt.Errorf("nil response from CreateAccessKey") + } + if createAccessKeyRes.AccessKey.AccessKeyId == nil || createAccessKeyRes.AccessKey.SecretAccessKey == nil { + return fmt.Errorf("nil AccessKeyId or SecretAccessKey returned from CreateAccessKey") + } + + oldAccessKey := config.AccessKey + + config.AccessKey = *createAccessKeyRes.AccessKey.AccessKeyId + config.SecretKey = *createAccessKeyRes.AccessKey.SecretAccessKey + + newEntry, err := logical.StorageEntryJSON("config/root", config) + if err != nil { + return fmt.Errorf("error generating new config/root JSON: %w", err) + } + if err := req.Storage.Put(ctx, newEntry); err != nil { + return fmt.Errorf("error saving new config/root: %w", err) + } + + b.iamClient = nil + b.stsClient = nil + + deleteAccessKeyInput := iam.DeleteAccessKeyInput{ + AccessKeyId: aws.String(oldAccessKey), + UserName: getUserRes.User.UserName, + } + _, err = client.DeleteAccessKeyWithContext(ctx, &deleteAccessKeyInput) + if err != nil { + return fmt.Errorf("error deleting old access key: %w", err) + } + + return nil + }, BackendType: logical.TypeLogical, } diff --git a/builtin/logical/aws/path_config_root.go b/builtin/logical/aws/path_config_root.go index 84b2f92fa555..96c13244304c 100644 --- a/builtin/logical/aws/path_config_root.go +++ b/builtin/logical/aws/path_config_root.go @@ -9,13 +9,18 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/helper/automatedrotationutil" "github.com/hashicorp/vault/sdk/helper/pluginidentityutil" "github.com/hashicorp/vault/sdk/helper/pluginutil" "github.com/hashicorp/vault/sdk/logical" + "github.com/hashicorp/vault/sdk/rotation" ) // A single default template that supports both the different credential types (IAM/STS) that are capped at differing length limits (64 chars/32 chars respectively) -const defaultUserNameTemplate = `{{ if (eq .Type "STS") }}{{ printf "vault-%s-%s" (unix_time) (random 20) | truncate 32 }}{{ else }}{{ printf "vault-%s-%s-%s" (printf "%s-%s" (.DisplayName) (.PolicyName) | truncate 42) (unix_time) (random 20) | truncate 64 }}{{ end }}` +const ( + defaultUserNameTemplate = `{{ if (eq .Type "STS") }}{{ printf "vault-%s-%s" (unix_time) (random 20) | truncate 32 }}{{ else }}{{ printf "vault-%s-%s-%s" (printf "%s-%s" (.DisplayName) (.PolicyName) | truncate 42) (unix_time) (random 20) | truncate 64 }}{{ end }}` + rootRotationJobName = "aws-root-creds" +) func pathConfigRoot(b *backend) *framework.Path { p := &framework.Path{ @@ -95,6 +100,7 @@ func pathConfigRoot(b *backend) *framework.Path { HelpDescription: pathConfigRootHelpDesc, } pluginidentityutil.AddPluginIdentityTokenFields(p.Fields) + automatedrotationutil.AddAutomatedRotationFields(p.Fields) return p } @@ -103,20 +109,14 @@ func (b *backend) pathConfigRootRead(ctx context.Context, req *logical.Request, b.clientMutex.RLock() defer b.clientMutex.RUnlock() - entry, err := req.Storage.Get(ctx, "config/root") + config, exists, err := getConfigFromStorage(ctx, req) if err != nil { return nil, err } - if entry == nil { + if !exists { return nil, nil } - var config rootConfig - - if err := entry.DecodeJSON(&config); err != nil { - return nil, err - } - configData := map[string]interface{}{ "access_key": config.AccessKey, "region": config.Region, @@ -131,6 +131,8 @@ func (b *backend) pathConfigRootRead(ctx context.Context, req *logical.Request, } config.PopulatePluginIdentityTokenData(configData) + config.PopulateAutomatedRotationData(configData) + return &logical.Response{ Data: configData, }, nil @@ -158,6 +160,12 @@ func (b *backend) pathConfigRootWrite(ctx context.Context, req *logical.Request, b.clientMutex.Lock() defer b.clientMutex.Unlock() + // check for existing config + previousCfg, previousCfgExists, err := getConfigFromStorage(ctx, req) + if err != nil { + return nil, err + } + rc := rootConfig{ AccessKey: data.Get("access_key").(string), SecretKey: data.Get("secret_key").(string), @@ -174,6 +182,9 @@ func (b *backend) pathConfigRootWrite(ctx context.Context, req *logical.Request, if err := rc.ParsePluginIdentityTokenFields(data); err != nil { return logical.ErrorResponse(err.Error()), nil } + if err := rc.ParseAutomatedRotationFields(data); err != nil { + return logical.ErrorResponse(err.Error()), nil + } if rc.IdentityTokenAudience != "" && rc.AccessKey != "" { return logical.ErrorResponse("only one of 'access_key' or 'identity_token_audience' can be set"), nil @@ -195,12 +206,54 @@ func (b *backend) pathConfigRootWrite(ctx context.Context, req *logical.Request, } } - entry, err := logical.StorageEntryJSON("config/root", rc) - if err != nil { - return nil, err + // Save the initial config only if it does not already exist + if !previousCfgExists { + if err := putConfigToStorage(ctx, req, &rc); err != nil { + return nil, err + } } - if err := req.Storage.Put(ctx, entry); err != nil { + // Now that the root config is set up, register the rotation job if it required + if rc.ShouldRegisterRotationJob() { + cfgReq := &rotation.RotationJobConfigureRequest{ + Name: rootRotationJobName, + MountPoint: req.MountPoint, + ReqPath: req.Path, + RotationSchedule: rc.RotationSchedule, + RotationWindow: rc.RotationWindow, + RotationPeriod: rc.RotationPeriod, + } + + rotationJob, err := rotation.ConfigureRotationJob(cfgReq) + if err != nil { + return logical.ErrorResponse("error configuring rotation job: %s", err), nil + } + + b.Logger().Debug("Registering rotation job", "mount", req.MountPoint+req.Path) + rotationID, err := b.System().RegisterRotationJob(ctx, rotationJob) + if err != nil { + return logical.ErrorResponse("error registering rotation job: %s", err), nil + } + + rc.RotationID = rotationID + } + + // Disable Automated Rotation and Deregister credentials if required + if rc.DisableAutomatedRotation { + // Ensure de-registering only occurs on updates and if + // a credential has actually been registered + if previousCfgExists && previousCfg.RotationID != "" { + err := b.System().DeregisterRotationJob(ctx, previousCfg.RotationID) + if err != nil { + return logical.ErrorResponse("error de-registering rotation job: %s", err), nil + } + + rc.RotationID = "" + } + } + + // update config entry with rotation ID + if err := putConfigToStorage(ctx, req, &rc); err != nil { return nil, err } @@ -212,8 +265,40 @@ func (b *backend) pathConfigRootWrite(ctx context.Context, req *logical.Request, return nil, nil } +func getConfigFromStorage(ctx context.Context, req *logical.Request) (*rootConfig, bool, error) { + entry, err := req.Storage.Get(ctx, "config/root") + if err != nil { + return nil, false, err + } + if entry == nil { + return nil, false, nil + } + + var config rootConfig + + if err := entry.DecodeJSON(&config); err != nil { + return nil, false, err + } + + return &config, true, nil +} + +func putConfigToStorage(ctx context.Context, req *logical.Request, rc *rootConfig) error { + entry, err := logical.StorageEntryJSON("config/root", rc) + if err != nil { + return err + } + + if err := req.Storage.Put(ctx, entry); err != nil { + return err + } + + return nil +} + type rootConfig struct { pluginidentityutil.PluginIdentityTokenParams + automatedrotationutil.AutomatedRotationParams AccessKey string `json:"access_key"` SecretKey string `json:"secret_key"` diff --git a/builtin/logical/aws/path_config_root_test.go b/builtin/logical/aws/path_config_root_test.go index 1439a8b5ce21..d0d205772b3e 100644 --- a/builtin/logical/aws/path_config_root_test.go +++ b/builtin/logical/aws/path_config_root_test.go @@ -8,9 +8,12 @@ import ( "reflect" "testing" + "github.com/hashicorp/vault/helper/namespace" + "github.com/hashicorp/vault/sdk/helper/automatedrotationutil" "github.com/hashicorp/vault/sdk/helper/pluginidentityutil" "github.com/hashicorp/vault/sdk/helper/pluginutil" "github.com/hashicorp/vault/sdk/logical" + "github.com/hashicorp/vault/sdk/rotation" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -25,19 +28,23 @@ func TestBackend_PathConfigRoot(t *testing.T) { } configData := map[string]interface{}{ - "access_key": "AKIAEXAMPLE", - "secret_key": "RandomData", - "region": "us-west-2", - "iam_endpoint": "https://iam.amazonaws.com", - "sts_endpoint": "https://sts.us-west-2.amazonaws.com", - "sts_region": "", - "sts_fallback_endpoints": []string{}, - "sts_fallback_regions": []string{}, - "max_retries": 10, - "username_template": defaultUserNameTemplate, - "role_arn": "", - "identity_token_audience": "", - "identity_token_ttl": int64(0), + "access_key": "AKIAEXAMPLE", + "secret_key": "RandomData", + "region": "us-west-2", + "iam_endpoint": "https://iam.amazonaws.com", + "sts_endpoint": "https://sts.us-west-2.amazonaws.com", + "sts_region": "", + "sts_fallback_endpoints": []string{}, + "sts_fallback_regions": []string{}, + "max_retries": 10, + "username_template": defaultUserNameTemplate, + "role_arn": "", + "identity_token_audience": "", + "identity_token_ttl": int64(0), + "rotation_schedule": "", + "rotation_window": 0, + "rotation_id": "", + "disable_automated_rotation": false, } configReq := &logical.Request{ @@ -62,6 +69,8 @@ func TestBackend_PathConfigRoot(t *testing.T) { } delete(configData, "secret_key") + // remove rotation_period from response for comparison with original config + delete(resp.Data, "rotation_period") require.Equal(t, configData, resp.Data) if !reflect.DeepEqual(resp.Data, configData) { t.Errorf("bad: expected to read config root as %#v, got %#v instead", configData, resp.Data) @@ -80,19 +89,23 @@ func TestBackend_PathConfigRoot_STSFallback(t *testing.T) { } configData := map[string]interface{}{ - "access_key": "AKIAEXAMPLE", - "secret_key": "RandomData", - "region": "us-west-2", - "iam_endpoint": "https://iam.amazonaws.com", - "sts_endpoint": "https://sts.us-west-2.amazonaws.com", - "sts_region": "", - "sts_fallback_endpoints": []string{"192.168.1.1", "127.0.0.1"}, - "sts_fallback_regions": []string{"my-house-1", "my-house-2"}, - "max_retries": 10, - "username_template": defaultUserNameTemplate, - "role_arn": "", - "identity_token_audience": "", - "identity_token_ttl": int64(0), + "access_key": "AKIAEXAMPLE", + "secret_key": "RandomData", + "region": "us-west-2", + "iam_endpoint": "https://iam.amazonaws.com", + "sts_endpoint": "https://sts.us-west-2.amazonaws.com", + "sts_region": "", + "sts_fallback_endpoints": []string{"192.168.1.1", "127.0.0.1"}, + "sts_fallback_regions": []string{"my-house-1", "my-house-2"}, + "max_retries": 10, + "username_template": defaultUserNameTemplate, + "role_arn": "", + "identity_token_audience": "", + "identity_token_ttl": int64(0), + "rotation_schedule": "", + "rotation_window": 0, + "rotation_id": "", + "disable_automated_rotation": false, } configReq := &logical.Request{ @@ -117,6 +130,8 @@ func TestBackend_PathConfigRoot_STSFallback(t *testing.T) { } delete(configData, "secret_key") + // remove rotation_period from response for comparison with original config + delete(resp.Data, "rotation_period") require.Equal(t, configData, resp.Data) if !reflect.DeepEqual(resp.Data, configData) { t.Errorf("bad: expected to read config root as %#v, got %#v instead", configData, resp.Data) @@ -124,19 +139,23 @@ func TestBackend_PathConfigRoot_STSFallback(t *testing.T) { // test we can handle comma separated strings, per CommaStringSlice configData = map[string]interface{}{ - "access_key": "AKIAEXAMPLE", - "secret_key": "RandomData", - "region": "us-west-2", - "iam_endpoint": "https://iam.amazonaws.com", - "sts_endpoint": "https://sts.us-west-2.amazonaws.com", - "sts_region": "", - "sts_fallback_endpoints": "1.1.1.1,8.8.8.8", - "sts_fallback_regions": "zone-1,zone-2", - "max_retries": 10, - "username_template": defaultUserNameTemplate, - "role_arn": "", - "identity_token_audience": "", - "identity_token_ttl": int64(0), + "access_key": "AKIAEXAMPLE", + "secret_key": "RandomData", + "region": "us-west-2", + "iam_endpoint": "https://iam.amazonaws.com", + "sts_endpoint": "https://sts.us-west-2.amazonaws.com", + "sts_region": "", + "sts_fallback_endpoints": "1.1.1.1,8.8.8.8", + "sts_fallback_regions": "zone-1,zone-2", + "max_retries": 10, + "username_template": defaultUserNameTemplate, + "role_arn": "", + "identity_token_audience": "", + "identity_token_ttl": int64(0), + "rotation_schedule": "", + "rotation_window": 0, + "rotation_id": "", + "disable_automated_rotation": false, } configReq = &logical.Request{ @@ -161,6 +180,8 @@ func TestBackend_PathConfigRoot_STSFallback(t *testing.T) { } delete(configData, "secret_key") + // remove rotation_period from response for comparison with original config + delete(resp.Data, "rotation_period") configData["sts_fallback_endpoints"] = []string{"1.1.1.1", "8.8.8.8"} configData["sts_fallback_regions"] = []string{"zone-1", "zone-2"} require.Equal(t, configData, resp.Data) @@ -245,6 +266,40 @@ func TestBackend_PathConfigRoot_PluginIdentityToken(t *testing.T) { assert.ErrorContains(t, resp.Error(), pluginidentityutil.ErrPluginWorkloadIdentityUnsupported.Error()) } +// TestBackend_PathConfigRoot_RegisterRootRotation tests that configuration +// and registering a root credential returns an immediate error. +func TestBackend_PathConfigRoot_RegisterRootRotation(t *testing.T) { + config := logical.TestBackendConfig() + config.StorageView = &logical.InmemStorage{} + config.System = &testSystemView{} + + nsCtx := namespace.ContextWithNamespace(context.Background(), namespace.RootNamespace) + + b := Backend(config) + if err := b.Setup(nsCtx, config); err != nil { + t.Fatal(err) + } + + configData := map[string]interface{}{ + "access_key": "access-key", + "secret_key": "secret-key", + "rotation_schedule": "*/30 * * * * *", + "rotation_window": 60, + } + + configReq := &logical.Request{ + Operation: logical.UpdateOperation, + Storage: config.StorageView, + Path: "config/root", + Data: configData, + } + + resp, err := b.HandleRequest(context.Background(), configReq) + assert.NoError(t, err) + assert.NotNil(t, resp) + assert.ErrorContains(t, resp.Error(), automatedrotationutil.ErrRotationManagerUnsupported.Error()) +} + type testSystemView struct { logical.StaticSystemView } @@ -252,3 +307,7 @@ type testSystemView struct { func (d testSystemView) GenerateIdentityToken(_ context.Context, _ *pluginutil.IdentityTokenRequest) (*pluginutil.IdentityTokenResponse, error) { return nil, pluginidentityutil.ErrPluginWorkloadIdentityUnsupported } + +func (d testSystemView) RegisterRotationJob(_ context.Context, _ *rotation.RotationJob) (string, error) { + return "", automatedrotationutil.ErrRotationManagerUnsupported +} diff --git a/builtin/logical/database/path_roles.go b/builtin/logical/database/path_roles.go index a6c2b233db86..f565e90ffa8a 100644 --- a/builtin/logical/database/path_roles.go +++ b/builtin/logical/database/path_roles.go @@ -649,11 +649,12 @@ func (b *databaseBackend) pathStaticRoleCreateUpdate(ctx context.Context, req *l } lastVaultRotation := role.StaticAccount.LastVaultRotation + updateAllowed := lastVaultRotation.IsZero() + if passwordRaw, ok := data.GetOk("password"); ok { // We will allow users to update the password until the point where // Vault assumes management of the account so that we don't break the // promise of Vault being the source of truth. - updateAllowed := lastVaultRotation.IsZero() if updateAllowed { role.StaticAccount.Password = passwordRaw.(string) @@ -663,7 +664,8 @@ func (b *databaseBackend) pathStaticRoleCreateUpdate(ctx context.Context, req *l } if connDetails != nil && connDetails.SelfManaged { - // Password and SelfManagedPassword should map to the same value + // SelfManagedPassword was deprecated in favor of Password, so they + // should map to the same value role.StaticAccount.SelfManagedPassword = passwordRaw.(string) } } else { @@ -671,13 +673,18 @@ func (b *databaseBackend) pathStaticRoleCreateUpdate(ctx context.Context, req *l } } - if smPasswordRaw, ok := data.GetOk("self_managed_password"); ok && createRole { + if smPasswordRaw, ok := data.GetOk("self_managed_password"); ok { if _, ok := data.GetOk("password"); ok { return logical.ErrorResponse(errNoPasswordAndSelfManagedPassword), nil } - // Password and SelfManagedPassword should map to the same value - role.StaticAccount.SelfManagedPassword = smPasswordRaw.(string) - role.StaticAccount.Password = smPasswordRaw.(string) + if updateAllowed { + // SelfManagedPassword was deprecated in favor of Password, so they + // should map to the same value + role.StaticAccount.SelfManagedPassword = smPasswordRaw.(string) + role.StaticAccount.Password = smPasswordRaw.(string) + } else { + return logical.ErrorResponse("%s: role=%s, lastVaultRotation=%s", errNoUpdateAfterRotation, name, lastVaultRotation), nil + } } if skipImportRotationRaw, ok := data.GetOk("skip_import_rotation"); ok { diff --git a/builtin/logical/database/rotation_test.go b/builtin/logical/database/rotation_test.go index 7ab4311d1255..6ef586f3679a 100644 --- a/builtin/logical/database/rotation_test.go +++ b/builtin/logical/database/rotation_test.go @@ -1029,28 +1029,23 @@ func TestBackend_StaticRole_Rotation_MongoDBAtlas(t *testing.T) { // does not break on invalid values. func TestQueueTickIntervalKeyConfig(t *testing.T) { t.Parallel() - cluster, sys := getClusterPostgresDB(t) + cluster, sys := getCluster(t) defer cluster.Cleanup() - config := logical.TestBackendConfig() - config.StorageView = &logical.InmemStorage{} - config.System = sys - config.Config[queueTickIntervalKey] = "1" - - // Rotation ticker starts running in Factory call - b, err := Factory(context.Background(), config) - require.Nil(t, err) - b.Cleanup(context.Background()) - - config.Config[queueTickIntervalKey] = "0" - b, err = Factory(context.Background(), config) - require.Nil(t, err) - b.Cleanup(context.Background()) - - config.Config[queueTickIntervalKey] = "-1" - b, err = Factory(context.Background(), config) - require.Nil(t, err) - b.Cleanup(context.Background()) + values := []string{"1", "0", "-1"} + for _, v := range values { + t.Run("test"+v, func(t *testing.T) { + config := logical.TestBackendConfig() + config.StorageView = &logical.InmemStorage{} + config.System = sys + config.Config[queueTickIntervalKey] = v + + // Rotation ticker starts running in Factory call + b, err := Factory(context.Background(), config) + require.Nil(t, err) + b.Cleanup(context.Background()) + }) + } } func testBackend_StaticRole_Rotations(t *testing.T, createUser userCreator, opts map[string]interface{}) { diff --git a/builtin/logical/pki/acme_billing_test.go b/builtin/logical/pki/acme_billing_test.go index f8db67e64478..b1948d7be29c 100644 --- a/builtin/logical/pki/acme_billing_test.go +++ b/builtin/logical/pki/acme_billing_test.go @@ -104,17 +104,15 @@ func TestACMEBilling(t *testing.T) { expectedCount = validateClientCount(t, client, "ns2/pki", expectedCount+1, "unique identifier in a different namespace") // Check the current fragment - localFragment, globalFragment := cluster.Cores[0].Core.ResetActivityLog() - if globalFragment == nil || localFragment == nil { + fragment := cluster.Cores[0].Core.ResetActivityLog()[0] + if fragment == nil { t.Fatal("no fragment created") } - validateAcmeClientTypes(t, localFragment[0], 0) - validateAcmeClientTypes(t, globalFragment[0], expectedCount) + validateAcmeClientTypes(t, fragment, expectedCount) } func validateAcmeClientTypes(t *testing.T, fragment *activity.LogFragment, expectedCount int64) { t.Helper() - if int64(len(fragment.Clients)) != expectedCount { t.Fatalf("bad number of entities, expected %v: got %v, entities are: %v", expectedCount, len(fragment.Clients), fragment.Clients) } diff --git a/builtin/logical/pki/acme_state.go b/builtin/logical/pki/acme_state.go index 63962d933b99..996639af1d9d 100644 --- a/builtin/logical/pki/acme_state.go +++ b/builtin/logical/pki/acme_state.go @@ -11,7 +11,6 @@ import ( "io" "net" "path" - "strings" "sync" "sync/atomic" "time" @@ -311,7 +310,22 @@ func (a *acmeState) UpdateAccount(sc *storageContext, acct *acmeAccount) error { // LoadAccount will load the account object based on the passed in keyId field value // otherwise will return an error if the account does not exist. func (a *acmeState) LoadAccount(ac *acmeContext, keyId string) (*acmeAccount, error) { - entry, err := ac.sc.Storage.Get(ac.sc.Context, acmeAccountPrefix+keyId) + acct, err := a.LoadAccountWithoutDirEnforcement(ac.sc, keyId) + if err != nil { + return acct, err + } + + if acct.AcmeDirectory != ac.acmeDirectory { + return nil, fmt.Errorf("%w: account part of different ACME directory path", ErrMalformed) + } + + return acct, nil +} + +// LoadAccountWithoutDirEnforcement will load the account object based on the passed in keyId field value, +// but does not enforce the ACME directory path, normally this is used by non ACME specific APIs. +func (a *acmeState) LoadAccountWithoutDirEnforcement(sc *storageContext, keyId string) (*acmeAccount, error) { + entry, err := sc.Storage.Get(sc.Context, acmeAccountPrefix+keyId) if err != nil { return nil, fmt.Errorf("error loading account: %w", err) } @@ -324,13 +338,7 @@ func (a *acmeState) LoadAccount(ac *acmeContext, keyId string) (*acmeAccount, er if err != nil { return nil, fmt.Errorf("error decoding account: %w", err) } - - if acct.AcmeDirectory != ac.acmeDirectory { - return nil, fmt.Errorf("%w: account part of different ACME directory path", ErrMalformed) - } - acct.KeyId = keyId - return &acct, nil } @@ -536,6 +544,27 @@ func (a *acmeState) LoadOrder(ac *acmeContext, userCtx *jwsCtx, orderId string) return &order, nil } +// LoadAccountOrders will load all orders for a given account ID, this should be used by the +// management interface only, not through any of the ACME APIs. +func (a *acmeState) LoadAccountOrders(sc *storageContext, accountId string) ([]*acmeOrder, error) { + orderIds, err := a.ListOrderIds(sc, accountId) + if err != nil { + return nil, fmt.Errorf("failed listing order ids for account id %s: %w", accountId, err) + } + + var orders []*acmeOrder + for _, orderId := range orderIds { + order, err := a.LoadOrder(&acmeContext{sc: sc}, &jwsCtx{Kid: accountId}, orderId) + if err != nil { + return nil, err + } + + orders = append(orders, order) + } + + return orders, nil +} + func (a *acmeState) SaveOrder(ac *acmeContext, order *acmeOrder) error { if order.OrderId == "" { return fmt.Errorf("invalid order, missing order id") @@ -565,15 +594,7 @@ func (a *acmeState) ListOrderIds(sc *storageContext, accountId string) ([]string return nil, fmt.Errorf("failed listing order ids for account %s: %w", accountId, err) } - orderIds := []string{} - for _, order := range rawOrderIds { - if strings.HasSuffix(order, "/") { - // skip any folders we might have for some reason - continue - } - orderIds = append(orderIds, order) - } - return orderIds, nil + return filterDirEntries(rawOrderIds), nil } type acmeCertEntry struct { @@ -672,17 +693,20 @@ func (a *acmeState) ListEabIds(sc *storageContext) ([]string, error) { if err != nil { return nil, err } - var ids []string - for _, entry := range entries { - if strings.HasSuffix(entry, "/") { - continue - } - ids = append(ids, entry) - } + ids := filterDirEntries(entries) return ids, nil } +func (a *acmeState) ListAccountIds(sc *storageContext) ([]string, error) { + entries, err := sc.Storage.List(sc.Context, acmeAccountPrefix) + if err != nil { + return nil, fmt.Errorf("failed listing ACME account prefix directory %s: %w", acmeAccountPrefix, err) + } + + return filterDirEntries(entries), nil +} + func getAcmeSerialToAccountTrackerPath(accountId string, serial string) string { return acmeAccountPrefix + accountId + "/certs/" + normalizeSerial(serial) } diff --git a/builtin/logical/pki/backend.go b/builtin/logical/pki/backend.go index 615380a826fa..de4f8c3f77de 100644 --- a/builtin/logical/pki/backend.go +++ b/builtin/logical/pki/backend.go @@ -237,6 +237,8 @@ func Backend(conf *logical.BackendConfig) *backend { pathAcmeConfig(&b), pathAcmeEabList(&b), pathAcmeEabDelete(&b), + pathAcmeMgmtAccountList(&b), + pathAcmeMgmtAccountRead(&b), }, Secrets: []*framework.Secret{ diff --git a/builtin/logical/pki/backend_test.go b/builtin/logical/pki/backend_test.go index 5c38989f8f85..2fcd946286ed 100644 --- a/builtin/logical/pki/backend_test.go +++ b/builtin/logical/pki/backend_test.go @@ -6831,6 +6831,7 @@ func TestProperAuthing(t *testing.T) { } serial := resp.Data["serial_number"].(string) eabKid := "13b80844-e60d-42d2-b7e9-152a8e834b90" + acmeKeyId := "hrKmDYTvicHoHGVN2-3uzZV_BPGdE0W_dNaqYTtYqeo=" paths := map[string]pathAuthChecker{ "ca_chain": shouldBeUnauthedReadList, "cert/ca_chain": shouldBeUnauthedReadList, @@ -6950,6 +6951,8 @@ func TestProperAuthing(t *testing.T) { "unified-ocsp/dGVzdAo=": shouldBeUnauthedReadList, "eab/": shouldBeAuthed, "eab/" + eabKid: shouldBeAuthed, + "acme/mgmt/account/keyid/": shouldBeAuthed, + "acme/mgmt/account/keyid/" + acmeKeyId: shouldBeAuthed, } entPaths := getEntProperAuthingPaths(serial) @@ -7020,7 +7023,10 @@ func TestProperAuthing(t *testing.T) { raw_path = strings.ReplaceAll(raw_path, "{serial}", serial) } if strings.Contains(raw_path, "acme/account/") && strings.Contains(raw_path, "{kid}") { - raw_path = strings.ReplaceAll(raw_path, "{kid}", "hrKmDYTvicHoHGVN2-3uzZV_BPGdE0W_dNaqYTtYqeo=") + raw_path = strings.ReplaceAll(raw_path, "{kid}", acmeKeyId) + } + if strings.Contains(raw_path, "acme/mgmt/account/") && strings.Contains(raw_path, "{keyid}") { + raw_path = strings.ReplaceAll(raw_path, "{keyid}", acmeKeyId) } if strings.Contains(raw_path, "acme/") && strings.Contains(raw_path, "{auth_id}") { raw_path = strings.ReplaceAll(raw_path, "{auth_id}", "29da8c38-7a09-465e-b9a6-3d76802b1afd") diff --git a/builtin/logical/pki/cert_util_test.go b/builtin/logical/pki/cert_util_test.go index 90b8a12f438f..b980245bb122 100644 --- a/builtin/logical/pki/cert_util_test.go +++ b/builtin/logical/pki/cert_util_test.go @@ -8,7 +8,6 @@ import ( "crypto/x509" "crypto/x509/pkix" "fmt" - "github.com/hashicorp/vault/sdk/helper/testhelpers/schema" "net" "net/url" "os" @@ -23,6 +22,7 @@ import ( "github.com/hashicorp/vault/builtin/logical/pki/parsing" "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/helper/certutil" + "github.com/hashicorp/vault/sdk/helper/testhelpers/schema" "github.com/hashicorp/vault/sdk/logical" "github.com/stretchr/testify/require" ) diff --git a/builtin/logical/pki/fields.go b/builtin/logical/pki/fields.go index 24d030576f56..e9da69c065e2 100644 --- a/builtin/logical/pki/fields.go +++ b/builtin/logical/pki/fields.go @@ -419,7 +419,7 @@ Ranges must be specified in the notation of IP address and prefix length, like " Type: framework.TypeCommaStringSlice, Description: `Email addresses for which this certificate is allowed to sign or issue child certificates (see https://tools.ietf.org/html/rfc5280#section-4.2.1.10).`, DisplayAttrs: &framework.DisplayAttributes{ - Name: "Permitted email adresses", + Name: "Permitted email addresses", }, } fields["excluded_email_addresses"] = &framework.FieldSchema{ diff --git a/builtin/logical/pki/metadata.pb.go b/builtin/logical/pki/metadata.pb.go index fe8da60ea29f..53574ddc5ebb 100644 --- a/builtin/logical/pki/metadata.pb.go +++ b/builtin/logical/pki/metadata.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: builtin/logical/pki/metadata.proto @@ -25,14 +25,13 @@ const ( ) type CertificateMetadata struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` IssuerId string `protobuf:"bytes,1,opt,name=issuer_id,json=issuerId,proto3" json:"issuer_id,omitempty"` Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"` Expiration *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=expiration,proto3" json:"expiration,omitempty"` ClientMetadata []byte `protobuf:"bytes,4,opt,name=client_metadata,json=clientMetadata,proto3,oneof" json:"client_metadata,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *CertificateMetadata) Reset() { diff --git a/builtin/logical/pki/path_acme_account_mgmt.go b/builtin/logical/pki/path_acme_account_mgmt.go new file mode 100644 index 000000000000..ef85aa5fdaab --- /dev/null +++ b/builtin/logical/pki/path_acme_account_mgmt.go @@ -0,0 +1,226 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package pki + +import ( + "context" + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" +) + +func pathAcmeMgmtAccountList(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "acme/mgmt/account/keyid/?$", + + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.pathAcmeMgmtListAccounts, + DisplayAttrs: &framework.DisplayAttributes{ + OperationPrefix: operationPrefixPKI, + OperationVerb: "list-acme-account-keys", + Description: "List all ACME account key identifiers.", + }, + }, + }, + + HelpSynopsis: "List all ACME account key identifiers.", + HelpDescription: `Allows an operator to list all ACME account key identifiers.`, + } +} + +func pathAcmeMgmtAccountRead(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "acme/mgmt/account/keyid/" + framework.GenericNameRegex("keyid"), + Fields: map[string]*framework.FieldSchema{ + "keyid": { + Type: framework.TypeString, + Description: "The key identifier of the account.", + Required: true, + }, + "status": { + Type: framework.TypeString, + Description: "The status of the account.", + Required: true, + AllowedValues: []interface{}{AccountStatusValid.String(), AccountStatusRevoked.String()}, + }, + }, + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ReadOperation: &framework.PathOperation{ + Callback: b.pathAcmeMgmtReadAccount, + DisplayAttrs: &framework.DisplayAttributes{ + OperationPrefix: operationPrefixPKI, + OperationSuffix: "acme-key-id", + }, + }, + logical.UpdateOperation: &framework.PathOperation{ + Callback: b.pathAcmeMgmtUpdateAccount, + DisplayAttrs: &framework.DisplayAttributes{ + OperationPrefix: operationPrefixPKI, + OperationSuffix: "acme-key-id", + }, + }, + }, + + HelpSynopsis: "Fetch the details or update the status of an ACME account by key identifier.", + HelpDescription: `Allows an operator to retrieve details of an ACME account and to update the account status.`, + } +} + +func (b *backend) pathAcmeMgmtListAccounts(ctx context.Context, r *logical.Request, d *framework.FieldData) (*logical.Response, error) { + sc := b.makeStorageContext(ctx, r.Storage) + + accountIds, err := b.GetAcmeState().ListAccountIds(sc) + if err != nil { + return nil, err + } + + return logical.ListResponse(accountIds), nil +} + +func (b *backend) pathAcmeMgmtReadAccount(ctx context.Context, r *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyId := d.Get("keyid").(string) + if len(keyId) == 0 { + return logical.ErrorResponse("keyid is required"), logical.ErrInvalidRequest + } + + sc := b.makeStorageContext(ctx, r.Storage) + as := b.GetAcmeState() + + accountEntry, err := as.LoadAccountWithoutDirEnforcement(sc, keyId) + if err != nil { + if errors.Is(err, ErrAccountDoesNotExist) { + return logical.ErrorResponse("ACME key id %s did not exist", keyId), logical.ErrNotFound + } + return nil, fmt.Errorf("failed loading ACME account id %q: %w", keyId, err) + } + + orders, err := as.LoadAccountOrders(sc, accountEntry.KeyId) + if err != nil { + return nil, fmt.Errorf("failed loading orders for account %q: %w", accountEntry.KeyId, err) + } + + orderData := make([]map[string]interface{}, 0, len(orders)) + for _, order := range orders { + orderData = append(orderData, acmeOrderToDataMap(order)) + } + + dataMap := acmeAccountToDataMap(accountEntry) + dataMap["orders"] = orderData + return &logical.Response{Data: dataMap}, nil +} + +func (b *backend) pathAcmeMgmtUpdateAccount(ctx context.Context, r *logical.Request, d *framework.FieldData) (*logical.Response, error) { + keyId := d.Get("keyid").(string) + if len(keyId) == 0 { + return logical.ErrorResponse("keyid is required"), logical.ErrInvalidRequest + } + + status, err := convertToAccountStatus(d.Get("status")) + if err != nil { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + if status != AccountStatusValid && status != AccountStatusRevoked { + return logical.ErrorResponse("invalid status %q", status), logical.ErrInvalidRequest + } + + sc := b.makeStorageContext(ctx, r.Storage) + as := b.GetAcmeState() + + accountEntry, err := as.LoadAccountWithoutDirEnforcement(sc, keyId) + if err != nil { + if errors.Is(err, ErrAccountDoesNotExist) { + return logical.ErrorResponse("ACME key id %q did not exist", keyId), logical.ErrNotFound + } + return nil, fmt.Errorf("failed loading ACME account id %q: %w", keyId, err) + } + + if accountEntry.Status != status { + accountEntry.Status = status + + switch status { + case AccountStatusRevoked: + accountEntry.AccountRevokedDate = time.Now() + case AccountStatusValid: + accountEntry.AccountRevokedDate = time.Time{} + } + + if err := as.UpdateAccount(sc, accountEntry); err != nil { + return nil, fmt.Errorf("failed saving account %q: %w", keyId, err) + } + } + + dataMap := acmeAccountToDataMap(accountEntry) + return &logical.Response{Data: dataMap}, nil +} + +func convertToAccountStatus(status any) (ACMEAccountStatus, error) { + if status == nil { + return "", fmt.Errorf("status is required") + } + + statusStr, ok := status.(string) + if !ok { + return "", fmt.Errorf("status must be a string") + } + + switch strings.ToLower(strings.TrimSpace(statusStr)) { + case AccountStatusValid.String(): + return AccountStatusValid, nil + case AccountStatusRevoked.String(): + return AccountStatusRevoked, nil + case AccountStatusDeactivated.String(): + return AccountStatusDeactivated, nil + default: + return "", fmt.Errorf("invalid status %q", statusStr) + } +} + +func acmeAccountToDataMap(accountEntry *acmeAccount) map[string]interface{} { + revokedDate := "" + if !accountEntry.AccountRevokedDate.IsZero() { + revokedDate = accountEntry.AccountRevokedDate.Format(time.RFC3339) + } + + eab := map[string]string{} + if accountEntry.Eab != nil { + eab["eab_id"] = accountEntry.Eab.KeyID + eab["directory"] = accountEntry.Eab.AcmeDirectory + eab["created_time"] = accountEntry.Eab.CreatedOn.Format(time.RFC3339) + eab["key_type"] = accountEntry.Eab.KeyType + } + + return map[string]interface{}{ + "key_id": accountEntry.KeyId, + "status": accountEntry.Status, + "contacts": accountEntry.Contact, + "created_time": accountEntry.AccountCreatedDate.Format(time.RFC3339), + "revoked_time": revokedDate, + "directory": accountEntry.AcmeDirectory, + "eab": eab, + } +} + +func acmeOrderToDataMap(order *acmeOrder) map[string]interface{} { + identifiers := make([]string, 0, len(order.Identifiers)) + for _, identifier := range order.Identifiers { + identifiers = append(identifiers, identifier.Value) + } + var certExpiry string + if !order.CertificateExpiry.IsZero() { + certExpiry = order.CertificateExpiry.Format(time.RFC3339) + } + return map[string]interface{}{ + "order_id": order.OrderId, + "status": string(order.Status), + "identifiers": identifiers, + "cert_serial_number": strings.ReplaceAll(order.CertificateSerialNumber, "-", ":"), + "cert_expiry": certExpiry, + "order_expiry": order.Expires.Format(time.RFC3339), + } +} diff --git a/builtin/logical/pki/path_acme_eab.go b/builtin/logical/pki/path_acme_eab.go index fa026a1c1892..00b1cdaa13d8 100644 --- a/builtin/logical/pki/path_acme_eab.go +++ b/builtin/logical/pki/path_acme_eab.go @@ -173,7 +173,7 @@ a warning that it did not exist.`, } type eabType struct { - KeyID string `json:"-"` + KeyID string `json:"key-id"` KeyType string `json:"key-type"` PrivateBytes []byte `json:"private-bytes"` AcmeDirectory string `json:"acme-directory"` diff --git a/builtin/logical/pki/path_acme_test.go b/builtin/logical/pki/path_acme_test.go index ac16c36cc871..599e7d92b63a 100644 --- a/builtin/logical/pki/path_acme_test.go +++ b/builtin/logical/pki/path_acme_test.go @@ -1625,7 +1625,7 @@ func TestAcmeRevocationAcrossAccounts(t *testing.T) { acmeClient1 := getAcmeClientForCluster(t, cluster, baseAcmeURL, accountKey1) - leafKey, certs := doACMEWorkflow(t, vaultClient, acmeClient1) + _, leafKey, certs := doACMEWorkflow(t, vaultClient, acmeClient1) acmeCert, err := x509.ParseCertificate(certs[0]) require.NoError(t, err, "failed parsing acme cert bytes") @@ -1675,7 +1675,7 @@ func TestAcmeRevocationAcrossAccounts(t *testing.T) { "revocation time was not greater than 0, cert was not revoked: %v", revocationTimeInt) // Make sure we can revoke a certificate without a registered ACME account - leafKey2, certs2 := doACMEWorkflow(t, vaultClient, acmeClient1) + _, leafKey2, certs2 := doACMEWorkflow(t, vaultClient, acmeClient1) acmeClient3 := getAcmeClientForCluster(t, cluster, baseAcmeURL, nil) err = acmeClient3.RevokeCert(ctx, leafKey2, certs2[0], acme.CRLReasonUnspecified) @@ -1781,7 +1781,94 @@ func TestAcmeMaxTTL(t *testing.T) { require.Less(t, acmeCertNotAfter, maxTTL.Add(buffer), "ACME cert: %v should have been less than max TTL was %v", acmeCert.NotAfter, maxTTL) } -func doACMEWorkflow(t *testing.T, vaultClient *api.Client, acmeClient *acme.Client) (*ecdsa.PrivateKey, [][]byte) { +// TestVaultOperatorACMEDisableWorkflow validates that the Vault management API for ACME accounts works as expected. +func TestVaultOperatorACMEDisableWorkflow(t *testing.T) { + t.Parallel() + cluster, vaultClient, _ := setupAcmeBackend(t) + defer cluster.Cleanup() + testCtx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + + // Make sure we can call list on an empty ACME mount + resp, err := vaultClient.Logical().ListWithContext(testCtx, "pki/acme/mgmt/account/keyid") + require.NoError(t, err, "failed listing acme accounts") + require.Nil(t, resp, "expected nil, nil response on list of an empty mount") + + // Make sure we get nil, nil response when trying to read a non-existent key (the API returns this for a 404) + resp, err = vaultClient.Logical().ReadWithContext(testCtx, "pki/acme/mgmt/account/keyid/doesnotexist") + require.NoError(t, err, "failed reading non-existent ACME key") + require.Nil(t, resp, "expected nil, nil response on a non-existent ACME key") + + // Make sure we get an error response when trying to write to a non-existent key, unlike read the write call returns an error. + _, err = vaultClient.Logical().WriteWithContext(testCtx, "pki/acme/mgmt/account/keyid/doesnotexist", map[string]interface{}{"status": "valid"}) + require.ErrorContains(t, err, "did not exist", "failed writing non-existent ACME key") + + baseAcmeURL := "/v1/pki/acme/" + accountKey1, err := cryptoutil.GenerateRSAKey(rand.Reader, 2048) + require.NoError(t, err, "failed creating rsa key") + + acmeClient := getAcmeClientForCluster(t, cluster, baseAcmeURL, accountKey1) + acct, _, _ := doACMEWorkflow(t, vaultClient, acmeClient) + + // ACME client KID is formatted as https://127.0.0.1:60777/v1/pki/acme/account/45f52b66-a3ed-4080-dec7-cdcff1ef189f + acmeClientKid := acmeClient.KID + + // Make sure we can call list on an empty ACME mount + resp, err = vaultClient.Logical().ListWithContext(testCtx, "pki/acme/mgmt/account/keyid") + require.NoError(t, err, "failed listing acme accounts") + require.NotNil(t, resp, "expected non-nil response on list on ACME keyid") + keysFromList := resp.Data["keys"].([]interface{}) + require.Len(t, keysFromList, 1, "expected one key in the list") + kid := keysFromList[0].(string) + require.True(t, strings.HasSuffix(string(acmeClientKid), kid), "expected key to match the one the ACME client has") + + // Make sure we can read the key we just listed + resp, err = vaultClient.Logical().ReadWithContext(testCtx, "pki/acme/mgmt/account/keyid/"+kid) + require.NoError(t, err, "failed reading ACME with account key") + require.NotNil(t, resp, "read response was nil on ACME keyid") + require.Equal(t, "acme/", resp.Data["directory"], "expected directory field in response") + require.Equal(t, kid, resp.Data["key_id"], "expected key_id field in response") + require.Equal(t, "valid", resp.Data["status"], "expected status field in response") + require.NotEmpty(t, resp.Data["created_time"], "expected created_time field in response") + require.NotEmpty(t, resp.Data["orders"], "expected orders field in response") + require.Empty(t, resp.Data["revoked_time"], "expected revoked_time field in response") + require.Empty(t, resp.Data["eab"], "expected eab field in response to be empty") + orders := resp.Data["orders"].([]interface{}) + require.Len(t, orders, 1, "expected one order in the list") + order := orders[0].(map[string]interface{}) + require.NotEmpty(t, order["order_id"], "expected order_id field in response") + require.NotEmpty(t, order["cert_expiry"], "expected cert_expiry field in response") + require.NotEmpty(t, order["cert_serial_number"], "expected cert_serial_number field in response") + + // Make sure we can update the status of the account to revoked and the revoked_time field is set + resp, err = vaultClient.Logical().WriteWithContext(testCtx, "pki/acme/mgmt/account/keyid/"+kid, map[string]interface{}{"status": "revoked"}) + require.NoError(t, err, "failed updating writing ACME with account key") + require.NotNil(t, resp, "expected non-nil response on write to ACME keyid") + require.Equal(t, "acme/", resp.Data["directory"], "expected directory field in response") + require.Equal(t, kid, resp.Data["key_id"], "expected key_id field in response") + require.Equal(t, "revoked", resp.Data["status"], "expected status field in response") + require.NotEmpty(t, resp.Data["created_time"], "expected created_time field in response") + require.NotEmpty(t, resp.Data["revoked_time"], "expected revoked_time field in response") + require.Empty(t, resp.Data["eab"], "expected eab field in response to be empty") + require.Empty(t, resp.Data["orders"], "write response should not contain orders") + + // Now make sure that we can't use the ACME account anymore + identifiers := []string{"*.localdomain"} + _, err = acmeClient.AuthorizeOrder(testCtx, []acme.AuthzID{ + {Type: "dns", Value: identifiers[0]}, + }) + require.ErrorContains(t, err, "account in status: revoked", "Requesting an order with a revoked account should have failed") + + // Switch the account back to valid and make sure we can use it again + resp, err = vaultClient.Logical().WriteWithContext(testCtx, "pki/acme/mgmt/account/keyid/"+kid, map[string]interface{}{"status": "valid"}) + require.NoError(t, err, "failed updating writing ACME with account key") + require.Empty(t, resp.Data["revoked_time"], "revoked_time should have been reset") + require.Equal(t, "valid", resp.Data["status"], "status should have been reset to valid") + + doACMEOrderWorkflow(t, vaultClient, acmeClient, acct) +} + +func doACMEWorkflow(t *testing.T, vaultClient *api.Client, acmeClient *acme.Client) (*acme.Account, *ecdsa.PrivateKey, [][]byte) { testCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() @@ -1796,6 +1883,14 @@ func doACMEWorkflow(t *testing.T, vaultClient *api.Client, acmeClient *acme.Clie } } + csrKey, certs := doACMEOrderWorkflow(t, vaultClient, acmeClient, acct) + return acct, csrKey, certs +} + +func doACMEOrderWorkflow(t *testing.T, vaultClient *api.Client, acmeClient *acme.Client, acct *acme.Account) (*ecdsa.PrivateKey, [][]byte) { + testCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + // Create an order identifiers := []string{"*.localdomain"} order, err := acmeClient.AuthorizeOrder(testCtx, []acme.AuthzID{ diff --git a/builtin/logical/pki/storage.go b/builtin/logical/pki/storage.go index 43c4853ba34c..8b21d3e7992e 100644 --- a/builtin/logical/pki/storage.go +++ b/builtin/logical/pki/storage.go @@ -829,3 +829,15 @@ func fetchRevocationInfo(sc pki_backend.StorageContext, serial string) (*revocat return revInfo, nil } + +// filterDirEntries filters out directory entries from a list of entries normally from a List operation. +func filterDirEntries(entries []string) []string { + ids := make([]string, 0, len(entries)) + for _, entry := range entries { + if strings.HasSuffix(entry, "/") { + continue + } + ids = append(ids, entry) + } + return ids +} diff --git a/builtin/logical/transit/backend_ce.go b/builtin/logical/transit/backend_ce.go index 4c88fc30a35a..23744596dd2f 100644 --- a/builtin/logical/transit/backend_ce.go +++ b/builtin/logical/transit/backend_ce.go @@ -8,6 +8,7 @@ package transit import ( "context" + "github.com/hashicorp/vault/sdk/helper/keysutil" "github.com/hashicorp/vault/sdk/logical" ) @@ -24,3 +25,11 @@ func (b *backend) periodicFuncEnt(_ context.Context, _ *logical.Request) error { func (b *backend) cleanupEnt(_ context.Context) {} func (b *backend) setupEnt() {} + +func entEncodePrivateKey(_ string, p *keysutil.Policy, _ *keysutil.KeyEntry) (string, error) { + return "", nil +} + +func entEncodePublicKey(_ string, p *keysutil.Policy, _ *keysutil.KeyEntry) (string, error) { + return "", nil +} diff --git a/builtin/logical/transit/path_export.go b/builtin/logical/transit/path_export.go index 30735c2c749a..7bb0db808956 100644 --- a/builtin/logical/transit/path_export.go +++ b/builtin/logical/transit/path_export.go @@ -225,6 +225,14 @@ func getExportKey(policy *keysutil.Policy, key *keysutil.KeyEntry, exportType st return "", err } return rsaKey, nil + default: + key, err := entEncodePrivateKey(exportType, policy, key) + if err != nil { + return "", err + } + if key != "" { + return key, nil + } } case exportTypePublicKey: switch policy.Type { @@ -253,6 +261,14 @@ func getExportKey(policy *keysutil.Policy, key *keysutil.KeyEntry, exportType st return "", err } return rsaKey, nil + default: + key, err := entEncodePublicKey(exportType, policy, key) + if err != nil { + return "", err + } + if key != "" { + return key, nil + } } case exportTypeCertificateChain: if key.CertificateChain == nil { diff --git a/builtin/logical/transit/path_export_test.go b/builtin/logical/transit/path_export_test.go index b91ef47fb420..c886306b177e 100644 --- a/builtin/logical/transit/path_export_test.go +++ b/builtin/logical/transit/path_export_test.go @@ -62,127 +62,136 @@ func TestTransit_Export_Unknown_ExportType(t *testing.T) { func TestTransit_Export_KeyVersion_ExportsCorrectVersion(t *testing.T) { t.Parallel() - verifyExportsCorrectVersion(t, "encryption-key", "aes128-gcm96") - verifyExportsCorrectVersion(t, "encryption-key", "aes256-gcm96") - verifyExportsCorrectVersion(t, "encryption-key", "chacha20-poly1305") - verifyExportsCorrectVersion(t, "encryption-key", "rsa-2048") - verifyExportsCorrectVersion(t, "encryption-key", "rsa-3072") - verifyExportsCorrectVersion(t, "encryption-key", "rsa-4096") - verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p256") - verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p384") - verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p521") - verifyExportsCorrectVersion(t, "signing-key", "ed25519") - verifyExportsCorrectVersion(t, "signing-key", "rsa-2048") - verifyExportsCorrectVersion(t, "signing-key", "rsa-3072") - verifyExportsCorrectVersion(t, "signing-key", "rsa-4096") - verifyExportsCorrectVersion(t, "hmac-key", "aes128-gcm96") - verifyExportsCorrectVersion(t, "hmac-key", "aes256-gcm96") - verifyExportsCorrectVersion(t, "hmac-key", "chacha20-poly1305") - verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p256") - verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p384") - verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p521") - verifyExportsCorrectVersion(t, "hmac-key", "ed25519") - verifyExportsCorrectVersion(t, "hmac-key", "hmac") - verifyExportsCorrectVersion(t, "public-key", "rsa-2048") - verifyExportsCorrectVersion(t, "public-key", "rsa-3072") - verifyExportsCorrectVersion(t, "public-key", "rsa-4096") - verifyExportsCorrectVersion(t, "public-key", "ecdsa-p256") - verifyExportsCorrectVersion(t, "public-key", "ecdsa-p384") - verifyExportsCorrectVersion(t, "public-key", "ecdsa-p521") - verifyExportsCorrectVersion(t, "public-key", "ed25519") + verifyExportsCorrectVersion(t, "encryption-key", "aes128-gcm96", "", "") + verifyExportsCorrectVersion(t, "encryption-key", "aes256-gcm96", "", "") + verifyExportsCorrectVersion(t, "encryption-key", "chacha20-poly1305", "", "") + verifyExportsCorrectVersion(t, "encryption-key", "rsa-2048", "", "") + verifyExportsCorrectVersion(t, "encryption-key", "rsa-3072", "", "") + verifyExportsCorrectVersion(t, "encryption-key", "rsa-4096", "", "") + verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p256", "", "") + verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p384", "", "") + verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p521", "", "") + verifyExportsCorrectVersion(t, "signing-key", "ed25519", "", "") + verifyExportsCorrectVersion(t, "signing-key", "rsa-2048", "", "") + verifyExportsCorrectVersion(t, "signing-key", "rsa-3072", "", "") + verifyExportsCorrectVersion(t, "signing-key", "rsa-4096", "", "") + verifyExportsCorrectVersion(t, "hmac-key", "aes128-gcm96", "", "") + verifyExportsCorrectVersion(t, "hmac-key", "aes256-gcm96", "", "") + verifyExportsCorrectVersion(t, "hmac-key", "chacha20-poly1305", "", "") + verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p256", "", "") + verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p384", "", "") + verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p521", "", "") + verifyExportsCorrectVersion(t, "hmac-key", "ed25519", "", "") + verifyExportsCorrectVersion(t, "hmac-key", "hmac", "", "") + verifyExportsCorrectVersion(t, "public-key", "rsa-2048", "", "") + verifyExportsCorrectVersion(t, "public-key", "rsa-3072", "", "") + verifyExportsCorrectVersion(t, "public-key", "rsa-4096", "", "") + verifyExportsCorrectVersion(t, "public-key", "ecdsa-p256", "", "") + verifyExportsCorrectVersion(t, "public-key", "ecdsa-p384", "", "") + verifyExportsCorrectVersion(t, "public-key", "ecdsa-p521", "", "") + verifyExportsCorrectVersion(t, "public-key", "ed25519", "", "") } -func verifyExportsCorrectVersion(t *testing.T, exportType, keyType string) { - b, storage := createBackendWithSysView(t) +func verifyExportsCorrectVersion(t *testing.T, exportType, keyType, parameterSet, ecKeyType string) { + t.Run(keyType+":"+ecKeyType, func(t *testing.T) { + b, storage := createBackendWithSysView(t) - // First create a key, v1 - req := &logical.Request{ - Storage: storage, - Operation: logical.UpdateOperation, - Path: "keys/foo", - } - req.Data = map[string]interface{}{ - "exportable": true, - "type": keyType, - } - if keyType == "hmac" { - req.Data["key_size"] = 32 - } - _, err := b.HandleRequest(context.Background(), req) - if err != nil { - t.Fatal(err) - } - - verifyVersion := func(versionRequest string, expectedVersion int) { + // First create a key, v1 req := &logical.Request{ Storage: storage, - Operation: logical.ReadOperation, - Path: fmt.Sprintf("export/%s/foo/%s", exportType, versionRequest), - } - rsp, err := b.HandleRequest(context.Background(), req) - if err != nil { - t.Fatal(err) - } - - typRaw, ok := rsp.Data["type"] - if !ok { - t.Fatal("no type returned from export") + Operation: logical.UpdateOperation, + Path: "keys/foo", } - typ, ok := typRaw.(string) - if !ok { - t.Fatalf("could not find key type, resp data is %#v", rsp.Data) + req.Data = map[string]interface{}{ + "exportable": true, + "type": keyType, } - if typ != keyType { - t.Fatalf("key type mismatch; %q vs %q", typ, keyType) + if parameterSet != "" { + req.Data["parameter_set"] = parameterSet } - - keysRaw, ok := rsp.Data["keys"] - if !ok { - t.Fatal("could not find keys value") + if ecKeyType != "" { + req.Data["hybrid_key_type_pqc"] = "ml-dsa" + req.Data["hybrid_key_type_ec"] = ecKeyType } - keys, ok := keysRaw.(map[string]string) - if !ok { - t.Fatal("could not cast to keys map") + if keyType == "hmac" { + req.Data["key_size"] = 32 } - if len(keys) != 1 { - t.Fatal("unexpected number of keys found") + _, err := b.HandleRequest(context.Background(), req) + if err != nil { + t.Fatal(err) } - for k := range keys { - if k != strconv.Itoa(expectedVersion) { - t.Fatalf("expected version %q, received version %q", strconv.Itoa(expectedVersion), k) + verifyVersion := func(versionRequest string, expectedVersion int) { + req := &logical.Request{ + Storage: storage, + Operation: logical.ReadOperation, + Path: fmt.Sprintf("export/%s/foo/%s", exportType, versionRequest), + } + rsp, err := b.HandleRequest(context.Background(), req) + if err != nil { + t.Fatal(err) + } + + typRaw, ok := rsp.Data["type"] + if !ok { + t.Fatal("no type returned from export") + } + typ, ok := typRaw.(string) + if !ok { + t.Fatalf("could not find key type, resp data is %#v", rsp.Data) + } + if typ != keyType { + t.Fatalf("key type mismatch; %q vs %q", typ, keyType) + } + + keysRaw, ok := rsp.Data["keys"] + if !ok { + t.Fatal("could not find keys value") + } + keys, ok := keysRaw.(map[string]string) + if !ok { + t.Fatal("could not cast to keys map") + } + if len(keys) != 1 { + t.Fatal("unexpected number of keys found") + } + + for k := range keys { + if k != strconv.Itoa(expectedVersion) { + t.Fatalf("expected version %q, received version %q", strconv.Itoa(expectedVersion), k) + } } } - } - verifyVersion("v1", 1) - verifyVersion("1", 1) - verifyVersion("latest", 1) + verifyVersion("v1", 1) + verifyVersion("1", 1) + verifyVersion("latest", 1) - req.Path = "keys/foo/rotate" - // v2 - _, err = b.HandleRequest(context.Background(), req) - if err != nil { - t.Fatal(err) - } + req.Path = "keys/foo/rotate" + // v2 + _, err = b.HandleRequest(context.Background(), req) + if err != nil { + t.Fatal(err) + } - verifyVersion("v1", 1) - verifyVersion("1", 1) - verifyVersion("v2", 2) - verifyVersion("2", 2) - verifyVersion("latest", 2) + verifyVersion("v1", 1) + verifyVersion("1", 1) + verifyVersion("v2", 2) + verifyVersion("2", 2) + verifyVersion("latest", 2) - // v3 - _, err = b.HandleRequest(context.Background(), req) - if err != nil { - t.Fatal(err) - } + // v3 + _, err = b.HandleRequest(context.Background(), req) + if err != nil { + t.Fatal(err) + } - verifyVersion("v1", 1) - verifyVersion("1", 1) - verifyVersion("v3", 3) - verifyVersion("3", 3) - verifyVersion("latest", 3) + verifyVersion("v1", 1) + verifyVersion("1", 1) + verifyVersion("v3", 3) + verifyVersion("3", 3) + verifyVersion("latest", 3) + }) } func TestTransit_Export_ValidVersionsOnly(t *testing.T) { diff --git a/builtin/logical/transit/path_import.go b/builtin/logical/transit/path_import.go index a38167e98d57..c4c75c31e356 100644 --- a/builtin/logical/transit/path_import.go +++ b/builtin/logical/transit/path_import.go @@ -46,7 +46,7 @@ func (b *backend) pathImport() *framework.Path { Default: "aes256-gcm96", Description: `The type of key being imported. Currently, "aes128-gcm96" (symmetric), "aes256-gcm96" (symmetric), "ecdsa-p256" (asymmetric), "ecdsa-p384" (asymmetric), "ecdsa-p521" (asymmetric), "ed25519" (asymmetric), "rsa-2048" (asymmetric), "rsa-3072" -(asymmetric), "rsa-4096" (asymmetric), "hmac", "aes128-cmac", "aes256-cmac" are supported. Defaults to "aes256-gcm96". +(asymmetric), "rsa-4096" (asymmetric), "ml-dsa-44 (asymmetric)", "ml-dsa-65 (asymmetric)", "ml-dsa-87 (asymmetric)", "hmac", "aes128-cmac", "aes256-cmac" are supported. Defaults to "aes256-gcm96". `, }, "hash_function": { diff --git a/builtin/logical/transit/path_keys.go b/builtin/logical/transit/path_keys.go index 3c7d16f74ed6..20585b3c1eb7 100644 --- a/builtin/logical/transit/path_keys.go +++ b/builtin/logical/transit/path_keys.go @@ -143,7 +143,7 @@ Supported types are: ML-DSA.`, "hybrid_key_type_ec": { Type: framework.TypeString, Description: `The key type of the elliptic curve key to use for hybrid signature schemes. -Supported types are: ecdsa-p256, ecdsa-p384, ecdsa-p521.`, +Supported types are: ecdsa-p256, ecdsa-p384, ecdsa-p521, and ed25519.`, }, }, @@ -247,6 +247,7 @@ func (b *backend) pathPolicyWrite(ctx context.Context, req *logical.Request, d * polReq.KeyType = keysutil.KeyType_AES256_CMAC case "ml-dsa": polReq.KeyType = keysutil.KeyType_ML_DSA + if parameterSet != keysutil.ParameterSet_ML_DSA_44 && parameterSet != keysutil.ParameterSet_ML_DSA_65 && parameterSet != keysutil.ParameterSet_ML_DSA_87 { @@ -322,6 +323,7 @@ type asymKey struct { PublicKey string `json:"public_key" structs:"public_key" mapstructure:"public_key"` CertificateChain string `json:"certificate_chain" structs:"certificate_chain" mapstructure:"certificate_chain"` CreationTime time.Time `json:"creation_time" structs:"creation_time" mapstructure:"creation_time"` + HybridPublicKey string `json:"hybrid_public_key" structs:"hybrid_public_key" mapstructure:"hybrid_public_key"` } func (b *backend) pathPolicyRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { @@ -538,6 +540,8 @@ func getHybridKeyConfig(pqcKeyType, parameterSet, ecKeyType string) (keysutil.Hy config.ECKeyType = keysutil.KeyType_ECDSA_P384 case "ecdsa-p521": config.ECKeyType = keysutil.KeyType_ECDSA_P521 + case "ed25519": + config.ECKeyType = keysutil.KeyType_ED25519 default: return keysutil.HybridKeyConfig{}, fmt.Errorf("invalid key type for hybrid key: %s", ecKeyType) } diff --git a/changelog/29134.txt b/changelog/29134.txt new file mode 100644 index 000000000000..8fd4ca62e02f --- /dev/null +++ b/changelog/29134.txt @@ -0,0 +1,3 @@ +```release-note:change +auth/ldap: No longer return authentication warnings to client. +``` diff --git a/changelog/29173.txt b/changelog/29173.txt new file mode 100644 index 000000000000..7ccdfbdda39b --- /dev/null +++ b/changelog/29173.txt @@ -0,0 +1,3 @@ +```release-note:improvement +secrets/pki: Add a new set of APIs that allow listing ACME account key ids, retrieving ACME account information along with the associated order and certificate information and updating an ACME account's status +``` diff --git a/changelog/29176.txt b/changelog/29176.txt new file mode 100644 index 000000000000..a701cd11708b --- /dev/null +++ b/changelog/29176.txt @@ -0,0 +1,3 @@ +```release-note:bug +core: Prevent integer overflows of the barrier key counter on key rotation requests +``` diff --git a/changelog/29241.txt b/changelog/29241.txt new file mode 100644 index 000000000000..06699fdf1271 --- /dev/null +++ b/changelog/29241.txt @@ -0,0 +1,3 @@ +```release-note:bug +UI: Fix missing Client Count card when running as a Vault Dedicated cluster +``` diff --git a/changelog/29263.txt b/changelog/29263.txt new file mode 100644 index 000000000000..f6df0717fdc5 --- /dev/null +++ b/changelog/29263.txt @@ -0,0 +1,3 @@ +```release-note:improvement +ui: Add support for the name constraints extension to be fully specified when creating root and intermediate CA certificates. +``` \ No newline at end of file diff --git a/changelog/29273.txt b/changelog/29273.txt new file mode 100644 index 000000000000..b491294a14b8 --- /dev/null +++ b/changelog/29273.txt @@ -0,0 +1,3 @@ +```release-note:improvement +sdk: Add helpers and CE stubs for plugins to communicate with Rotation Manager (Enterprise). +``` diff --git a/changelog/29290.txt b/changelog/29290.txt new file mode 100644 index 000000000000..1120ae65d8f5 --- /dev/null +++ b/changelog/29290.txt @@ -0,0 +1,3 @@ +```release-note:change +ui: Partially reverts #20431 and removes ability to download unencrypted kv v2 secret data +``` \ No newline at end of file diff --git a/changelog/29293.txt b/changelog/29293.txt new file mode 100644 index 000000000000..056b7cf96892 --- /dev/null +++ b/changelog/29293.txt @@ -0,0 +1,6 @@ +```release-note:improvement +ui: Adds navigation for LDAP hierarchical libraries +``` +```release-note:bug +ui: Fixes navigation for quick actions in LDAP roles' popup menu +``` \ No newline at end of file diff --git a/changelog/29295.txt b/changelog/29295.txt new file mode 100644 index 000000000000..488f86bab9c4 --- /dev/null +++ b/changelog/29295.txt @@ -0,0 +1,3 @@ +```release-note:change +auth/cf: Update plugin to v0.19.1 +``` diff --git a/command/command_testonly/operator_usage_testonly_test.go b/command/command_testonly/operator_usage_testonly_test.go index 4cdfc0536ac3..31de4b88eb15 100644 --- a/command/command_testonly/operator_usage_testonly_test.go +++ b/command/command_testonly/operator_usage_testonly_test.go @@ -53,7 +53,7 @@ func TestOperatorUsageCommandRun(t *testing.T) { now := time.Now().UTC() - _, _, err = clientcountutil.NewActivityLogData(client). + _, err = clientcountutil.NewActivityLogData(client). NewPreviousMonthData(1). NewClientsSeen(6, clientcountutil.WithClientType("entity")). NewClientsSeen(4, clientcountutil.WithClientType("non-entity-token")). diff --git a/go.mod b/go.mod index 6982f3226f95..3a4d2ec0d32f 100644 --- a/go.mod +++ b/go.mod @@ -122,14 +122,14 @@ require ( github.com/hashicorp/hcp-sdk-go v0.101.0 github.com/hashicorp/nomad/api v0.0.0-20240213164230-c364cb57298d github.com/hashicorp/raft v1.7.1 - github.com/hashicorp/raft-autopilot v0.2.0 + github.com/hashicorp/raft-autopilot v0.3.0 github.com/hashicorp/raft-boltdb/v2 v2.3.0 github.com/hashicorp/raft-snapshot v1.0.4 github.com/hashicorp/raft-wal v0.4.0 github.com/hashicorp/vault-hcp-lib v0.0.0-20240704151836-a5c058ac604c github.com/hashicorp/vault-plugin-auth-alicloud v0.19.0 github.com/hashicorp/vault-plugin-auth-azure v0.19.2 - github.com/hashicorp/vault-plugin-auth-cf v0.19.0 + github.com/hashicorp/vault-plugin-auth-cf v0.19.1 github.com/hashicorp/vault-plugin-auth-gcp v0.19.1 github.com/hashicorp/vault-plugin-auth-jwt v0.22.0 github.com/hashicorp/vault-plugin-auth-kerberos v0.13.0 @@ -211,7 +211,7 @@ require ( go.uber.org/goleak v1.3.0 golang.org/x/crypto v0.31.0 golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 - golang.org/x/net v0.31.0 + golang.org/x/net v0.33.0 golang.org/x/oauth2 v0.24.0 golang.org/x/sync v0.10.0 golang.org/x/sys v0.28.0 diff --git a/go.sum b/go.sum index ec1dbdad5e95..4c040190e612 100644 --- a/go.sum +++ b/go.sum @@ -1410,7 +1410,6 @@ github.com/hashicorp/go-gcp-common v0.9.1 h1:ZzAJNAz6OwpNUutnnUVnFERtR2fI1oZT5Z2 github.com/hashicorp/go-gcp-common v0.9.1/go.mod h1:JJ5Zvnsmrn1GkBg64+oDfSK/gJtnGyX5x2nFuSdulLw= github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= @@ -1538,11 +1537,10 @@ github.com/hashicorp/nomad/api v0.0.0-20240213164230-c364cb57298d h1:nvfutImOr3G github.com/hashicorp/nomad/api v0.0.0-20240213164230-c364cb57298d/go.mod h1:ijDwa6o1uG1jFSq6kERiX2PamKGpZzTmo0XOFNeFZgw= github.com/hashicorp/raft v1.0.1/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI= github.com/hashicorp/raft v1.1.2-0.20191002163536-9c6bd3e3eb17/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= -github.com/hashicorp/raft v1.2.0/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= github.com/hashicorp/raft v1.7.1 h1:ytxsNx4baHsRZrhUcbt3+79zc4ly8qm7pi0393pSchY= github.com/hashicorp/raft v1.7.1/go.mod h1:hUeiEwQQR/Nk2iKDD0dkEhklSsu3jcAcqvPzPoZSAEM= -github.com/hashicorp/raft-autopilot v0.2.0 h1:2/R2RPgamgRKgNWGQioULZvjeKXQZmDuw5Ty+6c+H7Y= -github.com/hashicorp/raft-autopilot v0.2.0/go.mod h1:q6tZ8UAZ5xio2gv2JvjgmtOlh80M6ic8xQYBe2Egkg8= +github.com/hashicorp/raft-autopilot v0.3.0 h1:KhXCecBFqAMpC0i77qVfuYd937cl2dNatSA/sSNs+2s= +github.com/hashicorp/raft-autopilot v0.3.0/go.mod h1:pUBzcE8bXIm/NcFZ/xKz7O3aNOU/4T4Zkv11YqdxpUc= github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= github.com/hashicorp/raft-boltdb v0.0.0-20230125174641-2a8082862702 h1:RLKEcCuKcZ+qp2VlaaZsYZfLOmIiuJNpEi48Rl8u9cQ= github.com/hashicorp/raft-boltdb v0.0.0-20230125174641-2a8082862702/go.mod h1:nTakvJ4XYq45UXtn0DbwR4aU9ZdjlnIenpbs6Cd+FM0= @@ -1560,8 +1558,8 @@ github.com/hashicorp/vault-plugin-auth-alicloud v0.19.0 h1:LgNFlAgUsOjt8THbhcnWD github.com/hashicorp/vault-plugin-auth-alicloud v0.19.0/go.mod h1:hkcOv6HSKRMWwZA/YZ6OgStW6iQXCv90KfSTJYbt5vc= github.com/hashicorp/vault-plugin-auth-azure v0.19.2 h1:zf+M+Hhht4cXkmfF20pDQ8PADm9/X9UGLidMRmao0po= github.com/hashicorp/vault-plugin-auth-azure v0.19.2/go.mod h1:elSxwfldjnRJQsJIAfD305g7gvUnFDykGvuY5phNNgw= -github.com/hashicorp/vault-plugin-auth-cf v0.19.0 h1:/I084ZCypbhTO5ZiYjxhjzokuDqOWWLLxHatyViU9ss= -github.com/hashicorp/vault-plugin-auth-cf v0.19.0/go.mod h1:LiH/IttNxAgto2ooR9l2g6+CiXc5c/1uPE0pT0hILRg= +github.com/hashicorp/vault-plugin-auth-cf v0.19.1 h1:mW5wI7Xn7cCOnppQ+e3NSnCtaNlSvmCcJ0ZIi/BXsEs= +github.com/hashicorp/vault-plugin-auth-cf v0.19.1/go.mod h1:A9DtK8jx6r/LLiQFB4nH6xgoMoRPuy1cn++twIFXb4E= github.com/hashicorp/vault-plugin-auth-gcp v0.19.1 h1:ALSm4IUBRien3uKrdtvihxSwmOaKJxzKqDmTR2WpMG8= github.com/hashicorp/vault-plugin-auth-gcp v0.19.1/go.mod h1:NwWKw3t/ZjqDd4PdYe2LVTvX0EAMmwFaexIQQWb+U0U= github.com/hashicorp/vault-plugin-auth-jwt v0.22.0 h1:ihjx6HszRSt8Vfknc5t0AKXBQqFhqTQ4Wdd/PK+EboU= @@ -1819,7 +1817,6 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= @@ -2477,8 +2474,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2560,7 +2557,6 @@ golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/helper/forwarding/types.pb.go b/helper/forwarding/types.pb.go index f3b1d9f60da0..3f262195d674 100644 --- a/helper/forwarding/types.pb.go +++ b/helper/forwarding/types.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: helper/forwarding/types.proto @@ -24,20 +24,19 @@ const ( ) type Request struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Not used right now but reserving in case it turns out that streaming // makes things more economical on the gRPC side // uint64 id = 1; Method string `protobuf:"bytes,2,opt,name=method,proto3" json:"method,omitempty"` Url *URL `protobuf:"bytes,3,opt,name=url,proto3" json:"url,omitempty"` - HeaderEntries map[string]*HeaderEntry `protobuf:"bytes,4,rep,name=header_entries,json=headerEntries,proto3" json:"header_entries,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + HeaderEntries map[string]*HeaderEntry `protobuf:"bytes,4,rep,name=header_entries,json=headerEntries,proto3" json:"header_entries,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` Body []byte `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"` Host string `protobuf:"bytes,6,opt,name=host,proto3" json:"host,omitempty"` RemoteAddr string `protobuf:"bytes,7,opt,name=remote_addr,json=remoteAddr,proto3" json:"remote_addr,omitempty"` PeerCertificates [][]byte `protobuf:"bytes,8,rep,name=peer_certificates,json=peerCertificates,proto3" json:"peer_certificates,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Request) Reset() { @@ -120,12 +119,9 @@ func (x *Request) GetPeerCertificates() [][]byte { } type URL struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Scheme string `protobuf:"bytes,1,opt,name=scheme,proto3" json:"scheme,omitempty"` - Opaque string `protobuf:"bytes,2,opt,name=opaque,proto3" json:"opaque,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Scheme string `protobuf:"bytes,1,opt,name=scheme,proto3" json:"scheme,omitempty"` + Opaque string `protobuf:"bytes,2,opt,name=opaque,proto3" json:"opaque,omitempty"` // This isn't needed now but might be in the future, so we'll skip the // number to keep the ordering in net/url // UserInfo user = 3; @@ -134,8 +130,10 @@ type URL struct { RawPath string `protobuf:"bytes,6,opt,name=raw_path,json=rawPath,proto3" json:"raw_path,omitempty"` // This also isn't needed right now, but we'll reserve the number // bool force_query = 7; - RawQuery string `protobuf:"bytes,8,opt,name=raw_query,json=rawQuery,proto3" json:"raw_query,omitempty"` - Fragment string `protobuf:"bytes,9,opt,name=fragment,proto3" json:"fragment,omitempty"` + RawQuery string `protobuf:"bytes,8,opt,name=raw_query,json=rawQuery,proto3" json:"raw_query,omitempty"` + Fragment string `protobuf:"bytes,9,opt,name=fragment,proto3" json:"fragment,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *URL) Reset() { @@ -218,11 +216,10 @@ func (x *URL) GetFragment() string { } type HeaderEntry struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Values []string `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` unknownFields protoimpl.UnknownFields - - Values []string `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` + sizeCache protoimpl.SizeCache } func (x *HeaderEntry) Reset() { @@ -263,10 +260,7 @@ func (x *HeaderEntry) GetValues() []string { } type Response struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Not used right now but reserving in case it turns out that streaming // makes things more economical on the gRPC side // uint64 id = 1; @@ -274,8 +268,10 @@ type Response struct { Body []byte `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` // Added in 0.6.2 to ensure that the content-type is set appropriately, as // well as any other information - HeaderEntries map[string]*HeaderEntry `protobuf:"bytes,4,rep,name=header_entries,json=headerEntries,proto3" json:"header_entries,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + HeaderEntries map[string]*HeaderEntry `protobuf:"bytes,4,rep,name=header_entries,json=headerEntries,proto3" json:"header_entries,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` LastRemoteWal uint64 `protobuf:"varint,5,opt,name=last_remote_wal,json=lastRemoteWal,proto3" json:"last_remote_wal,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Response) Reset() { diff --git a/helper/identity/mfa/types.pb.go b/helper/identity/mfa/types.pb.go index 5d8a57367d39..730f6d77f70b 100644 --- a/helper/identity/mfa/types.pb.go +++ b/helper/identity/mfa/types.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: helper/identity/mfa/types.proto @@ -28,10 +28,7 @@ const ( // Configuration information differs by type. Handler of each type should know // what to expect from the Config field. type Config struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // @inject_tag: sentinel:"-" Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty" sentinel:"-"` // @inject_tag: sentinel:"-" @@ -44,7 +41,7 @@ type Config struct { UsernameFormat string `protobuf:"bytes,5,opt,name=username_format,json=usernameFormat,proto3" json:"username_format,omitempty" sentinel:"-"` // @inject_tag: sentinel:"-" // - // Types that are assignable to Config: + // Types that are valid to be assigned to Config: // // *Config_TOTPConfig // *Config_OktaConfig @@ -52,7 +49,9 @@ type Config struct { // *Config_PingIDConfig Config isConfig_Config `protobuf_oneof:"config" sentinel:"-"` // @inject_tag: sentinel:"-" - NamespaceID string `protobuf:"bytes,10,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty" sentinel:"-"` + NamespaceID string `protobuf:"bytes,10,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty" sentinel:"-"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Config) Reset() { @@ -120,37 +119,45 @@ func (x *Config) GetUsernameFormat() string { return "" } -func (m *Config) GetConfig() isConfig_Config { - if m != nil { - return m.Config +func (x *Config) GetConfig() isConfig_Config { + if x != nil { + return x.Config } return nil } func (x *Config) GetTOTPConfig() *TOTPConfig { - if x, ok := x.GetConfig().(*Config_TOTPConfig); ok { - return x.TOTPConfig + if x != nil { + if x, ok := x.Config.(*Config_TOTPConfig); ok { + return x.TOTPConfig + } } return nil } func (x *Config) GetOktaConfig() *OktaConfig { - if x, ok := x.GetConfig().(*Config_OktaConfig); ok { - return x.OktaConfig + if x != nil { + if x, ok := x.Config.(*Config_OktaConfig); ok { + return x.OktaConfig + } } return nil } func (x *Config) GetDuoConfig() *DuoConfig { - if x, ok := x.GetConfig().(*Config_DuoConfig); ok { - return x.DuoConfig + if x != nil { + if x, ok := x.Config.(*Config_DuoConfig); ok { + return x.DuoConfig + } } return nil } func (x *Config) GetPingIDConfig() *PingIDConfig { - if x, ok := x.GetConfig().(*Config_PingIDConfig); ok { - return x.PingIDConfig + if x != nil { + if x, ok := x.Config.(*Config_PingIDConfig); ok { + return x.PingIDConfig + } } return nil } @@ -196,10 +203,7 @@ func (*Config_PingIDConfig) isConfig_Config() {} // by the information stored in the entity and not from the values in the // configuration. type TOTPConfig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // @inject_tag: sentinel:"-" Issuer string `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty" sentinel:"-"` // @inject_tag: sentinel:"-" @@ -216,6 +220,8 @@ type TOTPConfig struct { QRSize int32 `protobuf:"varint,7,opt,name=qr_size,json=qrSize,proto3" json:"qr_size,omitempty" sentinel:"-"` // @inject_tag: sentinel:"-" MaxValidationAttempts uint32 `protobuf:"varint,8,opt,name=max_validation_attempts,json=maxValidationAttempts,proto3" json:"max_validation_attempts,omitempty" sentinel:"-"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *TOTPConfig) Reset() { @@ -307,10 +313,7 @@ func (x *TOTPConfig) GetMaxValidationAttempts() uint32 { // DuoConfig represents the configuration information required to perform // Duo authentication. type DuoConfig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // @inject_tag: sentinel:"-" IntegrationKey string `protobuf:"bytes,1,opt,name=integration_key,json=integrationKey,proto3" json:"integration_key,omitempty" sentinel:"-"` // @inject_tag: sentinel:"-" @@ -320,7 +323,9 @@ type DuoConfig struct { // @inject_tag: sentinel:"-" PushInfo string `protobuf:"bytes,4,opt,name=push_info,json=pushInfo,proto3" json:"push_info,omitempty" sentinel:"-"` // @inject_tag: sentinel:"-" - UsePasscode bool `protobuf:"varint,5,opt,name=use_passcode,json=usePasscode,proto3" json:"use_passcode,omitempty" sentinel:"-"` + UsePasscode bool `protobuf:"varint,5,opt,name=use_passcode,json=usePasscode,proto3" json:"use_passcode,omitempty" sentinel:"-"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DuoConfig) Reset() { @@ -391,10 +396,7 @@ func (x *DuoConfig) GetUsePasscode() bool { // OktaConfig contains Okta configuration parameters required to perform Okta // authentication. type OktaConfig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // @inject_tag: sentinel:"-" OrgName string `protobuf:"bytes,1,opt,name=org_name,json=orgName,proto3" json:"org_name,omitempty" sentinel:"-"` // @inject_tag: sentinel:"-" @@ -404,7 +406,9 @@ type OktaConfig struct { // @inject_tag: sentinel:"-" BaseURL string `protobuf:"bytes,4,opt,name=base_url,json=baseUrl,proto3" json:"base_url,omitempty" sentinel:"-"` // @inject_tag: sentinel:"-" - PrimaryEmail bool `protobuf:"varint,5,opt,name=primary_email,json=primaryEmail,proto3" json:"primary_email,omitempty" sentinel:"-"` + PrimaryEmail bool `protobuf:"varint,5,opt,name=primary_email,json=primaryEmail,proto3" json:"primary_email,omitempty" sentinel:"-"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *OktaConfig) Reset() { @@ -474,10 +478,7 @@ func (x *OktaConfig) GetPrimaryEmail() bool { // PingIDConfig contains PingID configuration information type PingIDConfig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // @inject_tag: sentinel:"-" UseBase64Key string `protobuf:"bytes,1,opt,name=use_base64_key,json=useBase64Key,proto3" json:"use_base64_key,omitempty" sentinel:"-"` // @inject_tag: sentinel:"-" @@ -492,6 +493,8 @@ type PingIDConfig struct { AdminURL string `protobuf:"bytes,6,opt,name=admin_url,json=adminUrl,proto3" json:"admin_url,omitempty" sentinel:"-"` // @inject_tag: sentinel:"-" AuthenticatorURL string `protobuf:"bytes,7,opt,name=authenticator_url,json=authenticatorUrl,proto3" json:"authenticator_url,omitempty" sentinel:"-"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *PingIDConfig) Reset() { @@ -576,16 +579,15 @@ func (x *PingIDConfig) GetAuthenticatorURL() string { // Secret represents all the types of secrets which the entity can hold. // Each MFA type should add a secret type to the oneof block in this message. type Secret struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // @inject_tag: sentinel:"-" MethodName string `protobuf:"bytes,1,opt,name=method_name,json=methodName,proto3" json:"method_name,omitempty" sentinel:"-"` - // Types that are assignable to Value: + // Types that are valid to be assigned to Value: // // *Secret_TOTPSecret - Value isSecret_Value `protobuf_oneof:"value"` + Value isSecret_Value `protobuf_oneof:"value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Secret) Reset() { @@ -625,16 +627,18 @@ func (x *Secret) GetMethodName() string { return "" } -func (m *Secret) GetValue() isSecret_Value { - if m != nil { - return m.Value +func (x *Secret) GetValue() isSecret_Value { + if x != nil { + return x.Value } return nil } func (x *Secret) GetTOTPSecret() *TOTPSecret { - if x, ok := x.GetValue().(*Secret_TOTPSecret); ok { - return x.TOTPSecret + if x != nil { + if x, ok := x.Value.(*Secret_TOTPSecret); ok { + return x.TOTPSecret + } } return nil } @@ -654,10 +658,7 @@ func (*Secret_TOTPSecret) isSecret_Value() {} // particular MFA method. This information is used to validate the MFA // credential supplied over the API during request time. type TOTPSecret struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // @inject_tag: sentinel:"-" Issuer string `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty" sentinel:"-"` // @inject_tag: sentinel:"-" @@ -674,7 +675,9 @@ type TOTPSecret struct { // @inject_tag: sentinel:"-" AccountName string `protobuf:"bytes,8,opt,name=account_name,json=accountName,proto3" json:"account_name,omitempty" sentinel:"-"` // @inject_tag: sentinel:"-" - Key string `protobuf:"bytes,9,opt,name=key,proto3" json:"key,omitempty" sentinel:"-"` + Key string `protobuf:"bytes,9,opt,name=key,proto3" json:"key,omitempty" sentinel:"-"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *TOTPSecret) Reset() { @@ -766,18 +769,17 @@ func (x *TOTPSecret) GetKey() string { // MFAEnforcementConfig is what the user provides to the // mfa/login_enforcement endpoint. type MFAEnforcementConfig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - NamespaceID string `protobuf:"bytes,2,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` - MFAMethodIDs []string `protobuf:"bytes,3,rep,name=mfa_method_ids,json=mfaMethodIds,proto3" json:"mfa_method_ids,omitempty"` - AuthMethodAccessors []string `protobuf:"bytes,4,rep,name=auth_method_accessors,json=authMethodAccessors,proto3" json:"auth_method_accessors,omitempty"` - AuthMethodTypes []string `protobuf:"bytes,5,rep,name=auth_method_types,json=authMethodTypes,proto3" json:"auth_method_types,omitempty"` - IdentityGroupIds []string `protobuf:"bytes,6,rep,name=identity_group_ids,json=identityGroupIds,proto3" json:"identity_group_ids,omitempty"` - IdentityEntityIDs []string `protobuf:"bytes,7,rep,name=identity_entity_ids,json=identityEntityIds,proto3" json:"identity_entity_ids,omitempty"` - ID string `protobuf:"bytes,8,opt,name=id,proto3" json:"id,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + NamespaceID string `protobuf:"bytes,2,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` + MFAMethodIDs []string `protobuf:"bytes,3,rep,name=mfa_method_ids,json=mfaMethodIds,proto3" json:"mfa_method_ids,omitempty"` + AuthMethodAccessors []string `protobuf:"bytes,4,rep,name=auth_method_accessors,json=authMethodAccessors,proto3" json:"auth_method_accessors,omitempty"` + AuthMethodTypes []string `protobuf:"bytes,5,rep,name=auth_method_types,json=authMethodTypes,proto3" json:"auth_method_types,omitempty"` + IdentityGroupIds []string `protobuf:"bytes,6,rep,name=identity_group_ids,json=identityGroupIds,proto3" json:"identity_group_ids,omitempty"` + IdentityEntityIDs []string `protobuf:"bytes,7,rep,name=identity_entity_ids,json=identityEntityIds,proto3" json:"identity_entity_ids,omitempty"` + ID string `protobuf:"bytes,8,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MFAEnforcementConfig) Reset() { diff --git a/helper/identity/types.pb.go b/helper/identity/types.pb.go index a3055992823f..6483f082a8c8 100644 --- a/helper/identity/types.pb.go +++ b/helper/identity/types.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: helper/identity/types.proto @@ -27,10 +27,7 @@ const ( // Group represents an identity group. type Group struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // ID is the unique identifier for this group // @inject_tag: sentinel:"-" ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" sentinel:"-"` @@ -51,7 +48,7 @@ type Group struct { MemberEntityIDs []string `protobuf:"bytes,5,rep,name=member_entity_ids,json=memberEntityIDs,proto3" json:"member_entity_ids,omitempty" sentinel:"-"` // Metadata represents the custom data tied with this group // @inject_tag: sentinel:"-" - Metadata map[string]string `protobuf:"bytes,6,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3" sentinel:"-"` + Metadata map[string]string `protobuf:"bytes,6,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value" sentinel:"-"` // CreationTime is the time at which this group was created // @inject_tag: sentinel:"-" CreationTime *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty" sentinel:"-"` @@ -81,7 +78,9 @@ type Group struct { // belongs to. Do not return this value over the API when reading the // group. // @inject_tag: sentinel:"-" - NamespaceID string `protobuf:"bytes,13,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty" sentinel:"-"` + NamespaceID string `protobuf:"bytes,13,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty" sentinel:"-"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Group) Reset() { @@ -208,11 +207,10 @@ func (x *Group) GetNamespaceID() string { // LocalAliases holds the aliases belonging to an entity that are local to the // cluster. type LocalAliases struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Aliases []*Alias `protobuf:"bytes,1,rep,name=aliases,proto3" json:"aliases,omitempty"` unknownFields protoimpl.UnknownFields - - Aliases []*Alias `protobuf:"bytes,1,rep,name=aliases,proto3" json:"aliases,omitempty"` + sizeCache protoimpl.SizeCache } func (x *LocalAliases) Reset() { @@ -255,10 +253,7 @@ func (x *LocalAliases) GetAliases() []*Alias { // Entity represents an entity that gets persisted and indexed. // Entity is fundamentally composed of zero or many aliases. type Entity struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Aliases are the identities that this entity is made of. This can be // empty as well to favor being able to create the entity first and then // incrementally adding aliases. @@ -281,7 +276,7 @@ type Entity struct { // on this explicit metadata. This enables virtual groupings of entities // based on its metadata. // @inject_tag: sentinel:"-" - Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3" sentinel:"-"` + Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value" sentinel:"-"` // CreationTime is the time at which this entity is first created. // @inject_tag: sentinel:"-" CreationTime *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty" sentinel:"-"` @@ -307,7 +302,7 @@ type Entity struct { // MFASecrets holds the MFA secrets indexed by the identifier of the MFA // method configuration. // @inject_tag: sentinel:"-" - MFASecrets map[string]*mfa.Secret `protobuf:"bytes,10,rep,name=mfa_secrets,json=mfaSecrets,proto3" json:"mfa_secrets,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3" sentinel:"-"` + MFASecrets map[string]*mfa.Secret `protobuf:"bytes,10,rep,name=mfa_secrets,json=mfaSecrets,proto3" json:"mfa_secrets,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value" sentinel:"-"` // Disabled indicates whether tokens associated with the account should not // be able to be used // @inject_tag: sentinel:"-" @@ -316,7 +311,9 @@ type Entity struct { // belongs to. Do not return this value over the API when reading the // entity. // @inject_tag: sentinel:"-" - NamespaceID string `protobuf:"bytes,12,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty" sentinel:"-"` + NamespaceID string `protobuf:"bytes,12,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty" sentinel:"-"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Entity) Reset() { @@ -437,10 +434,7 @@ func (x *Entity) GetNamespaceID() string { // entity object in storage and also represents in an in-memory index of an // alias object. type Alias struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // ID is the unique identifier that represents this alias // @inject_tag: sentinel:"-" ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" sentinel:"-"` @@ -464,7 +458,7 @@ type Alias struct { // which enables virtual grouping of aliases. Aliases will be indexed // against their metadata. // @inject_tag: sentinel:"-" - Metadata map[string]string `protobuf:"bytes,6,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3" sentinel:"-"` + Metadata map[string]string `protobuf:"bytes,6,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value" sentinel:"-"` // Name is the identifier of this alias in its authentication source. // This does not uniquely identify an alias in Vault. This in conjunction // with MountAccessor form to be the factors that represent an alias in a @@ -489,7 +483,7 @@ type Alias struct { NamespaceID string `protobuf:"bytes,11,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty" sentinel:"-"` // Custom Metadata represents the custom data tied to this alias // @inject_tag: sentinel:"-" - CustomMetadata map[string]string `protobuf:"bytes,12,rep,name=custom_metadata,json=customMetadata,proto3" json:"custom_metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3" sentinel:"-"` + CustomMetadata map[string]string `protobuf:"bytes,12,rep,name=custom_metadata,json=customMetadata,proto3" json:"custom_metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value" sentinel:"-"` // Local indicates if the alias only belongs to the cluster where it was // created. If true, the alias will be stored in a location that is ignored by // the performance replication subsystem. @@ -500,6 +494,8 @@ type Alias struct { // during invalidation of local aliases in performance standbys. // @inject_tag: sentinel:"-" LocalBucketKey string `protobuf:"bytes,14,opt,name=local_bucket_key,json=localBucketKey,proto3" json:"local_bucket_key,omitempty" sentinel:"-"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Alias) Reset() { @@ -632,20 +628,19 @@ func (x *Alias) GetLocalBucketKey() string { // Deprecated. Retained for backwards compatibility. type EntityStorageEntry struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Personas []*PersonaIndexEntry `protobuf:"bytes,1,rep,name=personas,proto3" json:"personas,omitempty"` ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` CreationTime *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` LastUpdateTime *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=last_update_time,json=lastUpdateTime,proto3" json:"last_update_time,omitempty"` MergedEntityIDs []string `protobuf:"bytes,7,rep,name=merged_entity_ids,json=mergedEntityIDs,proto3" json:"merged_entity_ids,omitempty"` Policies []string `protobuf:"bytes,8,rep,name=policies,proto3" json:"policies,omitempty"` BucketKeyHash string `protobuf:"bytes,9,opt,name=bucket_key_hash,json=bucketKeyHash,proto3" json:"bucket_key_hash,omitempty"` - MFASecrets map[string]*mfa.Secret `protobuf:"bytes,10,rep,name=mfa_secrets,json=mfaSecrets,proto3" json:"mfa_secrets,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MFASecrets map[string]*mfa.Secret `protobuf:"bytes,10,rep,name=mfa_secrets,json=mfaSecrets,proto3" json:"mfa_secrets,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *EntityStorageEntry) Reset() { @@ -750,20 +745,19 @@ func (x *EntityStorageEntry) GetMFASecrets() map[string]*mfa.Secret { // Deprecated. Retained for backwards compatibility. type PersonaIndexEntry struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` EntityID string `protobuf:"bytes,2,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` MountType string `protobuf:"bytes,3,opt,name=mount_type,json=mountType,proto3" json:"mount_type,omitempty"` MountAccessor string `protobuf:"bytes,4,opt,name=mount_accessor,json=mountAccessor,proto3" json:"mount_accessor,omitempty"` MountPath string `protobuf:"bytes,5,opt,name=mount_path,json=mountPath,proto3" json:"mount_path,omitempty"` - Metadata map[string]string `protobuf:"bytes,6,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Metadata map[string]string `protobuf:"bytes,6,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` Name string `protobuf:"bytes,7,opt,name=name,proto3" json:"name,omitempty"` CreationTime *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` LastUpdateTime *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=last_update_time,json=lastUpdateTime,proto3" json:"last_update_time,omitempty"` MergedFromEntityIDs []string `protobuf:"bytes,10,rep,name=merged_from_entity_ids,json=mergedFromEntityIDs,proto3" json:"merged_from_entity_ids,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *PersonaIndexEntry) Reset() { diff --git a/helper/storagepacker/types.pb.go b/helper/storagepacker/types.pb.go index a2893799fc4c..3bb573ce07ac 100644 --- a/helper/storagepacker/types.pb.go +++ b/helper/storagepacker/types.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: helper/storagepacker/types.proto @@ -26,10 +26,7 @@ const ( // Item represents an entry that gets inserted into the storage packer type Item struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // ID must be provided by the caller; the same value, if used with GetItem, // can be used to fetch the item. However, when iterating through a bucket, // this ID will be an internal ID. In other words, outside of the use-case @@ -37,7 +34,9 @@ type Item struct { // consistent with what they passed in. ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // message is the contents of the item - Message *anypb.Any `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + Message *anypb.Any `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Item) Reset() { @@ -91,16 +90,15 @@ func (x *Item) GetMessage() *anypb.Any { // to become independent buckets. Hence, this can grow infinitely in terms of // storage space for items that get inserted. type Bucket struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Key is the storage path where the bucket gets stored Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // Items holds the items contained within this bucket. Used by v1. Items []*Item `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` // ItemMap stores a mapping of item ID to message. Used by v2. - ItemMap map[string]*anypb.Any `protobuf:"bytes,3,rep,name=item_map,json=itemMap,proto3" json:"item_map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + ItemMap map[string]*anypb.Any `protobuf:"bytes,3,rep,name=item_map,json=itemMap,proto3" json:"item_map,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Bucket) Reset() { diff --git a/helper/testhelpers/testhelpers.go b/helper/testhelpers/testhelpers.go index acecc084f8e5..5b96e1abe747 100644 --- a/helper/testhelpers/testhelpers.go +++ b/helper/testhelpers/testhelpers.go @@ -1003,3 +1003,15 @@ func WaitForNodesExcludingSelectedStandbys(t testing.TB, cluster *vault.TestClus func IsLocalOrRegressionTests() bool { return os.Getenv("CI") == "" || os.Getenv("VAULT_REGRESSION_TESTS") == "true" } + +func RaftDataDir(t testing.TB, core *vault.TestClusterCore) string { + t.Helper() + r, ok := core.UnderlyingStorage.(*raft.RaftBackend) + if !ok { + r, ok = core.UnderlyingHAStorage.(*raft.RaftBackend) + if !ok { + t.Fatal("no raft backend") + } + } + return r.DataDir(t) +} diff --git a/physical/raft/testing.go b/physical/raft/testing.go index 0a72e3f13cc6..c2e95320963f 100644 --- a/physical/raft/testing.go +++ b/physical/raft/testing.go @@ -13,6 +13,11 @@ import ( "github.com/hashicorp/go-uuid" ) +func (b *RaftBackend) DataDir(t testing.TB) string { + t.Helper() + return b.dataDir +} + func GetRaft(t testing.TB, bootstrap bool, noStoreState bool) (*RaftBackend, string) { return getRaftInternal(t, bootstrap, defaultRaftConfig(t, bootstrap, noStoreState), nil, nil, nil) } diff --git a/physical/raft/types.pb.go b/physical/raft/types.pb.go index 301664e42274..2538564d816a 100644 --- a/physical/raft/types.pb.go +++ b/physical/raft/types.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: physical/raft/types.proto @@ -24,10 +24,7 @@ const ( ) type LogOperation struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // OpType is the Operation type OpType uint32 `protobuf:"varint,1,opt,name=op_type,json=opType,proto3" json:"op_type,omitempty"` // Flags is an opaque value, currently unused. Reserved. @@ -35,7 +32,9 @@ type LogOperation struct { // Key that is being affected Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` // Value is optional, corresponds to the key - Value []byte `protobuf:"bytes,4,opt,name=value,proto3" json:"value,omitempty"` + Value []byte `protobuf:"bytes,4,opt,name=value,proto3" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *LogOperation) Reset() { @@ -97,11 +96,10 @@ func (x *LogOperation) GetValue() []byte { } type LogData struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Operations []*LogOperation `protobuf:"bytes,1,rep,name=operations,proto3" json:"operations,omitempty"` unknownFields protoimpl.UnknownFields - - Operations []*LogOperation `protobuf:"bytes,1,rep,name=operations,proto3" json:"operations,omitempty"` + sizeCache protoimpl.SizeCache } func (x *LogData) Reset() { @@ -142,12 +140,11 @@ func (x *LogData) GetOperations() []*LogOperation { } type IndexValue struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Term uint64 `protobuf:"varint,1,opt,name=term,proto3" json:"term,omitempty"` + Index uint64 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` unknownFields protoimpl.UnknownFields - - Term uint64 `protobuf:"varint,1,opt,name=term,proto3" json:"term,omitempty"` - Index uint64 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` + sizeCache protoimpl.SizeCache } func (x *IndexValue) Reset() { @@ -195,13 +192,12 @@ func (x *IndexValue) GetIndex() uint64 { } type Server struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Suffrage int32 `protobuf:"varint,1,opt,name=suffrage,proto3" json:"suffrage,omitempty"` + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` unknownFields protoimpl.UnknownFields - - Suffrage int32 `protobuf:"varint,1,opt,name=suffrage,proto3" json:"suffrage,omitempty"` - Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` - Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Server) Reset() { @@ -256,12 +252,11 @@ func (x *Server) GetAddress() string { } type ConfigurationValue struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Index uint64 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` + Servers []*Server `protobuf:"bytes,2,rep,name=servers,proto3" json:"servers,omitempty"` unknownFields protoimpl.UnknownFields - - Index uint64 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` - Servers []*Server `protobuf:"bytes,2,rep,name=servers,proto3" json:"servers,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ConfigurationValue) Reset() { @@ -309,11 +304,10 @@ func (x *ConfigurationValue) GetServers() []*Server { } type LocalNodeConfigValue struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - DesiredSuffrage string `protobuf:"bytes,1,opt,name=desired_suffrage,json=desiredSuffrage,proto3" json:"desired_suffrage,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + DesiredSuffrage string `protobuf:"bytes,1,opt,name=desired_suffrage,json=desiredSuffrage,proto3" json:"desired_suffrage,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *LocalNodeConfigValue) Reset() { diff --git a/sdk/database/dbplugin/database.pb.go b/sdk/database/dbplugin/database.pb.go index d48c5f107bdc..7a4f43bca536 100644 --- a/sdk/database/dbplugin/database.pb.go +++ b/sdk/database/dbplugin/database.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: sdk/database/dbplugin/database.proto @@ -26,12 +26,11 @@ const ( // Deprecated: Marked as deprecated in sdk/database/dbplugin/database.proto. type InitializeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Config []byte `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` - VerifyConnection bool `protobuf:"varint,2,opt,name=verify_connection,json=verifyConnection,proto3" json:"verify_connection,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Config []byte `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` + VerifyConnection bool `protobuf:"varint,2,opt,name=verify_connection,json=verifyConnection,proto3" json:"verify_connection,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *InitializeRequest) Reset() { @@ -79,12 +78,11 @@ func (x *InitializeRequest) GetVerifyConnection() bool { } type InitRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Config []byte `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` - VerifyConnection bool `protobuf:"varint,2,opt,name=verify_connection,json=verifyConnection,proto3" json:"verify_connection,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Config []byte `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` + VerifyConnection bool `protobuf:"varint,2,opt,name=verify_connection,json=verifyConnection,proto3" json:"verify_connection,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *InitRequest) Reset() { @@ -132,13 +130,12 @@ func (x *InitRequest) GetVerifyConnection() bool { } type CreateUserRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Statements *Statements `protobuf:"bytes,1,opt,name=statements,proto3" json:"statements,omitempty"` UsernameConfig *UsernameConfig `protobuf:"bytes,2,opt,name=username_config,json=usernameConfig,proto3" json:"username_config,omitempty"` Expiration *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=expiration,proto3" json:"expiration,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *CreateUserRequest) Reset() { @@ -193,13 +190,12 @@ func (x *CreateUserRequest) GetExpiration() *timestamppb.Timestamp { } type RenewUserRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Statements *Statements `protobuf:"bytes,1,opt,name=statements,proto3" json:"statements,omitempty"` + Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` + Expiration *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=expiration,proto3" json:"expiration,omitempty"` unknownFields protoimpl.UnknownFields - - Statements *Statements `protobuf:"bytes,1,opt,name=statements,proto3" json:"statements,omitempty"` - Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` - Expiration *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=expiration,proto3" json:"expiration,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RenewUserRequest) Reset() { @@ -254,12 +250,11 @@ func (x *RenewUserRequest) GetExpiration() *timestamppb.Timestamp { } type RevokeUserRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Statements *Statements `protobuf:"bytes,1,opt,name=statements,proto3" json:"statements,omitempty"` + Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` unknownFields protoimpl.UnknownFields - - Statements *Statements `protobuf:"bytes,1,opt,name=statements,proto3" json:"statements,omitempty"` - Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RevokeUserRequest) Reset() { @@ -307,11 +302,10 @@ func (x *RevokeUserRequest) GetUsername() string { } type RotateRootCredentialsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Statements []string `protobuf:"bytes,1,rep,name=statements,proto3" json:"statements,omitempty"` unknownFields protoimpl.UnknownFields - - Statements []string `protobuf:"bytes,1,rep,name=statements,proto3" json:"statements,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RotateRootCredentialsRequest) Reset() { @@ -352,10 +346,7 @@ func (x *RotateRootCredentialsRequest) GetStatements() []string { } type Statements struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // DEPRECATED, will be removed in 0.12 // // Deprecated: Marked as deprecated in sdk/database/dbplugin/database.proto. @@ -377,6 +368,8 @@ type Statements struct { Rollback []string `protobuf:"bytes,7,rep,name=rollback,proto3" json:"rollback,omitempty"` Renewal []string `protobuf:"bytes,8,rep,name=renewal,proto3" json:"renewal,omitempty"` Rotation []string `protobuf:"bytes,9,rep,name=rotation,proto3" json:"rotation,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Statements) Reset() { @@ -477,12 +470,11 @@ func (x *Statements) GetRotation() []string { } type UsernameConfig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + DisplayName string `protobuf:"bytes,1,opt,name=DisplayName,proto3" json:"DisplayName,omitempty"` + RoleName string `protobuf:"bytes,2,opt,name=RoleName,proto3" json:"RoleName,omitempty"` unknownFields protoimpl.UnknownFields - - DisplayName string `protobuf:"bytes,1,opt,name=DisplayName,proto3" json:"DisplayName,omitempty"` - RoleName string `protobuf:"bytes,2,opt,name=RoleName,proto3" json:"RoleName,omitempty"` + sizeCache protoimpl.SizeCache } func (x *UsernameConfig) Reset() { @@ -530,11 +522,10 @@ func (x *UsernameConfig) GetRoleName() string { } type InitResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Config []byte `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` unknownFields protoimpl.UnknownFields - - Config []byte `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` + sizeCache protoimpl.SizeCache } func (x *InitResponse) Reset() { @@ -575,12 +566,11 @@ func (x *InitResponse) GetConfig() []byte { } type CreateUserResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` unknownFields protoimpl.UnknownFields - - Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` - Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreateUserResponse) Reset() { @@ -628,11 +618,10 @@ func (x *CreateUserResponse) GetPassword() string { } type TypeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` unknownFields protoimpl.UnknownFields - - Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + sizeCache protoimpl.SizeCache } func (x *TypeResponse) Reset() { @@ -673,11 +662,10 @@ func (x *TypeResponse) GetType() string { } type RotateRootCredentialsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Config []byte `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` unknownFields protoimpl.UnknownFields - - Config []byte `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RotateRootCredentialsResponse) Reset() { @@ -718,9 +706,9 @@ func (x *RotateRootCredentialsResponse) GetConfig() []byte { } type Empty struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Empty) Reset() { @@ -754,11 +742,10 @@ func (*Empty) Descriptor() ([]byte, []int) { } type GenerateCredentialsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"` unknownFields protoimpl.UnknownFields - - Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GenerateCredentialsResponse) Reset() { @@ -799,13 +786,12 @@ func (x *GenerateCredentialsResponse) GetPassword() string { } type StaticUserConfig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` + Create bool `protobuf:"varint,3,opt,name=create,proto3" json:"create,omitempty"` unknownFields protoimpl.UnknownFields - - Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` - Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` - Create bool `protobuf:"varint,3,opt,name=create,proto3" json:"create,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StaticUserConfig) Reset() { @@ -860,12 +846,11 @@ func (x *StaticUserConfig) GetCreate() bool { } type SetCredentialsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Statements *Statements `protobuf:"bytes,1,opt,name=statements,proto3" json:"statements,omitempty"` - StaticUserConfig *StaticUserConfig `protobuf:"bytes,2,opt,name=static_user_config,json=staticUserConfig,proto3" json:"static_user_config,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Statements *Statements `protobuf:"bytes,1,opt,name=statements,proto3" json:"statements,omitempty"` + StaticUserConfig *StaticUserConfig `protobuf:"bytes,2,opt,name=static_user_config,json=staticUserConfig,proto3" json:"static_user_config,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SetCredentialsRequest) Reset() { @@ -913,12 +898,11 @@ func (x *SetCredentialsRequest) GetStaticUserConfig() *StaticUserConfig { } type SetCredentialsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` unknownFields protoimpl.UnknownFields - - Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` - Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SetCredentialsResponse) Reset() { diff --git a/sdk/database/dbplugin/v5/proto/database.pb.go b/sdk/database/dbplugin/v5/proto/database.pb.go index 594d77a8c7a2..3ca3ddb13cd8 100644 --- a/sdk/database/dbplugin/v5/proto/database.pb.go +++ b/sdk/database/dbplugin/v5/proto/database.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: sdk/database/dbplugin/v5/proto/database.proto @@ -29,12 +29,11 @@ const ( // Initialize() // /////////////// type InitializeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ConfigData *structpb.Struct `protobuf:"bytes,1,opt,name=config_data,json=configData,proto3" json:"config_data,omitempty"` - VerifyConnection bool `protobuf:"varint,2,opt,name=verify_connection,json=verifyConnection,proto3" json:"verify_connection,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + ConfigData *structpb.Struct `protobuf:"bytes,1,opt,name=config_data,json=configData,proto3" json:"config_data,omitempty"` + VerifyConnection bool `protobuf:"varint,2,opt,name=verify_connection,json=verifyConnection,proto3" json:"verify_connection,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *InitializeRequest) Reset() { @@ -82,11 +81,10 @@ func (x *InitializeRequest) GetVerifyConnection() bool { } type InitializeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ConfigData *structpb.Struct `protobuf:"bytes,1,opt,name=config_data,json=configData,proto3" json:"config_data,omitempty"` unknownFields protoimpl.UnknownFields - - ConfigData *structpb.Struct `protobuf:"bytes,1,opt,name=config_data,json=configData,proto3" json:"config_data,omitempty"` + sizeCache protoimpl.SizeCache } func (x *InitializeResponse) Reset() { @@ -127,10 +125,7 @@ func (x *InitializeResponse) GetConfigData() *structpb.Struct { } type NewUserRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` UsernameConfig *UsernameConfig `protobuf:"bytes,1,opt,name=username_config,json=usernameConfig,proto3" json:"username_config,omitempty"` Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` Expiration *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=expiration,proto3" json:"expiration,omitempty"` @@ -139,6 +134,8 @@ type NewUserRequest struct { CredentialType int32 `protobuf:"varint,6,opt,name=credential_type,json=credentialType,proto3" json:"credential_type,omitempty"` PublicKey []byte `protobuf:"bytes,7,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` Subject string `protobuf:"bytes,8,opt,name=subject,proto3" json:"subject,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *NewUserRequest) Reset() { @@ -228,12 +225,11 @@ func (x *NewUserRequest) GetSubject() string { } type UsernameConfig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + DisplayName string `protobuf:"bytes,1,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + RoleName string `protobuf:"bytes,2,opt,name=role_name,json=roleName,proto3" json:"role_name,omitempty"` unknownFields protoimpl.UnknownFields - - DisplayName string `protobuf:"bytes,1,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` - RoleName string `protobuf:"bytes,2,opt,name=role_name,json=roleName,proto3" json:"role_name,omitempty"` + sizeCache protoimpl.SizeCache } func (x *UsernameConfig) Reset() { @@ -281,11 +277,10 @@ func (x *UsernameConfig) GetRoleName() string { } type NewUserResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` unknownFields protoimpl.UnknownFields - - Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + sizeCache protoimpl.SizeCache } func (x *NewUserResponse) Reset() { @@ -329,16 +324,15 @@ func (x *NewUserResponse) GetUsername() string { // UpdateUser() // /////////////// type UpdateUserRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` - Password *ChangePassword `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` - Expiration *ChangeExpiration `protobuf:"bytes,3,opt,name=expiration,proto3" json:"expiration,omitempty"` - PublicKey *ChangePublicKey `protobuf:"bytes,4,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` - CredentialType int32 `protobuf:"varint,5,opt,name=credential_type,json=credentialType,proto3" json:"credential_type,omitempty"` - SelfManagedPassword string `protobuf:"bytes,6,opt,name=self_managed_password,json=selfManagedPassword,proto3" json:"self_managed_password,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + Password *ChangePassword `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` + Expiration *ChangeExpiration `protobuf:"bytes,3,opt,name=expiration,proto3" json:"expiration,omitempty"` + PublicKey *ChangePublicKey `protobuf:"bytes,4,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + CredentialType int32 `protobuf:"varint,5,opt,name=credential_type,json=credentialType,proto3" json:"credential_type,omitempty"` + SelfManagedPassword string `protobuf:"bytes,6,opt,name=self_managed_password,json=selfManagedPassword,proto3" json:"self_managed_password,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *UpdateUserRequest) Reset() { @@ -414,12 +408,11 @@ func (x *UpdateUserRequest) GetSelfManagedPassword() string { } type ChangePassword struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + NewPassword string `protobuf:"bytes,1,opt,name=new_password,json=newPassword,proto3" json:"new_password,omitempty"` + Statements *Statements `protobuf:"bytes,2,opt,name=statements,proto3" json:"statements,omitempty"` unknownFields protoimpl.UnknownFields - - NewPassword string `protobuf:"bytes,1,opt,name=new_password,json=newPassword,proto3" json:"new_password,omitempty"` - Statements *Statements `protobuf:"bytes,2,opt,name=statements,proto3" json:"statements,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ChangePassword) Reset() { @@ -467,12 +460,11 @@ func (x *ChangePassword) GetStatements() *Statements { } type ChangePublicKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + NewPublicKey []byte `protobuf:"bytes,1,opt,name=new_public_key,json=newPublicKey,proto3" json:"new_public_key,omitempty"` + Statements *Statements `protobuf:"bytes,2,opt,name=statements,proto3" json:"statements,omitempty"` unknownFields protoimpl.UnknownFields - - NewPublicKey []byte `protobuf:"bytes,1,opt,name=new_public_key,json=newPublicKey,proto3" json:"new_public_key,omitempty"` - Statements *Statements `protobuf:"bytes,2,opt,name=statements,proto3" json:"statements,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ChangePublicKey) Reset() { @@ -520,12 +512,11 @@ func (x *ChangePublicKey) GetStatements() *Statements { } type ChangeExpiration struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` NewExpiration *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=new_expiration,json=newExpiration,proto3" json:"new_expiration,omitempty"` Statements *Statements `protobuf:"bytes,2,opt,name=statements,proto3" json:"statements,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ChangeExpiration) Reset() { @@ -573,9 +564,9 @@ func (x *ChangeExpiration) GetStatements() *Statements { } type UpdateUserResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *UpdateUserResponse) Reset() { @@ -612,12 +603,11 @@ func (*UpdateUserResponse) Descriptor() ([]byte, []int) { // DeleteUser() // /////////////// type DeleteUserRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + Statements *Statements `protobuf:"bytes,2,opt,name=statements,proto3" json:"statements,omitempty"` unknownFields protoimpl.UnknownFields - - Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` - Statements *Statements `protobuf:"bytes,2,opt,name=statements,proto3" json:"statements,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DeleteUserRequest) Reset() { @@ -665,9 +655,9 @@ func (x *DeleteUserRequest) GetStatements() *Statements { } type DeleteUserResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DeleteUserResponse) Reset() { @@ -704,11 +694,10 @@ func (*DeleteUserResponse) Descriptor() ([]byte, []int) { // Type() // /////////////// type TypeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"` unknownFields protoimpl.UnknownFields - - Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"` + sizeCache protoimpl.SizeCache } func (x *TypeResponse) Reset() { @@ -752,11 +741,10 @@ func (x *TypeResponse) GetType() string { // General purpose // /////////////// type Statements struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Commands []string `protobuf:"bytes,1,rep,name=Commands,proto3" json:"Commands,omitempty"` unknownFields protoimpl.UnknownFields - - Commands []string `protobuf:"bytes,1,rep,name=Commands,proto3" json:"Commands,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Statements) Reset() { @@ -797,9 +785,9 @@ func (x *Statements) GetCommands() []string { } type Empty struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Empty) Reset() { diff --git a/sdk/framework/backend.go b/sdk/framework/backend.go index 5ebf9deb25de..7eb3dcf106be 100644 --- a/sdk/framework/backend.go +++ b/sdk/framework/backend.go @@ -108,6 +108,10 @@ type Backend struct { // RunningVersion is the optional version that will be self-reported RunningVersion string + // RotateCredential is the callback function used by the RotationManager + // to communicate with a plugin on when to rotate a credential + RotateCredential func(context.Context, *logical.Request) error + logger log.Logger system logical.SystemView events logical.EventSender @@ -216,6 +220,8 @@ func (b *Backend) HandleRequest(ctx context.Context, req *logical.Request) (*log return b.handleRevokeRenew(ctx, req) case logical.RollbackOperation: return b.handleRollback(ctx, req) + case logical.RotationOperation: + return b.handleRotation(ctx, req) } // If the path is empty and it is a help operation, handle that. @@ -665,6 +671,19 @@ func (b *Backend) handleRollback(ctx context.Context, req *logical.Request) (*lo return resp, merr.ErrorOrNil() } +// handleRotation invokes the RotateCredential func set on the backend. +func (b *Backend) handleRotation(ctx context.Context, req *logical.Request) (*logical.Response, error) { + if b.RotateCredential == nil { + return nil, logical.ErrUnsupportedOperation + } + + err := b.RotateCredential(ctx, req) + if err != nil { + return nil, err + } + return &logical.Response{}, nil +} + func (b *Backend) handleAuthRenew(ctx context.Context, req *logical.Request) (*logical.Response, error) { if b.AuthRenew == nil { return logical.ErrorResponse("this auth type doesn't support renew"), nil diff --git a/sdk/go.mod b/sdk/go.mod index 8d306d850a4e..2e243af41329 100644 --- a/sdk/go.mod +++ b/sdk/go.mod @@ -1,6 +1,6 @@ module github.com/hashicorp/vault/sdk -go 1.23.0 +go 1.23.3 require ( cloud.google.com/go/cloudsqlconn v1.4.3 @@ -8,26 +8,26 @@ require ( github.com/armon/go-radix v1.0.0 github.com/cenkalti/backoff/v3 v3.2.2 github.com/docker/docker v27.2.1+incompatible - github.com/docker/go-connections v0.4.0 + github.com/docker/go-connections v0.5.0 github.com/evanphx/json-patch/v5 v5.6.0 github.com/fatih/structs v1.1.0 - github.com/go-ldap/ldap/v3 v3.4.6 - github.com/go-test/deep v1.1.0 + github.com/go-ldap/ldap/v3 v3.4.8 + github.com/go-test/deep v1.1.1 github.com/golang/protobuf v1.5.4 github.com/golang/snappy v0.0.4 - github.com/hashicorp/cap/ldap v0.0.0-20240328153749-fcfe271d0227 + github.com/hashicorp/cap/ldap v0.0.0-20240403125925-c0418810d10e github.com/hashicorp/errwrap v1.1.0 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-hclog v1.6.3 github.com/hashicorp/go-immutable-radix v1.3.1 - github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 - github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 + github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.1 + github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-plugin v1.6.1 github.com/hashicorp/go-retryablehttp v0.7.7 github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 github.com/hashicorp/go-secure-stdlib/cryptoutil v0.1.0 - github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 + github.com/hashicorp/go-secure-stdlib/mlock v0.1.3 github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 github.com/hashicorp/go-secure-stdlib/password v0.1.1 github.com/hashicorp/go-secure-stdlib/plugincontainer v0.4.1 @@ -35,54 +35,55 @@ require ( github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.3 github.com/hashicorp/go-sockaddr v1.0.6 github.com/hashicorp/go-uuid v1.0.3 - github.com/hashicorp/go-version v1.6.0 - github.com/hashicorp/golang-lru v0.5.4 + github.com/hashicorp/go-version v1.7.0 + github.com/hashicorp/golang-lru v1.0.2 github.com/hashicorp/hcl v1.0.1-vault-5 - github.com/hashicorp/vault/api v1.14.0 + github.com/hashicorp/vault v1.18.3 + github.com/hashicorp/vault/api v1.15.0 github.com/mitchellh/copystructure v1.2.0 github.com/mitchellh/mapstructure v1.5.0 github.com/pierrec/lz4 v2.6.1+incompatible + github.com/robfig/cron/v3 v3.0.1 github.com/ryanuber/go-glob v1.0.0 github.com/stretchr/testify v1.9.0 github.com/tink-crypto/tink-go/v2 v2.2.0 - go.uber.org/atomic v1.9.0 - golang.org/x/crypto v0.27.0 - golang.org/x/net v0.29.0 - golang.org/x/text v0.18.0 - google.golang.org/grpc v1.66.1 - google.golang.org/protobuf v1.34.2 + go.uber.org/atomic v1.11.0 + golang.org/x/crypto v0.31.0 + golang.org/x/net v0.31.0 + golang.org/x/text v0.21.0 + google.golang.org/grpc v1.68.0 + google.golang.org/protobuf v1.35.2 ) require ( + cloud.google.com/go/auth v0.10.2 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.5 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/go-jose/go-jose/v4 v4.0.1 // indirect + github.com/go-jose/go-jose/v4 v4.0.4 // indirect github.com/hashicorp/go-hmac-drbg v0.0.0-20210916214228-a6e5a68489f6 // indirect - github.com/kr/pretty v0.3.1 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/sys/userns v0.1.0 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/prometheus/client_golang v1.20.5 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect - golang.org/x/sync v0.8.0 // indirect ) require ( - cloud.google.com/go/compute/metadata v0.3.0 // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + cloud.google.com/go/compute/metadata v0.5.2 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/containerd/log v0.1.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/fatih/color v1.16.0 // indirect + github.com/fatih/color v1.17.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/frankban/quicktest v1.14.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect @@ -90,10 +91,10 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/google/s2a-go v0.1.7 // indirect + github.com/google/s2a-go v0.1.8 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.2 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect + github.com/googleapis/gax-go/v2 v2.14.0 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect @@ -101,11 +102,11 @@ require ( github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgproto3/v2 v2.3.3 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgtype v1.14.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgtype v1.14.3 // indirect github.com/jackc/pgx/v4 v4.18.3 github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531 // indirect - github.com/klauspost/compress v1.16.5 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -113,30 +114,26 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/patternmatcher v0.5.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect - github.com/moby/sys/user v0.1.0 // indirect + github.com/moby/sys/user v0.2.0 // indirect github.com/oklog/run v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect - github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/rogpeppe/go-internal v1.10.0 // indirect - github.com/sasha-s/go-deadlock v0.2.0 + github.com/sasha-s/go-deadlock v0.3.5 github.com/sirupsen/logrus v1.9.3 // indirect github.com/stretchr/objx v0.5.2 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect go.opentelemetry.io/otel v1.30.0 // indirect go.opentelemetry.io/otel/metric v1.30.0 // indirect go.opentelemetry.io/otel/trace v1.30.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/term v0.24.0 // indirect - golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - google.golang.org/api v0.169.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/term v0.27.0 // indirect + golang.org/x/time v0.8.0 // indirect + google.golang.org/api v0.207.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/sdk/go.sum b/sdk/go.sum index b226fc928814..94410aaaa8b7 100644 --- a/sdk/go.sum +++ b/sdk/go.sum @@ -1,60 +1,34 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/auth v0.10.2 h1:oKF7rgBfSHdp/kuhXtqU/tNDr0mZqhYbEh+6SiqzkKo= +cloud.google.com/go/auth v0.10.2/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= +cloud.google.com/go/auth/oauth2adapt v0.2.5 h1:2p29+dePqsCHPP1bqDJcKj4qxRyYCcbzKpFyKGt3MTk= +cloud.google.com/go/auth/oauth2adapt v0.2.5/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= cloud.google.com/go/cloudsqlconn v1.4.3 h1:/WYFbB1NtMtoMxCbqpzzTFPDkxxlLTPme390KEGaEPc= cloud.google.com/go/cloudsqlconn v1.4.3/go.mod h1:QL3tuStVOO70txb3rs4G8j5uMfo5ztZii8K3oGD3VYA= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= +cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +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/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= -github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= @@ -69,16 +43,12 @@ github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEe github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -99,8 +69,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/docker v27.2.1+incompatible h1:fQdiLfW7VLscyoeYEBz7/J8soYFDZV1u6VW6gJEjNMI= github.com/docker/docker v27.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -110,8 +80,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -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/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -120,33 +90,29 @@ github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzP github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= -github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= +github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= +github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= 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= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= -github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= +github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ= +github.com/go-ldap/ldap/v3 v3.4.8/go.mod h1:qS3Sjlu76eHfHGpUdWkAXQTw4beih+cHsco2jXlIXrk= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= -github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= -github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= +github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -155,80 +121,50 @@ github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2V github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= -github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= +github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= +github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/googleapis/gax-go/v2 v2.14.0 h1:f+jMrjBPl+DL9nI4IQzLUxMq7XrAqFYB7hBPqMNIe8o= +github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= -github.com/hashicorp/cap/ldap v0.0.0-20240328153749-fcfe271d0227 h1:R5CMNyBNZqODw2DcGaSa2X96AgtLotXsH7aOa07zTTI= -github.com/hashicorp/cap/ldap v0.0.0-20240328153749-fcfe271d0227/go.mod h1:Ofp5fMLl1ImcwjNGu9FtEwNOdxA0LYoWpcWQE2vltuI= +github.com/hashicorp/cap/ldap v0.0.0-20240403125925-c0418810d10e h1:IakB/NhT0YtMEGqAf2tViMdBABC2cMAZn3O/mVeg2j4= +github.com/hashicorp/cap/ldap v0.0.0-20240403125925-c0418810d10e/go.mod h1:Ofp5fMLl1ImcwjNGu9FtEwNOdxA0LYoWpcWQE2vltuI= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -242,10 +178,10 @@ github.com/hashicorp/go-hmac-drbg v0.0.0-20210916214228-a6e5a68489f6/go.mod h1:y github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8= -github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.8 h1:9Q2lu1YbbmiAgvYZ7Pr31RdlVonUpX+mmDL7Z7qTA2U= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.8/go.mod h1:qTCjxGig/kjuj3hk1z8pOUrzbse/GxB1tGfbrq8tGJg= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.1 h1:KIge4FHZEDb2/xjaWgmBheCTgRL6HV4sgTfDsH876L8= +github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.1/go.mod h1:aHO1EoFD0kBYLBedqxXgalfFT8lrWfP7kpuSoaqGjH0= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.16/go.mod h1:ZiKZctjRTLEppuRwrttWkp71VYMbTTCkazK4xT7U/NQ= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-plugin v1.6.1 h1:P7MR2UP6gNKGPp+y7EZw2kOiq4IR9WiqLvp0XOsVdwI= @@ -259,8 +195,8 @@ github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 h1:ET4pqyjiGmY09R5y+rSd70J2w github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= github.com/hashicorp/go-secure-stdlib/cryptoutil v0.1.0 h1:4B46+S65WqQUlp0rX2F7TX6/p0HmUZsDD+cVzFTwztw= github.com/hashicorp/go-secure-stdlib/cryptoutil v0.1.0/go.mod h1:hH8rgXHh9fPSDPerG6WzABHsHF+9ZpLhRI1LPk4JZ8c= -github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= -github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.3 h1:kH3Rhiht36xhAfhuHyWJDgdXXEx9IIZhDGRk24CDhzg= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.3/go.mod h1:ov1Q0oEDjC3+A4BwsG2YdKltrmEw8sf9Pau4V9JQ4Vo= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 h1:iBt4Ew4XEGLfh6/bPk4rSYmuZJGizr6/x/AEizP0CQc= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8/go.mod h1:aiJI+PIApBRQG7FZTEBx5GiiX+HbOHilUdNxUZi4eV0= github.com/hashicorp/go-secure-stdlib/password v0.1.1 h1:6JzmBqXprakgFEHwBgdchsjaA9x3GyjdI568bXKxa60= @@ -277,19 +213,19 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= -github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= -github.com/hashicorp/vault/api v1.14.0 h1:Ah3CFLixD5jmjusOgm8grfN9M0d+Y8fVR2SW0K6pJLU= -github.com/hashicorp/vault/api v1.14.0/go.mod h1:pV9YLxBGSz+cItFDd8Ii4G17waWOQ32zVjMWHe/cOqk= +github.com/hashicorp/vault v1.18.3 h1:M5ZIM6N3qAfcmCfcxmBtFRD2KHIO7YdrbnMILMi9lto= +github.com/hashicorp/vault v1.18.3/go.mod h1:pm/2xflI/XldISU4G0qyL8P8wmoJpuXP8FzcXP3Pkcg= +github.com/hashicorp/vault/api v1.15.0 h1:O24FYQCWwhwKnF7CuSqP30S51rTV7vz1iACXE/pj5DA= +github.com/hashicorp/vault/api v1.15.0/go.mod h1:+5YTO09JGn0u+b6ySD/LLVf8WkJCPLAL2Vkmrn2+CM8= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -320,23 +256,39 @@ github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwX github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.14.3 h1:h6W9cPuHsRWQFTWUZMAKMgG5jSwQI0Zurzdvlx3Plus= +github.com/jackc/pgtype v1.14.3/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= +github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= @@ -346,26 +298,17 @@ github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531 h1:hgVxRoDDPtQE68PT4 github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531/go.mod h1:fqTUQpVYBvhCNIsMXGl2GE9q6z94DIP6NtFKXCSTVbg= github.com/joshlf/testutil v0.0.0-20170608050642-b5d8aa79d93d h1:J8tJzRyiddAFF65YVgxli+TyWBi0f79Sld6rJP6CBcY= github.com/joshlf/testutil v0.0.0-20170608050642-b5d8aa79d93d/go.mod h1:b+Q3v8Yrg5o15d71PSUraUzYb+jWl6wQMSBXSGS/hv0= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= -github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -393,8 +336,6 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ 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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microsoft/go-mssqldb v1.5.0 h1:CgENxkwtOBNj3Jg6T1X209y2blCfTTcwuOlznd2k9fk= github.com/microsoft/go-mssqldb v1.5.0/go.mod h1:lmWsjHD8XX/Txr0f8ZqgbEZSC+BZjmEQy/Ms+rLrvho= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= @@ -413,8 +354,8 @@ github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= -github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= -github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= +github.com/moby/sys/user v0.2.0 h1:OnpapJsRp25vkhw8TFG6OLJODNh/3rEwRWtJ3kakwRM= +github.com/moby/sys/user v0.2.0/go.mod h1:RYstrcWOJpVh+6qzUqp2bU3eaRpdiQeKGlKitaH0PM8= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= @@ -423,24 +364,23 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8= -github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -451,52 +391,44 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/sasha-s/go-deadlock v0.2.0 h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y= -github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10= +github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= +github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -520,21 +452,14 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8 github.com/tink-crypto/tink-go/v2 v2.2.0 h1:L2Da0F2Udh2agtKztdr69mV/KpnY3/lGTkMgLTVIXlA= github.com/tink-crypto/tink-go/v2 v2.2.0/go.mod h1:JJ6PomeNPF3cJpfWC0lgyTES6zpJILkAX0cJNwlS3xU= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= @@ -553,8 +478,8 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -566,7 +491,6 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -574,155 +498,78 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -730,21 +577,22 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -752,144 +600,52 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY= -google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= +google.golang.org/api v0.207.0 h1:Fvt6IGCYjf7YLcQ+GCegeAI2QSQCfIWhRkmrMPj3JRM= +google.golang.org/api v0.207.0/go.mod h1:I53S168Yr/PNDNMi5yPnDc0/LGRZO6o7PoEbl/HY3CM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 h1:g/4bk7P6TPMkAUbUhquq98xey1slwvuVJPosdBqYJlU= -google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU= -google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto v0.0.0-20241113202542-65e8d215514f h1:zDoHYmMzMacIdjNe+P2XiTmPsLawi/pCbSPfxt6lTfw= +google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 h1:M0KvPgPmDZHPlbRbaNU1APr28TvwvvdUPlSv7PUvy8g= +google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:dguCy7UOdZhTvLzDyt15+rOrawrpM4q7DD9dQ1P11P4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f h1:C1QccEa9kUwvMgEUORqQD9S17QesQijxjZ84sO82mfo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM= -google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= +google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -898,12 +654,9 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -916,20 +669,11 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/sdk/helper/automatedrotationutil/fields.go b/sdk/helper/automatedrotationutil/fields.go new file mode 100644 index 000000000000..938aef94d79c --- /dev/null +++ b/sdk/helper/automatedrotationutil/fields.go @@ -0,0 +1,115 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package automatedrotationutil + +import ( + "errors" + "fmt" + + "github.com/hashicorp/vault/sdk/framework" +) + +var ( + ErrRotationMutuallyExclusiveFields = errors.New("mutually exclusive fields rotation_schedule and rotation_period were both specified; only one of them can be provided") + ErrRotationManagerUnsupported = errors.New("rotation manager capabilities not supported in Vault community edition") +) + +// AutomatedRotationParams contains a set of common parameters that plugins +// can use for setting automated credential rotation. +type AutomatedRotationParams struct { + // RotationSchedule is the CRON-style rotation schedule. + RotationSchedule string `json:"rotation_schedule"` + // RotationWindow specifies the amount of time in which the rotation is allowed to + // occur starting from a given rotation_schedule. + RotationWindow int `json:"rotation_window"` + // RotationPeriod is an alternate choice for simple time-to-live based rotation timing. + RotationPeriod int `json:"rotation_period"` + + // RotationID is the unique ID of the registered rotation job. + // Used by the plugin to track the rotation. + RotationID string `json:"rotation_id"` + + // If set, will deregister all registered rotation jobs from the RotationManager for plugin. + DisableAutomatedRotation bool `json:"disable_automated_rotation"` +} + +// ParseAutomatedRotationFields provides common field parsing to embedding structs. +func (p *AutomatedRotationParams) ParseAutomatedRotationFields(d *framework.FieldData) error { + rotationScheduleRaw, scheduleOk := d.GetOk("rotation_schedule") + rotationWindowRaw, windowOk := d.GetOk("rotation_window") + rotationPeriodRaw, periodOk := d.GetOk("rotation_period") + + if scheduleOk { + if periodOk { + return ErrRotationMutuallyExclusiveFields + } + p.RotationSchedule = rotationScheduleRaw.(string) + } + + if windowOk { + if periodOk { + return fmt.Errorf("rotation_window does not apply to period") + } + p.RotationWindow = rotationWindowRaw.(int) + } + + if periodOk { + p.RotationPeriod = rotationPeriodRaw.(int) + } + + if (scheduleOk && !windowOk) || (windowOk && !scheduleOk) { + return fmt.Errorf("must include both schedule and window") + } + + p.DisableAutomatedRotation = d.Get("disable_automated_rotation").(bool) + + return nil +} + +// PopulateAutomatedRotationData adds PluginIdentityTokenParams info into the given map. +func (p *AutomatedRotationParams) PopulateAutomatedRotationData(m map[string]interface{}) { + m["rotation_schedule"] = p.RotationSchedule + m["rotation_window"] = p.RotationWindow + m["rotation_period"] = p.RotationPeriod + m["rotation_id"] = p.RotationID + m["disable_automated_rotation"] = p.DisableAutomatedRotation +} + +func (p *AutomatedRotationParams) ShouldRegisterRotationJob() bool { + return p.RotationSchedule != "" || p.RotationPeriod != 0 +} + +// AddAutomatedRotationFields adds plugin identity token fields to the given +// field schema map. +func AddAutomatedRotationFields(m map[string]*framework.FieldSchema) { + fields := map[string]*framework.FieldSchema{ + "rotation_schedule": { + Type: framework.TypeString, + Description: "CRON-style string that will define the schedule on which rotations should occur. Mutually exclusive with rotation_period", + }, + "rotation_window": { + Type: framework.TypeInt, + Description: "Specifies the amount of time in which the rotation is allowed to occur starting from a given rotation_schedule", + }, + "rotation_period": { + Type: framework.TypeInt, + Description: "TTL for automatic credential rotation of the given username. Mutually exclusive with rotation_schedule", + }, + "rotation_id": { + Type: framework.TypeInt, + Description: "Unique ID of the registered rotation job", + }, + "disable_automated_rotation": { + Type: framework.TypeBool, + Description: "If set to true, will deregister all registered rotation jobs from the RotationManager for the plugin.", + }, + } + + for name, schema := range fields { + if _, ok := m[name]; ok { + panic(fmt.Sprintf("adding field %q would overwrite existing field", name)) + } + m[name] = schema + } +} diff --git a/sdk/helper/clientcountutil/clientcountutil.go b/sdk/helper/clientcountutil/clientcountutil.go index 85b25dab4348..7d0be5526e1b 100644 --- a/sdk/helper/clientcountutil/clientcountutil.go +++ b/sdk/helper/clientcountutil/clientcountutil.go @@ -280,46 +280,35 @@ func (d *ActivityLogDataGenerator) ToProto() *generation.ActivityLogMockInput { } // Write writes the data to the API with the given write options. The method -// returns the new local and global paths that have been written. Note that the API endpoint will +// returns the new paths that have been written. Note that the API endpoint will // only be present when Vault has been compiled with the "testonly" flag. -func (d *ActivityLogDataGenerator) Write(ctx context.Context, writeOptions ...generation.WriteOptions) ([]string, []string, error) { +func (d *ActivityLogDataGenerator) Write(ctx context.Context, writeOptions ...generation.WriteOptions) ([]string, error) { d.data.Write = writeOptions err := VerifyInput(d.data) if err != nil { - return nil, nil, err + return nil, err } data, err := d.ToJSON() if err != nil { - return nil, nil, err + return nil, err } resp, err := d.client.Logical().WriteWithContext(ctx, "sys/internal/counters/activity/write", map[string]interface{}{"input": string(data)}) if err != nil { - return nil, nil, err + return nil, err } if resp.Data == nil { - return nil, nil, fmt.Errorf("received no data") + return nil, fmt.Errorf("received no data") } - - localPaths := resp.Data["local_paths"] - localCastedPaths, ok := localPaths.([]interface{}) - if !ok { - return nil, nil, fmt.Errorf("invalid local paths data: %v", localPaths) - } - returnLocalPaths := make([]string, 0, len(localCastedPaths)) - for _, path := range localCastedPaths { - returnLocalPaths = append(returnLocalPaths, path.(string)) - } - - globalPaths := resp.Data["global_paths"] - globalCastedPaths, ok := globalPaths.([]interface{}) + paths := resp.Data["paths"] + castedPaths, ok := paths.([]interface{}) if !ok { - return nil, nil, fmt.Errorf("invalid global paths data: %v", globalPaths) + return nil, fmt.Errorf("invalid paths data: %v", paths) } - returnGlobalPaths := make([]string, 0, len(globalCastedPaths)) - for _, path := range globalCastedPaths { - returnGlobalPaths = append(returnGlobalPaths, path.(string)) + returnPaths := make([]string, 0, len(castedPaths)) + for _, path := range castedPaths { + returnPaths = append(returnPaths, path.(string)) } - return returnLocalPaths, returnGlobalPaths, nil + return returnPaths, nil } // VerifyInput checks that the input data is valid diff --git a/sdk/helper/clientcountutil/clientcountutil_test.go b/sdk/helper/clientcountutil/clientcountutil_test.go index 637407436503..6a5b224bc675 100644 --- a/sdk/helper/clientcountutil/clientcountutil_test.go +++ b/sdk/helper/clientcountutil/clientcountutil_test.go @@ -116,7 +116,7 @@ func TestNewCurrentMonthData_AddClients(t *testing.T) { // sent to the server is correct. func TestWrite(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := io.WriteString(w, `{"data":{"global_paths":["path2","path3"], "local_paths":["path3","path4"]}}`) + _, err := io.WriteString(w, `{"data":{"paths":["path1","path2"]}}`) require.NoError(t, err) body, err := io.ReadAll(r.Body) require.NoError(t, err) @@ -131,7 +131,7 @@ func TestWrite(t *testing.T) { Address: ts.URL, }) require.NoError(t, err) - localPaths, globalPaths, err := NewActivityLogData(client). + paths, err := NewActivityLogData(client). NewPreviousMonthData(3). NewClientSeen(). NewPreviousMonthData(2). @@ -140,8 +140,7 @@ func TestWrite(t *testing.T) { NewCurrentMonthData().Write(context.Background(), generation.WriteOptions_WRITE_ENTITIES) require.NoError(t, err) - require.Equal(t, []string{"path2", "path3"}, globalPaths) - require.Equal(t, []string{"path3", "path4"}, localPaths) + require.Equal(t, []string{"path1", "path2"}, paths) } func testAddClients(t *testing.T, makeGenerator func() *ActivityLogDataGenerator, getClient func(data *ActivityLogDataGenerator) *generation.Client) { diff --git a/sdk/helper/clientcountutil/generation/generate_data.pb.go b/sdk/helper/clientcountutil/generation/generate_data.pb.go index 02f621b173d6..13062203a82d 100644 --- a/sdk/helper/clientcountutil/generation/generate_data.pb.go +++ b/sdk/helper/clientcountutil/generation/generate_data.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: sdk/helper/clientcountutil/generation/generate_data.proto @@ -82,12 +82,11 @@ func (WriteOptions) EnumDescriptor() ([]byte, []int) { } type ActivityLogMockInput struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Write []WriteOptions `protobuf:"varint,1,rep,packed,name=write,proto3,enum=generation.WriteOptions" json:"write,omitempty"` + Data []*Data `protobuf:"bytes,2,rep,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields - - Write []WriteOptions `protobuf:"varint,1,rep,packed,name=write,proto3,enum=generation.WriteOptions" json:"write,omitempty"` - Data []*Data `protobuf:"bytes,2,rep,name=data,proto3" json:"data,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ActivityLogMockInput) Reset() { @@ -135,16 +134,13 @@ func (x *ActivityLogMockInput) GetData() []*Data { } type Data struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Month: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Month: // // *Data_CurrentMonth // *Data_MonthsAgo Month isData_Month `protobuf_oneof:"month"` - // Types that are assignable to Clients: + // Types that are valid to be assigned to Clients: // // *Data_All // *Data_Segments @@ -152,6 +148,8 @@ type Data struct { EmptySegmentIndexes []int32 `protobuf:"varint,5,rep,packed,name=empty_segment_indexes,json=emptySegmentIndexes,proto3" json:"empty_segment_indexes,omitempty"` SkipSegmentIndexes []int32 `protobuf:"varint,6,rep,packed,name=skip_segment_indexes,json=skipSegmentIndexes,proto3" json:"skip_segment_indexes,omitempty"` NumSegments int32 `protobuf:"varint,7,opt,name=num_segments,json=numSegments,proto3" json:"num_segments,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Data) Reset() { @@ -184,44 +182,52 @@ func (*Data) Descriptor() ([]byte, []int) { return file_sdk_helper_clientcountutil_generation_generate_data_proto_rawDescGZIP(), []int{1} } -func (m *Data) GetMonth() isData_Month { - if m != nil { - return m.Month +func (x *Data) GetMonth() isData_Month { + if x != nil { + return x.Month } return nil } func (x *Data) GetCurrentMonth() bool { - if x, ok := x.GetMonth().(*Data_CurrentMonth); ok { - return x.CurrentMonth + if x != nil { + if x, ok := x.Month.(*Data_CurrentMonth); ok { + return x.CurrentMonth + } } return false } func (x *Data) GetMonthsAgo() int32 { - if x, ok := x.GetMonth().(*Data_MonthsAgo); ok { - return x.MonthsAgo + if x != nil { + if x, ok := x.Month.(*Data_MonthsAgo); ok { + return x.MonthsAgo + } } return 0 } -func (m *Data) GetClients() isData_Clients { - if m != nil { - return m.Clients +func (x *Data) GetClients() isData_Clients { + if x != nil { + return x.Clients } return nil } func (x *Data) GetAll() *Clients { - if x, ok := x.GetClients().(*Data_All); ok { - return x.All + if x != nil { + if x, ok := x.Clients.(*Data_All); ok { + return x.All + } } return nil } func (x *Data) GetSegments() *Segments { - if x, ok := x.GetClients().(*Data_Segments); ok { - return x.Segments + if x != nil { + if x, ok := x.Clients.(*Data_Segments); ok { + return x.Segments + } } return nil } @@ -280,11 +286,10 @@ func (*Data_All) isData_Clients() {} func (*Data_Segments) isData_Clients() {} type Segments struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Segments []*Segment `protobuf:"bytes,1,rep,name=segments,proto3" json:"segments,omitempty"` unknownFields protoimpl.UnknownFields - - Segments []*Segment `protobuf:"bytes,1,rep,name=segments,proto3" json:"segments,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Segments) Reset() { @@ -325,12 +330,11 @@ func (x *Segments) GetSegments() []*Segment { } type Segment struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + SegmentIndex *int32 `protobuf:"varint,1,opt,name=segment_index,json=segmentIndex,proto3,oneof" json:"segment_index,omitempty"` + Clients *Clients `protobuf:"bytes,2,opt,name=clients,proto3" json:"clients,omitempty"` unknownFields protoimpl.UnknownFields - - SegmentIndex *int32 `protobuf:"varint,1,opt,name=segment_index,json=segmentIndex,proto3,oneof" json:"segment_index,omitempty"` - Clients *Clients `protobuf:"bytes,2,opt,name=clients,proto3" json:"clients,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Segment) Reset() { @@ -378,11 +382,10 @@ func (x *Segment) GetClients() *Clients { } type Clients struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Clients []*Client `protobuf:"bytes,1,rep,name=clients,proto3" json:"clients,omitempty"` unknownFields protoimpl.UnknownFields - - Clients []*Client `protobuf:"bytes,1,rep,name=clients,proto3" json:"clients,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Clients) Reset() { @@ -423,17 +426,16 @@ func (x *Clients) GetClients() []*Client { } type Client struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Count int32 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"` - Repeated bool `protobuf:"varint,3,opt,name=repeated,proto3" json:"repeated,omitempty"` - RepeatedFromMonth int32 `protobuf:"varint,4,opt,name=repeated_from_month,json=repeatedFromMonth,proto3" json:"repeated_from_month,omitempty"` - Namespace string `protobuf:"bytes,5,opt,name=namespace,proto3" json:"namespace,omitempty"` - Mount string `protobuf:"bytes,6,opt,name=mount,proto3" json:"mount,omitempty"` - ClientType string `protobuf:"bytes,7,opt,name=client_type,json=clientType,proto3" json:"client_type,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Count int32 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"` + Repeated bool `protobuf:"varint,3,opt,name=repeated,proto3" json:"repeated,omitempty"` + RepeatedFromMonth int32 `protobuf:"varint,4,opt,name=repeated_from_month,json=repeatedFromMonth,proto3" json:"repeated_from_month,omitempty"` + Namespace string `protobuf:"bytes,5,opt,name=namespace,proto3" json:"namespace,omitempty"` + Mount string `protobuf:"bytes,6,opt,name=mount,proto3" json:"mount,omitempty"` + ClientType string `protobuf:"bytes,7,opt,name=client_type,json=clientType,proto3" json:"client_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Client) Reset() { diff --git a/sdk/helper/keysutil/policy.go b/sdk/helper/keysutil/policy.go index 534827acdd88..f712322083d3 100644 --- a/sdk/helper/keysutil/policy.go +++ b/sdk/helper/keysutil/policy.go @@ -323,19 +323,19 @@ type KeyEntry struct { // Time of creation CreationTime time.Time `json:"time"` - EC_X *big.Int `json:"ec_x"` - EC_Y *big.Int `json:"ec_y"` - EC_D *big.Int `json:"ec_d"` + EC_X *big.Int `json:"ec_x,omitempty"` + EC_Y *big.Int `json:"ec_y,omitempty"` + EC_D *big.Int `json:"ec_d,omitempty"` - RSAKey *rsa.PrivateKey `json:"rsa_key"` - RSAPublicKey *rsa.PublicKey `json:"rsa_public_key"` + RSAKey *rsa.PrivateKey `json:"rsa_key,omitempty"` + RSAPublicKey *rsa.PublicKey `json:"rsa_public_key,omitempty"` // The public key in an appropriate format for the type of key - FormattedPublicKey string `json:"public_key"` + FormattedPublicKey string `json:"public_key,omitempty"` // If convergent is enabled, the version (falling back to what's in the // policy) - ConvergentVersion int `json:"convergent_version"` + ConvergentVersion int `json:"convergent_version,omitempty"` // This is deprecated (but still filled) in favor of the value above which // is more precise @@ -345,7 +345,7 @@ type KeyEntry struct { // Key entry certificate chain. If set, leaf certificate key matches the // KeyEntry key - CertificateChain [][]byte `json:"certificate_chain"` + CertificateChain [][]byte `json:"certificate_chain,omitempty"` } func (ke *KeyEntry) IsPrivateKeyMissing() bool { @@ -977,7 +977,6 @@ func (p *Policy) DeriveKey(context, salt []byte, ver int, numBytes int) ([]byte, return nil, errutil.InternalError{Err: fmt.Sprintf("error generating derived key: %v", err)} } return pri, nil - default: return nil, errutil.InternalError{Err: "unsupported key type for derivation"} } @@ -1274,30 +1273,10 @@ func (p *Policy) SignWithOptions(ver int, context, input []byte, options *Signin case KeyType_ECDSA_P256, KeyType_ECDSA_P384, KeyType_ECDSA_P521: sig, err = signWithECDSA(p.Type, keyParams, input, marshaling) case KeyType_ED25519: - var key ed25519.PrivateKey - - if p.Derived { - // Derive the key that should be used - var err error - key, err = p.GetKey(context, ver, 32) - if err != nil { - return nil, errutil.InternalError{Err: fmt.Sprintf("error deriving key: %v", err)} - } - pubKey = key.Public().(ed25519.PublicKey) - } else { - key = ed25519.PrivateKey(keyParams.Key) - } - - opts, err := genEd25519Options(hashAlgorithm, options.SigContext) - if err != nil { - return nil, errutil.UserError{Err: fmt.Sprintf("error generating Ed25519 options: %v", err)} - } - - sig, err = key.Sign(rand.Reader, input, opts) + sig, pubKey, err = p.signWithEd25519(ver, input, context, options, keyParams) if err != nil { return nil, err } - case KeyType_RSA2048, KeyType_RSA3072, KeyType_RSA4096: key := keyParams.RSAKey @@ -1328,7 +1307,7 @@ func (p *Policy) SignWithOptions(ver int, context, input []byte, options *Signin return nil, errutil.InternalError{Err: fmt.Sprintf("unsupported rsa signature algorithm %s", sigAlgorithm)} } default: - sig, err = entSignWithOptions(p, input, ver, options) + sig, err = entSignWithOptions(p, input, context, ver, hashAlgorithm, options) } // Convert to base64 @@ -1347,6 +1326,33 @@ func (p *Policy) SignWithOptions(ver int, context, input []byte, options *Signin return res, nil } +func (p *Policy) signWithEd25519(ver int, input []byte, context []byte, options *SigningOptions, keyParams KeyEntry) ([]byte, []byte, error) { + var key ed25519.PrivateKey + var pubKey []byte + if p.Derived { + // Derive the key that should be used + var err error + key, err = p.GetKey(context, ver, 32) + if err != nil { + return nil, nil, errutil.InternalError{Err: fmt.Sprintf("error deriving key: %v", err)} + } + pubKey = key.Public().(ed25519.PublicKey) + } else { + key = ed25519.PrivateKey(keyParams.Key) + } + + opts, err := genEd25519Options(options.HashAlgorithm, options.SigContext) + if err != nil { + return nil, nil, errutil.UserError{Err: fmt.Sprintf("error generating Ed25519 options: %v", err)} + } + + sig, err := key.Sign(rand.Reader, input, opts) + if err != nil { + return nil, nil, err + } + return sig, pubKey, nil +} + func signWithECDSA(keyType KeyType, keyParams KeyEntry, input []byte, marshaling MarshalingType) ([]byte, error) { var curveBits int var curve elliptic.Curve @@ -1484,42 +1490,8 @@ func (p *Policy) VerifySignatureWithOptions(context, input []byte, sig string, o return false, err } return verifyWithECDSA(p.Type, key, input, sigBytes, marshaling) - case KeyType_ED25519: - var pub ed25519.PublicKey - - if p.Derived { - // Derive the key that should be used - key, err := p.GetKey(context, ver, 32) - if err != nil { - return false, errutil.InternalError{Err: fmt.Sprintf("error deriving key: %v", err)} - } - pub = ed25519.PrivateKey(key).Public().(ed25519.PublicKey) - } else { - keyEntry, err := p.safeGetKeyEntry(ver) - if err != nil { - return false, err - } - - raw, err := base64.StdEncoding.DecodeString(keyEntry.FormattedPublicKey) - if err != nil { - return false, err - } - - pub = ed25519.PublicKey(raw) - } - - opts, err := genEd25519Options(hashAlgorithm, options.SigContext) - if err != nil { - return false, errutil.UserError{Err: fmt.Sprintf("error generating Ed25519 options: %v", err)} - } - if err := stdlibEd25519.VerifyWithOptions(pub, input, sigBytes, opts); err != nil { - // We drop the error, just report back that we failed signature verification - return false, nil - } - - return true, nil - + return p.verifyEd25519WithOptions(ver, input, context, options, sigBytes) case KeyType_RSA2048, KeyType_RSA3072, KeyType_RSA4096: keyEntry, err := p.safeGetKeyEntry(ver) if err != nil { @@ -1558,7 +1530,7 @@ func (p *Policy) VerifySignatureWithOptions(context, input []byte, sig string, o return err == nil, nil default: - return entVerifySignatureWithOptions(p, input, sigBytes, ver, options) + return entVerifySignatureWithOptions(p, input, context, sigBytes, ver, options) } } @@ -1606,6 +1578,48 @@ func verifyWithECDSA(keyType KeyType, keyParams KeyEntry, input, sigBytes []byte return ecdsa.Verify(key, input, ecdsaSig.R, ecdsaSig.S), nil } +func (p *Policy) verifyEd25519WithOptions(ver int, input []byte, context []byte, options *SigningOptions, sigBytes []byte) (bool, error) { + var pub ed25519.PublicKey + if p.Derived { + // Derive the key that should be used + key, err := p.GetKey(context, ver, 32) + if err != nil { + return false, errutil.InternalError{Err: fmt.Sprintf("error deriving key: %v", err)} + } + pub = ed25519.PrivateKey(key).Public().(ed25519.PublicKey) + } else { + keyEntry, err := p.safeGetKeyEntry(ver) + if err != nil { + return false, err + } + + raw, err := base64.StdEncoding.DecodeString(keyEntry.FormattedPublicKey) + if err != nil { + return false, err + } + + pub = ed25519.PublicKey(raw) + } + + return p.verifyEd25519WithPublicKey(input, sigBytes, pub, options) +} + +func (p *Policy) verifyEd25519WithPublicKey(input []byte, sigBytes []byte, pub ed25519.PublicKey, options *SigningOptions) (bool, error) { + opts, err := genEd25519Options(options.HashAlgorithm, options.SigContext) + if err != nil { + return false, errutil.UserError{Err: fmt.Sprintf("error generating Ed25519 options: %v", err)} + } + if pub == nil { + return false, errutil.InternalError{Err: "no Ed25519 public key on policy"} + } + if err := stdlibEd25519.VerifyWithOptions(pub, input, sigBytes, opts); err != nil { + // We drop the error, just report back that we failed signature verification + return false, nil + } + + return true, nil +} + func (p *Policy) Import(ctx context.Context, storage logical.Storage, key []byte, randReader io.Reader) error { return p.ImportPublicOrPrivate(ctx, storage, key, true, randReader) } @@ -1797,19 +1811,10 @@ func (p *Policy) RotateInMemory(randReader io.Reader) (retErr error) { } case KeyType_ED25519: - // Go uses a 64-byte private key for Ed25519 keys (private+public, each - // 32-bytes long). When we do Key derivation, we still generate a 32-byte - // random value (and compute the corresponding Ed25519 public key), but - // use this entire 64-byte key as if it was an HKDF key. The corresponding - // underlying public key is never returned (which is probably good, because - // doing so would leak half of our HKDF key...), but means we cannot import - // derived-enabled Ed25519 public key components. - pub, pri, err := ed25519.GenerateKey(randReader) + err := generateEd25519Key(randReader, &entry.Key, &entry.FormattedPublicKey) if err != nil { return err } - entry.Key = pri - entry.FormattedPublicKey = base64.StdEncoding.EncodeToString(pub) case KeyType_RSA2048, KeyType_RSA3072, KeyType_RSA4096: bitSize := 2048 if p.Type == KeyType_RSA3072 { @@ -1858,6 +1863,23 @@ func (p *Policy) RotateInMemory(randReader io.Reader) (retErr error) { return nil } +func generateEd25519Key(randReader io.Reader, private *[]byte, public *string) error { + // Go uses a 64-byte private key for Ed25519 keys (private+public, each + // 32-bytes long). When we do Key derivation, we still generate a 32-byte + // random value (and compute the corresponding Ed25519 public key), but + // use this entire 64-byte key as if it was an HKDF key. The corresponding + // underlying public key is never returned (which is probably good, because + // doing so would leak half of our HKDF key...), but means we cannot import + // derived-enabled Ed25519 public key components. + pub, pri, err := ed25519.GenerateKey(randReader) + if err != nil { + return err + } + *private = pri + *public = base64.StdEncoding.EncodeToString(pub) + return nil +} + func (p *Policy) MigrateKeyToKeysMap() { now := time.Now() p.Keys = keyEntryMap{ diff --git a/sdk/helper/keysutil/policy_ce.go b/sdk/helper/keysutil/policy_ce.go index a78c6e5fb02e..a883f7e8c0ad 100644 --- a/sdk/helper/keysutil/policy_ce.go +++ b/sdk/helper/keysutil/policy_ce.go @@ -18,11 +18,11 @@ func (e entKeyEntry) IsEntPrivateKeyMissing() bool { return true } -func entSignWithOptions(p *Policy, input []byte, ver int, options *SigningOptions) ([]byte, error) { +func entSignWithOptions(p *Policy, input, context []byte, ver int, hashAlgorithm HashType, options *SigningOptions) ([]byte, error) { return nil, fmt.Errorf("unsupported key type %v", p.Type) } -func entVerifySignatureWithOptions(p *Policy, input []byte, sigBytes []byte, ver int, options *SigningOptions) (bool, error) { +func entVerifySignatureWithOptions(p *Policy, input, context []byte, sigBytes []byte, ver int, options *SigningOptions) (bool, error) { return false, errutil.InternalError{Err: fmt.Sprintf("unsupported key type %v", p.Type)} } diff --git a/sdk/helper/keysutil/policy_test.go b/sdk/helper/keysutil/policy_test.go index 7dfeec3ae58d..45c94b11ebaf 100644 --- a/sdk/helper/keysutil/policy_test.go +++ b/sdk/helper/keysutil/policy_test.go @@ -55,7 +55,7 @@ func TestPolicy_KeyTypes(t *testing.T) { } } -func TestPolicy_HmacCmacSuported(t *testing.T) { +func TestPolicy_HmacCmacSupported(t *testing.T) { // Test HMAC supported feature for _, keyType := range allTestKeyTypes { switch keyType { diff --git a/sdk/helper/pluginutil/multiplexing.pb.go b/sdk/helper/pluginutil/multiplexing.pb.go index c6b2fe4942c1..5c96a16a470b 100644 --- a/sdk/helper/pluginutil/multiplexing.pb.go +++ b/sdk/helper/pluginutil/multiplexing.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: sdk/helper/pluginutil/multiplexing.proto @@ -24,9 +24,9 @@ const ( ) type MultiplexingSupportRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MultiplexingSupportRequest) Reset() { @@ -60,11 +60,10 @@ func (*MultiplexingSupportRequest) Descriptor() ([]byte, []int) { } type MultiplexingSupportResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Supported bool `protobuf:"varint,1,opt,name=supported,proto3" json:"supported,omitempty"` unknownFields protoimpl.UnknownFields - - Supported bool `protobuf:"varint,1,opt,name=supported,proto3" json:"supported,omitempty"` + sizeCache protoimpl.SizeCache } func (x *MultiplexingSupportResponse) Reset() { diff --git a/sdk/logical/event.pb.go b/sdk/logical/event.pb.go index 4197adec5fcb..14128d08c9a7 100644 --- a/sdk/logical/event.pb.go +++ b/sdk/logical/event.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: sdk/logical/event.proto @@ -26,10 +26,7 @@ const ( // EventPluginInfo contains data related to the plugin that generated an event. type EventPluginInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The type of plugin this event originated from, i.e., "auth" or "secrets. MountClass string `protobuf:"bytes,1,opt,name=mount_class,json=mountClass,proto3" json:"mount_class,omitempty"` // Unique ID of the mount entry, e.g., "kv_957bb7d8" @@ -41,7 +38,9 @@ type EventPluginInfo struct { // Plugin version of the plugin this event originated from, e.g., "v0.13.3+builtin" PluginVersion string `protobuf:"bytes,5,opt,name=plugin_version,json=pluginVersion,proto3" json:"plugin_version,omitempty"` // Mount version that this event originated from, i.e., if KVv2, then "2". Usually empty. - Version string `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"` + Version string `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *EventPluginInfo) Reset() { @@ -118,10 +117,7 @@ func (x *EventPluginInfo) GetVersion() string { // EventData contains event data in a CloudEvents container. type EventData struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // ID identifies the event. It is required. The combination of // CloudEvents Source (i.e., Vault cluster) + ID must be unique. // Events with the same Source + ID can be assumed to be duplicates @@ -135,7 +131,9 @@ type EventData struct { // Any IDs that the event relates to, i.e., UUIDs, paths. EntityIds []string `protobuf:"bytes,3,rep,name=entity_ids,json=entityIds,proto3" json:"entity_ids,omitempty"` // Human-readable note. - Note string `protobuf:"bytes,4,opt,name=note,proto3" json:"note,omitempty"` + Note string `protobuf:"bytes,4,opt,name=note,proto3" json:"note,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *EventData) Reset() { @@ -199,15 +197,14 @@ func (x *EventData) GetNote() string { // EventReceived is used to consume events and includes additional metadata regarding // the event type and plugin information. type EventReceived struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Event *EventData `protobuf:"bytes,1,opt,name=event,proto3" json:"event,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Event *EventData `protobuf:"bytes,1,opt,name=event,proto3" json:"event,omitempty"` // namespace path - Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` - EventType string `protobuf:"bytes,3,opt,name=event_type,json=eventType,proto3" json:"event_type,omitempty"` - PluginInfo *EventPluginInfo `protobuf:"bytes,4,opt,name=plugin_info,json=pluginInfo,proto3" json:"plugin_info,omitempty"` + Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` + EventType string `protobuf:"bytes,3,opt,name=event_type,json=eventType,proto3" json:"event_type,omitempty"` + PluginInfo *EventPluginInfo `protobuf:"bytes,4,opt,name=plugin_info,json=pluginInfo,proto3" json:"plugin_info,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *EventReceived) Reset() { diff --git a/sdk/logical/identity.pb.go b/sdk/logical/identity.pb.go index bccf313866fa..4e4fec68e1d3 100644 --- a/sdk/logical/identity.pb.go +++ b/sdk/logical/identity.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: sdk/logical/identity.proto @@ -24,10 +24,7 @@ const ( ) type Entity struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // ID is the unique identifier for the entity ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` // Name is the human-friendly unique identifier for the entity @@ -35,12 +32,14 @@ type Entity struct { // Aliases contains thhe alias mappings for the given entity Aliases []*Alias `protobuf:"bytes,3,rep,name=aliases,proto3" json:"aliases,omitempty"` // Metadata represents the custom data tied to this entity - Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // Disabled is true if the entity is disabled. Disabled bool `protobuf:"varint,5,opt,name=disabled,proto3" json:"disabled,omitempty"` // NamespaceID is the identifier of the namespace to which this entity // belongs to. - NamespaceID string `protobuf:"bytes,6,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` + NamespaceID string `protobuf:"bytes,6,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Entity) Reset() { @@ -116,10 +115,7 @@ func (x *Entity) GetNamespaceID() string { } type Alias struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // MountType is the backend mount's type to which this identity belongs MountType string `protobuf:"bytes,1,opt,name=mount_type,json=mountType,proto3" json:"mount_type,omitempty"` // MountAccessor is the identifier of the mount entry to which this @@ -133,18 +129,20 @@ type Alias struct { // a significant performance impact at scale. See the SDK's // "aliasmetadata" package for a helper that eases and standardizes // using this safely. - Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // ID is the unique identifier for the alias ID string `protobuf:"bytes,5,opt,name=ID,proto3" json:"ID,omitempty"` // NamespaceID is the identifier of the namespace to which this alias // belongs. NamespaceID string `protobuf:"bytes,6,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` // Custom Metadata represents the custom data tied to this alias - CustomMetadata map[string]string `protobuf:"bytes,7,rep,name=custom_metadata,json=customMetadata,proto3" json:"custom_metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + CustomMetadata map[string]string `protobuf:"bytes,7,rep,name=custom_metadata,json=customMetadata,proto3" json:"custom_metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // Local indicates if the alias only belongs to the cluster where it was // created. If true, the alias will be stored in a location that are ignored // by the performance replication subsystem. - Local bool `protobuf:"varint,8,opt,name=local,proto3" json:"local,omitempty"` + Local bool `protobuf:"varint,8,opt,name=local,proto3" json:"local,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Alias) Reset() { @@ -234,19 +232,18 @@ func (x *Alias) GetLocal() bool { } type Group struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // ID is the unique identifier for the group ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` // Name is the human-friendly unique identifier for the group Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // Metadata represents the custom data tied to this group - Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // NamespaceID is the identifier of the namespace to which this group // belongs to. - NamespaceID string `protobuf:"bytes,4,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` + NamespaceID string `protobuf:"bytes,4,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Group) Reset() { @@ -308,14 +305,13 @@ func (x *Group) GetNamespaceID() string { } type MFAMethodID struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + UsesPasscode bool `protobuf:"varint,3,opt,name=uses_passcode,json=usesPasscode,proto3" json:"uses_passcode,omitempty"` + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` unknownFields protoimpl.UnknownFields - - Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` - ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` - UsesPasscode bool `protobuf:"varint,3,opt,name=uses_passcode,json=usesPasscode,proto3" json:"uses_passcode,omitempty"` - Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + sizeCache protoimpl.SizeCache } func (x *MFAMethodID) Reset() { @@ -377,11 +373,10 @@ func (x *MFAMethodID) GetName() string { } type MFAConstraintAny struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Any []*MFAMethodID `protobuf:"bytes,1,rep,name=any,proto3" json:"any,omitempty"` unknownFields protoimpl.UnknownFields - - Any []*MFAMethodID `protobuf:"bytes,1,rep,name=any,proto3" json:"any,omitempty"` + sizeCache protoimpl.SizeCache } func (x *MFAConstraintAny) Reset() { @@ -422,12 +417,11 @@ func (x *MFAConstraintAny) GetAny() []*MFAMethodID { } type MFARequirement struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` MFARequestID string `protobuf:"bytes,1,opt,name=mfa_request_id,json=mfaRequestId,proto3" json:"mfa_request_id,omitempty"` - MFAConstraints map[string]*MFAConstraintAny `protobuf:"bytes,2,rep,name=mfa_constraints,json=mfaConstraints,proto3" json:"mfa_constraints,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MFAConstraints map[string]*MFAConstraintAny `protobuf:"bytes,2,rep,name=mfa_constraints,json=mfaConstraints,proto3" json:"mfa_constraints,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MFARequirement) Reset() { diff --git a/sdk/logical/plugin.pb.go b/sdk/logical/plugin.pb.go index 9da3a80e3f7b..641e55425074 100644 --- a/sdk/logical/plugin.pb.go +++ b/sdk/logical/plugin.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: sdk/logical/plugin.proto @@ -25,10 +25,7 @@ const ( ) type PluginEnvironment struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // VaultVersion is the version of the Vault server VaultVersion string `protobuf:"bytes,1,opt,name=vault_version,json=vaultVersion,proto3" json:"vault_version,omitempty"` // VaultVersionPrerelease is the prerelease information of the Vault server @@ -37,6 +34,8 @@ type PluginEnvironment struct { VaultVersionMetadata string `protobuf:"bytes,3,opt,name=vault_version_metadata,json=vaultVersionMetadata,proto3" json:"vault_version_metadata,omitempty"` // VaultBuildDate is the build date of the Vault server VaultBuildDate *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=vault_build_date,json=vaultBuildDate,proto3" json:"vault_build_date,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *PluginEnvironment) Reset() { diff --git a/sdk/logical/request.go b/sdk/logical/request.go index 1c360d4dbc42..bc8e731d3c53 100644 --- a/sdk/logical/request.go +++ b/sdk/logical/request.go @@ -203,6 +203,10 @@ type Request struct { // X-Vault-MFA header MFACreds MFACreds `json:"mfa_creds" structs:"mfa_creds" mapstructure:"mfa_creds" sentinel:""` + // RotationEntryName is internally used by + // the RotationManager to rotate root credentials + RotationEntryName string + // Cached token entry. This avoids another lookup in request handling when // we've already looked it up at http handling time. Note that this token // has not been "used", as in it will not properly take into account use @@ -456,6 +460,7 @@ const ( RevokeOperation Operation = "revoke" RenewOperation = "renew" RollbackOperation = "rollback" + RotationOperation = "rotate" ) type MFACreds map[string][]string diff --git a/sdk/logical/system_view.go b/sdk/logical/system_view.go index cecbc261e14e..4cfb7d8c2492 100644 --- a/sdk/logical/system_view.go +++ b/sdk/logical/system_view.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/vault/sdk/helper/license" "github.com/hashicorp/vault/sdk/helper/pluginutil" "github.com/hashicorp/vault/sdk/helper/wrapping" + "github.com/hashicorp/vault/sdk/rotation" ) // SystemView exposes system configuration information in a safe way @@ -100,6 +101,16 @@ type SystemView interface { // GenerateIdentityToken returns an identity token for the requesting plugin. GenerateIdentityToken(ctx context.Context, req *pluginutil.IdentityTokenRequest) (*pluginutil.IdentityTokenResponse, error) + + // RegisterRotationJob returns a rotation ID after registering a + // rotation job for the requesting plugin. + // NOTE: This method is intended for use only by HashiCorp Vault Enterprise plugins. + RegisterRotationJob(ctx context.Context, job *rotation.RotationJob) (rotationID string, err error) + + // DeregisterRotationJob returns any errors in de-registering a + // credential from the Rotation Manager. + // NOTE: This method is intended for use only by HashiCorp Vault Enterprise plugins. + DeregisterRotationJob(ctx context.Context, rotationID string) error } type PasswordPolicy interface { @@ -285,3 +296,11 @@ func (d StaticSystemView) GenerateIdentityToken(_ context.Context, _ *pluginutil func (d StaticSystemView) APILockShouldBlockRequest() (bool, error) { return d.APILockShouldBlockRequestVal, nil } + +func (d StaticSystemView) RegisterRotationJob(_ context.Context, _ *rotation.RotationJob) (rotationID string, err error) { + return "", errors.New("RegisterRotationJob is not implemented in StaticSystemView") +} + +func (d StaticSystemView) DeregisterRotationJob(_ context.Context, _ string) (err error) { + return errors.New("DeregisterRotationJob is not implemented in StaticSystemView") +} diff --git a/sdk/logical/version.pb.go b/sdk/logical/version.pb.go index 66cd5872124f..7ffdb0e3cae9 100644 --- a/sdk/logical/version.pb.go +++ b/sdk/logical/version.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: sdk/logical/version.proto @@ -24,9 +24,9 @@ const ( ) type Empty struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Empty) Reset() { @@ -61,11 +61,10 @@ func (*Empty) Descriptor() ([]byte, []int) { // VersionReply is the reply for the Version method. type VersionReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + PluginVersion string `protobuf:"bytes,1,opt,name=plugin_version,json=pluginVersion,proto3" json:"plugin_version,omitempty"` unknownFields protoimpl.UnknownFields - - PluginVersion string `protobuf:"bytes,1,opt,name=plugin_version,json=pluginVersion,proto3" json:"plugin_version,omitempty"` + sizeCache protoimpl.SizeCache } func (x *VersionReply) Reset() { diff --git a/sdk/plugin/grpc_system.go b/sdk/plugin/grpc_system.go index d907e60eac6f..7f51b02921b6 100644 --- a/sdk/plugin/grpc_system.go +++ b/sdk/plugin/grpc_system.go @@ -16,9 +16,11 @@ import ( "github.com/hashicorp/vault/sdk/helper/wrapping" "github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/sdk/plugin/pb" + "github.com/hashicorp/vault/sdk/rotation" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/structpb" ) var errMissingSystemView = errors.New("missing system view implementation: this method should not be called during plugin Setup, but only during and after Initialize") @@ -226,6 +228,43 @@ func (s *gRPCSystemViewClient) GenerateIdentityToken(ctx context.Context, req *p }, nil } +func (s *gRPCSystemViewClient) RegisterRotationJob(ctx context.Context, job *rotation.RotationJob) (id string, retErr error) { + scheduleData := map[string]interface{}{ + "schedule": job.Schedule.Schedule, + "rotation_window": job.Schedule.RotationWindow, + "rotation_schedule": job.Schedule.RotationSchedule, + "next_vault_rotation": job.Schedule.NextVaultRotation, + } + m, err := structpb.NewValue(scheduleData) + if err != nil { + return "", err + } + req := &pb.RegisterRotationJobRequest{ + Job: &pb.RotationJobInput{ + Schedule: m.GetStructValue(), + RotationID: job.RotationID, + Path: job.Path, + Name: job.Name, + }, + } + resp, err := s.client.RegisterRotationJob(ctx, req) + if err != nil { + return "", err + } + return resp.RotationID, nil +} + +func (s *gRPCSystemViewClient) DeregisterRotationJob(ctx context.Context, rotationID string) error { + _, err := s.client.DeregisterRotationJob(ctx, &pb.DeregisterRotationJobRequest{ + RotationID: rotationID, + }) + if err != nil { + return err + } + + return nil +} + type gRPCSystemViewServer struct { pb.UnimplementedSystemViewServer diff --git a/sdk/plugin/pb/backend.pb.go b/sdk/plugin/pb/backend.pb.go index 4813700b0d52..0083b4e386d9 100644 --- a/sdk/plugin/pb/backend.pb.go +++ b/sdk/plugin/pb/backend.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: sdk/plugin/pb/backend.proto @@ -13,6 +13,7 @@ import ( logical "github.com/hashicorp/vault/sdk/logical" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + structpb "google.golang.org/protobuf/types/known/structpb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" @@ -26,9 +27,9 @@ const ( ) type Empty struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Empty) Reset() { @@ -62,11 +63,10 @@ func (*Empty) Descriptor() ([]byte, []int) { } type Header struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Header []string `protobuf:"bytes,1,rep,name=header,proto3" json:"header,omitempty"` unknownFields protoimpl.UnknownFields - - Header []string `protobuf:"bytes,1,rep,name=header,proto3" json:"header,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Header) Reset() { @@ -107,10 +107,7 @@ func (x *Header) GetHeader() []string { } type ProtoError struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Error type can be one of: // ErrTypeUnknown uint32 = iota // ErrTypeUserError @@ -123,9 +120,11 @@ type ProtoError struct { // ErrTypePermissionDenied // ErrTypeMultiAuthzPending // ErrTypeUnrecoverable - ErrType uint32 `protobuf:"varint,1,opt,name=err_type,json=errType,proto3" json:"err_type,omitempty"` - ErrMsg string `protobuf:"bytes,2,opt,name=err_msg,json=errMsg,proto3" json:"err_msg,omitempty"` - ErrCode int64 `protobuf:"varint,3,opt,name=err_code,json=errCode,proto3" json:"err_code,omitempty"` + ErrType uint32 `protobuf:"varint,1,opt,name=err_type,json=errType,proto3" json:"err_type,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=err_msg,json=errMsg,proto3" json:"err_msg,omitempty"` + ErrCode int64 `protobuf:"varint,3,opt,name=err_code,json=errCode,proto3" json:"err_code,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ProtoError) Reset() { @@ -181,10 +180,7 @@ func (x *ProtoError) GetErrCode() int64 { // Paths is the structure of special paths that is used for SpecialPaths. type Paths struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Root are the paths that require a root token to access Root []string `protobuf:"bytes,1,rep,name=root,proto3" json:"root,omitempty"` // Unauthenticated are the paths that can be accessed without any auth. @@ -209,7 +205,9 @@ type Paths struct { // Limited paths are storage paths that require special-case request limiting. // // See note in /sdk/logical/logical.go. - Limited []string `protobuf:"bytes,7,rep,name=limited,proto3" json:"limited,omitempty"` + Limited []string `protobuf:"bytes,7,rep,name=limited,proto3" json:"limited,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Paths) Reset() { @@ -292,10 +290,7 @@ func (x *Paths) GetLimited() []string { } type Request struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // ID is the uuid associated with each request ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // If set, the name given to the replication secondary where this request @@ -319,7 +314,7 @@ type Request struct { // Headers will contain the http headers from the request. This value will // be used in the audit broker to ensure we are auditing only the allowed // headers. - Headers map[string]*Header `protobuf:"bytes,8,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Headers map[string]*Header `protobuf:"bytes,8,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // ClientToken is provided to the core so that the identity // can be verified and ACLs applied. This value is passed // through to the logical backends but after being salted and @@ -361,7 +356,9 @@ type Request struct { // Connection will be non-nil only for credential providers to // inspect the connection information and potentially use it for // authentication/protection. - Connection *Connection `protobuf:"bytes,20,opt,name=connection,proto3" json:"connection,omitempty"` + Connection *Connection `protobuf:"bytes,20,opt,name=connection,proto3" json:"connection,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Request) Reset() { @@ -535,11 +532,8 @@ func (x *Request) GetConnection() *Connection { } type Auth struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - LeaseOptions *LeaseOptions `protobuf:"bytes,1,opt,name=lease_options,json=leaseOptions,proto3" json:"lease_options,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + LeaseOptions *LeaseOptions `protobuf:"bytes,1,opt,name=lease_options,json=leaseOptions,proto3" json:"lease_options,omitempty"` // InternalData is a JSON object that is stored with the auth struct. // This will be sent back during a Renew/Revoke for storing internal data // used for those operations. @@ -557,7 +551,7 @@ type Auth struct { // Metadata is used to attach arbitrary string-type metadata to // an authenticated user. This metadata will be outputted into the // audit log. - Metadata map[string]string `protobuf:"bytes,5,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Metadata map[string]string `protobuf:"bytes,5,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // ClientToken is the token that is generated for the authentication. // This will be filled in by Vault core when an auth structure is // returned. Setting this manually will have no effect. @@ -599,6 +593,8 @@ type Auth struct { TokenType uint32 `protobuf:"varint,17,opt,name=token_type,json=tokenType,proto3" json:"token_type,omitempty"` // Whether the default policy should be added automatically by core NoDefaultPolicy bool `protobuf:"varint,18,opt,name=no_default_policy,json=noDefaultPolicy,proto3" json:"no_default_policy,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Auth) Reset() { @@ -758,32 +754,31 @@ func (x *Auth) GetNoDefaultPolicy() bool { } type TokenEntry struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Accessor string `protobuf:"bytes,2,opt,name=accessor,proto3" json:"accessor,omitempty"` - Parent string `protobuf:"bytes,3,opt,name=parent,proto3" json:"parent,omitempty"` - Policies []string `protobuf:"bytes,4,rep,name=policies,proto3" json:"policies,omitempty"` - Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"` - Meta map[string]string `protobuf:"bytes,6,rep,name=meta,proto3" json:"meta,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - DisplayName string `protobuf:"bytes,7,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` - NumUses int64 `protobuf:"varint,8,opt,name=num_uses,json=numUses,proto3" json:"num_uses,omitempty"` - CreationTime int64 `protobuf:"varint,9,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` - TTL int64 `protobuf:"varint,10,opt,name=ttl,proto3" json:"ttl,omitempty"` - ExplicitMaxTTL int64 `protobuf:"varint,11,opt,name=explicit_max_ttl,json=explicitMaxTtl,proto3" json:"explicit_max_ttl,omitempty"` - Role string `protobuf:"bytes,12,opt,name=role,proto3" json:"role,omitempty"` - Period int64 `protobuf:"varint,13,opt,name=period,proto3" json:"period,omitempty"` - EntityID string `protobuf:"bytes,14,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` - BoundCIDRs []string `protobuf:"bytes,15,rep,name=bound_cidrs,json=boundCidrs,proto3" json:"bound_cidrs,omitempty"` - NamespaceID string `protobuf:"bytes,16,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` - CubbyholeID string `protobuf:"bytes,17,opt,name=cubbyhole_id,json=cubbyholeId,proto3" json:"cubbyhole_id,omitempty"` - Type uint32 `protobuf:"varint,18,opt,name=type,proto3" json:"type,omitempty"` - InternalMeta map[string]string `protobuf:"bytes,19,rep,name=internal_meta,json=internalMeta,proto3" json:"internal_meta,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - InlinePolicy string `protobuf:"bytes,20,opt,name=inline_policy,json=inlinePolicy,proto3" json:"inline_policy,omitempty"` - NoIdentityPolicies bool `protobuf:"varint,21,opt,name=no_identity_policies,json=noIdentityPolicies,proto3" json:"no_identity_policies,omitempty"` - ExternalID string `protobuf:"bytes,22,opt,name=external_id,json=externalId,proto3" json:"external_id,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Accessor string `protobuf:"bytes,2,opt,name=accessor,proto3" json:"accessor,omitempty"` + Parent string `protobuf:"bytes,3,opt,name=parent,proto3" json:"parent,omitempty"` + Policies []string `protobuf:"bytes,4,rep,name=policies,proto3" json:"policies,omitempty"` + Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"` + Meta map[string]string `protobuf:"bytes,6,rep,name=meta,proto3" json:"meta,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + DisplayName string `protobuf:"bytes,7,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + NumUses int64 `protobuf:"varint,8,opt,name=num_uses,json=numUses,proto3" json:"num_uses,omitempty"` + CreationTime int64 `protobuf:"varint,9,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` + TTL int64 `protobuf:"varint,10,opt,name=ttl,proto3" json:"ttl,omitempty"` + ExplicitMaxTTL int64 `protobuf:"varint,11,opt,name=explicit_max_ttl,json=explicitMaxTtl,proto3" json:"explicit_max_ttl,omitempty"` + Role string `protobuf:"bytes,12,opt,name=role,proto3" json:"role,omitempty"` + Period int64 `protobuf:"varint,13,opt,name=period,proto3" json:"period,omitempty"` + EntityID string `protobuf:"bytes,14,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` + BoundCIDRs []string `protobuf:"bytes,15,rep,name=bound_cidrs,json=boundCidrs,proto3" json:"bound_cidrs,omitempty"` + NamespaceID string `protobuf:"bytes,16,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` + CubbyholeID string `protobuf:"bytes,17,opt,name=cubbyhole_id,json=cubbyholeId,proto3" json:"cubbyhole_id,omitempty"` + Type uint32 `protobuf:"varint,18,opt,name=type,proto3" json:"type,omitempty"` + InternalMeta map[string]string `protobuf:"bytes,19,rep,name=internal_meta,json=internalMeta,proto3" json:"internal_meta,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + InlinePolicy string `protobuf:"bytes,20,opt,name=inline_policy,json=inlinePolicy,proto3" json:"inline_policy,omitempty"` + NoIdentityPolicies bool `protobuf:"varint,21,opt,name=no_identity_policies,json=noIdentityPolicies,proto3" json:"no_identity_policies,omitempty"` + ExternalID string `protobuf:"bytes,22,opt,name=external_id,json=externalId,proto3" json:"external_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *TokenEntry) Reset() { @@ -971,15 +966,14 @@ func (x *TokenEntry) GetExternalID() string { } type LeaseOptions struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + TTL int64 `protobuf:"varint,1,opt,name=TTL,proto3" json:"TTL,omitempty"` + Renewable bool `protobuf:"varint,2,opt,name=renewable,proto3" json:"renewable,omitempty"` + Increment int64 `protobuf:"varint,3,opt,name=increment,proto3" json:"increment,omitempty"` + IssueTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=issue_time,json=issueTime,proto3" json:"issue_time,omitempty"` + MaxTTL int64 `protobuf:"varint,5,opt,name=MaxTTL,proto3" json:"MaxTTL,omitempty"` unknownFields protoimpl.UnknownFields - - TTL int64 `protobuf:"varint,1,opt,name=TTL,proto3" json:"TTL,omitempty"` - Renewable bool `protobuf:"varint,2,opt,name=renewable,proto3" json:"renewable,omitempty"` - Increment int64 `protobuf:"varint,3,opt,name=increment,proto3" json:"increment,omitempty"` - IssueTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=issue_time,json=issueTime,proto3" json:"issue_time,omitempty"` - MaxTTL int64 `protobuf:"varint,5,opt,name=MaxTTL,proto3" json:"MaxTTL,omitempty"` + sizeCache protoimpl.SizeCache } func (x *LeaseOptions) Reset() { @@ -1048,11 +1042,8 @@ func (x *LeaseOptions) GetMaxTTL() int64 { } type Secret struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - LeaseOptions *LeaseOptions `protobuf:"bytes,1,opt,name=lease_options,json=leaseOptions,proto3" json:"lease_options,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + LeaseOptions *LeaseOptions `protobuf:"bytes,1,opt,name=lease_options,json=leaseOptions,proto3" json:"lease_options,omitempty"` // InternalData is a JSON object that is stored with the secret. // This will be sent back during a Renew/Revoke for storing internal data // used for those operations. @@ -1060,7 +1051,9 @@ type Secret struct { // LeaseID is the ID returned to the user to manage this secret. // This is generated by Vault core. Any set value will be ignored. // For requests, this will always be blank. - LeaseID string `protobuf:"bytes,3,opt,name=lease_id,json=leaseId,proto3" json:"lease_id,omitempty"` + LeaseID string `protobuf:"bytes,3,opt,name=lease_id,json=leaseId,proto3" json:"lease_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Secret) Reset() { @@ -1115,10 +1108,7 @@ func (x *Secret) GetLeaseID() string { } type Response struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Secret, if not nil, denotes that this response represents a secret. Secret *Secret `protobuf:"bytes,1,opt,name=secret,proto3" json:"secret,omitempty"` // Auth, if not nil, contains the authentication information for @@ -1142,10 +1132,12 @@ type Response struct { // Headers will contain the http headers from the response. This value will // be used in the audit broker to ensure we are auditing only the allowed // headers. - Headers map[string]*Header `protobuf:"bytes,7,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Headers map[string]*Header `protobuf:"bytes,7,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // MountType, if non-empty, provides some information about what kind // of mount this secret came from. - MountType string `protobuf:"bytes,8,opt,name=mount_type,json=mountType,proto3" json:"mount_type,omitempty"` + MountType string `protobuf:"bytes,8,opt,name=mount_type,json=mountType,proto3" json:"mount_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Response) Reset() { @@ -1235,10 +1227,7 @@ func (x *Response) GetMountType() string { } type ResponseWrapInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Setting to non-zero specifies that the response should be wrapped. // Specifies the desired TTL of the wrapping token. TTL int64 `protobuf:"varint,1,opt,name=TTL,proto3" json:"TTL,omitempty"` @@ -1261,7 +1250,9 @@ type ResponseWrapInfo struct { // the wrapped response. CreationPath string `protobuf:"bytes,8,opt,name=creation_path,json=creationPath,proto3" json:"creation_path,omitempty"` // Controls seal wrapping behavior downstream for specific use cases - SealWrap bool `protobuf:"varint,9,opt,name=seal_wrap,json=sealWrap,proto3" json:"seal_wrap,omitempty"` + SealWrap bool `protobuf:"varint,9,opt,name=seal_wrap,json=sealWrap,proto3" json:"seal_wrap,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ResponseWrapInfo) Reset() { @@ -1358,10 +1349,7 @@ func (x *ResponseWrapInfo) GetSealWrap() bool { } type RequestWrapInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Setting to non-zero specifies that the response should be wrapped. // Specifies the desired TTL of the wrapping token. TTL int64 `protobuf:"varint,1,opt,name=TTL,proto3" json:"TTL,omitempty"` @@ -1370,7 +1358,9 @@ type RequestWrapInfo struct { Format string `protobuf:"bytes,2,opt,name=format,proto3" json:"format,omitempty"` // A flag to conforming backends that data for a given request should be // seal wrapped - SealWrap bool `protobuf:"varint,3,opt,name=seal_wrap,json=sealWrap,proto3" json:"seal_wrap,omitempty"` + SealWrap bool `protobuf:"varint,3,opt,name=seal_wrap,json=sealWrap,proto3" json:"seal_wrap,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RequestWrapInfo) Reset() { @@ -1426,12 +1416,11 @@ func (x *RequestWrapInfo) GetSealWrap() bool { // HandleRequestArgs is the args for HandleRequest method. type HandleRequestArgs struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + StorageID uint32 `protobuf:"varint,1,opt,name=storage_id,json=storageId,proto3" json:"storage_id,omitempty"` + Request *Request `protobuf:"bytes,2,opt,name=request,proto3" json:"request,omitempty"` unknownFields protoimpl.UnknownFields - - StorageID uint32 `protobuf:"varint,1,opt,name=storage_id,json=storageId,proto3" json:"storage_id,omitempty"` - Request *Request `protobuf:"bytes,2,opt,name=request,proto3" json:"request,omitempty"` + sizeCache protoimpl.SizeCache } func (x *HandleRequestArgs) Reset() { @@ -1480,12 +1469,11 @@ func (x *HandleRequestArgs) GetRequest() *Request { // HandleRequestReply is the reply for HandleRequest method. type HandleRequestReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Response *Response `protobuf:"bytes,1,opt,name=response,proto3" json:"response,omitempty"` + Err *ProtoError `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` unknownFields protoimpl.UnknownFields - - Response *Response `protobuf:"bytes,1,opt,name=response,proto3" json:"response,omitempty"` - Err *ProtoError `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` + sizeCache protoimpl.SizeCache } func (x *HandleRequestReply) Reset() { @@ -1534,9 +1522,9 @@ func (x *HandleRequestReply) GetErr() *ProtoError { // InitializeArgs is the args for Initialize method. type InitializeArgs struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *InitializeArgs) Reset() { @@ -1571,11 +1559,10 @@ func (*InitializeArgs) Descriptor() ([]byte, []int) { // InitializeReply is the reply for Initialize method. type InitializeReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Err *ProtoError `protobuf:"bytes,1,opt,name=err,proto3" json:"err,omitempty"` unknownFields protoimpl.UnknownFields - - Err *ProtoError `protobuf:"bytes,1,opt,name=err,proto3" json:"err,omitempty"` + sizeCache protoimpl.SizeCache } func (x *InitializeReply) Reset() { @@ -1617,11 +1604,10 @@ func (x *InitializeReply) GetErr() *ProtoError { // SpecialPathsReply is the reply for SpecialPaths method. type SpecialPathsReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Paths *Paths `protobuf:"bytes,1,opt,name=paths,proto3" json:"paths,omitempty"` unknownFields protoimpl.UnknownFields - - Paths *Paths `protobuf:"bytes,1,opt,name=paths,proto3" json:"paths,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SpecialPathsReply) Reset() { @@ -1663,12 +1649,11 @@ func (x *SpecialPathsReply) GetPaths() *Paths { // HandleExistenceCheckArgs is the args for HandleExistenceCheck method. type HandleExistenceCheckArgs struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + StorageID uint32 `protobuf:"varint,1,opt,name=storage_id,json=storageId,proto3" json:"storage_id,omitempty"` + Request *Request `protobuf:"bytes,2,opt,name=request,proto3" json:"request,omitempty"` unknownFields protoimpl.UnknownFields - - StorageID uint32 `protobuf:"varint,1,opt,name=storage_id,json=storageId,proto3" json:"storage_id,omitempty"` - Request *Request `protobuf:"bytes,2,opt,name=request,proto3" json:"request,omitempty"` + sizeCache protoimpl.SizeCache } func (x *HandleExistenceCheckArgs) Reset() { @@ -1717,13 +1702,12 @@ func (x *HandleExistenceCheckArgs) GetRequest() *Request { // HandleExistenceCheckReply is the reply for HandleExistenceCheck method. type HandleExistenceCheckReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + CheckFound bool `protobuf:"varint,1,opt,name=check_found,json=checkFound,proto3" json:"check_found,omitempty"` + Exists bool `protobuf:"varint,2,opt,name=exists,proto3" json:"exists,omitempty"` + Err *ProtoError `protobuf:"bytes,3,opt,name=err,proto3" json:"err,omitempty"` unknownFields protoimpl.UnknownFields - - CheckFound bool `protobuf:"varint,1,opt,name=check_found,json=checkFound,proto3" json:"check_found,omitempty"` - Exists bool `protobuf:"varint,2,opt,name=exists,proto3" json:"exists,omitempty"` - Err *ProtoError `protobuf:"bytes,3,opt,name=err,proto3" json:"err,omitempty"` + sizeCache protoimpl.SizeCache } func (x *HandleExistenceCheckReply) Reset() { @@ -1779,13 +1763,12 @@ func (x *HandleExistenceCheckReply) GetErr() *ProtoError { // SetupArgs is the args for Setup method. type SetupArgs struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + BrokerID uint32 `protobuf:"varint,1,opt,name=broker_id,json=brokerId,proto3" json:"broker_id,omitempty"` + Config map[string]string `protobuf:"bytes,2,rep,name=Config,proto3" json:"Config,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + BackendUUID string `protobuf:"bytes,3,opt,name=backendUUID,proto3" json:"backendUUID,omitempty"` unknownFields protoimpl.UnknownFields - - BrokerID uint32 `protobuf:"varint,1,opt,name=broker_id,json=brokerId,proto3" json:"broker_id,omitempty"` - Config map[string]string `protobuf:"bytes,2,rep,name=Config,proto3" json:"Config,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - BackendUUID string `protobuf:"bytes,3,opt,name=backendUUID,proto3" json:"backendUUID,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SetupArgs) Reset() { @@ -1841,11 +1824,10 @@ func (x *SetupArgs) GetBackendUUID() string { // SetupReply is the reply for Setup method. type SetupReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Err string `protobuf:"bytes,1,opt,name=err,proto3" json:"err,omitempty"` unknownFields protoimpl.UnknownFields - - Err string `protobuf:"bytes,1,opt,name=err,proto3" json:"err,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SetupReply) Reset() { @@ -1887,11 +1869,10 @@ func (x *SetupReply) GetErr() string { // TypeReply is the reply for the Type method. type TypeReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type uint32 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"` unknownFields protoimpl.UnknownFields - - Type uint32 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"` + sizeCache protoimpl.SizeCache } func (x *TypeReply) Reset() { @@ -1932,11 +1913,10 @@ func (x *TypeReply) GetType() uint32 { } type InvalidateKeyArgs struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` unknownFields protoimpl.UnknownFields - - Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + sizeCache protoimpl.SizeCache } func (x *InvalidateKeyArgs) Reset() { @@ -1977,13 +1957,12 @@ func (x *InvalidateKeyArgs) GetKey() string { } type StorageEntry struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + SealWrap bool `protobuf:"varint,3,opt,name=seal_wrap,json=sealWrap,proto3" json:"seal_wrap,omitempty"` unknownFields protoimpl.UnknownFields - - Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` - SealWrap bool `protobuf:"varint,3,opt,name=seal_wrap,json=sealWrap,proto3" json:"seal_wrap,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StorageEntry) Reset() { @@ -2038,11 +2017,10 @@ func (x *StorageEntry) GetSealWrap() bool { } type StorageListArgs struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Prefix string `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"` unknownFields protoimpl.UnknownFields - - Prefix string `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StorageListArgs) Reset() { @@ -2083,12 +2061,11 @@ func (x *StorageListArgs) GetPrefix() string { } type StorageListReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Keys []string `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys,omitempty"` + Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` unknownFields protoimpl.UnknownFields - - Keys []string `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys,omitempty"` - Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StorageListReply) Reset() { @@ -2136,11 +2113,10 @@ func (x *StorageListReply) GetErr() string { } type StorageGetArgs struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` unknownFields protoimpl.UnknownFields - - Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StorageGetArgs) Reset() { @@ -2181,12 +2157,11 @@ func (x *StorageGetArgs) GetKey() string { } type StorageGetReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Entry *StorageEntry `protobuf:"bytes,1,opt,name=entry,proto3" json:"entry,omitempty"` + Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` unknownFields protoimpl.UnknownFields - - Entry *StorageEntry `protobuf:"bytes,1,opt,name=entry,proto3" json:"entry,omitempty"` - Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StorageGetReply) Reset() { @@ -2234,11 +2209,10 @@ func (x *StorageGetReply) GetErr() string { } type StoragePutArgs struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Entry *StorageEntry `protobuf:"bytes,1,opt,name=entry,proto3" json:"entry,omitempty"` unknownFields protoimpl.UnknownFields - - Entry *StorageEntry `protobuf:"bytes,1,opt,name=entry,proto3" json:"entry,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StoragePutArgs) Reset() { @@ -2279,11 +2253,10 @@ func (x *StoragePutArgs) GetEntry() *StorageEntry { } type StoragePutReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Err string `protobuf:"bytes,1,opt,name=err,proto3" json:"err,omitempty"` unknownFields protoimpl.UnknownFields - - Err string `protobuf:"bytes,1,opt,name=err,proto3" json:"err,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StoragePutReply) Reset() { @@ -2324,11 +2297,10 @@ func (x *StoragePutReply) GetErr() string { } type StorageDeleteArgs struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` unknownFields protoimpl.UnknownFields - - Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StorageDeleteArgs) Reset() { @@ -2369,11 +2341,10 @@ func (x *StorageDeleteArgs) GetKey() string { } type StorageDeleteReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Err string `protobuf:"bytes,1,opt,name=err,proto3" json:"err,omitempty"` unknownFields protoimpl.UnknownFields - - Err string `protobuf:"bytes,1,opt,name=err,proto3" json:"err,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StorageDeleteReply) Reset() { @@ -2414,11 +2385,10 @@ func (x *StorageDeleteReply) GetErr() string { } type TTLReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + TTL int64 `protobuf:"varint,1,opt,name=TTL,proto3" json:"TTL,omitempty"` unknownFields protoimpl.UnknownFields - - TTL int64 `protobuf:"varint,1,opt,name=TTL,proto3" json:"TTL,omitempty"` + sizeCache protoimpl.SizeCache } func (x *TTLReply) Reset() { @@ -2459,11 +2429,10 @@ func (x *TTLReply) GetTTL() int64 { } type TaintedReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Tainted bool `protobuf:"varint,1,opt,name=tainted,proto3" json:"tainted,omitempty"` unknownFields protoimpl.UnknownFields - - Tainted bool `protobuf:"varint,1,opt,name=tainted,proto3" json:"tainted,omitempty"` + sizeCache protoimpl.SizeCache } func (x *TaintedReply) Reset() { @@ -2504,11 +2473,10 @@ func (x *TaintedReply) GetTainted() bool { } type CachingDisabledReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Disabled bool `protobuf:"varint,1,opt,name=disabled,proto3" json:"disabled,omitempty"` unknownFields protoimpl.UnknownFields - - Disabled bool `protobuf:"varint,1,opt,name=disabled,proto3" json:"disabled,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CachingDisabledReply) Reset() { @@ -2549,11 +2517,10 @@ func (x *CachingDisabledReply) GetDisabled() bool { } type ReplicationStateReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + State int32 `protobuf:"varint,1,opt,name=state,proto3" json:"state,omitempty"` unknownFields protoimpl.UnknownFields - - State int32 `protobuf:"varint,1,opt,name=state,proto3" json:"state,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ReplicationStateReply) Reset() { @@ -2594,13 +2561,12 @@ func (x *ReplicationStateReply) GetState() int32 { } type ResponseWrapDataArgs struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + TTL int64 `protobuf:"varint,2,opt,name=TTL,proto3" json:"TTL,omitempty"` + JWT bool `protobuf:"varint,3,opt,name=JWT,proto3" json:"JWT,omitempty"` unknownFields protoimpl.UnknownFields - - Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` - TTL int64 `protobuf:"varint,2,opt,name=TTL,proto3" json:"TTL,omitempty"` - JWT bool `protobuf:"varint,3,opt,name=JWT,proto3" json:"JWT,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ResponseWrapDataArgs) Reset() { @@ -2655,12 +2621,11 @@ func (x *ResponseWrapDataArgs) GetJWT() bool { } type ResponseWrapDataReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + WrapInfo *ResponseWrapInfo `protobuf:"bytes,1,opt,name=wrap_info,json=wrapInfo,proto3" json:"wrap_info,omitempty"` + Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` unknownFields protoimpl.UnknownFields - - WrapInfo *ResponseWrapInfo `protobuf:"bytes,1,opt,name=wrap_info,json=wrapInfo,proto3" json:"wrap_info,omitempty"` - Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ResponseWrapDataReply) Reset() { @@ -2708,11 +2673,10 @@ func (x *ResponseWrapDataReply) GetErr() string { } type MlockEnabledReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` unknownFields protoimpl.UnknownFields - - Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + sizeCache protoimpl.SizeCache } func (x *MlockEnabledReply) Reset() { @@ -2753,11 +2717,10 @@ func (x *MlockEnabledReply) GetEnabled() bool { } type LocalMountReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Local bool `protobuf:"varint,1,opt,name=local,proto3" json:"local,omitempty"` unknownFields protoimpl.UnknownFields - - Local bool `protobuf:"varint,1,opt,name=local,proto3" json:"local,omitempty"` + sizeCache protoimpl.SizeCache } func (x *LocalMountReply) Reset() { @@ -2798,11 +2761,10 @@ func (x *LocalMountReply) GetLocal() bool { } type EntityInfoArgs struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + EntityID string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` unknownFields protoimpl.UnknownFields - - EntityID string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` + sizeCache protoimpl.SizeCache } func (x *EntityInfoArgs) Reset() { @@ -2843,12 +2805,11 @@ func (x *EntityInfoArgs) GetEntityID() string { } type EntityInfoReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Entity *logical.Entity `protobuf:"bytes,1,opt,name=entity,proto3" json:"entity,omitempty"` + Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` unknownFields protoimpl.UnknownFields - - Entity *logical.Entity `protobuf:"bytes,1,opt,name=entity,proto3" json:"entity,omitempty"` - Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` + sizeCache protoimpl.SizeCache } func (x *EntityInfoReply) Reset() { @@ -2896,12 +2857,11 @@ func (x *EntityInfoReply) GetErr() string { } type GroupsForEntityReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Groups []*logical.Group `protobuf:"bytes,1,rep,name=groups,proto3" json:"groups,omitempty"` + Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` unknownFields protoimpl.UnknownFields - - Groups []*logical.Group `protobuf:"bytes,1,rep,name=groups,proto3" json:"groups,omitempty"` - Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupsForEntityReply) Reset() { @@ -2949,12 +2909,11 @@ func (x *GroupsForEntityReply) GetErr() string { } type PluginEnvReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` PluginEnvironment *logical.PluginEnvironment `protobuf:"bytes,1,opt,name=plugin_environment,json=pluginEnvironment,proto3" json:"plugin_environment,omitempty"` Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *PluginEnvReply) Reset() { @@ -3002,11 +2961,10 @@ func (x *PluginEnvReply) GetErr() string { } type GeneratePasswordFromPolicyRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + PolicyName string `protobuf:"bytes,1,opt,name=policy_name,json=policyName,proto3" json:"policy_name,omitempty"` unknownFields protoimpl.UnknownFields - - PolicyName string `protobuf:"bytes,1,opt,name=policy_name,json=policyName,proto3" json:"policy_name,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GeneratePasswordFromPolicyRequest) Reset() { @@ -3047,11 +3005,10 @@ func (x *GeneratePasswordFromPolicyRequest) GetPolicyName() string { } type GeneratePasswordFromPolicyReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"` unknownFields protoimpl.UnknownFields - - Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GeneratePasswordFromPolicyReply) Reset() { @@ -3092,13 +3049,12 @@ func (x *GeneratePasswordFromPolicyReply) GetPassword() string { } type ClusterInfoReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ClusterName string `protobuf:"bytes,1,opt,name=cluster_name,json=clusterName,proto3" json:"cluster_name,omitempty"` + ClusterID string `protobuf:"bytes,2,opt,name=cluster_id,json=clusterId,proto3" json:"cluster_id,omitempty"` + Err string `protobuf:"bytes,3,opt,name=err,proto3" json:"err,omitempty"` unknownFields protoimpl.UnknownFields - - ClusterName string `protobuf:"bytes,1,opt,name=cluster_name,json=clusterName,proto3" json:"cluster_name,omitempty"` - ClusterID string `protobuf:"bytes,2,opt,name=cluster_id,json=clusterId,proto3" json:"cluster_id,omitempty"` - Err string `protobuf:"bytes,3,opt,name=err,proto3" json:"err,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ClusterInfoReply) Reset() { @@ -3153,12 +3109,11 @@ func (x *ClusterInfoReply) GetErr() string { } type GenerateIdentityTokenRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Audience string `protobuf:"bytes,1,opt,name=audience,proto3" json:"audience,omitempty"` + TTL int64 `protobuf:"varint,2,opt,name=ttl,proto3" json:"ttl,omitempty"` unknownFields protoimpl.UnknownFields - - Audience string `protobuf:"bytes,1,opt,name=audience,proto3" json:"audience,omitempty"` - TTL int64 `protobuf:"varint,2,opt,name=ttl,proto3" json:"ttl,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GenerateIdentityTokenRequest) Reset() { @@ -3206,12 +3161,11 @@ func (x *GenerateIdentityTokenRequest) GetTTL() int64 { } type GenerateIdentityTokenResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` + TTL int64 `protobuf:"varint,2,opt,name=ttl,proto3" json:"ttl,omitempty"` unknownFields protoimpl.UnknownFields - - Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` - TTL int64 `protobuf:"varint,2,opt,name=ttl,proto3" json:"ttl,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GenerateIdentityTokenResponse) Reset() { @@ -3258,11 +3212,216 @@ func (x *GenerateIdentityTokenResponse) GetTTL() int64 { return 0 } -type Connection struct { - state protoimpl.MessageState +type RegisterRotationJobRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Job *RotationJobInput `protobuf:"bytes,1,opt,name=job,proto3" json:"job,omitempty"` + unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache +} + +func (x *RegisterRotationJobRequest) Reset() { + *x = RegisterRotationJobRequest{} + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegisterRotationJobRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterRotationJobRequest) ProtoMessage() {} + +func (x *RegisterRotationJobRequest) ProtoReflect() protoreflect.Message { + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[49] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterRotationJobRequest.ProtoReflect.Descriptor instead. +func (*RegisterRotationJobRequest) Descriptor() ([]byte, []int) { + return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{49} +} + +func (x *RegisterRotationJobRequest) GetJob() *RotationJobInput { + if x != nil { + return x.Job + } + return nil +} + +type RegisterRotationJobResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + RotationID string `protobuf:"bytes,1,opt,name=rotation_id,json=rotationId,proto3" json:"rotation_id,omitempty"` + Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RegisterRotationJobResponse) Reset() { + *x = RegisterRotationJobResponse{} + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegisterRotationJobResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterRotationJobResponse) ProtoMessage() {} + +func (x *RegisterRotationJobResponse) ProtoReflect() protoreflect.Message { + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[50] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterRotationJobResponse.ProtoReflect.Descriptor instead. +func (*RegisterRotationJobResponse) Descriptor() ([]byte, []int) { + return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{50} +} + +func (x *RegisterRotationJobResponse) GetRotationID() string { + if x != nil { + return x.RotationID + } + return "" +} + +func (x *RegisterRotationJobResponse) GetErr() string { + if x != nil { + return x.Err + } + return "" +} + +type RotationJobInput struct { + state protoimpl.MessageState `protogen:"open.v1"` + Schedule *structpb.Struct `protobuf:"bytes,1,opt,name=schedule,proto3" json:"schedule,omitempty"` + RotationID string `protobuf:"bytes,2,opt,name=rotation_id,json=rotationId,proto3" json:"rotation_id,omitempty"` + Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"` + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RotationJobInput) Reset() { + *x = RotationJobInput{} + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RotationJobInput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RotationJobInput) ProtoMessage() {} + +func (x *RotationJobInput) ProtoReflect() protoreflect.Message { + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[51] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RotationJobInput.ProtoReflect.Descriptor instead. +func (*RotationJobInput) Descriptor() ([]byte, []int) { + return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{51} +} + +func (x *RotationJobInput) GetSchedule() *structpb.Struct { + if x != nil { + return x.Schedule + } + return nil +} + +func (x *RotationJobInput) GetRotationID() string { + if x != nil { + return x.RotationID + } + return "" +} + +func (x *RotationJobInput) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *RotationJobInput) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type DeregisterRotationJobRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + RotationID string `protobuf:"bytes,1,opt,name=rotation_id,json=rotationId,proto3" json:"rotation_id,omitempty"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeregisterRotationJobRequest) Reset() { + *x = DeregisterRotationJobRequest{} + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeregisterRotationJobRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeregisterRotationJobRequest) ProtoMessage() {} + +func (x *DeregisterRotationJobRequest) ProtoReflect() protoreflect.Message { + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[52] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} +// Deprecated: Use DeregisterRotationJobRequest.ProtoReflect.Descriptor instead. +func (*DeregisterRotationJobRequest) Descriptor() ([]byte, []int) { + return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{52} +} + +func (x *DeregisterRotationJobRequest) GetRotationID() string { + if x != nil { + return x.RotationID + } + return "" +} + +type Connection struct { + state protoimpl.MessageState `protogen:"open.v1"` // RemoteAddr is the network address that sent the request. RemoteAddr string `protobuf:"bytes,1,opt,name=remote_addr,json=remoteAddr,proto3" json:"remote_addr,omitempty"` // RemotePort is the network port that sent the request. @@ -3270,11 +3429,13 @@ type Connection struct { // ConnectionState is the marshalled tls.ConnectionState from the original // request ConnectionState *ConnectionState `protobuf:"bytes,2,opt,name=connection_state,json=connectionState,proto3" json:"connection_state,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Connection) Reset() { *x = Connection{} - mi := &file_sdk_plugin_pb_backend_proto_msgTypes[49] + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3286,7 +3447,7 @@ func (x *Connection) String() string { func (*Connection) ProtoMessage() {} func (x *Connection) ProtoReflect() protoreflect.Message { - mi := &file_sdk_plugin_pb_backend_proto_msgTypes[49] + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3299,7 +3460,7 @@ func (x *Connection) ProtoReflect() protoreflect.Message { // Deprecated: Use Connection.ProtoReflect.Descriptor instead. func (*Connection) Descriptor() ([]byte, []int) { - return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{49} + return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{53} } func (x *Connection) GetRemoteAddr() string { @@ -3324,27 +3485,26 @@ func (x *Connection) GetConnectionState() *ConnectionState { } type ConnectionState struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` - HandshakeComplete bool `protobuf:"varint,2,opt,name=handshake_complete,json=handshakeComplete,proto3" json:"handshake_complete,omitempty"` - DidResume bool `protobuf:"varint,3,opt,name=did_resume,json=didResume,proto3" json:"did_resume,omitempty"` - CipherSuite uint32 `protobuf:"varint,4,opt,name=cipher_suite,json=cipherSuite,proto3" json:"cipher_suite,omitempty"` - NegotiatedProtocol string `protobuf:"bytes,5,opt,name=negotiated_protocol,json=negotiatedProtocol,proto3" json:"negotiated_protocol,omitempty"` - NegotiatedProtocolIsMutual bool `protobuf:"varint,6,opt,name=negotiated_protocol_is_mutual,json=negotiatedProtocolIsMutual,proto3" json:"negotiated_protocol_is_mutual,omitempty"` - ServerName string `protobuf:"bytes,7,opt,name=server_name,json=serverName,proto3" json:"server_name,omitempty"` - PeerCertificates *CertificateChain `protobuf:"bytes,8,opt,name=peer_certificates,json=peerCertificates,proto3" json:"peer_certificates,omitempty"` - VerifiedChains []*CertificateChain `protobuf:"bytes,9,rep,name=verified_chains,json=verifiedChains,proto3" json:"verified_chains,omitempty"` - SignedCertificateTimestamps [][]byte `protobuf:"bytes,10,rep,name=signed_certificate_timestamps,json=signedCertificateTimestamps,proto3" json:"signed_certificate_timestamps,omitempty"` - OcspResponse []byte `protobuf:"bytes,11,opt,name=ocsp_response,json=ocspResponse,proto3" json:"ocsp_response,omitempty"` - TlsUnique []byte `protobuf:"bytes,12,opt,name=tls_unique,json=tlsUnique,proto3" json:"tls_unique,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + HandshakeComplete bool `protobuf:"varint,2,opt,name=handshake_complete,json=handshakeComplete,proto3" json:"handshake_complete,omitempty"` + DidResume bool `protobuf:"varint,3,opt,name=did_resume,json=didResume,proto3" json:"did_resume,omitempty"` + CipherSuite uint32 `protobuf:"varint,4,opt,name=cipher_suite,json=cipherSuite,proto3" json:"cipher_suite,omitempty"` + NegotiatedProtocol string `protobuf:"bytes,5,opt,name=negotiated_protocol,json=negotiatedProtocol,proto3" json:"negotiated_protocol,omitempty"` + NegotiatedProtocolIsMutual bool `protobuf:"varint,6,opt,name=negotiated_protocol_is_mutual,json=negotiatedProtocolIsMutual,proto3" json:"negotiated_protocol_is_mutual,omitempty"` + ServerName string `protobuf:"bytes,7,opt,name=server_name,json=serverName,proto3" json:"server_name,omitempty"` + PeerCertificates *CertificateChain `protobuf:"bytes,8,opt,name=peer_certificates,json=peerCertificates,proto3" json:"peer_certificates,omitempty"` + VerifiedChains []*CertificateChain `protobuf:"bytes,9,rep,name=verified_chains,json=verifiedChains,proto3" json:"verified_chains,omitempty"` + SignedCertificateTimestamps [][]byte `protobuf:"bytes,10,rep,name=signed_certificate_timestamps,json=signedCertificateTimestamps,proto3" json:"signed_certificate_timestamps,omitempty"` + OcspResponse []byte `protobuf:"bytes,11,opt,name=ocsp_response,json=ocspResponse,proto3" json:"ocsp_response,omitempty"` + TlsUnique []byte `protobuf:"bytes,12,opt,name=tls_unique,json=tlsUnique,proto3" json:"tls_unique,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ConnectionState) Reset() { *x = ConnectionState{} - mi := &file_sdk_plugin_pb_backend_proto_msgTypes[50] + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3356,7 +3516,7 @@ func (x *ConnectionState) String() string { func (*ConnectionState) ProtoMessage() {} func (x *ConnectionState) ProtoReflect() protoreflect.Message { - mi := &file_sdk_plugin_pb_backend_proto_msgTypes[50] + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3369,7 +3529,7 @@ func (x *ConnectionState) ProtoReflect() protoreflect.Message { // Deprecated: Use ConnectionState.ProtoReflect.Descriptor instead. func (*ConnectionState) Descriptor() ([]byte, []int) { - return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{50} + return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{54} } func (x *ConnectionState) GetVersion() uint32 { @@ -3457,16 +3617,15 @@ func (x *ConnectionState) GetTlsUnique() []byte { } type Certificate struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Asn1Data []byte `protobuf:"bytes,1,opt,name=asn1_data,json=asn1Data,proto3" json:"asn1_data,omitempty"` unknownFields protoimpl.UnknownFields - - Asn1Data []byte `protobuf:"bytes,1,opt,name=asn1_data,json=asn1Data,proto3" json:"asn1_data,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Certificate) Reset() { *x = Certificate{} - mi := &file_sdk_plugin_pb_backend_proto_msgTypes[51] + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3478,7 +3637,7 @@ func (x *Certificate) String() string { func (*Certificate) ProtoMessage() {} func (x *Certificate) ProtoReflect() protoreflect.Message { - mi := &file_sdk_plugin_pb_backend_proto_msgTypes[51] + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3491,7 +3650,7 @@ func (x *Certificate) ProtoReflect() protoreflect.Message { // Deprecated: Use Certificate.ProtoReflect.Descriptor instead. func (*Certificate) Descriptor() ([]byte, []int) { - return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{51} + return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{55} } func (x *Certificate) GetAsn1Data() []byte { @@ -3502,16 +3661,15 @@ func (x *Certificate) GetAsn1Data() []byte { } type CertificateChain struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Certificates []*Certificate `protobuf:"bytes,1,rep,name=certificates,proto3" json:"certificates,omitempty"` unknownFields protoimpl.UnknownFields - - Certificates []*Certificate `protobuf:"bytes,1,rep,name=certificates,proto3" json:"certificates,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CertificateChain) Reset() { *x = CertificateChain{} - mi := &file_sdk_plugin_pb_backend_proto_msgTypes[52] + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3523,7 +3681,7 @@ func (x *CertificateChain) String() string { func (*CertificateChain) ProtoMessage() {} func (x *CertificateChain) ProtoReflect() protoreflect.Message { - mi := &file_sdk_plugin_pb_backend_proto_msgTypes[52] + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3536,7 +3694,7 @@ func (x *CertificateChain) ProtoReflect() protoreflect.Message { // Deprecated: Use CertificateChain.ProtoReflect.Descriptor instead. func (*CertificateChain) Descriptor() ([]byte, []int) { - return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{52} + return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{56} } func (x *CertificateChain) GetCertificates() []*Certificate { @@ -3547,17 +3705,16 @@ func (x *CertificateChain) GetCertificates() []*Certificate { } type SendEventRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + EventType string `protobuf:"bytes,1,opt,name=event_type,json=eventType,proto3" json:"event_type,omitempty"` + Event *logical.EventData `protobuf:"bytes,2,opt,name=event,proto3" json:"event,omitempty"` unknownFields protoimpl.UnknownFields - - EventType string `protobuf:"bytes,1,opt,name=event_type,json=eventType,proto3" json:"event_type,omitempty"` - Event *logical.EventData `protobuf:"bytes,2,opt,name=event,proto3" json:"event,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SendEventRequest) Reset() { *x = SendEventRequest{} - mi := &file_sdk_plugin_pb_backend_proto_msgTypes[53] + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3569,7 +3726,7 @@ func (x *SendEventRequest) String() string { func (*SendEventRequest) ProtoMessage() {} func (x *SendEventRequest) ProtoReflect() protoreflect.Message { - mi := &file_sdk_plugin_pb_backend_proto_msgTypes[53] + mi := &file_sdk_plugin_pb_backend_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3582,7 +3739,7 @@ func (x *SendEventRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SendEventRequest.ProtoReflect.Descriptor instead. func (*SendEventRequest) Descriptor() ([]byte, []int) { - return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{53} + return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{57} } func (x *SendEventRequest) GetEventType() string { @@ -3606,565 +3763,599 @@ var file_sdk_plugin_pb_backend_proto_rawDesc = []byte{ 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 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, 0x17, 0x73, 0x64, 0x6b, 0x2f, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2f, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x73, 0x64, 0x6b, - 0x2f, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x73, 0x64, 0x6b, 0x2f, 0x6c, 0x6f, 0x67, - 0x69, 0x63, 0x61, 0x6c, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x20, 0x0a, 0x06, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, 0x5b, 0x0a, 0x0a, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x72, - 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x65, 0x72, - 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x5f, 0x6d, 0x73, 0x67, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x19, - 0x0a, 0x08, 0x65, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x07, 0x65, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x80, 0x02, 0x0a, 0x05, 0x50, 0x61, - 0x74, 0x68, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, - 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x53, - 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x65, 0x61, 0x6c, 0x5f, 0x77, - 0x72, 0x61, 0x70, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0f, 0x73, 0x65, 0x61, 0x6c, 0x57, 0x72, 0x61, 0x70, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x12, 0x36, 0x0a, 0x17, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x77, - 0x61, 0x72, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x15, 0x77, 0x72, 0x69, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, - 0x64, 0x65, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x69, - 0x6e, 0x61, 0x72, 0x79, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x62, 0x69, 0x6e, 0x61, - 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x18, 0x07, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x22, 0xbf, 0x06, 0x0a, - 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x22, - 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, - 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, - 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x08, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, - 0x12, 0x32, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x64, - 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, - 0x0a, 0x0b, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x0c, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0d, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x25, - 0x0a, 0x0e, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, - 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x09, 0x77, 0x72, 0x61, 0x70, 0x5f, 0x69, 0x6e, - 0x66, 0x6f, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x72, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x77, - 0x72, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, - 0x67, 0x5f, 0x75, 0x73, 0x65, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x18, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, - 0x6e, 0x67, 0x55, 0x73, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x5f, 0x69, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x6f, 0x76, - 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x0f, - 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, - 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x62, 0x2e, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x46, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xe6, - 0x05, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x35, 0x0a, 0x0d, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, - 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x0c, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, - 0x0a, 0x0d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, - 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, - 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, - 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, - 0x65, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x2e, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x19, 0x0a, - 0x08, 0x6e, 0x75, 0x6d, 0x5f, 0x75, 0x73, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x07, 0x6e, 0x75, 0x6d, 0x55, 0x73, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x0b, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2e, 0x41, - 0x6c, 0x69, 0x61, 0x73, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x33, 0x0a, 0x0d, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x03, + 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x17, 0x73, 0x64, 0x6b, 0x2f, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2f, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x73, 0x64, 0x6b, 0x2f, 0x6c, + 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x73, 0x64, 0x6b, 0x2f, 0x6c, 0x6f, 0x67, 0x69, 0x63, + 0x61, 0x6c, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x20, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, 0x5b, 0x0a, 0x0a, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x72, 0x72, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x65, 0x72, 0x72, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x19, 0x0a, 0x08, + 0x65, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, + 0x65, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x80, 0x02, 0x0a, 0x05, 0x50, 0x61, 0x74, 0x68, + 0x73, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, + 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, + 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, + 0x23, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x65, 0x61, 0x6c, 0x5f, 0x77, 0x72, 0x61, + 0x70, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0f, 0x73, 0x65, 0x61, 0x6c, 0x57, 0x72, 0x61, 0x70, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x12, 0x36, 0x0a, 0x17, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, + 0x64, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x15, 0x77, 0x72, 0x69, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, + 0x64, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x69, 0x6e, 0x61, + 0x72, 0x79, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, + 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x07, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x22, 0xbf, 0x06, 0x0a, 0x07, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x12, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x06, + 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, + 0x62, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, + 0x12, 0x1c, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, + 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, 0x12, 0x32, + 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, + 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1d, 0x0a, + 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0e, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, 0x0e, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x09, 0x77, 0x72, 0x61, 0x70, 0x5f, 0x69, 0x6e, 0x66, 0x6f, + 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x57, 0x72, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x77, 0x72, 0x61, + 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x5f, + 0x75, 0x73, 0x65, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x18, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, + 0x55, 0x73, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, + 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, + 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x6f, 0x76, 0x65, 0x72, + 0x72, 0x69, 0x64, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, + 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x13, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x46, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xe6, 0x05, 0x0a, + 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x35, 0x0a, 0x0d, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, + 0x62, 0x2e, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0c, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x61, 0x74, + 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, + 0x12, 0x32, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x2e, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6e, + 0x75, 0x6d, 0x5f, 0x75, 0x73, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6e, + 0x75, 0x6d, 0x55, 0x73, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2e, 0x41, 0x6c, 0x69, - 0x61, 0x73, 0x52, 0x0c, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, - 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x73, 0x18, - 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x69, 0x64, 0x72, - 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x0f, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x10, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, - 0x74, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x74, 0x6c, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0e, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x4d, 0x61, 0x78, 0x54, 0x74, 0x6c, 0x12, - 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x11, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2a, - 0x0a, 0x11, 0x6e, 0x6f, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6e, 0x6f, 0x44, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xca, 0x06, 0x0a, 0x0a, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x2c, 0x0a, 0x04, 0x6d, 0x65, - 0x74, 0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, - 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6e, - 0x75, 0x6d, 0x5f, 0x75, 0x73, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6e, - 0x75, 0x6d, 0x55, 0x73, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, - 0x74, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x12, 0x28, 0x0a, - 0x10, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x74, - 0x6c, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, - 0x74, 0x4d, 0x61, 0x78, 0x54, 0x74, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, - 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, - 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x70, 0x65, 0x72, - 0x69, 0x6f, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, - 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, - 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x73, 0x18, - 0x0f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x69, 0x64, 0x72, - 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x62, 0x62, 0x79, 0x68, 0x6f, 0x6c, - 0x65, 0x5f, 0x69, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x75, 0x62, 0x62, - 0x79, 0x68, 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x12, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x45, 0x0a, 0x0d, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x13, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4d, 0x65, - 0x74, 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x6c, 0x69, 0x6e, - 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x30, 0x0a, 0x14, 0x6e, 0x6f, 0x5f, 0x69, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, - 0x15, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x6e, 0x6f, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, - 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x1a, 0x3f, 0x0a, 0x11, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4d, - 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x22, 0xaf, 0x01, 0x0a, 0x0c, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x6e, 0x65, 0x77, - 0x61, 0x62, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x6e, 0x65, - 0x77, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x5f, 0x74, 0x69, 0x6d, - 0x65, 0x18, 0x04, 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, 0x09, 0x69, 0x73, 0x73, 0x75, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x4d, 0x61, 0x78, 0x54, 0x54, 0x4c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, - 0x4d, 0x61, 0x78, 0x54, 0x54, 0x4c, 0x22, 0x7f, 0x0a, 0x06, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, - 0x12, 0x35, 0x0a, 0x0d, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x65, 0x61, - 0x73, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0c, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x12, 0x19, 0x0a, 0x08, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x49, 0x64, 0x22, 0xe7, 0x02, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, - 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x74, 0x68, - 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, - 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, - 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, - 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, - 0x67, 0x73, 0x12, 0x31, 0x0a, 0x09, 0x77, 0x72, 0x61, 0x70, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x77, 0x72, 0x61, - 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x33, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, - 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x1a, 0x46, 0x0a, 0x0c, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x22, 0xc8, 0x02, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, - 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, - 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x0c, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x77, - 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, - 0x64, 0x5f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x12, - 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x61, 0x6c, 0x5f, 0x77, 0x72, 0x61, 0x70, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x08, 0x73, 0x65, 0x61, 0x6c, 0x57, 0x72, 0x61, 0x70, 0x22, 0x58, 0x0a, 0x0f, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x72, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x10, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x54, 0x54, - 0x4c, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x61, - 0x6c, 0x5f, 0x77, 0x72, 0x61, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x65, - 0x61, 0x6c, 0x57, 0x72, 0x61, 0x70, 0x22, 0x59, 0x0a, 0x11, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x72, 0x67, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, - 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x09, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x07, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x62, - 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0x60, 0x0a, 0x12, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x28, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x20, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, - 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x03, - 0x65, 0x72, 0x72, 0x22, 0x10, 0x0a, 0x0e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, - 0x65, 0x41, 0x72, 0x67, 0x73, 0x22, 0x33, 0x0a, 0x0f, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, - 0x69, 0x7a, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x20, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x34, 0x0a, 0x11, 0x53, 0x70, - 0x65, 0x63, 0x69, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, - 0x1f, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, - 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, - 0x22, 0x60, 0x0a, 0x18, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x65, - 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x41, 0x72, 0x67, 0x73, 0x12, 0x1d, 0x0a, 0x0a, - 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x07, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, - 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x22, 0x76, 0x0a, 0x19, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, - 0x74, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, - 0x1f, 0x0a, 0x0b, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x46, 0x6f, 0x75, 0x6e, 0x64, - 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x06, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x12, 0x20, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0xb8, 0x01, 0x0a, 0x09, 0x53, - 0x65, 0x74, 0x75, 0x70, 0x41, 0x72, 0x67, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x72, 0x6f, 0x6b, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x62, 0x72, 0x6f, - 0x6b, 0x65, 0x72, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x74, 0x75, 0x70, - 0x41, 0x72, 0x67, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, - 0x65, 0x6e, 0x64, 0x55, 0x55, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, - 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x55, 0x49, 0x44, 0x1a, 0x39, 0x0a, 0x0b, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x61, 0x73, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x33, 0x0a, 0x0d, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0e, 0x2e, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, + 0x52, 0x0c, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x1f, + 0x0a, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x73, 0x18, 0x0d, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x69, 0x64, 0x72, 0x73, 0x12, + 0x25, 0x0a, 0x0e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, + 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x10, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x69, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x5f, + 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x74, 0x6c, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x65, + 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x4d, 0x61, 0x78, 0x54, 0x74, 0x6c, 0x12, 0x1d, 0x0a, + 0x0a, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x11, + 0x6e, 0x6f, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6e, 0x6f, 0x44, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x1e, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xca, 0x06, 0x0a, 0x0a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, + 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x2c, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, + 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, + 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x75, 0x6d, + 0x5f, 0x75, 0x73, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6e, 0x75, 0x6d, + 0x55, 0x73, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74, 0x6c, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x12, 0x28, 0x0a, 0x10, 0x65, + 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x74, 0x6c, 0x18, + 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x4d, + 0x61, 0x78, 0x54, 0x74, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x65, 0x72, + 0x69, 0x6f, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, + 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x0e, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x1f, + 0x0a, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x73, 0x18, 0x0f, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x69, 0x64, 0x72, 0x73, 0x12, + 0x21, 0x0a, 0x0c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x62, 0x62, 0x79, 0x68, 0x6f, 0x6c, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x75, 0x62, 0x62, 0x79, 0x68, + 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x12, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x45, 0x0a, 0x0d, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, + 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x30, 0x0a, 0x14, 0x6e, 0x6f, 0x5f, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x15, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x12, 0x6e, 0x6f, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x1a, 0x3f, 0x0a, 0x11, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x74, + 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0xaf, 0x01, 0x0a, 0x0c, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x6e, 0x65, 0x77, 0x61, 0x62, + 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x6e, 0x65, 0x77, 0x61, + 0x62, 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x04, 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, 0x09, 0x69, 0x73, 0x73, 0x75, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x4d, 0x61, 0x78, 0x54, 0x54, 0x4c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x4d, 0x61, + 0x78, 0x54, 0x54, 0x4c, 0x22, 0x7f, 0x0a, 0x06, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x35, + 0x0a, 0x0d, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x65, 0x61, 0x73, 0x65, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0c, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x49, 0x64, 0x22, 0xe7, 0x02, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x22, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x06, + 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x04, + 0x61, 0x75, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x64, 0x69, + 0x72, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x64, 0x69, + 0x72, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, + 0x12, 0x31, 0x0a, 0x09, 0x77, 0x72, 0x61, 0x70, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x57, 0x72, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x77, 0x72, 0x61, 0x70, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x33, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x07, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x1a, 0x46, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0xc8, 0x02, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, + 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x0c, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x77, 0x72, 0x61, + 0x70, 0x70, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x41, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x6f, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, + 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1b, 0x0a, + 0x09, 0x73, 0x65, 0x61, 0x6c, 0x5f, 0x77, 0x72, 0x61, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x08, 0x73, 0x65, 0x61, 0x6c, 0x57, 0x72, 0x61, 0x70, 0x22, 0x58, 0x0a, 0x0f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x72, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, + 0x03, 0x54, 0x54, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, + 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x61, 0x6c, 0x5f, + 0x77, 0x72, 0x61, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x65, 0x61, 0x6c, + 0x57, 0x72, 0x61, 0x70, 0x22, 0x59, 0x0a, 0x11, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x72, 0x67, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x62, 0x2e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0x60, 0x0a, 0x12, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x28, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x20, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, + 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x03, 0x65, 0x72, + 0x72, 0x22, 0x10, 0x0a, 0x0e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x41, + 0x72, 0x67, 0x73, 0x22, 0x33, 0x0a, 0x0f, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x20, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x34, 0x0a, 0x11, 0x53, 0x70, 0x65, 0x63, + 0x69, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1f, 0x0a, + 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x70, + 0x62, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x22, 0x60, + 0x0a, 0x18, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, + 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x41, 0x72, 0x67, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x07, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x62, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x22, 0x76, 0x0a, 0x19, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x65, + 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1f, 0x0a, + 0x0b, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x16, + 0x0a, 0x06, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, + 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x12, 0x20, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0xb8, 0x01, 0x0a, 0x09, 0x53, 0x65, 0x74, + 0x75, 0x70, 0x41, 0x72, 0x67, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x62, 0x72, 0x6f, 0x6b, 0x65, + 0x72, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x74, 0x75, 0x70, 0x41, 0x72, + 0x67, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, + 0x64, 0x55, 0x55, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x61, 0x63, + 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x55, 0x49, 0x44, 0x1a, 0x39, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0x1e, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x65, 0x72, 0x72, 0x22, 0x1f, 0x0a, 0x09, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x22, 0x25, 0x0a, 0x11, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x72, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x53, 0x0a, 0x0c, 0x53, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x61, 0x6c, 0x5f, 0x77, 0x72, 0x61, 0x70, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x65, 0x61, 0x6c, 0x57, 0x72, 0x61, 0x70, + 0x22, 0x29, 0x0a, 0x0f, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x41, + 0x72, 0x67, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x38, 0x0a, 0x10, 0x53, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, + 0x12, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6b, + 0x65, 0x79, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x22, 0x0a, 0x0e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x47, 0x65, 0x74, 0x41, 0x72, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x4b, 0x0a, 0x0f, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x05, + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x62, + 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x38, 0x0a, 0x0e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x50, 0x75, 0x74, 0x41, 0x72, 0x67, 0x73, 0x12, 0x26, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x22, 0x23, 0x0a, 0x0f, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x50, 0x75, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x1f, 0x0a, 0x09, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x25, 0x0a, 0x11, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x72, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x53, 0x0a, - 0x0c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x61, 0x6c, 0x5f, 0x77, 0x72, - 0x61, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x65, 0x61, 0x6c, 0x57, 0x72, - 0x61, 0x70, 0x22, 0x29, 0x0a, 0x0f, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, - 0x74, 0x41, 0x72, 0x67, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x38, 0x0a, - 0x10, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x04, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x22, 0x0a, 0x0e, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x47, 0x65, 0x74, 0x41, 0x72, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x4b, 0x0a, 0x0f, 0x53, - 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, - 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, - 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x38, 0x0a, 0x0e, 0x53, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x50, 0x75, 0x74, 0x41, 0x72, 0x67, 0x73, 0x12, 0x26, 0x0a, 0x05, 0x65, 0x6e, - 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x53, - 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, - 0x72, 0x79, 0x22, 0x23, 0x0a, 0x0f, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x50, 0x75, 0x74, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x25, 0x0a, 0x11, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x72, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x26, - 0x0a, 0x12, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x1c, 0x0a, 0x08, 0x54, 0x54, 0x4c, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x03, 0x54, 0x54, 0x4c, 0x22, 0x28, 0x0a, 0x0c, 0x54, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x64, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x74, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x64, 0x22, 0x32, - 0x0a, 0x14, 0x43, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, - 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x22, 0x2d, 0x0a, 0x15, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x73, - 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, - 0x65, 0x22, 0x4e, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, - 0x70, 0x44, 0x61, 0x74, 0x61, 0x41, 0x72, 0x67, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, - 0x03, 0x54, 0x54, 0x4c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, - 0x10, 0x0a, 0x03, 0x4a, 0x57, 0x54, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x4a, 0x57, - 0x54, 0x22, 0x5c, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, - 0x70, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x31, 0x0a, 0x09, 0x77, 0x72, - 0x61, 0x70, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, - 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x77, 0x72, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, + 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x25, 0x0a, 0x11, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x72, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x26, 0x0a, 0x12, + 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x65, 0x72, 0x72, 0x22, 0x1c, 0x0a, 0x08, 0x54, 0x54, 0x4c, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x54, + 0x54, 0x4c, 0x22, 0x28, 0x0a, 0x0c, 0x54, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x07, 0x74, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x64, 0x22, 0x32, 0x0a, 0x14, + 0x43, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x22, 0x2d, 0x0a, 0x15, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, + 0x4e, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, 0x44, + 0x61, 0x74, 0x61, 0x41, 0x72, 0x67, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x54, + 0x54, 0x4c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, 0x10, 0x0a, + 0x03, 0x4a, 0x57, 0x54, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x4a, 0x57, 0x54, 0x22, + 0x5c, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, 0x44, + 0x61, 0x74, 0x61, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x31, 0x0a, 0x09, 0x77, 0x72, 0x61, 0x70, + 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x62, + 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x08, 0x77, 0x72, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x65, + 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x2d, 0x0a, + 0x11, 0x4d, 0x6c, 0x6f, 0x63, 0x6b, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x27, 0x0a, 0x0f, + 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x22, 0x2d, 0x0a, 0x0e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, + 0x6e, 0x66, 0x6f, 0x41, 0x72, 0x67, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x49, 0x64, 0x22, 0x4c, 0x0a, 0x0f, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x27, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, + 0x6c, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, + 0x72, 0x72, 0x22, 0x50, 0x0a, 0x14, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x46, 0x6f, 0x72, 0x45, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x06, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6f, 0x67, + 0x69, 0x63, 0x61, 0x6c, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x65, 0x72, 0x72, 0x22, 0x6d, 0x0a, 0x0e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x45, 0x6e, + 0x76, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x49, 0x0a, 0x12, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, + 0x5f, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2e, 0x50, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x11, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x65, 0x72, 0x72, 0x22, 0x44, 0x0a, 0x21, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3d, 0x0a, 0x1f, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x46, 0x72, 0x6f, + 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x08, + 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x66, 0x0a, 0x10, 0x43, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x21, 0x0a, 0x0c, + 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 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, 0x10, + 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x72, 0x72, + 0x22, 0x4c, 0x0a, 0x1c, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, + 0x74, 0x74, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x22, 0x47, + 0x0a, 0x1d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x22, 0x44, 0x0a, 0x1a, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x22, 0x50, 0x0a, + 0x1b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, + 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, - 0x2d, 0x0a, 0x11, 0x4d, 0x6c, 0x6f, 0x63, 0x6b, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x27, - 0x0a, 0x0f, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x22, 0x2d, 0x0a, 0x0e, 0x45, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x41, 0x72, 0x67, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x22, 0x4c, 0x0a, 0x0f, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x27, 0x0a, 0x06, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6f, 0x67, 0x69, - 0x63, 0x61, 0x6c, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x65, 0x72, 0x72, 0x22, 0x50, 0x0a, 0x14, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x46, 0x6f, - 0x72, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x06, - 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, - 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x6d, 0x0a, 0x0e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x45, 0x6e, 0x76, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x49, 0x0a, 0x12, 0x70, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x5f, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2e, 0x50, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, - 0x52, 0x11, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, - 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x44, 0x0a, 0x21, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, - 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3d, 0x0a, 0x1f, 0x47, - 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x46, - 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, - 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x66, 0x0a, 0x10, 0x43, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x21, - 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, - 0x65, 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, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, - 0x72, 0x72, 0x22, 0x4c, 0x0a, 0x1c, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x10, - 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x74, 0x74, 0x6c, - 0x22, 0x47, 0x0a, 0x1d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x22, 0x8e, 0x01, 0x0a, 0x0a, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, - 0x74, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, - 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x6d, - 0x6f, 0x74, 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, - 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x3e, 0x0a, 0x10, 0x63, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0xbb, 0x04, 0x0a, 0x0f, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x12, 0x68, 0x61, 0x6e, 0x64, - 0x73, 0x68, 0x61, 0x6b, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x43, - 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x69, 0x64, 0x5f, 0x72, - 0x65, 0x73, 0x75, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x64, 0x69, 0x64, - 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, - 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x69, - 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x6e, 0x65, 0x67, - 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, - 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x41, 0x0a, 0x1d, 0x6e, 0x65, - 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x5f, 0x69, 0x73, 0x5f, 0x6d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x1a, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x73, 0x4d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x12, 0x1f, 0x0a, - 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x41, - 0x0a, 0x11, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, - 0x10, 0x70, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x73, 0x12, 0x3d, 0x0a, 0x0f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x63, 0x68, - 0x61, 0x69, 0x6e, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x62, 0x2e, - 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x52, 0x0e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x73, - 0x12, 0x42, 0x0a, 0x1d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x1b, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x6f, 0x63, 0x73, 0x70, 0x5f, 0x72, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x6f, 0x63, 0x73, - 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6c, 0x73, - 0x5f, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, - 0x6c, 0x73, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x22, 0x2a, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x73, 0x6e, 0x31, 0x5f, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x73, 0x6e, 0x31, - 0x44, 0x61, 0x74, 0x61, 0x22, 0x47, 0x0a, 0x10, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x63, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, - 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, - 0x0c, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x22, 0x5b, 0x0a, - 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x28, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x12, 0x2e, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x44, - 0x61, 0x74, 0x61, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x32, 0xa5, 0x03, 0x0a, 0x07, 0x42, - 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x12, 0x3e, 0x0a, 0x0d, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x61, 0x6e, - 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x16, - 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x30, 0x0a, 0x0c, 0x53, 0x70, 0x65, 0x63, 0x69, 0x61, - 0x6c, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x70, 0x65, 0x63, 0x69, 0x61, 0x6c, 0x50, 0x61, - 0x74, 0x68, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x53, 0x0a, 0x14, 0x48, 0x61, 0x6e, 0x64, - 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x12, 0x1c, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, - 0x74, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x1d, - 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x65, - 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1f, 0x0a, - 0x07, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x75, 0x70, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x31, - 0x0a, 0x0d, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, - 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4b, - 0x65, 0x79, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x12, 0x26, 0x0a, 0x05, 0x53, 0x65, 0x74, 0x75, 0x70, 0x12, 0x0d, 0x2e, 0x70, 0x62, 0x2e, - 0x53, 0x65, 0x74, 0x75, 0x70, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x53, - 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x35, 0x0a, 0x0a, 0x49, 0x6e, 0x69, - 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x69, - 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x13, 0x2e, 0x70, 0x62, - 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x12, 0x20, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x32, 0xd5, 0x01, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x31, - 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x14, 0x2e, 0x70, 0x62, - 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x12, 0x2e, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x47, 0x65, 0x74, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x13, 0x2e, 0x70, - 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x12, 0x2e, 0x0a, 0x03, 0x50, 0x75, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x50, 0x75, 0x74, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x13, 0x2e, 0x70, - 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x50, 0x75, 0x74, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x12, 0x37, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x70, 0x62, - 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x72, - 0x67, 0x73, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x32, 0xbf, 0x06, 0x0a, 0x0a, 0x53, - 0x79, 0x73, 0x74, 0x65, 0x6d, 0x56, 0x69, 0x65, 0x77, 0x12, 0x2a, 0x0a, 0x0f, 0x44, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x54, 0x54, 0x4c, 0x12, 0x09, 0x2e, 0x70, - 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x54, 0x4c, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x0b, 0x4d, 0x61, 0x78, 0x4c, 0x65, 0x61, 0x73, - 0x65, 0x54, 0x54, 0x4c, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, - 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x54, 0x4c, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, - 0x07, 0x54, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x64, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x64, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x36, 0x0a, 0x0f, 0x43, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, - 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, - 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x38, 0x0a, - 0x10, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x70, - 0x62, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x47, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x2e, 0x70, 0x62, - 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, 0x44, 0x61, 0x74, - 0x61, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x19, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x12, 0x30, 0x0a, 0x0c, 0x4d, 0x6c, 0x6f, 0x63, 0x6b, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x90, 0x01, 0x0a, 0x10, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x49, + 0x6e, 0x70, 0x75, 0x74, 0x12, 0x33, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, + 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x6f, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, + 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x22, 0x3f, 0x0a, 0x1c, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x22, 0x8e, 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, + 0x64, 0x64, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, + 0x50, 0x6f, 0x72, 0x74, 0x12, 0x3e, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x22, 0xbb, 0x04, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x12, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x5f, + 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, + 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x69, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x64, 0x69, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, + 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, + 0x69, 0x74, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x12, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x41, 0x0a, 0x1d, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, + 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x73, 0x5f, 0x6d, + 0x75, 0x74, 0x75, 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x6e, 0x65, 0x67, + 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, + 0x73, 0x4d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x65, 0x65, 0x72, + 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x10, 0x70, 0x65, 0x65, 0x72, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x12, 0x3d, 0x0a, 0x0f, 0x76, + 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x09, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x0e, 0x76, 0x65, 0x72, 0x69, + 0x66, 0x69, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x42, 0x0a, 0x1d, 0x73, 0x69, + 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, + 0x0c, 0x52, 0x1b, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x12, 0x23, + 0x0a, 0x0d, 0x6f, 0x63, 0x73, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6c, 0x73, 0x5f, 0x75, 0x6e, 0x69, 0x71, 0x75, + 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x6c, 0x73, 0x55, 0x6e, 0x69, 0x71, + 0x75, 0x65, 0x22, 0x2a, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x73, 0x6e, 0x31, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x73, 0x6e, 0x31, 0x44, 0x61, 0x74, 0x61, 0x22, 0x47, + 0x0a, 0x10, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x63, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x22, 0x5b, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6f, 0x67, 0x69, + 0x63, 0x61, 0x6c, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x44, 0x61, 0x74, 0x61, 0x52, 0x05, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x32, 0xa5, 0x03, 0x0a, 0x07, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, + 0x12, 0x3e, 0x0a, 0x0d, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x61, + 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x12, 0x30, 0x0a, 0x0c, 0x53, 0x70, 0x65, 0x63, 0x69, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x70, 0x62, - 0x2e, 0x4d, 0x6c, 0x6f, 0x63, 0x6b, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x2c, 0x0a, 0x0a, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4d, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x13, 0x2e, 0x70, 0x62, - 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x12, 0x35, 0x0a, 0x0a, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, - 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x41, 0x72, - 0x67, 0x73, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2a, 0x0a, 0x09, 0x50, 0x6c, 0x75, 0x67, 0x69, - 0x6e, 0x45, 0x6e, 0x76, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, - 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x45, 0x6e, 0x76, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x12, 0x3f, 0x0a, 0x0f, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x46, 0x6f, 0x72, - 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x18, 0x2e, 0x70, 0x62, 0x2e, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x46, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x12, 0x68, 0x0a, 0x1a, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x12, 0x25, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x62, 0x2e, 0x47, - 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x46, - 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2e, - 0x0a, 0x0b, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x09, 0x2e, - 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x5c, - 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, - 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x62, 0x2e, 0x47, - 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x36, 0x0a, 0x06, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x12, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x70, 0x62, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x53, 0x70, 0x65, 0x63, 0x69, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x12, 0x53, 0x0a, 0x14, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, + 0x74, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x1c, 0x2e, 0x70, 0x62, 0x2e, + 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x1d, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x61, + 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x07, 0x43, 0x6c, 0x65, 0x61, 0x6e, + 0x75, 0x70, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x09, 0x2e, + 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x31, 0x0a, 0x0d, 0x49, 0x6e, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x49, + 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x72, 0x67, 0x73, + 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x26, 0x0a, 0x05, 0x53, + 0x65, 0x74, 0x75, 0x70, 0x12, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x74, 0x75, 0x70, 0x41, + 0x72, 0x67, 0x73, 0x1a, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x12, 0x35, 0x0a, 0x0a, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x65, 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x65, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, + 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x20, 0x0a, 0x04, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0d, 0x2e, + 0x70, 0x62, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x32, 0xd5, 0x01, 0x0a, + 0x07, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, + 0x74, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x03, 0x47, + 0x65, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x47, + 0x65, 0x74, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x03, 0x50, + 0x75, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x50, + 0x75, 0x74, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x50, 0x75, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x37, 0x0a, 0x06, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x16, 0x2e, 0x70, + 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x32, 0xdd, 0x07, 0x0a, 0x0a, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x56, + 0x69, 0x65, 0x77, 0x12, 0x2a, 0x0a, 0x0f, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4c, 0x65, + 0x61, 0x73, 0x65, 0x54, 0x54, 0x4c, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x1a, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x54, 0x4c, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, + 0x26, 0x0a, 0x0b, 0x4d, 0x61, 0x78, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x54, 0x54, 0x4c, 0x12, 0x09, + 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, + 0x54, 0x4c, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x07, 0x54, 0x61, 0x69, 0x6e, 0x74, + 0x65, 0x64, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x10, 0x2e, + 0x70, 0x62, 0x2e, 0x54, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, + 0x36, 0x0a, 0x0f, 0x43, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x18, 0x2e, + 0x70, 0x62, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x38, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x09, 0x2e, 0x70, 0x62, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x47, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, + 0x70, 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, 0x44, 0x61, 0x74, 0x61, 0x41, 0x72, 0x67, 0x73, 0x1a, + 0x19, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, + 0x70, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x30, 0x0a, 0x0c, 0x4d, 0x6c, + 0x6f, 0x63, 0x6b, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x6c, 0x6f, 0x63, 0x6b, + 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2c, 0x0a, 0x0a, + 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, + 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x35, 0x0a, 0x0a, 0x45, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x13, 0x2e, 0x70, + 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x2a, 0x0a, 0x09, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x45, 0x6e, 0x76, 0x12, 0x09, + 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x50, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x45, 0x6e, 0x76, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x3f, 0x0a, + 0x0f, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x46, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, + 0x41, 0x72, 0x67, 0x73, 0x1a, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, + 0x46, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x68, + 0x0a, 0x1a, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x25, 0x2e, 0x70, + 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x0b, 0x43, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x5c, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x20, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x12, 0x1e, 0x2e, + 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, + 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, + 0x0a, 0x15, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x12, 0x20, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x72, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, + 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x32, 0x36, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2c, + 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x2e, 0x70, 0x62, + 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x2a, 0x5a, 0x28, + 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, 0x73, 0x64, 0x6b, 0x2f, 0x70, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -4179,7 +4370,7 @@ func file_sdk_plugin_pb_backend_proto_rawDescGZIP() []byte { return file_sdk_plugin_pb_backend_proto_rawDescData } -var file_sdk_plugin_pb_backend_proto_msgTypes = make([]protoimpl.MessageInfo, 60) +var file_sdk_plugin_pb_backend_proto_msgTypes = make([]protoimpl.MessageInfo, 64) var file_sdk_plugin_pb_backend_proto_goTypes = []any{ (*Empty)(nil), // 0: pb.Empty (*Header)(nil), // 1: pb.Header @@ -4230,43 +4421,48 @@ var file_sdk_plugin_pb_backend_proto_goTypes = []any{ (*ClusterInfoReply)(nil), // 46: pb.ClusterInfoReply (*GenerateIdentityTokenRequest)(nil), // 47: pb.GenerateIdentityTokenRequest (*GenerateIdentityTokenResponse)(nil), // 48: pb.GenerateIdentityTokenResponse - (*Connection)(nil), // 49: pb.Connection - (*ConnectionState)(nil), // 50: pb.ConnectionState - (*Certificate)(nil), // 51: pb.Certificate - (*CertificateChain)(nil), // 52: pb.CertificateChain - (*SendEventRequest)(nil), // 53: pb.SendEventRequest - nil, // 54: pb.Request.HeadersEntry - nil, // 55: pb.Auth.MetadataEntry - nil, // 56: pb.TokenEntry.MetaEntry - nil, // 57: pb.TokenEntry.InternalMetaEntry - nil, // 58: pb.Response.HeadersEntry - nil, // 59: pb.SetupArgs.ConfigEntry - (*logical.Alias)(nil), // 60: logical.Alias - (*timestamppb.Timestamp)(nil), // 61: google.protobuf.Timestamp - (*logical.Entity)(nil), // 62: logical.Entity - (*logical.Group)(nil), // 63: logical.Group - (*logical.PluginEnvironment)(nil), // 64: logical.PluginEnvironment - (*logical.EventData)(nil), // 65: logical.EventData + (*RegisterRotationJobRequest)(nil), // 49: pb.RegisterRotationJobRequest + (*RegisterRotationJobResponse)(nil), // 50: pb.RegisterRotationJobResponse + (*RotationJobInput)(nil), // 51: pb.RotationJobInput + (*DeregisterRotationJobRequest)(nil), // 52: pb.DeregisterRotationJobRequest + (*Connection)(nil), // 53: pb.Connection + (*ConnectionState)(nil), // 54: pb.ConnectionState + (*Certificate)(nil), // 55: pb.Certificate + (*CertificateChain)(nil), // 56: pb.CertificateChain + (*SendEventRequest)(nil), // 57: pb.SendEventRequest + nil, // 58: pb.Request.HeadersEntry + nil, // 59: pb.Auth.MetadataEntry + nil, // 60: pb.TokenEntry.MetaEntry + nil, // 61: pb.TokenEntry.InternalMetaEntry + nil, // 62: pb.Response.HeadersEntry + nil, // 63: pb.SetupArgs.ConfigEntry + (*logical.Alias)(nil), // 64: logical.Alias + (*timestamppb.Timestamp)(nil), // 65: google.protobuf.Timestamp + (*logical.Entity)(nil), // 66: logical.Entity + (*logical.Group)(nil), // 67: logical.Group + (*logical.PluginEnvironment)(nil), // 68: logical.PluginEnvironment + (*structpb.Struct)(nil), // 69: google.protobuf.Struct + (*logical.EventData)(nil), // 70: logical.EventData } var file_sdk_plugin_pb_backend_proto_depIDxs = []int32{ 8, // 0: pb.Request.secret:type_name -> pb.Secret 5, // 1: pb.Request.auth:type_name -> pb.Auth - 54, // 2: pb.Request.headers:type_name -> pb.Request.HeadersEntry + 58, // 2: pb.Request.headers:type_name -> pb.Request.HeadersEntry 11, // 3: pb.Request.wrap_info:type_name -> pb.RequestWrapInfo - 49, // 4: pb.Request.connection:type_name -> pb.Connection + 53, // 4: pb.Request.connection:type_name -> pb.Connection 7, // 5: pb.Auth.lease_options:type_name -> pb.LeaseOptions - 55, // 6: pb.Auth.metadata:type_name -> pb.Auth.MetadataEntry - 60, // 7: pb.Auth.alias:type_name -> logical.Alias - 60, // 8: pb.Auth.group_aliases:type_name -> logical.Alias - 56, // 9: pb.TokenEntry.meta:type_name -> pb.TokenEntry.MetaEntry - 57, // 10: pb.TokenEntry.internal_meta:type_name -> pb.TokenEntry.InternalMetaEntry - 61, // 11: pb.LeaseOptions.issue_time:type_name -> google.protobuf.Timestamp + 59, // 6: pb.Auth.metadata:type_name -> pb.Auth.MetadataEntry + 64, // 7: pb.Auth.alias:type_name -> logical.Alias + 64, // 8: pb.Auth.group_aliases:type_name -> logical.Alias + 60, // 9: pb.TokenEntry.meta:type_name -> pb.TokenEntry.MetaEntry + 61, // 10: pb.TokenEntry.internal_meta:type_name -> pb.TokenEntry.InternalMetaEntry + 65, // 11: pb.LeaseOptions.issue_time:type_name -> google.protobuf.Timestamp 7, // 12: pb.Secret.lease_options:type_name -> pb.LeaseOptions 8, // 13: pb.Response.secret:type_name -> pb.Secret 5, // 14: pb.Response.auth:type_name -> pb.Auth 10, // 15: pb.Response.wrap_info:type_name -> pb.ResponseWrapInfo - 58, // 16: pb.Response.headers:type_name -> pb.Response.HeadersEntry - 61, // 17: pb.ResponseWrapInfo.creation_time:type_name -> google.protobuf.Timestamp + 62, // 16: pb.Response.headers:type_name -> pb.Response.HeadersEntry + 65, // 17: pb.ResponseWrapInfo.creation_time:type_name -> google.protobuf.Timestamp 4, // 18: pb.HandleRequestArgs.request:type_name -> pb.Request 9, // 19: pb.HandleRequestReply.response:type_name -> pb.Response 2, // 20: pb.HandleRequestReply.err:type_name -> pb.ProtoError @@ -4274,79 +4470,85 @@ var file_sdk_plugin_pb_backend_proto_depIDxs = []int32{ 3, // 22: pb.SpecialPathsReply.paths:type_name -> pb.Paths 4, // 23: pb.HandleExistenceCheckArgs.request:type_name -> pb.Request 2, // 24: pb.HandleExistenceCheckReply.err:type_name -> pb.ProtoError - 59, // 25: pb.SetupArgs.Config:type_name -> pb.SetupArgs.ConfigEntry + 63, // 25: pb.SetupArgs.Config:type_name -> pb.SetupArgs.ConfigEntry 23, // 26: pb.StorageGetReply.entry:type_name -> pb.StorageEntry 23, // 27: pb.StoragePutArgs.entry:type_name -> pb.StorageEntry 10, // 28: pb.ResponseWrapDataReply.wrap_info:type_name -> pb.ResponseWrapInfo - 62, // 29: pb.EntityInfoReply.entity:type_name -> logical.Entity - 63, // 30: pb.GroupsForEntityReply.groups:type_name -> logical.Group - 64, // 31: pb.PluginEnvReply.plugin_environment:type_name -> logical.PluginEnvironment - 50, // 32: pb.Connection.connection_state:type_name -> pb.ConnectionState - 52, // 33: pb.ConnectionState.peer_certificates:type_name -> pb.CertificateChain - 52, // 34: pb.ConnectionState.verified_chains:type_name -> pb.CertificateChain - 51, // 35: pb.CertificateChain.certificates:type_name -> pb.Certificate - 65, // 36: pb.SendEventRequest.event:type_name -> logical.EventData - 1, // 37: pb.Request.HeadersEntry.value:type_name -> pb.Header - 1, // 38: pb.Response.HeadersEntry.value:type_name -> pb.Header - 12, // 39: pb.Backend.HandleRequest:input_type -> pb.HandleRequestArgs - 0, // 40: pb.Backend.SpecialPaths:input_type -> pb.Empty - 17, // 41: pb.Backend.HandleExistenceCheck:input_type -> pb.HandleExistenceCheckArgs - 0, // 42: pb.Backend.Cleanup:input_type -> pb.Empty - 22, // 43: pb.Backend.InvalidateKey:input_type -> pb.InvalidateKeyArgs - 19, // 44: pb.Backend.Setup:input_type -> pb.SetupArgs - 14, // 45: pb.Backend.Initialize:input_type -> pb.InitializeArgs - 0, // 46: pb.Backend.Type:input_type -> pb.Empty - 24, // 47: pb.Storage.List:input_type -> pb.StorageListArgs - 26, // 48: pb.Storage.Get:input_type -> pb.StorageGetArgs - 28, // 49: pb.Storage.Put:input_type -> pb.StoragePutArgs - 30, // 50: pb.Storage.Delete:input_type -> pb.StorageDeleteArgs - 0, // 51: pb.SystemView.DefaultLeaseTTL:input_type -> pb.Empty - 0, // 52: pb.SystemView.MaxLeaseTTL:input_type -> pb.Empty - 0, // 53: pb.SystemView.Tainted:input_type -> pb.Empty - 0, // 54: pb.SystemView.CachingDisabled:input_type -> pb.Empty - 0, // 55: pb.SystemView.ReplicationState:input_type -> pb.Empty - 36, // 56: pb.SystemView.ResponseWrapData:input_type -> pb.ResponseWrapDataArgs - 0, // 57: pb.SystemView.MlockEnabled:input_type -> pb.Empty - 0, // 58: pb.SystemView.LocalMount:input_type -> pb.Empty - 40, // 59: pb.SystemView.EntityInfo:input_type -> pb.EntityInfoArgs - 0, // 60: pb.SystemView.PluginEnv:input_type -> pb.Empty - 40, // 61: pb.SystemView.GroupsForEntity:input_type -> pb.EntityInfoArgs - 44, // 62: pb.SystemView.GeneratePasswordFromPolicy:input_type -> pb.GeneratePasswordFromPolicyRequest - 0, // 63: pb.SystemView.ClusterInfo:input_type -> pb.Empty - 47, // 64: pb.SystemView.GenerateIdentityToken:input_type -> pb.GenerateIdentityTokenRequest - 53, // 65: pb.Events.SendEvent:input_type -> pb.SendEventRequest - 13, // 66: pb.Backend.HandleRequest:output_type -> pb.HandleRequestReply - 16, // 67: pb.Backend.SpecialPaths:output_type -> pb.SpecialPathsReply - 18, // 68: pb.Backend.HandleExistenceCheck:output_type -> pb.HandleExistenceCheckReply - 0, // 69: pb.Backend.Cleanup:output_type -> pb.Empty - 0, // 70: pb.Backend.InvalidateKey:output_type -> pb.Empty - 20, // 71: pb.Backend.Setup:output_type -> pb.SetupReply - 15, // 72: pb.Backend.Initialize:output_type -> pb.InitializeReply - 21, // 73: pb.Backend.Type:output_type -> pb.TypeReply - 25, // 74: pb.Storage.List:output_type -> pb.StorageListReply - 27, // 75: pb.Storage.Get:output_type -> pb.StorageGetReply - 29, // 76: pb.Storage.Put:output_type -> pb.StoragePutReply - 31, // 77: pb.Storage.Delete:output_type -> pb.StorageDeleteReply - 32, // 78: pb.SystemView.DefaultLeaseTTL:output_type -> pb.TTLReply - 32, // 79: pb.SystemView.MaxLeaseTTL:output_type -> pb.TTLReply - 33, // 80: pb.SystemView.Tainted:output_type -> pb.TaintedReply - 34, // 81: pb.SystemView.CachingDisabled:output_type -> pb.CachingDisabledReply - 35, // 82: pb.SystemView.ReplicationState:output_type -> pb.ReplicationStateReply - 37, // 83: pb.SystemView.ResponseWrapData:output_type -> pb.ResponseWrapDataReply - 38, // 84: pb.SystemView.MlockEnabled:output_type -> pb.MlockEnabledReply - 39, // 85: pb.SystemView.LocalMount:output_type -> pb.LocalMountReply - 41, // 86: pb.SystemView.EntityInfo:output_type -> pb.EntityInfoReply - 43, // 87: pb.SystemView.PluginEnv:output_type -> pb.PluginEnvReply - 42, // 88: pb.SystemView.GroupsForEntity:output_type -> pb.GroupsForEntityReply - 45, // 89: pb.SystemView.GeneratePasswordFromPolicy:output_type -> pb.GeneratePasswordFromPolicyReply - 46, // 90: pb.SystemView.ClusterInfo:output_type -> pb.ClusterInfoReply - 48, // 91: pb.SystemView.GenerateIdentityToken:output_type -> pb.GenerateIdentityTokenResponse - 0, // 92: pb.Events.SendEvent:output_type -> pb.Empty - 66, // [66:93] is the sub-list for method output_type - 39, // [39:66] is the sub-list for method input_type - 39, // [39:39] is the sub-list for extension type_name - 39, // [39:39] is the sub-list for extension extendee - 0, // [0:39] is the sub-list for field type_name + 66, // 29: pb.EntityInfoReply.entity:type_name -> logical.Entity + 67, // 30: pb.GroupsForEntityReply.groups:type_name -> logical.Group + 68, // 31: pb.PluginEnvReply.plugin_environment:type_name -> logical.PluginEnvironment + 51, // 32: pb.RegisterRotationJobRequest.job:type_name -> pb.RotationJobInput + 69, // 33: pb.RotationJobInput.schedule:type_name -> google.protobuf.Struct + 54, // 34: pb.Connection.connection_state:type_name -> pb.ConnectionState + 56, // 35: pb.ConnectionState.peer_certificates:type_name -> pb.CertificateChain + 56, // 36: pb.ConnectionState.verified_chains:type_name -> pb.CertificateChain + 55, // 37: pb.CertificateChain.certificates:type_name -> pb.Certificate + 70, // 38: pb.SendEventRequest.event:type_name -> logical.EventData + 1, // 39: pb.Request.HeadersEntry.value:type_name -> pb.Header + 1, // 40: pb.Response.HeadersEntry.value:type_name -> pb.Header + 12, // 41: pb.Backend.HandleRequest:input_type -> pb.HandleRequestArgs + 0, // 42: pb.Backend.SpecialPaths:input_type -> pb.Empty + 17, // 43: pb.Backend.HandleExistenceCheck:input_type -> pb.HandleExistenceCheckArgs + 0, // 44: pb.Backend.Cleanup:input_type -> pb.Empty + 22, // 45: pb.Backend.InvalidateKey:input_type -> pb.InvalidateKeyArgs + 19, // 46: pb.Backend.Setup:input_type -> pb.SetupArgs + 14, // 47: pb.Backend.Initialize:input_type -> pb.InitializeArgs + 0, // 48: pb.Backend.Type:input_type -> pb.Empty + 24, // 49: pb.Storage.List:input_type -> pb.StorageListArgs + 26, // 50: pb.Storage.Get:input_type -> pb.StorageGetArgs + 28, // 51: pb.Storage.Put:input_type -> pb.StoragePutArgs + 30, // 52: pb.Storage.Delete:input_type -> pb.StorageDeleteArgs + 0, // 53: pb.SystemView.DefaultLeaseTTL:input_type -> pb.Empty + 0, // 54: pb.SystemView.MaxLeaseTTL:input_type -> pb.Empty + 0, // 55: pb.SystemView.Tainted:input_type -> pb.Empty + 0, // 56: pb.SystemView.CachingDisabled:input_type -> pb.Empty + 0, // 57: pb.SystemView.ReplicationState:input_type -> pb.Empty + 36, // 58: pb.SystemView.ResponseWrapData:input_type -> pb.ResponseWrapDataArgs + 0, // 59: pb.SystemView.MlockEnabled:input_type -> pb.Empty + 0, // 60: pb.SystemView.LocalMount:input_type -> pb.Empty + 40, // 61: pb.SystemView.EntityInfo:input_type -> pb.EntityInfoArgs + 0, // 62: pb.SystemView.PluginEnv:input_type -> pb.Empty + 40, // 63: pb.SystemView.GroupsForEntity:input_type -> pb.EntityInfoArgs + 44, // 64: pb.SystemView.GeneratePasswordFromPolicy:input_type -> pb.GeneratePasswordFromPolicyRequest + 0, // 65: pb.SystemView.ClusterInfo:input_type -> pb.Empty + 47, // 66: pb.SystemView.GenerateIdentityToken:input_type -> pb.GenerateIdentityTokenRequest + 49, // 67: pb.SystemView.RegisterRotationJob:input_type -> pb.RegisterRotationJobRequest + 52, // 68: pb.SystemView.DeregisterRotationJob:input_type -> pb.DeregisterRotationJobRequest + 57, // 69: pb.Events.SendEvent:input_type -> pb.SendEventRequest + 13, // 70: pb.Backend.HandleRequest:output_type -> pb.HandleRequestReply + 16, // 71: pb.Backend.SpecialPaths:output_type -> pb.SpecialPathsReply + 18, // 72: pb.Backend.HandleExistenceCheck:output_type -> pb.HandleExistenceCheckReply + 0, // 73: pb.Backend.Cleanup:output_type -> pb.Empty + 0, // 74: pb.Backend.InvalidateKey:output_type -> pb.Empty + 20, // 75: pb.Backend.Setup:output_type -> pb.SetupReply + 15, // 76: pb.Backend.Initialize:output_type -> pb.InitializeReply + 21, // 77: pb.Backend.Type:output_type -> pb.TypeReply + 25, // 78: pb.Storage.List:output_type -> pb.StorageListReply + 27, // 79: pb.Storage.Get:output_type -> pb.StorageGetReply + 29, // 80: pb.Storage.Put:output_type -> pb.StoragePutReply + 31, // 81: pb.Storage.Delete:output_type -> pb.StorageDeleteReply + 32, // 82: pb.SystemView.DefaultLeaseTTL:output_type -> pb.TTLReply + 32, // 83: pb.SystemView.MaxLeaseTTL:output_type -> pb.TTLReply + 33, // 84: pb.SystemView.Tainted:output_type -> pb.TaintedReply + 34, // 85: pb.SystemView.CachingDisabled:output_type -> pb.CachingDisabledReply + 35, // 86: pb.SystemView.ReplicationState:output_type -> pb.ReplicationStateReply + 37, // 87: pb.SystemView.ResponseWrapData:output_type -> pb.ResponseWrapDataReply + 38, // 88: pb.SystemView.MlockEnabled:output_type -> pb.MlockEnabledReply + 39, // 89: pb.SystemView.LocalMount:output_type -> pb.LocalMountReply + 41, // 90: pb.SystemView.EntityInfo:output_type -> pb.EntityInfoReply + 43, // 91: pb.SystemView.PluginEnv:output_type -> pb.PluginEnvReply + 42, // 92: pb.SystemView.GroupsForEntity:output_type -> pb.GroupsForEntityReply + 45, // 93: pb.SystemView.GeneratePasswordFromPolicy:output_type -> pb.GeneratePasswordFromPolicyReply + 46, // 94: pb.SystemView.ClusterInfo:output_type -> pb.ClusterInfoReply + 48, // 95: pb.SystemView.GenerateIdentityToken:output_type -> pb.GenerateIdentityTokenResponse + 50, // 96: pb.SystemView.RegisterRotationJob:output_type -> pb.RegisterRotationJobResponse + 0, // 97: pb.SystemView.DeregisterRotationJob:output_type -> pb.Empty + 0, // 98: pb.Events.SendEvent:output_type -> pb.Empty + 70, // [70:99] is the sub-list for method output_type + 41, // [41:70] is the sub-list for method input_type + 41, // [41:41] is the sub-list for extension type_name + 41, // [41:41] is the sub-list for extension extendee + 0, // [0:41] is the sub-list for field type_name } func init() { file_sdk_plugin_pb_backend_proto_init() } @@ -4360,7 +4562,7 @@ func file_sdk_plugin_pb_backend_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_sdk_plugin_pb_backend_proto_rawDesc, NumEnums: 0, - NumMessages: 60, + NumMessages: 64, NumExtensions: 0, NumServices: 4, }, diff --git a/sdk/plugin/pb/backend.proto b/sdk/plugin/pb/backend.proto index cf0f47d8dbe7..1bf023726505 100644 --- a/sdk/plugin/pb/backend.proto +++ b/sdk/plugin/pb/backend.proto @@ -5,6 +5,7 @@ syntax = "proto3"; package pb; import "google/protobuf/timestamp.proto"; +import "google/protobuf/struct.proto"; import "sdk/logical/event.proto"; import "sdk/logical/identity.proto"; import "sdk/logical/plugin.proto"; @@ -607,6 +608,26 @@ message GenerateIdentityTokenResponse { int64 ttl = 2; } +message RegisterRotationJobRequest { + RotationJobInput job = 1; +} + +message RegisterRotationJobResponse { + string rotation_id = 1; + string err = 2; +} + +message RotationJobInput { + google.protobuf.Struct schedule = 1; + string rotation_id = 2; + string path = 3; + string name = 4; +} + +message DeregisterRotationJobRequest { + string rotation_id = 1; +} + // SystemView exposes system configuration information in a safe way for plugins // to consume. Plugins should implement the client for this service. service SystemView { @@ -665,6 +686,12 @@ service SystemView { // GenerateIdentityToken returns an identity token for the requesting plugin. rpc GenerateIdentityToken(GenerateIdentityTokenRequest) returns (GenerateIdentityTokenResponse); + + // RegisterRotationJob returns a rotation ID for the requested plugin credential. + rpc RegisterRotationJob(RegisterRotationJobRequest) returns (RegisterRotationJobResponse); + + // DeregisterRotationJob returns any errors in de-registering a credential from the Rotation Manager. + rpc DeregisterRotationJob(DeregisterRotationJobRequest) returns (Empty); } message Connection { diff --git a/sdk/plugin/pb/backend_grpc.pb.go b/sdk/plugin/pb/backend_grpc.pb.go index 65d59ae77abc..8c15395f7d5b 100644 --- a/sdk/plugin/pb/backend_grpc.pb.go +++ b/sdk/plugin/pb/backend_grpc.pb.go @@ -688,6 +688,8 @@ const ( SystemView_GeneratePasswordFromPolicy_FullMethodName = "/pb.SystemView/GeneratePasswordFromPolicy" SystemView_ClusterInfo_FullMethodName = "/pb.SystemView/ClusterInfo" SystemView_GenerateIdentityToken_FullMethodName = "/pb.SystemView/GenerateIdentityToken" + SystemView_RegisterRotationJob_FullMethodName = "/pb.SystemView/RegisterRotationJob" + SystemView_DeregisterRotationJob_FullMethodName = "/pb.SystemView/DeregisterRotationJob" ) // SystemViewClient is the client API for SystemView service. @@ -739,6 +741,10 @@ type SystemViewClient interface { ClusterInfo(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*ClusterInfoReply, error) // GenerateIdentityToken returns an identity token for the requesting plugin. GenerateIdentityToken(ctx context.Context, in *GenerateIdentityTokenRequest, opts ...grpc.CallOption) (*GenerateIdentityTokenResponse, error) + // RegisterRotationJob returns a rotation ID for the requested plugin credential. + RegisterRotationJob(ctx context.Context, in *RegisterRotationJobRequest, opts ...grpc.CallOption) (*RegisterRotationJobResponse, error) + // DeregisterRotationJob returns any errors in de-registering a credential from the Rotation Manager. + DeregisterRotationJob(ctx context.Context, in *DeregisterRotationJobRequest, opts ...grpc.CallOption) (*Empty, error) } type systemViewClient struct { @@ -889,6 +895,26 @@ func (c *systemViewClient) GenerateIdentityToken(ctx context.Context, in *Genera return out, nil } +func (c *systemViewClient) RegisterRotationJob(ctx context.Context, in *RegisterRotationJobRequest, opts ...grpc.CallOption) (*RegisterRotationJobResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RegisterRotationJobResponse) + err := c.cc.Invoke(ctx, SystemView_RegisterRotationJob_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *systemViewClient) DeregisterRotationJob(ctx context.Context, in *DeregisterRotationJobRequest, opts ...grpc.CallOption) (*Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Empty) + err := c.cc.Invoke(ctx, SystemView_DeregisterRotationJob_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // SystemViewServer is the server API for SystemView service. // All implementations must embed UnimplementedSystemViewServer // for forward compatibility. @@ -938,6 +964,10 @@ type SystemViewServer interface { ClusterInfo(context.Context, *Empty) (*ClusterInfoReply, error) // GenerateIdentityToken returns an identity token for the requesting plugin. GenerateIdentityToken(context.Context, *GenerateIdentityTokenRequest) (*GenerateIdentityTokenResponse, error) + // RegisterRotationJob returns a rotation ID for the requested plugin credential. + RegisterRotationJob(context.Context, *RegisterRotationJobRequest) (*RegisterRotationJobResponse, error) + // DeregisterRotationJob returns any errors in de-registering a credential from the Rotation Manager. + DeregisterRotationJob(context.Context, *DeregisterRotationJobRequest) (*Empty, error) mustEmbedUnimplementedSystemViewServer() } @@ -990,6 +1020,12 @@ func (UnimplementedSystemViewServer) ClusterInfo(context.Context, *Empty) (*Clus func (UnimplementedSystemViewServer) GenerateIdentityToken(context.Context, *GenerateIdentityTokenRequest) (*GenerateIdentityTokenResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GenerateIdentityToken not implemented") } +func (UnimplementedSystemViewServer) RegisterRotationJob(context.Context, *RegisterRotationJobRequest) (*RegisterRotationJobResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterRotationJob not implemented") +} +func (UnimplementedSystemViewServer) DeregisterRotationJob(context.Context, *DeregisterRotationJobRequest) (*Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeregisterRotationJob not implemented") +} func (UnimplementedSystemViewServer) mustEmbedUnimplementedSystemViewServer() {} func (UnimplementedSystemViewServer) testEmbeddedByValue() {} @@ -1263,6 +1299,42 @@ func _SystemView_GenerateIdentityToken_Handler(srv interface{}, ctx context.Cont return interceptor(ctx, in, info, handler) } +func _SystemView_RegisterRotationJob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RegisterRotationJobRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SystemViewServer).RegisterRotationJob(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SystemView_RegisterRotationJob_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SystemViewServer).RegisterRotationJob(ctx, req.(*RegisterRotationJobRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _SystemView_DeregisterRotationJob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeregisterRotationJobRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SystemViewServer).DeregisterRotationJob(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SystemView_DeregisterRotationJob_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SystemViewServer).DeregisterRotationJob(ctx, req.(*DeregisterRotationJobRequest)) + } + return interceptor(ctx, in, info, handler) +} + // SystemView_ServiceDesc is the grpc.ServiceDesc for SystemView service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -1326,6 +1398,14 @@ var SystemView_ServiceDesc = grpc.ServiceDesc{ MethodName: "GenerateIdentityToken", Handler: _SystemView_GenerateIdentityToken_Handler, }, + { + MethodName: "RegisterRotationJob", + Handler: _SystemView_RegisterRotationJob_Handler, + }, + { + MethodName: "DeregisterRotationJob", + Handler: _SystemView_DeregisterRotationJob_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "sdk/plugin/pb/backend.proto", diff --git a/sdk/rotation/rotation_job.go b/sdk/rotation/rotation_job.go new file mode 100644 index 000000000000..ec395d06c203 --- /dev/null +++ b/sdk/rotation/rotation_job.go @@ -0,0 +1,105 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package rotation + +import ( + "fmt" + "time" + + "github.com/robfig/cron/v3" +) + +// RotationOptions is an embeddable struct to capture common rotation +// settings between a Secret and Auth +type RotationOptions struct { + // Schedule holds the info for the framework.Schedule + Schedule *RotationSchedule +} + +// RotationJob represents the secret part of a response. +type RotationJob struct { + RotationOptions + + // RotationID is the ID returned to the user to manage this secret. + // This is generated by Vault core. Any set value will be ignored. + // For requests, this will always be blank. + RotationID string `sentinel:""` + Path string + Name string +} + +type RotationJobConfigureRequest struct { + Name string + MountPoint string + ReqPath string + RotationSchedule string + RotationWindow int + RotationPeriod int +} + +func (s *RotationJob) Validate() error { + // TODO: validation? + return nil +} + +func newRotationJob(rotationSchedule, path, rotationJobName string, rotationWindow, ttl int) (*RotationJob, error) { + var cronSc *cron.SpecSchedule + if rotationSchedule != "" { + var err error + cronSc, err = DefaultScheduler.Parse(rotationSchedule) + if err != nil { + return nil, err + } + } + + rs := &RotationSchedule{ + Schedule: cronSc, + RotationSchedule: rotationSchedule, + RotationWindow: time.Duration(rotationWindow) * time.Second, + RotationPeriod: time.Duration(ttl) * time.Second, + // TODO + // decide if next rotation should be set here + // or when we actually push item into queue + NextVaultRotation: time.Time{}, + LastVaultRotation: time.Time{}, + } + + return &RotationJob{ + RotationOptions: RotationOptions{ + Schedule: rs, + }, + // Figure out how to get mount info + Path: path, + Name: rotationJobName, + }, nil +} + +// ConfigureRotationJob builds and returns a configured RotationJob for the mount and request with the given schedule. +func ConfigureRotationJob(configRequest *RotationJobConfigureRequest) (*RotationJob, error) { + mount := configRequest.MountPoint + configRequest.ReqPath + + var rotationJob *RotationJob + if configRequest.RotationSchedule != "" && configRequest.RotationWindow != 0 { + var err error + rotationJob, err = newRotationJob(configRequest.RotationSchedule, mount, configRequest.Name, configRequest.RotationWindow, 0) + if err != nil { + return nil, err + } + } + + if configRequest.RotationPeriod != 0 { + var err error + rotationJob, err = newRotationJob("", mount, configRequest.Name, 0, configRequest.RotationPeriod) + if err != nil { + return nil, err + } + } + + // Expect rotation job to exist here + if rotationJob == nil { + return nil, fmt.Errorf("rotation credential was nil; expected non-nil value") + } + + return rotationJob, nil +} diff --git a/sdk/rotation/schedule.go b/sdk/rotation/schedule.go new file mode 100644 index 000000000000..7c35f3615e62 --- /dev/null +++ b/sdk/rotation/schedule.go @@ -0,0 +1,112 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package rotation + +import ( + "fmt" + "time" + + "github.com/robfig/cron/v3" +) + +const ( + // Minimum allowed value for rotation_window + minRotationWindowSeconds = 3600 + parseOptions = cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow +) + +// RotationSchedule holds the parsed and unparsed versions of the schedule, along with the projected next rotation time. +type RotationSchedule struct { + Schedule *cron.SpecSchedule `json:"schedule"` + RotationWindow time.Duration `json:"rotation_window"` // seconds of window + RotationSchedule string `json:"rotation_schedule"` + RotationPeriod time.Duration `json:"rotation_period"` + NextVaultRotation time.Time `json:"next_vault_rotation"` + LastVaultRotation time.Time `json:"last_vault_rotation"` +} + +type Scheduler interface { + Parse(rotationSchedule string) (*cron.SpecSchedule, error) + ValidateRotationWindow(s int) error + NextRotationTimeFromInput(rs *RotationSchedule, input time.Time) time.Time + IsInsideRotationWindow(rs *RotationSchedule, t time.Time) bool + ShouldRotate(rs *RotationSchedule, priority int64, t time.Time) bool + NextRotationTime(rs *RotationSchedule) time.Time + SetNextVaultRotation(rs *RotationSchedule, t time.Time) + UsesTTL(rs *RotationSchedule) bool + UsesRotationSchedule(rs *RotationSchedule) bool +} + +var DefaultScheduler Scheduler = &DefaultSchedule{} + +type DefaultSchedule struct{} + +func (d *DefaultSchedule) Parse(rotationSchedule string) (*cron.SpecSchedule, error) { + parser := cron.NewParser(parseOptions) + schedule, err := parser.Parse(rotationSchedule) + if err != nil { + return nil, err + } + sched, ok := schedule.(*cron.SpecSchedule) + if !ok { + return nil, fmt.Errorf("invalid rotation schedule") + } + return sched, nil +} + +func (d *DefaultSchedule) ValidateRotationWindow(s int) error { + if s < minRotationWindowSeconds { + return fmt.Errorf("rotation_window must be %d seconds or more", minRotationWindowSeconds) + } + return nil +} + +func (d *DefaultSchedule) UsesRotationSchedule(rs *RotationSchedule) bool { + return rs.RotationSchedule != "" && rs.RotationPeriod == 0 +} + +func (d *DefaultSchedule) UsesTTL(rs *RotationSchedule) bool { + return rs.RotationPeriod != 0 && rs.RotationSchedule == "" +} + +// NextRotationTime calculates the next scheduled rotation +func (d *DefaultSchedule) NextRotationTime(rs *RotationSchedule) time.Time { + if d.UsesTTL(rs) { + return rs.LastVaultRotation.Add(rs.RotationPeriod) + } + return rs.Schedule.Next(time.Now()) +} + +// NextRotationTimeFromInput calculates and returns the next rotation time based on the provided schedule and input time +func (d *DefaultSchedule) NextRotationTimeFromInput(rs *RotationSchedule, input time.Time) time.Time { + if d.UsesTTL(rs) { + return input.Add(rs.RotationPeriod) + } + return rs.Schedule.Next(input) +} + +// IsInsideRotationWindow checks if the current time is before the calculated end of the rotation window, +// to make sure that t time is within the specified rotation window +// It returns true if rotation window is not specified +func (d *DefaultSchedule) IsInsideRotationWindow(rs *RotationSchedule, t time.Time) bool { + if rs.RotationWindow != 0 { + return t.Before(rs.NextVaultRotation.Add(rs.RotationWindow)) + } + return true +} + +// ShouldRotate checks if the rotation should occur based on priority, current time, and rotation window +// It returns true if the priority is less than or equal to the current time and the current time is within the rotation window +func (d *DefaultSchedule) ShouldRotate(rs *RotationSchedule, priority int64, t time.Time) bool { + return priority <= t.Unix() && d.IsInsideRotationWindow(rs, t) +} + +// SetNextVaultRotation calculates the next rotation time of a given schedule based on the time. +func (d *DefaultSchedule) SetNextVaultRotation(rs *RotationSchedule, t time.Time) { + if d.UsesTTL(rs) { + rs.NextVaultRotation = t.Add(rs.RotationPeriod) + } else { + rs.NextVaultRotation = rs.Schedule.Next(t) + } +} diff --git a/ui/app/adapters/gcp/config.js b/ui/app/adapters/gcp/config.js new file mode 100644 index 000000000000..fd2129be1385 --- /dev/null +++ b/ui/app/adapters/gcp/config.js @@ -0,0 +1,26 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: BUSL-1.1 + */ + +import ApplicationAdapter from '../application'; +import { encodePath } from 'vault/utils/path-encoding-helpers'; + +export default class GcpConfig extends ApplicationAdapter { + namespace = 'v1'; + + _url(backend) { + return `${this.buildURL()}/${encodePath(backend)}/config`; + } + + queryRecord(store, type, query) { + const { backend } = query; + return this.ajax(this._url(backend), 'GET').then((resp) => { + return { + ...resp, + id: backend, + backend, + }; + }); + } +} diff --git a/ui/app/adapters/ldap/library.js b/ui/app/adapters/ldap/library.js index 66dca68e4f81..3120b505a74c 100644 --- a/ui/app/adapters/ldap/library.js +++ b/ui/app/adapters/ldap/library.js @@ -7,23 +7,28 @@ import NamedPathAdapter from 'vault/adapters/named-path'; import { encodePath } from 'vault/utils/path-encoding-helpers'; export default class LdapLibraryAdapter extends NamedPathAdapter { - getURL(backend, name) { + // path could be the library name (full path) or just part of the path i.e. west-account/ + _getURL(backend, path) { const base = `${this.buildURL()}/${encodePath(backend)}/library`; - return name ? `${base}/${name}` : base; + return path ? `${base}/${path}` : base; } urlForUpdateRecord(name, modelName, snapshot) { - return this.getURL(snapshot.attr('backend'), name); + // when editing the name IS the full path so we can use "name" instead of "completeLibraryName" here + return this._getURL(snapshot.attr('backend'), name); } urlForDeleteRecord(name, modelName, snapshot) { - return this.getURL(snapshot.attr('backend'), name); + const { backend, completeLibraryName } = snapshot.record; + return this._getURL(backend, completeLibraryName); } query(store, type, query) { - const { backend } = query; - return this.ajax(this.getURL(backend), 'GET', { data: { list: true } }) + const { backend, path_to_library } = query; + // if we have a path_to_library then we're listing subdirectories at a hierarchical library path (i.e west-account/my-library) + const url = this._getURL(backend, path_to_library); + return this.ajax(url, 'GET', { data: { list: true } }) .then((resp) => { - return resp.data.keys.map((name) => ({ name, backend })); + return resp.data.keys.map((name) => ({ name, backend, path_to_library })); }) .catch((error) => { if (error.httpStatus === 404) { @@ -34,11 +39,11 @@ export default class LdapLibraryAdapter extends NamedPathAdapter { } queryRecord(store, type, query) { const { backend, name } = query; - return this.ajax(this.getURL(backend, name), 'GET').then((resp) => ({ ...resp.data, backend, name })); + return this.ajax(this._getURL(backend, name), 'GET').then((resp) => ({ ...resp.data, backend, name })); } fetchStatus(backend, name) { - const url = `${this.getURL(backend, name)}/status`; + const url = `${this._getURL(backend, name)}/status`; return this.ajax(url, 'GET').then((resp) => { const statuses = []; for (const key in resp.data) { @@ -53,7 +58,7 @@ export default class LdapLibraryAdapter extends NamedPathAdapter { }); } checkOutAccount(backend, name, ttl) { - const url = `${this.getURL(backend, name)}/check-out`; + const url = `${this._getURL(backend, name)}/check-out`; return this.ajax(url, 'POST', { data: { ttl } }).then((resp) => { const { lease_id, lease_duration, renewable } = resp; const { service_account_name: account, password } = resp.data; @@ -61,7 +66,7 @@ export default class LdapLibraryAdapter extends NamedPathAdapter { }); } checkInAccount(backend, name, service_account_names) { - const url = `${this.getURL(backend, name)}/check-in`; + const url = `${this._getURL(backend, name)}/check-in`; return this.ajax(url, 'POST', { data: { service_account_names } }).then((resp) => resp.data); } } diff --git a/ui/app/adapters/ldap/role.js b/ui/app/adapters/ldap/role.js index 93bb67db371a..f02d3b79112d 100644 --- a/ui/app/adapters/ldap/role.js +++ b/ui/app/adapters/ldap/role.js @@ -56,8 +56,8 @@ export default class LdapRoleAdapter extends ApplicationAdapter { } urlForDeleteRecord(id, modelName, snapshot) { - const { backend, type, name } = snapshot.record; - return this._getURL(backend, this._pathForRoleType(type), name); + const { backend, type, completeRoleName } = snapshot.record; + return this._getURL(backend, this._pathForRoleType(type), completeRoleName); } /* diff --git a/ui/app/components/dashboard/overview.hbs b/ui/app/components/dashboard/overview.hbs index bc3abf150637..0d56a1007788 100644 --- a/ui/app/components/dashboard/overview.hbs +++ b/ui/app/components/dashboard/overview.hbs @@ -7,12 +7,14 @@
- {{#if (and @version.isEnterprise @isRootNamespace)}} + {{#if @version.isEnterprise}}
- {{#if (has-permission "clients" routeParams="activity")}} + {{#if (and (has-permission "clients" routeParams="activity") this.shouldShowClientCount)}} {{/if}} - {{#if (and (has-permission "status" routeParams="replication") (not (is-empty-value @replication)))}} + {{#if + (and (has-permission "status" routeParams="replication") (not (is-empty-value @replication)) @isRootNamespace) + }}
- {{else}}
diff --git a/ui/app/components/dashboard/overview.ts b/ui/app/components/dashboard/overview.ts new file mode 100644 index 000000000000..06dffea602f4 --- /dev/null +++ b/ui/app/components/dashboard/overview.ts @@ -0,0 +1,46 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: BUSL-1.1 + */ + +import Component from '@glimmer/component'; +import { service } from '@ember/service'; + +import type flagsService from 'vault/services/flags'; +import NamespaceService from 'vault/services/namespace'; + +export type Args = { + isRootNamespace: boolean; + replication: unknown; + secretsEngines: unknown; + vaultConfiguration: unknown; + version: { isEnterprise: boolean }; +}; + +export default class OverviewComponent extends Component { + @service declare readonly flags: flagsService; + @service declare readonly namespace: NamespaceService; + + /** + * the client count card should show in the following conditions + * Self Managed clusters that are running enterprise and showing the `root` namespace + * Managed clusters that are running enterprise and show the `admin` namespace + */ + // for self managed clusters, this is the `root` namespace + // for HVD clusters, this is the `admin` namespace + get shouldShowClientCount() { + const { version, isRootNamespace } = this.args; + const { flags, namespace } = this; + + // don't show client count if this isn't an enterprise cluster + if (!version.isEnterprise) return false; + + // HVD clusters + if (flags.isHvdManaged && namespace.currentNamespace === 'admin') return true; + + // SM clusters + if (isRootNamespace) return true; + + return false; + } +} diff --git a/ui/app/components/secret-engine/configuration-details.hbs b/ui/app/components/secret-engine/configuration-details.hbs index 5a682b2a5655..46410ac748bc 100644 --- a/ui/app/components/secret-engine/configuration-details.hbs +++ b/ui/app/components/secret-engine/configuration-details.hbs @@ -30,12 +30,15 @@ @title="{{@typeDisplay}} not configured" @message="Get started by configuring your {{@typeDisplay}} secrets engine." > - + {{! TODO: short-term conditional to be removed once configuration for gcp is merged. }} + {{#unless (eq @typeDisplay "Google Cloud")}} + + {{/unless}} {{/each}} \ No newline at end of file diff --git a/ui/app/helpers/mountable-secret-engines.js b/ui/app/helpers/mountable-secret-engines.js index 7265ab3d9fd4..6f9b9d4a5c21 100644 --- a/ui/app/helpers/mountable-secret-engines.js +++ b/ui/app/helpers/mountable-secret-engines.js @@ -142,8 +142,7 @@ export function wifEngines() { } // The UI only supports configuration views for these secrets engines. The CLI must be used to manage other engine resources (i.e. roles, credentials). -// Will eventually include gcp. -export const CONFIGURATION_ONLY = ['azure']; +export const CONFIGURATION_ONLY = ['azure', 'gcp']; export function configurationOnly() { return CONFIGURATION_ONLY.slice(); @@ -151,7 +150,7 @@ export function configurationOnly() { // Secret engines that have their own configuration page and actions // These engines do not exist in their own Ember engine. -export const CONFIGURABLE_SECRET_ENGINES = ['aws', 'azure', 'ssh']; +export const CONFIGURABLE_SECRET_ENGINES = ['aws', 'azure', 'gcp', 'ssh']; export function configurableSecretEngines() { return CONFIGURABLE_SECRET_ENGINES.slice(); @@ -161,7 +160,7 @@ export function mountableEngines() { return MOUNTABLE_SECRET_ENGINES.slice(); } // secret engines that have not other views than the mount view and mount details view -export const UNSUPPORTED_ENGINES = ['alicloud', 'consul', 'gcp', 'gcpkms', 'nomad', 'rabbitmq', 'totp']; +export const UNSUPPORTED_ENGINES = ['alicloud', 'consul', 'gcpkms', 'nomad', 'rabbitmq', 'totp']; export function unsupportedEngines() { return UNSUPPORTED_ENGINES.slice(); diff --git a/ui/app/helpers/supported-secret-backends.js b/ui/app/helpers/supported-secret-backends.js index 507887eee876..5ca16fc14892 100644 --- a/ui/app/helpers/supported-secret-backends.js +++ b/ui/app/helpers/supported-secret-backends.js @@ -10,6 +10,7 @@ const SUPPORTED_SECRET_BACKENDS = [ 'azure', 'cubbyhole', 'database', + 'gcp', 'generic', 'keymgmt', 'kmip', diff --git a/ui/app/models/gcp/config.js b/ui/app/models/gcp/config.js new file mode 100644 index 000000000000..3bdbcb18abe7 --- /dev/null +++ b/ui/app/models/gcp/config.js @@ -0,0 +1,71 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: BUSL-1.1 + */ + +import Model, { attr } from '@ember-data/model'; +import { expandAttributeMeta } from 'vault/utils/field-to-attrs'; + +export default class GcpConfig extends Model { + @attr('string') backend; // dynamic path of secret -- set on response from value passed to queryRecord + + /* GCP config fields */ + @attr({ + label: 'Config TTL', + editType: 'ttl', + helperTextDisabled: 'The TTL (time-to-live) of generated tokens.', + }) + ttl; + + @attr({ + label: 'Max TTL', + editType: 'ttl', + helperTextDisabled: + 'Specifies the maximum config TTL (time-to-live) for long-lived credentials (i.e. service account keys).', + }) + maxTtl; + + @attr('string', { + label: 'JSON credentials', + subText: + 'If empty, Vault will use the GOOGLE_APPLICATION_CREDENTIALS environment variable if configured.', + editType: 'file', + docLink: '/vault/docs/secrets/gcp#authentication', + }) + credentials; // obfuscated, never returned by API. + + /* WIF config fields */ + @attr('string', { + subText: + 'The audience claim value for plugin identity tokens. Must match an allowed audience configured for the target IAM OIDC identity provider.', + }) + identityTokenAudience; + + @attr({ + label: 'Identity token TTL', + helperTextDisabled: + 'The TTL of generated tokens. Defaults to 1 hour, toggle on to specify a different value.', + helperTextEnabled: 'The TTL of generated tokens.', + editType: 'ttl', + }) + identityTokenTtl; + + @attr('string', { + subText: 'Email ID for the Service Account to impersonate for Workload Identity Federation.', + }) + serviceAccountEmail; + + configurableParams = [ + 'credentials', + 'serviceAccountEmail', + 'ttl', + 'maxTtl', + 'identityTokenAudience', + 'identityTokenTtl', + ]; + + get displayAttrs() { + const formFields = expandAttributeMeta(this, this.configurableParams); + return formFields.filter((attr) => attr.name !== 'credentials'); + } +} diff --git a/ui/app/models/ldap/library.js b/ui/app/models/ldap/library.js index e66789a6eb1f..972d91569bfe 100644 --- a/ui/app/models/ldap/library.js +++ b/ui/app/models/ldap/library.js @@ -18,6 +18,7 @@ const formFields = ['name', 'service_account_names', 'ttl', 'max_ttl', 'disable_ @withFormFields(formFields) export default class LdapLibraryModel extends Model { @attr('string') backend; // dynamic path of secret -- set on response from value passed to queryRecord + @attr('string') path_to_library; // ancestral path to the library added in the adapter (only exists for nested libraries) @attr('string', { label: 'Library name', @@ -64,6 +65,12 @@ export default class LdapLibraryModel extends Model { }) disable_check_in_enforcement; + get completeLibraryName() { + // if there is a path_to_library then the name is hierarchical + // and we must concat the ancestors with the leaf name to get the full library path + return this.path_to_library ? this.path_to_library + this.name : this.name; + } + get displayFields() { return this.formFields.filter((field) => field.name !== 'service_account_names'); } diff --git a/ui/app/models/ldap/role.js b/ui/app/models/ldap/role.js index 4c2dc68c2f1f..74d0aed000ab 100644 --- a/ui/app/models/ldap/role.js +++ b/ui/app/models/ldap/role.js @@ -163,6 +163,12 @@ export default class LdapRoleModel extends Model { }) rollback_ldif; + get completeRoleName() { + // if there is a path_to_role then the name is hierarchical + // and we must concat the ancestors with the leaf name to get the full role path + return this.path_to_role ? this.path_to_role + this.name : this.name; + } + get isStatic() { return this.type === 'static'; } @@ -224,9 +230,11 @@ export default class LdapRoleModel extends Model { } fetchCredentials() { - return this.store.adapterFor('ldap/role').fetchCredentials(this.backend, this.type, this.name); + return this.store + .adapterFor('ldap/role') + .fetchCredentials(this.backend, this.type, this.completeRoleName); } rotateStaticPassword() { - return this.store.adapterFor('ldap/role').rotateStaticPassword(this.backend, this.name); + return this.store.adapterFor('ldap/role').rotateStaticPassword(this.backend, this.completeRoleName); } } diff --git a/ui/app/models/pki/sign-intermediate.js b/ui/app/models/pki/sign-intermediate.js index 2dfbb7bf6c9a..c5aeff91ebd4 100644 --- a/ui/app/models/pki/sign-intermediate.js +++ b/ui/app/models/pki/sign-intermediate.js @@ -21,7 +21,6 @@ const validations = { 'notBeforeDuration', 'enforceLeafNotAfterBehavior', 'format', - 'permittedDnsDomains', 'maxPathLength', ]) export default class PkiSignIntermediateModel extends PkiCertificateBaseModel { @@ -59,17 +58,53 @@ export default class PkiSignIntermediateModel extends PkiCertificateBaseModel { enforceLeafNotAfterBehavior; @attr({ - label: 'Permitted DNS domains', - subText: - 'DNS domains for which certificates are allowed to be issued or signed by this CA certificate. Enter each value as a new input.', + subText: 'Specifies the maximum path length to encode in the generated certificate. -1 means no limit', + defaultValue: '-1', + }) + maxPathLength; + + /* Name constraint overrides */ + @attr({ + subText: 'DNS domains for which certificates are allowed to be issued or signed by this CA certificate.', }) permittedDnsDomains; @attr({ - subText: 'Specifies the maximum path length to encode in the generated certificate. -1 means no limit', - defaultValue: '-1', + subText: 'Domains for which this certificate is not allowed to sign or issue child certificates.', }) - maxPathLength; + excludedDnsDomains; + + @attr({ + subText: 'Email addresses for which this certificate is not allowed to sign or issue child certificates.', + }) + excludedEmailAddresses; + + @attr({ + subText: + 'IP ranges for which this certificate is not allowed to sign or issue child certificates. Ranges must be specified in the notation of IP address and prefix length, such as "192.0.2.0/24" or "2001:db8::/32", as defined in RFC 4632 and RFC 4291.', + }) + excludedIpRanges; + + @attr({ + subText: 'URI domains for which this certificate is not allowed to sign or issue child certificates.', + }) + excludedUriDomains; + + @attr({ + subText: 'Email addresses for which this certificate is allowed to sign or issue child certificates.', + }) + permittedEmailAddresses; + + @attr({ + subText: + 'IP ranges for which this certificate is allowed to sign or issue child certificates. Ranges must be specified in the notation of IP address and prefix length, such as "192.0.2.0/24" or "2001:db8::/32", as defined in RFC 4632 and RFC 4291.', + }) + permittedIpRanges; + + @attr({ + subText: 'URI domains for which this certificate is allowed to sign or issue child certificates.', + }) + permittedUriDomains; /* Signing Options overrides */ @attr({ diff --git a/ui/app/routes/vault/cluster/secrets/backend/configuration/index.js b/ui/app/routes/vault/cluster/secrets/backend/configuration/index.js index 327ffa4329ff..1386f25eed68 100644 --- a/ui/app/routes/vault/cluster/secrets/backend/configuration/index.js +++ b/ui/app/routes/vault/cluster/secrets/backend/configuration/index.js @@ -63,13 +63,16 @@ export default class SecretsBackendConfigurationRoute extends Route { } fetchConfig(type, id) { + // id is the path where the backend is mounted since there's only one config per engine (often this path is referred to just as backend) switch (type) { case 'aws': return this.fetchAwsConfigs(id); - case 'ssh': - return this.fetchSshCaConfig(id); case 'azure': return this.fetchAzureConfig(id); + case 'gcp': + return this.fetchGcpConfig(id); + case 'ssh': + return this.fetchSshCaConfig(id); default: return reject({ httpStatus: 404, message: 'not found', path: id }); } @@ -104,28 +107,6 @@ export default class SecretsBackendConfigurationRoute extends Route { } } - async fetchIssuer() { - try { - return await this.store.queryRecord('identity/oidc/config', {}); - } catch (e) { - // silently fail if the endpoint is not available or the user doesn't have permission to access it. - return; - } - } - - async fetchSshCaConfig(id) { - try { - return await this.store.queryRecord('ssh/ca-config', { backend: id }); - } catch (e) { - if (e.httpStatus === 400 && e.errors[0] === `keys haven't been configured yet`) { - // When first mounting a SSH engine it throws a 400 error with this specific message. - // We want to catch this situation and return nothing so that the component can handle it correctly. - return; - } - throw e; - } - } - async fetchAzureConfig(id) { try { const azureModel = await this.store.queryRecord('azure/config', { backend: id }); @@ -149,6 +130,49 @@ export default class SecretsBackendConfigurationRoute extends Route { } } + async fetchGcpConfig(id) { + try { + const gcpModel = await this.store.queryRecord('gcp/config', { backend: id }); + let issuer = null; + if (this.version.isEnterprise) { + const WIF_FIELDS = ['identityTokenAudience', 'identityTokenTtl', 'serviceAccountEmail']; + WIF_FIELDS.some((field) => gcpModel[field]) ? (issuer = await this.fetchIssuer()) : null; + } + const configArray = []; + if (gcpModel) configArray.push(gcpModel); + if (issuer) configArray.push(issuer); + return configArray; + } catch (e) { + if (e.httpStatus === 404) { + // a 404 error is thrown when GCP's config hasn't been set yet. + return; + } + throw e; + } + } + + async fetchIssuer() { + try { + return await this.store.queryRecord('identity/oidc/config', {}); + } catch (e) { + // silently fail if the endpoint is not available or the user doesn't have permission to access it. + return; + } + } + + async fetchSshCaConfig(id) { + try { + return await this.store.queryRecord('ssh/ca-config', { backend: id }); + } catch (e) { + if (e.httpStatus === 400 && e.errors[0] === `keys haven't been configured yet`) { + // When first mounting a SSH engine it throws a 400 error with this specific message. + // We want to catch this situation and return nothing so that the component can handle it correctly. + return; + } + throw e; + } + } + setupController(controller, resolvedModel) { super.setupController(controller, resolvedModel); controller.typeDisplay = allEngines().find( diff --git a/ui/app/serializers/gcp/config.js b/ui/app/serializers/gcp/config.js new file mode 100644 index 000000000000..93ab8f103dd3 --- /dev/null +++ b/ui/app/serializers/gcp/config.js @@ -0,0 +1,23 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: BUSL-1.1 + */ + +import ApplicationSerializer from '../application'; + +export default class GcpConfigSerializer extends ApplicationSerializer { + normalizeResponse(store, primaryModelClass, payload, id, requestType) { + if (!payload.data) { + return super.normalizeResponse(...arguments); + } + + const normalizedPayload = { + id: payload.id, + backend: payload.backend, + data: { + ...payload.data, + }, + }; + return super.normalizeResponse(store, primaryModelClass, normalizedPayload, id, requestType); + } +} diff --git a/ui/app/templates/vault/cluster/secrets/backend/configuration/index.hbs b/ui/app/templates/vault/cluster/secrets/backend/configuration/index.hbs index abaef090a3e3..3b3c5c4bf9f4 100644 --- a/ui/app/templates/vault/cluster/secrets/backend/configuration/index.hbs +++ b/ui/app/templates/vault/cluster/secrets/backend/configuration/index.hbs @@ -6,17 +6,20 @@ {{#if this.isConfigurable}} - - - - Configure - - - + {{! TODO: short-term conditional to be removed once configuration for gcp is merged. }} + {{#unless (eq this.typeDisplay "Google Cloud")}} + + + + Configure + + + + {{/unless}} - + {{else}} diff --git a/ui/lib/ldap/addon/components/page/libraries.hbs b/ui/lib/ldap/addon/components/page/libraries.hbs index b881dff58a4a..55f31e266038 100644 --- a/ui/lib/ldap/addon/components/page/libraries.hbs +++ b/ui/lib/ldap/addon/components/page/libraries.hbs @@ -43,10 +43,10 @@ {{else}}
{{#each this.filteredLibraries as |library|}} - + - {{library.name}} + {{library.name}} {{#if (or library.canRead library.canEdit library.canDelete)}} @@ -55,24 +55,36 @@ @icon="more-horizontal" @text="More options" @hasChevron={{false}} - data-test-popup-menu-trigger + data-test-popup-menu-trigger={{library.completeLibraryName}} /> - {{#if library.canEdit}} - Edit - {{/if}} - {{#if library.canRead}} - Details - {{/if}} - {{#if library.canDelete}} + {{#if (this.isHierarchical library.name)}} Delete + data-test-subdirectory + @route="libraries.subdirectory" + @model={{library.completeLibraryName}} + >Content + {{else}} + {{#if library.canEdit}} + Edit + {{/if}} + {{#if library.canRead}} + Details + {{/if}} + {{#if library.canDelete}} + Delete + {{/if}} {{/if}} {{/if}} diff --git a/ui/lib/ldap/addon/components/page/libraries.ts b/ui/lib/ldap/addon/components/page/libraries.ts index 06d7bb35b320..28a4fc688d24 100644 --- a/ui/lib/ldap/addon/components/page/libraries.ts +++ b/ui/lib/ldap/addon/components/page/libraries.ts @@ -14,6 +14,7 @@ import type LdapLibraryModel from 'vault/models/ldap/library'; import type SecretEngineModel from 'vault/models/secret-engine'; import type FlashMessageService from 'vault/services/flash-messages'; import type { Breadcrumb, EngineOwner } from 'vault/vault/app-types'; +import type RouterService from '@ember/routing/router-service'; interface Args { libraries: Array; @@ -24,10 +25,18 @@ interface Args { export default class LdapLibrariesPageComponent extends Component { @service declare readonly flashMessages: FlashMessageService; + @service('app-router') declare readonly router: RouterService; @tracked filterValue = ''; @tracked libraryToDelete: LdapLibraryModel | null = null; + isHierarchical = (name: string) => name.endsWith('/'); + + linkParams = (library: LdapLibraryModel) => { + const route = this.isHierarchical(library.name) ? 'libraries.subdirectory' : 'libraries.library.details'; + return [route, library.completeLibraryName]; + }; + get mountPoint(): string { const owner = getOwner(this) as EngineOwner; return owner.mountPoint; @@ -43,8 +52,9 @@ export default class LdapLibrariesPageComponent extends Component { @action async onDelete(model: LdapLibraryModel) { try { - const message = `Successfully deleted library ${model.name}.`; + const message = `Successfully deleted library ${model.completeLibraryName}.`; await model.destroyRecord(); + this.router.transitionTo('vault.cluster.secrets.backend.ldap.libraries'); this.flashMessages.success(message); } catch (error) { this.flashMessages.danger(`Error deleting library \n ${errorMessage(error)}`); diff --git a/ui/lib/ldap/addon/components/page/roles.hbs b/ui/lib/ldap/addon/components/page/roles.hbs index cf9747a5dff4..946adeb39c42 100644 --- a/ui/lib/ldap/addon/components/page/roles.hbs +++ b/ui/lib/ldap/addon/components/page/roles.hbs @@ -61,7 +61,7 @@ Content {{else}} {{#if role.canEdit}} @@ -72,7 +72,11 @@ >Edit {{/if}} {{#if role.canReadCreds}} - + Get credentials {{/if}} @@ -87,7 +91,7 @@ data-test-details @route="roles.role.details" {{! this will force the roles.role model hook to fire since we may only have a partial model loaded in the list view }} - @models={{array role.type role.name}} + @models={{array role.type role.completeRoleName}} >Details {{#if role.canDelete}} { linkParams = (role: LdapRoleModel) => { const route = this.isHierarchical(role.name) ? 'roles.subdirectory' : 'roles.role.details'; - // if there is a path_to_role we're in a subdirectory - // and must concat the ancestors with the leaf name to get the full role path - const roleName = role.path_to_role ? role.path_to_role + role.name : role.name; - return [route, role.type, roleName]; + return [route, role.type, role.completeRoleName]; }; get mountPoint(): string { @@ -61,7 +58,7 @@ export default class LdapRolesPageComponent extends Component { @action async onRotate(model: LdapRoleModel) { try { - const message = `Successfully rotated credentials for ${model.name}.`; + const message = `Successfully rotated credentials for ${model.completeRoleName}.`; await model.rotateStaticPassword(); this.flashMessages.success(message); } catch (error) { @@ -74,7 +71,7 @@ export default class LdapRolesPageComponent extends Component { @action async onDelete(model: LdapRoleModel) { try { - const message = `Successfully deleted role ${model.name}.`; + const message = `Successfully deleted role ${model.completeRoleName}.`; await model.destroyRecord(); this.pagination.clearDataset('ldap/role'); this.router.transitionTo('vault.cluster.secrets.backend.ldap.roles'); diff --git a/ui/lib/ldap/addon/routes.js b/ui/lib/ldap/addon/routes.js index 593128f47abe..f11c0ceb4cc3 100644 --- a/ui/lib/ldap/addon/routes.js +++ b/ui/lib/ldap/addon/routes.js @@ -19,6 +19,8 @@ export default buildRoutes(function () { }); this.route('libraries', function () { this.route('create'); + // wildcard route so we can traverse hierarchical libraries i.e. prod/admin/my-library + this.route('subdirectory', { path: '/subdirectory/*path_to_library' }); this.route('library', { path: '/:name' }, function () { this.route('details', function () { this.route('accounts'); diff --git a/ui/lib/ldap/addon/routes/libraries/library/check-out.ts b/ui/lib/ldap/addon/routes/libraries/library/check-out.ts index 23025f96892b..c8f71936a25f 100644 --- a/ui/lib/ldap/addon/routes/libraries/library/check-out.ts +++ b/ui/lib/ldap/addon/routes/libraries/library/check-out.ts @@ -16,6 +16,7 @@ import type Transition from '@ember/routing/transition'; import type { Breadcrumb } from 'vault/vault/app-types'; import { LdapLibraryCheckOutCredentials } from 'vault/vault/adapters/ldap/library'; import type AdapterError from 'ember-data/adapter'; // eslint-disable-line ember/use-ember-data-rfc-395-imports +import { ldapBreadcrumbs, libraryRoutes } from 'ldap/utils/ldap-breadcrumbs'; interface LdapLibraryCheckOutController extends Controller { breadcrumbs: Array; @@ -45,12 +46,14 @@ export default class LdapLibraryCheckOutRoute extends Route { transition: Transition ) { super.setupController(controller, resolvedModel, transition); - const library = this.modelFor('libraries.library') as LdapLibraryModel; + const routeParams = (childResource: string) => { + return [library.backend, childResource]; + }; controller.breadcrumbs = [ { label: library.backend, route: 'overview' }, { label: 'Libraries', route: 'libraries' }, - { label: library.name, route: 'libraries.library' }, + ...ldapBreadcrumbs(library.name, routeParams, libraryRoutes), { label: 'Check-Out' }, ]; } diff --git a/ui/lib/ldap/addon/routes/libraries/library/details.ts b/ui/lib/ldap/addon/routes/libraries/library/details.ts index 233835b602c8..e39ab6e1c346 100644 --- a/ui/lib/ldap/addon/routes/libraries/library/details.ts +++ b/ui/lib/ldap/addon/routes/libraries/library/details.ts @@ -9,6 +9,7 @@ import type LdapLibraryModel from 'vault/models/ldap/library'; import type Controller from '@ember/controller'; import type Transition from '@ember/routing/transition'; import type { Breadcrumb } from 'vault/vault/app-types'; +import { ldapBreadcrumbs, libraryRoutes } from 'ldap/utils/ldap-breadcrumbs'; interface LdapLibraryDetailsController extends Controller { breadcrumbs: Array; @@ -23,10 +24,14 @@ export default class LdapLibraryDetailsRoute extends Route { ) { super.setupController(controller, resolvedModel, transition); + const routeParams = (childResource: string) => { + return [resolvedModel.backend, childResource]; + }; + controller.breadcrumbs = [ { label: resolvedModel.backend, route: 'overview' }, { label: 'Libraries', route: 'libraries' }, - { label: resolvedModel.name }, + ...ldapBreadcrumbs(resolvedModel.name, routeParams, libraryRoutes, true), ]; } } diff --git a/ui/lib/ldap/addon/routes/libraries/library/edit.ts b/ui/lib/ldap/addon/routes/libraries/library/edit.ts index 191190cee140..5a3059ab6e41 100644 --- a/ui/lib/ldap/addon/routes/libraries/library/edit.ts +++ b/ui/lib/ldap/addon/routes/libraries/library/edit.ts @@ -9,6 +9,7 @@ import type LdapLibraryModel from 'vault/models/ldap/library'; import type Controller from '@ember/controller'; import type Transition from '@ember/routing/transition'; import type { Breadcrumb } from 'vault/vault/app-types'; +import { ldapBreadcrumbs, libraryRoutes } from 'ldap/utils/ldap-breadcrumbs'; interface LdapLibraryEditController extends Controller { breadcrumbs: Array; @@ -23,10 +24,13 @@ export default class LdapLibraryEditRoute extends Route { ) { super.setupController(controller, resolvedModel, transition); + const routeParams = (childResource: string) => { + return [resolvedModel.backend, childResource]; + }; controller.breadcrumbs = [ { label: resolvedModel.backend, route: 'overview' }, { label: 'Libraries', route: 'libraries' }, - { label: resolvedModel.name, route: 'libraries.library.details' }, + ...ldapBreadcrumbs(resolvedModel.name, routeParams, libraryRoutes), { label: 'Edit' }, ]; } diff --git a/ui/lib/ldap/addon/routes/libraries/subdirectory.ts b/ui/lib/ldap/addon/routes/libraries/subdirectory.ts new file mode 100644 index 000000000000..136bb435d529 --- /dev/null +++ b/ui/lib/ldap/addon/routes/libraries/subdirectory.ts @@ -0,0 +1,60 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: BUSL-1.1 + */ + +import Route from '@ember/routing/route'; +import { service } from '@ember/service'; +import { hash } from 'rsvp'; + +import type Store from '@ember-data/store'; +import type SecretMountPath from 'vault/services/secret-mount-path'; +import type Transition from '@ember/routing/transition'; +import type LdapLibraryModel from 'vault/models/ldap/library'; +import type SecretEngineModel from 'vault/models/secret-engine'; +import type Controller from '@ember/controller'; +import type { Breadcrumb } from 'vault/vault/app-types'; +import { ldapBreadcrumbs, libraryRoutes } from 'ldap/utils/ldap-breadcrumbs'; + +interface RouteModel { + backendModel: SecretEngineModel; + path_to_library: string; + libraries: Array; +} +interface RouteController extends Controller { + breadcrumbs: Array; + model: RouteModel; +} +interface RouteParams { + path_to_library?: string; +} + +export default class LdapLibrariesSubdirectoryRoute extends Route { + @service declare readonly store: Store; + @service declare readonly secretMountPath: SecretMountPath; + + model(params: RouteParams) { + const backendModel = this.modelFor('application') as SecretEngineModel; + const { path_to_library } = params; + return hash({ + backendModel, + path_to_library, + libraries: this.store.query('ldap/library', { backend: backendModel.id, path_to_library }), + }); + } + + setupController(controller: RouteController, resolvedModel: RouteModel, transition: Transition) { + super.setupController(controller, resolvedModel, transition); + + const routeParams = (childResource: string) => { + return [resolvedModel.backendModel.id, childResource]; + }; + + controller.breadcrumbs = [ + { label: 'Secrets', route: 'secrets', linkExternal: true }, + { label: resolvedModel.backendModel.id, route: 'overview' }, + { label: 'Libraries', route: 'libraries' }, + ...ldapBreadcrumbs(resolvedModel.path_to_library, routeParams, libraryRoutes, true), + ]; + } +} diff --git a/ui/lib/ldap/addon/routes/roles/role/credentials.ts b/ui/lib/ldap/addon/routes/roles/role/credentials.ts index a3082de8431d..70c68c813568 100644 --- a/ui/lib/ldap/addon/routes/roles/role/credentials.ts +++ b/ui/lib/ldap/addon/routes/roles/role/credentials.ts @@ -5,7 +5,7 @@ import Route from '@ember/routing/route'; import { service } from '@ember/service'; -import { ldapBreadcrumbs } from 'ldap/utils/ldap-breadcrumbs'; +import { ldapBreadcrumbs, roleRoutes } from 'ldap/utils/ldap-breadcrumbs'; import type Store from '@ember-data/store'; import type LdapRoleModel from 'vault/models/ldap/role'; @@ -58,11 +58,14 @@ export default class LdapRoleCredentialsRoute extends Route { super.setupController(controller, resolvedModel, transition); const role = this.modelFor('roles.role') as LdapRoleModel; + const routeParams = (childResource: string) => { + return [role.backend, role.type, childResource]; + }; controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: role.backend, route: 'overview' }, { label: 'Roles', route: 'roles' }, - ...ldapBreadcrumbs(role.name, role.type, role.backend), + ...ldapBreadcrumbs(role.name, routeParams, roleRoutes), { label: 'Credentials' }, ]; } diff --git a/ui/lib/ldap/addon/routes/roles/role/details.ts b/ui/lib/ldap/addon/routes/roles/role/details.ts index 0b6ee9afa490..c8c7ecb65236 100644 --- a/ui/lib/ldap/addon/routes/roles/role/details.ts +++ b/ui/lib/ldap/addon/routes/roles/role/details.ts @@ -5,7 +5,7 @@ import Route from '@ember/routing/route'; import { service } from '@ember/service'; -import { ldapBreadcrumbs } from 'ldap/utils/ldap-breadcrumbs'; +import { ldapBreadcrumbs, roleRoutes } from 'ldap/utils/ldap-breadcrumbs'; import type { Breadcrumb } from 'vault/vault/app-types'; import type Controller from '@ember/controller'; @@ -24,11 +24,15 @@ export default class LdapRolesRoleDetailsRoute extends Route { setupController(controller: RouteController, resolvedModel: LdapRoleModel, transition: Transition) { super.setupController(controller, resolvedModel, transition); + const routeParams = (childResource: string) => { + return [this.secretMountPath.currentPath, resolvedModel.type, childResource]; + }; + controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: resolvedModel.backend, route: 'overview' }, { label: 'Roles', route: 'roles' }, - ...ldapBreadcrumbs(resolvedModel.name, resolvedModel.type, this.secretMountPath.currentPath, true), + ...ldapBreadcrumbs(resolvedModel.name, routeParams, roleRoutes, true), ]; } } diff --git a/ui/lib/ldap/addon/routes/roles/role/edit.ts b/ui/lib/ldap/addon/routes/roles/role/edit.ts index c12ad20e3a3f..df383ad03cad 100644 --- a/ui/lib/ldap/addon/routes/roles/role/edit.ts +++ b/ui/lib/ldap/addon/routes/roles/role/edit.ts @@ -4,7 +4,7 @@ */ import Route from '@ember/routing/route'; -import { ldapBreadcrumbs } from 'ldap/utils/ldap-breadcrumbs'; +import { ldapBreadcrumbs, roleRoutes } from 'ldap/utils/ldap-breadcrumbs'; import type LdapRoleModel from 'vault/models/ldap/role'; import type Controller from '@ember/controller'; @@ -20,11 +20,15 @@ export default class LdapRoleEditRoute extends Route { setupController(controller: RouteController, resolvedModel: LdapRoleModel, transition: Transition) { super.setupController(controller, resolvedModel, transition); + const routeParams = (childResource: string) => { + return [resolvedModel.backend, resolvedModel.type, childResource]; + }; + controller.breadcrumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: resolvedModel.backend, route: 'overview' }, { label: 'Roles', route: 'roles' }, - ...ldapBreadcrumbs(resolvedModel.name, resolvedModel.type, resolvedModel.backend), + ...ldapBreadcrumbs(resolvedModel.name, routeParams, roleRoutes), { label: 'Edit' }, ]; } diff --git a/ui/lib/ldap/addon/routes/roles/subdirectory.ts b/ui/lib/ldap/addon/routes/roles/subdirectory.ts index cb84d232566b..5b83c72deca4 100644 --- a/ui/lib/ldap/addon/routes/roles/subdirectory.ts +++ b/ui/lib/ldap/addon/routes/roles/subdirectory.ts @@ -5,7 +5,7 @@ import LdapRolesRoute from '../roles'; import { hash } from 'rsvp'; -import { ldapBreadcrumbs } from 'ldap/utils/ldap-breadcrumbs'; +import { ldapBreadcrumbs, roleRoutes } from 'ldap/utils/ldap-breadcrumbs'; import type { Breadcrumb } from 'vault/vault/app-types'; import type Controller from '@ember/controller'; @@ -55,11 +55,16 @@ export default class LdapRolesSubdirectoryRoute extends LdapRolesRoute { setupController(controller: RouteController, resolvedModel: RouteModel, transition: Transition) { super.setupController(controller, resolvedModel, transition); const { backendModel, roleAncestry } = resolvedModel; + + const routeParams = (childResource: string) => { + return [backendModel.id, roleAncestry.type, childResource]; + }; + const crumbs = [ { label: 'Secrets', route: 'secrets', linkExternal: true }, { label: backendModel.id, route: 'overview' }, { label: 'Roles', route: 'roles' }, - ...ldapBreadcrumbs(roleAncestry.path_to_role, roleAncestry.type, backendModel.id, true), + ...ldapBreadcrumbs(roleAncestry.path_to_role, routeParams, roleRoutes, true), ]; // must call 'set' so breadcrumbs update as we navigate through directories diff --git a/ui/lib/ldap/addon/templates/libraries/subdirectory.hbs b/ui/lib/ldap/addon/templates/libraries/subdirectory.hbs new file mode 100644 index 000000000000..0cc729408812 --- /dev/null +++ b/ui/lib/ldap/addon/templates/libraries/subdirectory.hbs @@ -0,0 +1,11 @@ +{{! + Copyright (c) HashiCorp, Inc. + SPDX-License-Identifier: BUSL-1.1 +~}} + + \ No newline at end of file diff --git a/ui/lib/ldap/addon/utils/ldap-breadcrumbs.ts b/ui/lib/ldap/addon/utils/ldap-breadcrumbs.ts index cbc21b50564b..cdeda3a12a7f 100644 --- a/ui/lib/ldap/addon/utils/ldap-breadcrumbs.ts +++ b/ui/lib/ldap/addon/utils/ldap-breadcrumbs.ts @@ -4,10 +4,16 @@ */ import type { Breadcrumb } from 'vault/vault/app-types'; +export const roleRoutes = { details: 'roles.role.details', subdirectory: 'roles.subdirectory' }; +export const libraryRoutes = { + details: 'libraries.library.details', + subdirectory: 'libraries.subdirectory', +}; + export const ldapBreadcrumbs = ( fullPath: string | undefined, // i.e. path/to/item - roleType: string, - mountPath: string, + routeParams: (childResource: string) => string[], // array of route param strings + routes: { details: string; subdirectory: string }, lastItemCurrent = false // this array of objects can be spread anywhere within the crumbs array ): Breadcrumb[] => { if (!fullPath) return []; @@ -26,11 +32,10 @@ export const ldapBreadcrumbs = ( const segment = ancestry.slice(0, idx + 1).join('/'); const itemPath = isLast && !isDirectory ? segment : `${segment}/`; - const routeParams = [mountPath, roleType, itemPath]; return { label: name, - route: isLast && !isDirectory ? 'roles.role.details' : 'roles.subdirectory', - models: routeParams, + route: isLast && !isDirectory ? routes.details : routes.subdirectory, + models: routeParams(itemPath), }; }); }; diff --git a/ui/lib/pki/addon/components/pki-generate-toggle-groups.hbs b/ui/lib/pki/addon/components/pki-generate-toggle-groups.hbs index 210e9101b029..a2f1b0758578 100644 --- a/ui/lib/pki/addon/components/pki-generate-toggle-groups.hbs +++ b/ui/lib/pki/addon/components/pki-generate-toggle-groups.hbs @@ -43,6 +43,13 @@ etc.) to be protected by a single certificate. {{else if (eq group "Additional subject fields")}} These fields provide more information about the client to which the certificate belongs. + {{else if (eq group "Name constraints")}} + These fields create the name constraints extension when generating CA certificates. Specifying any combination of + these parameters will trigger the creation of the name constraints extension as per + RFC 5280 section 4.2.1.10. {{/if}}

{{#each fields as |fieldName|}} diff --git a/ui/lib/pki/addon/components/pki-sign-intermediate-form.ts b/ui/lib/pki/addon/components/pki-sign-intermediate-form.ts index 2fb1c660ab57..335e9b5fedaa 100644 --- a/ui/lib/pki/addon/components/pki-sign-intermediate-form.ts +++ b/ui/lib/pki/addon/components/pki-sign-intermediate-form.ts @@ -49,6 +49,16 @@ export default class PkiSignIntermediateFormComponent extends Component { get groups() { return { + 'Name constraints': [ + 'permittedDnsDomains', + 'permittedEmailAddresses', + 'permittedIpRanges', + 'permittedUriDomains', + 'excludedDnsDomains', + 'excludedEmailAddresses', + 'excludedIpRanges', + 'excludedUriDomains', + ], 'Signing options': ['usePss', 'skid', 'signatureBits'], 'Subject Alternative Name (SAN) Options': ['altNames', 'ipSans', 'uriSans', 'otherSans'], 'Additional subject fields': [ diff --git a/ui/mirage/handlers/ldap.js b/ui/mirage/handlers/ldap.js index 47fb433de204..99aed83da6e7 100644 --- a/ui/mirage/handlers/ldap.js +++ b/ui/mirage/handlers/ldap.js @@ -46,14 +46,16 @@ export default function (server) { }; const listOrGetRecord = (schema, req, type) => { - // if the param name is admin, we want to LIST admin/ roles + const dbKey = type ? 'ldapRoles' : 'ldapLibraries'; + const query = type ? { type, name: `admin/child-${type}-role` } : { name: 'admin/test-library' }; if (req.queryParams.list) { - // passing a query with specific name is not flexible - // but we only seeded the mirage db with one hierarchical role for each type - return listRecords(schema, 'ldapRoles', { type, name: `admin/child-${type}-role` }); + // the mirage database has setup all hierarchical names to be prefixed with "admin/" + // while passing a query with specific name is not flexible, for simplicity + // we only seeded the mirage db with one hierarchical resource for each role and a library + return listRecords(schema, dbKey, query); } - // otherwise we want to view details for a specific role - return getRecord(schema, req, 'ldapRoles', type); + // otherwise we want to view details for a specific resource + return getRecord(schema, req, dbKey); }; // config @@ -77,9 +79,9 @@ export default function (server) { })); // libraries server.post('/:backend/library/:name', (schema, req) => createOrUpdateRecord(schema, req, 'ldapLibraries')); - server.get('/:backend/library/:name', (schema, req) => getRecord(schema, req, 'ldapLibraries')); + server.get('/:backend/library/*name', (schema, req) => listOrGetRecord(schema, req)); server.get('/:backend/library', (schema) => listRecords(schema, 'ldapLibraries')); - server.get('/:backend/library/:name/status', (schema) => { + server.get('/:backend/library/*name/status', (schema) => { const data = schema.db['ldapAccountStatuses'].reduce((prev, curr) => { prev[curr.account] = { available: curr.available, diff --git a/ui/mirage/scenarios/ldap.js b/ui/mirage/scenarios/ldap.js index cff48bd84df1..66df01ff37ef 100644 --- a/ui/mirage/scenarios/ldap.js +++ b/ui/mirage/scenarios/ldap.js @@ -14,6 +14,8 @@ export default function (server) { server.create('ldap-role', 'static', { name: 'my-role' }); server.create('ldap-role', 'dynamic', { name: 'my-role' }); server.create('ldap-library', { name: 'test-library' }); + // mirage handler is hardcoded to accommodate hierarchical paths starting with 'admin/' + server.create('ldap-library', { name: 'admin/test-library' }); server.create('ldap-account-status', { id: 'bob.johnson', account: 'bob.johnson', diff --git a/ui/tests/acceptance/secrets/backend/gcp/gcp-configuration-test.js b/ui/tests/acceptance/secrets/backend/gcp/gcp-configuration-test.js new file mode 100644 index 000000000000..288f0a61eeaf --- /dev/null +++ b/ui/tests/acceptance/secrets/backend/gcp/gcp-configuration-test.js @@ -0,0 +1,130 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: BUSL-1.1 + */ + +import { click, visit, currentURL } from '@ember/test-helpers'; +import { module, test } from 'qunit'; +import { setupApplicationTest } from 'ember-qunit'; +import { v4 as uuidv4 } from 'uuid'; + +import authPage from 'vault/tests/pages/auth'; +import enablePage from 'vault/tests/pages/settings/mount-secret-backend'; +import { setupMirage } from 'ember-cli-mirage/test-support'; +import { runCmd } from 'vault/tests/helpers/commands'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; +import { overrideResponse } from 'vault/tests/helpers/stubs'; +import { SECRET_ENGINE_SELECTORS as SES } from 'vault/tests/helpers/secret-engine/secret-engine-selectors'; +import { mountBackend } from 'vault/tests/helpers/components/mount-backend-form-helpers'; +import { + expectedConfigKeys, + expectedValueOfConfigKeys, + configUrl, +} from 'vault/tests/helpers/secret-engine/secret-engine-helpers'; + +module('Acceptance | GCP | configuration', function (hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); + + hooks.beforeEach(function () { + this.store = this.owner.lookup('service:store'); + this.version = this.owner.lookup('service:version'); + this.uid = uuidv4(); + this.type = 'gcp'; + return authPage.login(); + }); + module('isEnterprise', function (hooks) { + hooks.beforeEach(function () { + this.version.type = 'enterprise'; + }); + + test('it should show empty state and navigate to configuration view after mounting the GCP engine', async function (assert) { + const path = `GCP-${this.uid}`; + await visit('/vault/settings/mount-secret-backend'); + await mountBackend(this.type, path); + + assert.strictEqual( + currentURL(), + `/vault/secrets/${path}/configuration`, + 'navigated to configuration view' + ); + assert.dom(GENERAL.emptyStateTitle).hasText('Google Cloud not configured'); + assert.dom(GENERAL.emptyStateActions).doesNotContainText('Configure GCP'); + // cleanup + await runCmd(`delete sys/mounts/${path}`); + }); + + test('it should not show "Configure" from toolbar', async function (assert) { + const path = `GCP-${this.uid}`; + await enablePage.enable(this.type, path); + assert.dom(SES.configure).doesNotExist('Configure button does not exist.'); + // cleanup + await runCmd(`delete sys/mounts/${path}`); + }); + + test('it should show configuration details with WIF options configured', async function (assert) { + const path = `GCP-${this.uid}`; + const wifAttrs = { + service_account_email: 'service-email', + identity_token_audience: 'audience', + identity_token_ttl: 720000, + }; + this.server.get(`${path}/config`, () => { + assert.ok(true, 'request made to config when navigating to the configuration page.'); + return { data: { id: path, type: this.type, ...wifAttrs } }; + }); + await enablePage.enable(this.type, path); + for (const key of expectedConfigKeys('gcp-wif')) { + const responseKeyAndValue = expectedValueOfConfigKeys(this.type, key); + assert + .dom(GENERAL.infoRowValue(key)) + .hasText(responseKeyAndValue, `value for ${key} on the ${this.type} config details exists.`); + } + // check mount configuration details are present and accurate. + await click(SES.configurationToggle); + assert + .dom(GENERAL.infoRowValue('Path')) + .hasText(`${path}/`, 'mount path is displayed in the configuration details'); + // cleanup + await runCmd(`delete sys/mounts/${path}`); + }); + + test('it should show configuration details with GCP account options configured', async function (assert) { + const path = `GCP-${this.uid}`; + const GCPAccountAttrs = { + credentials: '{"some-key":"some-value"}', + ttl: '1 hour', + max_ttl: '4 hours', + }; + this.server.get(`${path}/config`, () => { + assert.ok(true, 'request made to config when navigating to the configuration page.'); + return { data: { id: path, type: this.type, ...GCPAccountAttrs } }; + }); + await enablePage.enable(this.type, path); + for (const key of expectedConfigKeys(this.type)) { + const responseKeyAndValue = expectedValueOfConfigKeys(this.type, key); + assert + .dom(GENERAL.infoRowValue(key)) + .hasText(responseKeyAndValue, `value for ${key} on the ${this.type} config details exists.`); + } + // check mount configuration details are present and accurate. + await click(SES.configurationToggle); + assert + .dom(GENERAL.infoRowValue('Path')) + .hasText(`${path}/`, 'mount path is displayed in the configuration details'); + // cleanup + await runCmd(`delete sys/mounts/${path}`); + }); + + test('it should show API error when configuration read fails', async function (assert) { + assert.expect(1); + const path = `GCP-${this.uid}`; + // interrupt get and return API error + this.server.get(configUrl(this.type, path), () => { + return overrideResponse(400, { errors: ['bad request'] }); + }); + await enablePage.enable(this.type, path); + assert.dom(SES.error.title).hasText('Error', 'shows the secrets backend error route'); + }); + }); +}); diff --git a/ui/tests/acceptance/secrets/backend/ldap/libraries-test.js b/ui/tests/acceptance/secrets/backend/ldap/libraries-test.js index fee09ad7f859..d04b3718846a 100644 --- a/ui/tests/acceptance/secrets/backend/ldap/libraries-test.js +++ b/ui/tests/acceptance/secrets/backend/ldap/libraries-test.js @@ -10,9 +10,10 @@ import { v4 as uuidv4 } from 'uuid'; import ldapMirageScenario from 'vault/mirage/scenarios/ldap'; import ldapHandlers from 'vault/mirage/handlers/ldap'; import authPage from 'vault/tests/pages/auth'; -import { click } from '@ember/test-helpers'; +import { click, currentURL } from '@ember/test-helpers'; import { isURL, visitURL } from 'vault/tests/helpers/ldap/ldap-helpers'; import { deleteEngineCmd, mountEngineCmd, runCmd } from 'vault/tests/helpers/commands'; +import { LDAP_SELECTORS } from 'vault/tests/helpers/ldap/ldap-selectors'; module('Acceptance | ldap | libraries', function (hooks) { setupApplicationTest(hooks); @@ -37,7 +38,7 @@ module('Acceptance | ldap | libraries', function (hooks) { test('it should show libraries on overview page', async function (assert) { await visitURL('overview', this.backend); - assert.dom('[data-test-libraries-count]').hasText('1'); + assert.dom('[data-test-libraries-count]').hasText('2'); }); test('it should transition to create library route on toolbar link click', async function (assert) { @@ -49,15 +50,34 @@ module('Acceptance | ldap | libraries', function (hooks) { }); test('it should transition to library details route on list item click', async function (assert) { - await click('[data-test-list-item-link] a'); - assert.true( - isURL('libraries/test-library/details/accounts', this.backend), + await click(LDAP_SELECTORS.libraryItem('test-library')); + assert.strictEqual( + currentURL(), + `/vault/secrets/${this.backend}/ldap/libraries/test-library/details/accounts`, 'Transitions to library details accounts route on list item click' ); assert.dom('[data-test-account-name]').exists({ count: 2 }, 'lists the accounts'); assert.dom('[data-test-checked-out-account]').exists({ count: 1 }, 'lists the checked out accounts'); }); + test('it should transition to library details for hierarchical list items', async function (assert) { + await click(LDAP_SELECTORS.libraryItem('admin/')); + assert.strictEqual( + currentURL(), + `/vault/secrets/${this.backend}/ldap/libraries/subdirectory/admin/`, + 'Transitions to subdirectory list view' + ); + + await click(LDAP_SELECTORS.libraryItem('admin/test-library')); + assert.strictEqual( + currentURL(), + `/vault/secrets/${this.backend}/ldap/libraries/admin%2Ftest-library/details/accounts`, + 'Transitions to child library details accounts' + ); + assert.dom('[data-test-account-name]').exists({ count: 2 }, 'lists the accounts'); + assert.dom('[data-test-checked-out-account]').exists({ count: 1 }, 'lists the checked out accounts'); + }); + test('it should transition to routes from list item action menu', async function (assert) { assert.expect(2); diff --git a/ui/tests/helpers/ldap/ldap-selectors.ts b/ui/tests/helpers/ldap/ldap-selectors.ts index 73933bcaae8c..b99b77d0dd77 100644 --- a/ui/tests/helpers/ldap/ldap-selectors.ts +++ b/ui/tests/helpers/ldap/ldap-selectors.ts @@ -5,6 +5,8 @@ export const LDAP_SELECTORS = { roleItem: (type: string, name: string) => `[data-test-role="${type} ${name}"]`, + libraryItem: (name: string) => `[data-test-library="${name}"]`, roleMenu: (type: string, name: string) => `[data-test-popup-menu-trigger="${type} ${name}"]`, + libraryMenu: (name: string) => `[data-test-popup-menu-trigger="${name}"]`, action: (action: string) => `[data-test-${action}]`, }; diff --git a/ui/tests/helpers/openapi/expected-secret-attrs.js b/ui/tests/helpers/openapi/expected-secret-attrs.js index c72160e1a963..373851ff8e34 100644 --- a/ui/tests/helpers/openapi/expected-secret-attrs.js +++ b/ui/tests/helpers/openapi/expected-secret-attrs.js @@ -1345,7 +1345,7 @@ const pki = { fieldGroup: 'default', helpText: 'Email addresses for which this certificate is allowed to sign or issue child certificates (see https://tools.ietf.org/html/rfc5280#section-4.2.1.10).', - label: 'Permitted email adresses', + label: 'Permitted email addresses', }, permittedIpRanges: { editType: 'stringArray', diff --git a/ui/tests/helpers/secret-engine/secret-engine-helpers.js b/ui/tests/helpers/secret-engine/secret-engine-helpers.js index f21dd0a9eb5b..93161ba4dd11 100644 --- a/ui/tests/helpers/secret-engine/secret-engine-helpers.js +++ b/ui/tests/helpers/secret-engine/secret-engine-helpers.js @@ -148,6 +148,35 @@ const createAzureConfig = (store, backend, accessType = 'generic') => { return store.peekRecord('azure/config', backend); }; +const createGcpConfig = (store, backend, accessType = 'gcp') => { + // clear any records first + store.unloadAll('gcp/config'); + if (accessType === 'wif') { + store.pushPayload('gcp/config', { + id: backend, + modelName: 'gcp/config', + data: { + backend, + service_account_email: 'service-email', + identity_token_audience: 'audience', + identity_token_ttl: 7200, + }, + }); + } else { + store.pushPayload('gcp/config', { + id: backend, + modelName: 'gcp/config', + data: { + backend, + credentials: '{"some-key":"some-value"}', + ttl: '1 hour', + max_ttl: '4 hours', + }, + }); + } + return store.peekRecord('gcp/config', backend); +}; + export function configUrl(type, backend) { switch (type) { case 'aws': @@ -181,6 +210,8 @@ export const createConfig = (store, backend, type) => { return createAzureConfig(store, backend, 'wif'); case 'azure-generic': return createAzureConfig(store, backend, 'generic'); + case 'gcp': + return createGcpConfig(store, backend); } }; // Used in tests to assert the expected keys in the config details of configurable secret engines @@ -220,6 +251,12 @@ export const expectedConfigKeys = (type) => { 'identityTokenAudience', 'Identity token TTL', ]; + case 'gcp': + return ['Config TTL', 'Max TTL']; + case 'gcp-wif': + return ['Service account email', 'Identity token audience', 'Identity token TTL']; + case 'gcp-wif-camelCase': + return ['serviceAccountEmail', 'identityTokenAudience', 'Identity token TTL']; } }; @@ -257,6 +294,23 @@ const valueOfAzureKeys = (string) => { } }; +const valueOfGcpKeys = (string) => { + switch (string) { + case 'Credentials': + return '"{"some-key":"some-value"}",'; + case 'Service account email': + return 'service-email'; + case 'Config TTL': + return '1 hour'; + case 'Max TTL': + return '4 hours'; + case 'Identity token audience': + return 'audience'; + case 'Identity token TTL': + return '8 days 8 hours'; + } +}; + const valueOfSshKeys = (string) => { switch (string) { case 'Public key': @@ -272,6 +326,8 @@ export const expectedValueOfConfigKeys = (type, string) => { return valueOfAwsKeys(string); case 'azure': return valueOfAzureKeys(string); + case 'gcp': + return valueOfGcpKeys(string); case 'ssh': return valueOfSshKeys(string); } diff --git a/ui/tests/integration/components/dashboard/overview-test.js b/ui/tests/integration/components/dashboard/overview-test.js index c64ead6d4ec7..0cb9df8474c3 100644 --- a/ui/tests/integration/components/dashboard/overview-test.js +++ b/ui/tests/integration/components/dashboard/overview-test.js @@ -15,8 +15,10 @@ module('Integration | Component | dashboard/overview', function (hooks) { setupMirage(hooks); hooks.beforeEach(function () { - this.store = this.owner.lookup('service:store'); + this.flags = this.owner.lookup('service:flags'); + this.namespace = this.owner.lookup('service:namespace'); this.permissions = this.owner.lookup('service:permissions'); + this.store = this.owner.lookup('service:store'); this.version = this.owner.lookup('service:version'); this.version.version = '1.13.1+ent'; this.version.type = 'enterprise'; @@ -151,6 +153,46 @@ module('Integration | Component | dashboard/overview', function (hooks) { assert.dom(DASHBOARD.cardName('replication')).exists(); }); + test('it should show client count on enterprise in admin namespace when running a managed mode', async function (assert) { + this.permissions.exactPaths = { + 'admin/sys/internal/counters/activity': { + capabilities: ['read'], + }, + 'admin/sys/replication/status': { + capabilities: ['read'], + }, + }; + + this.version.type = 'enterprise'; + this.flags.featureFlags = ['VAULT_CLOUD_ADMIN_NAMESPACE']; + this.namespace.path = 'admin'; + this.isRootNamespace = false; + + await this.renderComponent(); + + assert.dom(DASHBOARD.cardName('client-count')).exists(); + }); + + test('it should hide client count on enterprise in any other namespace when running a managed mode', async function (assert) { + this.permissions.exactPaths = { + 'sys/internal/counters/activity': { + capabilities: ['read'], + }, + 'sys/replication/status': { + capabilities: ['read'], + }, + }; + + this.version.type = 'enterprise'; + this.flags.featureFlags = ['VAULT_CLOUD_ADMIN_NAMESPACE']; + this.namespace.path = 'groceries'; + this.isRootNamespace = false; + + await this.renderComponent(); + + assert.dom(DASHBOARD.cardName('client-count')).doesNotExist(); + }); + test('it should hide cards on enterprise in root namespace but no permission', async function (assert) { await this.renderComponent(); assert.dom(DASHBOARD.cardName('client-count')).doesNotExist(); diff --git a/ui/tests/integration/components/ldap/page/libraries-test.js b/ui/tests/integration/components/ldap/page/libraries-test.js index b9b3be13cd3c..09cd90945db6 100644 --- a/ui/tests/integration/components/ldap/page/libraries-test.js +++ b/ui/tests/integration/components/ldap/page/libraries-test.js @@ -12,6 +12,7 @@ import hbs from 'htmlbars-inline-precompile'; import { allowAllCapabilitiesStub } from 'vault/tests/helpers/stubs'; import { createSecretsEngine, generateBreadcrumbs } from 'vault/tests/helpers/ldap/ldap-helpers'; import { setRunOptions } from 'ember-a11y-testing/test-support'; +import { LDAP_SELECTORS } from 'vault/tests/helpers/ldap/ldap-selectors'; module('Integration | Component | ldap | Page::Libraries', function (hooks) { setupRenderingTest(hooks); @@ -25,7 +26,7 @@ module('Integration | Component | ldap | Page::Libraries', function (hooks) { this.backend = createSecretsEngine(this.store); this.breadcrumbs = generateBreadcrumbs(this.backend.id); - for (const name of ['foo', 'bar']) { + for (const name of ['foo', 'bar', 'foo/']) { this.store.pushPayload('ldap/library', { modelName: 'ldap/library', backend: 'ldap-test', @@ -93,12 +94,19 @@ module('Integration | Component | ldap | Page::Libraries', function (hooks) { await this.renderComponent(); assert.dom('[data-test-list-item-content] svg').hasClass('hds-icon-folder', 'List item icon renders'); - assert.dom('[data-test-library]').hasText(this.libraries[0].name, 'List item name renders'); + assert.dom('[data-test-library="foo"]').hasText('foo', 'List item name renders'); - await click('[data-test-popup-menu-trigger]'); + await click(LDAP_SELECTORS.libraryMenu('foo')); + assert.dom('[data-test-subdirectory]').doesNotExist(); assert.dom('[data-test-edit]').hasText('Edit', 'Edit link renders in menu'); assert.dom('[data-test-details]').hasText('Details', 'Details link renders in menu'); assert.dom('[data-test-delete]').hasText('Delete', 'Details link renders in menu'); + + await click(LDAP_SELECTORS.libraryMenu('foo/')); + assert.dom('[data-test-subdirectory]').hasText('Content', 'Content link renders in menu'); + assert.dom('[data-test-edit]').doesNotExist(); + assert.dom('[data-test-details]').doesNotExist(); + assert.dom('[data-test-delete]').doesNotExist(); }); test('it should filter libraries', async function (assert) { @@ -110,11 +118,11 @@ module('Integration | Component | ldap | Page::Libraries', function (hooks) { .hasText('There are no libraries matching "baz"', 'Filter message renders'); await fillIn('[data-test-filter-input]', 'foo'); - assert.dom('[data-test-list-item-content]').exists({ count: 1 }, 'List is filtered with correct results'); + assert.dom('[data-test-list-item-content]').exists({ count: 2 }, 'List is filtered with correct results'); await fillIn('[data-test-filter-input]', ''); assert .dom('[data-test-list-item-content]') - .exists({ count: 2 }, 'All libraries are displayed when filter is cleared'); + .exists({ count: 3 }, 'All libraries are displayed when filter is cleared'); }); }); diff --git a/ui/tests/integration/components/pki/pki-sign-intermediate-form-test.js b/ui/tests/integration/components/pki/pki-sign-intermediate-form-test.js index 0b4981290193..3dca52d4914a 100644 --- a/ui/tests/integration/components/pki/pki-sign-intermediate-form-test.js +++ b/ui/tests/integration/components/pki/pki-sign-intermediate-form-test.js @@ -14,9 +14,7 @@ import { setupMirage } from 'ember-cli-mirage/test-support'; const selectors = { form: '[data-test-sign-intermediate-form]', csrInput: '[data-test-input="csr"]', - toggleSigningOptions: '[data-test-toggle-group="Signing options"]', - toggleSANOptions: '[data-test-toggle-group="Subject Alternative Name (SAN) Options"]', - toggleAdditionalFields: '[data-test-toggle-group="Additional subject fields"]', + toggleGroup: (group) => `[data-test-toggle-group="${group}"]`, fieldByName: (name) => `[data-test-field="${name}"]`, saveButton: '[data-test-pki-sign-intermediate-save]', cancelButton: '[data-test-pki-sign-intermediate-cancel]', @@ -40,19 +38,24 @@ module('Integration | Component | pki-sign-intermediate-form', function (hooks) }); test('renders correctly on load', async function (assert) { - assert.expect(9); + assert.expect(10); await render(hbs``, { owner: this.engine, }); assert.dom(selectors.form).exists('Form is rendered'); assert.dom(selectors.resultsContainer).doesNotExist('Results display not rendered'); - assert.dom('[data-test-field]').exists({ count: 10 }, '10 default fields shown'); - assert.dom(selectors.toggleSigningOptions).exists(); - assert.dom(selectors.toggleSANOptions).exists(); - assert.dom(selectors.toggleAdditionalFields).exists(); + assert.dom('[data-test-field]').exists({ count: 9 }, '9 default fields shown'); + [ + 'Name constraints', + 'Signing options', + 'Subject Alternative Name (SAN) Options', + 'Additional subject fields', + ].forEach((group) => { + assert.dom(selectors.toggleGroup(group)).exists(`${group} renders`); + }); - await click(selectors.toggleSigningOptions); + await click(selectors.toggleGroup('Signing options')); ['usePss', 'skid', 'signatureBits'].forEach((name) => { assert.dom(selectors.fieldByName(name)).exists(); }); diff --git a/ui/tests/integration/components/secret-engine/configuration-details-test.js b/ui/tests/integration/components/secret-engine/configuration-details-test.js index 9b5127dce8d1..b849e16fd0d4 100644 --- a/ui/tests/integration/components/secret-engine/configuration-details-test.js +++ b/ui/tests/integration/components/secret-engine/configuration-details-test.js @@ -16,6 +16,8 @@ import { expectedValueOfConfigKeys, } from 'vault/tests/helpers/secret-engine/secret-engine-helpers'; +const allEnginesArray = allEngines(); // saving as const so we don't invoke the method multiple times via the for loop + module('Integration | Component | SecretEngine/ConfigurationDetails', function (hooks) { setupRenderingTest(hooks); @@ -35,10 +37,8 @@ module('Integration | Component | SecretEngine/ConfigurationDetails', function ( .hasText(`Get started by configuring your Display Name secrets engine.`); }); - test('it shows config details if configModel(s) are passed in', async function (assert) { - assert.expect(36); - const allEnginesArray = allEngines(); // saving as const so we don't invoke the method multiple times via the for loop - for (const type of CONFIGURABLE_SECRET_ENGINES) { + for (const type of CONFIGURABLE_SECRET_ENGINES) { + test(`it shows config details if configModel(s) are passed in for type: ${type}`, async function (assert) { const backend = `test-${type}`; this.configModels = createConfig(this.store, backend, type); this.typeDisplay = allEnginesArray.find((engine) => engine.type === type).displayName; @@ -60,6 +60,6 @@ module('Integration | Component | SecretEngine/ConfigurationDetails', function ( assert.dom(GENERAL.infoRowValue(key)).doesNotHaveClass('masked-input', `${key} is not masked`); } } - } - }); + }); + } }); diff --git a/ui/tests/unit/adapters/ldap/role-test.js b/ui/tests/unit/adapters/ldap/role-test.js index 78bda11cbabb..aa61b2f3ea2e 100644 --- a/ui/tests/unit/adapters/ldap/role-test.js +++ b/ui/tests/unit/adapters/ldap/role-test.js @@ -19,8 +19,8 @@ module('Unit | Adapter | ldap/role', function (hooks) { this.adapter = this.store.adapterFor('ldap/role'); this.path = 'role'; - this.getModel = (type) => { - const name = 'test-role'; + this.getModel = (type, roleName) => { + const name = roleName || 'test-role'; this.store.pushPayload('ldap/role', { modelName: 'ldap/role', backend: 'ldap-test', @@ -32,214 +32,296 @@ module('Unit | Adapter | ldap/role', function (hooks) { }; }); - test('it should make request to correct endpoints when listing records', async function (assert) { - assert.expect(6); + module('happy paths', function () { + test('it should make request to correct endpoints when listing records', async function (assert) { + assert.expect(6); - const assertRequest = (schema, req) => { - assert.ok(req.queryParams.list, 'list query param sent when listing roles'); - const name = req.url.includes('static-role') ? 'static-test' : 'dynamic-test'; - return { data: { keys: [name] } }; - }; - - this.server.get('/ldap-test/static-role', assertRequest); - this.server.get('/ldap-test/role', assertRequest); + const assertRequest = (schema, req) => { + assert.ok(req.queryParams.list, 'list query param sent when listing roles'); + const name = req.url.includes('static-role') ? 'static-test' : 'dynamic-test'; + return { data: { keys: [name] } }; + }; - this.models = await this.store.query('ldap/role', { backend: 'ldap-test' }); + this.server.get('/ldap-test/static-role', assertRequest); + this.server.get('/ldap-test/role', assertRequest); - const model = this.models[0]; - assert.strictEqual(this.models.length, 2, 'Returns responses from both endpoints'); - assert.strictEqual(model.backend, 'ldap-test', 'Backend value is set on records returned from query'); - // sorted alphabetically by name so dynamic should be first - assert.strictEqual(model.type, 'dynamic', 'Type value is set on records returned from query'); - assert.strictEqual(model.name, 'dynamic-test', 'Name value is set on records returned from query'); - }); + this.models = await this.store.query('ldap/role', { backend: 'ldap-test' }); - test('it should conditionally trigger info level flash message for single endpoint error from query', async function (assert) { - const flashMessages = this.owner.lookup('service:flashMessages'); - const flashSpy = sinon.spy(flashMessages, 'info'); - - this.server.get('/ldap-test/static-role', () => { - return new Response(403, {}, { errors: ['permission denied'] }); + const model = this.models[0]; + assert.strictEqual(this.models.length, 2, 'Returns responses from both endpoints'); + assert.strictEqual(model.backend, 'ldap-test', 'Backend value is set on records returned from query'); + // sorted alphabetically by name so dynamic should be first + assert.strictEqual(model.type, 'dynamic', 'Type value is set on records returned from query'); + assert.strictEqual(model.name, 'dynamic-test', 'Name value is set on records returned from query'); }); - this.server.get('/ldap-test/role', () => ({ data: { keys: ['dynamic-test'] } })); - - await this.store.query('ldap/role', { backend: 'ldap-test' }); - await this.store.query( - 'ldap/role', - { backend: 'ldap-test' }, - { adapterOptions: { showPartialError: true } } - ); - - assert.true( - flashSpy.calledOnceWith('Error fetching roles from /v1/ldap-test/static-role: permission denied'), - 'Partial error info only displays when adapter option is passed' - ); - }); - test('it should throw error for query when requests to both endpoints fail', async function (assert) { - assert.expect(2); + test('it should conditionally trigger info level flash message for single endpoint error from query', async function (assert) { + const flashMessages = this.owner.lookup('service:flashMessages'); + const flashSpy = sinon.spy(flashMessages, 'info'); - this.server.get('/ldap-test/:path', (schema, req) => { - const errors = { - 'static-role': ['permission denied'], - role: ['server error'], - }[req.params.path]; - return new Response(req.params.path === 'static-role' ? 403 : 500, {}, { errors }); - }); + this.server.get('/ldap-test/static-role', () => { + return new Response(403, {}, { errors: ['permission denied'] }); + }); + this.server.get('/ldap-test/role', () => ({ data: { keys: ['dynamic-test'] } })); - try { await this.store.query('ldap/role', { backend: 'ldap-test' }); - } catch (error) { - assert.deepEqual( - error.errors, - ['/v1/ldap-test/static-role: permission denied', '/v1/ldap-test/role: server error'], - 'Error messages is thrown with correct payload from query.' + await this.store.query( + 'ldap/role', + { backend: 'ldap-test' }, + { adapterOptions: { showPartialError: true } } ); - assert.strictEqual( - error.message, - 'Error fetching roles:', - 'Error message is thrown with correct payload from query.' - ); - } - }); - - test('it should make request to correct endpoints when querying record', async function (assert) { - assert.expect(5); - this.server.get('/ldap-test/:path/test-role', (schema, req) => { - assert.strictEqual( - req.params.path, - this.path, - 'GET request made to correct endpoint when querying record' + assert.true( + flashSpy.calledOnceWith('Error fetching roles from /v1/ldap-test/static-role: permission denied'), + 'Partial error info only displays when adapter option is passed' ); }); - for (const type of ['dynamic', 'static']) { - this.model = await this.store.queryRecord('ldap/role', { - backend: 'ldap-test', - type, - name: 'test-role', + test('it should throw error for query when requests to both endpoints fail', async function (assert) { + assert.expect(2); + + this.server.get('/ldap-test/:path', (schema, req) => { + const errors = { + 'static-role': ['permission denied'], + role: ['server error'], + }[req.params.path]; + return new Response(req.params.path === 'static-role' ? 403 : 500, {}, { errors }); }); - this.path = 'static-role'; - } - assert.strictEqual( - this.model.backend, - 'ldap-test', - 'Backend value is set on records returned from query' - ); - assert.strictEqual(this.model.type, 'static', 'Type value is set on records returned from query'); - assert.strictEqual(this.model.name, 'test-role', 'Name value is set on records returned from query'); - }); + try { + await this.store.query('ldap/role', { backend: 'ldap-test' }); + } catch (error) { + assert.deepEqual( + error.errors, + ['/v1/ldap-test/static-role: permission denied', '/v1/ldap-test/role: server error'], + 'Error messages is thrown with correct payload from query.' + ); + assert.strictEqual( + error.message, + 'Error fetching roles:', + 'Error message is thrown with correct payload from query.' + ); + } + }); - test('it should make request to correct endpoints when creating new dynamic role record', async function (assert) { - assert.expect(1); + test('it should make request to correct endpoints when querying record', async function (assert) { + assert.expect(5); + + this.server.get('/ldap-test/:path/test-role', (schema, req) => { + assert.strictEqual( + req.params.path, + this.path, + 'GET request made to correct endpoint when querying record' + ); + }); + + for (const type of ['dynamic', 'static']) { + this.model = await this.store.queryRecord('ldap/role', { + backend: 'ldap-test', + type, + name: 'test-role', + }); + this.path = 'static-role'; + } - this.server.post('/ldap-test/:path/:name', (schema, req) => { assert.strictEqual( - req.params.path, - this.path, - 'POST request made to correct endpoint when creating new record for a dynamic role' + this.model.backend, + 'ldap-test', + 'Backend value is set on records returned from query' ); + assert.strictEqual(this.model.type, 'static', 'Type value is set on records returned from query'); + assert.strictEqual(this.model.name, 'test-role', 'Name value is set on records returned from query'); }); - const getModel = (type, name) => { - return this.store.createRecord('ldap/role', { - backend: 'ldap-test', - name, - type, + test('it should make request to correct endpoints when creating new dynamic role record', async function (assert) { + assert.expect(1); + + this.server.post('/ldap-test/:path/:name', (schema, req) => { + assert.strictEqual( + req.params.path, + this.path, + 'POST request made to correct endpoint when creating new record for a dynamic role' + ); }); - }; - const model = getModel('dynamic-role', 'dynamic-role-name'); - await model.save(); - }); + const getModel = (type, name) => { + return this.store.createRecord('ldap/role', { + backend: 'ldap-test', + name, + type, + }); + }; - test('it should make request to correct endpoints when creating new static role record', async function (assert) { - assert.expect(1); + const model = getModel('dynamic-role', 'dynamic-role-name'); + await model.save(); + }); - this.server.post('/ldap-test/:path/:name', (schema, req) => { - assert.strictEqual( - req.params.path, - this.path, - 'POST request made to correct endpoint when creating new record for a static role' - ); + test('it should make request to correct endpoints when creating new static role record', async function (assert) { + assert.expect(1); + + this.server.post('/ldap-test/:path/:name', (schema, req) => { + assert.strictEqual( + req.params.path, + this.path, + 'POST request made to correct endpoint when creating new record for a static role' + ); + }); + + const getModel = (type, name) => { + return this.store.createRecord('ldap/role', { + backend: 'ldap-test', + name, + type, + }); + }; + + const model = getModel('static-role', 'static-role-name'); + await model.save(); }); - const getModel = (type, name) => { - return this.store.createRecord('ldap/role', { - backend: 'ldap-test', - name, - type, + test('it should make request to correct endpoints when updating record', async function (assert) { + assert.expect(2); + + this.server.post('/ldap-test/:path/test-role', (schema, req) => { + assert.strictEqual( + req.params.path, + this.path, + 'POST request made to correct endpoint when updating record' + ); }); - }; - const model = getModel('static-role', 'static-role-name'); - await model.save(); - }); + for (const type of ['dynamic', 'static']) { + const record = this.getModel(type); + await record.save(); + this.path = 'static-role'; + } + }); - test('it should make request to correct endpoints when updating record', async function (assert) { - assert.expect(2); + test('it should make request to correct endpoints when deleting record', async function (assert) { + assert.expect(2); - this.server.post('/ldap-test/:path/test-role', (schema, req) => { - assert.strictEqual( - req.params.path, - this.path, - 'POST request made to correct endpoint when updating record' - ); + this.server.delete('/ldap-test/:path/test-role', (schema, req) => { + assert.strictEqual( + req.params.path, + this.path, + 'DELETE request made to correct endpoint when deleting record' + ); + }); + + for (const type of ['dynamic', 'static']) { + const record = this.getModel(type); + await record.destroyRecord(); + this.path = 'static-role'; + } }); - for (const type of ['dynamic', 'static']) { - const record = this.getModel(type); - await record.save(); - this.path = 'static-role'; - } - }); + test('it should make request to correct endpoints when fetching credentials', async function (assert) { + assert.expect(2); - test('it should make request to correct endpoints when deleting record', async function (assert) { - assert.expect(2); + this.path = 'creds'; - this.server.delete('/ldap-test/:path/test-role', (schema, req) => { - assert.strictEqual( - req.params.path, - this.path, - 'DELETE request made to correct endpoint when deleting record' - ); + this.server.get('/ldap-test/:path/test-role', (schema, req) => { + assert.strictEqual( + req.params.path, + this.path, + 'GET request made to correct endpoint when fetching credentials' + ); + }); + + for (const type of ['dynamic', 'static']) { + await this.adapter.fetchCredentials('ldap-test', type, 'test-role'); + this.path = 'static-cred'; + } }); - for (const type of ['dynamic', 'static']) { - const record = this.getModel(type); - await record.destroyRecord(); - this.path = 'static-role'; - } + test('it should make request to correct endpoint when rotating static role password', async function (assert) { + assert.expect(1); + + this.server.post('/ldap-test/rotate-role/test-role', () => { + assert.ok('GET request made to correct endpoint when rotating static role password'); + }); + + await this.adapter.rotateStaticPassword('ldap-test', 'test-role'); + }); }); - test('it should make request to correct endpoints when fetching credentials', async function (assert) { - assert.expect(2); + module('hierarchical paths', function () { + test('it should make request to correct endpoint when listing hierarchical records', async function (assert) { + assert.expect(2); - this.path = 'creds'; + const staticAncestry = { path_to_role: 'static-admin/', type: 'static' }; + const dynamicAncestry = { path_to_role: 'dynamic-admin/', type: 'dynamic' }; - this.server.get('/ldap-test/:path/test-role', (schema, req) => { - assert.strictEqual( - req.params.path, - this.path, - 'GET request made to correct endpoint when fetching credentials' + this.server.get(`/ldap-test/static-role/${staticAncestry.path_to_role}`, (schema, req) => { + assert.strictEqual( + req.queryParams.list, + 'true', + `query request lists roles of type: ${staticAncestry.type}` + ); + return { data: { keys: ['my-static-role'] } }; + }); + this.server.get(`/ldap-test/role/${dynamicAncestry.path_to_role}`, (schema, req) => { + assert.strictEqual( + req.queryParams.list, + 'true', + `query request lists roles of type: ${dynamicAncestry.type}` + ); + return { data: { keys: ['my-dynamic-role'] } }; + }); + + await this.store.query( + 'ldap/role', + { backend: 'ldap-test' }, + { adapterOptions: { roleAncestry: staticAncestry } } + ); + await this.store.query( + 'ldap/role', + { backend: 'ldap-test' }, + { adapterOptions: { roleAncestry: dynamicAncestry } } ); }); for (const type of ['dynamic', 'static']) { - await this.adapter.fetchCredentials('ldap-test', type, 'test-role'); - this.path = 'static-cred'; + test(`it should make request to correct endpoint when deleting a role for type: ${type}`, async function (assert) { + assert.expect(1); + + const url = + type === 'static' + ? '/ldap-test/static-role/admin/my-static-role' + : '/ldap-test/role/admin/my-dynamic-role'; + + this.server.delete(url, () => { + assert.true(true, `DELETE request made to delete hierarchical role of type: ${type}`); + }); + + const record = this.getModel(type, `admin/my-${type}-role`); + await record.destroyRecord(); + }); + + test(`it should make request to correct endpoints when fetching credentials for type: ${type}`, async function (assert) { + assert.expect(1); + + const url = + type === 'static' + ? '/ldap-test/static-cred/admin/my-static-role' + : '/ldap-test/creds/admin/my-dynamic-role'; + + this.server.get(url, () => { + assert.true(true, `request made to fetch credentials for role type: ${type}`); + }); + + await this.adapter.fetchCredentials('ldap-test', type, `admin/my-${type}-role`); + }); } - }); - test('it should make request to correct endpoint when rotating static role password', async function (assert) { - assert.expect(1); + test('it should make request to correct endpoint when rotating static role password', async function (assert) { + assert.expect(1); - this.server.post('/ldap-test/rotate-role/test-role', () => { - assert.ok('GET request made to correct endpoint when rotating static role password'); - }); + this.server.post('/ldap-test/rotate-role/admin/test-role', () => { + assert.ok('GET request made to correct endpoint when rotating static role password'); + }); - await this.adapter.rotateStaticPassword('ldap-test', 'test-role'); + await this.adapter.rotateStaticPassword('ldap-test', 'admin/test-role'); + }); }); }); diff --git a/ui/tests/unit/utils/ldap-breadcrumbs-test.js b/ui/tests/unit/utils/ldap-breadcrumbs-test.js index 8c1318b40c7c..5ad510594b2a 100644 --- a/ui/tests/unit/utils/ldap-breadcrumbs-test.js +++ b/ui/tests/unit/utils/ldap-breadcrumbs-test.js @@ -3,15 +3,18 @@ * SPDX-License-Identifier: BUSL-1.1 */ -import { ldapBreadcrumbs } from 'ldap/utils/ldap-breadcrumbs'; +import { ldapBreadcrumbs, roleRoutes } from 'ldap/utils/ldap-breadcrumbs'; import { module, test } from 'qunit'; module('Unit | Utility | ldap breadcrumbs', function (hooks) { hooks.beforeEach(async function () { this.mountPath = 'my-engine'; this.roleType = 'static'; + const routeParams = (childResource) => { + return [this.mountPath, this.roleType, childResource]; + }; this.testCrumbs = (path, { lastItemCurrent }) => { - return ldapBreadcrumbs(path, this.roleType, this.mountPath, lastItemCurrent); + return ldapBreadcrumbs(path, routeParams, roleRoutes, lastItemCurrent); }; }); diff --git a/ui/types/vault/models/ldap/library.d.ts b/ui/types/vault/models/ldap/library.d.ts index 1def4cc4f6f1..969538ba951e 100644 --- a/ui/types/vault/models/ldap/library.d.ts +++ b/ui/types/vault/models/ldap/library.d.ts @@ -13,10 +13,12 @@ import type { export default interface LdapLibraryModel extends WithFormFieldsAndValidationsModel { backend: string; name: string; + path_to_library: string; service_account_names: string; default_ttl: number; max_ttl: number; disable_check_in_enforcement: string; + get completeLibraryName(): string; get displayFields(): Array; libraryPath: CapabilitiesModel; statusPath: CapabilitiesModel; diff --git a/ui/types/vault/models/ldap/role.d.ts b/ui/types/vault/models/ldap/role.d.ts index 6464e3686496..cb7dce38e879 100644 --- a/ui/types/vault/models/ldap/role.d.ts +++ b/ui/types/vault/models/ldap/role.d.ts @@ -20,6 +20,7 @@ export default interface LdapRoleModel extends WithFormFieldsAndValidationsModel username_template: string; creation_ldif: string; rollback_ldif: string; + get completeRoleName(): string; get isStatic(): string; get isDynamic(): string; get fieldsForType(): Array; diff --git a/vault/activity/activity_log.pb.go b/vault/activity/activity_log.pb.go index aa7ce5d5919c..6f4056c170ef 100644 --- a/vault/activity/activity_log.pb.go +++ b/vault/activity/activity_log.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: vault/activity/activity_log.proto @@ -27,12 +27,9 @@ const ( // can store clients associated with entities or nonEntity clients, and really // is a ClientRecord, not specifically an EntityRecord. type EntityRecord struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ClientID string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` - NamespaceID string `protobuf:"bytes,2,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + ClientID string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + NamespaceID string `protobuf:"bytes,2,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` // using the Timestamp type would cost us an extra // 4 bytes per record to store nanoseconds. Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` @@ -44,7 +41,9 @@ type EntityRecord struct { MountAccessor string `protobuf:"bytes,5,opt,name=mount_accessor,json=mountAccessor,proto3" json:"mount_accessor,omitempty"` // client_type identifies the source of the entity record (entity, // non-entity, acme, etc.) - ClientType string `protobuf:"bytes,6,opt,name=client_type,json=clientType,proto3" json:"client_type,omitempty"` + ClientType string `protobuf:"bytes,6,opt,name=client_type,json=clientType,proto3" json:"client_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *EntityRecord) Reset() { @@ -120,10 +119,7 @@ func (x *EntityRecord) GetClientType() string { } type LogFragment struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // hostname (or node ID?) where the fragment originated, // used for debugging. OriginatingNode string `protobuf:"bytes,1,opt,name=originating_node,json=originatingNode,proto3" json:"originating_node,omitempty"` @@ -131,10 +127,9 @@ type LogFragment struct { Clients []*EntityRecord `protobuf:"bytes,2,rep,name=clients,proto3" json:"clients,omitempty"` // token counts not yet in a log segment, // indexed by namespace ID - NonEntityTokens map[string]uint64 `protobuf:"bytes,3,rep,name=non_entity_tokens,json=nonEntityTokens,proto3" json:"non_entity_tokens,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - // the cluster id that this fragment originated from - // this is used when a fragment is sent from a secondary - OriginatingCluster string `protobuf:"bytes,4,opt,name=originating_cluster,json=originatingCluster,proto3" json:"originating_cluster,omitempty"` + NonEntityTokens map[string]uint64 `protobuf:"bytes,3,rep,name=non_entity_tokens,json=nonEntityTokens,proto3" json:"non_entity_tokens,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *LogFragment) Reset() { @@ -188,21 +183,13 @@ func (x *LogFragment) GetNonEntityTokens() map[string]uint64 { return nil } -func (x *LogFragment) GetOriginatingCluster() string { - if x != nil { - return x.OriginatingCluster - } - return "" -} - // This activity log stores records for both clients with entities // and clients without entities type EntityActivityLog struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Clients []*EntityRecord `protobuf:"bytes,1,rep,name=clients,proto3" json:"clients,omitempty"` unknownFields protoimpl.UnknownFields - - Clients []*EntityRecord `protobuf:"bytes,1,rep,name=clients,proto3" json:"clients,omitempty"` + sizeCache protoimpl.SizeCache } func (x *EntityActivityLog) Reset() { @@ -243,11 +230,10 @@ func (x *EntityActivityLog) GetClients() []*EntityRecord { } type TokenCount struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - CountByNamespaceID map[string]uint64 `protobuf:"bytes,1,rep,name=count_by_namespace_id,json=countByNamespaceId,proto3" json:"count_by_namespace_id,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + state protoimpl.MessageState `protogen:"open.v1"` + CountByNamespaceID map[string]uint64 `protobuf:"bytes,1,rep,name=count_by_namespace_id,json=countByNamespaceId,proto3" json:"count_by_namespace_id,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *TokenCount) Reset() { @@ -288,9 +274,9 @@ func (x *TokenCount) GetCountByNamespaceID() map[string]uint64 { } type LogFragmentResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *LogFragmentResponse) Reset() { @@ -342,7 +328,7 @@ var file_vault_activity_activity_log_proto_rawDesc = []byte{ 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, - 0x79, 0x70, 0x65, 0x22, 0xb7, 0x02, 0x0a, 0x0b, 0x4c, 0x6f, 0x67, 0x46, 0x72, 0x61, 0x67, 0x6d, + 0x79, 0x70, 0x65, 0x22, 0x86, 0x02, 0x0a, 0x0b, 0x4c, 0x6f, 0x67, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x30, @@ -354,35 +340,32 @@ var file_vault_activity_activity_log_proto_rawDesc = []byte{ 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x4c, 0x6f, 0x67, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x6f, 0x6e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x6e, 0x6f, 0x6e, 0x45, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x6f, 0x72, 0x69, 0x67, - 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, - 0x6e, 0x67, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x1a, 0x42, 0x0a, 0x14, 0x4e, 0x6f, 0x6e, - 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x45, 0x0a, - 0x11, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x4c, - 0x6f, 0x67, 0x12, 0x30, 0x0a, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x45, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x73, 0x22, 0xb4, 0x01, 0x0a, 0x0a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x5f, 0x0a, 0x15, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, - 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x12, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x49, 0x64, 0x1a, 0x45, 0x0a, 0x17, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x4e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x15, 0x0a, 0x13, 0x4c, - 0x6f, 0x67, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x42, 0x2b, 0x5a, 0x29, 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, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x1a, 0x42, 0x0a, 0x14, 0x4e, 0x6f, 0x6e, 0x45, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x45, 0x0a, 0x11, + 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x4c, 0x6f, + 0x67, 0x12, 0x30, 0x0a, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x45, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x73, 0x22, 0xb4, 0x01, 0x0a, 0x0a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x5f, 0x0a, 0x15, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2c, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x2e, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x4e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x12, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x49, 0x64, 0x1a, 0x45, 0x0a, 0x17, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x4e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x6f, + 0x67, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x42, 0x2b, 0x5a, 0x29, 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, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/vault/activity/activity_log.proto b/vault/activity/activity_log.proto index ac68db1c4e2a..cb0a6b94e8d7 100644 --- a/vault/activity/activity_log.proto +++ b/vault/activity/activity_log.proto @@ -38,10 +38,6 @@ message LogFragment { // token counts not yet in a log segment, // indexed by namespace ID map non_entity_tokens = 3; - - // the cluster id that this fragment originated from - // this is used when a fragment is sent from a secondary - string originating_cluster = 4; } // This activity log stores records for both clients with entities diff --git a/vault/activity_log.go b/vault/activity_log.go index 757165f3e1f1..71df6654a16a 100644 --- a/vault/activity_log.go +++ b/vault/activity_log.go @@ -36,28 +36,23 @@ import ( const ( // activitySubPath is the directory under the system view where // the log will be stored. - activitySubPath = "counters/activity/" - activityEntityBasePath = "log/entity/" - activityTokenBasePath = "log/directtokens/" - activityTokenLocalBasePath = "local/" + activityTokenBasePath - activityQueryBasePath = "queries/" - activityConfigKey = "config" - activityIntentLogKey = "endofmonth" - activityGlobalPathPrefix = "global/" - activityLocalPathPrefix = "local/" + activitySubPath = "counters/activity/" + activityEntityBasePath = "log/entity/" + activityTokenBasePath = "log/directtokens/" + activityQueryBasePath = "queries/" + activityConfigKey = "config" + activityIntentLogKey = "endofmonth" activityACMERegenerationKey = "acme-regeneration" // sketch for each month that stores hash of client ids distinctClientsBasePath = "log/distinctclients/" // for testing purposes (public as needed) - ActivityGlobalLogPrefix = "sys/counters/activity/global/log/" - ActivityLogLocalPrefix = "sys/counters/activity/local/log/" - ActivityPrefix = "sys/counters/activity/" + ActivityLogPrefix = "sys/counters/activity/log/" + ActivityPrefix = "sys/counters/activity/" - // Time to wait before a perf standby sends data to the active node, or - // before the active node of a performance secondary sends global data to the primary. - activityFragmentSendInterval = 10 * time.Minute + // Time to wait on perf standby before sending fragment + activityFragmentStandbyTime = 10 * time.Minute // Time between writes of segment to storage activitySegmentInterval = 10 * time.Minute @@ -143,20 +138,13 @@ type ActivityLog struct { // ActivityLog.l protects the configuration settings, except enable, and any modifications // to the current segment. - // Acquire "l" before fragmentLock, globalFragmentLock, and localFragmentLock if all must be held. + // Acquire "l" before fragmentLock if both must be held. l sync.RWMutex - // fragmentLock protects enable + // fragmentLock protects enable, partialMonthClientTracker, fragment, + // standbyFragmentsReceived. fragmentLock sync.RWMutex - // localFragmentLock protects partialMonthLocalClientTracker, localFragment, - // standbyLocalFragmentsReceived. - localFragmentLock sync.RWMutex - - // globalFragmentLock protects enable secondaryGlobalClientFragments, standbyGlobalFragmentsReceived, currentGlobalFragment - // and globalPartialMonthClientTracker - globalFragmentLock sync.RWMutex - // enabled indicates if the activity log is enabled for this cluster. // This is protected by fragmentLock so we can check with only // a single synchronization call. @@ -178,18 +166,14 @@ type ActivityLog struct { // could be adapted to use a secondary in the future. nodeID string + // current log fragment (may be nil) + fragment *activity.LogFragment + fragmentCreation time.Time + // Channel to signal a new fragment has been created // so it's appropriate to start the timer. newFragmentCh chan struct{} - // current local log fragment (may be nil) - localFragment *activity.LogFragment - - // Channel to signal a new global fragment has been created - // so it's appropriate to start the timer. Once the timer finishes - // the secondary will send currentGlobalFragment to the primary - newGlobalClientFragmentCh chan struct{} - // Channel for sending fragment immediately sendCh chan struct{} @@ -199,20 +183,8 @@ type ActivityLog struct { // track metadata and contents of the most recent log segment currentSegment segmentInfo - // track metadata and contents of the most recent global log segment - currentGlobalSegment segmentInfo - - // track metadata and contents of the most recent local log segment - currentLocalSegment segmentInfo - - // Local fragments received from performance standbys - standbyLocalFragmentsReceived []*activity.LogFragment - - // Global fragments received from performance standbys - standbyGlobalFragmentsReceived []*activity.LogFragment - - // Fragments of global clients received from performance secondaries - secondaryGlobalClientFragments []*activity.LogFragment + // Fragments received from performance standbys + standbyFragmentsReceived []*activity.LogFragment // precomputed queries queryStore *activity.PrecomputedQueryStore @@ -230,11 +202,8 @@ type ActivityLog struct { // for testing: is config currently being invalidated. protected by l configInvalidationInProgress bool - // partialMonthLocalClientTracker tracks active local clients this month. Protected by localFragmentLock. - partialMonthLocalClientTracker map[string]*activity.EntityRecord - - // globalPartialMonthClientTracker tracks active clients this month. Protected by globalFragmentLock. - globalPartialMonthClientTracker map[string]*activity.EntityRecord + // partialMonthClientTracker tracks active clients this month. Protected by fragmentLock. + partialMonthClientTracker map[string]*activity.EntityRecord inprocessExport *atomic.Bool @@ -243,9 +212,6 @@ type ActivityLog struct { // precomputedQueryWritten receives an element whenever a precomputed query // is written. It's used for unit testing precomputedQueryWritten chan struct{} - - // currentGlobalFragment tracks the global clients of all the clients in memory - currentGlobalFragment *activity.LogFragment } // These non-persistent configuration options allow us to disable @@ -268,18 +234,6 @@ type ActivityLogCoreConfig struct { Clock timeutil.Clock DisableInvalidation bool - - // GlobalFragmentSendInterval sets the interval to send global data from the secondary to the primary - // This is only for testing purposes - GlobalFragmentSendInterval time.Duration - - // PerfStandbyFragmentSendInterval sets the interval to send fragment data from the perf standby to the active - // This is only for testing purposes - PerfStandbyFragmentSendInterval time.Duration - - // StorageWriteTestingInterval sets the interval flush data to the storage. - // This is only for testing purposes - StorageWriteTestingInterval time.Duration } // ActivityLogExportRecord is the output structure for activity export @@ -350,19 +304,17 @@ func NewActivityLog(core *Core, logger log.Logger, view *BarrierView, metrics me clock = timeutil.DefaultClock{} } a := &ActivityLog{ - core: core, - configOverrides: &core.activityLogConfig, - logger: logger, - view: view, - metrics: metrics, - nodeID: hostname, - newFragmentCh: make(chan struct{}, 1), - sendCh: make(chan struct{}, 1), // buffered so it can be triggered by fragment size - doneCh: make(chan struct{}, 1), - partialMonthLocalClientTracker: make(map[string]*activity.EntityRecord), - newGlobalClientFragmentCh: make(chan struct{}, 1), - globalPartialMonthClientTracker: make(map[string]*activity.EntityRecord), - clock: clock, + core: core, + configOverrides: &core.activityLogConfig, + logger: logger, + view: view, + metrics: metrics, + nodeID: hostname, + newFragmentCh: make(chan struct{}, 1), + sendCh: make(chan struct{}, 1), // buffered so it can be triggered by fragment size + doneCh: make(chan struct{}, 1), + partialMonthClientTracker: make(map[string]*activity.EntityRecord), + clock: clock, currentSegment: segmentInfo{ startTimestamp: 0, currentClients: &activity.EntityActivityLog{ @@ -376,37 +328,9 @@ func NewActivityLog(core *Core, logger log.Logger, view *BarrierView, metrics me }, clientSequenceNumber: 0, }, - currentGlobalSegment: segmentInfo{ - startTimestamp: 0, - currentClients: &activity.EntityActivityLog{ - Clients: make([]*activity.EntityRecord, 0), - }, - // tokenCount is deprecated, but must still exist for the current segment - // so the fragment that was using TWEs before the 1.9 changes - // can be flushed to the current segment. - tokenCount: &activity.TokenCount{ - CountByNamespaceID: make(map[string]uint64), - }, - clientSequenceNumber: 0, - }, - currentLocalSegment: segmentInfo{ - startTimestamp: 0, - currentClients: &activity.EntityActivityLog{ - Clients: make([]*activity.EntityRecord, 0), - }, - // tokenCount is deprecated, but must still exist for the current segment - // so the fragment that was using TWEs before the 1.9 changes - // can be flushed to the current segment. - tokenCount: &activity.TokenCount{ - CountByNamespaceID: make(map[string]uint64), - }, - clientSequenceNumber: 0, - }, - standbyLocalFragmentsReceived: make([]*activity.LogFragment, 0), - standbyGlobalFragmentsReceived: make([]*activity.LogFragment, 0), - secondaryGlobalClientFragments: make([]*activity.LogFragment, 0), - inprocessExport: atomic.NewBool(false), - precomputedQueryWritten: make(chan struct{}), + standbyFragmentsReceived: make([]*activity.LogFragment, 0), + inprocessExport: atomic.NewBool(false), + precomputedQueryWritten: make(chan struct{}), } config, err := a.loadConfigOrDefault(core.activeContext) @@ -449,90 +373,39 @@ func (a *ActivityLog) saveCurrentSegmentToStorageLocked(ctx context.Context, for defer a.metrics.MeasureSinceWithLabels([]string{"core", "activity", "segment_write"}, a.clock.Now(), []metricsutil.Label{}) - // Swap out the pending global fragments - a.globalFragmentLock.Lock() - secondaryGlobalClients := a.secondaryGlobalClientFragments - a.secondaryGlobalClientFragments = make([]*activity.LogFragment, 0) - standbyGlobalClients := a.standbyGlobalFragmentsReceived - a.standbyGlobalFragmentsReceived = make([]*activity.LogFragment, 0) - globalClients := a.currentGlobalFragment - a.currentGlobalFragment = nil - a.globalFragmentLock.Unlock() - - if !a.core.IsPerfSecondary() { - if a.currentGlobalFragment != nil { - a.metrics.IncrCounterWithLabels([]string{"core", "activity", "global_fragment_size"}, - float32(len(globalClients.Clients)), - []metricsutil.Label{ - {"type", "client"}, - }) - } - var globalReceivedFragmentTotal int - for _, globalReceivedFragment := range secondaryGlobalClients { - globalReceivedFragmentTotal += len(globalReceivedFragment.Clients) - } - for _, globalReceivedFragment := range standbyGlobalClients { - globalReceivedFragmentTotal += len(globalReceivedFragment.Clients) - } - a.metrics.IncrCounterWithLabels([]string{"core", "activity", "global_received_fragment_size"}, - float32(globalReceivedFragmentTotal), - []metricsutil.Label{ - {"type", "client"}, - }) - - } + // Swap out the pending fragments + a.fragmentLock.Lock() + localFragment := a.fragment + a.fragment = nil + standbys := a.standbyFragmentsReceived + a.standbyFragmentsReceived = make([]*activity.LogFragment, 0) + a.fragmentLock.Unlock() // If segment start time is zero, do not update or write // (even if force is true). This can happen if activityLog is // disabled after a save as been triggered. - if a.currentGlobalSegment.startTimestamp == 0 { + if a.currentSegment.startTimestamp == 0 { return nil } - // If we are the primary, store global clients - // Create fragments from global clients and store the segment - if !a.core.IsPerfSecondary() { - globalFragments := append(append(secondaryGlobalClients, globalClients), standbyGlobalClients...) - if ret := a.createCurrentSegmentFromFragments(ctx, globalFragments, &a.currentGlobalSegment, force, activityGlobalPathPrefix); ret != nil { - return ret - } - } - - // Swap out the pending local fragments - a.localFragmentLock.Lock() - localFragment := a.localFragment - a.localFragment = nil - standbyLocalFragments := a.standbyLocalFragmentsReceived - a.standbyLocalFragmentsReceived = make([]*activity.LogFragment, 0) - a.localFragmentLock.Unlock() - - // Measure the current local fragment + // Measure the current fragment if localFragment != nil { - a.metrics.IncrCounterWithLabels([]string{"core", "activity", "local_fragment_size"}, + a.metrics.IncrCounterWithLabels([]string{"core", "activity", "fragment_size"}, float32(len(localFragment.Clients)), []metricsutil.Label{ {"type", "entity"}, }) - a.metrics.IncrCounterWithLabels([]string{"core", "activity", "local_fragment_size"}, + a.metrics.IncrCounterWithLabels([]string{"core", "activity", "fragment_size"}, float32(len(localFragment.NonEntityTokens)), []metricsutil.Label{ {"type", "direct_token"}, }) } - // store local fragments - if ret := a.createCurrentSegmentFromFragments(ctx, append(standbyLocalFragments, localFragment), &a.currentLocalSegment, force, activityLocalPathPrefix); ret != nil { - return ret - } - - return nil -} - -func (a *ActivityLog) createCurrentSegmentFromFragments(ctx context.Context, fragments []*activity.LogFragment, currentSegment *segmentInfo, force bool, storagePathPrefix string) error { // Collect new entities and new tokens. saveChanges := false newEntities := make(map[string]*activity.EntityRecord) - for _, f := range fragments { + for _, f := range append(standbys, localFragment) { if f == nil { continue } @@ -542,7 +415,7 @@ func (a *ActivityLog) createCurrentSegmentFromFragments(ctx context.Context, fra for _, e := range f.Clients { // We could sort by timestamp to see which is first. // We'll ignore that; the order of the append above means - // that we choose entries in currentFragment over those + // that we choose entries in localFragment over those // from standby nodes. newEntities[e.ClientID] = e } @@ -551,12 +424,12 @@ func (a *ActivityLog) createCurrentSegmentFromFragments(ctx context.Context, fra // month when the client upgrades to 1.9, we must retain this functionality. for ns, val := range f.NonEntityTokens { // We track these pre-1.9 values in the old location, which is - // currentSegment.tokenCount, as opposed to the counter that stores tokens + // a.currentSegment.tokenCount, as opposed to the counter that stores tokens // without entities that have client IDs, namely // a.partialMonthClientTracker.nonEntityCountByNamespaceID. This preserves backward // compatibility for the precomputedQueryWorkers and the segment storing // logic. - currentSegment.tokenCount.CountByNamespaceID[ns] += val + a.currentSegment.tokenCount.CountByNamespaceID[ns] += val } } @@ -565,14 +438,14 @@ func (a *ActivityLog) createCurrentSegmentFromFragments(ctx context.Context, fra } // Will all new entities fit? If not, roll over to a new segment. - available := ActivitySegmentClientCapacity - len(currentSegment.currentClients.Clients) + available := ActivitySegmentClientCapacity - len(a.currentSegment.currentClients.Clients) remaining := available - len(newEntities) excess := 0 if remaining < 0 { excess = -remaining } - segmentClients := currentSegment.currentClients.Clients + segmentClients := a.currentSegment.currentClients.Clients excessClients := make([]*activity.EntityRecord, 0, excess) for _, record := range newEntities { if available > 0 { @@ -582,8 +455,9 @@ func (a *ActivityLog) createCurrentSegmentFromFragments(ctx context.Context, fra excessClients = append(excessClients, record) } } - currentSegment.currentClients.Clients = segmentClients - err := a.saveCurrentSegmentInternal(ctx, force, *currentSegment, storagePathPrefix) + a.currentSegment.currentClients.Clients = segmentClients + + err := a.saveCurrentSegmentInternal(ctx, force) if err != nil { // The current fragment(s) have already been placed into the in-memory // segment, but we may lose any excess (in excessClients). @@ -593,7 +467,7 @@ func (a *ActivityLog) createCurrentSegmentFromFragments(ctx context.Context, fra } if available <= 0 { - if currentSegment.clientSequenceNumber >= activityLogMaxSegmentPerMonth { + if a.currentSegment.clientSequenceNumber >= activityLogMaxSegmentPerMonth { // Cannot send as Warn because it will repeat too often, // and disabling/renabling would be complicated. a.logger.Trace("too many segments in current month", "dropped", len(excessClients)) @@ -601,13 +475,13 @@ func (a *ActivityLog) createCurrentSegmentFromFragments(ctx context.Context, fra } // Rotate to next segment - currentSegment.clientSequenceNumber += 1 + a.currentSegment.clientSequenceNumber += 1 if len(excessClients) > ActivitySegmentClientCapacity { a.logger.Warn("too many new active clients, dropping tail", "clients", len(excessClients)) excessClients = excessClients[:ActivitySegmentClientCapacity] } - currentSegment.currentClients.Clients = excessClients - err := a.saveCurrentSegmentInternal(ctx, force, *currentSegment, storagePathPrefix) + a.currentSegment.currentClients.Clients = excessClients + err := a.saveCurrentSegmentInternal(ctx, force) if err != nil { return err } @@ -616,12 +490,12 @@ func (a *ActivityLog) createCurrentSegmentFromFragments(ctx context.Context, fra } // :force: forces a save of tokens/entities even if the in-memory log is empty -func (a *ActivityLog) saveCurrentSegmentInternal(ctx context.Context, force bool, currentSegment segmentInfo, storagePathPrefix string) error { - _, err := a.saveSegmentEntitiesInternal(ctx, currentSegment, force, storagePathPrefix) +func (a *ActivityLog) saveCurrentSegmentInternal(ctx context.Context, force bool) error { + _, err := a.saveSegmentEntitiesInternal(ctx, a.currentSegment, force) if err != nil { return err } - _, err = a.saveSegmentTokensInternal(ctx, currentSegment, force) + _, err = a.saveSegmentTokensInternal(ctx, a.currentSegment, force) return err } @@ -630,7 +504,7 @@ func (a *ActivityLog) saveSegmentTokensInternal(ctx context.Context, currentSegm return "", nil } // RFC (VLT-120) defines this as 1-indexed, but it should be 0-indexed - tokenPath := fmt.Sprintf("%s%d/0", activityTokenLocalBasePath, currentSegment.startTimestamp) + tokenPath := fmt.Sprintf("%s%d/0", activityTokenBasePath, currentSegment.startTimestamp) // We must still allow for the tokenCount of the current segment to // be written to storage, since if we remove this code we will incur // data loss for one segment's worth of TWEs. @@ -640,15 +514,15 @@ func (a *ActivityLog) saveSegmentTokensInternal(ctx context.Context, currentSegm switch { case err != nil: a.logger.Error(fmt.Sprintf("unable to retrieve oldest version timestamp: %s", err.Error())) - case len(currentSegment.tokenCount.CountByNamespaceID) > 0 && + case len(a.currentSegment.tokenCount.CountByNamespaceID) > 0 && (oldestUpgradeTime.Add(time.Duration(trackedTWESegmentPeriod * time.Hour)).Before(time.Now())): a.logger.Error(fmt.Sprintf("storing nonzero token count over a month after vault was upgraded to %s", oldestVersion)) default: - if len(currentSegment.tokenCount.CountByNamespaceID) > 0 { + if len(a.currentSegment.tokenCount.CountByNamespaceID) > 0 { a.logger.Info("storing nonzero token count") } } - tokenCount, err := proto.Marshal(currentSegment.tokenCount) + tokenCount, err := proto.Marshal(a.currentSegment.tokenCount) if err != nil { return "", err } @@ -665,10 +539,10 @@ func (a *ActivityLog) saveSegmentTokensInternal(ctx context.Context, currentSegm return tokenPath, nil } -func (a *ActivityLog) saveSegmentEntitiesInternal(ctx context.Context, currentSegment segmentInfo, force bool, storagePathPrefix string) (string, error) { - entityPath := fmt.Sprintf("%s%s%d/%d", storagePathPrefix, activityEntityBasePath, currentSegment.startTimestamp, currentSegment.clientSequenceNumber) +func (a *ActivityLog) saveSegmentEntitiesInternal(ctx context.Context, currentSegment segmentInfo, force bool) (string, error) { + entityPath := fmt.Sprintf("%s%d/%d", activityEntityBasePath, currentSegment.startTimestamp, currentSegment.clientSequenceNumber) - for _, client := range currentSegment.currentClients.Clients { + for _, client := range a.currentSegment.currentClients.Clients { // Explicitly catch and throw clear error message if client ID creation and storage // results in a []byte that doesn't assert into a valid string. if !utf8.ValidString(client.ClientID) { @@ -712,7 +586,7 @@ func parseSegmentNumberFromPath(path string) (int, bool) { // sorted last to first func (a *ActivityLog) availableLogs(ctx context.Context, upTo time.Time) ([]time.Time, error) { paths := make([]string, 0) - for _, basePath := range []string{activityLocalPathPrefix + activityEntityBasePath, activityGlobalPathPrefix + activityEntityBasePath, activityTokenLocalBasePath} { + for _, basePath := range []string{activityEntityBasePath, activityTokenBasePath} { p, err := a.view.List(ctx, basePath) if err != nil { return nil, err @@ -761,21 +635,8 @@ func (a *ActivityLog) getMostRecentActivityLogSegment(ctx context.Context, now t } // getLastEntitySegmentNumber returns the (non-negative) last segment number for the :startTime:, if it exists -func (a *ActivityLog) getLastEntitySegmentNumber(ctx context.Context, startTime time.Time) (uint64, uint64, bool, error) { - globalHighestNum, globalSegmentPresent, err := a.getLastSegmentNumberByEntityPath(ctx, activityGlobalPathPrefix+activityEntityBasePath+fmt.Sprint(startTime.Unix())+"/") - if err != nil { - return 0, 0, false, err - } - localHighestNum, localSegmentPresent, err := a.getLastSegmentNumberByEntityPath(ctx, activityLocalPathPrefix+activityEntityBasePath+fmt.Sprint(startTime.Unix())+"/") - if err != nil { - return 0, 0, false, err - } - - return uint64(localHighestNum), uint64(globalHighestNum), (localSegmentPresent || globalSegmentPresent), nil -} - -func (a *ActivityLog) getLastSegmentNumberByEntityPath(ctx context.Context, entityPath string) (uint64, bool, error) { - p, err := a.view.List(ctx, entityPath) +func (a *ActivityLog) getLastEntitySegmentNumber(ctx context.Context, startTime time.Time) (uint64, bool, error) { + p, err := a.view.List(ctx, activityEntityBasePath+fmt.Sprint(startTime.Unix())+"/") if err != nil { return 0, false, err } @@ -789,45 +650,40 @@ func (a *ActivityLog) getLastSegmentNumberByEntityPath(ctx context.Context, enti } } - segmentPresent := true - segmentHighestNum := uint64(highestNum) if highestNum < 0 { // numbers less than 0 are invalid. if a negative number is the highest value, there isn't a segment - segmentHighestNum = 0 - segmentPresent = false + return 0, false, nil } - return segmentHighestNum, segmentPresent, nil + + return uint64(highestNum), true, nil } // WalkEntitySegments loads each of the entity segments for a particular start time func (a *ActivityLog) WalkEntitySegments(ctx context.Context, startTime time.Time, hll *hyperloglog.Sketch, walkFn func(*activity.EntityActivityLog, time.Time, *hyperloglog.Sketch) error) error { - baseGlobalPath := activityGlobalPathPrefix + activityEntityBasePath + fmt.Sprint(startTime.Unix()) + "/" - baseLocalPath := activityLocalPathPrefix + activityEntityBasePath + fmt.Sprint(startTime.Unix()) + "/" + basePath := activityEntityBasePath + fmt.Sprint(startTime.Unix()) + "/" + pathList, err := a.view.List(ctx, basePath) + if err != nil { + return err + } - for _, basePath := range []string{baseGlobalPath, baseLocalPath} { - pathList, err := a.view.List(ctx, basePath) + for _, path := range pathList { + raw, err := a.view.Get(ctx, basePath+path) if err != nil { return err } - for _, path := range pathList { - raw, err := a.view.Get(ctx, basePath+path) - if err != nil { - return err - } - if raw == nil { - a.logger.Warn("expected log segment not found", "startTime", startTime, "segment", path) - continue - } + if raw == nil { + a.logger.Warn("expected log segment not found", "startTime", startTime, "segment", path) + continue + } - out := &activity.EntityActivityLog{} - err = proto.Unmarshal(raw.Value, out) - if err != nil { - return fmt.Errorf("unable to parse segment %v%v: %w", basePath, path, err) - } - err = walkFn(out, startTime, hll) - if err != nil { - return fmt.Errorf("unable to walk entities: %w", err) - } + out := &activity.EntityActivityLog{} + err = proto.Unmarshal(raw.Value, out) + if err != nil { + return fmt.Errorf("unable to parse segment %v%v: %w", basePath, path, err) + } + err = walkFn(out, startTime, hll) + if err != nil { + return fmt.Errorf("unable to walk entities: %w", err) } } return nil @@ -838,7 +694,7 @@ func (a *ActivityLog) WalkTokenSegments(ctx context.Context, startTime time.Time, walkFn func(*activity.TokenCount), ) error { - basePath := activityTokenLocalBasePath + fmt.Sprint(startTime.Unix()) + "/" + basePath := activityTokenBasePath + fmt.Sprint(startTime.Unix()) + "/" pathList, err := a.view.List(ctx, basePath) if err != nil { return err @@ -864,141 +720,73 @@ func (a *ActivityLog) WalkTokenSegments(ctx context.Context, } // loadPriorEntitySegment populates the in-memory tracker for entity IDs that have -// been active "this month". If the entity segment to load is global, globalPartialMonthClientTracker -// is updated else partialMonthLocalClientTracker gets updated. -func (a *ActivityLog) loadPriorEntitySegment(ctx context.Context, startTime time.Time, sequenceNum uint64, isLocal bool) error { - a.l.RLock() - defer a.l.RUnlock() - - // protecting a.enabled - a.fragmentLock.Lock() - defer a.fragmentLock.Unlock() - - // load all the active global clients - if !isLocal { - globalPath := activityGlobalPathPrefix + activityEntityBasePath + fmt.Sprint(startTime.Unix()) + "/" + strconv.FormatUint(sequenceNum, 10) - data, err := a.view.Get(ctx, globalPath) - if err != nil { - return err - } - if data == nil { - return nil - } - out := &activity.EntityActivityLog{} - err = proto.Unmarshal(data.Value, out) - if err != nil { - return err - } - a.globalFragmentLock.Lock() - // Handle the (unlikely) case where the end of the month has been reached while background loading. - // Or the feature has been disabled. - if a.enabled && startTime.Unix() == a.currentGlobalSegment.startTimestamp { - for _, ent := range out.Clients { - a.globalPartialMonthClientTracker[ent.ClientID] = ent - } - } - a.globalFragmentLock.Unlock() - return nil - } - - // load all the active local clients - localPath := activityLocalPathPrefix + activityEntityBasePath + fmt.Sprint(startTime.Unix()) + "/" + strconv.FormatUint(sequenceNum, 10) - data, err := a.view.Get(ctx, localPath) +// been active "this month" +func (a *ActivityLog) loadPriorEntitySegment(ctx context.Context, startTime time.Time, sequenceNum uint64) error { + path := activityEntityBasePath + fmt.Sprint(startTime.Unix()) + "/" + strconv.FormatUint(sequenceNum, 10) + data, err := a.view.Get(ctx, path) if err != nil { return err } if data == nil { return nil } + out := &activity.EntityActivityLog{} err = proto.Unmarshal(data.Value, out) if err != nil { return err } - a.localFragmentLock.Lock() + + a.l.RLock() + a.fragmentLock.Lock() // Handle the (unlikely) case where the end of the month has been reached while background loading. // Or the feature has been disabled. - if a.enabled && startTime.Unix() == a.currentLocalSegment.startTimestamp { + if a.enabled && startTime.Unix() == a.currentSegment.startTimestamp { for _, ent := range out.Clients { - a.partialMonthLocalClientTracker[ent.ClientID] = ent + a.partialMonthClientTracker[ent.ClientID] = ent } } - a.localFragmentLock.Unlock() + a.fragmentLock.Unlock() + a.l.RUnlock() return nil } // loadCurrentClientSegment loads the most recent segment (for "this month") -// into memory (to append new entries), and to the globalPartialMonthClientTracker and partialMonthLocalClientTracker to -// avoid duplication call with fragmentLock, globalFragmentLock, localFragmentLock and l held. -func (a *ActivityLog) loadCurrentClientSegment(ctx context.Context, startTime time.Time, localSegmentSequenceNumber uint64, globalSegmentSequenceNumber uint64) error { - // load current global segment - path := activityGlobalPathPrefix + activityEntityBasePath + fmt.Sprint(startTime.Unix()) + "/" + strconv.FormatUint(globalSegmentSequenceNumber, 10) - - // setting a.currentSegment timestamp to support upgrades - a.currentSegment.startTimestamp = startTime.Unix() - +// into memory (to append new entries), and to the partialMonthClientTracker to +// avoid duplication call with fragmentLock and l held. +func (a *ActivityLog) loadCurrentClientSegment(ctx context.Context, startTime time.Time, sequenceNum uint64) error { + path := activityEntityBasePath + fmt.Sprint(startTime.Unix()) + "/" + strconv.FormatUint(sequenceNum, 10) data, err := a.view.Get(ctx, path) if err != nil { return err } - if data != nil { - out := &activity.EntityActivityLog{} - err = proto.Unmarshal(data.Value, out) - if err != nil { - return err - } - - if !a.core.perfStandby { - a.currentGlobalSegment = segmentInfo{ - startTimestamp: startTime.Unix(), - currentClients: &activity.EntityActivityLog{ - Clients: out.Clients, - }, - tokenCount: &activity.TokenCount{ - CountByNamespaceID: make(map[string]uint64), - }, - clientSequenceNumber: globalSegmentSequenceNumber, - } - } else { - // populate this for edge case checking (if end of month passes while background loading on standby) - a.currentGlobalSegment.startTimestamp = startTime.Unix() - } - for _, client := range out.Clients { - a.globalPartialMonthClientTracker[client.ClientID] = client - } + if data == nil { + return nil } - // load current local segment - path = activityLocalPathPrefix + activityEntityBasePath + fmt.Sprint(startTime.Unix()) + "/" + strconv.FormatUint(localSegmentSequenceNumber, 10) - data, err = a.view.Get(ctx, path) + out := &activity.EntityActivityLog{} + err = proto.Unmarshal(data.Value, out) if err != nil { return err } - if data != nil { - out := &activity.EntityActivityLog{} - err = proto.Unmarshal(data.Value, out) - if err != nil { - return err - } - if !a.core.perfStandby { - a.currentLocalSegment = segmentInfo{ - startTimestamp: startTime.Unix(), - currentClients: &activity.EntityActivityLog{ - Clients: out.Clients, - }, - tokenCount: a.currentLocalSegment.tokenCount, - clientSequenceNumber: localSegmentSequenceNumber, - } - } else { - // populate this for edge case checking (if end of month passes while background loading on standby) - a.currentLocalSegment.startTimestamp = startTime.Unix() - } - for _, client := range out.Clients { - a.partialMonthLocalClientTracker[client.ClientID] = client + if !a.core.perfStandby { + a.currentSegment = segmentInfo{ + startTimestamp: startTime.Unix(), + currentClients: &activity.EntityActivityLog{ + Clients: out.Clients, + }, + tokenCount: a.currentSegment.tokenCount, + clientSequenceNumber: sequenceNum, } + } else { + // populate this for edge case checking (if end of month passes while background loading on standby) + a.currentSegment.startTimestamp = startTime.Unix() + } + for _, client := range out.Clients { + a.partialMonthClientTracker[client.ClientID] = client } return nil @@ -1007,7 +795,7 @@ func (a *ActivityLog) loadCurrentClientSegment(ctx context.Context, startTime ti // tokenCountExists checks if there's a token log for :startTime: // this function should be called with the lock held func (a *ActivityLog) tokenCountExists(ctx context.Context, startTime time.Time) (bool, error) { - p, err := a.view.List(ctx, activityTokenLocalBasePath+fmt.Sprint(startTime.Unix())+"/") + p, err := a.view.List(ctx, activityTokenBasePath+fmt.Sprint(startTime.Unix())+"/") if err != nil { return false, err } @@ -1032,7 +820,7 @@ func (a *ActivityLog) loadTokenCount(ctx context.Context, startTime time.Time) e return nil } - path := activityTokenLocalBasePath + fmt.Sprint(startTime.Unix()) + "/0" + path := activityTokenBasePath + fmt.Sprint(startTime.Unix()) + "/0" data, err := a.view.Get(ctx, path) if err != nil { return err @@ -1055,15 +843,13 @@ func (a *ActivityLog) loadTokenCount(ctx context.Context, startTime time.Time) e // We must load the tokenCount of the current segment into the activity log // so that TWEs counted before the introduction of a client ID for TWEs are // still reported in the partial client counts. - a.currentLocalSegment.tokenCount = out + a.currentSegment.tokenCount = out return nil } -// entityBackgroundLoader loads entity activity log records for start_date `t`. -// If isLocal is true, it loads the local entity activity log records else it -// loads global entity activity log records. -func (a *ActivityLog) entityBackgroundLoader(ctx context.Context, wg *sync.WaitGroup, t time.Time, seqNums <-chan uint64, isLocal bool) { +// entityBackgroundLoader loads entity activity log records for start_date `t` +func (a *ActivityLog) entityBackgroundLoader(ctx context.Context, wg *sync.WaitGroup, t time.Time, seqNums <-chan uint64) { defer wg.Done() for seqNum := range seqNums { select { @@ -1073,7 +859,7 @@ func (a *ActivityLog) entityBackgroundLoader(ctx context.Context, wg *sync.WaitG default: } - err := a.loadPriorEntitySegment(ctx, t, seqNum, isLocal) + err := a.loadPriorEntitySegment(ctx, t, seqNum) if err != nil { a.logger.Error("error loading entity activity log", "time", t, "sequence", seqNum, "err", err) } @@ -1081,91 +867,81 @@ func (a *ActivityLog) entityBackgroundLoader(ctx context.Context, wg *sync.WaitG } // Initialize a new current segment, based on the current time. -// Call with fragmentLock, globalFragmentLock, localFragmentLock and l held. +// Call with fragmentLock and l held. func (a *ActivityLog) startNewCurrentLogLocked(now time.Time) { a.logger.Trace("initializing new log") a.resetCurrentLog() - a.setCurrentSegmentTimeLocked(now) + a.currentSegment.startTimestamp = now.Unix() } -// Should be called with fragmentLock, globalFragmentLock, localFragmentLock and l held. +// Should be called with fragmentLock and l held. func (a *ActivityLog) newMonthCurrentLogLocked(currentTime time.Time) { a.logger.Trace("continuing log to new month") a.resetCurrentLog() monthStart := timeutil.StartOfMonth(currentTime.UTC()) - a.setCurrentSegmentTimeLocked(monthStart) + a.currentSegment.startTimestamp = monthStart.Unix() } // Initialize a new current segment, based on the given time -// should be called with globalFragmentLock, localFragmentLock and l held. +// should be called with fragmentLock and l held. func (a *ActivityLog) newSegmentAtGivenTime(t time.Time) { timestamp := t.Unix() a.logger.Trace("starting a segment", "timestamp", timestamp) a.resetCurrentLog() - a.setCurrentSegmentTimeLocked(t) -} - -// Sets the timestamp of all the segments to the given time. -// should be called with l held. -func (a *ActivityLog) setCurrentSegmentTimeLocked(t time.Time) { - timestamp := t.Unix() - a.currentGlobalSegment.startTimestamp = timestamp - a.currentLocalSegment.startTimestamp = timestamp - // setting a.currentSegment timestamp to support upgrades a.currentSegment.startTimestamp = timestamp } // Reset all the current segment state. -// Should be called with globalFragmentLock, localFragmentLock and l held. +// Should be called with fragmentLock and l held. func (a *ActivityLog) resetCurrentLog() { - // setting a.currentSegment timestamp to support upgrades a.currentSegment.startTimestamp = 0 - - // global segment - a.currentGlobalSegment.startTimestamp = 0 - a.currentGlobalSegment.currentClients = &activity.EntityActivityLog{ + a.currentSegment.currentClients = &activity.EntityActivityLog{ Clients: make([]*activity.EntityRecord, 0), } - a.currentGlobalSegment.clientSequenceNumber = 0 - // local segment - a.currentLocalSegment.startTimestamp = 0 - a.currentLocalSegment.currentClients = &activity.EntityActivityLog{ - Clients: make([]*activity.EntityRecord, 0), + // We must still initialize the tokenCount to recieve tokenCounts from fragments + // during the month where customers upgrade to 1.9 + a.currentSegment.tokenCount = &activity.TokenCount{ + CountByNamespaceID: make(map[string]uint64), } - a.currentLocalSegment.clientSequenceNumber = 0 - a.currentGlobalFragment = nil - a.globalPartialMonthClientTracker = make(map[string]*activity.EntityRecord) + a.currentSegment.clientSequenceNumber = 0 - a.localFragment = nil - a.partialMonthLocalClientTracker = make(map[string]*activity.EntityRecord) + a.fragment = nil + a.partialMonthClientTracker = make(map[string]*activity.EntityRecord) - a.standbyLocalFragmentsReceived = make([]*activity.LogFragment, 0) - a.standbyGlobalFragmentsReceived = make([]*activity.LogFragment, 0) - a.secondaryGlobalClientFragments = make([]*activity.LogFragment, 0) + a.standbyFragmentsReceived = make([]*activity.LogFragment, 0) } func (a *ActivityLog) deleteLogWorker(ctx context.Context, startTimestamp int64, whenDone chan struct{}) { - entityPathsToDelete := make([]string, 0) - entityPathsToDelete = append(entityPathsToDelete, fmt.Sprintf("%s%v%v/", activityGlobalPathPrefix, activityEntityBasePath, startTimestamp)) - entityPathsToDelete = append(entityPathsToDelete, fmt.Sprintf("%s%v%v/", activityLocalPathPrefix, activityEntityBasePath, startTimestamp)) - entityPathsToDelete = append(entityPathsToDelete, fmt.Sprintf("%v%v/", activityTokenLocalBasePath, startTimestamp)) + entityPath := fmt.Sprintf("%v%v/", activityEntityBasePath, startTimestamp) + tokenPath := fmt.Sprintf("%v%v/", activityTokenBasePath, startTimestamp) - for _, path := range entityPathsToDelete { - segments, err := a.view.List(ctx, path) + entitySegments, err := a.view.List(ctx, entityPath) + if err != nil { + a.logger.Error("could not list entity paths", "error", err) + return + } + for _, p := range entitySegments { + err = a.view.Delete(ctx, entityPath+p) if err != nil { - a.logger.Error("could not list segment path", "error", err) - return + a.logger.Error("could not delete entity log", "error", err) } - for _, p := range segments { - err = a.view.Delete(ctx, path+p) - if err != nil { - a.logger.Error("could not delete log", "error", err) - } + } + + tokenSegments, err := a.view.List(ctx, tokenPath) + if err != nil { + a.logger.Error("could not list token paths", "error", err) + return + } + for _, p := range tokenSegments { + err = a.view.Delete(ctx, tokenPath+p) + if err != nil { + a.logger.Error("could not delete token log", "error", err) } } + // Allow whoever started this as a goroutine to wait for it to finish. close(whenDone) } @@ -1191,11 +967,6 @@ func (a *ActivityLog) refreshFromStoredLog(ctx context.Context, wg *sync.WaitGro defer a.l.Unlock() a.fragmentLock.Lock() defer a.fragmentLock.Unlock() - a.globalFragmentLock.Lock() - defer a.globalFragmentLock.Unlock() - // startNewCurrentLogLocked below calls resetCurrentLog which is protected by fragmentLock, globalFragmentLock, localFragmentLock and l - a.localFragmentLock.Lock() - defer a.localFragmentLock.Unlock() decreasingLogTimes, err := a.getMostRecentActivityLogSegment(ctx, now) if err != nil { @@ -1264,7 +1035,7 @@ func (a *ActivityLog) refreshFromStoredLog(ctx context.Context, wg *sync.WaitGro } // load entity logs from storage into memory - localLastSegment, globalLastSegment, segmentsExist, err := a.getLastEntitySegmentNumber(ctx, mostRecent) + lastSegment, segmentsExist, err := a.getLastEntitySegmentNumber(ctx, mostRecent) if err != nil { return err } @@ -1273,39 +1044,20 @@ func (a *ActivityLog) refreshFromStoredLog(ctx context.Context, wg *sync.WaitGro return nil } - err = a.loadCurrentClientSegment(ctx, mostRecent, localLastSegment, globalLastSegment) - // if both localLastSegment and globalLastSegment are 0, it will return nil here - if err != nil || (localLastSegment == 0 && globalLastSegment == 0) { + err = a.loadCurrentClientSegment(ctx, mostRecent, lastSegment) + if err != nil || lastSegment == 0 { return err } + lastSegment-- - // if last local segment that got loaded using loadCurrentClientSegment is not 0, there are more local segments to load - if localLastSegment != 0 { - localLastSegment-- + seqNums := make(chan uint64, lastSegment+1) + wg.Add(1) + go a.entityBackgroundLoader(ctx, wg, mostRecent, seqNums) - localSeqNums := make(chan uint64, localLastSegment+1) - wg.Add(1) - go a.entityBackgroundLoader(ctx, wg, mostRecent, localSeqNums, true) - - for n := int(localLastSegment); n >= 0; n-- { - localSeqNums <- uint64(n) - } - close(localSeqNums) - } - - // if last global segment that got loaded using loadCurrentClientSegment is not 0, there are more global segments to load - if globalLastSegment != 0 { - globalLastSegment-- - - globalSeqNums := make(chan uint64, globalLastSegment+1) - wg.Add(1) - go a.entityBackgroundLoader(ctx, wg, mostRecent, globalSeqNums, false) - - for n := int(globalLastSegment); n >= 0; n-- { - globalSeqNums <- uint64(n) - } - close(globalSeqNums) + for n := int(lastSegment); n >= 0; n-- { + seqNums <- uint64(n) } + close(seqNums) return nil } @@ -1341,9 +1093,6 @@ func (a *ActivityLog) SetConfig(ctx context.Context, config activityConfig) { // enabled is protected by fragmentLock a.fragmentLock.Lock() - // startNewCurrentLogLocked and resetCurrentLog is protected by fragmentLock, globalFragmentLock, localFragmentLock and l - a.localFragmentLock.Lock() - a.globalFragmentLock.Lock() originalEnabled := a.enabled switch config.Enabled { case "enable": @@ -1358,16 +1107,16 @@ func (a *ActivityLog) SetConfig(ctx context.Context, config activityConfig) { a.logger.Info("activity log enable changed", "original", originalEnabled, "current", a.enabled) } - if !a.enabled && a.currentGlobalSegment.startTimestamp != 0 && a.currentLocalSegment.startTimestamp != 0 { + if !a.enabled && a.currentSegment.startTimestamp != 0 { a.logger.Trace("deleting current segment") a.deleteDone = make(chan struct{}) // this is called from a request under stateLock, so use activeContext - go a.deleteLogWorker(a.core.activeContext, a.currentGlobalSegment.startTimestamp, a.deleteDone) + go a.deleteLogWorker(a.core.activeContext, a.currentSegment.startTimestamp, a.deleteDone) a.resetCurrentLog() } forceSave := false - if a.enabled && a.currentGlobalSegment.startTimestamp == 0 && a.currentLocalSegment.startTimestamp == 0 { + if a.enabled && a.currentSegment.startTimestamp == 0 { a.startNewCurrentLogLocked(a.clock.Now().UTC()) // Force a save so we can distinguish between // @@ -1381,13 +1130,10 @@ func (a *ActivityLog) SetConfig(ctx context.Context, config activityConfig) { forceSave = true } a.fragmentLock.Unlock() - a.localFragmentLock.Unlock() - a.globalFragmentLock.Unlock() if forceSave { // l is still held here - a.saveCurrentSegmentInternal(ctx, true, a.currentGlobalSegment, activityGlobalPathPrefix) - a.saveCurrentSegmentInternal(ctx, true, a.currentLocalSegment, activityLocalPathPrefix) + a.saveCurrentSegmentInternal(ctx, true) } a.defaultReportMonths = config.DefaultReportMonths @@ -1478,9 +1224,6 @@ func (c *Core) setupActivityLogLocked(ctx context.Context, wg *sync.WaitGroup, r } else { if !c.activityLogConfig.DisableFragmentWorker { go manager.activeFragmentWorker(ctx) - if c.IsPerfSecondary() { - go manager.secondaryFragmentWorker(ctx) - } } doRegeneration := !reload && !manager.hasRegeneratedACME(ctx) @@ -1622,107 +1365,16 @@ func (a *ActivityLog) StartOfNextMonth() time.Time { a.l.RLock() defer a.l.RUnlock() var segmentStart time.Time - if a.currentGlobalSegment.startTimestamp == 0 { + if a.currentSegment.startTimestamp == 0 { segmentStart = a.clock.Now().UTC() } else { - segmentStart = time.Unix(a.currentGlobalSegment.startTimestamp, 0).UTC() + segmentStart = time.Unix(a.currentSegment.startTimestamp, 0).UTC() } // Basing this on the segment start will mean we trigger EOM rollover when // necessary because we were down. return timeutil.StartOfNextMonth(segmentStart) } -// secondaryFragmentWorker handles scheduling global client fragments -// to send via RPC to the primary; it runs on performance secondaries -func (a *ActivityLog) secondaryFragmentWorker(ctx context.Context) { - timer := a.clock.NewTimer(time.Duration(0)) - fragmentWaiting := false - // Eat first event, so timer is stopped - <-timer.C - - endOfMonth := a.clock.NewTimer(a.StartOfNextMonth().Sub(a.clock.Now())) - if a.configOverrides.DisableTimers { - endOfMonth.Stop() - } - sendInterval := activityFragmentSendInterval - // This changes the interval to a duration that was set for testing purposes - if a.configOverrides.GlobalFragmentSendInterval.Microseconds() > 0 { - sendInterval = a.configOverrides.GlobalFragmentSendInterval - } - - sendFunc := func() { - ctx, cancel := context.WithTimeout(ctx, activityFragmentSendTimeout) - defer cancel() - err := a.sendGlobalClients(ctx) - if err != nil { - a.logger.Warn("activity log global fragment lost", "error", err) - } - } - - for { - select { - case <-a.doneCh: - // Shutting down activity log. - if fragmentWaiting && !timer.Stop() { - <-timer.C - } - if !endOfMonth.Stop() { - <-endOfMonth.C - } - return - case <-a.newGlobalClientFragmentCh: - // New fragment created, start the timer if not - // already running - if !fragmentWaiting { - fragmentWaiting = true - if !a.configOverrides.DisableTimers { - a.logger.Trace("reset global fragment timer") - timer.Reset(sendInterval) - } - } - case <-timer.C: - a.logger.Trace("sending global fragment on timer expiration") - fragmentWaiting = false - sendFunc() - case <-a.sendCh: - a.logger.Trace("sending global fragment on request") - // It might be that we get sendCh before fragmentCh - // if a fragment is created and then immediately fills - // up to its limit. So we attempt to send even if the timer's - // not running. - if fragmentWaiting { - fragmentWaiting = false - if !timer.Stop() { - <-timer.C - } - } - sendFunc() - case <-endOfMonth.C: - a.logger.Trace("sending global fragment on end of month") - // Flush the current fragment, if any - if fragmentWaiting { - fragmentWaiting = false - if !timer.Stop() { - <-timer.C - } - } - sendFunc() - - // clear active entity set - a.globalFragmentLock.Lock() - a.globalPartialMonthClientTracker = make(map[string]*activity.EntityRecord) - - a.globalFragmentLock.Unlock() - - // Set timer for next month. - // The current segment *probably* hasn't been set yet (via invalidation), - // so don't rely on it. - target := timeutil.StartOfNextMonth(a.clock.Now().UTC()) - endOfMonth.Reset(target.Sub(a.clock.Now())) - } - } -} - // perfStandbyFragmentWorker handles scheduling fragments // to send via RPC; it runs on perf standby nodes only. func (a *ActivityLog) perfStandbyFragmentWorker(ctx context.Context) { @@ -1736,12 +1388,6 @@ func (a *ActivityLog) perfStandbyFragmentWorker(ctx context.Context) { endOfMonth.Stop() } - sendInterval := activityFragmentSendInterval - // This changes the interval to a duration that was set for testing purposes - if a.configOverrides.PerfStandbyFragmentSendInterval.Microseconds() > 0 { - sendInterval = a.configOverrides.PerfStandbyFragmentSendInterval - } - sendFunc := func() { ctx, cancel := context.WithTimeout(ctx, activityFragmentSendTimeout) defer cancel() @@ -1769,7 +1415,7 @@ func (a *ActivityLog) perfStandbyFragmentWorker(ctx context.Context) { fragmentWaiting = true if !a.configOverrides.DisableTimers { a.logger.Trace("reset fragment timer") - timer.Reset(sendInterval) + timer.Reset(activityFragmentStandbyTime) } } case <-timer.C: @@ -1800,10 +1446,11 @@ func (a *ActivityLog) perfStandbyFragmentWorker(ctx context.Context) { } sendFunc() - // clear local active entity set - a.localFragmentLock.Lock() - a.partialMonthLocalClientTracker = make(map[string]*activity.EntityRecord) - a.localFragmentLock.Unlock() + // clear active entity set + a.fragmentLock.Lock() + a.partialMonthClientTracker = make(map[string]*activity.EntityRecord) + + a.fragmentLock.Unlock() // Set timer for next month. // The current segment *probably* hasn't been set yet (via invalidation), @@ -1817,13 +1464,7 @@ func (a *ActivityLog) perfStandbyFragmentWorker(ctx context.Context) { // activeFragmentWorker handles scheduling the write of the next // segment. It runs on active nodes only. func (a *ActivityLog) activeFragmentWorker(ctx context.Context) { - writeInterval := activitySegmentInterval - // This changes the interval to a duration that was set for testing purposes - if a.configOverrides.StorageWriteTestingInterval.Microseconds() > 0 { - writeInterval = a.configOverrides.StorageWriteTestingInterval - } - - ticker := a.clock.NewTicker(writeInterval) + ticker := a.clock.NewTicker(activitySegmentInterval) endOfMonth := a.clock.NewTimer(a.StartOfNextMonth().Sub(a.clock.Now())) if a.configOverrides.DisableTimers { @@ -1916,7 +1557,7 @@ func (a *ActivityLog) HandleEndOfMonth(ctx context.Context, currentTime time.Tim a.logger.Trace("starting end of month processing", "rolloverTime", currentTime) - err := a.writeIntentLog(ctx, a.currentGlobalSegment.startTimestamp, currentTime) + err := a.writeIntentLog(ctx, a.currentSegment.startTimestamp, currentTime) if err != nil { return err } @@ -1936,12 +1577,7 @@ func (a *ActivityLog) HandleEndOfMonth(ctx context.Context, currentTime time.Tim // in the previous month, and recover by calling newMonthCurrentLog // again and triggering the precomputed query. a.fragmentLock.Lock() - // calls newMonthCurrentLogLocked which is protected by fragmentLock, globalFragmentLock, localFragmentLock and l - a.localFragmentLock.Lock() - a.globalFragmentLock.Lock() a.newMonthCurrentLogLocked(currentTime) - a.globalFragmentLock.Unlock() - a.localFragmentLock.Unlock() a.fragmentLock.Unlock() // Work on precomputed queries in background @@ -1975,38 +1611,26 @@ func (a *ActivityLog) writeIntentLog(ctx context.Context, prevSegmentTimestamp i return nil } -// ResetActivityLog is used to extract the current local and global fragment(s) during +// ResetActivityLog is used to extract the current fragment(s) during // integration testing, so that it can be checked in a race-free way. -func (c *Core) ResetActivityLog() ([]*activity.LogFragment, []*activity.LogFragment) { +func (c *Core) ResetActivityLog() []*activity.LogFragment { c.stateLock.RLock() a := c.activityLog c.stateLock.RUnlock() if a == nil { - return nil, nil + return nil } - localFragments := make([]*activity.LogFragment, 0) - globalFragments := make([]*activity.LogFragment, 0) - - // local fragments - a.localFragmentLock.Lock() - localFragments = append(localFragments, a.localFragment) - a.localFragment = nil - localFragments = append(localFragments, a.standbyLocalFragmentsReceived...) - a.standbyLocalFragmentsReceived = make([]*activity.LogFragment, 0) - a.partialMonthLocalClientTracker = make(map[string]*activity.EntityRecord) - a.localFragmentLock.Unlock() + allFragments := make([]*activity.LogFragment, 1) + a.fragmentLock.Lock() + allFragments[0] = a.fragment + a.fragment = nil - // global fragments - a.globalFragmentLock.Lock() - globalFragments = append(globalFragments, a.currentGlobalFragment) - a.currentGlobalFragment = nil - globalFragments = append(globalFragments, a.standbyGlobalFragmentsReceived...) - a.globalPartialMonthClientTracker = make(map[string]*activity.EntityRecord) - a.standbyGlobalFragmentsReceived = make([]*activity.LogFragment, 0) - a.secondaryGlobalClientFragments = make([]*activity.LogFragment, 0) - a.globalFragmentLock.Unlock() - return localFragments, globalFragments + allFragments = append(allFragments, a.standbyFragmentsReceived...) + a.standbyFragmentsReceived = make([]*activity.LogFragment, 0) + a.partialMonthClientTracker = make(map[string]*activity.EntityRecord) + a.fragmentLock.Unlock() + return allFragments } func (a *ActivityLog) AddEntityToFragment(entityID string, namespaceID string, timestamp int64) { @@ -2043,16 +1667,11 @@ func (a *ActivityLog) AddActivityToFragment(clientID string, namespaceID string, a.fragmentLock.RLock() if a.enabled { - _, presentInRegularClientMap := a.globalPartialMonthClientTracker[clientID] - _, presentInLocalClientmap := a.partialMonthLocalClientTracker[clientID] - if presentInRegularClientMap || presentInLocalClientmap { - present = true - } + _, present = a.partialMonthClientTracker[clientID] } else { present = true } a.fragmentLock.RUnlock() - if present { return } @@ -2061,23 +1680,12 @@ func (a *ActivityLog) AddActivityToFragment(clientID string, namespaceID string, a.fragmentLock.Lock() defer a.fragmentLock.Unlock() - a.localFragmentLock.Lock() - defer a.localFragmentLock.Unlock() - - a.globalFragmentLock.Lock() - defer a.globalFragmentLock.Unlock() - // Re-check entity ID after re-acquiring lock - _, presentInRegularClientMap := a.globalPartialMonthClientTracker[clientID] - _, presentInLocalClientmap := a.partialMonthLocalClientTracker[clientID] - if presentInRegularClientMap || presentInLocalClientmap { - present = true - } + _, present = a.partialMonthClientTracker[clientID] if present { return } - // create fragments if doesn't already exist a.createCurrentFragment() clientRecord := &activity.EntityRecord{ @@ -2096,63 +1704,20 @@ func (a *ActivityLog) AddActivityToFragment(clientID string, namespaceID string, clientRecord.NonEntity = true } - if local, _ := a.isClientLocal(clientRecord); local { - // If the client is local then add the client to the current local fragment - a.localFragment.Clients = append(a.localFragment.Clients, clientRecord) - a.partialMonthLocalClientTracker[clientRecord.ClientID] = clientRecord - } else { - if _, ok := a.globalPartialMonthClientTracker[clientRecord.ClientID]; !ok { - // If the client is not local and has not already been seen, then add the client - // to the current global fragment - a.currentGlobalFragment.Clients = append(a.currentGlobalFragment.Clients, clientRecord) - a.globalPartialMonthClientTracker[clientRecord.ClientID] = clientRecord - } - } -} - -// isClientLocal checks whether the given client is on a local mount. -// In all other cases, we will assume it is a global client. -func (a *ActivityLog) isClientLocal(client *activity.EntityRecord) (bool, error) { - if !utf8.ValidString(client.ClientID) { - return false, fmt.Errorf("client ID %q is not a valid string", client.ClientID) - } - // Tokens are not replicated to performance secondary clusters - if client.GetClientType() == nonEntityTokenActivityType { - return true, nil - } - mountEntry := a.core.router.MatchingMountByAccessor(client.MountAccessor) - // If the mount entry is nil, this means the mount has been deleted. We will assume it was replicated because we do not want to - // over count clients - if mountEntry != nil && mountEntry.Local { - return true, nil - } - - return false, nil + a.fragment.Clients = append(a.fragment.Clients, clientRecord) + a.partialMonthClientTracker[clientRecord.ClientID] = clientRecord } -// Create the fragments (local fragment and global fragment) if it doesn't already exist. -// Must be called with the fragmentLock, localFragmentLock and globalFragmentLock held. +// Create the current fragment if it doesn't already exist. +// Must be called with the lock held. func (a *ActivityLog) createCurrentFragment() { - if a.currentGlobalFragment == nil { - // create local fragment - a.localFragment = &activity.LogFragment{ + if a.fragment == nil { + a.fragment = &activity.LogFragment{ OriginatingNode: a.nodeID, Clients: make([]*activity.EntityRecord, 0, 120), NonEntityTokens: make(map[string]uint64), } - - // create global fragment - a.currentGlobalFragment = &activity.LogFragment{ - OriginatingNode: a.nodeID, - OriginatingCluster: a.core.ClusterID(), - Clients: make([]*activity.EntityRecord, 0), - } - - if a.core.IsPerfSecondary() { - // Signal that a new global segment is available, start - // the timer to send it - a.newGlobalClientFragmentCh <- struct{}{} - } + a.fragmentCreation = a.clock.Now().UTC() // Signal that a new segment is available, start // the timer to send it. @@ -2160,78 +1725,25 @@ func (a *ActivityLog) createCurrentFragment() { } } -func (a *ActivityLog) receivedGlobalClientFragments(fragment *activity.LogFragment) { - a.logger.Trace("received fragment from secondary", "cluster_id", fragment.GetOriginatingCluster()) - - a.globalFragmentLock.Lock() - defer a.globalFragmentLock.Unlock() - - if !a.enabled { - return - } - - for _, e := range fragment.Clients { - a.globalPartialMonthClientTracker[e.ClientID] = e - } - - a.secondaryGlobalClientFragments = append(a.secondaryGlobalClientFragments, fragment) -} - func (a *ActivityLog) receivedFragment(fragment *activity.LogFragment) { a.logger.Trace("received fragment from standby", "node", fragment.OriginatingNode) - isLocalFragment := false - if !a.enabled { - return - } - a.fragmentLock.Lock() defer a.fragmentLock.Unlock() - // Check if the received fragment from standby is a local fragment. - // A fragment can have all local clients or all non-local clients except for regular fragment (which has both currently but will be modified to only hold non-local clients later). - // Check the first client to identify the type of fragment. - if len(fragment.Clients) > 0 { - client := fragment.Clients[0] - if local, _ := a.isClientLocal(client); local { - isLocalFragment = true - - a.localFragmentLock.Lock() - defer a.localFragmentLock.Unlock() - } else { - a.globalFragmentLock.Lock() - defer a.globalFragmentLock.Unlock() - } + if !a.enabled { + return } for _, e := range fragment.Clients { - if isLocalFragment { - a.partialMonthLocalClientTracker[e.ClientID] = e - } else { - a.globalPartialMonthClientTracker[e.ClientID] = e - } + a.partialMonthClientTracker[e.ClientID] = e } - if isLocalFragment { - a.standbyLocalFragmentsReceived = append(a.standbyLocalFragmentsReceived, fragment) - } else { - a.standbyGlobalFragmentsReceived = append(a.standbyGlobalFragmentsReceived, fragment) - } + a.standbyFragmentsReceived = append(a.standbyFragmentsReceived, fragment) // TODO: check if current segment is full and should be written } -// returns the active local and global clients for the current month -func (a *ActivityLog) GetAllPartialMonthClients() (map[string]*activity.EntityRecord, map[string]*activity.EntityRecord) { - a.localFragmentLock.Lock() - defer a.localFragmentLock.Unlock() - - a.globalFragmentLock.Lock() - defer a.globalFragmentLock.Unlock() - - return a.partialMonthLocalClientTracker, a.globalPartialMonthClientTracker -} - type ResponseCounts struct { EntityClients int `json:"entity_clients" mapstructure:"entity_clients"` NonEntityClients int `json:"non_entity_clients" mapstructure:"non_entity_clients"` @@ -2875,23 +2387,7 @@ func (a *ActivityLog) segmentToPrecomputedQuery(ctx context.Context, segmentTime // Iterate through entities, adding them to the hyperloglog and the summary maps in opts for { - entity, err := reader.ReadGlobalEntity(ctx) - if errors.Is(err, io.EOF) { - break - } - if err != nil { - a.logger.Warn("failed to read segment", "error", err) - return err - } - err = a.handleEntitySegment(entity, segmentTime, hyperloglog, opts) - if err != nil { - a.logger.Warn("failed to handle entity segment", "error", err) - return err - } - } - - for { - entity, err := reader.ReadLocalEntity(ctx) + entity, err := reader.ReadEntity(ctx) if errors.Is(err, io.EOF) { break } @@ -2904,7 +2400,6 @@ func (a *ActivityLog) segmentToPrecomputedQuery(ctx context.Context, segmentTime a.logger.Warn("failed to handle entity segment", "error", err) return err } - } // Store the hyperloglog @@ -3059,7 +2554,7 @@ func (a *ActivityLog) precomputedQueryWorker(ctx context.Context, intent *Activi // too old, and startTimestamp should only go forward (unless it is zero.) // If there's an intent log, finish it even if the feature is currently disabled. a.l.RLock() - currentMonth := a.currentGlobalSegment.startTimestamp + currentMonth := a.currentSegment.startTimestamp // Base retention period on the month we are generating (even in the past)--- a.clock.Now() // would work but this will be easier to control in tests. retentionWindow := timeutil.MonthsPreviousTo(a.retentionMonths, time.Unix(intent.NextMonth, 0).UTC()) @@ -3190,7 +2685,6 @@ func (a *ActivityLog) retentionWorker(ctx context.Context, currentTime time.Time // Periodic report of number of active entities, with the current month. // We don't break this down by namespace because that would require going to storage (that information // is not currently stored in memory.) -// TODO: to deprecate. These metrics are not useful anymore func (a *ActivityLog) PartialMonthMetrics(ctx context.Context) ([]metricsutil.GaugeLabelValues, error) { a.fragmentLock.RLock() defer a.fragmentLock.RUnlock() @@ -3198,7 +2692,7 @@ func (a *ActivityLog) PartialMonthMetrics(ctx context.Context) ([]metricsutil.Ga // Empty list return []metricsutil.GaugeLabelValues{}, nil } - count := len(a.globalPartialMonthClientTracker) + len(a.partialMonthLocalClientTracker) + count := len(a.partialMonthClientTracker) return []metricsutil.GaugeLabelValues{ { @@ -3224,10 +2718,7 @@ func (a *ActivityLog) populateNamespaceAndMonthlyBreakdowns() (map[int64]*proces // Parse the monthly clients and prepare the breakdowns. byNamespace := make(map[string]*processByNamespace) byMonth := make(map[int64]*processMonth) - for _, e := range a.globalPartialMonthClientTracker { - processClientRecord(e, byNamespace, byMonth, a.clock.Now()) - } - for _, e := range a.partialMonthLocalClientTracker { + for _, e := range a.partialMonthClientTracker { processClientRecord(e, byNamespace, byMonth, a.clock.Now()) } return byMonth, byNamespace diff --git a/vault/activity_log_stubs_oss.go b/vault/activity_log_stubs_oss.go deleted file mode 100644 index 7d2457360563..000000000000 --- a/vault/activity_log_stubs_oss.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -//go:build !enterprise - -package vault - -import "context" - -//go:generate go run github.com/hashicorp/vault/tools/stubmaker - -// sendGlobalClients is a no-op on CE -func (a *ActivityLog) sendGlobalClients(ctx context.Context) error { - return nil -} diff --git a/vault/activity_log_test.go b/vault/activity_log_test.go index 1f36a7856582..81a691dadbed 100644 --- a/vault/activity_log_test.go +++ b/vault/activity_log_test.go @@ -9,7 +9,6 @@ import ( "encoding/json" "errors" "fmt" - "io" "net/http" "reflect" "sort" @@ -24,7 +23,6 @@ import ( "github.com/go-test/deep" "github.com/golang/protobuf/proto" "github.com/hashicorp/go-uuid" - "github.com/hashicorp/vault/builtin/credential/userpass" "github.com/hashicorp/vault/helper/constants" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/helper/timeutil" @@ -34,18 +32,9 @@ import ( "github.com/stretchr/testify/require" ) -// TestActivityLog_Creation calls AddEntityToFragment and verifies that it appears correctly in a.currentGlobalFragment. +// TestActivityLog_Creation calls AddEntityToFragment and verifies that it appears correctly in a.fragment. func TestActivityLog_Creation(t *testing.T) { - storage := &logical.InmemStorage{} - coreConfig := &CoreConfig{ - CredentialBackends: map[string]logical.Factory{ - "userpass": userpass.Factory, - }, - Physical: storage.Underlying(), - } - - cluster := NewTestCluster(t, coreConfig, nil) - core := cluster.Cores[0].Core + core, _, _ := TestCoreUnsealed(t) a := core.activityLog a.SetEnable(true) @@ -56,14 +45,8 @@ func TestActivityLog_Creation(t *testing.T) { if a.logger == nil || a.view == nil { t.Fatal("activity log not initialized") } - currentGlobalFragment := core.GetActiveGlobalFragment() - if currentGlobalFragment != nil { - t.Fatal("activity log already has global fragment") - } - - localFragment := core.GetActiveLocalFragment() - if localFragment != nil { - t.Fatal("activity log already has a local fragment") + if a.fragment != nil { + t.Fatal("activity log already has fragment") } const entity_id = "entity_id_75432" @@ -71,29 +54,27 @@ func TestActivityLog_Creation(t *testing.T) { ts := time.Now() a.AddEntityToFragment(entity_id, namespace_id, ts.Unix()) - currentGlobalFragment = core.GetActiveGlobalFragment() - localFragment = core.GetActiveLocalFragment() - - if currentGlobalFragment == nil { + if a.fragment == nil { t.Fatal("no fragment created") } - if a.currentGlobalFragment.OriginatingNode != a.nodeID { - t.Errorf("mismatched node ID, %q vs %q", currentGlobalFragment.OriginatingNode, a.nodeID) - } - if currentGlobalFragment.OriginatingCluster != a.core.ClusterID() { - t.Errorf("mismatched cluster ID, %q vs %q", currentGlobalFragment.GetOriginatingCluster(), a.core.ClusterID()) + if a.fragment.OriginatingNode != a.nodeID { + t.Errorf("mismatched node ID, %q vs %q", a.fragment.OriginatingNode, a.nodeID) } - if currentGlobalFragment.Clients == nil { + if a.fragment.Clients == nil { t.Fatal("no fragment entity slice") } - if len(currentGlobalFragment.Clients) != 1 { - t.Fatalf("wrong number of entities %v", len(currentGlobalFragment.Clients)) + if a.fragment.NonEntityTokens == nil { + t.Fatal("no fragment token map") + } + + if len(a.fragment.Clients) != 1 { + t.Fatalf("wrong number of entities %v", len(a.fragment.Clients)) } - er := currentGlobalFragment.Clients[0] + er := a.fragment.Clients[0] if er.ClientID != entity_id { t.Errorf("mimatched entity ID, %q vs %q", er.ClientID, entity_id) } @@ -105,56 +86,20 @@ func TestActivityLog_Creation(t *testing.T) { } // Reset and test the other code path + a.fragment = nil a.AddTokenToFragment(namespace_id) - currentGlobalFragment = core.GetActiveGlobalFragment() - localFragment = core.GetActiveLocalFragment() - if currentGlobalFragment == nil { + if a.fragment == nil { t.Fatal("no fragment created") } - // test local fragment - localMe := &MountEntry{ - Table: credentialTableType, - Path: "userpass-local/", - Type: "userpass", - Local: true, - Accessor: "local_mount_accessor", - } - err := core.enableCredential(namespace.RootContext(nil), localMe) - require.NoError(t, err) - - const local_entity_id = "entity_id_75434" - local_ts := time.Now() - - a.AddClientToFragment(local_entity_id, "root", local_ts.Unix(), false, "local_mount_accessor") - localFragment = core.GetActiveLocalFragment() - - if localFragment.OriginatingNode != a.nodeID { - t.Errorf("mismatched node ID, %q vs %q", localFragment.OriginatingNode, a.nodeID) - } - - if localFragment.Clients == nil { - t.Fatal("no local fragment entity slice") - } - - if localFragment.NonEntityTokens == nil { - t.Fatal("no local fragment token map") + if a.fragment.NonEntityTokens == nil { + t.Fatal("no fragment token map") } - if len(localFragment.Clients) != 1 { - t.Fatalf("wrong number of entities %v", len(localFragment.Clients)) - } - - er = localFragment.Clients[0] - if er.ClientID != local_entity_id { - t.Errorf("mimatched entity ID, %q vs %q", er.ClientID, local_entity_id) - } - if er.NamespaceID != "root" { - t.Errorf("mimatched namespace ID, %q vs %q", er.NamespaceID, "root") - } - if er.Timestamp != ts.Unix() { - t.Errorf("mimatched timestamp, %v vs %v", er.Timestamp, ts.Unix()) + actual := a.fragment.NonEntityTokens[namespace_id] + if actual != 1 { + t.Errorf("mismatched number of tokens, %v vs %v", actual, 1) } } @@ -172,14 +117,11 @@ func TestActivityLog_Creation_WrappingTokens(t *testing.T) { if a.logger == nil || a.view == nil { t.Fatal("activity log not initialized") } - if core.GetActiveGlobalFragment() != nil { + a.fragmentLock.Lock() + if a.fragment != nil { t.Fatal("activity log already has fragment") } - - if core.GetActiveLocalFragment() != nil { - t.Fatal("activity log already has local fragment") - } - + a.fragmentLock.Unlock() const namespace_id = "ns123" te := &logical.TokenEntry{ @@ -196,9 +138,11 @@ func TestActivityLog_Creation_WrappingTokens(t *testing.T) { t.Fatal(err) } - if core.GetActiveGlobalFragment() != nil { + a.fragmentLock.Lock() + if a.fragment != nil { t.Fatal("fragment created") } + a.fragmentLock.Unlock() teNew := &logical.TokenEntry{ Path: "test", @@ -214,9 +158,11 @@ func TestActivityLog_Creation_WrappingTokens(t *testing.T) { t.Fatal(err) } - if core.GetActiveGlobalFragment() != nil { + a.fragmentLock.Lock() + if a.fragment != nil { t.Fatal("fragment created") } + a.fragmentLock.Unlock() } func checkExpectedEntitiesInMap(t *testing.T, a *ActivityLog, entityIDs []string) { @@ -252,15 +198,15 @@ func TestActivityLog_UniqueEntities(t *testing.T) { a.AddEntityToFragment(id2, "root", t3.Unix()) a.AddEntityToFragment(id1, "root", t3.Unix()) - currentGlobalFragment := core.GetActiveGlobalFragment() - if currentGlobalFragment == nil { - t.Fatal("no current global fragment") + if a.fragment == nil { + t.Fatal("no current fragment") } - if len(currentGlobalFragment.Clients) != 2 { - t.Fatalf("number of entities is %v", len(currentGlobalFragment.Clients)) + + if len(a.fragment.Clients) != 2 { + t.Fatalf("number of entities is %v", len(a.fragment.Clients)) } - for i, e := range currentGlobalFragment.Clients { + for i, e := range a.fragment.Clients { expectedID := id1 expectedTime := t1.Unix() expectedNS := "root" @@ -351,7 +297,7 @@ func TestActivityLog_SaveTokensToStorage(t *testing.T) { a.SetStartTimestamp(time.Now().Unix()) // set a nonzero segment nsIDs := [...]string{"ns1_id", "ns2_id", "ns3_id"} - path := fmt.Sprintf("%sdirecttokens/%d/0", ActivityLogLocalPrefix, a.GetStartTimestamp()) + path := fmt.Sprintf("%sdirecttokens/%d/0", ActivityLogPrefix, a.GetStartTimestamp()) for i := 0; i < 3; i++ { a.AddTokenToFragment(nsIDs[0]) @@ -361,14 +307,10 @@ func TestActivityLog_SaveTokensToStorage(t *testing.T) { if err != nil { t.Fatalf("got error writing tokens to storage: %v", err) } - if core.GetActiveGlobalFragment() != nil { + if a.fragment != nil { t.Errorf("fragment was not reset after write to storage") } - if core.GetActiveLocalFragment() != nil { - t.Errorf("local fragment was not reset after write to storage") - } - out := &activity.TokenCount{} protoSegment := readSegmentFromStorage(t, core, path) err = proto.Unmarshal(protoSegment.Value, out) @@ -397,15 +339,10 @@ func TestActivityLog_SaveTokensToStorage(t *testing.T) { if err != nil { t.Fatalf("got error writing tokens to storage: %v", err) } - - if core.GetActiveGlobalFragment() != nil { + if a.fragment != nil { t.Errorf("fragment was not reset after write to storage") } - if core.GetActiveLocalFragment() != nil { - t.Errorf("local fragment was not reset after write to storage") - } - protoSegment = readSegmentFromStorage(t, core, path) out = &activity.TokenCount{} err = proto.Unmarshal(protoSegment.Value, out) @@ -443,9 +380,8 @@ func TestActivityLog_SaveTokensToStorageDoesNotUpdateTokenCount(t *testing.T) { a.SetStandbyEnable(ctx, true) a.SetStartTimestamp(time.Now().Unix()) // set a nonzero segment - tokenPath := fmt.Sprintf("%sdirecttokens/%d/0", ActivityLogLocalPrefix, a.GetStartTimestamp()) - clientPath := fmt.Sprintf("sys/counters/activity/global/log/entity/%d/0", a.GetStartTimestamp()) - localPath := fmt.Sprintf("sys/counters/activity/local/log/entity/%d/0", a.GetStartTimestamp()) + tokenPath := fmt.Sprintf("%sdirecttokens/%d/0", ActivityLogPrefix, a.GetStartTimestamp()) + clientPath := fmt.Sprintf("sys/counters/activity/log/entity/%d/0", a.GetStartTimestamp()) // Create some entries without entityIDs tokenEntryOne := logical.TokenEntry{NamespaceID: namespace.RootNamespaceID, Policies: []string{"hi"}} entityEntry := logical.TokenEntry{EntityID: "foo", NamespaceID: namespace.RootNamespaceID, Policies: []string{"hi"}} @@ -459,9 +395,6 @@ func TestActivityLog_SaveTokensToStorageDoesNotUpdateTokenCount(t *testing.T) { } } - // verify that the client got added to a local fragment - require.Len(t, core.GetActiveLocalFragment().Clients, 1) - idEntity, isTWE := entityEntry.CreateClientID() for i := 0; i < 2; i++ { err := a.HandleTokenUsage(ctx, &entityEntry, idEntity, isTWE) @@ -469,53 +402,31 @@ func TestActivityLog_SaveTokensToStorageDoesNotUpdateTokenCount(t *testing.T) { t.Fatal(err) } } - - // verify that the client got added to the global fragment - require.Len(t, core.GetActiveGlobalFragment().Clients, 1) - err := a.saveCurrentSegmentToStorage(ctx, false) if err != nil { t.Fatalf("got error writing TWEs to storage: %v", err) } // Assert that new elements have been written to the fragment - if core.GetActiveGlobalFragment() != nil { + if a.fragment != nil { t.Errorf("fragment was not reset after write to storage") } - if core.GetActiveLocalFragment() != nil { - t.Errorf("local fragment was not reset after write to storage") - } - // Assert that no tokens have been written to the fragment readSegmentFromStorageNil(t, core, tokenPath) - allClients := make([]*activity.EntityRecord, 0) e := readSegmentFromStorage(t, core, clientPath) out := &activity.EntityActivityLog{} err = proto.Unmarshal(e.Value, out) if err != nil { t.Fatalf("could not unmarshal protobuf: %v", err) } - if len(out.Clients) != 1 { - t.Fatalf("added 2 distinct entity tokens that should all result in the same ID, got: %d", len(out.Clients)) - } - allClients = append(allClients, out.Clients...) - - e = readSegmentFromStorage(t, core, localPath) - out = &activity.EntityActivityLog{} - err = proto.Unmarshal(e.Value, out) - if err != nil { - t.Fatalf("could not unmarshal protobuf: %v", err) - } - if len(out.Clients) != 1 { - t.Fatalf("added 3 distinct TWEs that should all result in the same ID, got: %d", len(out.Clients)) + if len(out.Clients) != 2 { + t.Fatalf("added 3 distinct TWEs and 2 distinct entity tokens that should all result in the same ID, got: %d", len(out.Clients)) } - allClients = append(allClients, out.Clients...) - nonEntityTokenFlag := false entityTokenFlag := false - for _, client := range allClients { + for _, client := range out.Clients { if client.NonEntity == true { nonEntityTokenFlag = true if client.ClientID != idNonEntity { @@ -552,7 +463,7 @@ func TestActivityLog_SaveEntitiesToStorage(t *testing.T) { now.Add(1 * time.Second).Unix(), now.Add(2 * time.Second).Unix(), } - globalPath := fmt.Sprintf("%sentity/%d/0", ActivityGlobalLogPrefix, a.GetStartTimestamp()) + path := fmt.Sprintf("%sentity/%d/0", ActivityLogPrefix, a.GetStartTimestamp()) a.AddEntityToFragment(ids[0], "root", times[0]) a.AddEntityToFragment(ids[1], "root2", times[1]) @@ -560,14 +471,11 @@ func TestActivityLog_SaveEntitiesToStorage(t *testing.T) { if err != nil { t.Fatalf("got error writing entities to storage: %v", err) } - if core.GetActiveGlobalFragment() != nil { + if a.fragment != nil { t.Errorf("fragment was not reset after write to storage") } - if core.GetActiveLocalFragment() != nil { - t.Errorf("local fragment was not reset after write to storage") - } - protoSegment := readSegmentFromStorage(t, core, globalPath) + protoSegment := readSegmentFromStorage(t, core, path) out := &activity.EntityActivityLog{} err = proto.Unmarshal(protoSegment.Value, out) if err != nil { @@ -582,7 +490,7 @@ func TestActivityLog_SaveEntitiesToStorage(t *testing.T) { t.Fatalf("got error writing segments to storage: %v", err) } - protoSegment = readSegmentFromStorage(t, core, globalPath) + protoSegment = readSegmentFromStorage(t, core, path) out = &activity.EntityActivityLog{} err = proto.Unmarshal(protoSegment.Value, out) if err != nil { @@ -591,91 +499,6 @@ func TestActivityLog_SaveEntitiesToStorage(t *testing.T) { expectedEntityIDs(t, out, ids) } -// TestActivityLog_SaveEntitiesToStorageCommon calls AddClientToFragment with clients with local and non-local mount accessors and then -// writes the segment to storage. Read back from storage, and verify that client IDs exist in storage in the right local and non-local entity paths. -func TestActivityLog_SaveEntitiesToStorageCommon(t *testing.T) { - t.Parallel() - - storage := &logical.InmemStorage{} - coreConfig := &CoreConfig{ - CredentialBackends: map[string]logical.Factory{ - "userpass": userpass.Factory, - }, - Physical: storage.Underlying(), - } - - cluster := NewTestCluster(t, coreConfig, nil) - core := cluster.Cores[0].Core - TestWaitActive(t, core) - - ctx := namespace.RootContext(nil) - - a := core.activityLog - a.SetEnable(true) - a.SetStartTimestamp(time.Now().Unix()) // set a nonzero segment - - var err error - - // create a local and non-local mount entry - nonLocalMountEntry := &MountEntry{ - Table: credentialTableType, - Path: "nonLocalUserpass/", - Type: "userpass", - Accessor: "nonLocalMountAccessor", - } - err = core.enableCredential(ctx, nonLocalMountEntry) - require.NoError(t, err) - - localMountEntry := &MountEntry{ - Table: credentialTableType, - Path: "localUserpass/", - Local: true, - Type: "userpass", - Accessor: "localMountAccessor", - } - err = core.enableCredential(ctx, localMountEntry) - require.NoError(t, err) - - now := time.Now() - ids := []string{"non-local-client-id-1", "non-local-client-id-2", "local-client-id-1"} - - globalPath := fmt.Sprintf("%sentity/%d/0", ActivityGlobalLogPrefix, a.GetStartTimestamp()) - localPath := fmt.Sprintf("%sentity/%d/0", ActivityLogLocalPrefix, a.GetStartTimestamp()) - - // add clients with local and non-local mount accessors - a.AddClientToFragment(ids[0], "root", now.Unix(), false, "nonLocalMountAccessor") - a.AddClientToFragment(ids[1], "root", now.Unix(), false, "nonLocalMountAccessor") - a.AddClientToFragment(ids[2], "root", now.Unix(), false, "localMountAccessor") - - err = a.saveCurrentSegmentToStorage(ctx, false) - if err != nil { - t.Fatalf("got error writing entities to storage: %v", err) - } - if core.GetActiveGlobalFragment() != nil || core.GetActiveLocalFragment() != nil { - t.Errorf("fragment was not reset after write to storage") - } - - // read entity ids from non-local entity storage path - protoSegment := readSegmentFromStorage(t, core, globalPath) - out := &activity.EntityActivityLog{} - err = proto.Unmarshal(protoSegment.Value, out) - if err != nil { - t.Fatalf("could not unmarshal protobuf: %v", err) - } - expectedEntityIDs(t, out, ids[:2]) - - // read entity ids from local entity storage path - protoSegment = readSegmentFromStorage(t, core, localPath) - out = &activity.EntityActivityLog{} - err = proto.Unmarshal(protoSegment.Value, out) - if err != nil { - t.Fatalf("could not unmarshal protobuf: %v", err) - } - - // local entity is local-client-id-1 in ids with index 2 - expectedEntityIDs(t, out, ids[2:]) -} - // TestActivityLog_StoreAndReadHyperloglog inserts into a hyperloglog, stores it and then reads it back. The test // verifies the estimate count is correct. func TestActivityLog_StoreAndReadHyperloglog(t *testing.T) { @@ -740,8 +563,8 @@ func TestModifyResponseMonthsNilAppend(t *testing.T) { } // TestActivityLog_ReceivedFragment calls receivedFragment with a fragment and verifies it gets added to -// standbyGlobalFragmentsReceived. Send the same fragment again and then verify that it doesn't change the entity map but does -// get added to standbyGlobalFragmentsReceived. +// standbyFragmentsReceived. Send the same fragment again and then verify that it doesn't change the entity map but does +// get added to standbyFragmentsReceived. func TestActivityLog_ReceivedFragment(t *testing.T) { core, _, _ := TestCoreUnsealed(t) a := core.activityLog @@ -771,7 +594,7 @@ func TestActivityLog_ReceivedFragment(t *testing.T) { NonEntityTokens: make(map[string]uint64), } - if len(a.standbyGlobalFragmentsReceived) != 0 { + if len(a.standbyFragmentsReceived) != 0 { t.Fatalf("fragment already received") } @@ -779,8 +602,8 @@ func TestActivityLog_ReceivedFragment(t *testing.T) { checkExpectedEntitiesInMap(t, a, ids) - if len(a.standbyGlobalFragmentsReceived) != 1 { - t.Fatalf("fragment count is %v, expected 1", len(a.standbyGlobalFragmentsReceived)) + if len(a.standbyFragmentsReceived) != 1 { + t.Fatalf("fragment count is %v, expected 1", len(a.standbyFragmentsReceived)) } // Send a duplicate, should be stored but not change entity map @@ -788,8 +611,8 @@ func TestActivityLog_ReceivedFragment(t *testing.T) { checkExpectedEntitiesInMap(t, a, ids) - if len(a.standbyGlobalFragmentsReceived) != 2 { - t.Fatalf("fragment count is %v, expected 2", len(a.standbyGlobalFragmentsReceived)) + if len(a.standbyFragmentsReceived) != 2 { + t.Fatalf("fragment count is %v, expected 2", len(a.standbyFragmentsReceived)) } } @@ -814,21 +637,11 @@ func TestActivityLog_availableLogs(t *testing.T) { // set up a few files in storage core, _, _ := TestCoreUnsealed(t) a := core.activityLog - globalPaths := [...]string{"entity/1111/1", "entity/992/3", "entity/991/1"} - localPaths := [...]string{"entity/1111/1", "entity/992/3", "entity/990/1"} - tokenPaths := [...]string{"directtokens/1111/1", "directtokens/1000000/1", "directtokens/992/1"} - expectedTimes := [...]time.Time{time.Unix(1000000, 0), time.Unix(1111, 0), time.Unix(992, 0), time.Unix(991, 0), time.Unix(990, 0)} - - for _, path := range globalPaths { - WriteToStorage(t, core, ActivityGlobalLogPrefix+path, []byte("test")) - } + paths := [...]string{"entity/1111/1", "directtokens/1111/1", "directtokens/1000000/1", "entity/992/3", "directtokens/992/1"} + expectedTimes := [...]time.Time{time.Unix(1000000, 0), time.Unix(1111, 0), time.Unix(992, 0)} - for _, path := range localPaths { - WriteToStorage(t, core, ActivityLogLocalPrefix+path, []byte("test")) - } - - for _, path := range tokenPaths { - WriteToStorage(t, core, ActivityLogLocalPrefix+path, []byte("test")) + for _, path := range paths { + WriteToStorage(t, core, ActivityLogPrefix+path, []byte("test")) } // verify above files are there, and dates in correct order @@ -913,7 +726,7 @@ func TestActivityLog_createRegenerationIntentLog(t *testing.T) { } for _, subPath := range paths { - fullPath := ActivityGlobalLogPrefix + subPath + fullPath := ActivityLogPrefix + subPath WriteToStorage(t, core, fullPath, []byte("test")) deletePaths = append(deletePaths, fullPath) } @@ -962,10 +775,10 @@ func TestActivityLog_MultipleFragmentsAndSegments(t *testing.T) { a.SetStartTimestamp(time.Now().Unix()) // set a nonzero segment startTimestamp := a.GetStartTimestamp() - path0 := fmt.Sprintf("sys/counters/activity/global/log/entity/%d/0", startTimestamp) - path1 := fmt.Sprintf("sys/counters/activity/global/log/entity/%d/1", startTimestamp) - path2 := fmt.Sprintf("sys/counters/activity/global/log/entity/%d/2", startTimestamp) - tokenPath := fmt.Sprintf("sys/counters/activity/local/log/directtokens/%d/0", startTimestamp) + path0 := fmt.Sprintf("sys/counters/activity/log/entity/%d/0", startTimestamp) + path1 := fmt.Sprintf("sys/counters/activity/log/entity/%d/1", startTimestamp) + path2 := fmt.Sprintf("sys/counters/activity/log/entity/%d/2", startTimestamp) + tokenPath := fmt.Sprintf("sys/counters/activity/log/directtokens/%d/0", startTimestamp) genID := func(i int) string { return fmt.Sprintf("11111111-1111-1111-1111-%012d", i) @@ -1057,6 +870,11 @@ func TestActivityLog_MultipleFragmentsAndSegments(t *testing.T) { t.Fatalf("got error writing entities to storage: %v", err) } + seqNum := a.GetEntitySequenceNumber() + if seqNum != 2 { + t.Fatalf("expected sequence number 2, got %v", seqNum) + } + protoSegment0 = readSegmentFromStorage(t, core, path0) err = proto.Unmarshal(protoSegment0.Value, &entityLog0) if err != nil { @@ -1263,67 +1081,54 @@ func TestActivityLog_parseSegmentNumberFromPath(t *testing.T) { func TestActivityLog_getLastEntitySegmentNumber(t *testing.T) { core, _, _ := TestCoreUnsealed(t) a := core.activityLog - globalPaths := [...]string{"entity/992/0", "entity/1000/-1", "entity/1001/foo", "entity/1111/1"} - localPaths := [...]string{"entity/992/0", "entity/1000/-1", "entity/1001/foo", "entity/1111/0", "entity/1111/1"} - for _, path := range globalPaths { - WriteToStorage(t, core, ActivityGlobalLogPrefix+path, []byte("test")) - } - for _, path := range localPaths { - WriteToStorage(t, core, ActivityLogLocalPrefix+path, []byte("test")) + paths := [...]string{"entity/992/0", "entity/1000/-1", "entity/1001/foo", "entity/1111/0", "entity/1111/1"} + for _, path := range paths { + WriteToStorage(t, core, ActivityLogPrefix+path, []byte("test")) } testCases := []struct { - input int64 - expectedGlobalVal uint64 - expectedLocalVal uint64 - expectExists bool + input int64 + expectedVal uint64 + expectExists bool }{ { - input: 992, - expectedGlobalVal: 0, - expectedLocalVal: 0, - expectExists: true, + input: 992, + expectedVal: 0, + expectExists: true, }, { - input: 1000, - expectedGlobalVal: 0, - expectedLocalVal: 0, - expectExists: false, + input: 1000, + expectedVal: 0, + expectExists: false, }, { - input: 1001, - expectedGlobalVal: 0, - expectedLocalVal: 0, - expectExists: false, + input: 1001, + expectedVal: 0, + expectExists: false, }, { - input: 1111, - expectedGlobalVal: 1, - expectedLocalVal: 1, - expectExists: true, + input: 1111, + expectedVal: 1, + expectExists: true, }, { - input: 2222, - expectedGlobalVal: 0, - expectedLocalVal: 0, - expectExists: false, + input: 2222, + expectedVal: 0, + expectExists: false, }, } ctx := context.Background() for _, tc := range testCases { - localSegmentNumber, globalSegmentNumber, exists, err := a.getLastEntitySegmentNumber(ctx, time.Unix(tc.input, 0)) + result, exists, err := a.getLastEntitySegmentNumber(ctx, time.Unix(tc.input, 0)) if err != nil { t.Fatalf("unexpected error for input %d: %v", tc.input, err) } if exists != tc.expectExists { t.Errorf("expected result exists: %t, got: %t for input: %d", tc.expectExists, exists, tc.input) } - if globalSegmentNumber != tc.expectedGlobalVal { - t.Errorf("expected: %d got: %d for input: %d", tc.expectedGlobalVal, globalSegmentNumber, tc.input) - } - if localSegmentNumber != tc.expectedLocalVal { - t.Errorf("expected: %d got: %d for input: %d", tc.expectedLocalVal, localSegmentNumber, tc.input) + if result != tc.expectedVal { + t.Errorf("expected: %d got: %d for input: %d", tc.expectedVal, result, tc.input) } } } @@ -1335,7 +1140,7 @@ func TestActivityLog_tokenCountExists(t *testing.T) { a := core.activityLog paths := [...]string{"directtokens/992/0", "directtokens/1001/foo", "directtokens/1111/0", "directtokens/2222/1"} for _, path := range paths { - WriteToStorage(t, core, ActivityLogLocalPrefix+path, []byte("test")) + WriteToStorage(t, core, ActivityLogPrefix+path, []byte("test")) } testCases := []struct { @@ -1440,36 +1245,18 @@ func (a *ActivityLog) resetEntitiesInMemory(t *testing.T) { a.l.Lock() defer a.l.Unlock() - a.fragmentLock.Lock() defer a.fragmentLock.Unlock() - - a.localFragmentLock.Lock() - defer a.localFragmentLock.Unlock() - - a.globalFragmentLock.Lock() - defer a.globalFragmentLock.Unlock() - - a.currentGlobalSegment = segmentInfo{ - startTimestamp: time.Time{}.Unix(), - currentClients: &activity.EntityActivityLog{ - Clients: make([]*activity.EntityRecord, 0), - }, - tokenCount: a.currentGlobalSegment.tokenCount, - clientSequenceNumber: 0, - } - - a.currentLocalSegment = segmentInfo{ + a.currentSegment = segmentInfo{ startTimestamp: time.Time{}.Unix(), currentClients: &activity.EntityActivityLog{ Clients: make([]*activity.EntityRecord, 0), }, - tokenCount: a.currentLocalSegment.tokenCount, + tokenCount: a.currentSegment.tokenCount, clientSequenceNumber: 0, } - a.partialMonthLocalClientTracker = make(map[string]*activity.EntityRecord) - a.globalPartialMonthClientTracker = make(map[string]*activity.EntityRecord) + a.partialMonthClientTracker = make(map[string]*activity.EntityRecord) } // TestActivityLog_loadCurrentClientSegment writes entity segments and calls loadCurrentClientSegment, then verifies @@ -1484,7 +1271,7 @@ func TestActivityLog_loadCurrentClientSegment(t *testing.T) { CountByNamespaceID: tokenRecords, } a.l.Lock() - a.currentLocalSegment.tokenCount = tokenCount + a.currentSegment.tokenCount = tokenCount a.l.Unlock() // setup in-storage data to load for testing @@ -1544,22 +1331,17 @@ func TestActivityLog_loadCurrentClientSegment(t *testing.T) { if err != nil { t.Fatalf(err.Error()) } - WriteToStorage(t, core, ActivityGlobalLogPrefix+tc.path, data) - WriteToStorage(t, core, ActivityLogLocalPrefix+tc.path, data) + WriteToStorage(t, core, ActivityLogPrefix+tc.path, data) } ctx := context.Background() for _, tc := range testCases { a.l.Lock() a.fragmentLock.Lock() - a.globalFragmentLock.Lock() - a.localFragmentLock.Lock() // loadCurrentClientSegment requires us to grab the fragment lock and the // activityLog lock, as per the comment in the loadCurrentClientSegment // function - err := a.loadCurrentClientSegment(ctx, time.Unix(tc.time, 0), tc.seqNum, tc.seqNum) - a.localFragmentLock.Unlock() - a.globalFragmentLock.Unlock() + err := a.loadCurrentClientSegment(ctx, time.Unix(tc.time, 0), tc.seqNum) a.fragmentLock.Unlock() a.l.Unlock() @@ -1571,23 +1353,19 @@ func TestActivityLog_loadCurrentClientSegment(t *testing.T) { } // verify accurate data in in-memory current segment - require.Equal(t, tc.time, a.GetStartTimestamp()) - require.Equal(t, tc.seqNum, a.GetGlobalEntitySequenceNumber()) - require.Equal(t, tc.seqNum, a.GetLocalEntitySequenceNumber()) - - globalClients := core.GetActiveGlobalClientsList() - if err := ActiveEntitiesEqual(globalClients, tc.entities.Clients); err != nil { - t.Errorf("bad data loaded into active global entities. expected only set of EntityID from %v in %v for path %q: %v", tc.entities.Clients, globalClients, tc.path, err) + startTimestamp := a.GetStartTimestamp() + if startTimestamp != tc.time { + t.Errorf("bad timestamp loaded. expected: %v, got: %v for path %q", tc.time, startTimestamp, tc.path) } - localClients := core.GetActiveLocalClientsList() - if err := ActiveEntitiesEqual(localClients, tc.entities.Clients); err != nil { - t.Errorf("bad data loaded into active local entities. expected only set of EntityID from %v in %v for path %q: %v", tc.entities.Clients, localClients, tc.path, err) + seqNum := a.GetEntitySequenceNumber() + if seqNum != tc.seqNum { + t.Errorf("bad sequence number loaded. expected: %v, got: %v for path %q", tc.seqNum, seqNum, tc.path) } - currentGlobalEntities := a.GetCurrentGlobalEntities() - if !entityRecordsEqual(t, currentGlobalEntities.Clients, tc.entities.Clients) { - t.Errorf("bad data loaded. expected: %v, got: %v for path %q", tc.entities.Clients, currentGlobalEntities, tc.path) + currentEntities := a.GetCurrentEntities() + if !entityRecordsEqual(t, currentEntities.Clients, tc.entities.Clients) { + t.Errorf("bad data loaded. expected: %v, got: %v for path %q", tc.entities.Clients, currentEntities, tc.path) } activeClients := core.GetActiveClientsList() @@ -1666,30 +1444,21 @@ func TestActivityLog_loadPriorEntitySegment(t *testing.T) { if err != nil { t.Fatalf(err.Error()) } - WriteToStorage(t, core, ActivityGlobalLogPrefix+tc.path, data) - WriteToStorage(t, core, ActivityLogLocalPrefix+tc.path, data) + WriteToStorage(t, core, ActivityLogPrefix+tc.path, data) } ctx := context.Background() for _, tc := range testCases { if tc.refresh { a.l.Lock() - a.localFragmentLock.Lock() - a.partialMonthLocalClientTracker = make(map[string]*activity.EntityRecord) - a.globalPartialMonthClientTracker = make(map[string]*activity.EntityRecord) - a.currentGlobalSegment.startTimestamp = tc.time - a.currentLocalSegment.startTimestamp = tc.time - a.localFragmentLock.Unlock() + a.fragmentLock.Lock() + a.partialMonthClientTracker = make(map[string]*activity.EntityRecord) + a.currentSegment.startTimestamp = tc.time + a.fragmentLock.Unlock() a.l.Unlock() } - // load global segments - err := a.loadPriorEntitySegment(ctx, time.Unix(tc.time, 0), tc.seqNum, false) - if err != nil { - t.Fatalf("got error loading data for %q: %v", tc.path, err) - } - // load local segments - err = a.loadPriorEntitySegment(ctx, time.Unix(tc.time, 0), tc.seqNum, true) + err := a.loadPriorEntitySegment(ctx, time.Unix(tc.time, 0), tc.seqNum) if err != nil { t.Fatalf("got error loading data for %q: %v", tc.path, err) } @@ -1738,7 +1507,7 @@ func TestActivityLog_loadTokenCount(t *testing.T) { ctx := context.Background() for _, tc := range testCases { - WriteToStorage(t, core, ActivityLogLocalPrefix+tc.path, data) + WriteToStorage(t, core, ActivityLogPrefix+tc.path, data) } for _, tc := range testCases { @@ -1848,14 +1617,6 @@ func setupActivityRecordsInStorage(t *testing.T, base time.Time, includeEntities }, }...) } - - // append some local entity data - entityRecords = append(entityRecords, &activity.EntityRecord{ - ClientID: "44444444-4444-4444-4444-444444444444", - NamespaceID: namespace.RootNamespaceID, - Timestamp: time.Now().Unix(), - }) - for i, entityRecord := range entityRecords { entityData, err := proto.Marshal(&activity.EntityActivityLog{ Clients: []*activity.EntityRecord{entityRecord}, @@ -1863,15 +1624,10 @@ func setupActivityRecordsInStorage(t *testing.T, base time.Time, includeEntities if err != nil { t.Fatalf(err.Error()) } - switch i { - case 0: - WriteToStorage(t, core, ActivityGlobalLogPrefix+"entity/"+fmt.Sprint(monthsAgo.Unix())+"/0", entityData) - - case len(entityRecords) - 1: - // local data - WriteToStorage(t, core, ActivityLogLocalPrefix+"entity/"+fmt.Sprint(base.Unix())+"/"+strconv.Itoa(i-1), entityData) - default: - WriteToStorage(t, core, ActivityGlobalLogPrefix+"entity/"+fmt.Sprint(base.Unix())+"/"+strconv.Itoa(i-1), entityData) + if i == 0 { + WriteToStorage(t, core, ActivityLogPrefix+"entity/"+fmt.Sprint(monthsAgo.Unix())+"/0", entityData) + } else { + WriteToStorage(t, core, ActivityLogPrefix+"entity/"+fmt.Sprint(base.Unix())+"/"+strconv.Itoa(i-1), entityData) } } } @@ -1895,7 +1651,7 @@ func setupActivityRecordsInStorage(t *testing.T, base time.Time, includeEntities t.Fatalf(err.Error()) } - WriteToStorage(t, core, ActivityLogLocalPrefix+"directtokens/"+fmt.Sprint(base.Unix())+"/0", tokenData) + WriteToStorage(t, core, ActivityLogPrefix+"directtokens/"+fmt.Sprint(base.Unix())+"/0", tokenData) } return a, entityRecords, tokenRecords @@ -1914,36 +1670,19 @@ func TestActivityLog_refreshFromStoredLog(t *testing.T) { } wg.Wait() - // active clients for the entire month expectedActive := &activity.EntityActivityLog{ Clients: expectedClientRecords[1:], } - expectedActiveGlobal := &activity.EntityActivityLog{ - Clients: expectedClientRecords[1 : len(expectedClientRecords)-1], - } - - // local client is only added to the newest segment for the current month. This should also appear in the active clients for the entire month. - expectedCurrentLocal := &activity.EntityActivityLog{ - Clients: expectedClientRecords[len(expectedClientRecords)-1:], - } - - // global clients added to the newest local entity segment expectedCurrent := &activity.EntityActivityLog{ - Clients: expectedClientRecords[len(expectedClientRecords)-2 : len(expectedClientRecords)-1], + Clients: expectedClientRecords[len(expectedClientRecords)-1:], } - currentEntities := a.GetCurrentGlobalEntities() + currentEntities := a.GetCurrentEntities() if !entityRecordsEqual(t, currentEntities.Clients, expectedCurrent.Clients) { // we only expect the newest entity segment to be loaded (for the current month) t.Errorf("bad activity entity logs loaded. expected: %v got: %v", expectedCurrent, currentEntities) } - currentLocalEntities := a.GetCurrentLocalEntities() - if !entityRecordsEqual(t, currentLocalEntities.Clients, expectedCurrentLocal.Clients) { - // we only expect the newest local entity segment to be loaded (for the current month) - t.Errorf("bad activity entity logs loaded. expected: %v got: %v", expectedCurrentLocal, currentLocalEntities) - } - nsCount := a.GetStoredTokenCountByNamespaceID() if !reflect.DeepEqual(nsCount, expectedTokenCounts) { // we expect all token counts to be loaded @@ -1955,19 +1694,6 @@ func TestActivityLog_refreshFromStoredLog(t *testing.T) { // we expect activeClients to be loaded for the entire month t.Errorf("bad data loaded into active entities. expected only set of EntityID from %v in %v: %v", expectedActive.Clients, activeClients, err) } - - // verify active global clients list - activeGlobalClients := a.core.GetActiveGlobalClientsList() - if err := ActiveEntitiesEqual(activeGlobalClients, expectedActiveGlobal.Clients); err != nil { - // we expect activeClients to be loaded for the entire month - t.Errorf("bad data loaded into active global entities. expected only set of EntityID from %v in %v: %v", expectedActiveGlobal.Clients, activeGlobalClients, err) - } - // verify active local clients list - activeLocalClients := a.core.GetActiveLocalClientsList() - if err := ActiveEntitiesEqual(activeLocalClients, expectedCurrentLocal.Clients); err != nil { - // we expect activeClients to be loaded for the entire month - t.Errorf("bad data loaded into active local entities. expected only set of EntityID from %v in %v: %v", expectedCurrentLocal.Clients, activeLocalClients, err) - } } // TestActivityLog_refreshFromStoredLogWithBackgroundLoadingCancelled writes data from 3 months ago to this month. The @@ -1991,31 +1717,14 @@ func TestActivityLog_refreshFromStoredLogWithBackgroundLoadingCancelled(t *testi } wg.Wait() - // refreshFromStoredLog loads the most recent segment and then loads the older segments in the background - // most recent global and local entity from setupActivityRecordsInStorage expected := &activity.EntityActivityLog{ - Clients: expectedClientRecords[len(expectedClientRecords)-2:], - } - - // most recent global entity from setupActivityRecordsInStorage - expectedCurrent := &activity.EntityActivityLog{ - Clients: expectedClientRecords[len(expectedClientRecords)-2 : len(expectedClientRecords)-1], - } - // most recent local entity from setupActivityRecordsInStorage - expectedCurrentLocal := &activity.EntityActivityLog{ Clients: expectedClientRecords[len(expectedClientRecords)-1:], } - currentEntities := a.GetCurrentGlobalEntities() - if !entityRecordsEqual(t, currentEntities.Clients, expectedCurrent.Clients) { + currentEntities := a.GetCurrentEntities() + if !entityRecordsEqual(t, currentEntities.Clients, expected.Clients) { // we only expect the newest entity segment to be loaded (for the current month) - t.Errorf("bad activity entity logs loaded. expected: %v got: %v", expectedCurrent, currentEntities) - } - - currentLocalEntities := a.GetCurrentLocalEntities() - if !entityRecordsEqual(t, currentLocalEntities.Clients, expectedCurrentLocal.Clients) { - // we only expect the newest local entity segment to be loaded (for the current month) - t.Errorf("bad activity entity logs loaded. expected: %v got: %v", expectedCurrentLocal, currentLocalEntities) + t.Errorf("bad activity entity logs loaded. expected: %v got: %v", expected, currentEntities) } nsCount := a.GetStoredTokenCountByNamespaceID() @@ -2029,18 +1738,6 @@ func TestActivityLog_refreshFromStoredLogWithBackgroundLoadingCancelled(t *testi // we only expect activeClients to be loaded for the newest segment (for the current month) t.Error(err) } - - // verify if the right global clients are loaded for the newest segment (for the current month) - activeGlobalClients := a.core.GetActiveGlobalClientsList() - if err := ActiveEntitiesEqual(activeGlobalClients, expectedCurrent.Clients); err != nil { - t.Error(err) - } - - // the right local clients are loaded for the newest segment (for the current month) - activeLocalClients := a.core.GetActiveLocalClientsList() - if err := ActiveEntitiesEqual(activeLocalClients, currentLocalEntities.Clients); err != nil { - t.Error(err) - } } // TestActivityLog_refreshFromStoredLogContextCancelled writes data from 3 months ago to this month and calls @@ -2074,25 +1771,15 @@ func TestActivityLog_refreshFromStoredLogNoTokens(t *testing.T) { expectedActive := &activity.EntityActivityLog{ Clients: expectedClientRecords[1:], } - expectedCurrentGlobal := &activity.EntityActivityLog{ - Clients: expectedClientRecords[len(expectedClientRecords)-2 : len(expectedClientRecords)-1], - } - expectedCurrentLocal := &activity.EntityActivityLog{ + expectedCurrent := &activity.EntityActivityLog{ Clients: expectedClientRecords[len(expectedClientRecords)-1:], } - currentGlobalEntities := a.GetCurrentGlobalEntities() - if !entityRecordsEqual(t, currentGlobalEntities.Clients, expectedCurrentGlobal.Clients) { - // we only expect the newest entity segment to be loaded (for the current month) - t.Errorf("bad activity entity logs loaded. expected: %v got: %v", expectedCurrentGlobal, currentGlobalEntities) - } - - currentLocalEntities := a.GetCurrentLocalEntities() - if !entityRecordsEqual(t, currentLocalEntities.Clients, expectedCurrentLocal.Clients) { - // we only expect the newest local entity segment to be loaded (for the current month) - t.Errorf("bad activity entity logs loaded. expected: %v got: %v", expectedCurrentLocal, currentLocalEntities) + currentEntities := a.GetCurrentEntities() + if !entityRecordsEqual(t, currentEntities.Clients, expectedCurrent.Clients) { + // we expect all segments for the current month to be loaded + t.Errorf("bad activity entity logs loaded. expected: %v got: %v", expectedCurrent, currentEntities) } - activeClients := a.core.GetActiveClientsList() if err := ActiveEntitiesEqual(activeClients, expectedActive.Clients); err != nil { t.Error(err) @@ -2124,7 +1811,7 @@ func TestActivityLog_refreshFromStoredLogNoEntities(t *testing.T) { t.Errorf("bad activity token counts loaded. expected: %v got: %v", expectedTokenCounts, nsCount) } - currentEntities := a.GetCurrentGlobalEntities() + currentEntities := a.GetCurrentEntities() if len(currentEntities.Clients) > 0 { t.Errorf("expected no current entity segment to be loaded. got: %v", currentEntities) } @@ -2192,10 +1879,10 @@ func TestActivityLog_refreshFromStoredLogPreviousMonth(t *testing.T) { Clients: expectedClientRecords[1:], } expectedCurrent := &activity.EntityActivityLog{ - Clients: expectedClientRecords[len(expectedClientRecords)-2 : len(expectedClientRecords)-1], + Clients: expectedClientRecords[len(expectedClientRecords)-1:], } - currentEntities := a.GetCurrentGlobalEntities() + currentEntities := a.GetCurrentEntities() if !entityRecordsEqual(t, currentEntities.Clients, expectedCurrent.Clients) { // we only expect the newest entity segment to be loaded (for the current month) t.Errorf("bad activity entity logs loaded. expected: %v got: %v", expectedCurrent, currentEntities) @@ -2291,18 +1978,11 @@ func TestActivityLog_DeleteWorker(t *testing.T) { "entity/1111/2", "entity/1111/3", "entity/1112/1", - } - for _, path := range paths { - WriteToStorage(t, core, ActivityGlobalLogPrefix+path, []byte("test")) - WriteToStorage(t, core, ActivityLogLocalPrefix+path, []byte("test")) - } - - tokenPaths := []string{ "directtokens/1111/1", "directtokens/1112/1", } - for _, path := range tokenPaths { - WriteToStorage(t, core, ActivityLogLocalPrefix+path, []byte("test")) + for _, path := range paths { + WriteToStorage(t, core, ActivityLogPrefix+path, []byte("test")) } doneCh := make(chan struct{}) @@ -2317,18 +1997,14 @@ func TestActivityLog_DeleteWorker(t *testing.T) { } // Check segments still present - readSegmentFromStorage(t, core, ActivityGlobalLogPrefix+"entity/1112/1") - readSegmentFromStorage(t, core, ActivityLogLocalPrefix+"entity/1112/1") - readSegmentFromStorage(t, core, ActivityLogLocalPrefix+"directtokens/1112/1") + readSegmentFromStorage(t, core, ActivityLogPrefix+"entity/1112/1") + readSegmentFromStorage(t, core, ActivityLogPrefix+"directtokens/1112/1") // Check other segments not present - expectMissingSegment(t, core, ActivityGlobalLogPrefix+"entity/1111/1") - expectMissingSegment(t, core, ActivityGlobalLogPrefix+"entity/1111/2") - expectMissingSegment(t, core, ActivityGlobalLogPrefix+"entity/1111/3") - expectMissingSegment(t, core, ActivityLogLocalPrefix+"entity/1111/1") - expectMissingSegment(t, core, ActivityLogLocalPrefix+"entity/1111/2") - expectMissingSegment(t, core, ActivityLogLocalPrefix+"entity/1111/3") - expectMissingSegment(t, core, ActivityLogLocalPrefix+"directtokens/1111/1") + expectMissingSegment(t, core, ActivityLogPrefix+"entity/1111/1") + expectMissingSegment(t, core, ActivityLogPrefix+"entity/1111/2") + expectMissingSegment(t, core, ActivityLogPrefix+"entity/1111/3") + expectMissingSegment(t, core, ActivityLogPrefix+"directtokens/1111/1") } // checkAPIWarnings ensures there is a warning if switching from enabled -> disabled, @@ -2414,7 +2090,7 @@ func TestActivityLog_EnableDisable(t *testing.T) { } // verify segment exists - path := fmt.Sprintf("%ventity/%v/0", ActivityGlobalLogPrefix, seg1) + path := fmt.Sprintf("%ventity/%v/0", ActivityLogPrefix, seg1) readSegmentFromStorage(t, core, path) // Add in-memory fragment @@ -2444,10 +2120,10 @@ func TestActivityLog_EnableDisable(t *testing.T) { } // Verify empty segments are present - path = fmt.Sprintf("%ventity/%v/0", ActivityGlobalLogPrefix, seg2) + path = fmt.Sprintf("%ventity/%v/0", ActivityLogPrefix, seg2) readSegmentFromStorage(t, core, path) - path = fmt.Sprintf("%vdirecttokens/%v/0", ActivityLogLocalPrefix, seg2) + path = fmt.Sprintf("%vdirecttokens/%v/0", ActivityLogPrefix, seg2) } readSegmentFromStorage(t, core, path) } @@ -2456,23 +2132,9 @@ func TestActivityLog_EndOfMonth(t *testing.T) { // We only want *fake* end of months, *real* ones are too scary. timeutil.SkipAtEndOfMonth(t) - t.Parallel() - - storage := &logical.InmemStorage{} - coreConfig := &CoreConfig{ - CredentialBackends: map[string]logical.Factory{ - "userpass": userpass.Factory, - }, - Physical: storage.Underlying(), - } - - cluster := NewTestCluster(t, coreConfig, nil) - core := cluster.Cores[0].Core - TestWaitActive(t, core) - - ctx := namespace.RootContext(nil) - + core, _, _ := TestCoreUnsealed(t) a := core.activityLog + ctx := namespace.RootContext(nil) // Make sure we're enabled. a.SetConfig(ctx, activityConfig{ @@ -2484,23 +2146,8 @@ func TestActivityLog_EndOfMonth(t *testing.T) { id1 := "11111111-1111-1111-1111-111111111111" id2 := "22222222-2222-2222-2222-222222222222" id3 := "33333333-3333-3333-3333-333333333333" - id4 := "44444444-4444-4444-4444-444444444444" - - // add global data a.AddEntityToFragment(id1, "root", time.Now().Unix()) - // add local data - localMountEntry := &MountEntry{ - Table: credentialTableType, - Path: "localUserpass/", - Local: true, - Type: "userpass", - Accessor: "localMountAccessor", - } - err := core.enableCredential(ctx, localMountEntry) - require.NoError(t, err) - a.AddClientToFragment(id4, "root", time.Now().Unix(), false, "localMountAccessor") - month0 := time.Now().UTC() segment0 := a.GetStartTimestamp() month1 := timeutil.StartOfNextMonth(month0) @@ -2510,23 +2157,13 @@ func TestActivityLog_EndOfMonth(t *testing.T) { a.HandleEndOfMonth(ctx, month1) // Check segment is present, with 1 entity - path := fmt.Sprintf("%ventity/%v/0", ActivityGlobalLogPrefix, segment0) + path := fmt.Sprintf("%ventity/%v/0", ActivityLogPrefix, segment0) protoSegment := readSegmentFromStorage(t, core, path) out := &activity.EntityActivityLog{} - err = proto.Unmarshal(protoSegment.Value, out) - if err != nil { - t.Fatal(err) - } - expectedEntityIDs(t, out, []string{id1}) - - path = fmt.Sprintf("%ventity/%v/0", ActivityLogLocalPrefix, segment0) - protoSegment = readSegmentFromStorage(t, core, path) - out = &activity.EntityActivityLog{} - err = proto.Unmarshal(protoSegment.Value, out) + err := proto.Unmarshal(protoSegment.Value, out) if err != nil { t.Fatal(err) } - expectedEntityIDs(t, out, []string{id4}) segment1 := a.GetStartTimestamp() expectedTimestamp := timeutil.StartOfMonth(month1).Unix() @@ -2571,39 +2208,24 @@ func TestActivityLog_EndOfMonth(t *testing.T) { // Check all three segments still present, with correct entities testCases := []struct { - SegmentTimestamp int64 - ExpectedGlobalEntityIDs []string - ExpectedLocalEntityIDs []string + SegmentTimestamp int64 + ExpectedEntityIDs []string }{ - {segment0, []string{id1}, []string{id4}}, - {segment1, []string{id2}, []string{}}, - {segment2, []string{id3}, []string{}}, + {segment0, []string{id1}}, + {segment1, []string{id2}}, + {segment2, []string{id3}}, } for i, tc := range testCases { t.Logf("checking segment %v timestamp %v", i, tc.SegmentTimestamp) - - // Check for global entities at global storage path - path = fmt.Sprintf("%ventity/%v/0", ActivityGlobalLogPrefix, tc.SegmentTimestamp) - protoSegment = readSegmentFromStorage(t, core, path) - out = &activity.EntityActivityLog{} + path := fmt.Sprintf("%ventity/%v/0", ActivityLogPrefix, tc.SegmentTimestamp) + protoSegment := readSegmentFromStorage(t, core, path) + out := &activity.EntityActivityLog{} err = proto.Unmarshal(protoSegment.Value, out) if err != nil { t.Fatalf("could not unmarshal protobuf: %v", err) } - expectedEntityIDs(t, out, tc.ExpectedGlobalEntityIDs) - - // Check for local entities at local storage path - if len(tc.ExpectedLocalEntityIDs) > 0 { - path = fmt.Sprintf("%ventity/%v/0", ActivityLogLocalPrefix, tc.SegmentTimestamp) - protoSegment = readSegmentFromStorage(t, core, path) - out = &activity.EntityActivityLog{} - err = proto.Unmarshal(protoSegment.Value, out) - if err != nil { - t.Fatalf("could not unmarshal protobuf: %v", err) - } - expectedEntityIDs(t, out, tc.ExpectedLocalEntityIDs) - } + expectedEntityIDs(t, out, tc.ExpectedEntityIDs) } } @@ -2749,7 +2371,7 @@ func TestActivityLog_CalculatePrecomputedQueriesWithMixedTWEs(t *testing.T) { if err != nil { t.Fatal(err) } - tokenPath := fmt.Sprintf("%vdirecttokens/%v/%v", ActivityLogLocalPrefix, segment.StartTime, segment.Segment) + tokenPath := fmt.Sprintf("%vdirecttokens/%v/%v", ActivityLogPrefix, segment.StartTime, segment.Segment) WriteToStorage(t, core, tokenPath, data) } @@ -2766,7 +2388,7 @@ func TestActivityLog_CalculatePrecomputedQueriesWithMixedTWEs(t *testing.T) { if err != nil { t.Fatal(err) } - path := fmt.Sprintf("%ventity/%v/%v", ActivityGlobalLogPrefix, segment.StartTime, segment.Segment) + path := fmt.Sprintf("%ventity/%v/%v", ActivityLogPrefix, segment.StartTime, segment.Segment) WriteToStorage(t, core, path, data) } expectedCounts := []struct { @@ -3047,10 +2669,10 @@ func TestActivityLog_SaveAfterDisable(t *testing.T) { t.Fatal(err) } - path := ActivityGlobalLogPrefix + "entity/0/0" + path := ActivityLogPrefix + "entity/0/0" expectMissingSegment(t, core, path) - path = fmt.Sprintf("%ventity/%v/0", ActivityGlobalLogPrefix, startTimestamp) + path = fmt.Sprintf("%ventity/%v/0", ActivityLogPrefix, startTimestamp) expectMissingSegment(t, core, path) } @@ -3151,7 +2773,7 @@ func TestActivityLog_Precompute(t *testing.T) { if err != nil { t.Fatal(err) } - path := fmt.Sprintf("%ventity/%v/%v", ActivityGlobalLogPrefix, segment.StartTime, segment.Segment) + path := fmt.Sprintf("%ventity/%v/%v", ActivityLogPrefix, segment.StartTime, segment.Segment) WriteToStorage(t, core, path, data) } @@ -3462,7 +3084,7 @@ func TestActivityLog_Precompute_SkipMonth(t *testing.T) { if err != nil { t.Fatal(err) } - path := fmt.Sprintf("%ventity/%v/%v", ActivityGlobalLogPrefix, segment.StartTime, segment.Segment) + path := fmt.Sprintf("%ventity/%v/%v", ActivityLogPrefix, segment.StartTime, segment.Segment) WriteToStorage(t, core, path, data) } @@ -3679,7 +3301,7 @@ func TestActivityLog_PrecomputeNonEntityTokensWithID(t *testing.T) { if err != nil { t.Fatal(err) } - path := fmt.Sprintf("%ventity/%v/%v", ActivityGlobalLogPrefix, segment.StartTime, segment.Segment) + path := fmt.Sprintf("%ventity/%v/%v", ActivityLogPrefix, segment.StartTime, segment.Segment) WriteToStorage(t, core, path, data) } @@ -4068,11 +3690,11 @@ func TestActivityLog_Deletion(t *testing.T) { for i, start := range times { // no entities in some months, just for fun for j := 0; j < (i+3)%5; j++ { - entityPath := fmt.Sprintf("%ventity/%v/%v", ActivityGlobalLogPrefix, start.Unix(), j) + entityPath := fmt.Sprintf("%ventity/%v/%v", ActivityLogPrefix, start.Unix(), j) paths[i] = append(paths[i], entityPath) WriteToStorage(t, core, entityPath, []byte("test")) } - tokenPath := fmt.Sprintf("%vdirecttokens/%v/0", ActivityLogLocalPrefix, start.Unix()) + tokenPath := fmt.Sprintf("%vdirecttokens/%v/0", ActivityLogPrefix, start.Unix()) paths[i] = append(paths[i], tokenPath) WriteToStorage(t, core, tokenPath, []byte("test")) @@ -4444,7 +4066,7 @@ func TestActivityLog_partialMonthClientCountWithMultipleMountPaths(t *testing.T) if err != nil { t.Fatalf(err.Error()) } - storagePath := fmt.Sprintf("%sentity/%d/%d", ActivityGlobalLogPrefix, timeutil.StartOfMonth(now).Unix(), i) + storagePath := fmt.Sprintf("%sentity/%d/%d", ActivityLogPrefix, timeutil.StartOfMonth(now).Unix(), i) WriteToStorage(t, core, storagePath, entityData) } @@ -5071,44 +4693,15 @@ func TestActivityLog_HandleEndOfMonth(t *testing.T) { // clients and verifies that they are added correctly to the tracking data // structures func TestAddActivityToFragment(t *testing.T) { - storage := &logical.InmemStorage{} - coreConfig := &CoreConfig{ - CredentialBackends: map[string]logical.Factory{ - "userpass": userpass.Factory, - }, - Physical: storage.Underlying(), - } - - cluster := NewTestCluster(t, coreConfig, nil) - core := cluster.Cores[0].Core + core, _, _ := TestCoreUnsealed(t) a := core.activityLog a.SetEnable(true) - require.Nil(t, a.localFragment) - require.Nil(t, a.currentGlobalFragment) - mount := "mount" - localMount := "localMount" ns := "root" id := "id1" - - // keeps track of the number of clients added to localFragment - localCount := 0 - - // add a client to regular fragment a.AddActivityToFragment(id, ns, 0, entityActivityType, mount) - // create a local mount accessor for local clients - localMe := &MountEntry{ - Table: credentialTableType, - Path: "userpass-local/", - Type: "userpass", - Local: true, - Accessor: localMount, - } - err := core.enableCredential(namespace.RootContext(nil), localMe) - require.NoError(t, err) - testCases := []struct { name string id string @@ -5116,7 +4709,6 @@ func TestAddActivityToFragment(t *testing.T) { isAdded bool expectedID string isNonEntity bool - isLocal bool }{ { name: "duplicate", @@ -5124,7 +4716,6 @@ func TestAddActivityToFragment(t *testing.T) { activityType: entityActivityType, isAdded: false, expectedID: id, - isLocal: false, }, { name: "new entity", @@ -5132,7 +4723,6 @@ func TestAddActivityToFragment(t *testing.T) { activityType: entityActivityType, isAdded: true, expectedID: "new-id", - isLocal: false, }, { name: "new nonentity", @@ -5141,7 +4731,6 @@ func TestAddActivityToFragment(t *testing.T) { isAdded: true, expectedID: "new-nonentity", isNonEntity: true, - isLocal: true, }, { name: "new acme", @@ -5150,7 +4739,6 @@ func TestAddActivityToFragment(t *testing.T) { isAdded: true, expectedID: "pki-acme.new-acme", isNonEntity: true, - isLocal: false, }, { name: "new secret sync", @@ -5159,171 +4747,39 @@ func TestAddActivityToFragment(t *testing.T) { isAdded: true, expectedID: "new-secret-sync", isNonEntity: true, - isLocal: false, - }, - { - name: "new local entity", - id: "new-local-id", - activityType: entityActivityType, - isAdded: true, - expectedID: "new-local-id", - isNonEntity: false, - isLocal: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - var mountAccessor string - a.globalFragmentLock.RLock() - globalClientsBefore := len(a.currentGlobalFragment.Clients) - a.globalFragmentLock.RUnlock() - - numLocalClientsBefore := 0 - - // add client to the fragment - if tc.isLocal { - // data already present in local fragment, get client count before adding activity to fragment - a.localFragmentLock.RLock() - numLocalClientsBefore = len(a.localFragment.Clients) - a.localFragmentLock.RUnlock() - - mountAccessor = localMount - a.AddActivityToFragment(tc.id, ns, 0, tc.activityType, localMount) + a.fragmentLock.RLock() + numClientsBefore := len(a.fragment.Clients) + a.fragmentLock.RUnlock() - require.NotNil(t, a.localFragment) - localCount++ - } else { - mountAccessor = mount - a.AddActivityToFragment(tc.id, ns, 0, tc.activityType, mount) - } + a.AddActivityToFragment(tc.id, ns, 0, tc.activityType, mount) + a.fragmentLock.RLock() + defer a.fragmentLock.RUnlock() + numClientsAfter := len(a.fragment.Clients) - a.globalFragmentLock.RLock() - defer a.globalFragmentLock.RUnlock() - globalClientsAfter := len(a.currentGlobalFragment.Clients) - - // if local client, verify if local fragment is updated - if tc.isLocal { - a.localFragmentLock.RLock() - defer a.localFragmentLock.RUnlock() - - numLocalClientsAfter := len(a.localFragment.Clients) - switch tc.isAdded { - case true: - require.Equal(t, numLocalClientsBefore+1, numLocalClientsAfter) - default: - require.Equal(t, numLocalClientsBefore, numLocalClientsAfter) - } + if tc.isAdded { + require.Equal(t, numClientsBefore+1, numClientsAfter) } else { - // verify global clients - switch tc.isAdded { - case true: - if tc.activityType != nonEntityTokenActivityType { - require.Equal(t, globalClientsBefore+1, globalClientsAfter) - } - default: - require.Equal(t, globalClientsBefore, globalClientsAfter) - } + require.Equal(t, numClientsBefore, numClientsAfter) } - if tc.isLocal { - require.Contains(t, a.partialMonthLocalClientTracker, tc.expectedID) - require.True(t, proto.Equal(&activity.EntityRecord{ - ClientID: tc.expectedID, - NamespaceID: ns, - Timestamp: 0, - NonEntity: tc.isNonEntity, - MountAccessor: mountAccessor, - ClientType: tc.activityType, - }, a.partialMonthLocalClientTracker[tc.expectedID])) - } else { - require.Contains(t, a.globalPartialMonthClientTracker, tc.expectedID) - require.True(t, proto.Equal(&activity.EntityRecord{ - ClientID: tc.expectedID, - NamespaceID: ns, - Timestamp: 0, - NonEntity: tc.isNonEntity, - MountAccessor: mount, - ClientType: tc.activityType, - }, a.globalPartialMonthClientTracker[tc.expectedID])) - } + require.Contains(t, a.partialMonthClientTracker, tc.expectedID) + require.True(t, proto.Equal(&activity.EntityRecord{ + ClientID: tc.expectedID, + NamespaceID: ns, + Timestamp: 0, + NonEntity: tc.isNonEntity, + MountAccessor: mount, + ClientType: tc.activityType, + }, a.partialMonthClientTracker[tc.expectedID])) }) } } -// TestGetAllPartialMonthClients adds activity for a local and regular clients and verifies that -// GetAllPartialMonthClients returns the right local and global clients -func TestGetAllPartialMonthClients(t *testing.T) { - storage := &logical.InmemStorage{} - coreConfig := &CoreConfig{ - CredentialBackends: map[string]logical.Factory{ - "userpass": userpass.Factory, - }, - Physical: storage.Underlying(), - } - - cluster := NewTestCluster(t, coreConfig, nil) - core := cluster.Cores[0].Core - a := core.activityLog - a.SetEnable(true) - - require.Nil(t, a.localFragment) - require.Nil(t, a.currentGlobalFragment) - - ns := "root" - mount := "mount" - localMount := "localMount" - clientID := "id1" - localClientID := "new-local-id" - - // add a client to regular fragment, this should be added to globalPartialMonthClientTracker - a.AddActivityToFragment(clientID, ns, 0, entityActivityType, mount) - - require.NotNil(t, a.localFragment) - require.NotNil(t, a.currentGlobalFragment) - - // create a local mount accessor - localMe := &MountEntry{ - Table: credentialTableType, - Path: "userpass-local/", - Type: "userpass", - Local: true, - Accessor: localMount, - } - err := core.enableCredential(namespace.RootContext(nil), localMe) - require.NoError(t, err) - - // add client to local fragment, this should be added to partialMonthLocalClientTracker - a.AddActivityToFragment(localClientID, ns, 0, entityActivityType, localMount) - - require.NotNil(t, a.localFragment) - - // GetAllPartialMonthClients returns the partialMonthLocalClientTracker and globalPartialMonthClientTracker - localClients, globalClients := a.GetAllPartialMonthClients() - - // verify the returned localClients - require.Len(t, localClients, 1) - require.Contains(t, localClients, localClientID) - require.True(t, proto.Equal(&activity.EntityRecord{ - ClientID: localClientID, - NamespaceID: ns, - Timestamp: 0, - MountAccessor: localMount, - ClientType: entityActivityType, - }, localClients[localClientID])) - - // verify the returned globalClients - require.Len(t, globalClients, 1) - require.Contains(t, globalClients, clientID) - require.True(t, proto.Equal(&activity.EntityRecord{ - ClientID: clientID, - NamespaceID: ns, - Timestamp: 0, - MountAccessor: mount, - ClientType: entityActivityType, - }, globalClients[clientID])) -} - // TestActivityLog_reportPrecomputedQueryMetrics creates 3 clients per type and // calls reportPrecomputedQueryMetrics. The test verifies that the metric sink // gets metrics reported correctly, based on the segment time matching the @@ -5568,256 +5024,3 @@ func TestActivityLog_Export_CSV_Header(t *testing.T) { require.Empty(t, deep.Equal(expectedColumnIndex, encoder.columnIndex)) } - -// TestCreateSegment_StoreSegment verifies that -// the activity log will correctly create segments from -// the fragments and store the right number of clients at -// the proper path. This test should be modified to include local clients. -func TestCreateSegment_StoreSegment(t *testing.T) { - cluster := NewTestCluster(t, nil, nil) - core := cluster.Cores[0].Core - a := core.activityLog - a.SetEnable(true) - - ctx := context.Background() - timeStamp := time.Now() - - clientRecords := make([]*activity.EntityRecord, ActivitySegmentClientCapacity*2+1) - for i := range clientRecords { - clientRecords[i] = &activity.EntityRecord{ - ClientID: fmt.Sprintf("111122222-3333-4444-5555-%012v", i), - Timestamp: timeStamp.Unix(), - NonEntity: false, - } - } - - startTime := a.GetStartTimestamp() - parsedTime := time.Unix(startTime, 0) - - testCases := []struct { - testName string - numClients int - pathPrefix string - maxClientsPerFragment int - global bool - forceStore bool - }{ - { - testName: "[global] max client size, drop clients", - numClients: ActivitySegmentClientCapacity*2 + 1, - pathPrefix: activityGlobalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity, - global: true, - }, - { - testName: "[global, no-force] max client size, drop clients", - numClients: ActivitySegmentClientCapacity*2 + 1, - pathPrefix: activityGlobalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity, - global: true, - forceStore: true, - }, - { - testName: "[global] max segment size", - numClients: ActivitySegmentClientCapacity, - pathPrefix: activityGlobalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity, - global: true, - }, - { - testName: "[global, no-force] max segment size", - numClients: ActivitySegmentClientCapacity, - pathPrefix: activityGlobalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity, - global: true, - forceStore: true, - }, - { - testName: "[global] max segment size, multiple fragments", - numClients: ActivitySegmentClientCapacity, - pathPrefix: activityGlobalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity - 1, - global: true, - }, - { - testName: "[global, no-force] max segment size, multiple fragments", - numClients: ActivitySegmentClientCapacity, - pathPrefix: activityGlobalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity - 1, - global: true, - forceStore: true, - }, - { - testName: "[global] roll over", - numClients: ActivitySegmentClientCapacity + 2, - pathPrefix: activityGlobalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity, - global: true, - }, - { - testName: "[global, no-force] roll over", - numClients: ActivitySegmentClientCapacity + 2, - pathPrefix: activityGlobalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity, - global: true, - forceStore: true, - }, - { - testName: "[global] max segment size, rollover multiple fragments", - numClients: ActivitySegmentClientCapacity * 2, - pathPrefix: activityGlobalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity - 1, - global: true, - }, - { - testName: "[global, no-force] max segment size, rollover multiple fragments", - numClients: ActivitySegmentClientCapacity * 2, - pathPrefix: activityGlobalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity - 1, - global: true, - forceStore: true, - }, - { - testName: "[local] max client size, drop clients", - numClients: ActivitySegmentClientCapacity*2 + 1, - pathPrefix: activityLocalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity, - global: false, - }, - { - testName: "[local, no-force] max client size, drop clients", - numClients: ActivitySegmentClientCapacity*2 + 1, - pathPrefix: activityLocalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity, - global: false, - forceStore: true, - }, - { - testName: "[local] max segment size", - numClients: ActivitySegmentClientCapacity, - pathPrefix: activityLocalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity, - global: false, - }, - { - testName: "[local, no-force] max segment size", - numClients: ActivitySegmentClientCapacity, - pathPrefix: activityLocalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity, - global: false, - forceStore: true, - }, - { - testName: "[local] max segment size, multiple fragments", - numClients: ActivitySegmentClientCapacity, - pathPrefix: activityLocalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity - 1, - global: false, - }, - { - testName: "[local, no-force] max segment size, multiple fragments", - numClients: ActivitySegmentClientCapacity, - pathPrefix: activityLocalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity - 1, - global: false, - forceStore: true, - }, - { - testName: "[local] roll over", - numClients: ActivitySegmentClientCapacity + 2, - pathPrefix: activityLocalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity, - global: false, - }, - { - testName: "[local, no-force] roll over", - numClients: ActivitySegmentClientCapacity + 2, - pathPrefix: activityLocalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity, - global: false, - forceStore: true, - }, - { - testName: "[local] max segment size, rollover multiple fragments", - numClients: ActivitySegmentClientCapacity * 2, - pathPrefix: activityLocalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity - 1, - global: false, - }, - { - testName: "[local, no-force] max segment size, rollover multiple fragments", - numClients: ActivitySegmentClientCapacity * 2, - pathPrefix: activityLocalPathPrefix, - maxClientsPerFragment: ActivitySegmentClientCapacity - 1, - global: false, - forceStore: true, - }, - } - - for _, test := range testCases { - t.Run(test.testName, func(t *testing.T) { - // Add clients to fragments - fragments := make([]*activity.LogFragment, 0) - remainder := test.numClients - var i int - for i = 0; i+test.maxClientsPerFragment < test.numClients; i = i + test.maxClientsPerFragment { - clients := clientRecords[i : i+test.maxClientsPerFragment] - remainder -= test.maxClientsPerFragment - fragments = append(fragments, &activity.LogFragment{Clients: clients}) - } - if remainder > 0 { - clients := clientRecords[i : i+remainder] - fragments = append(fragments, &activity.LogFragment{Clients: clients}) - - } - - segment := &a.currentGlobalSegment - if !test.global { - segment = &a.currentLocalSegment - } - - // Create segments and write to storage - require.NoError(t, core.StoreCurrentSegment(ctx, fragments, segment, test.forceStore, test.pathPrefix)) - - reader, err := a.NewSegmentFileReader(ctx, parsedTime) - require.NoError(t, err) - var clientTotal int - if test.global { - for { - entity, err := reader.ReadGlobalEntity(ctx) - if errors.Is(err, io.EOF) { - break - } - require.NoError(t, err) - clientTotal += len(entity.GetClients()) - } - } else { - for { - entity, err := reader.ReadLocalEntity(ctx) - if errors.Is(err, io.EOF) { - break - } - require.NoError(t, err) - clientTotal += len(entity.GetClients()) - } - } - - // The current behavior is that there were greater than 2 * ActivitySegmentClientCapacity seen, then we - // drop of the remainder of those clients seen during that time. Let's verify that this is the case - expectedTotal := test.numClients - if test.numClients > 2*ActivitySegmentClientCapacity { - expectedTotal = 2 * ActivitySegmentClientCapacity - } - - require.Equal(t, expectedTotal, clientTotal) - - // Delete any logs written in this test - core.DeleteLogsAtPath(ctx, t, test.pathPrefix+activityEntityBasePath, startTime) - // Reset client sequence number and current client slice back to original values - segment.clientSequenceNumber = 0 - segment.currentClients = &activity.EntityActivityLog{ - Clients: make([]*activity.EntityRecord, 0), - } - }) - } -} diff --git a/vault/activity_log_testing_util.go b/vault/activity_log_testing_util.go index d0fd4b7b35ae..bbaae9551191 100644 --- a/vault/activity_log_testing_util.go +++ b/vault/activity_log_testing_util.go @@ -36,7 +36,7 @@ func (c *Core) InjectActivityLogDataThisMonth(t *testing.T) map[string]*activity Timestamp: c.activityLog.clock.Now().Unix(), NonEntity: i%2 == 0, } - c.activityLog.globalPartialMonthClientTracker[er.ClientID] = er + c.activityLog.partialMonthClientTracker[er.ClientID] = er } if constants.IsEnterprise { @@ -49,35 +49,25 @@ func (c *Core) InjectActivityLogDataThisMonth(t *testing.T) map[string]*activity Timestamp: c.activityLog.clock.Now().Unix(), NonEntity: i%2 == 0, } - c.activityLog.globalPartialMonthClientTracker[er.ClientID] = er + c.activityLog.partialMonthClientTracker[er.ClientID] = er } } } - return c.activityLog.globalPartialMonthClientTracker + return c.activityLog.partialMonthClientTracker } -// GetActiveClients returns the in-memory globalPartialMonthClientTracker and partialMonthLocalClientTracker from an +// GetActiveClients returns the in-memory partialMonthClientTracker from an // activity log. func (c *Core) GetActiveClients() map[string]*activity.EntityRecord { out := make(map[string]*activity.EntityRecord) c.stateLock.RLock() - c.activityLog.globalFragmentLock.RLock() - c.activityLog.localFragmentLock.RLock() - - // add active global clients - for k, v := range c.activityLog.globalPartialMonthClientTracker { - out[k] = v - } - - // add active local clients - for k, v := range c.activityLog.partialMonthLocalClientTracker { + c.activityLog.fragmentLock.RLock() + for k, v := range c.activityLog.partialMonthClientTracker { out[k] = v } - - c.activityLog.globalFragmentLock.RUnlock() - c.activityLog.localFragmentLock.RUnlock() + c.activityLog.fragmentLock.RUnlock() c.stateLock.RUnlock() return out @@ -93,42 +83,11 @@ func (c *Core) GetActiveClientsList() []*activity.EntityRecord { return out } -// GetActiveLocalClientsList returns the active clients from globalPartialMonthClientTracker in activity log -func (c *Core) GetActiveGlobalClientsList() []*activity.EntityRecord { - out := []*activity.EntityRecord{} - c.activityLog.globalFragmentLock.RLock() - // add active global clients - for _, v := range c.activityLog.globalPartialMonthClientTracker { - out = append(out, v) - } - c.activityLog.globalFragmentLock.RUnlock() - return out -} - -// GetActiveLocalClientsList returns the active clients from partialMonthLocalClientTracker in activity log -func (c *Core) GetActiveLocalClientsList() []*activity.EntityRecord { - out := []*activity.EntityRecord{} - c.activityLog.localFragmentLock.RLock() - // add active global clients - for _, v := range c.activityLog.partialMonthLocalClientTracker { - out = append(out, v) - } - c.activityLog.localFragmentLock.RUnlock() - return out -} - -// GetCurrentGlobalEntities returns the current clients from currentGlobalSegment in activity log -func (a *ActivityLog) GetCurrentGlobalEntities() *activity.EntityActivityLog { +// GetCurrentEntities returns the current entity activity log +func (a *ActivityLog) GetCurrentEntities() *activity.EntityActivityLog { a.l.RLock() defer a.l.RUnlock() - return a.currentGlobalSegment.currentClients -} - -// GetCurrentLocalEntities returns the current clients from currentLocalSegment in activity log -func (a *ActivityLog) GetCurrentLocalEntities() *activity.EntityActivityLog { - a.l.RLock() - defer a.l.RUnlock() - return a.currentLocalSegment.currentClients + return a.currentSegment.currentClients } // WriteToStorage is used to put entity data in storage @@ -164,11 +123,8 @@ func (a *ActivityLog) SetStandbyEnable(ctx context.Context, enabled bool) { // NOTE: AddTokenToFragment is deprecated and can no longer be used, except for // testing backward compatibility. Please use AddClientToFragment instead. func (a *ActivityLog) AddTokenToFragment(namespaceID string) { - a.globalFragmentLock.Lock() - defer a.globalFragmentLock.Unlock() - - a.localFragmentLock.Lock() - defer a.localFragmentLock.Unlock() + a.fragmentLock.Lock() + defer a.fragmentLock.Unlock() if !a.enabled { return @@ -176,7 +132,7 @@ func (a *ActivityLog) AddTokenToFragment(namespaceID string) { a.createCurrentFragment() - a.localFragment.NonEntityTokens[namespaceID] += 1 + a.fragment.NonEntityTokens[namespaceID] += 1 } func RandStringBytes(n int) string { @@ -197,63 +153,37 @@ func (a *ActivityLog) ExpectCurrentSegmentRefreshed(t *testing.T, expectedStart defer a.l.RUnlock() a.fragmentLock.RLock() defer a.fragmentLock.RUnlock() - if a.currentGlobalSegment.currentClients == nil { + if a.currentSegment.currentClients == nil { t.Fatalf("expected non-nil currentSegment.currentClients") } - if a.currentGlobalSegment.currentClients.Clients == nil { + if a.currentSegment.currentClients.Clients == nil { t.Errorf("expected non-nil currentSegment.currentClients.Entities") } - if a.currentGlobalSegment.tokenCount == nil { + if a.currentSegment.tokenCount == nil { t.Fatalf("expected non-nil currentSegment.tokenCount") } - if a.currentGlobalSegment.tokenCount.CountByNamespaceID == nil { + if a.currentSegment.tokenCount.CountByNamespaceID == nil { t.Errorf("expected non-nil currentSegment.tokenCount.CountByNamespaceID") } - if a.currentLocalSegment.currentClients == nil { - t.Fatalf("expected non-nil currentSegment.currentClients") + if a.partialMonthClientTracker == nil { + t.Errorf("expected non-nil partialMonthClientTracker") } - if a.currentLocalSegment.currentClients.Clients == nil { - t.Errorf("expected non-nil currentSegment.currentClients.Entities") + if len(a.currentSegment.currentClients.Clients) > 0 { + t.Errorf("expected no current entity segment to be loaded. got: %v", a.currentSegment.currentClients) } - if a.currentLocalSegment.tokenCount == nil { - t.Fatalf("expected non-nil currentSegment.tokenCount") - } - if a.currentLocalSegment.tokenCount.CountByNamespaceID == nil { - t.Errorf("expected non-nil currentSegment.tokenCount.CountByNamespaceID") + if len(a.currentSegment.tokenCount.CountByNamespaceID) > 0 { + t.Errorf("expected no token counts to be loaded. got: %v", a.currentSegment.tokenCount.CountByNamespaceID) } - if a.partialMonthLocalClientTracker == nil { - t.Errorf("expected non-nil partialMonthLocalClientTracker") - } - if a.globalPartialMonthClientTracker == nil { - t.Errorf("expected non-nil globalPartialMonthClientTracker") - } - if len(a.currentGlobalSegment.currentClients.Clients) > 0 { - t.Errorf("expected no current entity segment to be loaded. got: %v", a.currentGlobalSegment.currentClients) - } - if len(a.currentLocalSegment.currentClients.Clients) > 0 { - t.Errorf("expected no current entity segment to be loaded. got: %v", a.currentLocalSegment.currentClients) - } - if len(a.currentLocalSegment.tokenCount.CountByNamespaceID) > 0 { - t.Errorf("expected no token counts to be loaded. got: %v", a.currentLocalSegment.tokenCount.CountByNamespaceID) - } - if len(a.partialMonthLocalClientTracker) > 0 { - t.Errorf("expected no active entity segment to be loaded. got: %v", a.partialMonthLocalClientTracker) - } - if len(a.globalPartialMonthClientTracker) > 0 { - t.Errorf("expected no active entity segment to be loaded. got: %v", a.globalPartialMonthClientTracker) + if len(a.partialMonthClientTracker) > 0 { + t.Errorf("expected no active entity segment to be loaded. got: %v", a.partialMonthClientTracker) } if verifyTimeNotZero { - if a.currentGlobalSegment.startTimestamp == 0 { - t.Error("bad start timestamp. expected no reset but timestamp was reset") - } - if a.currentLocalSegment.startTimestamp == 0 { + if a.currentSegment.startTimestamp == 0 { t.Error("bad start timestamp. expected no reset but timestamp was reset") } - } else if a.currentGlobalSegment.startTimestamp != expectedStart { - t.Errorf("bad start timestamp. expected: %v got: %v", expectedStart, a.currentGlobalSegment.startTimestamp) - } else if a.currentLocalSegment.startTimestamp != expectedStart { - t.Errorf("bad start timestamp. expected: %v got: %v", expectedStart, a.currentLocalSegment.startTimestamp) + } else if a.currentSegment.startTimestamp != expectedStart { + t.Errorf("bad start timestamp. expected: %v got: %v", expectedStart, a.currentSegment.startTimestamp) } } @@ -272,39 +202,28 @@ func ActiveEntitiesEqual(active []*activity.EntityRecord, test []*activity.Entit func (a *ActivityLog) GetStartTimestamp() int64 { a.l.RLock() defer a.l.RUnlock() - if a.currentGlobalSegment.startTimestamp != a.currentLocalSegment.startTimestamp { - return -1 - } - return a.currentGlobalSegment.startTimestamp + return a.currentSegment.startTimestamp } // SetStartTimestamp sets the start timestamp on an activity log func (a *ActivityLog) SetStartTimestamp(timestamp int64) { a.l.Lock() defer a.l.Unlock() - a.currentGlobalSegment.startTimestamp = timestamp - a.currentLocalSegment.startTimestamp = timestamp + a.currentSegment.startTimestamp = timestamp } // GetStoredTokenCountByNamespaceID returns the count of tokens by namespace ID func (a *ActivityLog) GetStoredTokenCountByNamespaceID() map[string]uint64 { a.l.RLock() defer a.l.RUnlock() - return a.currentLocalSegment.tokenCount.CountByNamespaceID + return a.currentSegment.tokenCount.CountByNamespaceID } -// GetGlobalEntitySequenceNumber returns the current entity sequence number -func (a *ActivityLog) GetGlobalEntitySequenceNumber() uint64 { +// GetEntitySequenceNumber returns the current entity sequence number +func (a *ActivityLog) GetEntitySequenceNumber() uint64 { a.l.RLock() defer a.l.RUnlock() - return a.currentGlobalSegment.clientSequenceNumber -} - -// GetLocalEntitySequenceNumber returns the current entity sequence number -func (a *ActivityLog) GetLocalEntitySequenceNumber() uint64 { - a.l.RLock() - defer a.l.RUnlock() - return a.currentLocalSegment.clientSequenceNumber + return a.currentSegment.clientSequenceNumber } // SetEnable sets the enabled flag on the activity log @@ -328,45 +247,3 @@ func (a *ActivityLog) GetEnabled() bool { func (c *Core) GetActivityLog() *ActivityLog { return c.activityLog } - -func (c *Core) GetActiveGlobalFragment() *activity.LogFragment { - c.activityLog.globalFragmentLock.RLock() - defer c.activityLog.globalFragmentLock.RUnlock() - return c.activityLog.currentGlobalFragment -} - -func (c *Core) GetSecondaryGlobalFragments() []*activity.LogFragment { - c.activityLog.globalFragmentLock.RLock() - defer c.activityLog.globalFragmentLock.RUnlock() - return c.activityLog.secondaryGlobalClientFragments -} - -func (c *Core) GetActiveLocalFragment() *activity.LogFragment { - c.activityLog.localFragmentLock.RLock() - defer c.activityLog.localFragmentLock.RUnlock() - return c.activityLog.localFragment -} - -// StoreCurrentSegment is a test only method to create and store -// segments from fragments. This allows createCurrentSegmentFromFragments to remain -// private -func (c *Core) StoreCurrentSegment(ctx context.Context, fragments []*activity.LogFragment, currentSegment *segmentInfo, force bool, storagePathPrefix string) error { - return c.activityLog.createCurrentSegmentFromFragments(ctx, fragments, currentSegment, force, storagePathPrefix) -} - -// DeleteLogsAtPath is test helper function deletes all logs at the given path -func (c *Core) DeleteLogsAtPath(ctx context.Context, t *testing.T, storagePath string, startTime int64) { - basePath := storagePath + fmt.Sprint(startTime) + "/" - a := c.activityLog - segments, err := a.view.List(ctx, basePath) - if err != nil { - t.Fatalf("could not list path %v", err) - return - } - for _, p := range segments { - err = a.view.Delete(ctx, basePath+p) - if err != nil { - t.Fatalf("could not delete path %v", err) - } - } -} diff --git a/vault/activity_log_util_common.go b/vault/activity_log_util_common.go index f3cd616ed99a..3e71ee8cc0ac 100644 --- a/vault/activity_log_util_common.go +++ b/vault/activity_log_util_common.go @@ -424,32 +424,26 @@ type singleTypeSegmentReader struct { a *ActivityLog } type segmentReader struct { - tokens *singleTypeSegmentReader - globalEntities *singleTypeSegmentReader - localEntities *singleTypeSegmentReader + tokens *singleTypeSegmentReader + entities *singleTypeSegmentReader } // SegmentReader is an interface that provides methods to read tokens and entities in order type SegmentReader interface { ReadToken(ctx context.Context) (*activity.TokenCount, error) - ReadGlobalEntity(ctx context.Context) (*activity.EntityActivityLog, error) - ReadLocalEntity(ctx context.Context) (*activity.EntityActivityLog, error) + ReadEntity(ctx context.Context) (*activity.EntityActivityLog, error) } func (a *ActivityLog) NewSegmentFileReader(ctx context.Context, startTime time.Time) (SegmentReader, error) { - globalEntities, err := a.newSingleTypeSegmentReader(ctx, startTime, activityGlobalPathPrefix+activityEntityBasePath) + entities, err := a.newSingleTypeSegmentReader(ctx, startTime, activityEntityBasePath) if err != nil { return nil, err } - localEntities, err := a.newSingleTypeSegmentReader(ctx, startTime, activityLocalPathPrefix+activityEntityBasePath) + tokens, err := a.newSingleTypeSegmentReader(ctx, startTime, activityTokenBasePath) if err != nil { return nil, err } - tokens, err := a.newSingleTypeSegmentReader(ctx, startTime, activityTokenLocalBasePath) - if err != nil { - return nil, err - } - return &segmentReader{globalEntities: globalEntities, localEntities: localEntities, tokens: tokens}, nil + return &segmentReader{entities: entities, tokens: tokens}, nil } func (a *ActivityLog) newSingleTypeSegmentReader(ctx context.Context, startTime time.Time, prefix string) (*singleTypeSegmentReader, error) { @@ -504,22 +498,11 @@ func (e *segmentReader) ReadToken(ctx context.Context) (*activity.TokenCount, er return out, nil } -// ReadGlobalEntity reads a global entity from the global segment -// If there is none available, then the error will be io.EOF -func (e *segmentReader) ReadGlobalEntity(ctx context.Context) (*activity.EntityActivityLog, error) { - out := &activity.EntityActivityLog{} - err := e.globalEntities.nextValue(ctx, out) - if err != nil { - return nil, err - } - return out, nil -} - -// ReadLocalEntity reads a local entity from the local segment +// ReadEntity reads an entity from the segment // If there is none available, then the error will be io.EOF -func (e *segmentReader) ReadLocalEntity(ctx context.Context) (*activity.EntityActivityLog, error) { +func (e *segmentReader) ReadEntity(ctx context.Context) (*activity.EntityActivityLog, error) { out := &activity.EntityActivityLog{} - err := e.localEntities.nextValue(ctx, out) + err := e.entities.nextValue(ctx, out) if err != nil { return nil, err } diff --git a/vault/activity_log_util_common_test.go b/vault/activity_log_util_common_test.go index f84775da3fc2..48a3e8dea43b 100644 --- a/vault/activity_log_util_common_test.go +++ b/vault/activity_log_util_common_test.go @@ -990,20 +990,12 @@ func Test_ActivityLog_ComputeCurrentMonth_NamespaceMounts(t *testing.T) { } } -// writeGlobalEntitySegment writes a single global segment file with the given time and index for an entity -func writeGlobalEntitySegment(t *testing.T, core *Core, ts time.Time, index int, item *activity.EntityActivityLog) { +// writeEntitySegment writes a single segment file with the given time and index for an entity +func writeEntitySegment(t *testing.T, core *Core, ts time.Time, index int, item *activity.EntityActivityLog) { t.Helper() protoItem, err := proto.Marshal(item) require.NoError(t, err) - WriteToStorage(t, core, makeSegmentPath(t, activityGlobalPathPrefix+activityEntityBasePath, ts, index), protoItem) -} - -// writeLocalEntitySegment writes a single local segment file with the given time and index for an entity -func writeLocalEntitySegment(t *testing.T, core *Core, ts time.Time, index int, item *activity.EntityActivityLog) { - t.Helper() - protoItem, err := proto.Marshal(item) - require.NoError(t, err) - WriteToStorage(t, core, makeSegmentPath(t, activityLocalPathPrefix+activityEntityBasePath, ts, index), protoItem) + WriteToStorage(t, core, makeSegmentPath(t, activityEntityBasePath, ts, index), protoItem) } // writeTokenSegment writes a single segment file with the given time and index for a token @@ -1011,7 +1003,7 @@ func writeTokenSegment(t *testing.T, core *Core, ts time.Time, index int, item * t.Helper() protoItem, err := proto.Marshal(item) require.NoError(t, err) - WriteToStorage(t, core, makeSegmentPath(t, activityTokenLocalBasePath, ts, index), protoItem) + WriteToStorage(t, core, makeSegmentPath(t, activityTokenBasePath, ts, index), protoItem) } // makeSegmentPath formats the path for a segment at a particular time and index @@ -1028,9 +1020,8 @@ func TestSegmentFileReader_BadData(t *testing.T) { now := time.Now() // write bad data that won't be able to be unmarshaled at index 0 - WriteToStorage(t, core, makeSegmentPath(t, activityTokenLocalBasePath, now, 0), []byte("fake data")) - WriteToStorage(t, core, makeSegmentPath(t, activityGlobalPathPrefix+activityEntityBasePath, now, 0), []byte("fake data")) - WriteToStorage(t, core, makeSegmentPath(t, activityLocalPathPrefix+activityEntityBasePath, now, 0), []byte("fake data")) + WriteToStorage(t, core, makeSegmentPath(t, activityTokenBasePath, now, 0), []byte("fake data")) + WriteToStorage(t, core, makeSegmentPath(t, activityEntityBasePath, now, 0), []byte("fake data")) // write entity at index 1 entity := &activity.EntityActivityLog{Clients: []*activity.EntityRecord{ @@ -1038,11 +1029,7 @@ func TestSegmentFileReader_BadData(t *testing.T) { ClientID: "id", }, }} - // write global data at index 1 - writeGlobalEntitySegment(t, core, now, 1, entity) - - // write local data at index 1 - writeLocalEntitySegment(t, core, now, 1, entity) + writeEntitySegment(t, core, now, 1, entity) // write token at index 1 token := &activity.TokenCount{CountByNamespaceID: map[string]uint64{ @@ -1052,28 +1039,17 @@ func TestSegmentFileReader_BadData(t *testing.T) { reader, err := core.activityLog.NewSegmentFileReader(context.Background(), now) require.NoError(t, err) - // first the bad global entity is read, which returns an error - _, err = reader.ReadGlobalEntity(context.Background()) - require.Error(t, err) - - // then, the reader can read the good entity at index 1 - gotEntity, err := reader.ReadGlobalEntity(context.Background()) - require.True(t, proto.Equal(gotEntity, entity)) - require.Nil(t, err) - - // first the bad local entity is read, which returns an error - _, err = reader.ReadLocalEntity(context.Background()) + // first the bad entity is read, which returns an error + _, err = reader.ReadEntity(context.Background()) require.Error(t, err) - // then, the reader can read the good entity at index 1 - gotEntity, err = reader.ReadLocalEntity(context.Background()) + gotEntity, err := reader.ReadEntity(context.Background()) require.True(t, proto.Equal(gotEntity, entity)) require.Nil(t, err) // the bad token causes an error _, err = reader.ReadToken(context.Background()) require.Error(t, err) - // but the good token is able to be read gotToken, err := reader.ReadToken(context.Background()) require.True(t, proto.Equal(gotToken, token)) @@ -1087,8 +1063,9 @@ func TestSegmentFileReader_MissingData(t *testing.T) { now := time.Now() // write entities and tokens at indexes 0, 1, 2 for i := 0; i < 3; i++ { - WriteToStorage(t, core, makeSegmentPath(t, activityTokenLocalBasePath, now, i), []byte("fake data")) - WriteToStorage(t, core, makeSegmentPath(t, activityGlobalPathPrefix+activityEntityBasePath, now, i), []byte("fake data")) + WriteToStorage(t, core, makeSegmentPath(t, activityTokenBasePath, now, i), []byte("fake data")) + WriteToStorage(t, core, makeSegmentPath(t, activityEntityBasePath, now, i), []byte("fake data")) + } // write entity at index 3 entity := &activity.EntityActivityLog{Clients: []*activity.EntityRecord{ @@ -1096,13 +1073,7 @@ func TestSegmentFileReader_MissingData(t *testing.T) { ClientID: "id", }, }} - - // write global entity at index 3 - writeGlobalEntitySegment(t, core, now, 3, entity) - - // write local entity at index 3 - writeLocalEntitySegment(t, core, now, 3, entity) - + writeEntitySegment(t, core, now, 3, entity) // write token at index 3 token := &activity.TokenCount{CountByNamespaceID: map[string]uint64{ "ns": 1, @@ -1113,28 +1084,21 @@ func TestSegmentFileReader_MissingData(t *testing.T) { // delete the indexes 0, 1, 2 for i := 0; i < 3; i++ { - require.NoError(t, core.barrier.Delete(context.Background(), makeSegmentPath(t, activityTokenLocalBasePath, now, i))) - require.NoError(t, core.barrier.Delete(context.Background(), makeSegmentPath(t, activityGlobalPathPrefix+activityEntityBasePath, now, i))) - require.NoError(t, core.barrier.Delete(context.Background(), makeSegmentPath(t, activityLocalPathPrefix+activityEntityBasePath, now, i))) + require.NoError(t, core.barrier.Delete(context.Background(), makeSegmentPath(t, activityTokenBasePath, now, i))) + require.NoError(t, core.barrier.Delete(context.Background(), makeSegmentPath(t, activityEntityBasePath, now, i))) } // we expect the reader to only return the data at index 3, and then be done - gotToken, err := reader.ReadToken(context.Background()) - require.NoError(t, err) - require.True(t, proto.Equal(gotToken, token)) - _, err = reader.ReadToken(context.Background()) - require.Equal(t, err, io.EOF) - - gotEntity, err := reader.ReadGlobalEntity(context.Background()) + gotEntity, err := reader.ReadEntity(context.Background()) require.NoError(t, err) require.True(t, proto.Equal(gotEntity, entity)) - _, err = reader.ReadGlobalEntity(context.Background()) + _, err = reader.ReadEntity(context.Background()) require.Equal(t, err, io.EOF) - gotEntity, err = reader.ReadLocalEntity(context.Background()) + gotToken, err := reader.ReadToken(context.Background()) require.NoError(t, err) - require.True(t, proto.Equal(gotEntity, entity)) - _, err = reader.ReadLocalEntity(context.Background()) + require.True(t, proto.Equal(gotToken, token)) + _, err = reader.ReadToken(context.Background()) require.Equal(t, err, io.EOF) } @@ -1144,7 +1108,7 @@ func TestSegmentFileReader_NoData(t *testing.T) { now := time.Now() reader, err := core.activityLog.NewSegmentFileReader(context.Background(), now) require.NoError(t, err) - entity, err := reader.ReadGlobalEntity(context.Background()) + entity, err := reader.ReadEntity(context.Background()) require.Nil(t, entity) require.Equal(t, err, io.EOF) token, err := reader.ReadToken(context.Background()) @@ -1170,8 +1134,7 @@ func TestSegmentFileReader(t *testing.T) { token := &activity.TokenCount{CountByNamespaceID: map[string]uint64{ fmt.Sprintf("ns-%d", i): uint64(i), }} - writeGlobalEntitySegment(t, core, now, i, entity) - writeLocalEntitySegment(t, core, now, i, entity) + writeEntitySegment(t, core, now, i, entity) writeTokenSegment(t, core, now, i, token) entities = append(entities, entity) tokens = append(tokens, token) @@ -1180,20 +1143,13 @@ func TestSegmentFileReader(t *testing.T) { reader, err := core.activityLog.NewSegmentFileReader(context.Background(), now) require.NoError(t, err) - gotGlobalEntities := make([]*activity.EntityActivityLog, 0, 3) - gotLocalEntities := make([]*activity.EntityActivityLog, 0, 3) + gotEntities := make([]*activity.EntityActivityLog, 0, 3) gotTokens := make([]*activity.TokenCount, 0, 3) - // read the global entities from the reader - for entity, err := reader.ReadGlobalEntity(context.Background()); !errors.Is(err, io.EOF); entity, err = reader.ReadGlobalEntity(context.Background()) { - require.NoError(t, err) - gotGlobalEntities = append(gotGlobalEntities, entity) - } - - // read the local entities from the reader - for entity, err := reader.ReadLocalEntity(context.Background()); !errors.Is(err, io.EOF); entity, err = reader.ReadLocalEntity(context.Background()) { + // read the entities from the reader + for entity, err := reader.ReadEntity(context.Background()); !errors.Is(err, io.EOF); entity, err = reader.ReadEntity(context.Background()) { require.NoError(t, err) - gotLocalEntities = append(gotLocalEntities, entity) + gotEntities = append(gotEntities, entity) } // read the tokens from the reader @@ -1201,15 +1157,13 @@ func TestSegmentFileReader(t *testing.T) { require.NoError(t, err) gotTokens = append(gotTokens, token) } - require.Len(t, gotGlobalEntities, 3) - require.Len(t, gotLocalEntities, 3) + require.Len(t, gotEntities, 3) require.Len(t, gotTokens, 3) // verify that the entities and tokens we got from the reader are correct // we can't use require.Equals() here because there are protobuf differences in unexported fields for i := 0; i < 3; i++ { - require.True(t, proto.Equal(gotGlobalEntities[i], entities[i])) - require.True(t, proto.Equal(gotLocalEntities[i], entities[i])) + require.True(t, proto.Equal(gotEntities[i], entities[i])) require.True(t, proto.Equal(gotTokens[i], tokens[i])) } } diff --git a/vault/barrier_aes_gcm.go b/vault/barrier_aes_gcm.go index 1144c7e60f26..e75b7a78a8e2 100644 --- a/vault/barrier_aes_gcm.go +++ b/vault/barrier_aes_gcm.go @@ -621,6 +621,11 @@ func (b *AESGCMBarrier) Rotate(ctx context.Context, randomSource io.Reader) (uin term := b.keyring.ActiveTerm() newTerm := term + 1 + if newTerm < term { + // We've rolled over the uint32, don't allow this + return 0, errors.New("failed to generate a new term value due to integer overflow") + } + // Add a new encryption key newKeyring, err := b.keyring.AddKey(&Key{ Term: newTerm, diff --git a/vault/barrier_aes_gcm_test.go b/vault/barrier_aes_gcm_test.go index 1268bf006c61..77c5fee7e0de 100644 --- a/vault/barrier_aes_gcm_test.go +++ b/vault/barrier_aes_gcm_test.go @@ -8,6 +8,8 @@ import ( "context" "crypto/rand" "encoding/json" + "math" + "strings" "testing" "time" @@ -697,6 +699,45 @@ func TestBarrier_LegacyRotate(t *testing.T) { } } +// TestBarrier_RotateFailsOnOverflow validates that if we ever actually hit the +// barrier key rotation limit, we fail the rotation with an error. +func TestBarrier_RotateFailsOnOverflow(t *testing.T) { + inm, err := inmem.NewInmem(nil, logger) + if err != nil { + t.Fatalf("err: %v", err) + } + b, err := NewAESGCMBarrier(inm, false) + if err != nil { + t.Fatalf("err: %v", err) + } + key, err := b.GenerateKey(rand.Reader) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Initialize the barrier + ctx := context.Background() + err = b.Initialize(ctx, key, nil, rand.Reader) + if err != nil { + t.Fatalf("err: %v", err) + } + err = b.Unseal(ctx, key) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Hack to avoid generating a lot of keys... + b.keyring.activeTerm = math.MaxUint32 + + _, err = b.Rotate(ctx, rand.Reader) + if err == nil { + t.Fatalf("Rotate should fail on overflow but did not") + } + if !strings.Contains(err.Error(), "integer overflow") { + t.Fatalf("Rotate failed but not for the expected reason of integer overflow: %v", err) + } +} + // TestBarrier_persistKeyring_Context checks that we get the right errors if // the context is cancelled or times-out before the first part of persistKeyring // is able to persist the keyring itself (i.e. we don't go on to try and persist diff --git a/vault/core.go b/vault/core.go index 967e235552e9..bdae94d8238f 100644 --- a/vault/core.go +++ b/vault/core.go @@ -422,6 +422,9 @@ type Core struct { // renewal, expiration and revocation expiration *ExpirationManager + // the rotation manager handles periodic rotation of credentials + rotationManager *RotationManager + // rollback manager is used to run rollbacks periodically rollback *RollbackManager @@ -2612,6 +2615,9 @@ func buildUnsealSetupFunctionSlice(c *Core) []func(context.Context) error { setupFunctions = append(setupFunctions, func(_ context.Context) error { return c.setupExpiration(expireLeaseStrategyFairsharing) }) + setupFunctions = append(setupFunctions, func(_ context.Context) error { + return c.startRotation() + }) setupFunctions = append(setupFunctions, c.loadAudits) setupFunctions = append(setupFunctions, c.setupAuditedHeadersConfig) setupFunctions = append(setupFunctions, c.setupAudits) @@ -2910,6 +2916,9 @@ func (c *Core) preSeal() error { if err := c.stopExpiration(); err != nil { result = multierror.Append(result, fmt.Errorf("error stopping expiration: %w", err)) } + if err := c.stopRotation(); err != nil { + result = multierror.Append(result, fmt.Errorf("error stopping rotation: %w", err)) + } if err := c.teardownCredentials(context.Background()); err != nil { result = multierror.Append(result, fmt.Errorf("error tearing down credentials: %w", err)) } diff --git a/vault/core_test.go b/vault/core_test.go index 1681d2077510..d14052c6375c 100644 --- a/vault/core_test.go +++ b/vault/core_test.go @@ -3664,7 +3664,7 @@ func TestBuildUnsealSetupFunctionSlice(t *testing.T) { core: &Core{ replicationState: uint32Ptr(uint32(0)), }, - expectedLength: 25, + expectedLength: 26, }, { name: "dr secondary core", diff --git a/vault/diagnose/tls_verification_test.go b/vault/diagnose/tls_verification_test.go index 769330fb776d..9a7640fba1d0 100644 --- a/vault/diagnose/tls_verification_test.go +++ b/vault/diagnose/tls_verification_test.go @@ -14,6 +14,7 @@ import ( pkihelper "github.com/hashicorp/vault/helper/testhelpers/pki" "github.com/hashicorp/vault/internalshared/configutil" + "github.com/stretchr/testify/require" ) // TestTLSValidCert is the positive test case to show that specifying a valid cert and key @@ -124,13 +125,14 @@ func TestTLSExpiredCert(t *testing.T) { // TestTLSMismatchedCryptographicInfo verifies that a cert and key of differing cryptographic // types, when specified together, is met with a unique error message. func TestTLSMismatchedCryptographicInfo(t *testing.T) { + testCaFiles := pkihelper.GenerateCertWithRoot(t) listeners := []*configutil.Listener{ { Type: "tcp", Address: "127.0.0.1:443", ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", - TLSKeyFile: "./test-fixtures/ecdsa.key", + TLSCertFile: testCaFiles.Leaf.CertFile, + TLSKeyFile: "./test-fixtures/goodkey.pem", // pkihelper uses EC keys, this file is an RSA key TLSMinVersion: "tls10", TLSDisableClientCerts: true, }, @@ -148,7 +150,7 @@ func TestTLSMismatchedCryptographicInfo(t *testing.T) { Type: "tcp", Address: "127.0.0.1:443", ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./test-fixtures/ecdsa.crt", + TLSCertFile: testCaFiles.Leaf.CertFile, TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", TLSMinVersion: "tls10", @@ -189,13 +191,15 @@ func TestTLSMultiKeys(t *testing.T) { // TestTLSCertAsKey verifies that a unique error message is thrown when a cert is specified twice. func TestTLSCertAsKey(t *testing.T) { + testCaFiles := pkihelper.GenerateCertWithRoot(t) + listeners := []*configutil.Listener{ { Type: "tcp", Address: "127.0.0.1:443", ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", - TLSKeyFile: "./../../api/test-fixtures/keys/cert.pem", + TLSCertFile: testCaFiles.Leaf.CertFile, + TLSKeyFile: testCaFiles.Leaf.CertFile, TLSMinVersion: "tls10", TLSDisableClientCerts: true, }, @@ -213,13 +217,21 @@ func TestTLSCertAsKey(t *testing.T) { // the root. The root certificate used in this test is the Baltimore Cyber Trust root // certificate, downloaded from: https://www.digicert.com/kb/digicert-root-certificates.htm func TestTLSInvalidRoot(t *testing.T) { + testCaFiles := pkihelper.GenerateCertWithRoot(t) + otherRoot := pkihelper.GenerateRootCa(t) + + tempDir := t.TempDir() + mixedRoots := filepath.Join(tempDir, "leaf-with-bad-root.pem") + err := os.WriteFile(mixedRoots, append(pem.EncodeToMemory(testCaFiles.Leaf.CertPem), pem.EncodeToMemory(otherRoot.CertPem)...), 0o644) + require.NoError(t, err, "Failed to write file %s", mixedRoots) + listeners := []*configutil.Listener{ { Type: "tcp", Address: "127.0.0.1:443", ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./test-fixtures/goodcertbadroot.pem", - TLSKeyFile: "./test-fixtures/goodkey.pem", + TLSCertFile: mixedRoots, + TLSKeyFile: testCaFiles.Leaf.KeyFile, TLSMinVersion: "tls10", TLSDisableClientCerts: true, }, @@ -237,13 +249,15 @@ func TestTLSInvalidRoot(t *testing.T) { // is still accepted by diagnose as valid. This is an acceptable, though less secure, // server configuration. func TestTLSNoRoot(t *testing.T) { + testCaFiles := pkihelper.GenerateCertWithRoot(t) + listeners := []*configutil.Listener{ { Type: "tcp", Address: "127.0.0.1:443", ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", - TLSKeyFile: "./test-fixtures/goodkey.pem", + TLSCertFile: testCaFiles.Leaf.CertFile, + TLSKeyFile: testCaFiles.Leaf.KeyFile, TLSMinVersion: "tls10", TLSDisableClientCerts: true, }, @@ -258,14 +272,16 @@ func TestTLSNoRoot(t *testing.T) { // TestTLSInvalidMinVersion checks that a listener with an invalid minimum configured // version errors appropriately. func TestTLSInvalidMinVersion(t *testing.T) { + testCaFiles := pkihelper.GenerateCertWithRoot(t) + listeners := []*configutil.Listener{ { Type: "tcp", Address: "127.0.0.1:443", ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", - TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", - TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", + TLSCertFile: testCaFiles.Leaf.CertFile, + TLSKeyFile: testCaFiles.Leaf.KeyFile, + TLSClientCAFile: testCaFiles.RootCa.CertFile, TLSMinVersion: "0", TLSDisableClientCerts: true, }, @@ -282,14 +298,16 @@ func TestTLSInvalidMinVersion(t *testing.T) { // TestTLSInvalidMaxVersion checks that a listener with an invalid maximum configured // version errors appropriately. func TestTLSInvalidMaxVersion(t *testing.T) { + testCaFiles := pkihelper.GenerateCertWithRoot(t) + listeners := []*configutil.Listener{ { Type: "tcp", Address: "127.0.0.1:443", ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", - TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", - TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", + TLSCertFile: testCaFiles.Leaf.CertFile, + TLSKeyFile: testCaFiles.Leaf.KeyFile, + TLSClientCAFile: testCaFiles.RootCa.CertFile, TLSMaxVersion: "0", TLSDisableClientCerts: true, }, @@ -549,13 +567,15 @@ func TestTLSMultipleRootInClientCACert(t *testing.T) { // TestTLSSelfSignedCerts tests invalid self-signed cert as TLSClientCAFile func TestTLSSelfSignedCert(t *testing.T) { + testCaFiles := pkihelper.GenerateCertWithRoot(t) + listeners := []*configutil.Listener{ { Type: "tcp", Address: "127.0.0.1:443", ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", - TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSCertFile: testCaFiles.Leaf.CertFile, + TLSKeyFile: testCaFiles.Leaf.KeyFile, TLSClientCAFile: "test-fixtures/selfSignedCert.pem", TLSMinVersion: "tls10", TLSRequireAndVerifyClientCert: true, diff --git a/vault/dynamic_system_view.go b/vault/dynamic_system_view.go index 3c161ec5abc8..d24c0310ba6e 100644 --- a/vault/dynamic_system_view.go +++ b/vault/dynamic_system_view.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/vault/sdk/helper/pluginutil" "github.com/hashicorp/vault/sdk/helper/wrapping" "github.com/hashicorp/vault/sdk/logical" + "github.com/hashicorp/vault/sdk/rotation" "github.com/hashicorp/vault/vault/plugincatalog" "github.com/hashicorp/vault/version" "google.golang.org/protobuf/types/known/timestamppb" @@ -487,3 +488,27 @@ func (d dynamicSystemView) GenerateIdentityToken(ctx context.Context, req *plugi TTL: ttl, }, nil } + +func (d dynamicSystemView) RegisterRotationJob(ctx context.Context, job *rotation.RotationJob) (string, error) { + mountEntry := d.mountEntry + if mountEntry == nil { + return "", fmt.Errorf("no mount entry") + } + ns := mountEntry.Namespace() + path := job.Path + if ns != namespace.RootNamespace { + path = ns.Path + "/" + path + } + nsCtx := namespace.ContextWithNamespace(ctx, mountEntry.Namespace()) + id, err := d.core.RegisterRotationJob(nsCtx, path, job) + if err != nil { + return "", fmt.Errorf("error registering rotation job: %s", err) + } + + job.RotationID = id + return id, nil +} + +func (d dynamicSystemView) DeregisterRotationJob(_ context.Context, rotationID string) (err error) { + return d.core.DeregisterRotationJob(rotationID) +} diff --git a/vault/external_tests/activity_testonly/acme_regeneration_test.go b/vault/external_tests/activity_testonly/acme_regeneration_test.go index 5d70dc0c21c5..dbd8355f81a5 100644 --- a/vault/external_tests/activity_testonly/acme_regeneration_test.go +++ b/vault/external_tests/activity_testonly/acme_regeneration_test.go @@ -54,7 +54,7 @@ func TestACMERegeneration_RegenerateWithCurrentMonth(t *testing.T) { }) require.NoError(t, err) now := time.Now().UTC() - _, _, err = clientcountutil.NewActivityLogData(client). + _, err = clientcountutil.NewActivityLogData(client). NewPreviousMonthData(3). // 3 months ago, 15 non-entity clients and 10 ACME clients NewClientsSeen(15, clientcountutil.WithClientType("non-entity-token")). @@ -116,7 +116,7 @@ func TestACMERegeneration_RegenerateMuchOlder(t *testing.T) { client := cluster.Cores[0].Client now := time.Now().UTC() - _, _, err := clientcountutil.NewActivityLogData(client). + _, err := clientcountutil.NewActivityLogData(client). NewPreviousMonthData(5). // 5 months ago, 15 non-entity clients and 10 ACME clients NewClientsSeen(15, clientcountutil.WithClientType("non-entity-token")). @@ -159,7 +159,7 @@ func TestACMERegeneration_RegeneratePreviousMonths(t *testing.T) { client := cluster.Cores[0].Client now := time.Now().UTC() - _, _, err := clientcountutil.NewActivityLogData(client). + _, err := clientcountutil.NewActivityLogData(client). NewPreviousMonthData(3). // 3 months ago, 15 non-entity clients and 10 ACME clients NewClientsSeen(15, clientcountutil.WithClientType("non-entity-token")). diff --git a/vault/external_tests/activity_testonly/activity_testonly_oss_test.go b/vault/external_tests/activity_testonly/activity_testonly_oss_test.go index c5463bb801d2..dbb11c845332 100644 --- a/vault/external_tests/activity_testonly/activity_testonly_oss_test.go +++ b/vault/external_tests/activity_testonly/activity_testonly_oss_test.go @@ -29,7 +29,7 @@ func Test_ActivityLog_Disable(t *testing.T) { "enabled": "enable", }) require.NoError(t, err) - _, _, err = clientcountutil.NewActivityLogData(client). + _, err = clientcountutil.NewActivityLogData(client). NewPreviousMonthData(1). NewClientsSeen(5). NewCurrentMonthData(). diff --git a/vault/external_tests/activity_testonly/activity_testonly_test.go b/vault/external_tests/activity_testonly/activity_testonly_test.go index cd9dfb21574b..8141357efe70 100644 --- a/vault/external_tests/activity_testonly/activity_testonly_test.go +++ b/vault/external_tests/activity_testonly/activity_testonly_test.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 -////go:build testonly +//go:build testonly package activity_testonly @@ -86,7 +86,7 @@ func Test_ActivityLog_LoseLeadership(t *testing.T) { }) require.NoError(t, err) - _, _, err = clientcountutil.NewActivityLogData(client). + _, err = clientcountutil.NewActivityLogData(client). NewCurrentMonthData(). NewClientsSeen(10). Write(context.Background(), generation.WriteOptions_WRITE_ENTITIES) @@ -121,7 +121,7 @@ func Test_ActivityLog_ClientsOverlapping(t *testing.T) { "enabled": "enable", }) require.NoError(t, err) - _, _, err = clientcountutil.NewActivityLogData(client). + _, err = clientcountutil.NewActivityLogData(client). NewPreviousMonthData(1). NewClientsSeen(7). NewCurrentMonthData(). @@ -169,7 +169,7 @@ func Test_ActivityLog_ClientsNewCurrentMonth(t *testing.T) { "enabled": "enable", }) require.NoError(t, err) - _, _, err = clientcountutil.NewActivityLogData(client). + _, err = clientcountutil.NewActivityLogData(client). NewPreviousMonthData(1). NewClientsSeen(5). NewCurrentMonthData(). @@ -203,7 +203,7 @@ func Test_ActivityLog_EmptyDataMonths(t *testing.T) { "enabled": "enable", }) require.NoError(t, err) - _, _, err = clientcountutil.NewActivityLogData(client). + _, err = clientcountutil.NewActivityLogData(client). NewCurrentMonthData(). NewClientsSeen(10). Write(context.Background(), generation.WriteOptions_WRITE_PRECOMPUTED_QUERIES, generation.WriteOptions_WRITE_ENTITIES) @@ -243,7 +243,7 @@ func Test_ActivityLog_FutureEndDate(t *testing.T) { "enabled": "enable", }) require.NoError(t, err) - _, _, err = clientcountutil.NewActivityLogData(client). + _, err = clientcountutil.NewActivityLogData(client). NewPreviousMonthData(1). NewClientsSeen(10). NewCurrentMonthData(). @@ -316,7 +316,7 @@ func Test_ActivityLog_ClientTypeResponse(t *testing.T) { _, err := client.Logical().Write("sys/internal/counters/config", map[string]interface{}{ "enabled": "enable", }) - _, _, err = clientcountutil.NewActivityLogData(client). + _, err = clientcountutil.NewActivityLogData(client). NewCurrentMonthData(). NewClientsSeen(10, clientcountutil.WithClientType(tc.clientType)). Write(context.Background(), generation.WriteOptions_WRITE_ENTITIES) @@ -369,7 +369,7 @@ func Test_ActivityLogCurrentMonth_Response(t *testing.T) { _, err := client.Logical().Write("sys/internal/counters/config", map[string]interface{}{ "enabled": "enable", }) - _, _, err = clientcountutil.NewActivityLogData(client). + _, err = clientcountutil.NewActivityLogData(client). NewCurrentMonthData(). NewClientsSeen(10, clientcountutil.WithClientType(tc.clientType)). Write(context.Background(), generation.WriteOptions_WRITE_ENTITIES) @@ -420,7 +420,7 @@ func Test_ActivityLog_Deduplication(t *testing.T) { _, err := client.Logical().Write("sys/internal/counters/config", map[string]interface{}{ "enabled": "enable", }) - _, _, err = clientcountutil.NewActivityLogData(client). + _, err = clientcountutil.NewActivityLogData(client). NewPreviousMonthData(3). NewClientsSeen(10, clientcountutil.WithClientType(tc.clientType)). NewPreviousMonthData(2). @@ -462,7 +462,7 @@ func Test_ActivityLog_MountDeduplication(t *testing.T) { require.NoError(t, err) now := time.Now().UTC() - localPaths, globalPaths, err := clientcountutil.NewActivityLogData(client). + _, err = clientcountutil.NewActivityLogData(client). NewPreviousMonthData(1). NewClientSeen(clientcountutil.WithClientMount("sys")). NewClientSeen(clientcountutil.WithClientMount("secret")). @@ -473,10 +473,6 @@ func Test_ActivityLog_MountDeduplication(t *testing.T) { NewClientSeen(clientcountutil.WithClientMount("sys")). Write(context.Background(), generation.WriteOptions_WRITE_PRECOMPUTED_QUERIES, generation.WriteOptions_WRITE_ENTITIES) require.NoError(t, err) - // cubbyhole is local, 2 segments must exist for 2 months seen - require.Len(t, localPaths, 2) - // 2 global segments must exist for 2 months seen - require.Len(t, globalPaths, 2) resp, err := client.Logical().ReadWithData("sys/internal/counters/activity", map[string][]string{ "end_time": {timeutil.EndOfMonth(now).Format(time.RFC3339)}, @@ -673,7 +669,7 @@ func Test_ActivityLog_Export_Sudo(t *testing.T) { rootToken := client.Token() - _, _, err = clientcountutil.NewActivityLogData(client). + _, err = clientcountutil.NewActivityLogData(client). NewCurrentMonthData(). NewClientsSeen(10). Write(context.Background(), generation.WriteOptions_WRITE_ENTITIES) @@ -849,7 +845,7 @@ func TestHandleQuery_MultipleMounts(t *testing.T) { } // Write all the client count data - _, _, err = activityLogGenerator.Write(context.Background(), generation.WriteOptions_WRITE_PRECOMPUTED_QUERIES, generation.WriteOptions_WRITE_ENTITIES) + _, err = activityLogGenerator.Write(context.Background(), generation.WriteOptions_WRITE_PRECOMPUTED_QUERIES, generation.WriteOptions_WRITE_ENTITIES) require.NoError(t, err) endOfCurrentMonth := timeutil.EndOfMonth(time.Now().UTC()) diff --git a/vault/external_tests/raft/raft_test.go b/vault/external_tests/raft/raft_test.go index b1a28c9c2047..32de80f8c684 100644 --- a/vault/external_tests/raft/raft_test.go +++ b/vault/external_tests/raft/raft_test.go @@ -1378,14 +1378,26 @@ func TestRaftCluster_Removed(t *testing.T) { }) require.NoError(t, err) - _, err = cluster.Cores[0].Client.Logical().Write("/sys/storage/raft/remove-peer", map[string]interface{}{ + leaderClient := cluster.Cores[0].Client + _, err = leaderClient.Logical().Write("/sys/storage/raft/remove-peer", map[string]interface{}{ "server_id": follower.NodeID, }) + require.NoError(t, err) followerClient.SetCheckRedirect(func(request *http.Request, requests []*http.Request) error { require.Fail(t, "request caused a redirect", request.URL.Path) return fmt.Errorf("no redirects allowed") }) - require.NoError(t, err) + configChanged := func() bool { + config, err := leaderClient.Logical().Read("sys/storage/raft/configuration") + require.NoError(t, err) + cfg := config.Data["config"].(map[string]interface{}) + servers := cfg["servers"].([]interface{}) + return len(servers) == 2 + } + // raft config changes happen async, so block until the config change is + // applied + require.Eventually(t, configChanged, 3*time.Second, 50*time.Millisecond) + _, err = followerClient.Logical().Write("secret/foo", map[string]interface{}{ "test": "other_data", }) @@ -1514,8 +1526,7 @@ func TestSysHealth_Raft(t *testing.T) { var erroredResponse *api.Response // now that the node can connect again, it will start getting the removed - // error when trying to connect. The code should be removed, and the ha - // connection will be nil because there is no ha connection + // error when trying to connect. The code should be removed testhelpers.RetryUntil(t, 10*time.Second, func() error { resp, err := followerClient.Logical().ReadRawWithData("sys/health", map[string][]string{ "perfstandbyok": {"true"}, @@ -1536,7 +1547,12 @@ func TestSysHealth_Raft(t *testing.T) { }) r := parseHealthBody(t, erroredResponse) require.True(t, true, *r.RemovedFromCluster) - require.Nil(t, r.HAConnectionHealthy) + // The HA connection health should either be nil or false. It's possible + // for it to be false if we got the response in between the node marking + // itself removed and sealing + if r.HAConnectionHealthy != nil { + require.False(t, *r.HAConnectionHealthy) + } }) } @@ -1555,7 +1571,7 @@ func TestRaftCluster_Removed_ReAdd(t *testing.T) { "server_id": follower.NodeID, }) require.NoError(t, err) - require.Eventually(t, follower.Sealed, 3*time.Second, 250*time.Millisecond) + require.Eventually(t, follower.Sealed, 10*time.Second, 250*time.Millisecond) joinReq := &api.RaftJoinRequest{LeaderAPIAddr: leader.Address.String()} _, err = follower.Client.Sys().RaftJoin(joinReq) diff --git a/vault/external_tests/raftha/raft_ha_test.go b/vault/external_tests/raftha/raft_ha_test.go index 82529859e19a..bd163566157a 100644 --- a/vault/external_tests/raftha/raft_ha_test.go +++ b/vault/external_tests/raftha/raft_ha_test.go @@ -371,7 +371,7 @@ func TestRaftHACluster_Removed_ReAdd(t *testing.T) { "server_id": follower.NodeID, }) require.NoError(t, err) - require.Eventually(t, follower.Sealed, 3*time.Second, 250*time.Millisecond) + require.Eventually(t, follower.Sealed, 10*time.Second, 250*time.Millisecond) _, err = follower.Client.Sys().RaftJoin(joinReq) require.Error(t, err) diff --git a/vault/hcp_link/proto/link_control/link_control.pb.go b/vault/hcp_link/proto/link_control/link_control.pb.go index 952f0b0359a2..179d5ad87bba 100644 --- a/vault/hcp_link/proto/link_control/link_control.pb.go +++ b/vault/hcp_link/proto/link_control/link_control.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: vault/hcp_link/proto/link_control/link_control.proto @@ -24,9 +24,9 @@ const ( ) type PurgePolicyRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *PurgePolicyRequest) Reset() { @@ -60,9 +60,9 @@ func (*PurgePolicyRequest) Descriptor() ([]byte, []int) { } type PurgePolicyResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *PurgePolicyResponse) Reset() { diff --git a/vault/hcp_link/proto/meta/meta.pb.go b/vault/hcp_link/proto/meta/meta.pb.go index 55ed3f7fe8b3..d28ad9546c05 100644 --- a/vault/hcp_link/proto/meta/meta.pb.go +++ b/vault/hcp_link/proto/meta/meta.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: vault/hcp_link/proto/meta/meta.proto @@ -24,9 +24,9 @@ const ( ) type ListNamespacesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ListNamespacesRequest) Reset() { @@ -60,11 +60,10 @@ func (*ListNamespacesRequest) Descriptor() ([]byte, []int) { } type ListNamespacesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Paths []string `protobuf:"bytes,1,rep,name=Paths,proto3" json:"Paths,omitempty"` unknownFields protoimpl.UnknownFields - - Paths []string `protobuf:"bytes,1,rep,name=Paths,proto3" json:"Paths,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListNamespacesResponse) Reset() { @@ -105,9 +104,9 @@ func (x *ListNamespacesResponse) GetPaths() []string { } type ListMountsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ListMountsRequest) Reset() { @@ -141,13 +140,12 @@ func (*ListMountsRequest) Descriptor() ([]byte, []int) { } type Mount struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Path string `protobuf:"bytes,1,opt,name=Path,proto3" json:"Path,omitempty"` + Type string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"` + Description string `protobuf:"bytes,3,opt,name=Description,proto3" json:"Description,omitempty"` unknownFields protoimpl.UnknownFields - - Path string `protobuf:"bytes,1,opt,name=Path,proto3" json:"Path,omitempty"` - Type string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"` - Description string `protobuf:"bytes,3,opt,name=Description,proto3" json:"Description,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Mount) Reset() { @@ -202,11 +200,10 @@ func (x *Mount) GetDescription() string { } type ListMountsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Mounts []*Mount `protobuf:"bytes,1,rep,name=Mounts,proto3" json:"Mounts,omitempty"` unknownFields protoimpl.UnknownFields - - Mounts []*Mount `protobuf:"bytes,1,rep,name=Mounts,proto3" json:"Mounts,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListMountsResponse) Reset() { @@ -247,9 +244,9 @@ func (x *ListMountsResponse) GetMounts() []*Mount { } type ListAuthsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ListAuthsRequest) Reset() { @@ -283,13 +280,12 @@ func (*ListAuthsRequest) Descriptor() ([]byte, []int) { } type Auth struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Path string `protobuf:"bytes,1,opt,name=Path,proto3" json:"Path,omitempty"` + Type string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"` + Description string `protobuf:"bytes,3,opt,name=Description,proto3" json:"Description,omitempty"` unknownFields protoimpl.UnknownFields - - Path string `protobuf:"bytes,1,opt,name=Path,proto3" json:"Path,omitempty"` - Type string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"` - Description string `protobuf:"bytes,3,opt,name=Description,proto3" json:"Description,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Auth) Reset() { @@ -344,11 +340,10 @@ func (x *Auth) GetDescription() string { } type ListAuthResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Auths []*Auth `protobuf:"bytes,1,rep,name=Auths,proto3" json:"Auths,omitempty"` unknownFields protoimpl.UnknownFields - - Auths []*Auth `protobuf:"bytes,1,rep,name=Auths,proto3" json:"Auths,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListAuthResponse) Reset() { @@ -389,9 +384,9 @@ func (x *ListAuthResponse) GetAuths() []*Auth { } type GetClusterStatusRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetClusterStatusRequest) Reset() { @@ -425,11 +420,10 @@ func (*GetClusterStatusRequest) Descriptor() ([]byte, []int) { } type HANode struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Hostname string `protobuf:"bytes,1,opt,name=Hostname,proto3" json:"Hostname,omitempty"` unknownFields protoimpl.UnknownFields - - Hostname string `protobuf:"bytes,1,opt,name=Hostname,proto3" json:"Hostname,omitempty"` + sizeCache protoimpl.SizeCache } func (x *HANode) Reset() { @@ -470,12 +464,11 @@ func (x *HANode) GetHostname() string { } type HAStatus struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Enabled bool `protobuf:"varint,1,opt,name=Enabled,proto3" json:"Enabled,omitempty"` + Nodes []*HANode `protobuf:"bytes,2,rep,name=Nodes,proto3" json:"Nodes,omitempty"` unknownFields protoimpl.UnknownFields - - Enabled bool `protobuf:"varint,1,opt,name=Enabled,proto3" json:"Enabled,omitempty"` - Nodes []*HANode `protobuf:"bytes,2,rep,name=Nodes,proto3" json:"Nodes,omitempty"` + sizeCache protoimpl.SizeCache } func (x *HAStatus) Reset() { @@ -523,10 +516,7 @@ func (x *HAStatus) GetNodes() []*HANode { } type RaftServer struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // NodeID is the name of the server NodeID string `protobuf:"bytes,1,opt,name=NodeID,proto3" json:"NodeID,omitempty"` // Address is the IP:port of the server, used for Raft communications @@ -537,7 +527,9 @@ type RaftServer struct { ProtocolVersion string `protobuf:"bytes,4,opt,name=ProtocolVersion,proto3" json:"ProtocolVersion,omitempty"` // Voter is true if this server has a vote in the cluster. This might // be false if the server is staging and still coming online. - Voter bool `protobuf:"varint,5,opt,name=Voter,proto3" json:"Voter,omitempty"` + Voter bool `protobuf:"varint,5,opt,name=Voter,proto3" json:"Voter,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RaftServer) Reset() { @@ -606,11 +598,10 @@ func (x *RaftServer) GetVoter() bool { } type RaftConfiguration struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Servers []*RaftServer `protobuf:"bytes,1,rep,name=Servers,proto3" json:"Servers,omitempty"` unknownFields protoimpl.UnknownFields - - Servers []*RaftServer `protobuf:"bytes,1,rep,name=Servers,proto3" json:"Servers,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RaftConfiguration) Reset() { @@ -651,12 +642,11 @@ func (x *RaftConfiguration) GetServers() []*RaftServer { } type AutopilotServer struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` + Healthy bool `protobuf:"varint,2,opt,name=Healthy,proto3" json:"Healthy,omitempty"` unknownFields protoimpl.UnknownFields - - ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` - Healthy bool `protobuf:"varint,2,opt,name=Healthy,proto3" json:"Healthy,omitempty"` + sizeCache protoimpl.SizeCache } func (x *AutopilotServer) Reset() { @@ -704,12 +694,11 @@ func (x *AutopilotServer) GetHealthy() bool { } type AutopilotStatus struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Healthy bool `protobuf:"varint,1,opt,name=Healthy,proto3" json:"Healthy,omitempty"` + Servers []*AutopilotServer `protobuf:"bytes,2,rep,name=Servers,proto3" json:"Servers,omitempty"` unknownFields protoimpl.UnknownFields - - Healthy bool `protobuf:"varint,1,opt,name=Healthy,proto3" json:"Healthy,omitempty"` - Servers []*AutopilotServer `protobuf:"bytes,2,rep,name=Servers,proto3" json:"Servers,omitempty"` + sizeCache protoimpl.SizeCache } func (x *AutopilotStatus) Reset() { @@ -757,13 +746,12 @@ func (x *AutopilotStatus) GetServers() []*AutopilotServer { } type RaftStatus struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - RaftConfiguration *RaftConfiguration `protobuf:"bytes,1,opt,name=RaftConfiguration,proto3" json:"RaftConfiguration,omitempty"` - AutopilotStatus *AutopilotStatus `protobuf:"bytes,2,opt,name=AutopilotStatus,proto3" json:"AutopilotStatus,omitempty"` - QuorumWarning string `protobuf:"bytes,3,opt,name=QuorumWarning,proto3" json:"QuorumWarning,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + RaftConfiguration *RaftConfiguration `protobuf:"bytes,1,opt,name=RaftConfiguration,proto3" json:"RaftConfiguration,omitempty"` + AutopilotStatus *AutopilotStatus `protobuf:"bytes,2,opt,name=AutopilotStatus,proto3" json:"AutopilotStatus,omitempty"` + QuorumWarning string `protobuf:"bytes,3,opt,name=QuorumWarning,proto3" json:"QuorumWarning,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RaftStatus) Reset() { @@ -818,15 +806,14 @@ func (x *RaftStatus) GetQuorumWarning() string { } type GetClusterStatusResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ClusterID string `protobuf:"bytes,1,opt,name=ClusterID,proto3" json:"ClusterID,omitempty"` + HAStatus *HAStatus `protobuf:"bytes,2,opt,name=HAStatus,proto3" json:"HAStatus,omitempty"` + RaftStatus *RaftStatus `protobuf:"bytes,3,opt,name=RaftStatus,proto3" json:"RaftStatus,omitempty"` + StorageType string `protobuf:"bytes,4,opt,name=StorageType,proto3" json:"StorageType,omitempty"` + ClusterName string `protobuf:"bytes,5,opt,name=ClusterName,proto3" json:"ClusterName,omitempty"` unknownFields protoimpl.UnknownFields - - ClusterID string `protobuf:"bytes,1,opt,name=ClusterID,proto3" json:"ClusterID,omitempty"` - HAStatus *HAStatus `protobuf:"bytes,2,opt,name=HAStatus,proto3" json:"HAStatus,omitempty"` - RaftStatus *RaftStatus `protobuf:"bytes,3,opt,name=RaftStatus,proto3" json:"RaftStatus,omitempty"` - StorageType string `protobuf:"bytes,4,opt,name=StorageType,proto3" json:"StorageType,omitempty"` - ClusterName string `protobuf:"bytes,5,opt,name=ClusterName,proto3" json:"ClusterName,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetClusterStatusResponse) Reset() { diff --git a/vault/hcp_link/proto/node_status/status.pb.go b/vault/hcp_link/proto/node_status/status.pb.go index 1b275364c4a4..58929533da06 100644 --- a/vault/hcp_link/proto/node_status/status.pb.go +++ b/vault/hcp_link/proto/node_status/status.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: vault/hcp_link/proto/node_status/status.proto @@ -84,11 +84,10 @@ func (LogLevel) EnumDescriptor() ([]byte, []int) { } type RaftStatus struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + IsVoter bool `protobuf:"varint,1,opt,name=IsVoter,proto3" json:"IsVoter,omitempty"` unknownFields protoimpl.UnknownFields - - IsVoter bool `protobuf:"varint,1,opt,name=IsVoter,proto3" json:"IsVoter,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RaftStatus) Reset() { @@ -129,10 +128,7 @@ func (x *RaftStatus) GetIsVoter() bool { } type LinkedClusterNodeStatusResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"` Initialized bool `protobuf:"varint,2,opt,name=Initialized,proto3" json:"Initialized,omitempty"` Sealed bool `protobuf:"varint,3,opt,name=Sealed,proto3" json:"Sealed,omitempty"` @@ -155,6 +151,8 @@ type LinkedClusterNodeStatusResponse struct { LogLevel LogLevel `protobuf:"varint,20,opt,name=LogLevel,proto3,enum=hashicorp.vault.hcp_link.node_status.LogLevel" json:"LogLevel,omitempty"` ActiveTime *timestamppb.Timestamp `protobuf:"bytes,21,opt,name=ActiveTime,proto3" json:"ActiveTime,omitempty"` RaftStatus *RaftStatus `protobuf:"bytes,22,opt,name=RaftStatus,proto3" json:"RaftStatus,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *LinkedClusterNodeStatusResponse) Reset() { diff --git a/vault/logical_system_activity_write_testonly.go b/vault/logical_system_activity_write_testonly.go index 51fe65e61e6d..de52e4de35a8 100644 --- a/vault/logical_system_activity_write_testonly.go +++ b/vault/logical_system_activity_write_testonly.go @@ -85,31 +85,25 @@ func (b *SystemBackend) handleActivityWriteData(ctx context.Context, request *lo for _, opt := range input.Write { opts[opt] = struct{}{} } - localPaths, globalPaths, err := generated.write(ctx, opts, b.Core.activityLog, now) + paths, err := generated.write(ctx, opts, b.Core.activityLog, now) if err != nil { b.logger.Debug("failed to write activity log data", "error", err.Error()) return logical.ErrorResponse("failed to write data"), err } return &logical.Response{ Data: map[string]interface{}{ - "local_paths": localPaths, - "global_paths": globalPaths, + "paths": paths, }, }, nil } // singleMonthActivityClients holds a single month's client IDs, in the order they were seen type singleMonthActivityClients struct { - // globalClients are indexed by ID - globalClients []*activity.EntityRecord - // localClients are indexed by ID - localClients []*activity.EntityRecord - // predefinedGlobalSegments map from the segment number to the client's index in + // clients are indexed by ID + clients []*activity.EntityRecord + // predefinedSegments map from the segment number to the client's index in // the clients slice - predefinedGlobalSegments map[int][]int - // predefinedLocalSegments map from the segment number to the client's index in - // the clients slice - predefinedLocalSegments map[int][]int + predefinedSegments map[int][]int // generationParameters holds the generation request generationParameters *generation.Data } @@ -120,20 +114,11 @@ type multipleMonthsActivityClients struct { months []*singleMonthActivityClients } -func (s *singleMonthActivityClients) addEntityRecord(core *Core, record *activity.EntityRecord, segmentIndex *int, local bool) { - if !local { - s.globalClients = append(s.globalClients, record) - } else { - s.localClients = append(s.localClients, record) - } +func (s *singleMonthActivityClients) addEntityRecord(record *activity.EntityRecord, segmentIndex *int) { + s.clients = append(s.clients, record) if segmentIndex != nil { - if !local { - globalIndex := len(s.globalClients) - 1 - s.predefinedGlobalSegments[*segmentIndex] = append(s.predefinedGlobalSegments[*segmentIndex], globalIndex) - } else { - localIndex := len(s.localClients) - 1 - s.predefinedLocalSegments[*segmentIndex] = append(s.predefinedLocalSegments[*segmentIndex], localIndex) - } + index := len(s.clients) - 1 + s.predefinedSegments[*segmentIndex] = append(s.predefinedSegments[*segmentIndex], index) } } @@ -141,7 +126,7 @@ func (s *singleMonthActivityClients) addEntityRecord(core *Core, record *activit // keys are the segment index, and the value are the clients that were seen in // that index. If the value is an empty slice, then it's an empty index. If the // value is nil, then it's a skipped index -func (s *singleMonthActivityClients) populateSegments(predefinedSegments map[int][]int, clients []*activity.EntityRecord) (map[int][]*activity.EntityRecord, error) { +func (s *singleMonthActivityClients) populateSegments() (map[int][]*activity.EntityRecord, error) { segments := make(map[int][]*activity.EntityRecord) ignoreIndexes := make(map[int]struct{}) skipIndexes := s.generationParameters.SkipSegmentIndexes @@ -157,11 +142,11 @@ func (s *singleMonthActivityClients) populateSegments(predefinedSegments map[int } // if we have predefined segments, then we can construct the map using those - if len(predefinedSegments) > 0 { - for segment, clientIndexes := range predefinedSegments { + if len(s.predefinedSegments) > 0 { + for segment, clientIndexes := range s.predefinedSegments { clientsInSegment := make([]*activity.EntityRecord, 0, len(clientIndexes)) for _, idx := range clientIndexes { - clientsInSegment = append(clientsInSegment, clients[idx]) + clientsInSegment = append(clientsInSegment, s.clients[idx]) } segments[segment] = clientsInSegment } @@ -170,8 +155,8 @@ func (s *singleMonthActivityClients) populateSegments(predefinedSegments map[int // determine how many segments are necessary to store the clients for this month // using the default storage limits - numNecessarySegments := len(clients) / ActivitySegmentClientCapacity - if len(clients)%ActivitySegmentClientCapacity != 0 { + numNecessarySegments := len(s.clients) / ActivitySegmentClientCapacity + if len(s.clients)%ActivitySegmentClientCapacity != 0 { numNecessarySegments++ } totalSegmentCount := numNecessarySegments @@ -188,8 +173,8 @@ func (s *singleMonthActivityClients) populateSegments(predefinedSegments map[int } // determine how many clients should be in each segment - segmentSizes := len(clients) / usableSegmentCount - if len(clients)%usableSegmentCount != 0 { + segmentSizes := len(s.clients) / usableSegmentCount + if len(s.clients)%usableSegmentCount != 0 { segmentSizes++ } @@ -199,14 +184,14 @@ func (s *singleMonthActivityClients) populateSegments(predefinedSegments map[int clientIndex := 0 for i := 0; i < totalSegmentCount; i++ { - if clientIndex >= len(clients) { + if clientIndex >= len(s.clients) { break } if _, ok := ignoreIndexes[i]; ok { continue } - for len(segments[i]) < segmentSizes && clientIndex < len(clients) { - segments[i] = append(segments[i], clients[clientIndex]) + for len(segments[i]) < segmentSizes && clientIndex < len(s.clients) { + segments[i] = append(segments[i], s.clients[clientIndex]) clientIndex++ } } @@ -215,20 +200,14 @@ func (s *singleMonthActivityClients) populateSegments(predefinedSegments map[int // addNewClients generates clients according to the given parameters, and adds them to the month // the client will always have the mountAccessor as its mount accessor -func (s *singleMonthActivityClients) addNewClients(c *generation.Client, mountAccessor string, segmentIndex *int, monthsAgo int32, now time.Time, core *Core) error { +func (s *singleMonthActivityClients) addNewClients(c *generation.Client, mountAccessor string, segmentIndex *int, monthsAgo int32, now time.Time) error { count := 1 if c.Count > 1 { count = int(c.Count) } + isNonEntity := c.ClientType != entityActivityType ts := timeutil.MonthsPreviousTo(int(monthsAgo), now) - // identify is client is local or global - isLocal, err := isClientLocal(core, c.ClientType, mountAccessor) - if err != nil { - return err - } - - isNonEntity := c.ClientType != entityActivityType for i := 0; i < count; i++ { record := &activity.EntityRecord{ ClientID: c.Id, @@ -245,8 +224,7 @@ func (s *singleMonthActivityClients) addNewClients(c *generation.Client, mountAc return err } } - - s.addEntityRecord(core, record, segmentIndex, isLocal) + s.addEntityRecord(record, segmentIndex) } return nil } @@ -315,7 +293,7 @@ func (m *multipleMonthsActivityClients) processMonth(ctx context.Context, core * } } - err = m.addClientToMonth(month.GetMonthsAgo(), clients, mountAccessor, segmentIndex, now, core) + err = m.addClientToMonth(month.GetMonthsAgo(), clients, mountAccessor, segmentIndex, now) if err != nil { return err } @@ -341,39 +319,27 @@ func (m *multipleMonthsActivityClients) processMonth(ctx context.Context, core * return nil } -func (m *multipleMonthsActivityClients) addClientToMonth(monthsAgo int32, c *generation.Client, mountAccessor string, segmentIndex *int, now time.Time, core *Core) error { +func (m *multipleMonthsActivityClients) addClientToMonth(monthsAgo int32, c *generation.Client, mountAccessor string, segmentIndex *int, now time.Time) error { if c.Repeated || c.RepeatedFromMonth > 0 { - return m.addRepeatedClients(monthsAgo, c, mountAccessor, segmentIndex, core) + return m.addRepeatedClients(monthsAgo, c, mountAccessor, segmentIndex) } - return m.months[monthsAgo].addNewClients(c, mountAccessor, segmentIndex, monthsAgo, now, core) + return m.months[monthsAgo].addNewClients(c, mountAccessor, segmentIndex, monthsAgo, now) } -func (m *multipleMonthsActivityClients) addRepeatedClients(monthsAgo int32, c *generation.Client, mountAccessor string, segmentIndex *int, core *Core) error { +func (m *multipleMonthsActivityClients) addRepeatedClients(monthsAgo int32, c *generation.Client, mountAccessor string, segmentIndex *int) error { addingTo := m.months[monthsAgo] repeatedFromMonth := monthsAgo + 1 if c.RepeatedFromMonth > 0 { repeatedFromMonth = c.RepeatedFromMonth } repeatedFrom := m.months[repeatedFromMonth] - - // identify is client is local or global - isLocal, err := isClientLocal(core, c.ClientType, mountAccessor) - if err != nil { - return err - } - numClients := 1 if c.Count > 0 { numClients = int(c.Count) } - - repeatedClients := repeatedFrom.globalClients - if isLocal { - repeatedClients = repeatedFrom.localClients - } - for _, client := range repeatedClients { + for _, client := range repeatedFrom.clients { if c.ClientType == client.ClientType && mountAccessor == client.MountAccessor && c.Namespace == client.NamespaceID { - addingTo.addEntityRecord(core, client, segmentIndex, isLocal) + addingTo.addEntityRecord(client, segmentIndex) numClients-- if numClients == 0 { break @@ -386,23 +352,6 @@ func (m *multipleMonthsActivityClients) addRepeatedClients(monthsAgo int32, c *g return nil } -// isClientLocal checks whether the given client is on a local mount. -// In all other cases, we will assume it is a global client. -func isClientLocal(core *Core, clientType string, mountAccessor string) (bool, error) { - // Tokens are not replicated to performance secondary clusters - if clientType == nonEntityTokenActivityType { - return true, nil - } - mountEntry := core.router.MatchingMountByAccessor(mountAccessor) - // If the mount entry is nil, this means the mount has been deleted. We will assume it was replicated because we do not want to - // over count clients - if mountEntry != nil && mountEntry.Local { - return true, nil - } - - return false, nil -} - func (m *multipleMonthsActivityClients) addMissingCurrentMonth() { missing := m.months[0].generationParameters == nil && len(m.months) > 1 && @@ -420,9 +369,8 @@ func (m *multipleMonthsActivityClients) timestampForMonth(i int, now time.Time) return now } -func (m *multipleMonthsActivityClients) write(ctx context.Context, opts map[generation.WriteOptions]struct{}, activityLog *ActivityLog, now time.Time) ([]string, []string, error) { - globalPaths := []string{} - localPaths := []string{} +func (m *multipleMonthsActivityClients) write(ctx context.Context, opts map[generation.WriteOptions]struct{}, activityLog *ActivityLog, now time.Time) ([]string, error) { + paths := []string{} _, writePQ := opts[generation.WriteOptions_WRITE_PRECOMPUTED_QUERIES] _, writeDistinctClients := opts[generation.WriteOptions_WRITE_DISTINCT_CLIENTS] @@ -435,49 +383,25 @@ func (m *multipleMonthsActivityClients) write(ctx context.Context, opts map[gene continue } timestamp := m.timestampForMonth(i, now) - if len(month.globalClients) > 0 { - globalSegments, err := month.populateSegments(month.predefinedGlobalSegments, month.globalClients) - if err != nil { - return nil, nil, err - } - for segmentIndex, segment := range globalSegments { - if segment == nil { - // skip the index - continue - } - entityPath, err := activityLog.saveSegmentEntitiesInternal(ctx, segmentInfo{ - startTimestamp: timestamp.Unix(), - currentClients: &activity.EntityActivityLog{Clients: segment}, - clientSequenceNumber: uint64(segmentIndex), - tokenCount: &activity.TokenCount{}, - }, true, activityGlobalPathPrefix) - if err != nil { - return nil, nil, err - } - globalPaths = append(globalPaths, entityPath) - } + segments, err := month.populateSegments() + if err != nil { + return nil, err } - if len(month.localClients) > 0 { - localSegments, err := month.populateSegments(month.predefinedLocalSegments, month.localClients) - if err != nil { - return nil, nil, err + for segmentIndex, segment := range segments { + if segment == nil { + // skip the index + continue } - for segmentIndex, segment := range localSegments { - if segment == nil { - // skip the index - continue - } - entityPath, err := activityLog.saveSegmentEntitiesInternal(ctx, segmentInfo{ - startTimestamp: timestamp.Unix(), - currentClients: &activity.EntityActivityLog{Clients: segment}, - clientSequenceNumber: uint64(segmentIndex), - tokenCount: &activity.TokenCount{}, - }, true, activityLocalPathPrefix) - if err != nil { - return nil, nil, err - } - localPaths = append(localPaths, entityPath) + entityPath, err := activityLog.saveSegmentEntitiesInternal(ctx, segmentInfo{ + startTimestamp: timestamp.Unix(), + currentClients: &activity.EntityActivityLog{Clients: segment}, + clientSequenceNumber: uint64(segmentIndex), + tokenCount: &activity.TokenCount{}, + }, true) + if err != nil { + return nil, err } + paths = append(paths, entityPath) } } if writePQ || writeDistinctClients { @@ -499,16 +423,16 @@ func (m *multipleMonthsActivityClients) write(ctx context.Context, opts map[gene if writeIntentLog { err := activityLog.writeIntentLog(ctx, m.latestTimestamp(now, false).Unix(), m.latestTimestamp(now, true).UTC()) if err != nil { - return nil, nil, err + return nil, err } } wg := sync.WaitGroup{} err := activityLog.refreshFromStoredLog(ctx, &wg, now) if err != nil { - return nil, nil, err + return nil, err } wg.Wait() - return localPaths, globalPaths, nil + return paths, nil } func (m *multipleMonthsActivityClients) latestTimestamp(now time.Time, includeCurrentMonth bool) time.Time { @@ -536,8 +460,7 @@ func newMultipleMonthsActivityClients(numberOfMonths int) *multipleMonthsActivit } for i := 0; i < numberOfMonths; i++ { m.months[i] = &singleMonthActivityClients{ - predefinedGlobalSegments: make(map[int][]int), - predefinedLocalSegments: make(map[int][]int), + predefinedSegments: make(map[int][]int), } } return m @@ -561,20 +484,11 @@ type sliceSegmentReader struct { i int } -// ReadGlobalEntity here is a dummy implementation. -// Segment reader is never used when writing using the ClientCountUtil library -func (p *sliceSegmentReader) ReadGlobalEntity(ctx context.Context) (*activity.EntityActivityLog, error) { - if p.i == len(p.records) { - return nil, io.EOF - } - record := p.records[p.i] - p.i++ - return &activity.EntityActivityLog{Clients: record}, nil +func (p *sliceSegmentReader) ReadToken(ctx context.Context) (*activity.TokenCount, error) { + return nil, io.EOF } -// ReadLocalEntity here is a dummy implementation. -// Segment reader is never used when writing using the ClientCountUtil library -func (p *sliceSegmentReader) ReadLocalEntity(ctx context.Context) (*activity.EntityActivityLog, error) { +func (p *sliceSegmentReader) ReadEntity(ctx context.Context) (*activity.EntityActivityLog, error) { if p.i == len(p.records) { return nil, io.EOF } @@ -582,7 +496,3 @@ func (p *sliceSegmentReader) ReadLocalEntity(ctx context.Context) (*activity.Ent p.i++ return &activity.EntityActivityLog{Clients: record}, nil } - -func (p *sliceSegmentReader) ReadToken(ctx context.Context) (*activity.TokenCount, error) { - return nil, io.EOF -} diff --git a/vault/logical_system_activity_write_testonly_test.go b/vault/logical_system_activity_write_testonly_test.go index 420e2079d0ef..5254c0aaed6b 100644 --- a/vault/logical_system_activity_write_testonly_test.go +++ b/vault/logical_system_activity_write_testonly_test.go @@ -12,7 +12,6 @@ import ( "testing" "time" - "github.com/hashicorp/vault/builtin/credential/userpass" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/helper/timeutil" "github.com/hashicorp/vault/sdk/helper/clientcountutil/generation" @@ -27,12 +26,11 @@ import ( // correctly validated func TestSystemBackend_handleActivityWriteData(t *testing.T) { testCases := []struct { - name string - operation logical.Operation - input map[string]interface{} - hasLocalClients bool - wantError error - wantPaths int + name string + operation logical.Operation + input map[string]interface{} + wantError error + wantPaths int }{ { name: "read fails", @@ -86,13 +84,6 @@ func TestSystemBackend_handleActivityWriteData(t *testing.T) { input: map[string]interface{}{"input": `{"write":["WRITE_ENTITIES"],"data":[{"current_month":true,"num_segments":3,"all":{"clients":[{"count":5}]}}]}`}, wantPaths: 3, }, - { - name: "entities with multiple segments", - operation: logical.UpdateOperation, - input: map[string]interface{}{"input": `{"write":["WRITE_ENTITIES"],"data":[{"current_month":true,"num_segments":3,"all":{"clients":[{"count":5, "mount":"cubbyhole/"}]}}]}`}, - hasLocalClients: true, - wantPaths: 3, - }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { @@ -104,16 +95,8 @@ func TestSystemBackend_handleActivityWriteData(t *testing.T) { require.Equal(t, tc.wantError, err, resp.Error()) } else { require.NoError(t, err) - globalPaths := resp.Data["global_paths"].([]string) - localPaths := resp.Data["local_paths"].([]string) - if tc.hasLocalClients { - require.Len(t, globalPaths, 0) - require.Len(t, localPaths, tc.wantPaths) - } else { - require.Len(t, globalPaths, tc.wantPaths) - require.Len(t, localPaths, 0) - } - + paths := resp.Data["paths"].([]string) + require.Len(t, paths, tc.wantPaths) } }) } @@ -133,7 +116,6 @@ func Test_singleMonthActivityClients_addNewClients(t *testing.T) { wantNamespace string wantMount string wantID string - isLocal bool segmentIndex *int }{ { @@ -171,13 +153,6 @@ func Test_singleMonthActivityClients_addNewClients(t *testing.T) { ClientType: "non-entity", }, }, - { - name: "non entity token client", - clients: &generation.Client{ - ClientType: nonEntityTokenActivityType, - }, - isLocal: true, - }, { name: "acme client", clients: &generation.Client{ @@ -192,27 +167,17 @@ func Test_singleMonthActivityClients_addNewClients(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - core, _, _ := TestCoreUnsealed(t) m := &singleMonthActivityClients{ - predefinedGlobalSegments: make(map[int][]int), - predefinedLocalSegments: make(map[int][]int), + predefinedSegments: make(map[int][]int), } - err := m.addNewClients(tt.clients, tt.mount, tt.segmentIndex, 0, time.Now().UTC(), core) + err := m.addNewClients(tt.clients, tt.mount, tt.segmentIndex, 0, time.Now().UTC()) require.NoError(t, err) numNew := tt.clients.Count if numNew == 0 { numNew = 1 } - - var clients []*activity.EntityRecord - if tt.isLocal { - require.Len(t, m.localClients, int(numNew)) - clients = m.localClients - } else { - require.Len(t, m.globalClients, int(numNew)) - clients = m.globalClients - } - for i, rec := range clients { + require.Len(t, m.clients, int(numNew)) + for i, rec := range m.clients { require.NotNil(t, rec) require.Equal(t, tt.wantNamespace, rec.NamespaceID) require.Equal(t, tt.wantMount, rec.MountAccessor) @@ -222,11 +187,8 @@ func Test_singleMonthActivityClients_addNewClients(t *testing.T) { } else { require.NotEqual(t, "", rec.ClientID) } - if tt.segmentIndex != nil && tt.isLocal { - require.Contains(t, m.predefinedLocalSegments[*tt.segmentIndex], i) - } - if tt.segmentIndex != nil && !tt.isLocal { - require.Contains(t, m.predefinedGlobalSegments[*tt.segmentIndex], i) + if tt.segmentIndex != nil { + require.Contains(t, m.predefinedSegments[*tt.segmentIndex], i) } } }) @@ -242,7 +204,6 @@ func Test_multipleMonthsActivityClients_processMonth(t *testing.T) { name string clients *generation.Data wantError bool - isLocal bool numMonths int }{ { @@ -255,16 +216,6 @@ func Test_multipleMonthsActivityClients_processMonth(t *testing.T) { }, numMonths: 1, }, - { - name: "specified namespace and local mount exist", - clients: &generation.Data{ - Clients: &generation.Data_All{All: &generation.Clients{Clients: []*generation.Client{{ - Mount: "cubbyhole/", - }}}}, - }, - numMonths: 1, - isLocal: true, - }, { name: "mount missing slash", clients: &generation.Data{ @@ -329,24 +280,13 @@ func Test_multipleMonthsActivityClients_processMonth(t *testing.T) { require.Error(t, err) } else { require.NoError(t, err) - if tt.isLocal { - require.Len(t, m.months[tt.clients.GetMonthsAgo()].localClients, len(tt.clients.GetAll().Clients)) - for _, month := range m.months { - for _, c := range month.localClients { - require.NotEmpty(t, c.NamespaceID) - require.NotEmpty(t, c.MountAccessor) - } - } - } else { - require.Len(t, m.months[tt.clients.GetMonthsAgo()].globalClients, len(tt.clients.GetAll().Clients)) - for _, month := range m.months { - for _, c := range month.globalClients { - require.NotEmpty(t, c.NamespaceID) - require.NotEmpty(t, c.MountAccessor) - } + require.Len(t, m.months[tt.clients.GetMonthsAgo()].clients, len(tt.clients.GetAll().Clients)) + for _, month := range m.months { + for _, c := range month.clients { + require.NotEmpty(t, c.NamespaceID) + require.NotEmpty(t, c.MountAccessor) } } - } }) } @@ -381,97 +321,59 @@ func Test_multipleMonthsActivityClients_processMonth_segmented(t *testing.T) { m := newMultipleMonthsActivityClients(1) core, _, _ := TestCoreUnsealed(t) require.NoError(t, m.processMonth(context.Background(), core, data, time.Now().UTC())) - require.Len(t, m.months[0].predefinedGlobalSegments, 3) - require.Len(t, m.months[0].globalClients, 3) + require.Len(t, m.months[0].predefinedSegments, 3) + require.Len(t, m.months[0].clients, 3) // segment indexes are correct - require.Contains(t, m.months[0].predefinedGlobalSegments, 0) - require.Contains(t, m.months[0].predefinedGlobalSegments, 1) - require.Contains(t, m.months[0].predefinedGlobalSegments, 7) + require.Contains(t, m.months[0].predefinedSegments, 0) + require.Contains(t, m.months[0].predefinedSegments, 1) + require.Contains(t, m.months[0].predefinedSegments, 7) // the data in each segment is correct - require.Contains(t, m.months[0].predefinedGlobalSegments[0], 0) - require.Contains(t, m.months[0].predefinedGlobalSegments[1], 1) - require.Contains(t, m.months[0].predefinedGlobalSegments[7], 2) + require.Contains(t, m.months[0].predefinedSegments[0], 0) + require.Contains(t, m.months[0].predefinedSegments[1], 1) + require.Contains(t, m.months[0].predefinedSegments[7], 2) } // Test_multipleMonthsActivityClients_addRepeatedClients adds repeated clients // from 1 month ago and 2 months ago, and verifies that the correct clients are // added based on namespace, mount, and non-entity attributes func Test_multipleMonthsActivityClients_addRepeatedClients(t *testing.T) { - storage := &logical.InmemStorage{} - coreConfig := &CoreConfig{ - CredentialBackends: map[string]logical.Factory{ - "userpass": userpass.Factory, - }, - Physical: storage.Underlying(), - } - - cluster := NewTestCluster(t, coreConfig, nil) - core := cluster.Cores[0].Core now := time.Now().UTC() m := newMultipleMonthsActivityClients(3) defaultMount := "default" - // add global clients - require.NoError(t, m.addClientToMonth(2, &generation.Client{Count: 2}, "identity", nil, now, core)) - require.NoError(t, m.addClientToMonth(2, &generation.Client{Count: 2, Namespace: "other_ns"}, defaultMount, nil, now, core)) - require.NoError(t, m.addClientToMonth(1, &generation.Client{Count: 2}, defaultMount, nil, now, core)) - require.NoError(t, m.addClientToMonth(1, &generation.Client{Count: 2, ClientType: "non-entity"}, defaultMount, nil, now, core)) - - // create a local mount - localMount := "localMountAccessor" - localMe := &MountEntry{ - Table: credentialTableType, - Path: "userpass-local/", - Type: "userpass", - Local: true, - Accessor: localMount, - } - err := core.enableCredential(namespace.RootContext(nil), localMe) - require.NoError(t, err) - - // add a local client - require.NoError(t, m.addClientToMonth(2, &generation.Client{Count: 2}, localMount, nil, now, core)) - require.NoError(t, m.addClientToMonth(1, &generation.Client{Count: 2}, localMount, nil, now, core)) - - month2GlobalClients := m.months[2].globalClients - month1GlobalClients := m.months[1].globalClients + require.NoError(t, m.addClientToMonth(2, &generation.Client{Count: 2}, "identity", nil, now)) + require.NoError(t, m.addClientToMonth(2, &generation.Client{Count: 2, Namespace: "other_ns"}, defaultMount, nil, now)) + require.NoError(t, m.addClientToMonth(1, &generation.Client{Count: 2}, defaultMount, nil, now)) + require.NoError(t, m.addClientToMonth(1, &generation.Client{Count: 2, ClientType: "non-entity"}, defaultMount, nil, now)) - month2LocalClients := m.months[2].localClients - month1LocalClients := m.months[1].localClients + month2Clients := m.months[2].clients + month1Clients := m.months[1].clients thisMonth := m.months[0] // this will match the first client in month 1 - require.NoError(t, m.addRepeatedClients(0, &generation.Client{Count: 1, Repeated: true}, defaultMount, nil, core)) - require.Contains(t, month1GlobalClients, thisMonth.globalClients[0]) - - // this will match the first local client in month 1 - require.NoError(t, m.addRepeatedClients(0, &generation.Client{Count: 1, Repeated: true}, localMount, nil, core)) - require.Contains(t, month1LocalClients, thisMonth.localClients[0]) + require.NoError(t, m.addRepeatedClients(0, &generation.Client{Count: 1, Repeated: true}, defaultMount, nil)) + require.Contains(t, month1Clients, thisMonth.clients[0]) // this will match the 3rd client in month 1 - require.NoError(t, m.addRepeatedClients(0, &generation.Client{Count: 1, Repeated: true, ClientType: "non-entity"}, defaultMount, nil, core)) - require.Equal(t, month1GlobalClients[2], thisMonth.globalClients[1]) + require.NoError(t, m.addRepeatedClients(0, &generation.Client{Count: 1, Repeated: true, ClientType: "non-entity"}, defaultMount, nil)) + require.Equal(t, month1Clients[2], thisMonth.clients[1]) // this will match the first two clients in month 1 - require.NoError(t, m.addRepeatedClients(0, &generation.Client{Count: 2, Repeated: true}, defaultMount, nil, core)) - require.Equal(t, month1GlobalClients[0:2], thisMonth.globalClients[2:4]) + require.NoError(t, m.addRepeatedClients(0, &generation.Client{Count: 2, Repeated: true}, defaultMount, nil)) + require.Equal(t, month1Clients[0:2], thisMonth.clients[2:4]) // this will match the first client in month 2 - require.NoError(t, m.addRepeatedClients(0, &generation.Client{Count: 1, RepeatedFromMonth: 2}, "identity", nil, core)) - require.Equal(t, month2GlobalClients[0], thisMonth.globalClients[4]) - - // this will match the first local client in month 2 - require.NoError(t, m.addRepeatedClients(0, &generation.Client{Count: 1, RepeatedFromMonth: 2}, localMount, nil, core)) - require.Equal(t, month2LocalClients[0], thisMonth.localClients[1]) + require.NoError(t, m.addRepeatedClients(0, &generation.Client{Count: 1, RepeatedFromMonth: 2}, "identity", nil)) + require.Equal(t, month2Clients[0], thisMonth.clients[4]) // this will match the 3rd client in month 2 - require.NoError(t, m.addRepeatedClients(0, &generation.Client{Count: 1, RepeatedFromMonth: 2, Namespace: "other_ns"}, defaultMount, nil, core)) - require.Equal(t, month2GlobalClients[2], thisMonth.globalClients[5]) + require.NoError(t, m.addRepeatedClients(0, &generation.Client{Count: 1, RepeatedFromMonth: 2, Namespace: "other_ns"}, defaultMount, nil)) + require.Equal(t, month2Clients[2], thisMonth.clients[5]) - require.Error(t, m.addRepeatedClients(0, &generation.Client{Count: 1, RepeatedFromMonth: 2, Namespace: "other_ns"}, "other_mount", nil, core)) + require.Error(t, m.addRepeatedClients(0, &generation.Client{Count: 1, RepeatedFromMonth: 2, Namespace: "other_ns"}, "other_mount", nil)) } // Test_singleMonthActivityClients_populateSegments calls populateSegments for a @@ -553,8 +455,8 @@ func Test_singleMonthActivityClients_populateSegments(t *testing.T) { } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - s := singleMonthActivityClients{predefinedGlobalSegments: tc.segments, globalClients: clients, generationParameters: &generation.Data{EmptySegmentIndexes: tc.emptyIndexes, SkipSegmentIndexes: tc.skipIndexes, NumSegments: int32(tc.numSegments)}} - gotSegments, err := s.populateSegments(s.predefinedGlobalSegments, s.globalClients) + s := singleMonthActivityClients{predefinedSegments: tc.segments, clients: clients, generationParameters: &generation.Data{EmptySegmentIndexes: tc.emptyIndexes, SkipSegmentIndexes: tc.skipIndexes, NumSegments: int32(tc.numSegments)}} + gotSegments, err := s.populateSegments() require.NoError(t, err) require.Equal(t, tc.wantSegments, gotSegments) }) @@ -624,7 +526,7 @@ func Test_handleActivityWriteData(t *testing.T) { req.Data = map[string]interface{}{"input": string(marshaled)} resp, err := core.systemBackend.HandleRequest(namespace.RootContext(nil), req) require.NoError(t, err) - paths := resp.Data["global_paths"].([]string) + paths := resp.Data["paths"].([]string) require.Len(t, paths, 9) times, err := core.activityLog.availableLogs(context.Background(), time.Now()) diff --git a/vault/request_forwarding_service.pb.go b/vault/request_forwarding_service.pb.go index f414f016ad90..48f1d04ab361 100644 --- a/vault/request_forwarding_service.pb.go +++ b/vault/request_forwarding_service.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: vault/request_forwarding_service.proto @@ -27,11 +27,8 @@ const ( ) type EchoRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` // ClusterAddr is used to send up a standby node's address to the active // node upon heartbeat ClusterAddr string `protobuf:"bytes,2,opt,name=cluster_addr,json=clusterAddr,proto3" json:"cluster_addr,omitempty"` @@ -52,6 +49,8 @@ type EchoRequest struct { // 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"` ReplicationPrimaryCanaryAgeMillis int64 `protobuf:"varint,15,opt,name=replication_primary_canary_age_millis,json=replicationPrimaryCanaryAgeMillis,proto3" json:"replication_primary_canary_age_millis,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *EchoRequest) Reset() { @@ -190,18 +189,17 @@ func (x *EchoRequest) GetReplicationPrimaryCanaryAgeMillis() int64 { } type EchoReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` - ClusterAddrs []string `protobuf:"bytes,2,rep,name=cluster_addrs,json=clusterAddrs,proto3" json:"cluster_addrs,omitempty"` - ReplicationState uint32 `protobuf:"varint,3,opt,name=replication_state,json=replicationState,proto3" json:"replication_state,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"` + state protoimpl.MessageState `protogen:"open.v1"` + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + ClusterAddrs []string `protobuf:"bytes,2,rep,name=cluster_addrs,json=clusterAddrs,proto3" json:"cluster_addrs,omitempty"` + ReplicationState uint32 `protobuf:"varint,3,opt,name=replication_state,json=replicationState,proto3" json:"replication_state,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"` // now is the time on the server - Now *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=now,proto3" json:"now,omitempty"` + Now *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=now,proto3" json:"now,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *EchoReply) Reset() { @@ -284,16 +282,15 @@ func (x *EchoReply) GetNow() *timestamppb.Timestamp { } type NodeInformation struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ClusterAddr string `protobuf:"bytes,1,opt,name=cluster_addr,json=clusterAddr,proto3" json:"cluster_addr,omitempty"` - ApiAddr string `protobuf:"bytes,2,opt,name=api_addr,json=apiAddr,proto3" json:"api_addr,omitempty"` - Mode string `protobuf:"bytes,3,opt,name=mode,proto3" json:"mode,omitempty"` - NodeID string `protobuf:"bytes,4,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` - ReplicationState uint32 `protobuf:"varint,5,opt,name=replication_state,json=replicationState,proto3" json:"replication_state,omitempty"` - Hostname string `protobuf:"bytes,6,opt,name=hostname,proto3" json:"hostname,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + ClusterAddr string `protobuf:"bytes,1,opt,name=cluster_addr,json=clusterAddr,proto3" json:"cluster_addr,omitempty"` + ApiAddr string `protobuf:"bytes,2,opt,name=api_addr,json=apiAddr,proto3" json:"api_addr,omitempty"` + Mode string `protobuf:"bytes,3,opt,name=mode,proto3" json:"mode,omitempty"` + NodeID string `protobuf:"bytes,4,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + ReplicationState uint32 `protobuf:"varint,5,opt,name=replication_state,json=replicationState,proto3" json:"replication_state,omitempty"` + Hostname string `protobuf:"bytes,6,opt,name=hostname,proto3" json:"hostname,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *NodeInformation) Reset() { @@ -369,14 +366,13 @@ func (x *NodeInformation) GetHostname() string { } type ClientKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + X []byte `protobuf:"bytes,2,opt,name=x,proto3" json:"x,omitempty"` + Y []byte `protobuf:"bytes,3,opt,name=y,proto3" json:"y,omitempty"` + D []byte `protobuf:"bytes,4,opt,name=d,proto3" json:"d,omitempty"` unknownFields protoimpl.UnknownFields - - Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` - X []byte `protobuf:"bytes,2,opt,name=x,proto3" json:"x,omitempty"` - Y []byte `protobuf:"bytes,3,opt,name=y,proto3" json:"y,omitempty"` - D []byte `protobuf:"bytes,4,opt,name=d,proto3" json:"d,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ClientKey) Reset() { @@ -438,9 +434,9 @@ func (x *ClientKey) GetD() []byte { } type PerfStandbyElectionInput struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *PerfStandbyElectionInput) Reset() { @@ -474,16 +470,15 @@ func (*PerfStandbyElectionInput) Descriptor() ([]byte, []int) { } type PerfStandbyElectionResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - ClusterID string `protobuf:"bytes,2,opt,name=cluster_id,json=clusterId,proto3" json:"cluster_id,omitempty"` - PrimaryClusterAddr string `protobuf:"bytes,3,opt,name=primary_cluster_addr,json=primaryClusterAddr,proto3" json:"primary_cluster_addr,omitempty"` - CaCert []byte `protobuf:"bytes,4,opt,name=ca_cert,json=caCert,proto3" json:"ca_cert,omitempty"` - ClientCert []byte `protobuf:"bytes,5,opt,name=client_cert,json=clientCert,proto3" json:"client_cert,omitempty"` - ClientKey *ClientKey `protobuf:"bytes,6,opt,name=client_key,json=clientKey,proto3" json:"client_key,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ClusterID string `protobuf:"bytes,2,opt,name=cluster_id,json=clusterId,proto3" json:"cluster_id,omitempty"` + PrimaryClusterAddr string `protobuf:"bytes,3,opt,name=primary_cluster_addr,json=primaryClusterAddr,proto3" json:"primary_cluster_addr,omitempty"` + CaCert []byte `protobuf:"bytes,4,opt,name=ca_cert,json=caCert,proto3" json:"ca_cert,omitempty"` + ClientCert []byte `protobuf:"bytes,5,opt,name=client_cert,json=clientCert,proto3" json:"client_cert,omitempty"` + ClientKey *ClientKey `protobuf:"bytes,6,opt,name=client_key,json=clientKey,proto3" json:"client_key,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *PerfStandbyElectionResponse) Reset() { diff --git a/vault/rotation_stubs_oss.go b/vault/rotation_stubs_oss.go new file mode 100644 index 000000000000..4798e9375c38 --- /dev/null +++ b/vault/rotation_stubs_oss.go @@ -0,0 +1,33 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1package vault + +//go:build !enterprise + +package vault + +//go:generate go run github.com/hashicorp/vault/tools/stubmaker + +import ( + "context" + + "github.com/hashicorp/vault/sdk/helper/automatedrotationutil" + "github.com/hashicorp/vault/sdk/rotation" +) + +type RotationManager struct{} + +func (c *Core) startRotation() error { + return nil +} + +func (c *Core) stopRotation() error { + return nil +} + +func (c *Core) RegisterRotationJob(_ context.Context, _ string, _ *rotation.RotationJob) (string, error) { + return "", automatedrotationutil.ErrRotationManagerUnsupported +} + +func (c *Core) DeregisterRotationJob(_ string) error { + return automatedrotationutil.ErrRotationManagerUnsupported +} diff --git a/vault/seal/multi_wrap_value.pb.go b/vault/seal/multi_wrap_value.pb.go index 9a2d943e6ef7..acd94cc1a062 100644 --- a/vault/seal/multi_wrap_value.pb.go +++ b/vault/seal/multi_wrap_value.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: vault/seal/multi_wrap_value.proto @@ -26,14 +26,13 @@ const ( // MultiWrapValue can be used to keep track of different encryptions of a value. type MultiWrapValue struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Generation is used to keep track of when the MultiWrapValue was generated. Generation uint64 `protobuf:"varint,1,opt,name=generation,proto3" json:"generation,omitempty"` // Slots has a BlobInfo for each key used to encrypt the value. - Slots []*v2.BlobInfo `protobuf:"bytes,2,rep,name=slots,proto3" json:"slots,omitempty"` + Slots []*v2.BlobInfo `protobuf:"bytes,2,rep,name=slots,proto3" json:"slots,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MultiWrapValue) Reset() { diff --git a/vault/tokens/token.pb.go b/vault/tokens/token.pb.go index 95b13f57c3bd..f3c3cd7963a1 100644 --- a/vault/tokens/token.pb.go +++ b/vault/tokens/token.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.0 // protoc (unknown) // source: vault/tokens/token.proto @@ -25,13 +25,12 @@ const ( // SignedToken type SignedToken struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + TokenVersion uint64 `protobuf:"varint,1,opt,name=token_version,json=tokenVersion,proto3" json:"token_version,omitempty"` // always 1 for now + Hmac []byte `protobuf:"bytes,2,opt,name=hmac,proto3" json:"hmac,omitempty"` // HMAC of token + Token []byte `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty"` // protobuf-marshalled Token message unknownFields protoimpl.UnknownFields - - TokenVersion uint64 `protobuf:"varint,1,opt,name=token_version,json=tokenVersion,proto3" json:"token_version,omitempty"` // always 1 for now - Hmac []byte `protobuf:"bytes,2,opt,name=hmac,proto3" json:"hmac,omitempty"` // HMAC of token - Token []byte `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty"` // protobuf-marshalled Token message + sizeCache protoimpl.SizeCache } func (x *SignedToken) Reset() { @@ -86,13 +85,12 @@ func (x *SignedToken) GetToken() []byte { } type Token struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Random string `protobuf:"bytes,1,opt,name=random,proto3" json:"random,omitempty"` // unencoded equiv of former $randbase62 + LocalIndex uint64 `protobuf:"varint,2,opt,name=local_index,json=localIndex,proto3" json:"local_index,omitempty"` // required storage state to have this token + IndexEpoch uint32 `protobuf:"varint,3,opt,name=index_epoch,json=indexEpoch,proto3" json:"index_epoch,omitempty"` unknownFields protoimpl.UnknownFields - - Random string `protobuf:"bytes,1,opt,name=random,proto3" json:"random,omitempty"` // unencoded equiv of former $randbase62 - LocalIndex uint64 `protobuf:"varint,2,opt,name=local_index,json=localIndex,proto3" json:"local_index,omitempty"` // required storage state to have this token - IndexEpoch uint32 `protobuf:"varint,3,opt,name=index_epoch,json=indexEpoch,proto3" json:"index_epoch,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Token) Reset() { diff --git a/website/content/api-docs/auth/cf.mdx b/website/content/api-docs/auth/cf.mdx index c5b9d95cc29e..f3b2c5f3a666 100644 --- a/website/content/api-docs/auth/cf.mdx +++ b/website/content/api-docs/auth/cf.mdx @@ -46,6 +46,8 @@ documentation](/vault/docs/auth/cf). - `login_max_seconds_not_after` `(int: 60)`: In case of clock drift, the maximum number of seconds in the future when a signature could have been created. The lower the value, the lower the risk of replay attacks. +- `cf_timeout` `(duration: 0s)`: The timeout for the CF API. If not set, the default + timeout is 0, which means no timeout. ### Sample payload diff --git a/website/content/api-docs/secret/pki/issuance.mdx b/website/content/api-docs/secret/pki/issuance.mdx index c0cf65bdc458..80972618c804 100644 --- a/website/content/api-docs/secret/pki/issuance.mdx +++ b/website/content/api-docs/secret/pki/issuance.mdx @@ -13,6 +13,9 @@ description: This is the API documentation for the issuance protocol support in - [Delete Unused ACME EAB Binding Tokens](#delete-unused-acme-eab-binding-tokens) - [Get ACME Configuration](#get-acme-configuration) - [Set ACME Configuration](#set-acme-configuration) + - [List ACME Account Keys](#list-acme-account-keys) + - [Get ACME Account Info](#get-acme-account-info) + - [Update ACME Account Info](#update-acme-account-info) - [EST - Certificate Issuance ](#est-certificate-issuance) - [EST Protocol Paths ](#est-protocol-paths) - [Read EST Configuration ](#read-est-configuration) @@ -109,9 +112,13 @@ fetch an EAB token and pass it to the ACME client for use on the initial registration: this binds the ACME client's registration to an authenticated Vault endpoint, but not further to the client's entity or other information. -~> Note: Enabling EAB is strongly recommended for public-facing Vault - deployments. Use of the `VAULT_DISABLE_PUBLIC_ACME` environment variable - can be used to enforce all ACME instances have EAB enabled. + + +We strongly recommend enabling EAB for public-facing Vault +deployments. Use the `VAULT_DISABLE_PUBLIC_ACME` environment +variable to force-enable EAB for all ACME instances. + + #### ACME accounts @@ -367,6 +374,148 @@ $ curl \ } ``` +### List ACME account keys + +The `ListAcmeAccountKeys` endpoint returns a list of ACME account key +identifiers. + +| Method | Path | +|:-------|:-------------------------------| +| `LIST` | `/pki/acme/mgmt/account/keyid` | + +#### Sample request + +``` +$ curl \ + --header "X-Vault-Token: ..." \ + --request LIST \ + http://127.0.0.1:8200/v1/pki/acme/mgmt/account/keyid +``` + +#### Sample response + +``` +{ + "data": { + "keys": [ + "2ea9859a-eba8-ff24-cd03-2a51639fc7d5" + ] + } +} +``` + +### Get ACME account info + +The `GetAcmeAccountInfo` endpoint returns account information, +including orders and certificate details, for the provided ACME account +key. + +| Method | Path | +|:-------|:---------------------------------------| +| `GET` | `/pki/acme/mgmt/account/keyid/:key_id` | + +#### Path parameters + +- `key_id` `(string: )` - ID of the target ACME account. + +#### Sample request + +``` +$ curl \ + --header "X-Vault-Token: ..." \ + http://127.0.0.1:8200/v1/pki/acme/mgmt/account/keyid/2ea9859a-eba8-ff24-cd03-2a51639fc7d5 +``` + +#### Sample response + +``` +{ + "data": { + "contacts": null, + "created_time": "2024-12-12T12:55:50-05:00", + "directory": "acme/", + "eab": { + "created_time": "2024-12-12T12:55:29-05:00", + "directory": "acme/", + "eab_id": "24c0673a-df53-0671-a628-e7b9c995485c", + "key_type": "hs" + }, + "key_id": "2ea9859a-eba8-ff24-cd03-2a51639fc7d5", + "orders": [ + { + "cert_expiry": "2024-12-13T17:55:28Z", + "cert_serial_number": "4a:6f:d0:f7:13:55:f7:c9:19:82:fc:34:69:67:77:2e:58:27:02:8b", + "identifiers": [ + "testing.dadgarcorp.com" + ], + "order_expiry": "2024-12-13T12:56:04-05:00", + "order_id": "90699994-8863-571c-26b0-46755e0db351", + "status": "valid" + } + ], + "revoked_time": "", + "status": "valid" + }, +} +``` + +### Update ACME account info + +The `UpdateAcmeAccountInfo` endpoint revokes or re-enables an ACME +account and returns the account details excluding order or certificate +details. + +| Method | Path | +|:-------|:---------------------------------------| +| `POST` | `/pki/acme/mgmt/account/keyid/:key_id` | + +#### Path parameters + +- `key_id` `(string: )` - ID of the target ACME account. + + +### Parameters + +- `status` `(string: )` - The new account status. Must be one of: + `revoked`, `valid`. + + + +Revoking an ACME account forbids further operations on the account +without revoking existing certificates. You must revoke any existing +certificates manually. + + + +#### Sample request + +``` +$ curl \ + --header "X-Vault-Token: ..." \ + http://127.0.0.1:8200/v1/pki/acme/mgmt/account/keyid/2ea9859a-eba8-ff24-cd03-2a51639fc7d5 +``` + +#### Sample response + +``` +{ + "data": { + "contacts": null, + "created_time": "2024-12-12T12:55:50-05:00", + "directory": "acme/", + "eab": { + "created_time": "2024-12-12T12:55:29-05:00", + "directory": "acme/", + "eab_id": "24c0673a-df53-0671-a628-e7b9c995485c", + "key_type": "hs" + }, + "key_id": "2ea9859a-eba8-ff24-cd03-2a51639fc7d5", + "revoked_time": "2024-12-12T12:59:02-05:00", + "status": "revoked" + }, +} +``` + ## EST Certificate issuance Within Vault Enterprise, support can be enabled for the diff --git a/website/content/docs/concepts/integrated-storage/migrate-consul-storage.mdx b/website/content/docs/concepts/integrated-storage/migrate-consul-storage.mdx new file mode 100644 index 000000000000..c476e175e29d --- /dev/null +++ b/website/content/docs/concepts/integrated-storage/migrate-consul-storage.mdx @@ -0,0 +1,276 @@ +--- +layout: docs +page_title: Migrate Consul storage to Integrated Storage +description: Learn how to migrate Vault from Consul storage to Integrated Storage. +--- + +# Migrate Consul storage to Integrated Storage + +This guidance provides steps to migrate Vault server storage from Consul to +Integrated Storage. + + + +Integrated Storage requires **Vault 1.4** or later. + + + + + +Before continuing with this guidance, be sure to read the [Migration checklist](/vault/docs/concepts/integrated-storage/migration-checklist) +first. + +Also, review the [upgrade guide](/vault/docs/upgrading) to learn about version specific +details related to your current Vault version or versions between your current +version and the intended upgrade version. + + + +Use the following workflow to migrate Consul storage to Integrated Storage, +noting the recommendations specific to Vault Enterprise and Enterprise Replication. + +## Snapshot Vault data + +You should take a snapshot of the Vault data using [Consul +Snapshot](/consul/commands/snapshot) before performing an upgrade or Vault +storage migration. + +[Consul Enterprise](/consul/docs/enterprise) users can use the +[automated Snapshot Agent](/consul/commands/snapshot/agent) to +periodically capture and retain snapshots in a specified destination. +You can use the latest available snapshot to restore in case of issues +with upgrading or migrating the storage. + +### Snapshot Vault data + +Execute the following command from either directly on a Consul server, or +any system running a Consul client agent connected to the server cluster that +holds the Vault data. + +```shell-session +$ consul snapshot save backup.snap +Saved and verified snapshot to index 1394 +``` + +The snapshot file `backup.snap` will be present in the current working +directory. + +### Inspect the snapshot + +The snapshot file is a gzip compressed archive. You can perform some +inspection on the snapshot file via the `consul snapshot inspect` +command and also manually by decompressing the file and examining its contents. + +```shell-session +$ consul snapshot inspect backup.snap + +ID 2-1394-1515172423763 +Size 481887 +Index 1394 +Term 2 +Version 1 +``` + +This output shows the snapshot ID, size in bytes, plus the snapshot index, term, +and version. You can compare this with the server (for example, with +`consul info`) and is useful to detect any data corruption. + + + + Refer to [Datacenter backups](/consul/tutorials/production-deploy/backup-and-restore) for more information. + + + +## Migrate Vault storage + +If you have a multi-datacenter Vault Enterprise Replication deployments, skip to +the [Vault Enterprise Replication](#vault-enterprise-replications) section. + + + + Vault will need to be offline during the migration process. + + + +Perform the migration step on one of the nodes in the cluster which will become +the leader node. + +To walkthrough the migration steps, assume that the following is your **new** +Vault server configuration. + +```hcl +# Storage configuration +storage "raft" { + path = "/vault/raft/" + node_id = "node_1" +} + +listener "tcp" { + address = "0.0.0.0:8200" + cluster_address = "0.0.0.0:8201" + tls_cert_file = "/path/to/fullchain.pem" + tls_key_file = "/path/to/privkey.pem" +} + +api_addr = "https://13.57.14.206:8200" +cluster_addr = "https://10.0.101.22:8201" +disable_mlock = true +ui=true +``` + +Notice that the `path` value is `/vault/raft/` and `node_id` value is +`node_1`. (Refer to the [server configuration documentation](/vault/docs/configuration/storage/raft) +for details.) + + + + When using Integrated Storage , it is strongly recommended to +set `disable_mlock` to `true`, and to disable memory swapping on the system. + + + +1. Create a migration configuration file (e.g. `migrate.hcl`). + + ```hcl + storage_source "consul" { + address = "127.0.0.1:8500" + path = "vault" + } + + storage_destination "raft" { + path = "/vault/raft/" + node_id = "node_1" + } + + cluster_addr = "https://10.0.101.22:8201" + ``` + + The `storage_source` stanza should be the current storage type (`consul`) + configuration, and the `storage_destination` points to the [Integrated Storage + (`raft`) + configuration](/vault/docs/configuration/storage/raft). + + The `path` and `node_id` values must match the values you set in the server + configuration file. + + + + The `/vault/raft/` path must exist on the host machine. The + migration command will not create the folder for you. + + + +1. Execute the `vault operator` command to perform the migration. + + ```shell-session + $ vault operator migrate -config=migrate.hcl + ``` + + Refer to the Vault command documentation on [operator + migrate](/vault/docs/commands/operator/migrate#migrating-to-integrated-raft-storage) + for more information. + +1. You can start the Vault server using the new server configuration pointing to + the `raft` storage and unseal. + + At this point, there is just one raft cluster member. + + ```shell-session + $ vault operator raft list-peers + + Node Address State Voter + ---- ------- ----- ----- + node_1 https://10.0.101.22:8201 leader true + ``` + +1. Start the remaining Vault nodes in the cluster and add each node to the + cluster using the `vault operator raft join` command. If the configuration + enables [`retry_join`](/vault/docs/configuration/storage/raft#retry_join-stanza), + then there is no need to invoke the `raft join` command. The follower + nodes join the cluster automatically in this case. + + ```shell-session + $ vault operator raft join https://13.57.14.206:8200 + ``` + + While `https://13.57.14.206:8200` is the leader node's `api_addr`. + + If you are not familiar with how the HA cluster with Integrated Storage works, + read the [Vault HA Cluster with Integrated + Storage](/vault/tutorials/raft/raft-storage) tutorial to familiarize yourself with + the Integrated Storage. + +## Vault Enterprise Replication + +If you have multi-datacenter Vault Enterprise Replication deployments such as +the diagram, read the recommendation in this section. + + + +![Vault Enterprise Replication](/img/vault-ent-replication.png) + + + +### Recommended approach for Vault Enterprise + +1. Stop the DR secondary cluster (Cluster 4 in the diagram above as an example). + +1. [Create a new Vault cluster](/vault/tutorials/raft/raft-storage) configured with + Integrated Storage (Cluster 5 in the diagram) and [add it as a new DR + secondary](/vault/tutorials/enterprise/disaster-recovery#enable-dr-secondary-replication). + + + + ![Vault Enterprise Replication](/img/vault-ent-replication-2.png) + + + +1. As some workload comes through, monitor that the [DR secondary cluster is + catching up with its primary + cluster](/vault/tutorials/monitoring/monitor-replication#are-my-dr-clusters-in-sync) + (Cluster 2) which is still using Consul as storage. If there is no + issue, you can stop and decommission the old secondary cluster (Cluster 4) at this + point. + +1. Stop the primary cluster (Cluster 2) and [promote the DR + secondary](/vault/tutorials/enterprise/disaster-recovery#promote-dr-secondary-to-primary) + (Cluster 5) to be the new primary. + + If the cluster is a performance secondary, check to make sure that it is + [syncing up with its performance + primary](/vault/tutorials/monitoring/monitor-replication#are-my-performance-clusters-in-sync) + (Cluster 1). + +1. Repeat the step by creating a new cluster configured with Integrated Storage + (Cluster 6) and add it as a DR secondary to the new primary (Cluster 5). + + + + ![Vault Enterprise Replication](/img/vault-ent-replication-3.png) + + + + Monitor that [it syncs up with its + primary](/vault/tutorials/monitoring/monitor-replication#are-my-dr-clusters-in-sync) + as some workload comes through. Finally, you can terminate the old primary + cluster (Cluster 2). + +Repeat the same workflow to migrate the Vault data to Integrated Storage on the +performance primary (Cluster 1) and its DR secondary (Cluster 3). + +## Post-migration health check + +Once you migrate the storage, verify that the cluster is healthy, and check +logs for any unusual errors related to cluster health. Refer to the +following guidance to learn more: + +- [Troubleshooting Vault - Vault Logs](/vault/tutorials/monitoring/troubleshooting-vault#vault-logs) +- If you have Vault Enterprise Replication environment, refer to the [Monitoring Vault Replication](/vault/tutorials/monitoring/monitor-replication) + +## Help and reference + +- Vault command documentation on [operator migrate](/vault/docs/commands/operator/migrate#migrating-to-integrated-raft-storage) +- [Integrated Storage documentation](/vault/docs/internals/integrated-storage) +- [Integrated Storage Concepts](/vault/docs/concepts/integrated-storage) +- [Upgrading Vault guide](/vault/docs/upgrading) +- [Inspect Data in Integrated Storage](/vault/tutorials/monitoring/inspect-data-integrated-storage) diff --git a/website/content/docs/enterprise/license/utilization-reporting.mdx b/website/content/docs/enterprise/license/utilization-reporting.mdx index 615a261fc367..7625d3249b17 100644 --- a/website/content/docs/enterprise/license/utilization-reporting.mdx +++ b/website/content/docs/enterprise/license/utilization-reporting.mdx @@ -10,12 +10,7 @@ description: >- @include 'alerts/enterprise-only.mdx' Automated license utilization reporting sends license utilization data to -HashiCorp without requiring you to manually collect and report them. It also -lets you review your license usage with the monitoring solution you already use -(for example Splunk, Datadog, or others) so you can optimize and manage your -deployments. Use these reports to understand how much more you can deploy under -your current contract, protect against overutilization, and budget for predicted -consumption. +HashiCorp without requiring you to manually collect and report them. Automated reporting shares the minimum data required to validate license utilization as defined in our contracts. They consist of mostly computed metrics @@ -228,20 +223,20 @@ HashiCorp collects the following utilization data as JSON payloads: - `nonentity` - The sum of tokens without an entity attached - `metadata` - Optional product-specific metadata - `billing_start` - The billing start date associated with the reporting cluster (license start date if not configured). - + - - As of 1.16.7, 1.17.3 and later, - the billing start date automatically + + As of 1.16.7, 1.17.3 and later, + the billing start date automatically rolls over to the latest billing year at the end of the last cycle. - + For more information, refer to the upgrade guide for your Vault version: [Vault v1.16.x](/vault/docs/upgrading/upgrade-to-1.16.x#auto-rolled-billing-start-date), [Vault v1.17.x](/vault/docs/upgrading/upgrade-to-1.17.x#auto-rolled-billing-start-date) - - + + - `cluster_id` - The cluster UUID as shown by `vault status` on the reporting cluster diff --git a/website/data/docs-nav-data.json b/website/data/docs-nav-data.json index 6a12ed1bd2cc..b90a8a9af906 100644 --- a/website/data/docs-nav-data.json +++ b/website/data/docs-nav-data.json @@ -267,6 +267,10 @@ { "title": "Migration checklist", "path": "concepts/integrated-storage/migration-checklist" + }, + { + "title": "Migrate Consul storage", + "path": "concepts/integrated-storage/migrate-consul-storage" } ] }, diff --git a/website/public/img/vault-ent-replication-2.png b/website/public/img/vault-ent-replication-2.png new file mode 100644 index 000000000000..b859c937f533 Binary files /dev/null and b/website/public/img/vault-ent-replication-2.png differ diff --git a/website/public/img/vault-ent-replication-3.png b/website/public/img/vault-ent-replication-3.png new file mode 100644 index 000000000000..b4b5a34ef223 Binary files /dev/null and b/website/public/img/vault-ent-replication-3.png differ diff --git a/website/public/img/vault-ent-replication.png b/website/public/img/vault-ent-replication.png new file mode 100644 index 000000000000..f912ed626f97 Binary files /dev/null and b/website/public/img/vault-ent-replication.png differ