Problem
A desktop tag is not currently a reproducible release boundary. The same builder tag can resolve different dependency source and install a different MCP bridge later.
Confirmed findings
P0: release dependencies are taken from moving branches
.github/workflows/desktop-release.yml checks out manishiitg/mcpagent and manishiitg/multi-llm-provider-go without a ref, then rewrites agent_go/go.mod to those checkout directories. Both resolve to whatever their main branch contains when the workflow runs, not what the builder tag declared. A retry of one tag can build different binaries.
P0: the installer builds MCP bridge from moving main
install.sh downloads mcpagent and the provider from refs/heads/main.tar.gz. Two users installing the same DMG version at different times can receive different mcpbridge binaries that may not match the bundled server.
P1: build and publish are one mutable operation
The tag job rebuilds and publishes through electron-builder. A retry is another build rather than publication of an already verified immutable artifact. No release manifest binds source/dependency SHAs to the assets.
P1: release script can publish unreviewed local main
scripts/desktop-release.sh allows local main to be ahead of origin/main, pushes it, and tags it. It does not require HEAD == origin/main, validate the canonical origin URL, enforce a monotonic version, or require package/package-lock versions to match the tag before tagging.
P1: assets have no integrity/provenance bundle
Releases do not publish SHA-256 checksums, an SBOM, a machine-readable build manifest, or GitHub artifact attestation/provenance. The updater downloads a known filename but does not verify a release-published checksum.
P2: toolchain and Actions inputs float
go-version: 1.25.x, node-version: 20, macos-15-intel, and action major tags can change. npm dependencies are lockfile-controlled, but the OS/toolchain/build-action graph is not fully pinned. The unsigned/unnotarized DMG is also a distribution-security gap, though signing is separable from deterministic source selection.
P2: documentation describes a second manual release path
desktop/README.md still documents manual bump/tag/publish steps alongside the dedicated script, increasing the chance that releases bypass preflight and changelog behavior.
Recommended design
- Add a committed release/build manifest containing builder SHA, exact mcpagent SHA, exact provider SHA, Go/Node/Electron versions, architecture, and version.
- Make CI checkout dependencies at those exact SHAs. Never resolve dependency
main during a tag build.
- Split build from publication: build once, test/inspect it, upload an immutable workflow artifact, then attach exactly those files to the GitHub release. Retries of publication must not rebuild.
- Publish
SHA256SUMS, SBOMs, the build manifest, and GitHub artifact attestations. Verify the DMG checksum in the updater/installer.
- Version or bundle
mcpbridge with the release. Do not compile it from branch heads during installation.
- Make the release script require clean
main, canonical origin, HEAD == origin/main, no existing tag/release, a version greater than Latest, and matching desktop package/package-lock versions. Add --dry-run.
- Collapse README guidance to the release script and recovery instructions.
- Pin toolchain patch versions and action commit SHAs. Record the runner image in the manifest.
Suggested implementation phases
Phase 1: source reproducibility
- build manifest and exact dependency refs
- strict release preflight
- versioned/bundled mcpbridge
- build once, publish same artifact
Phase 2: integrity and supply chain
- checksums, SBOM, attestations
- updater checksum verification
- pin actions/toolchain
Phase 3: distribution hardening
- Developer ID signing and notarization
- installation test on a clean macOS VM
Tests / acceptance
- rerunning a release from the same manifest after dependency
main branches move produces the same server/frontend payload hashes
- publication retry reuses the original workflow artifact and does not invoke a build
- release fails before tagging when local main differs from origin, version is not greater than Latest, dependency SHAs are missing, or package versions disagree
- release contains manifest, checksums, SBOM, attestations, expected DMG/zip/update metadata, and exact source links
- installer obtains the bridge matching the release manifest and verifies its checksum
Current evidence
.github/workflows/desktop-release.yml: dependency checkouts have no refs; go mod edit -replace points to those moving checkouts
agent_go/go.mod: declares versions but also has local replace directives
scripts/desktop-release.sh: permits local-main-ahead push/tag flow
install.sh: downloads both bridge source repositories from main
desktop/README.md: parallel manual release path
Problem
A desktop tag is not currently a reproducible release boundary. The same builder tag can resolve different dependency source and install a different MCP bridge later.
Confirmed findings
P0: release dependencies are taken from moving branches
.github/workflows/desktop-release.ymlchecks outmanishiitg/mcpagentandmanishiitg/multi-llm-provider-gowithout aref, then rewritesagent_go/go.modto those checkout directories. Both resolve to whatever theirmainbranch contains when the workflow runs, not what the builder tag declared. A retry of one tag can build different binaries.P0: the installer builds MCP bridge from moving
maininstall.shdownloadsmcpagentand the provider fromrefs/heads/main.tar.gz. Two users installing the same DMG version at different times can receive differentmcpbridgebinaries that may not match the bundled server.P1: build and publish are one mutable operation
The tag job rebuilds and publishes through electron-builder. A retry is another build rather than publication of an already verified immutable artifact. No release manifest binds source/dependency SHAs to the assets.
P1: release script can publish unreviewed local
mainscripts/desktop-release.shallows localmainto be ahead oforigin/main, pushes it, and tags it. It does not requireHEAD == origin/main, validate the canonical origin URL, enforce a monotonic version, or require package/package-lock versions to match the tag before tagging.P1: assets have no integrity/provenance bundle
Releases do not publish SHA-256 checksums, an SBOM, a machine-readable build manifest, or GitHub artifact attestation/provenance. The updater downloads a known filename but does not verify a release-published checksum.
P2: toolchain and Actions inputs float
go-version: 1.25.x,node-version: 20,macos-15-intel, and action major tags can change. npm dependencies are lockfile-controlled, but the OS/toolchain/build-action graph is not fully pinned. The unsigned/unnotarized DMG is also a distribution-security gap, though signing is separable from deterministic source selection.P2: documentation describes a second manual release path
desktop/README.mdstill documents manual bump/tag/publish steps alongside the dedicated script, increasing the chance that releases bypass preflight and changelog behavior.Recommended design
mainduring a tag build.SHA256SUMS, SBOMs, the build manifest, and GitHub artifact attestations. Verify the DMG checksum in the updater/installer.mcpbridgewith the release. Do not compile it from branch heads during installation.main, canonical origin,HEAD == origin/main, no existing tag/release, a version greater than Latest, and matching desktop package/package-lock versions. Add--dry-run.Suggested implementation phases
Phase 1: source reproducibility
Phase 2: integrity and supply chain
Phase 3: distribution hardening
Tests / acceptance
mainbranches move produces the same server/frontend payload hashesCurrent evidence
.github/workflows/desktop-release.yml: dependency checkouts have no refs;go mod edit -replacepoints to those moving checkoutsagent_go/go.mod: declares versions but also has local replace directivesscripts/desktop-release.sh: permits local-main-ahead push/tag flowinstall.sh: downloads both bridge source repositories frommaindesktop/README.md: parallel manual release path