stoobly-agent 1.9.10__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 +1 -3
- stoobly_agent/app/cli/intercept_cli.py +1 -1
- stoobly_agent/app/cli/scaffold/app_command.py +1 -1
- stoobly_agent/app/cli/scaffold/app_config.py +13 -1
- stoobly_agent/app/cli/scaffold/app_create_command.py +8 -1
- stoobly_agent/app/cli/scaffold/command.py +3 -3
- stoobly_agent/app/cli/scaffold/constants.py +3 -1
- stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py +6 -6
- stoobly_agent/app/cli/scaffold/env.py +0 -2
- stoobly_agent/app/cli/scaffold/service_command.py +1 -1
- stoobly_agent/app/cli/scaffold/service_config.py +10 -6
- stoobly_agent/app/cli/scaffold/service_create_command.py +1 -1
- stoobly_agent/app/cli/scaffold/templates/app/.Makefile +14 -10
- stoobly_agent/app/cli/scaffold/templates/app/gateway/.docker-compose.base.template.yml +1 -1
- stoobly_agent/app/cli/scaffold/workflow_command.py +3 -3
- stoobly_agent/app/cli/scaffold/workflow_env.py +10 -3
- stoobly_agent/app/cli/scaffold/workflow_namesapce.py +47 -0
- stoobly_agent/app/cli/scaffold/workflow_run_command.py +15 -5
- stoobly_agent/app/cli/scaffold_cli.py +17 -10
- 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.10.dist-info → stoobly_agent-1.9.12.dist-info}/METADATA +1 -1
- {stoobly_agent-1.9.10.dist-info → stoobly_agent-1.9.12.dist-info}/RECORD +27 -26
- {stoobly_agent-1.9.10.dist-info → stoobly_agent-1.9.12.dist-info}/LICENSE +0 -0
- {stoobly_agent-1.9.10.dist-info → stoobly_agent-1.9.12.dist-info}/WHEEL +0 -0
- {stoobly_agent-1.9.10.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,11 +1,9 @@
|
|
1
1
|
import subprocess
|
2
2
|
import sys
|
3
3
|
|
4
|
-
|
4
|
+
DOTENV_PATH = 'STOOBLY_DOTENV_PATH'
|
5
5
|
|
6
6
|
def exec_stream(command):
|
7
|
-
load_dotenv()
|
8
|
-
|
9
7
|
# Start the process
|
10
8
|
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
11
9
|
|
@@ -8,7 +8,7 @@ from stoobly_agent.lib.api.keys.project_key import ProjectKey
|
|
8
8
|
|
9
9
|
from .helpers.handle_config_update_service import handle_intercept_active_update, handle_order_update
|
10
10
|
|
11
|
-
settings = Settings.instance()
|
11
|
+
settings: Settings = Settings.instance()
|
12
12
|
|
13
13
|
mode_options = [mode.MOCK, mode.RECORD, mode.REPLAY]
|
14
14
|
|
@@ -1,16 +1,25 @@
|
|
1
1
|
from .config import Config
|
2
|
-
from .constants import APP_NAME_ENV, APP_UI_PORT_ENV
|
2
|
+
from .constants import APP_DOCKER_SOCKET_PATH_ENV, APP_NAME_ENV, APP_UI_PORT_ENV
|
3
3
|
|
4
4
|
class AppConfig(Config):
|
5
5
|
|
6
6
|
def __init__(self, dir: str):
|
7
7
|
super().__init__(dir)
|
8
8
|
|
9
|
+
self.__docker_socket_path = '/var/run/docker.sock'
|
9
10
|
self.__name = None
|
10
11
|
self.__ui_port = None
|
11
12
|
|
12
13
|
self.load()
|
13
14
|
|
15
|
+
@property
|
16
|
+
def docker_socket_path(self):
|
17
|
+
return self.__docker_socket_path
|
18
|
+
|
19
|
+
@docker_socket_path.setter
|
20
|
+
def docker_socket_path(self, v):
|
21
|
+
self.__docker_socket_path = v
|
22
|
+
|
14
23
|
@property
|
15
24
|
def name(self):
|
16
25
|
return self.__name
|
@@ -36,6 +45,9 @@ class AppConfig(Config):
|
|
36
45
|
def write(self):
|
37
46
|
config = {}
|
38
47
|
|
48
|
+
if self.docker_socket_path:
|
49
|
+
config[APP_DOCKER_SOCKET_PATH_ENV] = self.docker_socket_path
|
50
|
+
|
39
51
|
if self.name:
|
40
52
|
config[APP_NAME_ENV] = self.name
|
41
53
|
|
@@ -7,8 +7,8 @@ from .app import App
|
|
7
7
|
from .app_command import AppCommand
|
8
8
|
|
9
9
|
class AppCreateOptions(TypedDict):
|
10
|
+
docker_socket_path: str
|
10
11
|
name: str
|
11
|
-
network: str
|
12
12
|
ui_port: int
|
13
13
|
|
14
14
|
class AppCreateCommand(AppCommand):
|
@@ -19,9 +19,16 @@ class AppCreateCommand(AppCommand):
|
|
19
19
|
if kwargs.get('app_name'):
|
20
20
|
self.app_config.name = kwargs['app_name']
|
21
21
|
|
22
|
+
if kwargs.get('docker_socket_path'):
|
23
|
+
self.app_config.docker_socket_path = kwargs['docker_socket_path']
|
24
|
+
|
22
25
|
if kwargs.get('ui_port'):
|
23
26
|
self.app_config.ui_port = kwargs['ui_port']
|
24
27
|
|
28
|
+
@property
|
29
|
+
def docker_socket_path(self):
|
30
|
+
return self.app_config.docker_socket_path
|
31
|
+
|
25
32
|
@property
|
26
33
|
def app_name(self):
|
27
34
|
return self.app_config.name
|
@@ -4,12 +4,12 @@ class Command():
|
|
4
4
|
|
5
5
|
def __init__(self, app: App):
|
6
6
|
self.__app = app
|
7
|
-
self.
|
7
|
+
self.__scaffold_namespace = app.scaffold_namespace
|
8
8
|
|
9
9
|
@property
|
10
10
|
def app(self):
|
11
11
|
return self.__app
|
12
12
|
|
13
13
|
@property
|
14
|
-
def
|
15
|
-
return self.
|
14
|
+
def scaffold_namespace(self):
|
15
|
+
return self.__scaffold_namespace
|
@@ -6,6 +6,7 @@ from stoobly_agent.config.data_dir import CERTS_DIR_NAME, DATA_DIR_NAME
|
|
6
6
|
|
7
7
|
APP_DIR = '${APP_DIR}'
|
8
8
|
APP_DIR_ENV = 'APP_DIR'
|
9
|
+
APP_DOCKER_SOCKET_PATH_ENV = 'APP_DOCKER_SOCKET_PATH'
|
9
10
|
APP_NETWORK_ENV = 'APP_NETWORK'
|
10
11
|
APP_NAME_ENV = 'APP_NAME'
|
11
12
|
APP_UI_PORT_ENV = 'APP_UI_PORT'
|
@@ -16,7 +17,8 @@ COMPOSE_TEMPLATE = '.docker-compose.{workflow}.yml'
|
|
16
17
|
CONFIG_FILE = '.config.yml'
|
17
18
|
CONTEXT_DIR_ENV = 'CONTEXT_DIR'
|
18
19
|
DOCKER_NAMESPACE = 'docker'
|
19
|
-
|
20
|
+
DOTENV_FILE = '.env'
|
21
|
+
DOTENV_PATH_ENV = 'STOOBLY_DOTENV_PATH'
|
20
22
|
NAMESERVERS_FILE = '.nameservers'
|
21
23
|
PUBLIC_FOLDER_NAME = 'public'
|
22
24
|
SERVICE_DETACHED = '${SERVICE_DETACHED}'
|
@@ -4,13 +4,13 @@ import yaml
|
|
4
4
|
|
5
5
|
from typing import List
|
6
6
|
|
7
|
-
from stoobly_agent.config.data_dir import DATA_DIR_NAME, TMP_DIR_NAME
|
8
7
|
from stoobly_agent.app.cli.scaffold.constants import APP_DIR
|
9
8
|
from stoobly_agent.app.cli.scaffold.service_config import ServiceConfig
|
10
9
|
from stoobly_agent.app.cli.scaffold.docker.constants import APP_INGRESS_NETWORK_NAME, APP_EGRESS_NETWORK_NAME, DOCKER_COMPOSE_BASE, DOCKER_COMPOSE_BASE_TEMPLATE
|
11
10
|
from stoobly_agent.app.cli.scaffold.templates.constants import CORE_GATEWAY_SERVICE_NAME
|
11
|
+
from stoobly_agent.app.cli.scaffold.workflow_namesapce import WorkflowNamespace
|
12
12
|
|
13
|
-
def configure_gateway(
|
13
|
+
def configure_gateway(workflow_namespace: WorkflowNamespace, service_paths: List[str], no_publish = False):
|
14
14
|
if len(service_paths) == 0:
|
15
15
|
return
|
16
16
|
|
@@ -36,7 +36,7 @@ def configure_gateway(namespace: str, service_paths: List[str], no_publish = Fal
|
|
36
36
|
gateway_base['ports'] = ports
|
37
37
|
|
38
38
|
app_dir_path = os.path.dirname(os.path.dirname(service_dir_path))
|
39
|
-
__with_traefik_config(
|
39
|
+
__with_traefik_config(workflow_namespace, service_paths, app_dir_path, gateway_base)
|
40
40
|
__with_networks(gateway_base, hostnames)
|
41
41
|
|
42
42
|
with open(docker_compose_dest_path, 'w') as fp:
|
@@ -50,7 +50,7 @@ def __with_networks(config: dict, hostnames: List[str]):
|
|
50
50
|
'aliases': hostnames
|
51
51
|
}
|
52
52
|
|
53
|
-
def __with_traefik_config(
|
53
|
+
def __with_traefik_config(workflow_namespace: WorkflowNamespace, service_paths: List[str], app_dir_path: str, compose: dict):
|
54
54
|
config_dest = '/etc/traefik/traefik.yml'
|
55
55
|
|
56
56
|
if not compose['volumes']:
|
@@ -98,8 +98,8 @@ def __with_traefik_config(namespace: str, service_paths: List[str], app_dir_path
|
|
98
98
|
})
|
99
99
|
|
100
100
|
# Create traefik.yml in .stoobly/tmp
|
101
|
-
traefik_template_relative_path =
|
102
|
-
traefik_template_dest_path =
|
101
|
+
traefik_template_relative_path = workflow_namespace.traefik_config_relative_path(app_dir_path)
|
102
|
+
traefik_template_dest_path = workflow_namespace.traefik_config_path
|
103
103
|
|
104
104
|
if not os.path.exists(os.path.dirname(traefik_template_dest_path)):
|
105
105
|
os.makedirs(os.path.dirname(traefik_template_dest_path), exist_ok=True)
|
@@ -56,7 +56,7 @@ class ServiceConfig(Config):
|
|
56
56
|
|
57
57
|
@property
|
58
58
|
def id(self):
|
59
|
-
return hashlib.md5(self.
|
59
|
+
return hashlib.md5(self.url.encode()).hexdigest()
|
60
60
|
|
61
61
|
@property
|
62
62
|
def hostname(self):
|
@@ -107,18 +107,22 @@ class ServiceConfig(Config):
|
|
107
107
|
if not self.hostname:
|
108
108
|
return ''
|
109
109
|
|
110
|
-
|
110
|
+
return f"reverse:{self.url}"
|
111
|
+
|
112
|
+
@property
|
113
|
+
def url(self):
|
114
|
+
_url = f"{self.scheme}://{self.hostname}"
|
111
115
|
|
112
116
|
if not self.port:
|
113
|
-
return
|
117
|
+
return _url
|
114
118
|
|
115
119
|
if self.scheme == 'http' and self.port == 80:
|
116
|
-
return
|
120
|
+
return _url
|
117
121
|
|
118
122
|
if self.scheme == 'https' and self.port == 443:
|
119
|
-
return
|
123
|
+
return _url
|
120
124
|
|
121
|
-
return f"{
|
125
|
+
return f"{_url}:{self.port}"
|
122
126
|
|
123
127
|
@proxy_mode.setter
|
124
128
|
def proxy_mode(self, v):
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# STOOBLY_CA_CERTS_DIR: path to folder where ca certs are stored, defaults to $(pwd)/.stoobly/ca_certs
|
5
5
|
# STOOBLY_CERTS_DIR: path to a folder to store certs, defaults to $(pwd)/.stoobly/certs
|
6
6
|
# STOOBLY_CONTEXT_DIR: path to the folder containing the .stoobly folder, defaults to $(pwd)
|
7
|
-
#
|
7
|
+
# STOOBLY_DOTENV_FILE: path to dotenv file, defaults to $(pwd)/.env
|
8
8
|
# STOOBLY_WORKFLOW_SERVICE_OPTIONS: extra --service options to pass 'stoobly-agent scaffold workflow' commands
|
9
9
|
|
10
10
|
# Overridable Options
|
@@ -28,7 +28,7 @@ app_dir=$$(realpath "$${STOOBLY_APP_DIR:-$(CONTEXT_DIR_DEFAULT)}")
|
|
28
28
|
ca_certs_dir=$$(realpath "$${STOOBLY_CA_CERTS_DIR:-$(app_data_dir)/ca_certs}")
|
29
29
|
certs_dir=$$(realpath "$${STOOBLY_CERTS_DIR:-$(app_data_dir)/certs}")
|
30
30
|
context_dir=$$(realpath "$${STOOBLY_CONTEXT_DIR:-$(CONTEXT_DIR_DEFAULT)}")
|
31
|
-
|
31
|
+
dotenv_file=$$(realpath "$${STOOBLY_DOTENV_FILE:-.env}" 2> /dev/null || echo '')
|
32
32
|
workflow=record
|
33
33
|
workflow_service_options=$(shell echo $$STOOBLY_WORKFLOW_SERVICE_OPTIONS)
|
34
34
|
|
@@ -38,6 +38,7 @@ app_tmp_dir=$(app_data_dir)/tmp
|
|
38
38
|
dockerfile_path=$(app_namespace_dir)/.Dockerfile.context
|
39
39
|
exec_docker_compose_file_path=$(app_namespace_dir)/stoobly-ui/exec/.docker-compose.exec.yml
|
40
40
|
workflow_namespace=$(if $(namespace),$(namespace),$(workflow))
|
41
|
+
workflow_namespace_dir=$(app_tmp_dir)/$(workflow_namespace)
|
41
42
|
workflow_script=.stoobly/tmp/$(workflow_namespace)/run.sh
|
42
43
|
|
43
44
|
# Options
|
@@ -48,24 +49,23 @@ workflow_down_options=$(working_dir_options) --user-id $(USER_ID) $(workflow_dow
|
|
48
49
|
workflow_log_options=$(workflow_log_extra_options)
|
49
50
|
workflow_run_options=--namespace $(workflow_namespace) --script-path $(workflow_script) $(workflow_service_options)
|
50
51
|
workflow_up_options=$(working_dir_options) $(certs_dir_options) --user-id $(USER_ID) $(workflow_up_extra_options)
|
51
|
-
|
52
|
+
|
52
53
|
# Commands
|
53
54
|
exec_env=APP_DIR="$(app_dir)" CA_CERTS_DIR="$(ca_certs_dir)" USER_ID="$(USER_ID)"
|
54
55
|
exec_up=$(DOCKER_BIN) compose -f "$(exec_docker_compose_file_path)" run --rm stoobly_ui.command
|
55
|
-
source_env=set -a; [ -f "$(env_file)" ] && . "$(env_file)"; set +a
|
56
56
|
|
57
57
|
# Build base image
|
58
58
|
stoobly_exec_build=$(DOCKER_BIN) build $(stoobly_exec_build_args) $(app_namespace_dir) > /dev/null
|
59
59
|
stoobly_exec_build_args=-f "$(dockerfile_path)" -t stoobly.$(USER_ID) --build-arg USER_ID=$(USER_ID) $(PULL_OPTION) --quiet
|
60
60
|
|
61
61
|
# Exec any
|
62
|
-
stoobly_exec=$(
|
62
|
+
stoobly_exec=$(stoobly_exec_build) && $(stoobly_exec_env) $(exec_up)
|
63
63
|
stoobly_exec_env=$(exec_env) CONTEXT_DIR="$(context_dir)"
|
64
64
|
|
65
65
|
# Exec workflow run
|
66
66
|
# Scaffold is stored in the application source code directory.
|
67
67
|
# When running a scaffold command from within a container, it needs access to $(app_dir) rather than $(context_dir)
|
68
|
-
stoobly_exec_run=$(
|
68
|
+
stoobly_exec_run=$(stoobly_exec_build) && $(stoobly_exec_run_env) $(exec_up)
|
69
69
|
stoobly_exec_run_env=$(exec_env) CONTEXT_DIR="$(app_dir)"
|
70
70
|
|
71
71
|
# Workflow run
|
@@ -88,14 +88,16 @@ ca-cert/install: stoobly/install
|
|
88
88
|
certs:
|
89
89
|
@export EXEC_COMMAND=scaffold/.mkcert EXEC_OPTIONS="" EXEC_ARGS="" && \
|
90
90
|
$(stoobly_exec)
|
91
|
-
|
91
|
+
dotenv: workflow/namespace
|
92
|
+
@if [ -f "$(dotenv_file)" ]; then cp "$(dotenv_file)" $(workflow_namespace_dir)/.env; fi
|
93
|
+
nameservers: workflow/namespace
|
92
94
|
@if [ -f /etc/resolv.conf ]; then \
|
93
95
|
nameserver=$$(grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' /etc/resolv.conf) && \
|
94
96
|
if [ "$$nameserver" = "127.0.0.53" ]; then \
|
95
97
|
echo "Nameserver is 127.0.0.53. Checking resolvectl status..."; \
|
96
98
|
nameserver=$$(resolvectl status | sed -n '/DNS Servers:/s/.*DNS Servers:\s*\([^ ]*\).*/\1/p' | head -n 1); \
|
97
99
|
fi; \
|
98
|
-
echo "$$nameserver" > $(
|
100
|
+
echo "$$nameserver" > $(workflow_namespace_dir)/.nameservers; \
|
99
101
|
else \
|
100
102
|
echo "/etc/resolv.conf not found." >&2; \
|
101
103
|
fi
|
@@ -158,7 +160,7 @@ test/logs: workflow/test workflow/logs
|
|
158
160
|
test/down: workflow/test workflow/down
|
159
161
|
tmpdir:
|
160
162
|
@mkdir -p $(app_tmp_dir)
|
161
|
-
workflow/down:
|
163
|
+
workflow/down: dotenv
|
162
164
|
@export EXEC_COMMAND=scaffold/.down EXEC_OPTIONS="$(workflow_down_options) $(workflow_run_options) $(options)" EXEC_ARGS="$(workflow)" && \
|
163
165
|
$(stoobly_exec_run) && \
|
164
166
|
$(workflow_run)
|
@@ -182,6 +184,8 @@ workflow/logs:
|
|
182
184
|
$(workflow_run)
|
183
185
|
workflow/mock:
|
184
186
|
$(eval workflow=mock)
|
187
|
+
workflow/namespace: tmpdir
|
188
|
+
@mkdir -p $(workflow_namespace_dir)
|
185
189
|
workflow/record:
|
186
190
|
$(eval workflow=record)
|
187
191
|
workflow/services:
|
@@ -189,7 +193,7 @@ workflow/services:
|
|
189
193
|
$(stoobly_exec_run)
|
190
194
|
workflow/test:
|
191
195
|
$(eval workflow=test) $(eval workflow_up_extra_options=$(workflow_up_extra_options) --no-publish)
|
192
|
-
workflow/up:
|
196
|
+
workflow/up: dotenv
|
193
197
|
@export EXEC_COMMAND=scaffold/.up EXEC_OPTIONS="$(workflow_up_options) $(workflow_run_options) $(options)" EXEC_ARGS="$(workflow)" && \
|
194
198
|
$(stoobly_exec_run) && \
|
195
199
|
$(workflow_run)
|
@@ -5,7 +5,7 @@ import yaml
|
|
5
5
|
from stoobly_agent.lib.logger import Logger
|
6
6
|
|
7
7
|
from .app import App
|
8
|
-
from .constants import BIN_FOLDER_NAME, COMPOSE_TEMPLATE, CONFIG_FILE,
|
8
|
+
from .constants import BIN_FOLDER_NAME, COMPOSE_TEMPLATE, CONFIG_FILE, DOTENV_FILE, PUBLIC_FOLDER_NAME
|
9
9
|
from .docker.constants import DOCKER_COMPOSE_CUSTOM
|
10
10
|
from .service_command import ServiceCommand
|
11
11
|
from .workflow_config import WorkflowConfig
|
@@ -101,8 +101,8 @@ class WorkflowCommand(ServiceCommand):
|
|
101
101
|
return os.path.join(self.workflow_path, CONFIG_FILE)
|
102
102
|
|
103
103
|
@property
|
104
|
-
def
|
105
|
-
return os.path.join(self.workflow_path,
|
104
|
+
def workflow_dotenv_path(self):
|
105
|
+
return os.path.join(self.workflow_path, DOTENV_FILE)
|
106
106
|
|
107
107
|
@property
|
108
108
|
def workflow_exists(self):
|
@@ -1,11 +1,15 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
from dotenv import dotenv_values
|
4
|
+
|
1
5
|
from .config import Config
|
2
|
-
from .constants import
|
6
|
+
from .constants import DOTENV_FILE
|
3
7
|
from .env import Env
|
4
8
|
|
5
9
|
class WorkflowEnv(Config):
|
6
10
|
|
7
11
|
def __init__(self, dir: str):
|
8
|
-
super().__init__(dir,
|
12
|
+
super().__init__(dir, DOTENV_FILE)
|
9
13
|
|
10
14
|
self.__env_vars = {}
|
11
15
|
|
@@ -15,6 +19,9 @@ class WorkflowEnv(Config):
|
|
15
19
|
def load(self):
|
16
20
|
self.__env_vars = self.read()
|
17
21
|
|
18
|
-
def write(self, env_vars: dict):
|
22
|
+
def write(self, env_vars: dict, dotenv_path: str = None):
|
23
|
+
if dotenv_path and os.path.exists(dotenv_path):
|
24
|
+
env_vars = { **env_vars, **dotenv_values(dotenv_path) }
|
25
|
+
|
19
26
|
Env(self.path).write(env_vars)
|
20
27
|
self.__env_vars = env_vars
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import os
|
2
|
+
import shutil
|
3
|
+
|
4
|
+
from .app import App
|
5
|
+
from .constants import DOTENV_PATH_ENV, DOTENV_FILE, NAMESERVERS_FILE
|
6
|
+
|
7
|
+
class WorkflowNamespace():
|
8
|
+
|
9
|
+
def __init__(self, app: App, namespace: str = None):
|
10
|
+
self._app = app
|
11
|
+
self._namespace = namespace
|
12
|
+
self._path = os.path.join(app.data_dir.tmp_dir_path, namespace or '')
|
13
|
+
|
14
|
+
@property
|
15
|
+
def dotenv_path(self):
|
16
|
+
return os.path.join(self.path, DOTENV_FILE)
|
17
|
+
|
18
|
+
@property
|
19
|
+
def nameservers_path(self):
|
20
|
+
return os.path.join(self.path, NAMESERVERS_FILE)
|
21
|
+
|
22
|
+
@property
|
23
|
+
def namespace(self):
|
24
|
+
return self._namespace
|
25
|
+
|
26
|
+
@property
|
27
|
+
def path(self):
|
28
|
+
return self._path
|
29
|
+
|
30
|
+
@property
|
31
|
+
def run_script_path(self):
|
32
|
+
return os.path.join(self.path, 'run.sh')
|
33
|
+
|
34
|
+
@property
|
35
|
+
def traefik_config_path(self):
|
36
|
+
return os.path.join(self.path, 'traefik.yml')
|
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
|
+
|
44
|
+
def traefik_config_relative_path(self, path: str):
|
45
|
+
if not path:
|
46
|
+
return path
|
47
|
+
return self.traefik_config_path.replace(path if path[len(path) - 1] == '/' else path + '/', '', 1)
|
@@ -1,22 +1,23 @@
|
|
1
1
|
import dns.resolver
|
2
|
-
import hashlib
|
3
2
|
import os
|
4
3
|
import pdb
|
5
4
|
import subprocess
|
6
5
|
import re
|
7
6
|
|
7
|
+
|
8
8
|
from stoobly_agent.config.data_dir import DataDir
|
9
9
|
from stoobly_agent.lib.logger import Logger
|
10
10
|
|
11
11
|
from .app import App
|
12
12
|
from .constants import (
|
13
|
-
APP_DIR_ENV, APP_NETWORK_ENV, CA_CERTS_DIR_ENV, CERTS_DIR_ENV, CONTEXT_DIR_ENV,
|
13
|
+
APP_DIR_ENV, APP_NETWORK_ENV, CA_CERTS_DIR_ENV, CERTS_DIR_ENV, CONTEXT_DIR_ENV,
|
14
14
|
SERVICE_DNS_ENV, SERVICE_NAME_ENV, SERVICE_SCRIPTS_DIR, SERVICE_SCRIPTS_ENV, USER_ID_ENV,
|
15
15
|
WORKFLOW_NAME_ENV, WORKFLOW_NAMESPACE_ENV, WORKFLOW_SCRIPTS_DIR, WORKFLOW_SCRIPTS_ENV, WORKFLOW_TEMPLATE_ENV
|
16
16
|
)
|
17
17
|
from .docker.constants import APP_EGRESS_NETWORK_TEMPLATE, APP_INGRESS_NETWORK_TEMPLATE, DOCKERFILE_CONTEXT
|
18
18
|
from .workflow_command import WorkflowCommand
|
19
19
|
from .workflow_env import WorkflowEnv
|
20
|
+
from .workflow_namesapce import WorkflowNamespace
|
20
21
|
from ..types.workflow_run_command import BuildOptions, ComposeOptions, DownOptions, UpOptions
|
21
22
|
|
22
23
|
LOG_ID = 'WorkflowRunCommand'
|
@@ -30,7 +31,8 @@ class WorkflowRunCommand(WorkflowCommand):
|
|
30
31
|
self.__ca_certs_dir_path = kwargs.get('ca_certs_dir_path') or app.ca_certs_dir_path
|
31
32
|
self.__certs_dir_path = kwargs.get('certs_dir_path') or app.certs_dir_path
|
32
33
|
self.__context_dir_path = kwargs.get('context_dir_path') or app.context_dir_path
|
33
|
-
self.
|
34
|
+
self.__namespace = kwargs.get('namespace') or self.workflow_name
|
35
|
+
self.__network = f"{self.__namespace}.{kwargs.get('network') or app.network}"
|
34
36
|
|
35
37
|
@property
|
36
38
|
def app_dir_path(self):
|
@@ -60,6 +62,10 @@ class WorkflowRunCommand(WorkflowCommand):
|
|
60
62
|
def current_working_dir(self, v):
|
61
63
|
self.__current_working_dir = v
|
62
64
|
|
65
|
+
@property
|
66
|
+
def dotenv_path(self):
|
67
|
+
return WorkflowNamespace(self.app, self.namespace).dotenv_path
|
68
|
+
|
63
69
|
@property
|
64
70
|
def nameservers(self):
|
65
71
|
path = self.nameservers_path
|
@@ -72,7 +78,11 @@ class WorkflowRunCommand(WorkflowCommand):
|
|
72
78
|
|
73
79
|
@property
|
74
80
|
def nameservers_path(self):
|
75
|
-
return
|
81
|
+
return WorkflowNamespace(self.app, self.namespace).nameservers_path
|
82
|
+
|
83
|
+
@property
|
84
|
+
def namespace(self):
|
85
|
+
return self.__namespace
|
76
86
|
|
77
87
|
@property
|
78
88
|
def network(self):
|
@@ -272,7 +282,7 @@ class WorkflowRunCommand(WorkflowCommand):
|
|
272
282
|
_config[SERVICE_DNS_ENV] = '8.8.8.8'
|
273
283
|
|
274
284
|
env_vars = self.config(_config)
|
275
|
-
WorkflowEnv(self.workflow_path).write(env_vars)
|
285
|
+
WorkflowEnv(self.workflow_path).write(env_vars, self.dotenv_path)
|
276
286
|
return env_vars
|
277
287
|
|
278
288
|
def __find_nameservers(self, dns_resolver: dns.resolver.Resolver):
|
@@ -30,6 +30,7 @@ from stoobly_agent.app.cli.scaffold.workflow import Workflow
|
|
30
30
|
from stoobly_agent.app.cli.scaffold.workflow_create_command import WorkflowCreateCommand
|
31
31
|
from stoobly_agent.app.cli.scaffold.workflow_copy_command import WorkflowCopyCommand
|
32
32
|
from stoobly_agent.app.cli.scaffold.workflow_log_command import WorkflowLogCommand
|
33
|
+
from stoobly_agent.app.cli.scaffold.workflow_namesapce import WorkflowNamespace
|
33
34
|
from stoobly_agent.app.cli.scaffold.workflow_run_command import WorkflowRunCommand
|
34
35
|
from stoobly_agent.app.cli.scaffold.workflow_validate_command import WorkflowValidateCommand
|
35
36
|
from stoobly_agent.config.constants import env_vars
|
@@ -88,6 +89,7 @@ def hostname(ctx):
|
|
88
89
|
help="Scaffold application"
|
89
90
|
)
|
90
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', type=click.Path(exists=True, file_okay=True, dir_okay=False), help='Path to Docker socket.')
|
91
93
|
@click.option('--quiet', is_flag=True, help='Disable log output.')
|
92
94
|
@click.option('--ui-port', default=4200, type=click.IntRange(1, 65535), help='UI service port.')
|
93
95
|
@click.argument('app_name', callback=validate_app_name)
|
@@ -337,7 +339,7 @@ def copy(**kwargs):
|
|
337
339
|
@click.option('--service', multiple=True, help='Select which services to log. Defaults to all.')
|
338
340
|
@click.option('--user-id', default=os.getuid(), help='OS user ID of the owner of context dir path.')
|
339
341
|
@click.argument('workflow_name')
|
340
|
-
def down(**kwargs):
|
342
|
+
def down(**kwargs):
|
341
343
|
os.environ[env_vars.LOG_LEVEL] = kwargs['log_level']
|
342
344
|
|
343
345
|
containerized = kwargs['containerized']
|
@@ -347,6 +349,7 @@ def down(**kwargs):
|
|
347
349
|
__validate_app(app)
|
348
350
|
|
349
351
|
__with_namespace_defaults(kwargs)
|
352
|
+
__with_workflow_namespace(app, kwargs['namespace'])
|
350
353
|
|
351
354
|
services = __get_services(
|
352
355
|
app, service=kwargs['service'], workflow=[kwargs['workflow_name']]
|
@@ -360,7 +363,7 @@ def down(**kwargs):
|
|
360
363
|
command.current_working_dir = current_working_dir
|
361
364
|
commands.append(command)
|
362
365
|
|
363
|
-
script = __build_script(**kwargs)
|
366
|
+
script = __build_script(app, **kwargs)
|
364
367
|
|
365
368
|
commands = sorted(commands, key=lambda command: command.service_config.priority)
|
366
369
|
for index, command in enumerate(commands):
|
@@ -449,7 +452,7 @@ def logs(**kwargs):
|
|
449
452
|
command = WorkflowLogCommand(app, **config)
|
450
453
|
commands.append(command)
|
451
454
|
|
452
|
-
script = __build_script(**kwargs)
|
455
|
+
script = __build_script(app, **kwargs)
|
453
456
|
|
454
457
|
commands = sorted(commands, key=lambda command: command.service_config.priority)
|
455
458
|
for index, command in enumerate(commands):
|
@@ -501,6 +504,7 @@ def up(**kwargs):
|
|
501
504
|
__validate_app(app)
|
502
505
|
|
503
506
|
__with_namespace_defaults(kwargs)
|
507
|
+
workflow_namespace = __with_workflow_namespace(app, kwargs['namespace'])
|
504
508
|
|
505
509
|
services = __get_services(
|
506
510
|
app, service=kwargs['service'], workflow=[kwargs['workflow_name']]
|
@@ -512,9 +516,7 @@ def up(**kwargs):
|
|
512
516
|
|
513
517
|
# Gateway ports are dynamically set depending on the workflow run
|
514
518
|
workflow = Workflow(kwargs['workflow_name'], app)
|
515
|
-
configure_gateway(
|
516
|
-
kwargs['namespace'] or workflow.workflow_name, workflow.service_paths_from_services(services), kwargs['no_publish']
|
517
|
-
)
|
519
|
+
configure_gateway(workflow_namespace, workflow.service_paths_from_services(services), kwargs['no_publish'])
|
518
520
|
|
519
521
|
commands: List[WorkflowRunCommand] = []
|
520
522
|
for service in services:
|
@@ -524,7 +526,7 @@ def up(**kwargs):
|
|
524
526
|
command.current_working_dir = current_working_dir
|
525
527
|
commands.append(command)
|
526
528
|
|
527
|
-
script = __build_script(**kwargs)
|
529
|
+
script = __build_script(app, **kwargs)
|
528
530
|
|
529
531
|
# Before services can be started, their image and network needs to be created
|
530
532
|
if len(commands) > 0:
|
@@ -677,11 +679,11 @@ scaffold.add_command(service)
|
|
677
679
|
scaffold.add_command(workflow)
|
678
680
|
scaffold.add_command(hostname)
|
679
681
|
|
680
|
-
def __build_script(**kwargs):
|
682
|
+
def __build_script(app: App, **kwargs):
|
681
683
|
script_path = kwargs['script_path']
|
682
684
|
if not script_path:
|
683
|
-
|
684
|
-
script_path =
|
685
|
+
workflow_namespace = WorkflowNamespace(app, kwargs.get('namespace') or kwargs['workflow_name'])
|
686
|
+
script_path = workflow_namespace.run_script_path
|
685
687
|
|
686
688
|
script_dir = os.path.dirname(script_path)
|
687
689
|
if not os.path.exists(script_dir):
|
@@ -836,3 +838,8 @@ def __workflow_create(app, **kwargs):
|
|
836
838
|
template=kwargs['template'],
|
837
839
|
workflow_decorators=workflow_decorators
|
838
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
|
@@ -61,19 +61,19 @@ stoobly_agent/app/cli/helpers/trace_aliases.py,sha256=8N8pnsnONwVv-fabCTvDlXec-W
|
|
61
61
|
stoobly_agent/app/cli/helpers/trace_context_facade.py,sha256=3MDjY_bdhvE2dad_B_w9gemCZZoiVjotbE8o9hrmVYo,1027
|
62
62
|
stoobly_agent/app/cli/helpers/validations.py,sha256=nvcrEHvjMOAyHlJK0bQIwyzBUciJ0qNkNESa2zZ5ZFo,6232
|
63
63
|
stoobly_agent/app/cli/helpers/verify_raw_request_service.py,sha256=tmLeRBYhNgAQeJD-rF6Nj22F_TfVktVSb1wjRPFblBQ,658
|
64
|
-
stoobly_agent/app/cli/intercept_cli.py,sha256=
|
64
|
+
stoobly_agent/app/cli/intercept_cli.py,sha256=LNHfAec6Tf_cFNwuNvcvig-k9lKi7kVsMGIDC0fWp2o,5116
|
65
65
|
stoobly_agent/app/cli/main_group.py,sha256=3UzBxin2f2p5KNqo6Oayo_I1VI2pHpqOoRexUnJ74a4,2187
|
66
66
|
stoobly_agent/app/cli/project_cli.py,sha256=EXjeLjbnq9PhfCjvyfZ0UnJ2tejeCS0SIAo3Nc4fKOc,3852
|
67
67
|
stoobly_agent/app/cli/report_cli.py,sha256=ZxJw0Xkx7KFZJn9e45BSKRKon8AD0Msrwy1fbPfbv0c,2543
|
68
68
|
stoobly_agent/app/cli/request_cli.py,sha256=THNloW111l9MLE0oPg4y7hVXL1U7OXoz760g0A1CtJ0,7747
|
69
69
|
stoobly_agent/app/cli/scaffold/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
70
70
|
stoobly_agent/app/cli/scaffold/app.py,sha256=0HJm8cdyIBAdOBr18499MkZGhmEFu6I7GSZXR7pKxkw,3650
|
71
|
-
stoobly_agent/app/cli/scaffold/app_command.py,sha256=
|
72
|
-
stoobly_agent/app/cli/scaffold/app_config.py,sha256=
|
73
|
-
stoobly_agent/app/cli/scaffold/app_create_command.py,sha256=
|
74
|
-
stoobly_agent/app/cli/scaffold/command.py,sha256=
|
71
|
+
stoobly_agent/app/cli/scaffold/app_command.py,sha256=w15VCsyefIE9HfzpIRMrv2BEep46ZSPgvsjZmFOMPZs,2377
|
72
|
+
stoobly_agent/app/cli/scaffold/app_config.py,sha256=z4sxZcXZTEoXyUZajUuffuWQN8x8eovu-TBtgoTMXEE,1182
|
73
|
+
stoobly_agent/app/cli/scaffold/app_create_command.py,sha256=HOlXL6Ugid2qHagqDVGl3ksjLKE4WF_3Dji8FoQlpuM,1215
|
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
|
@@ -82,7 +82,7 @@ stoobly_agent/app/cli/scaffold/docker/constants.py,sha256=1khQdgTaQ89ykGRNdTQh_e
|
|
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
84
|
stoobly_agent/app/cli/scaffold/docker/service/builder.py,sha256=u3_YNuxX8TT4TvhzTqe5b2Zvi9fF7TLWJFepkBSXwhk,5857
|
85
|
-
stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py,sha256=
|
85
|
+
stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py,sha256=jbMaa08R2EoZ2esoC4uREfPoBK9b5vyPRuTNOT0QDjE,3949
|
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
|
@@ -91,13 +91,13 @@ stoobly_agent/app/cli/scaffold/docker/workflow/decorators_factory.py,sha256=bjQ8
|
|
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
|
94
|
-
stoobly_agent/app/cli/scaffold/env.py,sha256=
|
94
|
+
stoobly_agent/app/cli/scaffold/env.py,sha256=dT33tHoQaUxfsFCYm8kfaAv-qPVrUPmNFQmLnFQhZeQ,1107
|
95
95
|
stoobly_agent/app/cli/scaffold/hosts_file_manager.py,sha256=zNX5wh6zXQ4J2BA0YYdD7_CPqDz02b_ghXsY3oTjjB4,4999
|
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=74JwjTRRkk6lo-k9hre1iGztbKa9zDqjPVx3Qgpze-s,699
|
98
|
-
stoobly_agent/app/cli/scaffold/service_command.py,sha256=
|
99
|
-
stoobly_agent/app/cli/scaffold/service_config.py,sha256=
|
100
|
-
stoobly_agent/app/cli/scaffold/service_create_command.py,sha256=
|
98
|
+
stoobly_agent/app/cli/scaffold/service_command.py,sha256=n5tVp8jIypnNO9uxtaMt33lX5ho0xhV6A53HDN2Yet4,1239
|
99
|
+
stoobly_agent/app/cli/scaffold/service_config.py,sha256=WCHy1bZ8-nlVwCWdOWKXrdIVTtjye8XStA1bqvbRgZ0,3959
|
100
|
+
stoobly_agent/app/cli/scaffold/service_create_command.py,sha256=nCONco0ducMcX4rsdFe3A-iRiySyUnu-T6bTb312XP0,2824
|
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_update_command.py,sha256=oWusBKfvjt4RnK03_V3CJYWrfsCI4_LcR7W12eLXMR4,2579
|
@@ -105,7 +105,7 @@ stoobly_agent/app/cli/scaffold/service_workflow.py,sha256=sQ_Edy_wGHKMXpD0DmhnOW
|
|
105
105
|
stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py,sha256=-hdg7RLsoEQXCI9rebIXyO3d8JbpyTxGnhpjaPQfmFk,11514
|
106
106
|
stoobly_agent/app/cli/scaffold/templates/__init__.py,sha256=x8C_a0VoO_vUbosp4_6IC1U7Ge9NnUdVKDPpVMtMkeY,171
|
107
107
|
stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.context,sha256=Okk4Q0Fj7Wi5NU58gQfpjpFwAL3RUBJyRe56kteQfcA,158
|
108
|
-
stoobly_agent/app/cli/scaffold/templates/app/.Makefile,sha256=
|
108
|
+
stoobly_agent/app/cli/scaffold/templates/app/.Makefile,sha256=uV-xqit3fz3tfcU6sbBOxK0Zon11v-fydfuYLSxS7jQ,9164
|
109
109
|
stoobly_agent/app/cli/scaffold/templates/app/.docker-compose.base.yml,sha256=6tFqXh3ine8vaD0FCL5TMoY5NjKx2wLUR8XpW3tJtew,245
|
110
110
|
stoobly_agent/app/cli/scaffold/templates/app/.docker-compose.networks.yml,sha256=I4PbJpQjFHb5IbAUWNvYM6okDEtmwtKFDQg-yog05WM,141
|
111
111
|
stoobly_agent/app/cli/scaffold/templates/app/Makefile,sha256=TEmPG7Bf0KZOnmfsgdzza3UdwcVMmM5Lj1YdLc4cgjA,79
|
@@ -138,7 +138,7 @@ stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/configure,sha25
|
|
138
138
|
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/init,sha256=YxWVVQMEdGarcMtBcE1Sj2kdLgUgwY9kXp3MjPsVcmg,46
|
139
139
|
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/docker-compose.yml,sha256=JpWLQrW69EatLD3HPHpmi3Y6n7cjlrUgekYVbJ4ngSY,523
|
140
140
|
stoobly_agent/app/cli/scaffold/templates/app/gateway/.config.yml,sha256=XnLQZMzzMMIwVycjyPN5QXsmRztkTFAna1kIHYuDfJQ,19
|
141
|
-
stoobly_agent/app/cli/scaffold/templates/app/gateway/.docker-compose.base.template.yml,sha256=
|
141
|
+
stoobly_agent/app/cli/scaffold/templates/app/gateway/.docker-compose.base.template.yml,sha256=QipWNy2mEbJuceiNfRbv6L3ARk1lMkD1gE4l_Z0PrPU,246
|
142
142
|
stoobly_agent/app/cli/scaffold/templates/app/gateway/mock/.docker-compose.mock.yml,sha256=CDL5x18-ues4F_ujqpNef_zJTG6PyDOkQ11cIHBOW5k,136
|
143
143
|
stoobly_agent/app/cli/scaffold/templates/app/gateway/record/.docker-compose.record.yml,sha256=eyLH2h33Peunus8M1sUKL9AALCG2ABhV_heiJKhvgwo,138
|
144
144
|
stoobly_agent/app/cli/scaffold/templates/app/gateway/test/.docker-compose.test.yml,sha256=oJO6i0lsuQaQeIH80yoPZo3Vs0LzUAH2WRl853yLq6g,136
|
@@ -196,15 +196,16 @@ stoobly_agent/app/cli/scaffold/templates/workflow/test/public/.gitignore,sha256=
|
|
196
196
|
stoobly_agent/app/cli/scaffold/validate_command.py,sha256=BEDcF5qPDbMjWe-SCAr5jxcrVMZlV3ciLa89TDDENmM,3787
|
197
197
|
stoobly_agent/app/cli/scaffold/validate_exceptions.py,sha256=Jtjl4OkbbSRWm0hy7Kf_50zcFh2J324HhNcnwJKH_Oc,54
|
198
198
|
stoobly_agent/app/cli/scaffold/workflow.py,sha256=KlbWT9CIo9EpZxKU1WVZtmodhxK7CpmLUHPNk4Mh6DA,1570
|
199
|
-
stoobly_agent/app/cli/scaffold/workflow_command.py,sha256=
|
199
|
+
stoobly_agent/app/cli/scaffold/workflow_command.py,sha256=sGe5uVr34P6IZ0qfCTgM8sQ7LkvdvymM2LmBzXpw1ZY,3353
|
200
200
|
stoobly_agent/app/cli/scaffold/workflow_config.py,sha256=ghnbcnCyb6ECdylUJCAJ6A8ulzaFY9bu7RvRuYeiRkk,901
|
201
201
|
stoobly_agent/app/cli/scaffold/workflow_copy_command.py,sha256=wi8qHH_M2e6jXIPuumx65Zd4Zt7hTBb6b3Z4vt4xYeQ,1320
|
202
202
|
stoobly_agent/app/cli/scaffold/workflow_create_command.py,sha256=-fwsr6_LvGT8BbBWdGY3Qd8cSQhBOSJiMr1r8s2R86w,3390
|
203
|
-
stoobly_agent/app/cli/scaffold/workflow_env.py,sha256=
|
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/
|
205
|
+
stoobly_agent/app/cli/scaffold/workflow_namesapce.py,sha256=VNaZrcqMMeqrzpPGhD9-oaZems1k0ebRc6wR74EvA8c,1170
|
206
|
+
stoobly_agent/app/cli/scaffold/workflow_run_command.py,sha256=H9s0F8LaoB7ZLUVXWP6M6yPLYk5IE4JD8qgGXntwtMc,11138
|
206
207
|
stoobly_agent/app/cli/scaffold/workflow_validate_command.py,sha256=Uo_yo6rVR1ZR7xpvsQvlH48AyMBVLRupd4G-bRjzm_Q,5584
|
207
|
-
stoobly_agent/app/cli/scaffold_cli.py,sha256=
|
208
|
+
stoobly_agent/app/cli/scaffold_cli.py,sha256=F93zXk9WNRLfiDJ-9MpMB4My7gAJJVHDvV_fKPLsxdA,32896
|
208
209
|
stoobly_agent/app/cli/scenario_cli.py,sha256=3J1EiJOvunkfWrEkOsanw-XrKkOk78ij_GjBlE9p7CE,8229
|
209
210
|
stoobly_agent/app/cli/snapshot_cli.py,sha256=1Dw5JgDlmG6vctrawIRO7CdB73vAQk_wRBnPG2lVOrQ,11929
|
210
211
|
stoobly_agent/app/cli/trace_cli.py,sha256=K7E-vx3JUcqEDSWOdIOi_AieKNQz7dBfmRrVvKDkzFI,4605
|
@@ -330,7 +331,7 @@ stoobly_agent/app/proxy/mitmproxy/response_facade.py,sha256=0wCSzUULUhDDV93QXUgz
|
|
330
331
|
stoobly_agent/app/proxy/mock/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
331
332
|
stoobly_agent/app/proxy/mock/context.py,sha256=vDo5_3WBL73mVFnsmQWvcxvPg5nWtRJbigSrE3zGc-o,794
|
332
333
|
stoobly_agent/app/proxy/mock/custom_not_found_response_builder.py,sha256=0KWB3KFxVrnJOKDaYxm5eoJEccw7IpJZRyUvBX61-8k,697
|
333
|
-
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
|
334
335
|
stoobly_agent/app/proxy/mock/eval_request_service.py,sha256=A1tcE3wmrC1HwLpz0aRuRw-Nucn0dyHD_yHw5BeQEJU,8146
|
335
336
|
stoobly_agent/app/proxy/mock/hashed_request_decorator.py,sha256=h1ma90fdaYI9LBWpMWMqWBz-RjNwI628O4VuS_uUBX4,5061
|
336
337
|
stoobly_agent/app/proxy/mock/ignored_components_response_builder.py,sha256=E32_E1eSdmPn2SeM_e1jWnqu4xh5w_SnmOs32Shx99E,501
|
@@ -717,7 +718,7 @@ stoobly_agent/test/app/models/schemas/.stoobly/settings.yml,sha256=vLwMjweKOdod6
|
|
717
718
|
stoobly_agent/test/app/models/schemas/.stoobly/tmp/options.json,sha256=OTRzarwus48CTrItedXCrgQttJHSEZonEYc7R_knvYg,2212
|
718
719
|
stoobly_agent/test/app/models/schemas/request_test.py,sha256=9SF43KXbjO-vMr2uObPJlyLeop_JQstl6Jrh0M1A70c,1116
|
719
720
|
stoobly_agent/test/app/proxy/mitmproxy/request_facade_test.py,sha256=sXlzjKVvpORJ8fxEs5Qfc4IC0itTWxqDIzMujGjlW7I,5765
|
720
|
-
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
|
721
722
|
stoobly_agent/test/app/proxy/replay/body_parser_service_test.py,sha256=MTC4a3QxrptHzroHAfgrCEzCZ3Ur0Ijyj9_3k-bG0jQ,1228
|
722
723
|
stoobly_agent/test/app/proxy/replay/rewrite_params_service_test.py,sha256=4KVaP48KjCeoZKqY3IdrFAP5Pnb3jO86k8L7ffvz2ZI,3770
|
723
724
|
stoobly_agent/test/app/proxy/replay/trace_context_test.py,sha256=y0oBNC89sp3BG8biOBTiaTopk1LtqjThlA4d6BwAHzM,14462
|
@@ -752,8 +753,8 @@ stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml,sha256=1W
|
|
752
753
|
stoobly_agent/test/mock_data/scaffold/index.html,sha256=qJwuYajKZ4ihWZrJQ3BNObV5kf1VGnnm_vqlPJzdqLE,258
|
753
754
|
stoobly_agent/test/mock_data/uspto.yaml,sha256=6U5se7C3o-86J4m9xpOk9Npias399f5CbfWzR87WKwE,7835
|
754
755
|
stoobly_agent/test/test_helper.py,sha256=m_oAI7tmRYCNZdKfNqISWhMv3e44tjeYViQ3nTUfnos,1007
|
755
|
-
stoobly_agent-1.9.
|
756
|
-
stoobly_agent-1.9.
|
757
|
-
stoobly_agent-1.9.
|
758
|
-
stoobly_agent-1.9.
|
759
|
-
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
|