HTTP Controller updates for label queries (#96)

Add controller methods for:

* Retrieving label queries
* Storing results of label queries
This commit is contained in:
Zachary Wasserman 2016-08-24 16:50:28 -07:00 committed by GitHub
parent 3f81dda638
commit 41fe404ef1
8 changed files with 584 additions and 24 deletions

View File

@ -202,6 +202,13 @@ func (orm gormDB) AuthenticateHost(nodeKey string) (*kolide.Host, error) {
return &host, nil
}
func (orm gormDB) SaveHost(host *kolide.Host) error {
if err := orm.DB.Save(host).Error; err != nil {
return errors.DatabaseError(err)
}
return nil
}
func (orm gormDB) MarkHostSeen(host *kolide.Host, t time.Time) error {
updateTime := time.Now()
err := orm.DB.Exec("UPDATE hosts SET updated_at=? WHERE node_key=?", t, host.NodeKey).Error

8
glide.lock generated
View File

@ -1,5 +1,5 @@
hash: 4ffa52b45a47295720fcf4dfcc0cc85c9f47a35a3bd43bdc6e0c2355bdd76109
updated: 2016-08-17T10:01:54.299187864-07:00
hash: 082be2432c000297d8d76bd1dc0f2be4e98954d0f49682603469e1b3056790f5
updated: 2016-08-24T14:33:02.991120417-07:00
imports:
- name: github.com/alecthomas/template
version: a0175ee3bccc567396460bf5acd36800cb10c49c
@ -32,6 +32,10 @@ imports:
- render
- name: github.com/go-sql-driver/mysql
version: 3654d25ec346ee8ce71a68431025458d52a38ac0
- name: github.com/golang/mock
version: bd3c8e81be01eef76d4b503f5e687d2d1354d2d9
subpackages:
- gomock
- name: github.com/golang/protobuf
version: c3cefd437628a0b7d31b34fe44b3a7a540e98527
subpackages:

View File

@ -76,3 +76,4 @@ import:
- package: github.com/spf13/viper
- package: gopkg.in/natefinch/lumberjack.v2
version: v2.0
- package: github.com/golang/mock

238
kolide/mock_osquery.go Normal file
View File

@ -0,0 +1,238 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: kolide/osquery.go
package kolide
import (
gomock "github.com/golang/mock/gomock"
time "time"
)
// Mock of OsqueryStore interface
type MockOsqueryStore struct {
ctrl *gomock.Controller
recorder *_MockOsqueryStoreRecorder
}
// Recorder for MockOsqueryStore (not exported)
type _MockOsqueryStoreRecorder struct {
mock *MockOsqueryStore
}
func NewMockOsqueryStore(ctrl *gomock.Controller) *MockOsqueryStore {
mock := &MockOsqueryStore{ctrl: ctrl}
mock.recorder = &_MockOsqueryStoreRecorder{mock}
return mock
}
func (_m *MockOsqueryStore) EXPECT() *_MockOsqueryStoreRecorder {
return _m.recorder
}
func (_m *MockOsqueryStore) EnrollHost(uuid string, hostname string, ip string, platform string, nodeKeySize int) (*Host, error) {
ret := _m.ctrl.Call(_m, "EnrollHost", uuid, hostname, ip, platform, nodeKeySize)
ret0, _ := ret[0].(*Host)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockOsqueryStoreRecorder) EnrollHost(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "EnrollHost", arg0, arg1, arg2, arg3, arg4)
}
func (_m *MockOsqueryStore) AuthenticateHost(nodeKey string) (*Host, error) {
ret := _m.ctrl.Call(_m, "AuthenticateHost", nodeKey)
ret0, _ := ret[0].(*Host)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockOsqueryStoreRecorder) AuthenticateHost(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "AuthenticateHost", arg0)
}
func (_m *MockOsqueryStore) SaveHost(host *Host) error {
ret := _m.ctrl.Call(_m, "SaveHost", host)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockOsqueryStoreRecorder) SaveHost(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "SaveHost", arg0)
}
func (_m *MockOsqueryStore) MarkHostSeen(host *Host, t time.Time) error {
ret := _m.ctrl.Call(_m, "MarkHostSeen", host, t)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockOsqueryStoreRecorder) MarkHostSeen(arg0, arg1 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "MarkHostSeen", arg0, arg1)
}
func (_m *MockOsqueryStore) LabelQueriesForHost(host *Host, cutoff time.Time) (map[string]string, error) {
ret := _m.ctrl.Call(_m, "LabelQueriesForHost", host, cutoff)
ret0, _ := ret[0].(map[string]string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockOsqueryStoreRecorder) LabelQueriesForHost(arg0, arg1 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "LabelQueriesForHost", arg0, arg1)
}
func (_m *MockOsqueryStore) RecordLabelQueryExecutions(host *Host, results map[string]bool, t time.Time) error {
ret := _m.ctrl.Call(_m, "RecordLabelQueryExecutions", host, results, t)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockOsqueryStoreRecorder) RecordLabelQueryExecutions(arg0, arg1, arg2 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "RecordLabelQueryExecutions", arg0, arg1, arg2)
}
func (_m *MockOsqueryStore) NewQuery(query *Query) error {
ret := _m.ctrl.Call(_m, "NewQuery", query)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockOsqueryStoreRecorder) NewQuery(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "NewQuery", arg0)
}
func (_m *MockOsqueryStore) SaveQuery(query *Query) error {
ret := _m.ctrl.Call(_m, "SaveQuery", query)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockOsqueryStoreRecorder) SaveQuery(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "SaveQuery", arg0)
}
func (_m *MockOsqueryStore) DeleteQuery(query *Query) error {
ret := _m.ctrl.Call(_m, "DeleteQuery", query)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockOsqueryStoreRecorder) DeleteQuery(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "DeleteQuery", arg0)
}
func (_m *MockOsqueryStore) Query(id uint) (*Query, error) {
ret := _m.ctrl.Call(_m, "Query", id)
ret0, _ := ret[0].(*Query)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockOsqueryStoreRecorder) Query(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Query", arg0)
}
func (_m *MockOsqueryStore) Queries() ([]*Query, error) {
ret := _m.ctrl.Call(_m, "Queries")
ret0, _ := ret[0].([]*Query)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockOsqueryStoreRecorder) Queries() *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Queries")
}
func (_m *MockOsqueryStore) NewLabel(label *Label) error {
ret := _m.ctrl.Call(_m, "NewLabel", label)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockOsqueryStoreRecorder) NewLabel(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "NewLabel", arg0)
}
func (_m *MockOsqueryStore) NewPack(pack *Pack) error {
ret := _m.ctrl.Call(_m, "NewPack", pack)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockOsqueryStoreRecorder) NewPack(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "NewPack", arg0)
}
func (_m *MockOsqueryStore) SavePack(pack *Pack) error {
ret := _m.ctrl.Call(_m, "SavePack", pack)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockOsqueryStoreRecorder) SavePack(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "SavePack", arg0)
}
func (_m *MockOsqueryStore) DeletePack(pack *Pack) error {
ret := _m.ctrl.Call(_m, "DeletePack", pack)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockOsqueryStoreRecorder) DeletePack(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "DeletePack", arg0)
}
func (_m *MockOsqueryStore) Pack(id uint) (*Pack, error) {
ret := _m.ctrl.Call(_m, "Pack", id)
ret0, _ := ret[0].(*Pack)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockOsqueryStoreRecorder) Pack(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Pack", arg0)
}
func (_m *MockOsqueryStore) Packs() ([]*Pack, error) {
ret := _m.ctrl.Call(_m, "Packs")
ret0, _ := ret[0].([]*Pack)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockOsqueryStoreRecorder) Packs() *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Packs")
}
func (_m *MockOsqueryStore) AddQueryToPack(query *Query, pack *Pack) error {
ret := _m.ctrl.Call(_m, "AddQueryToPack", query, pack)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockOsqueryStoreRecorder) AddQueryToPack(arg0, arg1 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "AddQueryToPack", arg0, arg1)
}
func (_m *MockOsqueryStore) GetQueriesInPack(pack *Pack) ([]*Query, error) {
ret := _m.ctrl.Call(_m, "GetQueriesInPack", pack)
ret0, _ := ret[0].([]*Query)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockOsqueryStoreRecorder) GetQueriesInPack(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "GetQueriesInPack", arg0)
}
func (_m *MockOsqueryStore) RemoveQueryFromPack(query *Query, pack *Pack) error {
ret := _m.ctrl.Call(_m, "RemoveQueryFromPack", query, pack)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockOsqueryStoreRecorder) RemoveQueryFromPack(arg0, arg1 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "RemoveQueryFromPack", arg0, arg1)
}

View File

@ -7,6 +7,7 @@ type OsqueryStore interface {
// Host methods
EnrollHost(uuid, hostname, ip, platform string, nodeKeySize int) (*Host, error)
AuthenticateHost(nodeKey string) (*Host, error)
SaveHost(host *Host) error
MarkHostSeen(host *Host, t time.Time) error
LabelQueriesForHost(host *Host, cutoff time.Time) (map[string]string, error)
RecordLabelQueryExecutions(host *Host, results map[string]bool, t time.Time) error

View File

@ -32,8 +32,9 @@ type OsqueryStatusHandler interface {
// It can be configured in a `main` function to bind the appropriate handlers
// and it's methods can be attached to routes.
type OsqueryHandler struct {
ResultHandler OsqueryResultHandler
StatusHandler OsqueryStatusHandler
LabelQueryInterval time.Duration
ResultHandler OsqueryResultHandler
StatusHandler OsqueryStatusHandler
}
// Basic implementation of the `OsqueryResultHandler` and
@ -64,8 +65,27 @@ type OsqueryEnrollPostBody struct {
HostIdentifier string `json:"host_identifier" validate:"required"`
}
// OsqueryConfigPostBody is the generic osquery config endpoint request body
// structure. Typically the node key and action will be parsed, and then the
// Data JSON will be unmarshalled into one of the more specific OsqueryConfig*
// structs.
type OsqueryConfigPostBody struct {
NodeKey string `json:"node_key" validate:"required"`
NodeKey string `json:"node_key" validate:"required"`
Action string `json:"action" validate:"required"`
Data *json.RawMessage `json:"data" validate:"required"`
}
// OsqueryConfigDetail is the expected extra information provided with an
// initial config request. This data will be used to determine which label
// queries are supplied to the host.
type OsqueryConfigDetail struct {
Platform string `json:"platform" validate:"required"`
}
// OsqueryConfigQueryResults contains the final information needed to generate a
// config for the host. It containst the results of the label queries.
type OsqueryConfigQueryResults struct {
Results map[string]bool `json:"results" validate:"required"`
}
type OsqueryLogPostBody struct {
@ -141,31 +161,94 @@ func OsqueryEnroll(c *gin.Context) {
})
}
func OsqueryConfig(c *gin.Context) {
func (h *OsqueryHandler) handleConfigDetail(db kolide.OsqueryStore, host *kolide.Host, data json.RawMessage) (map[string]string, error) {
var detail OsqueryConfigDetail
if err := json.Unmarshal(data, &detail); err != nil {
return nil, errors.NewFromError(err, http.StatusBadRequest, "JSON parse error")
}
if err := validateStruct(&detail); err != nil {
return nil, err
}
// Update fields from detail (only save if there are changes)
if host.Platform != detail.Platform {
host.Platform = detail.Platform
if err := db.SaveHost(host); err != nil {
return nil, err
}
}
return kolide.LabelQueriesForHost(db, host, h.LabelQueryInterval)
}
func (h *OsqueryHandler) handleConfigQueryResults(db kolide.OsqueryStore, host *kolide.Host, data json.RawMessage) error {
var results OsqueryConfigQueryResults
if err := json.Unmarshal(data, &results); err != nil {
return errors.NewFromError(err, http.StatusBadRequest, "JSON parse error")
}
if err := validateStruct(&results); err != nil {
return err
}
return db.RecordLabelQueryExecutions(host, results.Results, time.Now())
}
// Endpoint used by the osqueryd TLS logger plugin
func (h *OsqueryHandler) OsqueryConfig(c *gin.Context) {
var body OsqueryConfigPostBody
err := ParseAndValidateJSON(c, &body)
if err != nil {
errors.ReturnOsqueryError(c, err)
return
}
logrus.Debugf("OsqueryConfig: %s", body.NodeKey)
c.JSON(http.StatusOK,
gin.H{
"schedule": map[string]map[string]interface{}{
"time": {
"query": "select * from time;",
"interval": 1,
},
},
"node_invalid": false,
})
db := GetDB(c)
host, err := db.AuthenticateHost(body.NodeKey)
if err != nil {
errors.ReturnOsqueryError(c, err)
return
}
if body.Data == nil {
errors.ReturnOsqueryError(c,
errors.New("Missing body data", "Got nil pointer for data in config"),
)
}
var res map[string]string
switch body.Action {
case "request":
res, err = h.handleConfigDetail(db, host, *body.Data)
if err != nil {
c.JSON(http.StatusOK, res)
return
}
case "results":
err = h.handleConfigQueryResults(db, host, *body.Data)
// Now we should be able to calculate the appropriate config
default:
err = errors.NewWithStatus(
errors.StatusUnprocessableEntity,
"Unknown config request action",
fmt.Sprintf("Unknown config request action: %s", body.Action),
)
}
if err != nil {
errors.ReturnOsqueryError(c, err)
return
}
// TODO: Generate the config and return it here!
}
// Unmarshal the status logs before sending them to the status log handler
func (h *OsqueryHandler) handleStatusLogs(data *json.RawMessage, nodeKey string) error {
func (h *OsqueryHandler) handleStatusLogs(data json.RawMessage, nodeKey string) error {
var statuses []OsqueryStatusLog
if err := json.Unmarshal(*data, &statuses); err != nil {
if err := json.Unmarshal(data, &statuses); err != nil {
return errors.NewFromError(err, http.StatusBadRequest, "JSON parse error")
}
// Perhaps we should validate the unmarshalled status log
@ -181,9 +264,9 @@ func (h *OsqueryHandler) handleStatusLogs(data *json.RawMessage, nodeKey string)
}
// Unmarshal the result logs before sending them to the result log handler
func (h *OsqueryHandler) handleResultLogs(data *json.RawMessage, nodeKey string) error {
func (h *OsqueryHandler) handleResultLogs(data json.RawMessage, nodeKey string) error {
var results []OsqueryResultLog
if err := json.Unmarshal(*data, &results); err != nil {
if err := json.Unmarshal(data, &results); err != nil {
return errors.NewFromError(err, http.StatusBadRequest, "JSON parse error")
}
// Perhaps we should validate the unmarshalled result log
@ -215,12 +298,18 @@ func (h *OsqueryHandler) OsqueryLog(c *gin.Context) {
return
}
if body.Data == nil {
errors.ReturnOsqueryError(c,
errors.New("Missing body data", "Got nil pointer for data in log"),
)
}
switch body.LogType {
case "status":
err = h.handleStatusLogs(body.Data, body.NodeKey)
err = h.handleStatusLogs(*body.Data, body.NodeKey)
case "result":
err = h.handleResultLogs(body.Data, body.NodeKey)
err = h.handleResultLogs(*body.Data, body.NodeKey)
default:
err = errors.NewWithStatus(

View File

@ -5,7 +5,10 @@ import (
"fmt"
"net/http"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/kolide/kolide-ose/errors"
"github.com/kolide/kolide-ose/kolide"
"github.com/stretchr/testify/assert"
)
@ -842,3 +845,216 @@ func TestDeleteQueryFromPack(t *testing.T) {
assert.Nil(t, err)
assert.Len(t, p.Queries, len(queriesInPack)-1)
}
func TestHandleConfigDetail(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
db := kolide.NewMockOsqueryStore(ctrl)
detail := OsqueryConfigDetail{Platform: "darwin"}
detailBytes, err := json.Marshal(detail)
assert.NoError(t, err)
detailJSON := json.RawMessage(detailBytes)
host := &kolide.Host{
NodeKey: "fake_key",
}
expectHost := &kolide.Host{
NodeKey: "fake_key",
Platform: "darwin",
}
handler := OsqueryHandler{
LabelQueryInterval: time.Minute,
}
expectQueries := map[string]string{
"1": "query1",
"3": "query3",
}
db.EXPECT().SaveHost(expectHost)
db.EXPECT().LabelQueriesForHost(expectHost, gomock.Any()).
Return(expectQueries, nil).
Do(func(_ *kolide.Host, cutoff time.Time) {
// Check that the cutoff is in the correct interval
expectCutoff := time.Now().Add(-handler.LabelQueryInterval)
allowedDelta := 5 * time.Second
assert.WithinDuration(t, expectCutoff, cutoff, allowedDelta)
})
res, err := handler.handleConfigDetail(db, host, detailJSON)
assert.NoError(t, err)
assert.Equal(t, expectQueries, res)
}
func TestHandleConfigDetailNoSave(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
db := kolide.NewMockOsqueryStore(ctrl)
detail := OsqueryConfigDetail{Platform: "darwin"}
detailBytes, err := json.Marshal(detail)
assert.NoError(t, err)
detailJSON := json.RawMessage(detailBytes)
host := &kolide.Host{
NodeKey: "fake_key",
Platform: "darwin",
}
expectHost := &kolide.Host{
NodeKey: "fake_key",
Platform: "darwin",
}
handler := OsqueryHandler{
LabelQueryInterval: time.Hour,
}
expectQueries := map[string]string{}
// Note that we don't expect a call to save because the platform did
// not change
db.EXPECT().LabelQueriesForHost(expectHost, gomock.Any()).
Return(expectQueries, nil).
Do(func(_ *kolide.Host, cutoff time.Time) {
// Check that the cutoff is in the correct interval
expectCutoff := time.Now().Add(-handler.LabelQueryInterval)
allowedDelta := 5 * time.Second
assert.WithinDuration(t, expectCutoff, cutoff, allowedDelta)
})
res, err := handler.handleConfigDetail(db, host, detailJSON)
assert.NoError(t, err)
assert.Equal(t, expectQueries, res)
}
func marshalRawMessage(t *testing.T, obj interface{}) json.RawMessage {
objBytes, err := json.Marshal(obj)
assert.NoError(t, err)
objJSON := json.RawMessage(objBytes)
return objJSON
}
func TestHandleConfigDetailError(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
db := kolide.NewMockOsqueryStore(ctrl)
detail := OsqueryConfigDetail{Platform: "darwin"}
detailBytes, err := json.Marshal(detail)
assert.NoError(t, err)
detailJSON := json.RawMessage(detailBytes)
host := &kolide.Host{
NodeKey: "fake_key",
Platform: "darwin",
}
expectHost := &kolide.Host{
NodeKey: "fake_key",
Platform: "darwin",
}
handler := OsqueryHandler{
LabelQueryInterval: time.Hour,
}
// The DB call should error in this test
db.EXPECT().LabelQueriesForHost(expectHost, gomock.Any()).
Return(nil, errors.New("public", "private")).
Do(func(_ *kolide.Host, cutoff time.Time) {
// Check that the cutoff is in the correct interval
expectCutoff := time.Now().Add(-handler.LabelQueryInterval)
allowedDelta := 5 * time.Second
assert.WithinDuration(t, expectCutoff, cutoff, allowedDelta)
})
res, err := handler.handleConfigDetail(db, host, detailJSON)
assert.Error(t, err)
assert.Nil(t, res)
}
func TestHandleConfigQueryResults(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
db := kolide.NewMockOsqueryStore(ctrl)
results := OsqueryConfigQueryResults{
Results: map[string]bool{
"1": true,
"3": false,
"4": true,
},
}
resultsJSON := marshalRawMessage(t, results)
host := &kolide.Host{
NodeKey: "fake_key",
Platform: "darwin",
}
handler := OsqueryHandler{
LabelQueryInterval: time.Hour,
}
db.EXPECT().RecordLabelQueryExecutions(host, results.Results, gomock.Any()).
Return(nil).
Do(func(_ *kolide.Host, _ map[string]bool, recordTime time.Time) {
// Check that the cutoff is in the correct interval
allowedDelta := 5 * time.Second
assert.WithinDuration(t, time.Now(), recordTime, allowedDelta)
})
assert.NoError(t, handler.handleConfigQueryResults(db, host, resultsJSON))
}
func TestHandleConfigQueryResultsError(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
db := kolide.NewMockOsqueryStore(ctrl)
results := OsqueryConfigQueryResults{
Results: map[string]bool{
"1": true,
"3": false,
"4": true,
},
}
resultsJSON := marshalRawMessage(t, results)
host := &kolide.Host{
NodeKey: "fake_key",
Platform: "darwin",
}
handler := OsqueryHandler{
LabelQueryInterval: time.Hour,
}
// DB errors this time
db.EXPECT().RecordLabelQueryExecutions(host, results.Results, gomock.Any()).
Return(errors.New("public", "private")).
Do(func(_ *kolide.Host, _ map[string]bool, recordTime time.Time) {
// Check that the cutoff is in the correct interval
allowedDelta := 5 * time.Second
assert.WithinDuration(t, time.Now(), recordTime, allowedDelta)
})
assert.Error(t, handler.handleConfigQueryResults(db, host, resultsJSON))
}

View File

@ -100,6 +100,10 @@ func ParseAndValidateJSON(c *gin.Context, obj interface{}) error {
return err
}
return validateStruct(obj)
}
func validateStruct(obj interface{}) error {
return validate.Struct(obj)
}
@ -209,7 +213,7 @@ func CreateServer(ds datastore.Datastore, pool kolide.SMTPConnectionPool, w io.W
}
osq.POST("/enroll", OsqueryEnroll)
osq.POST("/config", OsqueryConfig)
osq.POST("/config", osqueryHandler.OsqueryConfig)
osq.POST("/log", osqueryHandler.OsqueryLog)
osq.POST("/distributed/read", OsqueryDistributedRead)
osq.POST("/distributed/write", OsqueryDistributedWrite)