<commit_before>local _M = {
  _VERSION = '0.01',
}

local len = string.len
local pairs = pairs
local type = type
local tostring = tostring
local next = next
local lower = string.lower
local insert = table.insert
local setmetatable = setmetatable
local null = ngx.null

local env = require 'resty.env'
local resty_url = require 'resty.url'
local util = require 'apicast.util'
local policy_chain = require 'apicast.policy_chain'
local mapping_rule = require 'apicast.mapping_rule'
local tab_new = require('resty.core.base').new_tab

local re = require 'ngx.re'
local match = ngx.re.match

local mt = { __index = _M, __tostring = function() return 'Configuration' end }

local function map(func, tbl)
  local newtbl = {}
  for i,v in pairs(tbl) do
    newtbl[i] = func(v)
  end
  return newtbl
end

local function value(val)
    if val ~= null then return val end
end

local Service = require 'apicast.configuration.service'

local noop = function() end
local function readonly_table(table)
    return setmetatable({}, { __newindex = noop, __index = table })
end

local empty_t = readonly_table()
local fake_backend = readonly_table({ endpoint = 'http://127.0.0.1:8081' })

local function backend_endpoint(proxy)
    local backend_endpoint_override = resty_url.parse(env.get("BACKEND_ENDPOINT_OVERRIDE"))
    local backend = backend_endpoint_override or proxy.backend or empty_t

    if backend == empty_t then
        local test_nginx_server_port = env.get('TEST_NGINX_SERVER_PORT')
        if test_nginx_server_port then
            return { endpoint =  'http://127.0.0.1:' .. test_nginx_server_port }
        else
            return fake_backend
        end
    else
        return { endpoint = backend.endpoint or tostring(backend), host = backend.host }
    end
end

local function build_policy_chain(policies)
  if not value(policies) then return nil, 'no policy chain' end

  local chain = tab_new(#policies, 0)

  for i=1, #policies do
      local policy, err = policy_chain.load_policy(policies[i].name, policies[i].version, policies[i].configuration)

      if policy then
        insert(chain, policy)
      elseif err then
        ngx.log(ngx.WARN, 'failed to load policy: ', policies[i].name, ' version: ', policies[i].version, ' err: ', err)
      end
  end

  return policy_chain.new(chain)
end

function _M.parse_service(service)
  local backend_version = tostring(service.backend_version)
  local proxy = service.proxy or empty_t
  local backend = backend_endpoint(proxy)

  return Service.new({
      id = tostring(service.id or 'default'),
      system_name = tostring(service.system_name or ''),
      backend_version = backend_version,
      authentication_method = proxy.authentication_method or backend_version,
      hosts = proxy.hosts or { 'localhost' }, -- TODO: verify localhost is good default
      api_backend = proxy.api_backend,
      policy_chain = build_policy_chain(proxy.policy_chain),
      error_auth_failed = proxy.error_auth_failed or 'Authentication failed',
      error_limits_exceeded = proxy.error_limits_exceeded or 'Limits exceeded',
      error_auth_missing = proxy.error_auth_missing or 'Authentication parameters missing',
      auth_failed_headers = proxy.error_headers_auth_failed or 'text/plain; charset=utf-8',
      limits_exceeded_headers = proxy.error_headers_limits_exceeded or 'text/plain; charset=utf-8',
      auth_missing_headers = proxy.error_headers_auth_missing or 'text/plain; charset=utf-8',<commit_msg>configuration: check order of policies when parsing<commit_after>local _M = {
  _VERSION = '0.01',
}

local len = string.len
local pairs = pairs
local type = type
local tostring = tostring
local next = next
local lower = string.lower
local insert = table.insert
local setmetatable = setmetatable
local null = ngx.null

local env = require 'resty.env'
local resty_url = require 'resty.url'
local util = require 'apicast.util'
local policy_chain = require 'apicast.policy_chain'
local mapping_rule = require 'apicast.mapping_rule'
local tab_new = require('resty.core.base').new_tab

local re = require 'ngx.re'
local match = ngx.re.match

local mt = { __index = _M, __tostring = function() return 'Configuration' end }

local function map(func, tbl)
  local newtbl = {}
  for i,v in pairs(tbl) do
    newtbl[i] = func(v)
  end
  return newtbl
end

local function value(val)
    if val ~= null then return val end
end

local Service = require 'apicast.configuration.service'

local noop = function() end
local function readonly_table(table)
    return setmetatable({}, { __newindex = noop, __index = table })
end

local empty_t = readonly_table()
local fake_backend = readonly_table({ endpoint = 'http://127.0.0.1:8081' })

local function backend_endpoint(proxy)
    local backend_endpoint_override = resty_url.parse(env.get("BACKEND_ENDPOINT_OVERRIDE"))
    local backend = backend_endpoint_override or proxy.backend or empty_t

    if backend == empty_t then
        local test_nginx_server_port = env.get('TEST_NGINX_SERVER_PORT')
        if test_nginx_server_port then
            return { endpoint =  'http://127.0.0.1:' .. test_nginx_server_port }
        else
            return fake_backend
        end
    else
        return { endpoint = backend.endpoint or tostring(backend), host = backend.host }
    end
end

local function build_policy_chain(policies)
  if not value(policies) then return nil, 'no policy chain' end

  local chain = tab_new(#policies, 0)

  for i=1, #policies do
      local policy, err = policy_chain.load_policy(policies[i].name, policies[i].version, policies[i].configuration)

      if policy then
        insert(chain, policy)
      elseif err then
        ngx.log(ngx.WARN, 'failed to load policy: ', policies[i].name, ' version: ', policies[i].version, ' err: ', err)
      end
  end

  local built_chain = policy_chain.new(chain)
  built_chain:check_order()
  return built_chain
end

function _M.parse_service(service)
  local backend_version = tostring(service.backend_version)
  local proxy = service.proxy or empty_t
  local backend = backend_endpoint(proxy)

  return Service.new({
      id = tostring(service.id or 'default'),
      system_name = tostring(service.system_name or ''),
      backend_version = backend_version,
      authentication_method = proxy.authentication_method or backend_version,
      hosts = proxy.hosts or { 'localhost' }, -- TODO: verify localhost is good default
      api_backend = proxy.api_backend,
      policy_chain = build_policy_chain(proxy.policy_chain),
      error_auth_failed = proxy.error_auth_failed or 'Authentication failed',
      error_limits_exceeded = proxy.error_limits_exceeded or 'Limits exceeded',
      error_auth_missing = proxy.error_auth_missing or 'Authentication parameters missing',
      auth_failed_headers = proxy.error_headers_auth_failed or 'text/plain; charset=utf-8',
      limits_exceeded_headers = proxy.error_headers_limits_exceeded or 'text/plain; charset=utf-8',
      auth_missing_headers = proxy.error_headers_auth_missing or 'text/plain; charset=utf-8',
{'fraction_non_alphanumeric': 0.09311913562695479, 'fraction_numerical': 0.0068239977253340914, 'mean_word_length': 3.9964488636363638, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6944026', 'n_tokens_mistral': 2181, 'n_tokens_neox': 2141, 'n_words': 585}