Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/swift-otters-wander.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@redocly/openapi-core": minor
"@redocly/respect-core": minor
"@redocly/cli": minor
---

Added the `spec-parameters-in-by-context` Arazzo rule, which validates that a parameter's `in` field is specified when the parent workflow, step, success action, or failure action does not reference a `workflowId`. Extended success and failure action objects to accept a `parameters` property that maps to workflow inputs.

Note: because this rule is part of the `spec` ruleset (and is set to `error` in `recommended-strict` and `all`), linting Arazzo descriptions that omit a required `in` field, or that specify `in` when referencing a `workflowId`, may now report new errors.
133 changes: 133 additions & 0 deletions docs/@v2/rules/arazzo/spec-parameters-in-by-context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# spec-parameters-in-by-context

Requires the `in` field on a parameter to be specified or omitted based on the parent context.

| Arazzo | Compatibility |
| ------ | ------------- |
| 1.x | ✅ |

## Design principles

The Arazzo specification states that when a step, success action, or failure action specifies a `workflowId`, all parameters map to the referenced workflow's inputs and the `in` field MUST NOT be specified.
In every other case (for example, when a step specifies an `operationId`, `operationPath`, or `x-operation`, or for parameters defined at the workflow level), the `in` field MUST be specified on each parameter.

This rule additionally enforces that success and failure action `parameters` are only valid when the action references a `workflowId`.

## Configuration

| Option | Type | Description |
| -------- | ------ | ------------------------------------------------------- |
| severity | string | Possible values: `off`, `warn`, `error`. Default `off`. |

An example configuration:

```yaml
rules:
spec-parameters-in-by-context: error
```

## Examples

Given the following configuration:

```yaml
rules:
spec-parameters-in-by-context: error
```

Example of a **correct** step referencing an `operationId` (each parameter declares `in`):

```yaml
# Correct example - operationId
workflows:
- workflowId: get-museum-hours
steps:
- stepId: list-hours
operationId: listMuseumHours
parameters:
- in: query
name: startDate
value: '2024-01-01'
```

Example of a **correct** step referencing a `workflowId` (parameters map to workflow inputs, no `in` field):

```yaml
# Correct example - workflowId
workflows:
- workflowId: buy-tickets
steps:
- stepId: reuse-hours-workflow
workflowId: get-museum-hours
parameters:
- name: startDate
value: '2024-01-01'
```

Example of a **correct** success action transferring to another workflow with mapped parameters:

```yaml
# Correct example - success action
workflows:
- workflowId: buy-tickets
steps:
- stepId: purchase
operationId: createTicket
onSuccess:
- name: continue-to-hours
type: goto
workflowId: get-museum-hours
parameters:
- name: startDate
value: '2024-01-01'
```

Example of an **incorrect** step referencing a `workflowId` while declaring `in` on a parameter:

```yaml
# Incorrect example - workflowId with `in`
workflows:
- workflowId: buy-tickets
steps:
- stepId: reuse-hours-workflow
workflowId: get-museum-hours
parameters:
- in: query
name: startDate
value: '2024-01-01'
```

Example of an **incorrect** step referencing an `operationId` while omitting `in`:

```yaml
# Incorrect example - operationId without `in`
workflows:
- workflowId: get-museum-hours
steps:
- stepId: list-hours
operationId: listMuseumHours
parameters:
- name: startDate
value: '2024-01-01'
```

Example of an **incorrect** success action defining `parameters` without referencing a `workflowId`:

```yaml
# Incorrect example - action without workflowId
workflows:
- workflowId: buy-tickets
steps:
- stepId: purchase
operationId: createTicket
onSuccess:
- name: end-with-params
type: end
parameters:
- name: startDate
value: '2024-01-01'
```

## Resources

- [Rule source](https://github.com/Redocly/redocly-cli/blob/main/packages/core/src/rules/arazzo/spec-parameters-in-by-context.ts)
1 change: 1 addition & 0 deletions docs/@v2/rules/built-in-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ Within the Arazzo family of rules, there are rules for the main Arazzo specifica
- [requestBody-replacements-unique](./arazzo/requestBody-replacements-unique.md): the `replacements` of the `requestBody` object must be unique
- [sourceDescription-name-unique](./arazzo/sourceDescription-name-unique.md): the `name` property of the `sourceDescription` object must be unique across all source descriptions
- [sourceDescription-type](./arazzo/sourceDescription-type.md): the `type` property of the `sourceDescription` object must be either `openapi` or `arazzo`
- [spec-parameters-in-by-context](./arazzo/spec-parameters-in-by-context.md): the parameter `in` field must be specified or omitted based on whether the parent step or action references a `workflowId`
- [stepId-unique](./arazzo/stepId-unique.md): the `stepId` must be unique amongst all steps described in the workflow
- [step-onFailure-unique](./arazzo/step-onFailure-unique.md): the `onFailure` actions of the `step` object must be unique
- [step-onSuccess-unique](./arazzo/step-onSuccess-unique.md): the `onSuccess` actions of the `step` object must be unique
Expand Down
1 change: 1 addition & 0 deletions docs/@v2/v2.sidebars.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@
- page: rules/arazzo/requestBody-replacements-unique.md
- page: rules/arazzo/sourceDescription-name-unique.md
- page: rules/arazzo/sourceDescription-type.md
- page: rules/arazzo/spec-parameters-in-by-context.md
- page: rules/arazzo/stepId-unique.md
- page: rules/arazzo/step-onFailure-unique.md
- page: rules/arazzo/step-onSuccess-unique.md
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ exports[`resolveConfig > should ignore minimal from the root and read local file
"sourceDescription-name-unique": "error",
"sourceDescription-type": "error",
"sourceDescriptions-not-empty": "error",
"spec-parameters-in-by-context": "warn",
"step-onFailure-unique": "warn",
"step-onSuccess-unique": "warn",
"stepId-unique": "error",
Expand Down Expand Up @@ -407,6 +408,7 @@ exports[`resolveConfig > should resolve extends with local file config which con
"sourceDescription-name-unique": "error",
"sourceDescription-type": "error",
"sourceDescriptions-not-empty": "error",
"spec-parameters-in-by-context": "warn",
"step-onFailure-unique": "warn",
"step-onSuccess-unique": "warn",
"stepId-unique": "error",
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/config/__tests__/load.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ describe('loadConfig', () => {
"sourceDescription-name-unique": "off",
"sourceDescription-type": "off",
"sourceDescriptions-not-empty": "off",
"spec-parameters-in-by-context": "off",
"step-onFailure-unique": "off",
"step-onSuccess-unique": "off",
"stepId-unique": "error",
Expand Down Expand Up @@ -466,6 +467,7 @@ describe('loadConfig', () => {
"sourceDescription-name-unique": "error",
"sourceDescription-type": "error",
"sourceDescriptions-not-empty": "error",
"spec-parameters-in-by-context": "warn",
"step-onFailure-unique": "warn",
"step-onSuccess-unique": "warn",
"stepId-unique": "error",
Expand Down Expand Up @@ -795,6 +797,7 @@ describe('loadConfig', () => {
"sourceDescription-name-unique": "off",
"sourceDescription-type": "off",
"sourceDescriptions-not-empty": "off",
"spec-parameters-in-by-context": "off",
"step-onFailure-unique": "off",
"step-onSuccess-unique": "off",
"stepId-unique": "error",
Expand Down Expand Up @@ -1208,6 +1211,7 @@ describe('loadConfig', () => {
"sourceDescription-name-unique": "off",
"sourceDescription-type": "off",
"sourceDescriptions-not-empty": "off",
"spec-parameters-in-by-context": "off",
"step-onFailure-unique": "off",
"step-onSuccess-unique": "off",
"stepId-unique": "error",
Expand Down Expand Up @@ -1532,6 +1536,7 @@ describe('loadConfig', () => {
"sourceDescription-name-unique": "error",
"sourceDescription-type": "error",
"sourceDescriptions-not-empty": "error",
"spec-parameters-in-by-context": "warn",
"step-onFailure-unique": "warn",
"step-onSuccess-unique": "warn",
"stepId-unique": "error",
Expand Down Expand Up @@ -1861,6 +1866,7 @@ describe('loadConfig', () => {
"sourceDescription-name-unique": "off",
"sourceDescription-type": "off",
"sourceDescriptions-not-empty": "off",
"spec-parameters-in-by-context": "off",
"step-onFailure-unique": "off",
"step-onSuccess-unique": "off",
"stepId-unique": "error",
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/config/all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ const all: RawGovernanceConfig<'built-in'> = {
'sourceDescription-name-unique': 'error',
'sourceDescription-type': 'error',
'sourceDescriptions-not-empty': 'error',
'spec-parameters-in-by-context': 'error',
'step-onFailure-unique': 'error',
'step-onSuccess-unique': 'error',
'stepId-unique': 'error',
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/config/minimal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ const minimal: RawGovernanceConfig<'built-in'> = {
'sourceDescription-name-unique': 'off',
'sourceDescription-type': 'off',
'sourceDescriptions-not-empty': 'off',
'spec-parameters-in-by-context': 'off',
'step-onFailure-unique': 'off',
'step-onSuccess-unique': 'off',
'stepId-unique': 'error',
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/config/recommended-strict.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ const recommendedStrict: RawGovernanceConfig<'built-in'> = {
'sourceDescription-name-unique': 'error',
'sourceDescription-type': 'error',
'sourceDescriptions-not-empty': 'error',
'spec-parameters-in-by-context': 'error',
'step-onFailure-unique': 'error',
'step-onSuccess-unique': 'error',
'stepId-unique': 'error',
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/config/recommended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ const recommended: RawGovernanceConfig<'built-in'> = {
'sourceDescription-name-unique': 'error',
'sourceDescription-type': 'error',
'sourceDescriptions-not-empty': 'error',
'spec-parameters-in-by-context': 'warn',
'step-onFailure-unique': 'warn',
'step-onSuccess-unique': 'warn',
'stepId-unique': 'error',
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/config/spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ const spec: RawGovernanceConfig<'built-in'> = {
'sourceDescription-name-unique': 'error',
'sourceDescription-type': 'error',
'sourceDescriptions-not-empty': 'error',
'spec-parameters-in-by-context': 'error',
'step-onFailure-unique': 'error',
'step-onSuccess-unique': 'error',
'stepId-unique': 'error',
Expand Down
Loading
Loading