This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git
The following commit(s) were added to refs/heads/main by this push:
new d64ad02 Use the storage interface for the form to regenerate all KEYS
files
d64ad02 is described below
commit d64ad0215cad38fea9314762472bd05b45d643d6
Author: Sean B. Palmer <[email protected]>
AuthorDate: Tue Jul 22 15:18:28 2025 +0100
Use the storage interface for the form to regenerate all KEYS files
---
atr/blueprints/admin/admin.py | 33 ++++++++++++++++++++++++---------
atr/storage/__init__.py | 20 ++++++++++++++++++++
atr/storage/types.py | 25 ++++++++++++++-----------
atr/storage/writers/keys.py | 43 ++++++++++++++++++++++++++++++-------------
4 files changed, 88 insertions(+), 33 deletions(-)
diff --git a/atr/blueprints/admin/admin.py b/atr/blueprints/admin/admin.py
index 1e9b57b..03edd75 100644
--- a/atr/blueprints/admin/admin.py
+++ b/atr/blueprints/admin/admin.py
@@ -47,6 +47,7 @@ import atr.ldap as ldap
import atr.models.sql as sql
import atr.routes.keys as keys
import atr.routes.mapping as mapping
+import atr.storage as storage
import atr.storage.types as types
import atr.template as template
import atr.util as util
@@ -422,15 +423,29 @@ async def admin_keys_regenerate_all() -> quart.Response:
mimetype="text/html",
)
- try:
- okay, failures = await _regenerate_keys_all()
- msg = f"KEYS file regeneration results: {okay} okay, {len(failures)}
failed"
- if failures:
- msg += f"\nFailures:\n{'\n'.join(failures)}"
- return quart.Response(msg, mimetype="text/plain")
- except Exception as e:
- _LOGGER.exception("Exception during KEYS file regeneration:")
- return quart.Response(f"Exception during KEYS file regeneration:
{e!s}", mimetype="text/plain")
+ async with db.session() as data:
+ committee_names = [c.name for c in await data.committee().all()]
+
+ web_session = await session.read()
+ if web_session is None:
+ raise base.ASFQuartException("Not authenticated", 401)
+ asf_uid = web_session.uid
+ if asf_uid is None:
+ raise base.ASFQuartException("Invalid session, uid is None", 500)
+
+ outcomes = types.Outcomes[str]()
+ async with storage.write(asf_uid) as write:
+ for committee_name in committee_names:
+ wacm = write.as_committee_member(committee_name).writer_or_raise()
+ outcomes.append(await wacm.keys.autogenerate_keys_file())
+
+ response_lines = []
+ for ocr in outcomes.results():
+ response_lines.append(f"Regenerated: {ocr}")
+ for oce in outcomes.exceptions():
+ response_lines.append(f"Error regenerating: {type(oce).__name__}
{oce}")
+
+ return quart.Response("\n".join(response_lines), mimetype="text/plain")
@admin.BLUEPRINT.route("/keys/update", methods=["GET", "POST"])
diff --git a/atr/storage/__init__.py b/atr/storage/__init__.py
index ab2da74..642780a 100644
--- a/atr/storage/__init__.py
+++ b/atr/storage/__init__.py
@@ -197,6 +197,26 @@ class WriteAsCommitteeMember(WriteAsCommitteeParticipant):
return VALIDATE_AT_RUNTIME
+# class WriteAsFoundationAdmin(WriteAsFoundationMember):
+# def __init__(self, data: db.Session, asf_uid: str):
+# self.__data = data
+# self.__asf_uid = asf_uid
+# self.__authenticated = True
+# self.keys = writers.keys.FoundationAdmin(
+# self,
+# self.__data,
+# self.__asf_uid,
+# )
+
+# @property
+# def authenticated(self) -> bool:
+# return self.__authenticated
+
+# @property
+# def validate_at_runtime(self) -> bool:
+# return VALIDATE_AT_RUNTIME
+
+
class Write:
# Read and Write have authenticator methods which return access outcomes
def __init__(self, data: db.Session, asf_uid: str | None = None):
diff --git a/atr/storage/types.py b/atr/storage/types.py
index b639474..82e7ee0 100644
--- a/atr/storage/types.py
+++ b/atr/storage/types.py
@@ -79,7 +79,7 @@ class OutcomeResult[T](OutcomeCore[T]):
return None
-class OutcomeException[T, E: Exception](OutcomeCore[T]):
+class OutcomeException[T, E: Exception = Exception](OutcomeCore[T]):
__exception: E
def __init__(self, exception: E, name: str | None = None):
@@ -109,6 +109,9 @@ class OutcomeException[T, E: Exception](OutcomeCore[T]):
return type(self.__exception)
+type Outcome[T] = OutcomeResult[T] | OutcomeException[T, Exception]
+
+
class Outcomes[T]:
__outcomes: list[OutcomeResult[T] | OutcomeException[T, Exception]]
@@ -123,11 +126,14 @@ class Outcomes[T]:
def all_ok(self) -> bool:
return all(outcome.ok for outcome in self.__outcomes)
- def append(self, result_or_error: T | Exception, name: str | None = None)
-> None:
- if isinstance(result_or_error, Exception):
- self.__outcomes.append(OutcomeException(result_or_error, name))
+ def append(self, outcome: OutcomeResult[T] | OutcomeException[T,
Exception]) -> None:
+ self.__outcomes.append(outcome)
+
+ def append_roe(self, roe: T | Exception, name: str | None = None) -> None:
+ if isinstance(roe, Exception):
+ self.__outcomes.append(OutcomeException[T, Exception](roe, name))
else:
- self.__outcomes.append(OutcomeResult(result_or_error, name))
+ self.__outcomes.append(OutcomeResult[T](roe, name))
@property
def exception_count(self) -> int:
@@ -142,9 +148,9 @@ class Outcomes[T]:
exceptions_list.append(exception_or_none)
return exceptions_list
- def extend(self, result_or_error_list: Sequence[T | Exception]) -> None:
- for result_or_error in result_or_error_list:
- self.append(result_or_error)
+ def extend(self, roes: Sequence[T | Exception]) -> None:
+ for roe in roes:
+ self.append_roe(roe)
def named_results(self) -> dict[str, T]:
named = {}
@@ -193,9 +199,6 @@ class Outcomes[T]:
self.__outcomes[i] = OutcomeResult(result, outcome.name)
-type Outcome[T] = OutcomeResult[T] | OutcomeException[T, Exception]
-
-
class KeyStatus(enum.Flag):
PARSED = 0
INSERTED = enum.auto()
diff --git a/atr/storage/writers/keys.py b/atr/storage/writers/keys.py
index 2794c94..fe8d9d1 100644
--- a/atr/storage/writers/keys.py
+++ b/atr/storage/writers/keys.py
@@ -263,7 +263,7 @@ class CommitteeMember(CommitteeParticipant):
except Exception as e:
return types.OutcomeException(e)
try:
- autogenerated_outcome = await self.__autogenerate_keys_file()
+ autogenerated_outcome = await self.autogenerate_keys_file()
except Exception as e:
return types.OutcomeException(e)
return types.OutcomeResult(
@@ -288,20 +288,24 @@ class CommitteeMember(CommitteeParticipant):
async def ensure_stored(self, keys_file_text: str) ->
types.Outcomes[types.Key]:
return await self.__ensure(keys_file_text, associate=False)
- async def __autogenerate_keys_file(
+ async def autogenerate_keys_file(
self,
) -> types.Outcome[str]:
- base_downloads_dir = util.get_downloads_dir()
+ try:
+ base_downloads_dir = util.get_downloads_dir()
- committee = await self.committee()
- is_podling = committee.is_podling
+ committee = await self.committee()
+ is_podling = committee.is_podling
+
+ full_keys_file_content = await self.__keys_formatter()
+ if is_podling:
+ committee_keys_dir = base_downloads_dir / "incubator" /
self.__committee_name
+ else:
+ committee_keys_dir = base_downloads_dir / self.__committee_name
+ committee_keys_path = committee_keys_dir / "KEYS"
+ except Exception as e:
+ return types.OutcomeException(e)
- full_keys_file_content = await self.__keys_formatter()
- if is_podling:
- committee_keys_dir = base_downloads_dir / "incubator" /
self.__committee_name
- else:
- committee_keys_dir = base_downloads_dir / self.__committee_name
- committee_keys_path = committee_keys_dir / "KEYS"
try:
await asyncio.to_thread(committee_keys_dir.mkdir, parents=True,
exist_ok=True)
await asyncio.to_thread(util.chmod_directories,
committee_keys_dir, permissions=0o755)
@@ -430,14 +434,14 @@ class CommitteeMember(CommitteeParticipant):
ldap_data = await util.email_to_uid_map()
key_blocks = util.parse_key_blocks(keys_file_text)
except Exception as e:
- outcomes.append(e)
+ outcomes.append_roe(e)
return outcomes
for key_block in key_blocks:
try:
key_models = await asyncio.to_thread(self.__block_models,
key_block, ldap_data)
outcomes.extend(key_models)
except Exception as e:
- outcomes.append(e)
+ outcomes.append_roe(e)
# Try adding the keys to the database
# If not, all keys will be replaced with a PostParseError
outcomes = await self.__database_add_models(outcomes,
associate=associate)
@@ -534,3 +538,16 @@ and was published by the committee.\
key_count_for_header=key_count_for_header,
key_blocks_str=key_blocks_str,
)
+
+
+# class FoundationAdmin(FoundationMember):
+# def __init__(
+# self, credentials: storage.WriteAsFoundationAdmin, data: db.Session,
asf_uid: str
+# ):
+# self.__data = data
+# self.__credentials = credentials
+# self.__asf_uid = asf_uid
+
+# @performance_async
+# async def ensure_stored_one(self, key_file_text: str) ->
types.Outcome[types.Key]:
+# return await self.__ensure_one(key_file_text, associate=False)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]