fluidattacks-core 2.16.0__py3-none-any.whl → 3.0.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.
- fluidattacks_core/git/constants.py +1 -0
- fluidattacks_core/git/download_file.py +29 -15
- fluidattacks_core/git/download_repo.py +8 -1
- fluidattacks_core/logging/__init__.py +34 -2
- fluidattacks_core/logging/filters.py +1 -11
- fluidattacks_core/logging/formatters.py +10 -7
- fluidattacks_core/logging/presets.py +0 -66
- fluidattacks_core/logging/utils.py +14 -2
- {fluidattacks_core-2.16.0.dist-info → fluidattacks_core-3.0.0.dist-info}/METADATA +1 -1
- {fluidattacks_core-2.16.0.dist-info → fluidattacks_core-3.0.0.dist-info}/RECORD +12 -11
- {fluidattacks_core-2.16.0.dist-info → fluidattacks_core-3.0.0.dist-info}/WHEEL +0 -0
- {fluidattacks_core-2.16.0.dist-info → fluidattacks_core-3.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
DEFAULT_DOWNLOAD_BUFFER_SIZE = 64 * 1024 # 64KB
|
|
@@ -4,23 +4,37 @@ from pathlib import Path
|
|
|
4
4
|
import aiofiles
|
|
5
5
|
import aiohttp
|
|
6
6
|
|
|
7
|
+
from .constants import DEFAULT_DOWNLOAD_BUFFER_SIZE
|
|
8
|
+
|
|
7
9
|
LOGGER = logging.getLogger(__name__)
|
|
8
10
|
|
|
9
11
|
|
|
10
|
-
async def download_file(
|
|
11
|
-
|
|
12
|
+
async def download_file(
|
|
13
|
+
*,
|
|
14
|
+
url: str,
|
|
15
|
+
destination_path: str,
|
|
16
|
+
download_buffer_size: int = DEFAULT_DOWNLOAD_BUFFER_SIZE,
|
|
17
|
+
) -> bool:
|
|
18
|
+
timeout = aiohttp.ClientTimeout(total=60 * 60, connect=30)
|
|
19
|
+
async with aiohttp.ClientSession(timeout=timeout) as session: # noqa: SIM117
|
|
12
20
|
async with session.get(url) as response:
|
|
13
|
-
if response.status
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
if response.status != 200:
|
|
22
|
+
LOGGER.error(
|
|
23
|
+
"Failed to download file: HTTP %s, for path %s",
|
|
24
|
+
response.status,
|
|
25
|
+
destination_path,
|
|
26
|
+
)
|
|
27
|
+
return False
|
|
28
|
+
|
|
29
|
+
async with aiofiles.open(destination_path, "wb") as file:
|
|
30
|
+
while True:
|
|
31
|
+
try:
|
|
32
|
+
chunk = await response.content.read(download_buffer_size)
|
|
33
|
+
except TimeoutError:
|
|
34
|
+
LOGGER.exception("Read timeout for path %s", destination_path)
|
|
35
|
+
return False
|
|
36
|
+
if not chunk:
|
|
37
|
+
break
|
|
38
|
+
await file.write(chunk)
|
|
25
39
|
|
|
26
|
-
|
|
40
|
+
return Path(destination_path).exists()
|
|
@@ -9,6 +9,7 @@ from git import GitError
|
|
|
9
9
|
from git.cmd import Git
|
|
10
10
|
from git.repo import Repo
|
|
11
11
|
|
|
12
|
+
from .constants import DEFAULT_DOWNLOAD_BUFFER_SIZE
|
|
12
13
|
from .delete_files import delete_out_of_scope_files
|
|
13
14
|
from .download_file import download_file
|
|
14
15
|
|
|
@@ -83,12 +84,18 @@ async def download_repo_from_s3(
|
|
|
83
84
|
download_url: str,
|
|
84
85
|
destination_path: Path,
|
|
85
86
|
git_ignore: list[str] | None = None,
|
|
87
|
+
*,
|
|
88
|
+
download_buffer_size: int = DEFAULT_DOWNLOAD_BUFFER_SIZE,
|
|
86
89
|
) -> bool:
|
|
87
90
|
destination_path.parent.mkdir(parents=True, exist_ok=True)
|
|
88
91
|
with tempfile.TemporaryDirectory(prefix="fluidattacks_", ignore_cleanup_errors=True) as tmpdir:
|
|
89
92
|
tmp_path = Path(tmpdir)
|
|
90
93
|
file_path = tmp_path / "repo.tar.gz"
|
|
91
|
-
result = await download_file(
|
|
94
|
+
result = await download_file(
|
|
95
|
+
url=download_url,
|
|
96
|
+
destination_path=str(file_path.absolute()),
|
|
97
|
+
download_buffer_size=download_buffer_size,
|
|
98
|
+
)
|
|
92
99
|
if not result:
|
|
93
100
|
LOGGER.error("Failed to download repository from %s", download_url)
|
|
94
101
|
return False
|
|
@@ -1,12 +1,44 @@
|
|
|
1
|
-
|
|
1
|
+
import logging
|
|
2
|
+
import logging.config
|
|
3
|
+
import sys
|
|
4
|
+
from types import TracebackType
|
|
5
|
+
|
|
6
|
+
from fluidattacks_core.logging.presets import DATE_FORMAT, PRODUCT_LOGGING
|
|
2
7
|
from fluidattacks_core.logging.types import JobMetadata
|
|
3
8
|
from fluidattacks_core.logging.utils import get_job_metadata, set_telemetry_metadata
|
|
4
9
|
|
|
10
|
+
|
|
11
|
+
def init_uncaught_exception_logging() -> None:
|
|
12
|
+
logger = logging.getLogger("unhandled")
|
|
13
|
+
|
|
14
|
+
def handle_uncaught_exception(
|
|
15
|
+
exception_type: type[BaseException],
|
|
16
|
+
msg: BaseException,
|
|
17
|
+
traceback: TracebackType | None,
|
|
18
|
+
) -> None:
|
|
19
|
+
if issubclass(exception_type, KeyboardInterrupt):
|
|
20
|
+
sys.__excepthook__(exception_type, msg, traceback)
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
logger.critical(
|
|
24
|
+
"Uncaught exception",
|
|
25
|
+
exc_info=(exception_type, msg, traceback),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
sys.excepthook = handle_uncaught_exception
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def init_logging() -> None:
|
|
32
|
+
logging.config.dictConfig(PRODUCT_LOGGING)
|
|
33
|
+
init_uncaught_exception_logging()
|
|
34
|
+
|
|
35
|
+
|
|
5
36
|
__all__ = [
|
|
6
|
-
"BATCH_LOGGING",
|
|
7
37
|
"DATE_FORMAT",
|
|
8
38
|
"PRODUCT_LOGGING",
|
|
9
39
|
"JobMetadata",
|
|
10
40
|
"get_job_metadata",
|
|
41
|
+
"init_logging",
|
|
42
|
+
"init_uncaught_exception_logging",
|
|
11
43
|
"set_telemetry_metadata",
|
|
12
44
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
-
from fluidattacks_core.logging.utils import
|
|
3
|
+
from fluidattacks_core.logging.utils import is_trunk_branch
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class NoProductionFilter(logging.Filter):
|
|
@@ -15,13 +15,3 @@ class ProductionOnlyFilter(logging.Filter):
|
|
|
15
15
|
|
|
16
16
|
def filter(self, _record: logging.LogRecord) -> bool:
|
|
17
17
|
return is_trunk_branch()
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class BatchOnlyFilter(logging.Filter):
|
|
21
|
-
def filter(self, _record: logging.LogRecord) -> bool:
|
|
22
|
-
return get_job_metadata().job_id is not None
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class NoBatchFilter(logging.Filter):
|
|
26
|
-
def filter(self, _record: logging.LogRecord) -> bool:
|
|
27
|
-
return get_job_metadata().job_id is None
|
|
@@ -13,6 +13,8 @@ from fluidattacks_core.logging.utils import (
|
|
|
13
13
|
get_pipeline_environment,
|
|
14
14
|
get_pipeline_metadata,
|
|
15
15
|
get_telemetry_metadata,
|
|
16
|
+
is_in_batch,
|
|
17
|
+
is_in_lambda,
|
|
16
18
|
)
|
|
17
19
|
|
|
18
20
|
# Main formats
|
|
@@ -101,19 +103,20 @@ class CustomJsonFormatter(JsonFormatter):
|
|
|
101
103
|
"""Add service information to the log record.
|
|
102
104
|
|
|
103
105
|
It includes:
|
|
106
|
+
- Source
|
|
107
|
+
- Service
|
|
104
108
|
- Version
|
|
105
|
-
- Product name
|
|
106
109
|
"""
|
|
107
110
|
batch_info = get_job_metadata().job_queue
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
+
source = (
|
|
112
|
+
f"batch/{batch_info}" if is_in_batch() else "lambda" if is_in_lambda() else "python"
|
|
113
|
+
)
|
|
114
|
+
service = get_environment_metadata().product_id
|
|
111
115
|
version = get_environment_metadata().version
|
|
112
116
|
|
|
113
|
-
log_record["
|
|
114
|
-
log_record["service.version"] = version
|
|
117
|
+
log_record["ddsource"] = source
|
|
115
118
|
log_record["dd.service"] = service
|
|
116
|
-
log_record["
|
|
119
|
+
log_record["dd.version"] = version
|
|
117
120
|
|
|
118
121
|
def _add_deployment_fields(self, log_record: dict[str, Any]) -> None:
|
|
119
122
|
"""Add deployment information to the log record.
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
from fluidattacks_core.logging.filters import BatchOnlyFilter, NoBatchFilter
|
|
2
|
-
from fluidattacks_core.logging.formatters import ColorfulFormatter
|
|
3
1
|
from fluidattacks_core.logging.handlers import DebuggingHandler, ProductionSyncHandler
|
|
4
|
-
from fluidattacks_core.logging.utils import get_environment_metadata, get_job_metadata
|
|
5
2
|
|
|
6
3
|
# Main formats
|
|
7
4
|
DATE_FORMAT = "%Y-%m-%dT%H:%M:%S%z"
|
|
@@ -10,69 +7,6 @@ Default date format for logs.
|
|
|
10
7
|
"""
|
|
11
8
|
|
|
12
9
|
|
|
13
|
-
# Configuration for logging in batch environments
|
|
14
|
-
_JOB_METADATA = get_job_metadata()
|
|
15
|
-
_ENVIRONMENT_METADATA = get_environment_metadata()
|
|
16
|
-
|
|
17
|
-
BATCH_LOGGING = {
|
|
18
|
-
"version": 1,
|
|
19
|
-
"disable_existing_loggers": False,
|
|
20
|
-
"filters": {
|
|
21
|
-
"batch_only": {"()": BatchOnlyFilter},
|
|
22
|
-
"no_batch": {"()": NoBatchFilter},
|
|
23
|
-
},
|
|
24
|
-
"formatters": {
|
|
25
|
-
"one_line_format": {
|
|
26
|
-
"class": "logging.Formatter",
|
|
27
|
-
"format": (
|
|
28
|
-
"{asctime} {levelname} [{name}] [{filename}:{lineno}] "
|
|
29
|
-
"[trace_id=None span_id=None "
|
|
30
|
-
f"service.name=batch/{_JOB_METADATA.job_queue} "
|
|
31
|
-
f"service.version={_ENVIRONMENT_METADATA.version} "
|
|
32
|
-
f"deployment.environment={_ENVIRONMENT_METADATA.environment} "
|
|
33
|
-
"trace_sampled=False]"
|
|
34
|
-
" - {message}, extra=None"
|
|
35
|
-
),
|
|
36
|
-
"datefmt": DATE_FORMAT,
|
|
37
|
-
"style": "{",
|
|
38
|
-
},
|
|
39
|
-
"simple_format": {
|
|
40
|
-
"class": "logging.Formatter",
|
|
41
|
-
"format": "{asctime} [{levelname}] [{name}] {message}",
|
|
42
|
-
"datefmt": DATE_FORMAT,
|
|
43
|
-
"style": "{",
|
|
44
|
-
},
|
|
45
|
-
"colorful_format": {
|
|
46
|
-
"()": ColorfulFormatter,
|
|
47
|
-
"datefmt": DATE_FORMAT,
|
|
48
|
-
"style": "{",
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
"handlers": {
|
|
52
|
-
"batch_handler": {
|
|
53
|
-
"class": "logging.StreamHandler",
|
|
54
|
-
"stream": "ext://sys.stdout",
|
|
55
|
-
"formatter": "one_line_format",
|
|
56
|
-
"filters": ["batch_only"],
|
|
57
|
-
},
|
|
58
|
-
"console_handler": {
|
|
59
|
-
"class": "logging.StreamHandler",
|
|
60
|
-
"stream": "ext://sys.stdout",
|
|
61
|
-
"formatter": "colorful_format",
|
|
62
|
-
"filters": ["no_batch"],
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
"root": {
|
|
66
|
-
"handlers": ["batch_handler", "console_handler"],
|
|
67
|
-
"level": "INFO",
|
|
68
|
-
},
|
|
69
|
-
}
|
|
70
|
-
"""
|
|
71
|
-
Logging configuration dict for batch environments.
|
|
72
|
-
|
|
73
|
-
Root logger will have two handlers for batch and non-batch environments.
|
|
74
|
-
"""
|
|
75
|
-
|
|
76
10
|
PRODUCT_LOGGING = {
|
|
77
11
|
"version": 1,
|
|
78
12
|
"disable_existing_loggers": False,
|
|
@@ -10,10 +10,20 @@ DEFAULT_TELEMETRY_METADATA = {}
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def is_trunk_branch() -> bool:
|
|
13
|
-
"""Check if code is using the trunk branch."""
|
|
13
|
+
"""Check if the code is using the trunk branch."""
|
|
14
14
|
return os.environ.get("CI_COMMIT_REF_NAME", "default") == "trunk"
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
def is_in_batch() -> bool:
|
|
18
|
+
"""Check if the code is running in a batch environment."""
|
|
19
|
+
return os.environ.get("AWS_BATCH_JOB_ID") is not None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def is_in_lambda() -> bool:
|
|
23
|
+
"""Check if the code is running in an AWS Lambda function."""
|
|
24
|
+
return os.environ.get("AWS_LAMBDA_FUNCTION_NAME") is not None
|
|
25
|
+
|
|
26
|
+
|
|
17
27
|
def get_job_metadata() -> JobMetadata:
|
|
18
28
|
"""Get the job metadata for applications running in batch environments."""
|
|
19
29
|
return JobMetadata(
|
|
@@ -26,7 +36,9 @@ def get_job_metadata() -> JobMetadata:
|
|
|
26
36
|
def get_environment_metadata() -> EnvironmentMetadata:
|
|
27
37
|
"""Get the environment metadata for applications."""
|
|
28
38
|
environment = "production" if is_trunk_branch() else "development"
|
|
29
|
-
product_id =
|
|
39
|
+
product_id = (
|
|
40
|
+
os.environ.get("AWS_LAMBDA_FUNCTION_NAME") or os.environ.get("PRODUCT_ID") or "universe"
|
|
41
|
+
)
|
|
30
42
|
commit_sha = os.environ.get("CI_COMMIT_SHA", "00000000")
|
|
31
43
|
commit_short_sha = commit_sha[:8]
|
|
32
44
|
|
|
@@ -18,9 +18,10 @@ fluidattacks_core/git/__init__.py,sha256=aLiDZd-Jl7axe4zVvIiDQP2RPBiRvAf1jqEAc33
|
|
|
18
18
|
fluidattacks_core/git/classes.py,sha256=vgCVOUF6tqeW0lKtD9giCNFQtzRit44bnu5qOAx7qCI,579
|
|
19
19
|
fluidattacks_core/git/clone.py,sha256=alvidqUITrtTkvv4Ur9djI4Ch37QdhVWtHupMmV1eMc,7571
|
|
20
20
|
fluidattacks_core/git/codecommit_utils.py,sha256=Ec1Ymk9F1DTTyRTdqrni77UUktGQgQB_jSq5n3wWy7Q,3422
|
|
21
|
+
fluidattacks_core/git/constants.py,sha256=dTFn5bLkJ-VG-954MVJVHXxa4UCnvaurSM7GY73BiWk,49
|
|
21
22
|
fluidattacks_core/git/delete_files.py,sha256=_EfPFl61tRK4CyQHL2QtvqCQQkQ38RTXVP0Db_d6rWg,1189
|
|
22
|
-
fluidattacks_core/git/download_file.py,sha256=
|
|
23
|
-
fluidattacks_core/git/download_repo.py,sha256=
|
|
23
|
+
fluidattacks_core/git/download_file.py,sha256=0W0jhUiA6V7LRbAlbwUU3LbQiI1-UPqno7A70s2eo8s,1296
|
|
24
|
+
fluidattacks_core/git/download_repo.py,sha256=GiZT0-kgqLTAg7uqV09P6V0AXyyPrxCe5QN3Fhp2iaE,4114
|
|
24
25
|
fluidattacks_core/git/https_utils.py,sha256=V2Z9ClFq9F3sUvTqc_h6uf2PRdEzD-6MuC9zZJHy7_0,7036
|
|
25
26
|
fluidattacks_core/git/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
27
|
fluidattacks_core/git/remote.py,sha256=cPuyBMHeGrzRkEjroB6zlRLMA-QH2gIyIkGJNyf8wZc,1255
|
|
@@ -30,20 +31,20 @@ fluidattacks_core/git/warp.py,sha256=yLotfzBFWSWzM_DzI-hbp4t3hWggKNNGqBr-0mYQhLU
|
|
|
30
31
|
fluidattacks_core/http/__init__.py,sha256=3Zz90L6e3_z-M-8Bvk_53rv-CFhPThkRGXnxCiQrmaU,60
|
|
31
32
|
fluidattacks_core/http/client.py,sha256=jIhtGU2cKi5GZbxHq8WJOPgnk0beScRtxlz9tBSaKuw,2454
|
|
32
33
|
fluidattacks_core/http/validations.py,sha256=h10Hr906KJqda1rJJb8eOqk1Xyyz81lAJ1glXeae4kM,3766
|
|
33
|
-
fluidattacks_core/logging/__init__.py,sha256=
|
|
34
|
-
fluidattacks_core/logging/filters.py,sha256=
|
|
35
|
-
fluidattacks_core/logging/formatters.py,sha256=
|
|
34
|
+
fluidattacks_core/logging/__init__.py,sha256=WFH1_0ctw4zSKLjsInHUvlFguIQuJJ2dVDW7VHyXPfY,1173
|
|
35
|
+
fluidattacks_core/logging/filters.py,sha256=OqAS-cf-eDN8rWtbFpEK2kNPVyFTL31lKPonKHZ3kVA,492
|
|
36
|
+
fluidattacks_core/logging/formatters.py,sha256=iGr5WnUNKPO9kxFpP87TT7pz62_UJaNXkXecywrQ-3c,6723
|
|
36
37
|
fluidattacks_core/logging/handlers.py,sha256=g6PB5L84oOk9nwLTzLL0eB9zFnfLJSM69Qb2Y3qPf9g,4084
|
|
37
|
-
fluidattacks_core/logging/presets.py,sha256=
|
|
38
|
+
fluidattacks_core/logging/presets.py,sha256=JoUkhALSRNJ7qYxkuh7wdvWe0dXwKRxDGb6N-ihKArg,664
|
|
38
39
|
fluidattacks_core/logging/types.py,sha256=aAPGXCEOSCtjVF36rAfWixAhiY7w6E3WDfd_pNAmNRw,233
|
|
39
|
-
fluidattacks_core/logging/utils.py,sha256=
|
|
40
|
+
fluidattacks_core/logging/utils.py,sha256=RhmX-aFR41XpphU0FLXCFcWzyWZocNEZ14qgVB8SwAM,4195
|
|
40
41
|
fluidattacks_core/sarif/__init__.py,sha256=vZkbzafVeqRPEc_dzq6oevZuNp50NNyNGa_eS0oNXnc,101519
|
|
41
42
|
fluidattacks_core/semver/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
43
|
fluidattacks_core/semver/match_versions.py,sha256=3L3C0TIVH0AtDpISvk5HHBXFSbJh5V7AINgfKEXYnYI,10157
|
|
43
44
|
fluidattacks_core/serializers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
44
45
|
fluidattacks_core/serializers/snippet.py,sha256=e520pZHC-fsNuYVNY30A7TcSugvUlFL6xdr74j5aCDM,12780
|
|
45
46
|
fluidattacks_core/serializers/syntax.py,sha256=DkRsdMyMNrL0pRfsOSVAx79K8F0AmjBk676_d_v7PjM,15908
|
|
46
|
-
fluidattacks_core-
|
|
47
|
-
fluidattacks_core-
|
|
48
|
-
fluidattacks_core-
|
|
49
|
-
fluidattacks_core-
|
|
47
|
+
fluidattacks_core-3.0.0.dist-info/METADATA,sha256=lo9JNVnYwKzZkgZtod7Ih95ITDjx5AcdUkgGZt7WhJc,3199
|
|
48
|
+
fluidattacks_core-3.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
49
|
+
fluidattacks_core-3.0.0.dist-info/top_level.txt,sha256=m49ZyZ2zPQmDBxkSpjb20wr-ZbGVXdOMFBZrDiP5Lb8,18
|
|
50
|
+
fluidattacks_core-3.0.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|