Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions .github/workflows/winget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@ name: Publish to WinGet
# To make the automatic trigger real, CI / Release would need to create the Release
# with a PAT instead of GITHUB_TOKEN. Left as-is deliberately — see CLAUDE.md.
#
# Requires repo secret WINGET_TOKEN: a classic PAT with `public_repo` scope
# (winget-releaser does not support fine-grained tokens). `public_repo` IS enough —
# if you hit a permissions-looking error, read the sync step below before touching
# the token, because that error is almost never about the token.
# Requires repo secret WINGET_TOKEN: a classic PAT (winget-releaser does not support
# fine-grained tokens) with BOTH scopes:
#
# public_repo — submit the manifest PR to microsoft/winget-pkgs
# workflow — sync our fork, which copies upstream's .github/workflows/*.yml
#
# The `workflow` scope is the non-obvious one and its absence does NOT look like a
# scope problem: the sync fails with HTTP 422, the fork goes stale, and the SUBMIT
# step then reports "does not have the correct permissions to execute CreateRef".
# See the sync step below for the full chain.

on:
release:
Expand All @@ -40,21 +46,31 @@ jobs:
# dozens of commits a day, so a fork left alone between releases falls far
# enough behind that GitHub rejects the branch creation.
#
# The failure is badly disguised — it surfaces as
# The failure is badly disguised — it surfaces from the SUBMIT step as
# "<user> does not have the correct permissions to execute `CreateRef`"
# "failed to create branch UmageAI.CodeShellManager-<version>-<hash>"
# which reads like a token-scope problem and is not one. v0.6.0 burned three
# regenerated PATs (including needlessly widening the scope to full `repo`)
# before the actual cause turned up. See komac#376 and winget-releaser#336.
# which reads like a token problem. Three releases were spent rotating and
# widening PATs before the real chain turned up:
#
# WINGET_TOKEN lacks `workflow` scope
# -> merge-upstream refuses with HTTP 422, because upstream winget-pkgs
# contains .github/workflows/*.yml and syncing means writing them
# -> the fork stays stale
# -> CreateRef is rejected
#
# So WINGET_TOKEN must be a classic PAT with BOTH `public_repo` AND `workflow`.
# See komac#376 and winget-releaser#336 for the symptom; the scope is ours.
#
# NOT continue-on-error, deliberately. It was — and that is precisely why this
# masqueraded as a token problem for three releases: the sync failed silently
# and only the misleading downstream error was ever seen. A failed sync means
# the submit is about to fail anyway, so fail here where the message is honest.
#
# NOTE the fork komac uses is the one under the SAME OWNER as this repo —
# umage-ai/winget-pkgs — not a maintainer's personal fork. A personal fork of
# winget-pkgs may also exist; syncing that one does nothing. Override with the
# `fork-user` input if this ever needs to point elsewhere.
# continue-on-error: a sync hiccup must not block a submit that might still
# succeed, and if the submit then fails we want its real error, not this one.
- name: Sync umage-ai/winget-pkgs with upstream
continue-on-error: true
env:
GH_TOKEN: ${{ secrets.WINGET_TOKEN }}
run: |
Expand Down
15 changes: 9 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -428,9 +428,9 @@ gh workflow run chocolatey.yml -f tag=vX.Y.Z

To make it genuinely automatic, CI / Release would have to create the Release with a PAT rather than `GITHUB_TOKEN`.

### winget: the `CreateRef` error is not about the token
### winget: the `CreateRef` error names the wrong culprit

`winget.yml` submits the signed MSI to microsoft/winget-pkgs as `UmageAI.CodeShellManager` via [winget-releaser](https://github.com/vedantmgoyal9/winget-releaser). Needs `WINGET_TOKEN` — a **classic** PAT with `public_repo` (fine-grained tokens are unsupported).
`winget.yml` submits the signed MSI to microsoft/winget-pkgs as `UmageAI.CodeShellManager` via [winget-releaser](https://github.com/vedantmgoyal9/winget-releaser). Needs `WINGET_TOKEN` — a **classic** PAT (fine-grained tokens are unsupported) with **both** `public_repo` and `workflow`.

When it fails you will see:

Expand All @@ -439,14 +439,17 @@ When it fails you will see:
1: failed to create branch UmageAI.CodeShellManager-<version>-<hash>
```

**This is almost never a token problem.** It means our fork of winget-pkgs is too far behind upstream for GitHub to accept the new branch. Upstream lands dozens of commits a day, so a fork untouched since the last release is always stale by the next one.
**The message points at the wrong thing.** Two distinct causes produce it, and the token itself is the *second* one, not the first:

Two traps that cost real time on v0.6.0:
1. **The fork is stale.** komac creates its branch in `umage-ai/winget-pkgs`; upstream lands dozens of commits a day, so a fork untouched since the last release is always too far behind for GitHub to accept a new branch.
2. **`WINGET_TOKEN` is missing the `workflow` scope**, so the automatic sync that would have fixed (1) *cannot* run — `merge-upstream` returns HTTP 422 because upstream winget-pkgs contains `.github/workflows/*.yml` and syncing means writing them. The fork stays stale and you land back at (1).

Two traps that cost real time across v0.6.0 and v0.7.0:

- **Sync the fork under the org, `umage-ai/winget-pkgs`** — komac uses the fork owned by the same account as this repo. A maintainer's *personal* fork (`AThraen/winget-pkgs`) may also exist and is a red herring; syncing it changes nothing.
- **Don't widen the token scope.** `public_repo` is sufficient. winget-releaser's README once carried advice to use full `repo`; the PR proposing it was closed unmerged. Broadening the scope does not fix this and hands CI write access to every private repo the owner can reach.
- **`public_repo` alone is not enough — the token also needs `workflow`.** This was recorded backwards here through v0.6.0 ("`public_repo` is sufficient"), which is why the same failure was rediagnosed three releases running. It is still true that widening to *full* `repo` is wrong and does not help: that grants CI write access to every private repo the owner can reach. `public_repo` + `workflow`, nothing more.

`winget.yml` now syncs the org fork automatically before submitting, so this should not recur. If it does, sync manually and re-dispatch:
`winget.yml` syncs the org fork automatically before submitting, and that step is deliberately **not** `continue-on-error` — it used to be, which is exactly how a failing sync stayed invisible and only the misleading `CreateRef` error was ever seen. If the sync fails, fix the token scope; to unblock a release in the meantime, sync by hand and re-dispatch:

```bash
gh api -X POST repos/umage-ai/winget-pkgs/merge-upstream -f branch=master
Expand Down