diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9c789b0a..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 @@ -999,6 +1005,24 @@ 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 + 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' uses: actions/download-artifact@v4 @@ -1031,7 +1055,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..6cdfb8a3 100644 --- a/technical-documentation/engineering/release-and-secrets.md +++ b/technical-documentation/engineering/release-and-secrets.md @@ -169,6 +169,14 @@ 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. + +**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. ## Discord secrets and variables