Skip to content

fix(openapi): support kin-openapi exclusive bounds - #7607

Closed
llebihan wants to merge 1 commit into
projectdiscovery:devfrom
LebtekOrg:upstream-kin-openapi-v0.145
Closed

fix(openapi): support kin-openapi exclusive bounds#7607
llebihan wants to merge 1 commit into
projectdiscovery:devfrom
LebtekOrg:upstream-kin-openapi-v0.145

Conversation

@llebihan

@llebihan llebihan commented Jul 26, 2026

Copy link
Copy Markdown

Proposed changes

Update kin-openapi to v0.145.0 and adapt OpenAPI example generation to its version-aware ExclusiveBound type. OpenAPI 3.0 boolean exclusive bounds retain their existing behavior, while OpenAPI 3.1 numeric exclusiveMinimum and exclusiveMaximum values are now used as the effective bounds. Impossible exclusive integer ranges return ErrNoExample.

Fixes #7606.

Proof

  • GOWORK=off go test ./pkg/input/formats/openapi -count=1
  • GOWORK=off go vet ./pkg/input/formats/openapi
  • Regression coverage includes OpenAPI 3.0 boolean minimum/maximum, OpenAPI 3.1 numeric minimum/maximum/range, and an empty exclusive integer range.

Checklist

  • Pull request is created against the dev branch
  • All repository checks passed; awaiting GitHub Actions
  • I have added tests that prove the fix is effective
  • Documentation is not required for this compatibility fix

Summary by CodeRabbit

  • Bug Fixes

    • Improved OpenAPI example generation for numeric and integer schemas with inclusive and exclusive boundaries.
    • Prevented invalid examples from being produced when exclusive integer ranges contain no valid values.
  • Tests

    • Added coverage for OpenAPI 3.0 and 3.1 exclusive-bound behavior.
    • Added validation for empty exclusive integer ranges.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Updates OpenAPI dependencies and refactors numeric example generation to support kin-openapi exclusive bounds, including OpenAPI 3.0 and 3.1 cases and impossible integer ranges.

Changes

OpenAPI example compatibility

Layer / File(s) Summary
Dependency and numeric dispatch
go.mod, pkg/input/formats/openapi/examples.go
OpenAPI-related dependencies are updated, and numeric or integer schemas delegate example generation to numericExample.
Exclusive-bound example calculation
pkg/input/formats/openapi/examples.go, pkg/input/formats/openapi/examples_test.go
Numeric examples account for exclusive bounds and integer boundaries, validate generated values, and return ErrNoExample for empty ranges; tests cover OpenAPI 3.0, 3.1, and invalid integer ranges.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: dwisiswant0

Poem

I’m a rabbit with numbers to spare,
Finding examples that fit every pair.
Exclusive bounds hop into view,
Integer gaps get rejected too.
Kin-openapi burrows compile—
Tests twitch their noses in style!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: OpenAPI example support for kin-openapi exclusive bounds.
Linked Issues check ✅ Passed The changes update kin-openapi, handle boolean and numeric exclusive bounds, and add regression tests for the requested cases.
Out of Scope Changes check ✅ Passed The dependency updates appear tied to the kin-openapi upgrade, with no clearly unrelated code changes shown.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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: 1

🧹 Nitpick comments (1)
pkg/input/formats/openapi/examples_test.go (1)

11-53: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Good coverage for the documented scenarios; consider adding a narrow-range case.

These cases correctly validate boolean (3.0) and numeric (3.1) exclusive bounds. Consider adding a case like Min=0 (exclusive) + Max=1 (inclusive) for an integer schema — this narrow range currently trips up the midpoint-selection logic in numericExample (see comment on examples.go), so it would make a useful regression test once that's fixed.

🤖 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 `@pkg/input/formats/openapi/examples_test.go` around lines 11 - 53, The
existing exclusive-bound test table lacks coverage for a narrow integer range.
Add a regression case to TestOpenAPIExampleExclusiveBounds using an exclusive
minimum of 0 and inclusive maximum of 1, and assert the valid generated example
is 1; keep the case focused on the numericExample midpoint-selection behavior.
🤖 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 `@pkg/input/formats/openapi/examples.go`:
- Around line 277-300: Update the midpoint handling in the example-generation
logic, including the branches for belowMinimum with maximum and aboveMaximum
with minimum, so integer candidates respect exclusive bounds and narrow ranges
return a valid boundary value when the midpoint truncates onto an excluded
boundary. Prefer the boundary-adjusted candidate and use the midpoint only when
it satisfies all bounds; add regression coverage in examples_test.go for both
asymmetric narrow exclusive-integer cases.

---

Nitpick comments:
In `@pkg/input/formats/openapi/examples_test.go`:
- Around line 11-53: The existing exclusive-bound test table lacks coverage for
a narrow integer range. Add a regression case to
TestOpenAPIExampleExclusiveBounds using an exclusive minimum of 0 and inclusive
maximum of 1, and assert the valid generated example is 1; keep the case focused
on the numericExample midpoint-selection behavior.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d5477e45-5754-446d-adf2-18b552f2445f

📥 Commits

Reviewing files that changed from the base of the PR and between 6ecdb94 and 071783c.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (3)
  • go.mod
  • pkg/input/formats/openapi/examples.go
  • pkg/input/formats/openapi/examples_test.go

Comment on lines +277 to +300
switch {
case belowMinimum && maximum != nil:
value = (*minimum + *maximum) / 2.0
case belowMinimum:
value = *minimum
if minimumExclusive {
if schema.Type.Is("integer") {
value = math.Floor(value) + 1
} else {
value = math.Nextafter(value, math.Inf(1))
}
}
case aboveMaximum && minimum != nil:
value = (*minimum + *maximum) / 2.0
case aboveMaximum:
value = *maximum
if maximumExclusive {
if schema.Type.Is("integer") {
value = math.Ceil(value) - 1
} else {
value = math.Nextafter(value, math.Inf(-1))
}
}
}

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 | 🟠 Major | ⚡ Quick win

Midpoint branches mis-handle narrow exclusive integer ranges — valid schemas incorrectly return ErrNoExample.

For schema.Type=integer, Min=0 with exclusive minimum, Max=1 (inclusive) — i.e. {"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":1} — the only valid value is 1, but the current logic returns ErrNoExample:

  • belowMinimum && maximum != nilvalue = (0+1)/2 = 0.5
  • math.Trunc(0.5)0
  • Final check: minimumExclusive && 0 <= 0ErrNoExample

The same defect is symmetric for aboveMaximum && minimum != nil (e.g. minimum=-2, exclusiveMaximum at -1, integer — valid answer -2 is also rejected). Unlike the boundary-only branches (belowMinimum, aboveMaximum), the midpoint branches never apply the Floor+1/Ceil-1 integer-exclusivity adjustment, nor do they fall back if the midpoint truncates onto an excluded boundary. This directly undermines the exclusive-bound support this PR is meant to add, and isn't covered by the added tests (which all use ranges wide enough that the midpoint truncation happens to land safely inside the bounds).

🐛 Proposed fix: try the boundary-adjusted candidate first, fall back to midpoint only if it doesn't fit
 	switch {
 	case belowMinimum && maximum != nil:
-		value = (*minimum + *maximum) / 2.0
+		value = *minimum
+		if minimumExclusive {
+			if schema.Type.Is("integer") {
+				value = math.Floor(value) + 1
+			} else {
+				value = math.Nextafter(value, math.Inf(1))
+			}
+		}
+		if value > *maximum || (maximumExclusive && value >= *maximum) {
+			value = (*minimum + *maximum) / 2.0
+		}
 	case belowMinimum:
 		value = *minimum
 		if minimumExclusive {
 			if schema.Type.Is("integer") {
 				value = math.Floor(value) + 1
 			} else {
 				value = math.Nextafter(value, math.Inf(1))
 			}
 		}
 	case aboveMaximum && minimum != nil:
-		value = (*minimum + *maximum) / 2.0
+		value = *maximum
+		if maximumExclusive {
+			if schema.Type.Is("integer") {
+				value = math.Ceil(value) - 1
+			} else {
+				value = math.Nextafter(value, math.Inf(-1))
+			}
+		}
+		if value < *minimum || (minimumExclusive && value <= *minimum) {
+			value = (*minimum + *maximum) / 2.0
+		}
 	case aboveMaximum:
 		value = *maximum
 		if maximumExclusive {
 			if schema.Type.Is("integer") {
 				value = math.Ceil(value) - 1
 			} else {
 				value = math.Nextafter(value, math.Inf(-1))
 			}
 		}
 	}

Please also add a regression test for this narrow-range case in examples_test.go once fixed.

📝 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
switch {
case belowMinimum && maximum != nil:
value = (*minimum + *maximum) / 2.0
case belowMinimum:
value = *minimum
if minimumExclusive {
if schema.Type.Is("integer") {
value = math.Floor(value) + 1
} else {
value = math.Nextafter(value, math.Inf(1))
}
}
case aboveMaximum && minimum != nil:
value = (*minimum + *maximum) / 2.0
case aboveMaximum:
value = *maximum
if maximumExclusive {
if schema.Type.Is("integer") {
value = math.Ceil(value) - 1
} else {
value = math.Nextafter(value, math.Inf(-1))
}
}
}
switch {
case belowMinimum && maximum != nil:
value = *minimum
if minimumExclusive {
if schema.Type.Is("integer") {
value = math.Floor(value) + 1
} else {
value = math.Nextafter(value, math.Inf(1))
}
}
if value > *maximum || (maximumExclusive && value >= *maximum) {
value = (*minimum + *maximum) / 2.0
}
case belowMinimum:
value = *minimum
if minimumExclusive {
if schema.Type.Is("integer") {
value = math.Floor(value) + 1
} else {
value = math.Nextafter(value, math.Inf(1))
}
}
case aboveMaximum && minimum != nil:
value = *maximum
if maximumExclusive {
if schema.Type.Is("integer") {
value = math.Ceil(value) - 1
} else {
value = math.Nextafter(value, math.Inf(-1))
}
}
if value < *minimum || (minimumExclusive && value <= *minimum) {
value = (*minimum + *maximum) / 2.0
}
case aboveMaximum:
value = *maximum
if maximumExclusive {
if schema.Type.Is("integer") {
value = math.Ceil(value) - 1
} else {
value = math.Nextafter(value, math.Inf(-1))
}
}
}
🤖 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 `@pkg/input/formats/openapi/examples.go` around lines 277 - 300, Update the
midpoint handling in the example-generation logic, including the branches for
belowMinimum with maximum and aboveMaximum with minimum, so integer candidates
respect exclusive bounds and narrow ranges return a valid boundary value when
the midpoint truncates onto an excluded boundary. Prefer the boundary-adjusted
candidate and use the midpoint only when it satisfies all bounds; add regression
coverage in examples_test.go for both asymmetric narrow exclusive-integer cases.

@dwisiswant0

Copy link
Copy Markdown
Member

Superseded by #7609.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenAPI example generation does not compile with kin-openapi v0.145

2 participants