From b35ded0cb8908916d58f352de2b02187930adaac Mon Sep 17 00:00:00 2001 From: Marc Boudreau Date: Wed, 17 May 2023 14:56:45 -0400 Subject: [PATCH] VAULT-16217 Fixing Broken OpenAPI Specification Generation (#20597) * including path parameters into stub Paths for enterprise-only endpoints * Set Required to true for path parameters in enterprise-only path stubs Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * properly format go code * re-adding initialization of Fields and Operations fields in the stubbed Path struct --------- Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> --- vault/logical_system_helpers.go | 199 +++++++++++++++++--------------- 1 file changed, 106 insertions(+), 93 deletions(-) diff --git a/vault/logical_system_helpers.go b/vault/logical_system_helpers.go index 95c26504b..c702b39ae 100644 --- a/vault/logical_system_helpers.go +++ b/vault/logical_system_helpers.go @@ -16,6 +16,11 @@ import ( "github.com/hashicorp/vault/sdk/logical" ) +type enterprisePathStub struct { + parameters []string + operations []logical.Operation +} + var ( invalidateMFAConfig = func(context.Context, *SystemBackend, string) {} invalidateLoginMFAConfig = func(context.Context, *SystemBackend, string) {} @@ -62,23 +67,31 @@ var ( entPaths = entStubPaths entStubPaths = func(b *SystemBackend) []*framework.Path { - buildEnterpriseOnlyPaths := func(paths map[string][]logical.Operation) []*framework.Path { + buildEnterpriseOnlyPaths := func(paths map[string]enterprisePathStub) []*framework.Path { var results []*framework.Path - for pattern, operations := range paths { - operationsMap := map[logical.Operation]framework.OperationHandler{} + for pattern, pathSpec := range paths { + path := &framework.Path{ + Pattern: pattern, + Operations: make(map[logical.Operation]framework.OperationHandler), + Fields: make(map[string]*framework.FieldSchema), + } - for _, operation := range operations { - operationsMap[operation] = &framework.PathOperation{ + for _, parameter := range pathSpec.parameters { + path.Fields[parameter] = &framework.FieldSchema{ + Type: framework.TypeString, + Required: true, + } + } + + for _, operation := range pathSpec.operations { + path.Operations[operation] = &framework.PathOperation{ Callback: func(context.Context, *logical.Request, *framework.FieldData) (*logical.Response, error) { return logical.ErrorResponse("enterprise-only feature"), logical.ErrUnsupportedPath }, } } - results = append(results, &framework.Path{ - Pattern: pattern, - Operations: operationsMap, - }) + results = append(results, path) } return results @@ -87,66 +100,66 @@ var ( var paths []*framework.Path // license paths - paths = append(paths, buildEnterpriseOnlyPaths(map[string][]logical.Operation{ - "license/status$": {logical.ReadOperation}, + paths = append(paths, buildEnterpriseOnlyPaths(map[string]enterprisePathStub{ + "license/status$": {operations: []logical.Operation{logical.ReadOperation}}, })...) // group-policy-application paths - paths = append(paths, buildEnterpriseOnlyPaths(map[string][]logical.Operation{ - "config/group-policy-application$": {logical.ReadOperation, logical.UpdateOperation}, + paths = append(paths, buildEnterpriseOnlyPaths(map[string]enterprisePathStub{ + "config/group-policy-application$": {operations: []logical.Operation{logical.ReadOperation, logical.UpdateOperation}}, })...) // namespaces paths - paths = append(paths, buildEnterpriseOnlyPaths(map[string][]logical.Operation{ - "namespaces/?$": {logical.ListOperation}, - "namespaces/api-lock/lock" + framework.OptionalParamRegex("path"): {logical.UpdateOperation}, - "namespaces/api-lock/unlock" + framework.OptionalParamRegex("path"): {logical.UpdateOperation}, - "namespaces/(?P.+?)": {logical.DeleteOperation, logical.PatchOperation, logical.ReadOperation, logical.UpdateOperation}, + paths = append(paths, buildEnterpriseOnlyPaths(map[string]enterprisePathStub{ + "namespaces/?$": {operations: []logical.Operation{logical.ListOperation}}, + "namespaces/api-lock/lock" + framework.OptionalParamRegex("path"): {parameters: []string{"path"}, operations: []logical.Operation{logical.UpdateOperation}}, + "namespaces/api-lock/unlock" + framework.OptionalParamRegex("path"): {parameters: []string{"path"}, operations: []logical.Operation{logical.UpdateOperation}}, + "namespaces/(?P.+?)": {parameters: []string{"path"}, operations: []logical.Operation{logical.DeleteOperation, logical.PatchOperation, logical.ReadOperation, logical.UpdateOperation}}, })...) // replication paths - paths = append(paths, buildEnterpriseOnlyPaths(map[string][]logical.Operation{ - "replication/performance/primary/enable": {logical.UpdateOperation}, - "replication/dr/primary/enable": {logical.UpdateOperation}, - "replication/performance/primary/demote": {logical.UpdateOperation}, - "replication/dr/primary/demote": {logical.UpdateOperation}, - "replication/performance/primary/disable": {logical.UpdateOperation}, - "replication/dr/primary/disable": {logical.UpdateOperation}, - "replication/performance/primary/secondary-token": {logical.UpdateOperation}, - "replication/dr/primary/secondary-token": {logical.UpdateOperation}, - "replication/performance/primary/revoke-secondary": {logical.UpdateOperation}, - "replication/dr/primary/revoke-secondary": {logical.UpdateOperation}, - "replication/performance/secondary/generate-public-key": {logical.UpdateOperation}, - "replication/dr/secondary/generate-public-key": {logical.UpdateOperation}, - "replication/performance/secondary/enable": {logical.UpdateOperation}, - "replication/dr/secondary/enable": {logical.UpdateOperation}, - "replication/performance/secondary/promote": {logical.UpdateOperation}, - "replication/dr/secondary/promote": {logical.UpdateOperation}, - "replication/performance/secondary/disable": {logical.UpdateOperation}, - "replication/dr/secondary/disable": {logical.UpdateOperation}, - "replication/dr/secondary/operation-token/delete": {logical.UpdateOperation}, - "replication/performance/secondary/update-primary": {logical.UpdateOperation}, - "replication/dr/secondary/update-primary": {logical.UpdateOperation}, - "replication/dr/secondary/license/status": {logical.ReadOperation}, - "replication/dr/secondary/config/reload/(?P.+)": {logical.UpdateOperation}, - "replication/recover": {logical.UpdateOperation}, - "replication/dr/secondary/recover": {logical.UpdateOperation}, - "replication/dr/secondary/reindex": {logical.UpdateOperation}, - "replication/reindex": {logical.UpdateOperation}, - "replication/dr/status": {logical.ReadOperation}, - "replication/performance/status": {logical.ReadOperation}, - "replication/primary/enable": {logical.UpdateOperation}, - "replication/primary/demote": {logical.UpdateOperation}, - "replication/primary/disable": {logical.UpdateOperation}, - "replication/primary/secondary-token": {logical.UpdateOperation}, - "replication/performance/primary/paths-filter/" + framework.GenericNameRegex("id"): {logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}, - "replication/performance/primary/dynamic-filter/" + framework.GenericNameRegex("id"): {logical.ReadOperation}, - "replication/primary/revoke-secondary": {logical.UpdateOperation}, - "replication/secondary/enable": {logical.UpdateOperation}, - "replication/secondary/promote": {logical.UpdateOperation}, - "replication/secondary/disable": {logical.UpdateOperation}, - "replication/secondary/update-primary": {logical.UpdateOperation}, - "replication/performance/secondary/dynamic-filter/" + framework.GenericNameRegex("id"): {logical.ReadOperation}, + paths = append(paths, buildEnterpriseOnlyPaths(map[string]enterprisePathStub{ + "replication/performance/primary/enable": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/primary/enable": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/performance/primary/demote": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/primary/demote": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/performance/primary/disable": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/primary/disable": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/performance/primary/secondary-token": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/primary/secondary-token": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/performance/primary/revoke-secondary": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/primary/revoke-secondary": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/performance/secondary/generate-public-key": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/secondary/generate-public-key": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/performance/secondary/enable": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/secondary/enable": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/performance/secondary/promote": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/secondary/promote": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/performance/secondary/disable": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/secondary/disable": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/secondary/operation-token/delete": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/performance/secondary/update-primary": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/secondary/update-primary": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/secondary/license/status": {operations: []logical.Operation{logical.ReadOperation}}, + "replication/dr/secondary/config/reload/(?P.+)": {parameters: []string{"subsystem"}, operations: []logical.Operation{logical.UpdateOperation}}, + "replication/recover": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/secondary/recover": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/secondary/reindex": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/reindex": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/dr/status": {operations: []logical.Operation{logical.ReadOperation}}, + "replication/performance/status": {operations: []logical.Operation{logical.ReadOperation}}, + "replication/primary/enable": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/primary/demote": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/primary/disable": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/primary/secondary-token": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/performance/primary/paths-filter/" + framework.GenericNameRegex("id"): {parameters: []string{"id"}, operations: []logical.Operation{logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}}, + "replication/performance/primary/dynamic-filter/" + framework.GenericNameRegex("id"): {parameters: []string{"id"}, operations: []logical.Operation{logical.ReadOperation}}, + "replication/primary/revoke-secondary": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/secondary/enable": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/secondary/promote": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/secondary/disable": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/secondary/update-primary": {operations: []logical.Operation{logical.UpdateOperation}}, + "replication/performance/secondary/dynamic-filter/" + framework.GenericNameRegex("id"): {parameters: []string{"id"}, operations: []logical.Operation{logical.ReadOperation}}, })...) // This path, though an enterprise path, has always been handled in OSS. paths = append(paths, &framework.Path{ @@ -164,59 +177,59 @@ var ( }) // seal paths - paths = append(paths, buildEnterpriseOnlyPaths(map[string][]logical.Operation{ - "sealwrap/rewrap": {logical.ReadOperation, logical.UpdateOperation}, + paths = append(paths, buildEnterpriseOnlyPaths(map[string]enterprisePathStub{ + "sealwrap/rewrap": {operations: []logical.Operation{logical.ReadOperation, logical.UpdateOperation}}, })...) // mfa paths - paths = append(paths, buildEnterpriseOnlyPaths(map[string][]logical.Operation{ - "mfa/method/?": {logical.ListOperation}, - "mfa/method/totp/" + framework.GenericNameRegex("name") + "/generate$": {logical.ReadOperation}, - "mfa/method/totp/" + framework.GenericNameRegex("name") + "/admin-generate$": {logical.UpdateOperation}, - "mfa/method/totp/" + framework.GenericNameRegex("name") + "/admin-destroy$": {logical.UpdateOperation}, - "mfa/method/totp/" + framework.GenericNameRegex("name"): {logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}, - "mfa/method/okta/" + framework.GenericNameRegex("name"): {logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}, - "mfa/method/duo/" + framework.GenericNameRegex("name"): {logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}, - "mfa/method/pingid/" + framework.GenericNameRegex("name"): {logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}, + paths = append(paths, buildEnterpriseOnlyPaths(map[string]enterprisePathStub{ + "mfa/method/?": {operations: []logical.Operation{logical.ListOperation}}, + "mfa/method/totp/" + framework.GenericNameRegex("name") + "/generate$": {parameters: []string{"name"}, operations: []logical.Operation{logical.ReadOperation}}, + "mfa/method/totp/" + framework.GenericNameRegex("name") + "/admin-generate$": {parameters: []string{"name"}, operations: []logical.Operation{logical.UpdateOperation}}, + "mfa/method/totp/" + framework.GenericNameRegex("name") + "/admin-destroy$": {parameters: []string{"name"}, operations: []logical.Operation{logical.UpdateOperation}}, + "mfa/method/totp/" + framework.GenericNameRegex("name"): {parameters: []string{"name"}, operations: []logical.Operation{logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}}, + "mfa/method/okta/" + framework.GenericNameRegex("name"): {parameters: []string{"name"}, operations: []logical.Operation{logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}}, + "mfa/method/duo/" + framework.GenericNameRegex("name"): {parameters: []string{"name"}, operations: []logical.Operation{logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}}, + "mfa/method/pingid/" + framework.GenericNameRegex("name"): {parameters: []string{"name"}, operations: []logical.Operation{logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}}, })...) // control-group paths - paths = append(paths, buildEnterpriseOnlyPaths(map[string][]logical.Operation{ - "control-group/authorize": {logical.UpdateOperation}, - "control-group/request": {logical.UpdateOperation}, - "config/control-group": {logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}, + paths = append(paths, buildEnterpriseOnlyPaths(map[string]enterprisePathStub{ + "control-group/authorize": {operations: []logical.Operation{logical.UpdateOperation}}, + "control-group/request": {operations: []logical.Operation{logical.UpdateOperation}}, + "config/control-group": {operations: []logical.Operation{logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}}, })...) // sentinel paths - paths = append(paths, buildEnterpriseOnlyPaths(map[string][]logical.Operation{ - "policies/rgp/?$": {logical.ListOperation}, - "policies/rgp/(?P.+)": {logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}, - "policies/egp/?$": {logical.ListOperation}, - "policies/egp/(?P.+)": {logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}, + paths = append(paths, buildEnterpriseOnlyPaths(map[string]enterprisePathStub{ + "policies/rgp/?$": {operations: []logical.Operation{logical.ListOperation}}, + "policies/rgp/(?P.+)": {parameters: []string{"name"}, operations: []logical.Operation{logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}}, + "policies/egp/?$": {operations: []logical.Operation{logical.ListOperation}}, + "policies/egp/(?P.+)": {parameters: []string{"name"}, operations: []logical.Operation{logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}}, })...) // plugins reload status paths - paths = append(paths, buildEnterpriseOnlyPaths(map[string][]logical.Operation{ - "plugins/reload/backend/status$": {logical.ReadOperation}, + paths = append(paths, buildEnterpriseOnlyPaths(map[string]enterprisePathStub{ + "plugins/reload/backend/status$": {operations: []logical.Operation{logical.ReadOperation}}, })...) // quotas paths - paths = append(paths, buildEnterpriseOnlyPaths(map[string][]logical.Operation{ - "quotas/lease-count/?$": {logical.ListOperation}, - "quotas/lease-count/" + framework.GenericNameRegex("name"): {logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}, + paths = append(paths, buildEnterpriseOnlyPaths(map[string]enterprisePathStub{ + "quotas/lease-count/?$": {operations: []logical.Operation{logical.ListOperation}}, + "quotas/lease-count/" + framework.GenericNameRegex("name"): {parameters: []string{"name"}, operations: []logical.Operation{logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}}, })...) // raft auto-snapshot paths - paths = append(paths, buildEnterpriseOnlyPaths(map[string][]logical.Operation{ - "storage/raft/snapshot-auto/config/": {logical.ListOperation}, - "storage/raft/snapshot-auto/config/" + framework.GenericNameRegex("name"): {logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}, - "storage/raft/snapshot-auto/status/" + framework.GenericNameRegex("name"): {logical.ReadOperation}, + paths = append(paths, buildEnterpriseOnlyPaths(map[string]enterprisePathStub{ + "storage/raft/snapshot-auto/config/": {operations: []logical.Operation{logical.ListOperation}}, + "storage/raft/snapshot-auto/config/" + framework.GenericNameRegex("name"): {parameters: []string{"name"}, operations: []logical.Operation{logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}}, + "storage/raft/snapshot-auto/status/" + framework.GenericNameRegex("name"): {parameters: []string{"name"}, operations: []logical.Operation{logical.ReadOperation}}, })...) - paths = append(paths, buildEnterpriseOnlyPaths(map[string][]logical.Operation{ - "managed-keys/" + framework.GenericNameRegex("type") + "/?": {logical.ListOperation}, - "managed-keys/" + framework.GenericNameRegex("type") + "/" + framework.GenericNameRegex("name"): {logical.CreateOperation, logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}, - "managed-keys/" + framework.GenericNameRegex("type") + "/" + framework.GenericNameRegex("name") + "/test/sign": {logical.CreateOperation, logical.UpdateOperation}, + paths = append(paths, buildEnterpriseOnlyPaths(map[string]enterprisePathStub{ + "managed-keys/" + framework.GenericNameRegex("type") + "/?": {parameters: []string{"type"}, operations: []logical.Operation{logical.ListOperation}}, + "managed-keys/" + framework.GenericNameRegex("type") + "/" + framework.GenericNameRegex("name"): {parameters: []string{"type", "name"}, operations: []logical.Operation{logical.CreateOperation, logical.DeleteOperation, logical.ReadOperation, logical.UpdateOperation}}, + "managed-keys/" + framework.GenericNameRegex("type") + "/" + framework.GenericNameRegex("name") + "/test/sign": {parameters: []string{"type", "name"}, operations: []logical.Operation{logical.CreateOperation, logical.UpdateOperation}}, })...) return paths