Skip to content

Pr 150 enhanced context#163

Draft
anandkuma77 wants to merge 3 commits into
openshift:mainfrom
anandkuma77:pr-150-enhanced-context
Draft

Pr 150 enhanced context#163
anandkuma77 wants to merge 3 commits into
openshift:mainfrom
anandkuma77:pr-150-enhanced-context

Conversation

@anandkuma77

@anandkuma77 anandkuma77 commented Jul 1, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

  • Documentation
    • Added comprehensive repository guidance covering contribution workflow, build/test commands, linting, naming, and generated-file expectations.
    • Published architecture, glossary, and context-map docs to make the operator’s design and terminology easier to understand.
    • Added focused guidelines for API contracts, error handling, performance, security, integration, and testing practices.
    • Introduced ADRs documenting key architectural decisions and a README for navigating decision records.

@openshift-ci

openshift-ci Bot commented Jul 1, 2026

Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 1, 2026
@openshift-ci

openshift-ci Bot commented Jul 1, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: anandkuma77
Once this PR has been reviewed and has the lgtm label, please assign mytreya-rh for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Walkthrough

This PR adds a comprehensive set of new documentation files with no code changes: entry-point guides (AGENTS.md, ARCHITECTURE.md, CLAUDE.md, CONTRIBUTING.md), a GLOSSARY.md, five domain guideline docs (API contracts, error handling, integration, performance, security, testing), four ADRs plus an ADR index, and a docs/CONTEXT_MAP.md organizing all documentation.

Changes

Documentation additions

Layer / File(s) Summary
Entry-point guidance
AGENTS.md, ARCHITECTURE.md, CLAUDE.md
New docs covering project overview, build/lint/code style rules, architecture invariants and code map, and AI-assistant command conventions.
Contribution process guide
CONTRIBUTING.md
New full contribution guide covering workflow, coding conventions, testing requirements, PR process, workspace, and container build tooling.
API contracts guidelines
docs/api-contracts-guidelines.md
New doc defining CRD markers, validation patterns (CEL/XValidation), status conventions, defaults, regeneration pipeline, and field-addition checklist.
Error handling guidelines
docs/error-handling-guidelines.md
New doc defining error categories, reconcile result mapping, retry/wrapping conventions, condition updates, events, and logging conventions.
Integration guidelines
docs/integration-guidelines.md
New doc covering bindata reconciliation flow, conditional asset creation, cert-manager, OpenShift and Bitwarden integrations, and plugin checklist.
Performance guidelines
docs/performance-guidelines.md
New doc covering cache architecture, watch/predicate patterns, reconciliation error handling, retries, concurrency, and drift detection.
Security guidelines
docs/security-guidelines.md
New doc covering container hardening, RBAC, TLS/webhook security, network policies, and singleton enforcement.
Testing guidelines
docs/testing-guidelines.md
New doc describing unit, API integration, and E2E testing tiers plus coverage and CI notes.
Glossary and context map
GLOSSARY.md, docs/CONTEXT_MAP.md
New glossary of domain terminology and a context map organizing documentation by audience/purpose with cross-references.
Architecture Decision Records
docs/decisions/001-...md...004-...md, docs/decisions/README.md
Four new ADRs covering bindata vs Helm, three-controller design, CEL-only validation, and singleton CR pattern, plus an ADR index README.

Estimated code review effort: 2 (Simple) | ~15 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error FAIL: install_external_secrets.go logs raw user-supplied label values ("value", v) when skipping disallowed labels, which may expose customer data. Do not log raw label values; log only the key or a redacted/sanitized summary.
Microshift Test Compatibility ⚠️ Warning New e2e specs use operator.openshift.io CRs and proxy.config.openshift.io with no [Skipped:MicroShift] or apigroup guard. Add MicroShift guards (e.g. [Skipped:MicroShift] or [apigroup:config.openshift.io]/[apigroup:operator.openshift.io]) or exclude these suites from MicroShift jobs.
Ipv6 And Disconnected Network Test Compatibility ⚠️ Warning Bitwarden e2e jobs hardcode docker.io/curlimages/curl:latest, so they need a public registry pull in disconnected CI. Mirror/override the curl job image to an internal registry (or make it configurable) so disconnected IPv6 jobs can run without public pulls.
Title check ❓ Inconclusive The title is vague and doesn’t clearly describe the broad docs-only context expansion across multiple repository guidance files. Rename it to a specific summary, e.g. "Add repository context and contributor guidance docs".
✅ Passed checks (11 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed Scanned 288 Ginkgo/YAML test titles; none use dynamic data, and the one UUID title is static/descriptive.
Test Structure And Quality ✅ Passed PR only adds docs/ADR files; no Go/Ginkgo test code changed, so the test-structure checklist is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed PASS: The added e2e tests only exercise API/secret/network-policy behavior and contain no node/topology/replica assumptions or SNO guards.
Topology-Aware Scheduling Compatibility ✅ Passed PR only adds documentation files; no deployment manifests, operator code, or controllers changed, so no new topology-sensitive scheduling constraints were introduced.
Ote Binary Stdout Contract ✅ Passed PASS: process-level hooks found no stdout writes; main.go uses textlogger (stderr by default) and suite setup logs only to GinkgoWriter.
No-Weak-Crypto ✅ Passed PASS: The PR is docs-only; scans of all added docs found no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or token/secret comparisons.
Container-Privileges ✅ Passed All changed files are Markdown docs; no pod/container manifests were added, and the only security hits were safe guidance like hostNetwork: false.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 11

🧹 Nitpick comments (3)
docs/performance-guidelines.md (1)

38-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Narrow the predicate rule to managed-resource watches.

The same document already calls out exceptions (ExternalSecretsManager, metadata-only watches) that intentionally do not use managedResources, so this "always" reads too broadly.

♻️ Suggested wording tweak
- When adding new watched resources, always apply at minimum the `managedResources` predicate to avoid reconciling unrelated objects.
+ When adding new label-filtered managed resources, apply at minimum the `managedResources` predicate to avoid reconciling unrelated objects.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/performance-guidelines.md` around lines 38 - 39, The guidance in the
performance guidelines is too broad because it says to always apply
managedResources, even though some watches intentionally use different
predicates. Update the wording in the relevant docs section near WatchesMetadata
to scope the rule to managed-resource watches only, and keep the exceptions for
ExternalSecretsManager and metadata-only watches clear and explicit.
DEVELOPMENT.md (1)

255-265: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid go install ...@latest here.

The guide already says the repo uses vendored tooling; pulling Delve from @latest makes the setup non-reproducible and bypasses the repo-managed toolchain.

♻️ Suggested fix
-# Install delve
-go install github.com/go-delve/delve/cmd/dlv@latest
+# Use the repository-managed Delve version (or pin the exact version used by CI).
Based on learnings, use the repository’s Makefile targets and vendored toolchain instead of installing tools globally.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DEVELOPMENT.md` around lines 255 - 265, Replace the Delve install step with
the repository-managed tooling instead of using go install ...@latest, since the
guide should stay reproducible and use vendored tools. Update the debugger setup
in DEVELOPMENT.md to point readers to the existing Makefile targets/toolchain
for launching and using dlv, and keep the rest of the debugging flow aligned
with those repo-supported commands.

Source: Learnings

docs/decisions/001-bindata-over-helm.md (1)

34-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Drop the Tiller-era Helm reference.

This rationale mixes Helm 2-only behavior with current Helm trade-offs. If the intent is to document modern Helm behavior, keep the release-tracking / three-way-merge concerns and remove Tiller.

♻️ Suggested fix
-- Helm adds operational complexity (Tiller/3-way merge, release tracking)
+- Helm adds operational complexity (release tracking, three-way merge)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/decisions/001-bindata-over-helm.md` around lines 34 - 39, The “Why not
Helm?” rationale in the decision doc still references Tiller, which is Helm
2-era behavior and no longer relevant. Update the Helm trade-offs text to focus
on current concerns only by removing the Tiller mention while keeping the
release-tracking and three-way-merge points in the same section.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@DEVELOPMENT.md`:
- Around line 333-339: The shell example in DEVELOPMENT.md has broken line
continuations because the backslashes are followed by inline comments. Update
the example so the command uses valid continuations in the same block,
referencing the go run invocation and the --zap-log-level,
--metrics-bind-address, --health-probe-bind-address, and --leader-elect flags,
with comments moved to separate lines or removed from the continued lines.

In `@docs/decisions/004-singleton-cr-pattern.md`:
- Around line 51-57: The singleton rationale in the “Why Singleton?” section
overstates the design by mentioning leader election, which is unrelated to the
CR ownership argument. Update the wording in the decision doc so the explanation
stays focused on config/reconciliation ownership, especially the rationale
around “Simplifies reconciliation” and “Clear ownership,” and remove any
implication that singleton CRs eliminate or depend on leader election.

In `@docs/error-handling-guidelines.md`:
- Around line 50-58: The error-handling guidance currently lists Exists
alongside client operations that should be wrapped with common.FromClientError,
but that should be removed. Update the wording in the error-handling guidelines
so only Get, Create, Update, Delete, and Patch are covered, and note that
CtrlClient.Exists already normalizes NotFound to (false, nil) in
pkg/controller/client/client.go. Keep the standard reconciliation references
(such as deployments.go and services.go) aligned with this corrected contract.

In `@docs/examples/advanced-configuration.yaml`:
- Around line 114-148: The advanced configuration example enables the Bitwarden
plugin but only adds egress rules for the controller, so the bitwardenSDKServer
path is not covered. Update the networkPolicies section to include an explicit
egress rule for the bitwardenSDKServer to reach Bitwarden or your proxy, or add
clear documentation near plugins.bitwardenSecretManagerProvider explaining the
required network dependency.
- Around line 54-73: The advanced configuration example hard-codes infra-node
placement and combines both affinity and nodeSelector, which makes the base
example unsuitable for compact topologies and contradicts the “alternative”
note. Update the YAML example to remove the fixed infra nodeSelector from the
base example and keep only one scheduling mechanism in this snippet, using the
existing affinity/tolerations or moving the selector into a separate overlay
example.

In `@docs/examples/bitwarden-plugin.yaml`:
- Around line 39-95: The Bitwarden example currently includes realistic-looking
secret material in the Secret manifests and auth token, which should not ship in
docs. Update the examples in bitwarden-plugin.yaml to use obvious placeholders
or commented generation commands for the TLS data, caBundle, and token values,
and keep the ClusterSecretStore/Secret structure intact so readers can still
follow the setup using non-sensitive sample content.

In `@docs/examples/cert-manager-integration.yaml`:
- Around line 15-60: Move the cert-manager issuer example out of the same
manifest as the ExternalSecretsConfig, because the current
certProvider.certManager issuerRef points to a ClusterIssuer that is defined
later in the file and makes the example order-dependent. Update the docs/example
so the ClusterIssuer is created before the ExternalSecretsConfig, or place it in
a separate manifest, while keeping the issuerRef and certManager configuration
as-is.

In `@docs/examples/corporate-proxy.yaml`:
- Around line 90-121: This proxy example is being added as a second
ExternalSecretsConfig/cluster singleton, which would overwrite the earlier
example if applied together. Update the docs/example so it is a patch/overlay or
otherwise clearly separate from the existing cluster singleton, and keep the
configuration consistent with the first ExternalSecretsConfig block. Also revise
controllerConfig.networkPolicies in the example to allow egress to the proxy
host/endpoints instead of the AWS Secrets Manager CIDR, so the policy matches
the documented proxy-based flow.
- Around line 23-70: The proxy example is using the wrong CA bundle contract by
nesting trusted CA under controllerConfig and pointing it at an openshift-config
ConfigMap. Update the example to use the operator’s top-level trustedCABundle
field from the external secrets config contract, and show the ConfigMap in the
operand namespace as required. Keep the proxy settings under
controllerConfig.proxy, but remove the mixed trustedCA/OpenShift CNO wiring so
the example matches the trustedCABundle behavior.

In `@docs/examples/README.md`:
- Around line 12-21: The quick-start instructions reference a non-existent
standalone issuer manifest, causing the setup steps to break. Update the example
in README’s production-grade setup section to point the ClusterIssuer command at
the actual manifest used in this PR, or add a separate issuer file and reference
it consistently. Use the cert-manager setup steps in the README and the
cert-manager-integration example as the source of truth.

In `@TROUBLESHOOTING.md`:
- Around line 284-297: The troubleshooting example under the
ExternalSecretsConfig section still hard-codes the worker-only nodeSelector,
which breaks SNO and Two-Node topologies. Update that managed-resources example
to remove the node-role.kubernetes.io/worker selector from the
controllerConfig/controller snippet, or explicitly note it is only for
dedicated-worker clusters; keep the guidance aligned with the
ExternalSecretsConfig and controllerConfig examples.

---

Nitpick comments:
In `@DEVELOPMENT.md`:
- Around line 255-265: Replace the Delve install step with the
repository-managed tooling instead of using go install ...@latest, since the
guide should stay reproducible and use vendored tools. Update the debugger setup
in DEVELOPMENT.md to point readers to the existing Makefile targets/toolchain
for launching and using dlv, and keep the rest of the debugging flow aligned
with those repo-supported commands.

In `@docs/decisions/001-bindata-over-helm.md`:
- Around line 34-39: The “Why not Helm?” rationale in the decision doc still
references Tiller, which is Helm 2-era behavior and no longer relevant. Update
the Helm trade-offs text to focus on current concerns only by removing the
Tiller mention while keeping the release-tracking and three-way-merge points in
the same section.

In `@docs/performance-guidelines.md`:
- Around line 38-39: The guidance in the performance guidelines is too broad
because it says to always apply managedResources, even though some watches
intentionally use different predicates. Update the wording in the relevant docs
section near WatchesMetadata to scope the rule to managed-resource watches only,
and keep the exceptions for ExternalSecretsManager and metadata-only watches
clear and explicit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: f3ff14ab-15fc-4df9-8785-be03c51192d9

📥 Commits

Reviewing files that changed from the base of the PR and between 4cc2a97 and 254d785.

📒 Files selected for processing (26)
  • AGENTS.md
  • ARCHITECTURE.md
  • CLAUDE.md
  • CONTRIBUTING.md
  • DEVELOPMENT.md
  • GLOSSARY.md
  • SECURITY.md
  • TROUBLESHOOTING.md
  • docs/CONTEXT_MAP.md
  • docs/api-contracts-guidelines.md
  • docs/decisions/001-bindata-over-helm.md
  • docs/decisions/002-three-controller-design.md
  • docs/decisions/003-cel-validation-only.md
  • docs/decisions/004-singleton-cr-pattern.md
  • docs/decisions/README.md
  • docs/error-handling-guidelines.md
  • docs/examples/README.md
  • docs/examples/advanced-configuration.yaml
  • docs/examples/basic-installation.yaml
  • docs/examples/bitwarden-plugin.yaml
  • docs/examples/cert-manager-integration.yaml
  • docs/examples/corporate-proxy.yaml
  • docs/integration-guidelines.md
  • docs/performance-guidelines.md
  • docs/security-guidelines.md
  • docs/testing-guidelines.md

Comment thread DEVELOPMENT.md Outdated
Comment on lines +333 to +339
```bash
go run ./cmd/external-secrets-operator/main.go \
--zap-log-level=4 \ # Verbose logs
--metrics-bind-address=:8080 \ # Enable metrics/pprof
--health-probe-bind-address=:8081 \ # Health checks
--leader-elect=false # Disable leader election (safe for local dev)
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix the shell example's line continuations.

The inline comments after \ break the command if someone copies it verbatim.

♻️ Suggested fix
 go run ./cmd/external-secrets-operator/main.go \
-  --zap-log-level=4 \                    # Verbose logs
-  --metrics-bind-address=:8080 \         # Enable metrics/pprof
-  --health-probe-bind-address=:8081 \    # Health checks
-  --leader-elect=false                   # Disable leader election (safe for local dev)
+  --zap-log-level=4 \
+  --metrics-bind-address=:8080 \
+  --health-probe-bind-address=:8081 \
+  --leader-elect=false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```bash
go run ./cmd/external-secrets-operator/main.go \
--zap-log-level=4 \ # Verbose logs
--metrics-bind-address=:8080 \ # Enable metrics/pprof
--health-probe-bind-address=:8081 \ # Health checks
--leader-elect=false # Disable leader election (safe for local dev)
```
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DEVELOPMENT.md` around lines 333 - 339, The shell example in DEVELOPMENT.md
has broken line continuations because the backslashes are followed by inline
comments. Update the example so the command uses valid continuations in the same
block, referencing the go run invocation and the --zap-log-level,
--metrics-bind-address, --health-probe-bind-address, and --leader-elect flags,
with comments moved to separate lines or removed from the continued lines.

Comment on lines +51 to +57
### Why Singleton?

1. **Prevents conflicts**: Multiple configs would create ambiguity about which should apply

2. **Simplifies reconciliation**: Controller always knows which CR to watch (no need for leader election or config merging)

3. **Clear ownership**: One CR, one operator instance managing it

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== docs/decisions/004-singleton-cr-pattern.md (around lines 51-57) ==\n'
sed -n '40,70p' docs/decisions/004-singleton-cr-pattern.md

printf '\n== Search for leader election references ==\n'
rg -n --hidden --no-ignore-vcs -S "leader election|leader-election|leaderElection|LeaderElection" .

Repository: openshift/external-secrets-operator

Length of output: 50391


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Non-vendor leader election references ==\n'
rg -n -S --glob '!vendor/**' --glob '!**/vendor/**' "LeaderElection|leader election|LeaderElectionID|NeedLeaderElection" .

printf '\n== Decision doc full context ==\n'
sed -n '1,120p' docs/decisions/004-singleton-cr-pattern.md

Repository: openshift/external-secrets-operator

Length of output: 6917


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '110,220p' cmd/external-secrets-operator/main.go

Repository: openshift/external-secrets-operator

Length of output: 4780


Drop the leader-election claim from the singleton rationale Singleton CRs remove config-merging ambiguity; leader election is a separate manager setting, so keep this sentence scoped to reconciliation/config ownership.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/decisions/004-singleton-cr-pattern.md` around lines 51 - 57, The
singleton rationale in the “Why Singleton?” section overstates the design by
mentioning leader election, which is unrelated to the CR ownership argument.
Update the wording in the decision doc so the explanation stays focused on
config/reconciliation ownership, especially the rationale around “Simplifies
reconciliation” and “Clear ownership,” and remove any implication that singleton
CRs eliminate or depend on leader election.

Comment on lines +50 to +58
For any Kubernetes client operation (Get, Create, Update, Delete, Patch, Exists), wrap the error with `common.FromClientError`:

```go
if err := r.Create(r.ctx, obj); err != nil {
return common.FromClientError(err, "failed to create %s deployment resource", name)
}
```

This is the standard pattern across all resource reconciliation files (rbacs.go, deployments.go, services.go, secret.go, certificate.go, configmap.go, networkpolicy.go, validatingwebhook.go, serviceaccounts.go). `FromClientError` auto-classifies the API error so callers do not manually pick irrecoverable vs retryable.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Exclude Exists from the FromClientError guidance.

CtrlClient.Exists already normalizes NotFound to (false, nil) in pkg/controller/client/client.go; wrapping it here would turn a plain presence check into a retry/error path and conflict with the helper contract.

🛠️ Suggested wording fix
- For any Kubernetes client operation (Get, Create, Update, Delete, Patch, Exists), wrap the error with `common.FromClientError`:
+ For Kubernetes client operations that can return API errors (Get, Create, Update, Delete, Patch), wrap the error with `common.FromClientError`:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
For any Kubernetes client operation (Get, Create, Update, Delete, Patch, Exists), wrap the error with `common.FromClientError`:
```go
if err := r.Create(r.ctx, obj); err != nil {
return common.FromClientError(err, "failed to create %s deployment resource", name)
}
```
This is the standard pattern across all resource reconciliation files (rbacs.go, deployments.go, services.go, secret.go, certificate.go, configmap.go, networkpolicy.go, validatingwebhook.go, serviceaccounts.go). `FromClientError` auto-classifies the API error so callers do not manually pick irrecoverable vs retryable.
For Kubernetes client operations that can return API errors (Get, Create, Update, Delete, Patch), wrap the error with `common.FromClientError`:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/error-handling-guidelines.md` around lines 50 - 58, The error-handling
guidance currently lists Exists alongside client operations that should be
wrapped with common.FromClientError, but that should be removed. Update the
wording in the error-handling guidelines so only Get, Create, Update, Delete,
and Patch are covered, and note that CtrlClient.Exists already normalizes
NotFound to (false, nil) in pkg/controller/client/client.go. Keep the standard
reconciliation references (such as deployments.go and services.go) aligned with
this corrected contract.

Comment on lines +54 to +73
# Node affinity - run on infra nodes
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: node-role.kubernetes.io/infra
operator: Exists

# Tolerations for tainted nodes
tolerations:
- key: node-role.kubernetes.io/infra
operator: Exists
effect: NoSchedule

# Node selector (alternative to affinity)
nodeSelector:
node-role.kubernetes.io/infra: ""

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Don't hard-code infra placement in the base example.

As per path instructions, YAML examples must not assume dedicated worker/infra nodes without considering SNO and Two-Node topologies. This nodeSelector makes the example unschedulable on compact clusters, and it also contradicts the "alternative" wording because the affinity and selector are both active. Keep only one mechanism here or move the selector to a separate overlay.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/examples/advanced-configuration.yaml` around lines 54 - 73, The advanced
configuration example hard-codes infra-node placement and combines both affinity
and nodeSelector, which makes the base example unsuitable for compact topologies
and contradicts the “alternative” note. Update the YAML example to remove the
fixed infra nodeSelector from the base example and keep only one scheduling
mechanism in this snippet, using the existing affinity/tolerations or moving the
selector into a separate overlay example.

Source: Path instructions

Comment on lines +114 to +148
# Custom network policies
networkPolicies:
# Allow egress to AWS Secrets Manager (us-east-1)
- name: allow-aws-secrets-manager
componentName: controller
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 52.94.0.0/16 # AWS IP range
ports:
- protocol: TCP
port: 443

# Allow egress to GCP Secret Manager
- name: allow-gcp-secret-manager
componentName: controller
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 35.190.247.0/24 # GCP Secret Manager
ports:
- protocol: TCP
port: 443

# Bitwarden plugin enabled
plugins:
bitwardenSecretManagerProvider:
mode: Enabled
secretRef:
name: bitwarden-tls

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add Bitwarden egress coverage or document the dependency.

This "production" example enables the Bitwarden plugin but only defines controller egress policies. If network policies are managed, the bitwardenSDKServer still needs an explicit rule to reach Bitwarden (or your proxy), otherwise the plugin cannot fetch secrets.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/examples/advanced-configuration.yaml` around lines 114 - 148, The
advanced configuration example enables the Bitwarden plugin but only adds egress
rules for the controller, so the bitwardenSDKServer path is not covered. Update
the networkPolicies section to include an explicit egress rule for the
bitwardenSDKServer to reach Bitwarden or your proxy, or add clear documentation
near plugins.bitwardenSecretManagerProvider explaining the required network
dependency.

Comment on lines +15 to +60
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
metadata:
name: cluster
spec:
managementState: Managed

controllerConfig:
certProvider:
certManager:
# Enable cert-manager mode (IMMUTABLE - cannot change once set)
mode: Enabled

# Reference to cert-manager Issuer (IMMUTABLE)
issuerRef:
# ClusterIssuer (cluster-scoped) or Issuer (namespace-scoped)
kind: ClusterIssuer
name: letsencrypt-prod # Must exist before creating this CR

# Inject CA bundle into operand CRDs via annotations (IMMUTABLE)
# When "true", crd-annotator adds cert-manager.io/inject-ca-from
# annotation to ExternalSecret/SecretStore/etc. CRDs
injectAnnotations: "true"

# Certificate validity and renewal settings
certificateCheckInterval: "5m" # How often to check cert validity
certificateDuration: "2160h" # 90 days (default: 8760h = 1 year)
certificateRenewBefore: "720h" # Renew 30 days before expiry

# Example ClusterIssuer (create separately):
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod-account-key
solvers:
- http01:
ingress:
class: openshift-default

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Split the issuer example from the CR.

The file says issuerRef must already exist, but the ClusterIssuer is defined later in the same manifest. That makes the example order-dependent and can race the controller. Put the issuer first or move it to a separate file.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/examples/cert-manager-integration.yaml` around lines 15 - 60, Move the
cert-manager issuer example out of the same manifest as the
ExternalSecretsConfig, because the current certProvider.certManager issuerRef
points to a ClusterIssuer that is defined later in the file and makes the
example order-dependent. Update the docs/example so the ClusterIssuer is created
before the ExternalSecretsConfig, or place it in a separate manifest, while
keeping the issuerRef and certManager configuration as-is.

Comment thread docs/examples/corporate-proxy.yaml Outdated
Comment on lines +23 to +70
controllerConfig:
# Proxy configuration
proxy:
httpProxy: "http://proxy.example.com:8080"
httpsProxy: "http://proxy.example.com:8080"

# NO_PROXY: comma-separated list (no spaces)
# Include: cluster.local, .svc, pod/service CIDRs, internal APIs
noProxy: ".cluster.local,.svc,10.0.0.0/8,172.30.0.0/16,localhost,127.0.0.1"

# Trusted CA bundle (for proxy TLS inspection)
trustedCA:
# ConfigMap name in "openshift-config" namespace
name: corporate-ca-bundle

# Key within ConfigMap (default: "ca-bundle.crt")
key: "ca-bundle.crt"

# Network policy provisioning must be Managed for automatic proxy egress
networkPolicyProvisioning: Managed

# Create ConfigMap with proxy CA certificate:
---
apiVersion: v1
kind: ConfigMap
metadata:
name: corporate-ca-bundle
namespace: openshift-config # Standard OpenShift location
data:
ca-bundle.crt: |
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKZ... (Corporate Root CA)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDYDCCAkigAwIBAgIJALa... (Intermediate CA, if any)
-----END CERTIFICATE-----

# OR inject cluster-wide CA via OpenShift CNO (auto-populates ConfigMap):
---
apiVersion: v1
kind: ConfigMap
metadata:
name: corporate-ca-bundle
namespace: openshift-config
labels:
# OpenShift CNO injects cluster CA bundle into ConfigMaps with this label
config.openshift.io/inject-trusted-cabundle: "true"
data: {} # CNO populates this

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use the operator's trusted CABundle contract here.

Based on the upstream contract in api/v1alpha1/external_secrets_config_types.go:148-181, the trusted CA bundle is a top-level trustedCABundle and its ConfigMap must live in the operand namespace. This example instead wires controllerConfig.trustedCA to an openshift-config ConfigMap, which mixes two different CA paths and won't work as written.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/examples/corporate-proxy.yaml` around lines 23 - 70, The proxy example
is using the wrong CA bundle contract by nesting trusted CA under
controllerConfig and pointing it at an openshift-config ConfigMap. Update the
example to use the operator’s top-level trustedCABundle field from the external
secrets config contract, and show the ConfigMap in the operand namespace as
required. Keep the proxy settings under controllerConfig.proxy, but remove the
mixed trustedCA/OpenShift CNO wiring so the example matches the trustedCABundle
behavior.

Comment thread docs/examples/corporate-proxy.yaml Outdated
Comment on lines +90 to +121
# Additional network policy for external provider through proxy:
---
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
metadata:
name: cluster
spec:
managementState: Managed

controllerConfig:
proxy:
httpProxy: "http://proxy.example.com:8080"
httpsProxy: "http://proxy.example.com:8080"
noProxy: ".cluster.local,.svc,10.0.0.0/8"

trustedCA:
name: corporate-ca-bundle

# Custom network policy for AWS Secrets Manager through proxy
networkPolicies:
- name: allow-aws-secrets-manager
componentName: controller
policyTypes:
- Egress
egress:
- to:
# AWS Secrets Manager endpoint CIDR (example: us-east-1)
- ipBlock:
cidr: 52.94.0.0/16 # AWS IP range
ports:
- protocol: TCP
port: 443

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't turn the proxy example into a second singleton CR.

This second ExternalSecretsConfig/cluster will overwrite the first example if the file is applied as-is, so it's not a standalone configuration. The custom egress rule also targets the AWS CIDR instead of the proxy endpoint, which defeats the stated proxy flow. Split this into a patch/overlay or rewrite the policy around the proxy host.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/examples/corporate-proxy.yaml` around lines 90 - 121, This proxy example
is being added as a second ExternalSecretsConfig/cluster singleton, which would
overwrite the earlier example if applied together. Update the docs/example so it
is a patch/overlay or otherwise clearly separate from the existing cluster
singleton, and keep the configuration consistent with the first
ExternalSecretsConfig block. Also revise controllerConfig.networkPolicies in the
example to allow egress to the proxy host/endpoints instead of the AWS Secrets
Manager CIDR, so the policy matches the documented proxy-based flow.

Comment thread docs/examples/README.md Outdated
Comment on lines +12 to +21
**Production-grade setup** (recommended):
```bash
# 1. Install cert-manager first
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml

# 2. Create ClusterIssuer (see cert-manager-integration.yaml for example)
kubectl apply -f clusterissuer.yaml

# 3. Apply configuration
kubectl apply -f cert-manager-integration.yaml

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix the quick-start target.

clusterissuer.yaml is not one of the example files in this PR; the issuer manifest only appears inside cert-manager-integration.yaml. As written, this copy-paste path will fail. Point the command at the actual file or add a standalone issuer manifest.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 13-13: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/examples/README.md` around lines 12 - 21, The quick-start instructions
reference a non-existent standalone issuer manifest, causing the setup steps to
break. Update the example in README’s production-grade setup section to point
the ClusterIssuer command at the actual manifest used in this PR, or add a
separate issuer file and reference it consistently. Use the cert-manager setup
steps in the README and the cert-manager-integration example as the source of
truth.

Comment thread TROUBLESHOOTING.md Outdated
Comment on lines +284 to +297
**Fix**:
- **Don't manually edit managed resources** - they will be reverted
- Instead, configure via `ExternalSecretsConfig`:
```yaml
spec:
controllerConfig:
controller: # for main controller deployment
resources:
limits:
cpu: 500m
memory: 256Mi
nodeSelector:
node-role.kubernetes.io/worker: ""
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Remove the worker-only selector from the example.

node-role.kubernetes.io/worker makes this snippet unschedulable on SNO/Two-Node clusters. Either omit the selector or call out that it only applies to dedicated-worker topologies.

🐛 Proposed docs fix
-        nodeSelector:
-          node-role.kubernetes.io/worker: ""
+        # Omit this selector on SNO / Two-Node clusters.
+        # If you need pinning, document a topology-aware selector instead.

As per coding guidelines, **/*.{yaml,yml}: "Flag deployment manifests or operator code that assume dedicated worker nodes exist without considering SNO and Two-Node topologies where all workloads run on control-plane nodes."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
**Fix**:
- **Don't manually edit managed resources** - they will be reverted
- Instead, configure via `ExternalSecretsConfig`:
```yaml
spec:
controllerConfig:
controller: # for main controller deployment
resources:
limits:
cpu: 500m
memory: 256Mi
nodeSelector:
node-role.kubernetes.io/worker: ""
```
**Fix**:
- **Don't manually edit managed resources** - they will be reverted
- Instead, configure via `ExternalSecretsConfig`:
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 287-287: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@TROUBLESHOOTING.md` around lines 284 - 297, The troubleshooting example under
the ExternalSecretsConfig section still hard-codes the worker-only nodeSelector,
which breaks SNO and Two-Node topologies. Update that managed-resources example
to remove the node-role.kubernetes.io/worker selector from the
controllerConfig/controller snippet, or explicitly note it is only for
dedicated-worker clusters; keep the guidance aligned with the
ExternalSecretsConfig and controllerConfig examples.

Source: Coding guidelines

Extends PR openshift#150 with focused Track 1 Contextualization additions:

Added ADRs (Architecture Decision Records):
- docs/decisions/001-bindata-over-helm.md - Why bindata pattern
- docs/decisions/002-three-controller-design.md - Why three controllers
- docs/decisions/003-cel-validation-only.md - Why CEL validation
- docs/decisions/004-singleton-cr-pattern.md - Why singleton CRs
- docs/decisions/README.md - ADR index

Added Core Documentation:
- GLOSSARY.md - Domain-specific terminology (bindata, ESC/ESM, etc.)
- docs/CONTEXT_MAP.md - Documentation navigation map

These additions provide:
- Prescriptive context explaining architectural "why" (ADRs)
- Essential terminology for AI agents and developers (GLOSSARY)
- Clear documentation organization (CONTEXT_MAP)

All documentation follows Track 1 principles:
- Grounded in source code (file paths, line numbers)
- Separates prescriptive from descriptive context
- Designed for both human and AI consumption

Ready for Track 1 Phase 2 context registration in Cyborg.

Total additions: 7 files focusing on core architectural context.
@anandkuma77 anandkuma77 force-pushed the pr-150-enhanced-context branch from 254d785 to 2b034cc Compare July 1, 2026 06:27

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/CONTEXT_MAP.md`:
- Around line 193-210: Add a language identifier to the dependency tree fenced
block in CONTEXT_MAP.md so it no longer uses an untyped code fence; update the
diagram block under the dependency tree section to use a suitable tag such as
text or plaintext, keeping the existing content and structure unchanged.
- Around line 237-251: The Context registry example markdown fence is missing
surrounding whitespace, so add a blank line before the YAML code block in the
Context Map section. Update the nearby markdown around the “Context registry
example” block so the fenced example is separated from the preceding text and
remains lint-clean, without changing the content of the example itself.
- Line 187: Fix the filename casing in CONTEXT_MAP.md so the referenced
ARCHITECTURE entry matches the actual lowercase filename. Update the
ARCHITECTURE.MD reference under the relevant list item to ARCHITECTURE.md,
keeping the rest of the context map text unchanged. Use the existing
ARCHITECTURE entry in CONTEXT_MAP.md to locate and correct this typo.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 2e0f9ae8-9656-458e-a5e9-4ca128c1890e

📥 Commits

Reviewing files that changed from the base of the PR and between 254d785 and 2b034cc.

📒 Files selected for processing (7)
  • GLOSSARY.md
  • docs/CONTEXT_MAP.md
  • docs/decisions/001-bindata-over-helm.md
  • docs/decisions/002-three-controller-design.md
  • docs/decisions/003-cel-validation-only.md
  • docs/decisions/004-singleton-cr-pattern.md
  • docs/decisions/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/decisions/001-bindata-over-helm.md

Comment thread docs/CONTEXT_MAP.md
### Most Referenced Docs

1. **AGENTS.md** - Referenced by README, CONTRIBUTING, CLAUDE.md, all guidelines
2. **ARCHITECTURE.MD** - Referenced by AGENTS, ADRs, guidelines

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the filename casing.

ARCHITECTURE.MD should be ARCHITECTURE.md to match the actual file name and avoid copy/paste failures on case-sensitive systems.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/CONTEXT_MAP.md` at line 187, Fix the filename casing in CONTEXT_MAP.md
so the referenced ARCHITECTURE entry matches the actual lowercase filename.
Update the ARCHITECTURE.MD reference under the relevant list item to
ARCHITECTURE.md, keeping the rest of the context map text unchanged. Use the
existing ARCHITECTURE entry in CONTEXT_MAP.md to locate and correct this typo.

Comment thread docs/CONTEXT_MAP.md
Comment on lines +193 to +210
```
README.md
├── AGENTS.md (AI entry point)
├── CONTRIBUTING.md (process)
└── ARCHITECTURE.md (design)

AGENTS.md
├── docs/*-guidelines.md (domain docs)
├── GLOSSARY.md (terminology)
└── ARCHITECTURE.md (system design)

ARCHITECTURE.md
└── docs/decisions/ (why decisions)

CONTRIBUTING.md
├── AGENTS.md (architecture context)
└── docs/testing-guidelines.md (testing)
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a language tag to the dependency tree fence.

The untyped code block triggers markdownlint MD040 and makes the block less searchable; text or plaintext fits this diagram.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 193-193: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/CONTEXT_MAP.md` around lines 193 - 210, Add a language identifier to the
dependency tree fenced block in CONTEXT_MAP.md so it no longer uses an untyped
code fence; update the diagram block under the dependency tree section to use a
suitable tag such as text or plaintext, keeping the existing content and
structure unchanged.

Source: Linters/SAST tools

Comment thread docs/CONTEXT_MAP.md
Comment on lines +237 to +251
**Context registry example**:
```yaml
# Future Cyborg YAML
team: external-secrets-operator
context:
entry_point: github.com/.../AGENTS.md
architecture: github.com/.../ARCHITECTURE.md
decisions: github.com/.../docs/decisions/
domain_guidelines:
- github.com/.../docs/api-contracts-guidelines.md
- github.com/.../docs/error-handling-guidelines.md
# ... etc
terminology: github.com/.../GLOSSARY.md
process: github.com/.../CONTRIBUTING.md
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Insert a blank line before the YAML example.

markdownlint flags this fence for missing surrounding whitespace; adding the blank line improves readability and keeps the doc lint-clean.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 238-238: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/CONTEXT_MAP.md` around lines 237 - 251, The Context registry example
markdown fence is missing surrounding whitespace, so add a blank line before the
YAML code block in the Context Map section. Update the nearby markdown around
the “Context registry example” block so the fenced example is separated from the
preceding text and remains lint-clean, without changing the content of the
example itself.

Source: Linters/SAST tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants