From d9f6302687ffc3e7d6598d9275049622c3a43fe3 Mon Sep 17 00:00:00 2001 From: ostempel Date: Tue, 14 Jan 2025 16:50:38 +0100 Subject: [PATCH 01/20] started with audit implementation --- cmd/admin/v1/audit.go | 82 +++++++++++++++++++++++++++++++++++++++++++ cmd/sorters/audit.go | 22 ++++++++++++ go.mod | 2 +- go.sum | 2 ++ 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 cmd/admin/v1/audit.go create mode 100644 cmd/sorters/audit.go diff --git a/cmd/admin/v1/audit.go b/cmd/admin/v1/audit.go new file mode 100644 index 0000000..f83314a --- /dev/null +++ b/cmd/admin/v1/audit.go @@ -0,0 +1,82 @@ +package v1 + +import ( + "fmt" + + "connectrpc.com/connect" + apiv1 "github.com/metal-stack-cloud/api/go/api/v1" + "github.com/metal-stack-cloud/cli/cmd/config" + "github.com/metal-stack-cloud/cli/cmd/sorters" + "github.com/metal-stack/metal-lib/pkg/genericcli" + "github.com/metal-stack/metal-lib/pkg/genericcli/printers" + "github.com/spf13/cobra" +) + +type audit struct { + c *config.Config +} + +func newAuditCmd(c *config.Config) *cobra.Command { + a := &audit{ + c: c, + } + + cmdsConfig := &genericcli.CmdsConfig[*apiv1.AuditServiceGetRequest, *apiv1.AuditServiceListRequest, *apiv1.AuditTrace]{ + BinaryName: config.BinaryName, + Singular: "audit trace", + Plural: "audit traces", + Description: "show audit traces of the api-server", + Sorter: sorters.AuditSorter(), + DescribePrinter: func() printers.Printer { return c.DescribePrinter }, + ListPrinter: func() printers.Printer { return c.ListPrinter }, + } + + listCmd := &cobra.Command{ + Use: "list", + Short: "list all audit traces", + RunE: func(cmd *cobra.Command, args []string) error { + return nil + }, + } + + getCmd := &cobra.Command{ + Use: "get", + Short: "gets the audit trace", + RunE: func(cmd *cobra.Command, args []string) error { + return nil + }, + } + + return genericcli.NewCmds(cmdsConfig, listCmd, getCmd) +} + +func (a *audit) Get(req *apiv1.AuditServiceGetRequest) (*apiv1.AuditTrace, error) { + ctx, cancel := a.c.NewRequestContext() + defer cancel() + + // not sure about how to get tenant of current user + tenant, err := a.c.GetTenant() + if err != nil { + return nil, fmt.Errorf("tenant is required") + } + req.Login = tenant + + resp, err := a.c.Client.Apiv1().Audit().Get(ctx, connect.NewRequest(req)) + if err != nil { + return nil, fmt.Errorf("failed to get audit trace: %w", err) + } + + return resp.Msg.Audit, nil +} + +func (a *audit) List(req *apiv1.AuditServiceListRequest) ([]*apiv1.AuditTrace, error) { + ctx, cancel := a.c.NewRequestContext() + defer cancel() + + resp, err := a.c.Client.Apiv1().Audit().List(ctx, connect.NewRequest(req)) + if err != nil { + return nil, fmt.Errorf("failed to list audit traces: %w", err) + } + + return resp.Msg.Audits, nil +} diff --git a/cmd/sorters/audit.go b/cmd/sorters/audit.go new file mode 100644 index 0000000..556c320 --- /dev/null +++ b/cmd/sorters/audit.go @@ -0,0 +1,22 @@ +package sorters + +import ( + "time" + + apiv1 "github.com/metal-stack-cloud/api/go/api/v1" + "github.com/metal-stack/metal-lib/pkg/multisort" +) + +func AuditSorter() *multisort.Sorter[*apiv1.AuditTrace] { + return multisort.New(multisort.FieldMap[*apiv1.AuditTrace]{ + "timestamp": func(a, b *apiv1.AuditTrace, descending bool) multisort.CompareResult { + return multisort.Compare(time.Time(a.Timestamp.AsTime()).Unix(), time.Time(b.Timestamp.AsTime()).Unix(), descending) + }, + "user": func(a, b *apiv1.AuditTrace, descending bool) multisort.CompareResult { + return multisort.Compare(a.User, b.User, descending) + }, + "method": func(a, b *apiv1.AuditTrace, descending bool) multisort.CompareResult { + return multisort.Compare(a.Method, b.Method, descending) + }, + }, multisort.Keys{{ID: "timestamp", Descending: true}}) +} diff --git a/go.mod b/go.mod index b5fa434..e40b7df 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.18.0 github.com/google/go-cmp v0.6.0 - github.com/metal-stack-cloud/api v0.10.7 + github.com/metal-stack-cloud/api v0.11.1-0.20250114085412-0a5890ec354f github.com/metal-stack/metal-lib v0.19.0 github.com/metal-stack/v v1.0.3 github.com/olekukonko/tablewriter v0.0.5 diff --git a/go.sum b/go.sum index bcd1be1..25cbc97 100644 --- a/go.sum +++ b/go.sum @@ -199,6 +199,8 @@ github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= github.com/metal-stack-cloud/api v0.10.7 h1:jBQySi3f3MLsGtdTa7OcC4Png/F7eWn/9huUwLhxwss= github.com/metal-stack-cloud/api v0.10.7/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= +github.com/metal-stack-cloud/api v0.11.1-0.20250114085412-0a5890ec354f h1:TAv0sl9ZXeXSPgy5HuNSA9VbYIA6hH2BtIh0Qp5EjQE= +github.com/metal-stack-cloud/api v0.11.1-0.20250114085412-0a5890ec354f/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= github.com/metal-stack/metal-lib v0.19.0 h1:4yBnp/jPGgX9KeCje3A4MFL2oDjgjOjgsIK391LltRI= github.com/metal-stack/metal-lib v0.19.0/go.mod h1:fCMaWwVGA/xAoGvBk72/nfzqBkHly0iOzrWpc55Fau4= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= From 7d0a888cb66eadac706329c2049ebfcce7c6361d Mon Sep 17 00:00:00 2001 From: AnnaSchreiner Date: Wed, 15 Jan 2025 15:31:22 +0100 Subject: [PATCH 02/20] add audit, list, test and printer --- cmd/admin/v1/audit.go | 87 ++++++++++++++++++- cmd/admin/v1/commands.go | 1 + cmd/audit_test.go | 163 ++++++++++++++++++++++++++++++++++++ cmd/tableprinters/audit.go | 44 ++++++++++ cmd/tableprinters/common.go | 5 ++ 5 files changed, 297 insertions(+), 3 deletions(-) create mode 100644 cmd/audit_test.go create mode 100644 cmd/tableprinters/audit.go diff --git a/cmd/admin/v1/audit.go b/cmd/admin/v1/audit.go index f83314a..f10f832 100644 --- a/cmd/admin/v1/audit.go +++ b/cmd/admin/v1/audit.go @@ -2,6 +2,7 @@ package v1 import ( "fmt" + "time" "connectrpc.com/connect" apiv1 "github.com/metal-stack-cloud/api/go/api/v1" @@ -10,6 +11,8 @@ import ( "github.com/metal-stack/metal-lib/pkg/genericcli" "github.com/metal-stack/metal-lib/pkg/genericcli/printers" "github.com/spf13/cobra" + "github.com/spf13/viper" + "google.golang.org/protobuf/types/known/timestamppb" ) type audit struct { @@ -23,12 +26,35 @@ func newAuditCmd(c *config.Config) *cobra.Command { cmdsConfig := &genericcli.CmdsConfig[*apiv1.AuditServiceGetRequest, *apiv1.AuditServiceListRequest, *apiv1.AuditTrace]{ BinaryName: config.BinaryName, + GenericCLI: genericcli.NewGenericCLI[*apiv1.AuditServiceGetRequest, *apiv1.AuditServiceListRequest, *apiv1.AuditTrace](a).WithFS(c.Fs), Singular: "audit trace", Plural: "audit traces", Description: "show audit traces of the api-server", Sorter: sorters.AuditSorter(), DescribePrinter: func() printers.Printer { return c.DescribePrinter }, ListPrinter: func() printers.Printer { return c.ListPrinter }, + ListCmdMutateFn: func(cmd *cobra.Command) { + //cmd.Flags().StringP("query", "q", "", "filters audit trace body payloads for the given text.") + + cmd.Flags().String("request-id", "", "request id of the audit trace.") + + cmd.Flags().String("from", "1h", "start of range of the audit traces. e.g. 1h, 10m, 2006-01-02 15:04:05") + cmd.Flags().String("to", "", "end of range of the audit traces. e.g. 1h, 10m, 2006-01-02 15:04:05") + + cmd.Flags().String("user", "", "user of the audit trace.") + cmd.Flags().String("tenant", "", "tenant of the audit trace.") + + cmd.Flags().String("project", "", "project id of the audit trace") + + cmd.Flags().String("method", "", "api Method of the audit trace.") + + cmd.Flags().String("result-code", "", "HTTP status code of the audit trace.") + cmd.Flags().String("source-ip", "", "source-ip of the audit trace.") + + //cmd.Flags().Int64("limit", 100, "limit the number of audit traces.") + + genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.Completion.ProjectListCompletion)) + }, } listCmd := &cobra.Command{ @@ -50,7 +76,7 @@ func newAuditCmd(c *config.Config) *cobra.Command { return genericcli.NewCmds(cmdsConfig, listCmd, getCmd) } -func (a *audit) Get(req *apiv1.AuditServiceGetRequest) (*apiv1.AuditTrace, error) { +func (a *audit) Get(id string) (*apiv1.AuditTrace, error) { ctx, cancel := a.c.NewRequestContext() defer cancel() @@ -59,7 +85,11 @@ func (a *audit) Get(req *apiv1.AuditServiceGetRequest) (*apiv1.AuditTrace, error if err != nil { return nil, fmt.Errorf("tenant is required") } - req.Login = tenant + + req := &apiv1.AuditServiceGetRequest{ + Login: tenant, + Uuid: id, + } resp, err := a.c.Client.Apiv1().Audit().Get(ctx, connect.NewRequest(req)) if err != nil { @@ -69,10 +99,30 @@ func (a *audit) Get(req *apiv1.AuditServiceGetRequest) (*apiv1.AuditTrace, error return resp.Msg.Audit, nil } -func (a *audit) List(req *apiv1.AuditServiceListRequest) ([]*apiv1.AuditTrace, error) { +func (a *audit) List() ([]*apiv1.AuditTrace, error) { ctx, cancel := a.c.NewRequestContext() defer cancel() + fromDateTime, err := eventuallyRelativeDateTime(viper.GetString("from")) + if err != nil { + return nil, err + } + toDateTime, err := eventuallyRelativeDateTime(viper.GetString("to")) + if err != nil { + return nil, err + } + + req := &apiv1.AuditServiceListRequest{ + Uuid: viper.GetString("request-id"), + From: fromDateTime, + To: toDateTime, + User: viper.GetString("user"), + Tenant: viper.GetString("tenant"), + Project: viper.GetString("project"), + Method: viper.GetString("method"), + ResultCode: viper.GetString("result-code"), + } + resp, err := a.c.Client.Apiv1().Audit().List(ctx, connect.NewRequest(req)) if err != nil { return nil, fmt.Errorf("failed to list audit traces: %w", err) @@ -80,3 +130,34 @@ func (a *audit) List(req *apiv1.AuditServiceListRequest) ([]*apiv1.AuditTrace, e return resp.Msg.Audits, nil } + +func eventuallyRelativeDateTime(s string) (*timestamppb.Timestamp, error) { + if s == "" { + return timestamppb.Now(), nil + } + duration, err := time.ParseDuration(s) + if err == nil { + return timestamppb.New(time.Now().Add(-duration)), nil + } + t, err := time.Parse("2006-01-02 15:04:05", s) + if err != nil { + return timestamppb.Now(), fmt.Errorf("failed to convert time: %w", err) + } + return timestamppb.New(t), nil +} + +func (a *audit) Convert(*apiv1.AuditTrace) (string, *apiv1.AuditServiceGetRequest, *apiv1.AuditServiceListRequest, error) { + return "", nil, nil, fmt.Errorf("not implemented for audit traces") +} + +func (a *audit) Delete(id string) (*apiv1.AuditTrace, error) { + return nil, fmt.Errorf("not implemented for audit traces") +} + +func (a *audit) Create(*apiv1.AuditServiceGetRequest) (*apiv1.AuditTrace, error) { + return nil, fmt.Errorf("not implemented for audit traces") +} + +func (a *audit) Update(*apiv1.AuditServiceListRequest) (*apiv1.AuditTrace, error) { + return nil, fmt.Errorf("not implemented for audit traces") +} diff --git a/cmd/admin/v1/commands.go b/cmd/admin/v1/commands.go index 97f3aeb..f7be3af 100644 --- a/cmd/admin/v1/commands.go +++ b/cmd/admin/v1/commands.go @@ -25,6 +25,7 @@ func AddCmds(cmd *cobra.Command, c *config.Config) { adminCmd.AddCommand(newStorageCmd(c)) adminCmd.AddCommand(newClusterCmd(c)) adminCmd.AddCommand(newTokenCmd(c)) + adminCmd.AddCommand(newAuditCmd(c)) cmd.AddCommand(adminCmd) } diff --git a/cmd/audit_test.go b/cmd/audit_test.go new file mode 100644 index 0000000..5f3a855 --- /dev/null +++ b/cmd/audit_test.go @@ -0,0 +1,163 @@ +package cmd + +import ( + "net/http" + "strconv" + "testing" + "time" + + "connectrpc.com/connect" + apiv1 "github.com/metal-stack-cloud/api/go/api/v1" + apitests "github.com/metal-stack-cloud/api/go/tests" + "github.com/metal-stack/metal-lib/pkg/pointer" + "github.com/stretchr/testify/mock" + "google.golang.org/protobuf/types/known/timestamppb" +) + +var t, _ = time.Parse("2006-01-02 15:04:05", testTime.Format("2006-01-02 15:04:05")) +var ( + auditTrace1 = &apiv1.AuditTrace{ + Uuid: "c40ad996-e1fd-4511-a7bf-418219cb8d91", + Timestamp: timestamppb.New(t), + User: "a-user", + Tenant: "a-tenant", + Project: "project-a", + Method: "/apiv1/ip", + ResponsePayload: `{"a": "b"}`, + SourceIp: "192.168.2.1", + ResultCode: strconv.Itoa(http.StatusOK), + } + auditTrace2 = &apiv1.AuditTrace{ + Uuid: "b5817ef7-980a-41ef-9ed3-741a143870b0", + Timestamp: timestamppb.New(t), + User: "b-user", + Tenant: "b-tenant", + Project: "project-b", + Method: "/apiv1/cluster", + ResponsePayload: `{"c": "d"}`, + SourceIp: "192.168.2.3", + ResultCode: strconv.Itoa(http.StatusForbidden), + } +) //Limit: 100, + +func Test_AuditCmd_MultiResult(t *testing.T) { + tests := []*Test[[]*apiv1.AuditTrace]{ + { + Name: "list", + Cmd: func(want []*apiv1.AuditTrace) []string { + return []string{"admin", "audit", "list"} + }, + ClientMocks: &apitests.ClientMockFns{ + Apiv1Mocks: &apitests.Apiv1MockFns{ + Audit: func(m *mock.Mock) { + beforeOneHour := timestamppb.New(testTime.Add(-1 * time.Hour)) + m.On("List", mock.Anything, connect.NewRequest(&apiv1.AuditServiceListRequest{ + From: beforeOneHour, + To: timestamppb.Now(), + })). + Return(&connect.Response[apiv1.AuditServiceListResponse]{ + Msg: &apiv1.AuditServiceListResponse{ + Audits: []*apiv1.AuditTrace{ + auditTrace2, + auditTrace1, + }, + }, + }, nil) + }, + }, + }, + Want: []*apiv1.AuditTrace{ + auditTrace2, + auditTrace1, + }, + WantTable: pointer.Pointer(` +TIME REQUEST-ID USER TENANT METHOD +2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user b-tenant /apiv1/cluster +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user a-tenant /apiv1/ip + `), + WantWideTable: pointer.Pointer(` +TIME REQUEST-ID USER TENANT PROJECT METHOD SOURCE-IP RESULT-CODE BODY +2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user b-tenant project-b /apiv1/cluster 192.168.2.3 403 {"c": "d"} +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user a-tenant project-a /apiv1/ip 192.168.2.1 200 {"a": "b"} + `), + Template: pointer.Pointer(`{{ date "02/01/2006" .timestamp }} {{ .uuid }}`), + WantTemplate: pointer.Pointer(` +19/05/2022 b5817ef7-980a-41ef-9ed3-741a143870b0 +19/05/2022 c40ad996-e1fd-4511-a7bf-418219cb8d91 + `), + WantMarkdown: pointer.Pointer(` +| TIME | REQUEST-ID | USER | TENANT | METHOD | +|---------------------|--------------------------------------|--------|----------|----------------| +| 2022-05-19 01:02:03 | b5817ef7-980a-41ef-9ed3-741a143870b0 | b-user | b-tenant | /apiv1/cluster | +| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | a-tenant | /apiv1/ip | + `), + }, + { + Name: "list with filters", + Cmd: func(want []*apiv1.AuditTrace) []string { + args := []string{"admin", "audit", "list", + //"--query", want[0].ResponsePayload, + "--request-id", want[0].Uuid, + "--from", want[0].Timestamp.AsTime().Format("2006-01-02 15:04:05"), + "--to", want[0].Timestamp.AsTime().Format("2006-01-02 15:04:05"), + "--user", want[0].User, + "--tenant", want[0].Tenant, + "--project", want[0].Project, + "--method", want[0].Method, + "--source-ip", want[0].SourceIp, + "--result-code", want[0].ResultCode, + //"--limit", "100", + } + AssertExhaustiveArgs(t, args, "sort-by") + return args + }, + ClientMocks: &apitests.ClientMockFns{ + Apiv1Mocks: &apitests.Apiv1MockFns{ + Audit: func(m *mock.Mock) { + m.On("List", mock.Anything, connect.NewRequest(&apiv1.AuditServiceListRequest{ + Uuid: auditTrace1.Uuid, + From: auditTrace1.Timestamp, + To: auditTrace1.Timestamp, + User: auditTrace1.User, + Tenant: auditTrace1.Tenant, + Project: auditTrace1.Project, + Method: auditTrace1.Method, + ResultCode: auditTrace1.ResultCode, + })). + Return(&connect.Response[apiv1.AuditServiceListResponse]{ + Msg: &apiv1.AuditServiceListResponse{ + Audits: []*apiv1.AuditTrace{ + auditTrace1, + }, + }, + }, nil) + }, + }, + }, + Want: []*apiv1.AuditTrace{ + auditTrace1, + }, + + WantTable: pointer.Pointer(` + TIME REQUEST-ID USER TENANT METHOD +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user a-tenant /apiv1/ip + `), + WantWideTable: pointer.Pointer(` +TIME REQUEST-ID USER TENANT PROJECT METHOD SOURCE-IP RESULT-CODE BODY +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user a-tenant project-a /apiv1/ip 192.168.2.1 200 {"a": "b"} + `), + Template: pointer.Pointer(`{{ date "02/01/2006" .timestamp }} {{ .uuid }}`), + WantTemplate: pointer.Pointer(` +19/05/2022 c40ad996-e1fd-4511-a7bf-418219cb8d91 + `), + WantMarkdown: pointer.Pointer(` +| TIME | REQUEST-ID | USER | TENANT | METHOD | +|---------------------|--------------------------------------|--------|----------|-----------| +| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | a-tenant | /apiv1/ip | + `), + }, + } + for _, tt := range tests { + tt.TestCmd(t) + } +} diff --git a/cmd/tableprinters/audit.go b/cmd/tableprinters/audit.go new file mode 100644 index 0000000..d1ef0f5 --- /dev/null +++ b/cmd/tableprinters/audit.go @@ -0,0 +1,44 @@ +package tableprinters + +import ( + "time" + + apiv1 "github.com/metal-stack-cloud/api/go/api/v1" +) + +func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string, [][]string, error) { + var ( + rows [][]string + ) + + header := []string{"TIME", "REQUEST-ID", "USER", "TENANT", "METHOD"} + if wide { + header = []string{"TIME", "REQUEST-ID", "USER", "TENANT", "PROJECT", "METHOD", "SOURCE-IP", "RESULT-CODE", "BODY"} + } + + for _, audit := range data { + id := audit.Uuid + time := truncateToSeconds(audit.Timestamp.AsTime()).Format("2006-01-02 15:04:05") + user := audit.User + tenant := audit.Tenant + project := audit.Project + + method := audit.Method + sourceIp := audit.SourceIp + resultCode := audit.ResultCode + + body := audit.ResponsePayload + + if wide { + rows = append(rows, []string{time, id, user, tenant, project, method, sourceIp, resultCode, body}) + } else { + rows = append(rows, []string{time, id, user, tenant, method}) + } + } + + return header, rows, nil +} + +func truncateToSeconds(t time.Time) time.Time { + return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), 0, t.Location()) +} diff --git a/cmd/tableprinters/common.go b/cmd/tableprinters/common.go index ebaaeaa..c61cb20 100644 --- a/cmd/tableprinters/common.go +++ b/cmd/tableprinters/common.go @@ -30,6 +30,11 @@ func (t *TablePrinter) ToHeaderAndRows(data any, wide bool) ([]string, [][]strin case []*apiv1.Asset: return t.AssetTable(d, wide) + case *apiv1.AuditTrace: + return t.AuditTable(pointer.WrapInSlice(d), wide) + case []*apiv1.AuditTrace: + return t.AuditTable(d, wide) + case *config.Contexts: return t.ContextTable(d, wide) From 9dcdf9a006a713fa2012749c25915a5812063b23 Mon Sep 17 00:00:00 2001 From: AnnaSchreiner Date: Thu, 16 Jan 2025 16:18:22 +0100 Subject: [PATCH 03/20] change request-id/uuid --- cmd/admin/v1/audit.go | 51 ++++++++++++++++++++++++++----------------- cmd/audit_test.go | 2 +- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/cmd/admin/v1/audit.go b/cmd/admin/v1/audit.go index f10f832..126d2ac 100644 --- a/cmd/admin/v1/audit.go +++ b/cmd/admin/v1/audit.go @@ -10,6 +10,7 @@ import ( "github.com/metal-stack-cloud/cli/cmd/sorters" "github.com/metal-stack/metal-lib/pkg/genericcli" "github.com/metal-stack/metal-lib/pkg/genericcli/printers" + "github.com/metal-stack/metal-lib/pkg/pointer" "github.com/spf13/cobra" "github.com/spf13/viper" "google.golang.org/protobuf/types/known/timestamppb" @@ -26,7 +27,7 @@ func newAuditCmd(c *config.Config) *cobra.Command { cmdsConfig := &genericcli.CmdsConfig[*apiv1.AuditServiceGetRequest, *apiv1.AuditServiceListRequest, *apiv1.AuditTrace]{ BinaryName: config.BinaryName, - GenericCLI: genericcli.NewGenericCLI[*apiv1.AuditServiceGetRequest, *apiv1.AuditServiceListRequest, *apiv1.AuditTrace](a).WithFS(c.Fs), + GenericCLI: genericcli.NewGenericCLI(a).WithFS(c.Fs), Singular: "audit trace", Plural: "audit traces", Description: "show audit traces of the api-server", @@ -56,24 +57,24 @@ func newAuditCmd(c *config.Config) *cobra.Command { genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.Completion.ProjectListCompletion)) }, } - - listCmd := &cobra.Command{ - Use: "list", - Short: "list all audit traces", - RunE: func(cmd *cobra.Command, args []string) error { - return nil - }, - } - - getCmd := &cobra.Command{ - Use: "get", - Short: "gets the audit trace", - RunE: func(cmd *cobra.Command, args []string) error { - return nil - }, - } - - return genericcli.NewCmds(cmdsConfig, listCmd, getCmd) + /* + listCmd := &cobra.Command{ + Use: "list", + Short: "list all audit traces", + RunE: func(cmd *cobra.Command, args []string) error { + return a.listAudits() + }, + } + + getCmd := &cobra.Command{ + Use: "get", + Short: "gets the audit trace", + RunE: func(cmd *cobra.Command, args []string) error { + return nil + }, + } */ + + return genericcli.NewCmds(cmdsConfig) //, listCmd, getCmd) } func (a *audit) Get(id string) (*apiv1.AuditTrace, error) { @@ -112,8 +113,14 @@ func (a *audit) List() ([]*apiv1.AuditTrace, error) { return nil, err } + /* tenant, err := a.c.GetTenant() + if err != nil { + return nil, fmt.Errorf("tenant is required %w", err) + } */ + req := &apiv1.AuditServiceListRequest{ - Uuid: viper.GetString("request-id"), + //Login: tenant, + //Uuid: pointer.Pointer(viper.GetString("request-id")), From: fromDateTime, To: toDateTime, User: viper.GetString("user"), @@ -123,6 +130,10 @@ func (a *audit) List() ([]*apiv1.AuditTrace, error) { ResultCode: viper.GetString("result-code"), } + if viper.IsSet("request-id") { + req.Uuid = pointer.Pointer(viper.GetString("request-id")) + } + resp, err := a.c.Client.Apiv1().Audit().List(ctx, connect.NewRequest(req)) if err != nil { return nil, fmt.Errorf("failed to list audit traces: %w", err) diff --git a/cmd/audit_test.go b/cmd/audit_test.go index 5f3a855..6b4f9a3 100644 --- a/cmd/audit_test.go +++ b/cmd/audit_test.go @@ -115,7 +115,7 @@ TIME REQUEST-ID USER TENANT Apiv1Mocks: &apitests.Apiv1MockFns{ Audit: func(m *mock.Mock) { m.On("List", mock.Anything, connect.NewRequest(&apiv1.AuditServiceListRequest{ - Uuid: auditTrace1.Uuid, + Uuid: pointer.Pointer(auditTrace1.Uuid), From: auditTrace1.Timestamp, To: auditTrace1.Timestamp, User: auditTrace1.User, From 658685a3b104c22f2051eb3a3394328a404ffc20 Mon Sep 17 00:00:00 2001 From: ostempel Date: Fri, 17 Jan 2025 17:15:57 +0100 Subject: [PATCH 04/20] draft list and get --- cmd/admin/v1/commands.go | 1 - cmd/{admin => api}/v1/audit.go | 57 +++++++++++++--------------------- cmd/api/v1/commands.go | 15 ++++----- cmd/audit_test.go | 10 +++--- cmd/tableprinters/audit.go | 9 +++--- go.mod | 2 +- go.sum | 12 +++---- 7 files changed, 44 insertions(+), 62 deletions(-) rename cmd/{admin => api}/v1/audit.go (76%) diff --git a/cmd/admin/v1/commands.go b/cmd/admin/v1/commands.go index f7be3af..97f3aeb 100644 --- a/cmd/admin/v1/commands.go +++ b/cmd/admin/v1/commands.go @@ -25,7 +25,6 @@ func AddCmds(cmd *cobra.Command, c *config.Config) { adminCmd.AddCommand(newStorageCmd(c)) adminCmd.AddCommand(newClusterCmd(c)) adminCmd.AddCommand(newTokenCmd(c)) - adminCmd.AddCommand(newAuditCmd(c)) cmd.AddCommand(adminCmd) } diff --git a/cmd/admin/v1/audit.go b/cmd/api/v1/audit.go similarity index 76% rename from cmd/admin/v1/audit.go rename to cmd/api/v1/audit.go index 126d2ac..89d7fd1 100644 --- a/cmd/admin/v1/audit.go +++ b/cmd/api/v1/audit.go @@ -5,6 +5,7 @@ import ( "time" "connectrpc.com/connect" + "github.com/davecgh/go-spew/spew" apiv1 "github.com/metal-stack-cloud/api/go/api/v1" "github.com/metal-stack-cloud/cli/cmd/config" "github.com/metal-stack-cloud/cli/cmd/sorters" @@ -25,13 +26,14 @@ func newAuditCmd(c *config.Config) *cobra.Command { c: c, } - cmdsConfig := &genericcli.CmdsConfig[*apiv1.AuditServiceGetRequest, *apiv1.AuditServiceListRequest, *apiv1.AuditTrace]{ + cmdsConfig := &genericcli.CmdsConfig[*apiv1.AuditServiceGetRequest, *apiv1.AuditServiceGetRequest, *apiv1.AuditTrace]{ BinaryName: config.BinaryName, - GenericCLI: genericcli.NewGenericCLI(a).WithFS(c.Fs), + GenericCLI: genericcli.NewGenericCLI[*apiv1.AuditServiceGetRequest, *apiv1.AuditServiceGetRequest, *apiv1.AuditTrace](a).WithFS(c.Fs), Singular: "audit trace", Plural: "audit traces", Description: "show audit traces of the api-server", Sorter: sorters.AuditSorter(), + OnlyCmds: genericcli.OnlyCmds(genericcli.ListCmd, genericcli.DescribeCmd), DescribePrinter: func() printers.Printer { return c.DescribePrinter }, ListPrinter: func() printers.Printer { return c.ListPrinter }, ListCmdMutateFn: func(cmd *cobra.Command) { @@ -52,29 +54,13 @@ func newAuditCmd(c *config.Config) *cobra.Command { cmd.Flags().String("result-code", "", "HTTP status code of the audit trace.") cmd.Flags().String("source-ip", "", "source-ip of the audit trace.") - //cmd.Flags().Int64("limit", 100, "limit the number of audit traces.") + cmd.Flags().Int64("limit", 100, "limit the number of audit traces.") genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.Completion.ProjectListCompletion)) }, } - /* - listCmd := &cobra.Command{ - Use: "list", - Short: "list all audit traces", - RunE: func(cmd *cobra.Command, args []string) error { - return a.listAudits() - }, - } - - getCmd := &cobra.Command{ - Use: "get", - Short: "gets the audit trace", - RunE: func(cmd *cobra.Command, args []string) error { - return nil - }, - } */ - - return genericcli.NewCmds(cmdsConfig) //, listCmd, getCmd) + + return genericcli.NewCmds(cmdsConfig) } func (a *audit) Get(id string) (*apiv1.AuditTrace, error) { @@ -113,25 +99,26 @@ func (a *audit) List() ([]*apiv1.AuditTrace, error) { return nil, err } - /* tenant, err := a.c.GetTenant() - if err != nil { - return nil, fmt.Errorf("tenant is required %w", err) - } */ + tenant, err := a.c.GetTenant() + if err != nil { + return nil, fmt.Errorf("tenant is required %w", err) + } req := &apiv1.AuditServiceListRequest{ - //Login: tenant, - //Uuid: pointer.Pointer(viper.GetString("request-id")), + Login: tenant, + Uuid: pointer.PointerOrNil(viper.GetString("request-id")), From: fromDateTime, To: toDateTime, - User: viper.GetString("user"), - Tenant: viper.GetString("tenant"), - Project: viper.GetString("project"), - Method: viper.GetString("method"), - ResultCode: viper.GetString("result-code"), + User: pointer.PointerOrNil(viper.GetString("user")), + Project: pointer.PointerOrNil(viper.GetString("project")), + Method: pointer.PointerOrNil(viper.GetString("method")), + ResultCode: pointer.PointerOrNil(viper.GetString("result-code")), + Limit: pointer.PointerOrNil(viper.GetUint64("limit")), } + spew.Dump(req) if viper.IsSet("request-id") { - req.Uuid = pointer.Pointer(viper.GetString("request-id")) + req.Uuid = pointer.PointerOrNil(viper.GetString("request-id")) } resp, err := a.c.Client.Apiv1().Audit().List(ctx, connect.NewRequest(req)) @@ -157,7 +144,7 @@ func eventuallyRelativeDateTime(s string) (*timestamppb.Timestamp, error) { return timestamppb.New(t), nil } -func (a *audit) Convert(*apiv1.AuditTrace) (string, *apiv1.AuditServiceGetRequest, *apiv1.AuditServiceListRequest, error) { +func (a *audit) Convert(*apiv1.AuditTrace) (string, *apiv1.AuditServiceGetRequest, *apiv1.AuditServiceGetRequest, error) { return "", nil, nil, fmt.Errorf("not implemented for audit traces") } @@ -169,6 +156,6 @@ func (a *audit) Create(*apiv1.AuditServiceGetRequest) (*apiv1.AuditTrace, error) return nil, fmt.Errorf("not implemented for audit traces") } -func (a *audit) Update(*apiv1.AuditServiceListRequest) (*apiv1.AuditTrace, error) { +func (a *audit) Update(*apiv1.AuditServiceGetRequest) (*apiv1.AuditTrace, error) { return nil, fmt.Errorf("not implemented for audit traces") } diff --git a/cmd/api/v1/commands.go b/cmd/api/v1/commands.go index 5c6beeb..4eb2ad0 100644 --- a/cmd/api/v1/commands.go +++ b/cmd/api/v1/commands.go @@ -6,18 +6,19 @@ import ( ) func AddCmds(cmd *cobra.Command, c *config.Config) { - cmd.AddCommand(newVersionCmd(c)) - cmd.AddCommand(newHealthCmd(c)) cmd.AddCommand(newAssetCmd(c)) - cmd.AddCommand(newTokenCmd(c)) - cmd.AddCommand(newIPCmd(c)) - cmd.AddCommand(newStorageCmd(c)) + cmd.AddCommand(newAuditCmd(c)) cmd.AddCommand(newClusterCmd(c)) - cmd.AddCommand(newProjectCmd(c)) - cmd.AddCommand(newTenantCmd(c)) + cmd.AddCommand(newHealthCmd(c)) + cmd.AddCommand(newIPCmd(c)) cmd.AddCommand(newMethodsCmd(c)) cmd.AddCommand(newPaymentCmd(c)) + cmd.AddCommand(newProjectCmd(c)) + cmd.AddCommand(newStorageCmd(c)) + cmd.AddCommand(newTenantCmd(c)) + cmd.AddCommand(newTokenCmd(c)) cmd.AddCommand(newUserCmd(c)) + cmd.AddCommand(newVersionCmd(c)) } func newStorageCmd(c *config.Config) *cobra.Command { diff --git a/cmd/audit_test.go b/cmd/audit_test.go index 6b4f9a3..fcb6408 100644 --- a/cmd/audit_test.go +++ b/cmd/audit_test.go @@ -115,14 +115,14 @@ TIME REQUEST-ID USER TENANT Apiv1Mocks: &apitests.Apiv1MockFns{ Audit: func(m *mock.Mock) { m.On("List", mock.Anything, connect.NewRequest(&apiv1.AuditServiceListRequest{ - Uuid: pointer.Pointer(auditTrace1.Uuid), + Uuid: &auditTrace1.Uuid, From: auditTrace1.Timestamp, To: auditTrace1.Timestamp, - User: auditTrace1.User, + User: &auditTrace1.User, Tenant: auditTrace1.Tenant, - Project: auditTrace1.Project, - Method: auditTrace1.Method, - ResultCode: auditTrace1.ResultCode, + Project: &auditTrace1.Project, + Method: &auditTrace1.Method, + ResultCode: &auditTrace1.ResultCode, })). Return(&connect.Response[apiv1.AuditServiceListResponse]{ Msg: &apiv1.AuditServiceListResponse{ diff --git a/cmd/tableprinters/audit.go b/cmd/tableprinters/audit.go index d1ef0f5..ea39f44 100644 --- a/cmd/tableprinters/audit.go +++ b/cmd/tableprinters/audit.go @@ -11,16 +11,15 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string rows [][]string ) - header := []string{"TIME", "REQUEST-ID", "USER", "TENANT", "METHOD"} + header := []string{"TIME", "REQUEST-ID", "USER", "METHOD"} if wide { - header = []string{"TIME", "REQUEST-ID", "USER", "TENANT", "PROJECT", "METHOD", "SOURCE-IP", "RESULT-CODE", "BODY"} + header = []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD", "SOURCE-IP", "RESULT-CODE", "BODY"} } for _, audit := range data { id := audit.Uuid time := truncateToSeconds(audit.Timestamp.AsTime()).Format("2006-01-02 15:04:05") user := audit.User - tenant := audit.Tenant project := audit.Project method := audit.Method @@ -30,9 +29,9 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string body := audit.ResponsePayload if wide { - rows = append(rows, []string{time, id, user, tenant, project, method, sourceIp, resultCode, body}) + rows = append(rows, []string{time, id, user, project, method, sourceIp, resultCode, body}) } else { - rows = append(rows, []string{time, id, user, tenant, method}) + rows = append(rows, []string{time, id, user, method}) } } diff --git a/go.mod b/go.mod index e40b7df..2b564a0 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.18.0 github.com/google/go-cmp v0.6.0 - github.com/metal-stack-cloud/api v0.11.1-0.20250114085412-0a5890ec354f + github.com/metal-stack-cloud/api v0.11.1-0.20250117155502-e4e4409d4d80 github.com/metal-stack/metal-lib v0.19.0 github.com/metal-stack/v v1.0.3 github.com/olekukonko/tablewriter v0.0.5 diff --git a/go.sum b/go.sum index 25cbc97..8a86d40 100644 --- a/go.sum +++ b/go.sum @@ -197,10 +197,10 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/metal-stack-cloud/api v0.10.7 h1:jBQySi3f3MLsGtdTa7OcC4Png/F7eWn/9huUwLhxwss= -github.com/metal-stack-cloud/api v0.10.7/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= -github.com/metal-stack-cloud/api v0.11.1-0.20250114085412-0a5890ec354f h1:TAv0sl9ZXeXSPgy5HuNSA9VbYIA6hH2BtIh0Qp5EjQE= -github.com/metal-stack-cloud/api v0.11.1-0.20250114085412-0a5890ec354f/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= +github.com/metal-stack-cloud/api v0.11.1-0.20250117103800-b3baf4d94f3d h1:YdSOn8tRI21KwgHTbCzEMtJLCYBbazW3IYKAn//DxSY= +github.com/metal-stack-cloud/api v0.11.1-0.20250117103800-b3baf4d94f3d/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= +github.com/metal-stack-cloud/api v0.11.1-0.20250117155502-e4e4409d4d80 h1:FY3+z2bGhP5E1++huiX81novaekToTrvknGFt9pDKQE= +github.com/metal-stack-cloud/api v0.11.1-0.20250117155502-e4e4409d4d80/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= github.com/metal-stack/metal-lib v0.19.0 h1:4yBnp/jPGgX9KeCje3A4MFL2oDjgjOjgsIK391LltRI= github.com/metal-stack/metal-lib v0.19.0/go.mod h1:fCMaWwVGA/xAoGvBk72/nfzqBkHly0iOzrWpc55Fau4= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= @@ -343,8 +343,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -373,8 +371,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= -golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From 3c059845b305fcfce490fee528a3fd38d04d6f89 Mon Sep 17 00:00:00 2001 From: ostempel Date: Mon, 20 Jan 2025 14:24:20 +0100 Subject: [PATCH 05/20] finish audit drafts --- cmd/api/v1/audit.go | 43 +++++++++++++++++++++++++++++++------- cmd/audit_test.go | 2 +- cmd/tableprinters/audit.go | 10 ++++++--- go.mod | 4 ++-- go.sum | 12 +++++++---- 5 files changed, 54 insertions(+), 17 deletions(-) diff --git a/cmd/api/v1/audit.go b/cmd/api/v1/audit.go index 89d7fd1..acb09fa 100644 --- a/cmd/api/v1/audit.go +++ b/cmd/api/v1/audit.go @@ -1,7 +1,9 @@ package v1 import ( + "encoding/json" "fmt" + "strings" "time" "connectrpc.com/connect" @@ -37,7 +39,6 @@ func newAuditCmd(c *config.Config) *cobra.Command { DescribePrinter: func() printers.Printer { return c.DescribePrinter }, ListPrinter: func() printers.Printer { return c.ListPrinter }, ListCmdMutateFn: func(cmd *cobra.Command) { - //cmd.Flags().StringP("query", "q", "", "filters audit trace body payloads for the given text.") cmd.Flags().String("request-id", "", "request id of the audit trace.") @@ -49,15 +50,21 @@ func newAuditCmd(c *config.Config) *cobra.Command { cmd.Flags().String("project", "", "project id of the audit trace") - cmd.Flags().String("method", "", "api Method of the audit trace.") - - cmd.Flags().String("result-code", "", "HTTP status code of the audit trace.") + cmd.Flags().String("method", "", "api method of the audit trace.") + cmd.Flags().Int32("result-code", 0, "HTTP status code of the audit trace.") cmd.Flags().String("source-ip", "", "source-ip of the audit trace.") - cmd.Flags().Int64("limit", 100, "limit the number of audit traces.") + cmd.Flags().String("body", "", "filters audit trace body payloads for the giben text.") + cmd.Flags().String("error", "", "error of the audit trace.") + + //removed since issues arise with current flow of merging req and res to one request + //cmd.Flags().Int64("limit", 100, "limit the number of audit traces.") genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.Completion.ProjectListCompletion)) }, + DescribeCmdMutateFn: func(cmd *cobra.Command) { + cmd.Flags().Bool("prettify-body", false, "attempts to interpret the body as json and prettifies it.") + }, } return genericcli.NewCmds(cmdsConfig) @@ -83,6 +90,26 @@ func (a *audit) Get(id string) (*apiv1.AuditTrace, error) { return nil, fmt.Errorf("failed to get audit trace: %w", err) } + trace := resp.Msg.Audit + + if viper.GetBool("prettify-body") { + trimmed := strings.Trim(trace.RequestPayload, `"`) + body := map[string]any{} + err = json.Unmarshal([]byte(trimmed), &body) + if err == nil { + if pretty, err := json.MarshalIndent(body, "", " "); err == nil { + trace.RequestPayload = string(pretty) + } + } + trimmed = strings.Trim(trace.ResponsePayload, `"`) + err = json.Unmarshal([]byte(trimmed), &body) + if err == nil { + if pretty, err := json.MarshalIndent(body, "", " "); err == nil { + trace.ResponsePayload = string(pretty) + } + } + } + return resp.Msg.Audit, nil } @@ -112,8 +139,10 @@ func (a *audit) List() ([]*apiv1.AuditTrace, error) { User: pointer.PointerOrNil(viper.GetString("user")), Project: pointer.PointerOrNil(viper.GetString("project")), Method: pointer.PointerOrNil(viper.GetString("method")), - ResultCode: pointer.PointerOrNil(viper.GetString("result-code")), - Limit: pointer.PointerOrNil(viper.GetUint64("limit")), + ResultCode: pointer.PointerOrNil(viper.GetInt32("result-code")), + Body: pointer.PointerOrNil(viper.GetString("body")), + Error: pointer.PointerOrNil(viper.GetString("error")), + SourceIp: pointer.PointerOrNil(viper.GetString("source-ip")), } spew.Dump(req) diff --git a/cmd/audit_test.go b/cmd/audit_test.go index fcb6408..e089161 100644 --- a/cmd/audit_test.go +++ b/cmd/audit_test.go @@ -25,7 +25,7 @@ var ( Method: "/apiv1/ip", ResponsePayload: `{"a": "b"}`, SourceIp: "192.168.2.1", - ResultCode: strconv.Itoa(http.StatusOK), + ResultCode: trconv.Itoa(http.StatusOK), } auditTrace2 = &apiv1.AuditTrace{ Uuid: "b5817ef7-980a-41ef-9ed3-741a143870b0", diff --git a/cmd/tableprinters/audit.go b/cmd/tableprinters/audit.go index ea39f44..8f8d3a4 100644 --- a/cmd/tableprinters/audit.go +++ b/cmd/tableprinters/audit.go @@ -4,6 +4,7 @@ import ( "time" apiv1 "github.com/metal-stack-cloud/api/go/api/v1" + "github.com/metal-stack/metal-lib/pkg/genericcli" ) func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string, [][]string, error) { @@ -13,7 +14,7 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string header := []string{"TIME", "REQUEST-ID", "USER", "METHOD"} if wide { - header = []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD", "SOURCE-IP", "RESULT-CODE", "BODY"} + header = []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD", "SOURCE-IP", "RESULT-CODE", "ERROR", "REQ-BODY", "RES-BODY"} } for _, audit := range data { @@ -26,10 +27,13 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string sourceIp := audit.SourceIp resultCode := audit.ResultCode - body := audit.ResponsePayload + resBody := genericcli.TruncateEnd(audit.ResponsePayload, 30) + reqBody := genericcli.TruncateEnd(audit.RequestPayload, 30) + + error := audit.Error if wide { - rows = append(rows, []string{time, id, user, project, method, sourceIp, resultCode, body}) + rows = append(rows, []string{time, id, user, project, method, sourceIp, resultCode, error, reqBody, resBody}) } else { rows = append(rows, []string{time, id, user, method}) } diff --git a/go.mod b/go.mod index 2b564a0..c51aa8f 100644 --- a/go.mod +++ b/go.mod @@ -5,10 +5,11 @@ go 1.23 require ( bou.ke/monkey v1.0.2 connectrpc.com/connect v1.17.0 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.18.0 github.com/google/go-cmp v0.6.0 - github.com/metal-stack-cloud/api v0.11.1-0.20250117155502-e4e4409d4d80 + github.com/metal-stack-cloud/api v0.11.1-0.20250120131007-0e9d14e3b177 github.com/metal-stack/metal-lib v0.19.0 github.com/metal-stack/v v1.0.3 github.com/olekukonko/tablewriter v0.0.5 @@ -50,7 +51,6 @@ require ( github.com/coder/websocket v1.8.12 // indirect github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dblohm7/wingoes v0.0.0-20240801171404-fc12d7c70140 // indirect github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect diff --git a/go.sum b/go.sum index 8a86d40..b39a321 100644 --- a/go.sum +++ b/go.sum @@ -197,10 +197,14 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/metal-stack-cloud/api v0.11.1-0.20250117103800-b3baf4d94f3d h1:YdSOn8tRI21KwgHTbCzEMtJLCYBbazW3IYKAn//DxSY= -github.com/metal-stack-cloud/api v0.11.1-0.20250117103800-b3baf4d94f3d/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= -github.com/metal-stack-cloud/api v0.11.1-0.20250117155502-e4e4409d4d80 h1:FY3+z2bGhP5E1++huiX81novaekToTrvknGFt9pDKQE= -github.com/metal-stack-cloud/api v0.11.1-0.20250117155502-e4e4409d4d80/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= +github.com/metal-stack-cloud/api v0.11.1-0.20250120091634-35ceed19c4f5 h1:9/Ja3hYtVY/psoi4hOkRemA525F/I7tktKsmJmxJ2XM= +github.com/metal-stack-cloud/api v0.11.1-0.20250120091634-35ceed19c4f5/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= +github.com/metal-stack-cloud/api v0.11.1-0.20250120101721-b366bdaa2519 h1:kWZmJvwt7/i9pe4kNXYRCiWlS7DiK1GCUtBK9mdqHN0= +github.com/metal-stack-cloud/api v0.11.1-0.20250120101721-b366bdaa2519/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= +github.com/metal-stack-cloud/api v0.11.1-0.20250120104711-0b37c9a2b2df h1:NYikwFAfJVo+r4AExovesI4b+AUfqfqFGNCu+QCnf1s= +github.com/metal-stack-cloud/api v0.11.1-0.20250120104711-0b37c9a2b2df/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= +github.com/metal-stack-cloud/api v0.11.1-0.20250120131007-0e9d14e3b177 h1:Qt8dSg/VxW75EXIFauAyx5KIczSDzr0mzobcZQ3lqX8= +github.com/metal-stack-cloud/api v0.11.1-0.20250120131007-0e9d14e3b177/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= github.com/metal-stack/metal-lib v0.19.0 h1:4yBnp/jPGgX9KeCje3A4MFL2oDjgjOjgsIK391LltRI= github.com/metal-stack/metal-lib v0.19.0/go.mod h1:fCMaWwVGA/xAoGvBk72/nfzqBkHly0iOzrWpc55Fau4= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= From fd002c95a941ee56b8bf644675e7c540ac843140 Mon Sep 17 00:00:00 2001 From: ostempel Date: Tue, 21 Jan 2025 15:47:36 +0100 Subject: [PATCH 06/20] fix audit tests --- cmd/api/v1/audit.go | 2 -- cmd/audit_test.go | 69 +++++++++++++++++++++----------------- cmd/tableprinters/audit.go | 6 +++- go.mod | 4 +-- go.sum | 10 ++---- 5 files changed, 47 insertions(+), 44 deletions(-) diff --git a/cmd/api/v1/audit.go b/cmd/api/v1/audit.go index acb09fa..3933591 100644 --- a/cmd/api/v1/audit.go +++ b/cmd/api/v1/audit.go @@ -7,7 +7,6 @@ import ( "time" "connectrpc.com/connect" - "github.com/davecgh/go-spew/spew" apiv1 "github.com/metal-stack-cloud/api/go/api/v1" "github.com/metal-stack-cloud/cli/cmd/config" "github.com/metal-stack-cloud/cli/cmd/sorters" @@ -145,7 +144,6 @@ func (a *audit) List() ([]*apiv1.AuditTrace, error) { SourceIp: pointer.PointerOrNil(viper.GetString("source-ip")), } - spew.Dump(req) if viper.IsSet("request-id") { req.Uuid = pointer.PointerOrNil(viper.GetString("request-id")) } diff --git a/cmd/audit_test.go b/cmd/audit_test.go index e089161..d637e40 100644 --- a/cmd/audit_test.go +++ b/cmd/audit_test.go @@ -25,7 +25,9 @@ var ( Method: "/apiv1/ip", ResponsePayload: `{"a": "b"}`, SourceIp: "192.168.2.1", - ResultCode: trconv.Itoa(http.StatusOK), + ResultCode: http.StatusOK, + Error: "err1", + RequestPayload: "{}", } auditTrace2 = &apiv1.AuditTrace{ Uuid: "b5817ef7-980a-41ef-9ed3-741a143870b0", @@ -36,24 +38,28 @@ var ( Method: "/apiv1/cluster", ResponsePayload: `{"c": "d"}`, SourceIp: "192.168.2.3", - ResultCode: strconv.Itoa(http.StatusForbidden), + ResultCode: http.StatusForbidden, + Error: "err2", + RequestPayload: "{}", } -) //Limit: 100, +) func Test_AuditCmd_MultiResult(t *testing.T) { tests := []*Test[[]*apiv1.AuditTrace]{ { Name: "list", Cmd: func(want []*apiv1.AuditTrace) []string { - return []string{"admin", "audit", "list"} + return []string{"audit", "list", "--tenant", "a-tenant"} }, ClientMocks: &apitests.ClientMockFns{ Apiv1Mocks: &apitests.Apiv1MockFns{ Audit: func(m *mock.Mock) { beforeOneHour := timestamppb.New(testTime.Add(-1 * time.Hour)) + m.On("List", mock.Anything, connect.NewRequest(&apiv1.AuditServiceListRequest{ - From: beforeOneHour, - To: timestamppb.Now(), + Login: "a-tenant", + From: beforeOneHour, + To: timestamppb.Now(), })). Return(&connect.Response[apiv1.AuditServiceListResponse]{ Msg: &apiv1.AuditServiceListResponse{ @@ -71,14 +77,14 @@ func Test_AuditCmd_MultiResult(t *testing.T) { auditTrace1, }, WantTable: pointer.Pointer(` -TIME REQUEST-ID USER TENANT METHOD -2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user b-tenant /apiv1/cluster -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user a-tenant /apiv1/ip +TIME REQUEST-ID USER METHOD +2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user /apiv1/cluster +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user /apiv1/ip `), WantWideTable: pointer.Pointer(` -TIME REQUEST-ID USER TENANT PROJECT METHOD SOURCE-IP RESULT-CODE BODY -2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user b-tenant project-b /apiv1/cluster 192.168.2.3 403 {"c": "d"} -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user a-tenant project-a /apiv1/ip 192.168.2.1 200 {"a": "b"} +TIME REQUEST-ID USER PROJECT METHOD SOURCE-IP RESULT-CODE ERROR REQ-BODY RES-BODY +2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster 192.168.2.3 403 err2 {} {"c": "d"} +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip 192.168.2.1 200 err1 {} {"a": "b"} `), Template: pointer.Pointer(`{{ date "02/01/2006" .timestamp }} {{ .uuid }}`), WantTemplate: pointer.Pointer(` @@ -86,43 +92,45 @@ TIME REQUEST-ID USER TENANT 19/05/2022 c40ad996-e1fd-4511-a7bf-418219cb8d91 `), WantMarkdown: pointer.Pointer(` -| TIME | REQUEST-ID | USER | TENANT | METHOD | -|---------------------|--------------------------------------|--------|----------|----------------| -| 2022-05-19 01:02:03 | b5817ef7-980a-41ef-9ed3-741a143870b0 | b-user | b-tenant | /apiv1/cluster | -| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | a-tenant | /apiv1/ip | +| TIME | REQUEST-ID | USER | METHOD | +|---------------------|--------------------------------------|--------|----------------| +| 2022-05-19 01:02:03 | b5817ef7-980a-41ef-9ed3-741a143870b0 | b-user | /apiv1/cluster | +| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | /apiv1/ip | `), }, { Name: "list with filters", Cmd: func(want []*apiv1.AuditTrace) []string { - args := []string{"admin", "audit", "list", - //"--query", want[0].ResponsePayload, + args := []string{"audit", "list", + "--tenant", "a-tenant", "--request-id", want[0].Uuid, "--from", want[0].Timestamp.AsTime().Format("2006-01-02 15:04:05"), "--to", want[0].Timestamp.AsTime().Format("2006-01-02 15:04:05"), "--user", want[0].User, - "--tenant", want[0].Tenant, "--project", want[0].Project, "--method", want[0].Method, "--source-ip", want[0].SourceIp, - "--result-code", want[0].ResultCode, - //"--limit", "100", + "--result-code", strconv.Itoa(int(want[0].ResultCode)), + "--body", want[0].ResponsePayload, + "--error", want[0].Error, } - AssertExhaustiveArgs(t, args, "sort-by") return args }, ClientMocks: &apitests.ClientMockFns{ Apiv1Mocks: &apitests.Apiv1MockFns{ Audit: func(m *mock.Mock) { m.On("List", mock.Anything, connect.NewRequest(&apiv1.AuditServiceListRequest{ + Login: "a-tenant", Uuid: &auditTrace1.Uuid, From: auditTrace1.Timestamp, To: auditTrace1.Timestamp, User: &auditTrace1.User, - Tenant: auditTrace1.Tenant, Project: &auditTrace1.Project, Method: &auditTrace1.Method, ResultCode: &auditTrace1.ResultCode, + SourceIp: &auditTrace1.SourceIp, + Error: &auditTrace1.Error, + Body: &auditTrace1.ResponsePayload, })). Return(&connect.Response[apiv1.AuditServiceListResponse]{ Msg: &apiv1.AuditServiceListResponse{ @@ -137,23 +145,22 @@ TIME REQUEST-ID USER TENANT Want: []*apiv1.AuditTrace{ auditTrace1, }, - WantTable: pointer.Pointer(` - TIME REQUEST-ID USER TENANT METHOD -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user a-tenant /apiv1/ip +TIME REQUEST-ID USER METHOD +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user /apiv1/ip `), WantWideTable: pointer.Pointer(` -TIME REQUEST-ID USER TENANT PROJECT METHOD SOURCE-IP RESULT-CODE BODY -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user a-tenant project-a /apiv1/ip 192.168.2.1 200 {"a": "b"} +TIME REQUEST-ID USER PROJECT METHOD SOURCE-IP RESULT-CODE ERROR REQ-BODY RES-BODY +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip 192.168.2.1 200 err1 {} {"a": "b"} `), Template: pointer.Pointer(`{{ date "02/01/2006" .timestamp }} {{ .uuid }}`), WantTemplate: pointer.Pointer(` 19/05/2022 c40ad996-e1fd-4511-a7bf-418219cb8d91 `), WantMarkdown: pointer.Pointer(` -| TIME | REQUEST-ID | USER | TENANT | METHOD | -|---------------------|--------------------------------------|--------|----------|-----------| -| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | a-tenant | /apiv1/ip | +| TIME | REQUEST-ID | USER | METHOD | +|---------------------|--------------------------------------|--------|-----------| +| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | /apiv1/ip | `), }, } diff --git a/cmd/tableprinters/audit.go b/cmd/tableprinters/audit.go index 8f8d3a4..09d3bb9 100644 --- a/cmd/tableprinters/audit.go +++ b/cmd/tableprinters/audit.go @@ -1,6 +1,7 @@ package tableprinters import ( + "fmt" "time" apiv1 "github.com/metal-stack-cloud/api/go/api/v1" @@ -25,7 +26,6 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string method := audit.Method sourceIp := audit.SourceIp - resultCode := audit.ResultCode resBody := genericcli.TruncateEnd(audit.ResponsePayload, 30) reqBody := genericcli.TruncateEnd(audit.RequestPayload, 30) @@ -33,6 +33,10 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string error := audit.Error if wide { + var resultCode string + if audit.ResultCode != 0 { + resultCode = fmt.Sprintf("%d", audit.ResultCode) + } rows = append(rows, []string{time, id, user, project, method, sourceIp, resultCode, error, reqBody, resBody}) } else { rows = append(rows, []string{time, id, user, method}) diff --git a/go.mod b/go.mod index c51aa8f..dec41a8 100644 --- a/go.mod +++ b/go.mod @@ -5,11 +5,10 @@ go 1.23 require ( bou.ke/monkey v1.0.2 connectrpc.com/connect v1.17.0 - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.18.0 github.com/google/go-cmp v0.6.0 - github.com/metal-stack-cloud/api v0.11.1-0.20250120131007-0e9d14e3b177 + github.com/metal-stack-cloud/api v0.11.1-0.20250121081135-d58cc0c5d261 github.com/metal-stack/metal-lib v0.19.0 github.com/metal-stack/v v1.0.3 github.com/olekukonko/tablewriter v0.0.5 @@ -51,6 +50,7 @@ require ( github.com/coder/websocket v1.8.12 // indirect github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dblohm7/wingoes v0.0.0-20240801171404-fc12d7c70140 // indirect github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect diff --git a/go.sum b/go.sum index b39a321..b64459c 100644 --- a/go.sum +++ b/go.sum @@ -197,14 +197,8 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/metal-stack-cloud/api v0.11.1-0.20250120091634-35ceed19c4f5 h1:9/Ja3hYtVY/psoi4hOkRemA525F/I7tktKsmJmxJ2XM= -github.com/metal-stack-cloud/api v0.11.1-0.20250120091634-35ceed19c4f5/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= -github.com/metal-stack-cloud/api v0.11.1-0.20250120101721-b366bdaa2519 h1:kWZmJvwt7/i9pe4kNXYRCiWlS7DiK1GCUtBK9mdqHN0= -github.com/metal-stack-cloud/api v0.11.1-0.20250120101721-b366bdaa2519/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= -github.com/metal-stack-cloud/api v0.11.1-0.20250120104711-0b37c9a2b2df h1:NYikwFAfJVo+r4AExovesI4b+AUfqfqFGNCu+QCnf1s= -github.com/metal-stack-cloud/api v0.11.1-0.20250120104711-0b37c9a2b2df/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= -github.com/metal-stack-cloud/api v0.11.1-0.20250120131007-0e9d14e3b177 h1:Qt8dSg/VxW75EXIFauAyx5KIczSDzr0mzobcZQ3lqX8= -github.com/metal-stack-cloud/api v0.11.1-0.20250120131007-0e9d14e3b177/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= +github.com/metal-stack-cloud/api v0.11.1-0.20250121081135-d58cc0c5d261 h1:31SeSPscrmhYeAoIMhUnPmjR+CGIhmPhNibPkr6NcT0= +github.com/metal-stack-cloud/api v0.11.1-0.20250121081135-d58cc0c5d261/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= github.com/metal-stack/metal-lib v0.19.0 h1:4yBnp/jPGgX9KeCje3A4MFL2oDjgjOjgsIK391LltRI= github.com/metal-stack/metal-lib v0.19.0/go.mod h1:fCMaWwVGA/xAoGvBk72/nfzqBkHly0iOzrWpc55Fau4= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= From 4d3d4173434f6734c4b72552e6dcefa8ea03ff7c Mon Sep 17 00:00:00 2001 From: ostempel Date: Mon, 27 Jan 2025 11:19:23 +0100 Subject: [PATCH 07/20] finish audit traces --- cmd/api/v1/audit.go | 4 ---- cmd/sorters/audit.go | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd/api/v1/audit.go b/cmd/api/v1/audit.go index 3933591..646ceeb 100644 --- a/cmd/api/v1/audit.go +++ b/cmd/api/v1/audit.go @@ -144,10 +144,6 @@ func (a *audit) List() ([]*apiv1.AuditTrace, error) { SourceIp: pointer.PointerOrNil(viper.GetString("source-ip")), } - if viper.IsSet("request-id") { - req.Uuid = pointer.PointerOrNil(viper.GetString("request-id")) - } - resp, err := a.c.Client.Apiv1().Audit().List(ctx, connect.NewRequest(req)) if err != nil { return nil, fmt.Errorf("failed to list audit traces: %w", err) diff --git a/cmd/sorters/audit.go b/cmd/sorters/audit.go index 556c320..e281992 100644 --- a/cmd/sorters/audit.go +++ b/cmd/sorters/audit.go @@ -18,5 +18,8 @@ func AuditSorter() *multisort.Sorter[*apiv1.AuditTrace] { "method": func(a, b *apiv1.AuditTrace, descending bool) multisort.CompareResult { return multisort.Compare(a.Method, b.Method, descending) }, + "project": func(a, b *apiv1.AuditTrace, descending bool) multisort.CompareResult { + return multisort.Compare(a.Project, b.Project, descending) + }, }, multisort.Keys{{ID: "timestamp", Descending: true}}) } From 8f789220d93c0814cd32a0f2efaaf8fa5a954c9b Mon Sep 17 00:00:00 2001 From: ostempel Date: Mon, 27 Jan 2025 11:26:40 +0100 Subject: [PATCH 08/20] add project field to tabelprinter --- cmd/tableprinters/audit.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/tableprinters/audit.go b/cmd/tableprinters/audit.go index 09d3bb9..05903a3 100644 --- a/cmd/tableprinters/audit.go +++ b/cmd/tableprinters/audit.go @@ -13,7 +13,7 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string rows [][]string ) - header := []string{"TIME", "REQUEST-ID", "USER", "METHOD"} + header := []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD"} if wide { header = []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD", "SOURCE-IP", "RESULT-CODE", "ERROR", "REQ-BODY", "RES-BODY"} } @@ -39,7 +39,7 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string } rows = append(rows, []string{time, id, user, project, method, sourceIp, resultCode, error, reqBody, resBody}) } else { - rows = append(rows, []string{time, id, user, method}) + rows = append(rows, []string{time, id, user, project, method}) } } From ee40e98ed7f611c2e0f383f686d0b77a72469c82 Mon Sep 17 00:00:00 2001 From: ostempel Date: Mon, 27 Jan 2025 11:44:29 +0100 Subject: [PATCH 09/20] remove error field from audit-trace --- cmd/api/v1/audit.go | 1 - cmd/audit_test.go | 38 +++++++++++++++++--------------------- cmd/tableprinters/audit.go | 6 ++---- go.mod | 2 +- go.sum | 2 ++ 5 files changed, 22 insertions(+), 27 deletions(-) diff --git a/cmd/api/v1/audit.go b/cmd/api/v1/audit.go index 646ceeb..ef5e2a5 100644 --- a/cmd/api/v1/audit.go +++ b/cmd/api/v1/audit.go @@ -140,7 +140,6 @@ func (a *audit) List() ([]*apiv1.AuditTrace, error) { Method: pointer.PointerOrNil(viper.GetString("method")), ResultCode: pointer.PointerOrNil(viper.GetInt32("result-code")), Body: pointer.PointerOrNil(viper.GetString("body")), - Error: pointer.PointerOrNil(viper.GetString("error")), SourceIp: pointer.PointerOrNil(viper.GetString("source-ip")), } diff --git a/cmd/audit_test.go b/cmd/audit_test.go index d637e40..1e1c988 100644 --- a/cmd/audit_test.go +++ b/cmd/audit_test.go @@ -26,7 +26,6 @@ var ( ResponsePayload: `{"a": "b"}`, SourceIp: "192.168.2.1", ResultCode: http.StatusOK, - Error: "err1", RequestPayload: "{}", } auditTrace2 = &apiv1.AuditTrace{ @@ -39,7 +38,6 @@ var ( ResponsePayload: `{"c": "d"}`, SourceIp: "192.168.2.3", ResultCode: http.StatusForbidden, - Error: "err2", RequestPayload: "{}", } ) @@ -77,14 +75,14 @@ func Test_AuditCmd_MultiResult(t *testing.T) { auditTrace1, }, WantTable: pointer.Pointer(` -TIME REQUEST-ID USER METHOD -2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user /apiv1/cluster -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user /apiv1/ip +TIME REQUEST-ID USER PROJECT METHOD +2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip `), WantWideTable: pointer.Pointer(` -TIME REQUEST-ID USER PROJECT METHOD SOURCE-IP RESULT-CODE ERROR REQ-BODY RES-BODY -2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster 192.168.2.3 403 err2 {} {"c": "d"} -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip 192.168.2.1 200 err1 {} {"a": "b"} +TIME REQUEST-ID USER PROJECT METHOD SOURCE-IP RESULT-CODE REQ-BODY RES-BODY +2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster 192.168.2.3 403 {} {"c": "d"} +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip 192.168.2.1 200 {} {"a": "b"} `), Template: pointer.Pointer(`{{ date "02/01/2006" .timestamp }} {{ .uuid }}`), WantTemplate: pointer.Pointer(` @@ -92,10 +90,10 @@ TIME REQUEST-ID USER PROJECT 19/05/2022 c40ad996-e1fd-4511-a7bf-418219cb8d91 `), WantMarkdown: pointer.Pointer(` -| TIME | REQUEST-ID | USER | METHOD | -|---------------------|--------------------------------------|--------|----------------| -| 2022-05-19 01:02:03 | b5817ef7-980a-41ef-9ed3-741a143870b0 | b-user | /apiv1/cluster | -| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | /apiv1/ip | +| TIME | REQUEST-ID | USER | PROJECT | METHOD | +|---------------------|--------------------------------------|--------|-----------|----------------| +| 2022-05-19 01:02:03 | b5817ef7-980a-41ef-9ed3-741a143870b0 | b-user | project-b | /apiv1/cluster | +| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | `), }, { @@ -112,7 +110,6 @@ TIME REQUEST-ID USER PROJECT "--source-ip", want[0].SourceIp, "--result-code", strconv.Itoa(int(want[0].ResultCode)), "--body", want[0].ResponsePayload, - "--error", want[0].Error, } return args }, @@ -129,7 +126,6 @@ TIME REQUEST-ID USER PROJECT Method: &auditTrace1.Method, ResultCode: &auditTrace1.ResultCode, SourceIp: &auditTrace1.SourceIp, - Error: &auditTrace1.Error, Body: &auditTrace1.ResponsePayload, })). Return(&connect.Response[apiv1.AuditServiceListResponse]{ @@ -146,21 +142,21 @@ TIME REQUEST-ID USER PROJECT auditTrace1, }, WantTable: pointer.Pointer(` -TIME REQUEST-ID USER METHOD -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user /apiv1/ip +TIME REQUEST-ID USER PROJECT METHOD +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip `), WantWideTable: pointer.Pointer(` -TIME REQUEST-ID USER PROJECT METHOD SOURCE-IP RESULT-CODE ERROR REQ-BODY RES-BODY -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip 192.168.2.1 200 err1 {} {"a": "b"} +TIME REQUEST-ID USER PROJECT METHOD SOURCE-IP RESULT-CODE REQ-BODY RES-BODY +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip 192.168.2.1 200 {} {"a": "b"} `), Template: pointer.Pointer(`{{ date "02/01/2006" .timestamp }} {{ .uuid }}`), WantTemplate: pointer.Pointer(` 19/05/2022 c40ad996-e1fd-4511-a7bf-418219cb8d91 `), WantMarkdown: pointer.Pointer(` -| TIME | REQUEST-ID | USER | METHOD | -|---------------------|--------------------------------------|--------|-----------| -| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | /apiv1/ip | +| TIME | REQUEST-ID | USER | PROJECT | METHOD | +|---------------------|--------------------------------------|--------|-----------|-----------| +| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | `), }, } diff --git a/cmd/tableprinters/audit.go b/cmd/tableprinters/audit.go index 05903a3..148ab25 100644 --- a/cmd/tableprinters/audit.go +++ b/cmd/tableprinters/audit.go @@ -15,7 +15,7 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string header := []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD"} if wide { - header = []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD", "SOURCE-IP", "RESULT-CODE", "ERROR", "REQ-BODY", "RES-BODY"} + header = []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD", "SOURCE-IP", "RESULT-CODE", "REQ-BODY", "RES-BODY"} } for _, audit := range data { @@ -30,14 +30,12 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string resBody := genericcli.TruncateEnd(audit.ResponsePayload, 30) reqBody := genericcli.TruncateEnd(audit.RequestPayload, 30) - error := audit.Error - if wide { var resultCode string if audit.ResultCode != 0 { resultCode = fmt.Sprintf("%d", audit.ResultCode) } - rows = append(rows, []string{time, id, user, project, method, sourceIp, resultCode, error, reqBody, resBody}) + rows = append(rows, []string{time, id, user, project, method, sourceIp, resultCode, reqBody, resBody}) } else { rows = append(rows, []string{time, id, user, project, method}) } diff --git a/go.mod b/go.mod index dec41a8..30601b5 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.18.0 github.com/google/go-cmp v0.6.0 - github.com/metal-stack-cloud/api v0.11.1-0.20250121081135-d58cc0c5d261 + github.com/metal-stack-cloud/api v0.11.1-0.20250127103731-881df2ebf865 github.com/metal-stack/metal-lib v0.19.0 github.com/metal-stack/v v1.0.3 github.com/olekukonko/tablewriter v0.0.5 diff --git a/go.sum b/go.sum index b64459c..b1bbd35 100644 --- a/go.sum +++ b/go.sum @@ -199,6 +199,8 @@ github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= github.com/metal-stack-cloud/api v0.11.1-0.20250121081135-d58cc0c5d261 h1:31SeSPscrmhYeAoIMhUnPmjR+CGIhmPhNibPkr6NcT0= github.com/metal-stack-cloud/api v0.11.1-0.20250121081135-d58cc0c5d261/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= +github.com/metal-stack-cloud/api v0.11.1-0.20250127103731-881df2ebf865 h1:5QRM9lnLp/Ro8EvqStKwApE7QDOprtDbSsjIr0dnscM= +github.com/metal-stack-cloud/api v0.11.1-0.20250127103731-881df2ebf865/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= github.com/metal-stack/metal-lib v0.19.0 h1:4yBnp/jPGgX9KeCje3A4MFL2oDjgjOjgsIK391LltRI= github.com/metal-stack/metal-lib v0.19.0/go.mod h1:fCMaWwVGA/xAoGvBk72/nfzqBkHly0iOzrWpc55Fau4= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= From 2311749704a53e5de3c486bacbb839c9a293613b Mon Sep 17 00:00:00 2001 From: ostempel Date: Tue, 4 Mar 2025 16:35:48 +0100 Subject: [PATCH 10/20] remove split of req/res and add limit --- cmd/api/v1/audit.go | 18 ++++-------- cmd/tableprinters/audit.go | 12 ++++---- go.mod | 32 ++++++++++---------- go.sum | 60 +++++++++++++++++++------------------- 4 files changed, 59 insertions(+), 63 deletions(-) diff --git a/cmd/api/v1/audit.go b/cmd/api/v1/audit.go index ef5e2a5..ceaae05 100644 --- a/cmd/api/v1/audit.go +++ b/cmd/api/v1/audit.go @@ -56,8 +56,7 @@ func newAuditCmd(c *config.Config) *cobra.Command { cmd.Flags().String("body", "", "filters audit trace body payloads for the giben text.") cmd.Flags().String("error", "", "error of the audit trace.") - //removed since issues arise with current flow of merging req and res to one request - //cmd.Flags().Int64("limit", 100, "limit the number of audit traces.") + cmd.Flags().Int64("limit", 6, "limit the number of audit traces.") genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.Completion.ProjectListCompletion)) }, @@ -73,7 +72,8 @@ func (a *audit) Get(id string) (*apiv1.AuditTrace, error) { ctx, cancel := a.c.NewRequestContext() defer cancel() - // not sure about how to get tenant of current user + project := a.c.GetProject() + fmt.Printf("project: %s", project) tenant, err := a.c.GetTenant() if err != nil { return nil, fmt.Errorf("tenant is required") @@ -92,19 +92,12 @@ func (a *audit) Get(id string) (*apiv1.AuditTrace, error) { trace := resp.Msg.Audit if viper.GetBool("prettify-body") { - trimmed := strings.Trim(trace.RequestPayload, `"`) + trimmed := strings.Trim(trace.Body, `"`) body := map[string]any{} err = json.Unmarshal([]byte(trimmed), &body) if err == nil { if pretty, err := json.MarshalIndent(body, "", " "); err == nil { - trace.RequestPayload = string(pretty) - } - } - trimmed = strings.Trim(trace.ResponsePayload, `"`) - err = json.Unmarshal([]byte(trimmed), &body) - if err == nil { - if pretty, err := json.MarshalIndent(body, "", " "); err == nil { - trace.ResponsePayload = string(pretty) + trace.Body = string(pretty) } } } @@ -141,6 +134,7 @@ func (a *audit) List() ([]*apiv1.AuditTrace, error) { ResultCode: pointer.PointerOrNil(viper.GetInt32("result-code")), Body: pointer.PointerOrNil(viper.GetString("body")), SourceIp: pointer.PointerOrNil(viper.GetString("source-ip")), + Limit: pointer.PointerOrNil(viper.GetInt32("limit")), } resp, err := a.c.Client.Apiv1().Audit().List(ctx, connect.NewRequest(req)) diff --git a/cmd/tableprinters/audit.go b/cmd/tableprinters/audit.go index 148ab25..cc9b68a 100644 --- a/cmd/tableprinters/audit.go +++ b/cmd/tableprinters/audit.go @@ -13,9 +13,9 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string rows [][]string ) - header := []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD"} + header := []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD", "PHASE"} if wide { - header = []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD", "SOURCE-IP", "RESULT-CODE", "REQ-BODY", "RES-BODY"} + header = []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD", "PHASE", "SOURCE-IP", "RESULT-CODE", "BODY"} } for _, audit := range data { @@ -23,21 +23,21 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string time := truncateToSeconds(audit.Timestamp.AsTime()).Format("2006-01-02 15:04:05") user := audit.User project := audit.Project + phase := audit.Phase method := audit.Method sourceIp := audit.SourceIp - resBody := genericcli.TruncateEnd(audit.ResponsePayload, 30) - reqBody := genericcli.TruncateEnd(audit.RequestPayload, 30) + body := genericcli.TruncateEnd(audit.Body, 30) if wide { var resultCode string if audit.ResultCode != 0 { resultCode = fmt.Sprintf("%d", audit.ResultCode) } - rows = append(rows, []string{time, id, user, project, method, sourceIp, resultCode, reqBody, resBody}) + rows = append(rows, []string{time, id, user, project, method, phase, sourceIp, resultCode, body}) } else { - rows = append(rows, []string{time, id, user, project, method}) + rows = append(rows, []string{time, id, user, project, method, phase}) } } diff --git a/go.mod b/go.mod index 30601b5..afe1284 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,16 @@ module github.com/metal-stack-cloud/cli -go 1.23 +go 1.24 + +toolchain go1.24.0 require ( bou.ke/monkey v1.0.2 - connectrpc.com/connect v1.17.0 + connectrpc.com/connect v1.18.1 github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.18.0 github.com/google/go-cmp v0.6.0 - github.com/metal-stack-cloud/api v0.11.1-0.20250127103731-881df2ebf865 + github.com/metal-stack-cloud/api v0.12.2-0.20250304153041-e5722a29eeac github.com/metal-stack/metal-lib v0.19.0 github.com/metal-stack/v v1.0.3 github.com/olekukonko/tablewriter v0.0.5 @@ -17,8 +19,8 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.10.0 - golang.org/x/net v0.31.0 - google.golang.org/protobuf v1.35.2 + golang.org/x/net v0.35.0 + google.golang.org/protobuf v1.36.5 k8s.io/api v0.31.0 k8s.io/apimachinery v0.31.0 k8s.io/client-go v0.31.0 @@ -26,7 +28,7 @@ require ( ) require ( - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.35.2-20240920164238-5a7b106cbb87.1 // indirect + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.5-20250219170025-d39267d9df8f.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/akutz/memconn v0.1.0 // indirect github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect @@ -82,7 +84,7 @@ require ( github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect github.com/jsimonetti/rtnetlink v1.4.2 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.11 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/connect-compress/v2 v2.0.0 // indirect github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a // indirect github.com/magiconair/properties v1.8.7 // indirect @@ -130,16 +132,16 @@ require ( go.uber.org/multierr v1.11.0 // indirect go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.29.0 // indirect - golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect - golang.org/x/mod v0.22.0 // indirect + golang.org/x/crypto v0.33.0 // indirect + golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect + golang.org/x/mod v0.23.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/term v0.26.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/term v0.29.0 // indirect + golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.8.0 // indirect - golang.org/x/tools v0.27.0 // indirect + golang.org/x/tools v0.30.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect diff --git a/go.sum b/go.sum index b1bbd35..1763440 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ bou.ke/monkey v1.0.2 h1:kWcnsrCNUatbxncxR/ThdYqbytgOIArtYWqcQLQzKLI= bou.ke/monkey v1.0.2/go.mod h1:OqickVX3tNx6t33n1xvtTtu85YN5s6cKwVug+oHMaIA= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.35.2-20240920164238-5a7b106cbb87.1 h1:7QIeAuTdLp173vC/9JojRMDFcpmqtoYrxPmvdHAOynw= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.35.2-20240920164238-5a7b106cbb87.1/go.mod h1:mnHCFccv4HwuIAOHNGdiIc5ZYbBCvbTWZcodLN5wITI= -connectrpc.com/connect v1.17.0 h1:W0ZqMhtVzn9Zhn2yATuUokDLO5N+gIuBWMOnsQrfmZk= -connectrpc.com/connect v1.17.0/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.5-20250219170025-d39267d9df8f.1 h1:Y0dvIjy09SvloaRbMLTH//k1qDzWcxNm8uBrCwp75ug= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.5-20250219170025-d39267d9df8f.1/go.mod h1:eOqrCVUfhh7SLo00urDe/XhJHljj0dWMZirS0aX7cmc= +connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= +connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= filippo.io/mkcert v1.4.4 h1:8eVbbwfVlaqUM7OwuftKc2nuYOoTDQWqsoXmzoXZdbc= @@ -165,8 +165,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/connect-compress/v2 v2.0.0 h1:L7TVsLa6Oo9Hkkb6r3DwSrhBbcWlXjneqBj7fCRXviU= github.com/klauspost/connect-compress/v2 v2.0.0/go.mod h1:604CD9JSAjGqtVzCM4SRgM/9TFTkWBcp+2wlQfGyJ6c= github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ= @@ -197,10 +197,10 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/metal-stack-cloud/api v0.11.1-0.20250121081135-d58cc0c5d261 h1:31SeSPscrmhYeAoIMhUnPmjR+CGIhmPhNibPkr6NcT0= -github.com/metal-stack-cloud/api v0.11.1-0.20250121081135-d58cc0c5d261/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= -github.com/metal-stack-cloud/api v0.11.1-0.20250127103731-881df2ebf865 h1:5QRM9lnLp/Ro8EvqStKwApE7QDOprtDbSsjIr0dnscM= -github.com/metal-stack-cloud/api v0.11.1-0.20250127103731-881df2ebf865/go.mod h1:YozV0MdIuEa3X/WWz41LNxV9TBxHySfNbj8Yt1e/hgs= +github.com/metal-stack-cloud/api v0.12.2-0.20250304151308-be49d41ce6a8 h1:eIXNj2AaVMAjOxfSYzsxs2u6GkMXaSDD7aNcnT0jaOM= +github.com/metal-stack-cloud/api v0.12.2-0.20250304151308-be49d41ce6a8/go.mod h1:Wsm+LQw/ee1uv68Dlsp1VJk9PcreFJH0WxDtZmJ7maU= +github.com/metal-stack-cloud/api v0.12.2-0.20250304153041-e5722a29eeac h1:Tkx9Qr5o63pl6qQxaFd+jZK7eJubvjXEaboGnRfBY1s= +github.com/metal-stack-cloud/api v0.12.2-0.20250304153041-e5722a29eeac/go.mod h1:Wsm+LQw/ee1uv68Dlsp1VJk9PcreFJH0WxDtZmJ7maU= github.com/metal-stack/metal-lib v0.19.0 h1:4yBnp/jPGgX9KeCje3A4MFL2oDjgjOjgsIK391LltRI= github.com/metal-stack/metal-lib v0.19.0/go.mod h1:fCMaWwVGA/xAoGvBk72/nfzqBkHly0iOzrWpc55Fau4= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= @@ -325,32 +325,32 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/W golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4= +golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= golang.org/x/exp/typeparams v0.0.0-20240119083558-1b970713d09a h1:8qmSSA8Gz/1kTrCe0nqR0R3Gb/NDhykzWw2q2mWZydM= golang.org/x/exp/typeparams v0.0.0-20240119083558-1b970713d09a/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -363,22 +363,22 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= -golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= -golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -389,8 +389,8 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= -google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From e375f162bae0facba2da930e9f3469c21b06b197 Mon Sep 17 00:00:00 2001 From: ostempel Date: Mon, 24 Mar 2025 13:15:50 +0100 Subject: [PATCH 11/20] adjust limit of audit traces --- cmd/api/v1/audit.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/api/v1/audit.go b/cmd/api/v1/audit.go index ceaae05..15d1a03 100644 --- a/cmd/api/v1/audit.go +++ b/cmd/api/v1/audit.go @@ -56,7 +56,7 @@ func newAuditCmd(c *config.Config) *cobra.Command { cmd.Flags().String("body", "", "filters audit trace body payloads for the giben text.") cmd.Flags().String("error", "", "error of the audit trace.") - cmd.Flags().Int64("limit", 6, "limit the number of audit traces.") + cmd.Flags().Int64("limit", 100, "limit the number of audit traces.") genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.Completion.ProjectListCompletion)) }, From 2818199d6b86297f5f7c8de2936a9a916d0199ae Mon Sep 17 00:00:00 2001 From: ostempel Date: Tue, 25 Mar 2025 11:17:00 +0100 Subject: [PATCH 12/20] adjust audits to api and updated tests --- cmd/api/v1/audit.go | 15 ++++--- cmd/audit_test.go | 81 ++++++++++++++++++++++---------------- cmd/sorters/audit.go | 2 +- cmd/tableprinters/audit.go | 15 ++++--- go.mod | 2 +- go.sum | 4 ++ 6 files changed, 72 insertions(+), 47 deletions(-) diff --git a/cmd/api/v1/audit.go b/cmd/api/v1/audit.go index 15d1a03..171f84d 100644 --- a/cmd/api/v1/audit.go +++ b/cmd/api/v1/audit.go @@ -92,12 +92,15 @@ func (a *audit) Get(id string) (*apiv1.AuditTrace, error) { trace := resp.Msg.Audit if viper.GetBool("prettify-body") { - trimmed := strings.Trim(trace.Body, `"`) - body := map[string]any{} - err = json.Unmarshal([]byte(trimmed), &body) - if err == nil { - if pretty, err := json.MarshalIndent(body, "", " "); err == nil { - trace.Body = string(pretty) + if trace.Body != nil { + trimmed := strings.Trim(*trace.Body, `"`) + body := map[string]any{} + err = json.Unmarshal([]byte(trimmed), &body) + if err == nil { + if pretty, err := json.MarshalIndent(body, "", " "); err == nil { + var prettifiedBody = string(pretty) + trace.Body = &prettifiedBody + } } } } diff --git a/cmd/audit_test.go b/cmd/audit_test.go index 1e1c988..7f48cf8 100644 --- a/cmd/audit_test.go +++ b/cmd/audit_test.go @@ -16,29 +16,35 @@ import ( var t, _ = time.Parse("2006-01-02 15:04:05", testTime.Format("2006-01-02 15:04:05")) var ( + projectA = "project-a" + body1 = `{"a": "b"}` + code1 = int32(http.StatusOK) auditTrace1 = &apiv1.AuditTrace{ Uuid: "c40ad996-e1fd-4511-a7bf-418219cb8d91", Timestamp: timestamppb.New(t), User: "a-user", Tenant: "a-tenant", - Project: "project-a", + Project: &projectA, Method: "/apiv1/ip", - ResponsePayload: `{"a": "b"}`, + Body: &body1, SourceIp: "192.168.2.1", - ResultCode: http.StatusOK, - RequestPayload: "{}", + ResultCode: &code1, + Phase: "request", } + projectB = "project-b" + body2 = `{"c": "d"}` + code2 = int32(http.StatusForbidden) auditTrace2 = &apiv1.AuditTrace{ Uuid: "b5817ef7-980a-41ef-9ed3-741a143870b0", Timestamp: timestamppb.New(t), User: "b-user", Tenant: "b-tenant", - Project: "project-b", + Project: &projectB, Method: "/apiv1/cluster", - ResponsePayload: `{"c": "d"}`, + Body: &body2, SourceIp: "192.168.2.3", - ResultCode: http.StatusForbidden, - RequestPayload: "{}", + ResultCode: &code2, + Phase: "response", } ) @@ -53,11 +59,12 @@ func Test_AuditCmd_MultiResult(t *testing.T) { Apiv1Mocks: &apitests.Apiv1MockFns{ Audit: func(m *mock.Mock) { beforeOneHour := timestamppb.New(testTime.Add(-1 * time.Hour)) - + limit := int32(100) m.On("List", mock.Anything, connect.NewRequest(&apiv1.AuditServiceListRequest{ Login: "a-tenant", From: beforeOneHour, - To: timestamppb.Now(), + To: timestamppb.Now(), + Limit: &limit, })). Return(&connect.Response[apiv1.AuditServiceListResponse]{ Msg: &apiv1.AuditServiceListResponse{ @@ -75,14 +82,14 @@ func Test_AuditCmd_MultiResult(t *testing.T) { auditTrace1, }, WantTable: pointer.Pointer(` -TIME REQUEST-ID USER PROJECT METHOD -2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip +TIME REQUEST-ID USER PROJECT METHOD PHASE +2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster response +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip request `), WantWideTable: pointer.Pointer(` -TIME REQUEST-ID USER PROJECT METHOD SOURCE-IP RESULT-CODE REQ-BODY RES-BODY -2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster 192.168.2.3 403 {} {"c": "d"} -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip 192.168.2.1 200 {} {"a": "b"} +TIME REQUEST-ID USER PROJECT METHOD PHASE SOURCE-IP RESULT-CODE BODY +2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster response 192.168.2.3 60712428 {"c": "d"} +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip request 192.168.2.1 60712424 {"a": "b"} `), Template: pointer.Pointer(`{{ date "02/01/2006" .timestamp }} {{ .uuid }}`), WantTemplate: pointer.Pointer(` @@ -90,43 +97,49 @@ TIME REQUEST-ID USER PROJECT 19/05/2022 c40ad996-e1fd-4511-a7bf-418219cb8d91 `), WantMarkdown: pointer.Pointer(` -| TIME | REQUEST-ID | USER | PROJECT | METHOD | -|---------------------|--------------------------------------|--------|-----------|----------------| -| 2022-05-19 01:02:03 | b5817ef7-980a-41ef-9ed3-741a143870b0 | b-user | project-b | /apiv1/cluster | -| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | +| TIME | REQUEST-ID | USER | PROJECT | METHOD | PHASE | +|---------------------|--------------------------------------|--------|-----------|----------------|----------| +| 2022-05-19 01:02:03 | b5817ef7-980a-41ef-9ed3-741a143870b0 | b-user | project-b | /apiv1/cluster | response | +| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | request | `), }, { Name: "list with filters", Cmd: func(want []*apiv1.AuditTrace) []string { + project := *want[0].Project + code := *want[0].ResultCode + body := *want[0].Body args := []string{"audit", "list", "--tenant", "a-tenant", "--request-id", want[0].Uuid, "--from", want[0].Timestamp.AsTime().Format("2006-01-02 15:04:05"), "--to", want[0].Timestamp.AsTime().Format("2006-01-02 15:04:05"), "--user", want[0].User, - "--project", want[0].Project, + "--project", project, "--method", want[0].Method, "--source-ip", want[0].SourceIp, - "--result-code", strconv.Itoa(int(want[0].ResultCode)), - "--body", want[0].ResponsePayload, + "--result-code", strconv.Itoa(int(code)), + "--body", body, } return args }, ClientMocks: &apitests.ClientMockFns{ Apiv1Mocks: &apitests.Apiv1MockFns{ Audit: func(m *mock.Mock) { + limit := int32(100) + m.On("List", mock.Anything, connect.NewRequest(&apiv1.AuditServiceListRequest{ Login: "a-tenant", Uuid: &auditTrace1.Uuid, From: auditTrace1.Timestamp, - To: auditTrace1.Timestamp, + To: auditTrace1.Timestamp, User: &auditTrace1.User, - Project: &auditTrace1.Project, + Project: auditTrace1.Project, Method: &auditTrace1.Method, - ResultCode: &auditTrace1.ResultCode, + ResultCode: auditTrace1.ResultCode, SourceIp: &auditTrace1.SourceIp, - Body: &auditTrace1.ResponsePayload, + Body: auditTrace1.Body, + Limit: &limit, })). Return(&connect.Response[apiv1.AuditServiceListResponse]{ Msg: &apiv1.AuditServiceListResponse{ @@ -142,21 +155,21 @@ TIME REQUEST-ID USER PROJECT auditTrace1, }, WantTable: pointer.Pointer(` -TIME REQUEST-ID USER PROJECT METHOD -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip +TIME REQUEST-ID USER PROJECT METHOD PHASE +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip request `), WantWideTable: pointer.Pointer(` -TIME REQUEST-ID USER PROJECT METHOD SOURCE-IP RESULT-CODE REQ-BODY RES-BODY -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip 192.168.2.1 200 {} {"a": "b"} +TIME REQUEST-ID USER PROJECT METHOD PHASE SOURCE-IP RESULT-CODE BODY +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip request 192.168.2.1 60712424 {"a": "b"} `), Template: pointer.Pointer(`{{ date "02/01/2006" .timestamp }} {{ .uuid }}`), WantTemplate: pointer.Pointer(` 19/05/2022 c40ad996-e1fd-4511-a7bf-418219cb8d91 `), WantMarkdown: pointer.Pointer(` -| TIME | REQUEST-ID | USER | PROJECT | METHOD | -|---------------------|--------------------------------------|--------|-----------|-----------| -| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | +| TIME | REQUEST-ID | USER | PROJECT | METHOD | PHASE | +|---------------------|--------------------------------------|--------|-----------|-----------|---------| +| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | request | `), }, } diff --git a/cmd/sorters/audit.go b/cmd/sorters/audit.go index e281992..839d5d0 100644 --- a/cmd/sorters/audit.go +++ b/cmd/sorters/audit.go @@ -19,7 +19,7 @@ func AuditSorter() *multisort.Sorter[*apiv1.AuditTrace] { return multisort.Compare(a.Method, b.Method, descending) }, "project": func(a, b *apiv1.AuditTrace, descending bool) multisort.CompareResult { - return multisort.Compare(a.Project, b.Project, descending) + return multisort.Compare(*a.Project, *b.Project, descending) }, }, multisort.Keys{{ID: "timestamp", Descending: true}}) } diff --git a/cmd/tableprinters/audit.go b/cmd/tableprinters/audit.go index cc9b68a..ac36a65 100644 --- a/cmd/tableprinters/audit.go +++ b/cmd/tableprinters/audit.go @@ -22,17 +22,22 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string id := audit.Uuid time := truncateToSeconds(audit.Timestamp.AsTime()).Format("2006-01-02 15:04:05") user := audit.User - project := audit.Project phase := audit.Phase - method := audit.Method sourceIp := audit.SourceIp - body := genericcli.TruncateEnd(audit.Body, 30) + project := "" + if audit.Project != nil { + project = *audit.Project + } + body := "" + if audit.Body != nil { + body = genericcli.TruncateEnd(*audit.Body, 30) + } if wide { - var resultCode string - if audit.ResultCode != 0 { + var resultCode = "" + if audit.ResultCode != nil { resultCode = fmt.Sprintf("%d", audit.ResultCode) } rows = append(rows, []string{time, id, user, project, method, phase, sourceIp, resultCode, body}) diff --git a/go.mod b/go.mod index afe1284..091a66b 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.18.0 github.com/google/go-cmp v0.6.0 - github.com/metal-stack-cloud/api v0.12.2-0.20250304153041-e5722a29eeac + github.com/metal-stack-cloud/api v0.13.1-0.20250325094406-eed1b2fc58f5 github.com/metal-stack/metal-lib v0.19.0 github.com/metal-stack/v v1.0.3 github.com/olekukonko/tablewriter v0.0.5 diff --git a/go.sum b/go.sum index 1763440..8039c31 100644 --- a/go.sum +++ b/go.sum @@ -201,6 +201,10 @@ github.com/metal-stack-cloud/api v0.12.2-0.20250304151308-be49d41ce6a8 h1:eIXNj2 github.com/metal-stack-cloud/api v0.12.2-0.20250304151308-be49d41ce6a8/go.mod h1:Wsm+LQw/ee1uv68Dlsp1VJk9PcreFJH0WxDtZmJ7maU= github.com/metal-stack-cloud/api v0.12.2-0.20250304153041-e5722a29eeac h1:Tkx9Qr5o63pl6qQxaFd+jZK7eJubvjXEaboGnRfBY1s= github.com/metal-stack-cloud/api v0.12.2-0.20250304153041-e5722a29eeac/go.mod h1:Wsm+LQw/ee1uv68Dlsp1VJk9PcreFJH0WxDtZmJ7maU= +github.com/metal-stack-cloud/api v0.13.1-0.20250324122259-c692aa84fe5d h1:xkhAh+al89RLluXR2TlM1ij3akQVEXnCHlYshuRzLkI= +github.com/metal-stack-cloud/api v0.13.1-0.20250324122259-c692aa84fe5d/go.mod h1:Wsm+LQw/ee1uv68Dlsp1VJk9PcreFJH0WxDtZmJ7maU= +github.com/metal-stack-cloud/api v0.13.1-0.20250325094406-eed1b2fc58f5 h1:EZyhVs1DAtPqukRb6FzAB5D0mkvOlYq+FnoAXB4pHFo= +github.com/metal-stack-cloud/api v0.13.1-0.20250325094406-eed1b2fc58f5/go.mod h1:Wsm+LQw/ee1uv68Dlsp1VJk9PcreFJH0WxDtZmJ7maU= github.com/metal-stack/metal-lib v0.19.0 h1:4yBnp/jPGgX9KeCje3A4MFL2oDjgjOjgsIK391LltRI= github.com/metal-stack/metal-lib v0.19.0/go.mod h1:fCMaWwVGA/xAoGvBk72/nfzqBkHly0iOzrWpc55Fau4= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= From 439078320acefbfa5a1e87ac6404e3c6a96c5f6f Mon Sep 17 00:00:00 2001 From: ostempel Date: Tue, 25 Mar 2025 13:51:00 +0100 Subject: [PATCH 13/20] update to latest api --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 091a66b..0142ec7 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.18.0 github.com/google/go-cmp v0.6.0 - github.com/metal-stack-cloud/api v0.13.1-0.20250325094406-eed1b2fc58f5 + github.com/metal-stack-cloud/api v0.13.1-0.20250325121620-df8dd0323b54 github.com/metal-stack/metal-lib v0.19.0 github.com/metal-stack/v v1.0.3 github.com/olekukonko/tablewriter v0.0.5 diff --git a/go.sum b/go.sum index 8039c31..ddaefee 100644 --- a/go.sum +++ b/go.sum @@ -205,6 +205,8 @@ github.com/metal-stack-cloud/api v0.13.1-0.20250324122259-c692aa84fe5d h1:xkhAh+ github.com/metal-stack-cloud/api v0.13.1-0.20250324122259-c692aa84fe5d/go.mod h1:Wsm+LQw/ee1uv68Dlsp1VJk9PcreFJH0WxDtZmJ7maU= github.com/metal-stack-cloud/api v0.13.1-0.20250325094406-eed1b2fc58f5 h1:EZyhVs1DAtPqukRb6FzAB5D0mkvOlYq+FnoAXB4pHFo= github.com/metal-stack-cloud/api v0.13.1-0.20250325094406-eed1b2fc58f5/go.mod h1:Wsm+LQw/ee1uv68Dlsp1VJk9PcreFJH0WxDtZmJ7maU= +github.com/metal-stack-cloud/api v0.13.1-0.20250325121620-df8dd0323b54 h1:dseh6qNRIh7uS/IIdrDMahjtH9fPjAdLGUICRuvxrqU= +github.com/metal-stack-cloud/api v0.13.1-0.20250325121620-df8dd0323b54/go.mod h1:Wsm+LQw/ee1uv68Dlsp1VJk9PcreFJH0WxDtZmJ7maU= github.com/metal-stack/metal-lib v0.19.0 h1:4yBnp/jPGgX9KeCje3A4MFL2oDjgjOjgsIK391LltRI= github.com/metal-stack/metal-lib v0.19.0/go.mod h1:fCMaWwVGA/xAoGvBk72/nfzqBkHly0iOzrWpc55Fau4= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= From 58eae79d40eea51ca95633f88cc36c50f94813e5 Mon Sep 17 00:00:00 2001 From: Gerrit Date: Wed, 23 Apr 2025 14:27:01 +0200 Subject: [PATCH 14/20] Updates. --- .gitignore | 3 +- cmd/api/v1/audit.go | 84 +++++++++++++++++--------- cmd/api/v1/project.go | 12 +--- cmd/audit_test.go | 111 ++++++++++++++++++----------------- cmd/completion/audit.go | 10 ++++ cmd/config/config.go | 22 ++++--- cmd/tableprinters/audit.go | 28 ++++----- docs/metal.md | 1 + docs/metal_audit.md | 33 +++++++++++ docs/metal_audit_describe.md | 32 ++++++++++ docs/metal_audit_list.md | 44 ++++++++++++++ go.mod | 2 +- go.sum | 4 +- 13 files changed, 268 insertions(+), 118 deletions(-) create mode 100644 cmd/completion/audit.go create mode 100644 docs/metal_audit.md create mode 100644 docs/metal_audit_describe.md create mode 100644 docs/metal_audit_list.md diff --git a/.gitignore b/.gitignore index 142e438..a01bd84 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.out -bin/ \ No newline at end of file +bin/ +.vscode diff --git a/cmd/api/v1/audit.go b/cmd/api/v1/audit.go index 171f84d..d213e88 100644 --- a/cmd/api/v1/audit.go +++ b/cmd/api/v1/audit.go @@ -27,9 +27,9 @@ func newAuditCmd(c *config.Config) *cobra.Command { c: c, } - cmdsConfig := &genericcli.CmdsConfig[*apiv1.AuditServiceGetRequest, *apiv1.AuditServiceGetRequest, *apiv1.AuditTrace]{ + cmdsConfig := &genericcli.CmdsConfig[any, any, *apiv1.AuditTrace]{ BinaryName: config.BinaryName, - GenericCLI: genericcli.NewGenericCLI[*apiv1.AuditServiceGetRequest, *apiv1.AuditServiceGetRequest, *apiv1.AuditTrace](a).WithFS(c.Fs), + GenericCLI: genericcli.NewGenericCLI(a).WithFS(c.Fs), Singular: "audit trace", Plural: "audit traces", Description: "show audit traces of the api-server", @@ -38,10 +38,9 @@ func newAuditCmd(c *config.Config) *cobra.Command { DescribePrinter: func() printers.Printer { return c.DescribePrinter }, ListPrinter: func() printers.Printer { return c.ListPrinter }, ListCmdMutateFn: func(cmd *cobra.Command) { - cmd.Flags().String("request-id", "", "request id of the audit trace.") - cmd.Flags().String("from", "1h", "start of range of the audit traces. e.g. 1h, 10m, 2006-01-02 15:04:05") + cmd.Flags().String("from", "", "start of range of the audit traces. e.g. 1h, 10m, 2006-01-02 15:04:05") cmd.Flags().String("to", "", "end of range of the audit traces. e.g. 1h, 10m, 2006-01-02 15:04:05") cmd.Flags().String("user", "", "user of the audit trace.") @@ -49,19 +48,31 @@ func newAuditCmd(c *config.Config) *cobra.Command { cmd.Flags().String("project", "", "project id of the audit trace") + cmd.Flags().String("phase", "", "the audit trace phase.") cmd.Flags().String("method", "", "api method of the audit trace.") - cmd.Flags().Int32("result-code", 0, "HTTP status code of the audit trace.") + cmd.Flags().Int32("result-code", 0, "gRPC result status code of the audit trace.") cmd.Flags().String("source-ip", "", "source-ip of the audit trace.") - cmd.Flags().String("body", "", "filters audit trace body payloads for the giben text.") + cmd.Flags().String("body", "", "filters audit trace body payloads for the given text (full-text search).") cmd.Flags().String("error", "", "error of the audit trace.") - cmd.Flags().Int64("limit", 100, "limit the number of audit traces.") + cmd.Flags().Int64("limit", 0, "limit the number of audit traces.") + + cmd.Flags().Bool("prettify-body", false, "attempts to interpret the body as json and prettifies it.") + genericcli.Must(cmd.RegisterFlagCompletionFunc("phase", c.Completion.AuditPhaseListCompletion)) genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.Completion.ProjectListCompletion)) + genericcli.Must(cmd.RegisterFlagCompletionFunc("tenant", c.Completion.TenantListCompletion)) }, DescribeCmdMutateFn: func(cmd *cobra.Command) { + cmd.Flags().String("tenant", "", "tenant of the audit trace.") + + cmd.Flags().String("phase", "", "the audit trace phase.") + cmd.Flags().Bool("prettify-body", false, "attempts to interpret the body as json and prettifies it.") + + genericcli.Must(cmd.RegisterFlagCompletionFunc("phase", c.Completion.AuditPhaseListCompletion)) + genericcli.Must(cmd.RegisterFlagCompletionFunc("tenant", c.Completion.TenantListCompletion)) }, } @@ -72,16 +83,15 @@ func (a *audit) Get(id string) (*apiv1.AuditTrace, error) { ctx, cancel := a.c.NewRequestContext() defer cancel() - project := a.c.GetProject() - fmt.Printf("project: %s", project) tenant, err := a.c.GetTenant() if err != nil { - return nil, fmt.Errorf("tenant is required") + return nil, err } req := &apiv1.AuditServiceGetRequest{ Login: tenant, Uuid: id, + Phase: a.toPhase(viper.GetString("phase")), } resp, err := a.c.Client.Apiv1().Audit().Get(ctx, connect.NewRequest(req)) @@ -89,23 +99,11 @@ func (a *audit) Get(id string) (*apiv1.AuditTrace, error) { return nil, fmt.Errorf("failed to get audit trace: %w", err) } - trace := resp.Msg.Audit - if viper.GetBool("prettify-body") { - if trace.Body != nil { - trimmed := strings.Trim(*trace.Body, `"`) - body := map[string]any{} - err = json.Unmarshal([]byte(trimmed), &body) - if err == nil { - if pretty, err := json.MarshalIndent(body, "", " "); err == nil { - var prettifiedBody = string(pretty) - trace.Body = &prettifiedBody - } - } - } + a.tryPrettifyBody(resp.Msg.Trace) } - return resp.Msg.Audit, nil + return resp.Msg.Trace, nil } func (a *audit) List() ([]*apiv1.AuditTrace, error) { @@ -138,6 +136,7 @@ func (a *audit) List() ([]*apiv1.AuditTrace, error) { Body: pointer.PointerOrNil(viper.GetString("body")), SourceIp: pointer.PointerOrNil(viper.GetString("source-ip")), Limit: pointer.PointerOrNil(viper.GetInt32("limit")), + Phase: a.toPhase(viper.GetString("phase")), } resp, err := a.c.Client.Apiv1().Audit().List(ctx, connect.NewRequest(req)) @@ -145,12 +144,18 @@ func (a *audit) List() ([]*apiv1.AuditTrace, error) { return nil, fmt.Errorf("failed to list audit traces: %w", err) } - return resp.Msg.Audits, nil + if viper.GetBool("prettify-body") { + for _, trace := range resp.Msg.Traces { + a.tryPrettifyBody(trace) + } + } + + return resp.Msg.Traces, nil } func eventuallyRelativeDateTime(s string) (*timestamppb.Timestamp, error) { if s == "" { - return timestamppb.Now(), nil + return nil, nil } duration, err := time.ParseDuration(s) if err == nil { @@ -163,7 +168,7 @@ func eventuallyRelativeDateTime(s string) (*timestamppb.Timestamp, error) { return timestamppb.New(t), nil } -func (a *audit) Convert(*apiv1.AuditTrace) (string, *apiv1.AuditServiceGetRequest, *apiv1.AuditServiceGetRequest, error) { +func (a *audit) Convert(*apiv1.AuditTrace) (string, any, any, error) { return "", nil, nil, fmt.Errorf("not implemented for audit traces") } @@ -171,10 +176,31 @@ func (a *audit) Delete(id string) (*apiv1.AuditTrace, error) { return nil, fmt.Errorf("not implemented for audit traces") } -func (a *audit) Create(*apiv1.AuditServiceGetRequest) (*apiv1.AuditTrace, error) { +func (a *audit) Create(any) (*apiv1.AuditTrace, error) { return nil, fmt.Errorf("not implemented for audit traces") } -func (a *audit) Update(*apiv1.AuditServiceGetRequest) (*apiv1.AuditTrace, error) { +func (a *audit) Update(any) (*apiv1.AuditTrace, error) { return nil, fmt.Errorf("not implemented for audit traces") } + +func (a *audit) tryPrettifyBody(trace *apiv1.AuditTrace) { + if trace.Body != nil { + trimmed := strings.Trim(*trace.Body, `"`) + body := map[string]any{} + if err := json.Unmarshal([]byte(trimmed), &body); err == nil { + if pretty, err := json.MarshalIndent(body, "", " "); err == nil { + trace.Body = pointer.Pointer(string(pretty)) + } + } + } +} + +func (a *audit) toPhase(phase string) *apiv1.AuditPhase { + p, ok := apiv1.AuditPhase_value[phase] + if !ok { + return nil + } + + return pointer.Pointer(apiv1.AuditPhase(p)) +} diff --git a/cmd/api/v1/project.go b/cmd/api/v1/project.go index dacf10c..90a1570 100644 --- a/cmd/api/v1/project.go +++ b/cmd/api/v1/project.go @@ -247,15 +247,9 @@ func (c *project) Update(rq *apiv1.ProjectServiceUpdateRequest) (*apiv1.Project, } func (c *project) createRequestFromCLI() (*apiv1.ProjectServiceCreateRequest, error) { - tenant := viper.GetString("tenant") - - if tenant == "" && c.c.GetProject() != "" { - project, err := c.Get(c.c.GetProject()) - if err != nil { - return nil, fmt.Errorf("unable to derive tenant from project: %w", err) - } - - tenant = project.Tenant + tenant, err := c.c.GetTenant() + if err != nil { + return nil, err } if viper.GetString("name") == "" { diff --git a/cmd/audit_test.go b/cmd/audit_test.go index 5fc157a..4bc6457 100644 --- a/cmd/audit_test.go +++ b/cmd/audit_test.go @@ -4,7 +4,6 @@ import ( "net/http" "strconv" "testing" - "time" "connectrpc.com/connect" apiv1 "github.com/metal-stack-cloud/api/go/api/v1" @@ -14,37 +13,34 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" ) -var t, _ = time.Parse("2006-01-02 15:04:05", testTime.Format("2006-01-02 15:04:05")) var ( - projectA = "project-a" - body1 = `{"a": "b"}` - code1 = int32(http.StatusOK) + code1 = int32(http.StatusOK) auditTrace1 = &apiv1.AuditTrace{ - Uuid: "c40ad996-e1fd-4511-a7bf-418219cb8d91", - Timestamp: timestamppb.New(t), - User: "a-user", - Tenant: "a-tenant", - Project: &projectA, - Method: "/apiv1/ip", - Body: &body1, - SourceIp: "192.168.2.1", - ResultCode: &code1, - Phase: "request", + Uuid: "c40ad996-e1fd-4511-a7bf-418219cb8d91", + Timestamp: timestamppb.New(testTime), + User: "a-user", + Tenant: "a-tenant", + Project: pointer.Pointer("project-a"), + Method: "/apiv1/ip", + Body: pointer.Pointer(`{"a": "b"}`), + SourceIp: "192.168.2.1", + ResultCode: &code1, + Phase: apiv1.AuditPhase_AUDIT_PHASE_REQUEST, } - projectB = "project-b" - body2 = `{"c": "d"}` - code2 = int32(http.StatusForbidden) + projectB = "project-b" + body2 = `{"c": "d"}` + code2 = int32(http.StatusForbidden) auditTrace2 = &apiv1.AuditTrace{ - Uuid: "b5817ef7-980a-41ef-9ed3-741a143870b0", - Timestamp: timestamppb.New(t), - User: "b-user", - Tenant: "b-tenant", - Project: &projectB, - Method: "/apiv1/cluster", - Body: &body2, - SourceIp: "192.168.2.3", - ResultCode: &code2, - Phase: "response", + Uuid: "b5817ef7-980a-41ef-9ed3-741a143870b0", + Timestamp: timestamppb.New(testTime), + User: "b-user", + Tenant: "b-tenant", + Project: &projectB, + Method: "/apiv1/cluster", + Body: &body2, + SourceIp: "192.168.2.3", + ResultCode: &code2, + Phase: apiv1.AuditPhase_AUDIT_PHASE_RESPONSE, } ) @@ -58,17 +54,12 @@ func Test_AuditCmd_MultiResult(t *testing.T) { ClientMocks: &apitests.ClientMockFns{ Apiv1Mocks: &apitests.Apiv1MockFns{ Audit: func(m *mock.Mock) { - beforeOneHour := timestamppb.New(testTime.Add(-1 * time.Hour)) - limit := int32(100) m.On("List", mock.Anything, connect.NewRequest(&apiv1.AuditServiceListRequest{ Login: "a-tenant", - From: beforeOneHour, - To: timestamppb.Now(), - Limit: &limit, })). Return(&connect.Response[apiv1.AuditServiceListResponse]{ Msg: &apiv1.AuditServiceListResponse{ - Audits: []*apiv1.AuditTrace{ + Traces: []*apiv1.AuditTrace{ auditTrace2, auditTrace1, }, @@ -82,14 +73,14 @@ func Test_AuditCmd_MultiResult(t *testing.T) { auditTrace1, }, WantTable: pointer.Pointer(` -TIME REQUEST-ID USER PROJECT METHOD PHASE -2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster response -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip request +TIME REQUEST-ID USER PROJECT METHOD PHASE CODE +2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster AUDIT_PHASE_RESPONSE 403 +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip AUDIT_PHASE_REQUEST 200 `), WantWideTable: pointer.Pointer(` -TIME REQUEST-ID USER PROJECT METHOD PHASE SOURCE-IP RESULT-CODE BODY -2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster response 192.168.2.3 403 {"c": "d"} -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip request 192.168.2.1 200 {"a": "b"} +TIME REQUEST-ID USER PROJECT METHOD PHASE SOURCE-IP CODE BODY +2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster AUDIT_PHASE_RESPONSE 192.168.2.3 403 {"c": "d"} +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip AUDIT_PHASE_REQUEST 192.168.2.1 200 {"a": "b"} `), Template: pointer.Pointer(`{{ date "02/01/2006" .timestamp }} {{ .uuid }}`), WantTemplate: pointer.Pointer(` @@ -97,10 +88,10 @@ TIME REQUEST-ID USER PROJECT 19/05/2022 c40ad996-e1fd-4511-a7bf-418219cb8d91 `), WantMarkdown: pointer.Pointer(` -| TIME | REQUEST-ID | USER | PROJECT | METHOD | PHASE | -|---------------------|--------------------------------------|--------|-----------|----------------|----------| -| 2022-05-19 01:02:03 | b5817ef7-980a-41ef-9ed3-741a143870b0 | b-user | project-b | /apiv1/cluster | response | -| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | request | +| TIME | REQUEST-ID | USER | PROJECT | METHOD | PHASE | CODE | +|---------------------|--------------------------------------|--------|-----------|----------------|----------------------|------| +| 2022-05-19 01:02:03 | b5817ef7-980a-41ef-9ed3-741a143870b0 | b-user | project-b | /apiv1/cluster | AUDIT_PHASE_RESPONSE | 403 | +| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | AUDIT_PHASE_REQUEST | 200 | `), }, { @@ -119,31 +110,39 @@ TIME REQUEST-ID USER PROJECT "--method", want[0].Method, "--source-ip", want[0].SourceIp, "--result-code", strconv.Itoa(int(code)), + "--error", "an-error", + "--limit", "100", + "--phase", want[0].Phase.String(), "--body", body, + "--prettify-body", } + AssertExhaustiveArgs(t, args, "sort-by") return args }, ClientMocks: &apitests.ClientMockFns{ Apiv1Mocks: &apitests.Apiv1MockFns{ Audit: func(m *mock.Mock) { limit := int32(100) + ts := auditTrace1.Timestamp + ts.Nanos = 0 // nano sec prec gets lost from command line m.On("List", mock.Anything, connect.NewRequest(&apiv1.AuditServiceListRequest{ Login: "a-tenant", Uuid: &auditTrace1.Uuid, - From: auditTrace1.Timestamp, - To: auditTrace1.Timestamp, + From: ts, + To: ts, User: &auditTrace1.User, Project: auditTrace1.Project, Method: &auditTrace1.Method, ResultCode: auditTrace1.ResultCode, SourceIp: &auditTrace1.SourceIp, Body: auditTrace1.Body, - Limit: &limit, + Limit: &limit, + Phase: &auditTrace1.Phase, })). Return(&connect.Response[apiv1.AuditServiceListResponse]{ Msg: &apiv1.AuditServiceListResponse{ - Audits: []*apiv1.AuditTrace{ + Traces: []*apiv1.AuditTrace{ auditTrace1, }, }, @@ -155,21 +154,23 @@ TIME REQUEST-ID USER PROJECT auditTrace1, }, WantTable: pointer.Pointer(` -TIME REQUEST-ID USER PROJECT METHOD PHASE -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip request +TIME REQUEST-ID USER PROJECT METHOD PHASE CODE +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip AUDIT_PHASE_REQUEST 200 `), WantWideTable: pointer.Pointer(` -TIME REQUEST-ID USER PROJECT METHOD PHASE SOURCE-IP RESULT-CODE BODY -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip request 192.168.2.1 200 {"a": "b"} +TIME REQUEST-ID USER PROJECT METHOD PHASE SOURCE-IP CODE BODY +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip AUDIT_PHASE_REQUEST 192.168.2.1 200 { + "a": "b" + } `), Template: pointer.Pointer(`{{ date "02/01/2006" .timestamp }} {{ .uuid }}`), WantTemplate: pointer.Pointer(` 19/05/2022 c40ad996-e1fd-4511-a7bf-418219cb8d91 `), WantMarkdown: pointer.Pointer(` -| TIME | REQUEST-ID | USER | PROJECT | METHOD | PHASE | -|---------------------|--------------------------------------|--------|-----------|-----------|---------| -| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | request | +| TIME | REQUEST-ID | USER | PROJECT | METHOD | PHASE | CODE | +|---------------------|--------------------------------------|--------|-----------|-----------|---------------------|------| +| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | AUDIT_PHASE_REQUEST | 200 | `), }, } diff --git a/cmd/completion/audit.go b/cmd/completion/audit.go new file mode 100644 index 0000000..2e18031 --- /dev/null +++ b/cmd/completion/audit.go @@ -0,0 +1,10 @@ +package completion + +import ( + apiv1 "github.com/metal-stack-cloud/api/go/api/v1" + "github.com/spf13/cobra" +) + +func (c *Completion) AuditPhaseListCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{apiv1.AuditPhase_AUDIT_PHASE_REQUEST.String(), apiv1.AuditPhase_AUDIT_PHASE_RESPONSE.String()}, cobra.ShellCompDirectiveNoFileComp +} diff --git a/cmd/config/config.go b/cmd/config/config.go index 4e7af67..08685b7 100644 --- a/cmd/config/config.go +++ b/cmd/config/config.go @@ -101,21 +101,29 @@ func (c *Config) GetTenant() (string, error) { return viper.GetString("tenant"), nil } - if c.GetProject() == "" { - return "", fmt.Errorf("tenant is not set") + if c.GetProject() != "" { + ctx, cancel := c.NewRequestContext() + defer cancel() + + projectResp, err := c.Client.Apiv1().Project().Get(ctx, connect.NewRequest(&apiv1.ProjectServiceGetRequest{ + Project: c.GetProject(), + })) + if err != nil { + return "", fmt.Errorf("unable to derive tenant from project: %w", err) + } + + return projectResp.Msg.Project.Tenant, nil } ctx, cancel := c.NewRequestContext() defer cancel() - projectResp, err := c.Client.Apiv1().Project().Get(ctx, connect.NewRequest(&apiv1.ProjectServiceGetRequest{ - Project: c.GetProject(), - })) + user, err := c.Client.Apiv1().User().Get(ctx, connect.NewRequest(&apiv1.UserServiceGetRequest{})) if err != nil { - return "", fmt.Errorf("unable to derive tenant from project: %w", err) + return "", fmt.Errorf("unable to derive tenant from token: %w", err) } - return projectResp.Msg.Project.Tenant, nil + return user.Msg.User.Login, nil } func (c *Config) GetToken() string { diff --git a/cmd/tableprinters/audit.go b/cmd/tableprinters/audit.go index e4fecd7..916284e 100644 --- a/cmd/tableprinters/audit.go +++ b/cmd/tableprinters/audit.go @@ -2,10 +2,10 @@ package tableprinters import ( "fmt" - "time" apiv1 "github.com/metal-stack-cloud/api/go/api/v1" "github.com/metal-stack/metal-lib/pkg/genericcli" + "github.com/olekukonko/tablewriter" ) func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string, [][]string, error) { @@ -13,14 +13,14 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string rows [][]string ) - header := []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD", "PHASE"} + header := []string{"Time", "Request-Id", "User", "Project", "Method", "Phase", "Code"} if wide { - header = []string{"TIME", "REQUEST-ID", "USER", "PROJECT", "METHOD", "PHASE", "SOURCE-IP", "RESULT-CODE", "BODY"} + header = []string{"Time", "Request-Id", "User", "Project", "Method", "Phase", "Source-Ip", "Code", "Body"} } for _, audit := range data { id := audit.Uuid - time := truncateToSeconds(audit.Timestamp.AsTime()).Format("2006-01-02 15:04:05") + time := audit.Timestamp.AsTime().Format("2006-01-02 15:04:05") user := audit.User phase := audit.Phase method := audit.Method @@ -34,21 +34,21 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string if audit.Body != nil { body = genericcli.TruncateEnd(*audit.Body, 30) } + code := "" + if audit.ResultCode != nil { + code = fmt.Sprintf("%d", *audit.ResultCode) + } if wide { - var resultCode = "" - if audit.ResultCode != nil { - resultCode = fmt.Sprintf("%d", *audit.ResultCode) - } - rows = append(rows, []string{time, id, user, project, method, phase, sourceIp, resultCode, body}) + rows = append(rows, []string{time, id, user, project, method, phase.String(), sourceIp, code, body}) } else { - rows = append(rows, []string{time, id, user, project, method, phase}) + rows = append(rows, []string{time, id, user, project, method, phase.String(), code}) } } - return header, rows, nil -} + t.t.MutateTable(func(table *tablewriter.Table) { + table.SetAutoWrapText(false) + }) -func truncateToSeconds(t time.Time) time.Time { - return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), 0, t.Location()) + return header, rows, nil } diff --git a/docs/metal.md b/docs/metal.md index 0dddcb8..5a239d4 100644 --- a/docs/metal.md +++ b/docs/metal.md @@ -20,6 +20,7 @@ cli for managing entities in metal-stack-cloud * [metal api-methods](metal_api-methods.md) - show available api-methods of the metalstack.cloud api * [metal asset](metal_asset.md) - show asset +* [metal audit](metal_audit.md) - manage audit trace entities * [metal cluster](metal_cluster.md) - manage cluster entities * [metal completion](metal_completion.md) - Generate the autocompletion script for the specified shell * [metal context](metal_context.md) - manage cli contexts diff --git a/docs/metal_audit.md b/docs/metal_audit.md new file mode 100644 index 0000000..2effe03 --- /dev/null +++ b/docs/metal_audit.md @@ -0,0 +1,33 @@ +## metal audit + +manage audit trace entities + +### Synopsis + +show audit traces of the api-server + +### Options + +``` + -h, --help help for audit +``` + +### Options inherited from parent commands + +``` + --api-token string the token used for api requests + --api-url string the url to the metalstack.cloud api (default "https://api.metalstack.cloud") + -c, --config string alternative config file path, (default is ~/.metal-stack-cloud/config.yaml) + --debug debug output + --force-color force colored output even without tty + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. + --timeout duration request timeout used for api requests +``` + +### SEE ALSO + +* [metal](metal.md) - cli for managing entities in metal-stack-cloud +* [metal audit describe](metal_audit_describe.md) - describes the audit trace +* [metal audit list](metal_audit_list.md) - list all audit traces + diff --git a/docs/metal_audit_describe.md b/docs/metal_audit_describe.md new file mode 100644 index 0000000..cc28bc4 --- /dev/null +++ b/docs/metal_audit_describe.md @@ -0,0 +1,32 @@ +## metal audit describe + +describes the audit trace + +``` +metal audit describe [flags] +``` + +### Options + +``` + -h, --help help for describe + --prettify-body attempts to interpret the body as json and prettifies it. +``` + +### Options inherited from parent commands + +``` + --api-token string the token used for api requests + --api-url string the url to the metalstack.cloud api (default "https://api.metalstack.cloud") + -c, --config string alternative config file path, (default is ~/.metal-stack-cloud/config.yaml) + --debug debug output + --force-color force colored output even without tty + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. + --timeout duration request timeout used for api requests +``` + +### SEE ALSO + +* [metal audit](metal_audit.md) - manage audit trace entities + diff --git a/docs/metal_audit_list.md b/docs/metal_audit_list.md new file mode 100644 index 0000000..ca776ab --- /dev/null +++ b/docs/metal_audit_list.md @@ -0,0 +1,44 @@ +## metal audit list + +list all audit traces + +``` +metal audit list [flags] +``` + +### Options + +``` + --body string filters audit trace body payloads for the giben text. + --error string error of the audit trace. + --from string start of range of the audit traces. e.g. 1h, 10m, 2006-01-02 15:04:05 (default "1h") + -h, --help help for list + --limit int limit the number of audit traces. (default 100) + --method string api method of the audit trace. + --project string project id of the audit trace + --request-id string request id of the audit trace. + --result-code int32 HTTP status code of the audit trace. + --sort-by strings sort by (comma separated) column(s), sort direction can be changed by appending :asc or :desc behind the column identifier. possible values: method|project|timestamp|user + --source-ip string source-ip of the audit trace. + --tenant string tenant of the audit trace. + --to string end of range of the audit traces. e.g. 1h, 10m, 2006-01-02 15:04:05 + --user string user of the audit trace. +``` + +### Options inherited from parent commands + +``` + --api-token string the token used for api requests + --api-url string the url to the metalstack.cloud api (default "https://api.metalstack.cloud") + -c, --config string alternative config file path, (default is ~/.metal-stack-cloud/config.yaml) + --debug debug output + --force-color force colored output even without tty + -o, --output-format string output format (table|wide|markdown|json|yaml|template|jsonraw|yamlraw), wide is a table with more columns, jsonraw and yamlraw do not translate proto enums into string types but leave the original int32 values intact. (default "table") + --template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference. + --timeout duration request timeout used for api requests +``` + +### SEE ALSO + +* [metal audit](metal_audit.md) - manage audit trace entities + diff --git a/go.mod b/go.mod index 7d8ad99..b6083aa 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.18.0 github.com/google/go-cmp v0.7.0 - github.com/metal-stack-cloud/api v0.13.1-0.20250325121620-df8dd0323b54 + github.com/metal-stack-cloud/api v0.13.1-0.20250423091441-7817111ceca7 github.com/metal-stack/metal-lib v0.20.2 github.com/metal-stack/v v1.0.3 github.com/olekukonko/tablewriter v0.0.5 diff --git a/go.sum b/go.sum index 85da6e7..7031b4c 100644 --- a/go.sum +++ b/go.sum @@ -197,8 +197,8 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/metal-stack-cloud/api v0.13.1-0.20250325121620-df8dd0323b54 h1:dseh6qNRIh7uS/IIdrDMahjtH9fPjAdLGUICRuvxrqU= -github.com/metal-stack-cloud/api v0.13.1-0.20250325121620-df8dd0323b54/go.mod h1:Wsm+LQw/ee1uv68Dlsp1VJk9PcreFJH0WxDtZmJ7maU= +github.com/metal-stack-cloud/api v0.13.1-0.20250423091441-7817111ceca7 h1:qjMNpPx559zcaAEU60jZoaFLsL2Q3cEW9drmj75HYi0= +github.com/metal-stack-cloud/api v0.13.1-0.20250423091441-7817111ceca7/go.mod h1:Wsm+LQw/ee1uv68Dlsp1VJk9PcreFJH0WxDtZmJ7maU= github.com/metal-stack/metal-lib v0.20.2 h1:Dy6JNIo8ku8mdGyuijlBELkvJ/q2SDBpvDyztgAqEDE= github.com/metal-stack/metal-lib v0.20.2/go.mod h1:zYzXYpNA4nQ+ANx19s/+1Yb/Q6xhS1nQK2yK2/ryXZM= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= From 7a1e2ae19046d602e8af1f0773fe0ac3cd407561 Mon Sep 17 00:00:00 2001 From: Gerrit Date: Wed, 23 Apr 2025 14:45:55 +0200 Subject: [PATCH 15/20] Update. --- cmd/api/v1/audit.go | 8 +++++-- cmd/audit_test.go | 48 ++++++++++++++++---------------------- cmd/tableprinters/audit.go | 16 ++++--------- go.mod | 1 + go.sum | 5 ++++ 5 files changed, 37 insertions(+), 41 deletions(-) diff --git a/cmd/api/v1/audit.go b/cmd/api/v1/audit.go index d213e88..bb0ba64 100644 --- a/cmd/api/v1/audit.go +++ b/cmd/api/v1/audit.go @@ -54,7 +54,6 @@ func newAuditCmd(c *config.Config) *cobra.Command { cmd.Flags().String("source-ip", "", "source-ip of the audit trace.") cmd.Flags().String("body", "", "filters audit trace body payloads for the given text (full-text search).") - cmd.Flags().String("error", "", "error of the audit trace.") cmd.Flags().Int64("limit", 0, "limit the number of audit traces.") @@ -124,6 +123,11 @@ func (a *audit) List() ([]*apiv1.AuditTrace, error) { return nil, fmt.Errorf("tenant is required %w", err) } + var code *int32 + if viper.IsSet("result-code") { + code = pointer.Pointer(viper.GetInt32("result-code")) + } + req := &apiv1.AuditServiceListRequest{ Login: tenant, Uuid: pointer.PointerOrNil(viper.GetString("request-id")), @@ -132,7 +136,7 @@ func (a *audit) List() ([]*apiv1.AuditTrace, error) { User: pointer.PointerOrNil(viper.GetString("user")), Project: pointer.PointerOrNil(viper.GetString("project")), Method: pointer.PointerOrNil(viper.GetString("method")), - ResultCode: pointer.PointerOrNil(viper.GetInt32("result-code")), + ResultCode: code, Body: pointer.PointerOrNil(viper.GetString("body")), SourceIp: pointer.PointerOrNil(viper.GetString("source-ip")), Limit: pointer.PointerOrNil(viper.GetInt32("limit")), diff --git a/cmd/audit_test.go b/cmd/audit_test.go index 4bc6457..720da24 100644 --- a/cmd/audit_test.go +++ b/cmd/audit_test.go @@ -1,7 +1,6 @@ package cmd import ( - "net/http" "strconv" "testing" @@ -10,11 +9,11 @@ import ( apitests "github.com/metal-stack-cloud/api/go/tests" "github.com/metal-stack/metal-lib/pkg/pointer" "github.com/stretchr/testify/mock" + "google.golang.org/grpc/codes" "google.golang.org/protobuf/types/known/timestamppb" ) var ( - code1 = int32(http.StatusOK) auditTrace1 = &apiv1.AuditTrace{ Uuid: "c40ad996-e1fd-4511-a7bf-418219cb8d91", Timestamp: timestamppb.New(testTime), @@ -24,22 +23,19 @@ var ( Method: "/apiv1/ip", Body: pointer.Pointer(`{"a": "b"}`), SourceIp: "192.168.2.1", - ResultCode: &code1, + ResultCode: pointer.Pointer(int32(codes.OK)), Phase: apiv1.AuditPhase_AUDIT_PHASE_REQUEST, } - projectB = "project-b" - body2 = `{"c": "d"}` - code2 = int32(http.StatusForbidden) auditTrace2 = &apiv1.AuditTrace{ Uuid: "b5817ef7-980a-41ef-9ed3-741a143870b0", Timestamp: timestamppb.New(testTime), User: "b-user", Tenant: "b-tenant", - Project: &projectB, + Project: pointer.Pointer("project-b"), Method: "/apiv1/cluster", - Body: &body2, + Body: pointer.Pointer(`{"c": "d"}`), SourceIp: "192.168.2.3", - ResultCode: &code2, + ResultCode: pointer.Pointer(int32(codes.NotFound)), Phase: apiv1.AuditPhase_AUDIT_PHASE_RESPONSE, } ) @@ -74,13 +70,13 @@ func Test_AuditCmd_MultiResult(t *testing.T) { }, WantTable: pointer.Pointer(` TIME REQUEST-ID USER PROJECT METHOD PHASE CODE -2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster AUDIT_PHASE_RESPONSE 403 -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip AUDIT_PHASE_REQUEST 200 +2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster AUDIT_PHASE_RESPONSE NotFound +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip AUDIT_PHASE_REQUEST OK `), WantWideTable: pointer.Pointer(` -TIME REQUEST-ID USER PROJECT METHOD PHASE SOURCE-IP CODE BODY -2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster AUDIT_PHASE_RESPONSE 192.168.2.3 403 {"c": "d"} -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip AUDIT_PHASE_REQUEST 192.168.2.1 200 {"a": "b"} +TIME REQUEST-ID USER PROJECT METHOD PHASE SOURCE-IP CODE BODY +2022-05-19 01:02:03 b5817ef7-980a-41ef-9ed3-741a143870b0 b-user project-b /apiv1/cluster AUDIT_PHASE_RESPONSE 192.168.2.3 NotFound {"c": "d"} +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip AUDIT_PHASE_REQUEST 192.168.2.1 OK {"a": "b"} `), Template: pointer.Pointer(`{{ date "02/01/2006" .timestamp }} {{ .uuid }}`), WantTemplate: pointer.Pointer(` @@ -88,32 +84,28 @@ TIME REQUEST-ID USER PROJECT 19/05/2022 c40ad996-e1fd-4511-a7bf-418219cb8d91 `), WantMarkdown: pointer.Pointer(` -| TIME | REQUEST-ID | USER | PROJECT | METHOD | PHASE | CODE | -|---------------------|--------------------------------------|--------|-----------|----------------|----------------------|------| -| 2022-05-19 01:02:03 | b5817ef7-980a-41ef-9ed3-741a143870b0 | b-user | project-b | /apiv1/cluster | AUDIT_PHASE_RESPONSE | 403 | -| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | AUDIT_PHASE_REQUEST | 200 | +| TIME | REQUEST-ID | USER | PROJECT | METHOD | PHASE | CODE | +|---------------------|--------------------------------------|--------|-----------|----------------|----------------------|----------| +| 2022-05-19 01:02:03 | b5817ef7-980a-41ef-9ed3-741a143870b0 | b-user | project-b | /apiv1/cluster | AUDIT_PHASE_RESPONSE | NotFound | +| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | AUDIT_PHASE_REQUEST | OK | `), }, { Name: "list with filters", Cmd: func(want []*apiv1.AuditTrace) []string { - project := *want[0].Project - code := *want[0].ResultCode - body := *want[0].Body args := []string{"audit", "list", "--tenant", "a-tenant", "--request-id", want[0].Uuid, "--from", want[0].Timestamp.AsTime().Format("2006-01-02 15:04:05"), "--to", want[0].Timestamp.AsTime().Format("2006-01-02 15:04:05"), "--user", want[0].User, - "--project", project, + "--project", *want[0].Project, "--method", want[0].Method, "--source-ip", want[0].SourceIp, - "--result-code", strconv.Itoa(int(code)), - "--error", "an-error", + "--result-code", strconv.Itoa(int(*want[0].ResultCode)), "--limit", "100", "--phase", want[0].Phase.String(), - "--body", body, + "--body", *want[0].Body, "--prettify-body", } AssertExhaustiveArgs(t, args, "sort-by") @@ -155,11 +147,11 @@ TIME REQUEST-ID USER PROJECT }, WantTable: pointer.Pointer(` TIME REQUEST-ID USER PROJECT METHOD PHASE CODE -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip AUDIT_PHASE_REQUEST 200 +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip AUDIT_PHASE_REQUEST OK `), WantWideTable: pointer.Pointer(` TIME REQUEST-ID USER PROJECT METHOD PHASE SOURCE-IP CODE BODY -2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip AUDIT_PHASE_REQUEST 192.168.2.1 200 { +2022-05-19 01:02:03 c40ad996-e1fd-4511-a7bf-418219cb8d91 a-user project-a /apiv1/ip AUDIT_PHASE_REQUEST 192.168.2.1 OK { "a": "b" } `), @@ -170,7 +162,7 @@ TIME REQUEST-ID USER PROJECT WantMarkdown: pointer.Pointer(` | TIME | REQUEST-ID | USER | PROJECT | METHOD | PHASE | CODE | |---------------------|--------------------------------------|--------|-----------|-----------|---------------------|------| -| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | AUDIT_PHASE_REQUEST | 200 | +| 2022-05-19 01:02:03 | c40ad996-e1fd-4511-a7bf-418219cb8d91 | a-user | project-a | /apiv1/ip | AUDIT_PHASE_REQUEST | OK | `), }, } diff --git a/cmd/tableprinters/audit.go b/cmd/tableprinters/audit.go index 916284e..943d5d0 100644 --- a/cmd/tableprinters/audit.go +++ b/cmd/tableprinters/audit.go @@ -1,11 +1,11 @@ package tableprinters import ( - "fmt" - apiv1 "github.com/metal-stack-cloud/api/go/api/v1" "github.com/metal-stack/metal-lib/pkg/genericcli" + "github.com/metal-stack/metal-lib/pkg/pointer" "github.com/olekukonko/tablewriter" + "google.golang.org/grpc/codes" ) func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string, [][]string, error) { @@ -25,18 +25,12 @@ func (t *TablePrinter) AuditTable(data []*apiv1.AuditTrace, wide bool) ([]string phase := audit.Phase method := audit.Method sourceIp := audit.SourceIp + project := pointer.SafeDeref(audit.Project) + body := genericcli.TruncateEnd(pointer.SafeDeref(audit.Body), 30) - project := "" - if audit.Project != nil { - project = *audit.Project - } - body := "" - if audit.Body != nil { - body = genericcli.TruncateEnd(*audit.Body, 30) - } code := "" if audit.ResultCode != nil { - code = fmt.Sprintf("%d", *audit.ResultCode) + code = codes.Code(uint32(*audit.ResultCode)).String() } if wide { diff --git a/go.mod b/go.mod index b6083aa..9adcd27 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.10.0 golang.org/x/net v0.35.0 + google.golang.org/grpc v1.67.3 google.golang.org/protobuf v1.36.5 k8s.io/api v0.31.0 k8s.io/apimachinery v0.31.0 diff --git a/go.sum b/go.sum index 7031b4c..e1aadf5 100644 --- a/go.sum +++ b/go.sum @@ -387,6 +387,11 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= +google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99 h1:ZSlhAUqC4r8TPzqLXQ0m3upBNZeF+Y8jQ3c4CR3Ujms= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/grpc v1.67.3 h1:OgPcDAFKHnH8X3O4WcO4XUc8GRDeKsKReqbQtiCj7N8= +google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 06935a59f102d7d75239a90a4b8a72d9d5fc3c91 Mon Sep 17 00:00:00 2001 From: Gerrit Date: Thu, 24 Apr 2025 11:45:25 +0200 Subject: [PATCH 16/20] Fix linting issues. --- .github/workflows/docker.yaml | 4 ++-- cmd/admin/v1/cluster.go | 4 ++-- cmd/api/v1/cluster.go | 8 ++++---- cmd/api/v1/methods.go | 2 +- cmd/api/v1/project.go | 8 ++++---- cmd/api/v1/tenant.go | 8 ++++---- cmd/api/v1/token.go | 8 ++++---- cmd/api/v1/volume.go | 8 ++++---- cmd/context.go | 14 +++++++------- cmd/tableprinters/ip.go | 3 +-- pkg/helpers/ssh.go | 6 ++++-- 11 files changed, 37 insertions(+), 36 deletions(-) diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 05f9712..4f96ea3 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -26,9 +26,9 @@ jobs: cache: false - name: Lint - uses: golangci/golangci-lint-action@v6 + uses: golangci/golangci-lint-action@v7 with: - args: --build-tags integration -p bugs -p unused -D protogetter --timeout=5m + args: -D protogetter --timeout=5m - name: Test run: | diff --git a/cmd/admin/v1/cluster.go b/cmd/admin/v1/cluster.go index 086d1ae..8721e4c 100644 --- a/cmd/admin/v1/cluster.go +++ b/cmd/admin/v1/cluster.go @@ -196,7 +196,7 @@ func (c *cluster) kubeconfig(args []string) error { } if !viper.GetBool("merge") { - fmt.Fprintln(c.c.Out, resp.Msg.Kubeconfig) + _, _ = fmt.Fprintln(c.c.Out, resp.Msg.Kubeconfig) return nil } @@ -214,7 +214,7 @@ func (c *cluster) kubeconfig(args []string) error { return fmt.Errorf("unable to write merged kubeconfig: %w", err) } - fmt.Fprintf(c.c.Out, "%s merged context %q into %s\n", color.GreenString("✔"), merged.ContextName, merged.Path) + _, _ = fmt.Fprintf(c.c.Out, "%s merged context %q into %s\n", color.GreenString("✔"), merged.ContextName, merged.Path) return nil } diff --git a/cmd/api/v1/cluster.go b/cmd/api/v1/cluster.go index 7b1a04b..f829762 100644 --- a/cmd/api/v1/cluster.go +++ b/cmd/api/v1/cluster.go @@ -544,7 +544,7 @@ func (c *cluster) kubeconfig(args []string) error { } if !viper.GetBool("merge") { - fmt.Fprintln(c.c.Out, resp.Msg.Kubeconfig) + _, _ = fmt.Fprintln(c.c.Out, resp.Msg.Kubeconfig) return nil } @@ -568,7 +568,7 @@ func (c *cluster) kubeconfig(args []string) error { return fmt.Errorf("unable to write merged kubeconfig: %w", err) } - fmt.Fprintf(c.c.Out, "%s merged context %q into %s\n", color.GreenString("✔"), merged.ContextName, merged.Path) + _, _ = fmt.Fprintf(c.c.Out, "%s merged context %q into %s\n", color.GreenString("✔"), merged.ContextName, merged.Path) return nil } @@ -637,8 +637,8 @@ func (c *cluster) status(args []string) error { return nil } - fmt.Fprintln(c.c.Out) - fmt.Fprintln(c.c.Out, "Last Errors:") + _, _ = fmt.Fprintln(c.c.Out) + _, _ = fmt.Fprintln(c.c.Out, "Last Errors:") return c.c.ListPrinter.Print(resp.Msg.Cluster.Status.LastErrors) } diff --git a/cmd/api/v1/methods.go b/cmd/api/v1/methods.go index ad48cb6..e0643b4 100644 --- a/cmd/api/v1/methods.go +++ b/cmd/api/v1/methods.go @@ -47,7 +47,7 @@ func newMethodsCmd(c *config.Config) *cobra.Command { sort.Strings(methods) for _, method := range methods { - fmt.Fprintln(c.Out, method) + _, _ = fmt.Fprintln(c.Out, method) } return nil diff --git a/cmd/api/v1/project.go b/cmd/api/v1/project.go index 90a1570..7050b34 100644 --- a/cmd/api/v1/project.go +++ b/cmd/api/v1/project.go @@ -319,7 +319,7 @@ func (c *project) join(args []string) error { return fmt.Errorf("failed to join project: %w", err) } - fmt.Fprintf(c.c.Out, "%s successfully joined project \"%s\"\n", color.GreenString("✔"), color.GreenString(acceptResp.Msg.ProjectName)) + _, _ = fmt.Fprintf(c.c.Out, "%s successfully joined project \"%s\"\n", color.GreenString("✔"), color.GreenString(acceptResp.Msg.ProjectName)) return nil } @@ -341,8 +341,8 @@ func (c *project) generateInvite() error { return fmt.Errorf("failed to generate an invite: %w", err) } - fmt.Fprintf(c.c.Out, "You can share this secret with the member to join, it expires in %s:\n\n", humanize.Time(resp.Msg.Invite.ExpiresAt.AsTime())) - fmt.Fprintf(c.c.Out, "%s (https://console.metalstack.cloud/project-invite/%s)\n", resp.Msg.Invite.Secret, resp.Msg.Invite.Secret) + _, _ = fmt.Fprintf(c.c.Out, "You can share this secret with the member to join, it expires in %s:\n\n", humanize.Time(resp.Msg.Invite.ExpiresAt.AsTime())) + _, _ = fmt.Fprintf(c.c.Out, "%s (https://console.metalstack.cloud/project-invite/%s)\n", resp.Msg.Invite.Secret, resp.Msg.Invite.Secret) return nil } @@ -403,7 +403,7 @@ func (c *project) removeMember(args []string) error { return fmt.Errorf("failed to remove member from project: %w", err) } - fmt.Fprintf(c.c.Out, "%s successfully removed member %q\n", color.GreenString("✔"), member) + _, _ = fmt.Fprintf(c.c.Out, "%s successfully removed member %q\n", color.GreenString("✔"), member) return nil } diff --git a/cmd/api/v1/tenant.go b/cmd/api/v1/tenant.go index e6fd853..076714d 100644 --- a/cmd/api/v1/tenant.go +++ b/cmd/api/v1/tenant.go @@ -317,7 +317,7 @@ func (c *tenant) join(args []string) error { return fmt.Errorf("failed to join tenant: %w", err) } - fmt.Fprintf(c.c.Out, "%s successfully joined tenant \"%s\"\n", color.GreenString("✔"), color.GreenString(acceptResp.Msg.TenantName)) + _, _ = fmt.Fprintf(c.c.Out, "%s successfully joined tenant \"%s\"\n", color.GreenString("✔"), color.GreenString(acceptResp.Msg.TenantName)) return nil } @@ -339,8 +339,8 @@ func (c *tenant) generateInvite() error { return fmt.Errorf("failed to generate an invite: %w", err) } - fmt.Fprintf(c.c.Out, "You can share this secret with the member to join, it expires in %s:\n\n", humanize.Time(resp.Msg.Invite.ExpiresAt.AsTime())) - fmt.Fprintf(c.c.Out, "%s (https://console.metalstack.cloud/organization-invite/%s)\n", resp.Msg.Invite.Secret, resp.Msg.Invite.Secret) + _, _ = fmt.Fprintf(c.c.Out, "You can share this secret with the member to join, it expires in %s:\n\n", humanize.Time(resp.Msg.Invite.ExpiresAt.AsTime())) + _, _ = fmt.Fprintf(c.c.Out, "%s (https://console.metalstack.cloud/organization-invite/%s)\n", resp.Msg.Invite.Secret, resp.Msg.Invite.Secret) return nil } @@ -416,7 +416,7 @@ func (c *tenant) removeMember(args []string) error { return fmt.Errorf("failed to remove member from tenant: %w", err) } - fmt.Fprintf(c.c.Out, "%s successfully removed member %q\n", color.GreenString("✔"), member) + _, _ = fmt.Fprintf(c.c.Out, "%s successfully removed member %q\n", color.GreenString("✔"), member) return nil } diff --git a/cmd/api/v1/token.go b/cmd/api/v1/token.go index f2ac9e0..4a65677 100644 --- a/cmd/api/v1/token.go +++ b/cmd/api/v1/token.go @@ -159,10 +159,10 @@ func (c *token) Create(rq *apiv1.TokenServiceCreateRequest) (*apiv1.Token, error return nil, err } - fmt.Fprintf(c.c.Out, "Make sure to copy your personal access token now as you will not be able to see this again.\n") - fmt.Fprintln(c.c.Out) - fmt.Fprintln(c.c.Out, resp.Msg.GetSecret()) - fmt.Fprintln(c.c.Out) + _, _ = fmt.Fprintf(c.c.Out, "Make sure to copy your personal access token now as you will not be able to see this again.\n") + _, _ = fmt.Fprintln(c.c.Out) + _, _ = fmt.Fprintln(c.c.Out, resp.Msg.GetSecret()) + _, _ = fmt.Fprintln(c.c.Out) // TODO: allow printer in metal-lib to be silenced diff --git a/cmd/api/v1/volume.go b/cmd/api/v1/volume.go index a194546..83a68bf 100644 --- a/cmd/api/v1/volume.go +++ b/cmd/api/v1/volume.go @@ -194,7 +194,7 @@ func (c *volume) volumeManifest(args []string) error { if len(volume.AttachedTo) > 0 { nodes := connectedHosts(volume) - fmt.Fprintf(c.c.Out, "# be cautios! at the time being your volume:%s is still attached to worker node:%s, you can not mount it twice\n", volume.Uuid, strings.Join(nodes, ",")) + _, _ = fmt.Fprintf(c.c.Out, "# be cautios! at the time being your volume:%s is still attached to worker node:%s, you can not mount it twice\n", volume.Uuid, strings.Join(nodes, ",")) } y, err := yaml.Marshal(pv) @@ -202,7 +202,7 @@ func (c *volume) volumeManifest(args []string) error { panic(fmt.Errorf("unable to marshal to yaml: %w", err)) } - fmt.Fprintf(c.c.Out, "---\n%s", string(y)) + _, _ = fmt.Fprintf(c.c.Out, "---\n%s", string(y)) return nil } @@ -225,12 +225,12 @@ func (v *volume) volumeEncryptionSecretManifest() error { if err != nil { return err } - fmt.Fprintf(v.c.Out, `# Sample secret to be used in conjunction with the partition-gold-encrypted StorageClass. + _, _ = fmt.Fprintf(v.c.Out, `# Sample secret to be used in conjunction with the partition-gold-encrypted StorageClass. # Place this secret, after modifying namespace and the actual secret value, in the same namespace as the pvc. # # IMPORTANT # Remember to make a safe copy of this secret at a secure location, once lost all your data will be lost as well.`) - fmt.Fprintln(v.c.Out, string(y)) + _, _ = fmt.Fprintln(v.c.Out, string(y)) return nil } diff --git a/cmd/context.go b/cmd/context.go index 9892477..11f2879 100644 --- a/cmd/context.go +++ b/cmd/context.go @@ -144,7 +144,7 @@ func (c *ctx) short() error { return err } - fmt.Fprint(c.c.Out, ctxs.CurrentContext) + _, _ = fmt.Fprint(c.c.Out, ctxs.CurrentContext) return nil } @@ -185,7 +185,7 @@ func (c *ctx) add(args []string) error { return err } - fmt.Fprintf(c.c.Out, "%s added context \"%s\"\n", color.GreenString("✔"), color.GreenString(ctx.Name)) + _, _ = fmt.Fprintf(c.c.Out, "%s added context \"%s\"\n", color.GreenString("✔"), color.GreenString(ctx.Name)) return nil } @@ -228,7 +228,7 @@ func (c *ctx) update(args []string) error { return err } - fmt.Fprintf(c.c.Out, "%s updated context \"%s\"\n", color.GreenString("✔"), color.GreenString(ctx.Name)) + _, _ = fmt.Fprintf(c.c.Out, "%s updated context \"%s\"\n", color.GreenString("✔"), color.GreenString(ctx.Name)) return nil } @@ -256,7 +256,7 @@ func (c *ctx) remove(args []string) error { return err } - fmt.Fprintf(c.c.Out, "%s removed context \"%s\"\n", color.GreenString("✔"), color.GreenString(ctx.Name)) + _, _ = fmt.Fprintf(c.c.Out, "%s removed context \"%s\"\n", color.GreenString("✔"), color.GreenString(ctx.Name)) return nil } @@ -288,7 +288,7 @@ func (c *ctx) set(args []string) error { return fmt.Errorf("context %s not found", nextCtx) } if nextCtx == ctxs.CurrentContext { - fmt.Fprintf(c.c.Out, "%s context \"%s\" already active\n", color.GreenString("✔"), color.GreenString(ctxs.CurrentContext)) + _, _ = fmt.Fprintf(c.c.Out, "%s context \"%s\" already active\n", color.GreenString("✔"), color.GreenString(ctxs.CurrentContext)) return nil } ctxs.PreviousContext = ctxs.CurrentContext @@ -300,7 +300,7 @@ func (c *ctx) set(args []string) error { return err } - fmt.Fprintf(c.c.Out, "%s switched context to \"%s\"\n", color.GreenString("✔"), color.GreenString(ctxs.CurrentContext)) + _, _ = fmt.Fprintf(c.c.Out, "%s switched context to \"%s\"\n", color.GreenString("✔"), color.GreenString(ctxs.CurrentContext)) return nil } @@ -328,7 +328,7 @@ func (c *ctx) setProject(args []string) error { return err } - fmt.Fprintf(c.c.Out, "%s switched context default project to \"%s\"\n", color.GreenString("✔"), color.GreenString(ctx.DefaultProject)) + _, _ = fmt.Fprintf(c.c.Out, "%s switched context default project to \"%s\"\n", color.GreenString("✔"), color.GreenString(ctx.DefaultProject)) return nil } diff --git a/cmd/tableprinters/ip.go b/cmd/tableprinters/ip.go index d515478..3d45760 100644 --- a/cmd/tableprinters/ip.go +++ b/cmd/tableprinters/ip.go @@ -1,7 +1,6 @@ package tableprinters import ( - "fmt" "strings" apiv1 "github.com/metal-stack-cloud/api/go/api/v1" @@ -40,7 +39,7 @@ func (t *TablePrinter) IPTable(data []*apiv1.IP, wide bool) ([]string, [][]strin tm := tag.NewTagMap(ip.Tags) if value, ok := tm.Value(tag.ClusterServiceFQN); ok { if parts := strings.Split(value, "/"); len(parts) == 3 { - attachedService = fmt.Sprintf("%s", parts[2]) + attachedService = parts[2] } } diff --git a/pkg/helpers/ssh.go b/pkg/helpers/ssh.go index 7eb614b..795924f 100644 --- a/pkg/helpers/ssh.go +++ b/pkg/helpers/ssh.go @@ -19,14 +19,16 @@ func SSHViaVPN(out io.Writer, machineID string, creds *adminv1.ClusterServiceCre return fmt.Errorf("no vpn connection possible") } - fmt.Fprintf(out, "accessing firewall through vpn at %s ", creds.Vpn.Address) + _, _ = fmt.Fprintf(out, "accessing firewall through vpn at %s ", creds.Vpn.Address) ctx := context.Background() v, err := metalvpn.Connect(ctx, machineID, creds.Vpn.Address, creds.Vpn.Authkey) if err != nil { return err } - defer v.Close() + defer func() { + _ = v.Close() + }() opts := []metalssh.ConnectOpt{metalssh.ConnectOptOutputPrivateKey(creds.SshKeypair.Privatekey)} From 284071c426d54237e79fc9f0b8db83604b67679c Mon Sep 17 00:00:00 2001 From: Gerrit Date: Thu, 24 Apr 2025 16:08:37 +0200 Subject: [PATCH 17/20] Update. --- docs/metal_audit_describe.md | 2 ++ docs/metal_audit_list.md | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/metal_audit_describe.md b/docs/metal_audit_describe.md index cc28bc4..c749bd2 100644 --- a/docs/metal_audit_describe.md +++ b/docs/metal_audit_describe.md @@ -10,7 +10,9 @@ metal audit describe [flags] ``` -h, --help help for describe + --phase string the audit trace phase. --prettify-body attempts to interpret the body as json and prettifies it. + --tenant string tenant of the audit trace. ``` ### Options inherited from parent commands diff --git a/docs/metal_audit_list.md b/docs/metal_audit_list.md index ca776ab..c20b3ce 100644 --- a/docs/metal_audit_list.md +++ b/docs/metal_audit_list.md @@ -9,15 +9,16 @@ metal audit list [flags] ### Options ``` - --body string filters audit trace body payloads for the giben text. - --error string error of the audit trace. - --from string start of range of the audit traces. e.g. 1h, 10m, 2006-01-02 15:04:05 (default "1h") + --body string filters audit trace body payloads for the given text (full-text search). + --from string start of range of the audit traces. e.g. 1h, 10m, 2006-01-02 15:04:05 -h, --help help for list - --limit int limit the number of audit traces. (default 100) + --limit int limit the number of audit traces. --method string api method of the audit trace. + --phase string the audit trace phase. + --prettify-body attempts to interpret the body as json and prettifies it. --project string project id of the audit trace --request-id string request id of the audit trace. - --result-code int32 HTTP status code of the audit trace. + --result-code int32 gRPC result status code of the audit trace. --sort-by strings sort by (comma separated) column(s), sort direction can be changed by appending :asc or :desc behind the column identifier. possible values: method|project|timestamp|user --source-ip string source-ip of the audit trace. --tenant string tenant of the audit trace. From ad2b77cc0e1e3d57abc5098da277dedfca0c0682 Mon Sep 17 00:00:00 2001 From: Gerrit Date: Fri, 25 Apr 2025 08:29:42 +0200 Subject: [PATCH 18/20] Pin. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 9adcd27..29556e3 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.18.0 github.com/google/go-cmp v0.7.0 - github.com/metal-stack-cloud/api v0.13.1-0.20250423091441-7817111ceca7 + github.com/metal-stack-cloud/api v0.14.0 github.com/metal-stack/metal-lib v0.20.2 github.com/metal-stack/v v1.0.3 github.com/olekukonko/tablewriter v0.0.5 diff --git a/go.sum b/go.sum index e1aadf5..936c01e 100644 --- a/go.sum +++ b/go.sum @@ -197,8 +197,8 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/metal-stack-cloud/api v0.13.1-0.20250423091441-7817111ceca7 h1:qjMNpPx559zcaAEU60jZoaFLsL2Q3cEW9drmj75HYi0= -github.com/metal-stack-cloud/api v0.13.1-0.20250423091441-7817111ceca7/go.mod h1:Wsm+LQw/ee1uv68Dlsp1VJk9PcreFJH0WxDtZmJ7maU= +github.com/metal-stack-cloud/api v0.14.0 h1:Lg2Qtq/4eLBlYFUaKbtJcsGyAtv/BsBrBClo6jX2CoY= +github.com/metal-stack-cloud/api v0.14.0/go.mod h1:Wsm+LQw/ee1uv68Dlsp1VJk9PcreFJH0WxDtZmJ7maU= github.com/metal-stack/metal-lib v0.20.2 h1:Dy6JNIo8ku8mdGyuijlBELkvJ/q2SDBpvDyztgAqEDE= github.com/metal-stack/metal-lib v0.20.2/go.mod h1:zYzXYpNA4nQ+ANx19s/+1Yb/Q6xhS1nQK2yK2/ryXZM= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= From 33150aae074f31ed8e984ae2ac022e80ca3c4067 Mon Sep 17 00:00:00 2001 From: Gerrit Date: Fri, 25 Apr 2025 08:41:34 +0200 Subject: [PATCH 19/20] Result code completion. --- cmd/api/v1/audit.go | 1 + cmd/completion/audit.go | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/cmd/api/v1/audit.go b/cmd/api/v1/audit.go index bb0ba64..15c1d49 100644 --- a/cmd/api/v1/audit.go +++ b/cmd/api/v1/audit.go @@ -62,6 +62,7 @@ func newAuditCmd(c *config.Config) *cobra.Command { genericcli.Must(cmd.RegisterFlagCompletionFunc("phase", c.Completion.AuditPhaseListCompletion)) genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.Completion.ProjectListCompletion)) genericcli.Must(cmd.RegisterFlagCompletionFunc("tenant", c.Completion.TenantListCompletion)) + genericcli.Must(cmd.RegisterFlagCompletionFunc("result-code", c.Completion.AuditStatusCodesCompletion)) }, DescribeCmdMutateFn: func(cmd *cobra.Command) { cmd.Flags().String("tenant", "", "tenant of the audit trace.") diff --git a/cmd/completion/audit.go b/cmd/completion/audit.go index 2e18031..2007040 100644 --- a/cmd/completion/audit.go +++ b/cmd/completion/audit.go @@ -1,10 +1,23 @@ package completion import ( + "strconv" + apiv1 "github.com/metal-stack-cloud/api/go/api/v1" "github.com/spf13/cobra" + "google.golang.org/grpc/codes" ) func (c *Completion) AuditPhaseListCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return []string{apiv1.AuditPhase_AUDIT_PHASE_REQUEST.String(), apiv1.AuditPhase_AUDIT_PHASE_RESPONSE.String()}, cobra.ShellCompDirectiveNoFileComp } + +func (c *Completion) AuditStatusCodesCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + var result []string + + for i := range 16 { + result = append(result, strconv.Itoa(i)+"\t"+codes.Code(uint32(i)).String()) + } + + return result, cobra.ShellCompDirectiveNoFileComp +} From 557239c93998ff621fc7b8bf0d3c38893b0217e7 Mon Sep 17 00:00:00 2001 From: Gerrit Date: Fri, 25 Apr 2025 08:53:12 +0200 Subject: [PATCH 20/20] ID sorter. --- cmd/sorters/audit.go | 3 +++ docs/metal_audit_list.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/sorters/audit.go b/cmd/sorters/audit.go index 839d5d0..b3b33e2 100644 --- a/cmd/sorters/audit.go +++ b/cmd/sorters/audit.go @@ -9,6 +9,9 @@ import ( func AuditSorter() *multisort.Sorter[*apiv1.AuditTrace] { return multisort.New(multisort.FieldMap[*apiv1.AuditTrace]{ + "id": func(a, b *apiv1.AuditTrace, descending bool) multisort.CompareResult { + return multisort.Compare(a.Uuid, b.Uuid, descending) + }, "timestamp": func(a, b *apiv1.AuditTrace, descending bool) multisort.CompareResult { return multisort.Compare(time.Time(a.Timestamp.AsTime()).Unix(), time.Time(b.Timestamp.AsTime()).Unix(), descending) }, diff --git a/docs/metal_audit_list.md b/docs/metal_audit_list.md index c20b3ce..e516aa9 100644 --- a/docs/metal_audit_list.md +++ b/docs/metal_audit_list.md @@ -19,7 +19,7 @@ metal audit list [flags] --project string project id of the audit trace --request-id string request id of the audit trace. --result-code int32 gRPC result status code of the audit trace. - --sort-by strings sort by (comma separated) column(s), sort direction can be changed by appending :asc or :desc behind the column identifier. possible values: method|project|timestamp|user + --sort-by strings sort by (comma separated) column(s), sort direction can be changed by appending :asc or :desc behind the column identifier. possible values: id|method|project|timestamp|user --source-ip string source-ip of the audit trace. --tenant string tenant of the audit trace. --to string end of range of the audit traces. e.g. 1h, 10m, 2006-01-02 15:04:05