jdaugherty commented on code in PR #16229: URL: https://github.com/apache/grails-core/pull/16229#discussion_r4412978981
########## RELEASE.md: ########## @@ -433,6 +440,87 @@ 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 (experimental)` is `workflow_dispatch` plus the protected `release` environment. It uses the existing `NEXUS_STAGE_DEPLOYER_USER` / `NEXUS_STAGE_DEPLOYER_PW` secrets used to drop staging, but that account's promotion permission is unverified. Keep using the Nexus UI or local script. | +| 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 | Nexus UI or `.github/scripts/releaseJarFiles.sh`, 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 Infra-issued RSA 4096 key in `KEYS`, `Apache Grails Automated Release Signing <[email protected]>`, fingerprint `08E2 CEC4 7E38 FE41 5F08 0AB6 2ADE CADC 1177 5306`, already satisfies this requirement. The release workflow imports this key from `GRAILS_GPG_KEY` and signs with it using `GPG_KEY_ID`. Voters still compare an independent rebuild on trusted hardware with the uploaded artifacts. +5. Optional repository variables, after that setup: + + * `ATR_ENABLED=true` + * `ATR_PROJECT=grails` (the ATR project slug) + * `ATR_HOST=releases.apache.org` (optional; this is the default) + * `ATR_SSH_PORT=2222` (optional; this is the default) + +Do not enable ATR auto-archive of the prior release. On the ATR path, the release manager still removes the previous `dist/release` folder by hand so other current release lines are preserved. + +### Using ATR alongside a Grails release + +Keep the current `Release` workflow as the source of signed artifacts. After the `source` job has uploaded the zips to the GitHub Release: + +1. **Compose.** Run `Release - ATR Upload (experimental)`, or rely on `atr_upload` when `ATR_ENABLED=true`. This rsyncs `sources/apache-grails-<version>-src.zip` and, under `distribution/`, the binary zip, the wrapper zip, and the documentation zip, each with `.asc` and `.sha512`. The upload declares the release tag commit. ATR then checks that the source zip is a subset of that commit: omitted files are allowed, and files that are not in the git tree are not, except `PKG-INFO` when `pyproject.toml` is present. This zip adds `CHECKSUMS`, `PUBLISHED_ARTIFACTS`, `BUILD_DATE`, and `GIT_TAGS` under `grails/`. That records a concern from `atr.tasks.checks.compare.source_trees`. Starting the vote requires acknowledging that concern. A project ignore can mark the same checker as an exception, but a broad ignore also hides unexpected extra files, so acknowledge the concern until ATR can allow those specific added paths. Do not treat `dist/dev` as the files under vote when ATR is the staging location. See [Staging and voting](https://releases.apache.org/docs/staging-and-voting). +2. **Vote.** Start the vote on ATR. There is no Tooling GitHub Action for this. Select automatic publication to the SVN distribution area. The download path comes from the project suffix `core/{{VERSION}}`, which the current `release-on-atr` action does not override. Discard any `dist/dev` `[VOTE]` email if the `upload` job printed one; it skips that email when `ATR_ENABLED=true`. Keep the 72-hour PMC vote. The GitHub `release` environment approval is still the gate for later jobs. +3. **Resolve.** After the vote passes, run `Release - ATR Resolve Vote (experimental)` with `passed`. That replaces sending the `[RESULT][VOTE]` email by hand. `cancelled` is also a valid resolution. +4. **Publish.** If automatic publication was selected, ATR has committed the voted artifacts to `dist/release/grails/core/<version>/`. Otherwise press Publish on the finish page. Do not run `releaseDistributions.sh` and do not move `dist/atr`. +5. **Maven Central.** Use the Nexus UI or `.github/scripts/releaseJarFiles.sh` as your ASF user. The promotion workflow remains experimental until the stage-deployer account's promotion permission is verified. Once Maven Central is live, run `Release - ATR Record Distribution (experimental)` with `platform=MAVEN`, `distribution_owner_namespace=org.apache.grails`, and `distribution_package=grails-bom`. If the project tagging spec names Maven, ATR will not announce until that record exists. +6. **Public destinations named by the announcement.** Publish the voted documentation zip, release the version to SDKMAN!, and update plus publish the static website so [https://grails.apache.org/download.html](https://grails.apache.org/download.html) lists this version. The generated announcement links to that page. Confirm the page shows the new version before announcing. +7. **Announce.** Run `Release - ATR Announce (experimental)` once; it always sends to `[email protected]`. Leave `announce_body` empty to render `.github/vote_templates/announce.txt` (milestone wording is included only for `M` / `RC` versions). One successful announce must not be repeated for another list. If ATR rejects the call because the artifacts are not on the download mirrors yet, check the ATR finish page and retry that same announce. Do not retry an ambiguous failure. Then send the same body from your `@apache.org` address to `[email protected]`, `[email protected]`, and `[email protected]`. + +To verify an ATR candidate, set `GRAILS_DISTRIBUTION_BASE_URL` when running `verify.sh` or `download-release-artifacts.sh`, or supply `distribution_base_url` to `Release - Verify Troubleshooting`, to the ATR candidate directory for that version containing `sources/` and `distribution/`, not a GitHub release URL. Leave it empty to keep the default `https://dist.apache.org/repos/dist/dev/grails/core/<version>`; GitHub release asset downloads remain unchanged. Review Comment: Where does the release manager get this URL? The ATR docs (staging-and-voting, uploading-files) give no per-file download pattern; the candidate page offers a `curl` one-liner and a list of file URLs at `/download/urls/<project>/<version>`, and nothing says whether the `sources/` and `distribution/` subfolders that `atr_upload` rsyncs survive in those URLs. Please say here where to read the directory from, and note that `download-release-artifacts.sh` needs those two subfolders exactly as the upload job lays them out, since that is the layout the script appends to this URL. ########## RELEASE.md: ########## @@ -433,6 +440,87 @@ 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 (experimental)` is `workflow_dispatch` plus the protected `release` environment. It uses the existing `NEXUS_STAGE_DEPLOYER_USER` / `NEXUS_STAGE_DEPLOYER_PW` secrets used to drop staging, but that account's promotion permission is unverified. Keep using the Nexus UI or local script. | +| 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 | Nexus UI or `.github/scripts/releaseJarFiles.sh`, 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 Infra-issued RSA 4096 key in `KEYS`, `Apache Grails Automated Release Signing <[email protected]>`, fingerprint `08E2 CEC4 7E38 FE41 5F08 0AB6 2ADE CADC 1177 5306`, already satisfies this requirement. The release workflow imports this key from `GRAILS_GPG_KEY` and signs with it using `GPG_KEY_ID`. Voters still compare an independent rebuild on trusted hardware with the uploaded artifacts. +5. Optional repository variables, after that setup: + + * `ATR_ENABLED=true` + * `ATR_PROJECT=grails` (the ATR project slug) + * `ATR_HOST=releases.apache.org` (optional; this is the default) + * `ATR_SSH_PORT=2222` (optional; this is the default) + +Do not enable ATR auto-archive of the prior release. On the ATR path, the release manager still removes the previous `dist/release` folder by hand so other current release lines are preserved. Review Comment: This says the removal is done by hand but not how, and the ATR path has no script for it. On the dist/dev path `releaseDistributions.sh` lists `dist/release/grails/core`, offers each folder other than the new version, and runs `svn rm -m "Remove previous release <folder>" https://dist.apache.org/repos/dist/release/grails/core/<folder>`. Please put that command here, or split the prune loop out of the script so the ATR path can run the same step, so the release manager is not left to reconstruct it from the script. ########## AGENTS.md: ########## @@ -61,7 +61,7 @@ export GRADLE_OPTS="-Dorg.gradle.jvmargs=-Xmx4G" 12. **Clean violations before commit** - Before every automated commit, run `./gradlew clean aggregateViolations :grails-test-report:check --continue` from the root. The root `clean` runs `cleanViolationReports`, which deletes the analyzer reports and aggregate reports so every module is re-analyzed; without it, analyzers for unchanged modules stay UP-TO-DATE and their previous results are aggregated. Ensure the Checkstyle, CodeNarc, and `REPOSITORY_CONVENTIONS` reports have no issues, and ensure PMD and SpotBugs reports have no issues for their enabled projects. Enable PMD or SpotBugs per project through the `grailsCodeAnalysis` extension in that module's `build.gradle`; the `-Pgrails.code-analysis.enabled.pmd[.projects]` and `-Pgrails.code-analysis.enabled.spotbugs[.projects]` properties are baseline-run overrides. Disabled tools report their disabled status, not a clean result. Also review the test result reports under `grails-test-report/build/reports/tests/` and ensure there ar e no failures. `--continue` is required: the aggregate Markdown reports are written only by the aggregate lane, so without it a failing analyzer stops the build before the report that explains the failure is produced. Running an analyzer task directly, such as `./gradlew :grails-core:checkstyleMain`, produces only that task's own XML report and deliberately leaves the aggregate Markdown untouched, so a partial run can never overwrite an authoritative full-repository report. 13. **Mandatory test coverage** - Any class touched in a commit MUST be covered with tests that verify all behavior. You must run ALL tests in the affected module(s) and ensure they pass before committing. 14. **The BOM must manage the latest version** - `validateDependencyVersions` enforces that the BOM (`dependencies.gradle`) manages a version `>=` every transitively-resolved version. When it fails, **bump the version in `dependencies.gradle`** so the BOM wins — never silence it with `allowedBomOverrides` or an exclusion unless there is an explicit, documented conflict or an agreed-upon workaround. See [Dependency Management](#dependency-management). -15. **GitHub Actions must use ASF-approved references** - Every third-party action SHA must appear in the ASF allowlist; `actions/*` use the full tag of their latest release and `apache/*` use version or branch references, never SHAs. See [GitHub Actions](#github-actions). +15. **GitHub Actions must use ASF-approved references** - Every third-party action SHA must appear in the ASF allowlist; `actions/*` use the full tag of their latest release and `apache/*` use version or branch references, never SHAs, except `apache/tooling-actions/*`: these actions are untagged and ATR Trusted Publishing requires a full commit hash. See [GitHub Actions](#github-actions). Review Comment: One more copy of the rule this relaxes (commenting here because the file is not in the diff): `.agents/skills/violation-fixer/SKILL.md` line 119 still says `apache/*` must use "a version or branch reference, never a 40-hex SHA". That table is what an agent follows when it fixes a `REPOSITORY_CONVENTIONS` finding, so as written it would replace the hash the gate now requires with `@main`. Please add the `apache/tooling-actions/*` exception there too. -- 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]
