Skip to content

Add a CloudNativePG workspace: fleet triage, protection evidence, declarations and composed CNPG detail - #1921

Open
nadaverell wants to merge 17 commits into
mainfrom
feature/cnpg-workspace
Open

nadaverell wants to merge 17 commits into
mainfrom
feature/cnpg-workspace

Conversation

@nadaverell

@nadaverell nadaverell commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

CloudNativePG support in Radar today is ten separate CRD lists and renderers. Answering "which Postgres cluster needs attention, why, and what do I look at next" means stitching Clusters, Backups, ObjectStores, declarations and Pods together by hand. This adds a CloudNativePG workspace inside Resources that does that stitching. It covers fleet triage, recovery evidence, declared vs reconciled state, pooling and the operator. Every CNPG object gets one composed detail, whichever way you reach it.

The workspace is read-only. Every value it shows is something the cluster actually reports, labelled with its source. When something isn't reported it says so, never zero, "none" or green. The full contract is in docs/cnpg.md.

What changed

Workspace screens (/cnpg/*, inside Resources)

The Resources sidebar's CloudNativePG group gains a Workspace block above the exact kinds. Kinds sit under a collapsible "Resource kinds" block, grouped by API group.

  • Overview is the cluster fleet, defaulting to Needs attention. It shows instance pills, replication, protection, declarations, PG version and the top problem, with problem-category chips, search and a namespace chip. Each row inspects in the drawer and has explicit Logs and Open → actions.

  • Protection keeps these as separate facts per cluster, each with its source:

    • schedule
    • destination
    • last successful backup (newest of Backup CRs, ObjectStore status and in-tree status)
    • WAL archiving
    • recovery window: the earliest recoverable point from ObjectStore status, reaching the newest archived WAL. It reads "not advancing" only while WAL archiving fails; ObjectStore pages describe backup outcomes as recorded in status (a success whose status update failed is missing there), never as complete history
    • restore validation ("Unknown: no access to Backups" when the Backup a recovery names can't be read)

    It also lists failed backups from the last 7 days, destinations (ObjectStore upload health, labelled inferred with its evidence) and schedules. Restore validation is never green: Kubernetes records no restore tests.

  • Declarations lists Databases, Publications, Subscriptions and managed roles by cluster. It separates applied, not applied and pending, and shows controller errors and the GitOps source ("not recorded" when there isn't one).

  • Pooling lists Poolers and the clusters they front. Connection pressure reads "Not measured".

  • Operator shows operator and plugin Deployments with versions and readiness, image catalogs and their visible users, and operator configuration. Secret contents are never read.

One composed detail per object

  • WorkloadView gains an optional composed summary. For CNPG kinds, Overview is the summary (facts grouped by task, e.g. Backup → Outcome / Relationships) and the existing renderer moves to a Spec & status tab, so nothing repeats.
  • Every CNPG kind's full detail lives at /cnpg/<plural>/<ns|_>/<name>. You reach it from Open, from drawer expand, or by redirect from /workload/.... It keeps the workspace sidebar with the object nested under its home destination.
  • A Cluster adds three tabs: Protection; Activity, which replaces Timeline and covers the Cluster, its instance Pods and every CNPG object attributed to it, including deleted ones; and merged instance Logs, with role labels and parsed CNPG JSON levels (the PostgreSQL record.error_severity is read by the shared utils/log-level.ts, so every log viewer levels CNPG lines the same way). ?pod= preselects an instance.
  • The CNPG routes, gates and coverage states are listed in docs/cnpg.md#api; CLAUDE.md points there.

Navigation

  • Drawer: one drawer, URL-backed by ?drawer=kind:group:ns:name. Links inside it build a trail with a "← previous object" link in the drawer shell.
  • Return vs location: a drilldown carries a return label in history state ("← CloudNativePG Overview", "← Clusters"), kept across tab changes. Sidebar hops carry none. A crumb always names the object's place, so a fresh tab has a parent without a made-up previous task.
  • Context guard: detail URLs carry ctx=<kube context>, added on first view. After a context switch the page says " is not in ", with Switch back and Go to Overview, instead of opening a same-named object from another cluster.

Backend

  • GET /api/cnpg/workspace returns every CNPG kind plus instance Pods, authorized per kind, with coverage states: full, partial (including the allowed namespaces), denied, syncing, error or notInstalled.
    • Namespaced kinds fall back per namespace. ClusterImageCatalog needs a cluster-scope list.
    • Instance Pods must be controller-owned by the visible Cluster's UID.
    • Issues come from the Issues engine (flat, so Pod evidence only reaches callers who can list Pods), along with the cnpgNoDeclarativeBackup audit finding. Both are withheld where coverage is missing.
    • Denied namespaces are named only when the caller supplied the namespace list.
  • GET /api/cnpg/operator discovers operator and plugin workloads and their config references.
    • It ignores the namespace view filter, because the operator lives in its own namespace.
    • ConfigMap data is returned only with get configmaps; Secrets are never read.
  • GET /api/cnpg/clusters/{ns}/{name}/logs (plus /logs/stream) returns merged logs from owner-validated instance Pods. It is gated on get clusters, list pods and get pods/log.
  • GET /api/cnpg/clusters/{ns}/{name}/activity returns timeline events. Each kind is gated on list <kind>; Event rows additionally need list events.
  • Timeline attribution: ExtractLabels now retains cnpg.io/cluster (or spec.cluster.name) on CNPG objects and Pods, so deleted Backups and declarations stay attributed. No storage schema change.

Shared package (@skyhook-io/k8s-ui), all additive

  • ResourcesSidebar: optional categoryWorkspaces, with a pass-through sidebarCategoryWorkspaces on ResourcesView.
  • WorkloadView: optional renderSummary and extraTabs, plus a 'spec' value in WorkloadTabType.
  • WorkloadLogsViewer: optional initialPods.
  • New components/cnpg: buildCNPGFleet, the relation helpers and the summaries.

Consumers that pass none of these props see no change. That includes Radar Hub, which only needs to opt in if it wants the workspace.

Worth reviewing closely

  • Per-kind authorization in internal/server/cnpg_workspace.go: coverage, issue withholding, and not naming namespaces.
  • The certainty table in docs/cnpg.md, and packages/k8s-ui/src/components/cnpg/workspace.ts + relations.ts, which implement it.
  • The ?drawer= two-way sync in web/src/components/cnpg/CNPGView.tsx.
  • Context-switch handling in App.tsx, which preserves ctx on /cnpg/ routes.

Not included (needs a product/RBAC decision first)

  • Runtime data: replication lag, sessions, locks, WAL and slots via the instance manager (pods/proxy) and/or Prometheus. Replication reads "lag unknown" until then.
  • Write actions: Backup now, Switchover, Restart, Reload, Hibernate/Rehydrate, Restore to new cluster. No disabled placeholders are rendered.
  • Pooler connection pressure, which needs PgBouncer metrics.

These ship in #1922, stacked on this PR.

Testing

  • Up to date with main; CI is green on the head.
  • make tsc passes.
  • go test ./internal/server/ ./internal/timeline/ ./internal/k8s/ and pkg/timeline pass, including new handler tests for:
    • per-kind coverage, partial and denied namespaces, ClusterImageCatalog scope and kind collisions (Velero Backup, CAPI Cluster)
    • Pod evidence gating and instance ownership by UID
    • operator discovery and config gating
    • logs parsing, filtering and 403s
    • activity attribution of deleted children and per-kind and Event gating
  • k8s-ui vitest passes (4078 tests), including fleet derivation, relations, summaries and the sidebar workspace. Web vitest passes (1704 tests), including routes and the drawer trail.
  • make test: one unrelated cmd/desktop env test (TestEnrichEnvPrecedenceAndDiagnostics) failed under the full parallel run and passes on its own; nothing in cmd/ changed.
  • Visual: I ran against make cnpg-demo and walked these paths:
    • fleet → drawer → full Cluster page → Logs → return
    • Resources › Cluster → expand → same page → return to the list with the drawer restored
    • Protection → ObjectStore drawer → Cluster → trail back
    • Declarations with controller errors
    • Operator with the frozen demo operator scaled to 0
    • Activity including Backups
    • a context-mismatched link showing "not in this context"

Note

Medium Risk
New read-only APIs touch per-kind RBAC, merged pod logs, and timeline attribution; mistakes could leak withheld data or cross-namespace hints, though behavior is heavily tested and documented.

Overview
Adds a read-only CloudNativePG workspace under Resources (/cnpg/*) that composes fleet triage, protection evidence, declarations, pooling, and operator views from one workspace payload instead of separate CRD lists.

Backend: New GET /api/cnpg/workspace (per-kind coverage, issues, audit), GET /api/cnpg/operator, cluster logs (snapshot + SSE with instance validation), and activity (timeline with cnpg.io/cluster attribution). Routes are registered in server.go; pod log entries gain optional parsed level/logger/message.

Frontend (@skyhook-io/k8s-ui): New components/cnpg (fleet derivation, relations, per-kind Overview summaries) and optional hooks on WorkloadView / sidebar for composed CNPG detail (Overview + Spec & status, Cluster Protection/Activity/Logs).

Docs: docs/cnpg.md (certainty contract, navigation, API); README/CLAUDE/integrations updated for expanded CNPG kinds and workspace entry point.

Reviewed by Cursor Bugbot for commit a027865. Bugbot is set up for automated code reviews on this repo. Configure here.

… composed Cluster summary

- GET /api/cnpg/workspace: every CNPG kind plus owner-validated instance Pods,
  authorized per kind (namespaced kinds fall back per namespace; ClusterImageCatalog
  needs a cluster-scope list), with coverage states, CNPG issues from the Issues
  engine and the no-schedule audit finding withheld where coverage is missing.
- k8s-ui: buildCNPGFleet derives per-cluster facts (instances, replication,
  protection as separate schedule/destination/last-backup/WAL/recovery-window/
  restore-validation facts, declarations) without inventing values: replication
  lag is unknown without runtime data, restore validation is never green, and
  unreadable kinds read "No access" rather than none.
- ResourcesSidebar gains optional category workspaces (destinations above a
  collapsible Resource kinds block, grouped by API group).
- WorkloadView gains an optional composed summary: Overview shows it and the
  kind's renderer moves to a Spec & status tab.
- /cnpg: Overview fleet with Needs attention / All, problem-category chips,
  search, namespace chip and a URL-backed drawer (?drawer=kind:group:ns:name).
…ens and composed summaries

Screens (/cnpg/protection, /declarations, /pooling, /operator):
- Protection keeps schedule, destination, last successful backup (with its
  source), WAL archiving, recovery window and restore validation as separate
  facts; ObjectStore upload health is labelled inferred with its evidence.
- Declarations groups Databases, Publications, Subscriptions and managed roles
  by cluster, separating applied, not applied and pending, with controller
  errors and GitOps source.
- Pooling lists Poolers with readiness; connection pressure reads "Not
  measured" until PgBouncer metrics are read.
- Operator shows operator/plugin workloads and versions, image catalogs and
  their visible users, and operator configuration (Secret contents never read).

Composed Overview summaries (Spec & status keeps the existing renderers) for
Backup, ScheduledBackup, ObjectStore, Database, Publication, Subscription,
Pooler and image catalogs; drawer trail back-link on workspace screens.

GET /api/cnpg/operator discovers operator and plugin Deployments and their
config references, gated per namespace on list deployments/services and get
configmaps; it does not follow the namespace view filter.

Workspace hardening from review:
- issues are read flat, so Pod evidence only reaches callers with Pod access;
- instance Pods must be controller-owned by the visible Cluster's UID;
- partial coverage names denied namespaces only when the caller supplied the
  candidates, and always reports the allowed ones;
- unobserved managed roles are pending, unreadable schedules or Poolers are
  unknown rather than absent, restore evidence requires a ready restored
  cluster resolved by exact reference, and an unreadable Cluster list is not
  reported as "no clusters".
…ctivity

- Every CNPG kind now has a CNPG-framed full detail at /cnpg/<plural>/<ns|_>/<name>,
  reached from row Open, drawer expand and a redirect from /workload/...: the
  workspace sidebar stays highlighted with the object nested under its home, a
  return link names the page the drilldown came from (history state, kept
  across tab changes), and a crumb names the object's place.
- Detail URLs pin the kube context (ctx=, added on first view). After a context
  switch the page says the object is not in the new context and offers
  Switch back / Go to Overview instead of loading a same-named object.
- A Cluster adds Protection (its recovery evidence), Activity (replacing
  Timeline) and merged instance Logs; WorkloadView gains additive extraTabs and
  the logs viewer an initialPods selection.
- GET /api/cnpg/clusters/{ns}/{name}/logs (+/stream): logs from controller-owned
  instance Pods, gated on get clusters, list pods and get pods/log, with CNPG's
  JSON lines parsed into level/logger/message.
- GET /api/cnpg/clusters/{ns}/{name}/activity: timeline events for the Cluster,
  its instance Pods and CNPG objects attributed to it, per-kind gated. The
  timeline now records the owning cluster (cnpg.io/cluster label or
  spec.cluster.name) at ingestion so deleted Backups and declarations stay
  attributed; earlier history is reported as incomplete.
- The drawer trail back link moves to the drawer shell so it survives hops to
  Pods and Secrets.

Review fixes on the workspace screens and summaries: empty states follow each
kind's coverage, Declarations separates not applied from pending, GitOps
provenance reads "not recorded" instead of "applied directly", ObjectStore no
longer asserts recoverability, a Backup's destination inferred from the
Cluster's current config is labelled, schedule runs require the owner UID,
partial catalog coverage keeps the known users, and CNPG's six-field cron is
shown verbatim.

Docs: docs/cnpg.md (destinations, navigation, certainty table, access).
… redirects

- Activity rows from Kubernetes Events now also require list events in the
  namespace; they carry their subject's kind, so the subject check alone let
  Event messages through.
- The /workload redirect to a CNPG detail keeps ctx, pod and every other
  parameter, and maps a Cluster's timeline tab to Activity.
- The drawer trail back link keeps the page's return state.
- Activity describes its earliest linked child event as a recorded boundary,
  not a completeness guarantee.
@nadaverell
nadaverell requested a review from hisco as a code owner September 28, 2026 23:54
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add a read-only CloudNativePG workspace and composed object details

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add fleet, protection, declarations, pooling, and operator views for task-oriented CloudNativePG
 triage.
• Compose CNPG details from sourced evidence, distinguishing missing data from healthy or empty
 states.
• Authorize evidence per kind, add cluster activity and logs, and guard details across context
 switches.
Diagram

graph TD
  K["Kubernetes cache"] --> A["CNPG endpoints"] --> M["Fleet derivation"] --> S["Workspace screens"] --> D["CNPG detail"] --> V["Shared detail view"]
  I["Issues engine"] --> A
  T["Timeline store"] --> A
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Compose existing resource-list APIs in the browser
  • ➕ Avoids a dedicated aggregate endpoint.
  • ➖ Existing lists cannot reliably distinguish denied access from an empty kind.
  • ➖ Pod and issue evidence would still need independent authorization.
2. Derive all workspace facts on the server
  • ➕ Centralizes evidence interpretation.
  • ➖ Couples display-specific facts to Go handlers.
  • ➖ Reduces reuse of the additive shared UI model.

Recommendation: Keep the per-kind-authorized aggregate endpoint and shared pure derivations. This preserves the distinction between unreadable and absent evidence without duplicating the Issues engine. Review partial coverage and drawer/context transitions closely.

Files changed (60) +9741 / -73

Enhancement (45) +7079 / -72
cnpg_cluster_activity.goServe authorized CNPG cluster activity +238/-0

Serve authorized CNPG cluster activity

• Attributes retained Cluster, Pod, and child-object rows, including deleted children, while gating each kind and Kubernetes Events.

internal/server/cnpg_cluster_activity.go

cnpg_cluster_logs.goMerge owner-validated instance logs +465/-0

Merge owner-validated instance logs

• Adds bounded snapshots and SSE following with RBAC gates, Pod filtering, role labels, and CNPG JSON parsing.

internal/server/cnpg_cluster_logs.go

cnpg_operator.goDiscover operator, plugins, and configuration references +366/-0

Discover operator, plugins, and configuration references

• Reads authorized Deployments and Services; exposes ConfigMap data only with get permission and never reads Secrets.

internal/server/cnpg_operator.go

cnpg_workspace.goProvide per-kind-authorized CNPG workspace data +677/-0

Provide per-kind-authorized CNPG workspace data

• Lists CNPG kinds and owner-validated Pods with coverage, bounded Backup history, visibility-filtered issues, and guarded audit findings.

internal/server/cnpg_workspace.go

server.goRegister CNPG workspace and cluster endpoints +5/-0

Register CNPG workspace and cluster endpoints

• Adds workspace, operator, activity, log snapshot, and SSE stream routes.

internal/server/server.go

workload_logs.goAllow parsed fields on shared log entries +5/-1

Allow parsed fields on shared log entries

• Adds optional level, logger, and message fields and clarifies the pods/log permission error.

internal/server/workload_logs.go

CNPGBackupSummary.tsxCompose Backup and ScheduledBackup overviews +223/-0

Compose Backup and ScheduledBackup overviews

• Groups outcomes, timing, destinations, schedule relationships, and recent runs.

packages/k8s-ui/src/components/cnpg/CNPGBackupSummary.tsx

CNPGClusterSummary.tsxCompose cluster problems and sourced facts +222/-0

Compose cluster problems and sourced facts

• Displays triage evidence, instances, protection and declaration facts, relationships, and optional drawer actions.

packages/k8s-ui/src/components/cnpg/CNPGClusterSummary.tsx

CNPGDeclarativeSummary.tsxCompose declarative-resource details +264/-0

Compose declarative-resource details

• Separates declared state, reconciliation evidence, relationships, and GitOps provenance for Databases, Publications, and Subscriptions.

packages/k8s-ui/src/components/cnpg/CNPGDeclarativeSummary.tsx

CNPGImageCatalogSummary.tsxShow catalog images and visible consumers +80/-0

Show catalog images and visible consumers

• Lists PostgreSQL image versions and linked Clusters, accounting for catalog scope and incomplete visibility.

packages/k8s-ui/src/components/cnpg/CNPGImageCatalogSummary.tsx

CNPGObjectStoreSummary.tsxExplain ObjectStore recovery and inferred health +176/-0

Explain ObjectStore recovery and inferred health

• Shows per-cluster upload evidence, recovery windows, destination, and credential references without asserting direct ObjectStore health.

packages/k8s-ui/src/components/cnpg/CNPGObjectStoreSummary.tsx

CNPGPoolerSummary.tsxCompose Pooler status and routing overview +70/-0

Compose Pooler status and routing overview

• Shows reported instance counts, target Cluster, routing and Deployment links, and unmeasured connection pressure.

packages/k8s-ui/src/components/cnpg/CNPGPoolerSummary.tsx

CNPGSharedSummary.tsxShare CNPG summary evidence components +88/-0

Share CNPG summary evidence components

• Provides issue callouts, statuses, time formatting, and coverage-aware Cluster links.

packages/k8s-ui/src/components/cnpg/CNPGSharedSummary.tsx

index.tsExport CNPG workspace components +8/-0

Export CNPG workspace components

• Exposes fleet derivations, summary primitives, and object summaries.

packages/k8s-ui/src/components/cnpg/index.ts

primitives.tsxAdd sourced fact and problem primitives +134/-0

Add sourced fact and problem primitives

• Provides fact grids, tones, source tooltips, relationship links, and evidence callouts.

packages/k8s-ui/src/components/cnpg/primitives.tsx

relations.tsDerive evidence-backed CNPG relationships +417/-0

Derive evidence-backed CNPG relationships

• Resolves links among Backups, schedules, stores, declarations, Clusters, and catalogs while respecting scope and provenance.

packages/k8s-ui/src/components/cnpg/relations.ts

workspace.tsBuild coverage-aware CNPG fleet facts +683/-0

Build coverage-aware CNPG fleet facts

• Derives sourced protection, replication, declaration, instance, and problem facts without treating missing values as healthy.

packages/k8s-ui/src/components/cnpg/workspace.ts

WorkloadLogsViewer.tsxSupport initial Pod selection in logs +11/-3

Support initial Pod selection in logs

• Adds optional initialPods selection for instance-focused Cluster log links.

packages/k8s-ui/src/components/logs/WorkloadLogsViewer.tsx

ResourcesSidebar.tsxAdd optional task destinations within resource categories +183/-11

Add optional task destinations within resource categories

• Places workspace links above collapsible, API-grouped kinds without changing consumers that omit the prop.

packages/k8s-ui/src/components/resources/ResourcesSidebar.tsx

ResourcesView.tsxPass category workspaces into the sidebar +5/-1

Pass category workspaces into the sidebar

• Adds an optional ResourcesView prop and forwards it to ResourcesSidebar.

packages/k8s-ui/src/components/resources/ResourcesView.tsx

index.tsExport workspace sidebar types +1/-1

Export workspace sidebar types

• Makes destination and category types available to package consumers.

packages/k8s-ui/src/components/resources/index.ts

WorkloadView.tsxSupport composed summaries and extra detail tabs +90/-5

Support composed summaries and extra detail tabs

• Adds optional summary rendering, a Spec & status tab, and replaceable or insertable expanded tabs.

packages/k8s-ui/src/components/workload/WorkloadView.tsx

index.tsExport extra-tab contract +1/-0

Export extra-tab contract

• Exposes WorkloadExtraTab for domain-specific detail tabs.

packages/k8s-ui/src/components/workload/index.ts

index.tsPublish the shared CNPG module +3/-0

Publish the shared CNPG module

• Exports the workspace model and composed summaries at the package root.

packages/k8s-ui/src/index.ts

converter.goRetain CNPG Cluster identity on timeline rows +33/-3

Retain CNPG Cluster identity on timeline rows

• Extracts cnpg.io/cluster from CNPG labels or spec.cluster.name and from Pods, preserving attribution after deletion.

pkg/timeline/converter.go

App.tsxIntegrate CNPG routing and context-safe expansion +44/-5

Integrate CNPG routing and context-safe expansion

• Mounts the workspace under Resources, invalidates its query on CNPG changes, routes drawer expansion, and preserves pinned context.

web/src/App.tsx

cnpg.tsAdd typed CNPG workspace queries +95/-0

Add typed CNPG workspace queries

• Defines cached clients for workspace, operator, and Cluster activity responses.

web/src/api/cnpg.ts

CNPGClusterActivity.tsxDisplay attributed Cluster activity +49/-0

Display attributed Cluster activity

• Shows selectable time ranges and explains attribution gaps and truncated history.

web/src/components/cnpg/CNPGClusterActivity.tsx

CNPGClusterLogs.tsxConnect Cluster detail to merged instance logs +59/-0

Connect Cluster detail to merged instance logs

• Adapts the shared viewer to CNPG snapshots and SSE, with optional Pod preselection.

web/src/components/cnpg/CNPGClusterLogs.tsx

CNPGDeclarations.tsxTriage declared versus reconciled resources +311/-0

Triage declared versus reconciled resources

• Groups declarations and managed roles by Cluster, exposing pending states, controller errors, and GitOps sources.

web/src/components/cnpg/CNPGDeclarations.tsx

CNPGDetailPage.tsxFrame CNPG details within the workspace +228/-0

Frame CNPG details within the workspace

• Provides context-guarded details, home breadcrumbs and return state, plus Cluster Protection and Activity tabs.

web/src/components/cnpg/CNPGDetailPage.tsx

CNPGDrawerTrail.tsxNavigate backward through inspected objects +37/-0

Navigate backward through inspected objects

• Displays a previous-object action using the URL-backed CNPG drawer trail.

web/src/components/cnpg/CNPGDrawerTrail.tsx

CNPGOperator.tsxShow operator readiness and catalog usage +230/-0

Show operator readiness and catalog usage

• Displays workloads, configuration references, catalogs, visible users, and coverage gaps.

web/src/components/cnpg/CNPGOperator.tsx

CNPGOverview.tsxAdd searchable CNPG fleet triage +307/-0

Add searchable CNPG fleet triage

• Lists Clusters with instance and operational evidence, attention and category filters, and explicit drilldowns.

web/src/components/cnpg/CNPGOverview.tsx

CNPGPooling.tsxList Poolers and their target Clusters +116/-0

List Poolers and their target Clusters

• Shows routing, status, and instance counts while marking connection pressure unmeasured.

web/src/components/cnpg/CNPGPooling.tsx

CNPGProtection.tsxPresent recovery evidence by task +311/-0

Present recovery evidence by task

• Separates per-Cluster protection facts and lists recent failed Backups, destinations, and schedules.

web/src/components/cnpg/CNPGProtection.tsx

CNPGSummaryHost.tsxSelect composed summaries for CNPG kinds +143/-0

Select composed summaries for CNPG kinds

• Connects shared summaries to scoped workspace data and excludes same-named foreign kinds.

web/src/components/cnpg/CNPGSummaryHost.tsx

CNPGView.tsxCoordinate screens, sidebar, and URL-backed drawer +156/-0

Coordinate screens, sidebar, and URL-backed drawer

• Hosts workspace destinations and details with shared fleet data and two-way drawer synchronization.

web/src/components/cnpg/CNPGView.tsx

paths.tsBuild Cluster paths and return labels +13/-0

Build Cluster paths and return labels

• Centralizes Cluster detail URLs and labels for history-based drilldown returns.

web/src/components/cnpg/paths.ts

routes.tsDefine CNPG destinations and detail URLs +112/-0

Define CNPG destinations and detail URLs

• Maps kinds to homes and provides group-aware route parsing, context paths, and drawer-trail serialization.

web/src/components/cnpg/routes.ts

shared.tsxShare workspace screen states and controls +290/-0

Share workspace screen states and controls

• Provides loading and not-installed gates, coverage notices, filters, and reusable layout components.

web/src/components/cnpg/shared.tsx

useCNPGSidebarWorkspace.tsPopulate workspace destinations and counts +88/-0

Populate workspace destinations and counts

• Derives sidebar links and affected-Cluster counts from the same namespace-scoped fleet query as the screens.

web/src/components/cnpg/useCNPGSidebarWorkspace.ts

ResourceDetailDrawer.tsxShow CNPG navigation trail in the existing drawer +6/-0

Show CNPG navigation trail in the existing drawer

• Adds a previous-object control above drawer content on CNPG routes.

web/src/components/resources/ResourceDetailDrawer.tsx

ResourcesView.tsxExpose CNPG workspace from Resources +6/-38

Expose CNPG workspace from Resources

• Passes sidebar destinations to the shared view and moves resource-count querying into a reusable hook.

web/src/components/resources/ResourcesView.tsx

WorkloadView.tsxRoute CNPG objects to composed details +30/-4

Route CNPG objects to composed details

• Redirects generic CNPG links, supplies summaries and merged Cluster logs, and preserves return state across tabs.

web/src/components/workload/WorkloadView.tsx

Refactor (1) +49 / -0
useResourceCounts.tsShare sidebar resource-count querying +49/-0

Share sidebar resource-count querying

• Extracts the existing namespace-scoped count query for Resources and standalone CNPG sidebars.

web/src/hooks/useResourceCounts.ts

Tests (9) +2371 / -0
cnpg_cluster_history_test.goTest cluster logs and activity handlers +449/-0

Test cluster logs and activity handlers

• Exercises instance ownership, merged logs, historical attribution, and activity authorization.

internal/server/cnpg_cluster_history_test.go

cnpg_operator_test.goTest operator discovery and configuration gates +368/-0

Test operator discovery and configuration gates

• Covers identification, readiness, scope, and guarded configuration reads.

internal/server/cnpg_operator_test.go

cnpg_workspace_test.goTest workspace coverage and evidence isolation +584/-0

Test workspace coverage and evidence isolation

• Checks per-kind and namespace access, cluster-scoped catalogs, colliding API groups, Pod ownership, and evidence withholding.

internal/server/cnpg_workspace_test.go

CNPGObjectSummary.test.tsxTest rendered CNPG object overviews +231/-0

Test rendered CNPG object overviews

• Checks summary claims about backups, destinations, declarations, Poolers, catalogs, and ObjectStores.

packages/k8s-ui/src/components/cnpg/CNPGObjectSummary.test.tsx

relations.test.tsTest CNPG relationship and certainty helpers +304/-0

Test CNPG relationship and certainty helpers

• Validates group-aware links, schedule ownership, destinations, catalog users, reconciliation, and inferred health.

packages/k8s-ui/src/components/cnpg/relations.test.ts

workspace.test.tsTest fleet fact derivation +233/-0

Test fleet fact derivation

• Covers protection, replication uncertainty, declarations, access gaps, and issue-driven attention counts.

packages/k8s-ui/src/components/cnpg/workspace.test.ts

ResourcesSidebar.test.tsxTest category workspace sidebar +76/-0

Test category workspace sidebar

• Checks destinations, active-object nesting, collapsed kinds, zero-resource visibility, and API-group labels.

packages/k8s-ui/src/components/resources/ResourcesSidebar.test.tsx

converter_cnpg_test.goTest retained CNPG timeline attribution +66/-0

Test retained CNPG timeline attribution

• Checks supported groups, Pod forms, unrelated-kind exclusion, and attribution surviving tombstones.

pkg/timeline/converter_cnpg_test.go

routes.test.tsTest routes and drawer identity +60/-0

Test routes and drawer identity

• Covers destinations, detail kinds, context URLs, malformed trails, and API-group collisions.

web/src/components/cnpg/routes.test.ts

Documentation (5) +242 / -1
CLAUDE.mdDocument CNPG workspace contracts +5/-0

Document CNPG workspace contracts

• Links the certainty and navigation documentation and records the new endpoint access and attribution rules.

CLAUDE.md

README.mdList all supported CNPG kinds and workspace +1/-1

List all supported CNPG kinds and workspace

• Corrects the integration inventory and links to the new workspace.

README.md

cnpg.mdDefine workspace behavior and evidence certainty +66/-0

Define workspace behavior and evidence certainty

• Documents destinations, navigation, per-fact sources and unknown states, access rules, and deferred capabilities.

docs/cnpg.md

integrations.mdLink integration guidance to the workspace +2/-0

Link integration guidance to the workspace

• Introduces the workspace as the task-oriented complement to per-kind CloudNativePG views.

docs/integrations.md

CNPG_WORKSPACE.mdRecord the phased workspace design +168/-0

Record the phased workspace design

• Captures architecture, product decisions, risks, testing, deferred features, and design revisions.

docs/plans/CNPG_WORKSPACE.md

Comment thread packages/k8s-ui/src/components/cnpg/CNPGObjectSummary.test.tsx Fixed

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread packages/k8s-ui/src/components/cnpg/workspace.ts
Comment thread packages/k8s-ui/src/components/cnpg/workspace.ts
Comment thread internal/server/cnpg_cluster_activity.go
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (1) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Activity query failures lack server logs ✓ Resolved
Description
handleCNPGClusterActivity returns HTTP 500 for either failed timeline query without logging the
triggering err. When the initial history scan or the oldest-record lookup fails, the handler sends
err.Error() to the client but records no diagnostic entry on either path.
Code

internal/server/cnpg_cluster_activity.go[R146-147]

+	if err != nil {
+		s.writeError(w, http.StatusInternalServerError, err.Error())
Evidence
The new activity handler has two timeline-query error branches that write HTTP 500 without a
preceding log call; the cited rule requires a standardized log before each 500 response.

Rule 3036628: Log 500 errors with standardized module/action format before writing the response
internal/server/cnpg_cluster_activity.go[137-148]
internal/server/cnpg_cluster_activity.go[221-231]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Both timeline queries in the cluster activity handler can return HTTP 500 without a preceding diagnostic log.
## Fix Focus Areas
- internal/server/cnpg_cluster_activity.go[146-148]
- internal/server/cnpg_cluster_activity.go[229-231]
## Recommended Fix
Before each 500 response, log the triggering error with a `[cnpg] Failed to ... %s/%s: %v` message using the cluster namespace and name.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Stream setup failures lack server logs ✓ Resolved
Description
handleCNPGClusterLogsStream returns HTTP 500 when the response writer does not support flushing,
without first logging the failure. This path occurs after the cluster and its instance Pods are
selected, so the response alone does not leave a server-side diagnostic tied to their namespace and
name.
Code

internal/server/cnpg_cluster_logs.go[R369-372]

+	flusher, ok := w.(http.Flusher)
+	if !ok {
+		s.writeError(w, http.StatusInternalServerError, "streaming not supported")
+		return
Evidence
The added flusher check writes HTTP 500 directly when streaming is unsupported, with no preceding
log call as required by the cited rule.

Rule 3036628: Log 500 errors with standardized module/action format before writing the response
internal/server/cnpg_cluster_logs.go[369-372]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The cluster log stream handler sends a 500 when its response writer cannot flush, without recording a diagnostic log.
## Fix Focus Areas
- internal/server/cnpg_cluster_logs.go[369-372]
## Recommended Fix
Log the unsupported-flusher failure before writing the 500, using a `[cnpg] Failed to ... %s/%s: %v` message with the cluster namespace and name.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Recently failed backups disappear ✓ Resolved
Description
CNPGProtection filters the last-seven-days list using backupTime(), which prefers startedAt
and never checks stoppedAt. A backup that started more than seven days ago but failed recently is
retained by the backend's completion-time window yet omitted from the failed-backups table.
Code

web/src/components/cnpg/CNPGProtection.tsx[R43-45]

+function backupTime(b: any): string | undefined {
+  return b?.status?.startedAt || b?.metadata?.creationTimestamp
+}
Evidence
The frontend applies its seven-day cutoff to a start-time helper, whereas the backend retains
settled backups using stop time first.

web/src/components/cnpg/CNPGProtection.tsx[43-45]
web/src/components/cnpg/CNPGProtection.tsx[98-110]
internal/server/cnpg_workspace.go[366-419]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Recently failed, long-running backups are excluded because the frontend filters by start time while the backend retains them by stop time.
## Fix Focus Areas
- web/src/components/cnpg/CNPGProtection.tsx[43-45]
- web/src/components/cnpg/CNPGProtection.tsx[98-110]
- internal/server/cnpg_workspace.go[366-375]
## Recommended Fix
Use `stoppedAt`, falling back to `startedAt` and creation time, for the failure cutoff and ordering. Keep the table's explicitly labelled Started column based on `startedAt`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (7)
4. Interrupted streams replay old log lines ✓ Resolved
Description
handleCNPGClusterLogsStream removes a finished log reader from active, then its five-second
discovery tick starts that reader again with the original tail and time parameters. If a Pod log
stream reaches EOF or has a transient read error while the Pod remains present, its recent lines are
appended again on every restart.
Code

internal/server/cnpg_cluster_logs.go[R400-403]

+				go func(podName, containerName, key string) {
+					defer active.Delete(key)
+					streamPodLogs(streamCtx, client, namespace, podName, containerName, query.tailLines, query.sinceSeconds, logCh)
+				}(pod.Name, c, key)
Evidence
The reader deletes its active entry on exit; the periodic start(currentPods) call starts it again
with unchanged query parameters, and the client appends each received event.

internal/server/cnpg_cluster_logs.go[390-407]
internal/server/cnpg_cluster_logs.go[426-463]
internal/server/workload_logs.go[632-679]
packages/k8s-ui/src/components/logs/WorkloadLogsViewer.tsx[204-218]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A terminated per-Pod stream is restarted with its initial tail, repeatedly duplicating entries in the live viewer.
## Fix Focus Areas
- internal/server/cnpg_cluster_logs.go[390-407]
- internal/server/cnpg_cluster_logs.go[426-463]
- internal/server/workload_logs.go[632-679]
## Recommended Fix
Track each reader's last delivered timestamp and resume after it, deduplicating any overlap, or avoid automatically restarting finished readers with the original tail.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Live logs lose instance role labels ✓ Resolved
Description
WorkloadLogsViewer's live onLog handler discards the sourceLabel that the new cluster stream
puts on each entry. Snapshot lines receive their primary or replica label, but lines arriving after
streaming starts fall back to a Pod-name fragment.
Code

web/src/components/cnpg/CNPGClusterLogs.tsx[R45-48]

+
+  return (
+    <div className="h-full">
+      <WorkloadLogsViewer
Evidence
The server sends a role as SourceLabel, but the live handler constructs a new entry without it;
the log renderer uses that field for its displayed source.

internal/server/cnpg_cluster_logs.go[419-425]
packages/k8s-ui/src/components/logs/WorkloadLogsViewer.tsx[141-152]
packages/k8s-ui/src/components/logs/WorkloadLogsViewer.tsx[204-218]
packages/k8s-ui/src/components/logs/LogCore.tsx[1187-1189]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new CNPG stream supplies primary and replica labels, but the shared viewer drops them from live entries.
## Fix Focus Areas
- web/src/components/cnpg/CNPGClusterLogs.tsx[45-55]
- packages/k8s-ui/src/components/logs/WorkloadLogsViewer.tsx[204-218]
- internal/server/cnpg_cluster_logs.go[419-425]
## Recommended Fix
Pass `data.sourceLabel` into the viewer's buffered live entry and cover both snapshot and streaming labels in a test.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Database errors can show as info logs ✓ Resolved
Description
annotateCNPGLogEntry extracts PostgreSQL's record.error_severity, but the new viewer feeds only
raw content into a buffer that independently detects severity. When a wrapped record has a
top-level info level and a nested error severity, the displayed log level follows the top-level
value instead of the extracted database severity.
Code

internal/server/cnpg_cluster_logs.go[R218-225]

+		}
+		if rec.Record.Message != "" {
+			message = rec.Record.Message
+		}
+	}
+	if errText := cnpgLogErrorText(rec.Error); errText != "" {
+		if message == "" {
+			message = errText
Evidence
The backend explicitly overrides level from the nested record, while both viewer paths omit that
parsed field and the buffer detects only top-level JSON severity fields.

internal/server/cnpg_cluster_logs.go[188-233]
packages/k8s-ui/src/components/logs/WorkloadLogsViewer.tsx[141-152]
packages/k8s-ui/src/components/logs/WorkloadLogsViewer.tsx[204-218]
packages/k8s-ui/src/components/logs/useLogBuffer.ts[30-55]
packages/k8s-ui/src/components/logs/useLogBuffer.ts[82-93]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The backend extracts nested PostgreSQL severity, but the viewer discards it and reclassifies the raw JSON.
## Fix Focus Areas
- internal/server/cnpg_cluster_logs.go[207-233]
- packages/k8s-ui/src/components/logs/WorkloadLogsViewer.tsx[141-152]
- packages/k8s-ui/src/components/logs/WorkloadLogsViewer.tsx[204-218]
- packages/k8s-ui/src/components/logs/useLogBuffer.ts[30-55]
## Recommended Fix
Carry the server's parsed severity through snapshot and streaming entries, and let the log buffer prefer that supplied severity to raw-content detection.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Unrelated plugins look like restorations ✓ Resolved
Description
restoreValidationFact matches an external recovery plugin by barmanObjectName and server name
without checking the plugin's identity. Another plugin carrying those parameter names can make a
source cluster display that recovery was declared or completed from its backups.
Code

packages/k8s-ui/src/components/cnpg/workspace.ts[R416-418]

+      const ext = (c.spec?.externalClusters ?? []).find((e: any) => e?.name === sourceName)
+      const params = ext?.plugin?.parameters
+      if (store && params?.barmanObjectName === store && (params?.serverName || sourceName) === server) return true
Evidence
The source backup plugin is identified by name, but the external recovery plugin is not; the
parameter-only match directly produces the restore fact.

packages/k8s-ui/src/components/cnpg/workspace.ts[405-440]
packages/k8s-ui/src/components/resources/resource-utils-cnpg.ts[440-453]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Restore evidence is attributed to a source using parameter matches without verifying that the recovery plugin is barman-cloud.
## Fix Focus Areas
- packages/k8s-ui/src/components/cnpg/workspace.ts[410-424]
- packages/k8s-ui/src/components/resources/resource-utils-cnpg.ts[440-453]
## Recommended Fix
Require the matching external cluster's plugin name to be the barman-cloud plugin before treating its parameters as evidence of recovery from this source.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Plugin rows can reuse the same key ✓ Resolved
Description
CNPGOperator keys component rows solely by namespace and deployment, while unmatched plugin
Services produce components with no deployment. Two such Services in one namespace yield identical
React keys, making their rows unstable when the table updates.
Code

web/src/components/cnpg/CNPGOperator.tsx[R118-120]

+              rows={op.components}
+              rowKey={(c) => `${c.namespace}/${c.deployment}`}
+              rowResource={(c) => (c.deployment ? { kind: 'deployments', group: 'apps', namespace: c.namespace, name: c.deployment } : null)}
Evidence
The server appends a separate fallback component for each unmatched Service without setting
Deployment; the table uses that empty field as its only per-namespace key component.

internal/server/cnpg_operator.go[115-133]
web/src/components/cnpg/CNPGOperator.tsx[118-120]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Multiple unmatched plugin Services in a namespace produce components with the same empty-deployment row key.
## Fix Focus Areas
- internal/server/cnpg_operator.go[115-133]
- web/src/components/cnpg/CNPGOperator.tsx[118-120]
## Recommended Fix
Include the originating Service name in fallback components and use it, together with namespace and role, for a stable unique table key.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. Backup destinations show healthy on thin evidence ✓ Resolved
Description
inferStoreHealth returns 'Accepting uploads' with a healthy tone when any single user cluster has
healthy WAL archiving. Users whose archiving is unknown are ignored, not counted against the
verdict. So when one of a store's visible clusters has no ContinuousArchiving condition, or only a
subset of clusters is visible, the Protection screen shows green while the store's own detail view
says 'No failures reported' (unknown).
Code

web/src/components/cnpg/CNPGProtection.tsx[R76-78]

+    return { text: 'Accepting uploads', tone: 'healthy', evidence: `Inferred from WAL archiving on ${archiving.map((u) => u.name).join(', ')}` }
+  }
+  return { text: 'Unknown', tone: 'unknown', evidence: 'Its clusters report no archiving result yet' }
Evidence
On the Protection screen, the check that returns a healthy result only needs one user cluster to
report healthy archiving. walFact gives the 'unknown' tone to clusters with no ContinuousArchiving
condition, and those clusters get past both the failing check and the healthy check. The ObjectStore
detail in relations.ts requires every user to be healthy and otherwise returns unknown, so the two
views disagree.

web/src/components/cnpg/CNPGProtection.tsx[60-80]
packages/k8s-ui/src/components/cnpg/relations.ts[311-315]
packages/k8s-ui/src/components/cnpg/workspace.ts[389-394]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`inferStoreHealth` marks an ObjectStore 'Accepting uploads' (healthy) when at least one user cluster has healthy WAL archiving, even if other users report nothing. This breaks the rule that unknown is never shown as green, and it contradicts the ObjectStore detail logic in relations.ts.
## Fix Focus Areas
- web/src/components/cnpg/CNPGProtection.tsx[60-80]
- packages/k8s-ui/src/components/cnpg/relations.ts[294-315]
## Recommended Fix
Return the healthy verdict only when `users.every(u => u.protection.walArchiving.tone === 'healthy')`. Otherwise return an unknown tone such as 'No failures reported'. Better, reuse the relations.ts helper so the Protection screen and the ObjectStore detail share one inference.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


10. Staging loses plugin backup destinations 🔗 Cross-repo conflict ≡ Correctness
Description
cnpgWorkspaceKinds adds Barman ObjectStore resources, but the vendored Radar chart in the
deployment repo grants CloudNativePG access only to postgresql.cnpg.io. When the Barman plugin is
installed in staging, its barmancloud.cnpg.io ObjectStores cannot be read, so the workspace cannot
show their backup destinations.
Code

internal/server/cnpg_workspace.go[67]

+	{key: "objectStores", group: cnpgBarmanGroup, kind: "ObjectStore", resource: "objectstores"},
Evidence
The PR adds barmancloud.cnpg.io ObjectStores to the workspace and checks list permission before
reading each kind. The deployment repo enables its CloudNativePG RBAC option, but the corresponding
vendored rule grants only postgresql.cnpg.io; unlike Radar's chart, it omits the Barman group.

radar -> deployment
internal/server/cnpg_workspace.go[57-68]
internal/server/cnpg_workspace.go[293-310]
deploy/helm/radar/templates/clusterrole.yaml[271-277]
External repo: skyhook-dev/deployment, argocd/addons/radar-staging/radar-staging/skh-nonprod/charts/radar/values.yaml [125-135]
External repo: skyhook-dev/deployment, argocd/addons/radar-staging/radar-staging/skh-nonprod/charts/radar/templates/clusterrole.yaml [232-236]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The CNPG workspace reads Barman ObjectStores, but the deployment repo's vendored staging chart does not grant access to their API group.
## Fix Focus Areas
- internal/server/cnpg_workspace.go[57-68]
- /cross_repos/deployment/argocd/addons/radar-staging/radar-staging/skh-nonprod/charts/radar/templates/clusterrole.yaml[232-236]
## Recommended Fix
Update the deployment repo's vendored staging ClusterRole to grant read access to `barmancloud.cnpg.io` when CloudNativePG access is enabled, then deploy the chart alongside the workspace feature.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can copy the agent prompt from any finding and feed it to your IDE agent

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread internal/server/cnpg_cluster_activity.go
Comment thread internal/server/cnpg_cluster_logs.go
Comment thread web/src/components/cnpg/CNPGProtection.tsx
Comment thread internal/server/cnpg_cluster_logs.go Outdated
Comment thread web/src/components/cnpg/CNPGClusterLogs.tsx
Comment thread internal/server/cnpg_cluster_logs.go
Comment thread packages/k8s-ui/src/components/cnpg/workspace.ts
Comment thread web/src/components/cnpg/CNPGOperator.tsx
Comment thread web/src/components/cnpg/CNPGProtection.tsx Outdated
Comment thread internal/server/cnpg_workspace.go
…severity

- Replication and ObjectStore-sourced facts read "No access" when Pods or
  ObjectStores are unreadable, instead of asserting absence.
- Restore evidence only counts barman-cloud plugin recovery sources.
- Inferred ObjectStore health is "Accepting uploads" only when every user
  cluster reports archiving; the failed-backup window uses completion time.
- Log level detection reads CloudNativePG's nested PostgreSQL severity, and
  live stream lines keep their instance role label.
- A restarted instance log stream resumes from the last delivered line instead
  of replaying its tail; activity Pod rows must match the live Cluster's UID;
  activity and stream failures are logged.
- Workspace components use the shared Tooltip rather than native titles.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread packages/k8s-ui/src/components/cnpg/workspace.ts Outdated
Conflicts:
- CLAUDE.md: main condensed the endpoint list; the CloudNativePG
  endpoints move to docs/cnpg.md#api behind a one-line pointer.
- useLogBuffer.ts: main moved level detection to utils/log-level.ts;
  the CloudNativePG record.error_severity rule moves with it into
  selectLevelField.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread packages/k8s-ui/src/components/cnpg/workspace.ts
CloudNativePG's record.error_severity is one of PostgreSQL's severity
names; another logger's numeric or custom record field no longer
overrides the line's own level.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread packages/k8s-ui/src/utils/log-level.ts
…nreadable Backups

- PostgreSQL writes every DEBUGn level as DEBUG in error_severity.
- Restore validation says the Backup a recovery names couldn't be read,
  instead of None recorded, when Backups are denied in the namespace.
Recovery replays archived WAL past the latest base backup, and no
status reports the newest recoverable point, so the window shows its
earliest point and reaches the newest archived WAL. It reads not
advancing only while WAL archiving fails; a failed base backup no
longer implies it.
Recovery replays archived WAL past the last base backup, so a failed
backup makes recovery slower, not shorter; only archiving stops it.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 47f1b1b. Configure here.

Comment thread packages/k8s-ui/src/components/resources/renderers/CNPGObjectStoreRenderer.tsx Outdated
The failing-backups banner names servers whose cluster also stopped
archiving and drops the claim that recovery reaches the newest WAL, and
the row keeps its archiving-stopped note while backups fail.
With failures and no success the store holds nothing to restore from,
and retention isn't shown to move the earliest point.
The plugin keeps a successful backup when it fails to update the
ObjectStore status, so an absent success time leaves recoverability
unestablished rather than proving there is nothing to restore.
Status can miss a success whose update failed, so a failure is stated
as recorded after the last recorded success, and an entry without
timestamps reads as a recovery point not reported.
It is internal planning; docs/cnpg.md stops pointing at it.
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