Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
1ebe72a
release: freeze 0.1.0 surface and revision
aalsanie Sep 29, 2026
f75b858
release: configure Maven publications and signing
aalsanie Sep 29, 2026
8870cb1
release: build and verify Central bundle
aalsanie Sep 29, 2026
39c0785
release: verify Central bundle with ephemeral signing
aalsanie Sep 29, 2026
a6bec6a
release: harden Central staging task configuration
aalsanie Sep 29, 2026
c551065
release: exercise signing with protected ephemeral key
aalsanie Sep 29, 2026
df8d927
release: require Central publication signatures
aalsanie Sep 29, 2026
d7b7a77
release: remove execution-time project access
aalsanie Sep 29, 2026
e5bce4c
release: verify Central signatures end to end
aalsanie Sep 29, 2026
b90d35b
release: package CLI artifacts and bind release identity
aalsanie Sep 29, 2026
268f9bf
release: verify isolated Maven consumption
aalsanie Sep 29, 2026
708ee67
release: harden artifact verification
aalsanie Sep 29, 2026
5cffca8
release: fix consumer smoke and classify release tests
aalsanie Sep 29, 2026
a2cbaf1
docs: simplify 0.1.0 changelog
aalsanie Sep 29, 2026
68faa9f
release: fix CLI distribution task graph
aalsanie Sep 29, 2026
ed2880b
release: expose verified release identity
aalsanie Sep 29, 2026
5c89f88
release: add Central Portal client
aalsanie Sep 29, 2026
23f9799
release: add tag-governed Central publishing
aalsanie Sep 29, 2026
56e962b
release: enforce publication workflow policy
aalsanie Sep 29, 2026
273b904
docs: surface benchmark charts in README
aalsanie Sep 29, 2026
172630e
release: make Central mutations non-retrying
aalsanie Sep 29, 2026
69ec95a
Update section header
aalsanie Sep 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions .github/workflows/central-preflight.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
name: Central Release Preflight

on:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: central-release-preflight
cancel-in-progress: false

jobs:
preflight:
runs-on: ubuntu-latest
environment: release
steps:
- name: Checkout main
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false
fetch-depth: 0

- name: Require main
shell: bash
run: |
set -euo pipefail
test "$GITHUB_REF" = "refs/heads/main"
git fetch origin main --no-tags
test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)"

- name: Set up Java
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: '21'

- name: Set up Gradle
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0
with:
cache-provider: basic

- name: Load release identity
shell: bash
run: |
set -euo pipefail
./gradlew writeReleaseIdentity --stacktrace
cat build/release/identity.env >> "$GITHUB_ENV"

- name: Require release credentials
shell: bash
env:
MAVEN_GPG_PRIVATE_KEY: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
CENTRAL_TOKEN_USERNAME: ${{ secrets.CENTRAL_TOKEN_USERNAME }}
CENTRAL_TOKEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN_PASSWORD }}
run: |
set -euo pipefail
test -n "$MAVEN_GPG_PRIVATE_KEY"
test -n "$MAVEN_GPG_PASSPHRASE"
test -n "$CENTRAL_TOKEN_USERNAME"
test -n "$CENTRAL_TOKEN_PASSWORD"

- name: Build signed Central bundle
env:
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
run: ./gradlew centralBundle --stacktrace

- name: Verify signatures
shell: bash
env:
MAVEN_GPG_PRIVATE_KEY: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
run: |
set -euo pipefail
export GNUPGHOME="$RUNNER_TEMP/bounded-origin-preflight-gpg"
install -d -m 700 "$GNUPGHOME"
printf '%s\n' "$MAVEN_GPG_PRIVATE_KEY" | gpg --batch --import

signature_count=0
while IFS= read -r -d '' signature; do
gpg --batch --verify "$signature" "${signature%.asc}"
signature_count=$((signature_count + 1))
done < <(find build/central-staging -type f -name '*.asc' -print0)
test "$signature_count" -eq 16

- name: Prepare Central authorization
shell: bash
env:
CENTRAL_TOKEN_USERNAME: ${{ secrets.CENTRAL_TOKEN_USERNAME }}
CENTRAL_TOKEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN_PASSWORD }}
run: |
set -euo pipefail
encoded="$(printf '%s:%s' "$CENTRAL_TOKEN_USERNAME" "$CENTRAL_TOKEN_PASSWORD" | base64 | tr -d '\n')"
authorization="Bearer $encoded"
echo "::add-mask::$encoded"
echo "::add-mask::$authorization"
echo "CENTRAL_AUTHORIZATION=$authorization" >> "$GITHUB_ENV"

- name: Upload, validate, consume and drop
shell: bash
run: |
set -euo pipefail

public_count="$(scripts/central-portal.sh public-count "$RELEASE_VERSION")"
if [[ "$public_count" != "0" ]]; then
echo "0.1.0 is already visible on Maven Central; preflight must run before publication." >&2
exit 1
fi

deployment_id="$(
scripts/central-portal.sh upload \
"build/distributions/$RELEASE_ARTIFACT_BASE-central-bundle.zip" \
"$RELEASE_ARTIFACT_BASE-preflight-$GITHUB_RUN_ID"
)"

validated=0
cleanup() {
if [[ "$validated" == "1" ]]; then
scripts/central-portal.sh drop "$deployment_id" || true
fi
}
trap cleanup EXIT

scripts/central-portal.sh wait-state "$deployment_id" VALIDATED >/dev/null
validated=1

export BOUNDED_ORIGIN_REPOSITORY_AUTHORIZATION="$CENTRAL_AUTHORIZATION"
GRADLE_USER_HOME="$RUNNER_TEMP/preflight-consumer-gradle" \
./gradlew --no-daemon -p release-tests/consumer clean run \
-PboundedOriginRepository="https://central.sonatype.com/api/v1/publisher/deployment/$deployment_id/download/" \
-PboundedOriginVersion="$RELEASE_VERSION" \
--refresh-dependencies --stacktrace

scripts/central-portal.sh drop "$deployment_id"
validated=0
trap - EXIT
171 changes: 171 additions & 0 deletions .github/workflows/release-verification.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
name: Release Verification

on:
push:
branches: [release/0.1.0]
pull_request:
branches: [main]
paths:
- build.gradle.kts
- bounded-origin-cli/build.gradle.kts
- release-tests/**
- scripts/verify-release-*.sh
- .github/workflows/release-verification.yml
- .github/workflows/release.yml
- .github/workflows/central-preflight.yml
- scripts/central-portal.sh
- scripts/verify-release-workflow-policy.sh

permissions:
contents: read

concurrency:
group: release-verification-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
central-bundle:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false

- name: Set up Java
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: '21'

- name: Set up Gradle
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0
with:
cache-provider: basic

- name: Build and verify Central bundle with ephemeral signing key
shell: bash
run: |
set -euo pipefail
export GNUPGHOME="$RUNNER_TEMP/bounded-origin-release-gpg"
install -d -m 700 "$GNUPGHOME"

if ./gradlew :bounded-origin-api:verifyCentralSigningCredentials --stacktrace; then
echo "Central signing credential verification unexpectedly passed without a key" >&2
exit 1
fi

cat > "$RUNNER_TEMP/bounded-origin-release-key.conf" <<'EOF'
Key-Type: RSA
Key-Length: 2048
Subkey-Type: RSA
Subkey-Length: 2048
Name-Real: Bounded Origin CI
Name-Email: ci@bounded-origin.invalid
Expire-Date: 0
Passphrase: bounded-origin-ci-only
%commit
EOF

gpg --batch --generate-key "$RUNNER_TEMP/bounded-origin-release-key.conf"
export ORG_GRADLE_PROJECT_signingKey
ORG_GRADLE_PROJECT_signingKey="$(
gpg --batch --pinentry-mode loopback \
--passphrase bounded-origin-ci-only \
--armor --export-secret-keys ci@bounded-origin.invalid
)"
export ORG_GRADLE_PROJECT_signingPassword=bounded-origin-ci-only

./gradlew centralBundle --stacktrace

test -s build/distributions/bounded-origin-0.1.0-central-bundle.zip

signature_count=0
while IFS= read -r -d '' signature; do
gpg --batch --verify "$signature" "${signature%.asc}"
signature_count=$((signature_count + 1))
done < <(find build/central-staging -type f -name '*.asc' -print0)

test "$signature_count" -eq 16

- name: Negative release-contract tests
shell: bash
run: bash scripts/verify-release-negative.sh

cli-release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false

- name: Set up Java
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: '21'

- name: Set up Gradle
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0
with:
cache-provider: basic

- name: Build and verify CLI release artifacts
run: ./gradlew :bounded-origin-cli:cliReleaseArtifacts --stacktrace

external-consumer:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false

- name: Set up Java
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: '21'

- name: Set up Gradle
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0
with:
cache-provider: basic

- name: Resolve and run isolated Maven consumer
run: ./gradlew verifyExternalMavenConsumer --stacktrace

release-reproducibility:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false

- name: Set up Java
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: '21'

- name: Set up Gradle
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0
with:
cache-provider: basic

- name: Verify release artifact reproducibility
shell: bash
run: bash scripts/verify-release-reproducible.sh

release-policy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false

- name: Verify tag-only release policy
run: bash scripts/verify-release-workflow-policy.sh
Loading
Loading