From e0f51fdafc61599c4b80ef6ee56a6a3c51c2679d Mon Sep 17 00:00:00 2001 From: Etienne Lescot Date: Sat, 15 Aug 2026 00:46:30 +0200 Subject: [PATCH 1/2] fix(store): give msstore a project to publish, not just a package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v1.9.5 was the first release where publish-msstore actually ran — the job did not exist on the v1.9.1 or v1.9.2 builds — and it failed: We could not find a project publisher for the project at ...\artifacts\store\1.9.5\Openscreen.Setup.1.9.5.appx Credentials were never the problem; the CLI reported the configuration valid and resolved product 9MXQ1HQJL5G5. The call was wrong in two ways that compound. `msstore publish` takes a PROJECT ROOT positionally, detects the app type there (Electron, from package.json), and only then accepts a built package through `--inputFile` — so passing the .appx positionally asked it to find a project inside a zip. And the job never checked the repo out, so even the corrected command had nothing to point at. Checkout goes before the artifact download, not after: actions/checkout cleans the workspace and would delete the package it is meant to submit. Unverified, deliberately said out loud in the doc: `--inputFile` is documented for .msix and .msixupload, and build:win:store emits an .appx. Whether the CLI takes that extension cannot be tested without a stable release or a workflow_dispatch at a stable tag, so the Store keeps needing a manual upload until one of those goes green. Worth recording that this was visible at all only because the same release carried the fix reporting the submission's real outcome rather than the configuration's — the previous version would have printed "Submitted to the Store" over this. --- .github/workflows/build.yml | 16 +++++++++++++++- .../engineering/release-and-secrets.md | 6 ++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9c789b0a..c15d7782 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -999,6 +999,16 @@ jobs: exit 1 fi + # `msstore publish` takes a PROJECT root, not a package: it detects the app + # type there (Electron, via package.json) and only then accepts the built + # package through `--inputFile`. This job used to check nothing out, so + # there was no project to point it at. Checkout runs before the artifact + # download on purpose — actions/checkout cleans the workspace, and would + # delete the package if it ran after. + - name: Check out the project + if: steps.store.outputs.enabled == 'true' + uses: actions/checkout@v7 + - name: Download Store package if: steps.store.outputs.enabled == 'true' uses: actions/download-artifact@v4 @@ -1031,7 +1041,11 @@ jobs: throw 'more than one .appx in the artifact — refusing to guess which one to submit' } Write-Output "Submitting $($appx.Name) to product $env:PRODUCT_ID" - msstore publish $appx.FullName -id $env:PRODUCT_ID + # The positional argument is the project root, NOT the package — passing + # the .appx there is what failed the first real run of this job on + # v1.9.5: "We could not find a project publisher for the project at + # ...Openscreen.Setup.1.9.5.appx". The package goes through --inputFile. + msstore publish . --inputFile $appx.FullName --appId $env:PRODUCT_ID # Report what happened, not what was configured. Keyed off `enabled` alone # under always(), this claimed "Submitted to the Store" when `msstore diff --git a/technical-documentation/engineering/release-and-secrets.md b/technical-documentation/engineering/release-and-secrets.md index 3451ece8..83bdf810 100644 --- a/technical-documentation/engineering/release-and-secrets.md +++ b/technical-documentation/engineering/release-and-secrets.md @@ -169,6 +169,12 @@ Two constraints from Microsoft's documentation: automated updates through GitHub `msstore submission updateMetadata` can also drive the Store listing text from a versioned `metadata.json`, which would replace the CSV export/import round-trip. Not wired up here. +**It has submitted nothing yet.** v1.9.5 was the job's first real run — it did not exist on the v1.9.1 or v1.9.2 builds — and it failed: `We could not find a project publisher for the project at …Openscreen.Setup.1.9.5.appx`. Credentials were fine; the CLI reported the configuration valid and resolved the product. The call was wrong. `msstore publish` takes a **project root** as its positional argument, detects the app type there, and only then accepts a built package through `--inputFile`; the job passed the `.appx` positionally and never checked the repo out, so there was no project to detect. Fixed by adding a checkout (before the artifact download — `actions/checkout` cleans the workspace) and calling `msstore publish . --inputFile --appId `. + +That failure was visible only because the same release carried the fix that reports the submission's real outcome instead of the configuration's. The prior version wrote "Submitted to the Store" whenever credentials resolved, under `always()` — so this exact failure would have shipped as a green success. + +**Still unverified, and the next thing likely to break:** `--inputFile` is documented for `.msix` and `.msixupload`, and `build:win:store` produces an `.appx` (`electron-builder --win appx`). Whether the CLI accepts that extension is untested — the only way to find out is a stable release or a `workflow_dispatch` of `build.yml` with a stable `release_tag`. Until one of those goes green, assume the Store still needs the manual upload below. + Rotate by issuing a new client secret on the Entra registration, updating `AZURE_AD_APPLICATION_SECRET`, publishing one release to confirm, then deleting the old secret. The tenant, client and seller IDs change only when the registration or account does. ## Discord secrets and variables From 1221221879c029eaad1c9f779d833ee73b1d054a Mon Sep 17 00:00:00 2001 From: Etienne Lescot Date: Sat, 15 Aug 2026 00:57:24 +0200 Subject: [PATCH 2/2] fix(store): drop the write token from the Store job, and stop calling a dispatch a dry run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two review findings, both on things this PR introduced. The checkout I added inherits the workflow-wide `contents: write` token and, at checkout's default, writes it into .git/config where every later step can read it — in the one job that also handles Partner Center credentials and runs a third-party CLI action. Nothing here pushes, so: persist-credentials: false, plus job-level `permissions: contents: read`. The artifact download is same-run and uses the runtime token, so it is unaffected. And the doc offered a workflow_dispatch as the way to check whether the CLI accepts an .appx. That is not a check. `msstore publish` commits the submission unless given --noCommit, which this job does not pass, so a dispatch fired to satisfy curiosity puts a build into certification and onto users' machines. The doc now says there is no dry run, names --noCommit as what one would require, and points at the next stable release as the test. --- .github/workflows/build.yml | 14 ++++++++++++++ .../engineering/release-and-secrets.md | 4 +++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c15d7782..01b031fd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -957,6 +957,12 @@ jobs: publish-msstore: name: Publish to Microsoft Store runs-on: windows-latest + # The workflow-wide token is `contents: write` because publish-release needs + # it. This job only reads: it checks the tree out so the CLI can identify the + # project, downloads a same-run artifact (which uses the runtime token, not + # this one), and talks to Partner Center with its own Entra credentials. + permissions: + contents: read needs: - build-windows-store - publish-release @@ -1008,6 +1014,14 @@ jobs: - name: Check out the project if: steps.store.outputs.enabled == 'true' uses: actions/checkout@v7 + with: + # Nothing here pushes; the tree is only read so the CLI can see it is + # an Electron project. Left at the default, checkout writes the + # workflow's `contents: write` token into .git/config, where every + # later step can read it — including a third-party CLI action and the + # Store submission. See the job-level `permissions` above: same reason, + # other half. + persist-credentials: false - name: Download Store package if: steps.store.outputs.enabled == 'true' diff --git a/technical-documentation/engineering/release-and-secrets.md b/technical-documentation/engineering/release-and-secrets.md index 83bdf810..6cdfb8a3 100644 --- a/technical-documentation/engineering/release-and-secrets.md +++ b/technical-documentation/engineering/release-and-secrets.md @@ -173,7 +173,9 @@ Two constraints from Microsoft's documentation: automated updates through GitHub That failure was visible only because the same release carried the fix that reports the submission's real outcome instead of the configuration's. The prior version wrote "Submitted to the Store" whenever credentials resolved, under `always()` — so this exact failure would have shipped as a green success. -**Still unverified, and the next thing likely to break:** `--inputFile` is documented for `.msix` and `.msixupload`, and `build:win:store` produces an `.appx` (`electron-builder --win appx`). Whether the CLI accepts that extension is untested — the only way to find out is a stable release or a `workflow_dispatch` of `build.yml` with a stable `release_tag`. Until one of those goes green, assume the Store still needs the manual upload below. +**Still unverified, and the next thing likely to break:** `--inputFile` is documented for `.msix` and `.msixupload`, and `build:win:store` produces an `.appx` (`electron-builder --win appx`). Whether the CLI accepts that extension is untested. + +**There is no dry run, so do not reach for one.** The job is gated to stable tags, so the only ways to exercise it are a real release or a `workflow_dispatch` of `build.yml` with a stable `release_tag` — and neither is a rehearsal. `msstore publish` commits the submission unless it is given `-nc, --noCommit`, which this job does not pass, so a dispatch fired "just to see whether the `.appx` is accepted" creates a submission that enters certification and reaches users. Adding `--noCommit` behind a dispatch input is what a real validation path would need; until someone builds that, assume the Store needs the manual upload below, and treat the next stable release as the test. Rotate by issuing a new client secret on the Entra registration, updating `AZURE_AD_APPLICATION_SECRET`, publishing one release to confirm, then deleting the old secret. The tenant, client and seller IDs change only when the registration or account does.