Skip to content
This repository has been archived by the owner on Feb 16, 2023. It is now read-only.

Commit

Permalink
Merge pull request #215 from secrethub/feature/audit-pagination
Browse files Browse the repository at this point in the history
Paginate audit command
  • Loading branch information
SimonBarendse authored Nov 27, 2019
2 parents c6e76a1 + 67f6aae commit 6260bd5
Show file tree
Hide file tree
Showing 8 changed files with 279 additions and 240 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ require (
github.com/mitchellh/mapstructure v1.1.2
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/secrethub/demo-app v0.1.0
github.com/secrethub/secrethub-go v0.23.0
github.com/secrethub/secrethub-go v0.24.0
github.com/zalando/go-keyring v0.0.0-20190208082241-fbe81aec3a07
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ github.com/secrethub/secrethub-go v0.21.0 h1:5xbC+gdku7MXUQmlP5SPhAPLF+/U31soLKb
github.com/secrethub/secrethub-go v0.21.0/go.mod h1:rc2IfKKBJ4L0wGec0u4XnF5/pe0FFPE4Q1MWfrFso7s=
github.com/secrethub/secrethub-go v0.23.0 h1:6NzVGcAJDXeORUc2uZyuaYRCXCawmOKYvhNPP3ASNSM=
github.com/secrethub/secrethub-go v0.23.0/go.mod h1:rc2IfKKBJ4L0wGec0u4XnF5/pe0FFPE4Q1MWfrFso7s=
github.com/secrethub/secrethub-go v0.23.1-0.20191120150410-759ed0ccde7e h1:9FjAfwJiwGWGo7I0LbQ7CTS2qvjpaI5DTeZVIWisGBQ=
github.com/secrethub/secrethub-go v0.23.1-0.20191120150410-759ed0ccde7e/go.mod h1:rc2IfKKBJ4L0wGec0u4XnF5/pe0FFPE4Q1MWfrFso7s=
github.com/secrethub/secrethub-go v0.23.1-0.20191126142216-0736401365d7 h1:GH23+Ig/6Gsqyat8FQ06bMUVJvy1tisKuWhj22oS344=
github.com/secrethub/secrethub-go v0.23.1-0.20191126142216-0736401365d7/go.mod h1:rc2IfKKBJ4L0wGec0u4XnF5/pe0FFPE4Q1MWfrFso7s=
github.com/secrethub/secrethub-go v0.23.1-0.20191126145052-23fd5b7a4363 h1:0lHIjcVCBFrlpKv6Ag2JhuI5FlvxiGXXRnJUqgrFiaE=
github.com/secrethub/secrethub-go v0.23.1-0.20191126145052-23fd5b7a4363/go.mod h1:rc2IfKKBJ4L0wGec0u4XnF5/pe0FFPE4Q1MWfrFso7s=
github.com/secrethub/secrethub-go v0.24.0 h1:psxPZzPk5DrZTTTvnIE9F1oj43QVwHjJ2ZnBvsXn0wc=
github.com/secrethub/secrethub-go v0.24.0/go.mod h1:rc2IfKKBJ4L0wGec0u4XnF5/pe0FFPE4Q1MWfrFso7s=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
Expand Down
190 changes: 177 additions & 13 deletions internals/secrethub/audit.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
package secrethub

import (
"fmt"
"strings"
"text/tabwriter"

"github.com/secrethub/secrethub-cli/internals/cli/ui"
"github.com/secrethub/secrethub-cli/internals/secrethub/command"
"github.com/secrethub/secrethub-go/pkg/secrethub"
"github.com/secrethub/secrethub-go/pkg/secrethub/iterator"

"github.com/secrethub/secrethub-go/internals/api"
)
Expand All @@ -12,7 +18,9 @@ type AuditCommand struct {
io ui.IO
path api.Path
useTimestamps bool
timeFormatter TimeFormatter
newClient newClientFunc
perPage int
}

// NewAuditCommand creates a new audit command.
Expand All @@ -27,34 +35,190 @@ func NewAuditCommand(io ui.IO, newClient newClientFunc) *AuditCommand {
func (cmd *AuditCommand) Register(r command.Registerer) {
clause := r.Command("audit", "Show the audit log.")
clause.Arg("repo-path or secret-path", "Path to the repository or the secret to audit "+repoPathPlaceHolder+" or "+secretPathPlaceHolder).SetValue(&cmd.path)
clause.Flag("per-page", "number of audit events shown per page").Default("20").IntVar(&cmd.perPage)
registerTimestampFlag(clause).BoolVar(&cmd.useTimestamps)

command.BindAction(clause, cmd.Run)
}

// Run prints all audit events for the given repository or secret.
func (cmd *AuditCommand) Run() error {
cmd.beforeRun()
return cmd.run()
}

// beforeRun configures the command using the flag values.
func (cmd *AuditCommand) beforeRun() {
cmd.timeFormatter = NewTimeFormatter(cmd.useTimestamps)
}

// Run prints all audit events for the given repository or secret.
func (cmd *AuditCommand) run() error {
if cmd.perPage < 1 {
return fmt.Errorf("per-page should be positive, got %d", cmd.perPage)
}

iter, auditTable, err := cmd.iterAndAuditTable()
if err != nil {
return err
}

tabWriter := tabwriter.NewWriter(cmd.io.Stdout(), 0, 4, 4, ' ', 0)
header := strings.Join(auditTable.header(), "\t") + "\n"
fmt.Fprint(tabWriter, header)

i := 0
for {
i++
event, err := iter.Next()
if err == iterator.Done {
break
} else if err != nil {
return err
}

row, err := auditTable.row(event)
if err != nil {
return err
}

fmt.Fprint(tabWriter, strings.Join(row, "\t")+"\n")

if i == cmd.perPage {
err = tabWriter.Flush()
if err != nil {
return err
}
i = 0

// wait for <ENTER> to continue.
_, err := ui.Ask(cmd.io, "Press <ENTER> to show more results. Press <CTRL+C> to exit.")
if err != nil {
return err
}
fmt.Fprint(tabWriter, header)
}
}

err = tabWriter.Flush()
if err != nil {
return err
}

return nil
}

func (cmd *AuditCommand) iterAndAuditTable() (secrethub.AuditEventIterator, auditTable, error) {
repoPath, err := cmd.path.ToRepoPath()
if err == nil {
auditRepoCommand := AuditRepoCommand{
io: cmd.io,
path: repoPath,
useTimestamps: cmd.useTimestamps,
newClient: cmd.newClient,
client, err := cmd.newClient()
if err != nil {
return nil, nil, err
}
tree, err := client.Dirs().GetTree(repoPath.GetDirPath().Value(), -1, false)
if err != nil {
return nil, nil, err
}
return auditRepoCommand.Run()

iter := client.Repos().EventIterator(repoPath.Value(), &secrethub.AuditEventIteratorParams{})
auditTable := newRepoAuditTable(tree, cmd.timeFormatter)
return iter, auditTable, nil

}

secretPath, err := cmd.path.ToSecretPath()
if err == nil {
auditSecretCommand := AuditSecretCommand{
io: cmd.io,
path: secretPath,
useTimestamps: cmd.useTimestamps,
newClient: cmd.newClient,
if cmd.path.HasVersion() {
return nil, nil, ErrCannotAuditSecretVersion
}

client, err := cmd.newClient()
if err != nil {
return nil, nil, err
}
return auditSecretCommand.Run()

isDir, err := client.Dirs().Exists(secretPath.Value())
if err == nil && isDir {
return nil, nil, ErrCannotAuditDir
}

iter := client.Secrets().EventIterator(secretPath.Value(), &secrethub.AuditEventIteratorParams{})
auditTable := newSecretAuditTable(cmd.timeFormatter)
return iter, auditTable, nil
}

return nil, nil, ErrNoValidRepoOrSecretPath
}

type auditTable interface {
header() []string
row(event api.Audit) ([]string, error)
}

func newBaseAuditTable(timeFormatter TimeFormatter) baseAuditTable {
return baseAuditTable{
timeFormatter: timeFormatter,
}
}

type baseAuditTable struct {
timeFormatter TimeFormatter
}

func (table baseAuditTable) header(content ...string) []string {
res := append([]string{"AUTHOR", "EVENT"}, content...)
return append(res, "IP ADDRESS", "DATE")
}

func (table baseAuditTable) row(event api.Audit, content ...string) ([]string, error) {
actor, err := getAuditActor(event)
if err != nil {
return nil, err
}

res := append([]string{actor, getEventAction(event)}, content...)
return append(res, event.IPAddress, table.timeFormatter.Format(event.LoggedAt)), nil
}

func newSecretAuditTable(timeFormatter TimeFormatter) secretAuditTable {
return secretAuditTable{
baseAuditTable: newBaseAuditTable(timeFormatter),
}
}

type secretAuditTable struct {
baseAuditTable
}

func (table secretAuditTable) header() []string {
return table.baseAuditTable.header()
}

func (table secretAuditTable) row(event api.Audit) ([]string, error) {
return table.baseAuditTable.row(event)
}

func newRepoAuditTable(tree *api.Tree, timeFormatter TimeFormatter) repoAuditTable {
return repoAuditTable{
baseAuditTable: newBaseAuditTable(timeFormatter),
tree: tree,
}
}

type repoAuditTable struct {
baseAuditTable
tree *api.Tree
}

func (table repoAuditTable) header() []string {
return table.baseAuditTable.header("EVENT SUBJECT")
}

func (table repoAuditTable) row(event api.Audit) ([]string, error) {
subject, err := getAuditSubject(event, table.tree)
if err != nil {
return nil, err
}

return ErrNoValidRepoOrSecretPath
return table.baseAuditTable.row(event, subject)
}
6 changes: 3 additions & 3 deletions internals/secrethub/audit_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/secrethub/secrethub-go/internals/api"
)

func getAuditActor(event *api.Audit) (string, error) {
func getAuditActor(event api.Audit) (string, error) {
if event.Actor.Deleted {
return event.Actor.ActorID.String(), nil
}
Expand All @@ -21,7 +21,7 @@ func getAuditActor(event *api.Audit) (string, error) {
return "", ErrInvalidAuditActor
}

func getAuditSubject(event *api.Audit, tree *api.Tree) (string, error) {
func getAuditSubject(event api.Audit, tree *api.Tree) (string, error) {
if event.Subject.Deleted {
return event.Subject.SubjectID.String(), nil
}
Expand Down Expand Up @@ -65,7 +65,7 @@ func getAuditSubject(event *api.Audit, tree *api.Tree) (string, error) {

}

func getEventAction(event *api.Audit) string {
func getEventAction(event api.Audit) string {
action := event.Action
subjectType := event.Subject.Type

Expand Down
82 changes: 0 additions & 82 deletions internals/secrethub/audit_repo.go

This file was deleted.

Loading

0 comments on commit 6260bd5

Please sign in to comment.