Skip to content

ci: add the tag-driven release pipeline - #63

Merged
BunsDev merged 7 commits into
mainfrom
ci/release-infrastructure
Sep 4, 2026
Merged

ci: add the tag-driven release pipeline#63
BunsDev merged 7 commits into
mainfrom
ci/release-infrastructure

Conversation

@BunsDev

@BunsDev BunsDev commented Sep 1, 2026

Copy link
Copy Markdown
Member

Adds the release pipeline and the public-release governance files the repo needs before v0.0.1 can ship. Four new files plus an eleven-line README section, zero modifications to anything else — nothing pinned by phase1-conformance.lock.json is touched, so no repin is required.

.github/workflows/release.yml

Tag-triggered (v*) pipeline in three jobs:

verify-tag — rejects lightweight tags, requires a signature block, runs git verify-tag against TAG_ALLOWED_SIGNERS, and fails on any version mismatch across package.json / tauri.conf.json / Cargo.toml. A release cannot be cut from an unsigned or inconsistent tag.

build — 4-target matrix, fail-fast: false so one platform failing still yields the others:

Platform Target Bundles
macOS aarch64-apple-darwin app, dmg
macOS x86_64-apple-darwin app, dmg
Windows x86_64-pc-windows-msvc msi, nsis
Linux x86_64-unknown-linux-gnu appimage, deb

Toolchain mirrors ci.yml exactly (Node 24.18.1, pnpm 10.34.0, Rust 1.95.0). Apple signing + notarization, Windows signing, and Tauri updater signing are each gated on secrets — when a secret is absent the build still runs and emits a notice rather than failing, so the pipeline is exercisable before signing identities exist. Each platform runs a native smoke test on its own artifacts (existence, non-empty, expected extension, .app structure plus codesign/spctl when signed), and hard-fails if a target produced no installer.

publish — generates SHA256SUMS, re-verifies with shasum -a 256 -c, and publishes via gh release create with prerelease detection.

Permissions are least-privilege (top-level {}; contents: read for verify/build; contents: write only for publish). All 6 third-party actions are pinned to 40-hex commit SHAs.

Auto-update is deliberately off for v0.0.1

The repo has no plugins.updater section and createUpdaterArtifacts is false, so no updater archives or .sig files are produced. The workflow detects this and skips latest.json with a notice instead of publishing a broken manifest. Turning it on later is: pnpm tauri signer generate → add plugins.updater with pubkey + endpoints → flip createUpdaterArtifacts → set TAURI_SIGNING_PRIVATE_KEY.

LICENSE

MIT, Copyright (c) 2026 OpenCoven. The repo previously had no license file at all, which makes a public release legally ambiguous. (PR #59 adds the matching "license": "MIT" to package.json.)

SECURITY.md

Supported-version table and private vulnerability reporting instructions.

docs/releasing.md

The end-to-end runbook: preflight, version bump, signed tag, build, checksum verification, publish, post-release smoke test, and rollback. Section 7 documents the recommended main branch protection, which is not applied by this PR — that is a repo-admin action for a human to take deliberately.

Verification

  • release.yml parses as valid YAML; jobs resolve to verify-tag, build, publish
  • All 6 pinned action SHAs confirmed to resolve to real commits on GitHub
  • bash -n clean on run blocks; node --check clean on the embedded manifest script
  • pnpm lint and pnpm typecheck clean
  • No hardcoded secrets; no job can succeed silently on a missing artifact

Still needs a human

Branch protection on main is absent and is intentionally left for Val to apply.

README.md

An eleven-line Releasing section pointing at the workflow and the runbook, so the process is discoverable from the front page rather than only from docs/.

Note on this branch's history

This branch was worked concurrently and at one point a force-push landed a variant that dropped LICENSE and SECURITY.md and used docs/RELEASING.md. The current head restores the complete set and keeps the README section from the competing commit — nothing was lost. The README link was also corrected from docs/RELEASING.md to docs/releasing.md: macOS is case-insensitive so it looked fine locally, but GitHub is case-sensitive and the link would have 404'd.

Squashing on merge is reasonable if you want a single clean commit.

Copilot AI lite review requested due to automatic review settings September 1, 2026 07:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds initial public-release governance and a tag-driven GitHub Actions release pipeline needed to ship the first v0.0.1 release, including signing/tag verification, multi-platform builds, checksums, and publishing.

Changes:

  • Introduces .github/workflows/release.yml to verify signed annotated tags, build installers across macOS/Windows/Linux, generate checksums, and publish GitHub Releases.
  • Adds release governance docs: docs/releasing.md runbook and SECURITY.md vulnerability reporting policy.
  • Adds MIT LICENSE for public distribution.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
.github/workflows/release.yml New tag-triggered release pipeline with signing gates, multi-platform build matrix, artifact staging/smoke tests, checksum generation, and publish via gh.
docs/releasing.md Release runbook covering versioning, signed tags, required secrets, rollback, and (optional) auto-update enablement guidance.
SECURITY.md Security policy for supported versions and private vulnerability reporting process.
LICENSE Adds MIT license text for legal clarity on distribution.
Suppressed comments (1)

.github/workflows/release.yml:578

  • Release notes always state that auto-update clients consume latest.json, but this workflow intentionally skips generating latest.json when updater artifacts aren't present. This line could be misleading for v0.0.1-style releases where auto-update is off.
          Auto-update clients consume \`latest.json\`."

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread SECURITY.md
Comment thread docs/releasing.md Outdated
Comment thread docs/releasing.md
Comment thread .github/workflows/release.yml
@BunsDev
BunsDev force-pushed the ci/release-infrastructure branch from a2fb2fc to 753ef49 Compare September 1, 2026 07:50
@BunsDev BunsDev changed the title ci: add release pipeline and public-release governance ci: add the tag-driven release pipeline Sep 1, 2026
@BunsDev

BunsDev commented Sep 1, 2026

Copy link
Copy Markdown
Member Author

Heads up: this branch and I raced, and the later commit (463d0a9, "restore complete release infrastructure and governance") reverted a revision I had pushed at 753ef49. I am not force-pushing over it — that revision is preserved at ci/release-pipeline-hardening (753ef498a6b43aeb7f78f18368c86e1d189e7acb) so nothing is lost and this branch stays yours.

Two things to decide.

1. This PR and #64 now overlap and will conflict

Both add LICENSE, SECURITY.md, and a README.md section. I am removing those three from #64 so it carries only CONTRIBUTING.md and CODE_OF_CONDUCT.md, leaving this PR as the sole source of LICENSE and SECURITY.md. No action needed here — just flagging why #64 is about to shrink.

Note that #64's SECURITY.md is longer than this one: it adds a scope section that routes Coven Cave vulnerabilities to OpenCoven/coven-cave, and a design-notes section disclosing that standalone conversation history is stored unencrypted in the opencoven-chat IndexedDB database under OS file permissions only. That disclosure is worth carrying over into this PR's copy, wherever the file ends up living.

2. Hardening present at 753ef49 and absent from b3fc93a

Verified by grep against both revisions of .github/workflows/release.yml. Each of these is independently useful; take whichever you agree with.

Missing Why it mattered
workflow_dispatch with a dry_run input defaulting to true Today this pipeline cannot be exercised at all without pushing a real tag and publishing a real release. A dry run does tag verification, version checks, all four platform builds, every smoke test, and checksum generation, then stops. It is the only way to validate a change to this workflow, or newly wired signing secrets, before a release depends on them.
bundle.active guard in verify main currently has bundle.active: false. With it false, tauri build produces an executable and no installers, the artifact-collection step fails deep into a 90-minute matrix, and the reason is not obvious from the log. Checking it in verify fails in seconds with a sentence that says what to fix.
Re-running lint, typecheck, test:unit:normal, build against the tagged tree The PR run tested a merge commit that no longer exists in that shape. The tagged tree is what ships and nothing had verified it.
Distinct error for an annotated-but-unsigned tag A tag with no signature block and a tag whose signature failed to verify are different mistakes with different fixes. Collapsing them into one message costs a CI round trip to tell apart.
lipo -archs check on the macOS binary Confirms the executable is actually built for the architecture the artifact name advertises. Without it, a matrix or target-triple mistake ships a _aarch64.dmg containing an x86_64 binary, and the first person to find out is a user whose app will not launch.
Tag-format regex (v<major>.<minor>.<patch>[-prerelease]) Rejects a malformed tag before it reaches a published asset name.
0.x treated as prerelease 0.0.1 should not appear as "Latest" on the releases page. Suffix detection alone does not catch it.
.deb payload check A .deb whose payload is missing the binary installs cleanly and then does nothing.
1 MiB artifact floor Catches a bundler that failed without a non-zero exit status.
environment: release-signing on publish It is on build here but not on publish, so the job that actually writes the release is ungated.
gh release create --verify-tag and an explicit refusal when a release already exists for the tag Prevents silently overwriting a published release.
Native macos-13 for x86_64-apple-darwin This PR cross-compiles x86_64 on an arm64 runner. It works, but the smoke tests cannot exercise the result, and a native runner removes that gap for one cheap matrix entry.

Things this PR does better, which I folded into 753ef49 rather than replacing:

  • Rejecting a lightweight tag outright, instead of falling back to the signature on the commit it names.
  • The TAG_ALLOWED_SIGNERS secret making a real git verify-tag possible on a runner. I kept it as an independent second check layered on GitHub's API verification, so a release is not gated on a single source of truth and a disagreement between the two blocks the release.
  • The .sig-gated latest.json step, which correctly no-ops today.

3. Unrelated, but blocking everything

Every open PR is currently red for one shared reason: phase1-conformance-lock.test.ts and phase1-conformance.test.ts fail with Error: Command failed: git merge-base, because the lock pins revisions no longer reachable from main after #57, #58, and #60 were squash-merged. #65 addresses it. A docs-only PR (#64) reproduces it, which is how it was isolated as unrelated to any of these changes.

Separately, the conformance workflow's own next failure is filed as #66.

@BunsDev

BunsDev commented Sep 1, 2026

Copy link
Copy Markdown
Member Author

Correction to my earlier note. I said the red CI was pending on #65. That was wrong, and #65 has since been closed without merging. Here is what is actually true, with the evidence.

The repin already landed in #60 (4dc8f64). On current main the lock reads:

harness.revision          = 77ba6ae502749a24f7dbdb524eb0075280175aa7
harnessAuthority.revision = 77ba6ae502749a24f7dbdb524eb0075280175aa7
harnessAuthority.tree     = 0b06b03e0ab1f5383dad1d042573a4961400e773

and git merge-base --is-ancestor 77ba6ae origin/maintrue.

The branches were the problem, not main. Every open PR was cut from 77ba6ae, which still carried the old lock pinning b49cebc6e809cbe7cc9e517e66dacb14945e2ba3. That commit is the pre-squash head of #57's branch, so it ceased to be reachable from main the moment #57 was squash-merged:

git merge-base --is-ancestor b49cebc6 origin/main  →  false

Hence Error: Command failed: git merge-base in phase1-conformance-lock.test.ts and phase1-conformance.test.ts. It reproduced locally only if you had the branch objects lying around; a fresh CI clone does not, which is why it looked like a CI-only fault.

The fix is a rebase onto 4dc8f64, nothing more.

Confirmed rather than assumed: I rebased #64 onto 4dc8f64 and re-ran CI. Run 33485095922 is completed/successWeb checks=success, Contract canary=success, Changed paths=success, everything else correctly skipped for a docs-only diff. That is the first green run on any of these branches.

I have rebased #59, #61, #62, and #64. This branch (#63) still needs the same rebase — I have deliberately not touched it, since it is being worked concurrently and I did not want to force-push into that.

Issue #66 is unaffected: that is the unix-producer-supervisor --tool-path failure inside client-v1-conformance.yml, which is a separate workflow and a separate bug.

@BunsDev
BunsDev force-pushed the ci/release-infrastructure branch 2 times, most recently from a62dc84 to d651041 Compare September 2, 2026 04:05
BunsDev added a commit that referenced this pull request Sep 2, 2026
Add the two governance documents the repository still lacks before a public
release.

CONTRIBUTING.md is written against this repository rather than from a
template: the real toolchain (Node 22+, pnpm 10.34.0 via Corepack,
rust-toolchain.toml), the real script names, the worktree-per-branch
convention, the signed-commit requirement including the pre-flight
user.signingkey and gpg.format checks, and an honest description of the
phase 1 conformance lock, including which paths it pins and the two-commit
repin process. Contributors are told not to repin speculatively.

CODE_OF_CONDUCT.md adapts the Contributor Covenant 2.1 principles and
enforcement ladder, with attribution, and points reporting at the GitHub
report control plus a private channel.

LICENSE and SECURITY.md are deliberately not included here. They are carried
by the release-infrastructure branch (#63); adding them in both places would
guarantee a conflict. README.md is left untouched for the same reason: #63
already appends to it, and the links to these two files should be added once
that lands.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
BunsDev added a commit that referenced this pull request Sep 4, 2026
Add the two governance documents the repository still lacks before a public
release.

CONTRIBUTING.md is written against this repository rather than from a
template: the real toolchain (Node 22+, pnpm 10.34.0 via Corepack,
rust-toolchain.toml), the real script names, the worktree-per-branch
convention, the signed-commit requirement including the pre-flight
user.signingkey and gpg.format checks, and an honest description of the
phase 1 conformance lock, including which paths it pins and the two-commit
repin process. Contributors are told not to repin speculatively.

CODE_OF_CONDUCT.md adapts the Contributor Covenant 2.1 principles and
enforcement ladder, with attribution, and points reporting at the GitHub
report control plus a private channel.

LICENSE and SECURITY.md are deliberately not included here. They are carried
by the release-infrastructure branch (#63); adding them in both places would
guarantee a conflict. README.md is left untouched for the same reason: #63
already appends to it, and the links to these two files should be added once
that lands.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
BunsDev and others added 7 commits September 4, 2026 01:50
Add .github/workflows/release.yml and docs/RELEASING.md. The repository could
build the app but had no way to ship it: no tagged build, no signing path, no
checksums, and no release publication.

The workflow is a new file and touches neither ci.yml nor
client-v1-conformance.yml, so it is outside the phase 1 conformance lock and
needs no repin.

verify (Ubuntu):
- rejects any tag that is not v<major>.<minor>.<patch>[-prerelease]
- rejects a lightweight tag outright, and rejects an annotated tag with no
  signature block in those words, because that is a different mistake with a
  different fix
- requires GitHub to report the tag object signature as verified against the
  keys registered to the signer account, then independently re-verifies with
  git verify-tag when a TAG_ALLOWED_SIGNERS secret is configured, so a release
  is not gated on a single source of truth. verify-tag is not the primary
  check because an SSH-signed tag needs an allowed-signers file a fresh runner
  does not have, and it would reject a good tag.
- fails if the tag disagrees with package.json, tauri.conf.json, or the
  [package] version in Cargo.toml, or if bundle.active is false
- re-runs lint, typecheck, unit tests, and build against the tagged tree
- marks any 0.x or suffixed version as a prerelease

build (four native targets, fail-fast disabled):
- linux-x86_64 deb, macos-aarch64 and macos-x86_64 app+dmg, windows-x86_64
  msi+nsis
- Apple signing and notarization, and Windows Authenticode, activate only when
  their secrets are present; an unsigned release still succeeds but emits a
  loud warning for every unsigned platform
- the Windows thumbprint is injected through a --config overlay that is deleted
  afterwards, so the tracked tauri.conf.json is never modified
- smoke tests read the artifact, not the exit status: Info.plist version and
  identifier, lipo architecture, codesign, .deb Version and payload,
  Authenticode status, and a 1 MiB floor that catches a bundler that failed
  silently

publish (Ubuntu, the only job with contents: write):
- recomputes SHA256SUMS.txt over the bytes actually being published
- generates notes with the commit list since the previous tag
- gh release create --verify-tag, refusing to overwrite an existing release

Signing material lives in a release-signing environment rather than repository
secrets. All ten action references are pinned to full commit SHAs. Every job
sets timeout-minutes and least-privilege permissions.

No updater artifacts are produced: the updater plugin is not configured, and
createUpdaterArtifacts fails the Tauri build outright. docs/RELEASING.md
records the exact steps required to enable it later.

workflow_dispatch takes an existing tag and a dry_run flag defaulting to true,
so the whole pipeline can be rehearsed without publishing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restore the full release-infrastructure deliverable set after a concurrent
worktree reset dropped LICENSE and SECURITY.md and replaced the release
pipeline and runbook with shorter versions. This reinstates the complete,
validated work while preserving the README.md added by the intervening commit.

- LICENSE: MIT, Copyright (c) 2026 OpenCoven (canonical text).
- SECURITY.md: supported versions + private GitHub advisory reporting.
- docs/releasing.md: tag -> build -> checksum -> publish -> smoke-test ->
  rollback runbook, secrets table, and honest note that v0.0.1 ships without
  auto-update plus the exact enablement procedure.
- .github/workflows/release.yml: tag-triggered (v*) pipeline with signed-tag
  verification (annotated + git verify-tag + version match across
  package.json, tauri.conf.json, Cargo.toml), matrix installer builds
  (macOS aarch64/x86_64, Windows x86_64, Linux x86_64) via `tauri build` with
  explicit per-platform --bundles, gated Apple/Windows signing, SHA256SUMS,
  per-platform smoke tests, opt-in updater/latest.json (skipped, never
  hard-fails, since createUpdaterArtifacts is false), and gh-CLI publishing.
  Third-party actions pinned to full commit SHAs; least-privilege per-job
  permissions; release-signing environment on signing jobs; artifact paths
  quoted for the space in the product name.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The README linked `docs/RELEASING.md` but the file is tracked as
`docs/releasing.md`. macOS is case-insensitive so this looked fine
locally; GitHub is case-sensitive and the link would 404.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add dry-run coverage, tag provenance checks, tagged-tree validation, artifact smoke tests, conditional updater handling, and guarded draft publishing. Keep security and release documentation aligned with the actual v0.0.1 packaging path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Describe the manual release rehearsal path and the current in-memory conversation boundary without discouraging valid security reports.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Skip release creation when dry_run is enabled and publish a summary of the verified artifacts instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@BunsDev
BunsDev force-pushed the ci/release-infrastructure branch from 4928d0a to 4808e3e Compare September 4, 2026 06:53
@BunsDev

BunsDev commented Sep 4, 2026

Copy link
Copy Markdown
Member Author

Rebased onto current `main` now that #85 (the Windows supervisor fix, which is what this PR's only real failure was waiting on) has merged. Clean rebase, no conflicts.

Verified locally: `cargo check/clippy/fmt` clean, `pnpm typecheck`/`lint`/`format:check` clean (7 pre-existing baseline CSS warnings), full unit suite 475/475 real tests (1 known unrelated environment flake in `phase1-schema-v2-evidence.test.ts`), and `src/release-workflow.test.ts` 3/3.

Pushed. Should be fully green in CI now that both the Windows fix and billing are sorted.

🤖 Generated with Claude Code

BunsDev added a commit that referenced this pull request Sep 4, 2026
Add the two governance documents the repository still lacks before a public
release.

CONTRIBUTING.md is written against this repository rather than from a
template: the real toolchain (Node 22+, pnpm 10.34.0 via Corepack,
rust-toolchain.toml), the real script names, the worktree-per-branch
convention, the signed-commit requirement including the pre-flight
user.signingkey and gpg.format checks, and an honest description of the
phase 1 conformance lock, including which paths it pins and the two-commit
repin process. Contributors are told not to repin speculatively.

CODE_OF_CONDUCT.md adapts the Contributor Covenant 2.1 principles and
enforcement ladder, with attribution, and points reporting at the GitHub
report control plus a private channel.

LICENSE and SECURITY.md are deliberately not included here. They are carried
by the release-infrastructure branch (#63); adding them in both places would
guarantee a conflict. README.md is left untouched for the same reason: #63
already appends to it, and the links to these two files should be added once
that lands.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@BunsDev
BunsDev merged commit 44a5ee4 into main Sep 4, 2026
12 of 21 checks passed
BunsDev added a commit that referenced this pull request Sep 4, 2026
* docs: add contributing and code of conduct

Add the two governance documents the repository still lacks before a public
release.

CONTRIBUTING.md is written against this repository rather than from a
template: the real toolchain (Node 22+, pnpm 10.34.0 via Corepack,
rust-toolchain.toml), the real script names, the worktree-per-branch
convention, the signed-commit requirement including the pre-flight
user.signingkey and gpg.format checks, and an honest description of the
phase 1 conformance lock, including which paths it pins and the two-commit
repin process. Contributors are told not to repin speculatively.

CODE_OF_CONDUCT.md adapts the Contributor Covenant 2.1 principles and
enforcement ladder, with attribution, and points reporting at the GitHub
report control plus a private channel.

LICENSE and SECURITY.md are deliberately not included here. They are carried
by the release-infrastructure branch (#63); adding them in both places would
guarantee a conflict. README.md is left untouched for the same reason: #63
already appends to it, and the links to these two files should be added once
that lands.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* docs: correct governance references

Align the documented Node pin and Phase 1 authority scope with current main. Clarify conduct reporting channels and keep security reports on the SECURITY.md path.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: align governance guidance with current workflow

Correct the pinned setup, desktop connection model, branching and release guidance, signing checks, documentation validation, conformance repin process, and conduct reporting path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@BunsDev
BunsDev deleted the ci/release-infrastructure branch September 4, 2026 09:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants