You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: tools/spectral/CONTRIBUTING.md
+1-306Lines changed: 1 addition & 306 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,309 +16,4 @@ When adding new rules or updating the `.spectral.yaml` file, the validations wil
16
16
3. Review and merge the PR.
17
17
---
18
18
## IPA Rule Development
19
-
20
-
The rule validations are custom JS functions (see [/rulesets/functions](https://github.com/mongodb/openapi/tree/main/tools/spectral/ipa/rulesets/functions)). To learn more about custom functions, refer to the [Spectral Documentation](https://docs.stoplight.io/docs/spectral/a781e290eb9f9-custom-functions).
21
-
22
-
The custom rule implementation allows for:
23
-
24
-
- Advanced validations not available using the standard Spectral rules
25
-
- Custom exception handling
26
-
- Metrics collection
27
-
28
-
### Exceptions
29
-
30
-
Instead of using the [Spectral overrides approach](https://docs.stoplight.io/docs/spectral/293426e270fac-overrides), we use [custom OAS extensions](https://swagger.io/docs/specification/v3_0/openapi-extensions/) to handle exceptions to IPA validation rules. Exception extensions are added to the component which should be exempted, with the Spectral rule name and a reason.
31
-
32
-
```
33
-
"x-xgen-IPA-exception": {
34
-
"xgen-IPA-104-resource-has-GET": "Legacy API, not used by infrastructure-as-code tooling",
35
-
}
36
-
```
37
-
---
38
-
## Testing
39
-
40
-
- IPA Validation related code is tested using [Jest](https://jestjs.io/)
41
-
- Each custom validation function has tests, located in [/\_\_tests\_\_](https://github.com/mongodb/openapi/tree/main/tools/spectral/ipa/__tests__). They use the test hook [testRule.js](https://github.com/mongodb/openapi/blob/main/tools/spectral/ipa/__tests__/__helpers__/testRule.js) as a common approach for Spectral rule testing
42
-
- Helper/util functions are tested as well, see [/\_\_tests\_\_/utils](https://github.com/mongodb/openapi/tree/main/tools/spectral/ipa/__tests__/utils)
43
-
44
-
Install necessary dependencies with `npm install` if you haven't already. All Jest tests can be run with:
45
-
46
-
```
47
-
npm run test
48
-
```
49
-
50
-
To run a single test, in this case `singletonHasNoId.test.js`:
51
-
52
-
```
53
-
npm run test -- singletonHasNoId
54
-
```
55
-
---
56
-
57
-
## Code Style
58
-
59
-
- Use [Prettier](https://prettier.io/) for code formatting
60
-
61
-
```
62
-
npx prettier . --write
63
-
```
64
-
65
-
-[ESLint](https://eslint.org/) is being used for linting
66
-
---
67
-
68
-
## Pull Request Checklist
69
-
70
-
-[ ] Ensure that code builds and CI tests pass
71
-
-[ ] Add or update unit tests as needed
72
-
-[ ] Update documentation (if applicable)
73
-
74
-
```
75
-
npm run gen-ipa-docs
76
-
```
77
-
78
-
-[ ] Reference related issues (e.g., Closes #123)
79
-
---
80
-
## Getting Started with IPA Rule Development
81
-
82
-
#### Custom Rule Function Signature
83
-
84
-
Spectral custom rule functions follow this format:
-`input`: The current component from the OpenAPI spec. Derived from the given and field values in the rule definition.
90
-
-`path`: JSONPath array to the current component.
91
-
-`documentInventory`: The entire OpenAPI specification (use `resolved` or `unresolved` depending on rule context).
92
-
93
-
---
94
-
95
-
### Resource & Singleton Evaluation
96
-
97
-
In IPA Spectral validation, a **resource** is typically identified using a *resource collection path*, such as `/resource`.
98
-
99
-
To develop rules that evaluate resource and singleton patterns, you can use the following utility functions:
100
-
101
-
#### Retrieve Resource Path Items
102
-
103
-
Use [`getResourcePathItems`](https://github.com/mongodb/openapi/blob/99823b3dfd315f892c5f64f1db50f2124261929c/tools/spectral/ipa/rulesets/functions/utils/resourceEvaluation.js#L143) to retrieve all relevant path objects for a given resource:
104
-
105
-
- Returns path objects for:
106
-
- Resource collection path: `/resource`
107
-
- Single resource path: `/resource/{someId}`
108
-
- Custom method paths:
109
-
-`/resource/{someId}:customMethod`
110
-
-`/resource:customMethod`
111
-
112
-
#### Determine if Resource is a Singleton
113
-
114
-
Use [`isSingletonResource`](https://github.com/mongodb/openapi/blob/99823b3dfd315f892c5f64f1db50f2124261929c/tools/spectral/ipa/rulesets/functions/utils/resourceEvaluation.js#L71) to check if the resource behaves as a singleton. Pass the object returned by `getResourcePathItems`.
115
-
116
-
#### Identify Resource Collection or Single Resource Paths
117
-
118
-
Use the following helpers to check the type of a path:
119
-
120
-
-[`isResourceCollectionIdentifier`](https://github.com/mongodb/openapi/blob/99823b3dfd315f892c5f64f1db50f2124261929c/tools/spectral/ipa/rulesets/functions/utils/resourceEvaluation.js#L13): Determines if a path represents a resource collection (e.g., `/resource`).
121
-
-[`isSingleResourceIdentifier`](https://github.com/mongodb/openapi/blob/99823b3dfd315f892c5f64f1db50f2124261929c/tools/spectral/ipa/rulesets/functions/utils/resourceEvaluation.js#L31): Determines if a path represents a single resource (e.g., `/resource/{someId}`).
122
-
123
-
> **Note:** Paths such as `/resource/resource` or `/resource/{id}/{id}` are not recognized as valid resource or single resource identifiers using `isResourceCollectionIdentifier` or `isSingleResourceIdentifier`.
124
-
125
-
### Collecting Adoption, Violation, or Exception
126
-
127
-
#### Rule Design Guidance
128
-
129
-
As a rule developer, you need to define:
130
-
131
-
- What qualifies as a **violation**?
132
-
- What qualifies as an **adoption**?
133
-
- When should an **exception** be collected?
134
-
135
-
---
136
-
#### Helper Functions
137
-
138
-
Use the following helper functions from the `collectionUtils` module:
139
-
140
-
-[`collectAndReturnViolation(jsonPath, ruleName, errorData)`](https://github.com/mongodb/openapi/blob/cd4e085a68cb3bb6078e85dba85ad8ce1674f7da/tools/spectral/ipa/rulesets/functions/utils/collectionUtils.js#L14) — for reporting rule violations.
141
-
-[`collectAdoption(jsonPath, ruleName)`](https://github.com/mongodb/openapi/blob/cd4e085a68cb3bb6078e85dba85ad8ce1674f7da/tools/spectral/ipa/rulesets/functions/utils/collectionUtils.js#L32) — for marking rule adoption.
142
-
-[`collectException(object, ruleName, jsonPath)`](https://github.com/mongodb/openapi/blob/cd4e085a68cb3bb6078e85dba85ad8ce1674f7da/tools/spectral/ipa/rulesets/functions/utils/collectionUtils.js#L32) — for recording rule exceptions.
143
-
---
144
-
145
-
#### How to Decide the component level at which the rule will be processed
146
-
147
-
##### Collect the Exemption
148
-
149
-
When designing a rule, it is important to decide at which component level the rule exemption can be defined. It will also define the component level the adoption and violation will be collected.
150
-
151
-
**Decision Process**:
152
-
153
-
1. Identify where the component is defined in the OpenAPI specification. For instance, `enum` values are typically defined under the `schema` level in the OpenAPI spec.
154
-
155
-
**Example OpenAPI Spec**:
156
-
```yaml
157
-
"schemaName": {
158
-
"type": "string",
159
-
"enum": [
160
-
"ABC_ENUM",
161
-
"DEF_ENUM"
162
-
]
163
-
}
164
-
```
165
-
2. Determine the component level for the rule exemption. In this case, it would be `schemaName` in the OpenAPI spec.
3. In the rule implementation, use the `collectException(object, ruleName, jsonPath)` helper function to collect exceptions. The object here is what you get when you traverse the path defined by the `jsonPath`.
178
-
179
-
Exceptions can be defined at different levels, such as:
180
-
- Resource level
181
-
- Path level
182
-
- Operation (HTTP method) level
183
-
- Parameter level
184
-
- Response level
185
-
- Request body level
186
-
- Schema level
187
-
- Schema property level
188
-
- Tag level
189
-
190
-
##### Rule Design
191
-
Once you have decided on the component for which you want to collect exemptions, you can proceed with the rule design.
192
-
193
-
Each rule must specify the `given` and `then` fields, which define how the rule will traverse and evaluate the OpenAPI document. These fields should be determined based on the chosen component, ensuring that the rule is applied correctly to the relevant part of the specification.
194
-
195
-
**Case 1**: The rule evaluates an object as a whole
196
-
197
-
- If the given parameter targets a specific object (e.g., HTTP methods like get, post, etc.), and we want to pass that object in its entirety to the rule function:
198
-
- The rule function parameters will be:
199
-
-`input`: The object for the current `<pathKey>` the rule is processing
200
-
-`path`: `[‘paths’, ‘<pathKey>’, ‘get’]`
201
-
202
-
```yaml
203
-
xgen-IPA-xxx-rule-name:
204
-
description: "Rule description"
205
-
message: "{{error}} http:://go/ipa/x"
206
-
severity: warn
207
-
given: '$.paths[*].get'
208
-
then:
209
-
function: "customRuleFunction"
210
-
```
211
-
212
-
**Case 2**: The rule evaluates keys of an object
213
-
214
-
If the given parameter refers to an object, and we want to iterate through its keys (e.g., top-level API paths), use `@key` to pass each key (string) as the input.
215
-
216
-
- `input`: API endpoint path string such as `/api/atlas/v2/groups`
217
-
- `path`: `[‘paths’, ‘/api/atlas/v2/groups’]`
218
-
219
-
```yaml
220
-
xgen-IPA-xxx-rule-name:
221
-
description: "Rule description"
222
-
message: "{{error}} http:://go/ipa/x"
223
-
severity: warn
224
-
given: '$.paths'
225
-
then:
226
-
field: @key
227
-
function: "customRuleFunction"
228
-
```
229
-
230
-
**Case 3**: Parameterized rules
231
-
232
-
The `functionOptions` in the rule definition can be used to pass additional parameters to your custom rule function. This is useful when you need to configure or provide specific settings to the rule function for more flexible behavior.
233
-
234
-
- **Example**: Define `functionOptions` within the rule to adjust behavior:
0 commit comments