stoobly-agent 1.7.2__py3-none-any.whl → 1.8.0__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.
Files changed (26) hide show
  1. stoobly_agent/__init__.py +1 -1
  2. stoobly_agent/app/cli/scaffold/constants.py +0 -3
  3. stoobly_agent/app/cli/scaffold/docker/constants.py +0 -1
  4. stoobly_agent/app/cli/scaffold/docker/service/builder.py +10 -4
  5. stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py +50 -23
  6. stoobly_agent/app/cli/scaffold/docker/workflow/decorators_factory.py +2 -2
  7. stoobly_agent/app/cli/scaffold/service_config.py +10 -0
  8. stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py +0 -29
  9. stoobly_agent/app/cli/scaffold/templates/__init__.py +2 -2
  10. stoobly_agent/app/cli/scaffold/templates/app/gateway/.docker-compose.base.template.yml +5 -5
  11. stoobly_agent/app/cli/scaffold/templates/build/services/build/mock/.configure +6 -0
  12. stoobly_agent/app/cli/scaffold/templates/build/services/build/record/.configure +6 -0
  13. stoobly_agent/app/cli/scaffold/templates/build/services/build/test/.configure +6 -0
  14. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/mock/.configure +0 -6
  15. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/record/.configure +0 -6
  16. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/test/.configure +0 -6
  17. stoobly_agent/app/cli/scaffold/templates/constants.py +5 -5
  18. stoobly_agent/app/cli/scaffold/templates/factory.py +5 -7
  19. stoobly_agent/app/cli/scaffold_cli.py +11 -0
  20. stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
  21. {stoobly_agent-1.7.2.dist-info → stoobly_agent-1.8.0.dist-info}/METADATA +1 -1
  22. {stoobly_agent-1.7.2.dist-info → stoobly_agent-1.8.0.dist-info}/RECORD +25 -26
  23. stoobly_agent/app/cli/scaffold/templates/run/nginx.tmpl +0 -1060
  24. {stoobly_agent-1.7.2.dist-info → stoobly_agent-1.8.0.dist-info}/LICENSE +0 -0
  25. {stoobly_agent-1.7.2.dist-info → stoobly_agent-1.8.0.dist-info}/WHEEL +0 -0
  26. {stoobly_agent-1.7.2.dist-info → stoobly_agent-1.8.0.dist-info}/entry_points.txt +0 -0
stoobly_agent/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
1
  COMMAND = 'stoobly-agent'
2
- VERSION = '1.7.2'
2
+ VERSION = '1.8.0'
@@ -40,9 +40,6 @@ STOOBLY_HOME_DIR = '/home/stoobly'
40
40
  STOOBLY_DATA_DIR = os.path.join(STOOBLY_HOME_DIR, DATA_DIR_NAME)
41
41
  STOOBLY_CERTS_DIR = os.path.join(STOOBLY_DATA_DIR, CERTS_DIR_NAME)
42
42
  USER_ID_ENV = 'USER_ID'
43
- VIRTUAL_HOST_ENV = 'VIRTUAL_HOST'
44
- VIRTUAL_PORT_ENV = 'VIRTUAL_PORT'
45
- VIRTUAL_PROTO_ENV = 'VIRTUAL_PROTO'
46
43
  WORKFLOW_CONTAINER_CONFIGURE = 'configure'
47
44
  WORKFLOW_CONTAINER_INIT = 'init'
48
45
  WORKFLOW_CONTAINER_PROXY = 'proxy'
@@ -10,7 +10,6 @@ DOCKER_COMPOSE_CUSTOM = 'docker-compose.yml'
10
10
  DOCKER_COMPOSE_NETWORKS = '.docker-compose.networks.yml'
11
11
  DOCKERFILE_CONTEXT = '.Dockerfile.context'
12
12
  DOCKERFILE_SERVICE = 'Dockerfile.source'
13
- GATEWAY_NGINX_TEMPLATE = 'nginx.tmpl'
14
13
 
15
14
  # TODO: add scaffold container name templates here
16
15
 
@@ -91,22 +91,28 @@ class ServiceBuilder(Builder):
91
91
  if not self.config.hostname:
92
92
  return
93
93
 
94
+ service_id = self.config.id
94
95
  environment = { **self.env_dict() }
96
+ labels = [
97
+ 'traefik.enable=true',
98
+ f"traefik.http.routers.{service_id}.rule=Host(`{SERVICE_HOSTNAME}`)",
99
+ f"traefik.http.services.{service_id}.loadbalancer.server.port={SERVICE_PORT}"
100
+ ]
95
101
  volumes = []
96
102
 
97
- environment['VIRTUAL_HOST'] = SERVICE_HOSTNAME
98
- environment['VIRTUAL_PORT'] = SERVICE_PORT
99
- environment['VIRTUAL_PROTO'] = SERVICE_SCHEME
100
-
101
103
  if self.config.detached:
102
104
  self.__with_detached_volumes(volumes)
103
105
 
106
+ if self.config.tls:
107
+ labels.append(f"traefik.http.routers.{service_id}.tls=true")
108
+
104
109
  base = {
105
110
  'environment': environment,
106
111
  'extends': {
107
112
  'file': os.path.relpath(self.app_builder.compose_file_path, self.dir_path),
108
113
  'service': self.extends_service
109
114
  },
115
+ 'labels': labels,
110
116
  'working_dir': self.__working_dir,
111
117
  }
112
118
 
@@ -1,6 +1,5 @@
1
1
  import os
2
2
  import pdb
3
- import shutil
4
3
  import yaml
5
4
 
6
5
  from typing import List
@@ -8,9 +7,8 @@ from typing import List
8
7
  from stoobly_agent.config.data_dir import DATA_DIR_NAME, TMP_DIR_NAME
9
8
  from stoobly_agent.app.cli.scaffold.constants import APP_DIR
10
9
  from stoobly_agent.app.cli.scaffold.service_config import ServiceConfig
11
- from stoobly_agent.app.cli.scaffold.docker.constants import APP_INGRESS_NETWORK_NAME, APP_EGRESS_NETWORK_NAME, DOCKER_COMPOSE_BASE, DOCKER_COMPOSE_BASE_TEMPLATE, GATEWAY_NGINX_TEMPLATE
10
+ from stoobly_agent.app.cli.scaffold.docker.constants import APP_INGRESS_NETWORK_NAME, APP_EGRESS_NETWORK_NAME, DOCKER_COMPOSE_BASE, DOCKER_COMPOSE_BASE_TEMPLATE
12
11
  from stoobly_agent.app.cli.scaffold.templates.constants import CORE_GATEWAY_SERVICE_NAME
13
- from stoobly_agent.app.cli.scaffold.templates import run_template_path
14
12
 
15
13
  def configure_gateway(service_paths: List[str], no_publish = False):
16
14
  if len(service_paths) == 0:
@@ -38,7 +36,7 @@ def configure_gateway(service_paths: List[str], no_publish = False):
38
36
  gateway_base['ports'] = ports
39
37
 
40
38
  app_dir_path = os.path.dirname(os.path.dirname(service_dir_path))
41
- __with_no_publish(gateway_base, app_dir_path)
39
+ __with_traefik_config(service_paths, gateway_base, app_dir_path)
42
40
  __with_networks(gateway_base, hostnames)
43
41
 
44
42
  with open(docker_compose_dest_path, 'w') as fp:
@@ -52,31 +50,60 @@ def __with_networks(config: dict, hostnames: List[str]):
52
50
  'aliases': hostnames
53
51
  }
54
52
 
55
- def __with_no_publish(config: dict, app_dir_path: str):
56
- if not config['volumes']:
57
- config['volumes'] = []
53
+ def __with_traefik_config(service_paths: str, compose: dict, app_dir_path: str):
54
+ if not compose['volumes']:
55
+ compose['volumes'] = []
56
+
57
+ entry_points = {}
58
+ certificates = []
59
+ traefik_config = {
60
+ 'accessLog': {
61
+ 'format': 'common',
62
+ },
63
+ 'entryPoints': entry_points,
64
+ 'log': {
65
+ 'format': 'common',
66
+ 'level': 'INFO',
67
+ },
68
+ 'providers': {
69
+ 'docker': {
70
+ 'exposedByDefault': False
71
+ }
72
+ },
73
+ 'tls': {
74
+ 'certificates': certificates
75
+ }
76
+ }
58
77
 
59
- # Copy nginx.tmpl to .stoobly/tmp
60
- nginx_template_src_path = os.path.join(run_template_path(), GATEWAY_NGINX_TEMPLATE)
61
- nginx_template_relative_path = os.path.join(DATA_DIR_NAME, TMP_DIR_NAME, GATEWAY_NGINX_TEMPLATE)
62
- nginx_template_dest_path = os.path.join(app_dir_path, nginx_template_relative_path)
78
+ for path in service_paths:
79
+ config = ServiceConfig(path)
63
80
 
64
- if not os.path.exists(os.path.dirname(nginx_template_dest_path)):
65
- os.makedirs(os.path.dirname(nginx_template_dest_path), exist_ok=True)
81
+ if not config.hostname:
82
+ continue
66
83
 
67
- shutil.copy(nginx_template_src_path, nginx_template_dest_path)
84
+ entry_points[config.port] = {
85
+ 'address': f":{config.port}"
86
+ }
68
87
 
69
- config['volumes'].append(
70
- f"{os.path.join(APP_DIR, nginx_template_relative_path)}:/app/nginx.tmpl:ro"
71
- )
88
+ if config.scheme == 'https':
89
+ certificates.append({
90
+ 'certFile': f"/certs/{config.hostname}.crt",
91
+ 'keyFile': f"/certs/{config.hostname}.key"
92
+ })
93
+
94
+ # Create traefik.yml in .stoobly/tmp
95
+ traefik_template_relative_path = os.path.join(DATA_DIR_NAME, TMP_DIR_NAME, 'traefik.yml')
96
+ traefik_template_dest_path = os.path.join(app_dir_path, traefik_template_relative_path)
72
97
 
73
- environment = {}
74
- if not config['environment']:
75
- config['environment'] = environment
76
- else:
77
- environment = config['environment']
98
+ if not os.path.exists(os.path.dirname(traefik_template_dest_path)):
99
+ os.makedirs(os.path.dirname(traefik_template_dest_path), exist_ok=True)
78
100
 
79
- environment['HTTPS_METHOD'] = 'noredirect'
101
+ with open(traefik_template_dest_path, 'w') as fp:
102
+ fp.write(yaml.dump(traefik_config))
103
+
104
+ compose['volumes'].append(
105
+ f"{os.path.join(APP_DIR, traefik_template_relative_path)}:/etc/traefik/traefik.yml:ro"
106
+ )
80
107
 
81
108
  def __find_hosts(service_paths):
82
109
  hostnames = []
@@ -1,6 +1,6 @@
1
1
  from stoobly_agent.app.cli.scaffold.service_config import ServiceConfig
2
2
 
3
- from ...constants import WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE
3
+ from ...constants import WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE
4
4
  from .dns_decorator import DnsDecorator
5
5
  from .mock_decorator import MockDecorator
6
6
  from .reverse_proxy_decorator import ReverseProxyDecorator
@@ -12,7 +12,7 @@ def get_workflow_decorators(workflow: str, service_config: ServiceConfig):
12
12
  if service_config.hostname:
13
13
  workflow_decorators.append(ReverseProxyDecorator)
14
14
  workflow_decorators.append(DnsDecorator)
15
- elif workflow == WORKFLOW_MOCK_TYPE:
15
+ elif workflow == WORKFLOW_MOCK_TYPE or workflow == WORKFLOW_TEST_TYPE:
16
16
  if service_config.hostname:
17
17
  workflow_decorators.append(ReverseProxyDecorator if service_config.detached else MockDecorator)
18
18
  workflow_decorators.append(DnsDecorator)
@@ -1,4 +1,6 @@
1
1
  # Wraps the .config.yml file in the service folder
2
+ import hashlib
3
+ import os
2
4
  import pdb
3
5
 
4
6
  from .config import Config
@@ -51,6 +53,10 @@ class ServiceConfig(Config):
51
53
  def detached(self, v):
52
54
  self.__detached = v
53
55
 
56
+ @property
57
+ def id(self):
58
+ return hashlib.md5(os.path.basename(self.dir).encode()).hexdigest()
59
+
54
60
  @property
55
61
  def hostname(self):
56
62
  return (self.__hostname or '').strip()
@@ -120,6 +126,10 @@ class ServiceConfig(Config):
120
126
  def scheme(self, v):
121
127
  self.__scheme = v
122
128
 
129
+ @property
130
+ def tls(self) -> bool:
131
+ return self.__scheme == 'https'
132
+
123
133
  def load(self, config = None):
124
134
  config = config or self.read()
125
135
 
@@ -13,9 +13,6 @@ from docker.models.containers import Container
13
13
  from stoobly_agent.app.cli.scaffold.constants import (
14
14
  PUBLIC_FOLDER_NAME,
15
15
  STOOBLY_DATA_DIR,
16
- VIRTUAL_HOST_ENV,
17
- VIRTUAL_PORT_ENV,
18
- VIRTUAL_PROTO_ENV,
19
16
  WORKFLOW_RECORD_TYPE,
20
17
  WORKFLOW_TEST_TYPE,
21
18
  )
@@ -172,30 +169,6 @@ class ServiceWorkflowValidateCommand(ServiceCommand, ValidateCommand):
172
169
  if Counter(public_folder_contents_container) != Counter(public_folder_contents_scaffold):
173
170
  raise ScaffoldValidateException(f"public folder was not mounted properly, expected {self.public_dir_path} to exist in container path {public_folder_path}")
174
171
 
175
- # Note: might not need this if the hostname is reachable and working
176
- def proxy_environment_variables_exist(self, container: Container) -> None:
177
- environment_variables = container.attrs['Config']['Env']
178
- virtual_host_exists = False
179
- virtual_port_exists = False
180
- virtual_proto_exists = False
181
-
182
- for environment_variable in environment_variables:
183
- environment_variable_name, environment_variable_value = environment_variable.split('=')
184
- if environment_variable_name == VIRTUAL_HOST_ENV:
185
- virtual_host_exists = True
186
- elif environment_variable_name == VIRTUAL_PORT_ENV:
187
- virtual_port_exists = True
188
- elif environment_variable_name == VIRTUAL_PROTO_ENV:
189
- virtual_proto_exists = True
190
-
191
- if not virtual_host_exists:
192
- raise ScaffoldValidateException(f"VIRTUAL_HOST environment variable is missing from container: {container.name}")
193
- if not virtual_port_exists:
194
- raise ScaffoldValidateException(f"VIRTUAL_POST environment variable is missing from container: {container.name}")
195
- if not virtual_proto_exists:
196
- raise ScaffoldValidateException(f"VIRTUAL_PROTO environment variable is missing from container: {container.name}")
197
-
198
-
199
172
  def validate_proxy_container(self, service_proxy_container: Container):
200
173
  print(f"Validating proxy container: {service_proxy_container.name}")
201
174
 
@@ -209,8 +182,6 @@ class ServiceWorkflowValidateCommand(ServiceCommand, ValidateCommand):
209
182
  if not self.service_config.detached:
210
183
  self.validate_public_folder(service_proxy_container)
211
184
 
212
- self.proxy_environment_variables_exist(service_proxy_container)
213
-
214
185
  def validate_service_container(self):
215
186
  pass
216
187
 
@@ -4,5 +4,5 @@ import pathlib
4
4
  def __path():
5
5
  return os.path.join(pathlib.Path(__file__).parent.resolve())
6
6
 
7
- def run_template_path():
8
- return os.path.join(__path(), 'run')
7
+ def build_template_path():
8
+ return os.path.join(__path(), 'build')
@@ -1,10 +1,10 @@
1
1
  services:
2
2
  gateway_base:
3
- environment:
4
- TRUST_DOWNSTREAM_PROXY: true
5
- image: nginxproxy/nginx-proxy:1.7
3
+ command:
4
+ - "--configFile=/etc/traefik/traefik.yml"
5
+ image: traefik:v3
6
6
  profiles:
7
7
  - gateway_base
8
8
  volumes:
9
- - /var/run/docker.sock:/tmp/docker.sock:ro
10
- - ${CERTS_DIR}:/etc/nginx/certs
9
+ - /var/run/docker.sock:/var/run/docker.sock:ro
10
+ - ${CERTS_DIR}:/certs:ro
@@ -5,6 +5,12 @@
5
5
 
6
6
  stoobly-agent config reset
7
7
 
8
+ echo "Configuring intercept..."
9
+ stoobly-agent intercept configure --mode mock --policy all
10
+
11
+ echo "Enabling intercept..."
12
+ stoobly-agent intercept enable
13
+
8
14
  entrypoint=$1
9
15
 
10
16
  if [ -e "$entrypoint" ]; then
@@ -5,6 +5,12 @@
5
5
 
6
6
  stoobly-agent config reset
7
7
 
8
+ echo "Configuring intercept..."
9
+ stoobly-agent intercept configure --mode record --policy all
10
+
11
+ echo "Disabling intercept..."
12
+ stoobly-agent intercept disable
13
+
8
14
  entrypoint=$1
9
15
 
10
16
  if [ -e "$entrypoint" ]; then
@@ -5,6 +5,12 @@
5
5
 
6
6
  stoobly-agent config reset
7
7
 
8
+ echo "Configuring intercept..."
9
+ stoobly-agent intercept configure --mode mock --policy all
10
+
11
+ echo "Enabling intercept..."
12
+ stoobly-agent intercept enable
13
+
8
14
  entrypoint=$1
9
15
 
10
16
  if [ -e "$entrypoint" ]; then
@@ -3,12 +3,6 @@
3
3
  # This file was automatically generated. DO NOT EDIT.
4
4
  # Any changes made to this file will be overwritten.
5
5
 
6
- echo "Configuring intercept..."
7
- stoobly-agent intercept configure --mode mock --policy all
8
-
9
- echo "Enabling intercept..."
10
- stoobly-agent intercept enable
11
-
12
6
  entrypoint=$1
13
7
 
14
8
  if [ -e "$entrypoint" ]; then
@@ -3,12 +3,6 @@
3
3
  # This file was automatically generated. DO NOT EDIT.
4
4
  # Any changes made to this file will be overwritten.
5
5
 
6
- echo "Configuring intercept..."
7
- stoobly-agent intercept configure --mode record --policy all
8
-
9
- echo "Disabling intercept..."
10
- stoobly-agent intercept disable
11
-
12
6
  entrypoint=$1
13
7
 
14
8
  if [ -e "$entrypoint" ]; then
@@ -3,12 +3,6 @@
3
3
  # This file was automatically generated. DO NOT EDIT.
4
4
  # Any changes made to this file will be overwritten.
5
5
 
6
- echo "Configuring intercept..."
7
- stoobly-agent intercept configure --mode mock --policy all
8
-
9
- echo "Enabling intercept..."
10
- stoobly-agent intercept enable
11
-
12
6
  entrypoint=$1
13
7
 
14
8
  if [ -e "$entrypoint" ]; then
@@ -16,14 +16,13 @@ CUSTOM_CONFIGURE = os.path.join('bin', 'configure')
16
16
  CUSTOM_INIT = os.path.join('bin', 'init')
17
17
  CUSTOM_FIXTURES = 'fixtures.yml'
18
18
  CUSTOM_LIFECYCLE_HOOKS = os.path.join('lifecycle_hooks.py')
19
+ CUSTOM_PUBLIC_GITIGNORE = os.path.join('public', '.gitignore')
19
20
  MAINTAINED_CONFIGURE = os.path.join('bin', '.configure')
20
21
  MAINTAINED_INIT = os.path.join('bin', '.init')
21
- MAINTAINED_PUBLIC = os.path.join('public', '.gitignore')
22
22
 
23
23
  MOCK_WORKFLOW_MAINTAINED_FILES = [
24
24
  MAINTAINED_CONFIGURE,
25
25
  MAINTAINED_INIT,
26
- MAINTAINED_PUBLIC
27
26
  ]
28
27
 
29
28
  MOCK_WORKFLOW_CUSTOM_FILES = [
@@ -32,6 +31,7 @@ MOCK_WORKFLOW_CUSTOM_FILES = [
32
31
  CUSTOM_FIXTURES,
33
32
  CUSTOM_INIT,
34
33
  CUSTOM_LIFECYCLE_HOOKS,
34
+ CUSTOM_PUBLIC_GITIGNORE
35
35
  ]
36
36
 
37
37
  RECORD_WORKFLOW_MAINTAINED_FILES = [
@@ -43,13 +43,12 @@ RECORD_WORKFLOW_CUSTOM_FILES = [
43
43
  CUSTOM_BUILD,
44
44
  CUSTOM_CONFIGURE,
45
45
  CUSTOM_INIT,
46
- CUSTOM_LIFECYCLE_HOOKS
46
+ CUSTOM_LIFECYCLE_HOOKS,
47
47
  ]
48
48
 
49
49
  TEST_WORKFLOW_MAINTAINED_FILES = [
50
50
  MAINTAINED_CONFIGURE,
51
51
  MAINTAINED_INIT,
52
- MAINTAINED_PUBLIC
53
52
  ]
54
53
 
55
54
  TEST_WORKFLOW_CUSTOM_FILES = [
@@ -57,7 +56,8 @@ TEST_WORKFLOW_CUSTOM_FILES = [
57
56
  CUSTOM_CONFIGURE,
58
57
  CUSTOM_FIXTURES,
59
58
  CUSTOM_INIT,
60
- CUSTOM_LIFECYCLE_HOOKS
59
+ CUSTOM_LIFECYCLE_HOOKS,
60
+ CUSTOM_PUBLIC_GITIGNORE
61
61
  ]
62
62
 
63
63
  SERVICE_HOSTNAME_BUILD_ARG = 'SERVICE_HOSTNAME'
@@ -1,7 +1,9 @@
1
+ import pdb
2
+
1
3
  from ..constants import WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE
2
4
  from ..docker.workflow.builder import WorkflowBuilder
3
5
  from .constants import (
4
- CUSTOM_CONFIGURE, CUSTOM_INIT, MAINTAINED_CONFIGURE, MAINTAINED_PUBLIC, MOCK_WORKFLOW_CUSTOM_FILES, MOCK_WORKFLOW_MAINTAINED_FILES, RECORD_WORKFLOW_CUSTOM_FILES, RECORD_WORKFLOW_MAINTAINED_FILES, TEST_WORKFLOW_CUSTOM_FILES, TEST_WORKFLOW_MAINTAINED_FILES
6
+ CUSTOM_CONFIGURE, CUSTOM_INIT, CUSTOM_PUBLIC_GITIGNORE, MAINTAINED_CONFIGURE, MOCK_WORKFLOW_CUSTOM_FILES, MOCK_WORKFLOW_MAINTAINED_FILES, RECORD_WORKFLOW_CUSTOM_FILES, RECORD_WORKFLOW_MAINTAINED_FILES, TEST_WORKFLOW_CUSTOM_FILES, TEST_WORKFLOW_MAINTAINED_FILES
5
7
  )
6
8
 
7
9
  def custom_files(workflow: str, workflow_builder: WorkflowBuilder):
@@ -21,8 +23,8 @@ def custom_files(workflow: str, workflow_builder: WorkflowBuilder):
21
23
 
22
24
  # Fixtures are only relevant if the workflow is mock/test and if the service has a hostname
23
25
  if not workflow_builder.config.hostname:
24
- if MAINTAINED_PUBLIC in files:
25
- files.remove(MAINTAINED_PUBLIC)
26
+ if CUSTOM_PUBLIC_GITIGNORE in files:
27
+ files.remove(CUSTOM_PUBLIC_GITIGNORE)
26
28
 
27
29
  return files
28
30
 
@@ -39,8 +41,4 @@ def maintained_files(workflow: str, workflow_builder: WorkflowBuilder):
39
41
  if workflow_builder.configure in workflow_builder.services:
40
42
  files.append(MAINTAINED_CONFIGURE)
41
43
 
42
- if not workflow_builder.config.hostname:
43
- if MAINTAINED_PUBLIC in files:
44
- files.remove(MAINTAINED_PUBLIC)
45
-
46
44
  return files
@@ -1,6 +1,7 @@
1
1
  import click
2
2
  import os
3
3
  import pdb
4
+ import re
4
5
  import sys
5
6
 
6
7
  from io import TextIOWrapper
@@ -142,6 +143,16 @@ def mkcert(**kwargs):
142
143
  def create(**kwargs):
143
144
  __validate_app_dir(kwargs['app_dir_path'])
144
145
 
146
+ if '/' in kwargs['service_name']:
147
+ print(f"Error: {kwargs['service_name']} is invalid. It cannot container '/", file=sys.stderr)
148
+ sys.exit(1)
149
+
150
+ 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)
155
+
145
156
  app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
146
157
 
147
158
  service = Service(kwargs['service_name'], app)
@@ -1 +1 @@
1
- 1.7.0
1
+ 1.7.2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: stoobly-agent
3
- Version: 1.7.2
3
+ Version: 1.8.0
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=vcAemunWrTugNqMOkhqZIYsXqnkXMq5e2XHDuIQqj-0,44
1
+ stoobly_agent/__init__.py,sha256=aCZ-Nh64isEE2avfrBDGQco6VPg3SA0uNSp6keG2KPM,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
@@ -73,21 +73,21 @@ stoobly_agent/app/cli/scaffold/app_config.py,sha256=Gs-BynV1vY7_PpTOenn2mqc7lBIu
73
73
  stoobly_agent/app/cli/scaffold/app_create_command.py,sha256=sy4017eiir9MK0TEbTi1NyG9mhOGlenGGVnq0GsGUrQ,966
74
74
  stoobly_agent/app/cli/scaffold/command.py,sha256=aoTsdkkBzyu7TkVSMdNQQGk0Gj874jNgFcjR14y3TuM,254
75
75
  stoobly_agent/app/cli/scaffold/config.py,sha256=HZU5tkvr3dkPr4JMXZtrJlu2wxxO-134Em6jReFFcq0,688
76
- stoobly_agent/app/cli/scaffold/constants.py,sha256=Mc4eaBicnzvXWjt1vqSmJ8csNyFLcAQLBj9uMH8QZ7A,2488
76
+ stoobly_agent/app/cli/scaffold/constants.py,sha256=VEd8bXG6u919cmc9wGtxVQhoHzrRP2KLH0ZTjlDiUxI,2384
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
80
80
  stoobly_agent/app/cli/scaffold/docker/builder.py,sha256=uiGqhxBHEasZAqLzjKUGUs-1QEZiMsJQYn4mdJ2jy3A,3137
81
- stoobly_agent/app/cli/scaffold/docker/constants.py,sha256=K4u8MzpCcG75cxDXLjOV5L_JbZuy1it0jp1K7TfnKk0,730
81
+ stoobly_agent/app/cli/scaffold/docker/constants.py,sha256=1khQdgTaQ89ykGRNdTQh_ejFOdjNFGaZ_3cOGda6y7Y,692
82
82
  stoobly_agent/app/cli/scaffold/docker/service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
83
  stoobly_agent/app/cli/scaffold/docker/service/build_decorator.py,sha256=ZU7z4bkvdS3OK5O4fJhlA9_PNwnFtZW6t7vNF7V5obQ,1003
84
- stoobly_agent/app/cli/scaffold/docker/service/builder.py,sha256=xgtDPAJYCCuzPfRIaG7yxjbH7qcyfO6OcI5jGs4B8S0,5577
85
- stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py,sha256=oBp__kVxTxdiBhsLNXADPWIaSQzRQMyBF7aToQOkfOs,3302
84
+ stoobly_agent/app/cli/scaffold/docker/service/builder.py,sha256=HJ4XOjno-Jecrlo2m0eZwNt2zvZreG32Zzo1AfT8Kq4,5786
85
+ stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py,sha256=kKJDxbjV9cy5JIvnKKdVppdmlagvtTZ3z1j9-sS3Qic,3728
86
86
  stoobly_agent/app/cli/scaffold/docker/service/types.py,sha256=qB-yYHlu-PZDc0HYgTUvE5bWNpHxaSThC3JUG8okR1k,88
87
87
  stoobly_agent/app/cli/scaffold/docker/workflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
88
88
  stoobly_agent/app/cli/scaffold/docker/workflow/build_decorator.py,sha256=VKD9hXbJGRIWHS5IeYXeX0-FQ0F43zG8VmsegL6eYwA,703
89
89
  stoobly_agent/app/cli/scaffold/docker/workflow/builder.py,sha256=WmqH7skXJlsBEhqAMYUEhMRnEjjb-l0CzFOpNOE2ssI,5116
90
- stoobly_agent/app/cli/scaffold/docker/workflow/decorators_factory.py,sha256=gU4RfuZ13r_YoB4eLS6FuiB1A4kfuLrWLPmYjZ0EJJw,955
90
+ stoobly_agent/app/cli/scaffold/docker/workflow/decorators_factory.py,sha256=bjQ86cBDtgtqai7J-ds_mSMgrOi8gQSMBwbdpE0Wn3M,1009
91
91
  stoobly_agent/app/cli/scaffold/docker/workflow/dns_decorator.py,sha256=nlDPbyF1hkVItzFH3bk9KlqfDC8usyFZs353-ibqxvA,938
92
92
  stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py,sha256=DcBnwA8YhE-VdrUiWf2xPcqirEMZEQm3AwssAg9CxLo,1226
93
93
  stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py,sha256=zD4FEtBMiPEtvEb798LOfFH8sJhTWQYpA9THLq5UMbg,1227
@@ -96,13 +96,13 @@ stoobly_agent/app/cli/scaffold/hosts_file_manager.py,sha256=zNX5wh6zXQ4J2BA0YYdD
96
96
  stoobly_agent/app/cli/scaffold/managed_services_docker_compose.py,sha256=-wLBXUi7DCWsfm5KzZzd_kdJKOTl1NT924XR7dyjbSY,574
97
97
  stoobly_agent/app/cli/scaffold/service.py,sha256=L9K6QE0k5KSEC8_fSwtdwwTSO_DsIpqSPW-AG7Bg76o,501
98
98
  stoobly_agent/app/cli/scaffold/service_command.py,sha256=9kIKiFC5Jo425VWYD4NDvUOdMP-pNyq2D5Ip1ZAPj3A,1054
99
- stoobly_agent/app/cli/scaffold/service_config.py,sha256=NwJL4gwWQ_9B0fHrit1QekR6rSMg40m1CDizWxUNWCM,3598
99
+ stoobly_agent/app/cli/scaffold/service_config.py,sha256=aM9x_LQVl9MJyO7yqzwiXWlbbNg9FJA-Tk9IwVINLok,3798
100
100
  stoobly_agent/app/cli/scaffold/service_create_command.py,sha256=1B6TK3JDAjouikCV84WDrX7b0crdPMPIo1caMwhi-L8,2815
101
101
  stoobly_agent/app/cli/scaffold/service_delete_command.py,sha256=_nBDQjm8eL62MQpzSCxgUHlW04ZXKG8MDlN1BXxlqww,986
102
102
  stoobly_agent/app/cli/scaffold/service_docker_compose.py,sha256=OMUN1-ujQYIZXxDvS4XBf5C9wGalQULkwOiBBQPZbHY,820
103
103
  stoobly_agent/app/cli/scaffold/service_workflow.py,sha256=sQ_Edy_wGHKMXpD0DmhnOWkGEKz7gSgEGNI8f7aXOdg,444
104
- stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py,sha256=RxPJollW_FQjlPcIbvqGRVH2adJYPcLNCsVMpW5wjxs,12740
105
- stoobly_agent/app/cli/scaffold/templates/__init__.py,sha256=p-23uLU2QGksJASDD13soldc0vr_AOS3QdGlSnbs3bM,167
104
+ stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py,sha256=xONRUtfC3IBd-Kr4wdUKWgx9ppSsbu2H72pb2VinizQ,11412
105
+ stoobly_agent/app/cli/scaffold/templates/__init__.py,sha256=x8C_a0VoO_vUbosp4_6IC1U7Ge9NnUdVKDPpVMtMkeY,171
106
106
  stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.context,sha256=AK8j4JWDmQxfsOX-Ysp-LNckPGhp-tiDOdPMdYItmso,158
107
107
  stoobly_agent/app/cli/scaffold/templates/app/.Makefile,sha256=hree9QL8xl7v_Yzv40bcO4-ZDlyA4Qnm-VWU2dnMuXQ,8955
108
108
  stoobly_agent/app/cli/scaffold/templates/app/.docker-compose.base.yml,sha256=6tFqXh3ine8vaD0FCL5TMoY5NjKx2wLUR8XpW3tJtew,245
@@ -137,7 +137,7 @@ stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/configure,sha25
137
137
  stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/init,sha256=YxWVVQMEdGarcMtBcE1Sj2kdLgUgwY9kXp3MjPsVcmg,46
138
138
  stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/docker-compose.yml,sha256=JpWLQrW69EatLD3HPHpmi3Y6n7cjlrUgekYVbJ4ngSY,523
139
139
  stoobly_agent/app/cli/scaffold/templates/app/gateway/.config.yml,sha256=XnLQZMzzMMIwVycjyPN5QXsmRztkTFAna1kIHYuDfJQ,19
140
- stoobly_agent/app/cli/scaffold/templates/app/gateway/.docker-compose.base.template.yml,sha256=EhB1DcWmQLDYl_nMpJxIB0BVu_0y6lWgSHrTQWmZLHQ,251
140
+ stoobly_agent/app/cli/scaffold/templates/app/gateway/.docker-compose.base.template.yml,sha256=0A08JbYpa7LGv9SphRwCgkvy5y4_T74LoWiV-NyCmyA,241
141
141
  stoobly_agent/app/cli/scaffold/templates/app/gateway/mock/.docker-compose.mock.yml,sha256=CDL5x18-ues4F_ujqpNef_zJTG6PyDOkQ11cIHBOW5k,136
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
@@ -146,17 +146,17 @@ stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/.docker-compose.base.yml
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
149
- stoobly_agent/app/cli/scaffold/templates/build/services/build/mock/.configure,sha256=006exiS9OpKavy4fNWioWo0d8hrulQiWjaB3yXHdGig,212
149
+ stoobly_agent/app/cli/scaffold/templates/build/services/build/mock/.configure,sha256=Xs-Vq6IxkOr7j8oxUSLsZ89viG6_o_Wd7TRPzMqzVjc,365
150
150
  stoobly_agent/app/cli/scaffold/templates/build/services/build/mock/.init,sha256=5eg3Glb3_T-RTwU6tTSerFLQKsL93LtsnmR1B0vRjBw,219
151
- stoobly_agent/app/cli/scaffold/templates/build/services/build/record/.configure,sha256=006exiS9OpKavy4fNWioWo0d8hrulQiWjaB3yXHdGig,212
151
+ stoobly_agent/app/cli/scaffold/templates/build/services/build/record/.configure,sha256=SNaUNlV4hxBVB4yOeIxalYAsWiZ-JVtamiox5dERRDE,369
152
152
  stoobly_agent/app/cli/scaffold/templates/build/services/build/record/.init,sha256=5eg3Glb3_T-RTwU6tTSerFLQKsL93LtsnmR1B0vRjBw,219
153
- stoobly_agent/app/cli/scaffold/templates/build/services/build/test/.configure,sha256=006exiS9OpKavy4fNWioWo0d8hrulQiWjaB3yXHdGig,212
153
+ stoobly_agent/app/cli/scaffold/templates/build/services/build/test/.configure,sha256=Xs-Vq6IxkOr7j8oxUSLsZ89viG6_o_Wd7TRPzMqzVjc,365
154
154
  stoobly_agent/app/cli/scaffold/templates/build/services/build/test/.init,sha256=5eg3Glb3_T-RTwU6tTSerFLQKsL93LtsnmR1B0vRjBw,219
155
- stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/mock/.configure,sha256=SKvht2K_3tW08K24rl8_j0jMYOhq1k-GsVwhoHwjxYA,337
155
+ stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/mock/.configure,sha256=xWJGhCKQejtVLFAOEZMWnaCeGAc9tuqEh_WsG3xfA_0,184
156
156
  stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/mock/.init,sha256=AcM6SLUsZa6BOLDjxteDR_AXIco47GZNkWQCGPhPDAY,189
157
- stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/record/.configure,sha256=dnbPZUrYZDCEx0MxhIsrY-lTgH_9tN_Iixy3XrPIW8w,341
157
+ stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/record/.configure,sha256=xWJGhCKQejtVLFAOEZMWnaCeGAc9tuqEh_WsG3xfA_0,184
158
158
  stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/record/.init,sha256=AcM6SLUsZa6BOLDjxteDR_AXIco47GZNkWQCGPhPDAY,189
159
- stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/test/.configure,sha256=SKvht2K_3tW08K24rl8_j0jMYOhq1k-GsVwhoHwjxYA,337
159
+ stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/test/.configure,sha256=xWJGhCKQejtVLFAOEZMWnaCeGAc9tuqEh_WsG3xfA_0,184
160
160
  stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/test/.init,sha256=AcM6SLUsZa6BOLDjxteDR_AXIco47GZNkWQCGPhPDAY,189
161
161
  stoobly_agent/app/cli/scaffold/templates/build/workflows/exec/.create,sha256=EZe84bLAKB-mrB9PGMx-amyMjp6x-ESUZKC8wxrWdLE,245
162
162
  stoobly_agent/app/cli/scaffold/templates/build/workflows/exec/.delete,sha256=RspRDQ7WT5jpN2o-6qXOlH-A2VpN4981pD4ZJljk9Rw,260
@@ -176,9 +176,8 @@ stoobly_agent/app/cli/scaffold/templates/build/workflows/record/.configure,sha25
176
176
  stoobly_agent/app/cli/scaffold/templates/build/workflows/record/.init,sha256=q2dL6DmIM8re149WwyeZvwttjU6KqBXO2-9zVKKqtM0,313
177
177
  stoobly_agent/app/cli/scaffold/templates/build/workflows/test/.configure,sha256=xWJGhCKQejtVLFAOEZMWnaCeGAc9tuqEh_WsG3xfA_0,184
178
178
  stoobly_agent/app/cli/scaffold/templates/build/workflows/test/.init,sha256=el5LYLY-7P3-EuxZ8dAFgGNU_4zDhyA4D_iS6D4fvps,312
179
- stoobly_agent/app/cli/scaffold/templates/constants.py,sha256=EXBiBB_gnSINGrIqfXMaJ2w0HEaICw4FxVjwIHPBqYw,1457
180
- stoobly_agent/app/cli/scaffold/templates/factory.py,sha256=t7QExf7o22oAiw05XFBWTfoTcuQqK33gQZHo3j1dzTY,1749
181
- stoobly_agent/app/cli/scaffold/templates/run/nginx.tmpl,sha256=oVaMI3wTpSzLMB6r236jeXct6gv4D0p91UR4J7PkTuI,54024
179
+ stoobly_agent/app/cli/scaffold/templates/constants.py,sha256=Cj5kTsT04vLwuVECEKQCnkYDtVfuXQiAf_Ge43-Nows,1477
180
+ stoobly_agent/app/cli/scaffold/templates/factory.py,sha256=301fziK9-YlV3V_SQ7bzP3OhvsDvYwDvpuJsh0gWv8M,1662
182
181
  stoobly_agent/app/cli/scaffold/templates/workflow/mock/bin/configure,sha256=GAU7AfSPcyDSI9RJ7mynT83YqgN9r_E9HZYx0RXE1lU,279
183
182
  stoobly_agent/app/cli/scaffold/templates/workflow/mock/bin/init,sha256=EaoFDyoJbHc9Ui8ELYKmfweXAycJptVOQblszeh3XTE,94
184
183
  stoobly_agent/app/cli/scaffold/templates/workflow/mock/fixtures.yml,sha256=CJlZ_kugygZpmyqIauBjNZxqk7XyLaa3yl3AWj8KV28,259
@@ -203,7 +202,7 @@ stoobly_agent/app/cli/scaffold/workflow_env.py,sha256=x8V5pJmIiklD3f2q2-qq-CORf4
203
202
  stoobly_agent/app/cli/scaffold/workflow_log_command.py,sha256=Bke4lMOMxuDUFuAx9nlXHbKgYMO4KAg9ASHvjz4aVWc,1372
204
203
  stoobly_agent/app/cli/scaffold/workflow_run_command.py,sha256=eF3aaK4OIZXYuSBEAeBnhAL7EZrS1G4mSYrJbEiXt2o,11082
205
204
  stoobly_agent/app/cli/scaffold/workflow_validate_command.py,sha256=Uo_yo6rVR1ZR7xpvsQvlH48AyMBVLRupd4G-bRjzm_Q,5584
206
- stoobly_agent/app/cli/scaffold_cli.py,sha256=FfI_v_Rpzoieou8W3l640zUrmGSAnBDSdp_h4ND8tGU,29135
205
+ stoobly_agent/app/cli/scaffold_cli.py,sha256=g6LEBiL1Lz0IQwlohpz8LFkhoaQukRtnQHgjzwAiASs,29528
207
206
  stoobly_agent/app/cli/scenario_cli.py,sha256=3J1EiJOvunkfWrEkOsanw-XrKkOk78ij_GjBlE9p7CE,8229
208
207
  stoobly_agent/app/cli/snapshot_cli.py,sha256=cpCjxFYBuVwLuq_b2lIUu-5zWqupRlrp4xWgDytirSM,10047
209
208
  stoobly_agent/app/cli/trace_cli.py,sha256=K7E-vx3JUcqEDSWOdIOi_AieKNQz7dBfmRrVvKDkzFI,4605
@@ -703,7 +702,7 @@ stoobly_agent/test/app/models/factories/resource/local_db/helpers/log_test.py,sh
703
702
  stoobly_agent/test/app/models/factories/resource/local_db/helpers/tiebreak_scenario_request_test.py,sha256=a1SFLyEyRRLuADvAw6ckQQKORFXvyK1lyrbkaLWx8oU,3399
704
703
  stoobly_agent/test/app/models/factories/resource/local_db/request_adapter_test.py,sha256=Pzq1cBPnP9oSWG-p0c-VoymoHxgp483QmNwmV1b78RA,8453
705
704
  stoobly_agent/test/app/models/factories/resource/local_db/response_adapter_test.py,sha256=9P95EKH5rZGOrmRkRIDlQZqtiLJHk9735og18Ffwpfw,2204
706
- stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=u3Mg2DHnoVGqkBw15zJsdS-i71Ak8wdoxCMZuL7Rce0,6
705
+ stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=EsweFLPst1Z6S0S1U7ggLWHOwiK1tpz7HoVhJbiwG0Q,5
707
706
  stoobly_agent/test/app/models/schemas/.stoobly/db/stoobly_agent.sqlite3,sha256=ch8gNx6zIelLKQx65gwFx_LRNqUD3EC5xcHZ0ukIQiU,188416
708
707
  stoobly_agent/test/app/models/schemas/.stoobly/settings.yml,sha256=vLwMjweKOdod6tSLtIlyBefPQuNXq9wio4kBaODKtAU,726
709
708
  stoobly_agent/test/app/models/schemas/.stoobly/tmp/options.json,sha256=OTRzarwus48CTrItedXCrgQttJHSEZonEYc7R_knvYg,2212
@@ -744,8 +743,8 @@ stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml,sha256=1W
744
743
  stoobly_agent/test/mock_data/scaffold/index.html,sha256=qJwuYajKZ4ihWZrJQ3BNObV5kf1VGnnm_vqlPJzdqLE,258
745
744
  stoobly_agent/test/mock_data/uspto.yaml,sha256=6U5se7C3o-86J4m9xpOk9Npias399f5CbfWzR87WKwE,7835
746
745
  stoobly_agent/test/test_helper.py,sha256=m_oAI7tmRYCNZdKfNqISWhMv3e44tjeYViQ3nTUfnos,1007
747
- stoobly_agent-1.7.2.dist-info/LICENSE,sha256=o93sj12cdoEOsTCjPaPFsw3Xq0SXs3pPcY-9reE2sEw,548
748
- stoobly_agent-1.7.2.dist-info/METADATA,sha256=VxdMFDuGuf-ENsJINGiL3-mzWA3G8HlZbtJgKYr2C7o,3087
749
- stoobly_agent-1.7.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
750
- stoobly_agent-1.7.2.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
751
- stoobly_agent-1.7.2.dist-info/RECORD,,
746
+ stoobly_agent-1.8.0.dist-info/LICENSE,sha256=o93sj12cdoEOsTCjPaPFsw3Xq0SXs3pPcY-9reE2sEw,548
747
+ stoobly_agent-1.8.0.dist-info/METADATA,sha256=Df0YmuBA3DJyO61FaIfNKTXBZRQ31c2Eg6nsyg5zt9Y,3087
748
+ stoobly_agent-1.8.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
749
+ stoobly_agent-1.8.0.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
750
+ stoobly_agent-1.8.0.dist-info/RECORD,,