From 2680f0b1980f58982346531678aba06f9aec1890 Mon Sep 17 00:00:00 2001 From: Vinny Mannello <94396874+VinnyHC@users.noreply.github.com> Date: Wed, 22 Dec 2021 15:36:47 -0800 Subject: [PATCH] [Vault-4628] OpenAPI endpoint not expanding root alternations (#13487) --- changelog/13487.txt | 3 +++ sdk/framework/openapi.go | 30 +++++++++++++++++++++--------- sdk/framework/openapi_test.go | 4 ++++ 3 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 changelog/13487.txt diff --git a/changelog/13487.txt b/changelog/13487.txt new file mode 100644 index 000000000..1df81d25a --- /dev/null +++ b/changelog/13487.txt @@ -0,0 +1,3 @@ +```release-note:bug +sdk/framework: Generate proper OpenAPI specs for path patterns that use an alternation as the root. +``` \ No newline at end of file diff --git a/sdk/framework/openapi.go b/sdk/framework/openapi.go index 02667cda4..4c9d073f0 100644 --- a/sdk/framework/openapi.go +++ b/sdk/framework/openapi.go @@ -191,15 +191,16 @@ var OASStdRespNoContent = &OASResponse{ var optRe = regexp.MustCompile(`(?U)\([^(]*\)\?|\(/\(\?P<[^(]*\)\)\?`) var ( - reqdRe = regexp.MustCompile(`\(?\?P<(\w+)>[^)]*\)?`) // Capture required parameters, e.g. "(?Pregex)" - altRe = regexp.MustCompile(`\((.*)\|(.*)\)`) // Capture alternation elements, e.g. "(raw/?$|raw/(?P.+))" - pathFieldsRe = regexp.MustCompile(`{(\w+)}`) // Capture OpenAPI-style named parameters, e.g. "lookup/{urltoken}", - cleanCharsRe = regexp.MustCompile("[()^$?]") // Set of regex characters that will be stripped during cleaning - cleanSuffixRe = regexp.MustCompile(`/\?\$?$`) // Path suffix patterns that will be stripped during cleaning - wsRe = regexp.MustCompile(`\s+`) // Match whitespace, to be compressed during cleaning - altFieldsGroupRe = regexp.MustCompile(`\(\?P<\w+>\w+(\|\w+)+\)`) // Match named groups that limit options, e.g. "(?a|b|c)" - altFieldsRe = regexp.MustCompile(`\w+(\|\w+)+`) // Match an options set, e.g. "a|b|c" - nonWordRe = regexp.MustCompile(`[^\w]+`) // Match a sequence of non-word characters + altFieldsGroupRe = regexp.MustCompile(`\(\?P<\w+>\w+(\|\w+)+\)`) // Match named groups that limit options, e.g. "(?a|b|c)" + altFieldsRe = regexp.MustCompile(`\w+(\|\w+)+`) // Match an options set, e.g. "a|b|c" + altRe = regexp.MustCompile(`\((.*)\|(.*)\)`) // Capture alternation elements, e.g. "(raw/?$|raw/(?P.+))" + altRootsRe = regexp.MustCompile(`^\(([\w\-_]+(?:\|[\w\-_]+)+)\)(/.*)$`) // Pattern starting with alts, e.g. "(root1|root2)/(?Pregex)" + cleanCharsRe = regexp.MustCompile("[()^$?]") // Set of regex characters that will be stripped during cleaning + cleanSuffixRe = regexp.MustCompile(`/\?\$?$`) // Path suffix patterns that will be stripped during cleaning + nonWordRe = regexp.MustCompile(`[^\w]+`) // Match a sequence of non-word characters + pathFieldsRe = regexp.MustCompile(`{(\w+)}`) // Capture OpenAPI-style named parameters, e.g. "lookup/{urltoken}", + reqdRe = regexp.MustCompile(`\(?\?P<(\w+)>[^)]*\)?`) // Capture required parameters, e.g. "(?Pregex)" + wsRe = regexp.MustCompile(`\s+`) // Match whitespace, to be compressed during cleaning ) // documentPaths parses all paths in a framework.Backend into OpenAPI paths. @@ -464,6 +465,17 @@ func specialPathMatch(path string, specialPaths []string) bool { func expandPattern(pattern string) []string { var paths []string + // Determine if the pattern starts with an alternation for multiple roots + // example (root1|root2)/(?Pregex) -> match['(root1|root2)/(?Pregex)','root1|root2','/(?Pregex)'] + match := altRootsRe.FindStringSubmatch(pattern) + if len(match) == 3 { + var expandedRoots []string + for _, root := range strings.Split(match[1], "|") { + expandedRoots = append(expandedRoots, expandPattern(root+match[2])...) + } + return expandedRoots + } + // GenericNameRegex adds a regex that complicates our parsing. It is much easier to // detect and remove it now than to compensate for in the other regexes. // diff --git a/sdk/framework/openapi_test.go b/sdk/framework/openapi_test.go index 3efbecc61..9c7226820 100644 --- a/sdk/framework/openapi_test.go +++ b/sdk/framework/openapi_test.go @@ -199,6 +199,10 @@ func TestOpenAPI_ExpandPattern(t *testing.T) { {"^plugins/catalog/(?Pauth|database|secret)/?$", []string{ "plugins/catalog/{type}", }}, + {"(pathOne|pathTwo)/", []string{"pathOne/", "pathTwo/"}}, + {"(pathOne|pathTwo)/" + GenericNameRegex("name"), []string{"pathOne/{name}", "pathTwo/{name}"}}, + {"(pathOne|path-2|Path_3)/" + GenericNameRegex("name"), + []string{"Path_3/{name}", "path-2/{name}", "pathOne/{name}"}}, } for i, test := range tests {