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-site.git
The following commit(s) were added to refs/heads/main by this push:
new a4cb2e935 docs: rewrite the release guidelines as the current release
process (#324)
a4cb2e935 is described below
commit a4cb2e935b0c959b1eb244a044eb9dce90ee996d
Author: Lukasz Lenart <[email protected]>
AuthorDate: Fri Aug 14 13:27:30 2026 +0200
docs: rewrite the release guidelines as the current release process (#324)
The Release Process section described a process that has not been run in
years: an Ant "release" target, Cactus tests, a test build posted to
svn.apache.org/struts/, and a release plan on wiki.apache.org. The only
end-to-end description of how a release is actually made was the cwiki
page "Building Struts 2 - Normal release", last revised in 2017, which
is right about JIRA, the release plugin, Nexus and dist.apache.org and
wrong about everything downstream from there.
Replace it with the seven-phase process the 7.3.0 and 6.11.0 releases
were made with - prepare, cut, stage, vote, promote, publish, advisories
- each with a gate that someone other than the release manager can
verify, and with the commands needed at each step. Notably: releases are
cut on a release/X.Y.Z-RC1 branch rather than on the line branch, the
maven-release-plugin takes no command-line flags now that they live in
the pom, the SCM tag prompt needs STRUTS_X_Y_Z typed by hand, and the
site update is a pull request rather than an svn commit to a production
checkout that no longer exists.
Drop the Coding Conventions and Clarifications sections in favour of a
pointer to the coding standards page, which covers the same ground and
is maintained.
This page is now the source of truth for the process; the cwiki pages
will be replaced with pointers to it.
Co-authored-by: Claude Opus 5 <[email protected]>
---
source/release-guidelines.md | 490 ++++++++++++++++++++++++++++++++++---------
1 file changed, 396 insertions(+), 94 deletions(-)
diff --git a/source/release-guidelines.md b/source/release-guidelines.md
index ef3611478..97f78c92b 100644
--- a/source/release-guidelines.md
+++ b/source/release-guidelines.md
@@ -9,104 +9,406 @@ title: Release Guidelines
* Will be replaced with the ToC, excluding a header
{:toc}
-This document describes the Apache Struts release process and our [coding
conventions](#Coding),
-which are applicable to all subprojects. Both stable and development releases
are
-[available for download.](releases)
+This document describes how an Apache Struts release is made: the policy that
governs it, the
+seven phases it runs through, and the command needed at each step. It is
written for the release
+manager, but every committer is encouraged to read it — releases are easier
when more than one
+person knows what the next step is.
-## Release Process
+This page is the source of truth for the release process. Where an older wiki
page disagrees
+with it, this page is current. For coding conventions see [Coding
standards](coding-standards),
+and for building the framework day to day see [Builds](builds).
+
+## Release policy
A [point release](http://commons.apache.org/releases/versioning) should be
made before and after
-any product change that is not a "fully-compatible change" (see link). This
includes moving a dependency from
-an internal package to an external product, including products distributed
through the Apache Commons.
-We should place any fully-compatible changes in the hands of the community
before starting on a change that
-is only "interface" or "external-interface" compatible.
-
-Additional remarks:
-
-- Every committer is encouraged to participate in the release process, either
as the release manager or a
- helper. Committers may also share the release manager role.
-- The release process can seem daunting when you review it for the first time.
But, essentially, it breaks
- down into four phases of just a few steps each:
- - **Rolling** - Issues, dependencies, release notes, JAR manifest, licenses,
copyrights,
- and build (using the release target).
- - **Testing** - JUnit, Cactus, web apps (for all "supported" containers).
- - **Voting** - Upload test build to internal directory, post majority vote
on DEV list as to release
- grade: Alpha, Beta, General Availability.
- - **Distributing** - Checksum, sign, mirror, update download page, announce.
-- Committers are **required** to post a release plan before tagging the
repository and should wait
- the traditional 72 hours before proceeding.
-- A checklist format can be used for the [release
plan](http://wiki.apache.org/struts/StrutsReleasePlans),
- to help step through the process. The plan may be maintained in the
repository or on the
- [Struts wiki](http://wiki.apache.org/struts/).
-- Our dependencies on external JARs (including Commons JARs) should be in line
with our own release status.
- Our nightly build can be dependant on another nightly build. Our beta can be
dependant on another beta (or
- "release candidate"), but should avoid a dependance on a nightly build. Our
General Availability release
+any product change that is not a "fully-compatible change" (see link). We
should place any
+fully-compatible changes in the hands of the community before starting on a
change that is only
+"interface" or "external-interface" compatible.
+
+- Every committer is encouraged to participate in the release process, either
as the release
+ manager or a helper. Committers may also share the release manager role.
+- Our dependencies should be in line with our own release status. A General
Availability release
may only have dependencies on other GA, final, or stable releases.
-- Use your own discretion as to detail needed by the Release Notes. A
high-level description of the changes
- is more important than providing uninterpreted detail. At a minimum, new
features and deprecations should be
- summarized, since these are commonly asked questions. Ideally, the release
notes should be maintained,
- continuously for the nightly build so that we they do not need to be
assembled at the last minute.
-- Try building the distribution under prior version of J2SE, if possible, to
ensure that we are still
- backwardly-compatible. But, our distributions should be built using the
**latest production release of J2SE**,
- to take advantage of all available compiler enhancements.
-- If you have multiple J2SE versions configured, run the JUnit and Cactus
tests using the same configuration
- that will be used to build the distribution.
-- There is a "release" target in the buildfile that will zip and tar the
distribution. Before uploading the
- distribution, extract the sample web applications and deploy the WARs under
each of the "supported"
- containers (if you can). Play test each application under each container to
be sure they operate
- nominally.
-- The test build can be posted to the internal distribution directory
(svn.apache.org/struts/) and
- announced to the Struts DEV and PMC lists (only!). Do not announce a test
build on any other Apache lists or
- link to it from an Apache website.
-- If the test build is voted to Alpha, Beta, or GA status, the release can
announced to the User list and
- linked from the website.
+- Provide high-level API compatibility for any changes made within the same
major release series
+ (`#.x.x`). Changes which adversely affect compatibility should be slotted
for the next major
+ release series.
+- Use your own discretion as to the detail needed in the Version Notes. A
high-level description
+ of the changes is more important than uninterpreted detail. At a minimum,
new features and
+ deprecations should be summarised, since these are commonly asked questions.
- Any formal release may be submitted for mirroring. All GA releases **must**
be mirrored.
-- After announcing a release, remember to update the Downloads and
Announcements pages. If the release is
- to be mirrored, wait at least 24 hours after submittal before making public
announcements (as stated in the
- [Apache Mirroring guidelines](https://www.apache.org/dev/mirrors).
-- If a serious flaw if found in a test build or release, it may be withdrawn
by a majority vote of the PMC and
- removed from ASF distribution channels.
-
-## Coding Conventions and Guidelines
-
-Source code and documentation contributed to the Struts repositories should
observe the:
-- The ["Code Conventions for the Java Programming
Language"](http://www.oracle.com/technetwork/java/codeconvtoc-136057),
- as published by Oracle.
-
-## Clarifications
-- First, "Observe the style of the original". Resist the temptation to make
stylistic changes for their own
- sake. But, if you must reformat code, commit style changes separately from
code changes. Either change
- the style, commit, and then change the code, or vice-versa.
-- Set editors to replace tabs with spaces and do not trim trailing spaces.
Tabs confound the version
- control alerts. Trimming trailing spaces creates unnecessary changes.
-- Specify imported classes (do not use _.*_).
-- Write all if/else statements as full blocks with each clause within braces,
unless the entire statement fits
- on the same line.
-- Use `FIXME:` and `TODO:` tokens to mark follow up notes in code. You may also
- include your Apache username and the date.
-- Omit `@author` tags.
-- `@since` to document changes between Struts versions, as in `@since Struts
2.1.`
-- Wrap lines of code and JavaDoc at column 78. You can include a "comment
rule" in the source to help with
- this.
-- Please do your best to provide high-quality Javadocs for all source code
elements. Package overviews
- (aka "Developer Guides") are also encouraged.
-- When working on a bugfix, please first write a test case that proves the bug
exists, and then use the test
- to prove the bug is fixed. =:0)
-- When working on an enhancement, please feel free to use test-driven design
and write the test first `<head-slap/>`
-- As files are updated from year to year, the copyright on each file should be
extended to include the current
- year. *You do not need to change the copyright year unless you change the
file.* Every source file should
- include the ASF copyright notice and current Apache License and copyright.
-- Provide high-level API compatibility for any changes made within the same
major release series (#.x.x).
- Changes which adversely affect compatibility should be slotted for the next
major release series (++#.x.x).
-- Our favorite books about programming are
- [Design
Patterns](http://www.amazon.com/exec/obidos/ISBN=0201633612/apachesoftwar-20/),
-
[Refactoring](http://www.amazon.com/exec/obidos/ISBN=0201485672/apachesoftwar-20/),
- and [Code
Complete](http://www.amazon.com/exec/obidos/ISBN=0735619670/apachesoftwar-20/)
-- Our favorite book about open source development is the
- [The Cathedral and the
Bazaar](http://www.amazon.com/exec/obidos/ISBN=1565927249/apachesoftwar-20/)
-- Our favorite science fiction author is
- [Robert Heinlein](http://www.nitrosyncretic.com/rah/),
- [TANSTAAFL](http://jargon.net/jargonfile/t/TANSTAAFL),
- (Except on Friday, when we favor [Douglas
Adams](http://news.bbc.co.uk/1/hi/uk/1326657.stm)).
+- If a serious flaw is found in a release candidate or a release, it may be
withdrawn by a
+ majority vote of the PMC and removed from ASF distribution channels.
+
+## Before you start
+
+### Two lines mean two releases
+
+`main` is the 7.x line and `support/struts-6-x-x` is the 6.x line. Both are
protected in
+`.asf.yaml` and both must be green before you start.
+
+| Line | Branch | Build check that must pass | JDK |
+|---|---|---|---|
+| 7.x | `main` | `Build and Test (JDK 17)` | 17 |
+| 6.x | `support/struts-6-x-x` | `Build and Test (8)` | 8 |
+
+A change that lands on both lines is **two releases** — each with its own tag,
vote, site entry
+and announcement, not one release mentioned twice. They can be cut and voted
in parallel, and
+usually are, but keep the version numbers independent: 6.11.0 and 7.3.0
shipped on the same day
+and share nothing but a date.
+
+### Check the JDK before building anything
+
+The whole release is produced by whichever JDK happens to be active in your
shell, and the line
+dictates which one that must be. Cutting 6.x on JDK 17 produces artifacts that
will not run for
+the users that line exists for.
+
+```bash
+mvn -v # reports the JDK Maven is actually using, not just $JAVA_HOME
+```
+
+{:.alert .alert-warning}
+If it reports the wrong version, stop and switch before going any further.
+
+### The version number is decided at release time
+
+The `-SNAPSHOT` in the pom is a placeholder, not a decision. Pick the number
from the semantic
+versioning impact of what actually landed since the last tag, and state it
before cutting — the
+tag is the first irreversible act of the release.
+
+The pom cannot tell you what the number is. Because releases are cut on a side
branch, the root
+pom on `main` still read `7.2.2-SNAPSHOT` after 7.3.0 had shipped.
+
+### What you need access to
+
+- A committer account with your Apache and GitHub accounts linked in
+ [GitBox](https://gitbox.apache.org/setup/).
+- A code signing key published in
+ [`KEYS`](https://dist.apache.org/repos/dist/release/struts/KEYS) and in the
ASF web of trust.
+- ASF credentials for `dist.apache.org` (Subversion) and for
+ [Nexus](https://repository.apache.org/).
+
+## The seven phases
+
+A release is seven phases with a gate between each. A phase is finished when
its gate is
+verifiable by someone other than you: "I ran the command" is not a gate, "the
URL resolves" is.
+
+| # | Phase | Gate before moving on |
+|---|---|---|
+| 1 | [Prepare](#phase-1--prepare) | Branch green, version decided, parent
poms released |
+| 2 | [Cut](#phase-2--cut) | Tag pushed, artifacts in a **closed** Nexus
staging repository |
+| 3 | [Stage](#phase-3--stage) | Assemblies in `dist/dev`, Version Notes page
live, `[TEST]` mail sent |
+| 4 | [Vote](#phase-4--vote) | 72 hours elapsed, three binding `+1`, result
mail sent |
+| 5 | [Promote](#phase-5--promote) | Nexus repository released, `dist/dev` →
`dist/release`, 24 hour rsync waited |
+| 6 | [Publish](#phase-6--publish) | Site updated, GitHub release un-flagged,
`[ANN]` mail delivered |
+| 7 | [Advisories](#phase-7--security-advisories) | Bulletins public, CVE
records filled, advisory mails delivered |
+
+Phase 7 exists only when the release carries a security fix, and it is
strictly the last thing
+that happens — see [Security advisories](#phase-7--security-advisories).
+
+## Phase 1 — Prepare
+
+Start from a clean, up-to-date checkout of the line you are releasing and
confirm it builds.
+
+```bash
+git checkout main && git pull --ff-only
+mvn clean install -DskipAssembly
+```
+
+Then:
+
+- Decide the version number from its semantic versioning impact. Do not read
it off the
+ `-SNAPSHOT`.
+- Confirm that `struts-master` and `struts-annotations` are released versions,
not snapshots. The
+ root pom's `<parent>` must not point at a snapshot.
+- Review JIRA: every issue fixed since the last tag has a fix version set, and
nothing unresolved
+ carries the version you are about to release.
+- Release the version in JIRA once the last issue is closed, and add the next
version to the
+ roadmap.
+
+The BOM needs no version synchronisation. `bom/pom.xml` inherits the root
version through its
+`<parent>` and declares its members as `${project.version}`.
+
+## Phase 2 — Cut
+
+### Cut from a release branch, not from the line branch
+
+```bash
+git checkout -b release/7.3.0-RC1 main # or off support/struts-6-x-x for
the 6.x line
+git push -u origin release/7.3.0-RC1
+```
+
+The two `[maven-release-plugin]` commits land on that branch and the line
branch is never
+touched. A failed vote is then a deleted branch rather than a revert.
+
+### Prepare and perform
+
+```bash
+mvn release:prepare
+```
+
+No flags. `autoVersionSubmodules` is configured in the root pom, alongside the
ASF parent's
+`useReleaseProfile=false`, `goals=deploy` and
`releaseProfiles=apache-release`. If you find
+yourself passing `-D` to the release plugin, the setting belongs in the pom
instead — a flag that
+has to be remembered is a flag that will be forgotten.
+
+{:.alert .alert-warning}
+At the SCM tag prompt, type `STRUTS_X_Y_Z`. The plugin's default is derived
from the root
+artifactId and is wrong; every Struts tag in history uses the underscore form,
and the GitHub
+release, the Version Notes and the website all assume it.
+
+For a [dry
run](http://maven.apache.org/plugins/maven-release-plugin/usage.html) add
+`-DdryRun=true`, then `mvn release:clean` before the real run. If the command
fails part way
+through, re-run it as is: `-Dresume` defaults to true and it picks up where it
stopped.
+
+The result is two commits on the release branch — `[maven-release-plugin]
prepare release
+STRUTS_X_Y_Z` and `[maven-release-plugin] prepare for next development
iteration` — plus the tag.
+
+```bash
+mvn release:perform
+```
+
+`retryFailedDeploymentCount` is configured on `maven-deploy-plugin` in the
root pom, not passed
+here. It has to be in the pom to work at all: `release:perform` forks a fresh
Maven build, and
+that fork does not inherit `-D` properties from the outer invocation.
+
+If you need to run the deployment again, or from a different machine:
+
+```bash
+git checkout STRUTS_X_Y_Z
+mvn javadoc:javadoc deploy -DperformRelease=true -Papache-release
+```
+
+### Close the staging repository
+
+Log in to [Nexus](https://repository.apache.org/), then **Staging
Repositories** → select the
+repository → **Close**.
+
+{:.alert .alert-warning}
+A successful `release:perform` leaves the repository *open*, and an open
repository serves
+nothing under the staging group URL. Until it is closed, every link in the
Version Notes resolves
+to nothing and no one can test the build.
+
+The gate is that the artifacts resolve under:
+
+```
+https://repository.apache.org/content/groups/staging/org/apache/struts/struts2-core/$VERSION/
+```
+
+The staging repository is keyed by user *and* public IP address. If your
address changed mid
+release you will have two of them; check the dates and drop the stale one.
+
+## Phase 3 — Stage
+
+To make the build testable, the assemblies are moved out of Nexus into
+`https://dist.apache.org/repos/dist/dev/struts/$VERSION`. The steps are
scripted in
+[`stage-assemblies.sh`](https://github.com/apache/struts/blob/main/.claude/skills/releasing-struts/scripts/stage-assemblies.sh);
+run it from a scratch directory, since it creates `./$VERSION` and a temporary
Subversion working
+copy in the current directory.
+
+```bash
+cd "$(mktemp -d)"
+VERSION=7.3.0 /path/to/stage-assemblies.sh
+```
+
+It fetches the `zip`, `md5`, `sha1` and `asc` files from the closed staging
repository, strips
+the `2-assembly` infix from their names, drops the `.pom` files and the legacy
`md5`/`sha1`
+hashes, generates `.sha256` and `.sha512` locally, prints what it is about to
publish, and then
+commits the directory to `dist/dev/struts`. In outline:
+
+```bash
+wget -erobots=off -nv -l 1 --accept=zip,md5,sha1,asc -r -nd -nH \
+
https://repository.apache.org/content/groups/staging/org/apache/struts/struts2-assembly/$VERSION
+for f in *2-assembly*.zip*; do mv "$f" "$(echo "$f" | sed s/2-assembly//g)";
done
+rm -f struts2-assembly-*.pom* ./*.md5 ./*.sha1
+for f in *.zip; do shasum -a 256 "$f" > "$f.sha256"; shasum -a 512 "$f" >
"$f.sha512"; done
+svn --no-auth-cache co --depth empty
https://dist.apache.org/repos/dist/dev/struts/ struts-dev
+mv $VERSION struts-dev/ && cd struts-dev
+svn add --force ./
+svn --no-auth-cache commit -m "Updates test release $VERSION"
+```
+
+The gate is `https://dist.apache.org/repos/dist/dev/struts/$VERSION/`, holding
**six** assemblies
+— `struts-$VERSION-all.zip`, `-apps.zip`, `-docs.zip`, `-lib.zip`,
`-min-lib.zip` and `-src.zip`
+— each with an `.asc`, `.sha256` and `.sha512` beside it: 24 files, no `.md5`,
no `.sha1`, no
+`.pom`. `KEYS` lives one level up, in `dist/release/struts/`.
+
+{:.alert .alert-warning}
+Count the files. The script stops on a step that fails, not on a download that
quietly returns a
+subset, so a short upload can reach `dist/dev` looking healthy.
+
+The rest of this phase is paperwork:
+
+- Create the **Version Notes** page in the wiki for the new version, linking
the previous notes in
+ the series, the JIRA issues fixed, and the staging repository, and link it
from the
+ [Migration
Guide](https://cwiki.apache.org/confluence/display/WW/Migration+Guide).
+- Create the **GitHub release** for the tag, flagged as a **prerelease**.
+- Send a `[TEST]` mail to `[email protected]` and
`[email protected]` announcing that the
+ build is available, and give people time to test the actual bits.
+
+## Phase 4 — Vote
+
+Post a release/quality vote to the dev list and only the dev list.
+
+```
+To: [email protected]
+Bcc: [email protected]
+```
+
+Never `user@`. `private@` is copied so that binding voters see the thread.
+
+The vote runs for a **minimum of 72 hours** and needs **three binding `+1`**
votes; PMC members'
+votes are the binding ones. Close the vote with a result mail on the same
thread.
+
+If the vote fails, delete the release branch and start again from phase 1 with
a new version
+number. Nothing that has been published so far is promoted.
+
+## Phase 5 — Promote
+
+Move the assemblies from `dist/dev` to `dist/release`. This is the point at
which they start
+replicating to the mirrors. The step is scripted in
+[`promote-dist.sh`](https://github.com/apache/struts/blob/main/.claude/skills/releasing-struts/scripts/promote-dist.sh):
+
+```bash
+svn mv https://dist.apache.org/repos/dist/dev/struts/$VERSION/ \
+ https://dist.apache.org/repos/dist/release/struts/ \
+ -m "Release Struts $VERSION"
+```
+
+Then log in to [Nexus](https://repository.apache.org/) again and **release**
the staging
+repository, which replicates the artifacts to Maven Central. See
+[Releasing a Maven-based
project](http://maven.apache.org/developers/release/apache-release.html)
+for further details.
+
+Old releases may be removed from `dist/release/struts/` to keep the mirror set
small; everything
+removed stays available from
[archive.apache.org](https://archive.apache.org/dist/struts/).
+Decide deliberately which versions to keep — in practice several supported
versions from both
+lines are kept — and do not prune on autopilot.
+
+```bash
+svn del https://dist.apache.org/repos/dist/release/struts/$OLD_VERSION/ -m
"Removing old release"
+```
+
+{:.alert .alert-danger}
+Wait **24 hours** after the move before anything in phase 6. This is the ASF
mirroring
+requirement, and announcing into an unmirrored release sends everyone to a 404.
+
+## Phase 6 — Publish
+
+### Update the website
+
+The site is [apache/struts-site](https://github.com/apache/struts-site) and
publishing is the
+merge — there is no separate deploy step. Open a pull request against `main`;
it is staged
+automatically at [struts.staged.apache.org](https://struts.staged.apache.org/)
for review.
+
+`_config.yml` — these move together:
+
+```yaml
+current_version: 7.3.0
+current_version_short: 730
+prev_version: 6.11.0
+prev_version_short: 6110
+release_date: 1 August 2026
+prev_release_date: 1 August 2026
+release_date_short: 20260801
+prev_release_date_short: 20260801-6110
+```
+
+`release_date` is the **tag** date, not the announcement date: 7.2.1 was
tagged on 15 June and
+announced on 30 June, and the site says 15 June. The `*_date_short` values are
the anchors in
+`announce-YYYY.md`; when two releases share a tag date, disambiguate the
second one (as
+`20260801-6110` above) so that each home page box links to its own entry.
+
+Then:
+
+- `source/announce-YYYY.md` — a new `####` entry at the top, newest first,
with its
+ `{% raw %}{#aYYYYMMDD}{% endraw %}` anchor.
+- `source/releases.md` — the release table, and move the superseded version
into
+ **Prior Releases**. This one is easy to miss; a site update without it is
incomplete.
+- `source/index.html` — the GA boxes read their values from `_config.yml`; the
security boxes are
+ hand-edited.
+- `source/dtds/` — only if a new DTD shipped.
+
+`source/download.cgi` and `source/download.md` need no per-release edit: the
first is a wrapper
+around `mirrors.cgi`, and the second interpolates its versions from
`_config.yml`.
+
+### Un-flag the GitHub release
+
+Remove the prerelease flag from the GitHub release created in phase 3. Title
`Struts X.Y.Z`, tag
+`STRUTS_X_Y_Z`.
+
+{:.alert .alert-warning}
+The release must stay flagged as a prerelease for the whole of the vote.
Un-flagging it early
+means voting on an artifact the world already treats as final.
+
+### Announce it
+
+```
+To: [email protected]
+Cc: [email protected], [email protected]
+```
+
+`dev@` is not on it — the list already saw the `[TEST]` mail and the vote.
+
+{:.alert .alert-danger}
+The announcement must be **plain text** and sent from your `@apache.org`
identity.
+`[email protected]` rejects any message carrying a `text/html` part, and
+`[email protected]` rejects anything not sent from an
`@apache.org` address. One
+list accepting the mail is not evidence that the format was right.
+
+The body carries the General Availability boilerplate, a link to the Version
Notes, a link to the
+Migration Guide for a new major line, the minimum JDK and specification
requirements for that
+line, and the [download page](download.cgi).
+
+## Phase 7 — Security advisories
+
+This phase exists only when the release carries a security fix, and it happens
**after** phase 6.
+The bulletin itself is usually written when the report is triaged, which may
be months before a
+release carries the fix.
+
+The ordering is not negotiable:
+
+```
+release GA → bulletin published → advisory mails → CVE record submitted
+```
+
+A bulletin published before the fixed artifact is downloadable tells attackers
what to look for
+and gives operators nothing to do about it.
+
+{:.alert .alert-danger}
+Nothing about an unpublished advisory goes into the release paperwork — not
the Version Notes,
+not the `[TEST]` mail, not the `[VOTE]`, not the commit messages, not the site
entry. Neutral
+tickets are what let the embargo survive a public release process.
+
+A release containing *only* embargoed fixes is self-disclosing: the difference
between the two
+tags is the vulnerability, whatever the commit messages say. That is a reason
to bundle such
+fixes with unrelated work, or to publish the bulletins together with the
release — not a reason
+to pretend otherwise.
+
+The CVE record goes `RESERVED → DRAFT → READY`, and `READY` is the last state
the PMC sets. ASF
+Security submits it to the CVE Program and sets it `PUBLIC`, so `cve.org`
links return 404 until
+they do. That is expected and is not a reason to delay the bulletin or the
mails.
+
+See [Security bulletins](security/) for how bulletins are written and
published, and
+[Reporting security issues](security) for how reports reach us in the first
place.
+
+## After the release
+
+- Add a site announcement entry for any security advisory, in the same form as
the GA one.
+- Check the [NVD](https://nvd.nist.gov/) entry once a CVE goes public. The
affected ranges have
+ been wrong before; the fix is an email to `[email protected]` citing the CVE
record.
+- Answer any coordinator who is holding an advisory in their existing thread,
once ours is live.
+- Update the Version Notes page if the vote forced a re-cut.
+
+## Red flags
+
+Stop if any of these is about to happen:
+
+- Cutting a tag before the version number has been stated and agreed.
+- Inferring the release version from the `-SNAPSHOT` in the pom.
+- A `[VOTE]` opened on a staging repository that is not closed, or on a link
that 404s.
+- Announcing before the 24 hour mirror wait.
+- Any severity, CVE, `S2-XXX` or bulletin link appearing in release paperwork.
+- A bulletin published before the fixed release is downloadable.
+- One release "covering" both maintenance lines.
Next: [PMC Charter](bylaws)