Skip to content

fix(version-history): the tab was empty for EVERY app — it filtered on a field the response lacks - #89

Merged
rubenvdlinde merged 1 commit into
developmentfrom
verify-full
Aug 2, 2026
Merged

fix(version-history): the tab was empty for EVERY app — it filtered on a field the response lacks#89
rubenvdlinde merged 1 commit into
developmentfrom
verify-full

Conversation

@rubenvdlinde

@rubenvdlinde rubenvdlinde commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

The bug

VersionHistory fetches /apps/openbuild/api/applications/{slug}/versions, then filters the result with

raw.filter(r => r.applicationUuid === this.applicationUuid)   // "IDOR defence-in-depth"

That endpoint does not return applicationUuid. Measured:

GET /api/applications/pw-verchain/versions
-> 3 rows, each { name, slug, manifest, manifestDelta, baseRef, register, semver, status }
   — no applicationUuid on any of them

ApplicationVersionsTab passes both app-slug and application-uuid, so the filter removed every row and the "Version history" tab rendered empty for every application, always.

Filtering a server-scoped response against a field that response does not carry isn't defence in depth — it's an unconditional deny. The filter now applies only to the unscoped /applicationversions?applicationUuid= endpoint, where the field exists and the check is meaningful.

Verified live: 3 rows rendered, empty state gone.

This corrects a claim I committed in the previous PR — that VersionHistory "lists publish SNAPSHOTS, not versions, so it needs a fixture that publishes twice". Wrong. It lists exactly the versions versionChain.ts already creates; they were being filtered out.

versionRouting 9.2 — an assertion that was wrong twice over

  1. It passed for the wrong reason. Before the setup-wizard fix, a non-admin never reached the builder at all, so "no schema list" held because nothing rendered for anyone.
  2. It cannot distinguish the roles. Measured side by side, the viewer (denied staging) and the editor (allowed staging) render an identical surface: .openbuild-schema-list count 1, reading "No schemas yet".

No data leaks — the list is empty for both — so this is a UX gap (the builder renders no version-not-found state), not a security one. The assertion now checks what it can actually detect: that no schema of the forbidden version is named. The gate itself is covered by the three request-level tests, which is where it's enforced. 6/6 pass.

version-rollback — rewritten, deliberately left skipped

Rewritten against the verified contract (ApplicationVersionsTab.onRollback: manifest copied over, version relabelled <version>-rollback-<hex>, status forced to draft).

It is skipped because it has never been executed — the disposable e2e instance was destroyed by a disk-full event before it could run once. Enabling it is deleting one .skip, but that should happen with a run, not on the strength of a comment. Shipping an unexecuted spec as coverage is the exact failure mode the notes in that file document three times over.

Full-suite movement

Before this branch's predecessors: 21 failed / 162 passed / 74 skipped.
After: 4 failed / 182 passed / 74 skipped.

Of the remaining 4, one was the 9.2 assertion fixed here; the other three are docs-screenshots (×2) and a visual baseline, untouched by this work.

🤖 Generated with Claude Code

…n a field the response lacks

VersionHistory fetches `/apps/openbuild/api/applications/{slug}/versions`, then
filtered the result with

    raw.filter(r => r.applicationUuid === this.applicationUuid)

as "IDOR defence-in-depth". That endpoint does not return `applicationUuid`.
Measured:

    GET /api/applications/pw-verchain/versions
    -> 3 rows, each { name, slug, manifest, manifestDelta, baseRef, register,
                      semver, status } — no applicationUuid on any of them

ApplicationVersionsTab passes BOTH app-slug and application-uuid, so the filter
removed every row and the "Version history" tab rendered
`.version-history__empty` for every application, always.

Filtering a server-scoped response against a field that response does not carry
is not defence in depth, it is an unconditional deny. The filter now applies
only to the unscoped `/applicationversions?applicationUuid=` endpoint, where the
field does exist and the check is meaningful.

Verified live before the instance was lost: 3 rows rendered, empty-state gone.

This also corrects a claim I committed earlier in version-rollback.spec.ts —
that VersionHistory "lists publish SNAPSHOTS, not versions, so it needs a
fixture that publishes twice". That was wrong. It lists exactly the versions
versionChain.ts already creates; they were being filtered out.

versionRouting 9.2 — the viewer-UI assertion was wrong twice over:

  1. It PASSED for the wrong reason. Before the setup-wizard fix a non-admin
     never reached the builder at all, so "no schema list" held because nothing
     rendered for anyone.
  2. It cannot distinguish the roles. Measured side by side, the viewer (DENIED
     staging) and the editor (ALLOWED staging) render an IDENTICAL surface:
     `.openbuild-schema-list` count 1, reading "No schemas yet".

No data leaks — the list is empty for both — so this is a UX gap (the builder
renders no version-not-found state), not a security one. The assertion now
checks what it can actually detect: that no schema of the forbidden version is
NAMED. The gate itself is covered by the three request-level tests, which is
where it is enforced. 6/6 pass.

version-rollback.spec.ts — rewritten against the verified contract
(ApplicationVersionsTab.onRollback: manifest copied over, version relabelled
`<version>-rollback-<hex>`, status forced to draft), and left SKIPPED because it
has never been executed: the disposable instance was destroyed by a disk-full
event before it could run once. Enabling it is deleting one `.skip` — but do
that with a run, not on the strength of the comment.
@rubenvdlinde
rubenvdlinde merged commit fcaa7a8 into development Aug 2, 2026
16 of 20 checks passed
@rubenvdlinde
rubenvdlinde deleted the verify-full branch August 2, 2026 09:03
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openbuild @ cba0184

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 100/100
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-08-02 09:04 UTC

Download the full PDF report from the workflow artifacts.

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.

2 participants