kubescape / kubescape/headlamp-plugin
paginatedListQuery silently truncates results to one page per namespace for namespace-restricted users
- Dominant language
- TypeScript
- Stars
- 12
- Forks
- 8
- Avg merge
- 12h
- Merged PRs (30d)
- 9
Description
`paginatedListQuery` in `src/query.ts` pages correctly when it queries cluster-wide, but not when it queries a namespace list. In the namespaced branch it still sends `&limit=${pageSize}` with every request, and then returns `continuation: undefined` regardless of what the apiserver said:
```ts
if (allowedNamespaces.length > 0) {
const listOfLists: any[] = await Promise.all(
allowedNamespaces.map(namespace =>
request(`/apis/${group}/${version}/namespaces/${namespace}/${queryFragment}`)
)
);
...
return { items: listOfLists.flatMap(list => list.items), continuation: undefined };
}
```
`handleListPaginationTasks` loops `while (continueReading.current && task.continuation !== undefined)`, so an undefined token ends the loop after the first pass. The result is that each allowed namespace contributes at most `pageSize` objects (default 50, configurable in the plugin settings) and everything past that is dropped without any error or warning.
## Who this affects
Only users who have `allowedNamespaces` configured for a cluster in Headlamp. Everyone else takes the cluster-wide branch, which returns a real `metadata.continue` token and pages properly.
For those users, any namespace holding more than `pageSize` objects is silently truncated on the pages that read through this helper:
- Compliance (`src/compliance/Compliance.tsx`) — missing `WorkloadConfigurationScanSummary` objects mean missing workloads, and the compliance score is computed from the incomplete set, so the number shown is wrong rather than merely partial.
- Vulnerabilities (`src/vulnerabilities/Vulnerabilities.tsx`) — same helper, same truncation.
Nothing in the UI indicates the list is incomplete, which is the worst part: a restricted user sees a plausible-looking score with no hint that workloads were left out.
## Reproducing
1. Configure a cluster in Headlamp with `allowedNamespaces` set to a namespace holding more than 50 workloads.
2. Open the Kubescape Compliance page.
3. Count the resources listed against `kubectl get workloadconfigurationscansummaries -n --no-headers | wc -l`.
The UI stops at the configured page size.
## Suggested fix
The signature returns a single `continuation` value, which cannot express one offset per namespace, so handing back `undefined` was the only option that type allowed. Either drain each namespace inside the function (loop per namespace until its response carries no `metadata.continue`), or change the return type to track a token per namespace so the caller keeps its incremental behaviour.
Draining inside the function is the smaller change, and it is what kubescape/headlamp-plugin#158 does as a fix, since that PR reuses this helper for a new "matched workloads" view and inherits the truncation. Happy to split that part out into its own PR if that is easier to review, or to leave it in #158.
Worth noting the trade-off with draining: the namespaced path stops reporting progress between pages, so a large namespace takes longer before the first render. It is still strictly better than showing a wrong number, but if the incremental behaviour matters for those pages, the per-namespace token is the better shape.
Contributor guide
Research direction
Start in src/query.ts by reading paginatedListQuery and its caller handleListPaginationTasks, then reproduce the namespace-restricted case with more than 50 resources using the kubectl command described. Done means every allowed namespace is fully listed across apiserver pages, with no silent truncation and accurate results in the Compliance and Vulnerabilities views.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kubernetes, typescript
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100