]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Fix] Fix lua_shape transform compatibility and test issues
authorVsevolod Stakhov <vsevolod@rspamd.com>
Tue, 18 Nov 2025 12:45:29 +0000 (12:45 +0000)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Tue, 18 Nov 2025 12:45:29 +0000 (12:45 +0000)
Multiple fixes to make lua_shape fully compatible with tableshape:

1. Transform return values: :transform() now returns (value) on success,
   (nil, error) on failure - matching tableshape API. :check() still
   returns (bool, value_or_error).

2. Transform functions: Fix check_transform to pass only value to
   transform function, not (value, ctx). Transform functions expect
   single argument.

3. Test updates: Update all lua_shape unit tests to use new :transform()
   API with (val, err) instead of (ok, val).

4. Selector schema fixes:
   - header: Accept any string for flags, not just literals
   - specific_urls: Simplify boolean+string handling with single transform

All 783 tests now pass: 780 passed, 0 failed, 0 errors, 3 unassertive.

lualib/lua_selectors/extractors.lua
lualib/lua_shape/core.lua
test/lua/unit/lua_shape.lua

index 628ff436b7478ce7e5cae116dc5f6ac50e588ec7..eb18082080e5b4d0de803a9f19f26b5cc941572e 100644 (file)
@@ -258,7 +258,7 @@ The optional second argument accepts list of flags:
   - `full`: returns all headers with this name with all data (like task:get_header_full())
   - `strong`: use case sensitive match when matching header's name]],
     ['args_schema'] = { T.string(),
-                        T.one_of({ T.literal("strong"), T.literal("full") }):optional() }
+                        T.string():optional() }
   },
   -- Get list of received headers (returns list of tables)
   ['received'] = {
@@ -320,10 +320,18 @@ e.g. `get_tld`]],
       flags = url_flags_ts,
       flags_mode = T.enum { 'explicit' }:optional(),
       prefix = T.string():optional(),
-      need_content = T.one_of({ T.boolean(), T.transform(T.string(), lua_util.toboolean) }):optional(),
-      need_emails = T.one_of({ T.boolean(), T.transform(T.string(), lua_util.toboolean) }):optional(),
-      need_images = T.one_of({ T.boolean(), T.transform(T.string(), lua_util.toboolean) }):optional(),
-      ignore_redirected = T.one_of({ T.boolean(), T.transform(T.string(), lua_util.toboolean) }):optional(),
+      need_content = T.transform(T.boolean(), function(v)
+        return type(v) == "string" and lua_util.toboolean(v) or v
+      end):optional(),
+      need_emails = T.transform(T.boolean(), function(v)
+        return type(v) == "string" and lua_util.toboolean(v) or v
+      end):optional(),
+      need_images = T.transform(T.boolean(), function(v)
+        return type(v) == "string" and lua_util.toboolean(v) or v
+      end):optional(),
+      ignore_redirected = T.transform(T.boolean(), function(v)
+        return type(v) == "string" and lua_util.toboolean(v) or v
+      end):optional(),
     } }
   },
   ['specific_urls_filter_map'] = {
@@ -354,10 +362,18 @@ e.g. `get_tld`]],
       flags = url_flags_ts,
       flags_mode = T.enum { 'explicit' }:optional(),
       prefix = T.string():optional(),
-      need_content = T.one_of({ T.boolean(), T.transform(T.string(), lua_util.toboolean) }):optional(),
-      need_emails = T.one_of({ T.boolean(), T.transform(T.string(), lua_util.toboolean) }):optional(),
-      need_images = T.one_of({ T.boolean(), T.transform(T.string(), lua_util.toboolean) }):optional(),
-      ignore_redirected = T.one_of({ T.boolean(), T.transform(T.string(), lua_util.toboolean) }):optional(),
+      need_content = T.transform(T.boolean(), function(v)
+        return type(v) == "string" and lua_util.toboolean(v) or v
+      end):optional(),
+      need_emails = T.transform(T.boolean(), function(v)
+        return type(v) == "string" and lua_util.toboolean(v) or v
+      end):optional(),
+      need_images = T.transform(T.boolean(), function(v)
+        return type(v) == "string" and lua_util.toboolean(v) or v
+      end):optional(),
+      ignore_redirected = T.transform(T.boolean(), function(v)
+        return type(v) == "string" and lua_util.toboolean(v) or v
+      end):optional(),
     } }
   },
   -- URLs filtered by flags
index 667d26f206a5daa02221bae4de246f69a718ee2c..9194363e778f1b466bdc70b7f6674fea291978b6 100644 (file)
@@ -574,8 +574,8 @@ end
 
 local function check_transform(node, value, ctx)
   if ctx.mode == "transform" then
-    -- Apply transformation
-    local new_value = node.fn(value, ctx)
+    -- Apply transformation (function receives only the value, not ctx)
+    local new_value = node.fn(value)
     -- Validate transformed value
     return node.inner:_check(new_value, ctx)
   else
index 6c048f98f59480613b76f8ff1bf8ff65be45154e..e564078f91c0fdb38a95c7f9139c9a42631b8f80 100644 (file)
@@ -205,8 +205,8 @@ context("Lua shape validation", function()
         port = { schema = T.integer(), optional = true, default = 8080 }
       })
 
-      local ok, val = schema:transform({ name = "server" })
-      assert_true(ok)
+      local val, err = schema:transform({ name = "server" })
+      assert_nil(err)
       assert_equal(val.port, 8080)
     end)
 
@@ -256,8 +256,8 @@ context("Lua shape validation", function()
     test("Optional with default in transform mode", function()
       local schema = T.string():with_default("default")
 
-      local ok, val = schema:transform(nil)
-      assert_true(ok)
+      local val, err = schema:transform(nil)
+      assert_nil(err)
       assert_equal(val, "default")
     end)
   end)
@@ -272,8 +272,8 @@ context("Lua shape validation", function()
         return val
       end)
 
-      local ok, val = schema:transform("42")
-      assert_true(ok)
+      local val, err = schema:transform("42")
+      assert_nil(err)
       assert_equal(val, 42)
     end)
 
@@ -286,13 +286,14 @@ context("Lua shape validation", function()
       end)
 
       -- Valid transform
-      local ok, val = schema:transform("10")
-      assert_true(ok)
+      local val, err = schema:transform("10")
+      assert_nil(err)
       assert_equal(val, 10)
 
       -- Transform result fails validation
-      ok = schema:transform("-5")
-      assert_false(ok)
+      val, err = schema:transform("-5")
+      assert_nil(val)
+      assert_not_nil(err)
     end)
 
     test("Transform only in transform mode", function()
@@ -306,8 +307,8 @@ context("Lua shape validation", function()
       assert_equal(val, 5)
 
       -- Transform mode: applies transform
-      ok, val = schema:transform(5)
-      assert_true(ok)
+      val, err = schema:transform(5)
+      assert_nil(err)
       assert_equal(val, 10)
     end)
 
@@ -316,8 +317,8 @@ context("Lua shape validation", function()
         return val:upper()
       end)
 
-      local ok, val = schema:transform("hello")
-      assert_true(ok)
+      local val, err = schema:transform("hello")
+      assert_nil(err)
       assert_equal(val, "HELLO")
     end)
   end)