diff --git a/linter/spectral.yml b/linter/spectral.yml index da7089a..407143c 100644 --- a/linter/spectral.yml +++ b/linter/spectral.yml @@ -172,8 +172,8 @@ rules: char: "" nlgov:servers-use-https: - severity: warn - message: "Server URL {{value}} {{error}}." + severity: error + message: "Server URL {{value}} must start with https:// instead of http://." given: - $.servers[*] - $.paths..servers[*] @@ -181,7 +181,46 @@ rules: field: url function: pattern functionOptions: - match: ^https://.* + notMatch: ^http://.* + + nlgov:servers-at-most-one-relative: + severity: error + message: "At most one relative URL may be specified as server." + given: + - $.servers + - $.paths..servers + then: + function: schema + functionOptions: + dialect: draft2020-12 + schema: + type: array + contains: + type: object + properties: + url: + pattern: ^(?!https:).+ + minContains: 0 + maxContains: 1 + + nlgov:servers-at-least-one-absolute: + severity: error + message: "At least one absolute URL must be specified as server." + given: + - $.servers + - $.paths..servers + then: + function: schema + functionOptions: + dialect: draft2020-12 + schema: + type: array + contains: + type: object + properties: + url: + pattern: ^https://.* + minContains: 1 nlgov:use-problem-schema: severity: warn diff --git a/linter/testcases/servers-empty/expected-output.txt b/linter/testcases/servers-empty/expected-output.txt index 866834c..d50a6d3 100644 --- a/linter/testcases/servers-empty/expected-output.txt +++ b/linter/testcases/servers-empty/expected-output.txt @@ -1,5 +1,6 @@ /testcases/servers-empty/openapi.json - 13:15 error oas3-api-servers OpenAPI "servers" must be present and non-empty array. servers + 13:15 error nlgov:servers-at-least-one-absolute At least one absolute URL must be specified as server. servers + 13:15 error oas3-api-servers OpenAPI "servers" must be present and non-empty array. servers -✖ 1 problem (1 error, 0 warnings, 0 infos, 0 hints) +✖ 2 problems (2 errors, 0 warnings, 0 infos, 0 hints) diff --git a/linter/testcases/servers-no-absolute/expected-output.txt b/linter/testcases/servers-no-absolute/expected-output.txt new file mode 100644 index 0000000..6e2a080 --- /dev/null +++ b/linter/testcases/servers-no-absolute/expected-output.txt @@ -0,0 +1,5 @@ + +/testcases/servers-no-absolute/openapi.json + 13:15 error nlgov:servers-at-least-one-absolute At least one absolute URL must be specified as server. servers + +✖ 1 problem (1 error, 0 warnings, 0 infos, 0 hints) diff --git a/linter/testcases/servers-no-absolute/openapi.json b/linter/testcases/servers-no-absolute/openapi.json new file mode 100644 index 0000000..11938a9 --- /dev/null +++ b/linter/testcases/servers-no-absolute/openapi.json @@ -0,0 +1,81 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Baseline", + "description": "Deze OpenAPI specification bevat het minimale om aan alle regels te voldoen.", + "contact": { + "name": "Beheerder", + "url": "https://www.example.com", + "email": "mail@example.com" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "/api/v1", + "description": "API location on the origin that the openapi.json is served" + } + ], + "security": [ + { + "default": [] + } + ], + "tags": [ + { + "name": "openapi" + } + ], + "paths": { + "/openapi.json": { + "get": { + "tags": [ + "openapi" + ], + "description": "OpenAPI document", + "operationId": "getOpenapiJSON", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "headers": { + "API-Version": { + "description": "De huidige versie van de applicatie", + "style": "simple", + "schema": { + "type": "string" + } + }, + "access-control-allow-origin": { + "description": "Alle origins mogen bij deze resource", + "schema": { + "type": "string" + } + } + } + } + }, + "security": [ + { + "default": [] + } + ] + } + } + }, + "components": { + "schemas": { + }, + "securitySchemes": { + "default": { + "type": "oauth2", + "flows": { + "implicit": { + "authorizationUrl": "https://test.com", + "scopes": {} + } + } + } + } + } +} \ No newline at end of file diff --git a/linter/testcases/servers-no-https/expected-output.txt b/linter/testcases/servers-no-https/expected-output.txt new file mode 100644 index 0000000..6070a9a --- /dev/null +++ b/linter/testcases/servers-no-https/expected-output.txt @@ -0,0 +1,5 @@ + +/testcases/servers-no-https/openapi.json + 15:20 error nlgov:servers-use-https Server URL http://production.example.com/api/v1 must start with https:// instead of http://. servers[0].url + +✖ 1 problem (1 error, 0 warnings, 0 infos, 0 hints) diff --git a/linter/testcases/servers-no-https/openapi.json b/linter/testcases/servers-no-https/openapi.json new file mode 100644 index 0000000..f9ea2e5 --- /dev/null +++ b/linter/testcases/servers-no-https/openapi.json @@ -0,0 +1,85 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Baseline", + "description": "Deze OpenAPI specification bevat het minimale om aan alle regels te voldoen.", + "contact": { + "name": "Beheerder", + "url": "https://www.example.com", + "email": "mail@example.com" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://production.example.com/api/v1", + "description": "Production server" + }, + { + "url": "https://staging.example.com/api/v1", + "description": "Pre-production server" + } + ], + "security": [ + { + "default": [] + } + ], + "tags": [ + { + "name": "openapi" + } + ], + "paths": { + "/openapi.json": { + "get": { + "tags": [ + "openapi" + ], + "description": "OpenAPI document", + "operationId": "getOpenapiJSON", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "headers": { + "API-Version": { + "description": "De huidige versie van de applicatie", + "style": "simple", + "schema": { + "type": "string" + } + }, + "access-control-allow-origin": { + "description": "Alle origins mogen bij deze resource", + "schema": { + "type": "string" + } + } + } + } + }, + "security": [ + { + "default": [] + } + ] + } + } + }, + "components": { + "schemas": { + }, + "securitySchemes": { + "default": { + "type": "oauth2", + "flows": { + "implicit": { + "authorizationUrl": "https://test.com", + "scopes": {} + } + } + } + } + } +} \ No newline at end of file diff --git a/linter/testcases/servers-relative-one/expected-output.txt b/linter/testcases/servers-relative-one/expected-output.txt new file mode 100644 index 0000000..95cc954 --- /dev/null +++ b/linter/testcases/servers-relative-one/expected-output.txt @@ -0,0 +1 @@ +No results with a severity of 'error' found! diff --git a/linter/testcases/servers-relative-one/openapi.json b/linter/testcases/servers-relative-one/openapi.json new file mode 100644 index 0000000..4a42d58 --- /dev/null +++ b/linter/testcases/servers-relative-one/openapi.json @@ -0,0 +1,89 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Baseline", + "description": "Deze OpenAPI specification bevat het minimale om aan alle regels te voldoen.", + "contact": { + "name": "Beheerder", + "url": "https://www.example.com", + "email": "mail@example.com" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://production.example.com/api/v1", + "description": "Production server" + }, + { + "url": "https://staging.example.com/api/v1", + "description": "Pre-production server" + }, + { + "url": "/api/v1", + "description": "API location on the origin that the openapi.json is served" + } + ], + "security": [ + { + "default": [] + } + ], + "tags": [ + { + "name": "openapi" + } + ], + "paths": { + "/openapi.json": { + "get": { + "tags": [ + "openapi" + ], + "description": "OpenAPI document", + "operationId": "getOpenapiJSON", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "headers": { + "API-Version": { + "description": "De huidige versie van de applicatie", + "style": "simple", + "schema": { + "type": "string" + } + }, + "access-control-allow-origin": { + "description": "Alle origins mogen bij deze resource", + "schema": { + "type": "string" + } + } + } + } + }, + "security": [ + { + "default": [] + } + ] + } + } + }, + "components": { + "schemas": { + }, + "securitySchemes": { + "default": { + "type": "oauth2", + "flows": { + "implicit": { + "authorizationUrl": "https://test.com", + "scopes": {} + } + } + } + } + } +} \ No newline at end of file diff --git a/linter/testcases/servers-relative-two/expected-output.txt b/linter/testcases/servers-relative-two/expected-output.txt new file mode 100644 index 0000000..3e5525f --- /dev/null +++ b/linter/testcases/servers-relative-two/expected-output.txt @@ -0,0 +1,5 @@ + +/testcases/servers-relative-two/openapi.json + 13:15 error nlgov:servers-at-most-one-relative At most one relative URL may be specified as server. servers + +✖ 1 problem (1 error, 0 warnings, 0 infos, 0 hints) diff --git a/linter/testcases/servers-relative-two/openapi.json b/linter/testcases/servers-relative-two/openapi.json new file mode 100644 index 0000000..f6fe366 --- /dev/null +++ b/linter/testcases/servers-relative-two/openapi.json @@ -0,0 +1,93 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Baseline", + "description": "Deze OpenAPI specification bevat het minimale om aan alle regels te voldoen.", + "contact": { + "name": "Beheerder", + "url": "https://www.example.com", + "email": "mail@example.com" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://production.example.com/api/v1", + "description": "Production server" + }, + { + "url": "https://staging.example.com/api/v1", + "description": "Pre-production server" + }, + { + "url": "/api/v1", + "description": "API location on the origin that the openapi.json is served" + }, + { + "url": "/api/v2", + "description": "API location on the origin that the openapi.json is served" + } + ], + "security": [ + { + "default": [] + } + ], + "tags": [ + { + "name": "openapi" + } + ], + "paths": { + "/openapi.json": { + "get": { + "tags": [ + "openapi" + ], + "description": "OpenAPI document", + "operationId": "getOpenapiJSON", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "headers": { + "API-Version": { + "description": "De huidige versie van de applicatie", + "style": "simple", + "schema": { + "type": "string" + } + }, + "access-control-allow-origin": { + "description": "Alle origins mogen bij deze resource", + "schema": { + "type": "string" + } + } + } + } + }, + "security": [ + { + "default": [] + } + ] + } + } + }, + "components": { + "schemas": { + }, + "securitySchemes": { + "default": { + "type": "oauth2", + "flows": { + "implicit": { + "authorizationUrl": "https://test.com", + "scopes": {} + } + } + } + } + } +} \ No newline at end of file diff --git a/sections/designRules.md b/sections/designRules.md index 60c76cb..f1b81f5 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -534,6 +534,47 @@ An API is as good as the accompanying documentation. The documentation has to be +
Document server information
+servers.
+ One or more Server objects MUST have a url which is an absolute URL.
+ At most one Server object MAY have a servers list is present.Publish documentation in Dutch unless there is existing documentation in English