jdaugherty commented on code in PR #16229:
URL: https://github.com/apache/grails-core/pull/16229#discussion_r4326746255


##########
.github/workflows/release-atr-announce.yml:
##########
@@ -0,0 +1,137 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Experimental Apache Trusted Releases (ATR) announce step.
+# Sends ONE announcement through ATR. The first successful announce promotes
+# the candidate from preview to released, so this workflow must not be rerun
+# for additional mailing lists. The recipient is restricted to 
[email protected].
+# ATR documentation and the official workflow example:
+# https://tooling.apache.org/
+# 
https://github.com/apache/tooling-asf-example/blob/main/.github/workflows/announce-release-on-atr.yaml
+# After it succeeds, send the remaining lists by hand from your @apache.org
+# address: [email protected], [email protected], and
+# [email protected].
+#
+# Prerequisites (see RELEASE.md "Experimental: Apache Trusted Releases"):
+#   * This workflow listed under the project's ATR finish workflow paths
+#   * Vote already resolved as passed on ATR
+name: "Release - ATR Announce (experimental)"
+on:
+  workflow_dispatch:
+    inputs:
+      version:
+        description: 'Release version without the v prefix (e.g. 7.0.0 or 
8.0.0-M1)'
+        required: true
+        type: string
+      previous_version:
+        description: 'Previous released version without the v prefix, used in 
the compare URL'
+        required: true
+        type: string
+      announce_email_to:

Review Comment:
   This input can only ever hold `[email protected]`; any other value fails 
the first step. Drop the input and hardcode the recipient in the step. An input 
that exists only to be rejected invites someone to try the project lists 
through it.



##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/RepositoryConventionsTask.groovy:
##########
@@ -51,8 +51,10 @@ abstract class RepositoryConventionsTask extends DefaultTask 
{
     private static final Pattern DOCKER_IMAGE_DIGEST = 
Pattern.compile(/^docker:\/\/[^@\s]+@sha256:[0-9a-f]{64}$/)
     private static final Pattern CONTAINER_IMAGE_DIGEST = 
Pattern.compile(/^[^@\s]+@sha256:[0-9a-f]{64}$/)
     // GitHub-official and first-party ASF actions track upstream ASF 
approvals, so they use version or
-    // branch references and are never pinned to a commit SHA.
+    // branch references and are never pinned to a commit SHA. 
apache/tooling-actions is the exception:

Review Comment:
   AGENTS.md (CLAUDE.md links to it) still states the rule this relaxes: 
critical rule 12 says `apache/*` use "version or branch references, never 
SHAs", and the GitHub Actions section says "Never pin either by SHA". Please 
add the `apache/tooling-actions` exception there too, with the reason 
(untagged, full hash required by ATR Trusted Publishing), so the guide and the 
gate agree.



##########
RELEASE.md:
##########
@@ -433,6 +439,83 @@ Announcements should come from your apache email address 
(see https://infra.apac
 expected format. The announcement should be sent to `[email protected]`, 
`[email protected]`, `[email protected]`, &
 `[email protected]`. See the `close` job for a generated email.
 
+### What GitHub Actions may automate
+
+The following boundaries preserve PMC authority and use only opt-in, protected 
workflows. Apache's release policy permits
+automated release infrastructure to sign artifacts, while the vote remains a 
community email process.
+
+| Activity | GitHub Actions boundary and evidence |
+| --- | --- |
+| ATR compose, resolve, one announce, and distribution record | Opt-in 
workflows call [ASF Tooling actions](https://github.com/apache/tooling-actions) 
against [ATR Beta](https://releases.apache.org/docs/). Official examples: 
[compose](https://github.com/apache/tooling-asf-example/blob/main/.github/workflows/build-and-rsync-to-atr.yaml),
 
[resolve](https://github.com/apache/tooling-asf-example/blob/main/.github/workflows/resolve-vote-on-atr.yaml),
 
[announce](https://github.com/apache/tooling-asf-example/blob/main/.github/workflows/announce-release-on-atr.yaml),
 and 
[record](https://github.com/apache/tooling-asf-example/blob/main/.github/workflows/record-distribution-on-atr.yaml).
 |
+| Signing in GitHub Actions | [Apache release 
policy](https://www.apache.org/legal/release-policy.html) requires release 
artifacts to be signed by the Release Manager or automated release 
infrastructure. ATR [Trusted 
Publishing](https://releases.apache.org/docs/trusted-publishing) accepts those 
signatures when the committee is eligible for CI builds. |
+| Publish the voted distributions to `dist/release` | Beta ATR commits the 
approved artifacts to `svn:dist:release` itself. The workflow calls ATR. It 
does not write SVN. See [Promoting to 
release](https://releases.apache.org/docs/promoting-to-release). |
+| Documentation and website content | [GitHub Actions 
policy](https://infra.apache.org/github-actions-policy.html) permits work on 
website content and other non-released data. Grails already deploys 
documentation from GitHub Actions. |
+| Promote closed Nexus staging after a passed vote | `Release - Promote Nexus 
Staging` is `workflow_dispatch` plus the protected `release` environment. It 
follows the [Apache Polaris TLP promotion 
workflow](https://github.com/apache/polaris/blob/7866ce5c009d64e4c1454b47bca3df9873c6c0b2/.github/workflows/release-4-publish-release.yml)
 and uses the existing `NEXUS_STAGE_DEPLOYER_USER` / `NEXUS_STAGE_DEPLOYER_PW` 
secrets used to drop staging. |
+| Skip `dist/dev` only when using ATR | ATR candidates may skip the 
traditional staging location as described in [Staging and 
voting](https://releases.apache.org/docs/staging-and-voting). The `dist/dev` 
plus Nexus path remains Grails' official default until the PMC opts in to ATR. |
+
+The following must remain manual:
+
+| Activity | Why it remains manual |
+| --- | --- |
+| Start the binding PMC vote and hold it for at least 72 hours | [Apache 
release policy](https://www.apache.org/legal/release-policy.html) says release 
votes SHOULD remain open for at least 72 hours. ATR can send and tally the vote 
email, but `apache/tooling-actions` has no action that starts a vote. |
+| Move `dist/dev` distributions when ATR is not used | [GitHub Actions 
policy](https://infra.apache.org/github-actions-policy.html) prohibits 
automated services from pushing official release data without prior 
Infrastructure authorization. The default Grails path still uses 
`releaseDistributions.sh` as the release manager. |
+| Rebuild and compare artifacts on trusted hardware | Trusted Publishing 
requires an independent rebuild outside GitHub Actions before publication. 
Grails already documents that comparison in this file. |
+| Report the release to ASF Reporter | [ASF Reporter 
addrelease](https://reporter.apache.org/addrelease.html) has no documented 
public API. |
+| Send lists beyond the one ATR announcement | ATR rejects a second 
announcement for the same release. Send `[email protected]`, 
`[email protected]`, and `[email protected]` manually after the 
single ATR announce. |
+| Forge, SDKMAN!, the static website, and the blog | ATR records external 
distributions. It does not publish those Grails channels. |
+
+ATR Beta on `releases.apache.org` publishes finished releases directly to 
`svn:dist:release`. The PMC email that announces Beta to `pmcs@` is still 
tracked by 
[tooling-trusted-releases#1520](https://github.com/apache/tooling-trusted-releases/issues/1520).
 That open issue does not keep the platform on Alpha.
+
+## Apache Trusted Releases (ATR)
+
+[ASF Tooling](https://tooling.apache.org/) runs [Apache Trusted 
Releases](https://releases.apache.org/) to automate compose, vote, and finish. 
ATR is **Beta**. The existing `dist/dev` to `dist/release` and Nexus staging 
path remains the official Grails process until the PMC opts in. See the [ATR 
documentation](https://releases.apache.org/docs/) and 
[apache/tooling-actions](https://github.com/apache/tooling-actions).
+
+The workflows pin `apache/tooling-actions` to 
`dcba9f4ed2956f7a30113c3067e766eeda37d891` (`main` on 2026-10-08). [Trusted 
Publishing](https://releases.apache.org/docs/trusted-publishing) says these 
actions are not tagged and must be referenced by a full commit hash, not 
`@main`. Other `apache/*` actions stay on a branch. 
`validateRepositoryConventions` requires that commit hash for 
`apache/tooling-actions/*` and still rejects a commit hash for every other 
`apache/*` action.
+
+| Manual step today | Tooling action | Grails workflow |
+| --- | --- | --- |
+| Upload source, binary, wrapper, and docs zips | `upload-to-atr` | `Release - 
ATR Upload (experimental)`, or `atr_upload` in `release.yml` when 
`ATR_ENABLED=true` |
+| Send the `[VOTE]` email | none (start the vote in the [ATR 
UI](https://releases.apache.org/) or with `atr vote start`) | — |
+| Send the `[RESULT][VOTE]` email | `release-on-atr` with `resolve: true` | 
`Release - ATR Resolve Vote (experimental)` |
+| Publish the voted zips to `dist/release` | ATR, when automatic publication 
was selected at vote start, or the Publish button | not a GitHub Actions SVN 
write |
+| Promote Nexus staging to Maven Central | none | `Release - Promote Nexus 
Staging`, then `Release - ATR Record Distribution (experimental)` with 
`platform=MAVEN` |
+| Send the `[ANNOUNCE]` email | `release-on-atr` with `announce: true` | 
`Release - ATR Announce (experimental)` once, to `[email protected]` |
+| ASF Reporter, Forge, SDKMAN!, website, blog | none | unchanged |
+
+### Opt-in setup
+
+1. Log in at https://releases.apache.org/ with ASF credentials and confirm the 
Grails project. Discuss on 
[[email protected]](https://lists.apache.org/[email protected])
 / [#apache-trusted-releases](https://the-asf.slack.com/archives/C049WADAAQG).
+2. Set the project download path suffix to `core/{{VERSION}}`. Grails 
publishes under `dist/release/grails/core/<version>/`, not in the committee 
root next to `KEYS`.
+3. Configure [Trusted 
Publishing](https://releases.apache.org/docs/trusted-publishing) for repository 
`grails-core`:
+
+    * Compose: `.github/workflows/release.yml` and 
`.github/workflows/release-atr-upload.yml`
+    * Vote: `.github/workflows/release-atr-resolve.yml`
+    * Finish: `.github/workflows/release-atr-announce.yml` and 
`.github/workflows/release-atr-record.yml`
+
+4. The committee page must show CI builds enabled. That requires a signing key 
whose primary UID contains `Automated Release Signing` and whose email is 
`[email protected]`. The release workflow imports `GRAILS_GPG_KEY` and 
signs with `GPG_KEY_ID`. Confirm that selected key matches this UID before the 
workflows will be accepted. If it does not, ask Infrastructure for a key that 
does. Voters still compare an independent rebuild on trusted hardware with the 
uploaded artifacts.

Review Comment:
   This prerequisite is already met, so the step should say so rather than 
hedge. The only key in KEYS is `Apache Grails Automated Release Signing 
<[email protected]>` (RSA 4096, fingerprint `08E2 CEC4 7E38 FE41 5F08 
0AB6 2ADE CADC 1177 5306`, issued by Infra in May 2025), and the 7.0.6 and 
8.0.0-RC2 signatures were made with it (key id `2ADECADC11775306`), so the 
release workflow already signs with the automated key. Please replace "Confirm 
that selected key matches this UID ... ask Infrastructure for a key that does" 
with a statement that the Infra-issued key in KEYS satisfies this, so the next 
release manager does not go looking for a key to compare.



##########
.github/workflows/release-promote-jars.yml:
##########
@@ -0,0 +1,83 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Apache Polaris, a TLP, promotes a closed staging repository after its vote:
+# 
https://github.com/apache/polaris/blob/7866ce5c009d64e4c1454b47bca3df9873c6c0b2/.github/workflows/release-4-publish-release.yml
+# Grails already uses the same NEXUS_STAGE_DEPLOYER_* secrets in
+# release-drop-staging.yml. This workflow never writes dist.apache.org/release:
+# https://infra.apache.org/github-actions-policy.html
+name: "Release - Promote Nexus Staging"
+on:
+  workflow_dispatch:
+    inputs:
+      version:
+        description: 'Release version without the v prefix (e.g. 8.0.0-M1)'
+        required: true
+        type: string
+      staging_description:
+        description: 'Nexus staging repository description (defaults to 
<repository>:<version>)'
+        required: false
+        type: string
+        default: ''
+      repository:
+        description: 'Repository name used only for the default staging 
description'
+        required: false
+        type: string
+        default: grails-core
+permissions:
+  contents: read
+jobs:
+  promote:
+    name: "Promote Nexus staging repository"
+    environment: release
+    # Keep the release environment restricted to trusted refs.
+    runs-on: ubuntu-24.04
+    steps:
+      - name: "📥 Checkout the workflow ref"
+        uses: actions/[email protected]
+        with:
+          persist-credentials: false
+      - name: "📝 Establish staging description"
+        env:
+          VERSION: ${{ inputs.version }}
+          STAGING_DESCRIPTION_INPUT: ${{ inputs.staging_description }}
+          REPOSITORY: ${{ inputs.repository }}
+        run: |
+          set -euo pipefail
+          if [ -z "${VERSION}" ]; then
+            echo "::error::Version must not be empty."
+            exit 1
+          fi
+          if [ -n "${STAGING_DESCRIPTION_INPUT}" ]; then
+            echo "STAGING_DESCRIPTION=${STAGING_DESCRIPTION_INPUT}" >> 
"$GITHUB_ENV"
+          else
+            echo "STAGING_DESCRIPTION=${REPOSITORY}:${VERSION}" >> 
"$GITHUB_ENV"
+          fi
+      - name: "🚀 Promote Nexus staging repository"
+        env:
+          NEXUS_USER: ${{ secrets.NEXUS_STAGE_DEPLOYER_USER }}

Review Comment:
   I went looking for evidence either way and found none that this account can 
promote. Nothing on infra.apache.org says what the stage-deployer role may do 
beyond deploy, close and drop. The Polaris workflow this PR cites has no run on 
record that reached its Nexus release step: the real runs failed earlier, and 
the step logs of its two green runs have expired, so whether those were dry 
runs (the workflow's default) is unknowable. parquet-java has the same design 
with zero runs, and OpenDAL's Java artifacts on Central are not at the version 
its workflow reported released. So the precedent is a design, not a 
demonstration. Before this merges, please either dispatch the workflow against 
the closed staging repo of the next milestone or ask Infra in a ticket, and 
until one of those succeeds, drop the "prefer this workflow" wording in 
RELEASE.md and in the release job's echo so the documented path stays the one 
we know works.



##########
RELEASE.md:
##########
@@ -325,29 +326,34 @@ Confirm the Grails PMC votes passed with a +1 from at 
least 3 PMC members. The `
 
 ### Release the Staged Jar files
 
-The `release` job in the `Release` workflow has a step entitled `🚀 Release JAR 
files - MANUAL`. You can release the jar
-files by one of 2 ways:
+After the PMC vote has passed and the protected `release` environment is 
approved, prefer the opt-in
+`Release - Promote Nexus Staging` workflow. Run it from Actions with the 
version without `v`; leave
+`staging_description` empty to use `grails-core:<version>`. This is manually 
dispatched after the vote, following the
+[Apache Polaris TLP 
precedent](https://github.com/apache/polaris/blob/7866ce5c009d64e4c1454b47bca3df9873c6c0b2/.github/workflows/release-4-publish-release.yml).
 
-1. On https://repository.apache.org/#stagingRepositories, the staged artifacts 
must be released by opening the `grails-core` staging repository and
-   clicking the `Release` button. It took almost 2 hours for the initial ASF 
release to publish these jars to Maven
-   Central.
-2. Alternatively, the `release` job in the `Release` workflow will output an 
example command line to release the staging
-   repository via the scripts checked into grails-core. Execute the script & 
set the placeholder values to release the
-   jar files.
+The following remain fallbacks:
+
+1. On https://repository.apache.org/#stagingRepositories, release the staged 
artifacts by opening the `grails-core` staging repository and
+    clicking the `Release` button. It took almost 2 hours for the initial ASF 
release to publish these jars to Maven
+    Central.
+2. Run `.github/scripts/releaseJarFiles.sh grails-core:<version> <ASF_USER>`. 
The script prompts for a password unless
+    `NEXUS_PASS` is already set, which is how the protected workflow supplies 
its secret.
 
 ### Move the distributions from `dev` to `release`
 
-On dist.apache.org, the staged source distribution, binary distributions & 
documentation distribution must be moved from 
`https://dist.apache.org/repos/dist/dev/grails/` to 
`https://dist.apache.org/repos/dist/release/grails/`. Per ASF
-infrastructure, this must be performed manually, and we are not allowed to 
automate it via a gated approval workflow.
-Either move them via your SVN client or use the checked in script to perform 
these actions as your user.
+If this candidate was staged on ATR, skip this `dist/dev` move. Beta ATR 
commits the voted artifacts directly to `svn:dist:release` when the release is 
published. Set the Grails project's download path suffix to `core/{{VERSION}}` 
so the tree is `dist/release/grails/core/<version>/`, which is where the 
source, binary, wrapper, and documentation distributions belong. Do not run 
`releaseDistributions.sh` for an ATR candidate, and do not move anything out of 
`dist/atr`. See [Apache Trusted Releases (ATR)](#apache-trusted-releases-atr).

Review Comment:
   Two things `releaseDistributions.sh` does are lost on the ATR path and 
nothing here picks them up. The `upload` job still commits the candidate to 
`dist/dev/grails/core/<version>` whether or not `ATR_ENABLED` is set, and with 
the `svn mv` skipped that copy stays there for good (the abort workflow has the 
exact `svnmucc rm` for it). And the script's loop that offers to remove the 
prior release folder from `dist/release` never runs, so old releases accumulate 
until someone prunes them by hand; the auto-archive caveat in the ATR section 
only says not to let ATR do it. Please either gate the SVN steps of `upload` on 
`ATR_ENABLED` not being `true` (the job itself has to stay, `release` needs it) 
or add both the `svn rm` of the dev copy and the prior-release pruning to the 
ATR **Publish** step.



-- 
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]

Reply via email to