stoobly-agent 1.9.11__py3-none-any.whl → 1.9.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- stoobly_agent/__init__.py +1 -1
- stoobly_agent/app/cli/helpers/shell.py +0 -10
- stoobly_agent/app/cli/scaffold/constants.py +1 -0
- stoobly_agent/app/cli/scaffold/workflow_namesapce.py +8 -2
- stoobly_agent/app/cli/scaffold_cli.py +10 -7
- stoobly_agent/app/proxy/mock/eval_fixtures_service.py +33 -2
- stoobly_agent/test/app/proxy/mock/eval_fixtures_service_test.py +14 -2
- {stoobly_agent-1.9.11.dist-info → stoobly_agent-1.9.12.dist-info}/METADATA +1 -1
- {stoobly_agent-1.9.11.dist-info → stoobly_agent-1.9.12.dist-info}/RECORD +12 -12
- {stoobly_agent-1.9.11.dist-info → stoobly_agent-1.9.12.dist-info}/LICENSE +0 -0
- {stoobly_agent-1.9.11.dist-info → stoobly_agent-1.9.12.dist-info}/WHEEL +0 -0
- {stoobly_agent-1.9.11.dist-info → stoobly_agent-1.9.12.dist-info}/entry_points.txt +0 -0
stoobly_agent/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
COMMAND = 'stoobly-agent'
|
2
|
-
VERSION = '1.9.
|
2
|
+
VERSION = '1.9.12'
|
@@ -1,19 +1,9 @@
|
|
1
|
-
import os
|
2
1
|
import subprocess
|
3
2
|
import sys
|
4
3
|
|
5
|
-
from dotenv import load_dotenv
|
6
|
-
|
7
4
|
DOTENV_PATH = 'STOOBLY_DOTENV_PATH'
|
8
5
|
|
9
6
|
def exec_stream(command):
|
10
|
-
dotenv_path = os.environ.get(DOTENV_PATH)
|
11
|
-
|
12
|
-
if dotenv_path and os.path.exists(dotenv_path):
|
13
|
-
load_dotenv(dotenv_path=dotenv_path)
|
14
|
-
else:
|
15
|
-
load_dotenv()
|
16
|
-
|
17
7
|
# Start the process
|
18
8
|
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
19
9
|
|
@@ -18,6 +18,7 @@ CONFIG_FILE = '.config.yml'
|
|
18
18
|
CONTEXT_DIR_ENV = 'CONTEXT_DIR'
|
19
19
|
DOCKER_NAMESPACE = 'docker'
|
20
20
|
DOTENV_FILE = '.env'
|
21
|
+
DOTENV_PATH_ENV = 'STOOBLY_DOTENV_PATH'
|
21
22
|
NAMESERVERS_FILE = '.nameservers'
|
22
23
|
PUBLIC_FOLDER_NAME = 'public'
|
23
24
|
SERVICE_DETACHED = '${SERVICE_DETACHED}'
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import os
|
2
|
-
|
2
|
+
import shutil
|
3
3
|
|
4
4
|
from .app import App
|
5
|
-
from .constants import DOTENV_FILE, NAMESERVERS_FILE
|
5
|
+
from .constants import DOTENV_PATH_ENV, DOTENV_FILE, NAMESERVERS_FILE
|
6
6
|
|
7
7
|
class WorkflowNamespace():
|
8
8
|
|
@@ -35,6 +35,12 @@ class WorkflowNamespace():
|
|
35
35
|
def traefik_config_path(self):
|
36
36
|
return os.path.join(self.path, 'traefik.yml')
|
37
37
|
|
38
|
+
def copy_dotenv(self):
|
39
|
+
dotenv_path = os.environ.get(DOTENV_PATH_ENV) or '.env'
|
40
|
+
|
41
|
+
if os.path.isfile(dotenv_path):
|
42
|
+
shutil.copy(dotenv_path, self.dotenv_path)
|
43
|
+
|
38
44
|
def traefik_config_relative_path(self, path: str):
|
39
45
|
if not path:
|
40
46
|
return path
|
@@ -89,7 +89,7 @@ def hostname(ctx):
|
|
89
89
|
help="Scaffold application"
|
90
90
|
)
|
91
91
|
@click.option('--app-dir-path', default=current_working_dir, help='Path to create the app scaffold.')
|
92
|
-
@click.option('--docker-socket-path', default='/var/run/docker.sock', help='Path to Docker socket.')
|
92
|
+
@click.option('--docker-socket-path', default='/var/run/docker.sock', type=click.Path(exists=True, file_okay=True, dir_okay=False), help='Path to Docker socket.')
|
93
93
|
@click.option('--quiet', is_flag=True, help='Disable log output.')
|
94
94
|
@click.option('--ui-port', default=4200, type=click.IntRange(1, 65535), help='UI service port.')
|
95
95
|
@click.argument('app_name', callback=validate_app_name)
|
@@ -339,7 +339,7 @@ def copy(**kwargs):
|
|
339
339
|
@click.option('--service', multiple=True, help='Select which services to log. Defaults to all.')
|
340
340
|
@click.option('--user-id', default=os.getuid(), help='OS user ID of the owner of context dir path.')
|
341
341
|
@click.argument('workflow_name')
|
342
|
-
def down(**kwargs):
|
342
|
+
def down(**kwargs):
|
343
343
|
os.environ[env_vars.LOG_LEVEL] = kwargs['log_level']
|
344
344
|
|
345
345
|
containerized = kwargs['containerized']
|
@@ -349,6 +349,7 @@ def down(**kwargs):
|
|
349
349
|
__validate_app(app)
|
350
350
|
|
351
351
|
__with_namespace_defaults(kwargs)
|
352
|
+
__with_workflow_namespace(app, kwargs['namespace'])
|
352
353
|
|
353
354
|
services = __get_services(
|
354
355
|
app, service=kwargs['service'], workflow=[kwargs['workflow_name']]
|
@@ -503,6 +504,7 @@ def up(**kwargs):
|
|
503
504
|
__validate_app(app)
|
504
505
|
|
505
506
|
__with_namespace_defaults(kwargs)
|
507
|
+
workflow_namespace = __with_workflow_namespace(app, kwargs['namespace'])
|
506
508
|
|
507
509
|
services = __get_services(
|
508
510
|
app, service=kwargs['service'], workflow=[kwargs['workflow_name']]
|
@@ -514,11 +516,7 @@ def up(**kwargs):
|
|
514
516
|
|
515
517
|
# Gateway ports are dynamically set depending on the workflow run
|
516
518
|
workflow = Workflow(kwargs['workflow_name'], app)
|
517
|
-
configure_gateway(
|
518
|
-
WorkflowNamespace(app, kwargs['namespace'] or workflow.workflow_name),
|
519
|
-
workflow.service_paths_from_services(services),
|
520
|
-
kwargs['no_publish']
|
521
|
-
)
|
519
|
+
configure_gateway(workflow_namespace, workflow.service_paths_from_services(services), kwargs['no_publish'])
|
522
520
|
|
523
521
|
commands: List[WorkflowRunCommand] = []
|
524
522
|
for service in services:
|
@@ -840,3 +838,8 @@ def __workflow_create(app, **kwargs):
|
|
840
838
|
template=kwargs['template'],
|
841
839
|
workflow_decorators=workflow_decorators
|
842
840
|
)
|
841
|
+
|
842
|
+
def __with_workflow_namespace(app: App, namespace: str):
|
843
|
+
workflow_namespace = WorkflowNamespace(app, namespace)
|
844
|
+
workflow_namespace.copy_dotenv()
|
845
|
+
return workflow_namespace
|
@@ -7,7 +7,7 @@ from io import BytesIO
|
|
7
7
|
from mitmproxy.http import Request as MitmproxyRequest
|
8
8
|
from requests import Response
|
9
9
|
from requests.structures import CaseInsensitiveDict
|
10
|
-
from typing import Union
|
10
|
+
from typing import Optional, Union
|
11
11
|
|
12
12
|
from stoobly_agent.lib.logger import bcolors, Logger
|
13
13
|
from stoobly_agent.config.constants.custom_headers import MOCK_FIXTURE_PATH
|
@@ -62,7 +62,7 @@ def eval_fixtures(request: MitmproxyRequest, **options: Options) -> Union[Respon
|
|
62
62
|
with open(fixture_path, 'rb') as fp:
|
63
63
|
response = Response()
|
64
64
|
|
65
|
-
response.status_code = status_code
|
65
|
+
response.status_code = int(status_code)
|
66
66
|
response.raw = BytesIO(fp.read())
|
67
67
|
headers[MOCK_FIXTURE_PATH] = fixture_path
|
68
68
|
response.headers = headers
|
@@ -71,6 +71,11 @@ def eval_fixtures(request: MitmproxyRequest, **options: Options) -> Union[Respon
|
|
71
71
|
content_type = __guess_content_type(fixture_path)
|
72
72
|
if content_type:
|
73
73
|
response.headers['content-type'] = content_type
|
74
|
+
else:
|
75
|
+
# Default to highest priority accept header
|
76
|
+
content_type = __choose_highest_priority_content_type(request.headers.get('accept'))
|
77
|
+
if content_type:
|
78
|
+
response.headers['content-type'] = content_type
|
74
79
|
|
75
80
|
Logger.instance(LOG_ID).debug(f"{bcolors.OKBLUE}Resolved{bcolors.ENDC} fixture {fixture_path}")
|
76
81
|
|
@@ -125,6 +130,32 @@ def __eval_response_fixtures(request: MitmproxyRequest, response_fixtures: Fixtu
|
|
125
130
|
if path:
|
126
131
|
return fixture
|
127
132
|
|
133
|
+
def __choose_highest_priority_content_type(accept_header: str) -> Optional[str]:
|
134
|
+
if not accept_header:
|
135
|
+
return None
|
136
|
+
|
137
|
+
types = []
|
138
|
+
for part in accept_header.split(","):
|
139
|
+
media_range = part.strip()
|
140
|
+
if ";" in media_range:
|
141
|
+
mime, *params = media_range.split(";")
|
142
|
+
q = 1.0 # default
|
143
|
+
for param in params:
|
144
|
+
param = param.strip()
|
145
|
+
if param.startswith("q="):
|
146
|
+
try:
|
147
|
+
q = float(param[2:])
|
148
|
+
except ValueError:
|
149
|
+
q = 0.0 # invalid q values treated as lowest
|
150
|
+
else:
|
151
|
+
mime = media_range
|
152
|
+
q = 1.0
|
153
|
+
types.append((mime.strip(), q))
|
154
|
+
|
155
|
+
# Sort by descending q
|
156
|
+
types.sort(key=lambda x: -x[1])
|
157
|
+
return types[0][0] if types else None
|
158
|
+
|
128
159
|
def __parse_accept_header(accept_header):
|
129
160
|
types = []
|
130
161
|
for item in accept_header.split(","):
|
@@ -2,6 +2,7 @@ import os
|
|
2
2
|
import pdb
|
3
3
|
import pytest
|
4
4
|
import requests
|
5
|
+
import shutil
|
5
6
|
|
6
7
|
from click.testing import CliRunner
|
7
8
|
from mitmproxy.http import Request as MitmproxyRequest
|
@@ -156,6 +157,14 @@ class TestEvalFixturesService():
|
|
156
157
|
assert res != None
|
157
158
|
return res
|
158
159
|
|
160
|
+
@pytest.fixture()
|
161
|
+
def public_directory_default_response(self, index_file_path: str, mitmproxy_request: MitmproxyRequest, public_directory: str):
|
162
|
+
path = os.path.join(public_directory, 'index')
|
163
|
+
shutil.move(index_file_path, path)
|
164
|
+
res: requests.Response = eval_fixtures(mitmproxy_request, public_directory_path=public_directory)
|
165
|
+
assert res != None
|
166
|
+
return res
|
167
|
+
|
159
168
|
def test_it_sets_contents(
|
160
169
|
self, public_directory_response: requests.Response, index_file_contents: str
|
161
170
|
):
|
@@ -164,5 +173,8 @@ class TestEvalFixturesService():
|
|
164
173
|
def test_it_headers(self, public_directory_response: requests.Response):
|
165
174
|
assert public_directory_response.headers['Content-Type'] == 'text/html'
|
166
175
|
|
167
|
-
def test_it_sets_status_code(self,
|
168
|
-
assert public_directory_response.status_code == 200
|
176
|
+
def test_it_sets_status_code(self, public_directory_response: requests.Response):
|
177
|
+
assert public_directory_response.status_code == 200
|
178
|
+
|
179
|
+
def test_default_it_headers(self, public_directory_default_response: requests.Response):
|
180
|
+
assert public_directory_default_response.headers['Content-Type'] == 'application/json'
|
@@ -1,4 +1,4 @@
|
|
1
|
-
stoobly_agent/__init__.py,sha256=
|
1
|
+
stoobly_agent/__init__.py,sha256=xENhASdGvBATXYrZA-vmnaCPLgkr7RjAYnjGsnkvbrc,45
|
2
2
|
stoobly_agent/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
stoobly_agent/app/api/__init__.py,sha256=ctkB8KR-eXO0SFhj602huHiyvQ3PslFWd8fkcufgrAI,1000
|
4
4
|
stoobly_agent/app/api/application_http_request_handler.py,sha256=Vvz53yB0bR7J-QqMAkLlhcZrA4P64ZEN7w8cMbgl6o0,5261
|
@@ -52,7 +52,7 @@ stoobly_agent/app/cli/helpers/request_synchronize_handler.py,sha256=wawAL8hoZLqO
|
|
52
52
|
stoobly_agent/app/cli/helpers/run_command_service.py,sha256=w9CNDZDj_gxCCXAFFOLONuOVu6_W9f8z1RX3-5RKuTM,731
|
53
53
|
stoobly_agent/app/cli/helpers/scenario_facade.py,sha256=nWcycEZBL87OFCCQx85-5QaK0Q9XXk2-RMeC1uef2_Y,3134
|
54
54
|
stoobly_agent/app/cli/helpers/schema_builder.py,sha256=-R_oU_d8nPNdNA31WDp8lCh7XpCeazLm_1dl_Kq8DLU,1127
|
55
|
-
stoobly_agent/app/cli/helpers/shell.py,sha256=
|
55
|
+
stoobly_agent/app/cli/helpers/shell.py,sha256=vnQuv-wvLepcgSIZrz7e4CsL5HuKhAVYfHKF0WuPrgg,633
|
56
56
|
stoobly_agent/app/cli/helpers/synchronize_request_service.py,sha256=pwsILyrR6XPBJAIVaato0tRrbCT4z5-FymJgfeWTsVw,6018
|
57
57
|
stoobly_agent/app/cli/helpers/tabulate_print_service.py,sha256=d4xtJgn9sueL8nAwOSIyiyzuY1ptsD1wxEdLQe0X2tc,964
|
58
58
|
stoobly_agent/app/cli/helpers/test_facade.py,sha256=gRnbjYNxnzPmtvFp2J6TZgxaMSzDjpAWdb79kaFBt_I,2227
|
@@ -73,7 +73,7 @@ stoobly_agent/app/cli/scaffold/app_config.py,sha256=z4sxZcXZTEoXyUZajUuffuWQN8x8
|
|
73
73
|
stoobly_agent/app/cli/scaffold/app_create_command.py,sha256=HOlXL6Ugid2qHagqDVGl3ksjLKE4WF_3Dji8FoQlpuM,1215
|
74
74
|
stoobly_agent/app/cli/scaffold/command.py,sha256=G4Zp647cuviaEXUdcl7Rbx_qQAr0Z_DS7-Y3MWDC1Qc,281
|
75
75
|
stoobly_agent/app/cli/scaffold/config.py,sha256=HZU5tkvr3dkPr4JMXZtrJlu2wxxO-134Em6jReFFcq0,688
|
76
|
-
stoobly_agent/app/cli/scaffold/constants.py,sha256=
|
76
|
+
stoobly_agent/app/cli/scaffold/constants.py,sha256=8d0YTcPp78mIVOjLeueJkWU6XzC_KxB8ZaU2B-LuDFs,2652
|
77
77
|
stoobly_agent/app/cli/scaffold/containerized_app.py,sha256=dAjn4RwcZV3aEL0POUmrbF_DC-r9h6s1zx7gT2t45v0,175
|
78
78
|
stoobly_agent/app/cli/scaffold/docker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
79
79
|
stoobly_agent/app/cli/scaffold/docker/app_builder.py,sha256=7z5pk5JKlRDHx2USxY-WurttLyyUkIVYfl34_u1x9dE,501
|
@@ -202,10 +202,10 @@ stoobly_agent/app/cli/scaffold/workflow_copy_command.py,sha256=wi8qHH_M2e6jXIPuu
|
|
202
202
|
stoobly_agent/app/cli/scaffold/workflow_create_command.py,sha256=-fwsr6_LvGT8BbBWdGY3Qd8cSQhBOSJiMr1r8s2R86w,3390
|
203
203
|
stoobly_agent/app/cli/scaffold/workflow_env.py,sha256=shPjoX1SWe7K6pGpZvw2fPVHWd6j_azTe58jvOjGUns,607
|
204
204
|
stoobly_agent/app/cli/scaffold/workflow_log_command.py,sha256=Bke4lMOMxuDUFuAx9nlXHbKgYMO4KAg9ASHvjz4aVWc,1372
|
205
|
-
stoobly_agent/app/cli/scaffold/workflow_namesapce.py,sha256=
|
205
|
+
stoobly_agent/app/cli/scaffold/workflow_namesapce.py,sha256=VNaZrcqMMeqrzpPGhD9-oaZems1k0ebRc6wR74EvA8c,1170
|
206
206
|
stoobly_agent/app/cli/scaffold/workflow_run_command.py,sha256=H9s0F8LaoB7ZLUVXWP6M6yPLYk5IE4JD8qgGXntwtMc,11138
|
207
207
|
stoobly_agent/app/cli/scaffold/workflow_validate_command.py,sha256=Uo_yo6rVR1ZR7xpvsQvlH48AyMBVLRupd4G-bRjzm_Q,5584
|
208
|
-
stoobly_agent/app/cli/scaffold_cli.py,sha256=
|
208
|
+
stoobly_agent/app/cli/scaffold_cli.py,sha256=F93zXk9WNRLfiDJ-9MpMB4My7gAJJVHDvV_fKPLsxdA,32896
|
209
209
|
stoobly_agent/app/cli/scenario_cli.py,sha256=3J1EiJOvunkfWrEkOsanw-XrKkOk78ij_GjBlE9p7CE,8229
|
210
210
|
stoobly_agent/app/cli/snapshot_cli.py,sha256=1Dw5JgDlmG6vctrawIRO7CdB73vAQk_wRBnPG2lVOrQ,11929
|
211
211
|
stoobly_agent/app/cli/trace_cli.py,sha256=K7E-vx3JUcqEDSWOdIOi_AieKNQz7dBfmRrVvKDkzFI,4605
|
@@ -331,7 +331,7 @@ stoobly_agent/app/proxy/mitmproxy/response_facade.py,sha256=0wCSzUULUhDDV93QXUgz
|
|
331
331
|
stoobly_agent/app/proxy/mock/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
332
332
|
stoobly_agent/app/proxy/mock/context.py,sha256=vDo5_3WBL73mVFnsmQWvcxvPg5nWtRJbigSrE3zGc-o,794
|
333
333
|
stoobly_agent/app/proxy/mock/custom_not_found_response_builder.py,sha256=0KWB3KFxVrnJOKDaYxm5eoJEccw7IpJZRyUvBX61-8k,697
|
334
|
-
stoobly_agent/app/proxy/mock/eval_fixtures_service.py,sha256=
|
334
|
+
stoobly_agent/app/proxy/mock/eval_fixtures_service.py,sha256=J5CRp_RePD4cHuy0gtXqhA_8GJqXZL0NC0alT9TkjfU,5225
|
335
335
|
stoobly_agent/app/proxy/mock/eval_request_service.py,sha256=A1tcE3wmrC1HwLpz0aRuRw-Nucn0dyHD_yHw5BeQEJU,8146
|
336
336
|
stoobly_agent/app/proxy/mock/hashed_request_decorator.py,sha256=h1ma90fdaYI9LBWpMWMqWBz-RjNwI628O4VuS_uUBX4,5061
|
337
337
|
stoobly_agent/app/proxy/mock/ignored_components_response_builder.py,sha256=E32_E1eSdmPn2SeM_e1jWnqu4xh5w_SnmOs32Shx99E,501
|
@@ -718,7 +718,7 @@ stoobly_agent/test/app/models/schemas/.stoobly/settings.yml,sha256=vLwMjweKOdod6
|
|
718
718
|
stoobly_agent/test/app/models/schemas/.stoobly/tmp/options.json,sha256=OTRzarwus48CTrItedXCrgQttJHSEZonEYc7R_knvYg,2212
|
719
719
|
stoobly_agent/test/app/models/schemas/request_test.py,sha256=9SF43KXbjO-vMr2uObPJlyLeop_JQstl6Jrh0M1A70c,1116
|
720
720
|
stoobly_agent/test/app/proxy/mitmproxy/request_facade_test.py,sha256=sXlzjKVvpORJ8fxEs5Qfc4IC0itTWxqDIzMujGjlW7I,5765
|
721
|
-
stoobly_agent/test/app/proxy/mock/eval_fixtures_service_test.py,sha256=
|
721
|
+
stoobly_agent/test/app/proxy/mock/eval_fixtures_service_test.py,sha256=bPKabyNUEiOV_F3RG6tiLmfc71qEw5SiUfhhdmphUxA,6333
|
722
722
|
stoobly_agent/test/app/proxy/replay/body_parser_service_test.py,sha256=MTC4a3QxrptHzroHAfgrCEzCZ3Ur0Ijyj9_3k-bG0jQ,1228
|
723
723
|
stoobly_agent/test/app/proxy/replay/rewrite_params_service_test.py,sha256=4KVaP48KjCeoZKqY3IdrFAP5Pnb3jO86k8L7ffvz2ZI,3770
|
724
724
|
stoobly_agent/test/app/proxy/replay/trace_context_test.py,sha256=y0oBNC89sp3BG8biOBTiaTopk1LtqjThlA4d6BwAHzM,14462
|
@@ -753,8 +753,8 @@ stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml,sha256=1W
|
|
753
753
|
stoobly_agent/test/mock_data/scaffold/index.html,sha256=qJwuYajKZ4ihWZrJQ3BNObV5kf1VGnnm_vqlPJzdqLE,258
|
754
754
|
stoobly_agent/test/mock_data/uspto.yaml,sha256=6U5se7C3o-86J4m9xpOk9Npias399f5CbfWzR87WKwE,7835
|
755
755
|
stoobly_agent/test/test_helper.py,sha256=m_oAI7tmRYCNZdKfNqISWhMv3e44tjeYViQ3nTUfnos,1007
|
756
|
-
stoobly_agent-1.9.
|
757
|
-
stoobly_agent-1.9.
|
758
|
-
stoobly_agent-1.9.
|
759
|
-
stoobly_agent-1.9.
|
760
|
-
stoobly_agent-1.9.
|
756
|
+
stoobly_agent-1.9.12.dist-info/LICENSE,sha256=o93sj12cdoEOsTCjPaPFsw3Xq0SXs3pPcY-9reE2sEw,548
|
757
|
+
stoobly_agent-1.9.12.dist-info/METADATA,sha256=NZ_3l89VkM5yyJDF7zXVnpiVKWVZeRXdzT54Km0tj8I,3088
|
758
|
+
stoobly_agent-1.9.12.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
759
|
+
stoobly_agent-1.9.12.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
|
760
|
+
stoobly_agent-1.9.12.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|