modified release pipeline

This commit is contained in:
2026-08-13 16:23:10 +05:00
parent 42974ecc8f
commit 1aa9d9b44e
4 changed files with 393 additions and 70 deletions
+59 -17
View File
@@ -162,8 +162,27 @@ after a switch of the mode, and that is a question asked once.
## Updates
The Store updates the app, and the app itself does nothing about it: there is no
updates section in the window, no request to the network and no code for either.
The check runs when the settings window is opened, not when the machine is
switched on: the background half no longer goes to the network at all, and there
would be nothing in it to show the answer. The setting in the window says as much.
The app looks for new versions among the releases of its own repository. A
release counts when its tag is a plain version — `v1.2.3` or `1.2.3` — and an
MSIX package is attached to it. A tag with anything else in it, `v1.2.3-beta`
among them, is passed over: a pre-release version is asked for on purpose, not
offered by the app.
Out of the attached files the `.msixbundle` is preferred — it carries both
architectures. Failing that, the package whose name holds the architecture of
this machine is taken: `CursorLang-1.2.3.0-x64.msix`. Those are the names
`build-msix.ps1` produces, so a release is made by attaching what it built.
The package is downloaded to the temp folder and handed to the Windows app
installer: it shows the publisher, asks for a confirmation and replaces the
installed version. Windows checks the signature, so the package attached to a
release has to be signed — an unsigned one installs nowhere but a machine in
developer mode; the pipeline signs what it attaches. The running app keeps
working off the old files until it is restarted.
That is not a matter of taste but of what a signature costs. Windows installs an
MSIX only when it trusts the signature on it, and a publicly trusted code signing
@@ -222,10 +241,11 @@ running agent and fails if any part of the WPF renderer is in it.
The pipelines live in `.gitea/workflows` and run on Gitea Actions. A pull
request into `master` is built and tested; a tag of the form `v1.2.3` is built,
tested and packed into an MSIX, which is left in the artifacts of the run. The
version is taken from the tag alone — a tag shaped any other way stops the run
right at the start. The package version ends up as `1.2.3.0`: the Store takes
four numbers and keeps the last one for itself, so the tag has no say in it.
tested, packed into an MSIX and published as a release with the signed packages
attached. The version is taken from the tag alone — a tag shaped any other way
stops the run right at the start. The package version ends up as `1.2.3.0`: the
Store takes four numbers and keeps the last one for itself, so the tag has no
say in it.
Both pipelines ask for a Windows runner labelled `windows-x64` with the .NET 10
SDK and git-lfs on it. The checkout pulls LFS files: without them the icon is a
@@ -235,18 +255,31 @@ need a desktop of their own — the end-to-end ones, and those that ask for the
foreground window or the caret — skip themselves on a runner that lives as a
service in session 0, where there is no desktop to show a window on.
The package goes to the Store and nowhere else: it is unsigned, and Partner
Center puts its own signature on it. So the run leaves it in the artifacts under
the name `msix-1.2.3.0`, where whoever uploads it picks it up by hand; nothing
is attached to the release, which Gitea makes for the tag by itself and which
carries the tag alone. An unsigned package hanging off a release would look like
something to install and install nowhere — see the section on updates.
The package is built twice over, because the Store and a release want different
things of it.
The identity comes from repository variables and falls back to the defaults of
the script when unset: `MSIX_IDENTITY_NAME`, `MSIX_PUBLISHER` and
`MSIX_PUBLISHER_DISPLAY_NAME`. Together the identity and the publisher decide
the family name of the package, so both have to stay as they are from version to
version, or the Store takes the next one for a different app.
The Store one carries the identity reserved in Partner Center and no signature —
Partner Center signs it there. It never leaves the artifacts of the run: someone
picks it up and uploads it by hand. Its name says which one it is —
`CursorLang-1.2.3.0-store.msixbundle`. The identity comes from repository
variables and falls back to the defaults of the script when unset:
`MSIX_IDENTITY_NAME`, `MSIX_PUBLISHER` and `MSIX_PUBLISHER_DISPLAY_NAME`.
The one attached to the release is signed by the pipeline with a certificate
from SSL.com, whose private key stays in their HSM and never comes down to the
runner: eSigner CKA is installed on it as a key storage provider, and `signtool`
asks that for the key the way it would ask a token. The account is three
repository secrets — `ESIGNER_USERNAME`, `ESIGNER_PASSWORD` and
`ESIGNER_TOTP_SECRET`; the last one is the secret eSigner hands out for
automated signing, not a code read off a phone. They are checked before the
build rather than at the signing step: a release without a signed package is
not a release.
Its `Publisher` is not `MSIX_PUBLISHER` but the subject of that certificate,
read off it in the run — Windows takes a package naming anyone else for a
forgery. Together with the identity that subject decides the family name of the
package, so both have to stay as they are from release to release, or an update
installs beside the old version instead of replacing it.
## Building the MSIX package
@@ -276,6 +309,15 @@ sake of machines that run the x64 one under emulation anyway.
Nothing here is signed: the Store signs the package itself, and for installing it
on this machine the layout is registered instead — see `-Install` below.
`-CertificateThumbprint` signs everything the build produces, with the
certificate of that thumbprint out of the personal store of the current user;
`-Publisher` then has to name its subject, and the script says so before it
starts building rather than after. The pipeline is what normally signs, but the
same works by hand once eSigner CKA — or a certificate of any other kind — has
put a certificate into the store. `-PackageSuffix` goes at the end of the file
names: the builds for the Store and for a release differ in what is inside them
and in nothing else.
The app ships with its own copy of .NET: Windows does not include .NET 10, and
MSIX cannot install a runtime as a package dependency.