scriptworker 62.7.0__tar.gz → 63.0.1__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.
- {scriptworker-62.7.0 → scriptworker-63.0.1}/HISTORY.rst +25 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/PKG-INFO +1 -1
- {scriptworker-62.7.0 → scriptworker-63.0.1}/pyproject.toml +1 -1
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/cot/verify.py +32 -22
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/utils.py +16 -6
- {scriptworker-62.7.0 → scriptworker-63.0.1}/tox.ini +1 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/.gitignore +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/CONTRIBUTING.rst +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/LICENSE +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/README.rst +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/renovate.json +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/scripts/gen_ed25519_key.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/scriptworker.yaml.tmpl +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/__init__.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/artifacts.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/client.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/config.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/constants.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/context.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/cot/__init__.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/cot/generate.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/data/cot_v1_schema.json +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/data/scriptworker_task_schema.json +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/ed25519.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/exceptions.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/github.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/log.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/task.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/task_process.py +0 -0
- {scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/worker.py +0 -0
|
@@ -4,6 +4,31 @@ Change Log
|
|
|
4
4
|
All notable changes to this project will be documented in this file.
|
|
5
5
|
This project adheres to `Semantic Versioning <http://semver.org/>`__.
|
|
6
6
|
|
|
7
|
+
63.0.1 - 2026-04-27
|
|
8
|
+
|
|
9
|
+
Fixed
|
|
10
|
+
~~~~~
|
|
11
|
+
|
|
12
|
+
- File corruption caused by parallel downloads (#792)
|
|
13
|
+
|
|
14
|
+
63.0.0 - 2026-04-09
|
|
15
|
+
-------------------
|
|
16
|
+
|
|
17
|
+
Changed
|
|
18
|
+
~~~~~~~
|
|
19
|
+
|
|
20
|
+
- Parallelized several steps of Chain of Trust verification, significantly
|
|
21
|
+
improving end-to-end times. As a result, `scriptworker.cot.verify.build_link`
|
|
22
|
+
has been renamed to `scriptworker.cot.verify.add_link` and no longer recurses
|
|
23
|
+
into dependencies . One should call `build_task_dependencies` after adding
|
|
24
|
+
the link to walk the graph.
|
|
25
|
+
|
|
26
|
+
Fixed
|
|
27
|
+
~~~~~
|
|
28
|
+
|
|
29
|
+
- The root task isn't verified twice anymore when using `check_task=True` in
|
|
30
|
+
`verify_chain_of_trust` on non decision tasks.
|
|
31
|
+
|
|
7
32
|
62.7.0 - 2026-03-18
|
|
8
33
|
-------------------
|
|
9
34
|
|
|
@@ -222,7 +222,7 @@ class ChainOfTrust(object):
|
|
|
222
222
|
list: of all ``LinkOfTrust``s to verify.
|
|
223
223
|
|
|
224
224
|
"""
|
|
225
|
-
if self.
|
|
225
|
+
if self.task_id in self.dependent_task_ids():
|
|
226
226
|
return self.links
|
|
227
227
|
return [self] + self.links
|
|
228
228
|
|
|
@@ -619,8 +619,8 @@ def _sort_dependencies_by_name_then_task_id(dependencies):
|
|
|
619
619
|
|
|
620
620
|
|
|
621
621
|
# build_task_dependencies {{{1
|
|
622
|
-
async def
|
|
623
|
-
"""
|
|
622
|
+
async def add_link(chain, task_name, task_id):
|
|
623
|
+
"""Fetch a task definition and add it as a LinkOfTrust to the chain.
|
|
624
624
|
|
|
625
625
|
Args:
|
|
626
626
|
chain (ChainOfTrust): the chain of trust to add to.
|
|
@@ -633,17 +633,14 @@ async def build_link(chain, task_name, task_id):
|
|
|
633
633
|
"""
|
|
634
634
|
link = LinkOfTrust(chain.context, task_name, task_id)
|
|
635
635
|
json_path = link.get_artifact_full_path("task.json")
|
|
636
|
-
|
|
637
|
-
link.task = task_defn
|
|
636
|
+
link.task = await retry_get_task_definition(chain.context.queue, task_id, exception=CoTError)
|
|
638
637
|
chain.links.append(link)
|
|
639
|
-
# write task json to disk
|
|
640
638
|
makedirs(os.path.dirname(json_path))
|
|
641
639
|
with open(json_path, "w") as fh:
|
|
642
|
-
fh.write(format_json(
|
|
643
|
-
await build_task_dependencies(chain, task_defn, task_name, task_id)
|
|
640
|
+
fh.write(format_json(link.task))
|
|
644
641
|
|
|
645
642
|
|
|
646
|
-
async def build_task_dependencies(chain, task, name, my_task_id):
|
|
643
|
+
async def build_task_dependencies(chain, task, name, my_task_id, seen=None):
|
|
647
644
|
"""Recursively build the task dependencies of a task.
|
|
648
645
|
|
|
649
646
|
Args:
|
|
@@ -651,6 +648,7 @@ async def build_task_dependencies(chain, task, name, my_task_id):
|
|
|
651
648
|
task (dict): the task definition to operate on.
|
|
652
649
|
name (str): the name of the task to operate on.
|
|
653
650
|
my_task_id (str): the taskId of the task to operate on.
|
|
651
|
+
seen (set): shared set of already-seen task IDs to avoid duplicates
|
|
654
652
|
|
|
655
653
|
Raises:
|
|
656
654
|
CoTError: on failure.
|
|
@@ -661,9 +659,20 @@ async def build_task_dependencies(chain, task, name, my_task_id):
|
|
|
661
659
|
raise CoTError("Too deep recursion!\n{}".format(name))
|
|
662
660
|
sorted_dependencies = find_sorted_task_dependencies(task, name, my_task_id)
|
|
663
661
|
|
|
662
|
+
if seen is None:
|
|
663
|
+
seen = set(chain.dependent_task_ids())
|
|
664
|
+
new_deps = []
|
|
664
665
|
for task_name, task_id in sorted_dependencies:
|
|
665
|
-
if task_id not in
|
|
666
|
-
|
|
666
|
+
if task_id not in seen:
|
|
667
|
+
seen.add(task_id)
|
|
668
|
+
new_deps.append((task_name, task_id))
|
|
669
|
+
|
|
670
|
+
if not new_deps:
|
|
671
|
+
return
|
|
672
|
+
|
|
673
|
+
await asyncio.gather(*[add_link(chain, task_name, task_id) for task_name, task_id in new_deps])
|
|
674
|
+
|
|
675
|
+
await asyncio.gather(*[build_task_dependencies(chain, chain.get_link(task_id).task, task_name, task_id, seen) for task_name, task_id in new_deps])
|
|
667
676
|
|
|
668
677
|
|
|
669
678
|
# download_cot {{{1
|
|
@@ -1565,8 +1574,10 @@ async def get_jsone_context_and_template(chain, parent_link, decision_link, task
|
|
|
1565
1574
|
if tasks_for in ("action", "pr-action"):
|
|
1566
1575
|
jsone_context, tmpl = await get_action_context_and_template(chain, parent_link, decision_link, tasks_for)
|
|
1567
1576
|
else:
|
|
1568
|
-
tmpl = await
|
|
1569
|
-
|
|
1577
|
+
tmpl, jsone_context = await asyncio.gather(
|
|
1578
|
+
get_in_tree_template(decision_link),
|
|
1579
|
+
populate_jsone_context(chain, parent_link, decision_link, tasks_for),
|
|
1580
|
+
)
|
|
1570
1581
|
return jsone_context, tmpl
|
|
1571
1582
|
|
|
1572
1583
|
|
|
@@ -1803,14 +1814,14 @@ async def verify_task_types(chain):
|
|
|
1803
1814
|
"""
|
|
1804
1815
|
valid_task_types = get_valid_task_types()
|
|
1805
1816
|
task_count = {}
|
|
1817
|
+
tasks = []
|
|
1806
1818
|
for obj in chain.get_all_links_in_chain():
|
|
1807
1819
|
task_type = obj.task_type
|
|
1808
1820
|
log.info("Verifying {} {} as a {} task...".format(obj.name, obj.task_id, task_type))
|
|
1809
1821
|
task_count.setdefault(task_type, 0)
|
|
1810
1822
|
task_count[task_type] += 1
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
await valid_task_types[task_type](chain, obj)
|
|
1823
|
+
tasks.append(valid_task_types[task_type](chain, obj))
|
|
1824
|
+
await asyncio.gather(*tasks)
|
|
1814
1825
|
return task_count
|
|
1815
1826
|
|
|
1816
1827
|
|
|
@@ -1880,12 +1891,12 @@ async def verify_worker_impls(chain):
|
|
|
1880
1891
|
|
|
1881
1892
|
"""
|
|
1882
1893
|
valid_worker_impls = get_valid_worker_impls()
|
|
1894
|
+
tasks = []
|
|
1883
1895
|
for obj in chain.get_all_links_in_chain():
|
|
1884
1896
|
worker_impl = obj.worker_impl
|
|
1885
1897
|
log.info("Verifying {} {} as a {} task...".format(obj.name, obj.task_id, worker_impl))
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
await valid_worker_impls[worker_impl](chain, obj)
|
|
1898
|
+
tasks.append(valid_worker_impls[worker_impl](chain, obj))
|
|
1899
|
+
await asyncio.gather(*tasks)
|
|
1889
1900
|
|
|
1890
1901
|
|
|
1891
1902
|
# get_source_url {{{1
|
|
@@ -2042,9 +2053,8 @@ async def verify_chain_of_trust(chain, *, check_task=False):
|
|
|
2042
2053
|
try:
|
|
2043
2054
|
# build LinkOfTrust objects
|
|
2044
2055
|
if check_task:
|
|
2045
|
-
await
|
|
2046
|
-
|
|
2047
|
-
await build_task_dependencies(chain, chain.task, chain.name, chain.task_id)
|
|
2056
|
+
await add_link(chain, chain.name, chain.task_id)
|
|
2057
|
+
await build_task_dependencies(chain, chain.task, chain.name, chain.task_id)
|
|
2048
2058
|
# download the signed chain of trust artifacts
|
|
2049
2059
|
await download_cot(chain)
|
|
2050
2060
|
# verify the signatures and populate the ``link.cot``s
|
|
@@ -16,6 +16,7 @@ import random
|
|
|
16
16
|
import re
|
|
17
17
|
import shutil
|
|
18
18
|
import time
|
|
19
|
+
import uuid
|
|
19
20
|
from copy import deepcopy
|
|
20
21
|
from typing import IO, TYPE_CHECKING, Any, Awaitable, Callable, Dict, Match, Optional, Sequence, Tuple, Type, Union, cast, overload # noqa
|
|
21
22
|
from urllib.parse import unquote, urlparse
|
|
@@ -680,12 +681,21 @@ async def download_file(context, url, abs_filename, session=None, chunk_size=128
|
|
|
680
681
|
await _log_download_error(resp, "Failed to download %(url)s: %(status)s; body=%(body)s")
|
|
681
682
|
raise DownloadError("{} status {} is not 200!".format(loggable_url, resp.status))
|
|
682
683
|
makedirs(parent_dir)
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
684
|
+
tmp_filename = "{}.{}.part".format(abs_filename, uuid.uuid4().hex)
|
|
685
|
+
try:
|
|
686
|
+
with open(tmp_filename, "wb") as fd:
|
|
687
|
+
while True:
|
|
688
|
+
chunk = await resp.content.read(chunk_size)
|
|
689
|
+
if not chunk:
|
|
690
|
+
break
|
|
691
|
+
fd.write(chunk)
|
|
692
|
+
os.replace(tmp_filename, abs_filename)
|
|
693
|
+
except Exception:
|
|
694
|
+
try:
|
|
695
|
+
os.unlink(tmp_filename)
|
|
696
|
+
except OSError:
|
|
697
|
+
pass
|
|
698
|
+
raise
|
|
689
699
|
log.info("Done")
|
|
690
700
|
|
|
691
701
|
|
|
@@ -66,6 +66,7 @@ commands =
|
|
|
66
66
|
|
|
67
67
|
[flake8]
|
|
68
68
|
max-line-length = 160
|
|
69
|
+
extend-ignore = E203
|
|
69
70
|
# test_github.py ignored because of https://gitlab.com/pycqa/flake8/issues/375
|
|
70
71
|
exclude = .ropeproject,.tox,sandbox,docs,.eggs,*.egg,*.egg-info,setup.py,build/,tests/test_github.py,.venv
|
|
71
72
|
per-file-ignores =
|
|
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
|
{scriptworker-62.7.0 → scriptworker-63.0.1}/src/scriptworker/data/scriptworker_task_schema.json
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
|