Skip to content

Commit

Permalink
Add /zta endpoint to localserver
Browse files Browse the repository at this point in the history
  • Loading branch information
RebeccaMahany committed Feb 7, 2025
1 parent 0288928 commit 2663366
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 0 deletions.
3 changes: 3 additions & 0 deletions ee/localserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ func New(ctx context.Context, k types.Knapsack, presenceDetector presenceDetecto
// /v0/cmd left for transition period
mux.Handle("/v1/cmd", ecKryptoMiddleware.Wrap(ecAuthedMux))

// In the future, we will want to make this authenticated; for now, it is not authenticated.
mux.Handle("/zta", ls.requestZtaInfoHandler())

// uncomment to test without going through middleware
// for example:
// curl localhost:40978/query --data '{"query":"select * from kolide_launcher_info"}'
Expand Down
46 changes: 46 additions & 0 deletions ee/localserver/zta.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package localserver

import (
"log/slog"
"net/http"

"github.com/kolide/launcher/pkg/traces"
)

var (
localserverZtaInfoKey = []byte("localserver_zta_info")
)

func (ls *localServer) requestZtaInfoHandler() http.Handler {
return http.HandlerFunc(ls.requestZtaInfoHandlerFunc)
}

func (ls *localServer) requestZtaInfoHandlerFunc(w http.ResponseWriter, r *http.Request) {
r, span := traces.StartHttpRequestSpan(r, "path", r.URL.Path)
defer span.End()

if r.Method != http.MethodGet {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}

ztaInfo, err := ls.knapsack.ZtaInfoStore().Get(localserverZtaInfoKey)
if err != nil {
traces.SetError(span, err)
ls.slogger.Log(r.Context(), slog.LevelError,
"could not retrieve ZTA info from store",
"err", err,
)

w.WriteHeader(http.StatusInternalServerError)
return
}
// No data stored yet
if len(ztaInfo) == 0 {
w.WriteHeader(http.StatusNotFound)
return
}

w.Header().Set("Content-Type", "application/json")
w.Write(ztaInfo)
}
150 changes: 150 additions & 0 deletions ee/localserver/zta_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package localserver

import (
"context"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"testing"

"github.com/kolide/launcher/ee/agent/storage"
storageci "github.com/kolide/launcher/ee/agent/storage/ci"
typesmocks "github.com/kolide/launcher/ee/agent/types/mocks"
"github.com/kolide/launcher/pkg/log/multislogger"
"github.com/kolide/launcher/pkg/osquery"
"github.com/stretchr/testify/require"
)

func Test_requestZtaInfoHandler(t *testing.T) {
t.Parallel()

// Set up our ZTA store with some test data in it
slogger := multislogger.NewNopLogger()
ztaInfoStore, err := storageci.NewStore(t, slogger, storage.ZtaInfoStore.String())
require.NoError(t, err)
testZtaInfo, err := json.Marshal(map[string]string{
"some_test_data": "some_test_value",
})
require.NoError(t, err)
require.NoError(t, ztaInfoStore.Set(localserverZtaInfoKey, testZtaInfo))

// Set up the rest of our localserver dependencies
configStore, err := storageci.NewStore(t, slogger, storage.ConfigStore.String())
require.NoError(t, err)
require.NoError(t, osquery.SetupLauncherKeys(configStore))
k := typesmocks.NewKnapsack(t)
k.On("KolideServerURL").Return("localserver")
k.On("ConfigStore").Return(configStore)
k.On("Slogger").Return(slogger)
k.On("ZtaInfoStore").Return(ztaInfoStore)

// Set up localserver
ls, err := New(context.TODO(), k, nil)
require.NoError(t, err)

// Make a request to our handler
request := httptest.NewRequest(http.MethodGet, "/zta", nil)
responseRecorder := httptest.NewRecorder()
ls.requestZtaInfoHandler().ServeHTTP(responseRecorder, request)

// Make sure response was successful and contains the data we expect
require.Equal(t, http.StatusOK, responseRecorder.Code)
require.Equal(t, "application/json", responseRecorder.Header().Get("Content-Type"))
require.Equal(t, testZtaInfo, responseRecorder.Body.Bytes())

k.AssertExpectations(t)
}

func Test_requestZtaInfoHandler_badRequest(t *testing.T) {
t.Parallel()

for _, tt := range []struct {
testCaseName string
httpMethod string
requestBody io.Reader
}{
{
testCaseName: http.MethodPost,
httpMethod: http.MethodPost,
requestBody: http.NoBody,
},
{
testCaseName: http.MethodPut,
httpMethod: http.MethodPut,
requestBody: http.NoBody,
},
{
testCaseName: http.MethodPatch,
httpMethod: http.MethodPatch,
requestBody: http.NoBody,
},
{
testCaseName: http.MethodDelete,
httpMethod: http.MethodDelete,
requestBody: http.NoBody,
},
} {
tt := tt
t.Run(tt.testCaseName, func(t *testing.T) {
t.Parallel()

// Set up our localserver dependencies
slogger := multislogger.NewNopLogger()
configStore, err := storageci.NewStore(t, slogger, storage.ConfigStore.String())
require.NoError(t, err)
require.NoError(t, osquery.SetupLauncherKeys(configStore))
k := typesmocks.NewKnapsack(t)
k.On("KolideServerURL").Return("localserver")
k.On("ConfigStore").Return(configStore)
k.On("Slogger").Return(slogger)

// Set up localserver
ls, err := New(context.TODO(), k, nil)
require.NoError(t, err)

// Make a request to our handler
request := httptest.NewRequest(tt.httpMethod, "/zta", tt.requestBody)
responseRecorder := httptest.NewRecorder()
ls.requestZtaInfoHandler().ServeHTTP(responseRecorder, request)

// Make sure we got back a 405
require.Equal(t, http.StatusMethodNotAllowed, responseRecorder.Code)

k.AssertExpectations(t)
})
}
}

func Test_requestZtaInfoHandler_noDataAvailable(t *testing.T) {
t.Parallel()

// Set up our ZTA store, but do not store any data in it under the `localserverZtaInfoKey` key
slogger := multislogger.NewNopLogger()
ztaInfoStore, err := storageci.NewStore(t, slogger, storage.ZtaInfoStore.String())
require.NoError(t, err)

// Set up the rest of our localserver dependencies
configStore, err := storageci.NewStore(t, slogger, storage.ConfigStore.String())
require.NoError(t, err)
require.NoError(t, osquery.SetupLauncherKeys(configStore))
k := typesmocks.NewKnapsack(t)
k.On("KolideServerURL").Return("localserver")
k.On("ConfigStore").Return(configStore)
k.On("Slogger").Return(slogger)
k.On("ZtaInfoStore").Return(ztaInfoStore)

// Set up localserver
ls, err := New(context.TODO(), k, nil)
require.NoError(t, err)

// Make a request to our handler
request := httptest.NewRequest(http.MethodGet, "/zta", nil)
responseRecorder := httptest.NewRecorder()
ls.requestZtaInfoHandler().ServeHTTP(responseRecorder, request)

// Make sure response was a 404
require.Equal(t, http.StatusNotFound, responseRecorder.Code)

k.AssertExpectations(t)
}

0 comments on commit 2663366

Please sign in to comment.