Build, sign, and publish orbit CLI binary releases on tag
## Summary Publish signed cross-platform `orbit` CLI binaries to the project's GitLab Package Registry on each release tag, so users can download them the same way they did from the legacy `gitlab-org/rust/knowledge-graph` project. The new Orbit project already deploys server Docker images on tag, but does not yet ship standalone CLI binaries. This issue covers wiring up the binary release flow for the `orbit` CLI (and replaces the legacy `gkg` binary releases). ## Motivation - The legacy `knowledge-graph` project is being replaced by Orbit. - Orbit provides a much improved local CLI for code indexing (`orbit`), which is the user-facing replacement for the legacy `gkg` binary. - IDE extensions, install scripts, and end users currently fetch binaries from the legacy package registry. Orbit needs the equivalent surface so consumers can switch over. ## Goals - On every release tag (`vX.Y.Z`), publish: - `orbit-linux-x86_64.tar.gz` - `orbit-linux-aarch64.tar.gz` - `orbit-darwin-x86_64.tar.gz` (signed) - `orbit-darwin-aarch64.tar.gz` (signed) - `orbit-windows-x86_64.tar.gz` (signed) - A matching `.sha256` checksum file for each archive. - Attach all of the above to the GitLab Release as Generic Package Registry assets. - Drive everything from the existing semantic-release flow already used by Orbit. No new versioning scheme. ## Non-goals - No Homebrew, Scoop, apt, or other distribution channels in this iteration. - No SBOM, provenance, or in-toto attestations beyond what the canonical pipeline already produces. - No changes to Docker image release (already in place). - No public mirror to a separate "downloads" site. ## Approach Reuse the legacy pipeline shape. The legacy project's `.gitlab/ci/release.yml` is the reference implementation; the new flow should look almost identical, with the binary name and crate paths adjusted for Orbit. ### Versioning - Continue using the existing semantic-release setup (`.releaserc.json`, `package.json`). - The release tag (`vX.Y.Z`) created by semantic-release on `main` is the trigger for the binary build + publish jobs. - No second versioning scheme. ### Build - Add a `build` (or `release`) stage that runs only on tag pipelines (`$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/`). - Five build jobs, one per target, each producing `orbit-<os>-<arch>.tar.gz` containing the `orbit` binary (and any required runtime DLLs on Windows). - Linux + macOS jobs share a `scripts/build.sh`-style helper that takes `PLATFORM` / `ARCH` env vars and runs `cargo build --release --bin orbit --target <triple> --locked`. - Windows job builds with PowerShell, similar to the legacy `windows-prepare.ps1` + `cargo build --release --bin orbit --locked`. - Job-tag matrix mirrors the legacy project (`saas-linux-large-amd64`, `saas-linux-large-arm64`, `saas-macos-medium-m1`, `saas-windows-medium-amd64`). ### Sign - Add a `code-sign` job that consumes the unsigned macOS and Windows tarballs and re-emits signed ones. - Use the same image as the legacy project: `${CI_REGISTRY}/gitlab-com/gl-infra/common-ci-tasks-images/code-signer`. - Reuse the legacy `sign-and-repackage.sh` pattern (extract → run `sign-macos-binaries` / `sign-windows-binaries` → repackage). - Guard signing with the same canonical-project check used in the legacy pipeline so forks and security mirrors don't try to sign. ### Publish - Add a `release` job that runs on the same tag pipeline, after build + sign succeed. - Generate `sha256sum` for every `*.tar.gz`. - Use `@semantic-release/gitlab` (already a dev dependency) to attach all archives + checksums as Generic Package Registry assets on the GitLab Release that semantic-release already creates. - Alternative if simpler given that semantic-release already ran on `main`: a small `glab release upload` (or `release-cli`) step on the tag pipeline that uploads the tarballs to the Generic Package Registry and links them on the existing release. Either is acceptable; the goal is one release per tag with all assets attached. ### CI structure - Put the new jobs in `.gitlab/ci/release.yml` and `include:` from the root `.gitlab-ci.yml`, matching the legacy layout. - Add new stages only if needed; otherwise reuse `build` / `release`. - Keep all jobs gated to canonical project + tag, identical to existing `release-build-*` / `release-manifest` jobs. ## Acceptance criteria - A new tag pipeline produces all five tarballs and their `.sha256` files. - macOS and Windows binaries are signed; running them on a clean machine does not trigger Gatekeeper / SmartScreen warnings beyond the expected first-launch prompt. - The corresponding GitLab Release page lists all archives + checksums as downloadable assets in the Generic Package Registry. - `curl -L <package-registry-url>/orbit-linux-x86_64.tar.gz | tar xz` yields a working `orbit` binary that runs `orbit --version` and prints the tag version. - Forks and security mirrors do **not** publish binaries. ## References - Legacy release pipeline: [`.gitlab/ci/release.yml` in `gitlab-org/rust/knowledge-graph`](https://gitlab.com/gitlab-org/rust/knowledge-graph/-/blob/main/.gitlab/ci/release.yml) - Legacy build script: `scripts/build.sh` - Legacy signer wrapper: `scripts/sign-and-repackage.sh` - Existing Orbit Docker release jobs: `.gitlab-ci.yml` (`release-build-*`, `release-manifest`) - Existing Orbit semantic-release config: `.releaserc.json`, `package.json` ## Out of scope / follow-ups - IDE extension and install-script repointing to the new package registry (separate issue once binaries land). - Removing the legacy project's binary releases. - Documentation update for download URLs in user-facing docs.
issue