Skip to content

Establish GitHub CI/CD and a secure release process #31

Description

@danielblignaut

Outcome

Establish a secure GitHub Actions CI/CD and release process for OpenBot that validates every pull request, creates intentional version PRs, builds reproducible release artifacts, publishes auditable GitHub Releases, and supports approval-gated deployment of the official hosted installation.

Build on the existing Changesets configuration and version-PR workflow. Do not introduce a second changelog/version source.

Current state

  • The repository has a Changesets workflow that opens or updates a version PR on main.
  • There is no complete pull-request CI workflow, release/tag workflow, signed desktop artifact pipeline, artifact provenance, or production deployment workflow.
  • The monorepo already exposes canonical commands for contract generation, checks, builds, E2E tests, desktop packaging, and provider-coordinated production deployment.
  • Desktop signing/notarization belongs to Sign, notarize, and productize the macOS Electron app #32 but its release artifacts are published by this pipeline.

Architecture

1. Pull-request CI

Add one required ci.yml workflow with minimal permissions and cancel-in-progress concurrency per PR. Use repository-pinned Node 24 and pnpm 10 with a frozen lockfile.

Jobs should be risk-based and independently visible:

  1. Repository checks — install, generate protobuf contracts, prove generated files are clean, run pnpm check, and validate Changesets when a published package is affected.
  2. Build — run pnpm build and upload only bounded diagnostic artifacts on failure.
  3. Integration/E2E — run the concise suite from Build a concise integration/E2E suite and focused testing skills #20 on Linux with deterministic local providers and no production credentials.
  4. Desktop smoke — build and package an unsigned development artifact on macOS; verify bundle structure and launch/health behavior without using release secrets.
  5. Workflow/config validation — validate workflow YAML, package metadata, release configuration, symlinks from Support canonical repository instructions and skills across coding agents #27, generated-contract cleanliness, and repository secret scans.

Use Turbo/pnpm caches keyed by lockfile, Node version, OS, and architecture. Caches are performance hints, never release inputs. Fork pull requests must run safely without secrets and must never execute deployment or code-signing steps.

2. Branch protection and permissions

  • Require the focused CI jobs, linear history, and review before merging to main.
  • Set workflow-level permissions to read-only and elevate only the job that needs pull-requests: write, contents: write, id-token: write, or attestations: write.
  • Pin third-party actions to reviewed immutable commit SHAs; document the update process.
  • Prevent untrusted pull-request code from running in pull_request_target with repository or environment secrets.
  • Use GitHub Environments with required reviewers for desktop signing and production deployment.

3. Versioning and release intent

Changesets remains canonical for workspace package versions and changelog entries:

  • merge ordinary changes plus required changesets;
  • the existing Changesets action maintains one version PR;
  • merging the version PR produces the release commit and version;
  • a release coordinator validates that all fixed workspace packages and the desktop product have one coherent version;
  • create an annotated vX.Y.Z tag exactly once from that release commit.

Update the private-package Changesets settings so the desktop/application version can be tagged without attempting to publish private workspace packages to npm. Publishing packages to npm is a separate opt-in decision and must not happen accidentally.

Support explicit stable and prerelease channels. A tag is immutable; rebuilding replaces neither the tag nor existing assets silently.

4. Reproducible release build

Build every artifact from a clean checkout of the tagged commit using frozen dependencies:

The release manifest records version, commit SHA, workflow run, Node/pnpm/Electron versions, target OS/architecture, artifact SHA-256, the embedded CLI digest, and signing/notarization status. Do not embed build-host paths, tokens, or environment values.

Generate GitHub artifact attestations for executable release artifacts and document gh attestation verify alongside checksum verification. Attestation proves provenance, not software safety, so it complements rather than replaces signing, tests, and review.

5. Release publication

Use a draft GitHub Release as the assembly point:

  1. Create the draft from the immutable tag and Changesets changelog.
  2. Matrix jobs build, sign where required, verify, and upload uniquely named artifacts.
  3. A final release job downloads and verifies every expected artifact, checksum, SBOM, attestation, and notarization result.
  4. Publish the release only after the full manifest is complete.

Failures leave a draft release with diagnostics and never publish a partial “stable” release. Re-running a job must be idempotent and refuse mismatched bytes for an existing asset name.

6. CD for the official installation

Keep upstream software release separate from deploying an OpenBot installation.

Add a reusable deployment workflow invoked manually or by an explicitly configured official environment:

  • resolve an immutable release tag/commit;
  • run pnpm deploy:prod -- --dry-run --json and attach a redacted plan;
  • require environment approval;
  • run pnpm deploy:prod -- --yes through the provider coordinator;
  • verify control, agent, Tilde-resource, and Computer health;
  • record immutable provider deployment identifiers and a redacted manifest.

Do not replace the provider lifecycle with raw Vercel/Tilde commands. Forks get the reusable workflow but no trytilde production secrets or automatic deployment target. Production rollback selects the previous known-good release/provider artifacts and follows the same approved coordinator path.

7. Secret and supply-chain boundaries

  • CI jobs have no deployment, Apple, Tilde, SOPS-age, or provider credentials.
  • Desktop release secrets exist only in the protected signing environment used by Sign, notarize, and productize the macOS Electron app #32.
  • Production credentials exist only in the protected deployment environment and are passed through the existing secret-aware provider lifecycle.
  • Avoid long-lived cloud credentials where GitHub OIDC/workload identity is supported.
  • Never upload .env, decrypted SOPS files, age keys, setup state, browser profiles, Playwright traces containing user data, or provider command output with secrets.
  • Retain build and deployment logs/artifacts for a documented bounded period.

Delivery slices

  • Add PR CI with repository checks, build, focused E2E, desktop smoke, workflow validation, and safe fork behavior.
  • Configure required branch protection checks and least-privilege workflow permissions.
  • Finish Changesets/private-app versioning and deterministic tag creation.
  • Add draft release assembly, matrix artifacts, checksums, SBOM, attestations, and final manifest verification.
  • Integrate signed/notarized macOS artifacts from Sign, notarize, and productize the macOS Electron app #32.
  • Add the approval-gated reusable provider deployment workflow and rollback runbook.
  • Document contributor changesets, release operation, artifact verification, deployment, and recovery.

Acceptance criteria

  • Every pull request runs required checks from a clean frozen install without secrets; fork PRs cannot reach write tokens or protected environments.
  • Generated contracts, checks, build, focused E2E, desktop smoke, and workflow validation report independently and are required on main.
  • A merged version PR produces one immutable version/tag and one draft release without manually editing package versions.
  • Re-running release jobs is idempotent and cannot replace an existing asset with different bytes.
  • Release artifacts include checksums, licenses/notices, SBOM, release manifest, and verifiable GitHub attestations.
  • The CLI is built once from the release tag before Desktop packaging; the app's embedded CLI version/digest matches the release manifest and contains no development/test-only packages.
  • A stable release is not published until every expected platform artifact passes integrity and platform-signing verification.
  • The official deployment performs redacted dry-run, approval, provider-coordinated deployment, and smoke verification from an immutable release.
  • Rollback to the previous known-good release is documented and tested without retagging or rebuilding old source.
  • CI/release/deploy logs and artifacts contain no raw secrets, age keys, signing credentials, browser data, or decrypted configuration.

Dependencies

Open decisions

  • Initial support matrix: macOS arm64+x64 versus a universal binary, and which Linux formats remain release-blocking.
  • Stable-only versus stable plus prerelease/canary channels in the first release workflow.
  • Whether official production deployment follows every stable release after approval or remains manual workflow_dispatch initially.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions