CI & Release Process¶
Every platform repository uses the same pipeline rules. The gateway agent adds release channels on top.
Pipelines run on merge requests and tags¶
A pipeline runs for a merge request or for a tag. Pushing to main
runs no pipeline and deploys nothing: a merged change reaches no environment
until the commit is tagged.
| Stage | Runs on | Purpose |
|---|---|---|
check |
merge requests | Tests, formatting, type checks, lint |
build |
tags | Build the image or binary |
deploy / publish |
tags | Ship it |
promote |
tags, manual | Gateway only: move a build to the stable channel |
check is the merge gate and does not run on tags. A commit pushed straight to
main is therefore untested by CI.
Services (portal, nexus, realtime)¶
A tag builds an image per environment and deploys:
| Job | When |
|---|---|
deploy_dev |
automatically on the tag |
deploy_stg, deploy_prd |
manual: press play in the tag pipeline |
Nexus and radius-ctrl pull their build and deploy job templates from
digilan/infra/ci-templates with include:.
To release: merge the MR, tag the merge commit on main, then run the manual
staging and production jobs when ready.
Gateway agent¶
The agent is a binary that devices download, so its pipeline publishes to a release registry rather than deploying a container. A tag runs:
| Job | What it does |
|---|---|
build:amd64, build:arm64 |
Cross-compile for OpenBSD (CGO_ENABLED=0, -trimpath), stamp main.version with the tag and bake in the OTA signing public key; sign with ed25519 and verify the signature before going on |
publish:dev:<arch>, publish:prod:<arch> |
Upload to that environment's release bucket, then register the release on the beta channel with that environment's Nexus |
promote:stable:dev:<arch>, promote:stable:prod:<arch> |
Manual. Register the same object (same sha256, signature and key, no rebuild) on the stable channel |
- The tag is the version, verbatim:
v1.2.3-betais versionv1.2.3-beta. Tags are namedvX.Y.Z-betaby convention; every tag, whatever its name, publishes to beta only. - Every tag publishes to every environment (dev and prod), with identical bytes. A failure in one environment's job leaves the other untouched and can be retried alone.
- Promotion is per environment and per architecture. Run it once a canary
device on beta has taken the update and stayed healthy. Devices follow their
own channel (
stableby default); a beta release is invisible to them until promoted. - Nexus refuses a second registration of the same version, architecture and channel, so re-running a job that already succeeded fails rather than registering twice.
- Merge requests run
go build,go vet,go test -raceand agofmtcheck.
A manual pipeline on main with BACKFILL_TAG=<tag> registers an existing
tag's build in prod without rebuilding it: it fetches that tag's build:<arch>
artifact (kept for one week), checks it is a clean build of that tag, re-derives
sha256 and signature, and runs the prod publish and promote jobs.
CI variables¶
Names only; values come from tofu output in infra/terraform.
| Scope | Variables |
|---|---|
| shared | OTA_S3_ENDPOINT, OTA_S3_REGION, OTA_SIGNING_PRIVATE_KEY (file), OTA_SIGNING_PUBLIC_KEY (file) |
| dev | OTA_S3_BUCKET, OTA_PUBLISHER_ACCESS_KEY, OTA_PUBLISHER_SECRET_KEY, NEXUS_URL, RELEASE_PUBLISHER_KEY |
| prod | OTA_S3_BUCKET_PROD, OTA_PUBLISHER_ACCESS_KEY_PROD, OTA_PUBLISHER_SECRET_KEY_PROD, NEXUS_URL_PROD, RELEASE_PUBLISHER_KEY_PROD |
One signing key serves all environments, so a device moved between environments keeps accepting updates. The bucket publisher identities are write-only.
Only pipeline builds can self-update
The signing public key is baked into the binary at build time. A build made
without it (make build-openbsd, or any local build without
-X main.otaSigningPublicKey=...) logs self-update disabled and must be
replaced by hand. The install image builders therefore refuse an agent
without the release key (bench override: ALLOW_UNSIGNED_AGENT=1); see
Build the install image.
See Agent Releases for channels and rollout, and OTA Updates for how a device installs a release.