CI/CD Pipeline & Release Process
This document describes the automated CI/CD pipeline and release process for portctl.
Overview
The portctl project uses Dagger for all CI/CD automation, providing a modular, reproducible, and platform-agnostic pipeline. All build, test, and release steps are defined as Dagger functions in .dagger/main.go.
Pipeline Architecture
Dagger Functions
All pipeline steps are callable via dagger call <function>:
# Core development workflow
dagger call lint --src=. # Run golangci-lint
dagger call test --src=. # Run Go tests
dagger call build --src=. # Build binary
# Release workflow
dagger call generate-manifest --src=. # Generate MCP manifest
dagger call release --src=. export --path=./artifacts # Release with GoReleaser
dagger call publish-image --src=. # Publish Docker images
# Quality & Security
dagger call security-scan --src=. # Run gosec security scan
dagger call sbom --src=. # Generate SBOM
dagger call snapshot-test --src=. # Run snapshot tests
dagger call well-known --src=. # Validate .well-known metadata
# Documentation
dagger call docs --src=. # Build mdBook documentation
dagger call publish-docs --src=. # Publish to GitHub Pages
GitHub Actions Workflows
CI Workflow (.github/workflows/ci.yml)
Runs on every push and pull request:
- Linting with golangci-lint
- Unit tests with coverage
- Security scanning with gosec
- SBOM generation
- Documentation build
Release Workflow (.github/workflows/release.yml)
Triggered on version tags (e.g., v1.0.1):
- Validation: Runs lint and test steps
- Build & Release:
- Runs GoReleaser to build multi-platform binaries
- Generates SBOM and SLSA attestations
- Creates GitHub release with artifacts
- Updates Homebrew tap
- Artifact Export: Exports artifacts to host filesystem for upload
- Docker Publishing: Builds and publishes multi-arch images to GHCR
- Artifact Upload: Uploads artifacts to GitHub Actions
Release Process
Creating a Release
-
Ensure all changes are committed and pushed:
git add . git commit -m "feat: your changes" git push origin main -
Create and push a version tag:
# For a patch release (bug fixes) git tag -a v1.0.1 -m "Release v1.0.1" # For a minor release (new features) git tag -a v1.1.0 -m "Release v1.1.0" # For a major release (breaking changes) git tag -a v2.0.0 -m "Release v2.0.0" git push origin <tag-name> -
Monitor the release workflow:
- Go to https://github.com/ckodex-labs/portctl/actions
- Watch the "Release" workflow run
- Verify all steps complete successfully
What Gets Released
Each release includes:
- Multi-platform binaries: Linux, macOS, Windows (amd64, arm64)
- Docker images: Published to
ghcr.io/ckodex-labs/portctlwith tags:latest- Always points to the latest releasev1.0.x- Specific version tag
- Security & Compliance Artifacts:
*.sbom.spdx.json- Software Bill of Materials in SPDX format*.sbom.cyclonedx.json- Software Bill of Materials in CycloneDX format*.intoto.jsonl- SLSA provenance attestations (in-toto format)
- AI Integration Metadata (
.well-known/folder):mcp-manifest.jsonld- Model Context Protocol server manifestllms.txt- LLM guidance and context for AI agentsskills.txt- Capability descriptions for MCP tools
- Homebrew formula: Automatically updated in
ckodex-labs/homebrew-tap
Artifact Publishing
The release workflow exports artifacts from Dagger containers to the GitHub Actions runner:
- name: Build and Release
run: dagger call release --src=. --github-token=env:GITHUB_TOKEN --tap-github-token=env:TAP_GITHUB_TOKEN export --path=./artifacts
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: release-artifacts
path: ./artifacts
The export --path=./artifacts command writes the Dagger directory to the host filesystem, making artifacts available for upload.
Local Testing
Test the release process locally before pushing tags:
# Set required environment variables
export GITHUB_TOKEN="your-github-token"
export TAP_GITHUB_TOKEN="your-tap-token"
# Test the release build (without publishing)
dagger call release --src=. --github-token=env:GITHUB_TOKEN --tap-github-token=env:TAP_GITHUB_TOKEN export --path=./artifacts
# Verify artifacts were created
ls -la ./artifacts
Security & Compliance
SLSA Provenance
All releases include SLSA (Supply chain Levels for Software Artifacts) provenance attestations:
- Build provenance is generated by GoReleaser
- Attestations are signed and published with releases
- Verifiable supply chain security
SBOM (Software Bill of Materials)
Each release includes a comprehensive SBOM:
- Generated using Syft
- Lists all dependencies and their versions
- Helps with vulnerability tracking and compliance
SLSA Level 3 Compliance
portctl achieves SLSA Level 3 through:
- Signed provenance: GoReleaser generates signed
.intoto.jsonlattestations - Cosign signatures: All artifacts are cryptographically signed with keyless signing
- SBOM generation: Comprehensive dependency tracking with Syft
- Hardened build: GitHub Actions with OIDC authentication
Verifying Signatures
Download and verify a release artifact:
# Download artifacts
wget https://github.com/ckodex-labs/portctl/releases/download/v1.0.2/portctl_linux_amd64.tar.gz
wget https://github.com/ckodex-labs/portctl/releases/download/v1.0.2/portctl_linux_amd64.tar.gz.sig
wget https://github.com/ckodex-labs/portctl/releases/download/v1.0.2/portctl_linux_amd64.tar.gz.cert
# Verify with Cosign
cosign verify-blob \
--certificate portctl_linux_amd64.tar.gz.cert \
--signature portctl_linux_amd64.tar.gz.sig \
--certificate-identity-regexp="https://github.com/ckodex-labs/portctl" \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
portctl_linux_amd64.tar.gz
Verifying SLSA Provenance
# Download provenance
wget https://github.com/ckodex-labs/portctl/releases/download/v1.0.2/portctl_checksums.txt.intoto.jsonl
# Inspect provenance
cat portctl_checksums.txt.intoto.jsonl | jq
Documentation Publishing
Documentation is built with mdBook and published to GitHub Pages:
# Build documentation locally
dagger call docs --src=.
# Publish to GitHub Pages (requires GITHUB_TOKEN)
dagger call publish-docs --src=.
The documentation is automatically published on every release.
Troubleshooting
Release Workflow Fails
- Check the GitHub Actions logs for specific errors
- Verify all required secrets are set:
GITHUB_TOKEN(automatically provided)TAP_GITHUB_TOKEN(for Homebrew tap updates)
- Ensure the tag follows semantic versioning (e.g.,
v1.0.1)
Artifacts Not Uploaded
The artifact export mechanism requires:
- Dagger Release function returns
*dagger.Directory - Workflow uses
export --path=./artifacts - Upload step references the correct path
Docker Publishing Fails
Verify:
- GitHub Container Registry permissions are configured
GITHUB_TOKENhaspackages: writepermission- Multi-arch build platforms are supported
Best Practices
- Test locally first: Always test builds locally before creating tags
- Follow semantic versioning: Use appropriate version numbers
- Write clear release notes: Document changes in tag messages
- Monitor workflows: Watch GitHub Actions to catch issues early
- Verify artifacts: Download and test released artifacts