-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix multiple OpenAPI generation issues with new AST-based generator #18554
Fix multiple OpenAPI generation issues with new AST-based generator #18554
Conversation
The paths including `/.well-known/` in the Vault API could currently technically be invoked with any random character in place of the dot.
sdk/framework/openapi.go
Outdated
if err != nil { | ||
// Pattern cannot be transformed into sensible OpenAPI paths, so drop it entirely. | ||
// See lengthier comment inside collectPathsFromRegexpASTInternal below for more detailed discussion. | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was undecided as to whether I should add trace-level logging at this point.
On the plus side: It makes it easier for plugin developers to find out this condition is being hit.
On the minus side: It is additional logging which is uninteresting to server operators, as there is nothing that can be done to change it other than rebuilding the Vault or plugin binary, and it will trigger every time sys/internal/specs/openapi
or any relevant HelpOperation is invoked.
One alternative approach here would be to move the check to Backend.init, which is already set up to panic on initialisation if a backend author writes an empty or uncompilable path pattern - this could be expanded to include impossible-to-OpenAPI patterns not also marked as Unpublished. (I furthermore have another open PR, #18492, which seeks to add a check for CreateOperation being defined without an ExistenceCheck at the same point.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps a reasonable compromise could be added to change this error:
return nil, fmt.Errorf("pattern could not be translated for OpenAPI due to %v operation", rx.Op)
into a named error and then capturing it here with if errors.Is(...) { return nil }
. The advantage of this approach is that the code will be explicit about the intention of skipping specific regex operations. If collectPathsFromRegexpASTInternal
is modified in the future to return other errors, those will be propagated correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
@@ -18,75 +18,6 @@ import ( | |||
) | |||
|
|||
func TestOpenAPI_Regex(t *testing.T) { | |||
t.Run("Required", func(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are all of these tests just not doing anything any more, or is there a need for more test cases to be added back in place of these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of the tests being deleted, test the behaviour of various ad-hoc regexps, which were being used to parse other regexps (!).
They have all been deleted, and their job replaced by regexp/syntax
from the Go standard library.
The new code that has been written to process the output of the stdlib's regexp/syntax
is already well-exercised by the existing TestOpenAPI_ExpandPattern
- although, I could add some additional inputs and expected outputs to that test, which would fail with the old implementation, but pass with this rewritten one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could add some additional inputs and expected outputs to that test, which would fail with the old implementation, but pass with this rewritten one.
These would be awesome! I would also love to see some of the edge cases tested like ".*" that you mentioned in the comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I love this approach, I think it will be a great improvement to the stability of the generated OpenAPI output!
sdk/framework/openapi.go
Outdated
if err != nil { | ||
// Pattern cannot be transformed into sensible OpenAPI paths, so drop it entirely. | ||
// See lengthier comment inside collectPathsFromRegexpASTInternal below for more detailed discussion. | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps a reasonable compromise could be added to change this error:
return nil, fmt.Errorf("pattern could not be translated for OpenAPI due to %v operation", rx.Op)
into a named error and then capturing it here with if errors.Is(...) { return nil }
. The advantage of this approach is that the code will be explicit about the intention of skipping specific regex operations. If collectPathsFromRegexpASTInternal
is modified in the future to return other errors, those will be propagated correctly.
@@ -18,75 +18,6 @@ import ( | |||
) | |||
|
|||
func TestOpenAPI_Regex(t *testing.T) { | |||
t.Run("Required", func(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could add some additional inputs and expected outputs to that test, which would fail with the old implementation, but pass with this rewritten one.
These would be awesome! I would also love to see some of the edge cases tested like ".*" that you mentioned in the comments.
Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>
t.Fatalf("response size too small; expected: min %d, actual: %d", minLen, len(body)) | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note for reviewer: this test is being removed because it was a partial copy of the next test, just changed to have generic_mount_paths=true.
Since I needed to make changes, and didn't want to have to update both copies of the duplicated code, I resolved the duplication.
func TestSystemBackend_OpenAPI(t *testing.T) { | ||
_, b, rootToken := testCoreSystemBackend(t) | ||
var oapi map[string]interface{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note for reviewer: You're going to want to view this part of the diff ignoring whitespace.
I noticed there was potential cross-talk between local variables in different parts of this function, so I introduced enclosing scopes so each part of the function is defining its own local variables.
{path: "/auth/token/lookup", tag: "auth"}, | ||
{path: "/cubbyhole/{path}", tag: "secrets"}, | ||
{path: "/identity/group/id", tag: "identity"}, | ||
{path: expectedSecretPrefix + "^.*$", unpublished: true}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note for reviewer: This secret
thing here is actually neither a KV v1 nor a KV v2, it's actually the builtin passthrough backend within the Vault core, which has its own path regexp which is different to the real KV v1 that users use.
You can see here that the old code generated a path of .*
(because it strips out the anchor metacharacters), whereas the new code leaves them in, giving ^.*$
- I think that's an accidental improvement, as it makes it even more clear this is a weird edge case.
Since the new code forces operations whose regexps can't be successfully translated to OpenAPI patterns to be unpublished, the test expectations arae being updated accordingly.
All feedback addressed and CircleCI is now happy. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍 This is an awesome contribution! Thanks for fixing all the tests & adding new ones.
Skipping most OpenAPI tests as fix on 1.13 wasn't backported. See also: #18554 Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Skipping most OpenAPI tests as fix on 1.13 wasn't backported. See also: #18554 Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
…o release/1.12.x (#19712) * Split (un,)authenticated issuer fetch endpoints Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add tests to validate endpoint authentication status Skipping most OpenAPI tests as fix on 1.13 wasn't backported. See also: #18554 Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> --------- Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> Co-authored-by: Alexander Scheel <alex.scheel@hashicorp.com>
…o release/1.11.x (#19711) * Split (un,)authenticated issuer fetch endpoints Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add tests to validate endpoint authentication status Skipping most OpenAPI tests as fix on 1.13 wasn't backported. See also: #18554 Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> --------- Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> Co-authored-by: Alexander Scheel <alex.scheel@hashicorp.com>
…18554) * Regexp metacharacter `.` should be escaped when used literally The paths including `/.well-known/` in the Vault API could currently technically be invoked with any random character in place of the dot. * Replace implementation of OpenAPI path translator with regexp AST-based one * Add changelog * Typo fix from PR review - thanks! Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Add comment based on review feedback * Change style of error handling as suggested in code review * Make a further tweak to the handling of the error case * Add more tests, testing cases which fail with the previous implementation * Resolve issue with a test, and improve comment --------- Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>
…18554) * Regexp metacharacter `.` should be escaped when used literally The paths including `/.well-known/` in the Vault API could currently technically be invoked with any random character in place of the dot. * Replace implementation of OpenAPI path translator with regexp AST-based one * Add changelog * Typo fix from PR review - thanks! Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Add comment based on review feedback * Change style of error handling as suggested in code review * Make a further tweak to the handling of the error case * Add more tests, testing cases which fail with the previous implementation * Resolve issue with a test, and improve comment --------- Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>
… generator into release/1.12.x (#19718) * Fix multiple OpenAPI generation issues with new AST-based generator (#18554) * Regexp metacharacter `.` should be escaped when used literally The paths including `/.well-known/` in the Vault API could currently technically be invoked with any random character in place of the dot. * Replace implementation of OpenAPI path translator with regexp AST-based one * Add changelog * Typo fix from PR review - thanks! Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Add comment based on review feedback * Change style of error handling as suggested in code review * Make a further tweak to the handling of the error case * Add more tests, testing cases which fail with the previous implementation * Resolve issue with a test, and improve comment --------- Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * fix test for generic mount paths --------- Co-authored-by: Max Bowsher <maxbowsher@gmail.com> Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> Co-authored-by: Anton Averchenkov <anton.averchenkov@hashicorp.com>
… generator into release/1.11.x (#19717) * Fix multiple OpenAPI generation issues with new AST-based generator (#18554) * Regexp metacharacter `.` should be escaped when used literally The paths including `/.well-known/` in the Vault API could currently technically be invoked with any random character in place of the dot. * Replace implementation of OpenAPI path translator with regexp AST-based one * Add changelog * Typo fix from PR review - thanks! Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Add comment based on review feedback * Change style of error handling as suggested in code review * Make a further tweak to the handling of the error case * Add more tests, testing cases which fail with the previous implementation * Resolve issue with a test, and improve comment --------- Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Fix test --------- Co-authored-by: Max Bowsher <maxbowsher@gmail.com> Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> Co-authored-by: Anton Averchenkov <anton.averchenkov@hashicorp.com>
Currently, the Vault OpenAPI generator attempts to use a variety of ad-hoc regexps, to simplify the path regexps that are the canonical specification of URL paths in Vault backends, and convert them into OpenAPI URL patterns. Regexps are not well suited to parsing regexps, and this approach is fragile and incomplete.
Happily, the Go regexp library provides easy access to its string-to-AST parser, so we can just ask it to parse the regexps for us, and then walk the resulting AST for a more reliable translation from regexps to OpenAPI patterns - this PR makes that change.
Whilst developing this change, it came to light that there are incorrectly unescaped full stops in some existing patterns - so the dot in
/.well-known/
could in fact be any character. These are now properly escaped.As a result of these changes, the OpenAPI document changes in the following ways:
In the AWS secrets engine, the
/creds/{name}
endpoint was being incorrectly documented as/creds
- fixed (closes #18488).In the GCP secrets engine, the
/roleset
and/static-account
endpoints were missing - fixed.In the KV v2 secrets engine, the/.*
endpoint, which already had no visible operations since they are all marked asUnpublished
, is now removed from the OpenAPI document entirely, since'/.*
is not a valid OpenAPI path pattern.In the PKI secrets engine, widespread inaccuracies are fixed (closes #18484):
The following endpoints, which were incorrectly undocumented, are added:
The following endpoints, which were documented but don't actually exist, are removed:
In the RADIUS auth method,
/login
endpoint no longer documents an incorrecturlusername
field in the request body.In the
/sys/plugins/catalog/{type}/{name}
endpoint, thetype
parameter is now no longer also incorrectly included in the request body.In the
/sys/tools/hash
endpoints, theurlalgorithm
parameter is now no longer incorrectly included in the request body.In the
/sys/tools/random
and/transit/random
endpoints, thesource
andurlbytes
parameters are now no longer incorrectly included in the request body.In various
/transit/
endpoints, theurlalgorithm
parameter is now no longer incorrectly included in the request body.In the
/transit/restore
endpoints, thename
parameter is now no longer incorrectly included in the request body.These "parameter is now no longer incorrectly included in the request body" fixes are helpful, but accidental, and dependent on another bug - the request schema for multiple expansions for the same endpoint overwrites each other, with last generated wins, and the generation is simply happening in a more convenient order in this version of the code.