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