VAULT-12112: add openapi responses for /sys/internal endpoints (#18542)
* added responses for sys/internal/ui/mounts Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com> * responses for internal paths Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com> * added changelog * add schema validation for internal/ui/mounts Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com> * add counters test Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com> * update test to use new method Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com> * use new method in TestSystemBackend_InternalUIMounts Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com> * :rage4: fixed test, diff between core.HandleRequest and backend.HandleRequest Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com> * test feature flags Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com> --------- Signed-off-by: Daniel Huckins <dhuckins@users.noreply.github.com>
This commit is contained in:
parent
ff112ff695
commit
d9229a5fba
3
changelog/18542.txt
Normal file
3
changelog/18542.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
openapi: add openapi response definitions to /sys/internal endpoints
|
||||||
|
```
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/go-test/deep"
|
"github.com/go-test/deep"
|
||||||
"github.com/hashicorp/vault/helper/namespace"
|
"github.com/hashicorp/vault/helper/namespace"
|
||||||
|
"github.com/hashicorp/vault/sdk/helper/testhelpers/schema"
|
||||||
"github.com/hashicorp/vault/sdk/logical"
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,14 +24,22 @@ func testCountActiveTokens(t *testing.T, c *Core, root string) int {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
rootCtx := namespace.RootContext(nil)
|
rootCtx := namespace.RootContext(nil)
|
||||||
resp, err := c.HandleRequest(rootCtx, &logical.Request{
|
req := &logical.Request{
|
||||||
ClientToken: root,
|
ClientToken: root,
|
||||||
Operation: logical.ReadOperation,
|
Operation: logical.ReadOperation,
|
||||||
Path: "sys/internal/counters/tokens",
|
Path: "sys/internal/counters/tokens",
|
||||||
})
|
}
|
||||||
|
resp, err := c.HandleRequest(rootCtx, req)
|
||||||
if err != nil || (resp != nil && resp.IsError()) {
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
t.Fatalf("bad: resp: %#v\n err: %v", resp, err)
|
t.Fatalf("bad: resp: %#v\n err: %v", resp, err)
|
||||||
}
|
}
|
||||||
|
schema.ValidateResponse(
|
||||||
|
t,
|
||||||
|
// we remove the `sys/` prefix b/c Core removes it before routing to the 'sys' backend
|
||||||
|
schema.GetResponseSchema(t, c.systemBackend.Route("internal/counters/tokens"), req.Operation),
|
||||||
|
resp,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
|
||||||
activeTokens := resp.Data["counters"].(*ActiveTokens)
|
activeTokens := resp.Data["counters"].(*ActiveTokens)
|
||||||
return activeTokens.ServiceTokens.Total
|
return activeTokens.ServiceTokens.Total
|
||||||
|
|
|
@ -9,13 +9,15 @@ import (
|
||||||
|
|
||||||
"github.com/hashicorp/go-cleanhttp"
|
"github.com/hashicorp/go-cleanhttp"
|
||||||
vaulthttp "github.com/hashicorp/vault/http"
|
vaulthttp "github.com/hashicorp/vault/http"
|
||||||
|
"github.com/hashicorp/vault/sdk/helper/testhelpers/schema"
|
||||||
"github.com/hashicorp/vault/vault"
|
"github.com/hashicorp/vault/vault"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFeatureFlags(t *testing.T) {
|
func TestFeatureFlags(t *testing.T) {
|
||||||
cluster := vault.NewTestCluster(t, nil, &vault.TestClusterOptions{
|
cluster := vault.NewTestCluster(t, nil, &vault.TestClusterOptions{
|
||||||
HandlerFunc: vaulthttp.Handler,
|
HandlerFunc: vaulthttp.Handler,
|
||||||
|
RequestResponseCallback: schema.ResponseValidatingCallback(t),
|
||||||
})
|
})
|
||||||
cluster.Start()
|
cluster.Start()
|
||||||
defer cluster.Cleanup()
|
defer cluster.Cleanup()
|
||||||
|
|
|
@ -1612,6 +1612,17 @@ func (b *SystemBackend) internalPaths() []*framework.Path {
|
||||||
logical.ReadOperation: &framework.PathOperation{
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
// callback is absent because this is an unauthenticated method
|
// callback is absent because this is an unauthenticated method
|
||||||
Summary: "Lists enabled feature flags.",
|
Summary: "Lists enabled feature flags.",
|
||||||
|
Responses: map[int][]framework.Response{
|
||||||
|
http.StatusOK: {{
|
||||||
|
Description: "OK",
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"feature_flags": {
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-feature-flags"][0]),
|
HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-feature-flags"][0]),
|
||||||
|
@ -1623,6 +1634,23 @@ func (b *SystemBackend) internalPaths() []*framework.Path {
|
||||||
logical.ReadOperation: &framework.PathOperation{
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
Callback: b.pathInternalUIMountsRead,
|
Callback: b.pathInternalUIMountsRead,
|
||||||
Summary: "Lists all enabled and visible auth and secrets mounts.",
|
Summary: "Lists all enabled and visible auth and secrets mounts.",
|
||||||
|
Responses: map[int][]framework.Response{
|
||||||
|
http.StatusOK: {{
|
||||||
|
Description: "OK",
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"secret": {
|
||||||
|
Description: "secret mounts",
|
||||||
|
Type: framework.TypeMap,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
Description: "auth mounts",
|
||||||
|
Type: framework.TypeMap,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-mounts"][0]),
|
HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-mounts"][0]),
|
||||||
|
@ -1640,6 +1668,65 @@ func (b *SystemBackend) internalPaths() []*framework.Path {
|
||||||
logical.ReadOperation: &framework.PathOperation{
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
Callback: b.pathInternalUIMountRead,
|
Callback: b.pathInternalUIMountRead,
|
||||||
Summary: "Return information about the given mount.",
|
Summary: "Return information about the given mount.",
|
||||||
|
Responses: map[int][]framework.Response{
|
||||||
|
http.StatusOK: {{
|
||||||
|
Description: "OK",
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"type": {
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"accessor": {
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"local": {
|
||||||
|
Type: framework.TypeBool,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"seal_wrap": {
|
||||||
|
Type: framework.TypeBool,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"external_entropy_access": {
|
||||||
|
Type: framework.TypeBool,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
Type: framework.TypeMap,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"uuid": {
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"plugin_version": {
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"running_plugin_version": {
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"running_sha256": {
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
Type: framework.TypeMap,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-mounts"][0]),
|
HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-mounts"][0]),
|
||||||
|
@ -1651,6 +1738,17 @@ func (b *SystemBackend) internalPaths() []*framework.Path {
|
||||||
logical.ReadOperation: &framework.PathOperation{
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
Callback: pathInternalUINamespacesRead(b),
|
Callback: pathInternalUINamespacesRead(b),
|
||||||
Summary: "Backwards compatibility is not guaranteed for this API",
|
Summary: "Backwards compatibility is not guaranteed for this API",
|
||||||
|
Responses: map[int][]framework.Response{
|
||||||
|
http.StatusOK: {{
|
||||||
|
Description: "OK",
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"keys": {
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
Description: "field is only returned if there are one or more namespaces",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-namespaces"][0]),
|
HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-namespaces"][0]),
|
||||||
|
@ -1662,6 +1760,29 @@ func (b *SystemBackend) internalPaths() []*framework.Path {
|
||||||
logical.ReadOperation: &framework.PathOperation{
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
Callback: b.pathInternalUIResultantACL,
|
Callback: b.pathInternalUIResultantACL,
|
||||||
Summary: "Backwards compatibility is not guaranteed for this API",
|
Summary: "Backwards compatibility is not guaranteed for this API",
|
||||||
|
Responses: map[int][]framework.Response{
|
||||||
|
http.StatusNoContent: {{
|
||||||
|
Description: "empty response returned if no client token",
|
||||||
|
Fields: nil,
|
||||||
|
}},
|
||||||
|
http.StatusOK: {{
|
||||||
|
Description: "OK",
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"root": {
|
||||||
|
Type: framework.TypeBool,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"exact_paths": {
|
||||||
|
Type: framework.TypeMap,
|
||||||
|
Required: false,
|
||||||
|
},
|
||||||
|
"glob_paths": {
|
||||||
|
Type: framework.TypeMap,
|
||||||
|
Required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-resultant-acl"][0]),
|
HelpSynopsis: strings.TrimSpace(sysHelp["internal-ui-resultant-acl"][0]),
|
||||||
|
@ -1673,6 +1794,8 @@ func (b *SystemBackend) internalPaths() []*framework.Path {
|
||||||
logical.ReadOperation: &framework.PathOperation{
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
Callback: b.pathInternalCountersRequests,
|
Callback: b.pathInternalCountersRequests,
|
||||||
Summary: "Backwards compatibility is not guaranteed for this API",
|
Summary: "Backwards compatibility is not guaranteed for this API",
|
||||||
|
// callback only returns errors
|
||||||
|
Responses: nil,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
HelpSynopsis: strings.TrimSpace(sysHelp["internal-counters-requests"][0]),
|
HelpSynopsis: strings.TrimSpace(sysHelp["internal-counters-requests"][0]),
|
||||||
|
@ -1684,6 +1807,17 @@ func (b *SystemBackend) internalPaths() []*framework.Path {
|
||||||
logical.ReadOperation: &framework.PathOperation{
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
Callback: b.pathInternalCountersTokens,
|
Callback: b.pathInternalCountersTokens,
|
||||||
Summary: "Backwards compatibility is not guaranteed for this API",
|
Summary: "Backwards compatibility is not guaranteed for this API",
|
||||||
|
Responses: map[int][]framework.Response{
|
||||||
|
http.StatusOK: {{
|
||||||
|
Description: "OK",
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"counters": {
|
||||||
|
Type: framework.TypeMap,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
HelpSynopsis: strings.TrimSpace(sysHelp["internal-counters-tokens"][0]),
|
HelpSynopsis: strings.TrimSpace(sysHelp["internal-counters-tokens"][0]),
|
||||||
|
@ -1695,6 +1829,17 @@ func (b *SystemBackend) internalPaths() []*framework.Path {
|
||||||
logical.ReadOperation: &framework.PathOperation{
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
Callback: b.pathInternalCountersEntities,
|
Callback: b.pathInternalCountersEntities,
|
||||||
Summary: "Backwards compatibility is not guaranteed for this API",
|
Summary: "Backwards compatibility is not guaranteed for this API",
|
||||||
|
Responses: map[int][]framework.Response{
|
||||||
|
http.StatusOK: {{
|
||||||
|
Description: "OK",
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"counters": {
|
||||||
|
Type: framework.TypeMap,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
HelpSynopsis: strings.TrimSpace(sysHelp["internal-counters-entities"][0]),
|
HelpSynopsis: strings.TrimSpace(sysHelp["internal-counters-entities"][0]),
|
||||||
|
|
|
@ -3630,6 +3630,7 @@ func TestSystemBackend_ToolsRandom(t *testing.T) {
|
||||||
|
|
||||||
func TestSystemBackend_InternalUIMounts(t *testing.T) {
|
func TestSystemBackend_InternalUIMounts(t *testing.T) {
|
||||||
_, b, rootToken := testCoreSystemBackend(t)
|
_, b, rootToken := testCoreSystemBackend(t)
|
||||||
|
systemBackend := b.(*SystemBackend)
|
||||||
|
|
||||||
// Ensure no entries are in the endpoint as a starting point
|
// Ensure no entries are in the endpoint as a starting point
|
||||||
req := logical.TestRequest(t, logical.ReadOperation, "internal/ui/mounts")
|
req := logical.TestRequest(t, logical.ReadOperation, "internal/ui/mounts")
|
||||||
|
@ -3637,6 +3638,12 @@ func TestSystemBackend_InternalUIMounts(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
schema.ValidateResponse(
|
||||||
|
t,
|
||||||
|
schema.GetResponseSchema(t, systemBackend.Route(req.Path), req.Operation),
|
||||||
|
resp,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
|
||||||
exp := map[string]interface{}{
|
exp := map[string]interface{}{
|
||||||
"secret": map[string]interface{}{},
|
"secret": map[string]interface{}{},
|
||||||
|
@ -3652,6 +3659,12 @@ func TestSystemBackend_InternalUIMounts(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
schema.ValidateResponse(
|
||||||
|
t,
|
||||||
|
schema.GetResponseSchema(t, systemBackend.Route(req.Path), req.Operation),
|
||||||
|
resp,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
|
||||||
exp = map[string]interface{}{
|
exp = map[string]interface{}{
|
||||||
"secret": map[string]interface{}{
|
"secret": map[string]interface{}{
|
||||||
|
@ -3787,6 +3800,12 @@ func TestSystemBackend_InternalUIMounts(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
schema.ValidateResponse(
|
||||||
|
t,
|
||||||
|
schema.GetResponseSchema(t, systemBackend.Route(req.Path), req.Operation),
|
||||||
|
resp,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
|
||||||
exp = map[string]interface{}{
|
exp = map[string]interface{}{
|
||||||
"secret": map[string]interface{}{
|
"secret": map[string]interface{}{
|
||||||
|
@ -3811,6 +3830,7 @@ func TestSystemBackend_InternalUIMounts(t *testing.T) {
|
||||||
|
|
||||||
func TestSystemBackend_InternalUIMount(t *testing.T) {
|
func TestSystemBackend_InternalUIMount(t *testing.T) {
|
||||||
core, b, rootToken := testCoreSystemBackend(t)
|
core, b, rootToken := testCoreSystemBackend(t)
|
||||||
|
systemBackend := b.(*SystemBackend)
|
||||||
|
|
||||||
req := logical.TestRequest(t, logical.UpdateOperation, "policy/secret")
|
req := logical.TestRequest(t, logical.UpdateOperation, "policy/secret")
|
||||||
req.ClientToken = rootToken
|
req.ClientToken = rootToken
|
||||||
|
@ -3840,6 +3860,12 @@ func TestSystemBackend_InternalUIMount(t *testing.T) {
|
||||||
if err != nil || (resp != nil && resp.IsError()) {
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
t.Fatalf("Bad %#v %#v", err, resp)
|
t.Fatalf("Bad %#v %#v", err, resp)
|
||||||
}
|
}
|
||||||
|
schema.ValidateResponse(
|
||||||
|
t,
|
||||||
|
schema.GetResponseSchema(t, systemBackend.Route(req.Path), req.Operation),
|
||||||
|
resp,
|
||||||
|
true,
|
||||||
|
)
|
||||||
if resp.Data["type"] != "kv" {
|
if resp.Data["type"] != "kv" {
|
||||||
t.Fatalf("Bad Response: %#v", resp)
|
t.Fatalf("Bad Response: %#v", resp)
|
||||||
}
|
}
|
||||||
|
@ -3859,6 +3885,12 @@ func TestSystemBackend_InternalUIMount(t *testing.T) {
|
||||||
if err != nil || (resp != nil && resp.IsError()) {
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
t.Fatalf("Bad %#v %#v", err, resp)
|
t.Fatalf("Bad %#v %#v", err, resp)
|
||||||
}
|
}
|
||||||
|
schema.ValidateResponse(
|
||||||
|
t,
|
||||||
|
schema.GetResponseSchema(t, systemBackend.Route(req.Path), req.Operation),
|
||||||
|
resp,
|
||||||
|
true,
|
||||||
|
)
|
||||||
if resp.Data["type"] != "kv" {
|
if resp.Data["type"] != "kv" {
|
||||||
t.Fatalf("Bad Response: %#v", resp)
|
t.Fatalf("Bad Response: %#v", resp)
|
||||||
}
|
}
|
||||||
|
@ -3869,6 +3901,12 @@ func TestSystemBackend_InternalUIMount(t *testing.T) {
|
||||||
if err != nil || (resp != nil && resp.IsError()) {
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
t.Fatalf("Bad %#v %#v", err, resp)
|
t.Fatalf("Bad %#v %#v", err, resp)
|
||||||
}
|
}
|
||||||
|
schema.ValidateResponse(
|
||||||
|
t,
|
||||||
|
schema.GetResponseSchema(t, systemBackend.Route(req.Path), req.Operation),
|
||||||
|
resp,
|
||||||
|
true,
|
||||||
|
)
|
||||||
if resp.Data["type"] != "system" {
|
if resp.Data["type"] != "system" {
|
||||||
t.Fatalf("Bad Response: %#v", resp)
|
t.Fatalf("Bad Response: %#v", resp)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue