Skip to content

Conversation

@theobarberbany
Copy link
Contributor

@theobarberbany theobarberbany commented Sep 15, 2025

  • Adds CAPI Machine VAP, similar to the MAPI one, but for when MAPI is autoritative.
  • Adds tests
  • Cleans up some shared code between tests.
  • Updates MAPI VAP to block changes to `.cluster(s).x-k8s.io/ labels and annotations

We expect the tests to fail, as we currently have a bug with how watch filters for infra machines are set up. We expect the CAPI Machine name will always equal the InfraMachine name. When we control the creation of the CAPI machine and infra machine, this holds. It may not always be the case if people bring their own CAPI machines. This will be addressed in a separate PR.

Summary by CodeRabbit

  • New Features

    • Added a validating admission policy to enforce alignment between Machine API and Cluster API on Machine updates.
    • Added a verbose test logger utility to improve test logging output.
  • Bug Fixes

    • Enforces authoritative alignment and blocks modifications to restricted fields (including machine-template-hash).
    • Broadens policy applicability across all cluster.x-k8s.io versions and handles both Machine and template-based specs.
  • Tests

    • Expanded and refactored test coverage for admission policy scenarios and logging.

@openshift-ci-robot
Copy link

Pipeline controller notification
This repository is configured to use the pipeline controller. Second-stage tests will be triggered only if the required tests of the first stage are successful. The pipeline controller will automatically detect which contexts are required, or not needed and will utilize a set of /test and /override Prow commands to trigger the second stage.

@coderabbitai
Copy link

coderabbitai bot commented Sep 15, 2025

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'path_filters'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

Adds a new ValidatingAdmissionPolicy and Binding (cluster-api-machine-vap) to enforce authoritative alignment on Machine UPDATEs, expands guards to cluster.x-k8s.io metadata, forbids modifying machine-template-hash, makes existing policy template-aware and wildcarded across apiVersions, and centralizes a verbose test logger across test suites.

Changes

Cohort / File(s) Summary
Cluster API Admission Policies
manifests/0000_30_cluster-api_09_admission-policies.yaml
Adds cluster-api-machine-vap ValidatingAdmissionPolicy and Binding enforcing authoritative alignment for UPDATEs; extends guards to cluster.x-k8s.io/* labels/annotations; forbids modification of machine-template-hash; adds conditional handling for Machine vs template-based specs with path-aware error validations. Also updates openshift-cluster-api-prevent-setting-of-capi-fields-unsupported-by-mapi to apiVersions: ["*"] and introduces conditional machineSpec/specPath variables.
Test Logger Helper
pkg/test/envtest.go
Adds exported NewVerboseGinkgoLogger(verbosity int) returning a logr.Logger wired to GinkgoWriter (funcr) for verbose test logging.
Test Suite Logger Setup
pkg/controllers/machinesync/suite_test.go, pkg/controllers/machinemigration/suite_test.go, pkg/controllers/machinesetmigration/suite_test.go, pkg/controllers/machinesetsync/suite_test.go
Replaces GinkgoLogr with test.NewVerboseGinkgoLogger(...), assigns logf and ctrl to testLogger, and injects the logger into test contexts via logf.IntoContext.
Machine Sync Tests
pkg/controllers/machinesync/machine_sync_controller_test.go
Introduces test constants (testLabelValue, machineAPIMachineVAPName, clusterAPIMachineVAPName), refactors manager startup to use context cancellation, replaces literal VAP names with constants, uses sentinel validations via helper, adds Cluster API VAP test contexts and sentinel-owned resource chains, and adds assertions protecting metadata (e.g., machine-template-hash) and spec restrictions.
Manager Start Context Fixes
pkg/controllers/machinesetsync/machineset_sync_controller_test.go, pkg/controllers/machinesetsync/machineset_sync_controller_test.go*
Changes manager start to use the test-provided ctx for cancellation (ties manager lifecycle to test context).
Minor Test Scaffolding
pkg/controllers/.../suite_test.go*
Logging initialization and context injection adjustments across multiple controller test suites to use the new verbose test logger.

Note: .../* used to indicate similar files grouped for readability.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User as Client
    participant APIServer as kube-apiserver
    participant VAP as ValidatingAdmissionPolicy (cluster-api-machine-vap)
    participant Controller as controllers (machine-sync)
    note over User,APIServer `#DDEEFF`: UPDATE Machine request flow

    User->>APIServer: PATCH/UPDATE Machine (cluster.x-k8s.io)
    APIServer->>VAP: Evaluate ValidatingAdmissionPolicy
    alt object.kind == "Machine"
        VAP->>VAP: inspect object.spec (machineSpec)
    else template-based (e.g., MachineSet)
        VAP->>VAP: inspect object.spec.template.spec (machineSpec)
    end
    VAP->>APIServer: Admit or Deny (reasons: authoritativeAPI mismatch, forbidden fields, machine-template-hash)
    opt Admitted
        APIServer->>Controller: controllers process update (observedGeneration/status updates)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Review the admission policy YAML carefully: conditional spec selection, matchConstraints, variable usage, and path-specific error messages.
  • Check machine_sync tests: sentinel wiring, new CAPI test contexts, constants vs. literals, and label/annotation protection assertions.
  • Verify logger helper and its injection across suites don’t alter test behavior or log visibility.

Poem

🐰 I hopped through manifests, guards held tight,
Cluster and Machine now dance in right light,
Tests sing verbose while sentinels keep sight,
Hashes untouched through day and night,
A carrot-coded cheer — alignment's in flight! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change—adding a CAPI Machine VAP—which is the primary objective and the centerpiece of the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a0cc708 and 62fe45c.

📒 Files selected for processing (8)
  • manifests/0000_30_cluster-api_09_admission-policies.yaml (3 hunks)
  • pkg/controllers/machinemigration/suite_test.go (3 hunks)
  • pkg/controllers/machinesetmigration/suite_test.go (3 hunks)
  • pkg/controllers/machinesetsync/machineset_sync_controller_test.go (1 hunks)
  • pkg/controllers/machinesetsync/suite_test.go (3 hunks)
  • pkg/controllers/machinesync/machine_sync_controller_test.go (12 hunks)
  • pkg/controllers/machinesync/suite_test.go (3 hunks)
  • pkg/test/envtest.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/controllers/machinesetsync/suite_test.go
  • pkg/controllers/machinesync/suite_test.go
  • pkg/controllers/machinemigration/suite_test.go
🔇 Additional comments (1)
pkg/controllers/machinesetsync/machineset_sync_controller_test.go (1)

107-119: Good improvement: context now properly scoped to the test lifecycle.

Using the test-provided ctx instead of context.Background() ensures the manager's context is cancelled when the test completes or fails, providing better cleanup and preventing potential goroutine leaks.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.5.0)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


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

@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 Sep 15, 2025
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Sep 15, 2025

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

@theobarberbany
Copy link
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Sep 15, 2025

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
manifests/0000_30_cluster-api_09_admission-policies.yaml (3)

225-237: Fix inconsistent label pattern matching.

Line 229 uses k.contains('cluster.x-k8s.io/') while line 233 uses the same pattern. This is inconsistent with the startsWith() pattern used for other prefixes and could match unintended labels.

Apply this diff to use consistent prefix matching:

-                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.contains('cluster.x-k8s.io/')) &&
+                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.startsWith('cluster.x-k8s.io/')) &&
-                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.contains('cluster.x-k8s.io/')) &&
+                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.startsWith('cluster.x-k8s.io/')) &&

239-251: Fix inconsistent annotation pattern matching.

Similar to the label validation, lines 243 and 247 use k.contains() for cluster.x-k8s.io patterns instead of k.startsWith(), which could match unintended annotations.

Apply this diff to use consistent prefix matching:

-                  (k.startsWith('machine.openshift.io') || k.contains('cluster.x-k8s.io') || k.contains('clusters.x-k8s.io')) &&
+                  (k.startsWith('machine.openshift.io') || k.startsWith('cluster.x-k8s.io') || k.startsWith('clusters.x-k8s.io')) &&
-                  (k.startsWith('machine.openshift.io') || k.contains('cluster.x-k8s.io') || k.contains('clusters.x-k8s.io')) &&
+                  (k.startsWith('machine.openshift.io') || k.startsWith('cluster.x-k8s.io') || k.startsWith('clusters.x-k8s.io')) &&

237-237: Update error messages to reflect the expanded label/annotation protection.

The error messages don't mention cluster.x-k8s.io or clusters.x-k8s.io patterns that are now being protected.

Apply this diff to update the error messages:

-          message: "Cannot add, modify or delete any machine.openshift.io/* or kubernetes.io/* label. This is because status.authoritativeAPI is set to Machine API."
+          message: "Cannot add, modify or delete any machine.openshift.io/*, kubernetes.io/*, or cluster.x-k8s.io/* label. This is because status.authoritativeAPI is set to Machine API."
-          message: "Cannot add, modify or delete any machine.openshift.io/* or cluster.x-k8s.io or clusters.x-k8s.io annotation. This is because status.authoritativeAPI is set to Machine API."
+          message: "Cannot add, modify or delete any machine.openshift.io/*, cluster.x-k8s.io/*, or clusters.x-k8s.io/* annotation. This is because status.authoritativeAPI is set to Machine API."

Also applies to: 251-251

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between e6b0e94 and 1453e08.

📒 Files selected for processing (1)
  • manifests/0000_30_cluster-api_09_admission-policies.yaml (1 hunks)
🔇 Additional comments (5)
manifests/0000_30_cluster-api_09_admission-policies.yaml (5)

154-172: LGTM! ValidatingAdmissionPolicyBinding configuration looks correct.

The binding properly targets the openshift-cluster-api namespace and references parameters from openshift-machine-api namespace with appropriate fallback behavior using parameterNotFoundAction: Allow.


174-183: LGTM! Policy metadata and parameter configuration are correct.

The policy correctly targets Machine API objects (machine.openshift.io/v1beta1) as parameters for validating Cluster API machines.


185-190: LGTM! Resource matching configuration is appropriate.

The policy correctly targets Cluster API machines (cluster.x-k8s.io/v1beta1/machines) for UPDATE operations only, which aligns with the intent to control modifications.


222-223: LGTM! Spec change restriction is appropriately strict.

Unlike the Machine API policy which allows spec.authoritativeAPI changes, this policy completely locks the spec for Cluster API machines when Machine API is authoritative, which is the correct behavior.


253-260: LGTM! Parameter-controlled label validation logic is correct.

The validation properly ensures that labels can only change to match the authoritative Machine API values, maintaining consistency between the two APIs.

@theobarberbany theobarberbany force-pushed the tb/update-machine-vap branch 2 times, most recently from 367a0e9 to 7c44697 Compare September 16, 2025 16:09
@theobarberbany
Copy link
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Sep 16, 2025

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
manifests/0000_30_cluster-api_09_admission-policies.yaml (1)

203-203: AuthoritativeAPI equality check fixed.

The condition now explicitly compares against "MachineAPI". This resolves the earlier presence-only check.

🧹 Nitpick comments (3)
pkg/controllers/machinesync/machine_sync_controller_test.go (1)

1160-1163: Avoid mixing WithName("") and WithGenerateName — build a fresh object instead.

Setting Name to "" and then GenerateName is error‑prone; construct a new builder with only GenerateName.

-               testMachine := capiMachineBuilder.WithName("").WithGenerateName("test-machine-").Build()
+               testMachine := clusterv1resourcebuilder.
+                       Machine().
+                       WithNamespace(capiNamespace.GetName()).
+                       WithGenerateName("test-machine-").
+                       Build()
manifests/0000_30_cluster-api_09_admission-policies.yaml (2)

225-237: Use prefix match for cluster.x-k8s.io labels instead of substring.

contains() can false‑positive on keys that merely include the substring. Use startsWith() like other prefixes.

-              variables.newLabels.exists(k,
-                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.contains('cluster.x-k8s.io/')) &&
+              variables.newLabels.exists(k,
+                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.startsWith('cluster.x-k8s.io')) &&
                   (variables.oldLabels[?k].orValue(null) != variables.newLabels[k])
               ) ||
-              variables.oldLabels.exists(k,
-                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.contains('cluster.x-k8s.io/')) &&
+              variables.oldLabels.exists(k,
+                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.startsWith('cluster.x-k8s.io')) &&
                   !(k in variables.newLabels)
               )

239-251: Also switch annotation checks to prefix match.

Aligns with label logic and avoids substring matches.

-              variables.newAnn.exists(k,
-                  (k.startsWith('machine.openshift.io') || k.contains('cluster.x-k8s.io') || k.contains('clusters.x-k8s.io')) &&
+              variables.newAnn.exists(k,
+                  (k.startsWith('machine.openshift.io') || k.startsWith('cluster.x-k8s.io') || k.startsWith('clusters.x-k8s.io')) &&
                   (variables.oldAnn[?k].orValue(null) != variables.newAnn[k])
               ) ||
-              variables.oldAnn.exists(k,
-                  (k.startsWith('machine.openshift.io') || k.contains('cluster.x-k8s.io') || k.contains('clusters.x-k8s.io')) &&
+              variables.oldAnn.exists(k,
+                  (k.startsWith('machine.openshift.io') || k.startsWith('cluster.x-k8s.io') || k.startsWith('clusters.x-k8s.io')) &&
                   !(k in variables.newAnn)
               )
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between e6b0e94 and 7c44697.

📒 Files selected for processing (2)
  • manifests/0000_30_cluster-api_09_admission-policies.yaml (2 hunks)
  • pkg/controllers/machinesync/machine_sync_controller_test.go (9 hunks)
🔇 Additional comments (4)
pkg/controllers/machinesync/machine_sync_controller_test.go (3)

836-847: Good: centralized constants and shared sentinel validation.

This de-duplicates test data and keeps assertions consistent.


969-971: Good: assert on the shared sentinel message.

Keeps error checks stable against policy text changes.


1033-1036: Consistent use of testLabelValue across cases.

Reduces string drift in expectations.

Also applies to: 1071-1074, 1109-1112

manifests/0000_30_cluster-api_09_admission-policies.yaml (1)

275-284: Nice: factoring spec path logic for Machine vs MachineSet.

Makes the policy concise and less error‑prone.

@theobarberbany
Copy link
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Sep 16, 2025

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
manifests/0000_30_cluster-api_09_admission-policies.yaml (1)

200-204: Fixed: authoritativeAPI equality check is now correct and null‑safe

Switching to an explicit equality against "MachineAPI" (with optional chaining fallback) addresses the earlier logic bug. Looks good.

pkg/controllers/machinesync/machine_sync_controller_test.go (1)

1118-1135: Focused block removed (now Context) — resolves CI risk

Thanks for switching from FContext to Context; this prevents accidental focused runs in CI.

🧹 Nitpick comments (3)
manifests/0000_30_cluster-api_09_admission-policies.yaml (2)

225-238: Use startsWith for cluster.x-k8s.io label prefix checks (avoid over‑matching)

contains("cluster.x-k8s.io/") will also match domains like topology.cluster.x-k8s.io/* unintentionally. Prefer startsWith for precise prefix semantics (aligns with other checks here).

Apply this diff:

-                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.contains('cluster.x-k8s.io/')) &&
+                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.startsWith('cluster.x-k8s.io')) &&
@@
-                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.contains('cluster.x-k8s.io/')) &&
+                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.startsWith('cluster.x-k8s.io')) &&

239-251: Align annotation prefix checks with startsWith and consistent messaging

Same rationale as labels: contains("cluster.x-k8s.io") and contains("clusters.x-k8s.io") may over‑match. Use startsWith to target the intended prefixes. Also consider updating the message to include trailing /* for clarity, but that’s optional.

-                  (k.startsWith('machine.openshift.io') || k.contains('cluster.x-k8s.io') || k.contains('clusters.x-k8s.io')) &&
+                  (k.startsWith('machine.openshift.io') || k.startsWith('cluster.x-k8s.io') || k.startsWith('clusters.x-k8s.io')) &&
@@
-                  (k.startsWith('machine.openshift.io') || k.contains('cluster.x-k8s.io') || k.contains('clusters.x-k8s.io')) &&
+                  (k.startsWith('machine.openshift.io') || k.startsWith('cluster.x-k8s.io') || k.startsWith('clusters.x-k8s.io')) &&
pkg/controllers/machinesync/machine_sync_controller_test.go (1)

1173-1183: Nit: comment misattributes the rejection cause

This failure is due to the appended sentinel validation, not the protected label prefixes (the test label isn’t under machine.openshift.io/ or cluster.x-k8s.io/).

Consider updating the comment to: “Setting the test sentinel label is blocked by the appended sentinel validation.”

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between e6b0e94 and 9113184.

📒 Files selected for processing (2)
  • manifests/0000_30_cluster-api_09_admission-policies.yaml (2 hunks)
  • pkg/controllers/machinesync/machine_sync_controller_test.go (9 hunks)
🔇 Additional comments (18)
manifests/0000_30_cluster-api_09_admission-policies.yaml (4)

156-173: New Cluster API VAP and binding are well‑scoped

  • Binding targets openshift-cluster-api and pulls params from openshift-machine-api with parameterNotFoundAction: Allow.
  • Policy matches UPDATEs for cluster.x-k8s.io/v1beta1 Machines and gates validations behind param/name match plus SA exclusion.
    LGTM.

Also applies to: 175-184, 185-193


219-224: Spec lock for CAPI machines under MAPI authority

Denying any spec change when MAPI is authoritative is consistent with the design and test expectations. LGTM.


275-284: Generalized Machine vs MachineSet pathing looks good

The machineSpec/specPath variable split cleanly supports both Machine and MachineSet resources. LGTM.


164-171: Minor: confirm ParamRef selector behavior is as intended

paramRef.selector: {} plus a name equality matchCondition typically works, but ParamRef evaluation semantics can vary across versions. Please confirm we never end up evaluating against multiple params for the same request (which could cause unexpected denials).

Would you like a quick probe test added that creates two param objects with the same name in different namespaces to ensure only the intended one is evaluated?

Also applies to: 41-49

pkg/controllers/machinesync/machine_sync_controller_test.go (14)

836-841: Test constants improve readability and reduce duplication

Good extraction of shared names and values.


843-847: Shared sentinel validation is tidy and reusable

Centralizing the expression/message avoids drift across tests. LGTM.


875-882: Param‑controlled label seeded on MAPI machine

This neatly enables the param‑controlled label tests later. LGTM.


919-923: Patching VAP with sentinel validation via constant name

Looks good and matches later expectations on the sentinel message.


931-954: Binding patching to dynamic namespaces

Updating ParamRef.Namespace and NamespaceSelector to generated namespaces is correct for envtest. LGTM.


971-971: Assertion uses shared sentinel message

Good consistency; avoids brittle string duplication.


983-987: Spec update allowed under MAPI authority

Test reflects policy behavior correctly. LGTM.


1033-1037: Protected label test uses shared value

Solid coverage; minor duplication removed. LGTM.


1071-1075: Protected annotation test uses shared value

Consistent with previous test; LGTM.


1107-1112: Reject mixed spec update with spec.authoritativeAPI

Good negative test for partial spec updates. LGTM.


1196-1200: CAPI spec change correctly rejected under MAPI authority

Covers the core contract from the new VAP. LGTM.


1203-1250: Comprehensive coverage of protected label behaviors

Good positive/negative coverage for machine.openshift.io and cluster.x-k8s.io prefixes. LGTM.


1252-1288: Protected annotations are thoroughly exercised

Good balance of modify/delete/empty‑string cases and an allowed case. LGTM.


1290-1305: Param‑controlled label rules validated both ways

  • Accept when matching param value
  • Reject when diverging
    Looks correct.

@theobarberbany theobarberbany changed the title WIP: Adds CAPI Machine VAP Adds CAPI Machine VAP Sep 17, 2025
@theobarberbany theobarberbany marked this pull request as ready for review September 17, 2025 09:46
@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Sep 17, 2025
@openshift-ci openshift-ci bot requested review from RadekManak and damdo September 17, 2025 09:47
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/controllers/machinesync/machine_sync_controller_test.go (1)

1519-1524: *Fix compile-time bug: don't compare a string to a corev1.Namespace — compare to its name and guard the index.

capiNamespace is declared as "var capiNamespace *corev1.Namespace"; comparing expr.Values[i] (string) to capiNamespace is a type error. Replace the check with a string comparison (e.g. ensure len(expr.Values) > i && expr.Values[i] == capiNamespace.GetName()) and keep assigning namespace.Name.
File: pkg/controllers/machinesync/machine_sync_controller_test.go lines ~1543–1547.

♻️ Duplicate comments (1)
pkg/controllers/machinesync/machine_sync_controller_test.go (1)

1118-1135: Thanks for replacing the focused FContext with Context.

Prevents accidental CI skips. Nothing else to change here.

🧹 Nitpick comments (7)
pkg/controllers/machinesync/machine_sync_controller_test.go (4)

881-881: Clarify test intent for param-controlled label.

Consider a brief comment explaining this label is intentionally MAPI‑controlled and exercised later in CAPI VAP tests to avoid future confusion.


919-927: Wait for VAP ObservedGeneration correctly; minor: include a reason in By().

Flow is sound. Optional: annotate the By() with what change is being observed to ease debugging.


1160-1166: Avoid setting an empty Name before GenerateName.

WithName("") is redundant and may be misleading; GenerateName alone is sufficient.

Apply this diff:

- testMachine := capiMachineBuilder.WithName("").WithGenerateName("test-machine-").Build()
+ testMachine := capiMachineBuilder.WithGenerateName("test-machine-").Build()

1173-1179: Fix misleading comment: rejection is from the sentinel rule, not label guards.

"test-sentinel" is not a protected prefix; the failure here comes from the appended sentinel validation.

Apply this diff:

- // The sync controller will sync the labels from the MAPI Machine to the CAPI machine.
- // The labels are protected (machine.openshift.io/cluster.x-k8s.io),
- // and so setting the test sentinel label is blocked by the labels rule.
+ // The sync controller will sync labels; however, the "test-sentinel" label is not a protected prefix.
+ // The following mutation is expected to be blocked by the appended sentinel validation.
manifests/0000_30_cluster-api_09_admission-policies.yaml (3)

192-204: AuthoritativeAPI check uses equality; consider simplifying optional chaining.

Current expression is safe. If desired, simplify to avoid redundant orValue when params are present:

Apply this diff (behaviorally equivalent when params exist):

-          expression: "params.?status.?authoritativeAPI.orValue(\"\") == \"MachineAPI\""
+          expression: "params.?status.?authoritativeAPI == \"MachineAPI\""

225-238: Use startsWith for cluster.x-k8s.io label matching (precision/consistency).

contains() may match unintended keys; startsWith('cluster.x-k8s.io/') is clearer and matches the tests/messages.

Apply this diff:

-                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.contains('cluster.x-k8s.io/')) &&
+                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.startsWith('cluster.x-k8s.io/')) &&
@@
-                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.contains('cluster.x-k8s.io/')) &&
+                  (k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.startsWith('cluster.x-k8s.io/')) &&

239-252: Likewise for annotation prefixes: prefer startsWith.

Aligns with label guard and reduces accidental matches.

Apply this diff:

-                  (k.startsWith('machine.openshift.io') || k.contains('cluster.x-k8s.io') || k.contains('clusters.x-k8s.io')) &&
+                  (k.startsWith('machine.openshift.io') || k.startsWith('cluster.x-k8s.io') || k.startsWith('clusters.x-k8s.io')) &&
@@
-                  (k.startsWith('machine.openshift.io') || k.contains('cluster.x-k8s.io') || k.contains('clusters.x-k8s.io')) &&
+                  (k.startsWith('machine.openshift.io') || k.startsWith('cluster.x-k8s.io') || k.startsWith('clusters.x-k8s.io')) &&
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9113184 and eee4f5a.

📒 Files selected for processing (2)
  • manifests/0000_30_cluster-api_09_admission-policies.yaml (2 hunks)
  • pkg/controllers/machinesync/machine_sync_controller_test.go (9 hunks)
🔇 Additional comments (10)
pkg/controllers/machinesync/machine_sync_controller_test.go (8)

836-847: Good extraction of shared constants and sentinel validation.

Centralizing names and the sentinel reduces duplication and brittle assertions.


931-955: Binding patching logic looks correct.

ParamRef/namespaceSelector rewrites align with the test namespaces.


969-971: Nice assertion against the sentinel Message.

Keeps tests resilient to validation ordering.


985-986: Use of testLabelValue improves consistency.

Good replacement of magic strings.


1186-1200: Spec updates correctly denied when MAPI is authoritative.

Assertion message matches the VAP.


1202-1250: Label guards for CAPI path look comprehensive.

Covers modify/delete/empty-string cases and non-protected pass‑through.


1252-1288: Annotation guards for CAPI path look comprehensive.

Protected prefixes are enforced; unrelated keys allowed.


1290-1305: Param-controlled label tests are correct and mirror the MAPI path.

Matches policy behavior for CAPI respecting MAPI‑controlled labels.

manifests/0000_30_cluster-api_09_admission-policies.yaml (2)

156-173: Binding scope and parameter strategy look correct.

Binding cluster-api-machine-vap to openshift-cluster-api with params from openshift-machine-api and Allow on missing params aligns with migration scenarios.


275-284: Nice refactor to machineSpec/specPath variables.

CEL expressions are simpler and messages are clearer for Machines vs MachineSets.

@damdo
Copy link
Member

damdo commented Sep 17, 2025

/retitle OCPCLOUD-3170: Adds CAPI Machine VAP

@openshift-ci openshift-ci bot changed the title Adds CAPI Machine VAP OCPCLOUD-3170: Adds CAPI Machine VAP Sep 17, 2025
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Sep 17, 2025
@openshift-ci-robot
Copy link

openshift-ci-robot commented Sep 17, 2025

@theobarberbany: This pull request references OCPCLOUD-3170 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target either version "4.21." or "openshift-4.21.", but it targets "openshift-4.20" instead.

In response to this:

  • Adds CAPI Machine VAP, similar to the MAPI one, but for when MAPI is
    autoritative.
  • Adds tests
  • Cleans up some shared code between tests.

Summary by CodeRabbit

  • New Features

  • Adds Cluster API admission policies that enforce Machine API authority for Machines, preventing unauthorized spec, label, and annotation changes and applying to the openshift-cluster-api context while allowing when no matching params exist.

  • Tests

  • Adds and standardizes tests covering Cluster API admission behavior, parameterized label handling, sentinel-driven rejection messages, and consistency checks for synchronization conditions.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Sep 17, 2025

@theobarberbany: This pull request references OCPCLOUD-3170 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target either version "4.21." or "openshift-4.21.", but it targets "openshift-4.20" instead.

In response to this:

  • Adds CAPI Machine VAP, similar to the MAPI one, but for when MAPI is
    autoritative.
  • Adds tests
  • Cleans up some shared code between tests.

Summary by CodeRabbit

  • New Features

  • Adds Cluster API admission policies that enforce Machine API authority for Machines, preventing unauthorized spec, label, and annotation changes and applying to the openshift-cluster-api context while allowing when no matching params exist.

  • Tests

  • Adds and standardizes tests covering Cluster API admission behavior, parameterized label handling, sentinel-driven rejection messages, and consistency checks for synchronization conditions.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Sep 17, 2025

@theobarberbany: This pull request references OCPCLOUD-3170 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target either version "4.21." or "openshift-4.21.", but it targets "openshift-4.20" instead.

In response to this:

  • Adds CAPI Machine VAP, similar to the MAPI one, but for when MAPI is
    autoritative.
  • Adds tests
  • Cleans up some shared code between tests.

Summary by CodeRabbit (not accurate decided by human)

  • New Features

  • Adds Cluster API admission policies that enforce Machine API authority for Machines, preventing unauthorized spec, label, and annotation changes and applying to the openshift-cluster-api context while allowing when no matching params exist.

  • Tests

  • Adds and standardizes tests covering Cluster API admission behavior, parameterized label handling, sentinel-driven rejection messages, and consistency checks for synchronization conditions.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@damdo
Copy link
Member

damdo commented Sep 17, 2025

/test unit

@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Nov 7, 2025
@theobarberbany
Copy link
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Nov 8, 2025

✅ Actions performed

Full review triggered.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 8, 2025

@theobarberbany: This pull request references OCPCLOUD-3170 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target either version "4.21." or "openshift-4.21.", but it targets "openshift-4.20" instead.

In response to this:

  • Adds CAPI Machine VAP, similar to the MAPI one, but for when MAPI is autoritative.
  • Adds tests
  • Cleans up some shared code between tests.
  • Updates MAPI VAP to block changes to `.cluster(s).x-k8s.io/ labels and annotations

We expect the tests to fail, as we currently have a bug with how watch filters for infra machines are set up. We expect the CAPI Machine name will always equal the InfraMachine name. When we control the creation of the CAPI machine and infra machine, this holds. It may not always be the case if people bring their own CAPI machines. This will be addressed in a separate PR.

Summary by CodeRabbit

  • Bug Fixes

  • Enhanced cluster-api machine enforcement policies to ensure state alignment between Machine API and Cluster API during updates.

  • Extended policy coverage to all cluster.x-k8s.io versions for broader compatibility.

  • Added restrictions on forbidden field modifications, including machine-template-hash label protection.

  • Tests

  • Improved test logging infrastructure and expanded test coverage for policy enforcement scenarios.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 4b37064 and 1ee608d.

📒 Files selected for processing (8)
  • manifests/0000_30_cluster-api_09_admission-policies.yaml (3 hunks)
  • pkg/controllers/machinemigration/suite_test.go (3 hunks)
  • pkg/controllers/machinesetmigration/suite_test.go (3 hunks)
  • pkg/controllers/machinesetsync/machineset_sync_controller_test.go (1 hunks)
  • pkg/controllers/machinesetsync/suite_test.go (3 hunks)
  • pkg/controllers/machinesync/machine_sync_controller_test.go (12 hunks)
  • pkg/controllers/machinesync/suite_test.go (3 hunks)
  • pkg/test/envtest.go (3 hunks)

@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 10, 2025

@theobarberbany: This pull request references OCPCLOUD-3170 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target either version "4.21." or "openshift-4.21.", but it targets "openshift-4.20" instead.

In response to this:

  • Adds CAPI Machine VAP, similar to the MAPI one, but for when MAPI is autoritative.
  • Adds tests
  • Cleans up some shared code between tests.
  • Updates MAPI VAP to block changes to `.cluster(s).x-k8s.io/ labels and annotations

We expect the tests to fail, as we currently have a bug with how watch filters for infra machines are set up. We expect the CAPI Machine name will always equal the InfraMachine name. When we control the creation of the CAPI machine and infra machine, this holds. It may not always be the case if people bring their own CAPI machines. This will be addressed in a separate PR.

Summary by CodeRabbit

  • New Features

  • Added a validating admission policy to enforce alignment between Machine API and Cluster API on Machine updates.

  • Bug Fixes

  • Enforces authoritative alignment and blocks modifications to restricted fields (including machine-template-hash).

  • Broadens policy applicability across all cluster.x-k8s.io versions and handles both Machine and template-based specs.

  • Tests

  • Improved test logging and expanded end-to-end coverage for policy enforcement scenarios.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

- Adds CAPI Machine VAP, similar to the MAPI one, but for when MAPI is
  autoritative.
- Adds tests
- Updates machine sync reconciler to requeue after 2s of
  AuthoritativeAPI is empty (rather than the 10m default)
- Adds logger for test suites into the context used by log.FromContext()
  calls
- Adds a helper for creating a logr.Logger writing to GinkgoWriter and
  setting verbosity correctly (useful for debugging)
@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 10, 2025

@theobarberbany: This pull request references OCPCLOUD-3170 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target either version "4.21." or "openshift-4.21.", but it targets "openshift-4.20" instead.

In response to this:

  • Adds CAPI Machine VAP, similar to the MAPI one, but for when MAPI is autoritative.
  • Adds tests
  • Cleans up some shared code between tests.
  • Updates MAPI VAP to block changes to `.cluster(s).x-k8s.io/ labels and annotations

We expect the tests to fail, as we currently have a bug with how watch filters for infra machines are set up. We expect the CAPI Machine name will always equal the InfraMachine name. When we control the creation of the CAPI machine and infra machine, this holds. It may not always be the case if people bring their own CAPI machines. This will be addressed in a separate PR.

Summary by CodeRabbit

  • New Features

  • Added a validating admission policy to enforce alignment between Machine API and Cluster API on Machine updates.

  • Added a verbose test logger utility to improve test logging output.

  • Bug Fixes

  • Enforces authoritative alignment and blocks modifications to restricted fields (including machine-template-hash).

  • Broadens policy applicability across all cluster.x-k8s.io versions and handles both Machine and template-based specs.

  • Tests

  • Expanded and refactored test coverage for admission policy scenarios and logging.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@chrischdi
Copy link
Contributor

/lgtm

Just questions

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Nov 10, 2025
@openshift-ci-robot
Copy link

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-capi-techpreview
/test e2e-aws-ovn
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-aws-ovn-techpreview
/test e2e-aws-ovn-techpreview-upgrade
/test e2e-azure-capi-techpreview
/test e2e-azure-ovn-techpreview
/test e2e-azure-ovn-techpreview-upgrade
/test e2e-gcp-capi-techpreview
/test e2e-gcp-ovn-techpreview
/test e2e-metal3-capi-techpreview
/test e2e-openstack-capi-techpreview
/test e2e-openstack-ovn-techpreview
/test e2e-vsphere-capi-techpreview
/test regression-clusterinfra-aws-ipi-techpreview-capi

@sunzhaohua2
Copy link
Contributor

/retest

@sunzhaohua2
Copy link
Contributor

@miyadav PTAL, thanks!

@miyadav
Copy link
Member

miyadav commented Nov 11, 2025

/verified by @miyadav
test

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Nov 11, 2025
@openshift-ci-robot
Copy link

@miyadav: This PR has been marked as verified by @miyadav.

In response to this:

/verified by @miyadav
test

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@theobarberbany
Copy link
Contributor Author

/retest

@theobarberbany
Copy link
Contributor Author

/approve

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Nov 12, 2025

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: theobarberbany

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

The pull request process is described here

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

@openshift-ci openshift-ci bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Nov 12, 2025
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Nov 12, 2025

@theobarberbany: all tests passed!

Full PR test history. Your PR dashboard.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@openshift-merge-bot openshift-merge-bot bot merged commit 65fe142 into openshift:main Nov 12, 2025
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. verified Signifies that the PR passed pre-merge verification criteria

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants