leafo / tableshape

Test the shape or structure of a Lua table, inspired by React.PropTypes & LPeg
111 stars 9 forks source link

nested `extra_fields` in combination with `shape` #17

Open Conni2461 opened 1 year ago

Conni2461 commented 1 year ago

this is like a really weird issue and i am sorry for even opening it but i kinda have a question. I somewhat know lua/luajit because i am a maintainer of a somewhat popular project, so a coworker asked me if i could look into a lua bug that he had with another open source software, rspamd.

That software uses tableshape, so i looked into that rspamd bug (https://github.com/rspamd/rspamd/issues/4318#issuecomment-1453502529) and after that into tableshape documentation + source code and i think i found a missuse of tableshape in rspamd. I know that is not your issue but i kinda wanna make sure that its actually a missuse.

So i've created a minimal reproduce of the code that is being executed in rspamd.

package.path = package.path .. ";./?.lua;"
local ts = require("contrib.lua-tableshape.tableshape").types

local lua_redis_common = ts.shape {
  password = ts.string:is_optional(),
}

local lua_redis =
  -- Allow separate read/write servers to allow usage in the `extra_fields`
  ts.shape({
    read_servers = ts.string + ts.array_of(ts.string),
  }, { extra_fields = lua_redis_common }) + ts.shape({
    write_servers = ts.string + ts.array_of(ts.string),
  }, { extra_fields = lua_redis_common }) + ts.shape({
    read_servers = ts.string + ts.array_of(ts.string),
    write_servers = ts.string + ts.array_of(ts.string),
  }, { extra_fields = lua_redis_common })

local settings_schema = ts.shape({
  key_prefix = ts.string,
  nrows = ts.number,
  compress = ts.boolean,
}, { extra_fields = lua_redis })

local obj1 = {
  key_prefix = "rs_history",
  nrows = 1000,
  compress = true,

  read_servers = "127.0.0.1:6381",
  write_servers = "127.0.0.1:6381",
  -- password = "<password hidden>",
}

local res, err = settings_schema:transform(obj1)
print(res, err)

as soon as i comment in password everything "explodes" with the following error

nil     field "password": expected { "read_servers" = type "string", or array of type "string" }, { "write_servers" = type "string", or array of type "string" }, { "write_servers" = type "string", or array of type "string", "read_servers
" = type "string", or array of type "string" }, { "servers" = type "string", or array of type "string" }, or { "server" = type "string", or array of type "string" }

But it should be possible to optionally add password to that table.

If you confirm that this is a usecase that is currently not supported and never will be i could just rewrite the code in rspamd :laughing: