Skip to content

Commit

Permalink
Merge pull request #132 from grendel-consulting/fix-person-open-issue…
Browse files Browse the repository at this point in the history
…s-unmarshalling

fix: ensure person open issues is unmarshalled
  • Loading branch information
ramirezj committed May 8, 2024
2 parents d6d61bd + f77210f commit e07d4ba
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 6 deletions.
10 changes: 8 additions & 2 deletions kolide/table_kolide_person_open_issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func tableKolidePersonOpenIssue(_ context.Context) *plugin.Table {
Description: "Unresolved and non-exempt issues created when a device owned by a specific person fails a check; some checks, when they fail, will produce multiple Issues, each with a unique primary_key_value.",
Columns: []*plugin.Column{
// Filterable "top" columns
{Name: "person_id", Description: "Canonical identifier for the person whose device this issue relates to.", Type: proto.ColumnType_STRING},
{Name: "person_id", Description: "Canonical identifier for the person whose device this issue relates to.", Type: proto.ColumnType_STRING, Transform: transform.FromQual("person_id")},
{Name: "issue_key", Description: "Primary key that distinguishes one issue from another in the context of a single check; only applicable for checks that can produce multiple issues.", Type: proto.ColumnType_STRING},
{Name: "issue_value", Description: "Primary identifying value that distinguishes one issue from another in the context of a single check; only applicable for checks that can produce multiple issues.", Type: proto.ColumnType_STRING},
{Name: "title", Description: "Descriptive title for this issue.", Type: proto.ColumnType_STRING},
Expand Down Expand Up @@ -61,5 +61,11 @@ func listIssuesByPerson(ctx context.Context, d *plugin.QueryData, h *plugin.Hydr
return client.GetIssuesByPerson(id, cursor, limit, searches...)
}

return listAnythingById(ctx, d, h, "kolide_person_open_issue.listIssuesByPerson", "person_id", visitor, "Issues")
// Because the Kolide K2 API uses 'person_id' as a path parameter but does not, in this endpoint, return the value
// or support it as a searchable field AND because Steampipe requires it be specified as a KeyColumn in order to
// require it to be present in the SQL WHERE clause, we need to ensure it is removed from the search terms to be
// serialised by the Kolide client; otherwise it returns a 'HTTP 422 Unprocessable Entity'
var exclude = "person_id"

return listAnythingById(ctx, d, h, "kolide_person_open_issue.listIssuesByPerson", "person_id", visitor, "Issues", exclude)
}
15 changes: 11 additions & 4 deletions kolide/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"os"
"reflect"
"slices"

kolide "github.com/grendel-consulting/steampipe-plugin-kolide/kolide/client"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
Expand Down Expand Up @@ -129,14 +130,15 @@ func getAnything(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData

}

func listAnythingById(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData, callee string, id string, visitor ListByIdPredicate, target string) (interface{}, error) {
func listAnythingById(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData, callee string, id string, visitor ListByIdPredicate, target string, unfriendlies ...string) (interface{}, error) {
// Fail early if unique identifier is not present
uid := d.EqualsQualString(id)

if uid == "" {
return nil, nil
}
// Create a slice to hold search queries
searches, err := query(ctx, d)
searches, err := query(ctx, d, unfriendlies...)
if err != nil {
plugin.Logger(ctx).Error(callee, "qualifier_operator_error", err)
return nil, err
Expand Down Expand Up @@ -196,7 +198,7 @@ func listAnythingById(ctx context.Context, d *plugin.QueryData, _ *plugin.Hydrat
return nil, nil
}

func query(_ context.Context, d *plugin.QueryData) ([]kolide.Search, error) {
func query(_ context.Context, d *plugin.QueryData, unfriendlies ...string) ([]kolide.Search, error) {
// Create a slice to hold search queries
searches := make([]kolide.Search, 0)

Expand All @@ -207,7 +209,12 @@ func query(_ context.Context, d *plugin.QueryData) ([]kolide.Search, error) {
if err != nil {
return nil, err
}
searches = append(searches, search)

// Exclude this item if it is not a searchable field
if !slices.Contains(unfriendlies, item.Name) {
searches = append(searches, search)
}

}
}

Expand Down
9 changes: 9 additions & 0 deletions test/end-to-end/_query/kolide_unprocessable_entity.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
select
title,
person_id
from
kolide_person_open_issue
where
person_id = '1607'
order by
detected_at asc;
11 changes: 11 additions & 0 deletions test/end-to-end/_results/kolide_unprocessable_entity.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash

define_test_results(){
# Unexpected behaviour in Kolide API under K2; this endpoint returns an empty list
export EXPECTED_COUNT="0"
# export TITLE=""
# export DETECTED_AT=""
# export BLOCKS_DEVICE_AT=""
# export RESOLVED_AT=""
# export EXEMPTED=""
}
54 changes: 54 additions & 0 deletions test/end-to-end/kolide_unprocessable_entity.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# bats file_tags=table:kolide_person_open_issue, output:issue

setup_file() {
load "${BATS_TEST_DIRNAME}/_support/globals.bash"
define_file_globals

define_common_test_results

if [[ -f $EXPECTED_RESULTS ]]; then
load $EXPECTED_RESULTS
fi
}

setup() {
load "${BATS_TEST_DIRNAME}/_support/extensions.bash"
load_helpers
}

# Regression test for https://github.com/grendel-consulting/steampipe-plugin-kolide/issues/129
#bats test_tags=scope:regression
@test "can_execute_query_via_steampipe" {
steampipe query $QUERY_UNDER_TEST --output json > $QUERY_RESULTS
assert_exists $QUERY_RESULTS
}

@test "has_expected_number_of_results" {
if [[ ! -e $QUERY_RESULTS ]]; then skip ; fi

run bash -c "cat $QUERY_RESULTS | jq -r '. | length'"

if [[ -z "$EXPECTED_COUNT" ]]; then assert_output $EXPECTED_COUNT ; else assert [ "$output" -ge "1" ] ; fi
}

#bats test_tags=exactness:fuzzy
@test "has_expected_title" {
if [[ ! -e $QUERY_RESULTS ]]; then skip ; fi

run bash -c "cat $QUERY_RESULTS | jq -r '.[0].title'"
if [[ -z "$TITLE" ]]; then assert_output --partial $TITLE ; else assert_success ; fi
}

#bats test_tags=exactness:fuzzy
@test "has_expected_person_id" {
if [[ ! -e $QUERY_RESULTS ]]; then skip ; fi

run bash -c "cat $QUERY_RESULTS | jq -r '.[0].detected_at'"
if [[ -z "$DETECTED_AT" ]]; then assert_output --partial $DETECTED_AT ; else assert_success ; fi
}

teardown_file(){
if [[ -f $QUERY_RESULTS ]]; then
rm -f $QUERY_RESULTS
fi
}

0 comments on commit e07d4ba

Please sign in to comment.