From 939441125eb29b1f88b34e4b3acfd1c446328002 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Wed, 3 Jul 2019 13:01:11 +0200 Subject: [PATCH 1/9] policy: set correct version in initializers Two reasons for this: 1) Now logs show the correct version when printing the policy chain. 2) In order to verify the order of policies in the chain, we need the real version in the policy instance. We need "builtin" which is what appears in the schema instead of the 0.0 that's set by default. --- gateway/src/apicast/policy/3scale_batcher/3scale_batcher.lua | 2 +- gateway/src/apicast/policy/3scale_referrer/3scale_referrer.lua | 2 +- gateway/src/apicast/policy/apicast/apicast.lua | 2 +- gateway/src/apicast/policy/caching/caching.lua | 2 +- gateway/src/apicast/policy/conditional/conditional.lua | 2 +- gateway/src/apicast/policy/cors/cors.lua | 2 +- .../apicast/policy/default_credentials/default_credentials.lua | 2 +- gateway/src/apicast/policy/echo/echo.lua | 2 +- gateway/src/apicast/policy/headers/headers.lua | 2 +- gateway/src/apicast/policy/ip_check/ip_check.lua | 2 +- gateway/src/apicast/policy/jwt_claim_check/jwt_claim_check.lua | 2 +- .../apicast/policy/keycloak_role_check/keycloak_role_check.lua | 2 +- .../policy/liquid_context_debug/liquid_context_debug.lua | 2 +- .../apicast/policy/load_configuration/load_configuration.lua | 2 +- gateway/src/apicast/policy/logging/logging.lua | 2 +- gateway/src/apicast/policy/nginx_metrics/nginx_metrics.lua | 2 +- .../apicast/policy/oidc_authentication/oidc_authentication.lua | 2 +- gateway/src/apicast/policy/retry/retry.lua | 2 +- gateway/src/apicast/policy/routing/routing.lua | 2 +- gateway/src/apicast/policy/upstream/upstream.lua | 2 +- .../apicast/policy/upstream_connection/upstream_connection.lua | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/gateway/src/apicast/policy/3scale_batcher/3scale_batcher.lua b/gateway/src/apicast/policy/3scale_batcher/3scale_batcher.lua index d69ffe233..0c34390c6 100644 --- a/gateway/src/apicast/policy/3scale_batcher/3scale_batcher.lua +++ b/gateway/src/apicast/policy/3scale_batcher/3scale_batcher.lua @@ -17,7 +17,7 @@ local ipairs = ipairs local default_auths_ttl = 10 local default_batch_reports_seconds = 10 -local _M, mt = policy.new('3scale Batcher policy') +local _M, mt = policy.new('3scale Batcher policy', 'builtin') local new = _M.new diff --git a/gateway/src/apicast/policy/3scale_referrer/3scale_referrer.lua b/gateway/src/apicast/policy/3scale_referrer/3scale_referrer.lua index af26c9b12..29c242568 100644 --- a/gateway/src/apicast/policy/3scale_referrer/3scale_referrer.lua +++ b/gateway/src/apicast/policy/3scale_referrer/3scale_referrer.lua @@ -1,5 +1,5 @@ local policy = require('apicast.policy') -local _M = policy.new('3scale Referrer policy') +local _M = policy.new('3scale Referrer policy', 'builtin') function _M.rewrite(_, context) local referrer = ngx.var.http_referer diff --git a/gateway/src/apicast/policy/apicast/apicast.lua b/gateway/src/apicast/policy/apicast/apicast.lua index 88cb19815..da48e6e5c 100644 --- a/gateway/src/apicast/policy/apicast/apicast.lua +++ b/gateway/src/apicast/policy/apicast/apicast.lua @@ -6,7 +6,7 @@ local assert = assert local user_agent = require('apicast.user_agent') -local _M = require('apicast.policy').new('APIcast', require('apicast.version')) +local _M = require('apicast.policy').new('APIcast', 'builtin') local mt = { __index = _M diff --git a/gateway/src/apicast/policy/caching/caching.lua b/gateway/src/apicast/policy/caching/caching.lua index 92c9a7f2f..564428b05 100644 --- a/gateway/src/apicast/policy/caching/caching.lua +++ b/gateway/src/apicast/policy/caching/caching.lua @@ -18,7 +18,7 @@ -- - None: disables caching. local policy = require('apicast.policy') -local _M = policy.new('Caching policy') +local _M = policy.new('Caching policy', 'builtin') local new = _M.new diff --git a/gateway/src/apicast/policy/conditional/conditional.lua b/gateway/src/apicast/policy/conditional/conditional.lua index f17f11798..731b88247 100644 --- a/gateway/src/apicast/policy/conditional/conditional.lua +++ b/gateway/src/apicast/policy/conditional/conditional.lua @@ -8,7 +8,7 @@ local Condition = require('apicast.conditions.condition') local Operation = require('apicast.conditions.operation') local ngx_variable = require('apicast.policy.ngx_variable') -local _M = policy.new('Conditional policy') +local _M = policy.new('Conditional policy', 'builtin') local new = _M.new diff --git a/gateway/src/apicast/policy/cors/cors.lua b/gateway/src/apicast/policy/cors/cors.lua index b12ccf018..b183c9591 100644 --- a/gateway/src/apicast/policy/cors/cors.lua +++ b/gateway/src/apicast/policy/cors/cors.lua @@ -14,7 +14,7 @@ -- 'example.com' too. local policy = require('apicast.policy') -local _M = policy.new('CORS Policy') +local _M = policy.new('CORS Policy', 'builtin') local new = _M.new diff --git a/gateway/src/apicast/policy/default_credentials/default_credentials.lua b/gateway/src/apicast/policy/default_credentials/default_credentials.lua index 745dbb3c2..d72f977f9 100644 --- a/gateway/src/apicast/policy/default_credentials/default_credentials.lua +++ b/gateway/src/apicast/policy/default_credentials/default_credentials.lua @@ -3,7 +3,7 @@ local tostring = tostring local policy = require('apicast.policy') -local _M = policy.new('Default credentials policy') +local _M = policy.new('Default credentials policy', 'builtin') local new = _M.new diff --git a/gateway/src/apicast/policy/echo/echo.lua b/gateway/src/apicast/policy/echo/echo.lua index 6bb6b0d29..4ac820387 100644 --- a/gateway/src/apicast/policy/echo/echo.lua +++ b/gateway/src/apicast/policy/echo/echo.lua @@ -3,7 +3,7 @@ -- Also can interrupt the execution and skip the current phase or -- the whole processing of the request. -local _M = require('apicast.policy').new('Echo Policy') +local _M = require('apicast.policy').new('Echo Policy', 'builtin') local cjson = require('cjson') local tonumber = tonumber diff --git a/gateway/src/apicast/policy/headers/headers.lua b/gateway/src/apicast/policy/headers/headers.lua index e22b20687..f5553c223 100644 --- a/gateway/src/apicast/policy/headers/headers.lua +++ b/gateway/src/apicast/policy/headers/headers.lua @@ -14,7 +14,7 @@ local TemplateString = require 'apicast.template_string' local default_value_type = 'plain' local policy = require('apicast.policy') -local _M = policy.new('Headers policy') +local _M = policy.new('Headers policy', 'builtin') local new = _M.new diff --git a/gateway/src/apicast/policy/ip_check/ip_check.lua b/gateway/src/apicast/policy/ip_check/ip_check.lua index 8bcfa4e5b..41ba50e97 100644 --- a/gateway/src/apicast/policy/ip_check/ip_check.lua +++ b/gateway/src/apicast/policy/ip_check/ip_check.lua @@ -2,7 +2,7 @@ local iputils = require("resty.iputils") local ClientIP = require('apicast.policy.ip_check.client_ip') local policy = require('apicast.policy') -local _M = policy.new('IP check policy') +local _M = policy.new('IP check policy', 'builtin') local new = _M.new diff --git a/gateway/src/apicast/policy/jwt_claim_check/jwt_claim_check.lua b/gateway/src/apicast/policy/jwt_claim_check/jwt_claim_check.lua index ecbc945a9..683585197 100644 --- a/gateway/src/apicast/policy/jwt_claim_check/jwt_claim_check.lua +++ b/gateway/src/apicast/policy/jwt_claim_check/jwt_claim_check.lua @@ -1,5 +1,5 @@ local policy = require('apicast.policy') -local _M = policy.new('JWT check policy') +local _M = policy.new('JWT check policy', 'builtin') local Condition = require('apicast.conditions.condition') local MappingRule = require('apicast.mapping_rule') diff --git a/gateway/src/apicast/policy/keycloak_role_check/keycloak_role_check.lua b/gateway/src/apicast/policy/keycloak_role_check/keycloak_role_check.lua index 946ae1cc5..681126b1b 100644 --- a/gateway/src/apicast/policy/keycloak_role_check/keycloak_role_check.lua +++ b/gateway/src/apicast/policy/keycloak_role_check/keycloak_role_check.lua @@ -50,7 +50,7 @@ -- ] local policy = require('apicast.policy') -local _M = policy.new('Keycloak Role Check Policy') +local _M = policy.new('Keycloak Role Check Policy', 'builtin') local ipairs = ipairs local MappingRule = require('apicast.mapping_rule') diff --git a/gateway/src/apicast/policy/liquid_context_debug/liquid_context_debug.lua b/gateway/src/apicast/policy/liquid_context_debug/liquid_context_debug.lua index 07cbc23aa..a2f6e42f3 100644 --- a/gateway/src/apicast/policy/liquid_context_debug/liquid_context_debug.lua +++ b/gateway/src/apicast/policy/liquid_context_debug/liquid_context_debug.lua @@ -2,7 +2,7 @@ local context_content = require('context_content') local cjson = require('cjson') local policy = require('apicast.policy') local ngx_variable = require('apicast.policy.ngx_variable') -local _M = policy.new('Liquid context debug') +local _M = policy.new('Liquid context debug', 'builtin') local new = _M.new diff --git a/gateway/src/apicast/policy/load_configuration/load_configuration.lua b/gateway/src/apicast/policy/load_configuration/load_configuration.lua index 0d5dbefd7..16e52e4bb 100644 --- a/gateway/src/apicast/policy/load_configuration/load_configuration.lua +++ b/gateway/src/apicast/policy/load_configuration/load_configuration.lua @@ -2,7 +2,7 @@ local _M = require('apicast.policy').new('Load Configuration') local ssl = require('ngx.ssl') local configuration_loader = require('apicast.configuration_loader').new() -local configuration_store = require('apicast.configuration_store') +local configuration_store = require('apicast.configuration_store', 'builtin') local new = _M.new diff --git a/gateway/src/apicast/policy/logging/logging.lua b/gateway/src/apicast/policy/logging/logging.lua index 1feb7a55b..d9395169d 100644 --- a/gateway/src/apicast/policy/logging/logging.lua +++ b/gateway/src/apicast/policy/logging/logging.lua @@ -1,6 +1,6 @@ --- Logging policy -local _M = require('apicast.policy').new('Logging Policy') +local _M = require('apicast.policy').new('Logging Policy', 'builtin') local new = _M.new diff --git a/gateway/src/apicast/policy/nginx_metrics/nginx_metrics.lua b/gateway/src/apicast/policy/nginx_metrics/nginx_metrics.lua index d8d9f7bf7..c25d16b24 100644 --- a/gateway/src/apicast/policy/nginx_metrics/nginx_metrics.lua +++ b/gateway/src/apicast/policy/nginx_metrics/nginx_metrics.lua @@ -1,4 +1,4 @@ -local _M = require('apicast.policy').new('Metrics') +local _M = require('apicast.policy').new('Metrics', 'builtin') local resty_env = require('resty.env') local errlog = require('ngx.errlog') diff --git a/gateway/src/apicast/policy/oidc_authentication/oidc_authentication.lua b/gateway/src/apicast/policy/oidc_authentication/oidc_authentication.lua index 46d58aaa2..42e168e6f 100644 --- a/gateway/src/apicast/policy/oidc_authentication/oidc_authentication.lua +++ b/gateway/src/apicast/policy/oidc_authentication/oidc_authentication.lua @@ -8,7 +8,7 @@ local oidc_discovery = require('resty.oidc.discovery') local http_authorization = require('resty.http_authorization') local resty_url = require('resty.url') local policy = require('apicast.policy') -local _M = policy.new('oidc_authentication') +local _M = policy.new('oidc_authentication', 'builtin') local tostring = tostring diff --git a/gateway/src/apicast/policy/retry/retry.lua b/gateway/src/apicast/policy/retry/retry.lua index 0c91651ef..031c280ce 100644 --- a/gateway/src/apicast/policy/retry/retry.lua +++ b/gateway/src/apicast/policy/retry/retry.lua @@ -2,7 +2,7 @@ local tonumber = tonumber -local _M = require('apicast.policy').new('Retry Policy') +local _M = require('apicast.policy').new('Retry Policy', 'builtin') local new = _M.new diff --git a/gateway/src/apicast/policy/routing/routing.lua b/gateway/src/apicast/policy/routing/routing.lua index 5c5740aa4..0bb6b7341 100644 --- a/gateway/src/apicast/policy/routing/routing.lua +++ b/gateway/src/apicast/policy/routing/routing.lua @@ -7,7 +7,7 @@ local UpstreamSelector = require('upstream_selector') local Request = require('request') local Rule = require('rule') -local _M = require('apicast.policy').new('Routing policy') +local _M = require('apicast.policy').new('Routing policy', 'builtin') local new = _M.new diff --git a/gateway/src/apicast/policy/upstream/upstream.lua b/gateway/src/apicast/policy/upstream/upstream.lua index 5a7dc1842..4dfa8d58f 100644 --- a/gateway/src/apicast/policy/upstream/upstream.lua +++ b/gateway/src/apicast/policy/upstream/upstream.lua @@ -8,7 +8,7 @@ local tab_insert = table.insert local tab_new = require('resty.core.base').new_tab local balancer = require('apicast.balancer') -local _M = require('apicast.policy').new('Upstream policy') +local _M = require('apicast.policy').new('Upstream policy', 'builtin') local new = _M.new diff --git a/gateway/src/apicast/policy/upstream_connection/upstream_connection.lua b/gateway/src/apicast/policy/upstream_connection/upstream_connection.lua index f40f207db..369c54539 100644 --- a/gateway/src/apicast/policy/upstream_connection/upstream_connection.lua +++ b/gateway/src/apicast/policy/upstream_connection/upstream_connection.lua @@ -4,7 +4,7 @@ local tonumber = tonumber -local _M = require('apicast.policy').new('Upstream connection policy') +local _M = require('apicast.policy').new('Upstream connection policy', 'builtin') local new = _M.new From 9e1a5c7b1b794d134c353c98f9a853a8d90b4bd5 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Fri, 5 Jul 2019 10:40:30 +0200 Subject: [PATCH 2/9] policy/manifest: add order restrictions Also bump the version in the id. --- .../src/apicast/policy/manifest-schema.json | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/gateway/src/apicast/policy/manifest-schema.json b/gateway/src/apicast/policy/manifest-schema.json index 20a88ce5a..d99e02d40 100644 --- a/gateway/src/apicast/policy/manifest-schema.json +++ b/gateway/src/apicast/policy/manifest-schema.json @@ -1,5 +1,5 @@ { - "$id": "http://apicast.io/policy-v1/schema#manifest", + "$id": "http://apicast.io/policy-v1.1/schema#manifest", "type": "object", "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { @@ -57,6 +57,52 @@ [ "Redirect request to different upstream: ", " - based on path", "- set different Host header"] ] }, + "order": { + "$id": "/properties/order", + "type": "object", + "title": "Order restrictions of the policy", + "description": "Specifies before or after which policies the policy should be placed in the chain.", + "properties": { + "before": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "required": [ + "name", + "version" + ] + }, + "description": "The policy should be placed before these ones in the chain." + }, + "after": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "required": [ + "name", + "version" + ] + }, + "description": "The policy should be placed after these ones in the chain." + } + } + }, "version": { "$ref": "#/definitions/version" }, From 153cc96fb8434f709bd12514aa2b1290f3961cd3 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Fri, 5 Jul 2019 10:51:52 +0200 Subject: [PATCH 3/9] policy: add order restrictions in the schemas And also point to the new version of the manifest (v1.1) --- .../policy/3scale_batcher/apicast-policy.json | 2 +- .../policy/3scale_referrer/apicast-policy.json | 2 +- .../apicast/policy/apicast/apicast-policy.json | 2 +- .../apicast/policy/caching/apicast-policy.json | 2 +- .../policy/conditional/apicast-policy.json | 2 +- .../apicast/policy/cors/apicast-policy.json | 10 +++++++++- .../default_credentials/apicast-policy.json | 10 +++++++++- .../apicast/policy/echo/apicast-policy.json | 2 +- .../apicast/policy/headers/apicast-policy.json | 2 +- .../policy/ip_check/apicast-policy.json | 2 +- .../policy/jwt_claim_check/apicast-policy.json | 2 +- .../keycloak_role_check/apicast-policy.json | 2 +- .../liquid_context_debug/apicast-policy.json | 18 +++++++++++++++++- .../apicast/policy/logging/apicast-policy.json | 2 +- .../policy/rate_limit/apicast-policy.json | 2 +- .../apicast/policy/retry/apicast-policy.json | 2 +- .../rewrite_url_captures/apicast-policy.json | 2 +- .../apicast/policy/routing/apicast-policy.json | 10 +++++++++- .../apicast/policy/soap/apicast-policy.json | 2 +- .../policy/tls_validation/apicast-policy.json | 2 +- .../policy/upstream/apicast-policy.json | 10 +++++++++- .../upstream_connection/apicast-policy.json | 2 +- .../policy/url_rewriting/apicast-policy.json | 2 +- 23 files changed, 71 insertions(+), 23 deletions(-) diff --git a/gateway/src/apicast/policy/3scale_batcher/apicast-policy.json b/gateway/src/apicast/policy/3scale_batcher/apicast-policy.json index 28f7a8d3d..48baf0488 100644 --- a/gateway/src/apicast/policy/3scale_batcher/apicast-policy.json +++ b/gateway/src/apicast/policy/3scale_batcher/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "3scale batcher", "summary": "Caches auths from 3scale backend and batches reports.", "description": diff --git a/gateway/src/apicast/policy/3scale_referrer/apicast-policy.json b/gateway/src/apicast/policy/3scale_referrer/apicast-policy.json index 0f70775f3..ca5288176 100644 --- a/gateway/src/apicast/policy/3scale_referrer/apicast-policy.json +++ b/gateway/src/apicast/policy/3scale_referrer/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "3scale Referrer", "summary": "Sends the 'Referer' to 3scale backend so it can be validated.", "description": "Sends the 'Referer' to 3scale backend for validation.", diff --git a/gateway/src/apicast/policy/apicast/apicast-policy.json b/gateway/src/apicast/policy/apicast/apicast-policy.json index e95f68ff7..fa6e76f43 100644 --- a/gateway/src/apicast/policy/apicast/apicast-policy.json +++ b/gateway/src/apicast/policy/apicast/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "3scale APIcast", "summary": "Main functionality of APIcast to work with the 3scale API manager.", "description": diff --git a/gateway/src/apicast/policy/caching/apicast-policy.json b/gateway/src/apicast/policy/caching/apicast-policy.json index c44bbef1a..4a2790969 100644 --- a/gateway/src/apicast/policy/caching/apicast-policy.json +++ b/gateway/src/apicast/policy/caching/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "3scale auth caching", "summary": "Controls how to cache authorizations returned by the 3scale backend.", "description": diff --git a/gateway/src/apicast/policy/conditional/apicast-policy.json b/gateway/src/apicast/policy/conditional/apicast-policy.json index 453cea12c..a5ffd0cb0 100644 --- a/gateway/src/apicast/policy/conditional/apicast-policy.json +++ b/gateway/src/apicast/policy/conditional/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "Conditional policy [Tech preview]", "summary": "Executes a policy chain conditionally.", "description": [ diff --git a/gateway/src/apicast/policy/cors/apicast-policy.json b/gateway/src/apicast/policy/cors/apicast-policy.json index 7083fa11f..0a360ba48 100644 --- a/gateway/src/apicast/policy/cors/apicast-policy.json +++ b/gateway/src/apicast/policy/cors/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "CORS", "summary": "Enables CORS (Cross Origin Resource Sharing) request handling.", "description": @@ -9,6 +9,14 @@ "When combined with the APIcast policy, the CORS policy should be ", "placed before it in the chain."], "version": "builtin", + "order": { + "before": [ + { + "name": "apicast", + "version": "builtin" + } + ] + }, "configuration": { "type": "object", "properties": { diff --git a/gateway/src/apicast/policy/default_credentials/apicast-policy.json b/gateway/src/apicast/policy/default_credentials/apicast-policy.json index 4fce3b164..baaa06cc7 100644 --- a/gateway/src/apicast/policy/default_credentials/apicast-policy.json +++ b/gateway/src/apicast/policy/default_credentials/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "Anonymous access", "summary": "Provides default credentials for unauthenticated requests.", "description": @@ -11,6 +11,14 @@ "You need to configure a user_key; or, the combination of app_id + app_key. \n", "Note: this policy should be placed before the APIcast policy in the chain."], "version": "builtin", + "order": { + "before": [ + { + "name": "apicast", + "version": "builtin" + } + ] + }, "configuration": { "type":"object", "properties":{ diff --git a/gateway/src/apicast/policy/echo/apicast-policy.json b/gateway/src/apicast/policy/echo/apicast-policy.json index ccb0385e4..411d17f8c 100644 --- a/gateway/src/apicast/policy/echo/apicast-policy.json +++ b/gateway/src/apicast/policy/echo/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "Echo", "summary": "Prints the request back to the client and optionally sets a status code.", "description": diff --git a/gateway/src/apicast/policy/headers/apicast-policy.json b/gateway/src/apicast/policy/headers/apicast-policy.json index 7c07fa925..edcb1a30e 100644 --- a/gateway/src/apicast/policy/headers/apicast-policy.json +++ b/gateway/src/apicast/policy/headers/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "Header modification", "summary": "Allows to include custom headers.", "description": diff --git a/gateway/src/apicast/policy/ip_check/apicast-policy.json b/gateway/src/apicast/policy/ip_check/apicast-policy.json index d7a1d9832..f060a187b 100644 --- a/gateway/src/apicast/policy/ip_check/apicast-policy.json +++ b/gateway/src/apicast/policy/ip_check/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "IP check", "summary": "Accepts or denies a request based on the IP.", "description": [ diff --git a/gateway/src/apicast/policy/jwt_claim_check/apicast-policy.json b/gateway/src/apicast/policy/jwt_claim_check/apicast-policy.json index 4775cc38a..f63c89716 100644 --- a/gateway/src/apicast/policy/jwt_claim_check/apicast-policy.json +++ b/gateway/src/apicast/policy/jwt_claim_check/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "JWT Claim Check", "summary": "Allow or deny traffic based on a JWT claim", "description": [ diff --git a/gateway/src/apicast/policy/keycloak_role_check/apicast-policy.json b/gateway/src/apicast/policy/keycloak_role_check/apicast-policy.json index 780b49d21..ec3840c23 100644 --- a/gateway/src/apicast/policy/keycloak_role_check/apicast-policy.json +++ b/gateway/src/apicast/policy/keycloak_role_check/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "RH-SSO/Keycloak role check", "summary": "Adds role check with Keycloak.", "description": [ diff --git a/gateway/src/apicast/policy/liquid_context_debug/apicast-policy.json b/gateway/src/apicast/policy/liquid_context_debug/apicast-policy.json index ecbe8603e..f3a7c3dfe 100644 --- a/gateway/src/apicast/policy/liquid_context_debug/apicast-policy.json +++ b/gateway/src/apicast/policy/liquid_context_debug/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "Liquid context debug", "summary": "Inspects the available liquid context.", "description": [ @@ -16,6 +16,22 @@ "references." ], "version": "builtin", + "order": { + "before": [ + { + "name": "apicast", + "version": "builtin" + }, + { + "name": "upstream", + "version": "builtin" + }, + { + "name": "routing", + "version": "builtin" + } + ] + }, "configuration": { "type": "object", "properties": { diff --git a/gateway/src/apicast/policy/logging/apicast-policy.json b/gateway/src/apicast/policy/logging/apicast-policy.json index ccd56a87a..4ec568bb5 100644 --- a/gateway/src/apicast/policy/logging/apicast-policy.json +++ b/gateway/src/apicast/policy/logging/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "Logging", "summary": "Controls logging.", "description": [ diff --git a/gateway/src/apicast/policy/rate_limit/apicast-policy.json b/gateway/src/apicast/policy/rate_limit/apicast-policy.json index 17bd383ff..82d50680e 100644 --- a/gateway/src/apicast/policy/rate_limit/apicast-policy.json +++ b/gateway/src/apicast/policy/rate_limit/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "Edge limiting", "summary": "Adds rate limit.", "description": ["This policy adds rate limit."], diff --git a/gateway/src/apicast/policy/retry/apicast-policy.json b/gateway/src/apicast/policy/retry/apicast-policy.json index d9a1e3469..98579c060 100644 --- a/gateway/src/apicast/policy/retry/apicast-policy.json +++ b/gateway/src/apicast/policy/retry/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "Retry", "summary": "Allows to retry requests to the upstream", "description": "Allows to retry requests to the upstream", diff --git a/gateway/src/apicast/policy/rewrite_url_captures/apicast-policy.json b/gateway/src/apicast/policy/rewrite_url_captures/apicast-policy.json index 7d3e3dfa6..fdbb985d4 100644 --- a/gateway/src/apicast/policy/rewrite_url_captures/apicast-policy.json +++ b/gateway/src/apicast/policy/rewrite_url_captures/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "URL rewriting with captures", "summary": "Captures arguments in a URL and rewrites the URL using them.", "description": diff --git a/gateway/src/apicast/policy/routing/apicast-policy.json b/gateway/src/apicast/policy/routing/apicast-policy.json index acb6a77b0..89d79bf43 100644 --- a/gateway/src/apicast/policy/routing/apicast-policy.json +++ b/gateway/src/apicast/policy/routing/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "Routing", "summary": "Allows to modify the upstream URL of the request.", "description": [ @@ -10,6 +10,14 @@ "placed before it in the policy chain." ], "version": "builtin", + "order": { + "before": [ + { + "name": "apicast", + "version": "builtin" + } + ] + }, "configuration": { "type": "object", "definitions": { diff --git a/gateway/src/apicast/policy/soap/apicast-policy.json b/gateway/src/apicast/policy/soap/apicast-policy.json index 02c899c45..e0d201276 100644 --- a/gateway/src/apicast/policy/soap/apicast-policy.json +++ b/gateway/src/apicast/policy/soap/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "SOAP", "summary": "Adds support for a small subset of SOAP.", "description": diff --git a/gateway/src/apicast/policy/tls_validation/apicast-policy.json b/gateway/src/apicast/policy/tls_validation/apicast-policy.json index 32b85cf91..7705ec752 100644 --- a/gateway/src/apicast/policy/tls_validation/apicast-policy.json +++ b/gateway/src/apicast/policy/tls_validation/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "TLS Client Certificate Validation", "summary": "Validate certificates provided by the client during TLS handshake (HTTPS).", "description": [ diff --git a/gateway/src/apicast/policy/upstream/apicast-policy.json b/gateway/src/apicast/policy/upstream/apicast-policy.json index 17812c5a4..986d00f32 100644 --- a/gateway/src/apicast/policy/upstream/apicast-policy.json +++ b/gateway/src/apicast/policy/upstream/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "Upstream", "summary": "Allows to modify the upstream URL of the request based on its path.", "description": @@ -9,6 +9,14 @@ "When combined with the APIcast policy, the upstream policy should be ", "placed before it in the policy chain."], "version": "builtin", + "order": { + "before": [ + { + "name": "apicast", + "version": "builtin" + } + ] + }, "configuration": { "type": "object", "properties": { diff --git a/gateway/src/apicast/policy/upstream_connection/apicast-policy.json b/gateway/src/apicast/policy/upstream_connection/apicast-policy.json index bc524bb50..d3320ca0b 100644 --- a/gateway/src/apicast/policy/upstream_connection/apicast-policy.json +++ b/gateway/src/apicast/policy/upstream_connection/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "Upstream connection", "summary": "Allows to configure several options for the connections to the upstream", "description": "Allows to configure several options for the connections to the upstream", diff --git a/gateway/src/apicast/policy/url_rewriting/apicast-policy.json b/gateway/src/apicast/policy/url_rewriting/apicast-policy.json index 9573ad5fd..d1a854a47 100644 --- a/gateway/src/apicast/policy/url_rewriting/apicast-policy.json +++ b/gateway/src/apicast/policy/url_rewriting/apicast-policy.json @@ -1,5 +1,5 @@ { - "$schema": "http://apicast.io/policy-v1/schema#manifest#", + "$schema": "http://apicast.io/policy-v1.1/schema#manifest#", "name": "URL rewriting", "summary": "Allows to modify the path of a request.", "description": From e5ec477b4c2e062d5b8724b55b960459853b3ef3 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Fri, 5 Jul 2019 11:25:00 +0200 Subject: [PATCH 4/9] policy: add module that checks the order in the chain --- gateway/src/apicast/policy_order_checker.lua | 153 +++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 gateway/src/apicast/policy_order_checker.lua diff --git a/gateway/src/apicast/policy_order_checker.lua b/gateway/src/apicast/policy_order_checker.lua new file mode 100644 index 000000000..a5336344b --- /dev/null +++ b/gateway/src/apicast/policy_order_checker.lua @@ -0,0 +1,153 @@ +local setmetatable = setmetatable +local pairs = pairs +local ipairs = ipairs +local policy_loader = require 'apicast.policy_loader' +local insert = table.insert +local format = string.format + +local _M = {} + +local mt = { __index = _M } + +-- The name that appears in the schema is different from the name in an +-- instance of a policy. The name of the schema corresponds to the name of the +-- folder that contains the policy ("headers", "routing"), whereas the name in +-- an instantiated policy is "prettified" ("Headers policy", "Routing policy"). +-- +-- In a policy chain, we only have access to the "prettified" names, so in +-- order to compare them, we'll need to convert them using this function. +local function prettified_name(name_in_schema) + local policy_mod = policy_loader:pcall(name_in_schema) + return policy_mod and policy_mod._NAME +end + +local OrderRestrictions = {} + +function OrderRestrictions.new() + local self = setmetatable({}, { __index = OrderRestrictions }) + self.restrictions = {} + return self +end + +function OrderRestrictions.new_from_policy_manifests(policy_manifests) + local self = OrderRestrictions.new() + + -- Notice that the value is an array because there might be several versions + -- of a policy. + for policy_name, manifests in pairs(policy_manifests) do + for _, manifest in ipairs(manifests) do + if manifest.order then + local policy_in_manifest = { + name = prettified_name(policy_name), + version = manifest.version + } + + for _, policy_in_restriction in ipairs(manifest.order.before or {}) do + self:insert( + policy_in_manifest, + { + name = prettified_name(policy_in_restriction.name), + version = policy_in_restriction.version + } + ) + end + + for _, policy_in_restriction in ipairs(manifest.order.after or {}) do + self:insert( + { + name = prettified_name(policy_in_restriction.name), + version = policy_in_restriction.version + }, + policy_in_manifest + ) + end + end + end + end + + return self +end + +function OrderRestrictions:insert(policy_before, policy_after) + self.restrictions[policy_before.name] = self.restrictions[policy_before.name] or {} + self.restrictions[policy_before.name][policy_before.version] = + self.restrictions[policy_before.name][policy_before.version] or {} + + insert( + self.restrictions[policy_before.name][policy_before.version], + policy_after + ) +end + +function OrderRestrictions:policies_to_be_placed_after(policy_before) + return (self.restrictions[policy_before.name] and + self.restrictions[policy_before.name][policy_before.version]) or {} +end + +function _M.new(policy_manifests) + local self = setmetatable({}, mt) + self.restrictions = OrderRestrictions.new_from_policy_manifests(policy_manifests) + return self +end + +-- Returns a table with policies and their positions in the chain. +-- Example of a chain with 4 policies: +-- ['some_policy']['1.0.0'] = { 1, 2 } +-- ['some_policy']['2.0.0'] = 3 +-- ['another_policy']['builtin'] = 4 +local function positions_in_the_chain(policy_chain) + local res = {} + + for index, policy in ipairs(policy_chain) do + local policy_name = policy._NAME + local policy_version = policy._VERSION + + res[policy_name] = res[policy_name] or {} + res[policy_name][policy_version] = res[policy_name][policy_version] or {} + + insert(res[policy_name][policy_version], index) + end + + return res +end + +local function error_msg(policy_before, policy_after) + return format( + "%s (version: %s) should be placed before %s (version: %s)", + policy_before.name, policy_before.version, + policy_after.name, policy_after.version + ) +end + +-- Logs warnings when it detects that an order restriction has been violated in +-- the given policy chain. +function _M:check(policy_chain) + if not policy_chain then return end + + local positions = positions_in_the_chain(policy_chain) + + for index, policy in ipairs(policy_chain) do + local policy_name = policy._NAME + local policy_version = policy._VERSION + + local policies_to_be_placed_after = self.restrictions:policies_to_be_placed_after( + { name = policy_name, version = policy_version } + ) + + for _, policy_after in ipairs(policies_to_be_placed_after) do + local indexes_should_be_after = (positions[policy_after.name] and + positions[policy_after.name][policy_after.version]) or {} + + for _, index_after in ipairs(indexes_should_be_after) do + if index > index_after then + ngx.log( + ngx.WARN, + error_msg({ name = policy_name, version = policy_version }, policy_after) + ) + end + end + end + end +end + +return _M From 0fad2b9ab8c0b307bea32c801afa21d9d5115f1a Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Fri, 5 Jul 2019 11:25:23 +0200 Subject: [PATCH 5/9] spec: add specs for PolicyOrderChecker --- spec/policy_order_checker_spec.lua | 123 +++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 spec/policy_order_checker_spec.lua diff --git a/spec/policy_order_checker_spec.lua b/spec/policy_order_checker_spec.lua new file mode 100644 index 000000000..c0aff609f --- /dev/null +++ b/spec/policy_order_checker_spec.lua @@ -0,0 +1,123 @@ +local policy_manifests_loader = require 'apicast.policy_manifests_loader' +local PolicyOrderChecker = require 'apicast.policy_order_checker' +local IpCheckPolicy = require 'apicast.policy.ip_check' +local HeadersPolicy = require'apicast.policy.headers' +local CORSPolicy = require 'apicast.policy.cors' +local DefaultCredentialsPolicy = require 'apicast.policy.default_credentials' +local APIcastPolicy = require 'apicast.policy.apicast' + +describe('Policy Order Checker', function() + describe('.check', function() + -- Use the real manifests of the built-in policies + local manifests = policy_manifests_loader.get_all() + + local order_checker = PolicyOrderChecker.new(manifests) + + before_each(function() + stub(ngx, 'log') + end) + + it('does not show errors when there are no policies in the chain', function() + order_checker:check({}) + + assert.stub(ngx.log).was_not_called() + end) + + it('does not show errors when the chain is nil', function() + order_checker:check() + + assert.stub(ngx.log).was_not_called() + end) + + it('does not show errors when there are no order violations', function() + -- There are no order restrictions between the headers policy and the IP + -- check one. + local headers_policy_instance = HeadersPolicy.new({}) + local ip_check_policy_instance = IpCheckPolicy.new( + { ips = { '1.2.3.4' }, check_type = 'whitelist' } + ) + local chain = { headers_policy_instance, ip_check_policy_instance } + + order_checker:check(chain) + + assert.stub(ngx.log).was_not_called() + end) + + it('shows an error when there is a "before" order violation', function() + -- The CORS policy needs to be placed before the apicast one. + local apicast_policy_instance = APIcastPolicy.new({}) + local cors_policy_instance = CORSPolicy.new({}) + local chain = { apicast_policy_instance, cors_policy_instance } + + order_checker:check(chain) + + assert.stub(ngx.log).was_called_with( + ngx.WARN, + 'CORS Policy (version: builtin) should be placed before APIcast (version: builtin)' + ) + end) + + it('shows an error for each order violation when there are several of them', function() + -- Both the CORS policy and the default credentials one need to be placed + -- before the apicast one. + local apicast_policy_instance = APIcastPolicy.new({}) + local cors_policy_instance = CORSPolicy.new({}) + local default_creds_policy_instance = DefaultCredentialsPolicy.new( + { auth_type = 'user_key', user_key = 'uk' } + ) + local chain = { + apicast_policy_instance, + cors_policy_instance, + default_creds_policy_instance + } + + order_checker:check(chain) + + assert.stub(ngx.log).was_called(2) + + assert.stub(ngx.log).was_called_with( + ngx.WARN, + 'CORS Policy (version: builtin) should be placed before APIcast (version: builtin)' + ) + + assert.stub(ngx.log).was_called_with( + ngx.WARN, + 'Default credentials policy (version: builtin) should be placed before APIcast (version: builtin)' + ) + end) + + it('shows errors when there are several instances of a policy and one of them violates the rules', function() + -- The CORS policy needs to be placed before the apicast one. + local cors_policy_instance_1 = CORSPolicy.new({}) + local apicast_policy_instance = APIcastPolicy.new({}) + local cors_policy_instance_2 = CORSPolicy.new({}) + local chain = { + cors_policy_instance_1, + apicast_policy_instance, + cors_policy_instance_2 + } + + order_checker:check(chain) + + assert.stub(ngx.log).was_called(1) + assert.stub(ngx.log).was_called_with( + ngx.WARN, + 'CORS Policy (version: builtin) should be placed before APIcast (version: builtin)' + ) + end) + + it('does no show an error when the version does not match the one in the restriction', function() + -- The CORS policy needs to be placed before the apicast one (version + -- 'builtin'). This test instantiates it with a different version to + -- check that no errors are logged. + local apicast_policy_instance = APIcastPolicy.new({}) + apicast_policy_instance._VERSION = "0.1" + local cors_policy_instance = CORSPolicy.new({}) + local chain = { apicast_policy_instance, cors_policy_instance } + + order_checker:check(chain) + + assert.stub(ngx.log).was_not_called() + end) + end) +end) From 36f091eea2e93d68c1f40e67783d5998304045d5 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Fri, 5 Jul 2019 11:25:38 +0200 Subject: [PATCH 6/9] policy_chain: add method to check the order --- gateway/src/apicast/policy_chain.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gateway/src/apicast/policy_chain.lua b/gateway/src/apicast/policy_chain.lua index d70929365..ffa9851b1 100644 --- a/gateway/src/apicast/policy_chain.lua +++ b/gateway/src/apicast/policy_chain.lua @@ -22,6 +22,8 @@ require('apicast.loader') local linked_list = require('apicast.linked_list') local policy_phases = require('apicast.policy').phases local policy_loader = require('apicast.policy_loader') +local PolicyOrderChecker = require('apicast.policy_order_checker') +local policy_manifests_loader = require('apicast.policy_manifests_loader') local _M = { @@ -183,6 +185,14 @@ function _M:add_policy(name, version, ...) end end +-- Checks if there are any policies placed in the wrong place in the chain. +-- It doesn't return anything, it prints error messages when there's a problem. +function _M:check_order(manifests) + PolicyOrderChecker.new( + manifests or policy_manifests_loader.get_all() + ):check(self) +end + local function call_chain(phase_name) return function(self, context) for i=1, #self do From 11531ca67f614a3bc5976dedf0af6e2846cbc596 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Fri, 5 Jul 2019 11:26:02 +0200 Subject: [PATCH 7/9] configuration: check order of policies when parsing --- gateway/src/apicast/configuration.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gateway/src/apicast/configuration.lua b/gateway/src/apicast/configuration.lua index af4eb0898..5f399bf09 100644 --- a/gateway/src/apicast/configuration.lua +++ b/gateway/src/apicast/configuration.lua @@ -77,7 +77,9 @@ local function build_policy_chain(policies) end end - return policy_chain.new(chain) + local built_chain = policy_chain.new(chain) + built_chain:check_order() + return built_chain end function _M.parse_service(service) From 923e5ed6d037f732d660b3b4108a3e9ba6031941 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Fri, 5 Jul 2019 11:26:48 +0200 Subject: [PATCH 8/9] t: test checks of order of policies in the chain --- t/apicast-policies-order.t | 114 +++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 t/apicast-policies-order.t diff --git a/t/apicast-policies-order.t b/t/apicast-policies-order.t new file mode 100644 index 000000000..76544d208 --- /dev/null +++ b/t/apicast-policies-order.t @@ -0,0 +1,114 @@ +use lib 't'; +use Test::APIcast::Blackbox 'no_plan'; + +# Load the config on every request, because errors related with the order of +# policies in the chain only appear when loading the config. If we used a cache, +# the second request would fail because the error would not be there. +env_to_apicast( + 'APICAST_CONFIGURATION_LOADER' => 'lazy', + 'APICAST_CONFIGURATION_CACHE' => 0 +); + +run_tests(); + +__DATA__ + +=== TEST 1: shows an error when policies are placed in an incorrect order +The default credentials policy should be placed after the apicast policy in the +chain. In this test, we are going to place them in the reverse order and check +that APIcast logs an error. +The request returns a 401 status code (credentials missing) because APIcast +cannot set the default credentials. +--- configuration +{ + "services": [ + { + "id": 42, + "backend_version": 1, + "backend_authentication_type": "service_token", + "backend_authentication_value": "token-value", + "proxy": { + "policy_chain": [ + { + "name": "apicast.policy.apicast" + }, + { + "name": "apicast.policy.default_credentials", + "configuration": { + "auth_type": "user_key", + "user_key": "uk" + } + } + ], + "api_backend": "http://test:$TEST_NGINX_SERVER_PORT/", + "proxy_rules": [ + { "pattern": "/", "http_method": "GET", "metric_system_name": "hits", "delta": 2 } + ] + } + } + ] +} +--- backend + location /transactions/authrep.xml { + content_by_lua_block { + local expected = "service_token=token-value&service_id=42&usage%5Bhits%5D=2&user_key=uk" + require('luassert').same(ngx.decode_args(expected), ngx.req.get_uri_args(0)) + } + } +--- upstream + location / { + echo 'yay, api backend'; + } +--- request +GET / +--- error_code: 401 +--- error_log +Default credentials policy (version: builtin) should be placed before APIcast (version: builtin) + + +=== TEST 2: does not show any error when policies are placed in the correct order +--- configuration +{ + "services": [ + { + "id": 42, + "backend_version": 1, + "backend_authentication_type": "service_token", + "backend_authentication_value": "token-value", + "proxy": { + "policy_chain": [ + { + "name": "apicast.policy.default_credentials", + "configuration": { + "auth_type": "user_key", + "user_key": "uk" + } + }, + { + "name": "apicast.policy.apicast" + } + ], + "api_backend": "http://test:$TEST_NGINX_SERVER_PORT/", + "proxy_rules": [ + { "pattern": "/", "http_method": "GET", "metric_system_name": "hits", "delta": 2 } + ] + } + } + ] +} +--- backend + location /transactions/authrep.xml { + content_by_lua_block { + local expected = "service_token=token-value&service_id=42&usage%5Bhits%5D=2&user_key=uk" + require('luassert').same(ngx.decode_args(expected), ngx.req.get_uri_args(0)) + } + } +--- upstream + location / { + echo 'yay, api backend'; + } +--- request +GET / +--- error_code: 200 +--- no_error_log +should be placed From f73f239f4255b8080ffdeeddfb6f2477a476d092 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Fri, 5 Jul 2019 12:28:15 +0200 Subject: [PATCH 9/9] CHANGELOG: add policies order check --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6527cdde2..e87a0be45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - Extended variables in Liquid template operations [PR #1081](https://github.com/3scale/APIcast/pull/1081) +- Introduce possibility of specifying policy order restrictions in their schemas. APIcast now shows a warning when those restrictions are not respected [#1088](https://github.com/3scale/APIcast/pull/1088), [THREESCALE-2896](https://issues.jboss.org/browse/THREESCALE-2896) ## [3.6.0-beta1] - 2019-06-18