Repository: kurtosis-tech/kurtosis (go)

Issue:
support headers in `plan.request` and `plan.wait`
### Background & motivation

I am trying to make an http request and get some data but this API is behind bearer tokens; I now have to create a python script for thsi

### Desired behaviour

support headers in plan.request

### How important is this to you?

Painful; the lack of this feature makes using Kurtosis frictionful.

### What area of the product does this pertain to?

Other: anything not covered by the above

Pull request description:
feat: allow users to set custom headers for recipes
Closes #1971

Patch:
diff --git a/core/server/api_container/server/service_network/default_service_network.go b/core/server/api_container/server/service_network/default_service_network.go
index f859850b9..f0f46916c 100644
--- a/core/server/api_container/server/service_network/default_service_network.go
+++ b/core/server/api_container/server/service_network/default_service_network.go
@@ -628,7 +628,7 @@ func (network *DefaultServiceNetwork) RunExecs(ctx context.Context, userServiceC
 	return successfulExecs, failedExecs, nil
 }
 
-func (network *DefaultServiceNetwork) HttpRequestService(ctx context.Context, serviceIdentifier string, portId string, method string, contentType string, endpoint string, body string) (*http.Response, error) {
+func (network *DefaultServiceNetwork) HttpRequestService(ctx context.Context, serviceIdentifier string, portId string, method string, contentType string, endpoint string, body string, headers map[string]string) (*http.Response, error) {
 	logrus.Debugf("Making a request '%v' '%v' '%v' '%v' '%v' '%v'", serviceIdentifier, portId, method, contentType, endpoint, body)
 	userService, getServiceErr := network.GetService(ctx, serviceIdentifier)
 	if getServiceErr != nil {
@@ -643,6 +643,9 @@ func (network *DefaultServiceNetwork) HttpRequestService(ctx context.Context, se
 	if err != nil {
 		return nil, stacktrace.NewError("An error occurred building HTTP request on service '%v', URL '%v'", userService, url)
 	}
+	for header, headerValue := range headers {
+		req.Header.Set(header, headerValue)
+	}
 	if contentType != "" {
 		req.Header.Set("Content-Type", contentType)
 	}
diff --git a/core/server/api_container/server/service_network/mock_service_network.go b/core/server/api_container/server/service_network/mock_service_network.go
index 72022a913..6eaffba2d 100644
--- a/core/server/api_container/server/service_network/mock_service_network.go
+++ b/core/server/api_container/server/service_network/mock_service_network.go
@@ -682,25 +682,25 @@ func (_c *MockServiceNetwork_GetUniqueNameForFileArtifact_Call) RunAndReturn(run
 	return _c
 }
 
-// HttpRequestService provides a mock function with given fields: ctx, serviceIdentifier, portId, method, contentType, endpoint, body
-func (_m *MockServiceNetwork) HttpRequestService(ctx context.Context, serviceIdentifier string, portId string, method string, contentType string, endpoint string, body string) (*http.Response, error) {
-	ret := _m.Called(ctx, serviceIdentifier, portId, method, contentType, endpoint, body)
+// HttpRequestService provides a mock function with given fields: ctx, serviceIdentifier, portId, method, contentType, endpoint, body, headers
+func (_m *MockServiceNetwork) HttpRequestService(ctx context.Context, serviceIdentifier string, portId string, method string, contentType string, endpoint string, body string, headers map[string]string) (*http.Response, error) {
+	ret := _m.Called(ctx, serviceIdentifier, portId, method, contentType, endpoint, body, headers)
 
 	var r0 *http.Response
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, string, string) (*http.Response, error)); ok {
-		return rf(ctx, serviceIdentifier, portId, method, contentType, endpoint, body)
+	if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, string, string, map[string]string) (*http.Response, error)); ok {
+		return rf(ctx, serviceIdentifier, portId, method, contentType, endpoint, body, headers)
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, string, string) *http.Response); ok {
-		r0 = rf(ctx, serviceIdentifier, portId, method, contentType, endpoint, body)
+	if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, string, string, map[string]string) *http.Response); ok {
+		r0 = rf(ctx, serviceIdentifier, portId, method, contentType, endpoint, body, headers)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*http.Response)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string, string, string) error); ok {
-		r1 = rf(ctx, serviceIdentifier, portId, method, contentType, endpoint, body)
+	if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string, string, string, map[string]string) error); ok {
+		r1 = rf(ctx, serviceIdentifier, portId, method, contentType, endpoint, body, headers)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -721,13 +721,14 @@ type MockServiceNetwork_HttpRequestService_Call struct {
 //   - contentType string
 //   - endpoint string
 //   - body string
-func (_e *MockServiceNetwork_Expecter) HttpRequestService(ctx interface{}, serviceIdentifier interface{}, portId interface{}, method interface{}, contentType interface{}, endpoint interface{}, body interface{}) *MockServiceNetwork_HttpRequestService_Call {
-	return &MockServiceNetwork_HttpRequestService_Call{Call: _e.mock.On("HttpRequestService", ctx, serviceIdentifier, portId, method, contentType, endpoint, body)}
+//   - headers map[string]string
+func (_e *MockServiceNetwork_Expecter) HttpRequestService(ctx interface{}, serviceIdentifier interface{}, portId interface{}, method interface{}, contentType interface{}, endpoint interface{}, body interface{}, headers interface{}) *MockServiceNetwork_HttpRequestService_Call {
+	return &MockServiceNetwork_HttpRequestService_Call{Call: _e.mock.On("HttpRequestService", ctx, serviceIdentifier, portId, method, contentType, endpoint, body, headers)}
 }
 
-func (_c *MockServiceNetwork_HttpRequestService_Call) Run(run func(ctx context.Context, serviceIdentifier string, portId string, method string, contentType string, endpoint string, body string)) *MockServiceNetwork_HttpRequestService_Call {
+func (_c *MockServiceNetwork_HttpRequestService_Call) Run(run func(ctx context.Context, serviceIdentifier string, portId string, method string, contentType string, endpoint string, body string, headers map[string]string)) *MockServiceNetwork_HttpRequestService_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string), args[4].(string), args[5].(string), args[6].(string))
+		run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string), args[4].(string), args[5].(string), args[6].(string), args[7].(map[string]string))
 	})
 	return _c
 }
@@ -737,7 +738,7 @@ func (_c *MockServiceNetwork_HttpRequestService_Call) Return(_a0 *http.Response,
 	return _c
 }
 
-func (_c *MockServiceNetwork_HttpRequestService_Call) RunAndReturn(run func(context.Context, string, string, string, string, string, string) (*http.Response, error)) *MockServiceNetwork_HttpRequestService_Call {
+func (_c *MockServiceNetwork_HttpRequestService_Call) RunAndReturn(run func(context.Context, string, string, string, string, string, string, map[string]string) (*http.Response, error)) *MockServiceNetwork_HttpRequestService_Call {
 	_c.Call.Return(run)
 	return _c
 }
diff --git a/core/server/api_container/server/service_network/service_network.go b/core/server/api_container/server/service_network/service_network.go
index a8c113bf0..ba04f0cb2 100644
--- a/core/server/api_container/server/service_network/service_network.go
+++ b/core/server/api_container/server/service_network/service_network.go
@@ -90,7 +90,7 @@ type ServiceNetwork interface {
 		error,
 	)
 
-	HttpRequestService(ctx context.Context, serviceIdentifier string, portId string, method string, contentType string, endpoint string, body string) (*http.Response, error)
+	HttpRequestService(ctx context.Context, serviceIdentifier string, portId string, method string, contentType string, endpoint string, body string, headers map[string]string) (*http.Response, error)
 
 	GetService(ctx context.Context, serviceIdentifier string) (*service.Service, error)
 
diff --git a/core/server/api_container/server/startosis_engine/recipe/get_http_request_recipe.go b/core/server/api_container/server/startosis_engine/recipe/get_http_request_recipe.go
index 9b1f39352..f17c21349 100644
--- a/core/server/api_container/server/startosis_engine/recipe/get_http_request_recipe.go
+++ b/core/server/api_container/server/startosis_engine/recipe/get_http_request_recipe.go
@@ -52,6 +52,15 @@ func NewGetHttpRequestRecipeType() *kurtosis_type_constructor.KurtosisTypeConstr
 						return interpretationErr
 					},
 				},
+				{
+					Name:              HeadersAttr,
+					IsOptional:        true,
+					ZeroValueProvider: builtin_argument.ZeroValueProvider[*starlark.Dict],
+					Validator: func(value starlark.Value) *startosis_errors.InterpretationError {
+						_, interpretationErr := convertHeadersToMapStringString(true, value)
+						return interpretationErr
+					},
+				},
 			},
 		},
 		Instantiate: instantiateGetHttpRequestRecipe,
@@ -118,6 +127,16 @@ func (recipe *GetHttpRequestRecipe) Execute(
 		return nil, interpretationErr
 	}
 
+	rawHeaders, found, interpretationErr := kurtosis_type_constructor.ExtractAttrValue[*starlark.Dict](
+		recipe.KurtosisValueTypeDefault, HeadersAttr)
+	if interpretationErr != nil {
+		return nil, interpretationErr
+	}
+	headers, interpretationErr := convertHeadersToMapStringString(found, rawHeaders)
+	if interpretationErr != nil {
+		return nil, interpretationErr
+	}
+
 	serviceNameStr := string(serviceName)
 	if serviceNameStr == "" {
 		return nil, stacktrace.NewError("The service name parameter can't be an empty string")
@@ -134,6 +153,7 @@ func (recipe *GetHttpRequestRecipe) Execute(
 		noContentType,
 		endpoint.GoString(),
 		extractors,
+		headers,
 	)
 	if err != nil {
 		return nil, stacktrace.Propagate(err, "An error occurred when running HTTP request recipe '%v'", recipe.String())
diff --git a/core/server/api_container/server/startosis_engine/recipe/http_request_recipe.go b/core/server/api_container/server/startosis_engine/recipe/http_request_recipe.go
index a7a6b6c70..01cf4b511 100644
--- a/core/server/api_container/server/startosis_engine/recipe/http_request_recipe.go
+++ b/core/server/api_container/server/startosis_engine/recipe/http_request_recipe.go
@@ -7,6 +7,7 @@ import (
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/service_network"
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_instruction/shared_helpers/magic_string_helper"
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/builtin_argument"
+	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_types"
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/runtime_value_store"
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/startosis_errors"
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/startosis_validator"
@@ -27,6 +28,7 @@ const (
 	// Common attributes for both [Get|Post]HttpRequestRecipe
 	PortIdAttr   = "port_id"
 	EndpointAttr = "endpoint"
+	HeadersAttr  = "headers"
 	ExtractAttr  = "extract"
 )
 
@@ -50,6 +52,7 @@ func executeInternal(
 	contentType string,
 	endpoint string,
 	extractors map[string]string,
+	headers map[string]string,
 ) (map[string]starlark.Comparable, error) {
 	var response *http.Response
 	var err error
@@ -63,15 +66,7 @@ func executeInternal(
 		return nil, stacktrace.NewError("The service name parameter can't be an empty string")
 	}
 
-	response, err = serviceNetwork.HttpRequestService(
-		ctx,
-		serviceNameStr,
-		portId,
-		method,
-		contentType,
-		endpoint,
-		recipeBodyWithRuntimeValue,
-	)
+	response, err = serviceNetwork.HttpRequestService(ctx, serviceNameStr, portId, method, contentType, endpoint, recipeBodyWithRuntimeValue, headers)
 	if err != nil {
 		return nil, stacktrace.Propagate(err, "An error occurred when running HTTP request recipe")
 	}
@@ -135,6 +130,21 @@ func createStarlarkReturnValueInternal(resultUuid string, extractors map[string]
 	return dict, nil
 }
 
+func convertHeadersToMapStringString(isSet bool, headersStarlarkValue starlark.Value) (map[string]string, *startosis_errors.InterpretationError) {
+	if !isSet {
+		return map[string]string{}, nil
+	}
+	headersDict, ok := headersStarlarkValue.(*starlark.Dict)
+	if !ok {
+		return nil, startosis_errors.NewInterpretationError("expected '%v' to be a starlark dict but got '%v'", headersStarlarkValue, reflect.TypeOf(headersStarlarkValue))
+	}
+	headers, interpretationErr := kurtosis_types.SafeCastToMapStringString(headersDict, HeadersAttr)
+	if interpretationErr != nil {
+		return nil, interpretationErr
+	}
+	return headers, nil
+}
+
 func convertExtractorsToDict(isAttrSet bool, extractorsValue starlark.Value) (map[string]string, *startosis_errors.InterpretationError) {
 	extractorStringMap := map[string]string{}
 	if !isAttrSet {
diff --git a/core/server/api_container/server/startosis_engine/recipe/post_http_request_recipe.go b/core/server/api_container/server/startosis_engine/recipe/post_http_request_recipe.go
index 2264b276f..0fbe041f3 100644
--- a/core/server/api_container/server/startosis_engine/recipe/post_http_request_recipe.go
+++ b/core/server/api_container/server/startosis_engine/recipe/post_http_request_recipe.go
@@ -70,6 +70,15 @@ func NewPostHttpRequestRecipeType() *kurtosis_type_constructor.KurtosisTypeConst
 						return interpretationErr
 					},
 				},
+				{
+					Name:              HeadersAttr,
+					IsOptional:        true,
+					ZeroValueProvider: builtin_argument.ZeroValueProvider[*starlark.Dict],
+					Validator: func(value starlark.Value) *startosis_errors.InterpretationError {
+						_, interpretationErr := convertHeadersToMapStringString(true, value)
+						return interpretationErr
+					},
+				},
 			},
 		},
 		Instantiate: instantiatePostHttpRequestRecipe,
@@ -154,6 +163,16 @@ func (recipe *PostHttpRequestRecipe) Execute(
 		return nil, interpretationErr
 	}
 
+	rawHeaders, found, interpretationErr := kurtosis_type_constructor.ExtractAttrValue[*starlark.Dict](
+		recipe.KurtosisValueTypeDefault, HeadersAttr)
+	if interpretationErr != nil {
+		return nil, interpretationErr
+	}
+	headers, interpretationErr := convertHeadersToMapStringString(found, rawHeaders)
+	if interpretationErr != nil {
+		return nil, interpretationErr
+	}
+
 	serviceNameStr := string(serviceName)
 	if serviceNameStr == "" {
 		return nil, stacktrace.NewError("The service name parameter can't be an empty string")
@@ -170,6 +189,7 @@ func (recipe *PostHttpRequestRecipe) Execute(
 		contentType.GoString(),
 		endpoint.GoString(),
 		extractors,
+		headers,
 	)
 	if err != nil {
 		return nil, stacktrace.Propagate(err, "An error occurred when running HTTP request recipe '%v'", recipe.String())
diff --git a/docs/docs/api-reference/starlark-reference/get-http-request-recipe.md b/docs/docs/api-reference/starlark-reference/get-http-request-recipe.md
index 80bbc30cc..79418b2ef 100644
--- a/docs/docs/api-reference/starlark-reference/get-http-request-recipe.md
+++ b/docs/docs/api-reference/starlark-reference/get-http-request-recipe.md
@@ -28,6 +28,12 @@ get_request_recipe = GetHttpRequestRecipe(
     extract = {
         "extractfield" : ".name.id",
     },
+    
+    # This field allows you to pass custom headers with the GET request
+    # OPTIONAL (Default: {})
+    headers = {
+        "Authorization": "Bearer my.secret.token" 
+    },
 )
 ```
 
diff --git a/docs/docs/api-reference/starlark-reference/post-http-request-recipe.md b/docs/docs/api-reference/starlark-reference/post-http-request-recipe.md
index 1481ee043..d37dc7e70 100644
--- a/docs/docs/api-reference/starlark-reference/post-http-request-recipe.md
+++ b/docs/docs/api-reference/starlark-reference/post-http-request-recipe.md
@@ -31,6 +31,14 @@ post_request_recipe = PostHttpRequestRecipe(
     extract = {
         "extractfield" : ".name.id",
     },
+
+    # This field allows you to pass custom headers with the POST request
+    # Any content type passed through the content_type attribtue will hold preference
+    # over content type passed through this
+    # OPTIONAL (Default: {})
+    headers = {
+        "Authorization": "Bearer my.secret.token"
+    },
 )
 ```
 


Test patch:
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/add_services_framework_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/add_services_framework_test.go
index 8ff41e63a..37d083830 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/add_services_framework_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/add_services_framework_test.go
@@ -127,6 +127,7 @@ func (suite *KurtosisPlanInstructionTestSuite) TestAddServices() {
 		"",
 		testReadyConditionsRecipeEndpoint,
 		"",
+		testEmptyHeaders,
 	).Times(1).Return(&http.Response{
 		Status:     "200 OK",
 		StatusCode: 200,
@@ -155,6 +156,7 @@ func (suite *KurtosisPlanInstructionTestSuite) TestAddServices() {
 		"",
 		testReadyConditions2RecipeEndpoint,
 		"",
+		testEmptyHeaders,
 	).Times(1).Return(&http.Response{
 		Status:     "201 OK",
 		StatusCode: 201,
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/get_http_request_recipe_no_extractor_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/get_http_request_recipe_no_extractor_test.go
index 72dc5d5e4..defd48fbe 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/get_http_request_recipe_no_extractor_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/get_http_request_recipe_no_extractor_test.go
@@ -30,6 +30,7 @@ func (suite *KurtosisTypeConstructorTestSuite) TestGetHttpRequestRecipeNoExtract
 		"",
 		"/test",
 		"",
+		testEmptyHeaders,
 	).Times(1).Return(
 		&http.Response{
 			Status:           "200 OK",
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/get_http_request_recipe_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/get_http_request_recipe_test.go
index 0fcd60750..e9adc24cf 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/get_http_request_recipe_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/get_http_request_recipe_test.go
@@ -34,6 +34,7 @@ func (suite *KurtosisTypeConstructorTestSuite) TestGetHttpRequestRecipe() {
 		"",
 		"/test",
 		"",
+		testEmptyHeaders,
 	).Times(1).Return(
 		&http.Response{
 			Status:           "200 OK",
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/post_http_request_recipe_minimal_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/post_http_request_recipe_minimal_test.go
index 004b6ca89..5e0da0e3f 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/post_http_request_recipe_minimal_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/post_http_request_recipe_minimal_test.go
@@ -30,6 +30,7 @@ func (suite *KurtosisTypeConstructorTestSuite) TestPostHttpRequestRecipeMinimal(
 		"application/json",
 		"/test",
 		"",
+		testEmptyHeaders,
 	).Times(1).Return(
 		&http.Response{
 			Status:           "200 OK",
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/post_http_request_recipe_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/post_http_request_recipe_test.go
index e73f8c762..2a983d97f 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/post_http_request_recipe_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/post_http_request_recipe_test.go
@@ -34,6 +34,7 @@ func (suite *KurtosisTypeConstructorTestSuite) TestPostHttpRequestRecipe() {
 		"application/json",
 		"/test",
 		"{}",
+		map[string]string{"key": "value"},
 	).Times(1).Return(
 		&http.Response{
 			Status:           "200 OK",
@@ -63,7 +64,8 @@ func (suite *KurtosisTypeConstructorTestSuite) TestPostHttpRequestRecipe() {
 
 func (t *postHttpRequestRecipeTestCase) GetStarlarkCode() string {
 	extractors := `{"result": ".value"}`
-	return fmt.Sprintf("%s(%s=%q, %s=%q, %s=%q, %s=%q, %s=%s)", recipe.PostHttpRecipeTypeName, recipe.PortIdAttr, testPrivatePortId, recipe.EndpointAttr, "/test", recipe.RequestBodyAttr, "{}", recipe.ContentTypeAttr, "application/json", recipe.ExtractAttr, extractors)
+	headers := `{"key": "value"}`
+	return fmt.Sprintf("%s(%s=%q, %s=%q, %s=%q, %s=%q, %s=%s, %s=%s)", recipe.PostHttpRecipeTypeName, recipe.PortIdAttr, testPrivatePortId, recipe.EndpointAttr, "/test", recipe.RequestBodyAttr, "{}", recipe.ContentTypeAttr, "application/json", recipe.ExtractAttr, extractors, recipe.HeadersAttr, headers)
 }
 
 func (t *postHttpRequestRecipeTestCase) Assert(typeValue builtin_argument.KurtosisValueType) {
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/request_named_args_framework_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/request_named_args_framework_test.go
index fa9dcaf1b..bc84e1126 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/request_named_args_framework_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/request_named_args_framework_test.go
@@ -42,6 +42,7 @@ func (suite *KurtosisPlanInstructionTestSuite) TestRequestWithNamedArgs() {
 		requestContentType,
 		requestEndpoint,
 		requestBody,
+		testEmptyHeaders,
 	).Times(1).Return(
 		&http.Response{
 			Status:           "200 OK",
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/request_positional_args_framework_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/request_positional_args_framework_test.go
index bf9fb51a7..e69a6991e 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/request_positional_args_framework_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/request_positional_args_framework_test.go
@@ -30,6 +30,7 @@ func (suite *KurtosisPlanInstructionTestSuite) TestRequestWithPositionalArgs() {
 		requestContentType,
 		requestEndpoint,
 		requestBody,
+		testEmptyHeaders,
 	).Times(1).Return(
 		&http.Response{
 			Status:           "200 OK",
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/static_constants.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/static_constants.go
index 903735871..45f580e66 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/static_constants.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/static_constants.go
@@ -115,6 +115,7 @@ var (
 	testReadyConditionsTarget         = "200"
 	testReadyConditionsInterval       = "1s"
 	testReadyConditionsTimeout        = "100ms"
+	testEmptyHeaders                  = map[string]string{}
 
 	testReadyConditions2RecipePortId   = "https"
 	testReadyConditions2RecipeEndpoint = "/user-access"
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/wait_named_args_framework_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/wait_named_args_framework_test.go
index 0583cab90..2b5a013df 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/wait_named_args_framework_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/wait_named_args_framework_test.go
@@ -48,6 +48,7 @@ func (suite *KurtosisPlanInstructionTestSuite) TestWaitWithNamedArgs() {
 		waitRecipeContentType,
 		waitRecipeEndpoint,
 		waitRecipeBody,
+		testEmptyHeaders,
 	).Times(1).Return(
 		&http.Response{
 			Status:           "200 OK",
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/wait_positional_args_framework_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/wait_positional_args_framework_test.go
index 6a833babf..e3c9e8ec4 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/wait_positional_args_framework_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/wait_positional_args_framework_test.go
@@ -32,6 +32,7 @@ func (suite *KurtosisPlanInstructionTestSuite) TestWaitWithPositionalArgs() {
 		waitRecipeContentType,
 		waitRecipeEndpoint,
 		waitRecipeBody,
+		testEmptyHeaders,
 	).Times(1).Return(
 		&http.Response{
 			Status:           "200 OK",
diff --git a/internal_testsuites/golang/testsuite/startosis_request_wait_assert_test/startosis_complex_request_wait_assert_test.go b/internal_testsuites/golang/testsuite/startosis_request_wait_assert_test/startosis_complex_request_wait_assert_test.go
index ae27a8c83..24fd0a8f5 100644
--- a/internal_testsuites/golang/testsuite/startosis_request_wait_assert_test/startosis_complex_request_wait_assert_test.go
+++ b/internal_testsuites/golang/testsuite/startosis_request_wait_assert_test/startosis_complex_request_wait_assert_test.go
@@ -39,16 +39,19 @@ def run(plan):
 		port_id = "http-port",
 		endpoint = "/",
 		content_type="text/plain",
+		headers={"fizz":"buzz"},
 		body=response["extract.exploded-slash"],
 		extract = {
 			"my-body": ".body",
-			"my-content-type": '.headers["content-type"]'
+			"my-content-type": '.headers["content-type"]',
+			"my-headers-fizz": '.headers["fizz"]'
 		}
 	)
 	plan.wait(recipe=post_recipe, field="code", assertion="==", target_value=200, service_name="web-server-complex-request-wait-test")
 	post_response = plan.request(recipe=post_recipe, service_name="web-server-complex-request-wait-test")
 	plan.verify(post_response["code"], "==", 200)
 	plan.verify(post_response["extract.my-content-type"], "==", "text/plain")
+	plan.verify(post_response["extract.my-headers-fizz"], "==", "buzz")
 	plan.verify(post_response["extract.my-body"], "==", "bar")
 	post_recipe_no_body = PostHttpRequestRecipe(
 		port_id = "http-port",