mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	 3379eaa1cf
			
		
	
	3379eaa1cf
	
	
	
		
			
			* CLI: Add ability to display ListResponseWithInfos
The Vault Server API includes a ListResponseWithInfo call, allowing LIST
responses to contain additional information about their keys. This is in
a key=value mapping format (both for each key, to get the additional
metadata, as well as within each metadata).
Expand the `vault list` CLI command with a `-detailed` flag (and env var
VAULT_DETAILED_LISTS) to print this additional metadata. This looks
roughly like the following:
    $ vault list -detailed pki/issuers
    Keys                                    issuer_name
    ----                                    -----------
    0cba84d7-bbbe-836a-4ff6-a11b31dc0fb7    n/a
    35dfb02d-0cdb-3d35-ee64-d0cd6568c6b0    n/a
    382fad1e-e99c-9c54-e147-bb1faa8033d3    n/a
    8bb4a793-2ad9-460c-9fa8-574c84a981f7    n/a
    8bd231d7-20e2-f21f-ae1a-7aa3319715e7    n/a
    9425d51f-cb81-426d-d6ad-5147d092094e    n/a
    ae679732-b497-ab0d-3220-806a2b9d81ed    n/a
    c5a44a1f-2ae4-2140-3acf-74b2609448cc    utf8
    d41d2419-efce-0e36-c96b-e91179a24dc1    something
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Allow detailed printing of LIST responses in JSON
When using the JSON formatter, only the absolute list of keys were
returned. Reuse the `-detailed` flag value for the `-format=json` list
response printer, allowing us to show the complete API response returned
by Vault.
This returns something like the following:
    {
      "request_id": "e9a25dcd-b67a-97d7-0f08-3670918ef3ff",
      "lease_id": "",
      "lease_duration": 0,
      "renewable": false,
      "data": {
        "key_info": {
          "0cba84d7-bbbe-836a-4ff6-a11b31dc0fb7": {
            "issuer_name": ""
          },
          "35dfb02d-0cdb-3d35-ee64-d0cd6568c6b0": {
            "issuer_name": ""
          },
          "382fad1e-e99c-9c54-e147-bb1faa8033d3": {
            "issuer_name": ""
          },
          "8bb4a793-2ad9-460c-9fa8-574c84a981f7": {
            "issuer_name": ""
          },
          "8bd231d7-20e2-f21f-ae1a-7aa3319715e7": {
            "issuer_name": ""
          },
          "9425d51f-cb81-426d-d6ad-5147d092094e": {
            "issuer_name": ""
          },
          "ae679732-b497-ab0d-3220-806a2b9d81ed": {
            "issuer_name": ""
          },
          "c5a44a1f-2ae4-2140-3acf-74b2609448cc": {
            "issuer_name": "utf8"
          },
          "d41d2419-efce-0e36-c96b-e91179a24dc1": {
            "issuer_name": "something"
          }
        },
        "keys": [
          "0cba84d7-bbbe-836a-4ff6-a11b31dc0fb7",
          "35dfb02d-0cdb-3d35-ee64-d0cd6568c6b0",
          "382fad1e-e99c-9c54-e147-bb1faa8033d3",
          "8bb4a793-2ad9-460c-9fa8-574c84a981f7",
          "8bd231d7-20e2-f21f-ae1a-7aa3319715e7",
          "9425d51f-cb81-426d-d6ad-5147d092094e",
          "ae679732-b497-ab0d-3220-806a2b9d81ed",
          "c5a44a1f-2ae4-2140-3acf-74b2609448cc",
          "d41d2419-efce-0e36-c96b-e91179a24dc1"
        ]
      },
      "warnings": null
    }
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Use field on UI rather than secret.Data
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Only include headers from visitable key_infos
Certain API endpoints return data from non-visitable key_infos, by
virtue of using a hand-rolled response. Limit our headers to those
from visitable key_infos. This means we won't return entire columns with
n/a entries, if no key matches the key_info key that includes that
header.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Use setupEnv sourced detailed info
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix changelog environment variable
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix broken tests using setupEnv
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
		
	
		
			
				
	
	
		
			124 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			124 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package command
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/mitchellh/cli"
 | |
| 	"github.com/posener/complete"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	_ cli.Command             = (*ListCommand)(nil)
 | |
| 	_ cli.CommandAutocomplete = (*ListCommand)(nil)
 | |
| )
 | |
| 
 | |
| type ListCommand struct {
 | |
| 	*BaseCommand
 | |
| }
 | |
| 
 | |
| func (c *ListCommand) Synopsis() string {
 | |
| 	return "List data or secrets"
 | |
| }
 | |
| 
 | |
| func (c *ListCommand) Help() string {
 | |
| 	helpText := `
 | |
| 
 | |
| Usage: vault list [options] PATH
 | |
| 
 | |
|   Lists data from Vault at the given path. This can be used to list keys in a,
 | |
|   given secret engine.
 | |
| 
 | |
|   List values under the "my-app" folder of the generic secret engine:
 | |
| 
 | |
|       $ vault list secret/my-app/
 | |
| 
 | |
|   For a full list of examples and paths, please see the documentation that
 | |
|   corresponds to the secret engine in use. Not all engines support listing.
 | |
| 
 | |
| ` + c.Flags().Help()
 | |
| 
 | |
| 	return strings.TrimSpace(helpText)
 | |
| }
 | |
| 
 | |
| func (c *ListCommand) Flags() *FlagSets {
 | |
| 	set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat | FlagSetOutputDetailed)
 | |
| 	return set
 | |
| }
 | |
| 
 | |
| func (c *ListCommand) AutocompleteArgs() complete.Predictor {
 | |
| 	return c.PredictVaultFolders()
 | |
| }
 | |
| 
 | |
| func (c *ListCommand) AutocompleteFlags() complete.Flags {
 | |
| 	return c.Flags().Completions()
 | |
| }
 | |
| 
 | |
| func (c *ListCommand) Run(args []string) int {
 | |
| 	f := c.Flags()
 | |
| 
 | |
| 	if err := f.Parse(args); err != nil {
 | |
| 		c.UI.Error(err.Error())
 | |
| 		return 1
 | |
| 	}
 | |
| 
 | |
| 	args = f.Args()
 | |
| 	switch {
 | |
| 	case len(args) < 1:
 | |
| 		c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1, got %d)", len(args)))
 | |
| 		return 1
 | |
| 	case len(args) > 1:
 | |
| 		c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
 | |
| 		return 1
 | |
| 	}
 | |
| 
 | |
| 	client, err := c.Client()
 | |
| 	if err != nil {
 | |
| 		c.UI.Error(err.Error())
 | |
| 		return 2
 | |
| 	}
 | |
| 
 | |
| 	// Append trailing slash
 | |
| 	path := args[0]
 | |
| 	if !strings.HasSuffix(path, "/") {
 | |
| 		path += "/"
 | |
| 	}
 | |
| 
 | |
| 	path = sanitizePath(path)
 | |
| 	secret, err := client.Logical().List(path)
 | |
| 	if err != nil {
 | |
| 		c.UI.Error(fmt.Sprintf("Error listing %s: %s", path, err))
 | |
| 		return 2
 | |
| 	}
 | |
| 
 | |
| 	// If the secret is wrapped, return the wrapped response.
 | |
| 	if secret != nil && secret.WrapInfo != nil && secret.WrapInfo.TTL != 0 {
 | |
| 		return OutputSecret(c.UI, secret)
 | |
| 	}
 | |
| 
 | |
| 	_, ok := extractListData(secret)
 | |
| 	if Format(c.UI) != "table" {
 | |
| 		if secret == nil || secret.Data == nil || !ok {
 | |
| 			OutputData(c.UI, map[string]interface{}{})
 | |
| 			return 2
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if secret == nil {
 | |
| 		c.UI.Error(fmt.Sprintf("No value found at %s", path))
 | |
| 		return 2
 | |
| 	}
 | |
| 	if secret.Data == nil {
 | |
| 		// If secret wasn't nil, we have warnings, so output them anyways. We
 | |
| 		// may also have non-keys info.
 | |
| 		return OutputSecret(c.UI, secret)
 | |
| 	}
 | |
| 
 | |
| 	if !ok {
 | |
| 		c.UI.Error(fmt.Sprintf("No entries found at %s", path))
 | |
| 		return 2
 | |
| 	}
 | |
| 
 | |
| 	return OutputList(c.UI, secret)
 | |
| }
 |