assemblyline-v4-service 4.5.0.77__py3-none-any.whl → 4.5.0.79__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.
- assemblyline_v4_service/VERSION +1 -1
- assemblyline_v4_service/dev/run_service_once.py +14 -6
- assemblyline_v4_service/dev/updater.py +150 -0
- assemblyline_v4_service/updater/helper.py +2 -3
- assemblyline_v4_service/updater/updater.py +29 -18
- {assemblyline_v4_service-4.5.0.77.dist-info → assemblyline_v4_service-4.5.0.79.dist-info}/METADATA +1 -1
- {assemblyline_v4_service-4.5.0.77.dist-info → assemblyline_v4_service-4.5.0.79.dist-info}/RECORD +10 -9
- {assemblyline_v4_service-4.5.0.77.dist-info → assemblyline_v4_service-4.5.0.79.dist-info}/WHEEL +1 -1
- {assemblyline_v4_service-4.5.0.77.dist-info → assemblyline_v4_service-4.5.0.79.dist-info}/LICENCE.md +0 -0
- {assemblyline_v4_service-4.5.0.77.dist-info → assemblyline_v4_service-4.5.0.79.dist-info}/top_level.txt +0 -0
assemblyline_v4_service/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.5.0.
|
|
1
|
+
4.5.0.79
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import argparse
|
|
2
|
+
import cProfile
|
|
2
3
|
import json
|
|
3
4
|
import logging
|
|
4
5
|
import os
|
|
5
6
|
import pprint
|
|
6
7
|
import shutil
|
|
7
8
|
import tempfile
|
|
8
|
-
import
|
|
9
|
-
import cProfile
|
|
10
|
-
|
|
11
|
-
from cart import get_metadata_only, unpack_stream
|
|
12
|
-
from typing import Union, Dict
|
|
9
|
+
from typing import Dict, Union
|
|
13
10
|
|
|
14
11
|
from assemblyline.common import forge
|
|
15
12
|
from assemblyline.common.heuristics import HeuristicHandler, InvalidHeuristicException
|
|
@@ -19,12 +16,15 @@ from assemblyline.common.uid import get_random_id
|
|
|
19
16
|
from assemblyline.odm.messages.task import Task as ServiceTask
|
|
20
17
|
from assemblyline.odm.models.result import Result
|
|
21
18
|
from assemblyline.odm.models.service import Service
|
|
19
|
+
from assemblyline_v4_service.common.base import ServiceBase
|
|
22
20
|
from assemblyline_v4_service.common.helper import get_heuristics, get_service_manifest
|
|
21
|
+
from assemblyline_v4_service.dev.updater import load_rules
|
|
22
|
+
from cart import get_metadata_only, unpack_stream
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class RunService:
|
|
26
26
|
def __init__(self):
|
|
27
|
-
self.service = None
|
|
27
|
+
self.service: Union[ServiceBase, None] = None
|
|
28
28
|
self.service_class = None
|
|
29
29
|
self.submission_params = None
|
|
30
30
|
self.file_dir = None
|
|
@@ -41,6 +41,10 @@ class RunService:
|
|
|
41
41
|
|
|
42
42
|
self.load_service_manifest()
|
|
43
43
|
|
|
44
|
+
if self.service.service_attributes.update_config:
|
|
45
|
+
# Download required signatures and process them for the service run
|
|
46
|
+
load_rules(self.service)
|
|
47
|
+
|
|
44
48
|
if not os.path.isfile(FILE_PATH):
|
|
45
49
|
LOG.info(f"File not found: {FILE_PATH}")
|
|
46
50
|
return
|
|
@@ -179,6 +183,10 @@ class RunService:
|
|
|
179
183
|
LOG.info(f"Cleaning up file used for temporary processing: {target_file}")
|
|
180
184
|
os.unlink(target_file)
|
|
181
185
|
|
|
186
|
+
if self.service.rules_directory and self.service.rules_directory != "/":
|
|
187
|
+
LOG.info("Cleaning up downloaded signatures..")
|
|
188
|
+
shutil.rmtree(self.service.rules_directory)
|
|
189
|
+
|
|
182
190
|
LOG.info(f"Moving {result_json} to the working directory: {working_dir}/result.json")
|
|
183
191
|
shutil.move(result_json, os.path.join(working_dir, 'result.json'))
|
|
184
192
|
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import inspect
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import tempfile
|
|
6
|
+
import threading
|
|
7
|
+
|
|
8
|
+
from assemblyline.common.isotime import now_as_iso
|
|
9
|
+
from assemblyline.odm.models.service import SIGNATURE_DELIMITERS
|
|
10
|
+
from assemblyline_v4_service.common.base import ServiceBase
|
|
11
|
+
from assemblyline_v4_service.updater.client import (
|
|
12
|
+
BadlistClient,
|
|
13
|
+
SafelistClient,
|
|
14
|
+
SignatureClient,
|
|
15
|
+
UpdaterClient,
|
|
16
|
+
)
|
|
17
|
+
from assemblyline_v4_service.updater.updater import (
|
|
18
|
+
SIGNATURES_META_FILENAME,
|
|
19
|
+
SOURCE_STATUS_KEY,
|
|
20
|
+
ServiceUpdater,
|
|
21
|
+
UniqueQueue,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TestSignatureClient(SignatureClient):
|
|
26
|
+
def __init__(self, output_directory: str):
|
|
27
|
+
self.sync = False
|
|
28
|
+
self.output_directory = output_directory
|
|
29
|
+
|
|
30
|
+
def add_update_many(self, source, sig_type, data, dedup_name=True):
|
|
31
|
+
os.makedirs(os.path.join(self.output_directory, sig_type, source), exist_ok=True)
|
|
32
|
+
for d in data:
|
|
33
|
+
with open(os.path.join(self.output_directory, sig_type, source, d['name']), 'w') as f:
|
|
34
|
+
json.dump(d, f)
|
|
35
|
+
|
|
36
|
+
return {'success': len(data)}
|
|
37
|
+
|
|
38
|
+
class TestBadlistClient(BadlistClient):
|
|
39
|
+
def __init__(self, output_directory: str):
|
|
40
|
+
self.sync = False
|
|
41
|
+
self.output_directory = output_directory
|
|
42
|
+
|
|
43
|
+
def add_update_many(self, list_of_badlist_objects):
|
|
44
|
+
return {'success': len(list_of_badlist_objects)}
|
|
45
|
+
|
|
46
|
+
class TestSafelistClient(SafelistClient):
|
|
47
|
+
def __init__(self, output_directory: str):
|
|
48
|
+
self.sync = False
|
|
49
|
+
self.output_directory = output_directory
|
|
50
|
+
|
|
51
|
+
def add_update_many(self, list_of_safelist_objects):
|
|
52
|
+
return {'success': len(list_of_safelist_objects)}
|
|
53
|
+
|
|
54
|
+
class TestUpdaterClient(UpdaterClient):
|
|
55
|
+
def __init__(self, output_directory: str):
|
|
56
|
+
self._sync = False
|
|
57
|
+
self._classification_override = False
|
|
58
|
+
self.signature = TestSignatureClient(output_directory)
|
|
59
|
+
self.badlist = TestBadlistClient(output_directory)
|
|
60
|
+
self.safelist = TestSafelistClient(output_directory)
|
|
61
|
+
|
|
62
|
+
def load_rules(service: ServiceBase):
|
|
63
|
+
with tempfile.TemporaryDirectory() as latest_updates_dir:
|
|
64
|
+
updater_module = importlib.import_module(service.service_attributes.dependencies['updates'].container.command[-1])
|
|
65
|
+
# Find the UpdaterServer class
|
|
66
|
+
for v in updater_module.__dict__.values():
|
|
67
|
+
if inspect.isclass(v) and issubclass(v, ServiceUpdater) and v != ServiceUpdater:
|
|
68
|
+
updater_class = v
|
|
69
|
+
break
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Implement a class to be used with RunServiceOnce without a dependency on Assemblyline
|
|
73
|
+
class TestServiceUpdater(updater_class):
|
|
74
|
+
def __init__(self, *args, **kwargs):
|
|
75
|
+
self.update_data_hash = {}
|
|
76
|
+
self._current_source = ""
|
|
77
|
+
self.log = service.log
|
|
78
|
+
self._service = service.service_attributes
|
|
79
|
+
self.update_queue = UniqueQueue()
|
|
80
|
+
self.updater_type = self._service.name.lower()
|
|
81
|
+
self.delimiter = self._service.update_config.signature_delimiter
|
|
82
|
+
self.default_pattern = self._service.update_config.default_pattern
|
|
83
|
+
self.signatures_meta = {}
|
|
84
|
+
[self.update_queue.put(update.name) for update in self._service.update_config.sources]
|
|
85
|
+
|
|
86
|
+
self.latest_updates_dir = latest_updates_dir
|
|
87
|
+
self.client = TestUpdaterClient(latest_updates_dir)
|
|
88
|
+
self.source_update_flag = threading.Event()
|
|
89
|
+
self.local_update_flag = threading.Event()
|
|
90
|
+
self.local_update_start = threading.Event()
|
|
91
|
+
|
|
92
|
+
def set_source_update_time(self, update_time: float): ...
|
|
93
|
+
|
|
94
|
+
def set_source_extra(self, extra_data): ...
|
|
95
|
+
|
|
96
|
+
def set_active_config_hash(self, config_hash: int): ...
|
|
97
|
+
|
|
98
|
+
# Keep a record of the source status as a dictionary
|
|
99
|
+
def push_status(self, state: str, message: str):
|
|
100
|
+
# Push current state of updater with source
|
|
101
|
+
self.log.debug(f"Pushing state for {self._current_source}: [{state}] {message}")
|
|
102
|
+
self.update_data_hash[f'{self._current_source}.{SOURCE_STATUS_KEY}'] = \
|
|
103
|
+
dict(state=state, message=message, ts=now_as_iso())
|
|
104
|
+
|
|
105
|
+
def do_source_update(self):
|
|
106
|
+
super().do_source_update(self._service)
|
|
107
|
+
|
|
108
|
+
def do_local_update(self):
|
|
109
|
+
if self._service.update_config.generates_signatures:
|
|
110
|
+
signaure_data = []
|
|
111
|
+
updatepath = os.path.join(self.latest_updates_dir, self.updater_type)
|
|
112
|
+
for source in os.listdir(updatepath):
|
|
113
|
+
sourcepath = os.path.join(updatepath, source)
|
|
114
|
+
|
|
115
|
+
for file in os.listdir(sourcepath):
|
|
116
|
+
# Save signatures to disk
|
|
117
|
+
filepath = os.path.join(sourcepath, file)
|
|
118
|
+
with open(filepath) as f:
|
|
119
|
+
data = json.load(f)
|
|
120
|
+
|
|
121
|
+
signaure_data.append(data.pop('data'))
|
|
122
|
+
self.signatures_meta[data['signature_id']] = data
|
|
123
|
+
|
|
124
|
+
if self.delimiter != "file":
|
|
125
|
+
os.remove(filepath)
|
|
126
|
+
|
|
127
|
+
if self.delimiter != "file":
|
|
128
|
+
# Render the response when calling `client.signature.download`
|
|
129
|
+
os.removedirs(sourcepath)
|
|
130
|
+
with open(os.path.join(self.latest_updates_dir, source), 'w') as f:
|
|
131
|
+
f.write(SIGNATURE_DELIMITERS[self.delimiter].join(signaure_data))
|
|
132
|
+
|
|
133
|
+
else:
|
|
134
|
+
self.signatures_meta = {
|
|
135
|
+
source.name: {'classification': source['default_classification'].value}
|
|
136
|
+
for source in self._service.update_config.sources
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# Initialize updater, download signatures, and load them into the service
|
|
142
|
+
updater = TestServiceUpdater()
|
|
143
|
+
updater.do_source_update()
|
|
144
|
+
updater.do_local_update()
|
|
145
|
+
rules_directory = updater.prepare_output_directory()
|
|
146
|
+
service.signatures_meta = updater.signatures_meta
|
|
147
|
+
service.rules_directory = rules_directory
|
|
148
|
+
service.rules_list = [os.path.join(rules_directory, i) for i in os.listdir(rules_directory)
|
|
149
|
+
if i != SIGNATURES_META_FILENAME]
|
|
150
|
+
service._load_rules()
|
|
@@ -11,12 +11,12 @@ import certifi
|
|
|
11
11
|
import psutil
|
|
12
12
|
import regex as re
|
|
13
13
|
import requests
|
|
14
|
-
from assemblyline_v4_service.common.utils import DEVELOPMENT_MODE
|
|
15
14
|
from git import Repo
|
|
16
15
|
|
|
17
16
|
from assemblyline.common.digests import get_sha256_for_file
|
|
18
17
|
from assemblyline.common.identify import Identify
|
|
19
18
|
from assemblyline.common.isotime import iso_to_epoch
|
|
19
|
+
from assemblyline_v4_service.common.utils import DEVELOPMENT_MODE
|
|
20
20
|
|
|
21
21
|
BLOCK_SIZE = 64 * 1024
|
|
22
22
|
GIT_ALLOW_UNSAFE_PROTOCOLS = os.environ.get('GIT_ALLOW_UNSAFE_PROTOCOLS', 'false').lower() == 'true'
|
|
@@ -138,8 +138,7 @@ def url_download(source: Dict[str, Any], previous_update: int, logger: Logger, o
|
|
|
138
138
|
if fetch_method == 'get':
|
|
139
139
|
response = session.get(uri, auth=auth, headers=headers, proxies=proxies, stream=True)
|
|
140
140
|
elif fetch_method == 'post':
|
|
141
|
-
|
|
142
|
-
response = session.post(uri, auth=auth, headers=headers, proxies=proxies, json=json, stream=True)
|
|
141
|
+
response = session.post(uri, auth=auth, headers=headers, proxies=proxies, data=source.get('data'),stream=True)
|
|
143
142
|
else:
|
|
144
143
|
raise ValueError(f"Unknown fetch method: {fetch_method}")
|
|
145
144
|
|
|
@@ -1,37 +1,44 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import typing
|
|
5
|
-
import os
|
|
6
|
-
import logging
|
|
7
|
-
import time
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
8
4
|
import json
|
|
9
|
-
import
|
|
5
|
+
import logging
|
|
6
|
+
import os
|
|
7
|
+
import shutil
|
|
8
|
+
import subprocess
|
|
10
9
|
import tarfile
|
|
10
|
+
import tempfile
|
|
11
11
|
import threading
|
|
12
|
-
import
|
|
13
|
-
import
|
|
12
|
+
import time
|
|
13
|
+
import typing
|
|
14
14
|
from io import BytesIO
|
|
15
15
|
from queue import Queue
|
|
16
|
+
from typing import Any, List, Optional, Tuple
|
|
16
17
|
from zipfile import ZipFile
|
|
17
18
|
|
|
18
|
-
from
|
|
19
|
+
from assemblyline_core.server_base import ServiceStage, ThreadedCoreBase
|
|
20
|
+
|
|
21
|
+
from assemblyline.common import forge
|
|
22
|
+
from assemblyline.common import log as al_log
|
|
19
23
|
from assemblyline.common.isotime import epoch_to_iso, now_as_iso
|
|
20
24
|
from assemblyline.odm.messages.changes import Operation, ServiceChange, SignatureChange
|
|
21
|
-
from assemblyline.remote.datatypes.events import EventSender, EventWatcher
|
|
22
|
-
|
|
23
|
-
from assemblyline_core.server_base import ThreadedCoreBase, ServiceStage
|
|
24
25
|
from assemblyline.odm.models.service import Service, UpdateSource
|
|
26
|
+
from assemblyline.remote.datatypes.events import EventSender, EventWatcher
|
|
25
27
|
from assemblyline.remote.datatypes.hash import Hash
|
|
26
|
-
|
|
27
28
|
from assemblyline_v4_service.common.base import SIGNATURES_META_FILENAME
|
|
28
29
|
from assemblyline_v4_service.updater.client import UpdaterClient
|
|
29
|
-
from assemblyline_v4_service.updater.helper import
|
|
30
|
+
from assemblyline_v4_service.updater.helper import (
|
|
31
|
+
SkipSource,
|
|
32
|
+
filter_downloads,
|
|
33
|
+
git_clone_repo,
|
|
34
|
+
url_download,
|
|
35
|
+
)
|
|
30
36
|
|
|
31
37
|
if typing.TYPE_CHECKING:
|
|
32
38
|
import redis
|
|
33
|
-
|
|
39
|
+
|
|
34
40
|
from assemblyline.datastore.helper import AssemblylineDatastore
|
|
41
|
+
from assemblyline.odm.models.config import Config
|
|
35
42
|
RedisType = redis.Redis[typing.Any]
|
|
36
43
|
|
|
37
44
|
SERVICE_PULL_INTERVAL = 1200
|
|
@@ -65,10 +72,10 @@ class ServiceUpdater(ThreadedCoreBase):
|
|
|
65
72
|
shutdown_timeout: float = None, config: Config = None,
|
|
66
73
|
datastore: AssemblylineDatastore = None,
|
|
67
74
|
redis: RedisType = None, redis_persist: RedisType = None,
|
|
68
|
-
|
|
75
|
+
downloadable_signature_statuses=['DEPLOYED', 'NOISY']):
|
|
69
76
|
|
|
70
77
|
self.updater_type = os.environ['SERVICE_PATH'].split('.')[-1].lower()
|
|
71
|
-
self.default_pattern =
|
|
78
|
+
self.default_pattern = None
|
|
72
79
|
|
|
73
80
|
if not logger:
|
|
74
81
|
al_log.init_logging(f'updater.{self.updater_type}', log_level=os.environ.get('LOG_LEVEL', "WARNING"))
|
|
@@ -247,6 +254,10 @@ class ServiceUpdater(ThreadedCoreBase):
|
|
|
247
254
|
# Download the service object from datastore
|
|
248
255
|
self._service = self.datastore.get_service_with_delta(SERVICE_NAME)
|
|
249
256
|
|
|
257
|
+
# Set default pattern if not already set
|
|
258
|
+
if not self.default_pattern:
|
|
259
|
+
self.default_pattern = self._service.update_config.default_pattern
|
|
260
|
+
|
|
250
261
|
# Update signature client with any changes to classification rewrites
|
|
251
262
|
self.client.signature.classification_replace_map = \
|
|
252
263
|
self._service.config.get('updater', {}).get('classification_replace', {})
|
{assemblyline_v4_service-4.5.0.77.dist-info → assemblyline_v4_service-4.5.0.79.dist-info}/RECORD
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
assemblyline_v4_service/VERSION,sha256=
|
|
1
|
+
assemblyline_v4_service/VERSION,sha256=5sBPWf_BFKJmyxOzoUQy0aRuAccbut6nqeV5my3ZtKA,9
|
|
2
2
|
assemblyline_v4_service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
assemblyline_v4_service/healthz.py,sha256=3QGBg0EZuXC6UN411HFwpLNEop9UvS9feFhvBUTP-k4,1576
|
|
4
4
|
assemblyline_v4_service/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -15,14 +15,15 @@ assemblyline_v4_service/common/result.py,sha256=9AqM6qCYiia_Bpyn_fBFhzNQMcqJbtFS
|
|
|
15
15
|
assemblyline_v4_service/common/task.py,sha256=dJsvRpW0x88CCF_LW6w87jQ_UKTVaOs2Gb117IDNiU8,14233
|
|
16
16
|
assemblyline_v4_service/common/utils.py,sha256=k2__d-V5LjB6o2IKbjVe7tJWKcKuUHto5TyT5oKhIa0,3890
|
|
17
17
|
assemblyline_v4_service/dev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
-
assemblyline_v4_service/dev/run_service_once.py,sha256=
|
|
18
|
+
assemblyline_v4_service/dev/run_service_once.py,sha256=W9kR49IUbkt8tNXjCT40ZMh-8p5W_odxlkDx6nhTAYM,10656
|
|
19
|
+
assemblyline_v4_service/dev/updater.py,sha256=b-FK6XPRZbETbl-SIYEhnYGT-W7EcQhnxwD6x2NMC7g,6411
|
|
19
20
|
assemblyline_v4_service/updater/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
21
|
assemblyline_v4_service/updater/__main__.py,sha256=9Os-u8Tf7MD73JSrUSPmOaErTgfvesNLiEeszU4ujXA,133
|
|
21
22
|
assemblyline_v4_service/updater/app.py,sha256=Mtmx4bkXfP4nFqqa5q15jW8QIXr4JK84lCovxAVyvPs,3317
|
|
22
23
|
assemblyline_v4_service/updater/client.py,sha256=tLY84gaGdFBVIDaMgRHIEa7x2S8jBl7lQLzp4seC6aI,11200
|
|
23
24
|
assemblyline_v4_service/updater/gunicorn_config.py,sha256=p3j2KPBeD5jvMw9O5i7vAtlRgPSVVxIG9AO0DfN82J8,1247
|
|
24
|
-
assemblyline_v4_service/updater/helper.py,sha256=
|
|
25
|
-
assemblyline_v4_service/updater/updater.py,sha256=
|
|
25
|
+
assemblyline_v4_service/updater/helper.py,sha256=Zy6OBmbTh0YurW0MnM0wM92vaKYMbo_MKnafe_5ONUI,10034
|
|
26
|
+
assemblyline_v4_service/updater/updater.py,sha256=kli-5v1uVmk2FARAI9DsZ9YM4EhgirkmWJaMJWdm9GI,31795
|
|
26
27
|
test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
28
|
test/conftest.py,sha256=W3SieQpZsZpGEmtLqY4aIlxREDSsHceyCrFcFsWUM0U,1851
|
|
28
29
|
test/test_healthz.py,sha256=DkeLUlrb7rGx3nZ04aADU9HXXu5mZTf_DBwT0xhzIv4,7
|
|
@@ -38,8 +39,8 @@ test/test_common/test_request.py,sha256=Ceyds8BNO1O0f1kH1VEb84faJcaupvSjVKIrGdHe
|
|
|
38
39
|
test/test_common/test_result.py,sha256=6BiOKxEPrKBjOY44jv3TY-yiXm0qI1ok_CZBnjP9TM4,45447
|
|
39
40
|
test/test_common/test_task.py,sha256=P44mNcSe-3tJgDk9ppN3KbM7oN4LBVIuhONG-Gveh74,19007
|
|
40
41
|
test/test_common/test_utils.py,sha256=TbnBxqpS_ZC5ptXR9XJX3xtbItD0mTbtiBxxdyP8J5k,5904
|
|
41
|
-
assemblyline_v4_service-4.5.0.
|
|
42
|
-
assemblyline_v4_service-4.5.0.
|
|
43
|
-
assemblyline_v4_service-4.5.0.
|
|
44
|
-
assemblyline_v4_service-4.5.0.
|
|
45
|
-
assemblyline_v4_service-4.5.0.
|
|
42
|
+
assemblyline_v4_service-4.5.0.79.dist-info/LICENCE.md,sha256=NSkYo9EH8h5oOkzg4VhjAHF4339MqPP2cQ8msTPgl-c,1396
|
|
43
|
+
assemblyline_v4_service-4.5.0.79.dist-info/METADATA,sha256=LyBqjMlTZmsaanZ6pB3Ehh9-RjGV5Cj9Zw_-6YLiFio,5599
|
|
44
|
+
assemblyline_v4_service-4.5.0.79.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
|
45
|
+
assemblyline_v4_service-4.5.0.79.dist-info/top_level.txt,sha256=LpTOEaVCatkrvbVq3EZseMSIa2PQZU-2rhuO_FTpZgY,29
|
|
46
|
+
assemblyline_v4_service-4.5.0.79.dist-info/RECORD,,
|
{assemblyline_v4_service-4.5.0.77.dist-info → assemblyline_v4_service-4.5.0.79.dist-info}/LICENCE.md
RENAMED
|
File without changes
|
|
File without changes
|