Skip to content

Add Reflector support for ConfigMaps and Secrets - #1740

Merged
nadaverell merged 4 commits into
mainfrom
fix/reflector-relationships-independent
Sep 13, 2026
Merged

nadaverell merged 4 commits into
mainfrom
fix/reflector-relationships-independent

Conversation

@nadaverell

@nadaverell nadaverell commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

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.


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.

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

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Show authorized Reflector relationships in topology and resource details

âœĻ Enhancement 🧊 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

â€Ē Resolve observed Reflector annotations into source-to-mirror relationships for Secrets and
 ConfigMaps.
â€Ē Surface relationships without implying Kubernetes ownership or successful synchronization.
â€Ē Filter namespace and Secret endpoints per caller across REST, MCP, and SSE.
Diagram

graph TD
  K8S["Kubernetes Metadata"] --> Parser["Reflector Parser"] --> Builder["Topology Builder"] --> Cache[("Relationship Cache")] --> Filter["RBAC Projection"] --> REST["Resource Details"]
  Filter --> MCP["MCP Context"]
  Filter --> SSE["SSE Clients"]
Loading
High-Level Assessment

The shared metadata parser plus caller-specific cloned projections is the appropriate approach. Parsing annotations independently in each consumer would duplicate semantics, while modeling reflection as ownership or controller health would overstate what annotations prove; rebuilding the complete topology per caller would also be more expensive than filtering an immutable shared cache.

Files changed (13) +446 / -26

Enhancement (5) +218 / -23
resource_context.goInclude Secrets in MCP relationship topology +1/-0

Include Secrets in MCP relationship topology

â€Ē Enables Secret nodes when building MCP relationship-cache topology so reflected Secret relationships can appear in authorized resource contexts.

internal/mcp/resource_context.go

ai_handlers.goInclude Secrets in AI relationship topology +1/-0

Include Secrets in AI relationship topology

â€Ē Enables Secret nodes in relationship-focused topology builds used by AI resource contexts while retaining downstream access controls.

internal/server/ai_handlers.go

reflector.goParse and resolve Reflector metadata relationships +105/-0

Parse and resolve Reflector metadata relationships

â€Ē Introduces a metadata-only parser for Reflector source and mirror annotations on Secrets and ConfigMaps. It validates references, ignores self-links and absent endpoints, produces deterministic links, and propagates usage through chains and cycles.

pkg/configrefs/reflector.go

builder.goAdd reflection relationships to non-traffic topology +6/-23

Add reflection relationships to non-traffic topology

â€Ē Invokes Reflector relationship enrichment for non-traffic views. Reuses shared ConfigMap and Secret node constructors to preserve existing metadata and status shapes.

pkg/topology/builder.go

reflector.goBuild Reflector edges and Secret RBAC projections +105/-0

Build Reflector edges and Secret RBAC projections

â€Ē Adds observed Reflector endpoints and labeled source-to-mirror EdgeConfigures edges without duplicating existing nodes or edges. Also introduces Secret authorization tuple discovery, Secret stripping, and reusable core resource node constructors.

pkg/topology/reflector.go

Tests (3) +126 / -0
topology_relationship_auth_test.goVerify relationship filtering and cache immutability +35/-0

Verify relationship filtering and cache immutability

â€Ē Tests that unreadable ConfigMap and Secret endpoints and their incident edges are removed while the shared topology remains unchanged.

internal/server/topology_relationship_auth_test.go

reflector_test.goTest Reflector parsing and usage propagation +47/-0

Test Reflector parsing and usage propagation

â€Ē Covers differently named mirrors, kind isolation, deterministic ordering, malformed or missing references, transitive propagation, and cycle termination.

pkg/configrefs/reflector_test.go

reflector_test.goTest Reflector topology visibility and edge semantics +44/-0

Test Reflector topology visibility and edge semantics

â€Ē Verifies opt-in Secret visibility, namespace filtering, non-ownership edge semantics, and removal of incident edges when a Secret endpoint is unauthorized.

pkg/topology/reflector_test.go

Documentation (1) +9 / -0
integrations.mdDocument Reflector topology relationship semantics +9/-0

Document Reflector topology relationship semantics

â€Ē Documents support for EmberStack Reflector annotations, differently named mirrors, namespace filtering, and Secret visibility requirements. Clarifies that the edge represents a declaration rather than ownership or confirmed synchronization.

docs/integrations.md

Other (4) +93 / -3
tools.goApply Secret list authorization to MCP topology +18/-0

Apply Secret list authorization to MCP topology

â€Ē Collects Secret namespace authorization tuples and removes unauthorized Secret nodes and incident edges before applying existing cluster-scoped topology filtering.

internal/mcp/tools.go

server.goFilter cached relationships by caller permissions +26/-0

Filter cached relationships by caller permissions

â€Ē Adds Secret list authorization to cluster-scoped topology filtering. Resource detail handlers now clone and filter shared cached topology for authenticated users before projecting relationships.

internal/server/server.go

sse.goStream authorization-specific Secret topology projections +24/-3

Stream authorization-specific Secret topology projections

â€Ē Includes Secrets in relationship caches and filters them from initial and incremental SSE payloads according to list grants. Subscriber grouping keys now include Secret authorization tuples so differently authorized readers cannot share projections.

internal/server/sse.go

topology_relationship_auth.goCreate caller-safe relationship topology projections +25/-0

Create caller-safe relationship topology projections

â€Ē Adds a helper that clones shared topology, removes nodes from unreadable namespaces, and applies cluster-scoped and Secret RBAC filtering without mutating the cache.

internal/server/topology_relationship_auth.go

@qodo-code-review

qodo-code-review Bot commented Sep 13, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Reflector docs stop publishing ⊘ Outdated 🔗 Cross-repo conflict ☞ Reliability
Description
splitIntegrations() treats the new ## Reflector heading as an unknown integration because
radar-docs has no corresponding INTEGRATION_META entry. The radar-docs workflow then throws before
generating any integration pages, and its navigation also lacks the new Reflector page.
Code

docs/integrations.md[1479]

+## Reflector
Relevance

●●● Strong

Unknown integration headings can break synchronization, making metadata registration and navigation
necessary.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The PR introduces a level-two integration heading that the downstream parser processes, while
radar-docs has no metadata registration for it and explicitly fails synchronization when such
unknown headings are encountered.

docs/integrations.md[1479-1486]
External repo: skyhook-dev/radar-docs, scripts/sync-oss-docs.mjs [249-265]
External repo: skyhook-dev/radar-docs, scripts/sync-oss-docs.mjs [587-613]
External repo: skyhook-dev/radar-docs, scripts/sync-oss-docs.mjs [725-735]
External repo: skyhook-dev/radar-docs, .github/workflows/sync-oss-docs.yml [40-51]
External repo: skyhook-dev/radar-docs, docs.json [66-130]

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 Reflector integration heading is rejected by radar-docs synchronization because it has no matching integration metadata or navigation entry.

## Fix Focus Areas
- docs/integrations.md[1479-1486]
- /cross_repos/radar-docs/scripts/sync-oss-docs.mjs[249-265]
- /cross_repos/radar-docs/docs.json[66-130]

## Recommended Fix
Coordinate a radar-docs change that adds `Reflector` to `INTEGRATION_META` with its output slug and metadata, then add the generated Reflector page to the integrations navigation. Merge that change before or alongside this heading so the synchronization workflow recognizes and publishes it.

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



Remediation recommended

2. Reflector support misses topology matrix ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
docs/integrations.md adds a Reflector section using prose but provides no support table with a
Topology column. When readers use the standardized integration matrix to identify topology
support, the new ConfigMap and Secret reflection edges are not represented there.
Code

docs/integrations.md[R1479-1482]

+## Reflector
+
+Radar recognizes EmberStack Reflector annotations on core Secrets and ConfigMaps.
+When both objects are visible, the mirror's `reflects` annotation creates a
Relevance

●●● Strong

Explicit compliance rule requires topology integrations in the standardized Topology column.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 3036587 requires new topology integrations to be represented in the Topology column
of docs/integrations.md. The implementation creates a Reflector topology edge, while the added
documentation section describes it only in prose and contains no corresponding topology matrix.

Rule 3036587: Sync topology integration changes with docs/integrations.md Topology column
pkg/topology/reflector.go[58-62]
docs/integrations.md[1479-1486]

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 Reflector integration is described only in prose and lacks the required support matrix entry with a Topology column.

## Fix Focus Areas
- docs/integrations.md[1479-1486]

## Recommended Fix
Add a support table to the Reflector section with a `Topology` column, listing the supported core ConfigMap and Secret reflection relationships and marking their topology support.

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


Grey Divider

Context sources
✅ Compliance rules (platform): 44 rules
✅ Web pages:
  +7 more
✅ Cross-repo context — repo relationships
  Explored: repo: skyhook-dev/radar-hub (sha: 40701518)
  Explored: repo: skyhook-dev/radar-docs (sha: 82731c0c)
  Explored: repo: skyhook-dev/radar-e2e (sha: e4918cc2)
  Explored: repo: skyhook-dev/radar-hub-web (sha: 2b5189f1)
Review mode: 🧠 Deep: This is a high-risk, cross-cutting authorization and topology-cache change spanning multiple independent code paths, with substantial new parser, propagation, filtering, SSE, REST, and MCP logic where redundant review could catch subtle exposure defects.

Grey Divider

Tip of the day
ðŸ’Ą Did you know, you can start a comment with 'qodo' or '@qodo' to chat about any finding

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread docs/integrations.md Outdated
Comment thread docs/integrations.md Outdated

@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 pkg/topology/reflector.go
@nadaverell
nadaverell force-pushed the fix/reflector-relationships-independent branch from e7bf3cc to 4d937b2 Compare September 13, 2026 13:05
@nadaverell nadaverell changed the title Show Reflector relationships in topology and resource details Add Reflector support for ConfigMaps and Secrets Sep 13, 2026
@nadaverell
nadaverell force-pushed the fix/reflector-relationships-independent branch from 5399a00 to 48bb368 Compare September 13, 2026 15:34

@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 48bb368. Configure here.

Comment thread pkg/topology/reflector.go
@nadaverell
nadaverell merged commit 3d82b19 into main Sep 13, 2026
9 checks passed
@nadaverell
nadaverell deleted the fix/reflector-relationships-independent branch September 13, 2026 21:27
nadaverell added a commit that referenced this pull request Sep 15, 2026
## 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

| Available evidence | Result |
|---|---|
| An observed supported reference uses the object | Count it as
evaluated and passing, even if other consumer inventories are
unavailable |
| No reference, with adequate readable and initially synced consumer
inventories | Report the object as unused |
| No reference, with a required inventory unavailable or incomplete for
the subject namespace | Exclude it from both findings and
passing/evaluated counts; disclose incomplete reference evidence |

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 `missingInputs` carries `configmap-references` and
`secret-references` through 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
`ConfigReferenceEvidence` can establish observed use but cannot
establish absence.

## Validation

- `make test`, `make tsc`, and `make build` passed.
- Race tests passed for `pkg/audit`, `pkg/configrefs`, and the affected
audit/server/MCP scenarios.
- Live tests used the existing GitOps demo cluster with an explicit
kubectl context. Local and authenticated full-access results matched
exactly; Secret-denied identities disclosed missing inputs without
Secret findings. Alternating and concurrent identities retained separate
results.
- A temporary ConfigMap-only Reflector fixture exercised the central
case. Complete visibility evaluated two subjects, with the remotely
consumed source passing and the unused ConfigMap reported. A
source-namespace-only cache evaluated only the unused ConfigMap and
reported `configmap-references` for the unknown source. Configured REST,
dashboard, MCP and the rendered Checks page preserved that warning.
- Live test fixtures and processes were removed. No Kubernetes grants or
current-context changes. One actual embedded-UI screenshot verified the
warning; no frontend source changes.
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.

1 participant