asf-tooling commented on issue #1246:
URL:
https://github.com/apache/tooling-trusted-releases/issues/1246#issuecomment-4495904406
<!-- gofannon-issue-triage-bot v2 -->
**Automated triage** — analyzed at `main@ab610b23`
**Type:** `discussion` • **Classification:** `no_action` •
**Confidence:** `high`
**Application domain(s):** `distribution_and_publishing`,
`notification_and_messaging`, `release_workflow`
### Summary
This issue requests per-phase configurable mailing recipients in the release
workflow (vote, vote results, announcement). Currently the announce step
already allows recipient selection (email_to, email_cc, email_bcc in
AnnounceForm), but the vote-results step apparently doesn't have independent
recipient configuration. @dave2wave explicitly stated 'Let's discuss this later
this week', indicating the team wants to discuss the approach before any
implementation work begins. No diffs should be proposed at this stage.
### Where this lives in the code today
#### `atr/shared/announce.py` — `AnnounceForm` (lines 27-48)
_currently does this_
The announce form already has email_to, email_cc, email_bcc fields showing
recipient configuration is supported at the announcement phase.
```python
class AnnounceForm(form.Form):
"""Form for announcing a release preview."""
revision_number: safe.RevisionNumber = form.label("Revision number",
widget=form.Widget.HIDDEN)
email_to: str = form.label("To", widget=form.Widget.CUSTOM)
email_cc: form.StrList = form.label("CC")
email_bcc: form.StrList = form.label("BCC")
subject: str = form.label("Subject", widget=form.Widget.CUSTOM)
subject_template_hash: str = form.label("Subject template hash",
widget=form.Widget.HIDDEN)
body: str = form.label("Body", widget=form.Widget.CUSTOM,
max_length=100_000)
download_path_suffix: safe.OptionalRelPath = form.label("Download path
suffix", widget=form.Widget.CUSTOM)
auto_archive: form.Bool = form.label(
"Auto archive prior release",
"If set, the release shown below will be auto-archived",
widget=form.Widget.CHECKBOX,
default=False,
)
auto_archive_release: str = form.label("Version to archive",
widget=form.Widget.STATIC, default="")
confirm_announce: Literal["CONFIRM"] = form.label(
"Confirm",
"Type CONFIRM (in capitals) to enable the submit button.",
)
```
#### `atr/storage/writers/announce.py` — `CommitteeMember.release` (lines
106-123)
_currently does this_
The writer that actually sends the announcement email accepts recipient
parameters, validating them against permitted recipients.
```python
async def release( # noqa: C901
self,
project_key: safe.ProjectKey,
version_key: safe.VersionKey,
preview_revision_number: safe.RevisionNumber,
email_to: str,
body: str,
download_path_suffix: safe.RelPath | None,
fullname: str,
subject_template_hash: str | None = None,
email_cc: list[str] | None = None,
email_bcc: list[str] | None = None,
) -> None:
permitted = util.permitted_announce_recipients(self.__asf_uid)
all_addrs = [email_to] + (email_cc or []) + (email_bcc or [])
for addr in all_addrs:
if addr not in permitted:
raise storage.AccessError(f"You are not permitted to send
announcements to {addr}", status=403)
```
#### `atr/construct.py` — `StartVoteOptions` (lines 128-135)
_currently does this_
The vote start options dataclass shows the vote initiation path exists but
doesn't include recipient configuration in the template options (recipients are
handled separately in the vote start form).
```python
@dataclasses.dataclass
class StartVoteOptions:
asfuid: str
fullname: str
project_key: safe.ProjectKey
version_key: safe.VersionKey
revision_number: safe.RevisionNumber
vote_duration: int
```
#### `atr/tasks/message.py` — `send` (lines 30-53)
_currently does this_
The message send task handles all email sending via the task queue,
enforcing that recipients must be apache.org addresses. Any new per-phase
recipient configuration would ultimately go through this path.
```python
@checks.with_model(args.Send)
async def send(task_args: args.Send) -> results.Results | None:
if "@" not in task_args.email_sender:
log.warning(f"Invalid email sender: {task_args.email_sender}")
sender_asf_uid = task_args.email_sender
elif task_args.email_sender.endswith("@apache.org"):
sender_asf_uid = task_args.email_sender.split("@")[0]
else:
raise SendError(f"Invalid email sender: {task_args.email_sender}")
sender_account = await ldap.account_lookup(sender_asf_uid)
if sender_account is None:
raise SendError(f"Invalid email account: {task_args.email_sender}")
if ldap.is_banned(sender_account):
raise SendError(f"Email account {task_args.email_sender} is banned")
all_recipients = [task_args.email_to, *task_args.email_cc,
*task_args.email_bcc]
for addr in all_recipients:
recipient_domain = addr.split("@")[-1]
sending_to_self = addr == f"{sender_asf_uid}@apache.org"
# audit_guidance we intentionally allow users to send messages to
committees they are not a part of
sending_to_committee = recipient_domain.endswith(".apache.org")
if not (sending_to_self or sending_to_committee):
raise SendError(f"You are not permitted to send emails to
{addr}")
```
### Where new code would go
- `atr/models/sql.py` — after symbol ReleasePolicy or ProjectReleasePolicy
Per-phase default recipients would likely be stored as project/release
policy fields (e.g., policy_vote_recipients, policy_result_recipients,
policy_announce_recipients).
- `atr/shared/vote_result.py or atr/shared/vote.py` — new file or existing
vote form
A form for vote results would need recipient fields similar to
AnnounceForm if the vote-result step gets configurable recipients.
### Proposed approach
This issue is in early discussion phase — @dave2wave requested a team
discussion later in the week. The feature would involve: (1) adding per-phase
default recipient configuration to the project or release policy model in the
database, (2) presenting those defaults in each phase's form (vote start, vote
result, announcement), and (3) allowing users to adjust recipients at each step
independently. The announce step already supports this via AnnounceForm; the
vote-start step likely does too. The main gap appears to be the vote-results
step and possibly storing project-level defaults for each phase.
Since the team has explicitly deferred this to a design discussion, no
implementation should be proposed at this time.
### Open questions
- What is the current recipient handling for the vote-results email step?
(The vote result sender code was not in the provided files.)
- Should per-phase defaults be stored at the project level (in
ProjectReleasePolicy) or the release level?
- Should each phase have a 'permitted recipients' list that differs from the
other phases, or should all phases share the same permitted list with different
defaults?
- How does this relate to referenced issue #826?
- The team discussion hasn't happened yet — any implementation should wait
for the design conversation @dave2wave proposed.
_The agent reviewed this issue and is not proposing patches in this run.
Review the existing-code citations and open questions above before deciding
next steps._
### Files examined
- `atr/construct.py`
- `atr/post/announce.py`
- `atr/shared/announce.py`
- `atr/storage/writers/announce.py`
- `atr/get/announce.py`
- `atr/mail.py`
- `atr/storage/writers/mail.py`
- `atr/tasks/message.py`
---
*Draft from a triage agent. A human reviewer should validate before merging
any change. The agent did not run tests or verify diffs apply.*
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]