From cd3f230eef267440a9dff404c4ecb4e1ce9850d1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 06:50:37 +0000 Subject: [PATCH 1/3] Initial plan From dd7fd66808083749bd076ec18fe0326f9d265547 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 06:59:40 +0000 Subject: [PATCH 2/3] Fix query search to ignore invalid types when at least 1 resource type applies Co-authored-by: moshloop <1489660+moshloop@users.noreply.github.com> Agent-Logs-Url: https://github.com/flanksource/duty/sessions/9f9b0658-96ce-44ab-be44-b62e8ba4f07c --- query/models.go | 13 +++++++++---- query/resource_selector.go | 7 +++++++ tests/query_resource_selector_test.go | 10 ++++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/query/models.go b/query/models.go index 669845aee..856064864 100644 --- a/query/models.go +++ b/query/models.go @@ -1,6 +1,7 @@ package query import ( + "errors" "fmt" "slices" "strconv" @@ -9,7 +10,7 @@ import ( "github.com/flanksource/commons/collections" "github.com/google/uuid" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/samber/lo" "github.com/timberio/go-datemath" "gorm.io/gorm" @@ -20,6 +21,10 @@ import ( "github.com/flanksource/duty/query/grammar" ) +// ErrColumnNotSupported is returned when a query references a column that does not exist on the target table. +// Callers can detect this sentinel and skip the resource type rather than propagating the error. +var ErrColumnNotSupported = errors.New("column not supported") + // Maintained by a job var allTypesCache atomic.Value @@ -469,14 +474,14 @@ func (qm QueryModel) Apply(ctx context.Context, q grammar.QueryField, tx *gorm.D if mapper, ok := CommonFields[q.Field]; ok { tx, err = mapper(ctx, tx, val) if err != nil { - return nil, nil, errors.Wrapf(err, "Invalid value for %s", q.Field) + return nil, nil, pkgerrors.Wrapf(err, "Invalid value for %s", q.Field) } } if mapper, ok := qm.Custom[q.Field]; ok { tx, err = mapper(ctx, tx, val) if err != nil { - return nil, nil, errors.Wrapf(err, "Invalid value for %s", q.Field) + return nil, nil, pkgerrors.Wrapf(err, "Invalid value for %s", q.Field) } } @@ -512,7 +517,7 @@ func (qm QueryModel) Apply(ctx context.Context, q grammar.QueryField, tx *gorm.D if !slices.Contains(ignoreFieldsForClauses, q.Field) { if !slices.Contains(qm.Columns, q.Field) { - return nil, nil, fmt.Errorf("query for column:%s in table:%s not supported", q.Field, qm.Table) + return nil, nil, fmt.Errorf("%w: query for column:%s in table:%s not supported", ErrColumnNotSupported, q.Field, qm.Table) } if q.Field == "type" { diff --git a/query/resource_selector.go b/query/resource_selector.go index bfd845fff..af4c5c1a0 100644 --- a/query/resource_selector.go +++ b/query/resource_selector.go @@ -1,6 +1,7 @@ package query import ( + "errors" "fmt" "slices" "sort" @@ -680,6 +681,9 @@ func queryTableWithResourceSelectors( for _, resourceSelector := range resourceSelectors { items, err := queryResourceSelector[uuid.UUID](ctx, limit, []string{"id"}, resourceSelector, table) if err != nil { + if errors.Is(err, ErrColumnNotSupported) { + continue + } return nil, err } @@ -705,6 +709,9 @@ func QueryTableColumnsWithResourceSelectors[T any]( for _, resourceSelector := range resourceSelectors { items, err := queryResourceSelector[T](ctx, limit, selectColumns, resourceSelector, table, clauses...) if err != nil { + if errors.Is(err, ErrColumnNotSupported) { + continue + } return nil, err } diff --git a/tests/query_resource_selector_test.go b/tests/query_resource_selector_test.go index 3c2750083..bc036b807 100644 --- a/tests/query_resource_selector_test.go +++ b/tests/query_resource_selector_test.go @@ -393,6 +393,16 @@ var _ = ginkgo.Describe("SearchResourceSelectors", func() { Checks: []models.Check{dummy.LogisticsAPIHealthHTTPCheck}, Configs: []models.ConfigItem{dummy.EKSCluster}, }, + { + // #canary #config type=pod — canaries don't have a "type" column so the canary query + // should be silently skipped (no results, no error) while configs still return results. + description: "ignore unsupported type filter for canaries when configs support it", + query: query.SearchResourcesRequest{ + Canaries: []types.ResourceSelector{{Search: "type=Kubernetes::Node"}}, + Configs: []types.ResourceSelector{{Search: "type=Kubernetes::Node"}}, + }, + Configs: []models.ConfigItem{dummy.KubernetesNodeA, dummy.KubernetesNodeB, dummy.KubernetesNodeAKSPool1}, + }, { description: "case insensitive | config by id", query: query.SearchResourcesRequest{ From 37e13bafe66df761c2aa3d4f637bc99ed976e2a6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 07:03:51 +0000 Subject: [PATCH 3/3] Fix error format to follow Go convention (wrap sentinel at end) Co-authored-by: moshloop <1489660+moshloop@users.noreply.github.com> Agent-Logs-Url: https://github.com/flanksource/duty/sessions/9f9b0658-96ce-44ab-be44-b62e8ba4f07c --- query/models.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query/models.go b/query/models.go index 856064864..8348cf6e5 100644 --- a/query/models.go +++ b/query/models.go @@ -517,7 +517,7 @@ func (qm QueryModel) Apply(ctx context.Context, q grammar.QueryField, tx *gorm.D if !slices.Contains(ignoreFieldsForClauses, q.Field) { if !slices.Contains(qm.Columns, q.Field) { - return nil, nil, fmt.Errorf("%w: query for column:%s in table:%s not supported", ErrColumnNotSupported, q.Field, qm.Table) + return nil, nil, fmt.Errorf("query for column:%s in table:%s not supported: %w", q.Field, qm.Table, ErrColumnNotSupported) } if q.Field == "type" {