Releasing¶
The maintainer-facing runbook for cutting an Aegis-KMS release. This is the step-by-step you follow to ship a new version end-to-end.
This page renders the project-root RELEASING.md. The canonical source is at
github.com/sharma-bhaskar/aegis-kms/blob/main/RELEASING.md.
Releasing Aegis-KMS¶
This is the operator runbook for cutting a tagged release. The release.yml
GitHub Actions workflow does the heavy lifting on every v* tag push:
- CI gate (compile, scalafmt, scalafix, test) — same checks as the main branch CI.
- Publish library jars to Maven Central (
dev.aegiskms %% aegis-coreand friends) viasbt-ci-release. Skipped automatically if the signing secrets aren't configured. - Publish the
aegis-serverDocker image toghcr.io/<owner>/aegis-server:<version>using the built-inGITHUB_TOKEN. - Build the
aegis-cliuniversal tarball and attach it to a GitHub Release.
The version number is derived by sbt-dynver from the tag — v0.1.1 →
0.1.1 for the artifacts. Don't add a version := line to build.sbt;
that would override the derived value and ship every tag as
0.1.0-SNAPSHOT.
One-time setup (you, the maintainer, must do this once)¶
The Docker + GitHub Release path runs out of the box on a fresh repository. The Maven Central path requires four secrets that only you can set up.
1. Sonatype Central Portal account + namespace¶
Note: the legacy OSSRH host (
s01.oss.sonatype.org) was sunset on 2025-06-30. Publishing now goes through the Central Portal (central.sonatype.com). The build is configured for it:sbt-ci-release1.11+ on sbt 1.11+ targets the Central Portal automatically — there is nosonatypeCredentialHostsetting (adding one would break publishing).
If the dev.aegiskms namespace is already verified, skip to step 2. If not:
- Sign up / log in at https://central.sonatype.com.
- Register the
dev.aegiskmsnamespace under Account → Namespaces. The portal verifies ownership via a DNS TXT record onaegiskms.dev(it shows the exact token to add) or via the GitHubsharma-bhaskarnamespace. - Once verified, generate a user token (NOT your account password) at
https://central.sonatype.com/account → "Generate User Token". The token's
username and password are the values you'll set as GitHub Action secrets
below (
SONATYPE_USERNAME/SONATYPE_PASSWORD).
2. GPG signing key¶
Maven Central rejects unsigned artifacts. sbt-ci-release expects the
private key as a base64-encoded blob in an env var.
```bash
Generate a 4096-bit RSA key. Pick a passphrase you'll remember.¶
gpg --full-generate-key
Find the key id (the long hex string) and publish the public half to a¶
keyserver so verifiers can fetch it.¶
gpg --list-secret-keys --keyid-format LONG
gpg --keyserver keyserver.ubuntu.com --send-keys
Export the private key and base64-encode it (no line wrapping).¶
gpg --armor --export-secret-keys
Save the base64 blob; it goes into PGP_SECRET below.
3. GitHub Action secrets¶
In the GitHub repo, go to Settings → Secrets and variables → Actions → New repository secret and add:
| Secret name | Value |
|---|---|
PGP_SECRET |
The base64 blob from step 2. |
PGP_PASSPHRASE |
The passphrase you chose for the GPG key. |
SONATYPE_USERNAME |
The user-token name from step 1. |
SONATYPE_PASSWORD |
The user-token value from step 1. |
The release workflow gates the Maven publish step on PGP_SECRET != ''; if
any of these are missing the workflow ships the Docker image + CLI tarball
only and adds a ::notice to the run output instead of failing.
Cutting a release¶
Once setup is done, releasing is one command per tag:
```bash
1. Update CHANGELOG: rename the ## Unreleased section to ## 0.1.1 — YYYY-MM-DD,¶
open a fresh ## Unreleased block above it. Commit the change to main.¶
2. Tag and push. sbt-dynver reads the tag verbatim, minus the v prefix.¶
git tag v0.1.1 git push origin v0.1.1 ```
That's it. Watch the workflow at https://github.com/sharma-bhaskar/aegis-kms/actions/workflows/release.yml. On success:
aegis-core_3etc. appear at https://central.sonatype.com/artifact/dev.aegiskms/aegis-core_3 (allow ~10 min for staging → release sync).- The Docker image is at
ghcr.io/sharma-bhaskar/aegis-server:<version>(e.g.:0.2.0). For a stablevX.Y.Ztag the workflow also publishes the floating:X.Yand:latestaliases; pre-release tags (e.g.v0.3.0-rc.1) get the exact tag only — no:latest. - A release page on GitHub carries the CLI tarball and auto-generated changelog notes.
Troubleshooting¶
| Symptom | Likely cause | What to do |
|---|---|---|
Workflow's "Publish to Maven Central" step is skipped with a ::notice |
One of the four secrets above is unset | Set them in repo settings; subsequent tags will publish |
| Sonatype rejects with "Missing: gpg signature for ..." | GPG key not propagated to the keyserver yet | Re-run gpg --keyserver ... --send-keys against multiple servers; wait 10 min and retry the workflow |
| Sonatype rejects with "Invalid POM: missing description" | One of the modules lost its description := line |
Restore in build.sbt; the ThisBuild / description fallback should also catch this |
| Tag pushed but workflow didn't fire | Branch protection or workflow on: filter |
Verify the tag matches v*; check the Actions tab for queued runs |
Docker tag missing the v prefix |
Intentional — the workflow strips v so v0.1.1 → ghcr.io/...:0.1.1 |
This is the documented format |
For deeper diagnostics, the workflow run page captures the full sbt output; the Central Portal's Deployments view (central.sonatype.com) shows the upload's validation status and any rejection reasons.
Pre-release / SNAPSHOT versions¶
Pushes to main (without a tag) automatically produce
0.1.1+<n>-<sha>-SNAPSHOT artifacts via sbt-dynver. These are useful for
internal smoke tests but are not published anywhere by default. To publish a
SNAPSHOT manually from your laptop:
```bash
Set the same env vars the workflow sets (PGP_SECRET, etc.).¶
sbt ci-release ```
SNAPSHOTs publish to the Central Portal snapshot repository
(https://central.sonatype.com/repository/maven-snapshots/) and skip the
release validation/publish step that tagged versions go through.