You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tooling.apache.org by ar...@apache.org on 2026/03/12 11:17:25 UTC
(tooling-trusted-releases) branch safe_committee_type created (now 1a4dbeea)
This is an automated email from the ASF dual-hosted git repository.
arm pushed a change to branch safe_committee_type
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
at 1a4dbeea #840: safe committee name type - without validation
This branch includes the following new commits:
new 1a4dbeea #840: safe committee name type - without validation
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org
(tooling-trusted-releases) 01/01: #840: safe committee name type - without validation
Posted by ar...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
arm pushed a commit to branch safe_committee_type
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
commit 1a4dbeea31a4780af704e8a50fbfbec2b6897683
Author: Alastair McFarlane <ar...@apache.org>
AuthorDate: Thu Mar 12 11:16:53 2026 +0000
#840: safe committee name type - without validation
---
atr/api/__init__.py | 6 +++---
atr/blueprints/common.py | 1 +
atr/get/committees.py | 8 ++++----
atr/get/keys.py | 3 ++-
atr/get/projects.py | 17 ++++++++---------
atr/models/safe.py | 5 +++++
atr/post/projects.py | 5 ++---
atr/storage/writers/project.py | 9 ++++-----
atr/web.py | 4 ++--
9 files changed, 31 insertions(+), 27 deletions(-)
diff --git a/atr/api/__init__.py b/atr/api/__init__.py
index cbc0065e..8b6058f6 100644
--- a/atr/api/__init__.py
+++ b/atr/api/__init__.py
@@ -180,7 +180,7 @@ async def checks_ongoing(
@quart_schema.validate_response(models.api.CommitteeGetResults, 200)
async def committee_get(
_committee_get: Literal["committee/get"],
- name: unsafe.UnsafeStr,
+ name: safe.CommitteeName,
) -> DictResponse:
"""
URL: GET /committee/get/<name>
@@ -206,7 +206,7 @@ async def committee_get(
@quart_schema.validate_response(models.api.CommitteeKeysResults, 200)
async def committee_keys(
_committee_keys: Literal["committee/keys"],
- name: unsafe.UnsafeStr,
+ name: safe.CommitteeName,
) -> DictResponse:
"""
URL: GET /committee/keys/<name>
@@ -232,7 +232,7 @@ async def committee_keys(
@quart_schema.validate_response(models.api.CommitteeProjectsResults, 200)
async def committee_projects(
_committee_projects: Literal["committee/projects"],
- name: unsafe.UnsafeStr,
+ name: safe.CommitteeName,
) -> DictResponse:
"""
URL: GET /committee/projects/<name>
diff --git a/atr/blueprints/common.py b/atr/blueprints/common.py
index 0fd2073b..719c7dc0 100644
--- a/atr/blueprints/common.py
+++ b/atr/blueprints/common.py
@@ -40,6 +40,7 @@ QUART_CONVERTERS: dict[Any, str] = {
VALIDATED_TYPES: set[Any] = {
safe.Alphanumeric,
+ safe.CommitteeName,
safe.ProjectName,
safe.RevisionNumber,
safe.VersionName,
diff --git a/atr/get/committees.py b/atr/get/committees.py
index 1ab70af9..1512fd46 100644
--- a/atr/get/committees.py
+++ b/atr/get/committees.py
@@ -23,8 +23,8 @@ import asfquart.base as base
import atr.blueprints.get as get
import atr.db as db
import atr.form as form
+import atr.models.safe as safe
import atr.models.sql as sql
-import atr.models.unsafe as unsafe
import atr.post as post
import atr.shared as shared
import atr.template as template
@@ -49,7 +49,7 @@ async def directory(_session: web.Public, _committees: Literal["committees"]) ->
@get.typed
-async def view(_session: web.Public, _committees: Literal["committees"], name: unsafe.UnsafeStr) -> str:
+async def view(_session: web.Public, _committees: Literal["committees"], name: safe.CommitteeName) -> str:
"""
URL: /committees/<name>
"""
@@ -75,8 +75,8 @@ async def view(_session: web.Public, _committees: Literal["committees"], name: u
model_cls=shared.keys.UpdateCommitteeKeysForm,
action=util.as_url(post.keys.keys),
submit_label="Regenerate KEYS file",
- defaults={"committee_name": str(name)},
+ defaults={"committee_name": committee.name},
empty=True,
),
- is_standing=util.committee_is_standing(str(name)),
+ is_standing=util.committee_is_standing(committee.name),
)
diff --git a/atr/get/keys.py b/atr/get/keys.py
index d0fba17f..fdb7333a 100644
--- a/atr/get/keys.py
+++ b/atr/get/keys.py
@@ -26,6 +26,7 @@ import atr.blueprints.get as get
import atr.db as db
import atr.form as form
import atr.htm as htm
+import atr.models.safe as safe
import atr.models.sql as sql
import atr.models.unsafe as unsafe
import atr.post as post
@@ -183,7 +184,7 @@ async def details(session: web.Committer, _keys_details: Literal["keys/details"]
@get.typed
async def export(
- _session: web.Committer, _keys_export: Literal["keys/export"], committee_name: unsafe.UnsafeStr
+ _session: web.Committer, _keys_export: Literal["keys/export"], committee_name: safe.CommitteeName
) -> web.TextResponse:
"""
URL: /keys/export/<committee_name>
diff --git a/atr/get/projects.py b/atr/get/projects.py
index d57622cf..e47224ca 100644
--- a/atr/get/projects.py
+++ b/atr/get/projects.py
@@ -35,7 +35,6 @@ import atr.get.start as start
import atr.htm as htm
import atr.models.safe as safe
import atr.models.sql as sql
-import atr.models.unsafe as unsafe
import atr.post as post
import atr.registry as registry
import atr.shared as shared
@@ -47,12 +46,12 @@ import atr.web as web
@get.typed
async def add_project(
- session: web.Committer, _project_add: Literal["project/add"], committee_name: unsafe.UnsafeStr
+ session: web.Committer, _project_add: Literal["project/add"], committee_name: safe.CommitteeName
) -> web.WerkzeugResponse | str:
"""
URL: /project/add/<committee_name>
"""
- await session.check_access_committee(str(committee_name))
+ await session.check_access_committee(committee_name)
async with db.session() as data:
committee = await data.committee(name=str(committee_name)).demand(
@@ -60,20 +59,20 @@ async def add_project(
)
page = htm.Block()
- page.p[htm.a(".atr-back-link", href=util.as_url(committees.view, name=str(committee_name)))["← Back to committee"]]
+ page.p[htm.a(".atr-back-link", href=util.as_url(committees.view, name=committee.name))["← Back to committee"]]
page.h1["Add project"]
page.p[f"Add a new project to the {committee.display_name} committee."]
- committee_display_name = committee.full_name or str(committee_name).title()
+ committee_display_name = committee.full_name or committee.name.title()
form.render_block(
page,
model_cls=shared.projects.AddProjectForm,
- action=util.as_url(post.projects.add_project, committee_name=str(committee_name)),
+ action=util.as_url(post.projects.add_project, committee_name=committee.name),
submit_label="Add project",
- cancel_url=util.as_url(committees.view, name=str(committee_name)),
+ cancel_url=util.as_url(committees.view, name=committee.name),
defaults={
- "committee_name": str(committee_name),
+ "committee_name": committee.name,
},
)
@@ -81,7 +80,7 @@ async def add_project(
page.append(
htpy.div(
"#projects-add-config.d-none",
- data_committee_name=str(committee_name),
+ data_committee_name=committee.name,
data_committee_display_name=committee_display_name,
)
)
diff --git a/atr/models/safe.py b/atr/models/safe.py
index c71daf27..2f9bc0f5 100644
--- a/atr/models/safe.py
+++ b/atr/models/safe.py
@@ -86,6 +86,11 @@ class Alphanumeric(SafeType):
return _ALPHANUM
+class CommitteeName(Alphanumeric):
+ def _additional_validations(self, value: str):
+ pass
+
+
class Numeric(SafeType):
@classmethod
def _valid_chars(cls) -> frozenset[str]:
diff --git a/atr/post/projects.py b/atr/post/projects.py
index 6763bf48..f01c3117 100644
--- a/atr/post/projects.py
+++ b/atr/post/projects.py
@@ -37,7 +37,7 @@ import atr.web as web
async def add_project(
session: web.Committer,
_project_add: Literal["project/add"],
- committee_name: unsafe.UnsafeStr,
+ committee_name: safe.CommitteeName,
project_form: shared.projects.AddProjectForm,
) -> web.WerkzeugResponse:
"""
@@ -46,11 +46,10 @@ async def add_project(
display_name = project_form.display_name
label = project_form.label
- # TODO: Is this right? Name is unvalidated
async with storage.write(session) as write:
wacm = await write.as_project_committee_member(safe.ProjectName(str(committee_name)))
try:
- await wacm.project.create(str(committee_name), display_name, label)
+ await wacm.project.create(committee_name, display_name, label)
except storage.AccessError as e:
return await session.redirect(
get.projects.add_project, committee_name=str(committee_name), error=f"Error adding project: {e}"
diff --git a/atr/storage/writers/project.py b/atr/storage/writers/project.py
index 0580a2bc..cf6dbe30 100644
--- a/atr/storage/writers/project.py
+++ b/atr/storage/writers/project.py
@@ -132,15 +132,14 @@ class CommitteeMember(CommitteeParticipant):
return True
return False
- async def create(self, committee_name: str, display_name: str, label: str) -> None:
+ async def create(self, committee_name: safe.CommitteeName, display_name: str, label: str) -> None:
super_project = None
- # Wrap the name in safe.ProjectName so we can create it in the database
# TODO: Do we need to do any additional validation on the string value?
# Get the base project to derive from
# We're allowing derivation from a retired project here
# TODO: Should we disallow this instead?
committee_projects = await self.__data.project(
- committee_name=committee_name, _committee=True, _release_policy=True
+ committee_name=str(committee_name), _committee=True, _release_policy=True
).all()
for committee_project in committee_projects:
if label.startswith(str(committee_project.name) + "-"):
@@ -160,7 +159,7 @@ class CommitteeMember(CommitteeParticipant):
description=super_project.description if super_project else None,
category=super_project.category if super_project else None,
programming_languages=super_project.programming_languages if super_project else None,
- committee_name=committee_name,
+ committee_name=str(committee_name),
created=datetime.datetime.now(datetime.UTC),
created_by=self.__asf_uid,
)
@@ -172,7 +171,7 @@ class CommitteeMember(CommitteeParticipant):
await self.__data.commit()
self.__write_as.append_to_audit_log(
asf_uid=self.__asf_uid,
- committee_name=committee_name,
+ committee_name=str(committee_name),
project_name=label,
)
diff --git a/atr/web.py b/atr/web.py
index e8cbd8e0..6ef7ee9b 100644
--- a/atr/web.py
+++ b/atr/web.py
@@ -99,8 +99,8 @@ class Committer:
return
raise base.ASFQuartException("You do not have access to this project", errorcode=403)
- async def check_access_committee(self, committee_name: str) -> None:
- if committee_name not in self.committees:
+ async def check_access_committee(self, committee_name: safe.CommitteeName) -> None:
+ if str(committee_name) not in self.committees:
if self.is_admin:
# Admins can view all committees
# But we must warn them when the committee is not one of their own
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org