assemblyline-core 4.5.0.33__tar.gz → 4.5.0.35__tar.gz
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.
Potentially problematic release.
This version of assemblyline-core might be problematic. Click here for more details.
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/PKG-INFO +1 -1
- assemblyline-core-4.5.0.35/assemblyline_core/VERSION +1 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/dispatching/client.py +13 -18
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/ingester/ingester.py +11 -1
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/scaler/scaler_server.py +9 -2
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/tasking_client.py +5 -4
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/updater/helper.py +129 -69
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/workflow/run_workflow.py +1 -1
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core.egg-info/PKG-INFO +1 -1
- assemblyline-core-4.5.0.33/assemblyline_core/VERSION +0 -1
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/LICENCE.md +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/README.md +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/alerter/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/alerter/processing.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/alerter/run_alerter.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/archiver/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/archiver/run_archiver.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/badlist_client.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/dispatching/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/dispatching/__main__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/dispatching/dispatcher.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/dispatching/schedules.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/dispatching/timeout.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/expiry/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/expiry/run_expiry.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/ingester/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/ingester/__main__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/ingester/constants.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/metrics/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/metrics/es_metrics.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/metrics/heartbeat_formatter.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/metrics/helper.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/metrics/metrics_server.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/metrics/run_heartbeat_manager.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/metrics/run_metrics_aggregator.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/metrics/run_statistics_aggregator.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/plumber/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/plumber/run_plumber.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/client.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/creator/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/creator/run.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/creator/run_worker.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/loader/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/loader/run.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/loader/run_worker.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/replay.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/safelist_client.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/scaler/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/scaler/collection.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/scaler/controllers/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/scaler/controllers/docker_ctl.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/scaler/controllers/interface.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/scaler/controllers/kubernetes_ctl.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/scaler/run_scaler.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/server_base.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/signature_client.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/submission_client.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/updater/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/updater/run_updater.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/vacuum/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/vacuum/crawler.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/vacuum/department_map.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/vacuum/safelist.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/vacuum/stream_map.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/vacuum/worker.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/workflow/__init__.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core.egg-info/SOURCES.txt +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core.egg-info/dependency_links.txt +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core.egg-info/requires.txt +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core.egg-info/top_level.txt +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/setup.cfg +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/setup.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_alerter.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_badlist_client.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_dispatcher.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_expiry.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_plumber.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_replay.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_safelist_client.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_scaler.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_scheduler.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_signature_client.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_simulation.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_vacuum.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_worker_ingest.py +0 -0
- {assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/test/test_worker_submit.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
4.5.0.35
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/dispatching/client.py
RENAMED
|
@@ -254,7 +254,8 @@ class DispatchClient:
|
|
|
254
254
|
|
|
255
255
|
@elasticapm.capture_span(span_type='dispatch_client')
|
|
256
256
|
def service_finished(self, sid: str, result_key: str, result: Result,
|
|
257
|
-
temporary_data: Optional[dict[str, Any]] = None
|
|
257
|
+
temporary_data: Optional[dict[str, Any]] = None,
|
|
258
|
+
version="create"):
|
|
258
259
|
"""Notifies the dispatcher of service completion, and possible new files to dispatch."""
|
|
259
260
|
# Make sure the dispatcher knows we were working on this task
|
|
260
261
|
task_key = ServiceTask.make_key(sid=sid, service_name=result.response.service_name, sha=result.sha256)
|
|
@@ -272,28 +273,22 @@ class DispatchClient:
|
|
|
272
273
|
self.ds.emptyresult.save(result_key, {"expiry_ts": result.expiry_ts})
|
|
273
274
|
else:
|
|
274
275
|
while True:
|
|
275
|
-
old, version = self.ds.result.get_if_exists(result_key, version=True)
|
|
276
|
-
if old:
|
|
277
|
-
if old.expiry_ts and result.expiry_ts:
|
|
278
|
-
result.expiry_ts = max(result.expiry_ts, old.expiry_ts)
|
|
279
|
-
else:
|
|
280
|
-
result.expiry_ts = None
|
|
281
276
|
try:
|
|
282
|
-
if self.ds.result.exists(result_key):
|
|
283
|
-
# A result already exists for this key
|
|
284
|
-
# Regenerate entire result key based on result and modified task (ignore caching)
|
|
285
|
-
task.ignore_cache = True
|
|
286
|
-
result_key = Result.help_build_key(sha256=task.fileinfo.sha256,
|
|
287
|
-
service_name=result.response.service_name,
|
|
288
|
-
service_version=result.response.service_version,
|
|
289
|
-
service_tool_version=result.response.service_tool_version,
|
|
290
|
-
is_empty=False,
|
|
291
|
-
task=task)
|
|
292
|
-
version = "create"
|
|
293
277
|
self.ds.result.save(result_key, result, version=version)
|
|
294
278
|
break
|
|
295
279
|
except VersionConflictException as vce:
|
|
296
280
|
self.log.info(f"Retrying to save results due to version conflict: {str(vce)}")
|
|
281
|
+
# A result already exists for this key
|
|
282
|
+
# Regenerate entire result key based on result and modified task (ignore caching)
|
|
283
|
+
version = "create"
|
|
284
|
+
result.created = now_as_iso()
|
|
285
|
+
task.ignore_cache = True
|
|
286
|
+
result_key = Result.help_build_key(sha256=task.fileinfo.sha256,
|
|
287
|
+
service_name=result.response.service_name,
|
|
288
|
+
service_version=result.response.service_version,
|
|
289
|
+
service_tool_version=result.response.service_tool_version,
|
|
290
|
+
is_empty=False,
|
|
291
|
+
task=task)
|
|
297
292
|
|
|
298
293
|
# Send the result key to any watching systems
|
|
299
294
|
msg = {'status': 'OK', 'cache_key': result_key}
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/ingester/ingester.py
RENAMED
|
@@ -36,6 +36,7 @@ from assemblyline.remote.datatypes.queues.priority import PriorityQueue
|
|
|
36
36
|
from assemblyline.remote.datatypes.queues.comms import CommsQueue
|
|
37
37
|
from assemblyline.remote.datatypes.queues.multi import MultiQueue
|
|
38
38
|
from assemblyline.remote.datatypes.hash import Hash
|
|
39
|
+
from assemblyline.remote.datatypes.user_quota_tracker import UserQuotaTracker
|
|
39
40
|
from assemblyline import odm
|
|
40
41
|
from assemblyline.odm.models.submission import SubmissionParams, Submission as DatabaseSubmission
|
|
41
42
|
from assemblyline.odm.models.alert import EXTENDED_SCAN_VALUES
|
|
@@ -180,6 +181,9 @@ class Ingester(ThreadedCoreBase):
|
|
|
180
181
|
# Utility object to handle post-processing actions
|
|
181
182
|
self.postprocess_worker = ActionWorker(cache=True, config=self.config, datastore=self.datastore,
|
|
182
183
|
redis_persist=self.redis_persist)
|
|
184
|
+
# Async Submission quota tracker
|
|
185
|
+
self.async_submission_tracker = UserQuotaTracker('async_submissions', timeout=24 * 60 * 60, # 1 day timeout
|
|
186
|
+
redis=self.redis_persist)
|
|
183
187
|
|
|
184
188
|
if self.config.core.metrics.apm_server.server_url is not None:
|
|
185
189
|
self.log.info(f"Exporting application metrics to: {self.config.core.metrics.apm_server.server_url}")
|
|
@@ -640,7 +644,7 @@ class Ingester(ThreadedCoreBase):
|
|
|
640
644
|
'archived': False,
|
|
641
645
|
'archive_ts': None,
|
|
642
646
|
'classification': task.params.classification,
|
|
643
|
-
'expiry_ts':now_as_iso(task.params.ttl * 24 * 60 * 60),
|
|
647
|
+
'expiry_ts': now_as_iso(task.params.ttl * 24 * 60 * 60),
|
|
644
648
|
'from_archive': False,
|
|
645
649
|
'metadata': task.submission.metadata,
|
|
646
650
|
'params': task.params.as_primitives(),
|
|
@@ -863,6 +867,9 @@ class Ingester(ThreadedCoreBase):
|
|
|
863
867
|
return True
|
|
864
868
|
|
|
865
869
|
def _notify_drop(self, task: IngestTask):
|
|
870
|
+
if self.config.ui.enforce_quota:
|
|
871
|
+
self.async_submission_tracker.end(task.params.submitter)
|
|
872
|
+
|
|
866
873
|
self.send_notification(task)
|
|
867
874
|
|
|
868
875
|
c12n = task.params.classification
|
|
@@ -936,4 +943,7 @@ class Ingester(ThreadedCoreBase):
|
|
|
936
943
|
task.extended_scan = 'submitted'
|
|
937
944
|
task.params.psid = None
|
|
938
945
|
|
|
946
|
+
if self.config.ui.enforce_quota:
|
|
947
|
+
self.async_submission_tracker.end(task.params.submitter)
|
|
948
|
+
|
|
939
949
|
self.send_notification(task)
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/scaler/scaler_server.py
RENAMED
|
@@ -35,6 +35,7 @@ from assemblyline.common.uid import get_id_from_data
|
|
|
35
35
|
from assemblyline.common.forge import get_classification, get_service_queue, get_apm_client
|
|
36
36
|
from assemblyline.common.constants import SCALER_TIMEOUT_QUEUE, SERVICE_STATE_HASH, ServiceStatus
|
|
37
37
|
from assemblyline.common.version import FRAMEWORK_VERSION, SYSTEM_VERSION
|
|
38
|
+
from assemblyline_core.updater.helper import get_registry_config
|
|
38
39
|
from assemblyline_core.scaler.controllers import KubernetesController
|
|
39
40
|
from assemblyline_core.scaler.controllers.interface import ServiceControlError
|
|
40
41
|
from assemblyline_core.server_base import ServiceStage, ThreadedCoreBase
|
|
@@ -514,6 +515,12 @@ class ScalerServer(ThreadedCoreBase):
|
|
|
514
515
|
for var in default_settings.environment:
|
|
515
516
|
if var.name not in set_keys:
|
|
516
517
|
docker_config.environment.append(var)
|
|
518
|
+
|
|
519
|
+
# Set authentication to registry to pull the image
|
|
520
|
+
auth_config = get_registry_config(docker_config, self.config)
|
|
521
|
+
docker_config.registry_username = auth_config['username']
|
|
522
|
+
docker_config.registry_password = auth_config['password']
|
|
523
|
+
|
|
517
524
|
return docker_config
|
|
518
525
|
|
|
519
526
|
# noinspection PyBroadException
|
|
@@ -533,7 +540,7 @@ class ScalerServer(ThreadedCoreBase):
|
|
|
533
540
|
if not service.version.startswith(system_spec):
|
|
534
541
|
# If FW and SYS version don't prefix in the service version, we can't guarantee the
|
|
535
542
|
# service is compatible. Disable and treat it as incompatible due to service version.
|
|
536
|
-
self.log.warning("Disabling service with incompatible version. "
|
|
543
|
+
self.log.warning(f"Disabling {service.name} with incompatible version. "
|
|
537
544
|
f"[{service.version} != '{system_spec}.X.{service.update_channel}Y'].")
|
|
538
545
|
disable_incompatible_service()
|
|
539
546
|
elif service.update_config and service.update_config.wait_for_update and not service.update_config.sources:
|
|
@@ -648,7 +655,7 @@ class ScalerServer(ThreadedCoreBase):
|
|
|
648
655
|
profile.privileged = service.privileged
|
|
649
656
|
|
|
650
657
|
for dependency_name, dependency_blob in dependency_blobs.items():
|
|
651
|
-
if profile.dependency_blobs
|
|
658
|
+
if profile.dependency_blobs.get(dependency_name, '') != dependency_blob:
|
|
652
659
|
self.log.info(f"Updating deployment information for {name}/{dependency_name}")
|
|
653
660
|
profile.dependency_blobs[dependency_name] = dependency_blob
|
|
654
661
|
self.controller.start_stateful_container(
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/tasking_client.py
RENAMED
|
@@ -24,6 +24,7 @@ from assemblyline.remote.datatypes.events import EventSender, EventWatcher
|
|
|
24
24
|
from assemblyline.remote.datatypes.hash import ExpiringHash
|
|
25
25
|
from assemblyline_core.dispatching.client import DispatchClient
|
|
26
26
|
|
|
27
|
+
|
|
27
28
|
class TaskingClientException(Exception):
|
|
28
29
|
pass
|
|
29
30
|
|
|
@@ -252,7 +253,7 @@ class TaskingClient:
|
|
|
252
253
|
# If we are allowed, try to see if the result has been cached
|
|
253
254
|
if not task.ignore_cache and not service_data.disable_cache:
|
|
254
255
|
# Checking for previous results for this key
|
|
255
|
-
result = self.datastore.result.get_if_exists(result_key)
|
|
256
|
+
result, version = self.datastore.result.get_if_exists(result_key, version=True)
|
|
256
257
|
if result:
|
|
257
258
|
metric_factory.increment('cache_hit')
|
|
258
259
|
if result.result.score:
|
|
@@ -262,8 +263,8 @@ class TaskingClient:
|
|
|
262
263
|
|
|
263
264
|
result.archive_ts = None
|
|
264
265
|
|
|
265
|
-
if task.ttl:
|
|
266
|
-
result.expiry_ts = now_as_iso(task.ttl * 24 * 60 * 60)
|
|
266
|
+
if task.ttl and result.expiry_ts:
|
|
267
|
+
result.expiry_ts = max(result.expiry_ts, now_as_iso(task.ttl * 24 * 60 * 60))
|
|
267
268
|
|
|
268
269
|
# Create a list of files to freshen
|
|
269
270
|
freshen_hashes = [task.fileinfo.sha256]
|
|
@@ -286,7 +287,7 @@ class TaskingClient:
|
|
|
286
287
|
for sha256 in freshen_hashes:
|
|
287
288
|
self.datastore.save_or_freshen_file(sha256, {}, result.expiry_ts, result.classification)
|
|
288
289
|
|
|
289
|
-
self.dispatch_client.service_finished(task.sid, result_key, result)
|
|
290
|
+
self.dispatch_client.service_finished(task.sid, result_key, result, version=version)
|
|
290
291
|
cache_found = True
|
|
291
292
|
|
|
292
293
|
if not cache_found:
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/updater/helper.py
RENAMED
|
@@ -5,13 +5,15 @@ import string
|
|
|
5
5
|
import time
|
|
6
6
|
|
|
7
7
|
from assemblyline.common.version import FRAMEWORK_VERSION, SYSTEM_VERSION
|
|
8
|
-
from assemblyline.odm.models.config import Config as SystemConfig
|
|
9
|
-
from assemblyline.odm.models.service import Service as ServiceConfig
|
|
8
|
+
from assemblyline.odm.models.config import Config as SystemConfig, ServiceRegistry
|
|
9
|
+
from assemblyline.odm.models.service import Service as ServiceConfig, DockerConfig
|
|
10
10
|
|
|
11
11
|
from base64 import b64encode
|
|
12
12
|
from collections import defaultdict
|
|
13
13
|
from logging import Logger
|
|
14
|
+
from typing import Dict, List
|
|
14
15
|
from packaging.version import parse, Version
|
|
16
|
+
from urllib.parse import urlencode
|
|
15
17
|
|
|
16
18
|
DEFAULT_DOCKER_REGISTRY = "hub.docker.com"
|
|
17
19
|
|
|
@@ -130,9 +132,42 @@ REGISTRY_TYPE_MAPPING = {
|
|
|
130
132
|
'harbor': HarborRegistry()
|
|
131
133
|
}
|
|
132
134
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
def get_registry_config(docker_config: DockerConfig, system_config: SystemConfig) -> Dict[str, str]:
|
|
136
|
+
# Fix service image for calling Docker API
|
|
137
|
+
image_variables = defaultdict(str)
|
|
138
|
+
image_variables.update(system_config.services.image_variables)
|
|
139
|
+
image_variables.update(system_config.services.update_image_variables)
|
|
140
|
+
searchable_image = string.Template(docker_config.image).safe_substitute(image_variables)
|
|
141
|
+
|
|
142
|
+
server = searchable_image.split("/", 1)[0]
|
|
143
|
+
|
|
144
|
+
# Prioritize authentication given as a system configuration
|
|
145
|
+
registries: List[ServiceRegistry] = system_config.services.registries or []
|
|
146
|
+
for registry in registries:
|
|
147
|
+
if server.startswith(registry.name):
|
|
148
|
+
# Return authentication credentials and the type of registry
|
|
149
|
+
return dict(username=registry.username, password=registry.password, type=registry.type)
|
|
150
|
+
|
|
151
|
+
# Otherwise return what's configured for the service
|
|
152
|
+
return dict(username=docker_config.registry_username, password=docker_config.registry_password,
|
|
153
|
+
type=docker_config.registry_type)
|
|
154
|
+
|
|
155
|
+
def get_latest_tag_for_service(service_config: ServiceConfig, system_config: SystemConfig, logger: Logger,
|
|
156
|
+
prefix: str = ""):
|
|
157
|
+
"""
|
|
158
|
+
Retrieves the latest compatible tag for a given service from its respective Docker registry.
|
|
159
|
+
This function processes the image name to determine the correct server, authenticates
|
|
160
|
+
with the registry, and then fetches the latest tag that matches the service's framework
|
|
161
|
+
and system version constraints. It handles different registry configurations including
|
|
162
|
+
private and public ones.
|
|
163
|
+
Args:
|
|
164
|
+
service_config (ServiceConfig): The configuration object for the service which includes Docker configuration.
|
|
165
|
+
system_config (SystemConfig): System-wide configuration which includes service updates and registry configurations.
|
|
166
|
+
logger (Logger): Logger object for logging messages.
|
|
167
|
+
prefix (str, optional): A prefix string to prepend to log messages for clarity in logs.
|
|
168
|
+
Returns:
|
|
169
|
+
tuple: Returns a tuple of the final image name, the latest tag, and authentication config used for the Docker registry.
|
|
170
|
+
"""
|
|
136
171
|
def process_image(image):
|
|
137
172
|
# Find which server to search in
|
|
138
173
|
server = image.split("/")[0]
|
|
@@ -152,10 +187,9 @@ def get_latest_tag_for_service(
|
|
|
152
187
|
|
|
153
188
|
# Split repo name without the tag
|
|
154
189
|
image_name = image_name.rsplit(":", 1)[0]
|
|
155
|
-
|
|
156
190
|
return server, image_name
|
|
157
191
|
|
|
158
|
-
# Extract
|
|
192
|
+
# Extract and process service information
|
|
159
193
|
service_name = service_config.name
|
|
160
194
|
image = service_config.docker_config.image
|
|
161
195
|
update_channel = service_config.update_channel
|
|
@@ -168,36 +202,23 @@ def get_latest_tag_for_service(
|
|
|
168
202
|
|
|
169
203
|
# Get authentication
|
|
170
204
|
auth = None
|
|
171
|
-
auth_config = None
|
|
172
205
|
server, image_name = process_image(searchable_image)
|
|
173
206
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
service_config.docker_config.registry_username = registry['username']
|
|
180
|
-
service_config.docker_config.registry_password = registry['password']
|
|
181
|
-
service_config.docker_config.registry_type = registry['type']
|
|
182
|
-
break
|
|
183
|
-
|
|
184
|
-
if service_config.docker_config.registry_username and service_config.docker_config.registry_password:
|
|
185
|
-
# We're authenticating using Basic Auth
|
|
186
|
-
auth_config = {
|
|
187
|
-
'username': service_config.docker_config.registry_username,
|
|
188
|
-
'password': service_config.docker_config.registry_password
|
|
189
|
-
}
|
|
190
|
-
upass = f"{service_config.docker_config.registry_username}:{service_config.docker_config.registry_password}"
|
|
207
|
+
# Generate 'Authenication' header value for pulling tag list from registry
|
|
208
|
+
auth_config = get_registry_config(service_config.docker_config, system_config)
|
|
209
|
+
registry_type = auth_config.pop('type')
|
|
210
|
+
if auth_config['username'] and auth_config['password']:
|
|
211
|
+
upass = f"{auth_config['username']}:{auth_config['password']}"
|
|
191
212
|
auth = f"Basic {b64encode(upass.encode()).decode()}"
|
|
192
|
-
elif
|
|
213
|
+
elif auth_config['password']:
|
|
193
214
|
# We're assuming that if only a password is given, then this is a token
|
|
194
|
-
auth = f"Bearer {
|
|
215
|
+
auth = f"Bearer {auth_config['password']}"
|
|
195
216
|
|
|
196
217
|
if server.endswith(".azurecr.io"):
|
|
197
218
|
# This is an Azure Container Registry based on the server name
|
|
198
219
|
registry = AzureContainerRegistry()
|
|
199
220
|
else:
|
|
200
|
-
registry = REGISTRY_TYPE_MAPPING[
|
|
221
|
+
registry = REGISTRY_TYPE_MAPPING[registry_type]
|
|
201
222
|
token_server = None
|
|
202
223
|
proxies = None
|
|
203
224
|
for reg_conf in system_config.core.updater.registry_configs:
|
|
@@ -207,32 +228,27 @@ def get_latest_tag_for_service(
|
|
|
207
228
|
break
|
|
208
229
|
|
|
209
230
|
if server == DEFAULT_DOCKER_REGISTRY:
|
|
210
|
-
tags = _get_dockerhub_tags(image_name, update_channel, proxies)
|
|
231
|
+
tags = _get_dockerhub_tags(image_name, update_channel, prefix, proxies, logger=logger)
|
|
211
232
|
else:
|
|
212
233
|
tags = registry._get_proprietary_registry_tags(server, image_name, auth,
|
|
213
234
|
not system_config.services.allow_insecure_registry,
|
|
214
235
|
proxies, token_server)
|
|
215
|
-
|
|
216
|
-
tag_name = None
|
|
217
|
-
|
|
218
236
|
# Pre-filter tags to only consider 'compatible' tags relative to the running system
|
|
219
|
-
tags = [
|
|
220
|
-
if re.match(f"({FRAMEWORK_VERSION})
|
|
221
|
-
|
|
237
|
+
tags = [tag for tag in tags
|
|
238
|
+
if re.match(f"({FRAMEWORK_VERSION})\.({SYSTEM_VERSION})\.\\d+\.({update_channel})\\d+", tag)]
|
|
222
239
|
if not tags:
|
|
223
|
-
logger.warning(f"{prefix}Cannot fetch latest tag for service {service_name} - {image_name}"
|
|
240
|
+
logger.warning(f"{prefix} Cannot fetch latest tag for service {service_name} - {image_name}" \
|
|
224
241
|
f" => [server: {server}, repo_name: {image_name}, channel: {update_channel}]")
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
logger.info(f"{prefix}Latest {service_name} tag on {update_channel.upper()} channel is: {tag_name}")
|
|
242
|
+
tag_name = None
|
|
243
|
+
for tag in tags:
|
|
244
|
+
t_version = Version(tag.replace(update_channel, ""))
|
|
245
|
+
# Tag name gets assigned to the first viable option then relies on comparison to get the latest
|
|
246
|
+
if not tag_name:
|
|
247
|
+
tag_name = tag
|
|
248
|
+
elif t_version.major == FRAMEWORK_VERSION and t_version.minor == SYSTEM_VERSION and \
|
|
249
|
+
t_version > parse(tag_name.replace(update_channel, "")):
|
|
250
|
+
tag_name = tag
|
|
251
|
+
logger.info(f"{prefix}Latest {service_name} tag on {update_channel.upper()} channel is: {tag_name}")
|
|
236
252
|
|
|
237
253
|
# Fix service image for use in Kubernetes
|
|
238
254
|
image_variables = defaultdict(str)
|
|
@@ -246,29 +262,73 @@ def get_latest_tag_for_service(
|
|
|
246
262
|
|
|
247
263
|
return image_name, tag_name, auth_config
|
|
248
264
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
265
|
+
def _get_dockerhub_tags(image_name, update_channel, prefix, proxies=None, docker_registry=DEFAULT_DOCKER_REGISTRY,
|
|
266
|
+
logger: Logger=None):
|
|
267
|
+
"""
|
|
268
|
+
Retrieve DockerHub tags for a specific image and update channel.
|
|
269
|
+
Args:
|
|
270
|
+
image_name (str): Full name of the image (including namespace).
|
|
271
|
+
update_channel (str): Specific channel to filter tags (e.g., stable, beta).
|
|
272
|
+
proxies (dict, optional): Proxy configuration.
|
|
273
|
+
docker_registry (str, optional): Docker registry URL. Defaults to DEFAULT_DOCKER_REGISTRY.
|
|
274
|
+
Returns:
|
|
275
|
+
list: A list of tag names that match the given criteria, or None if an error occurs.
|
|
276
|
+
"""
|
|
254
277
|
namespace, repository = image_name.split('/', 1)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
278
|
+
base_url = f"https://{docker_registry}/v2/namespaces/{namespace}/repositories/{repository}/tags"
|
|
279
|
+
query_params = {
|
|
280
|
+
'page_size': 50,
|
|
281
|
+
'page': 1,
|
|
282
|
+
'name': update_channel,
|
|
283
|
+
'ordering': 'last_updated'
|
|
284
|
+
}
|
|
285
|
+
url = f"{base_url}?{urlencode(query_params)}"
|
|
258
286
|
while True:
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
287
|
+
try:
|
|
288
|
+
response = requests.get(url, proxies=proxies)
|
|
289
|
+
response.raise_for_status() # Raises an HTTPError for bad responses
|
|
290
|
+
response_data = response.json()
|
|
291
|
+
tags = []
|
|
292
|
+
if namespace == "cccs":
|
|
293
|
+
# The tags are coming from a repository managed by the Assemblyline team
|
|
294
|
+
for tag_info in response_data['results']:
|
|
295
|
+
tag_name = tag_info.get('name')
|
|
296
|
+
if tag_name and tag_name == f"{FRAMEWORK_VERSION}.{SYSTEM_VERSION}.{update_channel}":
|
|
297
|
+
# Ignore tag aliases containing the update_channel
|
|
298
|
+
continue
|
|
299
|
+
if tag_name and tag_name.startswith(f"{FRAMEWORK_VERSION}.{SYSTEM_VERSION}"):
|
|
300
|
+
# Because the order of paging is based on `last_updated`,
|
|
301
|
+
# we can return the first valid candidate
|
|
302
|
+
logger.info(f"{prefix}Valid tag found for {repository}: {tag_name}")
|
|
303
|
+
return [tag_name]
|
|
304
|
+
else:
|
|
305
|
+
# The tags are coming from another repository, so we're don't know the ordering of tags
|
|
306
|
+
tags.extend(tag_info.get('name') for tag_info in response_data['results'] if tag_info.get('name'))
|
|
307
|
+
url = response_data.get('next')
|
|
308
|
+
if not url:
|
|
309
|
+
logger.info(f"{prefix}No more pages left to fetch.")
|
|
266
310
|
break
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
311
|
+
except requests.exceptions.HTTPError as e:
|
|
312
|
+
if response.status_code == 429:
|
|
313
|
+
# Based on https://docs.docker.com/docker-hub/api/latest/#tag/rate-limiting
|
|
314
|
+
# We've hit the rate limit so we have to wait and try again later
|
|
315
|
+
logger.warning(f"{prefix}Rate limit reached for DockerHub. Retrying after sleep..")
|
|
316
|
+
time.sleep(int(response.headers['retry-after']) - int(time.time()))
|
|
317
|
+
else:
|
|
318
|
+
logger.error(f"{prefix}HTTP error occurred: {e}")
|
|
272
319
|
break
|
|
273
|
-
|
|
274
|
-
|
|
320
|
+
except requests.exceptions.ConnectionError as e:
|
|
321
|
+
logger.error(f"{prefix}Connection error occurred: {e}")
|
|
322
|
+
break
|
|
323
|
+
except requests.exceptions.Timeout as e:
|
|
324
|
+
logger.error(f"{prefix}Request timed out.")
|
|
325
|
+
break
|
|
326
|
+
except requests.exceptions.RequestException as e:
|
|
327
|
+
logger.error(f"{prefix}An error occurred during requests: {e}")
|
|
328
|
+
break
|
|
329
|
+
except ValueError as e:
|
|
330
|
+
logger.error(f"{prefix}JSON decode error: {e}")
|
|
331
|
+
break
|
|
332
|
+
if tags:
|
|
333
|
+
logger.info(f"{prefix}Tags retrieved successfully: {tags}")
|
|
334
|
+
return tags
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/workflow/run_workflow.py
RENAMED
|
@@ -175,7 +175,7 @@ class WorkflowManager(ServerBase):
|
|
|
175
175
|
|
|
176
176
|
except SearchException:
|
|
177
177
|
self.log.warning(f"Invalid query '{safe_str(workflow.query or '')}' in workflow "
|
|
178
|
-
f"'{workflow.name or 'unknown'}' by '{workflow.
|
|
178
|
+
f"'{workflow.name or 'unknown'}' by '{workflow.creator or 'unknown'}'")
|
|
179
179
|
|
|
180
180
|
# End of transaction
|
|
181
181
|
if self.apm_client:
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
4.5.0.33
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/alerter/__init__.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/alerter/processing.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/alerter/run_alerter.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/archiver/__init__.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/archiver/run_archiver.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/badlist_client.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/dispatching/__init__.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/dispatching/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/dispatching/schedules.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/dispatching/timeout.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/expiry/__init__.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/expiry/run_expiry.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/ingester/__init__.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/ingester/__main__.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/ingester/constants.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/metrics/__init__.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/metrics/es_metrics.py
RENAMED
|
File without changes
|
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/metrics/helper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/plumber/__init__.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/plumber/run_plumber.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/__init__.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/client.py
RENAMED
|
File without changes
|
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/creator/run.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/loader/run.py
RENAMED
|
File without changes
|
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/replay/replay.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/safelist_client.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/scaler/__init__.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/scaler/collection.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/scaler/run_scaler.py
RENAMED
|
File without changes
|
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/signature_client.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/submission_client.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/updater/__init__.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/updater/run_updater.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/vacuum/__init__.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/vacuum/crawler.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/vacuum/department_map.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/vacuum/safelist.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/vacuum/stream_map.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/vacuum/worker.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core/workflow/__init__.py
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core.egg-info/requires.txt
RENAMED
|
File without changes
|
{assemblyline-core-4.5.0.33 → assemblyline-core-4.5.0.35}/assemblyline_core.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|