From 26d399e259897dcb6897498a22ff296b63badc79 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Thu, 15 Sep 2022 18:20:27 +0000 Subject: [PATCH 01/11] Update the API --- coderd/audit.go | 72 +++++++++++++++++++++++++-- coderd/audit_test.go | 49 +++++++++++++++++- coderd/database/queries.sql.go | 26 ++++++++-- coderd/database/queries/auditlogs.sql | 13 +++++ codersdk/audit.go | 27 ++++++++-- site/src/api/api.ts | 20 +++++--- site/src/api/typesGenerated.ts | 11 ++++ 7 files changed, 198 insertions(+), 20 deletions(-) diff --git a/coderd/audit.go b/coderd/audit.go index 9fccb49ddfcd9..3b7d18f7b6496 100644 --- a/coderd/audit.go +++ b/coderd/audit.go @@ -6,6 +6,8 @@ import ( "net" "net/http" "net/netip" + "net/url" + "strings" "time" "github.com/google/uuid" @@ -30,9 +32,21 @@ func (api *API) auditLogs(rw http.ResponseWriter, r *http.Request) { return } + queryStr := r.URL.Query().Get("q") + filter, errs := auditSearchQuery(queryStr) + if len(errs) > 0 { + httpapi.Write(rw, http.StatusBadRequest, codersdk.Response{ + Message: "Invalid audit search query.", + Validations: errs, + }) + return + } + dblogs, err := api.Database.GetAuditLogsOffset(ctx, database.GetAuditLogsOffsetParams{ - Offset: int32(page.Offset), - Limit: int32(page.Limit), + Offset: int32(page.Offset), + Limit: int32(page.Limit), + ResourceType: filter.ResourceType, + Action: filter.Action, }) if err != nil { httpapi.InternalServerError(rw, err) @@ -97,16 +111,27 @@ func (api *API) generateFakeAuditLog(rw http.ResponseWriter, r *http.Request) { } } + var params codersdk.CreateTestAuditLogRequest + if !httpapi.Read(rw, r, ¶ms) { + return + } + if params.Action == "" { + params.Action = codersdk.AuditActionWrite + } + if params.ResourceType == "" { + params.ResourceType = codersdk.ResourceTypeUser + } + _, err = api.Database.InsertAuditLog(ctx, database.InsertAuditLogParams{ ID: uuid.New(), Time: time.Now(), UserID: user.ID, Ip: ipNet, UserAgent: r.UserAgent(), - ResourceType: database.ResourceTypeUser, + ResourceType: database.ResourceType(params.ResourceType), ResourceID: user.ID, ResourceTarget: user.Username, - Action: database.AuditActionWrite, + Action: database.AuditAction(params.Action), Diff: diff, StatusCode: http.StatusOK, AdditionalFields: []byte("{}"), @@ -179,3 +204,42 @@ func auditLogDescription(alog database.GetAuditLogsOffsetRow) string { codersdk.ResourceType(alog.ResourceType).FriendlyString(), ) } + +// auditSearchQuery takes a query string and returns the auditLog filter. +// It also can return the list of validation errors to return to the api. +func auditSearchQuery(query string) (database.GetAuditLogsOffsetParams, []codersdk.ValidationError) { + searchParams := make(url.Values) + if query == "" { + // No filter + return database.GetAuditLogsOffsetParams{}, nil + } + query = strings.ToLower(query) + // Because we do this in 2 passes, we want to maintain quotes on the first + // pass.Further splitting occurs on the second pass and quotes will be + // dropped. + elements := splitQueryParameterByDelimiter(query, ' ', true) + for _, element := range elements { + parts := splitQueryParameterByDelimiter(element, ':', false) + switch len(parts) { + case 1: + // No key:value pair. + searchParams.Set("resource_type", parts[0]) + case 2: + searchParams.Set(parts[0], parts[1]) + default: + return database.GetAuditLogsOffsetParams{}, []codersdk.ValidationError{ + {Field: "q", Detail: fmt.Sprintf("Query element %q can only contain 1 ':'", element)}, + } + } + } + + // Using the query param parser here just returns consistent errors with + // other parsing. + parser := httpapi.NewQueryParamParser() + filter := database.GetAuditLogsOffsetParams{ + ResourceType: parser.String(searchParams, "", "resource_type"), + Action: parser.String(searchParams, "", "action"), + } + + return filter, parser.Errors +} diff --git a/coderd/audit_test.go b/coderd/audit_test.go index f2050df93585f..718a08a704539 100644 --- a/coderd/audit_test.go +++ b/coderd/audit_test.go @@ -20,16 +20,61 @@ func TestAuditLogs(t *testing.T) { client := coderdtest.New(t, nil) _ = coderdtest.CreateFirstUser(t, client) - err := client.CreateTestAuditLog(ctx) + err := client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{}) require.NoError(t, err) count, err := client.AuditLogCount(ctx) require.NoError(t, err) - alogs, err := client.AuditLogs(ctx, codersdk.Pagination{Limit: 1}) + alogs, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{ + Pagination: codersdk.Pagination{ + Limit: 1, + }, + }) require.NoError(t, err) require.Equal(t, int64(1), count.Count) require.Len(t, alogs.AuditLogs, 1) }) } + +func TestAuditLogsFilter(t *testing.T) { + t.Parallel() + + t.Run("FilterByResourceType", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + client := coderdtest.New(t, nil) + _ = coderdtest.CreateFirstUser(t, client) + + // Create two logs with "Create" + err := client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{ + Action: codersdk.AuditActionCreate, + }) + require.NoError(t, err) + err = client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{ + Action: codersdk.AuditActionCreate, + }) + require.NoError(t, err) + // Create one log with "Delete" + err = client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{ + Action: codersdk.AuditActionDelete, + }) + require.NoError(t, err) + + // Verify the number of create logs + actionCreateLogs, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{ + SearchQuery: "action:create", + }) + require.NoError(t, err) + require.Len(t, actionCreateLogs, 2) + + // Verify the number of delete logs + actionDeleteLogs, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{ + SearchQuery: "action:delete", + }) + require.NoError(t, err) + require.Len(t, actionDeleteLogs, 1) + }) +} diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 88dd2091a7718..6013d6d93ff0b 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -314,6 +314,19 @@ FROM audit_logs LEFT JOIN users ON audit_logs.user_id = users.id +WHERE + -- Filter resource_type + CASE + WHEN $3 :: text != '' THEN + resource_type = LOWER($3) + ELSE true + END + -- Filter action + AND CASE + WHEN $4 :: text != '' THEN + resource_type = LOWER($4) + ELSE true + END ORDER BY "time" DESC LIMIT @@ -323,8 +336,10 @@ OFFSET ` type GetAuditLogsOffsetParams struct { - Limit int32 `db:"limit" json:"limit"` - Offset int32 `db:"offset" json:"offset"` + Limit int32 `db:"limit" json:"limit"` + Offset int32 `db:"offset" json:"offset"` + ResourceType string `db:"resource_type" json:"resource_type"` + Action string `db:"action" json:"action"` } type GetAuditLogsOffsetRow struct { @@ -354,7 +369,12 @@ type GetAuditLogsOffsetRow struct { // GetAuditLogsBefore retrieves `row_limit` number of audit logs before the provided // ID. func (q *sqlQuerier) GetAuditLogsOffset(ctx context.Context, arg GetAuditLogsOffsetParams) ([]GetAuditLogsOffsetRow, error) { - rows, err := q.db.QueryContext(ctx, getAuditLogsOffset, arg.Limit, arg.Offset) + rows, err := q.db.QueryContext(ctx, getAuditLogsOffset, + arg.Limit, + arg.Offset, + arg.ResourceType, + arg.Action, + ) if err != nil { return nil, err } diff --git a/coderd/database/queries/auditlogs.sql b/coderd/database/queries/auditlogs.sql index 0c2364f828b85..9c30ab0c1b72e 100644 --- a/coderd/database/queries/auditlogs.sql +++ b/coderd/database/queries/auditlogs.sql @@ -13,6 +13,19 @@ FROM audit_logs LEFT JOIN users ON audit_logs.user_id = users.id +WHERE + -- Filter resource_type + CASE + WHEN @resource_type :: text != '' THEN + resource_type = LOWER(@resource_type) + ELSE true + END + -- Filter action + AND CASE + WHEN @action :: text != '' THEN + resource_type = LOWER(@action) + ELSE true + END ORDER BY "time" DESC LIMIT diff --git a/codersdk/audit.go b/codersdk/audit.go index fd26fe58ec0e9..810cf72c2f608 100644 --- a/codersdk/audit.go +++ b/codersdk/audit.go @@ -5,6 +5,7 @@ import ( "encoding/json" "net/http" "net/netip" + "strings" "time" "github.com/google/uuid" @@ -93,6 +94,11 @@ type AuditLog struct { User *User `json:"user"` } +type AuditLogsRequest struct { + SearchQuery string `json:"q,omitempty"` + Pagination +} + type AuditLogResponse struct { AuditLogs []AuditLog `json:"audit_logs"` } @@ -101,9 +107,22 @@ type AuditLogCountResponse struct { Count int64 `json:"count"` } +type CreateTestAuditLogRequest struct { + Action AuditAction `json:"action,omitempty"` + ResourceType ResourceType `json:"resource_type,omitempty"` +} + // AuditLogs retrieves audit logs from the given page. -func (c *Client) AuditLogs(ctx context.Context, page Pagination) (AuditLogResponse, error) { - res, err := c.Request(ctx, http.MethodGet, "/api/v2/audit", nil, page.asRequestOption()) +func (c *Client) AuditLogs(ctx context.Context, req AuditLogsRequest) (AuditLogResponse, error) { + res, err := c.Request(ctx, http.MethodGet, "/api/v2/audit", nil, req.Pagination.asRequestOption(), func(r *http.Request) { + q := r.URL.Query() + var params []string + if req.SearchQuery != "" { + params = append(params, req.SearchQuery) + } + q.Set("q", strings.Join(params, " ")) + r.URL.RawQuery = q.Encode() + }) if err != nil { return AuditLogResponse{}, err } @@ -143,8 +162,8 @@ func (c *Client) AuditLogCount(ctx context.Context) (AuditLogCountResponse, erro return logRes, nil } -func (c *Client) CreateTestAuditLog(ctx context.Context) error { - res, err := c.Request(ctx, http.MethodPost, "/api/v2/audit/testgenerate", nil) +func (c *Client) CreateTestAuditLog(ctx context.Context, req CreateTestAuditLogRequest) error { + res, err := c.Request(ctx, http.MethodPost, "/api/v2/audit/testgenerate", req) if err != nil { return err } diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 3e2ea86c16d8b..7d4520c11a2a2 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -428,15 +428,21 @@ export const getEntitlements = async (): Promise => { return response.data } -interface GetAuditLogsOptions { - limit: number - offset: number -} - export const getAuditLogs = async ( - options: GetAuditLogsOptions, + options: TypesGen.AuditLogsRequest, ): Promise => { - const response = await axios.get(`/api/v2/audit?limit=${options.limit}&offset=${options.offset}`) + const searchParams = new URLSearchParams() + if (options.limit) { + searchParams.set("limit", options.limit.toString()) + } + if (options.offset) { + searchParams.set("offset", options.offset.toString()) + } + if (options.q) { + searchParams.set("q", options.q) + } + + const response = await axios.get(`/api/v2/audit?${searchParams.toString()}`) return response.data } diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index c5a90816563a4..98a4591ac74dc 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -86,6 +86,11 @@ export interface AuditLogResponse { readonly audit_logs: AuditLog[] } +// From codersdk/audit.go +export interface AuditLogsRequest extends Pagination { + readonly q?: string +} + // From codersdk/users.go export interface AuthMethods { readonly password: boolean @@ -166,6 +171,12 @@ export interface CreateTemplateVersionRequest { readonly parameter_values?: CreateParameterRequest[] } +// From codersdk/audit.go +export interface CreateTestAuditLogRequest { + readonly action?: AuditAction + readonly resource_type?: ResourceType +} + // From codersdk/users.go export interface CreateUserRequest { readonly email: string From 3f23deb0d070237f5bd5b25498d523ab6f1dce9d Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Thu, 15 Sep 2022 19:15:12 +0000 Subject: [PATCH 02/11] Fix database fake and expect --- coderd/audit_test.go | 4 ++-- coderd/database/databasefake/databasefake.go | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/coderd/audit_test.go b/coderd/audit_test.go index 718a08a704539..0d901a9f2dce8 100644 --- a/coderd/audit_test.go +++ b/coderd/audit_test.go @@ -68,13 +68,13 @@ func TestAuditLogsFilter(t *testing.T) { SearchQuery: "action:create", }) require.NoError(t, err) - require.Len(t, actionCreateLogs, 2) + require.Len(t, actionCreateLogs.AuditLogs, 2) // Verify the number of delete logs actionDeleteLogs, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{ SearchQuery: "action:delete", }) require.NoError(t, err) - require.Len(t, actionDeleteLogs, 1) + require.Len(t, actionDeleteLogs.AuditLogs, 1) }) } diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 76c0d278b8abe..8a0bc38a5c7c0 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -2337,6 +2337,14 @@ func (q *fakeQuerier) GetAuditLogsOffset(ctx context.Context, arg database.GetAu continue } + if arg.Action != "" && !strings.Contains(strings.ToLower(string(alog.Action)), strings.ToLower(arg.Action)) { + continue + } + + if arg.ResourceType != "" && !strings.Contains(strings.ToLower(string(alog.ResourceType)), strings.ToLower(arg.ResourceType)) { + continue + } + user, err := q.GetUserByID(ctx, alog.UserID) userValid := err == nil From 244d0a16c5be3fb52eb20bb5ca383a139bc58214 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Fri, 16 Sep 2022 13:39:42 +0000 Subject: [PATCH 03/11] Fix test --- coderd/audit_test.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/coderd/audit_test.go b/coderd/audit_test.go index 0d901a9f2dce8..0c750939fa54c 100644 --- a/coderd/audit_test.go +++ b/coderd/audit_test.go @@ -50,11 +50,13 @@ func TestAuditLogsFilter(t *testing.T) { // Create two logs with "Create" err := client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{ - Action: codersdk.AuditActionCreate, + Action: codersdk.AuditActionCreate, + ResourceType: codersdk.ResourceTypeTemplate, }) require.NoError(t, err) err = client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{ - Action: codersdk.AuditActionCreate, + Action: codersdk.AuditActionCreate, + ResourceType: codersdk.ResourceTypeUser, }) require.NoError(t, err) // Create one log with "Delete" @@ -66,6 +68,9 @@ func TestAuditLogsFilter(t *testing.T) { // Verify the number of create logs actionCreateLogs, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{ SearchQuery: "action:create", + Pagination: codersdk.Pagination{ + Limit: 25, + }, }) require.NoError(t, err) require.Len(t, actionCreateLogs.AuditLogs, 2) @@ -74,6 +79,7 @@ func TestAuditLogsFilter(t *testing.T) { actionDeleteLogs, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{ SearchQuery: "action:delete", }) + require.NoError(t, err) require.Len(t, actionDeleteLogs.AuditLogs, 1) }) From 10e4f33267fe061ee6ec87773d44b12a2143f784 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Fri, 16 Sep 2022 14:15:20 +0000 Subject: [PATCH 04/11] Fix action filter query --- coderd/database/queries.sql.go | 2 +- coderd/database/queries/auditlogs.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 6013d6d93ff0b..a0415506c4241 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -324,7 +324,7 @@ WHERE -- Filter action AND CASE WHEN $4 :: text != '' THEN - resource_type = LOWER($4) + action = LOWER($4) ELSE true END ORDER BY diff --git a/coderd/database/queries/auditlogs.sql b/coderd/database/queries/auditlogs.sql index 9c30ab0c1b72e..759cd3c686f4d 100644 --- a/coderd/database/queries/auditlogs.sql +++ b/coderd/database/queries/auditlogs.sql @@ -23,7 +23,7 @@ WHERE -- Filter action AND CASE WHEN @action :: text != '' THEN - resource_type = LOWER(@action) + action = LOWER(@action) ELSE true END ORDER BY From a678105c47f562c7ea97732dcc6e94f34243bcdf Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Fri, 16 Sep 2022 16:23:14 +0000 Subject: [PATCH 05/11] Fix query --- coderd/database/queries.sql.go | 4 ++-- coderd/database/queries/auditlogs.sql | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index a0415506c4241..99d93b16c0e5e 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -318,13 +318,13 @@ WHERE -- Filter resource_type CASE WHEN $3 :: text != '' THEN - resource_type = LOWER($3) + resource_type = $3 ELSE true END -- Filter action AND CASE WHEN $4 :: text != '' THEN - action = LOWER($4) + action = $4 ELSE true END ORDER BY diff --git a/coderd/database/queries/auditlogs.sql b/coderd/database/queries/auditlogs.sql index 759cd3c686f4d..3def599fdef4f 100644 --- a/coderd/database/queries/auditlogs.sql +++ b/coderd/database/queries/auditlogs.sql @@ -17,13 +17,13 @@ WHERE -- Filter resource_type CASE WHEN @resource_type :: text != '' THEN - resource_type = LOWER(@resource_type) + resource_type = @resource_type ELSE true END -- Filter action AND CASE WHEN @action :: text != '' THEN - action = LOWER(@action) + action = @action ELSE true END ORDER BY From 8e740de7e8c6068667be4ff55ad853dc2dc5c5fc Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Fri, 16 Sep 2022 16:50:01 +0000 Subject: [PATCH 06/11] Cast types --- coderd/database/queries/auditlogs.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coderd/database/queries/auditlogs.sql b/coderd/database/queries/auditlogs.sql index 3def599fdef4f..a00baef9eb707 100644 --- a/coderd/database/queries/auditlogs.sql +++ b/coderd/database/queries/auditlogs.sql @@ -16,13 +16,13 @@ LEFT JOIN WHERE -- Filter resource_type CASE - WHEN @resource_type :: text != '' THEN + WHEN @resource_type :: resource_type != '' THEN resource_type = @resource_type ELSE true END -- Filter action AND CASE - WHEN @action :: text != '' THEN + WHEN @action :: audit_action != '' THEN action = @action ELSE true END From 43a3b7146ddb3446fce39f0cc356fcf0283939bb Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Fri, 16 Sep 2022 16:54:11 +0000 Subject: [PATCH 07/11] Update query --- coderd/database/queries.sql.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 99d93b16c0e5e..c23e7271c9279 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -317,13 +317,13 @@ LEFT JOIN WHERE -- Filter resource_type CASE - WHEN $3 :: text != '' THEN + WHEN $3 :: resource_type != '' THEN resource_type = $3 ELSE true END -- Filter action AND CASE - WHEN $4 :: text != '' THEN + WHEN $4 :: audit_action != '' THEN action = $4 ELSE true END @@ -336,10 +336,10 @@ OFFSET ` type GetAuditLogsOffsetParams struct { - Limit int32 `db:"limit" json:"limit"` - Offset int32 `db:"offset" json:"offset"` - ResourceType string `db:"resource_type" json:"resource_type"` - Action string `db:"action" json:"action"` + Limit int32 `db:"limit" json:"limit"` + Offset int32 `db:"offset" json:"offset"` + ResourceType ResourceType `db:"resource_type" json:"resource_type"` + Action AuditAction `db:"action" json:"action"` } type GetAuditLogsOffsetRow struct { From 2e54641c29cc98f4be7936eb2304936f917f38cc Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Fri, 16 Sep 2022 17:00:04 +0000 Subject: [PATCH 08/11] Fix types in go --- coderd/audit.go | 4 ++-- coderd/database/databasefake/databasefake.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/coderd/audit.go b/coderd/audit.go index 3b7d18f7b6496..316097e95ca9c 100644 --- a/coderd/audit.go +++ b/coderd/audit.go @@ -237,8 +237,8 @@ func auditSearchQuery(query string) (database.GetAuditLogsOffsetParams, []coders // other parsing. parser := httpapi.NewQueryParamParser() filter := database.GetAuditLogsOffsetParams{ - ResourceType: parser.String(searchParams, "", "resource_type"), - Action: parser.String(searchParams, "", "action"), + ResourceType: database.ResourceType(parser.String(searchParams, "", "resource_type")), + Action: database.AuditAction(parser.String(searchParams, "", "action")), } return filter, parser.Errors diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 8a0bc38a5c7c0..104fcbb90e968 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -2337,11 +2337,11 @@ func (q *fakeQuerier) GetAuditLogsOffset(ctx context.Context, arg database.GetAu continue } - if arg.Action != "" && !strings.Contains(strings.ToLower(string(alog.Action)), strings.ToLower(arg.Action)) { + if arg.Action != "" && !strings.Contains(string(alog.Action), string(arg.Action)) { continue } - if arg.ResourceType != "" && !strings.Contains(strings.ToLower(string(alog.ResourceType)), strings.ToLower(arg.ResourceType)) { + if arg.ResourceType != "" && !strings.Contains(string(alog.ResourceType), string(arg.ResourceType)) { continue } From 897562a54a86e28bc917546177575cb65c9ff75e Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Fri, 16 Sep 2022 17:16:26 +0000 Subject: [PATCH 09/11] Fix query --- coderd/audit.go | 4 ++-- coderd/database/databasefake/databasefake.go | 4 ++-- coderd/database/queries.sql.go | 16 ++++++++-------- coderd/database/queries/auditlogs.sql | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/coderd/audit.go b/coderd/audit.go index 316097e95ca9c..3b7d18f7b6496 100644 --- a/coderd/audit.go +++ b/coderd/audit.go @@ -237,8 +237,8 @@ func auditSearchQuery(query string) (database.GetAuditLogsOffsetParams, []coders // other parsing. parser := httpapi.NewQueryParamParser() filter := database.GetAuditLogsOffsetParams{ - ResourceType: database.ResourceType(parser.String(searchParams, "", "resource_type")), - Action: database.AuditAction(parser.String(searchParams, "", "action")), + ResourceType: parser.String(searchParams, "", "resource_type"), + Action: parser.String(searchParams, "", "action"), } return filter, parser.Errors diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 104fcbb90e968..996c4c5a99ff7 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -2337,11 +2337,11 @@ func (q *fakeQuerier) GetAuditLogsOffset(ctx context.Context, arg database.GetAu continue } - if arg.Action != "" && !strings.Contains(string(alog.Action), string(arg.Action)) { + if arg.Action != "" && !strings.Contains(string(alog.Action), arg.Action) { continue } - if arg.ResourceType != "" && !strings.Contains(string(alog.ResourceType), string(arg.ResourceType)) { + if arg.ResourceType != "" && !strings.Contains(string(alog.ResourceType), arg.ResourceType) { continue } diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index c23e7271c9279..d18a0c57b031d 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -317,14 +317,14 @@ LEFT JOIN WHERE -- Filter resource_type CASE - WHEN $3 :: resource_type != '' THEN - resource_type = $3 + WHEN $3 :: text != '' THEN + resource_type = $3 :: resource_type ELSE true END -- Filter action AND CASE - WHEN $4 :: audit_action != '' THEN - action = $4 + WHEN $4 :: text != '' THEN + action = $4 :: audit_action ELSE true END ORDER BY @@ -336,10 +336,10 @@ OFFSET ` type GetAuditLogsOffsetParams struct { - Limit int32 `db:"limit" json:"limit"` - Offset int32 `db:"offset" json:"offset"` - ResourceType ResourceType `db:"resource_type" json:"resource_type"` - Action AuditAction `db:"action" json:"action"` + Limit int32 `db:"limit" json:"limit"` + Offset int32 `db:"offset" json:"offset"` + ResourceType string `db:"resource_type" json:"resource_type"` + Action string `db:"action" json:"action"` } type GetAuditLogsOffsetRow struct { diff --git a/coderd/database/queries/auditlogs.sql b/coderd/database/queries/auditlogs.sql index a00baef9eb707..3e29c74de4947 100644 --- a/coderd/database/queries/auditlogs.sql +++ b/coderd/database/queries/auditlogs.sql @@ -16,14 +16,14 @@ LEFT JOIN WHERE -- Filter resource_type CASE - WHEN @resource_type :: resource_type != '' THEN - resource_type = @resource_type + WHEN @resource_type :: text != '' THEN + resource_type = @resource_type :: resource_type ELSE true END -- Filter action AND CASE - WHEN @action :: audit_action != '' THEN - action = @action + WHEN @action :: text != '' THEN + action = @action :: audit_action ELSE true END ORDER BY From 897f2894cef3a9e773f08b956a0c65309677da13 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Fri, 16 Sep 2022 18:40:07 +0000 Subject: [PATCH 10/11] Add limit --- coderd/audit_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/coderd/audit_test.go b/coderd/audit_test.go index 0c750939fa54c..b297efd460830 100644 --- a/coderd/audit_test.go +++ b/coderd/audit_test.go @@ -61,7 +61,8 @@ func TestAuditLogsFilter(t *testing.T) { require.NoError(t, err) // Create one log with "Delete" err = client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{ - Action: codersdk.AuditActionDelete, + Action: codersdk.AuditActionDelete, + ResourceType: codersdk.ResourceTypeUser, }) require.NoError(t, err) @@ -78,6 +79,9 @@ func TestAuditLogsFilter(t *testing.T) { // Verify the number of delete logs actionDeleteLogs, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{ SearchQuery: "action:delete", + Pagination: codersdk.Pagination{ + Limit: 25, + }, }) require.NoError(t, err) From d407d9b6503b35a5dbeee4f5b39e12c998469f9b Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Fri, 16 Sep 2022 19:11:18 +0000 Subject: [PATCH 11/11] Add test cases --- coderd/audit_test.go | 58 ++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/coderd/audit_test.go b/coderd/audit_test.go index b297efd460830..47b7daf9a425f 100644 --- a/coderd/audit_test.go +++ b/coderd/audit_test.go @@ -59,6 +59,7 @@ func TestAuditLogsFilter(t *testing.T) { ResourceType: codersdk.ResourceTypeUser, }) require.NoError(t, err) + // Create one log with "Delete" err = client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{ Action: codersdk.AuditActionDelete, @@ -66,25 +67,46 @@ func TestAuditLogsFilter(t *testing.T) { }) require.NoError(t, err) - // Verify the number of create logs - actionCreateLogs, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{ - SearchQuery: "action:create", - Pagination: codersdk.Pagination{ - Limit: 25, + // Test cases + testCases := []struct { + Name string + SearchQuery string + ExpectedResult int + }{ + { + Name: "FilterByCreateAction", + SearchQuery: "action:create", + ExpectedResult: 2, }, - }) - require.NoError(t, err) - require.Len(t, actionCreateLogs.AuditLogs, 2) - - // Verify the number of delete logs - actionDeleteLogs, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{ - SearchQuery: "action:delete", - Pagination: codersdk.Pagination{ - Limit: 25, + { + Name: "FilterByDeleteAction", + SearchQuery: "action:delete", + ExpectedResult: 1, }, - }) - - require.NoError(t, err) - require.Len(t, actionDeleteLogs.AuditLogs, 1) + { + Name: "FilterByUserResourceType", + SearchQuery: "resource_type:user", + ExpectedResult: 2, + }, + { + Name: "FilterByTemplateResourceType", + SearchQuery: "resource_type:template", + ExpectedResult: 1, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Name, func(t *testing.T) { + t.Parallel() + auditLogs, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{ + SearchQuery: testCase.SearchQuery, + Pagination: codersdk.Pagination{ + Limit: 25, + }, + }) + require.NoError(t, err, "fetch audit logs") + require.Len(t, auditLogs.AuditLogs, testCase.ExpectedResult, "expected audit logs returned") + }) + } }) }