fix(version-history): the tab was empty for EVERY app — it filtered on a field the response lacks - #89
Merged
Merged
Conversation
…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.
Contributor
Quality Report — ConductionNL/openbuild @
|
| 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
VersionHistoryfetches/apps/openbuild/api/applications/{slug}/versions, then filters the result withThat endpoint does not return
applicationUuid. Measured:ApplicationVersionsTabpasses bothapp-slugandapplication-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.
versionRouting 9.2 — an assertion that was wrong twice over
.openbuild-schema-listcount 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 todraft).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 avisualbaseline, untouched by this work.🤖 Generated with Claude Code