This document outlines the process for creating and publishing new releases of the Replicated SDK.
The release process is automated through GitHub Actions. When a new version tag is pushed to the repository, it triggers a workflow that:
- Builds and tests the code
- Creates a Docker image using Chainguard's melange and apko
- Builds and publishes Helm charts
- Generates release notes
- Creates security attestations
To create releases, you'll need:
-
1Password Service Account Tokens:
- For staging environment access
- For production environment access
-
GitHub Token:
- With permissions to trigger the SLSA GitHub workflow
Supported version tag formats (without 'v' prefix):
- Release:
X.Y.Z(e.g.,1.2.3) - Beta:
X.Y.Z-betaorX.Y.Z-beta.N(e.g.,1.2.3-betaor1.2.3-beta.1) - Alpha:
X.Y.Z-alphaorX.Y.Z-alpha.N(e.g.,1.2.3-alphaor1.2.3-alpha.1)
Note: While older beta releases used a 'v' prefix (e.g., v1.0.0-beta.28), current releases do not use this prefix.
-
Create and push a new tag:
git tag X.Y.Z git push origin X.Y.Z
-
The GitHub Actions workflow will automatically:
- Run all tests
- Build the Go binaries
- Create and push Docker images
- Build and publish Helm charts
- Generate release notes
- Create a GitHub release
The release process is handled by the Publish function in dagger/publish.go. Here's how it works:
-
Package Building (Melange):
- The process starts by building packages using Chainguard's melange
- Version strings are sanitized for Alpine/Wolfi compatibility (e.g.,
1.6.0-beta.5becomes1.6.0_beta.5-r0) - Packages are built for both AMD64 and ARM64 architectures
- The melange build process:
// Updates melange.yaml with correct version melangeYaml = strings.Replace(melangeYaml, "version: 1.0.0", fmt.Sprintf("version: %s", packageVersion), 1) // Builds packages for both architectures amdPackages := dag.Melange().Build(source.File("deploy/melange.yaml"), dagger.MelangeBuildOpts{ SourceDir: source, Arch: "x86_64", }) armPackages := dag.Melange().Build(source.File("deploy/melange.yaml"), dagger.MelangeBuildOpts{ SourceDir: source, Arch: "aarch64", })
-
Container Image Building (Apko):
- Uses Chainguard's apko to build the final container image
- The apko.yaml is updated with:
- The correct package version constraint
- Environment variables
- Images are built and published to multiple registries:
// Updates apko.yaml with package version apkoYaml = strings.Replace( apkoYaml, " - replicated\n", fmt.Sprintf(" - replicated=%s-r0\n", sanitizeVersionForMelange(version)), 1, )
-
Image Publishing: The process publishes images to three different registries based on the build type:
- Development (if enabled):
ttl.sh/replicated/replicated-sdk:${VERSION} - Staging (if enabled):
index.docker.io/replicated/replicated-sdk:${VERSION} registry.staging.replicated.com/library/replicated-sdk-image:${VERSION} - Production (if enabled):
index.docker.io/replicated/replicated-sdk:${VERSION} registry.replicated.com/library/replicated-sdk-image:${VERSION}
- Development (if enabled):
-
Helm Chart Publishing: The process builds and publishes Helm charts to both staging and production registries:
- Updates values.yaml with correct version and registry information
- Publishes to:
- Staging:
registry.staging.replicated.com/library - Production:
registry.replicated.com/library
- Staging:
// Example of chart publishing process ctr := dag.Container().From("alpine/helm:latest"). WithMountedDirectory("/source", source). WithWorkdir("/source/chart"). WithNewFile("/source/chart/values.yaml", valuesYaml). WithEnvVariable("HELM_USERNAME", username). WithSecretVariable("HELM_PASSWORD", password). WithExec([]string{"helm", "dependency", "update"}). WithExec([]string{"helm", "package", "--version", version, "--app-version", version, "."}). WithExec([]string{"helm", "registry", "login", "registry.replicated.com", "--username", username, "--password", password}). WithExec([]string{"helm", "push", helmChartFilename, "oci://registry.replicated.com/library"})
-
SLSA Provenance: If SLSA provenance is enabled, the process triggers a GitHub workflow:
if slsa { ctr := dag.Gh(). Run(fmt.Sprintf(`api /repos/replicatedhq/replicated-sdk/actions/workflows/slsa.yml/dispatches \ -f ref=main \ -f inputs[digest]=%s`, digest), dagger.GhRunOpts{ Token: githubToken, }, ) }
Important notes about SLSA provenance:
- This step is automatically triggered by the Dagger pipeline during production releases
- Requires a GitHub token with permissions to trigger the SLSA workflow (
slsa.yml) - The workflow is triggered via GitHub API to generate and attach provenance to the image
- This step is skipped for development and staging releases
Each release includes:
- SLSA provenance attestation for all container images
- Daily security scans using Grype
- Automated vulnerability reporting
After a release is published, verify:
-
Docker Image:
docker pull registry.replicated/replicated-sdk-image:X.Y.Z
-
Helm Charts:
# List chart versions helm registry login registry.replicated.com helm search repo replicated --versions # Pull chart helm pull oci://registry.replicated.com/library/replicated --version X.Y.Z
-
Image Attestations: Use the verification script in the
certsdirectory to verify SLSA provenance, image signatures, and SBOM:./certs/verify-image.sh --env <dev|stage|prod> --version X.Y.Z --digest <image-digest>
The script verifies:
- SLSA provenance attestation
- Image signatures using environment-specific public keys
- SBOM content and signatures
To view the full SBOM content:
./certs/verify-image.sh --env <dev|stage|prod> --version X.Y.Z --digest <image-digest> --show-sbom
If the release workflow fails:
- Check the GitHub Actions logs for errors
- Common issues:
- Failed tests
- Docker registry authentication issues
- Helm chart validation failures
- Version format issues with melange/apko builds
- Missing or invalid credentials
- Insufficient GitHub token permissions
After a successful release:
- Verify the GitHub release is created
- Check the documentation PR in replicated-docs
- Monitor for any reported issues
- Update the changelog if necessary
If you encounter issues with the release process:
- Check the GitHub Actions logs
- Review the workflow error messages
- Contact the maintainers team
If issues are discovered after release:
- Tag and push a new patch release with fixes
Note: Always prefer forward fixes over rollbacks when possible.