Skip to content

validations: add 'allOf' property validation - #61

Open
saschagrunert wants to merge 1 commit into
kubernetes-sigs:mainfrom
saschagrunert:allof-validation
Open

saschagrunert wants to merge 1 commit into
kubernetes-sigs:mainfrom
saschagrunert:allof-validation

Conversation

@saschagrunert

@saschagrunert saschagrunert commented Apr 30, 2026

Copy link
Copy Markdown
Member

What this PR does:

Adds a property validation for the allOf JSON Schema keyword. It detects incompatible changes to allOf constraints on CRD properties:

  • Adding an allOf constraint when there was none previously
  • Adding new subschemas to an existing allOf constraint
  • Removing subschemas from an existing allOf constraint

Both additions and removals are treated as incompatible by default. An additionPolicy and removalPolicy configuration knob allow users to opt into treating additions or removals as compatible when appropriate for their reader/writer considerations.

Uses sets.Set with stringified schemas for diffing, matching the approach in #64.

Which issue this PR is related to:

Fixes #24

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Apr 30, 2026
@k8s-ci-robot
k8s-ci-robot requested a review from JoelSpeed April 30, 2026 09:30
@k8s-ci-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

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

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

@k8s-ci-robot
k8s-ci-robot requested a review from jpbetz April 30, 2026 09:30
@k8s-ci-robot k8s-ci-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Apr 30, 2026
@saschagrunert
saschagrunert force-pushed the allof-validation branch 2 times, most recently from a7ed633 to 692b916 Compare May 6, 2026 12:42
@saschagrunert

Copy link
Copy Markdown
Member Author

Rebased

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

Apologies for the long delay on the review here - I haven't been able to carve out much time to review PRs here for some time.

Overall this looks pretty good. Just one change I'd like to see made to what is considered compatible changes.

Comment thread docs/validations.md Outdated
@k8s-ci-robot k8s-ci-robot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels May 20, 2026
@saschagrunert
saschagrunert force-pushed the allof-validation branch 2 times, most recently from 81b274f to e38f529 Compare May 20, 2026 06:11
Comment thread docs/validations.md Outdated
Comment on lines +167 to +169
The `allOf` validation can be configured to allow removing subschemas as a compatible change when you are confident that relaxing validation will not affect API consumers:

- `removalPolicy` - controls whether removing allOf subschemas is considered compatible. Allowed values are `Allow` and `Disallow`. When set to `Allow`, the validation does not flag removals. The default is `Disallow` to ensure such changes are reviewed.

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.

I must've missed this previously, be we want both addition and removal policy configuration knobs so end-users can distinguish between reader/writer semantics for their APIs based on the actions they care about for their API.

For example, if a user only cares about the readers of their API, removals are likely tolerable but additions are not. If they only care about the writers of their API, removals are not tolerable, but additions likely are. If they care about both, neither are tolerable.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thanks for the feedback! Added an additionPolicy configuration knob alongside removalPolicy, both defaulting to Disallow. This lets users tailor validations to their reader/writer semantics independently.

Comment thread pkg/validations/property/allof.go Outdated
Comment on lines +134 to +170
func (ao *AllOf) compareExisting(old, updated []apiextensionsv1.JSONSchemaProps) error {
added := countNotFound(updated, old)
if added > 0 {
return fmt.Errorf("%w : %d subschema(s)", ErrAllOfConstraintAdded, added)
}

return ao.checkRemoved(countNotFound(old, updated), ErrAllOfConstraintRemoved)
}

func (ao *AllOf) checkRemoved(count int, sentinel error) error {
if count > 0 && ao.RemovalPolicy != AllOfRemovalPolicyAllow {
return fmt.Errorf("%w : %d subschema(s)", sentinel, count)
}

return nil
}

func countNotFound(check, against []apiextensionsv1.JSONSchemaProps) int {
count := 0

for i := range check {
found := false

for j := range against {
if equality.Semantic.DeepEqual(&check[i], &against[j]) {
found = true
break
}
}

if !found {
count++
}
}

return count
}

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.

In a more recent PR similar to this one, I saw the use of a string form of the apiextensionsv1.JSONSchemaProps object pushed into a sets.Set object for both the old and new properties. From there they used the Difference() method on the sets to identify any missing values from either set to determine adds/removals.

I suspect a similar behavior could be implemented here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Refactored to use sets.Set[string] with Difference() for schema diffing, matching the approach in #64. Also added normalizeAllOfSchema to strip non-structural fields before comparison.

@saschagrunert
saschagrunert force-pushed the allof-validation branch 2 times, most recently from aa4f8d0 to 8e382c6 Compare May 27, 2026 06:59
@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 2, 2026
Add additionPolicy and removalPolicy config knobs for reader/writer
semantics. Use sets.Set for schema diffing instead of manual loops.

Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Property Validation: allOf

3 participants