You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by st...@apache.org on 2026/08/27 19:17:29 UTC
(hadoop-cloudstore) branch main updated: HADOOP-19880. ATR Support (WiP)
This is an automated email from the ASF dual-hosted git repository.
steveloughran pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hadoop-cloudstore.git
The following commit(s) were added to refs/heads/main by this push:
new a52b577 HADOOP-19880. ATR Support (WiP)
a52b577 is described below
commit a52b577b6f24b89170fbb240f1b38415d1f6d443
Author: Steve Loughran <st...@apache.org>
AuthorDate: Thu Aug 27 20:12:14 2026 +0100
HADOOP-19880. ATR Support (WiP)
Written by Claude.ai
---
.github/workflows/release.yml | 174 ++++++++++++++++++++++++--------
.rat-excludes | 33 ++++++
BUILDING.md | 164 ++++++++++++++++++------------
dev-support/assembly/source-release.xml | 54 ++++++++++
pom.xml | 27 +++++
5 files changed, 349 insertions(+), 103 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 719e917..ef1040e 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -15,14 +15,45 @@
# limitations under the License.
# Automates the mechanical half of cutting a cloudstore release: build,
-# prove the build is reproducible, attest its provenance, and stage the
-# result as a draft GitHub Release. It does NOT sign or publish anything.
+# prove the build is reproducible, sign, and compose a release candidate on
+# Apache Trusted Releases (ATR, https://github.com/apache/tooling-trusted-releases).
+# The PMC vote and the final "finish" (publish) step remain manual, performed
+# through ATR itself -- this workflow only performs the *compose* phase of an
+# ATR release: https://github.com/apache/tooling-trusted-releases/blob/main/atr/docs/staging-and-voting.md
#
-# Reproducibility is enforced, not assumed: the release profile is run
-# twice from a clean checkout and the resulting jar + SBOMs must be
-# byte-identical, or the job fails. That's what backs the claim that a
-# third party rebuilding the same commit with the same JDK gets the same
-# binary -- see pom.xml's project.build.outputTimestamp for the mechanism.
+# Reproducibility is enforced, not assumed: the release profile is run twice
+# from a clean checkout and the resulting jar + SBOMs must be byte-identical,
+# or the job fails. Demonstrating this is also ATR's own prerequisite for
+# Trusted Publishing eligibility -- see
+# https://github.com/apache/tooling-trusted-releases/blob/main/atr/docs/trusted-publishing.md
+#
+# ## One-time setup this workflow depends on
+#
+# 1. ASF Security has confirmed cloudstore's build is reproducible, and ASF
+# Infra has generated an "Automated Release Signing" GPG keypair for the
+# committee (primary UID containing "Automated Release Signing", email
+# private@<committee>.apache.org). Its public half is imported into the
+# committee KEYS file via ATR.
+# 2. The private half of that key is stored as the `ATR_SIGNING_KEY` secret
+# on this repository (ASCII-armored, ideally without a passphrase since
+# this job runs unattended -- confirm with ASF Infra how it was cut).
+# 3. In the cloudstore project's ATR release policy (Trusted Publishing tab):
+# repository name `hadoop-cloudstore`, and this file's path
+# (`.github/workflows/release.yml`) registered under the *compose* phase.
+# 4. Repository variables (Settings > Secrets and variables > Actions > Variables):
+# ATR_HOST - ATR's hostname, no scheme (e.g. release.apache.org)
+# ATR_PROJECT_KEY - cloudstore's project key in ATR
+# ATR_SIGNING_KEY_ID - (optional) key id/fingerprint for `gpg --local-user`,
+# only needed if more than one key ends up importable
+# ATR_SSH_KNOWN_HOSTS - (recommended) `known_hosts` line(s) pinning ATR's
+# SSH host key; without this the job falls back to
+# trust-on-first-use, which does not protect against
+# a MITM'd first connection
+#
+# Whoever triggers this workflow (dispatches it) must have their GitHub
+# account linked to their ASF account (gitbox.apache.org/boxer), or ATR
+# rejects the SSH key registration -- see "How ATR matches a workflow" in
+# trusted-publishing.md.
#
# Third-party actions are SHA-pinned per SECURITY.md. When bumping, update
# both the SHA and the trailing tag comment in lockstep.
@@ -46,22 +77,24 @@ permissions:
concurrency:
# One in-flight build per version -- queue rather than race concurrent
- # dispatches for the same release onto the same draft/tag.
+ # dispatches for the same release onto the same ATR release candidate.
group: ${{ github.workflow }}-${{ inputs.version }}
cancel-in-progress: false
jobs:
build:
- name: Build, verify reproducibility, attest, stage
+ name: Build, verify reproducibility, sign, compose on ATR
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
- contents: write # create/update the draft release
- attestations: write # actions/attest-build-provenance
- id-token: write # OIDC token for keyless (Sigstore) attestation
+ attestations: write # actions/attest-build-provenance (independent of ATR)
+ id-token: write # OIDC token for GitHub->ATR Trusted Publishing and for attest-build-provenance
env:
RELEASE_VERSION: ${{ inputs.version }}
- RELEASE_TAG: v${{ inputs.version }}
+ ATR_HOST: ${{ vars.ATR_HOST }}
+ ATR_PROJECT_KEY: ${{ vars.ATR_PROJECT_KEY }}
+ ATR_SIGNING_KEY_ID: ${{ vars.ATR_SIGNING_KEY_ID }}
+ ATR_SSH_KNOWN_HOSTS: ${{ vars.ATR_SSH_KNOWN_HOSTS }}
steps:
- name: Validate version input
run: |
@@ -70,6 +103,16 @@ jobs:
exit 1
fi
+ - name: Check ATR configuration is present
+ run: |
+ missing=()
+ [[ -z "$ATR_HOST" ]] && missing+=("vars.ATR_HOST")
+ [[ -z "$ATR_PROJECT_KEY" ]] && missing+=("vars.ATR_PROJECT_KEY")
+ if [[ ${#missing[@]} -gt 0 ]]; then
+ echo "::error::not configured for ATR yet, missing: ${missing[*]} -- see the comment block at the top of this workflow"
+ exit 1
+ fi
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.ref }}
@@ -98,6 +141,7 @@ jobs:
run: |
mkdir -p /tmp/build1
cp "target/cloudstore-${RELEASE_VERSION}.jar" \
+ "target/cloudstore-${RELEASE_VERSION}-src.tar.gz" \
"target/cloudstore-${RELEASE_VERSION}-cyclonedx.json" \
"target/cloudstore-${RELEASE_VERSION}-cyclonedx.xml" \
/tmp/build1/
@@ -109,6 +153,7 @@ jobs:
run: |
status=0
for f in "cloudstore-${RELEASE_VERSION}.jar" \
+ "cloudstore-${RELEASE_VERSION}-src.tar.gz" \
"cloudstore-${RELEASE_VERSION}-cyclonedx.json" \
"cloudstore-${RELEASE_VERSION}-cyclonedx.xml"; do
if cmp -s "/tmp/build1/$f" "target/$f"; then
@@ -129,37 +174,86 @@ jobs:
with:
subject-path: |
target/cloudstore-${{ inputs.version }}.jar
+ target/cloudstore-${{ inputs.version }}-src.tar.gz
target/cloudstore-${{ inputs.version }}-cyclonedx.json
target/cloudstore-${{ inputs.version }}-cyclonedx.xml
- - name: Stage draft GitHub Release
+ - name: Sign artifacts with the automated release signing key
env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ ATR_SIGNING_KEY: ${{ secrets.ATR_SIGNING_KEY }}
+ run: |
+ if [[ -z "$ATR_SIGNING_KEY" ]]; then
+ echo "::error::secrets.ATR_SIGNING_KEY is not set -- see the comment block at the top of this workflow"
+ exit 1
+ fi
+ export GNUPGHOME="$(mktemp -d)"
+ trap 'rm -rf "$GNUPGHOME"' EXIT
+ printf '%s' "$ATR_SIGNING_KEY" | gpg --batch --import
+ local_user_args=()
+ [[ -n "$ATR_SIGNING_KEY_ID" ]] && local_user_args=(--local-user "$ATR_SIGNING_KEY_ID")
+ for f in "target/cloudstore-${RELEASE_VERSION}.jar" \
+ "target/cloudstore-${RELEASE_VERSION}-src.tar.gz" \
+ "target/cloudstore-${RELEASE_VERSION}-cyclonedx.json" \
+ "target/cloudstore-${RELEASE_VERSION}-cyclonedx.xml"; do
+ gpg --batch --yes --pinentry-mode loopback "${local_user_args[@]}" --detach-sign "$f"
+ done
+
+ - name: Register an ephemeral SSH key with ATR (GitHub OIDC Trusted Publishing)
+ id: atr-ssh
+ run: |
+ key_dir="$(mktemp -d)"
+ echo "key_dir=$key_dir" >> "$GITHUB_OUTPUT"
+ ssh-keygen -q -t ed25519 -N '' -f "$key_dir/atr_key" -C "cloudstore-release-${RELEASE_VERSION}"
+
+ oidc_token="$(curl -sf -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
+ "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=https://${ATR_HOST}/" | jq -r '.value')"
+ if [[ -z "$oidc_token" || "$oidc_token" == "null" ]]; then
+ echo "::error::failed to obtain a GitHub OIDC token"
+ exit 1
+ fi
+
+ ssh_pub="$(cat "$key_dir/atr_key.pub")"
+ body="$(jq -n --arg publisher github --arg jwt "$oidc_token" --arg ssh_key "$ssh_pub" \
+ '{publisher: $publisher, jwt: $jwt, ssh_key: $ssh_key}')"
+
+ response="$(curl -sf -X POST "https://${ATR_HOST}/api/publisher/ssh/register" \
+ -H 'Content-Type: application/json' -d "$body")"
+ echo "ATR registered key: $(jq -c '{project, fingerprint, expires}' <<<"$response")"
+
+ - name: Upload the release candidate to ATR over rsync
run: |
- assets=(
- "target/cloudstore-${RELEASE_VERSION}.jar"
- "target/cloudstore-${RELEASE_VERSION}.jar.sha256"
- "target/cloudstore-${RELEASE_VERSION}-cyclonedx.json"
- "target/cloudstore-${RELEASE_VERSION}-cyclonedx.json.sha256"
- "target/cloudstore-${RELEASE_VERSION}-cyclonedx.xml"
- "target/cloudstore-${RELEASE_VERSION}-cyclonedx.xml.sha256"
- "LICENSE-binary"
- "NOTICE-binary"
- )
- if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
- echo "release $RELEASE_TAG already exists -- uploading (replacing same-named assets)"
- gh release upload "$RELEASE_TAG" "${assets[@]}" --clobber
+ key_dir="${{ steps.atr-ssh.outputs.key_dir }}"
+ chmod 600 "$key_dir/atr_key"
+ known_hosts_args=(-o StrictHostKeyChecking=accept-new)
+ if [[ -n "$ATR_SSH_KNOWN_HOSTS" ]]; then
+ known_hosts_file="$key_dir/known_hosts"
+ printf '%s\n' "$ATR_SSH_KNOWN_HOSTS" > "$known_hosts_file"
+ known_hosts_args=(-o StrictHostKeyChecking=yes -o UserKnownHostsFile="$known_hosts_file")
else
- gh release create "$RELEASE_TAG" \
- --target "$(git rev-parse HEAD)" \
- --title "cloudstore $RELEASE_VERSION" \
- --draft \
- --generate-notes \
- "${assets[@]}"
+ echo "::warning::vars.ATR_SSH_KNOWN_HOSTS is not set -- trusting ATR's host key on first connection"
fi
- echo "### Staged draft release $RELEASE_TAG" >> "$GITHUB_STEP_SUMMARY"
- echo "Build verified reproducible; provenance attested. Remaining manual steps (see BUILDING.md):" >> "$GITHUB_STEP_SUMMARY"
- echo "1. Download the jar/SBOM assets and GPG-sign each locally with your ASF key." >> "$GITHUB_STEP_SUMMARY"
- echo "2. \`gh release upload $RELEASE_TAG *.asc\`" >> "$GITHUB_STEP_SUMMARY"
- echo "3. Start the dev@ vote, referencing this draft and its provenance attestation." >> "$GITHUB_STEP_SUMMARY"
- echo "4. On a passing vote: \`gh release edit $RELEASE_TAG --draft=false\`." >> "$GITHUB_STEP_SUMMARY"
+ rsync -av -e "ssh -i $key_dir/atr_key -p 2222 ${known_hosts_args[*]}" \
+ "target/cloudstore-${RELEASE_VERSION}.jar" \
+ "target/cloudstore-${RELEASE_VERSION}.jar.asc" \
+ "target/cloudstore-${RELEASE_VERSION}.jar.sha256" \
+ "target/cloudstore-${RELEASE_VERSION}-src.tar.gz" \
+ "target/cloudstore-${RELEASE_VERSION}-src.tar.gz.asc" \
+ "target/cloudstore-${RELEASE_VERSION}-src.tar.gz.sha256" \
+ "target/cloudstore-${RELEASE_VERSION}-cyclonedx.json" \
+ "target/cloudstore-${RELEASE_VERSION}-cyclonedx.json.asc" \
+ "target/cloudstore-${RELEASE_VERSION}-cyclonedx.json.sha256" \
+ "target/cloudstore-${RELEASE_VERSION}-cyclonedx.xml" \
+ "target/cloudstore-${RELEASE_VERSION}-cyclonedx.xml.asc" \
+ "target/cloudstore-${RELEASE_VERSION}-cyclonedx.xml.sha256" \
+ "github@${ATR_HOST}:/${ATR_PROJECT_KEY}/${RELEASE_VERSION}/"
+ rm -rf "$key_dir"
+
+ {
+ echo "### Composed release candidate on ATR"
+ echo "Build verified reproducible; artifacts signed and uploaded to ATR"
+ echo "(project \`$ATR_PROJECT_KEY\`, version \`$RELEASE_VERSION\`)."
+ echo "Remaining manual steps, in ATR:"
+ echo "1. Review the candidate and its checks on the ATR project page."
+ echo "2. Start the PMC vote from ATR; it links voters to the candidate there."
+ echo "3. On a passing vote, finish the release from ATR to publish it."
+ } >> "$GITHUB_STEP_SUMMARY"
diff --git a/.rat-excludes b/.rat-excludes
new file mode 100644
index 0000000..39ab72d
--- /dev/null
+++ b/.rat-excludes
@@ -0,0 +1,33 @@
+# 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
+#
+# http://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 RAT excludes for the packaged source release (cloudstore-<version>-src.tar.gz).
+# Ships at the archive root so a RAT scan of the extracted source release --
+# whether run by ATR or by hand -- picks up the same exclusions as this
+# project's own build (see pom.xml's apache-rat-plugin inputExcludes, which
+# this list is kept in step with by hand).
+.git/
+.idea/
+.*\.iml
+.*\.DS_Store
+pom.xml.versionsBackup
+.gitignore
+src/main/resources/cloudstore/required.txt
+src/main/resources/META-INF/MANIFEST.MF
+src/test/resources/auth-keys.xml
+src/test/resources/TestAuditLogs/.*
+dev-support/eclipse-formatter.xml
+NOTICE.*
diff --git a/BUILDING.md b/BUILDING.md
index d114523..f0ac0bc 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -113,27 +113,40 @@ dev-support/bump-version.sh 1.5-SNAPSHOT
## Releasing
-Cutting a release is two phases: an **automated** build+stage phase that runs
-in CI, and a **manual** sign/vote/publish phase performed by the release
-manager (RM). No private key lives in CI — GPG signing with the RM's
-personal ASF key remains a human step, as ASF release policy requires.
-What CI automates is everything before that: building, proving the build is
-reproducible, attesting its provenance, and staging the result as a draft
-GitHub Release.
+Cutting a release targets [Apache Trusted Releases](https://github.com/apache/tooling-trusted-releases)
+(ATR), the ASF's platform for composing, voting on, and publishing official
+releases. It is two phases: an **automated** build+compose phase that runs
+in CI and uploads a release candidate to ATR, and a **manual** vote+publish
+phase performed by the PMC through ATR itself. No private key lives outside
+ATR's own infrastructure: the compose phase signs with a dedicated
+"Automated Release Signing" key that ASF Infra provisions specifically for
+unattended CI use (see the setup checklist in `.github/workflows/release.yml`'s
+header comment), and voting/publishing happen as ASF release policy
+requires — a PMC vote is not something CI can substitute for.
Release builds activate the `release` profile, which:
1. Enforces a clean git tree via `buildnumber-maven-plugin`;
-2. Emits a CycloneDX SBOM next to the jar:
+2. Packages the whole source tree as the release's source artifact —
+ `target/cloudstore-<version>-src.tar.gz`, per
+ `dev-support/assembly/source-release.xml` — since every ASF release
+ needs at least one, and ATR checks for it;
+3. Emits a CycloneDX SBOM next to the jar:
- `target/cloudstore-<version>-cyclonedx.json`
- `target/cloudstore-<version>-cyclonedx.xml`
-3. Emits a SHA-256 digest next to the jar and each SBOM file:
+4. Emits a SHA-256 digest next to the jar, the source tarball, and each
+ SBOM file:
- `target/cloudstore-<version>.jar.sha256`
+ - `target/cloudstore-<version>-src.tar.gz.sha256`
- `target/cloudstore-<version>-cyclonedx.json.sha256`
- `target/cloudstore-<version>-cyclonedx.xml.sha256`
The SBOM is compile-scope only — `provided` dependencies are not in it because they are not shipped
-in the jar.
+in the jar. The source tarball ships plain `LICENSE`/`NOTICE` (not the
+`-binary` variants, which list third-party binary dependencies that aren't
+present in a source tree) and a `.rat-excludes` file at its root, so a RAT
+scan of the extracted tarball — whether run by ATR or by hand — uses the
+same exclusions as this project's own build.
The `.sha256` files are produced by `checksum-maven-plugin` in the `verify`
phase. They give downloaders a quick integrity check (`shasum -c
@@ -158,7 +171,19 @@ The build will fail if there are uncommitted changes.
Cannot create the build number because you have local modifications :
```
-### Phase 1: automated build + staging (CI)
+### One-time setup
+
+Before this workflow can be used at all, cloudstore's committee needs to be
+onboarded to ATR Trusted Publishing: ASF Security must confirm the build is
+reproducible, ASF Infra must cut the committee's "Automated Release Signing"
+key and store its private half as the `ATR_SIGNING_KEY` repository secret,
+and `.github/workflows/release.yml` must be registered under the *compose*
+phase of cloudstore's ATR release policy. The full checklist, including the
+repository variables to set (`ATR_HOST`, `ATR_PROJECT_KEY`, and friends),
+lives in that workflow file's header comment rather than being duplicated
+here — check there for the current state of that setup.
+
+### Phase 1: automated build + compose (CI)
After `dev-support/bump-version.sh <version>` and
`dev-support/update-site-docs.sh <version>` have been run and committed
@@ -173,78 +198,86 @@ gh run watch (gh run list --workflow=release.yml -L1 --json databaseId -q '.[0].
The workflow, from a clean checkout of the ref you dispatched from:
1. builds with the `release` profile *twice*, independently, and fails the
- job unless the jar and both SBOMs are byte-identical between the two
- builds — this is what backs "anyone else building this gets the same
- binary", rather than just asserting it;
-2. attests build provenance for the jar and SBOMs via
- `actions/attest-build-provenance` (keyless, Sigstore/OIDC-backed — no
- secret key stored in CI);
-3. stages everything as a **draft** GitHub Release tagged `v<version>`
- (superseding the old `tag-release-<timestamp>` scheme — one tag per
- release version now, since multiple runs for the same version just
- update the same draft).
-
-The job summary lists the Phase 2 steps below as a checklist.
-
-### Phase 2: manual sign, vote, publish (RM)
-
-```bash
-test -n "$ver"; or begin; echo "ERROR: \$ver is unset/empty -- run: set -gx ver <version>"; exit 1; end
-
-# Rebuild locally and sign -- reproducibility means this jar is byte-identical
-# to the one CI already staged, so signing it is equivalent to signing CI's.
-mvn clean install -Prelease,sign -DskipTests
-
-# Independent confirmation before trusting it: compare against the draft's
-# published digest.
-gh release download v$ver -D /tmp/release-$ver --pattern '*.sha256'
-[ "$(shasum -a 256 target/cloudstore-$ver.jar | awk '{print $1}')" = \
- "$(cat /tmp/release-$ver/cloudstore-$ver.jar.sha256)" ] && echo "reproducible: matches CI's build"
-
-# Upload just the signatures -- the jar/SBOMs/checksums are already staged.
-gh release upload v$ver \
- target/cloudstore-$ver.jar.asc \
- target/cloudstore-$ver-cyclonedx.json.asc \
- target/cloudstore-$ver-cyclonedx.xml.asc
-
-echo "go to the web ui to review, start the dev@ vote referencing the draft"
-echo "and its provenance attestation (gh attestation verify), and on a"
-echo "passing vote: gh release edit v$ver --draft=false"
-```
+ job unless the jar, the source tarball, and both SBOMs are all
+ byte-identical between the two builds — this is what backs "anyone else
+ building this gets the same binary", rather than just asserting it;
+2. attests build provenance for all four artifacts via
+ `actions/attest-build-provenance` (keyless, Sigstore/OIDC-backed —
+ independent of, and in addition to, ATR's own signature);
+3. signs all four artifacts with the committee's automated release
+ signing key;
+4. authenticates to ATR as a GitHub Actions Trusted Publisher (a GitHub
+ OIDC token, exchanged for a 20-minute single-project SSH key) and
+ uploads the signed artifacts, over rsync, into a new release candidate
+ on ATR.
+
+ATR then runs its own checks (signature, hash, archive structure, license,
+RAT, SBOM conformance) against the uploaded candidate automatically; the job
+summary points at where to review them.
+
+ATR itself doesn't need a git tag — it tracks the candidate by project and
+version — but tag the commit anyway so "Reproducing a release yourself"
+below stays meaningful: `git tag v$ver <ref>; git push origin v$ver`.
+
+### Phase 2: vote and publish (PMC, in ATR)
+
+From here the process is entirely in ATR, not this repository:
+
+1. Review the candidate and its check results on the ATR project page.
+2. Start the vote from ATR — it emails dev@ with a link to the candidate on
+ ATR (link only that page; see
+ [Staging and voting](https://github.com/apache/tooling-trusted-releases/blob/main/atr/docs/staging-and-voting.md#what-to-link-in-a-vote-announcement)
+ for why).
+3. PMC members vote, independently rebuilding and comparing hashes as
+ described below — this, not the automated signature, is what confirms
+ the CI-built artifacts are genuine.
+4. On a passing vote, finish the release from ATR. From Beta, ATR publishes
+ directly to `dist/release`; during Alpha it publishes to `dist/atr` and a
+ committer must move the files, as described in
+ [Promoting to release](https://github.com/apache/tooling-trusted-releases/blob/main/atr/docs/promoting-to-release.md).
### Reproducing a release yourself
-Anyone — CI, the RM, or a third party — gets the same binary from the same
-commit, provided they use the same JDK (Temurin 17, matching
-`release.yml`'s `Set up JDK` step; bytecode target is 1.8 either way):
+Anyone — a PMC member voting, or a third party after the fact — gets the
+same binary from the same commit, provided they use the same JDK (Temurin
+17, matching `release.yml`'s `Set up JDK` step; bytecode target is 1.8
+either way):
```bash
git checkout v$ver
mvn -Prelease clean package -DskipTests
-[ "$(shasum -a 256 target/cloudstore-$ver.jar | awk '{print $1}')" = \
- "$(curl -sL https://github.com/apache/hadoop-cloudstore/releases/download/v$ver/cloudstore-$ver.jar.sha256)" ] \
- && echo "reproducible"
+shasum -a 256 target/cloudstore-$ver.jar
+# compare against the .sha256 published alongside the candidate/release on ATR
```
This works because `project.build.outputTimestamp` in `pom.xml` pins the
jar's internal timestamps to a fixed point (HEAD's commit time at release-cut,
set by `dev-support/bump-version.sh`) instead of "whenever the build ran" —
see the [Maven reproducible builds guide](https://maven.apache.org/guides/mini/guide-reproducible-builds.html).
+Demonstrating exactly this was also the prerequisite for cloudstore's ATR
+Trusted Publishing eligibility in the first place.
-## Signing release artifacts
+## Signing release artifacts manually
-Activate the `sign` profile alongside `release` (as in the command
-above) to GPG-sign every attached artifact. The plugin produces a
-detached `.asc` next to each of:
+This is the fallback path: local smoke-testing of a release build, or
+composing a candidate on ATR by hand (browser upload or personal-key rsync)
+if Trusted Publishing isn't set up yet. `release.yml`'s automated compose
+(above) does the equivalent signing itself, with the committee's automated
+key, and does not need this.
+
+Activate the `sign` profile alongside `release` to GPG-sign every attached
+artifact with your own key. The plugin produces a detached `.asc` next to
+each of:
- `target/cloudstore-<version>.jar`
- `target/cloudstore-<version>.pom`
+- `target/cloudstore-<version>-src.tar.gz`
- `target/cloudstore-<version>-cyclonedx.json`
- `target/cloudstore-<version>-cyclonedx.xml`
Prerequisites:
-1. An OpenPGP key in the Hadoop committer KEYS file.
+1. An OpenPGP key in the Hadoop committer `KEYS` file.
2. `gpg-agent` running with the release key unlocked. A quick way to
warm the agent before the build is:
`echo test | gpg --clearsign -u <keyid> > /dev/null`.
@@ -271,9 +304,14 @@ compare directly:
gpg --verify cloudstore-$ver.jar.asc cloudstore-$ver.jar
```
-Phase 1 above already stages the jar, SBOMs, and `.sha256` digests on the
-draft release; Phase 2's `gh release upload v$ver *.asc` is what attaches
-the signatures produced here.
+To upload artifacts signed this way to ATR by hand, see the "How files reach
+ATR" section of
+[Staging and voting](https://github.com/apache/tooling-trusted-releases/blob/main/atr/docs/staging-and-voting.md#how-files-reach-atr).
+
+*Important* Although the build tries to keep cloud credentials in `src/test/resources/auth-keys.xml` out of the source tarball,
+along with all other build- and IDE-related artifacts, it is best to do a local release from a clean source directory not used
+for test runs.
+ATR is the preferred mechansim.
## How to bypass buildnumber checks
diff --git a/dev-support/assembly/source-release.xml b/dev-support/assembly/source-release.xml
new file mode 100644
index 0000000..8aab905
--- /dev/null
+++ b/dev-support/assembly/source-release.xml
@@ -0,0 +1,54 @@
+<!--
+ 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
+
+ http://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.
+-->
+
+<!--
+ Packages the whole source tree as the release's mandatory source
+ artifact, stripping out local build artifacts and possible cloud credentials
+ in auth-keys.xml
+-->
+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.2.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.2.0 http://maven.apache.org/xsd/assembly-2.2.0.xsd">
+ <id>src</id>
+ <formats>
+ <format>tar.gz</format>
+ </formats>
+ <includeBaseDirectory>true</includeBaseDirectory>
+ <baseDirectory>${project.artifactId}-${project.version}-src</baseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>${project.basedir}</directory>
+ <useDefaultExcludes>true</useDefaultExcludes>
+ <excludes>
+ <exclude>target/**</exclude>
+ <exclude>**/target/**</exclude>
+ <exclude>.git/**</exclude>
+ <exclude>.idea/**</exclude>
+ <exclude>.claude/**</exclude>
+ <exclude>**/*.iml</exclude>
+ <exclude>**/.DS_Store</exclude>
+ <exclude>pom.xml.versionsBackup</exclude>
+ <!-- CRITICAL: this must be excluded if anyone ever cuts a release from a local machine. -->
+ <exclude>src/test/resources/auth-keys.xml</exclude>
+ <!-- Binary-release-only notices; not applicable to a source tree. -->
+ <exclude>LICENSE-binary</exclude>
+ <exclude>NOTICE-binary</exclude>
+ </excludes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/pom.xml b/pom.xml
index 55e368d..66d3da1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -85,6 +85,7 @@
<junit.version>4.13.2</junit.version>
<!-- Add maven build version dependencies here, in order, prefixed with maven -->
+ <maven-assembly-plugin.version>3.8.0</maven-assembly-plugin.version>
<maven-buildnumber-plugin.version>3.3.0</maven-buildnumber-plugin.version>
<maven-checkstyle-plugin.version>3.6.0</maven-checkstyle-plugin.version>
<maven-compiler-plugin.version>3.15.0</maven-compiler-plugin.version>
@@ -306,6 +307,31 @@
</properties>
<build>
<plugins>
+ <!-- Every ASF release needs at least one source artifact; this is
+ cloudstore's. Packages the whole source tree per
+ dev-support/assembly/source-release.xml, honoring
+ project.build.outputTimestamp the same way maven-jar-plugin
+ does, so it stays reproducible alongside the jar and SBOMs. -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>${maven-assembly-plugin.version}</version>
+ <executions>
+ <execution>
+ <id>source-release</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>${project.basedir}/dev-support/assembly/source-release.xml</descriptor>
+ </descriptors>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
<!-- Emit a CycloneDX SBOM alongside the release jar.
compile scope only: provided/test deps (Hadoop, AWS SDK,
GCS, junit, hdfs) are intentionally excluded because they
@@ -364,6 +390,7 @@
<directory>${project.build.directory}</directory>
<includes>
<include>${project.artifactId}-${project.version}.jar</include>
+ <include>${project.artifactId}-${project.version}-src.tar.gz</include>
<include>${project.artifactId}-${project.version}-cyclonedx.json</include>
<include>${project.artifactId}-${project.version}-cyclonedx.xml</include>
</includes>
---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org