Skip to content

fix(release): outrank the App Store, and fail when the upload does not land - #593

Merged
rubenvdlinde merged 1 commit into
mainfrom
fix/release-outrank-the-store
Aug 27, 2026
Merged

fix(release): outrank the App Store, and fail when the upload does not land#593
rubenvdlinde merged 1 commit into
mainfrom
fix/release-outrank-the-store

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

What this fixes

Measured across all 21 fleet apps on 2026-08-27.

1. The computed version could be lower than what the store already serves

The baseline came from the newest stable git tag plus the branch's own info.xml. Neither can see a prerelease line that ran ahead elsewhere. The fleet released from Codeberg through June/July, where the beta line had walked up a minorpipelinq 0.4.0-beta.2, decidesk 1.1.0-beta.1, larpingapp 0.2.0-beta.1. Those are prerelease tags, so ^v[0-9]+\.[0-9]+\.[0-9]+$ is blind to them by construction.

Back on GitHub the baseline fell back to the old stable patch line. 14 of 21 apps were computing a downgrade — pipelinq proposes 0.3.2-beta against a store holding 0.4.0-beta.2.

Nothing rejected it: nextcloudappstore/api/v1/views.py::_check_permission validates existence and ownership and has no version ordering rule. A lower version uploads with a 200 and is then never offered to anyone on a higher one.

Fix: read /api/v1/apps.json, fold its max into the baseline, then assert under real semver that the new version outranks it.

2. A failed App Store upload was a ::warning:: and an exit 0

18 of 21 apps failed the upload on 2026-08-27 — HTTP 400 (id not registered) or 403 (token does not own the app) — and every one of those runs is recorded as a green release.

Fix: the upload failing fails the job, and the two failures the fleet actually hits name what to do.

3. Registration ran on every release and was getting rate limited

POST /api/v1/apps is the certificate-update endpoint. It was returning 429 {"detail":"Request was throttled. Expected available in 62877 seconds."} — a 17-hour lockout bought for nothing, since the app was already registered. It now runs only when the catalogue says the id is absent.

Verification

check result
apps.json vs union of 3 per-platform files agrees on 18/18 fleet ids
semver comparator unit cases 7/7, incl. 0.3.2-beta < 0.4.0-beta.2 and 1.0.10-beta.2 < 1.0.10
simulated over all 21 apps every app outranks its own and its pre-rename store entry
major bumps invented 0 — refused unless a stable release carries the major label
YAML parse / bash -n on every run: clean

Heads-up

This will turn ~18 apps' release runs red. That is the existing breakage becoming visible, not new breakage — those releases were already not reaching the store. Causes are tracked separately: 13 renamed ids await certificates (nextcloud/app-certificate-requests#1197–#1209), and openregister / zaakafhandelapp / pipelinq / shillinq need App Store ownership on the token account.

Follow-up

previous-app-id needs setting on the 11 renamed apps whose old entry is on the store, so their line picks up instead of restarting below it (filinq was about to publish 0.0.40 against docudesk's 0.1.0-beta.3).

…t land

Two defects, both of which made a broken release look like a good one.

1. The version could be lower than what the store already serves.

The baseline came from the newest stable git tag and, since #589, the
branch's own info.xml. Neither can see a prerelease line that ran ahead
somewhere else, and the fleet spent June and July releasing from
Codeberg where the beta line had walked up a minor: pipelinq
0.4.0-beta.2, decidesk 1.1.0-beta.1, larpingapp 0.2.0-beta.1. Those are
prerelease tags, so the ^v[0-9]+\.[0-9]+\.[0-9]+$ filter is blind to
them by construction. Back on GitHub the baseline fell back to the old
stable patch line, and pipelinq has been computing 0.3.2-beta against a
store holding 0.4.0-beta.2. Measured 2026-08-27: 14 of 21 fleet apps
were computing a downgrade.

Nothing rejected it. _check_permission in the appstore validates that
the app exists and that you own it; there is no version ordering rule at
all. A lower version uploads with a 200 and is then never offered to
anyone already on a higher one, so the only place this is visible is
here, before the number is chosen.

Read /api/v1/apps.json and fold its max into the baseline, then assert
under real semver that what we are about to publish outranks it. The
assertion is separate arithmetic on the full version string rather than
the stripped cores the baseline works in, so it can disagree with the
step it checks. Verified that apps.json agrees with the union of three
per-platform files across 18 fleet ids -- the per-platform endpoint
drops releases that do not match that platform and would reintroduce the
downgrade. A failed fetch fails the job; falling back to "the store has
nothing" is indistinguishable from an unregistered app.

A major bump is now refused unless it is a stable release carrying the
`major` label, so the arithmetic can adopt a higher minor but never
invent a major on its own.

Renamed apps are a new store entry starting from nothing, so their line
would restart below what the app already shipped: filinq was about to
publish 0.0.40 against docudesk's 0.1.0-beta.3. previous-app-id folds
the old entry in.

Simulated over all 21 apps: every one now outranks both its own entry
and its pre-rename entry, and none crosses a major.

2. A failed App Store upload was a ::warning:: and an exit 0.

On 2026-08-27 eighteen of the twenty-one fleet apps failed this call --
400 for an id that is not registered, 403 for a token that does not own
the app -- and every one of those runs is recorded as a green release.
The step advised a manual retry that nobody was ever told to perform.
Publishing to the store is the job; if it did not happen, the job did
not succeed. The two failures the fleet actually hits now name what to
do rather than what went wrong.

Registration also stops running on every release. POST /api/v1/apps is
the certificate-update endpoint and is rate limited hard; it was
returning 429 with a 17-hour lockout, bought for nothing since the app
was already registered. The catalogue fetched above says whether the id
exists, so registration runs only when it actually needs to.
This was referenced Aug 27, 2026
@rubenvdlinde
rubenvdlinde merged commit d143bc2 into main Aug 27, 2026
36 checks passed
@rubenvdlinde
rubenvdlinde deleted the fix/release-outrank-the-store branch August 27, 2026 16:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant