Move carve requests to server/fleet/ (#45785)
Resolves #36087 (one of several PRs) ## Testing - [x] QA'd all new/changed functionality manually. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Reorganized internal API request/response types for carve operations to centralize type definitions and improve code maintainability. * **Tests** * Updated carve operation tests to align with refactored code structure. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/45785?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
package fleet
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// List Carves
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type ListCarvesRequest struct {
|
||||
ListOptions CarveListOptions `url:"carve_options"`
|
||||
}
|
||||
|
||||
type ListCarvesResponse struct {
|
||||
Carves []CarveMetadata `json:"carves"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r ListCarvesResponse) Error() error { return r.Err }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Get Carve
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type GetCarveRequest struct {
|
||||
ID int64 `url:"id"`
|
||||
}
|
||||
|
||||
type GetCarveResponse struct {
|
||||
Carve CarveMetadata `json:"carve"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r GetCarveResponse) Error() error { return r.Err }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Get Carve Block
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type GetCarveBlockRequest struct {
|
||||
ID int64 `url:"id"`
|
||||
BlockId int64 `url:"block_id"`
|
||||
}
|
||||
|
||||
type GetCarveBlockResponse struct {
|
||||
Data []byte `json:"data"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r GetCarveBlockResponse) Error() error { return r.Err }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Begin File Carve
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type CarveBeginRequest struct {
|
||||
NodeKey string `json:"node_key"`
|
||||
BlockCount int64 `json:"block_count"`
|
||||
BlockSize int64 `json:"block_size"`
|
||||
CarveSize int64 `json:"carve_size"`
|
||||
CarveId string `json:"carve_id"`
|
||||
RequestId string `json:"request_id"`
|
||||
}
|
||||
|
||||
func (r *CarveBeginRequest) HostNodeKey() string {
|
||||
return r.NodeKey
|
||||
}
|
||||
|
||||
type CarveBeginResponse struct {
|
||||
SessionId string `json:"session_id"`
|
||||
Success bool `json:"success,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r CarveBeginResponse) Error() error { return r.Err }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Receive Block for File Carve
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type CarveBlockRequest struct {
|
||||
BlockId int64 `json:"block_id"`
|
||||
SessionId string `json:"session_id"`
|
||||
RequestId string `json:"request_id"`
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
|
||||
type CarveBlockResponse struct {
|
||||
Success bool `json:"success,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r CarveBlockResponse) Error() error { return r.Err }
|
||||
+23
-86
@@ -24,25 +24,14 @@ import (
|
||||
// List Carves
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type listCarvesRequest struct {
|
||||
ListOptions fleet.CarveListOptions `url:"carve_options"`
|
||||
}
|
||||
|
||||
type listCarvesResponse struct {
|
||||
Carves []fleet.CarveMetadata `json:"carves"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r listCarvesResponse) Error() error { return r.Err }
|
||||
|
||||
func listCarvesEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) {
|
||||
req := request.(*listCarvesRequest)
|
||||
req := request.(*fleet.ListCarvesRequest)
|
||||
carves, err := svc.ListCarves(ctx, req.ListOptions)
|
||||
if err != nil {
|
||||
return listCarvesResponse{Err: err}, nil
|
||||
return fleet.ListCarvesResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
resp := listCarvesResponse{}
|
||||
resp := fleet.ListCarvesResponse{}
|
||||
for _, carve := range carves {
|
||||
resp.Carves = append(resp.Carves, *carve)
|
||||
}
|
||||
@@ -61,25 +50,14 @@ func (svc *Service) ListCarves(ctx context.Context, opt fleet.CarveListOptions)
|
||||
// Get Carve
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type getCarveRequest struct {
|
||||
ID int64 `url:"id"`
|
||||
}
|
||||
|
||||
type getCarveResponse struct {
|
||||
Carve fleet.CarveMetadata `json:"carve"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r getCarveResponse) Error() error { return r.Err }
|
||||
|
||||
func getCarveEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) {
|
||||
req := request.(*getCarveRequest)
|
||||
req := request.(*fleet.GetCarveRequest)
|
||||
carve, err := svc.GetCarve(ctx, req.ID)
|
||||
if err != nil {
|
||||
return getCarveResponse{Err: err}, nil
|
||||
return fleet.GetCarveResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return getCarveResponse{Carve: *carve}, nil
|
||||
return fleet.GetCarveResponse{Carve: *carve}, nil
|
||||
}
|
||||
|
||||
func (svc *Service) GetCarve(ctx context.Context, id int64) (*fleet.CarveMetadata, error) {
|
||||
@@ -94,26 +72,14 @@ func (svc *Service) GetCarve(ctx context.Context, id int64) (*fleet.CarveMetadat
|
||||
// Get Carve Block
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type getCarveBlockRequest struct {
|
||||
ID int64 `url:"id"`
|
||||
BlockId int64 `url:"block_id"`
|
||||
}
|
||||
|
||||
type getCarveBlockResponse struct {
|
||||
Data []byte `json:"data"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r getCarveBlockResponse) Error() error { return r.Err }
|
||||
|
||||
func getCarveBlockEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) {
|
||||
req := request.(*getCarveBlockRequest)
|
||||
req := request.(*fleet.GetCarveBlockRequest)
|
||||
data, err := svc.GetBlock(ctx, req.ID, req.BlockId)
|
||||
if err != nil {
|
||||
return getCarveBlockResponse{Err: err}, nil
|
||||
return fleet.GetCarveBlockResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return getCarveBlockResponse{Data: data}, nil
|
||||
return fleet.GetCarveBlockResponse{Data: data}, nil
|
||||
}
|
||||
|
||||
func (svc *Service) GetBlock(ctx context.Context, carveId, blockId int64) ([]byte, error) {
|
||||
@@ -146,29 +112,8 @@ func (svc *Service) GetBlock(ctx context.Context, carveId, blockId int64) ([]byt
|
||||
// Begin File Carve
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type carveBeginRequest struct {
|
||||
NodeKey string `json:"node_key"`
|
||||
BlockCount int64 `json:"block_count"`
|
||||
BlockSize int64 `json:"block_size"`
|
||||
CarveSize int64 `json:"carve_size"`
|
||||
CarveId string `json:"carve_id"`
|
||||
RequestId string `json:"request_id"`
|
||||
}
|
||||
|
||||
func (r *carveBeginRequest) hostNodeKey() string {
|
||||
return r.NodeKey
|
||||
}
|
||||
|
||||
type carveBeginResponse struct {
|
||||
SessionId string `json:"session_id"`
|
||||
Success bool `json:"success,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r carveBeginResponse) Error() error { return r.Err }
|
||||
|
||||
func carveBeginEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) {
|
||||
req := request.(*carveBeginRequest)
|
||||
req := request.(*fleet.CarveBeginRequest)
|
||||
|
||||
payload := fleet.CarveBeginPayload{
|
||||
BlockCount: req.BlockCount,
|
||||
@@ -180,10 +125,10 @@ func carveBeginEndpoint(ctx context.Context, request interface{}, svc fleet.Serv
|
||||
|
||||
carve, err := svc.CarveBegin(ctx, payload)
|
||||
if err != nil {
|
||||
return carveBeginResponse{Err: err}, nil
|
||||
return fleet.CarveBeginResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return carveBeginResponse{SessionId: carve.SessionId, Success: true}, nil
|
||||
return fleet.CarveBeginResponse{SessionId: carve.SessionId, Success: true}, nil
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -249,19 +194,11 @@ func (svc *Service) CarveBegin(ctx context.Context, payload fleet.CarveBeginPayl
|
||||
// Receive Block for File Carve
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type carveBlockRequest struct {
|
||||
BlockId int64 `json:"block_id"`
|
||||
SessionId string `json:"session_id"`
|
||||
RequestId string `json:"request_id"`
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
|
||||
type carveBlockResponse struct {
|
||||
Success bool `json:"success,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r carveBlockResponse) Error() error { return r.Err }
|
||||
// decodeCarveBlockRequest is a service-local wrapper that owns the streaming
|
||||
// DecodeRequest used by the unauthenticated /osquery/carve/block endpoint.
|
||||
// The wrapper lives here (not in server/fleet) because it uses carvestorectx,
|
||||
// which imports server/fleet and would create a cycle.
|
||||
type decodeCarveBlockRequest struct{}
|
||||
|
||||
// DecodeRequest for the /api/v1/osquery/carve/block endpoint performs raw JSON parsing
|
||||
// to prevent DoS attacks on this unauthenticated endpoint.
|
||||
@@ -281,7 +218,7 @@ func (r carveBlockResponse) Error() error { return r.Err }
|
||||
// check remains the primary authentication mechanism. When the header is
|
||||
// valid, CarveBlock additionally verifies that the carve's host_id matches
|
||||
// the authenticated host.
|
||||
func (r carveBlockRequest) DecodeRequest(ctx context.Context, req *http.Request) (any, error) {
|
||||
func (decodeCarveBlockRequest) DecodeRequest(ctx context.Context, req *http.Request) (any, error) {
|
||||
carveStore := carvestorectx.FromContext(ctx)
|
||||
if carveStore == nil {
|
||||
return nil, ctxerr.New(ctx, "missing carve store from context")
|
||||
@@ -419,7 +356,7 @@ func (r carveBlockRequest) DecodeRequest(ctx context.Context, req *http.Request)
|
||||
}
|
||||
data = data[:n]
|
||||
|
||||
return &carveBlockRequest{
|
||||
return &fleet.CarveBlockRequest{
|
||||
BlockId: blockID,
|
||||
SessionId: sessionID,
|
||||
RequestId: requestID,
|
||||
@@ -428,7 +365,7 @@ func (r carveBlockRequest) DecodeRequest(ctx context.Context, req *http.Request)
|
||||
}
|
||||
|
||||
func carveBlockEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) {
|
||||
req := request.(*carveBlockRequest)
|
||||
req := request.(*fleet.CarveBlockRequest)
|
||||
|
||||
payload := fleet.CarveBlockPayload{
|
||||
SessionId: req.SessionId,
|
||||
@@ -439,10 +376,10 @@ func carveBlockEndpoint(ctx context.Context, request interface{}, svc fleet.Serv
|
||||
|
||||
err := svc.CarveBlock(ctx, payload)
|
||||
if err != nil {
|
||||
return carveBlockResponse{Err: err}, nil
|
||||
return fleet.CarveBlockResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return carveBlockResponse{Success: true}, nil
|
||||
return fleet.CarveBlockResponse{Success: true}, nil
|
||||
}
|
||||
|
||||
func (svc *Service) CarveBlock(ctx context.Context, payload fleet.CarveBlockPayload) error {
|
||||
@@ -450,7 +387,7 @@ func (svc *Service) CarveBlock(ctx context.Context, payload fleet.CarveBlockPayl
|
||||
svc.authz.SkipAuthorization(ctx)
|
||||
|
||||
// Authentication on this endpoint is layered:
|
||||
// 1. The streaming body parser (carveBlockRequest.DecodeRequest)
|
||||
// 1. The streaming body parser (decodeCarveBlockRequest.DecodeRequest)
|
||||
// verifies session_id+request_id against the carve store.
|
||||
// 2. When osquery.allow_body_auth_fallback=false, the HTTP pre-auth
|
||||
// middleware (osqueryCarveBlockHeaderPreAuth) is installed and
|
||||
|
||||
@@ -789,7 +789,7 @@ func TestCarveBlockDecodeRequest(t *testing.T) {
|
||||
wantErr bool
|
||||
wantErrType string // e.g., "AuthFailedError", "ctxerr", ""
|
||||
wantErrMessage string
|
||||
wantResult *carveBlockRequest
|
||||
wantResult *fleet.CarveBlockRequest
|
||||
}{
|
||||
{
|
||||
name: "valid request MySQL session IDs",
|
||||
@@ -803,7 +803,7 @@ func TestCarveBlockDecodeRequest(t *testing.T) {
|
||||
return carvestorectx.NewContext(ctx, store)
|
||||
},
|
||||
wantErr: false,
|
||||
wantResult: &carveBlockRequest{
|
||||
wantResult: &fleet.CarveBlockRequest{
|
||||
BlockId: 123,
|
||||
SessionId: "23bbbcf6-6b8a-4f3a-9924-bdd084f31097",
|
||||
RequestId: "req123",
|
||||
@@ -822,7 +822,7 @@ func TestCarveBlockDecodeRequest(t *testing.T) {
|
||||
return carvestorectx.NewContext(ctx, store)
|
||||
},
|
||||
wantErr: false,
|
||||
wantResult: &carveBlockRequest{
|
||||
wantResult: &fleet.CarveBlockRequest{
|
||||
BlockId: 123,
|
||||
SessionId: "JUMHLnWZ.A7y5ns2jUODzG8eTr5m9lvFKDD3nBN.hJ8mwr2szW0iUSNrusaE41__.wrtsNokzejFLQyNJTTqY_QN1grwAT0yXGi8A77Kf9ZJlvSiWggmncDAhVev4QXxx2PyN_GtTRPC71WGKPN2YxBFfWBjZlCZBXmPCtc4zrQ",
|
||||
RequestId: "req123",
|
||||
@@ -841,7 +841,7 @@ func TestCarveBlockDecodeRequest(t *testing.T) {
|
||||
return carvestorectx.NewContext(ctx, store)
|
||||
},
|
||||
wantErr: false,
|
||||
wantResult: &carveBlockRequest{
|
||||
wantResult: &fleet.CarveBlockRequest{
|
||||
BlockId: 123,
|
||||
SessionId: "ZGVhZDYwYTctZTVlOC00MzE1LWFhOWMtZDIzMzc5MTI4NGUyLjUzM2MxZjhhLTFiODktNDQ1YS04NTE0LTBjMWE0NDVlNjkwMXgxNzcwMTQ1Njc5NDgyNDg3NzE3",
|
||||
RequestId: "req123",
|
||||
@@ -860,7 +860,7 @@ func TestCarveBlockDecodeRequest(t *testing.T) {
|
||||
return carvestorectx.NewContext(ctx, store)
|
||||
},
|
||||
wantErr: false,
|
||||
wantResult: &carveBlockRequest{
|
||||
wantResult: &fleet.CarveBlockRequest{
|
||||
BlockId: 123,
|
||||
SessionId: strings.Repeat("F", 255),
|
||||
RequestId: "req123",
|
||||
@@ -1066,7 +1066,7 @@ func TestCarveBlockDecodeRequest(t *testing.T) {
|
||||
return carvestorectx.NewContext(ctx, store)
|
||||
},
|
||||
wantErr: false,
|
||||
wantResult: &carveBlockRequest{
|
||||
wantResult: &fleet.CarveBlockRequest{
|
||||
BlockId: 123,
|
||||
SessionId: "sess123",
|
||||
RequestId: strings.Repeat("F", 64),
|
||||
@@ -1291,7 +1291,7 @@ func TestCarveBlockDecodeRequest(t *testing.T) {
|
||||
return carvestorectx.NewContext(ctx, store)
|
||||
},
|
||||
wantErr: false,
|
||||
wantResult: &carveBlockRequest{
|
||||
wantResult: &fleet.CarveBlockRequest{
|
||||
BlockId: 1<<63 - 1,
|
||||
SessionId: "sess123",
|
||||
RequestId: "req123",
|
||||
@@ -1320,8 +1320,7 @@ func TestCarveBlockDecodeRequest(t *testing.T) {
|
||||
req := &http.Request{
|
||||
Body: io.NopCloser(bytes.NewReader([]byte(tt.body))),
|
||||
}
|
||||
var r carveBlockRequest
|
||||
result, err := r.DecodeRequest(ctx, req)
|
||||
result, err := decodeCarveBlockRequest{}.DecodeRequest(ctx, req)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("DecodeRequest() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
@@ -1336,9 +1335,9 @@ func TestCarveBlockDecodeRequest(t *testing.T) {
|
||||
}
|
||||
return
|
||||
}
|
||||
got, ok := result.(*carveBlockRequest)
|
||||
got, ok := result.(*fleet.CarveBlockRequest)
|
||||
if !ok {
|
||||
t.Errorf("result not *carveBlockRequest")
|
||||
t.Errorf("result not *fleet.CarveBlockRequest")
|
||||
return
|
||||
}
|
||||
if tt.wantResult != nil {
|
||||
|
||||
@@ -30,7 +30,7 @@ func (c *Client) ListCarves(opt fleet.CarveListOptions) ([]*fleet.CarveMetadata,
|
||||
)
|
||||
}
|
||||
|
||||
var responseBody listCarvesResponse
|
||||
var responseBody fleet.ListCarvesResponse
|
||||
err = json.NewDecoder(response.Body).Decode(&responseBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode get carves response: %w", err)
|
||||
@@ -63,7 +63,7 @@ func (c *Client) GetCarve(carveId int64) (*fleet.CarveMetadata, error) {
|
||||
extractServerErrorText(response.Body),
|
||||
)
|
||||
}
|
||||
var responseBody getCarveResponse
|
||||
var responseBody fleet.GetCarveResponse
|
||||
err = json.NewDecoder(response.Body).Decode(&responseBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode carve response: %w", err)
|
||||
@@ -95,7 +95,7 @@ func (c *Client) getCarveBlock(carveId, blockId int64) ([]byte, error) {
|
||||
)
|
||||
}
|
||||
|
||||
var responseBody getCarveBlockResponse
|
||||
var responseBody fleet.GetCarveBlockResponse
|
||||
err = json.NewDecoder(response.Body).Decode(&responseBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode get carve block response: %w", err)
|
||||
@@ -175,7 +175,7 @@ func (c *Client) DownloadCarve(id int64) (io.Reader, error) {
|
||||
)
|
||||
}
|
||||
|
||||
var responseBody getCarveResponse
|
||||
var responseBody fleet.GetCarveResponse
|
||||
err = json.NewDecoder(response.Body).Decode(&responseBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode get carve by name response: %w", err)
|
||||
|
||||
@@ -272,6 +272,9 @@ func authHeaderValue(prefix string) func(ctx context.Context, r interface{}) (st
|
||||
}
|
||||
|
||||
func getNodeKey(r interface{}) (string, error) {
|
||||
if hnk, ok := r.(interface{ HostNodeKey() string }); ok {
|
||||
return hnk.HostNodeKey(), nil
|
||||
}
|
||||
if hnk, ok := r.(interface{ hostNodeKey() string }); ok {
|
||||
return hnk.hostNodeKey(), nil
|
||||
}
|
||||
|
||||
@@ -540,9 +540,9 @@ func attachFleetAPIRoutes(r *mux.Router, svc fleet.Service, config config.FleetC
|
||||
ue.PATCH("/api/_version_/fleet/fleets/{fleet_id}/schedule/{report_id}", modifyTeamScheduleEndpoint, modifyTeamScheduleRequest{})
|
||||
ue.DELETE("/api/_version_/fleet/fleets/{fleet_id}/schedule/{report_id}", deleteTeamScheduleEndpoint, deleteTeamScheduleRequest{})
|
||||
|
||||
ue.GET("/api/_version_/fleet/carves", listCarvesEndpoint, listCarvesRequest{})
|
||||
ue.GET("/api/_version_/fleet/carves/{id:[0-9]+}", getCarveEndpoint, getCarveRequest{})
|
||||
ue.GET("/api/_version_/fleet/carves/{id:[0-9]+}/block/{block_id}", getCarveBlockEndpoint, getCarveBlockRequest{})
|
||||
ue.GET("/api/_version_/fleet/carves", listCarvesEndpoint, fleet.ListCarvesRequest{})
|
||||
ue.GET("/api/_version_/fleet/carves/{id:[0-9]+}", getCarveEndpoint, fleet.GetCarveRequest{})
|
||||
ue.GET("/api/_version_/fleet/carves/{id:[0-9]+}/block/{block_id}", getCarveBlockEndpoint, fleet.GetCarveBlockRequest{})
|
||||
|
||||
ue.GET("/api/_version_/fleet/hosts/{id:[0-9]+}/macadmins", getMacadminsDataEndpoint, getMacadminsDataRequest{})
|
||||
ue.GET("/api/_version_/fleet/macadmins", getAggregatedMacadminsDataEndpoint, getAggregatedMacadminsDataRequest{})
|
||||
@@ -988,7 +988,7 @@ func attachFleetAPIRoutes(r *mux.Router, svc fleet.Service, config config.FleetC
|
||||
distWriteReg.WithAltPaths("/api/v1/osquery/distributed/write").
|
||||
POST("/api/osquery/distributed/write", submitDistributedQueryResultsEndpoint, submitDistributedQueryResultsRequestShim{})
|
||||
heHeader.WithAltPaths("/api/v1/osquery/carve/begin").
|
||||
POST("/api/osquery/carve/begin", carveBeginEndpoint, carveBeginRequest{})
|
||||
POST("/api/osquery/carve/begin", carveBeginEndpoint, fleet.CarveBeginRequest{})
|
||||
logWriteReg.WithAltPaths("/api/v1/osquery/log").
|
||||
POST("/api/osquery/log", submitLogsEndpoint, submitLogsRequest{})
|
||||
he.WithAltPaths("/api/v1/osquery/yara/{name}").
|
||||
@@ -1119,7 +1119,7 @@ func attachFleetAPIRoutes(r *mux.Router, svc fleet.Service, config config.FleetC
|
||||
carveBlockReg = carveBlockReg.WithHTTPPreAuth(osqueryCarveBlockHeaderPreAuth(svc, logger))
|
||||
}
|
||||
carveBlockReg.WithAltPaths("/api/v1/osquery/carve/block").
|
||||
POST("/api/osquery/carve/block", carveBlockEndpoint, carveBlockRequest{})
|
||||
POST("/api/osquery/carve/block", carveBlockEndpoint, decodeCarveBlockRequest{})
|
||||
|
||||
ne.GET("/api/_version_/fleet/software/titles/{title_id:[0-9]+}/package/token/{token}", downloadSoftwareInstallerEndpoint,
|
||||
downloadSoftwareInstallerRequest{})
|
||||
|
||||
@@ -3829,7 +3829,7 @@ func (s *integrationTestSuite) TestListGetCarves() {
|
||||
c2.MaxBlock = 3
|
||||
require.NoError(t, s.ds.UpdateCarve(ctx, c2))
|
||||
|
||||
var listResp listCarvesResponse
|
||||
var listResp fleet.ListCarvesResponse
|
||||
s.DoJSON("GET", "/api/latest/fleet/carves", nil, http.StatusOK, &listResp, "per_page", "2", "order_key", "id")
|
||||
require.Len(t, listResp.Carves, 2)
|
||||
assert.Equal(t, c1.ID, listResp.Carves[0].ID)
|
||||
@@ -3854,7 +3854,7 @@ func (s *integrationTestSuite) TestListGetCarves() {
|
||||
require.Len(t, listResp.Carves, 0)
|
||||
|
||||
// get specific carve
|
||||
var getResp getCarveResponse
|
||||
var getResp fleet.GetCarveResponse
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/carves/%d", c2.ID), nil, http.StatusOK, &getResp)
|
||||
require.Equal(t, c2.ID, getResp.Carve.ID)
|
||||
require.True(t, getResp.Carve.Expired)
|
||||
@@ -3863,7 +3863,7 @@ func (s *integrationTestSuite) TestListGetCarves() {
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/carves/%d", c3.ID+1), nil, http.StatusNotFound, &getResp)
|
||||
|
||||
// get expired carve block
|
||||
var blkResp getCarveBlockResponse
|
||||
var blkResp fleet.GetCarveBlockResponse
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/carves/%d/block/%d", c2.ID, 1), nil, http.StatusInternalServerError, &blkResp)
|
||||
|
||||
// get valid carve block, but block not inserted yet
|
||||
@@ -9835,7 +9835,7 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
|
||||
// begin a carve with an invalid node key
|
||||
var errRes map[string]interface{}
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", carveBeginRequest{
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", fleet.CarveBeginRequest{
|
||||
NodeKey: *hosts[0].NodeKey + "zzz",
|
||||
BlockCount: 1,
|
||||
BlockSize: 1,
|
||||
@@ -9845,7 +9845,7 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
assert.Contains(t, errRes["error"], "invalid node key")
|
||||
|
||||
// invalid carve size
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", carveBeginRequest{
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", fleet.CarveBeginRequest{
|
||||
NodeKey: *hosts[0].NodeKey,
|
||||
BlockCount: 3,
|
||||
BlockSize: 3,
|
||||
@@ -9855,7 +9855,7 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
assert.Contains(t, errRes["error"], "carve_size must be greater")
|
||||
|
||||
// invalid block size too big
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", carveBeginRequest{
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", fleet.CarveBeginRequest{
|
||||
NodeKey: *hosts[0].NodeKey,
|
||||
BlockCount: 3,
|
||||
BlockSize: maxBlockSize + 1,
|
||||
@@ -9865,7 +9865,7 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
assert.Contains(t, errRes["error"], "block_size exceeds max")
|
||||
|
||||
// invalid carve size too big
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", carveBeginRequest{
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", fleet.CarveBeginRequest{
|
||||
NodeKey: *hosts[0].NodeKey,
|
||||
BlockCount: 3,
|
||||
BlockSize: maxBlockSize,
|
||||
@@ -9875,7 +9875,7 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
assert.Contains(t, errRes["error"], "carve_size exceeds max")
|
||||
|
||||
// invalid carve size, does not match blocks
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", carveBeginRequest{
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", fleet.CarveBeginRequest{
|
||||
NodeKey: *hosts[0].NodeKey,
|
||||
BlockCount: 3,
|
||||
BlockSize: 3,
|
||||
@@ -9885,8 +9885,8 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
assert.Contains(t, errRes["error"], "carve_size does not match")
|
||||
|
||||
// valid carve begin
|
||||
var beginResp carveBeginResponse
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", carveBeginRequest{
|
||||
var beginResp fleet.CarveBeginResponse
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", fleet.CarveBeginRequest{
|
||||
NodeKey: *hosts[0].NodeKey,
|
||||
BlockCount: 3,
|
||||
BlockSize: 3,
|
||||
@@ -9898,8 +9898,8 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
sid := beginResp.SessionId
|
||||
|
||||
// sending a block with invalid session id
|
||||
var blockResp carveBlockResponse
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", carveBlockRequest{
|
||||
var blockResp fleet.CarveBlockResponse
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", fleet.CarveBlockRequest{
|
||||
BlockId: 1,
|
||||
SessionId: sid + "zz",
|
||||
RequestId: "??",
|
||||
@@ -9907,7 +9907,7 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
}, http.StatusUnauthorized, &blockResp)
|
||||
|
||||
// sending a block with valid session id but invalid request id
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", carveBlockRequest{
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", fleet.CarveBlockRequest{
|
||||
BlockId: 1,
|
||||
SessionId: sid,
|
||||
RequestId: "??",
|
||||
@@ -9915,13 +9915,13 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
}, http.StatusUnauthorized, &blockResp)
|
||||
|
||||
checkCarveError := func(id uint, err string) {
|
||||
var getResp getCarveResponse
|
||||
var getResp fleet.GetCarveResponse
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/carves/%d", id), nil, http.StatusOK, &getResp)
|
||||
require.Equal(t, err, *getResp.Carve.Error)
|
||||
}
|
||||
|
||||
// sending a block with unexpected block id (expects 0, got 1)
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", carveBlockRequest{
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", fleet.CarveBlockRequest{
|
||||
BlockId: 1,
|
||||
SessionId: sid,
|
||||
RequestId: "r1",
|
||||
@@ -9930,7 +9930,7 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
checkCarveError(1, "block_id does not match expected block (0): 1")
|
||||
|
||||
// sending a block with valid payload, block 0
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", carveBlockRequest{
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", fleet.CarveBlockRequest{
|
||||
BlockId: 0,
|
||||
SessionId: sid,
|
||||
RequestId: "r1",
|
||||
@@ -9939,8 +9939,8 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
require.True(t, blockResp.Success)
|
||||
|
||||
// sending next block
|
||||
blockResp = carveBlockResponse{}
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", carveBlockRequest{
|
||||
blockResp = fleet.CarveBlockResponse{}
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", fleet.CarveBlockRequest{
|
||||
BlockId: 1,
|
||||
SessionId: sid,
|
||||
RequestId: "r1",
|
||||
@@ -9949,8 +9949,8 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
require.True(t, blockResp.Success)
|
||||
|
||||
// sending already-sent block again
|
||||
blockResp = carveBlockResponse{}
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", carveBlockRequest{
|
||||
blockResp = fleet.CarveBlockResponse{}
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", fleet.CarveBlockRequest{
|
||||
BlockId: 1,
|
||||
SessionId: sid,
|
||||
RequestId: "r1",
|
||||
@@ -9959,8 +9959,8 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
checkCarveError(1, "block_id does not match expected block (2): 1")
|
||||
|
||||
// sending final block with too many bytes
|
||||
blockResp = carveBlockResponse{}
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", carveBlockRequest{
|
||||
blockResp = fleet.CarveBlockResponse{}
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", fleet.CarveBlockRequest{
|
||||
BlockId: 2,
|
||||
SessionId: sid,
|
||||
RequestId: "r1",
|
||||
@@ -9969,8 +9969,8 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
checkCarveError(1, "exceeded declared block size 3: 7")
|
||||
|
||||
// sending actual final block
|
||||
blockResp = carveBlockResponse{}
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", carveBlockRequest{
|
||||
blockResp = fleet.CarveBlockResponse{}
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", fleet.CarveBlockRequest{
|
||||
BlockId: 2,
|
||||
SessionId: sid,
|
||||
RequestId: "r1",
|
||||
@@ -9979,8 +9979,8 @@ func (s *integrationTestSuite) TestCarve() {
|
||||
require.True(t, blockResp.Success)
|
||||
|
||||
// sending unexpected block
|
||||
blockResp = carveBlockResponse{}
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", carveBlockRequest{
|
||||
blockResp = fleet.CarveBlockResponse{}
|
||||
s.DoJSON("POST", "/api/osquery/carve/block", fleet.CarveBlockRequest{
|
||||
BlockId: 3,
|
||||
SessionId: sid,
|
||||
RequestId: "r1",
|
||||
|
||||
@@ -6919,8 +6919,8 @@ func (s *integrationEnterpriseTestSuite) TestGitOpsUserActions() {
|
||||
},
|
||||
}, http.StatusOK, &cur)
|
||||
maintainer := cur.User
|
||||
var carveBeginResp carveBeginResponse
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", carveBeginRequest{
|
||||
var carveBeginResp fleet.CarveBeginResponse
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", fleet.CarveBeginRequest{
|
||||
NodeKey: *h1.NodeKey,
|
||||
BlockCount: 3,
|
||||
BlockSize: 3,
|
||||
@@ -6929,8 +6929,8 @@ func (s *integrationEnterpriseTestSuite) TestGitOpsUserActions() {
|
||||
RequestId: "r1",
|
||||
}, http.StatusOK, &carveBeginResp)
|
||||
require.NotEmpty(t, carveBeginResp.SessionId)
|
||||
lcr := listCarvesResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/carves", listCarvesRequest{}, http.StatusOK, &lcr)
|
||||
lcr := fleet.ListCarvesResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/carves", fleet.ListCarvesRequest{}, http.StatusOK, &lcr)
|
||||
require.NotEmpty(t, lcr.Carves)
|
||||
carveID := lcr.Carves[0].ID
|
||||
// Create the global GitOps user we'll use in tests.
|
||||
@@ -7343,10 +7343,10 @@ func (s *integrationEnterpriseTestSuite) TestGitOpsUserActions() {
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/teams/%d/secrets", t1.ID), teamEnrollSecretsRequest{}, http.StatusForbidden, &teamEnrollSecretsResponse{})
|
||||
|
||||
// Attempt to list carved files, should fail.
|
||||
s.DoJSON("GET", "/api/latest/fleet/carves", listCarvesRequest{}, http.StatusForbidden, &listCarvesResponse{})
|
||||
s.DoJSON("GET", "/api/latest/fleet/carves", fleet.ListCarvesRequest{}, http.StatusForbidden, &fleet.ListCarvesResponse{})
|
||||
|
||||
// Attempt to get a carved file, should fail.
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/carves/%d", carveID), listCarvesRequest{}, http.StatusForbidden, &listCarvesResponse{})
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/carves/%d", carveID), fleet.GetCarveRequest{}, http.StatusForbidden, &fleet.GetCarveResponse{})
|
||||
|
||||
// Attempt to search hosts, should fail.
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", searchTargetsRequest{
|
||||
|
||||
@@ -21741,8 +21741,8 @@ func (s *integrationMDMTestSuite) TestTechnicianPermissions() {
|
||||
},
|
||||
}, http.StatusOK, &cur)
|
||||
maintainer := cur.User
|
||||
var carveBeginResp carveBeginResponse
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", carveBeginRequest{
|
||||
var carveBeginResp fleet.CarveBeginResponse
|
||||
s.DoJSON("POST", "/api/osquery/carve/begin", fleet.CarveBeginRequest{
|
||||
NodeKey: *h1.NodeKey,
|
||||
BlockCount: 3,
|
||||
BlockSize: 3,
|
||||
@@ -21751,8 +21751,8 @@ func (s *integrationMDMTestSuite) TestTechnicianPermissions() {
|
||||
RequestId: "r1",
|
||||
}, http.StatusOK, &carveBeginResp)
|
||||
require.NotEmpty(t, carveBeginResp.SessionId)
|
||||
lcr := listCarvesResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/carves", listCarvesRequest{}, http.StatusOK, &lcr)
|
||||
lcr := fleet.ListCarvesResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/carves", fleet.ListCarvesRequest{}, http.StatusOK, &lcr)
|
||||
require.NotEmpty(t, lcr.Carves)
|
||||
carveID := lcr.Carves[0].ID
|
||||
// Create the global Technician user we'll use in tests.
|
||||
@@ -22281,10 +22281,10 @@ func (s *integrationMDMTestSuite) TestTechnicianPermissions() {
|
||||
require.Equal(t, fleet.MaskedPassword, tesr.Secrets[0].Secret)
|
||||
|
||||
// Attempt to list carved files, should fail.
|
||||
s.DoJSON("GET", "/api/latest/fleet/carves", listCarvesRequest{}, http.StatusForbidden, &listCarvesResponse{})
|
||||
s.DoJSON("GET", "/api/latest/fleet/carves", fleet.ListCarvesRequest{}, http.StatusForbidden, &fleet.ListCarvesResponse{})
|
||||
|
||||
// Attempt to get a carved file, should fail.
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/carves/%d", carveID), listCarvesRequest{}, http.StatusForbidden, &listCarvesResponse{})
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/carves/%d", carveID), fleet.GetCarveRequest{}, http.StatusForbidden, &fleet.GetCarveResponse{})
|
||||
|
||||
// Attempt to search hosts, should allow.
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", searchTargetsRequest{
|
||||
|
||||
Reference in New Issue
Block a user