Skip to content

fix: no-required-schema-properties rule to report when required properties are not defined in all branches#2705

Merged
tatomyr merged 5 commits intomainfrom
fix/no-required-schema-properties-undefined
Apr 6, 2026
Merged

fix: no-required-schema-properties rule to report when required properties are not defined in all branches#2705
tatomyr merged 5 commits intomainfrom
fix/no-required-schema-properties-undefined

Conversation

@tatomyr
Copy link
Copy Markdown
Collaborator

@tatomyr tatomyr commented Mar 31, 2026

What/Why/How?

  • Fixed the no-required-schema-properties-undefined rule to report when a required property is not defined in every oneOf/anyOf branch.
  • Refactored the no-required-schema-properties rule code to avoid the 'grandparents' concept
  • Refactored tests: make the descriptions clearer and removed duplications.

Discovered internally.

Check yourself

  • Code changed? - Tested with Redoc/Realm/Reunite (internal)
  • All new/updated code is covered by tests
  • New package installed? - Tested in different environments (browser/node)
  • Documentation update considered

Security

  • The security impact of the change has been considered
  • Code follows company security practices and guidelines

Note

Medium Risk
Updates a core lint rule’s schema-walking logic, which may change reported violations (and potentially introduce false positives/negatives) across OpenAPI/AsyncAPI/Arazzo documents.

Overview
Fixes no-required-schema-properties-undefined so a required property must be present in every anyOf/oneOf branch (while still honoring allOf and $ref chains), using a new hasProperty traversal with cycle protection and a simplified composition-root lookup.

Updates and expands the test suite to cover the new branch-aware behavior, $ref/allOf nesting cases, and adjusts diagnostics (message text from "is undefined" to "is not defined") and expectations accordingly.

Reviewed by Cursor Bugbot for commit 9548252. Bugbot is set up for automated code reviews on this repo. Configure here.

@tatomyr tatomyr self-assigned this Mar 31, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 31, 2026

🦋 Changeset detected

Latest commit: 9548252

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@redocly/openapi-core Patch
@redocly/cli Patch
@redocly/respect-core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 31, 2026

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 79.92% (🎯 79%) 6685 / 8364
🔵 Statements 79.35% (🎯 79%) 6916 / 8715
🔵 Functions 83.12% (🎯 82%) 1355 / 1630
🔵 Branches 71.61% (🎯 71%) 4546 / 6348
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/core/src/rules/common/no-required-schema-properties-undefined.ts 97.29% 96.96% 100% 96.87% 59
Generated in workflow #9292 for commit 9548252 by the Vitest Coverage Report Action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 31, 2026

CLI Version Mean Time ± Std Dev (s) Relative Performance (Lower is Faster)
cli-latest 3.545s ± 0.048s ▓ 1.00x (Fastest)
cli-next 3.575s ± 0.048s ▓ 1.01x

});

it('should NOT report if one or more of the required properties are defined when used in schema with anyOf keyword', async () => {
it('should report when required properties are not declared in all anyOf branches', async () => {
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.

This is the actual test case added.

`);
});

it('should not report required properties are present after resolving $refs when used in schema with allOf keyword', async () => {
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.

Removed as duplicated.

return {};
}
visitedSchemas.add(schema);
const hasProperty = (
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.

Refactored similarly to the spec-discriminator-defaultMapping rule.

@tatomyr tatomyr marked this pull request as ready for review March 31, 2026 07:50
@tatomyr tatomyr requested review from a team as code owners March 31, 2026 07:50
return {};
}
return elevateProperties(resolved.node, resolved.location?.source.absoluteRef);
if (
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.

Maybe we could make it more readable, like

const { schema, location } = resolved;

const hasDirectProperty =
  schema.properties &&
  getOwn(schema.properties, propertyName) !== undefined;

const checkSome = (schemas?: any[]) =>
  schemas?.some((s) => hasProperty(s, propertyName, visited, location));

const checkEvery = (schemas?: any[]) =>
  schemas?.every((s) => hasProperty(s, propertyName, visited, location));

if (
  hasDirectProperty ||
  checkSome(schema.allOf) ||
  checkEvery(schema.anyOf) ||
  checkEvery(schema.oneOf)
) {
  return true;
}

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.

or similar.

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.

The point was to eagerly return once we've found the required property, but you're right--it might be not the most readable solution. I'll give it another try.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Shared visited set causes false positives across branches
    • The bug was real and was fixed by cloning the visited set for each anyOf/oneOf branch so shared references no longer poison sibling branch checks.

Create PR

Or push these changes by commenting:

@cursor push 94022a32f7
Preview (94022a32f7)
diff --git a/packages/core/src/rules/common/__tests__/no-required-schema-properties-undefined.test.ts b/packages/core/src/rules/common/__tests__/no-required-schema-properties-undefined.test.ts
--- a/packages/core/src/rules/common/__tests__/no-required-schema-properties-undefined.test.ts
+++ b/packages/core/src/rules/common/__tests__/no-required-schema-properties-undefined.test.ts
@@ -610,6 +610,51 @@
     expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
   });
 
+  it('should NOT report when all anyOf branches share the same referenced property definition', async () => {
+    const document = parseYamlToDocument(
+      outdent`
+          openapi: 3.0.0
+          components:
+            schemas:
+              Base:
+                type: object
+                properties:
+                  name:
+                    type: string
+              BranchA:
+                allOf:
+                  - $ref: '#/components/schemas/Base'
+                  - type: object
+                    properties:
+                      huntingSkill:
+                        type: string
+              BranchB:
+                allOf:
+                  - $ref: '#/components/schemas/Base'
+                  - type: object
+                    properties:
+                      curiosityLevel:
+                        type: number
+              Cat:
+                type: object
+                anyOf:
+                  - $ref: '#/components/schemas/BranchA'
+                  - $ref: '#/components/schemas/BranchB'
+                required:
+                  - name
+        `,
+      'foobar.yaml'
+    );
+
+    const results = await lintDocument({
+      externalRefResolver: new BaseResolver(),
+      document,
+      config: await createConfig({ rules: { 'no-required-schema-properties-undefined': 'error' } }),
+    });
+
+    expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`[]`);
+  });
+
   it('should report when required properties are not declared in all anyOf branches', async () => {
     const document = parseYamlToDocument(
       outdent`

diff --git a/packages/core/src/rules/common/no-required-schema-properties-undefined.ts b/packages/core/src/rules/common/no-required-schema-properties-undefined.ts
--- a/packages/core/src/rules/common/no-required-schema-properties-undefined.ts
+++ b/packages/core/src/rules/common/no-required-schema-properties-undefined.ts
@@ -44,10 +44,12 @@
           }
 
           const check = (s: AnySchema) => hasProperty(s, propertyName, visited, resolved.location);
+          const checkEvery = (s: AnySchema) =>
+            hasProperty(s, propertyName, new Set(visited), resolved.location);
 
           if (resolved.schema.allOf?.some(check)) return true;
-          if (resolved.schema.anyOf?.every(check)) return true;
-          if (resolved.schema.oneOf?.every(check)) return true;
+          if (resolved.schema.anyOf?.every(checkEvery)) return true;
+          if (resolved.schema.oneOf?.every(checkEvery)) return true;
 
           return false;
         };

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 70ce84a. Configure here.

@tatomyr tatomyr force-pushed the fix/no-required-schema-properties-undefined branch from 70ce84a to a52fa53 Compare April 6, 2026 09:13
@tatomyr tatomyr requested a review from DmitryAnansky April 6, 2026 09:45
@tatomyr tatomyr merged commit b849ef5 into main Apr 6, 2026
45 checks passed
@tatomyr tatomyr deleted the fix/no-required-schema-properties-undefined branch April 6, 2026 12:24
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.

3 participants