splunk-soar-sdk 3.6.1__py3-none-any.whl → 3.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.
- soar_sdk/actions_manager.py +40 -0
- soar_sdk/app.py +52 -4
- soar_sdk/asset.py +61 -69
- soar_sdk/asset_state.py +13 -3
- soar_sdk/auth/__init__.py +41 -0
- soar_sdk/auth/client.py +540 -0
- soar_sdk/auth/factories.py +120 -0
- soar_sdk/auth/flows.py +172 -0
- soar_sdk/auth/httpx_auth.py +97 -0
- soar_sdk/auth/models.py +101 -0
- soar_sdk/cli/package/cli.py +6 -4
- soar_sdk/shims/phantom/base_connector.py +7 -0
- {splunk_soar_sdk-3.6.1.dist-info → splunk_soar_sdk-3.8.0.dist-info}/METADATA +3 -1
- {splunk_soar_sdk-3.6.1.dist-info → splunk_soar_sdk-3.8.0.dist-info}/RECORD +17 -11
- {splunk_soar_sdk-3.6.1.dist-info → splunk_soar_sdk-3.8.0.dist-info}/WHEEL +0 -0
- {splunk_soar_sdk-3.6.1.dist-info → splunk_soar_sdk-3.8.0.dist-info}/entry_points.txt +0 -0
- {splunk_soar_sdk-3.6.1.dist-info → splunk_soar_sdk-3.8.0.dist-info}/licenses/LICENSE +0 -0
soar_sdk/auth/flows.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
from soar_sdk.auth.client import (
|
|
9
|
+
AuthorizationRequiredError,
|
|
10
|
+
OAuthClientError,
|
|
11
|
+
SOARAssetOAuthClient,
|
|
12
|
+
TokenExpiredError,
|
|
13
|
+
)
|
|
14
|
+
from soar_sdk.auth.models import OAuthConfig, OAuthGrantType, OAuthToken
|
|
15
|
+
from soar_sdk.logging import getLogger
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from soar_sdk.asset_state import AssetState
|
|
19
|
+
|
|
20
|
+
logger = getLogger()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class OAuthFlow(ABC):
|
|
24
|
+
"""Abstract base class for OAuth authentication flows."""
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def authenticate(self) -> OAuthToken:
|
|
28
|
+
"""Execute the authentication flow and return a valid token."""
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def get_token(self) -> OAuthToken:
|
|
32
|
+
"""Get a valid token, refreshing if necessary."""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ClientCredentialsFlow(OAuthFlow):
|
|
36
|
+
"""OAuth 2.0 Client Credentials flow."""
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
auth_state: AssetState,
|
|
41
|
+
*,
|
|
42
|
+
client_id: str,
|
|
43
|
+
client_secret: str,
|
|
44
|
+
token_endpoint: str,
|
|
45
|
+
scope: str | list[str] | None = None,
|
|
46
|
+
extra_params: dict[str, Any] | None = None,
|
|
47
|
+
) -> None:
|
|
48
|
+
self._auth_state = auth_state
|
|
49
|
+
self._extra_params = extra_params
|
|
50
|
+
|
|
51
|
+
self._config = OAuthConfig(
|
|
52
|
+
client_id=client_id,
|
|
53
|
+
client_secret=client_secret,
|
|
54
|
+
token_endpoint=token_endpoint,
|
|
55
|
+
scope=scope,
|
|
56
|
+
grant_type=OAuthGrantType.CLIENT_CREDENTIALS,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
self._client = SOARAssetOAuthClient(self._config, auth_state)
|
|
60
|
+
|
|
61
|
+
def authenticate(self) -> OAuthToken:
|
|
62
|
+
"""Authenticate using client credentials."""
|
|
63
|
+
return self._client.fetch_token_with_client_credentials(
|
|
64
|
+
extra_params=self._extra_params,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
def get_token(self) -> OAuthToken:
|
|
68
|
+
"""Get a valid token, fetching a new one if expired."""
|
|
69
|
+
try:
|
|
70
|
+
return self._client.get_valid_token(auto_refresh=False)
|
|
71
|
+
except (AuthorizationRequiredError, TokenExpiredError):
|
|
72
|
+
return self.authenticate()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class AuthorizationCodeFlow(OAuthFlow):
|
|
76
|
+
"""OAuth 2.0 Authorization Code flow."""
|
|
77
|
+
|
|
78
|
+
def __init__(
|
|
79
|
+
self,
|
|
80
|
+
auth_state: AssetState,
|
|
81
|
+
asset_id: str,
|
|
82
|
+
*,
|
|
83
|
+
client_id: str,
|
|
84
|
+
client_secret: str | None = None,
|
|
85
|
+
authorization_endpoint: str,
|
|
86
|
+
token_endpoint: str,
|
|
87
|
+
redirect_uri: str,
|
|
88
|
+
scope: str | list[str] | None = None,
|
|
89
|
+
use_pkce: bool = False,
|
|
90
|
+
extra_auth_params: dict[str, Any] | None = None,
|
|
91
|
+
extra_token_params: dict[str, Any] | None = None,
|
|
92
|
+
poll_timeout: int = 300,
|
|
93
|
+
poll_interval: int = 3,
|
|
94
|
+
) -> None:
|
|
95
|
+
self._auth_state = auth_state
|
|
96
|
+
self._asset_id = asset_id
|
|
97
|
+
self._use_pkce = use_pkce
|
|
98
|
+
self._extra_auth_params = extra_auth_params
|
|
99
|
+
self._extra_token_params = extra_token_params
|
|
100
|
+
self._poll_timeout = poll_timeout
|
|
101
|
+
self._poll_interval = poll_interval
|
|
102
|
+
|
|
103
|
+
self._config = OAuthConfig(
|
|
104
|
+
client_id=client_id,
|
|
105
|
+
client_secret=client_secret,
|
|
106
|
+
authorization_endpoint=authorization_endpoint,
|
|
107
|
+
token_endpoint=token_endpoint,
|
|
108
|
+
redirect_uri=redirect_uri,
|
|
109
|
+
scope=scope,
|
|
110
|
+
grant_type=OAuthGrantType.AUTHORIZATION_CODE,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
self._client = SOARAssetOAuthClient(self._config, auth_state)
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def client(self) -> SOARAssetOAuthClient:
|
|
117
|
+
"""Return the OAuth client."""
|
|
118
|
+
return self._client
|
|
119
|
+
|
|
120
|
+
def get_authorization_url(self) -> str:
|
|
121
|
+
"""Generate the authorization URL."""
|
|
122
|
+
auth_url, _ = self._client.create_authorization_url(
|
|
123
|
+
self._asset_id,
|
|
124
|
+
use_pkce=self._use_pkce,
|
|
125
|
+
extra_params=self._extra_auth_params,
|
|
126
|
+
)
|
|
127
|
+
return auth_url
|
|
128
|
+
|
|
129
|
+
def set_authorization_code(self, code: str) -> None:
|
|
130
|
+
"""Store authorization code in state (called by webhook)."""
|
|
131
|
+
self._client.set_authorization_code(code)
|
|
132
|
+
|
|
133
|
+
def exchange_code_for_token(self, code: str) -> OAuthToken:
|
|
134
|
+
"""Exchange an authorization code for tokens."""
|
|
135
|
+
return self._client.fetch_token_with_authorization_code(
|
|
136
|
+
code,
|
|
137
|
+
extra_params=self._extra_token_params,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
def wait_for_authorization(
|
|
141
|
+
self,
|
|
142
|
+
on_progress: Callable[[int], None] | None = None,
|
|
143
|
+
) -> OAuthToken:
|
|
144
|
+
"""Wait for user authorization to complete by polling state."""
|
|
145
|
+
start_time = time.time()
|
|
146
|
+
iteration = 0
|
|
147
|
+
|
|
148
|
+
while time.time() - start_time < self._poll_timeout:
|
|
149
|
+
time.sleep(self._poll_interval)
|
|
150
|
+
iteration += 1
|
|
151
|
+
|
|
152
|
+
if on_progress:
|
|
153
|
+
on_progress(iteration)
|
|
154
|
+
|
|
155
|
+
code = self._client.get_authorization_code(force_reload=True)
|
|
156
|
+
if code:
|
|
157
|
+
return self.exchange_code_for_token(code)
|
|
158
|
+
|
|
159
|
+
raise OAuthClientError(
|
|
160
|
+
f"Authorization timed out after {self._poll_timeout} seconds"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
def authenticate(self) -> OAuthToken:
|
|
164
|
+
"""Execute the full authorization code flow."""
|
|
165
|
+
auth_url = self.get_authorization_url()
|
|
166
|
+
raise AuthorizationRequiredError(
|
|
167
|
+
f"User authorization required. Please visit: {auth_url}"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def get_token(self) -> OAuthToken:
|
|
171
|
+
"""Get a valid token, refreshing if necessary."""
|
|
172
|
+
return self._client.get_valid_token(auto_refresh=True)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
from collections.abc import Generator
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
|
|
8
|
+
from soar_sdk.auth.client import SOARAssetOAuthClient
|
|
9
|
+
from soar_sdk.auth.models import OAuthToken
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BasicAuth(httpx.Auth):
|
|
13
|
+
"""HTTPX authentication using HTTP Basic Authentication."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, username: str, password: str) -> None:
|
|
16
|
+
self._username = username
|
|
17
|
+
self._password = password
|
|
18
|
+
|
|
19
|
+
def auth_flow(
|
|
20
|
+
self,
|
|
21
|
+
request: httpx.Request,
|
|
22
|
+
) -> Generator[httpx.Request, httpx.Response]:
|
|
23
|
+
"""Add Basic authentication header to the request."""
|
|
24
|
+
credentials = f"{self._username}:{self._password}"
|
|
25
|
+
encoded = base64.b64encode(credentials.encode()).decode("ascii")
|
|
26
|
+
request.headers["Authorization"] = f"Basic {encoded}"
|
|
27
|
+
yield request
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class StaticTokenAuth(httpx.Auth):
|
|
31
|
+
"""HTTPX authentication using a static token."""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
token: OAuthToken | str,
|
|
36
|
+
*,
|
|
37
|
+
token_type: str = "Bearer", # noqa: S107
|
|
38
|
+
header_name: str = "Authorization",
|
|
39
|
+
) -> None:
|
|
40
|
+
if isinstance(token, str):
|
|
41
|
+
self._access_token = token
|
|
42
|
+
else:
|
|
43
|
+
self._access_token = token.access_token
|
|
44
|
+
token_type = token.token_type or token_type
|
|
45
|
+
self._token_type = token_type
|
|
46
|
+
self._header_name = header_name
|
|
47
|
+
|
|
48
|
+
def auth_flow(
|
|
49
|
+
self,
|
|
50
|
+
request: httpx.Request,
|
|
51
|
+
) -> Generator[httpx.Request, httpx.Response]:
|
|
52
|
+
"""Add authentication header to the request."""
|
|
53
|
+
if self._token_type:
|
|
54
|
+
request.headers[self._header_name] = (
|
|
55
|
+
f"{self._token_type} {self._access_token}"
|
|
56
|
+
)
|
|
57
|
+
else:
|
|
58
|
+
request.headers[self._header_name] = self._access_token
|
|
59
|
+
yield request
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class OAuthBearerAuth(httpx.Auth):
|
|
63
|
+
"""HTTPX authentication using OAuth Bearer tokens."""
|
|
64
|
+
|
|
65
|
+
requires_response_body = True
|
|
66
|
+
|
|
67
|
+
def __init__(
|
|
68
|
+
self,
|
|
69
|
+
oauth_client: SOARAssetOAuthClient,
|
|
70
|
+
*,
|
|
71
|
+
auto_refresh: bool = True,
|
|
72
|
+
) -> None:
|
|
73
|
+
self._oauth_client = oauth_client
|
|
74
|
+
self._auto_refresh = auto_refresh
|
|
75
|
+
self._token: OAuthToken | None = None
|
|
76
|
+
|
|
77
|
+
def auth_flow(
|
|
78
|
+
self,
|
|
79
|
+
request: httpx.Request,
|
|
80
|
+
) -> Generator[httpx.Request, httpx.Response]:
|
|
81
|
+
"""Handle authentication flow for a request."""
|
|
82
|
+
if self._token is None or self._token.is_expired():
|
|
83
|
+
self._token = self._oauth_client.get_valid_token(
|
|
84
|
+
auto_refresh=self._auto_refresh
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
request.headers["Authorization"] = f"Bearer {self._token.access_token}"
|
|
88
|
+
response = yield request
|
|
89
|
+
|
|
90
|
+
if (
|
|
91
|
+
response.status_code == 401
|
|
92
|
+
and self._auto_refresh
|
|
93
|
+
and self._token.refresh_token
|
|
94
|
+
):
|
|
95
|
+
self._token = self._oauth_client.refresh_token(self._token.refresh_token)
|
|
96
|
+
request.headers["Authorization"] = f"Bearer {self._token.access_token}"
|
|
97
|
+
yield request
|
soar_sdk/auth/models.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from enum import StrEnum
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class OAuthGrantType(StrEnum):
|
|
10
|
+
"""Supported OAuth 2.0 grant types."""
|
|
11
|
+
|
|
12
|
+
AUTHORIZATION_CODE = "authorization_code"
|
|
13
|
+
CLIENT_CREDENTIALS = "client_credentials"
|
|
14
|
+
REFRESH_TOKEN = "refresh_token" # noqa: S105
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class OAuthToken(BaseModel):
|
|
18
|
+
"""OAuth 2.0 token response."""
|
|
19
|
+
|
|
20
|
+
model_config = ConfigDict(extra="allow")
|
|
21
|
+
|
|
22
|
+
_DEFAULT_TOKEN_TYPE = "Bearer" # noqa: S105
|
|
23
|
+
|
|
24
|
+
access_token: str
|
|
25
|
+
token_type: str = _DEFAULT_TOKEN_TYPE
|
|
26
|
+
expires_in: int | None = None
|
|
27
|
+
refresh_token: str | None = None
|
|
28
|
+
scope: str | None = None
|
|
29
|
+
expires_at: float | None = None
|
|
30
|
+
|
|
31
|
+
def model_post_init(self, __context: object) -> None:
|
|
32
|
+
"""Calculate expires_at if not provided but expires_in is available."""
|
|
33
|
+
if self.expires_at is None and self.expires_in is not None:
|
|
34
|
+
self.expires_at = time.time() + self.expires_in
|
|
35
|
+
|
|
36
|
+
def is_expired(self, leeway: int = 30) -> bool:
|
|
37
|
+
"""Check if the token is expired."""
|
|
38
|
+
if self.expires_at is None:
|
|
39
|
+
return False
|
|
40
|
+
return time.time() >= (self.expires_at - leeway)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class OAuthConfig(BaseModel):
|
|
44
|
+
"""Configuration for OAuth 2.0 authentication."""
|
|
45
|
+
|
|
46
|
+
model_config = ConfigDict(extra="forbid")
|
|
47
|
+
|
|
48
|
+
client_id: str
|
|
49
|
+
client_secret: str | None = None
|
|
50
|
+
authorization_endpoint: str | None = None
|
|
51
|
+
token_endpoint: str
|
|
52
|
+
redirect_uri: str | None = None
|
|
53
|
+
scope: str | list[str] | None = None
|
|
54
|
+
grant_type: OAuthGrantType = OAuthGrantType.AUTHORIZATION_CODE
|
|
55
|
+
|
|
56
|
+
def get_scope_string(self) -> str | None:
|
|
57
|
+
"""Return scope as a space-separated string."""
|
|
58
|
+
if self.scope is None:
|
|
59
|
+
return None
|
|
60
|
+
if isinstance(self.scope, list):
|
|
61
|
+
return " ".join(self.scope)
|
|
62
|
+
return self.scope
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class OAuthSession(BaseModel):
|
|
66
|
+
"""Represents an active OAuth authentication session."""
|
|
67
|
+
|
|
68
|
+
model_config = ConfigDict(extra="forbid")
|
|
69
|
+
|
|
70
|
+
session_id: str
|
|
71
|
+
asset_id: str
|
|
72
|
+
auth_pending: bool = True
|
|
73
|
+
auth_complete: bool = False
|
|
74
|
+
auth_code: str | None = None
|
|
75
|
+
error: str | None = None
|
|
76
|
+
error_description: str | None = None
|
|
77
|
+
state: str | None = None
|
|
78
|
+
code_verifier: str | None = None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class OAuthState(BaseModel):
|
|
82
|
+
"""State persisted in auth_state for OAuth authentication."""
|
|
83
|
+
|
|
84
|
+
model_config = ConfigDict(extra="forbid")
|
|
85
|
+
|
|
86
|
+
token: OAuthToken | None = None
|
|
87
|
+
session: OAuthSession | None = None
|
|
88
|
+
client_id: str | None = Field(
|
|
89
|
+
default=None,
|
|
90
|
+
description="Stored client_id to detect credential changes",
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class CertificateCredentials(BaseModel):
|
|
95
|
+
"""Certificate-based authentication credentials."""
|
|
96
|
+
|
|
97
|
+
model_config = ConfigDict(extra="forbid")
|
|
98
|
+
|
|
99
|
+
certificate_thumbprint: str
|
|
100
|
+
private_key: str
|
|
101
|
+
tenant_id: str | None = None
|
soar_sdk/cli/package/cli.py
CHANGED
|
@@ -66,10 +66,12 @@ async def collect_all_wheels(wheels: list[DependencyWheel]) -> list[tuple[str, b
|
|
|
66
66
|
cache = dict(gathered_results)
|
|
67
67
|
|
|
68
68
|
for key, wheel_group in dedupe_map.items():
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
for
|
|
72
|
-
|
|
69
|
+
representative = wheel_group[0]
|
|
70
|
+
if representative.sdist is not None or representative.source_dir is not None:
|
|
71
|
+
for path, _ in cache[key]:
|
|
72
|
+
wheel_name = Path(path).name
|
|
73
|
+
for wheel in wheel_group:
|
|
74
|
+
wheel._record_built_wheel(wheel_name)
|
|
73
75
|
|
|
74
76
|
return list(chain.from_iterable(cache.values()))
|
|
75
77
|
|
|
@@ -121,6 +121,13 @@ if TYPE_CHECKING or not _soar_is_available:
|
|
|
121
121
|
def get_config(self) -> dict:
|
|
122
122
|
return self.config
|
|
123
123
|
|
|
124
|
+
def get_app_id(self) -> str:
|
|
125
|
+
return self.__app_json.get("appid", "")
|
|
126
|
+
|
|
127
|
+
def get_state_dir(self) -> str:
|
|
128
|
+
phantom_home = os.getenv("PHANTOM_HOME", "/opt/phantom")
|
|
129
|
+
return f"{phantom_home}/local_data/app_states/{self.get_app_id()}/"
|
|
130
|
+
|
|
124
131
|
def save_state(self, state: dict) -> None:
|
|
125
132
|
self.__state = state
|
|
126
133
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: splunk-soar-sdk
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.8.0
|
|
4
4
|
Summary: The official framework for developing and testing Splunk SOAR Apps
|
|
5
5
|
Project-URL: Homepage, https://github.com/phantomcyber/splunk-soar-sdk
|
|
6
6
|
Project-URL: Documentation, https://github.com/phantomcyber/splunk-soar-sdk
|
|
@@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
17
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
18
|
Classifier: Typing :: Typed
|
|
19
19
|
Requires-Python: <3.15,>=3.13
|
|
20
|
+
Requires-Dist: authlib>=1.3.0
|
|
20
21
|
Requires-Dist: beautifulsoup4>=4.10.0
|
|
21
22
|
Requires-Dist: bleach>=6.2.0
|
|
22
23
|
Requires-Dist: build>=1.3.0
|
|
@@ -29,6 +30,7 @@ Requires-Dist: humanize>=4.12.2
|
|
|
29
30
|
Requires-Dist: jinja2>=3.1.0
|
|
30
31
|
Requires-Dist: packaging>=25.0
|
|
31
32
|
Requires-Dist: pydantic<3,>=2
|
|
33
|
+
Requires-Dist: pyjwt[crypto]>=2.8.0
|
|
32
34
|
Requires-Dist: requests<3
|
|
33
35
|
Requires-Dist: setuptools>=80.9.0
|
|
34
36
|
Requires-Dist: toml<1,>=0.10.2
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
soar_sdk/__init__.py,sha256=RzAng-ARqpK01SY82lNy4uYJFVG0yW6Q3CccEqbToJ4,726
|
|
2
2
|
soar_sdk/abstract.py,sha256=GycJhTrSNDa7eDg8hOD7hJjIt5eHEykZhpza-jh_Veo,7787
|
|
3
3
|
soar_sdk/action_results.py,sha256=eL4qBj2nXDKurzs733z_nnpNREc0SLLYJP2lPTpMKf0,11911
|
|
4
|
-
soar_sdk/actions_manager.py,sha256=
|
|
5
|
-
soar_sdk/app.py,sha256=
|
|
4
|
+
soar_sdk/actions_manager.py,sha256=8IYOi2k8i9LHXEhQVZ0Ig3IS1gD3iAmOJ9q0bi14g-o,7179
|
|
5
|
+
soar_sdk/app.py,sha256=2bUWx1BgWS9Kwkp0aUzVWM8LTdVUq1JI2eXR0LhwEMU,37092
|
|
6
6
|
soar_sdk/app_cli_runner.py,sha256=K1ATWyGs0iNgPfIjMthsN72laOXqXCFZNEXfuzAMOM4,11645
|
|
7
7
|
soar_sdk/app_client.py,sha256=hbe1R2QwXDmoS4959a-ay9oylD1Qk-oPJvJRnxvICz0,6281
|
|
8
|
-
soar_sdk/asset.py,sha256=
|
|
9
|
-
soar_sdk/asset_state.py,sha256=
|
|
8
|
+
soar_sdk/asset.py,sha256=CUCFjUVAawrk3hyGvQn_qNApqJx8J4VxzD--iGEE2pc,12123
|
|
9
|
+
soar_sdk/asset_state.py,sha256=qh4n8IoabVObIZXRPyM0zznwC5LcJpbADcybmDdQABc,2318
|
|
10
10
|
soar_sdk/async_utils.py,sha256=Dz7RagIRjyIagA9vivHWSb18S96J2WOuDB8B5Zy64AE,1428
|
|
11
11
|
soar_sdk/colors.py,sha256=--i_iXqfyITUz4O95HMjfZQGbwFZ34bLmBhtfpXXqlQ,1095
|
|
12
12
|
soar_sdk/compat.py,sha256=N4bG1wqISICV92K1jLx7v5JGrHC08Bdn3Gx3Cx1lEmE,3062
|
|
@@ -32,6 +32,12 @@ soar_sdk/app_templates/basic_app/logo.svg,sha256=_JTop6spn5oPWPk-w6Tzumx_FTSBanO
|
|
|
32
32
|
soar_sdk/app_templates/basic_app/logo_dark.svg,sha256=PTxIs_1CKK9ZY3v-K1QoGwaUng9ZUL2MhUeO2jeHu_0,291
|
|
33
33
|
soar_sdk/app_templates/basic_app/uv.lock,sha256=AfgaIBg88KH-0iyXpCXacXAwHYKm0c-on2gWXjV9L-Y,80216
|
|
34
34
|
soar_sdk/app_templates/basic_app/src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
|
+
soar_sdk/auth/__init__.py,sha256=Z6pSzWMd49aY4H-9IxdCeWxCEC8_K4kT7i4buyv03sw,896
|
|
36
|
+
soar_sdk/auth/client.py,sha256=QmQ2dcTpke7hI7aff4usgbM_LQ0Prw2PILEb56jQFII,17077
|
|
37
|
+
soar_sdk/auth/factories.py,sha256=lNDxhrJtQpEEVV_dGEarwHHdU64oNPCxcZTrv0L4GEY,3994
|
|
38
|
+
soar_sdk/auth/flows.py,sha256=ahSOdr129s-GQjGUK8e2kNaLmjLTRzkxEJG3IwUws78,5457
|
|
39
|
+
soar_sdk/auth/httpx_auth.py,sha256=b_ldXjRxqZZiCjCnR3eZvUiDWTqYZShZKhu9NBn1Vns,3009
|
|
40
|
+
soar_sdk/auth/models.py,sha256=vSgRqHxyga2W8FGQZLjqHtk0yEQHkbEREshDePfJXgo,2856
|
|
35
41
|
soar_sdk/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
42
|
soar_sdk/cli/cli.py,sha256=9OqjVFPoIBdsO-Zmijcf0yBnjk3ggBPEOaCxKfvvw6g,998
|
|
37
43
|
soar_sdk/cli/path_utils.py,sha256=aJy3fzw2MIU-WHZn21H021B4sjGkKxW61l02QIFVGJ8,1087
|
|
@@ -43,7 +49,7 @@ soar_sdk/cli/manifests/cli.py,sha256=cly5xVdj4bBIdZVMQPIWTXRgUfd1ON3qKO-76Fwql18
|
|
|
43
49
|
soar_sdk/cli/manifests/deserializers.py,sha256=kwgPAMgUEXtIn4AuQOh1nkLfWFqe4qnYPZ1czB-FQTU,16516
|
|
44
50
|
soar_sdk/cli/manifests/processors.py,sha256=soiRTbfLQuetstt1Xk7vKmWzOUhgVON5JxjWMvnGN7w,5141
|
|
45
51
|
soar_sdk/cli/manifests/serializers.py,sha256=ulpq3nS8g1YrIP371XoQC3_kpz-9v2Ln_mqPyMtpWn8,3632
|
|
46
|
-
soar_sdk/cli/package/cli.py,sha256=
|
|
52
|
+
soar_sdk/cli/package/cli.py,sha256=hdpVBRvVGWaYDYhpDILlA7LRhunfElLbNdh21jviKrM,10087
|
|
47
53
|
soar_sdk/cli/package/utils.py,sha256=fl6PMcrdC2zA7A16byQuxxPyAI2Z-BqBLfLlF2ZNnQ4,1712
|
|
48
54
|
soar_sdk/cli/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
49
55
|
soar_sdk/cli/test/cli.py,sha256=iDrthN8L7B1RplLhq0EI69MndaOhvAXn7bqv3XzlfpM,7655
|
|
@@ -83,7 +89,7 @@ soar_sdk/models/vault_attachment.py,sha256=sdRnQdPiwgaZDojpap4ohH7u1Q5TYGP-drs8K
|
|
|
83
89
|
soar_sdk/models/view.py,sha256=BUuz6VVVe78hg7irGgZCbvBcycOmuPqplkagdi3T4Dg,779
|
|
84
90
|
soar_sdk/shims/phantom/action_result.py,sha256=Nddc9oswAfHU7I2q0pLm3HZ2YiLUQZUEIqqAjToZWnM,1606
|
|
85
91
|
soar_sdk/shims/phantom/app.py,sha256=uvE7Hsz5KudARpwaye7cx9lEOTMmPsJlZdunmkV8_lY,303
|
|
86
|
-
soar_sdk/shims/phantom/base_connector.py,sha256=
|
|
92
|
+
soar_sdk/shims/phantom/base_connector.py,sha256=2Tbh5nHnP6euilRiQL9NaVtmrgQIiY0eIkkzu-ah8_Y,5152
|
|
87
93
|
soar_sdk/shims/phantom/connector_result.py,sha256=b6yrR1uUXBhfwpUf8HzESItPgfaiHxNTXF8FaGdQNsk,640
|
|
88
94
|
soar_sdk/shims/phantom/consts.py,sha256=eq6AIuDhb2Z-CJORwv98D3JbcIOW8CC673zx5dNPFKU,404
|
|
89
95
|
soar_sdk/shims/phantom/encryption_helper.py,sha256=20VqqSFuftjB8bMriP6mjgvYWpYqYZyokYzq_aydkqU,1503
|
|
@@ -110,8 +116,8 @@ soar_sdk/views/components/pie_chart.py,sha256=LVTeHVJN6nf2vjUs9y7PDBhS0U1fKW750l
|
|
|
110
116
|
soar_sdk/webhooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
111
117
|
soar_sdk/webhooks/models.py,sha256=j3kbvYmcOlcj3gQYKtrv7iS-lDavMKYNLdCNMy_I2Hc,4542
|
|
112
118
|
soar_sdk/webhooks/routing.py,sha256=OjezhuAb8wzW0MnbGSnIWeAH3uJcu-Sb7s3w9zoiPVM,6873
|
|
113
|
-
splunk_soar_sdk-3.
|
|
114
|
-
splunk_soar_sdk-3.
|
|
115
|
-
splunk_soar_sdk-3.
|
|
116
|
-
splunk_soar_sdk-3.
|
|
117
|
-
splunk_soar_sdk-3.
|
|
119
|
+
splunk_soar_sdk-3.8.0.dist-info/METADATA,sha256=Sulxm0L7rnkY_17tCaITHItSmYiHA2J26kYLZ2ymxcw,7544
|
|
120
|
+
splunk_soar_sdk-3.8.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
121
|
+
splunk_soar_sdk-3.8.0.dist-info/entry_points.txt,sha256=CgBjo2ZWpYNkt9TgvToL26h2Tg1yt8FbvYTb5NVgNuc,51
|
|
122
|
+
splunk_soar_sdk-3.8.0.dist-info/licenses/LICENSE,sha256=gNCGrGhrSQb1PUzBOByVUN1tvaliwLZfna-QU2r2hQ8,11345
|
|
123
|
+
splunk_soar_sdk-3.8.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|