-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ea0a6d9
commit 1093c58
Showing
62 changed files
with
5,042 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,3 +19,11 @@ | |
|
||
# Go workspace file | ||
go.work | ||
.idea | ||
|
||
.DS_Store | ||
.vscode/* | ||
vendor/* | ||
bin | ||
bin/* | ||
pkg/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
local-vault: | ||
vault server -dev | ||
|
||
setup-test-data: | ||
./helpers/setup.sh | ||
|
||
.PHONY: install-osx | ||
install-osx: | ||
cp ./bin/vaul7y /usr/local/bin/vaul7y | ||
|
||
.PHONY: dev | ||
dev: ## Build for the current development version | ||
@echo "==> Building Vaul7y..." | ||
@mkdir -p ./bin | ||
@CGO_ENABLED=0 go build -o ./bin/vaul7y ./cmd/vaul7y | ||
@rm -f $(GOPATH)/bin/vaul7y | ||
@cp ./bin/vaul7y/vaul7y $(GOPATH)/bin/vaul7y | ||
@echo "==> Done" | ||
|
||
.PHONY: build | ||
build: | ||
go build -o bin/vaul7y ./cmd/vaul7y | ||
|
||
.PHONY: run | ||
run: | ||
./bin/vaul7y |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,27 @@ | ||
# vaulty | ||
# Vaul7y / Vaulty | ||
|
||
Simple Vault CLI | ||
Vaulty is a TUI for Hashicorp Vault. The goal is to support as many functionalities as possible in order to make the tool as usefu as possible. | ||
|
||
## Why use Vaul7y | ||
|
||
I started the tool purely for personal use as I love tools like [K9s](https://github.com/derailed/k9s) or [Wander](https://github.com/robinovitch61/wander). I generally prefer the use of CLI tools but when it came to vault and looking up at stuff, sometimes having a UI just speeds things up. I couldn't find something finished, so decided to write my own. | ||
|
||
## Video | ||
![gif](./images/vaulty-min.gif) | ||
|
||
## Usage | ||
|
||
To see detailed guide on how to use the tool see the [docs](./docs/usage.md) | ||
|
||
## Features and Bugs | ||
|
||
The tool is in active development and is bug heavy. There are multiple things that are on my short and long term TODO list. | ||
|
||
If anyone decides to use this and wants to request a specific feature or even fix a bug - please open an issue :smile: | ||
|
||
## Short term TODO list: | ||
1. Change the logger (current one is a mess) | ||
1. Finish adding tests (wip in another branch) | ||
2. Finish implementing Update to existing secrets | ||
* Bonus: Create net new ones. | ||
3. Support for namespace changes. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
"os" | ||
"time" | ||
|
||
"github.com/dkyanakiev/vaulty/component" | ||
"github.com/dkyanakiev/vaulty/state" | ||
"github.com/dkyanakiev/vaulty/vault" | ||
"github.com/dkyanakiev/vaulty/view" | ||
"github.com/dkyanakiev/vaulty/watcher" | ||
"github.com/gdamore/tcell/v2" | ||
"github.com/rivo/tview" | ||
) | ||
|
||
var refreshIntervalDefault = time.Second * 5 | ||
var logger *log.Logger | ||
|
||
func main() { | ||
|
||
// | ||
|
||
LOG_FILE, exists := os.LookupEnv("VAULTY_LOG_FILE") | ||
if !exists { | ||
LOG_FILE = "/tmp/vaulty-errors" | ||
} // open log file | ||
logFile, err := os.OpenFile(LOG_FILE, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644) | ||
if err != nil { | ||
log.Panic(err) | ||
} | ||
defer logFile.Close() | ||
|
||
logger = log.New(logFile, "Vaulty ", log.LstdFlags) | ||
logger.SetOutput(logFile) | ||
|
||
// optional: log date-time, filename, and line number | ||
logger.SetFlags(log.Lshortfile | log.LstdFlags) | ||
|
||
tview.Styles.PrimitiveBackgroundColor = tcell.NewRGBColor(40, 44, 48) | ||
|
||
vaultClient, err := vault.New(func(v *vault.Vault) error { | ||
return vault.Default(v, logger) | ||
}) | ||
state := initializeState(vaultClient) | ||
commands := component.NewCommands() | ||
vaultInfo := component.NewVaultInfo() | ||
mounts := component.NewMountsTable() | ||
policies := component.NewPolicyTable() | ||
policyAcl := component.NewPolicyAclTable() | ||
secrets := component.NewSecretsTable() | ||
secretObj := component.NewSecretObjTable() | ||
logo := component.NewLogo() | ||
info := component.NewInfo() | ||
failure := component.NewInfo() | ||
errorComp := component.NewError() | ||
components := &view.Components{ | ||
VaultInfo: vaultInfo, | ||
Commands: commands, | ||
MountsTable: mounts, | ||
PolicyTable: policies, | ||
PolicyAclTable: policyAcl, | ||
SecretsTable: secrets, | ||
SecretObjTable: secretObj, | ||
Info: info, | ||
Error: errorComp, | ||
Failure: failure, | ||
Logo: logo, | ||
Logger: logger, | ||
} | ||
watcher := watcher.NewWatcher(state, vaultClient, refreshIntervalDefault, logger) | ||
view := view.New(components, watcher, vaultClient, state, logger) | ||
|
||
view.Init("0.0.1") | ||
err = view.Layout.Container.Run() | ||
if err != nil { | ||
log.Fatal("cannot initialize view.") | ||
} | ||
|
||
} | ||
|
||
func initializeState(client *vault.Vault) *state.State { | ||
state := state.New() | ||
addr := client.Address() | ||
state.VaultAddress = addr | ||
state.Namespace = "default" | ||
|
||
return state | ||
} | ||
|
||
func initLogger() { | ||
|
||
// TODO Rework later | ||
LOG_FILE := "/tmp/vaulty-errors" | ||
// open log file | ||
logFile, err := os.OpenFile(LOG_FILE, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644) | ||
if err != nil { | ||
log.Panic(err) | ||
} | ||
defer logFile.Close() | ||
|
||
logger = log.New(logFile, "app ", log.LstdFlags) | ||
|
||
// Set log out put and enjoy :) | ||
logger.SetOutput(logFile) | ||
|
||
// optional: log date-time, filename, and line number | ||
logger.SetFlags(log.Lshortfile | log.LstdFlags) | ||
|
||
} | ||
|
||
// // LOOK AT LATER | ||
// func main() { | ||
// vaultClient, _ := vault.New(vault.Default) | ||
// //ctx := context.TODO() | ||
// // mounts, _ := vaultClient.Sys.ListMounts() | ||
|
||
// secret, _ := vaultClient.ListSecrets("kv0FF76557") | ||
// log.Println(secret) | ||
|
||
// secrets, _ := vaultClient.ListNestedSecrets("kv0FF76557", "") | ||
// //secrets, err := vaultClient.Logical.List("randomkv/metadata/test/one") | ||
|
||
// for _, value := range secrets { | ||
// fmt.Printf("Key: %s\n", value.PathName) | ||
// fmt.Printf("IsSecret: %t\n", value.IsSecret) | ||
// } | ||
// // val, err := vaultClient.KV2.Get(ctx, "path") | ||
// // fmt.Println(val) | ||
// // fmt.Println(err) | ||
|
||
// // secretClient, err := vaultClient.Logical.List("credentials/metadata/") | ||
// // if err != nil { | ||
// // // TODO | ||
// // fmt.Println(err) | ||
// // } | ||
// // vault.DataIterator(secretClient.Data["keys"]) | ||
// } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package component | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/rivo/tview" | ||
|
||
primitive "github.com/dkyanakiev/vaulty/primitives" | ||
"github.com/dkyanakiev/vaulty/styles" | ||
) | ||
|
||
var ( | ||
MainCommands = []string{ | ||
fmt.Sprintf("%sMain Commands:", styles.HighlightSecondaryTag), | ||
fmt.Sprintf("%s<ctrl-m>%s to display System Mounts", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
fmt.Sprintf("%s<ctrl-p>%s to display ACL Policies", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
fmt.Sprintf("%s<ctrl-c>%s to Quit", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
} | ||
MountsCommands = []string{ | ||
fmt.Sprintf("\n%s Secret Mounts Command List:", styles.HighlightSecondaryTag), | ||
fmt.Sprintf("%s<e>%s to explore mount", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
} | ||
NoViewCommands = []string{} | ||
PolicyCommands = []string{ | ||
fmt.Sprintf("\n%s ACL Policy Commands:", styles.HighlightSecondaryTag), | ||
fmt.Sprintf("%s<i>%s to inspect policy", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
fmt.Sprintf("%s</>%s apply filter", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
} | ||
PolicyACLCommands = []string{ | ||
fmt.Sprintf("\n%s ACL Policy Commands:", styles.HighlightSecondaryTag), | ||
fmt.Sprintf("%s<Esc>%s to go back", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
//fmt.Sprintf("%s</>%s apply filter", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
} | ||
SecretsCommands = []string{ | ||
fmt.Sprintf("\n%s Secrets Commands:", styles.HighlightSecondaryTag), | ||
fmt.Sprintf("%s<e>%s to navigate to selected the path", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
fmt.Sprintf("%s<b>%s to go back to the previous path", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
} | ||
SecretObjectCommands = []string{ | ||
fmt.Sprintf("\n%s Secret Commands:", styles.HighlightSecondaryTag), | ||
fmt.Sprintf("%s<h>%s toggle display for secrets", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
fmt.Sprintf("%s<c>%s copy secret to clipboard", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
fmt.Sprintf("%s<j>%s toggle json view for secret", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
//TODO: Work in progress | ||
//fmt.Sprintf("%s<p>%s patch secret", styles.HighlightPrimaryTag, styles.StandardColorTag), | ||
} | ||
) | ||
|
||
type Commands struct { | ||
TextView TextView | ||
Props *CommandsProps | ||
slot *tview.Flex | ||
} | ||
|
||
type CommandsProps struct { | ||
MainCommands []string | ||
ViewCommands []string | ||
} | ||
|
||
func NewCommands() *Commands { | ||
return &Commands{ | ||
TextView: primitive.NewTextView(tview.AlignLeft), | ||
Props: &CommandsProps{ | ||
MainCommands: MainCommands, | ||
// ViewCommands: MainCommands, | ||
}, | ||
} | ||
} | ||
|
||
func (c *Commands) Update(commands []string) { | ||
c.Props.ViewCommands = commands | ||
|
||
c.updateText() | ||
} | ||
|
||
func (c *Commands) Render() error { | ||
if c.slot == nil { | ||
return ErrComponentNotBound | ||
} | ||
|
||
c.updateText() | ||
|
||
c.slot.AddItem(c.TextView.Primitive(), 0, 1, false) | ||
return nil | ||
} | ||
|
||
func (c *Commands) updateText() { | ||
commands := append(c.Props.MainCommands, c.Props.ViewCommands...) | ||
cmds := strings.Join(commands, "\n") | ||
c.TextView.SetText(cmds) | ||
} | ||
|
||
func (c *Commands) Bind(slot *tview.Flex) { | ||
c.slot = slot | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package component | ||
|
||
import ( | ||
"github.com/dkyanakiev/vaulty/models" | ||
"github.com/dkyanakiev/vaulty/primitives" | ||
|
||
"github.com/gdamore/tcell/v2" | ||
"github.com/rivo/tview" | ||
) | ||
|
||
const ( | ||
ErrComponentNotBound = models.Comp("component not bound") | ||
ErrComponentPropsNotSet = models.Comp("component properties not set") | ||
) | ||
|
||
//go:generate counterfeiter . DoneModalFunc | ||
type DoneModalFunc func(buttonIndex int, buttonLabel string) | ||
|
||
type Primitive interface { | ||
Primitive() tview.Primitive | ||
} | ||
|
||
//go:generate counterfeiter . Table | ||
type Table interface { | ||
Primitive | ||
SetTitle(format string, args ...interface{}) | ||
GetCellContent(row, column int) string | ||
GetSelection() (row, column int) | ||
Clear() | ||
RenderHeader(data []string) | ||
RenderRow(data []string, index int, c tcell.Color) | ||
SetSelectedFunc(fn func(row, column int)) | ||
SetInputCapture(capture func(event *tcell.EventKey) *tcell.EventKey) | ||
} | ||
|
||
//go:generate counterfeiter . TextView | ||
type TextView interface { | ||
Primitive | ||
GetText(bool) string | ||
SetText(text string) *tview.TextView | ||
Write(data []byte) (int, error) | ||
Highlight(regionIDs ...string) *tview.TextView | ||
Clear() *tview.TextView | ||
ModifyPrimitive(f func(t *tview.TextView)) | ||
} | ||
|
||
//go:generate counterfeiter . Modal | ||
type Modal interface { | ||
Primitive | ||
SetDoneFunc(handler func(buttonIndex int, buttonLabel string)) | ||
SetText(text string) | ||
SetFocus(index int) | ||
Container() tview.Primitive | ||
} | ||
|
||
type Form interface { | ||
Primitive | ||
Container() tview.Primitive | ||
} | ||
|
||
//go:generate counterfeiter . InputField | ||
type InputField interface { | ||
Primitive | ||
SetDoneFunc(handler func(k tcell.Key)) | ||
SetChangedFunc(handler func(text string)) | ||
SetAutocompleteFunc(callback func(currentText string) (entries []string)) | ||
SetText(text string) | ||
GetText() string | ||
} | ||
|
||
//go:generate counterfeiter . DropDown | ||
type DropDown interface { | ||
Primitive | ||
SetOptions(options []string, selected func(text string, index int)) | ||
SetCurrentOption(index int) | ||
SetSelectedFunc(selected func(text string, index int)) | ||
} | ||
|
||
//go:generate counterfeiter . Selector | ||
type Selector interface { | ||
Primitive | ||
GetTable() *primitives.Table | ||
Container() tview.Primitive | ||
} |
Oops, something went wrong.