The release.yaml workflow handles the complete release process for connector repositories, including building, signing, attestation, and publishing.
When a tag is pushed to a connector repository, the shared release workflow:
- Builds binaries for macOS and Linux (with Apple codesigning)
- Builds Windows zip and MSI installer (with WiX Toolset)
- Builds multi-arch Docker images
- Signs all artifacts with Sigstore (keyless)
- Generates SLSA provenance attestations
- Publishes to S3 and ECR Public
- Records the release in the connector registry API
Validates workflow inputs before proceeding:
- Ensures tag is valid semver starting with 'v' (e.g.,
v1.2.3) - Ensures
dockerfile_templateis only used whenlambda: false - Ensures
docker_extra_filesis only used whendockerfile_templateis set - Ensures
msi_wxs_pathhas no path traversal (..or absolute paths) - Ensures
GORELEASER_PRO_KEYis provided whenmsi: true
Resolves the exact SHA of the shared workflow being used. This pinned reference is embedded in all provenance attestations, ensuring verifiability.
Builds and signs binary archives for macOS and Linux:
- Cross-compiles for darwin/linux (amd64/arm64)
- Apple codesigning via gon (macOS only)
- Generates SBOMs using Syft
- Creates SLSA v1 provenance attestations
- Signs SBOMs as attestation bundles
- Uploads all artifacts to S3
Outputs: *.zip (macOS), *.tar.gz (Linux), *.provenance.sigstore.json, *.sbom.sigstore.json
Builds Windows zip and MSI installer:
- Native Windows build on Windows runner (not cross-compiled)
- Produces both
.ziparchive and.msiinstaller - MSI built using WiX Toolset with GoReleaser Pro
- Deterministic UpgradeCode via UUID v5 from repository name
- Supports custom WXS templates via
msi_wxs_pathinput - Generates SBOMs and SLSA v1 provenance attestations
- Uploads all artifacts to S3
Outputs: *.zip, *.msi, *.provenance.sigstore.json, *.sbom.sigstore.json
Custom WXS: For connectors requiring custom MSI behavior (Windows Service, registry keys, etc.), provide a custom WXS template via msi_wxs_path. If not provided, uses the default CLI installer template.
Builds and publishes container images:
- Multi-arch Docker images (amd64/arm64)
- Pushes to ECR Public (for Lambda deployment)
- Attaches provenance attestations to images (OCI referrers)
Outputs: ECR Public images with attached attestations
Finalizes distributable release artifacts:
- Creates unified checksums file (all platforms)
- Merges binary, Windows, and image manifests
- Signs
manifest.jsonand checksums with Sigstore - Uploads manifest and checksums to S3
- Exposes the final manifest to the registry API recording job
Records release metadata in the connector registry API:
- Reuses the exact manifest uploaded to S3
- Includes documentation and changelog data when present
- Includes
config_schema.jsonandbaton_capabilities.jsonwhen present - Sends release timestamp, commit SHA, and workflow run metadata
Post-release validation (non-blocking):
- Validates all artifacts are accessible
- Verifies all attestations with cosign
- Triggers Datadog notification on failure
All signatures use Sigstore's keyless signing:
- No long-lived keys to manage or rotate
- Identity based on GitHub Actions OIDC token
- Signatures recorded in Rekor transparency log
Every artifact includes SLSA v1 provenance that links it to:
- Source repository and commit
- Workflow that built it (pinned SHA)
- Build environment (runner OS, architecture)
- Build timestamp
Software Bill of Materials (SPDX format) for each binary:
- Generated by Syft during build
- Signed as in-toto attestation
- Links SBOM to the specific artifact
MSI installers are built using WiX Toolset with GoReleaser Pro:
- UpgradeCode: Deterministic UUID v5 generated from repository name, ensuring consistent upgrade behavior across versions
- Default template: Installs to
C:\Program Files\ConductorOne\<connector>and adds to PATH - Custom templates: Connectors can provide custom WXS via
msi_wxs_pathinput for Windows Service, registry keys, etc.
The MSI uses a WiX-compatible version format (x.x.x.0) since WiX doesn't support semver prerelease suffixes.
Both Windows zip and MSI have:
- Cosign signatures (
.sig,.cert) - SLSA provenance attestations
- SBOM attestations
Note: Windows code signing via Azure Trusted Signing is planned for Stage 2.
Anyone can verify artifacts using cosign:
# Verify binary provenance
cosign verify-blob-attestation \
--bundle artifact.provenance.sigstore.json \
--type https://slsa.dev/provenance/v1 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp 'https://github.com/ConductorOne/github-workflows/.github/workflows/release.yaml@.*' \
artifact.zip
# Verify image provenance
cosign verify-attestation \
--type https://slsa.dev/provenance/v1 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp 'https://github.com/ConductorOne/github-workflows/.github/workflows/release.yaml@.*' \
public.ecr.aws/conductorone/baton-foo@sha256:abc123All attestations are signed with a certificate containing:
- Issuer:
https://token.actions.githubusercontent.com - Identity:
https://github.com/ConductorOne/github-workflows/.github/workflows/release.yaml@<ref>
Verification requires matching both issuer and identity pattern.
$GITHUB_WORKSPACE/
├── _caller/ # Connector repo checkout
│ └── dist/ # GoReleaser output, attestation bundles
└── _workflows/ # github-workflows repo checkout
├── _generated/ # Generated configs (goreleaser, gon, predicate)
├── _output/ # Final manifest and signatures
├── templates/ # Source templates
└── cmd/ # Go commands
releases/{org}/{repo}/{tag}/
├── manifest.json
├── manifest.json.sig
├── manifest.json.cert
├── baton-foo_1.0.0_checksums.txt
├── baton-foo_1.0.0_checksums.txt.sig
├── baton-foo_1.0.0_checksums.txt.cert
├── baton-foo-v1.0.0-darwin-arm64.zip
├── baton-foo-v1.0.0-darwin-arm64.zip.sig
├── baton-foo-v1.0.0-darwin-arm64.zip.cert
├── baton-foo-v1.0.0-darwin-arm64.zip.provenance.sigstore.json
├── baton-foo-v1.0.0-darwin-arm64.zip.sbom.sigstore.json
├── baton-foo-v1.0.0-linux-amd64.tar.gz
├── baton-foo-v1.0.0-linux-amd64.tar.gz.sig
├── baton-foo-v1.0.0-linux-amd64.tar.gz.cert
├── baton-foo-v1.0.0-linux-amd64.tar.gz.provenance.sigstore.json
├── baton-foo-v1.0.0-linux-amd64.tar.gz.sbom.sigstore.json
├── baton-foo-v1.0.0-windows-amd64.zip
├── baton-foo-v1.0.0-windows-amd64.zip.sig
├── baton-foo-v1.0.0-windows-amd64.zip.cert
├── baton-foo-v1.0.0-windows-amd64.zip.provenance.sigstore.json
├── baton-foo-v1.0.0-windows-amd64.zip.sbom.sigstore.json
├── baton-foo_v1.0.0_windows_amd64.msi
├── baton-foo_v1.0.0_windows_amd64.msi.sig
├── baton-foo_v1.0.0_windows_amd64.msi.cert
├── baton-foo_v1.0.0_windows_amd64.msi.provenance.sigstore.json
├── baton-foo_v1.0.0_windows_amd64.msi.sbom.sigstore.json
└── ...
Use test connectors for validation:
ConductorOne/baton-runner- Custom WXS template testing (viamsi_wxs_pathatci/app.wxs)ConductorOne/baton-github-test- Default WXS template testing
- Make workflow changes on a branch
- Point test repo at your branch:
uses: ConductorOne/github-workflows/.github/workflows/release.yaml@your-branch
- Create a test release on test connector repo via UI
- Wait for workflow to complete
- Validate outputs:
./scripts/validate-release-artifacts.sh ConductorOne/baton-github-test v0.1.xxx
The scripts/validate-release-artifacts.sh script validates:
- Manifest structure and version match
- All binary assets are downloadable
- Provenance and SBOM attestations exist and verify
- ECR Public image attestations (if present)
- Manifest signature (if present)
./scripts/validate-release-artifacts.sh ORG/REPO VERSIONExit codes: 0 = all passed, 1 = failures
# Download and verify binary provenance
curl -LO "https://dist.conductorone.com/releases/ConductorOne/baton-github-test/v0.1.102/baton-github-test-v0.1.102-darwin-arm64.zip"
curl -LO "https://dist.conductorone.com/releases/ConductorOne/baton-github-test/v0.1.102/baton-github-test-v0.1.102-darwin-arm64.zip.provenance.sigstore.json"
cosign verify-blob-attestation \
--bundle baton-github-test-v0.1.102-darwin-arm64.zip.provenance.sigstore.json \
--type https://slsa.dev/provenance/v1 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp 'https://github.com/ConductorOne/github-workflows/.github/workflows/release.yaml@.*' \
baton-github-test-v0.1.102-darwin-arm64.zipTest the MSI installer on an actual Windows machine:
-
Download MSI from S3:
curl -LO "https://dist.conductorone.com/releases/ConductorOne/baton-runner/vX.Y.Z/baton-runner_vX.Y.Z_windows_amd64.msi"
-
Install and verify:
- Double-click MSI or run
msiexec /i baton-runner_vX.Y.Z_windows_amd64.msi - Check installation path:
C:\Program Files\ConductorOne\baton-runner\ - Verify PATH includes installation directory
- Run
baton-runner --helpfrom new terminal
- Double-click MSI or run
-
Test upgrade scenario:
- Install older version first
- Install newer version over it
- Verify clean upgrade (no duplicate entries, old version removed)
-
Test uninstall:
- Uninstall via Settings > Apps or
msiexec /x - Verify files removed from Program Files
- Verify PATH entry removed
- Uninstall via Settings > Apps or
-
Verify UpgradeCode consistency:
- UpgradeCode is deterministic UUID v5 from repository name
- Must be identical across all versions for upgrades to work
- Cosign version: Ensure using latest cosign (
cosign version) - MSI UpgradeCode: If upgrades don't work, verify UpgradeCode is consistent across versions
Currently MSI installers have Sigstore signatures (cosign) but not Windows Authenticode signatures. Stage 2 will add:
- Azure Trusted Signing integration for Authenticode signatures
- MSI files will be signed with Microsoft-trusted certificate
- Windows SmartScreen warnings will be eliminated
- Users can verify publisher identity in Windows UAC prompts
This requires:
- Azure Trusted Signing account setup
- GitHub Actions OIDC integration with Azure
- Workflow updates to sign MSI after build
- Support for Windows ARM64 builds
- Windows Service installer templates (for connectors that run as services)
