|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this |
| 4 | +repository. |
| 5 | + |
| 6 | +## Overview |
| 7 | + |
| 8 | +The Configuration Policy Controller is a Kubernetes controller that enforces and evaluates |
| 9 | +ConfigurationPolicy resources in Open Cluster Management. It monitors objects on managed clusters, |
| 10 | +checks compliance against policy templates, and can automatically remediate non-compliant resources |
| 11 | +when set to enforce mode. |
| 12 | + |
| 13 | +## Build, Test, and Run Commands |
| 14 | + |
| 15 | +### Building |
| 16 | + |
| 17 | +```bash |
| 18 | +# Build the controller binary |
| 19 | +make build |
| 20 | + |
| 21 | +# Build the dryrun CLI tool |
| 22 | +make build-cmd |
| 23 | + |
| 24 | +# Build container image (configurable with REGISTRY, IMG, TAG env vars) |
| 25 | +make build-images |
| 26 | +``` |
| 27 | + |
| 28 | +### Testing |
| 29 | + |
| 30 | +```bash |
| 31 | +# Run unit tests |
| 32 | +make test |
| 33 | + |
| 34 | +# Run unit tests with coverage |
| 35 | +make test-coverage |
| 36 | + |
| 37 | +# Run E2E tests (requires KinD cluster) |
| 38 | +make e2e-test |
| 39 | + |
| 40 | +# Run specific E2E tests |
| 41 | +TESTARGS="--focus=<pattern>" make e2e-test |
| 42 | + |
| 43 | +# Setup KinD cluster for development |
| 44 | +make kind-bootstrap-cluster-dev |
| 45 | + |
| 46 | +# Deploy controller to KinD and run E2E tests |
| 47 | +make kind-tests |
| 48 | +``` |
| 49 | + |
| 50 | +### Running Locally |
| 51 | + |
| 52 | +```bash |
| 53 | +# Run controller locally (must set WATCH_NAMESPACE) |
| 54 | +export WATCH_NAMESPACE=<namespace> |
| 55 | +make run |
| 56 | + |
| 57 | +# The controller requires a Kubernetes cluster configured via kubectl |
| 58 | +``` |
| 59 | + |
| 60 | +### Linting and Formatting |
| 61 | + |
| 62 | +```bash |
| 63 | +# Format code |
| 64 | +make fmt |
| 65 | +``` |
| 66 | + |
| 67 | +### Generate Manifests |
| 68 | + |
| 69 | +```bash |
| 70 | +# Generate CRDs and RBAC manifests |
| 71 | +make manifests |
| 72 | + |
| 73 | +# Generate DeepCopy implementations |
| 74 | +make generate |
| 75 | +``` |
| 76 | + |
| 77 | +## Architecture |
| 78 | + |
| 79 | +### Core Components |
| 80 | + |
| 81 | +**ConfigurationPolicyReconciler** (`controllers/configurationpolicy_controller.go`) |
| 82 | + |
| 83 | +- Main reconciler that evaluates ConfigurationPolicy resources |
| 84 | +- Handles both `inform` (report-only) and `enforce` (remediate) modes |
| 85 | +- Uses dynamic client to work with any Kubernetes resource type |
| 86 | +- Supports templating with Go templates and sprig functions |
| 87 | +- Implements watch-based evaluation for efficient resource monitoring |
| 88 | + |
| 89 | +**OperatorPolicyReconciler** (`controllers/operatorpolicy_controller.go`) |
| 90 | + |
| 91 | +- Manages OperatorPolicy resources for OLM operator lifecycle management |
| 92 | +- Controls operator subscriptions, CSV status, and upgrade behavior |
| 93 | + |
| 94 | +**Evaluation Flow**: |
| 95 | + |
| 96 | +1. Policy is reconciled based on evaluation interval or watch events |
| 97 | +2. Templates are resolved (if present) using go-template-utils library |
| 98 | +3. Namespace selector determines target namespaces |
| 99 | +4. For each object template: |
| 100 | + - Determine desired objects (resolving selectors if needed) |
| 101 | + - Compare with existing cluster state |
| 102 | + - If enforce mode: create, update, or delete objects as needed |
| 103 | + - If inform mode: report compliance status only |
| 104 | +5. Status is updated with compliance details and related objects |
| 105 | +6. Events are emitted to parent Policy resource |
| 106 | + |
| 107 | +### Key Packages |
| 108 | + |
| 109 | +**pkg/common** - Shared utilities: |
| 110 | + |
| 111 | +- `namespace_selection.go`: NamespaceSelector reconciler for efficient namespace filtering |
| 112 | +- `common.go`: Helper functions for environment detection |
| 113 | + |
| 114 | +**pkg/dryrun** - CLI tool for testing policies without a cluster: |
| 115 | + |
| 116 | +- Simulates policy evaluation using fake clients |
| 117 | +- Supports reading cluster resources or using local YAML files |
| 118 | +- Provides diff output and compliance message reporting |
| 119 | + |
| 120 | +**pkg/mappings** - API resource mappings for the dryrun CLI |
| 121 | + |
| 122 | +**pkg/triggeruninstall** - Handles controller uninstallation cleanup |
| 123 | + |
| 124 | +### Template Processing |
| 125 | + |
| 126 | +The controller supports Go templating in object definitions with these special features: |
| 127 | + |
| 128 | +- Hub templates: can reference objects from the hub cluster (when configured) |
| 129 | +- Context variables: `.Object`, `.ObjectName`, `.ObjectNamespace` for dynamic templating per |
| 130 | + namespace/object |
| 131 | +- Template functions: `fromSecret`, `fromConfigMap`, `fromClusterClaim`, `lookup`, plus sprig |
| 132 | + functions |
| 133 | +- `skipObject` function: allows conditional object creation based on template logic |
| 134 | +- Encryption support: templates can include encrypted values using AES encryption |
| 135 | + |
| 136 | +### Compliance Types |
| 137 | + |
| 138 | +- **musthave**: Object must exist and match the specified fields (partial match) |
| 139 | +- **mustnothave**: Object must not exist |
| 140 | +- **mustonlyhave**: Object must exist and match exactly (no extra fields) |
| 141 | + |
| 142 | +### Watch vs Polling |
| 143 | + |
| 144 | +The controller supports two evaluation modes: |
| 145 | + |
| 146 | +- **Watch mode** (default): Uses Kubernetes watches for efficient real-time evaluation |
| 147 | +- **Polling mode**: Periodically evaluates policies based on evaluationInterval |
| 148 | + |
| 149 | +The dynamic watcher (kubernetes-dependency-watches) automatically manages watches on related |
| 150 | +objects. |
| 151 | + |
| 152 | +### Hosted Mode |
| 153 | + |
| 154 | +The controller can run in "hosted mode" where: |
| 155 | + |
| 156 | +- Controller runs on hub cluster |
| 157 | +- Evaluates/enforces policies on a separate managed cluster |
| 158 | +- Configured via `--target-kubeconfig-path` flag |
| 159 | +- Uses separate managers for hub and managed cluster clients |
| 160 | + |
| 161 | +## Important Patterns |
| 162 | + |
| 163 | +### Object Comparison |
| 164 | + |
| 165 | +The comparison logic in `handleSingleKey` and `mergeSpecsHelper` is critical: |
| 166 | + |
| 167 | +- Merges template values into existing object to avoid false negatives |
| 168 | +- Handles arrays specially (preserves duplicates, matches by "name" field) |
| 169 | +- Dry-run updates verify actual API behavior before enforcement |
| 170 | +- `zeroValueEqualsNil` parameter controls empty value handling |
| 171 | + |
| 172 | +### Caching and Evaluation Optimization |
| 173 | + |
| 174 | +- `processedPolicyCache`: Tracks evaluated objects by resourceVersion to avoid redundant comparisons |
| 175 | +- `lastEvaluatedCache`: Prevents race conditions with controller-runtime cache staleness |
| 176 | +- Evaluation backoff (`--evaluation-backoff`): Throttles frequent policy evaluations |
| 177 | + |
| 178 | +### Pruning Behavior |
| 179 | + |
| 180 | +When `pruneObjectBehavior` is set: |
| 181 | + |
| 182 | +- **DeleteIfCreated**: Removes objects created by the policy |
| 183 | +- **DeleteAll**: Removes all objects matching the template |
| 184 | +- Tracked via finalizers and object UIDs in status.relatedObjects |
| 185 | + |
| 186 | +### Dry Run CLI |
| 187 | + |
| 188 | +The `dryrun` command provides policy testing without cluster modification: |
| 189 | + |
| 190 | +```bash |
| 191 | +# Test policy against local resources |
| 192 | +build/_output/bin/dryrun -p policy.yaml resource1.yaml resource2.yaml |
| 193 | + |
| 194 | +# Test policy against live cluster (read-only) |
| 195 | +build/_output/bin/dryrun -p policy.yaml --from-cluster |
| 196 | + |
| 197 | +# Compare status against expected |
| 198 | +build/_output/bin/dryrun -p policy.yaml resources.yaml --desired-status expected-status.yaml |
| 199 | +``` |
| 200 | + |
| 201 | +## Testing Guidelines |
| 202 | + |
| 203 | +### E2E Test Structure |
| 204 | + |
| 205 | +- Tests are in `test/e2e/` with descriptive case names |
| 206 | +- Use Ginkgo/Gomega framework |
| 207 | +- Tests can filter by label: `--label-filter='!hosted-mode'` |
| 208 | +- Helper functions in `test/utils/utils.go` for common operations |
| 209 | + |
| 210 | +### Writing Tests |
| 211 | + |
| 212 | +- Use `utils.GetWithTimeout` for eventually-consistent checks |
| 213 | +- Clean up resources in AfterEach blocks |
| 214 | +- Use unique names to avoid test conflicts |
| 215 | +- Test both inform and enforce modes where applicable |
| 216 | + |
| 217 | +## Configuration |
| 218 | + |
| 219 | +### Controller Flags |
| 220 | + |
| 221 | +Key flags when running the controller: |
| 222 | + |
| 223 | +- `--evaluation-concurrency`: Max concurrent policy evaluations (default: 2) |
| 224 | +- `--evaluation-backoff`: Seconds before re-evaluation in watch mode (default: 10) |
| 225 | +- `--enable-operator-policy`: Enable OperatorPolicy support |
| 226 | +- `--target-kubeconfig-path`: Path to managed cluster kubeconfig (hosted mode) |
| 227 | +- `--standalone-hub-templates-kubeconfig-path`: Hub cluster for template resolution |
| 228 | + |
| 229 | +### Environment Variables |
| 230 | + |
| 231 | +- `WATCH_NAMESPACE`: Namespace to monitor for policies (required when running locally) |
| 232 | +- `POD_NAME`: Used to detect controller pod name |
0 commit comments