stoobly-agent 1.9.2__py3-none-any.whl → 1.9.3__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 CHANGED
@@ -1,2 +1,2 @@
1
1
  COMMAND = 'stoobly-agent'
2
- VERSION = '1.9.2'
2
+ VERSION = '1.9.3'
@@ -1,8 +1,5 @@
1
1
  services:
2
2
  stoobly_ui.base:
3
- environment:
4
- SERVICE_NAME: ${SERVICE_NAME}
5
- WORKFLOW_NAME: ${WORKFLOW_NAME}
6
3
  extends:
7
4
  file: ../.docker-compose.base.yml
8
5
  service: context_base
@@ -2,4 +2,8 @@
2
2
 
3
3
  # Add custom initialization here
4
4
 
5
- app_path=$1 # Path to application source files
5
+ app_path=$1 # Path to application source files
6
+
7
+ # For example, the below commands copies files inside a dist folder into the public folder.
8
+ # The public folder is used when no recorded mocks are found.
9
+ #cp -r $app_path/dist/. public
@@ -6,6 +6,7 @@ import sys
6
6
 
7
7
  from io import TextIOWrapper
8
8
  from typing import List
9
+ from urllib.parse import urlparse
9
10
 
10
11
  from stoobly_agent.app.cli.helpers.certificate_authority import CertificateAuthority
11
12
  from stoobly_agent.app.cli.helpers.shell import exec_stream
@@ -148,10 +149,10 @@ def create(**kwargs):
148
149
  sys.exit(1)
149
150
 
150
151
  if kwargs.get('hostname'):
151
- hostname_regex = re.compile(r'^[a-zA-Z0-9.-]+$')
152
- if not re.search(hostname_regex, kwargs['hostname']):
153
- print(f"Error: {kwargs['hostname']} is invalid.", file=sys.stderr)
154
- sys.exit(1)
152
+ __validate_hostname(kwargs.get('hostname'))
153
+
154
+ if kwargs.get("proxy_mode"):
155
+ __validate_proxy_mode(kwargs.get("proxy_mode"))
155
156
 
156
157
  app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
157
158
 
@@ -216,6 +217,13 @@ def delete(**kwargs):
216
217
  @click.option('--port', type=click.IntRange(1, 65535), help='Service port.')
217
218
  @click.option('--priority', default=5, type=click.FloatRange(1.0, 9.0), help='Determines the service run order. Lower values run first.')
218
219
  @click.option('--scheme', type=click.Choice(['http', 'https']), help='Defaults to https if hostname is set.')
220
+ @click.option('--name', type=click.STRING, help='New name of the service to update to.')
221
+ @click.option('--proxy-mode', help='''
222
+ Proxy mode can be "regular", "transparent", "socks5",
223
+ "reverse:SPEC", or "upstream:SPEC". For reverse and
224
+ upstream proxy modes, SPEC is host specification in
225
+ the form of "http[s]://host[:port]".
226
+ ''')
219
227
  @click.argument('service_name')
220
228
  def update(**kwargs):
221
229
  app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
@@ -228,7 +236,20 @@ def update(**kwargs):
228
236
  service_config = ServiceConfig(service.dir_path)
229
237
 
230
238
  if kwargs['hostname']:
231
- service_config.hostname = kwargs['hostname']
239
+ __validate_hostname(kwargs['hostname'])
240
+
241
+ old_hostname = service_config.hostname
242
+
243
+ if old_hostname != kwargs['hostname']:
244
+ service_config.hostname = kwargs['hostname']
245
+
246
+ # If this is the default proxy_mode and the origin matches the original hostname, assume it is safe to update with the new hostname
247
+ if service_config.proxy_mode.startswith("reverse:"):
248
+ old_origin = service_config.proxy_mode.split("reverse:")[1]
249
+ parsed_origin_url = urlparse(old_origin)
250
+
251
+ if old_hostname == parsed_origin_url.hostname:
252
+ service_config.proxy_mode = service_config.proxy_mode.replace(old_hostname, service_config.hostname)
232
253
 
233
254
  if kwargs['priority']:
234
255
  service_config.priority = kwargs['priority']
@@ -239,6 +260,10 @@ def update(**kwargs):
239
260
  if kwargs['scheme']:
240
261
  service_config.scheme = kwargs['scheme']
241
262
 
263
+ if kwargs['proxy_mode']:
264
+ __validate_proxy_mode(kwargs['proxy_mode'])
265
+ service_config.proxy_mode = kwargs['proxy_mode']
266
+
242
267
  service_config.write()
243
268
 
244
269
  @workflow.command(
@@ -759,7 +784,42 @@ def __validate_app_dir(app_dir_path):
759
784
 
760
785
  def __validate_service_dir(service_dir_path):
761
786
  if not os.path.exists(service_dir_path):
762
- print(f"Error: {service_dir_path} does not exist, please scaffold this service", file=sys.stderr)
787
+ print(f"Error: '{service_dir_path}' does not exist, please scaffold this service", file=sys.stderr)
788
+ sys.exit(1)
789
+
790
+ def __validate_proxy_mode(proxy_mode: str) -> None:
791
+ valid_exact_matches = {
792
+ "regular": None,
793
+ "transparent": None,
794
+ "socks5": None,
795
+ }
796
+
797
+ valid_prefixes = {
798
+ "reverse": None,
799
+ "upstream": None
800
+ }
801
+
802
+ if proxy_mode in valid_exact_matches:
803
+ return
804
+
805
+ split_str = proxy_mode.split(":", 1)
806
+ if len(split_str) != 2:
807
+ print(f"Error: {proxy_mode} is invalid.", file=sys.stderr)
808
+ sys.exit(1)
809
+
810
+ prefix = split_str[0]
811
+ spec = split_str[1]
812
+
813
+ if prefix not in valid_prefixes:
814
+ print(f"Error: {proxy_mode} is invalid.", file=sys.stderr)
815
+ sys.exit(1)
816
+
817
+ # TODO: validate SPEC
818
+
819
+ def __validate_hostname(hostname: str) -> None:
820
+ hostname_regex = re.compile(r'^[a-zA-Z0-9.-]+$')
821
+ if not re.search(hostname_regex, hostname):
822
+ print(f"Error: {hostname} is invalid.", file=sys.stderr)
763
823
  sys.exit(1)
764
824
 
765
825
  def __workflow_create(app, **kwargs):
@@ -17,9 +17,7 @@ class JoinedRequestAdapter():
17
17
  if isinstance(payloads_delimitter, str):
18
18
  payloads_delimitter = payloads_delimitter.encode()
19
19
 
20
- self.__split_joined_request_string = joined_request_string.split(payloads_delimitter)
21
- if len(self.__split_joined_request_string) != 2:
22
- self.__split_joined_request_string = joined_request_string.split(payloads_delimitter.replace(b"\n", b"\r\n"))
20
+ self.__split_joined_request_string = self.raw_request_split(joined_request_string, payloads_delimitter)
23
21
 
24
22
  if len(self.__split_joined_request_string) != 2:
25
23
  raise ValueError(f"Could not split by {payloads_delimitter}")
@@ -47,7 +45,7 @@ class JoinedRequestAdapter():
47
45
  request_string = RequestString(None)
48
46
 
49
47
  delimitter = RequestStringCLRF
50
- request_string_toks = self.__split_joined_request_string[0].split(delimitter)
48
+ request_string_toks = self.repaired_string_toks(self.__split_joined_request_string[0], delimitter)
51
49
  request_string.set(self.raw_request_string or delimitter.join(request_string_toks[1:]))
52
50
  request_string.control = request_string_toks[0]
53
51
 
@@ -57,7 +55,7 @@ class JoinedRequestAdapter():
57
55
  response_string = ResponseString(None, None)
58
56
 
59
57
  delimitter = ResponseStringCLRF
60
- response_string_toks = self.__split_joined_request_string[1].split(delimitter)
58
+ response_string_toks = self.repaired_string_toks(self.__split_joined_request_string[1], delimitter)
61
59
  response_string.set(self.raw_response_string or delimitter.join(response_string_toks[1:]))
62
60
  response_string.control = response_string_toks[0]
63
61
 
@@ -68,4 +66,38 @@ class JoinedRequestAdapter():
68
66
 
69
67
  joined_request.request_string = self.build_request_string()
70
68
  joined_request.response_string = self.build_response_string()
71
- return joined_request
69
+ return joined_request
70
+
71
+ # If all CRLF characters have been replaced with LF e.g. visual studio code
72
+ # Then try to repair the raw string, see https://github.com/Stoobly/stoobly-agent/issues/415
73
+ @staticmethod
74
+ def repaired_string_toks(raw_string: bytes, delimitter: bytes):
75
+ toks = raw_string.split(delimitter)
76
+
77
+ if len(toks) == 1:
78
+ lf = b"\n"
79
+ toks = raw_string.split(lf)
80
+
81
+ # See for request: https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html
82
+ # See for response: https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html
83
+ i = 0
84
+ for line in toks:
85
+ i += 1
86
+
87
+ # On two lf characters, then the following lines are the body
88
+ if line == b'':
89
+ break
90
+
91
+ toks = toks[:i] + [lf.join(toks[i:])]
92
+
93
+ if len(toks) == 1:
94
+ raise ValueError(f"Could not split request by {delimitter}")
95
+
96
+ return toks
97
+
98
+ @staticmethod
99
+ def raw_request_split(raw_string: bytes, payloads_delimitter = REQUEST_DELIMITTER):
100
+ toks = raw_string.split(payloads_delimitter)
101
+ if len(toks) != 2:
102
+ toks = raw_string.split(payloads_delimitter.replace(b"\n", b"\r\n"))
103
+ return toks
@@ -2,10 +2,10 @@ import pdb
2
2
 
3
3
  from typing import List
4
4
 
5
+ from stoobly_agent.app.models.adapters.joined_request_adapter import JoinedRequestAdapter
5
6
  from stoobly_agent.app.models.factories.resource.local_db.helpers.log import Log
6
7
  from stoobly_agent.app.models.factories.resource.local_db.helpers.request_snapshot import RequestSnapshot
7
8
  from stoobly_agent.app.models.factories.resource.local_db.helpers.scenario_snapshot import ScenarioSnapshot
8
- from stoobly_agent.app.proxy.record import REQUEST_STRING_CLRF
9
9
  from stoobly_agent.app.settings import Settings
10
10
  from stoobly_agent.lib.logger import bcolors
11
11
 
@@ -165,7 +165,12 @@ class Apply():
165
165
  self.__logger(f"{bcolors.WARNING}Skipping Request{bcolors.ENDC} {error}")
166
166
  return error, 301
167
167
 
168
- return self.__put_request(uuid, raw_request)
168
+ res, status = self.__put_request(uuid, raw_request)
169
+
170
+ if status != 200:
171
+ return f"{res} {snapshot.path}", status
172
+
173
+ return res, status
169
174
 
170
175
  def __apply_delete_scenario(self, uuid: str):
171
176
  res, status = self.scenario_model.destroy(uuid, force=self.__force)
@@ -227,8 +232,8 @@ class Apply():
227
232
 
228
233
  if not raw_request:
229
234
  return f"{request_snapshot.path} is missing", 400
230
-
231
- toks = raw_request.split(REQUEST_STRING_CLRF, 1)
235
+
236
+ toks = JoinedRequestAdapter.raw_request_split(raw_request)
232
237
  if len(toks) != 2:
233
238
  return f"{request_snapshot.path} contains an invalid request", 400
234
239
 
@@ -236,7 +241,7 @@ class Apply():
236
241
  res, status = self.__put_request(uuid, raw_request, scenario_id=scenario['id'])
237
242
 
238
243
  if status != 200:
239
- return res, status
244
+ return f"{res} {request_snapshot.path}", status
240
245
 
241
246
  snapshot_requests[uuid] = res
242
247
 
@@ -274,8 +279,6 @@ class Apply():
274
279
 
275
280
  if self.__logger and status == 200:
276
281
  self.__logger(f"{bcolors.OKGREEN}Created Request{bcolors.ENDC} {res['list'][0]['url']}")
277
- else:
278
- self.__logger(f"{bcolors.FAIL}{status}{bcolors.ENDC} {res}")
279
282
  elif status == 200:
280
283
  params = {
281
284
  'is_deleted': False,
@@ -287,7 +290,5 @@ class Apply():
287
290
  if self.__logger:
288
291
  if status == 200:
289
292
  self.__logger(f"{bcolors.OKCYAN}Updated Request{bcolors.ENDC} {res['url']}")
290
- else:
291
- self.__logger(f"{bcolors.FAIL}{status}{bcolors.ENDC} {res}")
292
293
 
293
294
  return res, status
@@ -0,0 +1,38 @@
1
+ import pytest
2
+
3
+ from stoobly_agent.app.models.adapters.joined_request_adapter import RequestStringCLRF, JoinedRequestAdapter
4
+
5
+ class TestJoindRequestStringAdapter():
6
+
7
+ @pytest.fixture(scope='class', autouse=True)
8
+ def corrupted_raw_string(self):
9
+ toks = [
10
+ b"control",
11
+ b"header1",
12
+ b"header2",
13
+ b'',
14
+ b'body1',
15
+ b'body2'
16
+ ]
17
+ return b"\n".join(toks)
18
+
19
+ @pytest.fixture(scope='class', autouse=True)
20
+ def repaired_toks(self, corrupted_raw_string: bytes):
21
+ # [b'control', b'header1', b'header2', b'', b'body1\nbody2']
22
+ return JoinedRequestAdapter.repaired_string_toks(corrupted_raw_string, RequestStringCLRF)
23
+
24
+ def test_control(self, repaired_toks: list):
25
+ assert repaired_toks[0] == b'control'
26
+
27
+ def test_header1(self, repaired_toks: list):
28
+ assert repaired_toks[1] == b'header1'
29
+
30
+ def test_header2(self, repaired_toks: list):
31
+ assert repaired_toks[2] == b'header2'
32
+
33
+ def test_clrf(self, repaired_toks: list):
34
+ assert repaired_toks[3] == b''
35
+
36
+ def test_body(self, repaired_toks: list):
37
+ assert repaired_toks[4] == b'body1\nbody2'
38
+
@@ -1 +1 @@
1
- 1.9.0
1
+ 1.9.3
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: stoobly-agent
3
- Version: 1.9.2
3
+ Version: 1.9.3
4
4
  Summary: Record, mock, and test HTTP(s) requests. CLI agent for Stoobly
5
5
  License: Apache-2.0
6
6
  Author: Matt Le
@@ -1,4 +1,4 @@
1
- stoobly_agent/__init__.py,sha256=epZElDe2ihHM7JdgjopRIH49aMQpYH4SYIjmxXXMnY0,44
1
+ stoobly_agent/__init__.py,sha256=vWRmKJsuKpHHO4MRnGJ8EzKAw6gjkI7dsgVj0IsJ-DA,44
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
@@ -142,7 +142,7 @@ stoobly_agent/app/cli/scaffold/templates/app/gateway/mock/.docker-compose.mock.y
142
142
  stoobly_agent/app/cli/scaffold/templates/app/gateway/record/.docker-compose.record.yml,sha256=eyLH2h33Peunus8M1sUKL9AALCG2ABhV_heiJKhvgwo,138
143
143
  stoobly_agent/app/cli/scaffold/templates/app/gateway/test/.docker-compose.test.yml,sha256=oJO6i0lsuQaQeIH80yoPZo3Vs0LzUAH2WRl853yLq6g,136
144
144
  stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/.config.yml,sha256=XnLQZMzzMMIwVycjyPN5QXsmRztkTFAna1kIHYuDfJQ,19
145
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/.docker-compose.base.yml,sha256=bEmlH0ga_p3vsYZFagMGxvw47KscURmbYrfegMZb1CI,202
145
+ stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/.docker-compose.base.yml,sha256=bxrtZqf3YtaJCukzScslh5PgWC5q8xkGIP1wKJf33LA,111
146
146
  stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/.docker-compose.exec.yml,sha256=JN89sU5uRf6YqHvN_O63K8rwQIAPJHbhFDLFmuUjKNM,304
147
147
  stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/mock/.docker-compose.mock.yml,sha256=FnCn64DjxyAiB2P_1JUwFmXslMR961nVZHkYiEXytlg,232
148
148
  stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/record/.docker-compose.record.yml,sha256=t34FNYZboJSfrKnIB2oJ3UuE_mJaW77-hcbSn3sfWec,235
@@ -188,7 +188,7 @@ stoobly_agent/app/cli/scaffold/templates/workflow/record/bin/configure,sha256=5k
188
188
  stoobly_agent/app/cli/scaffold/templates/workflow/record/bin/init,sha256=EaoFDyoJbHc9Ui8ELYKmfweXAycJptVOQblszeh3XTE,94
189
189
  stoobly_agent/app/cli/scaffold/templates/workflow/record/lifecycle_hooks.py,sha256=4vaVc_gnDTCLEqtcZybIk5dcmXrKmGuesF6gc3-_kX8,473
190
190
  stoobly_agent/app/cli/scaffold/templates/workflow/test/bin/configure,sha256=GAU7AfSPcyDSI9RJ7mynT83YqgN9r_E9HZYx0RXE1lU,279
191
- stoobly_agent/app/cli/scaffold/templates/workflow/test/bin/init,sha256=EaoFDyoJbHc9Ui8ELYKmfweXAycJptVOQblszeh3XTE,94
191
+ stoobly_agent/app/cli/scaffold/templates/workflow/test/bin/init,sha256=_jnP53I1yyCtv5TXOnMtQcEMbU43tpZ-za7s8Ely6P0,281
192
192
  stoobly_agent/app/cli/scaffold/templates/workflow/test/fixtures.yml,sha256=CJlZ_kugygZpmyqIauBjNZxqk7XyLaa3yl3AWj8KV28,259
193
193
  stoobly_agent/app/cli/scaffold/templates/workflow/test/lifecycle_hooks.py,sha256=U7mlzT_wBR3uhHSG6CAyt5tBUNAvdIrCw33gdB-F294,467
194
194
  stoobly_agent/app/cli/scaffold/templates/workflow/test/public/.gitignore,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -203,7 +203,7 @@ stoobly_agent/app/cli/scaffold/workflow_env.py,sha256=x8V5pJmIiklD3f2q2-qq-CORf4
203
203
  stoobly_agent/app/cli/scaffold/workflow_log_command.py,sha256=Bke4lMOMxuDUFuAx9nlXHbKgYMO4KAg9ASHvjz4aVWc,1372
204
204
  stoobly_agent/app/cli/scaffold/workflow_run_command.py,sha256=eF3aaK4OIZXYuSBEAeBnhAL7EZrS1G4mSYrJbEiXt2o,11082
205
205
  stoobly_agent/app/cli/scaffold/workflow_validate_command.py,sha256=Uo_yo6rVR1ZR7xpvsQvlH48AyMBVLRupd4G-bRjzm_Q,5584
206
- stoobly_agent/app/cli/scaffold_cli.py,sha256=zrXf2nUI5jRnf6x-j3kKmia8vH_AngjpweVnjdD_R3Q,30075
206
+ stoobly_agent/app/cli/scaffold_cli.py,sha256=DFGhuCV_vugJj2o_44dypYOIwX-IY5LRWuNt3sImcfY,31946
207
207
  stoobly_agent/app/cli/scenario_cli.py,sha256=3J1EiJOvunkfWrEkOsanw-XrKkOk78ij_GjBlE9p7CE,8229
208
208
  stoobly_agent/app/cli/snapshot_cli.py,sha256=Uf6g6ivsD0hUY8G99eU0fxzS3FymncAhI70PxV7Uaac,11919
209
209
  stoobly_agent/app/cli/trace_cli.py,sha256=K7E-vx3JUcqEDSWOdIOi_AieKNQz7dBfmRrVvKDkzFI,4605
@@ -216,7 +216,7 @@ stoobly_agent/app/cli/types/snapshot_migration.py,sha256=4_Re46FKjsflcTOO3qhNsbW
216
216
  stoobly_agent/app/cli/types/test.py,sha256=1c458B7DFBWsEk5Q1CrZ2CUi84YzEzcs-W4qTcudwAk,714
217
217
  stoobly_agent/app/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
218
218
  stoobly_agent/app/models/adapters/__init__.py,sha256=cEEE--Bvrvk6DAsHx_uPgFhLnZJETP4zSBtWjMqyIKc,233
219
- stoobly_agent/app/models/adapters/joined_request_adapter.py,sha256=PUVhrZL_kYBasFByfcN78OHQ4aCeX9E7y2SLwn07_Vs,2591
219
+ stoobly_agent/app/models/adapters/joined_request_adapter.py,sha256=fSq16n3AAlxi8KJdBESHp3JGio_M9uzMnHbnQU8VI3w,3598
220
220
  stoobly_agent/app/models/adapters/mitmproxy/__init__.py,sha256=f14D_0y3_Pz6NpRXQMIwJQiWBGhwKk0Wk_AmlY3twh0,105
221
221
  stoobly_agent/app/models/adapters/mitmproxy/request/__init__.py,sha256=UZeK_-vxQKD02Tuu-YHBtpR92k5mK3XFgwmd99h2VHA,281
222
222
  stoobly_agent/app/models/adapters/mitmproxy/request/python_adapter.py,sha256=lWSppm63oOv7RDmTsUI0EmQkUWlQhRGdjtViBEDU-AA,377
@@ -287,7 +287,7 @@ stoobly_agent/app/models/factories/resource/stoobly/request_adapter.py,sha256=Zr
287
287
  stoobly_agent/app/models/factories/resource/stoobly/scenario_adapter.py,sha256=HnM4g5Qdv16QXj8u4JCiJm2Dbw9OhAxmn9e_R8oaHG4,1105
288
288
  stoobly_agent/app/models/header_model.py,sha256=m91upRZr8GfE5um0d5dguUESKigBMWhSyu_X3HFk28Y,1406
289
289
  stoobly_agent/app/models/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
290
- stoobly_agent/app/models/helpers/apply.py,sha256=ev8QmDvV7flFo82JUA6kBkofYCJ_lNXQGVIpknB94g8,8501
290
+ stoobly_agent/app/models/helpers/apply.py,sha256=VWHZnZ0BnpyyO1MU6eyohimn1HGQClkDQuvYk51BttA,8491
291
291
  stoobly_agent/app/models/helpers/create_request_params_service.py,sha256=o_VB2FsTGBX55UBBw1yQ8MtsJ4-0YXcxd4kNQ9l21nM,2070
292
292
  stoobly_agent/app/models/model.py,sha256=77ZTByQmH5sWBcSrCF3kG_C4muHggcFyH1DWsOhIgvg,1180
293
293
  stoobly_agent/app/models/query_param_model.py,sha256=EBj76phSJ9_45KgP0vIZGbkkG6-tSn_U1fNW_7qLy_4,1455
@@ -693,6 +693,7 @@ stoobly_agent/test/app/cli/snapshot/snapshot_copy_test.py,sha256=Yg78-FhSiG_r6Jp
693
693
  stoobly_agent/test/app/cli/snapshot/snapshot_migrate_test.py,sha256=voEvblK6CMGCrSJDTHVmkUkLXj0auNb78jxlGiiBBQQ,7370
694
694
  stoobly_agent/test/app/cli/snapshot/snapshot_prune_test.py,sha256=bn4yUU7Eb4-6GnwnRaPZPi5Cn7XEaIsrJ_mB7jydgWw,6693
695
695
  stoobly_agent/test/app/cli/snapshot/snapshot_update_test.py,sha256=fILsX2M5j4wuLRP6LJTHe4CPB8gvaEbsSoYmFCHmKVk,4514
696
+ stoobly_agent/test/app/models/adapters/joined_rquest_adapter_test.py,sha256=bF7WMrAiASQDNzDTvIXGJhsWLNhfYOmdQpSDo0hyWYY,1098
696
697
  stoobly_agent/test/app/models/adapters/orm/joined_request_string_adapter_test.py,sha256=a2IHTk3l7aiLyYF7vtqissrk0MFTF2wlUBiaKWyJKfU,2667
697
698
  stoobly_agent/test/app/models/adapters/orm/request/orm_mitmproxy_request_adapter_test.py,sha256=PbJsAaxPUEbF9vM7DX4z858biWf4qlGnvE8KBuy8SgY,2763
698
699
  stoobly_agent/test/app/models/adapters/orm/request/orm_python_request_adapter_test.py,sha256=1rHywokXUj7z3laHhfnei8j1GVmAHDOULvRWmtIyWuQ,2488
@@ -707,7 +708,7 @@ stoobly_agent/test/app/models/factories/resource/local_db/helpers/log_test.py,sh
707
708
  stoobly_agent/test/app/models/factories/resource/local_db/helpers/tiebreak_scenario_request_test.py,sha256=a1SFLyEyRRLuADvAw6ckQQKORFXvyK1lyrbkaLWx8oU,3399
708
709
  stoobly_agent/test/app/models/factories/resource/local_db/request_adapter_test.py,sha256=Pzq1cBPnP9oSWG-p0c-VoymoHxgp483QmNwmV1b78RA,8453
709
710
  stoobly_agent/test/app/models/factories/resource/local_db/response_adapter_test.py,sha256=9P95EKH5rZGOrmRkRIDlQZqtiLJHk9735og18Ffwpfw,2204
710
- stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=dxfL-Qxjo7CWAIdjoCBmI5kW-pkW-YJU0ao7JHCDD80,5
711
+ stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=JyvJHgCQJn-THkr7jL9H-s1Ea2VWcQz-X3BiHK64uxk,6
711
712
  stoobly_agent/test/app/models/schemas/.stoobly/db/stoobly_agent.sqlite3,sha256=ch8gNx6zIelLKQx65gwFx_LRNqUD3EC5xcHZ0ukIQiU,188416
712
713
  stoobly_agent/test/app/models/schemas/.stoobly/settings.yml,sha256=vLwMjweKOdod6tSLtIlyBefPQuNXq9wio4kBaODKtAU,726
713
714
  stoobly_agent/test/app/models/schemas/.stoobly/tmp/options.json,sha256=OTRzarwus48CTrItedXCrgQttJHSEZonEYc7R_knvYg,2212
@@ -748,8 +749,8 @@ stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml,sha256=1W
748
749
  stoobly_agent/test/mock_data/scaffold/index.html,sha256=qJwuYajKZ4ihWZrJQ3BNObV5kf1VGnnm_vqlPJzdqLE,258
749
750
  stoobly_agent/test/mock_data/uspto.yaml,sha256=6U5se7C3o-86J4m9xpOk9Npias399f5CbfWzR87WKwE,7835
750
751
  stoobly_agent/test/test_helper.py,sha256=m_oAI7tmRYCNZdKfNqISWhMv3e44tjeYViQ3nTUfnos,1007
751
- stoobly_agent-1.9.2.dist-info/LICENSE,sha256=o93sj12cdoEOsTCjPaPFsw3Xq0SXs3pPcY-9reE2sEw,548
752
- stoobly_agent-1.9.2.dist-info/METADATA,sha256=qMOKulRLao6AQJC0ctx4h0IyYP6Fd-ACe5NtoyuIY1U,3087
753
- stoobly_agent-1.9.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
754
- stoobly_agent-1.9.2.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
755
- stoobly_agent-1.9.2.dist-info/RECORD,,
752
+ stoobly_agent-1.9.3.dist-info/LICENSE,sha256=o93sj12cdoEOsTCjPaPFsw3Xq0SXs3pPcY-9reE2sEw,548
753
+ stoobly_agent-1.9.3.dist-info/METADATA,sha256=2T7T6OEFqeOhMH4V-af3VMftzxq-mIRn-nOcFd6-Crc,3087
754
+ stoobly_agent-1.9.3.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
755
+ stoobly_agent-1.9.3.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
756
+ stoobly_agent-1.9.3.dist-info/RECORD,,