This is an automated email from the ASF dual-hosted git repository. vatamane pushed a commit to branch fix-json-order-false-positive-in-scanner in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit 6e09ff49419197d93cc5f807afc58496746f556d Author: Nick Vatamaniuc <[email protected]> AuthorDate: Thu Aug 22 19:25:20 2024 -0400 Fix json order false positives in quickjs scanner plugin After scanning some production clusters, noticed that QuickJS and SM 91 seems to be using a different json order than SM 1.8.5. A KV proplist ejson prompt result could show up as a compatibility issue when the JSON key order is different. To fix it, use maps instead of ejson KVs. Could have just used a jiffy:encode/decode pair, but it seemed wasteful to serialize everything when we just want to transform the proplists so created a small utility function. --- src/couch/src/couch_util.erl | 10 ++++++++++ src/couch/test/eunit/couch_util_tests.erl | 13 +++++++++++++ src/couch_quickjs/src/couch_quickjs_scanner_plugin.erl | 5 ++++- .../test/couch_quickjs_scanner_plugin_tests.erl | 9 ++++++++- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/couch/src/couch_util.erl b/src/couch/src/couch_util.erl index 18faa9695..ee3c3fc4c 100644 --- a/src/couch/src/couch_util.erl +++ b/src/couch/src/couch_util.erl @@ -46,6 +46,7 @@ -export([verify_hash_names/2]). -export([get_config_hash_algorithms/0]). -export([remove_sensitive_data/1]). +-export([ejson_to_map/1]). -include_lib("couch/include/couch_db.hrl"). @@ -852,3 +853,12 @@ remove_sensitive_data(KVList) -> KVList1 = lists:keyreplace(<<"password">>, 1, KVList, {<<"password">>, <<"****">>}), % some KVList entries are atoms, so test fo this too lists:keyreplace(password, 1, KVList1, {password, <<"****">>}). + +ejson_to_map(#{} = Val) -> + maps:map(fun(_, V) -> ejson_to_map(V) end, Val); +ejson_to_map(Val) when is_list(Val) -> + lists:map(fun(V) -> ejson_to_map(V) end, Val); +ejson_to_map({Val}) when is_list(Val) -> + maps:from_list(lists:map(fun({K, V}) -> {K, ejson_to_map(V)} end, Val)); +ejson_to_map(Val) -> + Val. diff --git a/src/couch/test/eunit/couch_util_tests.erl b/src/couch/test/eunit/couch_util_tests.erl index 62ec20775..5f8f1ce43 100644 --- a/src/couch/test/eunit/couch_util_tests.erl +++ b/src/couch/test/eunit/couch_util_tests.erl @@ -193,3 +193,16 @@ json_decode_test_() -> ?_assertEqual({[]}, couch_util:json_decode(<<"{}">>, [])), ?_assertEqual(#{}, couch_util:json_decode(<<"{}">>, [return_maps])) ]. + +ejson_to_map_test() -> + ?assertEqual(0, couch_util:ejson_to_map(0)), + ?assertEqual(true, couch_util:ejson_to_map(true)), + ?assertEqual(0.1, couch_util:ejson_to_map(0.1)), + ?assertEqual(#{}, couch_util:ejson_to_map(#{})), + ?assertEqual(#{a => b}, couch_util:ejson_to_map(#{a => b})), + ?assertEqual([], couch_util:ejson_to_map([])), + ?assertEqual([1], couch_util:ejson_to_map([1])), + ?assertEqual(#{}, couch_util:ejson_to_map({[]})), + ?assertEqual(#{a => 1, b => 2}, couch_util:ejson_to_map({[{b, 2}, {a, 1}]})), + ?assertEqual(#{<<"a">> => [1, #{}]}, couch_util:ejson_to_map({[{<<"a">>, [1, {[]}]}]})), + ?assertEqual([#{true => 1}], couch_util:ejson_to_map([{[{true, 1}]}])). diff --git a/src/couch_quickjs/src/couch_quickjs_scanner_plugin.erl b/src/couch_quickjs/src/couch_quickjs_scanner_plugin.erl index ee8a76bcc..8d80388e8 100644 --- a/src/couch_quickjs/src/couch_quickjs_scanner_plugin.erl +++ b/src/couch_quickjs/src/couch_quickjs_scanner_plugin.erl @@ -579,8 +579,11 @@ proc(Pid) -> }. prompt(#proc{} = Proc, Prompt) -> + % Make sure to transform ejson with key values {[{K, V}, ...]} to + % one containing maps to avoid false positives resulting from + % differences in json key encoding order try - couch_query_servers:proc_prompt(Proc, Prompt) + couch_util:ejson_to_map(couch_query_servers:proc_prompt(Proc, Prompt)) catch Tag:Err -> {error, {Tag, Err}} diff --git a/src/couch_quickjs/test/couch_quickjs_scanner_plugin_tests.erl b/src/couch_quickjs/test/couch_quickjs_scanner_plugin_tests.erl index e91081f96..ed7d16410 100644 --- a/src/couch_quickjs/test/couch_quickjs_scanner_plugin_tests.erl +++ b/src/couch_quickjs/test/couch_quickjs_scanner_plugin_tests.erl @@ -392,6 +392,13 @@ ddoc_view(Doc) -> v_expr_fun1 => #{map => <<"(function(doc) {emit(1,2)})\n">>}, v_expr_fun2 => #{map => <<"(function(doc) {emit(3,4)});">>}, v_expr_fun3 => #{map => <<"y=9;\n(function(doc) {emit(5,y)})">>}, - v_expr_fun4 => #{map => <<"x=10; function(doc) {emit(x,6)}\n">>} + v_expr_fun4 => #{map => <<"x=10; function(doc) {emit(x,6)}\n">>}, + v_emit_map1 => #{ + map => << + "function(doc){ \n", + " emit(42, {NaN:1, \"2\": 1}); \n" + "};\n" + >> + } } }.
