Skip to content

feat: Guard search queries against common mistakes #6404

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Mar 2, 2023
Merged
Prev Previous commit
Next Next commit
PR comments
  • Loading branch information
Emyrk committed Mar 1, 2023
commit d6ba71bc62ab7ba852434723e860709aeeb08d5e
2 changes: 1 addition & 1 deletion coderd/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (api *API) auditLogs(rw http.ResponseWriter, r *http.Request) {
}

queryStr := r.URL.Query().Get("q")
filter, errs := searchquery.Audit(queryStr)
filter, errs := searchquery.AuditLogs(queryStr)
if len(errs) > 0 {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Invalid audit search query.",
Expand Down
4 changes: 2 additions & 2 deletions coderd/searchquery/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/coder/coder/codersdk"
)

func Audit(query string) (database.GetAuditLogsOffsetParams, []codersdk.ValidationError) {
func AuditLogs(query string) (database.GetAuditLogsOffsetParams, []codersdk.ValidationError) {
// Always lowercase for all searches.
query = strings.ToLower(query)
values, errors := searchTerms(query, func(term string, values url.Values) error {
Expand Down Expand Up @@ -63,7 +63,7 @@ func Users(query string) (database.GetUsersParams, []codersdk.ValidationError) {
return filter, parser.Errors
}

func Workspace(query string, page codersdk.Pagination, agentInactiveDisconnectTimeout time.Duration) (database.GetWorkspacesParams, []codersdk.ValidationError) {
func Workspaces(query string, page codersdk.Pagination, agentInactiveDisconnectTimeout time.Duration) (database.GetWorkspacesParams, []codersdk.ValidationError) {
filter := database.GetWorkspacesParams{
AgentInactiveDisconnectTimeoutSeconds: int64(agentInactiveDisconnectTimeout.Seconds()),

Expand Down
23 changes: 9 additions & 14 deletions coderd/searchquery/search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func TestSearchWorkspace(t *testing.T) {
c := c
t.Run(c.Name, func(t *testing.T) {
t.Parallel()
values, errs := searchquery.Workspace(c.Query, codersdk.Pagination{}, 0)
values, errs := searchquery.Workspaces(c.Query, codersdk.Pagination{}, 0)
if c.ExpectedErrorContains != "" {
require.True(t, len(errs) > 0, "expect some errors")
var s strings.Builder
Expand All @@ -162,7 +162,7 @@ func TestSearchWorkspace(t *testing.T) {

query := ``
timeout := 1337 * time.Second
values, errs := searchquery.Workspace(query, codersdk.Pagination{}, timeout)
values, errs := searchquery.Workspaces(query, codersdk.Pagination{}, timeout)
require.Empty(t, errs)
require.Equal(t, int64(timeout.Seconds()), values.AgentInactiveDisconnectTimeoutSeconds)
})
Expand Down Expand Up @@ -203,7 +203,7 @@ func TestSearchAudit(t *testing.T) {
c := c
t.Run(c.Name, func(t *testing.T) {
t.Parallel()
values, errs := searchquery.Audit(c.Query)
values, errs := searchquery.AuditLogs(c.Query)
if c.ExpectedErrorContains != "" {
require.True(t, len(errs) > 0, "expect some errors")
var s strings.Builder
Expand All @@ -228,9 +228,12 @@ func TestSearchUsers(t *testing.T) {
ExpectedErrorContains string
}{
{
Name: "Empty",
Query: "",
Expected: database.GetUsersParams{},
Name: "Empty",
Query: "",
Expected: database.GetUsersParams{
Status: []database.UserStatus{},
RbacRole: []string{},
},
},
{
Name: "Username",
Expand Down Expand Up @@ -320,14 +323,6 @@ func TestSearchUsers(t *testing.T) {
t.Run(c.Name, func(t *testing.T) {
t.Parallel()
values, errs := searchquery.Users(c.Query)
if c.Expected.Status == nil {
// This is a workaround for the fact that nil != len(0)
c.Expected.Status = []database.UserStatus{}
}
if c.Expected.RbacRole == nil {
// This is a workaround for the fact that nil != len(0)
c.Expected.RbacRole = []string{}
}
if c.ExpectedErrorContains != "" {
require.True(t, len(errs) > 0, "expect some errors")
var s strings.Builder
Expand Down
2 changes: 1 addition & 1 deletion coderd/workspaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (api *API) workspaces(rw http.ResponseWriter, r *http.Request) {
}

queryStr := r.URL.Query().Get("q")
filter, errs := searchquery.Workspace(queryStr, page, api.AgentInactiveDisconnectTimeout)
filter, errs := searchquery.Workspaces(queryStr, page, api.AgentInactiveDisconnectTimeout)
if len(errs) > 0 {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Invalid workspace search query.",
Expand Down
12 changes: 3 additions & 9 deletions site/src/components/SearchBarWithFilter/SearchBarWithFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { useCallback, useRef, useState } from "react"
import { getValidationErrorMessage } from "../../api/errors"
import { CloseDropdown, OpenDropdown } from "../DropdownArrows/DropdownArrows"
import { Stack } from "../Stack/Stack"
import { combineClasses } from "../../util/combineClasses"
import { combineClasses } from "util/combineClasses"

export const Language = {
filterName: "Filters",
Expand Down Expand Up @@ -145,11 +145,7 @@ export const SearchBarWithFilter: React.FC<
) : null}
</Stack>
{errorMessage && (
<Stack
className={combineClasses([styles.errorRoot, styles.newlineStyle])}
>
{errorMessage}
</Stack>
<Stack className={styles.errorRoot}>{errorMessage}</Stack>
)}
</Stack>
)
Expand Down Expand Up @@ -181,6 +177,7 @@ const useStyles = makeStyles<Theme, StyleProps>((theme) => ({
},
errorRoot: {
color: theme.palette.error.main,
whiteSpace: "pre-wrap",
},
inputStyles: {
height: "100%",
Expand All @@ -205,7 +202,4 @@ const useStyles = makeStyles<Theme, StyleProps>((theme) => ({
searchIcon: {
color: theme.palette.text.secondary,
},
newlineStyle: {
whiteSpace: "pre-wrap",
},
}))