diff --git a/CHANGELOG.md b/CHANGELOG.md index bd10920d8..4fd2772a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Caching policy [PR #546](https://github.com/3scale/apicast/pull/546), [PR #558](https://github.com/3scale/apicast/pull/558) - New phase: `content` for generating content or getting the upstream response [PR #535](https://github.com/3scale/apicast/pull/535) - Upstream policy [PR #562](https://github.com/3scale/apicast/pull/562) +- Policy JSON manifest [PR #565](https://github.com/3scale/apicast/pull/565) ## Fixed diff --git a/Makefile b/Makefile index d50ad81f8..b5907577d 100644 --- a/Makefile +++ b/Makefile @@ -155,9 +155,9 @@ doc: doc/lua/index.html ## Generate documentation lint-schema: apicast-source @ docker run --volumes-from ${COMPOSE_PROJECT_NAME}-source --workdir /opt/app-root/src \ - 3scale/ajv validate \ - -s /usr/local/lib/node_modules/ajv-cli/node_modules/ajv/lib/refs/json-schema-draft-07.json \ - $(addprefix -d ,$(shell find gateway/src/apicast/policy -name 'schema.json')) + 3scale/ajv validate \ + -s gateway/src/apicast/policy/manifest-schema.json \ + $(addprefix -d ,$(shell find gateway/src/apicast/policy -name 'apicast-policy.json')) node_modules/.bin/markdown-link-check: yarn install diff --git a/gateway/src/apicast/policy/caching/apicast-policy.json b/gateway/src/apicast/policy/caching/apicast-policy.json new file mode 100644 index 000000000..04d904937 --- /dev/null +++ b/gateway/src/apicast/policy/caching/apicast-policy.json @@ -0,0 +1,48 @@ +{ + "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "name": "Caching policy", + "description": + ["Configures a cache for the authentication calls against the 3scale ", + "backend. This policy support three kinds of caching: \n", + " - Strict: it only caches authorized calls. Denied and failed calls ", + "invalidate the cache entry.\n", + " - Resilient: caches authorized and denied calls. Failed calls do not ", + "invalidate the cache. This allows us to authorize and deny calls ", + "according to the result of the last request made even when backend is ", + "down.\n", + "- Allow: caches authorized and denied calls. When backend is ", + "unavailable, it will cache an authorization. In practice, this means ", + "that when backend is down _any_ request will be authorized unless last ", + "call to backend for that request returned 'deny' (status code = 4xx). ", + "Make sure to understand the implications of that before using this ", + "mode. It makes sense only in very specific use cases.\n", + "- None: disables caching."], + "version": "0.1", + "configuration": { + "type": "object", + "properties": { + "caching_type": { + "description": "Caching mode", + "type": "string", + "oneOf": [ + { + "const": "resilient", + "description": "Authorize according to last request when backend is down." + }, + { + "const": "strict", + "description": "It only caches authorized calls." + }, + { + "const": "allow", + "description": "When backend is down, allow everything unless seen before and denied." + }, + { + "const": "none", + "description": "Disables caching." + } + ] + } + } + } +} diff --git a/gateway/src/apicast/policy/caching/schema.json b/gateway/src/apicast/policy/caching/schema.json deleted file mode 100644 index 43c3db717..000000000 --- a/gateway/src/apicast/policy/caching/schema.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Caching policy configuration", - "type": "object", - "properties": { - "caching_type": { - "type": "string", - "enum": ["resilient", "strict", "allow", "none"] - } - } -} diff --git a/gateway/src/apicast/policy/cors/apicast-policy.json b/gateway/src/apicast/policy/cors/apicast-policy.json new file mode 100644 index 000000000..2f4c9ae12 --- /dev/null +++ b/gateway/src/apicast/policy/cors/apicast-policy.json @@ -0,0 +1,44 @@ +{ + "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "name": "CORS policy", + "description": "This policy enables CORS (Cross Origin Resource Sharing) request handling.", + "version": "0.1", + "configuration": { + "type": "object", + "properties": { + "allow_headers": { + "description": "Allowed headers", + "type": "array", + "items": { + "type": "string" + } + }, + "allow_methods": { + "description": "Allowed methods", + "type": "array", + "items": { + "type": "string", + "enum": [ + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + "PATCH", + "OPTIONS", + "TRACE", + "CONNECT" + ] + } + }, + "allow_origin": { + "description": "Origins for which the response can be shared with", + "type": "string" + }, + "allow_credentials": { + "description": "Whether the request can be made using credentials", + "type": "boolean" + } + } + } +} diff --git a/gateway/src/apicast/policy/cors/schema.json b/gateway/src/apicast/policy/cors/schema.json deleted file mode 100644 index af482ff55..000000000 --- a/gateway/src/apicast/policy/cors/schema.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "CORS policy configuration", - "type": "object", - "properties": { - "allow_headers": { - "type": "array", - "items": { - "type": "string" - } - }, - "allow_methods": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "GET", - "HEAD", - "POST", - "PUT", - "DELETE", - "PATCH", - "OPTIONS", - "TRACE", - "CONNECT" - ] - } - }, - "allow_origin": { - "type": "string" - }, - "allow_credentials": { - "type": "boolean" - } - } -} diff --git a/gateway/src/apicast/policy/echo/apicast-policy.json b/gateway/src/apicast/policy/echo/apicast-policy.json new file mode 100644 index 000000000..25937f8dd --- /dev/null +++ b/gateway/src/apicast/policy/echo/apicast-policy.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "name": "Echo policy", + "description": + ["This policy prints the request back to the client and optionally sets ", + "a status code."], + "version": "0.1", + "configuration": { + "type": "object", + "properties": { + "status": { + "description": "HTTP status code to be returned", + "type": "integer" + }, + "exit": { + "description": "Exit mode", + "type": "string", + "oneOf": [ + { + "const": "request", + "description": "Interrupts the processing of the request." + }, + { + "const": "set", + "description": "Only skips the rewrite phase." + } + ] + } + } + } +} diff --git a/gateway/src/apicast/policy/echo/schema.json b/gateway/src/apicast/policy/echo/schema.json deleted file mode 100644 index c8354195c..000000000 --- a/gateway/src/apicast/policy/echo/schema.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Echo policy configuration", - "type": "object", - "properties": { - "status": { - "type": "integer" - }, - "exit": { - "type": "string", - "enum": ["request", "phase"] - } - } -} diff --git a/gateway/src/apicast/policy/headers/apicast-policy.json b/gateway/src/apicast/policy/headers/apicast-policy.json new file mode 100644 index 000000000..a718009ac --- /dev/null +++ b/gateway/src/apicast/policy/headers/apicast-policy.json @@ -0,0 +1,55 @@ +{ + "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "name": "Headers policy", + "description": + ["This policy allows to include custom headers that will be sent to the ", + "upstream as well as modify or delete the ones included in the original ", + "request. Similarly, this policy also allows to add, modify, and delete ", + "the headers included in the response."], + "version": "0.1", + "configuration": { + "type": "object", + "definitions": { + "commands": { + "description": "List of operations to apply to the headers", + "type": "array", + "items": { + "type": "object", + "properties": { + "op": { + "description": "Operation to be applied", + "type": "string", + "oneOf": [ + { + "const": "add", + "description": "Adds a value to an existing header." + }, + { + "const": "set", + "description": "Creates the header when not set, replaces its value when set." + }, + { + "const": "push", + "description": "Creates the header when not set, adds the value when set." + } + ] + }, + "header": { + "description": "Header to be modified", + "type": "string" + }, + "value": { + "description": "Value that will be added, set or pushed in the header", + "type": "string" + } + }, + "required": ["op", "header", "value"] + } + } + }, + "properties": { + "request": { "$ref": "#/definitions/commands" }, + "response": { "$ref": "#/definitions/commands" } + } + } +} diff --git a/gateway/src/apicast/policy/headers/schema.json b/gateway/src/apicast/policy/headers/schema.json deleted file mode 100644 index 65b101abe..000000000 --- a/gateway/src/apicast/policy/headers/schema.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Headers policy configuration", - "type": "object", - "definitions": { - "commands": { - "type": "array", - "items": { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": ["add", "set", "push"] - }, - "header": { - "type": "string" - }, - "value": { - "type": "string" - } - }, - "required": ["op", "header", "value"] - } - } - }, - "properties": { - "request": { "$ref": "#/definitions/commands" }, - "response": { "$ref": "#/definitions/commands" } - } -} diff --git a/gateway/src/apicast/policy/manifest-schema.json b/gateway/src/apicast/policy/manifest-schema.json new file mode 100644 index 000000000..0984e70b7 --- /dev/null +++ b/gateway/src/apicast/policy/manifest-schema.json @@ -0,0 +1,58 @@ +{ + "$id": "http://apicast.io/policy-v1/schema#manifest", + "type": "object", + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "schema": { + "$id": "#/definitions/schema", + "$ref": "http://json-schema.org/draft-07/schema#", + "default": {} + }, + "version": { + "$id": "#/definitions/version", + "type": "string", + "title": "The Policy Version", + "description": "A semantic version of a policy.", + "examples": [ + "1.3.4", + "0.1" + ], + "pattern": "^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$" + } + }, + "properties": { + "name": { + "$id": "/properties/name", + "type": "string", + "title": "The Policy Name", + "description": "Name of the policy.", + "examples": [ + "Basic Authentication" + ], + "minLength": 1 + }, + "description": { + "$id": "/properties/description", + "oneOf": [ + { "type": "string", + "minLength": 1 }, + { "type": "array", "items": { "type": "string" }, + "minItems": 1 + } + ], + "title": "The Policy Description", + "description": "Longer description of what the policy does.", + "examples": [ + "Extract authentication credentials from the HTTP Authorization header and pass them to 3scale backend.", + [ "Redirect request to different upstream: ", " - based on path", "- set different Host header"] + ] + }, + "version": { + "$ref": "#/definitions/version" + }, + "configuration": { + "$ref": "#/definitions/schema" + } + }, + "required": ["name", "version", "configuration"] +} diff --git a/gateway/src/apicast/policy/upstream/apicast-policy.json b/gateway/src/apicast/policy/upstream/apicast-policy.json new file mode 100644 index 000000000..7b99d4b11 --- /dev/null +++ b/gateway/src/apicast/policy/upstream/apicast-policy.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "name": "Upstream policy", + "description": "This policy allows to modify the host of a request based on its path.", + "version": "0.1", + "configuration": { + "type": "object", + "properties": { + "rules": { + "description": "list of rules to be applied", + "type": "array", + "items": { + "type": "object", + "properties": { + "regex": { + "description": "regular expression to be matched", + "type": "string" + }, + "url": { + "description": "new URL in case of match", + "type": "string" + } + }, + "required": ["regex", "url"] + } + } + } + } +} diff --git a/gateway/src/apicast/policy/upstream/schema.json b/gateway/src/apicast/policy/upstream/schema.json deleted file mode 100644 index 719842402..000000000 --- a/gateway/src/apicast/policy/upstream/schema.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Upstream policy configuration", - "type": "object", - "properties": { - "rules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "regex": { - "type": "string" - }, - "url": { - "type": "string" - } - }, - "required": ["regex", "url"] - } - } - } -} diff --git a/gateway/src/apicast/policy/url_rewriting/apicast-policy.json b/gateway/src/apicast/policy/url_rewriting/apicast-policy.json new file mode 100644 index 000000000..1beb0cce0 --- /dev/null +++ b/gateway/src/apicast/policy/url_rewriting/apicast-policy.json @@ -0,0 +1,56 @@ +{ + "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "name": "URL rewriting policy", + "description": + ["This policy allows to modify the path of a request. ", + "The operations supported are sub and gsub based on ngx.re.sub and ", + "ngx.re.gsub provided by OpenResty. Please check ", + "https://github.com/openresty/lua-nginx-module for more details on how ", + "to define regular expressions and learn the options supported."], + "version": "0.1", + "configuration": { + "type": "object", + "properties": { + "commands": { + "description": "List of rewriting commands to be applied", + "type": "array", + "items": { + "type": "object", + "properties": { + "op": { + "description": "Operation to be applied (sub or gsub)", + "type": "string", + "oneOf": [ + { + "const": "sub", + "description": "Substitutes the first match of the regex applied." + }, + { + "const": "gsub", + "description": "Substitutes all the matches of the regex applied." + } + ] + }, + "regex": { + "description": "Regular expression to be matched", + "type": "string" + }, + "replace": { + "description": "String that will replace what is matched by the regex", + "type": "string" + }, + "options": { + "description": "Options that define how the regex matching is performed", + "type": "string" + }, + "break": { + "description": "when set to true, if the command rewrote the URL, it will be the last one applied", + "type": "boolean" + } + }, + "required": ["op", "regex", "replace"] + } + } + } + } +} diff --git a/gateway/src/apicast/policy/url_rewriting/schema.json b/gateway/src/apicast/policy/url_rewriting/schema.json deleted file mode 100644 index 07b9637f7..000000000 --- a/gateway/src/apicast/policy/url_rewriting/schema.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "URL rewriting policy configuration", - "type": "object", - "properties": { - "commands": { - "type": "array", - "items": { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": ["sub", "gsub"] - }, - "regex": { - "type": "string" - }, - "replace": { - "type": "string" - }, - "options": { - "type": "string" - }, - "break": { - "type": "boolean" - } - }, - "required": ["op", "regex", "replace"] - } - } - } -}