Documents
RELEASING
RELEASING
Type
External
Status
Published
Created
Feb 27, 2026
Updated
Apr 3, 2026
Updated by
Dosu Bot

Releasing opnDossier#

This document describes the release process for opnDossier.

Table of Contents#

Version Numbering#

opnDossier follows Semantic Versioning 2.0.0:

Version ComponentWhen to IncrementExample
MAJOR (X.0.0)Breaking changes to CLI interface, config format, or APIRemoving a flag, changing output format
MINOR (0.X.0)New features, backward-compatible additionsNew audit plugin, new output format
PATCH (0.0.X)Bug fixes, documentation, performance improvementsFix parsing bug, typo fixes

Pre-release Tags#

  • Release Candidates: v1.2.0-rc1, v1.2.0-rc2 - Feature-complete, needs testing
  • Beta: v1.2.0-beta.1 - Feature incomplete, early testing
  • Alpha: v1.2.0-alpha.1 - Experimental, unstable

Prerequisites#

Required Tools#

Install these tools before creating a release:

# Install via mise (recommended - see .mise.toml)
mise install

# Or install manually:
# goreleaser - https://goreleaser.com/install/
brew install goreleaser/tap/goreleaser

# git-cliff - https://git-cliff.org/docs/installation
brew install git-cliff

# cosign v3 - https://docs.sigstore.dev/cosign/installation/
# Note: v3+ uses keyless signing by default with .sigstore.json bundles
brew install cosign

# cyclonedx-gomod (for SBOM) - https://github.com/CycloneDX/cyclonedx-gomod
go install github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latest

# go-licenses (for third-party notices) - https://github.com/google/go-licenses
go install github.com/google/go-licenses@latest

# quill (for macOS code signing, optional) - https://github.com/anchore/quill
# Only needed if you want to sign and notarize macOS binaries
curl -sSfL https://raw.githubusercontent.com/anchore/quill/main/install.sh | sh -s -- -b /usr/local/bin

Environment Variables (Optional)#

For signed releases, configure these environment variables:

# macOS Code Signing with Quill (optional)
# See: https://github.com/anchore/quill
export QUILL_SIGN_P12="path/to/certificate.p12" # or base64-encoded P12
export QUILL_SIGN_PASSWORD="certificate-password"
export QUILL_NOTARY_KEY="path/to/AuthKey_XXXXX.p8" # Apple API key
export QUILL_NOTARY_KEY_ID="XXXXXXXXXX" # Key ID from App Store Connect
export QUILL_NOTARY_ISSUER="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" # Issuer UUID

# Linux Package Signing (optional)
export RPM_SIGNING_KEY_FILE="path/to/rpm-key"
export DEB_SIGNING_KEY_FILE="path/to/deb-key"
export APK_SIGNING_KEY_FILE="path/to/apk-key"

Note

Cosign v3 uses keyless signing via Sigstore OIDC, so no signing keys are needed for artifact signatures when running in GitHub Actions.

GitHub Permissions#

The release workflow requires:

  • contents: write - Create releases and upload assets
  • id-token: write - SLSA provenance and Cosign keyless signing

GitHub Secrets#

For GPG signing of release artifacts, add these repository secrets:

SecretDescription
GPG_PRIVATE_KEYBase64-encoded GPG private key (gpg --armor --export-secret-keys EMAIL | base64)
GPG_PASSPHRASEPassphrase for the GPG key

Note

GPG signing is optional. If these secrets are not set, releases will still be created with Cosign signatures for checksums.

Pre-release Checklist#

Before creating a release, verify:

  • All CI checks pass on main branch
  • All issues/PRs for the milestone are closed
  • CHANGELOG.md is up to date (or will be auto-generated)
  • Version references in code are correct (if any hardcoded)
  • Documentation reflects new features/changes
  • Breaking changes are documented

Verify CI Status#

# Check CI status for main branch
gh run list --branch main --limit 5

# View specific workflow run
gh run view <run-id>

Close Milestone#

# List open milestones
gh milestone list --state open

# Close milestone (goreleaser will also auto-close on release)
gh milestone edit <milestone-number> --state closed

Creating a Release#

Step 1: Validate Configuration#

# Check goreleaser configuration
goreleaser check

# Preview what would be built (no publish)
goreleaser release --snapshot --clean

# Check generated artifacts
ls -la dist/

Note

The release workflow automatically generates THIRD_PARTY_NOTICES via the just notices command as a GoReleaser before-hook. This file provides human-readable license attribution for all dependencies and is included in all distribution archives and packages. The formatting is controlled by the template at packaging/notices.tpl.

Step 2: Generate Changelog Preview#

# Preview changelog for unreleased commits
git-cliff --unreleased

# Preview full changelog
git-cliff --output /dev/stdout

Step 3: Create and Push Tag#

# Ensure you're on main with latest changes
git checkout main
git pull origin main

# Create annotated tag
git tag -a v1.2.0 -m "Release v1.2.0"

# Push tag to trigger release workflow
git push origin v1.2.0

Step 4: Create GitHub Release#

Option A: Via GitHub UI (Recommended)

  1. Go to Releases
  2. Click "Draft a new release"
  3. Select the tag you just pushed
  4. Click "Generate release notes" for auto-generated notes
  5. Review and edit the release notes
  6. Click "Publish release"

Option B: Via CLI

# Create release from tag (triggers workflow)
gh release create v1.2.0 \
  --title "v1.2.0" \
  --generate-notes

# Or with custom notes
gh release create v1.2.0 \
  --title "v1.2.0" \
  --notes-file RELEASE_NOTES.md

Step 5: Monitor Release Workflow#

# Watch the release workflow
gh run watch

# Or list recent workflow runs
gh run list --workflow=release.yml --limit 5

Post-release Verification#

After the release workflow completes:

Verify Artifacts#

# List release assets
gh release view v1.2.0

# Download and verify checksums
gh release download v1.2.0 --pattern "*checksums*"
sha256sum -c opnDossier_checksums.txt

Verify SLSA Provenance#

# Install slsa-verifier
brew install slsa-framework/tap/slsa-verifier

# Download provenance
gh release download v1.2.0 --pattern "*.intoto.jsonl"

# Verify provenance
slsa-verifier verify-artifact \
  --provenance-path opnDossier-v1.2.0.intoto.jsonl \
  --source-uri github.com/EvilBit-Labs/opnDossier \
  --source-tag v1.2.0 \
  opnDossier_checksums.txt

Verify Cosign Signatures (v3)#

# Download checksum file and its signature bundle
gh release download v1.2.0 --pattern "*checksums*"
gh release download v1.2.0 --pattern "*.sigstore.json"

# Verify signature with Cosign v3 (keyless, using Sigstore bundle format)
cosign verify-blob \
  --certificate-identity "https://github.com/EvilBit-Labs/opnDossier/.github/workflows/release.yml@refs/tags/v1.2.0" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  --bundle opnDossier_checksums.txt.sigstore.json \
  opnDossier_checksums.txt

Note

Cosign v3 uses .sigstore.json bundle format instead of separate .sig and .pem files.

Verify GPG Signatures#

All release archives and packages are signed with the EvilBit Labs software signing key.

# Import the public key (one-time setup)
curl -sSL https://raw.githubusercontent.com/EvilBit-Labs/opnDossier/main/keys/software-signing.asc | gpg --import

# Or from a local clone
gpg --import keys/software-signing.asc

# Download an artifact and its signature
gh release download v1.2.0 --pattern "opnDossier_Linux_x86_64.tar.gz*"

# Verify the signature
gpg --verify opnDossier_Linux_x86_64.tar.gz.sig opnDossier_Linux_x86_64.tar.gz

Key details:

  • Email: software@evilbitlabs.io
  • Fingerprint: 138B FA78 8F37 7661 EA48 2C1D EFC6 F4CA BED2 2E8E
  • Key type: RSA 4096
  • Expires: 2030-02-03

Test Installation#

# Test binary download and execution
gh release download v1.2.0 --pattern "*Darwin_arm64*"
tar -xzf opnDossier_Darwin_arm64.tar.gz
./opndossier --version

# Test package installation (Linux)
# Debian/Ubuntu
sudo dpkg -i opndossier_1.2.0_amd64.deb
opndossier --version

# RHEL/Fedora
sudo rpm -i opndossier-1.2.0-1.x86_64.rpm
opndossier --version

Release Candidates#

Use release candidates for significant releases that need broader testing.

Creating an RC#

# Tag release candidate
git tag -a v1.2.0-rc1 -m "Release candidate 1 for v1.2.0"
git push origin v1.2.0-rc1

# Create pre-release on GitHub
gh release create v1.2.0-rc1 \
  --title "v1.2.0-rc1" \
  --prerelease \
  --generate-notes

Promoting RC to Release#

If the RC is stable:

# Tag the same commit as final release
git tag -a v1.2.0 -m "Release v1.2.0"
git push origin v1.2.0

# Create the final release
gh release create v1.2.0 --title "v1.2.0" --generate-notes

Hotfix Process#

For urgent fixes to a released version:

Step 1: Create Hotfix Branch#

# Branch from the release tag
git checkout -b hotfix/v1.2.1 v1.2.0

# Make the fix
# ... edit files ...

# Commit with conventional commit format
git commit -m "fix(parser): handle edge case in XML parsing"

Step 2: Create PR and Merge#

# Push hotfix branch
git push origin hotfix/v1.2.1

# Create PR targeting main
gh pr create --title "fix: critical parsing bug" --base main

# After review and merge, tag the release
git checkout main
git pull
git tag -a v1.2.1 -m "Hotfix release v1.2.1"
git push origin v1.2.1

Troubleshooting#

Common Issues#

goreleaser check fails#

# Validate YAML syntax
yamllint .goreleaser.yaml

# Check for deprecated options
goreleaser check --deprecated

Cosign signing fails#

# Verify cosign is configured for keyless signing
cosign version

# Test keyless signing locally
echo "test" | cosign sign-blob --yes - --bundle test.bundle

SLSA provenance fails#

Check the workflow logs:

gh run view <run-id> --log-failed

Manual Release (Emergency)#

If the automated workflow fails, you can release manually:

# Build locally
goreleaser release --clean

# Or skip certain steps
goreleaser release --clean --skip=sign

macOS Code Signing (Optional)#

macOS binaries can be signed and notarized using Quill, an open-source alternative to gon that works cross-platform.

Setup#

  1. Obtain an Apple Developer certificate and API key from App Store Connect
  2. Export the certificate as a P12 file
  3. Set the environment variables listed in Environment Variables

How It Works#

The goreleaser configuration includes a post-build hook for macOS:

  • Snapshot builds: Ad-hoc signing only (no notarization)
  • Release builds: Full signing and notarization with Apple

If QUILL_SIGN_P12 is not set, macOS signing is skipped entirely.

Release Artifacts#

Each release includes:

ArtifactDescription
opnDossier_<OS>_<arch>.tar.gzBinary archives (Linux, macOS, FreeBSD) with man page and completions
opnDossier_<OS>_<arch>.zipBinary archive (Windows) with THIRD_PARTY_NOTICES
opndossier_<version>_amd64.debDebian/Ubuntu package with THIRD_PARTY_NOTICES in /usr/share/doc
opndossier-<version>-1.x86_64.rpmRHEL/Fedora package with THIRD_PARTY_NOTICES in /usr/share/doc
opndossier_<version>_x86_64.apkAlpine package with THIRD_PARTY_NOTICES
opndossier-<version>-1-x86_64.pkg.tar.zstArch Linux package with THIRD_PARTY_NOTICES
opnDossier_checksums.txtSHA256 checksums for all artifacts
opnDossier_checksums.txt.sigstore.jsonCosign v3 signature bundle
*.sigGPG detached signatures for archives/packages
*.bom.jsonSoftware Bill of Materials (CycloneDX SBOM)
THIRD_PARTY_NOTICESHuman-readable license attribution for all dependencies

Quick Release Checklist#

Copy-paste checklist for cutting a release. See sections above for details on each step.

Pre-flight#

  • CI green on maingh run list --branch main --limit 5
  • just ci-check passes locally (lint, tests, race detector)
  • Milestone closed — gh milestone list --state open, then close if exists
  • No uncommitted or unrelated changes on main

Prepare#

  • Generate changelog — just changelog-version vX.Y.Z
  • Review CHANGELOG.md — verify entries are correct and complete
  • Write or update RELEASE_NOTES.md
  • Commit RELEASE_NOTES.md and CHANGELOG.md to main
  • Push to main

Tag and Release#

  • Ensure you are on main with latest — git checkout main && git pull origin main
  • Create annotated tag — git tag -a vX.Y.Z -m "Release vX.Y.Z"
  • Push tag — git push origin vX.Y.Z
  • Create GitHub release — gh release create vX.Y.Z --title "vX.Y.Z" --notes-file RELEASE_NOTES.md

Reminder: Always tag the commit on main, never a feature branch head (see GOTCHAS.md #12.1).

Post-release Verification#

  • Monitor workflow — gh run watch or gh run list --workflow=release.yml
  • Verify artifacts — gh release view vX.Y.Z
  • Verify cosign signature — download checksums + .sigstore.json, run cosign verify-blob
  • Test binary — download, run opndossier --version, confirm version
  • Verify Docker — docker pull ghcr.io/evilbit-labs/opndossier:vX.Y.Z
  • Verify Homebrew cask updated (if HOMEBREW_TAP_TOKEN is set)