This is an automated email from the ASF dual-hosted git repository.
lukaszlenart pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/struts.git
The following commit(s) were added to refs/heads/main by this push:
new 9a0ea540b docs(skills): send CVE advisory mails from the ASF CVE tool
(#1851)
9a0ea540b is described below
commit 9a0ea540b5d5a4254224ae722e70083966c66c4a
Author: Lukasz Lenart <[email protected]>
AuthorDate: Sat Aug 15 06:53:18 2026 +0200
docs(skills): send CVE advisory mails from the ASF CVE tool (#1851)
Advisory mails for S2-070..S2-074 were composed and sent by hand from
Gmail. The bodies were already the CVE tool's generated text, but every
send failed at least once: one bounced for a [email protected] sender, four
bounced for carrying a text/html part, and the re-sends went out with a
hand-added [ANN] prefix.
sebb and raboof both pointed out on the S2-073 thread that these should
go through the 'Send these Emails' button on the record's OSS/ASF Emails
tab at cveprocess.apache.org, and that ASF CVE reports do not carry an
[ANN] prefix. Mail sent through the tool is moderated automatically; the
same text from a personal account waits for a human moderator.
The skill already recommended the tool's text but then documented a full
Gmail recipe underneath, so the fallback is what got used. Replace the
recommendation with an ordered recipe ending in the send button, and
demote Gmail to a conditional keyed to the button actually failing.
The reason hand-sending looked necessary was a misconfigured field:
CNA_private.userslist on the Struts records reads [email protected],
so the generated ASF mail addressed announce@ and dev@ and missed
[email protected]. Setting that one field is now step 1 of the send
and a pre-publication checklist item.
Also guard the release [ANN] mail explicitly: that prefix stays on
release announcements, and only advisory subjects drop it.
Co-authored-by: Claude Opus 5 <[email protected]>
---
.../skills/creating-security-bulletins/SKILL.md | 90 +++++++++++++++-------
.../bulletin-template.md | 2 +
.claude/skills/releasing-struts/SKILL.md | 3 +-
.claude/skills/releasing-struts/release-runbook.md | 11 ++-
4 files changed, 75 insertions(+), 31 deletions(-)
diff --git a/.claude/skills/creating-security-bulletins/SKILL.md
b/.claude/skills/creating-security-bulletins/SKILL.md
index 864908c1c..3d83e99b4 100644
--- a/.claude/skills/creating-security-bulletins/SKILL.md
+++ b/.claude/skills/creating-security-bulletins/SKILL.md
@@ -163,34 +163,66 @@ Publication is clearing them **completely** — read *and*
update, both empty, m
already-published bulletin. Verify with an unauthenticated fetch of the public
URL, not with the
API's response: the tool reporting success is not the page being readable.
-## Announcing it: the mail is text/plain, or it does not arrive
+## Announcing it: press the button on the CVE record
-Once the page is public the advisory goes to the lists. **The mail carries one
`text/plain`
-part and nothing else.** A `text/html` part is a delivery failure —
`[email protected]`
-rejects it permanently:
+Once the page is public the advisory goes out **from the CVE record**, not
from a mailbox.
+Every record on `cveprocess.apache.org` carries an *OSS/ASF Emails* tab —
+`https://cveprocess.apache.org/cve5/CVE-YYYY-NNNNN#email` — holding two
finished mails, one
+for `oss-security` and one for the ASF lists, generated from the record's own
affected
+ranges, description, credit and references. A single **`Send these Emails`**
button sits at
+the foot of the tab, and both mails point at it — *"Use the button below to
send these
+mails, or copy, paste, and send the email yourself."*
-```
-ezmlm-reject: fatal: Sorry, a message part has an unacceptable MIME
Content-Type: 'text/html' (#5.2.3)
-```
+The send is four steps, in order:
-**Do not rely on a bounce to catch it.** On the S2-070 run, 2026-08-14, one
send was rejected
-by `[email protected]` and *accepted* by `[email protected]`. The HTML
advisory reached
-the user list. A partial failure looks like success in the Sent folder.
+1. **Set `userslist` to `[email protected]`** — the field is in the
*Editor* tab, or as
+ `CNA_private.userslist` on the *Source* tab, which accepts the record as
raw JSON. It is
+ labelled *"This is your project list such as users@ where you also want
security
+ announcement emails go to"*, and it is what puts the Struts user list on
the ASF mail.
+2. **`SAVE`.** The mails are regenerated from the saved record, not from the
form.
+3. **Re-read both mails on the *OSS/ASF Emails* tab.** They are the
deliverable — read them
+ as closely as you read the bulletin.
+4. **Press `Send these Emails`.**
+
+**Take the subject the tool generates, unedited** — `CVE-YYYY-NNNNN: Apache
Struts: <title>`.
+No `[ANN]` prefix: that prefix belongs to *release* announcements, and ASF CVE
reports do not
+carry it. No `- S2-XXX` suffix either; the bulletin reaches readers as a
`References:` line.
+
+**Why the button rather than a mailbox.** Mail sent through the tool is
moderated
+automatically, while the same text from a personal account waits for a human
moderator. It
+also cannot get the `text/plain` contract or the sender identity wrong — which
is the entire
+class of failure below.
+
+Both points are sebb's, on the S2-073 announcement thread, 2026-08-14.
-Two unrelated defects bounced that morning, each from a different list:
+**Expect a delay either way, and do not read it as a failed send.** The tab
warns that
+*"ASF announcement mailing lists are moderated. It may take some hours/days
before your
+email will be published."* Silence on the archives an hour later is
moderation, not a
+bounce.
-| Defect | What the list says |
+### The failure this replaces
+
+On 2026-08-14 all five advisories were sent by hand from Gmail. Every one
failed at least
+once:
+
+| Send | Outcome |
|---|---|
-| A `text/html` part | `unacceptable MIME Content-Type: 'text/html' (#5.2.3)` |
-| Wrong sender identity | `Must be sent from an @apache.org address.` |
+| S2-070, from the personal Gmail identity | Bounced — `Must be sent from an
@apache.org address.` |
+| S2-071…074, to `user@` with `announce@` in Cc/Bcc | Bounced — `unacceptable
MIME Content-Type: 'text/html' (#5.2.3)` |
+| The re-sends, to `announce@` alone | Delivered, subjects hand-prefixed
`[ANN] ` |
+
+The *bodies* were already the tool's generated text. Only the **sending** was
hand-rolled,
+and every one of those failures came from the sending. `CNA_private.emailed`
on those
+records is still `null`.
-**The CVE tool generates both mails — use them.** Each record on
`cveprocess.apache.org` has an
-*OSS/ASF Emails* tab holding a finished `oss-security` mail and a finished
ASF-lists mail, built
-from the record's own affected ranges, description, credit and references,
with send buttons
-that go through ASF infrastructure rather than a personal mailbox. Copying
that text is how the
-mail stays consistent with the CVE record; composing a fresh one is how the
two drift.
+**A bounce is not a reliable alarm.** That morning one HTML send was rejected
by
+`[email protected]` and *accepted* by `[email protected]`. The HTML
advisory reached
+the user list. A partial failure looks like success in the Sent folder.
+
+### If the button is genuinely unavailable
-If you draft in Gmail instead, the deliverable is three things and is
incomplete without any:
+Only when the button itself fails — it errors, or the record will not save.
Moderation delay
+is not unavailability. Then the mail is three things and is incomplete without
any:
1. A draft with To, Bcc, Subject and `body`. **Never `htmlBody`** — and
passing `body` alone
does not make the mail plain text; Gmail generates the HTML part itself on
send.
@@ -198,12 +230,9 @@ If you draft in Gmail instead, the deliverable is three
things and is incomplete
3. The sending instruction in your handover: **plain-text mode on** (⋮ →
*Plain text mode*),
paste the file over the body, send from the `@apache.org` identity.
-The `oss-security` copy is a separate mail with no Cc and no Bcc — not the ASF
mail with an
-extra recipient.
-
-**Recipients are not interchangeable.** The tool's ASF mail addresses
`[email protected]` and
-`dev@`; Struts practice adds `[email protected]`, which is the list
operators actually
-read. `[email protected]` takes only `@apache.org` senders.
+Copy the recipients and subject off the tool's tab rather than composing them.
The
+`oss-security` copy is a separate mail with **no Cc and no Bcc** — not the ASF
mail with an
+extra recipient — and `[email protected]` accepts only
`@apache.org` senders.
## Start from the template, never from a previous bulletin
@@ -237,7 +266,9 @@ Read the whole page and rewrite it; do not patch the fields
you happen to notice
- Publishing without re-checking restrictions
- Treating an API success as proof the page is publicly readable
- `htmlBody` passed to the draft tool, for any reason
-- An announcement composed from scratch when the CVE record's *OSS/ASF Emails*
tab holds one
+- An advisory sent from a mailbox while the record's `Send these Emails`
button is available
+- `Send these Emails` pressed before `userslist` is set to
`[email protected]` and saved
+- `[ANN]`, an S2-XXX suffix, or any other hand-edit to the subject the tool
generated
- A draft handed over without the plain-text-mode instruction and the body file
- A severity rating chosen by feel, or by reachability alone, without checking
it against the published scale
- Rating something Low because the feature is opt-in — opt-in is the
definition of Moderate
@@ -263,4 +294,7 @@ Read the whole page and rewrite it; do not patch the fields
you happen to notice
| "I read the page a few minutes ago" | Someone else may have written to it
since. Re-fetch, then write. There is no conflict warning. |
| "I passed `body`, not `htmlBody`, so it's plain text" | Gmail generates the
HTML part itself on send. The format is decided in the compose window. |
| "It reached the lists, so the format was fine" | One list accepted the same
message another rejected. Check every recipient, not the Sent folder. |
-| "Writing the mail myself is quicker than opening the CVE tool" | The tool's
text is generated from the record. Hand-written text is how the mail and the
CVE drift apart. |
+| "I copied the tool's text, so the mail is fine" | The text was never what
failed. Sending by hand is. Press the button. |
+| "The tool doesn't mail `user@`, so I'll send it myself" | It does once
`userslist` says so. One field on the record, not a parallel process. |
+| "`[ANN]` marks it as an announcement" | ASF CVE reports don't carry it. The
tool's subject *is* the subject. |
+| "Sending it myself is quicker than pressing the button" | It is slower end
to end: a personal-account mail waits for a human moderator, the tool's does
not. |
diff --git a/.claude/skills/creating-security-bulletins/bulletin-template.md
b/.claude/skills/creating-security-bulletins/bulletin-template.md
index abb1efde5..d50524dea 100644
--- a/.claude/skills/creating-security-bulletins/bulletin-template.md
+++ b/.claude/skills/creating-security-bulletins/bulletin-template.md
@@ -117,6 +117,8 @@ but make it deliberately and record which way you went.
now, not at drafting time.
- [ ] The fixed release is out and accepted.
- [ ] Restrictions are lifted only at the coordinated publication moment.
+- [ ] The CVE record's `CNA_private.userslist` reads `[email protected]`
and is saved,
+ so `Send these Emails` on the *OSS/ASF Emails* tab reaches the Struts
user list.
## Storage-format skeleton
diff --git a/.claude/skills/releasing-struts/SKILL.md
b/.claude/skills/releasing-struts/SKILL.md
index 687dbddbb..4435c3bf8 100644
--- a/.claude/skills/releasing-struts/SKILL.md
+++ b/.claude/skills/releasing-struts/SKILL.md
@@ -35,7 +35,7 @@ fix them in a PR to `apache/struts-site`. Only what is
genuinely agent-specific
| 4 | Vote | 72 h elapsed, three binding `+1`, result mail sent |
| 5 | Promote | Nexus repo released, `dist/dev` → `dist/release`, 24 h rsync
waited |
| 6 | Publish | Site PR merged, GitHub release un-flagged, `[ANN]` mail
delivered |
-| 7 | Advisories | Bulletins public, CVE records filled, advisory mails
delivered |
+| 7 | Advisories | Bulletins public, CVE records filled, advisory mails sent
from the CVE tool |
Phase 7 only exists when the release carries a security fix, and *publishing*
the advisory is
**strictly after** phase 6 — see *Security work is a separate clock* below.
Writing the bulletin
@@ -147,6 +147,7 @@ answer is the last release, not the last wiki revision.
| "The vote passed, so it's released" | Nexus release, dist move and the
mirror wait all come after. |
| "I'll announce now and fix the site after" | The announcement links the
site. Merge the site PR first. |
| "The 6.x fix is the same change, so one announcement covers both" | Two
artifacts, two downloads, two sets of affected users. |
+| "The advisory is an announcement, so it gets `[ANN]` too" | `[ANN]` is for
releases. CVE reports take the CVE tool's subject unedited. |
| "The pom says 7.3.1-SNAPSHOT, so this is 7.3.1" | The placeholder is not a
decision. Semver impact decides. |
| "The process is documented in this skill" | It is documented on the site.
This skill adds ordering, ownership and hand-offs. |
| "I found the release steps on the wiki" | Those pages are stubs now. Their
history is the 2013–2017 process. |
diff --git a/.claude/skills/releasing-struts/release-runbook.md
b/.claude/skills/releasing-struts/release-runbook.md
index acece3284..e62fb998b 100644
--- a/.claude/skills/releasing-struts/release-runbook.md
+++ b/.claude/skills/releasing-struts/release-runbook.md
@@ -88,6 +88,9 @@ step: several supported versions from both lines are normally
kept.
## Phase 6 — Publish
+**The `[ANN]` prefix belongs to this mail, not to advisories.** Release
announcements keep it;
+CVE advisory subjects do not — see phase 7.
+
**The `[ANN]` mail must be `text/plain`, and a draft made with the Gmail tool
is an HTML draft
whatever you pass it.** `[email protected]` rejects any message carrying a
`text/html` part —
@@ -102,5 +105,9 @@ accepting the mail is not evidence the format was right.
## Phase 7 — Advisories
**`creating-security-bulletins`** owns all of it: unrestricting the bulletin,
the CVE record on
-<https://cveprocess.apache.org>, and the advisory mails from that record's
*OSS/ASF Emails* tab.
-Follow that skill from here; it is not a step in this runbook.
+<https://cveprocess.apache.org>, and the advisory mails. Follow that skill
from here; it is not
+a step in this runbook.
+
+**The mails are sent by the `Send these Emails` button** on the record's
*OSS/ASF Emails* tab,
+not from a mailbox, and the subject the tool generates carries no `[ANN]`.
That skill owns the
+detail, including the `userslist` field the button depends on.