Skip to content

ROSAENG-61803: feat: preserve service-set fields on update - #276

Closed
cdoan1 wants to merge 6 commits into
openshift-online:mainfrom
cdoan1:ROSAENG-61803-service-set-preservation
Closed

ROSAENG-61803: feat: preserve service-set fields on update#276
cdoan1 wants to merge 6 commits into
openshift-online:mainfrom
cdoan1:ROSAENG-61803-service-set-preservation

Conversation

@cdoan1

@cdoan1 cdoan1 commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Description

  • Snapshot the full spec before applying customer updates so platform-managed (service-set) fields like accountId, internalId, creatorARN, and issuerURL are restored after the spec replacement
  • Add AccountID and InternalID to internal ClusterSpec; AccountID and InternalPoolID to internal NodePoolSpec so they can be preserved through the update path
  • Add verbose mode to marker-scanner (make codegen VERBOSE=1) for debugging field registration

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactoring (no functional changes)
  • CI/CD or tooling change

Testing

  • Update a cluster and verify accountId, internalId, creatorARN, issuerURL are unchanged in the stored spec

  • Update a nodepool and verify accountId, internalPoolId are unchanged

  • Verify expirationTimestamp is only restored when the customer doesn't explicitly set it

  • Run make codegen VERBOSE=1 and confirm scanner logs field registration

  • Unit tests pass (make test)

  • Integration tests pass (if applicable)

  • Manual verification completed

Checklist

  • My code follows the project's coding conventions
  • I have updated documentation as needed
  • I have added tests that prove my fix/feature works
  • All new and existing tests pass

Summary by CodeRabbit

  • New Features

    • Added public v2alpha1 Cluster and NodePool APIs with lifecycle states, configuration, metadata, and status fields.
    • Added platform-managed account and internal identifiers.
    • Added feature-gate support for configurable capabilities.
    • Added validation for unsupported, immutable, and feature-gated fields with clear API errors.
  • Bug Fixes

    • Prevented clients from overriding service-managed values during updates.
    • Improved nested specification passthrough handling and validation.
  • Chores

    • Added documented code-generation and verification commands.

cdoan1 and others added 2 commits August 4, 2026 14:37
…and codegen pipeline

New standalone module at api/public/v2alpha1/ with generated passthrough
types (HostedClusterSpecPassthrough, NodePoolSpecPassthrough), envelope
types (Cluster, NodePool), configuration mirror types, and per-field
markers for write-mode, visibility, and feature gates.

Adds platform-api codegen packages: field metadata registry (120 fields),
feature gate registry (6 gates), and conversion helpers. Adds Makefile
codegen pipeline (make codegen) and updates verify/deps targets.

v1alpha1 internal CRD types are unchanged.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The marker-scanner produced flat registry keys (e.g. "pausedUntil") with
no root-type namespace, so fields with the same JSON name in different
passthrough types silently overwrote each other with non-deterministic
results. Prefix passthrough fields with their root type context
(spec.hostedCluster.* / spec.nodePool.*) to match the paths that
downstream consumers already construct.

Add a verify-codegen Makefile target that re-runs the full codegen
pipeline and fails on git diff, same pattern as verify-clientset, so CI
catches stale generated code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Aug 4, 2026
@openshift-ci-robot

openshift-ci-robot commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

@cdoan1: This pull request references ROSAENG-61803 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 the "5.0.0" version, but no target version was set.

Details

In response to this:

Description

  • Snapshot the full spec before applying customer updates so platform-managed (service-set) fields like accountId, internalId, creatorARN, and issuerURL are restored after the spec replacement
  • Add AccountID and InternalID to internal ClusterSpec; AccountID and InternalPoolID to internal NodePoolSpec so they can be preserved through the update path
  • Add verbose mode to marker-scanner (make codegen VERBOSE=1) for debugging field registration

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactoring (no functional changes)
  • CI/CD or tooling change

Testing

  • Update a cluster and verify accountId, internalId, creatorARN, issuerURL are unchanged in the stored spec

  • Update a nodepool and verify accountId, internalPoolId are unchanged

  • Verify expirationTimestamp is only restored when the customer doesn't explicitly set it

  • Run make codegen VERBOSE=1 and confirm scanner logs field registration

  • Unit tests pass (make test)

  • Integration tests pass (if applicable)

  • Manual verification completed

Checklist

  • My code follows the project's coding conventions
  • I have updated documentation as needed
  • I have added tests that prove my fix/feature works
  • All new and existing tests pass

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

openshift-ci Bot commented Aug 4, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: cdoan1

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

The pull request process is described 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

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 4, 2026
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: b75a4dd4-1c2b-42d1-8d43-da70abaf4808

📥 Commits

Reviewing files that changed from the base of the PR and between cab2231 and 8f04f71.

⛔ Files ignored due to path filters (4)
  • api/public/v2alpha1/go.sum is excluded by !**/*.sum
  • api/public/v2alpha1/zz_generated.deepcopy.go is excluded by !**/zz_generated*
  • hack/api-codegen/go.sum is excluded by !**/*.sum
  • platform-api/go.sum is excluded by !**/*.sum
📒 Files selected for processing (31)
  • .gitignore
  • Makefile
  • api/public/v2alpha1/cluster_types.go
  • api/public/v2alpha1/configuration.go
  • api/public/v2alpha1/go.mod
  • api/public/v2alpha1/groupversion_info.go
  • api/public/v2alpha1/hostedclusterspec.passthrough.go
  • api/public/v2alpha1/nodepool_types.go
  • hack/api-codegen/cmd/marker-scanner/main.go
  • hack/api-codegen/go.mod
  • hack/api-codegen/pkg/markers/gated_writemode_test.go
  • hack/api-codegen/pkg/markers/scanner.go
  • hack/api-codegen/pkg/markers/scanner_test.go
  • hack/api-codegen/pkg/markers/types.go
  • hyperfleet-operator/api/v1alpha1/cluster_types.go
  • hyperfleet-operator/api/v1alpha1/nodepool_types.go
  • hyperfleet-operator/config/crd/bases/hyperfleet.io_clusters.yaml
  • hyperfleet-operator/config/crd/bases/hyperfleet.io_nodepools.yaml
  • platform-api/Containerfile
  • platform-api/go.mod
  • platform-api/internal/codegen/conversion/cluster.go
  • platform-api/internal/codegen/featuregate/registry.go
  • platform-api/internal/codegen/featuregate/types.go
  • platform-api/internal/codegen/registry/field_metadata.go
  • platform-api/internal/codegen/registry/field_metadata.json
  • platform-api/pkg/clients/hyperfleetdb/convert.go
  • platform-api/pkg/clients/hyperfleetdb/convert_test.go
  • platform-api/pkg/handlers/cluster.go
  • platform-api/pkg/handlers/nodepool.go
  • platform-api/pkg/validation/field_validator.go
  • platform-api/pkg/validation/field_validator_test.go
🚧 Files skipped from review as they are similar to previous changes (29)
  • .gitignore
  • platform-api/Containerfile
  • hack/api-codegen/pkg/markers/gated_writemode_test.go
  • api/public/v2alpha1/go.mod
  • hyperfleet-operator/api/v1alpha1/cluster_types.go
  • platform-api/internal/codegen/featuregate/registry.go
  • hyperfleet-operator/config/crd/bases/hyperfleet.io_clusters.yaml
  • platform-api/internal/codegen/conversion/cluster.go
  • hyperfleet-operator/config/crd/bases/hyperfleet.io_nodepools.yaml
  • platform-api/internal/codegen/registry/field_metadata.go
  • platform-api/pkg/clients/hyperfleetdb/convert.go
  • hyperfleet-operator/api/v1alpha1/nodepool_types.go
  • hack/api-codegen/pkg/markers/types.go
  • hack/api-codegen/cmd/marker-scanner/main.go
  • platform-api/pkg/handlers/cluster.go
  • api/public/v2alpha1/hostedclusterspec.passthrough.go
  • api/public/v2alpha1/groupversion_info.go
  • platform-api/pkg/clients/hyperfleetdb/convert_test.go
  • api/public/v2alpha1/nodepool_types.go
  • hack/api-codegen/go.mod
  • platform-api/pkg/validation/field_validator.go
  • api/public/v2alpha1/configuration.go
  • hack/api-codegen/pkg/markers/scanner_test.go
  • platform-api/go.mod
  • platform-api/pkg/handlers/nodepool.go
  • platform-api/internal/codegen/featuregate/types.go
  • platform-api/internal/codegen/registry/field_metadata.json
  • hack/api-codegen/pkg/markers/scanner.go
  • api/public/v2alpha1/cluster_types.go

Walkthrough

The PR adds public v2alpha1 cluster and node pool APIs, passthrough code generation, field metadata, feature gates, conversion helpers, and request validation. Cluster and node pool handlers now validate fields and preserve platform-managed values during updates.

Changes

Public API and generated metadata

Layer / File(s) Summary
Public v2alpha1 API contracts
api/public/v2alpha1/*
Adds cluster, node pool, configuration, passthrough, lifecycle, status, scheme, and module definitions.
Passthrough scanning and registry generation
.gitignore, Makefile, hack/api-codegen/*, platform-api/Containerfile, platform-api/go.mod, platform-api/internal/codegen/registry/*
Adds prefixed passthrough scanning, verbose diagnostics, field registry generation, module wiring, and generated-output verification.
Feature-gate model and registry
platform-api/internal/codegen/featuregate/*
Adds feature stages, feature sets, six HyperFleet gates, eligibility checks, and sorted gate lists.

Managed fields and request enforcement

Layer / File(s) Summary
Managed identifier contracts and conversions
hyperfleet-operator/api/v1alpha1/*, hyperfleet-operator/config/crd/bases/*, platform-api/pkg/clients/hyperfleetdb/*, platform-api/internal/codegen/conversion/*
Adds platform-managed identifiers, service-set conversion helpers, and conversion tests.
Field validation engine
platform-api/pkg/validation/*
Adds field flattening, write-mode enforcement, immutable-field checks, service-set checks, feature-gate checks, and validation tests.
Handler validation and preservation
platform-api/pkg/handlers/*
Adds create and update validation, HTTP 422 responses, internal pool ID generation, and managed-field preservation.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 9 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Ai-Attribution ⚠️ Warning All six PR commits identify Claude Opus 4.6 with Co-Authored-By; the scan found 0 Assisted-by and 0 Generated-by trailers. Replace the AI Co-Authored-By trailers with the required Red Hat Assisted-by or Generated-by trailers in every affected commit.
✅ Passed checks (9 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes preserving service-set fields during cluster and nodepool updates.
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.
No-Weak-Crypto ✅ Passed The full PR diff adds no MD5, SHA-1, DES, RC4, Blowfish, or ECB usage, crypto imports, custom crypto, or secret/token comparisons.
Container-Privileges ✅ Passed No prohibited settings were added. Runtime manifests use non-root users and deny privilege escalation; image roots are limited to build setup, with final images running as UID 65534.
No-Sensitive-Data-In-Logs ✅ Passed The PR adds scanner diagnostics that log directory paths, field paths, and marker metadata only; no passwords, tokens, API keys, PII, hostnames, or customer values are logged.
No-Hardcoded-Secrets ✅ Passed PR additions contain no credential literals, embedded-credential URLs, key blocks, or secret-named string assignments; base64 hits are dependency checksums in go.sum.
No-Injection-Vectors ✅ Passed The complete PR diff contains no SQL concatenation, shell=True, eval/exec, pickle.loads, unsafe yaml.load, os.system, or dangerouslySetInnerHTML sinks.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (11)
hack/api-codegen/pkg/markers/scanner_test.go (2)

124-124: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

No test covers verbose=true.

All three call sites pass false for the new verbose parameter. The verbose path in MarkerScanner.logf and Scan has no coverage, so a nil-writer or format-string defect in that path stays unnoticed.

Add one case that constructs the scanner with verbose=true and asserts the registry output is identical.

🤖 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 `@hack/api-codegen/pkg/markers/scanner_test.go` at line 124, Add a test case
alongside the existing NewScanner coverage that constructs the scanner with
verbose=true, captures its registry output, and asserts it matches the
established expected output. Exercise the verbose path through
MarkerScanner.Scan and logf without changing the existing false-verbose cases.

155-159: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Broaden the collision guard beyond pausedUntil.

The assertion covers only the flat pausedUntil key. The generated registry in platform-api/internal/codegen/registry/field_metadata.go still contains flat duplicates for other scanned types, for example both maxPods and kubelet.maxPods. A narrow guard does not catch that class.

Assert that every key produced from these two roots is prefixed. This makes the test fail on any new unprefixed key, not just this one name.

♻️ Proposed assertion change
-	// Verify no flat "pausedUntil" key exists (the old collision)
-	if _, found := scanner.Registry["pausedUntil"]; found {
-		t.Error("flat key \"pausedUntil\" should not exist; passthrough fields must be prefixed")
-	}
+	// Every passthrough field must be registered under a spec.* prefix.
+	for key := range scanner.Registry {
+		if !strings.HasPrefix(key, "spec.") {
+			t.Errorf("unprefixed registry key %q; passthrough fields must be prefixed", key)
+		}
+	}

Add "strings" to the import block.

🤖 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 `@hack/api-codegen/pkg/markers/scanner_test.go` around lines 155 - 159, Broaden
the collision check in the scanner test beyond the single "pausedUntil" key:
iterate over every registry key produced from the two scanned roots and assert
that each is prefixed, using strings.HasPrefix with the expected root prefixes.
Add the strings import and retain the existing failure behavior for unprefixed
keys.
platform-api/internal/codegen/registry/field_metadata.go (1)

1-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep both registry outputs synchronized.

The generated Go and JSON registries under hack/api-codegen and platform-api differ. verify-codegen regenerates and checks only the platform-api registry. Generate one shared registry or compare both outputs in verify-codegen.

🤖 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 `@platform-api/internal/codegen/registry/field_metadata.go` around lines 1 -
22, Update verify-codegen and the registry generation flow around FieldRegistry
so the hack/api-codegen and platform-api registry outputs remain synchronized.
Either generate both from one shared registry source or make verify-codegen
compare both generated outputs, including the Go and JSON representations, and
fail when they differ.
platform-api/internal/codegen/conversion/cluster.go (1)

34-40: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Escape clusterID before joining the URL.

url.URL.JoinPath(clusterID) removes duplicate slashes but does not keep / or ../ inside clusterID as one path segment. Use u.JoinPath(url.PathEscape(clusterID)) and handle URL parse errors explicitly.

🤖 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 `@platform-api/internal/codegen/conversion/cluster.go` around lines 34 - 40,
Update RewriteCloudURLWithID to parse baseURL into a url.URL, explicitly handle
any parse error, and construct the cloudUrl with
u.JoinPath(url.PathEscape(clusterID)) so clusterID remains a single path
segment. Preserve the existing nil-spec early return and assign the resulting
URL string to spec["cloudUrl"].
platform-api/pkg/validation/field_validator_test.go (2)

162-185: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for arrays and for unchanged platform-managed values.

TestFlattenToFieldPaths uses only nested objects, so it passes even though flattenMap never descends into JSON arrays. Add a case with a list of objects to pin the intended behavior. Add a case in which an update resends an unchanged ServiceSet value, because TestValidateUpdate_RejectsServiceSetFields only exercises a changed value.

💚 Proposed tests
func TestFlattenToFieldPaths_DescendsIntoArrays(t *testing.T) {
	spec := map[string]any{
		"services": []any{
			map[string]any{"service": "APIServer"},
		},
	}

	result := flattenToFieldPaths("spec", spec)

	if _, found := result["spec.services.service"]; !found {
		t.Error("expected list element fields to be flattened")
	}
}

func TestValidateUpdate_AllowsUnchangedServiceSetValue(t *testing.T) {
	v := newTestValidator(map[string]registry.FieldMeta{
		"spec.accountId": {FieldPath: "spec.accountId", WriteMode: registry.ServiceSet},
	})

	existing := map[string]any{"accountId": "123"}
	updated := map[string]any{"accountId": "123"}

	if errs := v.ValidateUpdate(updated, existing, featuregate.Default); errs != nil {
		t.Errorf("expected no errors when platform-managed value is unchanged, got %v", errs)
	}
}
🤖 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 `@platform-api/pkg/validation/field_validator_test.go` around lines 162 - 185,
Extend validation test coverage by adding an array-of-objects case to
TestFlattenToFieldPaths that verifies nested list fields are flattened, and add
a TestValidateUpdate_AllowsUnchangedServiceSetValue case using identical
existing and updated platform-managed values. Keep the assertions focused on the
expected flattened path and absence of validation errors.

87-89: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Do not index errs[0] without a length check.

Each test registers a single registry entry, so one error is expected today. If a case later produces zero errors, errs[0] panics after errs == nil already passed for a non-nil empty slice. Assert the length first, or search the slice for the expected field as TestValidateCreate_RejectsServiceSetFields does.

Also applies to: 120-122

🤖 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 `@platform-api/pkg/validation/field_validator_test.go` around lines 87 - 89,
The validation tests index errs without confirming an error exists, allowing a
non-nil empty slice to panic. In the affected assertions and the corresponding
check around TestValidateCreate_RejectsServiceSetFields, assert the expected
error count before indexing, or search errs for the expected "spec.fips" field
while preserving the existing validation expectations.
platform-api/internal/codegen/featuregate/registry.go (1)

5-6: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Protect the gate registry from accidental mutation.

HyperFleetFeatureGates is an exported package-level map. Go maps are mutable, so any importing package can add or remove gates and change validation outcomes. Unexport the map and expose read-only accessors, or add a comment that states the map must never be modified after initialization.

🤖 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 `@platform-api/internal/codegen/featuregate/registry.go` around lines 5 - 6,
Protect the feature-gate registry declared as HyperFleetFeatureGates from
external mutation by unexporting the map and providing read-only accessors for
consumers, or explicitly documenting that it must not be modified after
initialization if the exported map is retained. Ensure existing validation code
uses the protected registry access path.
hyperfleet-operator/api/v1alpha1/nodepool_types.go (1)

39-45: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Naming differs between the two specs for the same concept.

ClusterSpec uses InternalID / internalId. NodePoolSpec uses InternalPoolID / internalPoolId. Both describe "an internal platform identifier". Confirm this asymmetry is deliberate, because consumers and the generated field registry must handle two different key names for one concept.

🤖 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 `@hyperfleet-operator/api/v1alpha1/nodepool_types.go` around lines 39 - 45,
Align the node pool internal identifier naming with ClusterSpec by renaming
NodePoolSpec’s InternalPoolID field and JSON key to InternalID and internalId,
unless the API intentionally requires distinct concepts; update generated
field-registry references and consumers consistently with the chosen contract.
platform-api/pkg/handlers/cluster.go (1)

315-325: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated writeValidationErrors helper in both handlers. The two functions have identical bodies and differ only in the error code string. Extract one shared helper that takes the code as a parameter, so the 422 response shape stays consistent as it evolves.

  • platform-api/pkg/handlers/cluster.go#L315-L325: replace the local helper with a call to the shared helper, passing "CLUSTERS-MGMT-VALIDATION-001".
  • platform-api/pkg/handlers/nodepool.go#L272-L282: replace the local helper with a call to the shared helper, passing "NODEPOOLS-MGMT-VALIDATION-001".
🤖 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 `@platform-api/pkg/handlers/cluster.go` around lines 315 - 325, Extract the
duplicated validation-response logic into one shared helper accepting the HTTP
writer, validation errors, and error code. In
platform-api/pkg/handlers/cluster.go lines 315-325, remove the local
writeValidationErrors implementation and call the shared helper with
"CLUSTERS-MGMT-VALIDATION-001"; do the same in
platform-api/pkg/handlers/nodepool.go lines 272-282 using
"NODEPOOLS-MGMT-VALIDATION-001", preserving the existing 422 response shape.
platform-api/internal/codegen/featuregate/types.go (1)

6-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document that the iota order defines gate inclusion.

Includes compares stage ordinals. DevPreviewNoUpgrade therefore also enables TechPreview gates because TechPreview is declared before DevPreview. Any new stage inserted in this const block changes gating behavior silently. Add a comment that states the required order, and add a unit test that asserts the inclusion matrix for the three feature sets.

♻️ Proposed comment
 const (
+	// The declaration order is significant. FeatureSet.Includes compares stage
+	// ordinals, so a stage must be declared after every stage it subsumes.
 	GA FeatureStage = iota
 	TechPreview
 	DevPreview
 )

Also applies to: 51-53

🤖 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 `@platform-api/internal/codegen/featuregate/types.go` around lines 6 - 10,
Document on the FeatureStage const block that declaration order is significant
because Includes uses stage ordinals, and preserve the required GA, TechPreview,
DevPreview ordering when adding stages. Add a unit test covering the inclusion
matrix for all three feature sets, including DevPreviewNoUpgrade enabling
TechPreview gates.
hyperfleet-operator/api/v1alpha1/cluster_types.go (1)

40-46: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider validation markers for the new identifier fields.

CreatorARN uses +kubebuilder:validation:Pattern. AccountID and InternalID accept any string, including very long values. Add MaxLength and, for AccountID, a 12-digit pattern to keep the CRD schema self-describing and to bound stored data.

Note also that the type doc states the owning AWS account is stored in the hyperfleet.io/account-id label. spec.accountId now duplicates that value, so the operator needs one authoritative source.

♻️ Proposed markers
 	// AccountID is the AWS account ID that owns this cluster (platform-managed).
 	// +optional
+	// +kubebuilder:validation:MaxLength=12
+	// +kubebuilder:validation:Pattern=`^[0-9]{12}$`
 	AccountID string `json:"accountId,omitempty"`
 
 	// InternalID is an internal platform identifier for this cluster (platform-managed).
 	// +optional
+	// +kubebuilder:validation:MaxLength=253
 	InternalID string `json:"internalId,omitempty"`
🤖 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 `@hyperfleet-operator/api/v1alpha1/cluster_types.go` around lines 40 - 46, Add
CRD validation markers to AccountID and InternalID, bounding both fields with an
appropriate MaxLength and restricting AccountID to exactly 12 digits like the
existing CreatorARN validation style. Update the operator’s account
lookup/reconciliation logic so hyperfleet.io/account-id is the single
authoritative source rather than allowing spec.accountId to diverge.
🤖 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 `@api/public/v2alpha1/cluster_types.go`:
- Around line 72-77: Update the CreatorARN validation pattern to accept all
supported AWS partitions, including aws, aws-us-gov, and aws-cn, while
preserving ARN prefix validation. Confirm the platform’s intended partition
scope before widening the kubebuilder pattern.
- Around line 36-88: Update marker-scanner and verify-codegen to include
hostedclusterspec.passthrough.go in mirror synchronization checks, comparing
every generated HostedCluster field with the tracked spec.hostedCluster registry
entry set. Ensure the passthrough generation step detects and skips or rejects
duplicate declarations so each upstream field has exactly one registry entry.

In `@api/public/v2alpha1/configuration.go`:
- Around line 7-63: Update HostedClusterSpecPassthrough.Configuration to use the
local ClusterConfiguration mirror instead of
hypershiftv1beta1.ClusterConfiguration, and register its nested fields under the
spec.hostedCluster.configuration prefix rather than as an unprefixed root.
Ensure the registration preserves the existing nested metadata, including
service-set write modes.

In `@api/public/v2alpha1/nodepool_types.go`:
- Around line 36-69: Update MarkerScanner and the FieldValidator registry
construction to detect duplicate field paths or namespace keys within each
resource type, including collisions between ClusterSpec and NodePoolSpec paths
such as spec.<field>. Return a clear generation error instead of overwriting an
existing entry, and ensure map iteration order cannot change whether the
conflict is detected.

In `@Makefile`:
- Around line 329-355: Update the codegen pipeline around codegen-passthrough
and verify-codegen so passthrough-gen output becomes the source compiled by the
build rather than being moved only to the ignored .raw file. Preserve any
required transformation, write the resulting output to the checked-in
passthrough source, and add a git diff verification for that source so
verify-codegen fails when generated content differs.

In `@platform-api/pkg/handlers/cluster.go`:
- Around line 115-118: Update both cluster validation paths, including the flow
around ValidateCreate, to pass the configured or account-specific FeatureSet
instead of featuregate.Default. Ensure the same resolved feature set is used for
create and update validation so TechPreview and DevPreview fields are validated
according to the request’s account configuration.
- Around line 239-246: The restoration block in ApplyPlatformUpdateToClusterCR
must preserve every registry-managed ServiceSet field after replacing cr.Spec,
not just AccountID, InternalID, CreatorARN, and IssuerURL. Restore omitted
HostedCluster values such as infraID, dns, release, and services using the
resource-specific registry paths, while retaining the existing expiration
fallback; apply the equivalent complete restoration in the nodepool update flow.

In `@platform-api/pkg/handlers/nodepool.go`:
- Around line 102-105: Update PlatformCreateToNodePoolCR to populate the node
pool spec’s service-owned AccountID and InternalPoolID fields before creating
the CR, using the authoritative accountID and internal pool ID sources rather
than client-provided req.Spec values. Preserve validation that rejects
client-supplied managed fields and continue applying the account label.

In `@platform-api/pkg/validation/field_validator.go`:
- Around line 131-136: Update the ServiceSet handling in ValidateUpdate so
OperationUpdate permits a field value that is unchanged from the existing
object, while still rejecting changed or newly supplied platform-managed values.
Preserve the current rejection behavior for non-update operations, and add tests
covering unchanged ServiceSet fields during updates.

---

Nitpick comments:
In `@hack/api-codegen/pkg/markers/scanner_test.go`:
- Line 124: Add a test case alongside the existing NewScanner coverage that
constructs the scanner with verbose=true, captures its registry output, and
asserts it matches the established expected output. Exercise the verbose path
through MarkerScanner.Scan and logf without changing the existing false-verbose
cases.
- Around line 155-159: Broaden the collision check in the scanner test beyond
the single "pausedUntil" key: iterate over every registry key produced from the
two scanned roots and assert that each is prefixed, using strings.HasPrefix with
the expected root prefixes. Add the strings import and retain the existing
failure behavior for unprefixed keys.

In `@hyperfleet-operator/api/v1alpha1/cluster_types.go`:
- Around line 40-46: Add CRD validation markers to AccountID and InternalID,
bounding both fields with an appropriate MaxLength and restricting AccountID to
exactly 12 digits like the existing CreatorARN validation style. Update the
operator’s account lookup/reconciliation logic so hyperfleet.io/account-id is
the single authoritative source rather than allowing spec.accountId to diverge.

In `@hyperfleet-operator/api/v1alpha1/nodepool_types.go`:
- Around line 39-45: Align the node pool internal identifier naming with
ClusterSpec by renaming NodePoolSpec’s InternalPoolID field and JSON key to
InternalID and internalId, unless the API intentionally requires distinct
concepts; update generated field-registry references and consumers consistently
with the chosen contract.

In `@platform-api/internal/codegen/conversion/cluster.go`:
- Around line 34-40: Update RewriteCloudURLWithID to parse baseURL into a
url.URL, explicitly handle any parse error, and construct the cloudUrl with
u.JoinPath(url.PathEscape(clusterID)) so clusterID remains a single path
segment. Preserve the existing nil-spec early return and assign the resulting
URL string to spec["cloudUrl"].

In `@platform-api/internal/codegen/featuregate/registry.go`:
- Around line 5-6: Protect the feature-gate registry declared as
HyperFleetFeatureGates from external mutation by unexporting the map and
providing read-only accessors for consumers, or explicitly documenting that it
must not be modified after initialization if the exported map is retained.
Ensure existing validation code uses the protected registry access path.

In `@platform-api/internal/codegen/featuregate/types.go`:
- Around line 6-10: Document on the FeatureStage const block that declaration
order is significant because Includes uses stage ordinals, and preserve the
required GA, TechPreview, DevPreview ordering when adding stages. Add a unit
test covering the inclusion matrix for all three feature sets, including
DevPreviewNoUpgrade enabling TechPreview gates.

In `@platform-api/internal/codegen/registry/field_metadata.go`:
- Around line 1-22: Update verify-codegen and the registry generation flow
around FieldRegistry so the hack/api-codegen and platform-api registry outputs
remain synchronized. Either generate both from one shared registry source or
make verify-codegen compare both generated outputs, including the Go and JSON
representations, and fail when they differ.

In `@platform-api/pkg/handlers/cluster.go`:
- Around line 315-325: Extract the duplicated validation-response logic into one
shared helper accepting the HTTP writer, validation errors, and error code. In
platform-api/pkg/handlers/cluster.go lines 315-325, remove the local
writeValidationErrors implementation and call the shared helper with
"CLUSTERS-MGMT-VALIDATION-001"; do the same in
platform-api/pkg/handlers/nodepool.go lines 272-282 using
"NODEPOOLS-MGMT-VALIDATION-001", preserving the existing 422 response shape.

In `@platform-api/pkg/validation/field_validator_test.go`:
- Around line 162-185: Extend validation test coverage by adding an
array-of-objects case to TestFlattenToFieldPaths that verifies nested list
fields are flattened, and add a
TestValidateUpdate_AllowsUnchangedServiceSetValue case using identical existing
and updated platform-managed values. Keep the assertions focused on the expected
flattened path and absence of validation errors.
- Around line 87-89: The validation tests index errs without confirming an error
exists, allowing a non-nil empty slice to panic. In the affected assertions and
the corresponding check around TestValidateCreate_RejectsServiceSetFields,
assert the expected error count before indexing, or search errs for the expected
"spec.fips" field while preserving the existing validation expectations.
🪄 Autofix

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-online/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: be4d1c60-fe86-4642-9045-76e611092add

📥 Commits

Reviewing files that changed from the base of the PR and between cab2231 and 6ceb151.

⛔ Files ignored due to path filters (4)
  • api/public/v2alpha1/go.sum is excluded by !**/*.sum
  • api/public/v2alpha1/zz_generated.deepcopy.go is excluded by !**/zz_generated*
  • hack/api-codegen/go.sum is excluded by !**/*.sum
  • platform-api/go.sum is excluded by !**/*.sum
📒 Files selected for processing (29)
  • .gitignore
  • Makefile
  • api/public/v2alpha1/cluster_types.go
  • api/public/v2alpha1/configuration.go
  • api/public/v2alpha1/go.mod
  • api/public/v2alpha1/groupversion_info.go
  • api/public/v2alpha1/hostedclusterspec.passthrough.go
  • api/public/v2alpha1/nodepool_types.go
  • hack/api-codegen/cmd/marker-scanner/main.go
  • hack/api-codegen/go.mod
  • hack/api-codegen/pkg/markers/gated_writemode_test.go
  • hack/api-codegen/pkg/markers/scanner.go
  • hack/api-codegen/pkg/markers/scanner_test.go
  • hack/api-codegen/pkg/markers/types.go
  • hyperfleet-operator/api/v1alpha1/cluster_types.go
  • hyperfleet-operator/api/v1alpha1/nodepool_types.go
  • hyperfleet-operator/config/crd/bases/hyperfleet.io_clusters.yaml
  • hyperfleet-operator/config/crd/bases/hyperfleet.io_nodepools.yaml
  • platform-api/Containerfile
  • platform-api/go.mod
  • platform-api/internal/codegen/conversion/cluster.go
  • platform-api/internal/codegen/featuregate/registry.go
  • platform-api/internal/codegen/featuregate/types.go
  • platform-api/internal/codegen/registry/field_metadata.go
  • platform-api/internal/codegen/registry/field_metadata.json
  • platform-api/pkg/handlers/cluster.go
  • platform-api/pkg/handlers/nodepool.go
  • platform-api/pkg/validation/field_validator.go
  • platform-api/pkg/validation/field_validator_test.go

Comment thread api/public/v2alpha1/cluster_types.go
Comment on lines +72 to +77
// CreatorARN is the IAM ARN of the user who created this cluster.
// +k8s:openapi-gen=false
// +hyperfleet:write-mode=service-set
// +optional
// +kubebuilder:validation:Pattern=`^arn:aws:`
CreatorARN string `json:"creatorARN,omitempty"`

@coderabbitai coderabbitai Bot Aug 4, 2026

Copy link
Copy Markdown
Contributor

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

Anchor the ARN pattern to all supported AWS partitions.

The pattern ^arn:aws: accepts only the aws partition. AWS GovCloud ARNs use arn:aws-us-gov: and China ARNs use arn:aws-cn:. If the platform sets CreatorARN from a GovCloud caller, the API server rejects the object at admission. The field is service-set, so the rejection surfaces as a platform-side failure, not a customer input error.

Confirm the intended partition scope. If GovCloud is in scope, widen the pattern.

🔧 Proposed pattern change
-	// +kubebuilder:validation:Pattern=`^arn:aws:`
+	// +kubebuilder:validation:Pattern=`^arn:aws(-[a-z]+)*:`
 	CreatorARN string `json:"creatorARN,omitempty"`
📝 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
// CreatorARN is the IAM ARN of the user who created this cluster.
// +k8s:openapi-gen=false
// +hyperfleet:write-mode=service-set
// +optional
// +kubebuilder:validation:Pattern=`^arn:aws:`
CreatorARN string `json:"creatorARN,omitempty"`
// CreatorARN is the IAM ARN of the user who created this cluster.
// +k8s:openapi-gen=false
// +hyperfleet:write-mode=service-set
// +optional
// +kubebuilder:validation:Pattern=`^arn:aws(-[a-z]+)*:`
CreatorARN string `json:"creatorARN,omitempty"`
🤖 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 `@api/public/v2alpha1/cluster_types.go` around lines 72 - 77, Update the
CreatorARN validation pattern to accept all supported AWS partitions, including
aws, aws-us-gov, and aws-cn, while preserving ARN prefix validation. Confirm the
platform’s intended partition scope before widening the kubebuilder pattern.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Skip. The CreatorARN field is service-set and hidden from the public API — customers cannot set or see it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@cdoan1 Acknowledged. I will skip this finding. CreatorARN is platform-managed and hidden from the public API.


✏️ Learnings added
Learnt from: cdoan1
Repo: openshift-online/rosa-hyperfleet-api PR: 276
File: api/public/v2alpha1/cluster_types.go:72-77
Timestamp: 2026-08-04T23:29:54.252Z
Learning: In `api/public/v2alpha1/cluster_types.go`, `ClusterSpec.CreatorARN` is a platform-managed service-set field and is hidden from the public API. Customers cannot set or view this field.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

Comment thread api/public/v2alpha1/configuration.go
Comment on lines +36 to +69
// NodePoolSpec defines the desired state of a NodePool.
type NodePoolSpec struct {
// DisplayName is a human-readable name for the node pool.
// +hyperfleet:write-mode=mutable
// +kubebuilder:validation:MaxLength=256
// +optional
DisplayName string `json:"displayName,omitempty"`

// AutoRepair enables automatic repair of unhealthy nodes.
// +hyperfleet:write-mode=mutable
// +optional
AutoRepair *bool `json:"autoRepair,omitempty"`

// Labels are customer-defined labels applied to nodes.
// +hyperfleet:write-mode=mutable
// +optional
Labels map[string]string `json:"labels,omitempty"`

// AccountID identifies the customer account (platform-managed, hidden from API).
// +k8s:openapi-gen=false
// +hyperfleet:write-mode=service-set
// +optional
AccountID string `json:"accountId,omitempty"`

// InternalPoolID is an internal platform identifier (platform-managed, hidden).
// +k8s:openapi-gen=false
// +hyperfleet:write-mode=service-set
// +optional
InternalPoolID string `json:"internalPoolId,omitempty"`

// NodePool is the full HyperShift NodePoolSpec.
// +kubebuilder:validation:Required
NodePool hypershiftv1beta1.NodePoolSpec `json:"nodePool"`
}

@coderabbitai coderabbitai Bot Aug 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Does the scanner detect or error on duplicate registry keys?
rg -n --type=go -C6 'Registry\[' hack/api-codegen/pkg/markers/scanner.go
ast-grep outline hack/api-codegen/pkg/markers/scanner.go --items all
# Does the validator distinguish cluster vs nodepool when looking up spec.* keys?
fd -t f 'field_validator.go' --exec rg -n -C5 'FieldRegistry|Lookup|spec\.' {}

Repository: openshift-online/rosa-hyperfleet-api

Length of output: 2504


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- scanner implementation ---'
sed -n '1,340p' hack/api-codegen/pkg/markers/scanner.go

printf '%s\n' '--- registry and validator files ---'
fd -t f . | rg '(^|/)(field_metadata\.go|field_validator\.go|registry|validator)'

Repository: openshift-online/rosa-hyperfleet-api

Length of output: 10119


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- generated registry keys ---'
rg -n -C2 '"spec\.(accountId|displayName)|spec\.(hostedCluster|nodePool)\.(accountId|displayName)' \
  platform-api/internal/codegen/registry/field_metadata.go \
  hack/api-codegen/pkg/registry/field_metadata.go \
  platform-api/internal/codegen/registry/field_metadata.json \
  hack/api-codegen/pkg/registry/field_metadata.json

printf '%s\n' '--- validator lookup and path construction ---'
sed -n '1,280p' platform-api/pkg/validation/field_validator.go
rg -n -C4 'buildFieldPath|rootTypePrefix|HostedClusterSpecPassthrough|NodePoolSpecPassthrough|type (Cluster|NodePool).*Spec' \
  platform-api hack/api-codegen api

Repository: openshift-online/rosa-hyperfleet-api

Length of output: 24610


Reject conflicting duplicate field paths in code generation.

ClusterSpec and NodePoolSpec both resolve fields to spec.<field>, and FieldValidator performs a flat registry lookup. MarkerScanner overwrites duplicate entries without an error while iterating root types from a map. Reject conflicting metadata or namespace registry keys by resource type.

🤖 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 `@api/public/v2alpha1/nodepool_types.go` around lines 36 - 69, Update
MarkerScanner and the FieldValidator registry construction to detect duplicate
field paths or namespace keys within each resource type, including collisions
between ClusterSpec and NodePoolSpec paths such as spec.<field>. Return a clear
generation error instead of overwriting an existing entry, and ensure map
iteration order cannot change whether the conflict is detected.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

defer: ROSAENG-64559

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@cdoan1, acknowledged. ROSAENG-64559 tracks this deferred finding.

You are interacting with an AI system.

Comment thread Makefile
Comment thread platform-api/pkg/handlers/cluster.go
Comment thread platform-api/pkg/handlers/cluster.go
Comment thread platform-api/pkg/handlers/nodepool.go
Comment thread platform-api/pkg/validation/field_validator.go
Wire the generated FieldRegistry into cluster and nodepool handlers to
enforce write-mode and feature-gate rules on create/update requests.

- Service-set fields rejected if sent by customers (422)
- Immutable fields rejected on update if changed (422)
- Feature-gated fields rejected without the gate enabled (422)
- Validation errors returned with per-field detail

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cdoan1
cdoan1 force-pushed the ROSAENG-61803-service-set-preservation branch from 6ceb151 to a321d18 Compare August 4, 2026 22:36
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
platform-api/pkg/validation/field_validator.go (1)

36-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Avoid ignored return values from strings.Builder.WriteString.

WriteString returns a nil error by contract, so this has no runtime failure risk. Use strings.Join to satisfy the error-handling rule and preserve the output.

🤖 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 `@platform-api/pkg/validation/field_validator.go` around lines 36 - 40, Update
the error formatting loop in the validation error method to use strings.Join
over the individual err.Error() messages, preserving the existing indentation
and newline output while avoiding ignored strings.Builder.WriteString return
values.

Source: Path instructions

🤖 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.

Nitpick comments:
In `@platform-api/pkg/validation/field_validator.go`:
- Around line 36-40: Update the error formatting loop in the validation error
method to use strings.Join over the individual err.Error() messages, preserving
the existing indentation and newline output while avoiding ignored
strings.Builder.WriteString return values.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: ac48957e-d8ce-4de8-add8-65ad79bc1bd7

📥 Commits

Reviewing files that changed from the base of the PR and between cab2231 and a321d18.

⛔ Files ignored due to path filters (4)
  • api/public/v2alpha1/go.sum is excluded by !**/*.sum
  • api/public/v2alpha1/zz_generated.deepcopy.go is excluded by !**/zz_generated*
  • hack/api-codegen/go.sum is excluded by !**/*.sum
  • platform-api/go.sum is excluded by !**/*.sum
📒 Files selected for processing (29)
  • .gitignore
  • Makefile
  • api/public/v2alpha1/cluster_types.go
  • api/public/v2alpha1/configuration.go
  • api/public/v2alpha1/go.mod
  • api/public/v2alpha1/groupversion_info.go
  • api/public/v2alpha1/hostedclusterspec.passthrough.go
  • api/public/v2alpha1/nodepool_types.go
  • hack/api-codegen/cmd/marker-scanner/main.go
  • hack/api-codegen/go.mod
  • hack/api-codegen/pkg/markers/gated_writemode_test.go
  • hack/api-codegen/pkg/markers/scanner.go
  • hack/api-codegen/pkg/markers/scanner_test.go
  • hack/api-codegen/pkg/markers/types.go
  • hyperfleet-operator/api/v1alpha1/cluster_types.go
  • hyperfleet-operator/api/v1alpha1/nodepool_types.go
  • hyperfleet-operator/config/crd/bases/hyperfleet.io_clusters.yaml
  • hyperfleet-operator/config/crd/bases/hyperfleet.io_nodepools.yaml
  • platform-api/Containerfile
  • platform-api/go.mod
  • platform-api/internal/codegen/conversion/cluster.go
  • platform-api/internal/codegen/featuregate/registry.go
  • platform-api/internal/codegen/featuregate/types.go
  • platform-api/internal/codegen/registry/field_metadata.go
  • platform-api/internal/codegen/registry/field_metadata.json
  • platform-api/pkg/handlers/cluster.go
  • platform-api/pkg/handlers/nodepool.go
  • platform-api/pkg/validation/field_validator.go
  • platform-api/pkg/validation/field_validator_test.go
🚧 Files skipped from review as they are similar to previous changes (26)
  • .gitignore
  • platform-api/internal/codegen/featuregate/types.go
  • hack/api-codegen/pkg/markers/gated_writemode_test.go
  • hack/api-codegen/pkg/markers/types.go
  • platform-api/internal/codegen/featuregate/registry.go
  • hack/api-codegen/cmd/marker-scanner/main.go
  • platform-api/Containerfile
  • hyperfleet-operator/api/v1alpha1/cluster_types.go
  • platform-api/go.mod
  • platform-api/internal/codegen/registry/field_metadata.go
  • hack/api-codegen/pkg/markers/scanner_test.go
  • hack/api-codegen/go.mod
  • hyperfleet-operator/config/crd/bases/hyperfleet.io_nodepools.yaml
  • platform-api/internal/codegen/conversion/cluster.go
  • hyperfleet-operator/config/crd/bases/hyperfleet.io_clusters.yaml
  • hyperfleet-operator/api/v1alpha1/nodepool_types.go
  • platform-api/pkg/handlers/nodepool.go
  • api/public/v2alpha1/go.mod
  • api/public/v2alpha1/nodepool_types.go
  • api/public/v2alpha1/groupversion_info.go
  • platform-api/pkg/validation/field_validator_test.go
  • hack/api-codegen/pkg/markers/scanner.go
  • platform-api/pkg/handlers/cluster.go
  • api/public/v2alpha1/hostedclusterspec.passthrough.go
  • api/public/v2alpha1/configuration.go
  • api/public/v2alpha1/cluster_types.go

cdoan1 and others added 3 commits August 4, 2026 20:47
Go structs without omitempty serialize zero values to JSON, causing
the field validator to reject fields the client never explicitly set.
Skip ServiceSet enforcement when the field value is at its zero value.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add AccountID, InternalID to internal ClusterSpec; AccountID,
  InternalPoolID to internal NodePoolSpec
- Restore all service-set fields after full spec replacement in
  cluster and nodepool update handlers
- Add verbose mode to marker-scanner (make codegen VERBOSE=1)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ions

PlatformCreateToClusterCR and PlatformCreateToNodePoolCR now set
AccountID/InternalID/InternalPoolID from authoritative platform sources
instead of relying on client-provided req.Spec values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cdoan1
cdoan1 force-pushed the ROSAENG-61803-service-set-preservation branch from 12e0b20 to 8f04f71 Compare August 5, 2026 03:50
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@openshift-ci

openshift-ci Bot commented Aug 5, 2026

Copy link
Copy Markdown

@cdoan1: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/unit 8f04f71 link true /test unit

Full PR test history. Your PR dashboard.

Details

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.

@cdoan1 cdoan1 closed this Aug 5, 2026
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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants