Skip to content

Support Validation of union types#423

Open
steiler wants to merge 6 commits into
mainfrom
supportunion
Open

Support Validation of union types#423
steiler wants to merge 6 commits into
mainfrom
supportunion

Conversation

@steiler
Copy link
Copy Markdown
Collaborator

@steiler steiler commented May 4, 2026

This PR fixes validation gaps for YANG leaves defined as union types.

Today, union branch selection happens at import time (XML/JSON/proto): the server tries branches in order and stores the first successfully parsed TypedValue. Later, validation runs against the outer union schema type instead of the specific matched branch type. Because the outer union type does not carry branch-specific constraints, several validators can no-op unexpectedly.

Problem
For union-typed leaves, the current validation path can miss real violations:

Pattern and length checks read constraints from the outer union type, which has none.
Range checks read constraints from the outer union type, which has none.
Leafref checks look for a leafref path on the outer union type, which is empty.
This means values that actually matched a leafref branch can bypass live-tree reference validation, allowing dangling references to pass undetected.

@steiler steiler linked an issue May 4, 2026 that may be closed by this pull request
steiler added a commit that referenced this pull request May 21, 2026
InferUnionMemberFromTypedValue narrows unions from wire TypedValues (lexical
re-parse + structural fallback); proto and XML importers and leaf defaults
attach the matched branch so validation and EffectiveLeafType align. Adds
ingress/parity tests and schema fixtures; drops the PR #423 supplement note.
steiler and others added 5 commits June 3, 2026 10:36
This PR fixes validation gaps for YANG leaves defined as union types.

Today, union branch selection happens at import time (XML/JSON/proto): the server tries branches in order and stores the first successfully parsed TypedValue. Later, validation runs against the outer union schema type instead of the specific matched branch type. Because the outer union type does not carry branch-specific constraints, several validators can no-op unexpectedly.

Problem
For union-typed leaves, the current validation path can miss real violations:

Pattern and length checks read constraints from the outer union type, which has none.
Range checks read constraints from the outer union type, which has none.
Leafref checks look for a leafref path on the outer union type, which is empty.
This means values that actually matched a leafref branch can bypass live-tree reference validation, allowing dangling references to pass undetected.
Co-authored-by: Copilot <copilot@github.com>
Apply EffectiveLeafType in navigateLeafRef so FollowLeafRef matches
validateLeafRefs for union+leafref leaves. Document leaf-list union
range limitation. Add optional-instance union leafref tests, internal
navigateLeafRef/FollowLeafRef test, and Update Equal/String coverage.
Regenerate sdcio ygot for unionoptionalleafreftest.

Refs: #177
Co-authored-by: Cursor <cursoragent@cursor.com>
InferUnionMemberFromTypedValue narrows unions from wire TypedValues (lexical
re-parse + structural fallback); proto and XML importers and leaf defaults
attach the matched branch so validation and EffectiveLeafType align. Adds
ingress/parity tests and schema fixtures; drops the PR #423 supplement note.
…ion/importer

- xml_tree_importer: remove redundant InferUnionMemberFromTypedValue call;
  TVFromStringWithType already recurses union branches and returns the matched
  branch-level SchemaLeafType directly
- converter: make JSON and string-val processing paths mutually exclusive (else-if)
  so a union field whose matched branch is a string type no longer loses its
  MatchedUnionType on the way out
- inferUnionStructuralUnique: early-return on first match instead of collecting
  a never-used slice (RFC 7950 §9.12 first-match semantics made explicit)
- validation: extract effectiveFieldType and resolveLeafref helpers replacing
  5 copy-pasted GetHighestPrecedence+EffectiveLeafType idioms; navigateLeafRefByPath
  now accepts the already-fetched LeafEntry instead of re-fetching it
- Update: add MatchedType() accessor; CopyWithNewOwnerAndPrio uses it instead of
  direct unexported field access and drops the redundant nil guard
- converter: expandedNoUnion() constructor replaces 9 verbose struct literals,
  making Phase-1 union deferrals explicit

Co-authored-by: Cursor <cursoragent@cursor.com>
@steiler steiler marked this pull request as ready for review June 3, 2026 08:52
@steiler steiler requested a review from a team as a code owner June 3, 2026 08:52
@steiler steiler requested a review from Copilot June 3, 2026 08:53
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR closes validation gaps for YANG union-typed leaves by carrying the resolved union member type alongside the parsed TypedValue, and updating validators to enforce member-specific constraints (pattern/length/range/leafref) across JSON/XML/proto/default/defaults/intent-expansion ingress paths.

Changes:

  • Add union-member attribution plumbing (MatchedUnionType / EffectiveLeafType) from import/conversion through tree updates.
  • Update validators to validate against the effective (matched) leaf type rather than the outer union type, plus add broad parity/regression tests.
  • Extend the test YANG model with union leaves and pin sdc-protos to a commit containing new union helper APIs.

Reviewed changes

Copilot reviewed 38 out of 39 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/schema/sdcio_model.yang Adds union-typed leaves covering pattern/length/range/leafref scenarios.
pkg/utils/testhelper/testhelpers.go Adapts helper to new converter expansion return type.
pkg/utils/converter.go Introduces ExpandedUpdate with matched union member metadata during expansion.
pkg/utils/converter_test.go Adds unit tests for matched union member propagation in converter expansion.
pkg/tree/types/update.go Stores matched union member type on types.Update and uses it in intent expansion.
pkg/tree/types/update_test.go Adds tests for EffectiveLeafType / matched type behavior and copying/equality.
pkg/tree/types/update_slice.go Preserves matched union member type when copying updates across owners/priorities.
pkg/tree/types/update_slice_test.go Tests matched-type preservation during UpdateSlice copy.
pkg/tree/processors/processor_importer.go Captures matched union member type from import adapters on leaf updates.
pkg/tree/ops/validation/validation_union_xml_json_parity_test.go Adds JSON vs canonical XML re-import parity coverage for unions.
pkg/tree/ops/validation/validation_union_range_test.go Adds union range validation coverage.
pkg/tree/ops/validation/validation_union_proto_roundtrip_test.go Adds proto round-trip parity tests for union validation outcomes.
pkg/tree/ops/validation/validation_union_leafref_test.go Adds union leafref validation coverage.
pkg/tree/ops/validation/validation_union_leafref_optional_test.go Adds optional-instance union leafref warning/error behavior coverage.
pkg/tree/ops/validation/validation_test_helpers_test.go Adds shared import helpers for union validation test matrix.
pkg/tree/ops/validation/validation_intent_expand_union_test.go Adds structured import vs intent-expand parity tests for union validation.
pkg/tree/ops/validation/validation_expand_union_ingress_matrix_test.go Adds a broader ingress matrix across constraint families and owners.
pkg/tree/ops/validation/validation_entry_range.go Uses effective (matched) type for leaf range validation.
pkg/tree/ops/validation/validation_entry_pattern.go Uses effective (matched) type for pattern validation.
pkg/tree/ops/validation/validation_entry_pattern_test.go Adds pattern validation tests including union branches.
pkg/tree/ops/validation/validation_entry_length.go Uses effective (matched) type for length validation.
pkg/tree/ops/validation/validation_entry_length_test.go Adds length validation tests including union branches.
pkg/tree/ops/validation/validation_entry_leafref.go Resolves leafref paths via effective (matched) type for union leafref branches.
pkg/tree/ops/validation/validation_dispatch.go Adds shared helpers (effectiveFieldType, resolveLeafref) for validators.
pkg/tree/ops/validation/navigate_leafref_union_internal_test.go Ensures internal leafref navigation works for union-matched leafref branches.
pkg/tree/ops/default_value.go Parses union defaults with matched-member attribution for later validation.
pkg/tree/ops/default_value_test.go Adds test ensuring union default values attach matched member type.
pkg/tree/importer/xml/xml_tree_importer.go Returns matched union member type from XML parsing (TVFromStringWithType).
pkg/tree/importer/xml/xml_tree_importer_test.go Tests matched-type selection, including RFC first-member behavior.
pkg/tree/importer/union_member.go Adds union-member inference for proto-imported TypedValues.
pkg/tree/importer/union_member_test.go Tests union-member inference RFC first-member selection behavior.
pkg/tree/importer/proto/proto_tree_importer.go Infers and returns matched union member type on proto import.
pkg/tree/importer/proto/proto_tree_importer_test.go Adds proto importer matched-type inference test.
pkg/tree/importer/json/json_tree_importer.go Returns matched union member type from JSON conversion.
pkg/tree/importer/json/json_tree_importer_test.go Extends JSON importer tests to assert matched-type behavior for union.
pkg/tree/importer/import_config_adapter.go Extends adapter contract to return matched union member type.
go.mod Adds replace pin for sdc-protos to get union helper APIs.
go.sum Updates sums for the pinned sdc-protos version.
Comments suppressed due to low confidence (1)

pkg/tree/ops/validation/validation_entry_length.go:29

  • Length constraints with multiple allowed intervals should pass if the value is within any interval. The current loop reports an error for every interval that doesn’t match, and can even fail when a later interval matches (e.g. length "1..3 | 10..12"). Consider checking all intervals first and emitting a single error only if none match.
		for _, lengthDef := range effectiveType.GetLength() {

			if lengthDef.Min.Value <= uint64(actualLength) && uint64(actualLength) <= lengthDef.Max.Value {
				// continue if the length is within the range
				continue

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/tree/importer/import_config_adapter.go Outdated
Comment thread go.mod
Comment on lines +7 to +9
// sdc-protos PR #115 (TypedValue union helpers). Remove this replace after the next sdc-protos release that includes it.
// https://github.com/sdcio/sdc-protos/pull/115
replace github.com/sdcio/sdc-protos => github.com/sdcio/sdc-protos v0.0.52-0.20260504101706-192d1e8e12bf
Comment thread pkg/tree/ops/validation/validation_entry_length_test.go
Comment thread pkg/tree/ops/default_value_test.go Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 3, 2026

Codecov Report

❌ Patch coverage is 47.20812% with 104 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pkg/tree/importer/union_member.go 16.17% 54 Missing and 3 partials ⚠️
pkg/utils/converter.go 31.42% 24 Missing ⚠️
pkg/utils/testhelper/testhelpers.go 0.00% 7 Missing ⚠️
pkg/tree/ops/validation/validation_dispatch.go 60.00% 3 Missing and 3 partials ⚠️
pkg/tree/types/update.go 75.00% 5 Missing ⚠️
...kg/tree/ops/validation/validation_entry_leafref.go 71.42% 2 Missing and 2 partials ⚠️
pkg/tree/importer/proto/proto_tree_importer.go 80.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Validation - Union Types are not taken into account yet

2 participants