Skip to content

Commit a03dee2

Browse files
authored
CLOUDP-306580: avoid mixed refs (#588)
1 parent f083270 commit a03dee2

File tree

4 files changed

+55
-71
lines changed

4 files changed

+55
-71
lines changed

tools/spectral/ipa/__tests__/IPA125OneOfNoBaseTypes.test.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ testRule('xgen-IPA-125-oneOf-no-base-types', [
7070
errors: [
7171
{
7272
code: 'xgen-IPA-125-oneOf-no-base-types',
73-
message: 'oneOf should not contain base types like integer, number, string, or boolean.',
73+
message: 'oneOf should not mix base types with references.',
7474
path: ['components', 'schemas', 'MixedType'],
7575
severity: DiagnosticSeverity.Warning,
7676
},
@@ -91,12 +91,29 @@ testRule('xgen-IPA-125-oneOf-no-base-types', [
9191
errors: [
9292
{
9393
code: 'xgen-IPA-125-oneOf-no-base-types',
94-
message: 'oneOf should not contain base types like integer, number, string, or boolean.',
94+
message: 'oneOf should not contain multiple different base types.',
9595
path: ['components', 'schemas', 'BaseTypes'],
9696
severity: DiagnosticSeverity.Warning,
9797
},
9898
],
9999
},
100+
{
101+
name: 'valid oneOf with same base type multiple times',
102+
document: {
103+
components: {
104+
schemas: {
105+
...componentSchemas,
106+
SameBaseType: {
107+
oneOf: [
108+
{ type: 'string', enum: ['one'] },
109+
{ type: 'string', enum: ['two'] },
110+
],
111+
},
112+
},
113+
},
114+
},
115+
errors: [],
116+
},
100117
{
101118
name: 'oneOf with exception',
102119
document: {

tools/spectral/ipa/rulesets/IPA-125.yaml

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -43,46 +43,21 @@ rules:
4343

4444
xgen-IPA-125-oneOf-no-base-types:
4545
description: |
46-
API producers should not use oneOf with base types like integer, string, boolean, or number.
46+
API producers should not use oneOf with different base types like integer, string, boolean, or number or references at the same time.
4747
4848
##### Implementation details
4949
Rule checks for the following conditions:
5050
- Applies to schemas with `oneOf` arrays
51-
- Ensures no element within oneOf has a type property that is a primitive/base type
51+
- Ensures no mixing of base types with references
52+
- Ensures no multiple different base types in the same oneOf
5253
- Base types considered are: integer, string, boolean, number
54+
- Using the same base type multiple times is allowed (e.g., multiple string enums)
5355
5456
##### Rationale
55-
Using oneOf with primitive types can lead to ambiguity and validation problems. Clients may not
57+
Using oneOf with multiple primitive types can lead to ambiguity and validation problems. Clients may not
5658
be able to properly determine which type to use in which context. Instead, use more specific
5759
object types with clear discriminators.
5860
59-
##### Example Violation
60-
```yaml
61-
# Incorrect - Using oneOf with base types
62-
type: object
63-
properties:
64-
value:
65-
oneOf:
66-
- type: string
67-
- type: integer
68-
```
69-
70-
##### Example Compliance
71-
```yaml
72-
# Correct - Using oneOf with object types only
73-
type: object
74-
properties:
75-
value:
76-
oneOf:
77-
- $ref: '#/components/schemas/StringValue'
78-
- $ref: '#/components/schemas/IntegerValue'
79-
discriminator:
80-
propertyName: valueType
81-
mapping:
82-
string: '#/components/schemas/StringValue'
83-
integer: '#/components/schemas/IntegerValue'
84-
```
85-
8661
message: '{{error}} https://mdb.link/mongodb-atlas-openapi-validation#xgen-IPA-125-oneOf-no-base-types'
8762
severity: warn
8863
given: '$.components.schemas[*]'

tools/spectral/ipa/rulesets/README.md

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -560,46 +560,21 @@ Rule checks for the following conditions:
560560
#### xgen-IPA-125-oneOf-no-base-types
561561
562562
![warn](https://img.shields.io/badge/warning-yellow)
563-
API producers should not use oneOf with base types like integer, string, boolean, or number.
563+
API producers should not use oneOf with different base types like integer, string, boolean, or number or references at the same time.
564564
565565
##### Implementation details
566566
Rule checks for the following conditions:
567567
- Applies to schemas with `oneOf` arrays
568-
- Ensures no element within oneOf has a type property that is a primitive/base type
568+
- Ensures no mixing of base types with references
569+
- Ensures no multiple different base types in the same oneOf
569570
- Base types considered are: integer, string, boolean, number
571+
- Using the same base type multiple times is allowed (e.g., multiple string enums)
570572

571573
##### Rationale
572-
Using oneOf with primitive types can lead to ambiguity and validation problems. Clients may not
574+
Using oneOf with multiple primitive types can lead to ambiguity and validation problems. Clients may not
573575
be able to properly determine which type to use in which context. Instead, use more specific
574576
object types with clear discriminators.
575577

576-
##### Example Violation
577-
```yaml
578-
# Incorrect - Using oneOf with base types
579-
type: object
580-
properties:
581-
value:
582-
oneOf:
583-
- type: string
584-
- type: integer
585-
```
586-
587-
##### Example Compliance
588-
```yaml
589-
# Correct - Using oneOf with object types only
590-
type: object
591-
properties:
592-
value:
593-
oneOf:
594-
- $ref: '#/components/schemas/StringValue'
595-
- $ref: '#/components/schemas/IntegerValue'
596-
discriminator:
597-
propertyName: valueType
598-
mapping:
599-
string: '#/components/schemas/StringValue'
600-
integer: '#/components/schemas/IntegerValue'
601-
```
602-
603578

604579

605580

tools/spectral/ipa/rulesets/functions/IPA125OneOfNoBaseTypes.js

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { resolveObject } from './utils/componentUtils.js';
33
import { hasException } from './utils/exceptions.js';
44

55
const RULE_NAME = 'xgen-IPA-125-oneOf-no-base-types';
6-
const ERROR_MESSAGE = 'oneOf should not contain base types like integer, number, string, or boolean.';
6+
const ERROR_MESSAGE_MIXED = 'oneOf should not mix base types with references.';
7+
const ERROR_MESSAGE_MULTIPLE = 'oneOf should not contain multiple different base types.';
78

89
export default (input, _, { path, documentInventory }) => {
910
if (!input.oneOf || !Array.isArray(input.oneOf)) {
@@ -22,14 +23,30 @@ export default (input, _, { path, documentInventory }) => {
2223
};
2324

2425
function checkViolationsAndReturnErrors(schema, path) {
25-
// Check if any oneOf item is a base type
26-
const baseTypes = ['integer', 'number', 'string', 'boolean'];
27-
const hasBaseType = schema.oneOf.some(
28-
(item) => typeof item === 'object' && item.type && baseTypes.includes(item.type)
29-
);
30-
31-
if (hasBaseType) {
32-
return [{ path, message: ERROR_MESSAGE }];
26+
const baseTypes = ['string', 'number', 'integer', 'boolean'];
27+
const foundBaseTypes = new Set();
28+
let hasRef = false;
29+
let hasBaseType = false;
30+
31+
// Check each oneOf item
32+
for (const item of schema.oneOf) {
33+
if (item.$ref) {
34+
hasRef = true;
35+
continue;
36+
}
37+
38+
if (item.type && baseTypes.includes(item.type)) {
39+
hasBaseType = true;
40+
foundBaseTypes.add(item.type);
41+
}
42+
}
43+
44+
if (hasRef && hasBaseType) {
45+
return [{ path, message: ERROR_MESSAGE_MIXED }];
46+
}
47+
48+
if (foundBaseTypes.size > 1) {
49+
return [{ path, message: ERROR_MESSAGE_MULTIPLE }];
3350
}
3451

3552
return [];

0 commit comments

Comments
 (0)