Repository navigation
Require evidence before reporting unused ConfigMaps and Secrets - #1741
Conversation
PR Summary by QodoReport incomplete audit coverage under partial Kubernetes access
AI Description
Diagram
High-Level Assessment
Files changed (44)
|
Code Review by Qodo
1.
|
28ec884 to
f989e7b
Compare
f989e7b to
18c07b4
Compare
18c07b4 to
e56fe2b
Compare
## Summary Add EmberStack Reflector support to Secret and ConfigMap details and resource topology. Operators can follow a configuration's source and visible mirrors, inspect reflection settings and recorded copy evidence, and spot local configuration mistakes without treating restricted visibility as a missing or unused object. Follow-up to #1710. The companion audit PR #1741 uses the identical shared dependency parser; either PR can merge first. ## Resource details A Reflector section explains source and mirror roles, automatic versus manual mirrors, reflection permission, and configured namespace rules. Sources and visible mirrors link to the existing resource drawers. Name patterns and label selectors are shown as alternatives within each rule; Radar does not evaluate controller regexes or predict a destination set. Large visible-mirror lists initially show ten entries with an expansion control. Mirrors show the recorded source version and copy time. When an authorized source is present in the topology snapshot, the section compares its observed resource version with the mirror's recorded version. Cached versions can lag reconciliation. The result is explicitly metadata evidence: metadata-only source edits change versions, while local mirror edits may preserve the recorded version. Neither equality nor mismatch is a content comparison or a synchronization-health verdict. Local warnings cover malformed/self source declarations, invalid booleans, automatic creation without reflection permission, disabled sources with visible mirrors, and mirror chains whose updates are not propagated as ordinary source updates. Mirror details and Secret edit confirmation explain that local edits can persist until a source change overwrites them. Editing permissions and controls retain their existing behavior. The README supported-resources table and integration documentation describe these surfaces and their limits. ## Relationships and access A shared metadata-only parser resolves explicit `reflects` annotations between observed same-kind core resources, including differently named mirrors. Resource topology adds a source-to-mirror **Reflects to** configuration edge. It implies no ownership or cascading deletion. Traffic topology is unchanged; Secret nodes remain hidden by default. The relationship response adds an optional `reflection` object containing the observed source, its resource version, and visible mirrors. Existing configuration/consumer arrays remain available to API consumers; the drawer avoids duplicating reflection links in its generic Related Resources section. Existing shared UI consumers can render annotation details without injecting relationship data. Private relationship caches retain ConfigMaps/PVCs on large clusters and include Secrets. REST, MCP, and SSE remove unreadable namespaces, Secret endpoints, and cluster-scoped kinds before projection; callers receive cloned projections rather than mutations of the shared cache. SSE groups payloads by Secret grants. Source-version evidence comes from these already filtered nodes, with no additional object fetches or Secret contents. Secret list authorization also applies to existing name-only Traefik/Contour TLS Secret stubs. Readers without that permission no longer see those stubs or incident edges. ## Verification - Full application build, frontend type checks, root Go tests, and shared Go module tests passed. - Shared UI suite: 3,662 tests passed, one skipped. Web suite: 1,148 passed. The final focused reflection suite adds two further diagnostic cases (19 passed). - Parser/topology tests cover chains, cycles, differently named mirrors, missing endpoints, namespace/kind filters, Secret visibility, edge semantics, and filtering source-version evidence. Existing authorization tests cover shared-cache isolation. - Test-cluster UI/API checks covered source/mirror navigation, matching and differing version records, unavailable sources, disabled-reflection warnings, ordinary-resource controls, and Secret edit confirmation (cancelled without writing). Visual checks covered both themes at 1280 and 1920 widths; browser console had no errors. Live checks used manually seeded annotations, not a running Reflector controller. Earlier restricted-identity tests covered raw detail/neighborhood filtering; this expansion adds a regression test for withholding source-version metadata. ## Limits Unavailable sources are not called missing, and visible mirror counts are not expected totals. Controller availability, name conflicts, absent automatic mirrors, destination eligibility, and synchronization lag require evidence beyond this integration. Reflector's installed version/configuration determines its namespace-rule behavior. No new controller watches, permissions, or mutation actions are added. Repository documentation is included. A separate public docs-site navigation entry requires coordinated metadata in the radar-docs repository. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches shared topology caches, per-user relationship projection, and Secret visibility in SSE/API pathsâauthorization mistakes could leak metadata or hide legitimate edges. > > **Overview** > Adds **first-class EmberStack Reflector** support for core **ConfigMaps** and **Secrets** across UI, topology, REST/MCP context, and docsâwithout new CRDs or controller watches. > > **Operator surfaces:** ConfigMap/Secret drawers get **Reflector** summary banners and a collapsible section (source/mirror role, reflection settings, recorded `reflected-version` / `reflected-at`, local config warnings). Mirrors link to authorized sources; Secret edits warn that local changes may be overwritten. Generic Related Resources no longer duplicate reflection links. > > **Backend:** A shared **`configrefs` parser** resolves `reflects` annotations between observed same-kind objects. Topology gains **Reflects to** configuration edges; relationship APIs expose optional **`reflection`** (source, mirrors, resource versions). **`resourceContext.reflection`** on `get_resource`/REST AI context includes declared vs observed source, copy metadata, and up to 20 RBAC-filtered mirrors. Cross-namespace lookup uses **`ReflectionLookup`** over the resource cache. > > **Access & caching:** Relationship topology is **cloned and filtered per user** (namespaces + Secret list RBAC) so shared caches are not mutated. SSE/MCP/REST strip unauthorized Secret nodes; relationship caches **include Secrets** and retain ConfigMaps/PVCs on large clusters for reflection edges. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8630abf. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
â Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 85ea382. Configure here.
Radar can cache more resources than an authenticated viewer may read. Previously, audit could evaluate cached Secrets and cluster-scoped Crossplane resources without checking that viewerâs grants, exposing findings and evaluation counts about hidden subjects. This PR applies those checks before evaluation and carries incomplete-input warnings through the audit surfaces. ### Authorization and behavior Secret subjects require `list secrets` in their namespace. Namespace-local grants remain valid when cluster-wide listing is denied. Cluster-scoped Crossplane subjects require `list` on their exact API group/resource. Other namespaced subjects retain Radarâs existing namespace-visibility policy. HTTP audit (including raw and per-resource reads), Home, AI context, MCP audit, and MCP resource summaries use the same subject scope. The existing five-second HTTP memo includes authorization scope and typed/dynamic cache identity, preventing one callerâs results from satisfying another callerâs differently scoped request. Local and fully authorized scans retain their findings and evaluation counts. Restricted callers lose unauthorized subjects and their counts. Existing `missingInputs` metadata now reaches Home, Checks, MCP and AI/resource context, including when no findings remain. Partial Secret grants are disclosed; namespace-local grants covering the whole ready namespace inventory do not produce a false warning. Home and Checks show neutral empty states when nothing was evaluated, and qualify results when inputs are missing. Fully evaluated clean scans retain their positive state. These presentation changes also affect full-access users when their scan evaluates nothing. The shared UI gains optional coverage props; downstream hosts need to supply them to display missing-input warnings. Per-resource REST audit responses remain arrays. ### Scope and risk This is the subject-authorization prerequisite for #1741. It does not solve whether orphan checks have enough consumer evidence to assert that a resource is unused. That broader coverage work remains separate. No discovery, informer lifecycle, Kubernetes grant, or cluster-write behavior changes. Risk is medium and concentrated in audit reads: incorrect scoping could hide valid findings, disclose hidden subjects through counts, or reuse another callerâs results. Tests cover these boundaries and live requests verify identity isolation. Full-access backend results are preserved. Cold permission checks still fan out across candidate namespaces and watched resource types with bounded concurrency; the existing single-slot memo can recompute across differing grant profiles. Large-cluster cold latency is not benchmarked here. Existing permission-cache invalidation timing and other kindsâ namespace-based authorization policy remain unchanged. Coverage warnings remain scan-wide: namespaces later excluded by local settings can still trigger them, and a terminating namespace can briefly trigger one after its grants disappear. The absence of a warning does not certify that Radarâs own cache covers every namespace; that existing limitation belongs to the separate coverage work in #1741. ### Validation - Full Go QA, shared audit/resource-context package tests, TypeScript checks, and the full application build passed before the final warning-only correction. Affected audit tests and race checks were rerun for that correction. - Full frontend suites passed: 3,695 shared UI tests (one existing skip) and 1,152 web tests. - Race tests covered audit, audit-context, HTTP and MCP packages. Regression cases include denial, namespace-local grants, exact cluster grants, group collisions, scope/cache isolation, warning propagation and neutral empty states. - Live-tested against the existing Kubernetes 1.36.1 GitOps demo cluster using explicit contexts. Local and authenticated full-access responses had identical summaries and check counts. A real Secret-denied identity received no Secret findings, with missing-input warnings across HTTP, Home and MCP. Alternating identities and 12 concurrent requests retained their own results. - Live MCP resource context preserved a missing-input warning at zero findings. Browser checks covered partial findings, partial empty states, authorized zero-evaluation states, and light/dark presentation in seven screenshots. - Namespace-local positive grants and cluster-scoped Crossplane grant combinations have automated regression coverage, not live fixture coverage. The final all-namespace warning correction is regression-tested; the earlier live/browser run predates that correction. All live checks were read-only against the cluster. The current kubeconfig context was preserved, temporary Radar/proxy processes were stopped, and no grants or fixtures were changed.
f5687f3 to
c10300a
Compare
âĶespaces #1792 rewrote this description to say Radar only sees the namespaces it can read, so a live consumer may sit outside that view. That is no longer true. Since #1741 the check drops a subject unless every typed consumer kind and every known CRD reference kind is synced and covers its namespace, the read scope allows it, and reflections are complete. Incomplete evidence means no finding at all, plus a configmap-references or secret-references missing input. The namespace case the sentence described cannot produce a finding. What stays unknowable is a consumer of a kind Radar does not parse: a CRD outside the reference registry, or an app that reads the Secret by name in code. The description now hedges on that instead. Remediation is unchanged. Confirming usage and keeping a copy of a Secret before deleting are right either way.

Why
A ConfigMap or Secret can look unused because Radar cannot see its consumer. For example, a workload can consume a Reflector mirror in another namespace while the audit is displaying only the source namespace. Suggesting deletion from that incomplete view is misleading.
This PR makes the unused ConfigMap/Secret check distinguish observed use, supported evidence of no use, and unknown evidence. It builds on the subject authorization and incomplete-scan presentation merged in #1753, and reuses the Reflector metadata parser from #1740. It has no remaining prerequisite on the deferred discovery work in #1750.
Behavior
The namespace picker selects subjects. For Reflector-annotated subjects, the collector can inspect authorized consumers of remote mirrors. Use propagates through observed same-kind links, including chains and cycles. Unused automatic mirrors with visible sources are exempt, but their existence does not establish source use.
Typed workload, ServiceAccount and Ingress inventories use the existing per-kind readiness and namespace-scope APIs. The existing dynamic reference handlers share a registry with their ConfigMap/Secret and cross-namespace requirements, so discovery and collection agree about which installed integrations matter. An installed but unsynced consumer kind is unknown, not empty. Partial discovery of a relevant group prevents an absence claim; unrelated discovery failures do not.
Cert-manager Issuer credential references cover ACME, CA, Vault and Venafi fields. ClusterIssuer credentials use the namespace established by an observed controller's explicit flag, including a literal or downward-API environment value. Hidden controllers, unresolved values or configuration files without an explicit namespace flag do not produce a guessed namespace. Explicit flags take precedence over configuration files. An authorized, synced, empty ClusterIssuer inventory needs no controller namespace.
Scope and tradeoffs
The runtime change stays in the audit collector and orphan check. It adds no shared discovery lifecycle, informer failure latch, permission grants, new watches, scan-cache redesign or coverage response schema. Existing
missingInputscarriesconfigmap-referencesandsecret-referencesthrough REST, Home, AI context and MCP. Tests in the HTTP/MCP adapters keep their authorization assertions while explicitly supplying the core-only inventory they depend on.Full-access users can also lose unsupported orphan findings while required inventories are still syncing. Restricted users can see fewer orphan evaluations when an installed integration can reference Secrets across namespaces. This is deliberate: an omitted unknown evaluation is preferable to an unsupported deletion suggestion. Known use still counts. The check covers supported reference fields, not arbitrary controller behavior. Existing Istio gateway workload-namespace and Contour delegated TLS resolution limitations are outside this change.
Readiness here means initial synchronization, not continuous watch freshness. The existing scan memo can lag evidence changes by up to five seconds. The per-resource audit endpoint retains its findings-array shape and has no completeness metadata; the scan and AI resource context provide that distinction. Package callers that omit
ConfigReferenceEvidencecan establish observed use but cannot establish absence.Validation
make test,make tsc, andmake buildpassed.pkg/audit,pkg/configrefs, and the affected audit/server/MCP scenarios.configmap-referencesfor the unknown source. Configured REST, dashboard, MCP and the rendered Checks page preserved that warning.