[keycloak] Fix destructive shallow merge of JSON data#17430
[keycloak] Fix destructive shallow merge of JSON data#17430chrisberkhout wants to merge 6 commits intoelastic:mainfrom
Conversation
|
Pinging @elastic/security-service-integrations (Team:Security-Service Integrations) |
🚀 Benchmarks reportTo see the full report comment with |
efd6
left a comment
There was a problem hiding this comment.
Changelog and manifest entries?
| } | ||
| mergeMaps(ctx, ctx.json); | ||
|
|
||
| # // Tests of mergeMaps that can the be run manually in Painless Lab |
There was a problem hiding this comment.
Is there a way to engineer these tests into pipeline tests in a reasonably concise way? If not, I'd suggest putting these either in the PR description or commit message (the latter being my preference, though entirely up to you given the length), and make it runnable from a terminal, e.g.
: "${KIBANA_URL:=https://localhost:5601}"
: "${KIBANA_USER:=elastic}"
: "${KIBANA_PASSWORD:=changeme}"
painless=$(cat <<'PAINLESS'
def mergeMaps(Map map1, Map map2) {
for (def key : map2.keySet()) {
if (!map1.containsKey(key)
|| map1[key] == null
|| map1[key] == ""
|| (map1[key] instanceof Map && map1[key].isEmpty())) {
map1[key] = map2[key];
} else if (map1[key] != map2[key]) {
if (map1[key] instanceof Map && map2[key] instanceof Map) {
map1[key] = mergeMaps(map1[key], map2[key]);
} else if (map1[key] instanceof List) {
def combined = new LinkedHashSet(map1[key]);
if (map2[key] instanceof List) {
combined.addAll(map2[key]);
} else if (map2[key] != null) {
combined.add(map2[key]);
}
map1[key] = new ArrayList(combined);
}
}
}
return map1;
}
def runTests(List tests) {
def results = new ArrayList();
for (def t : tests) {
def got = mergeMaps(t["map1"], t["map2"]);
results.add([
"test": t["name"],
"passed": got.equals(t["expect"]),
"got": got,
"expected": t["expect"]
]);
}
def passed = new ArrayList();
def failed = new ArrayList();
for (def r : results) {
if (r["passed"]) passed.add(r);
else failed.add(r);
}
def result = new LinkedHashMap();
result.put("passed_all", passed.size() == tests.size());
result.put("passed_count", passed.size());
result.put("failed_count", failed.size());
result.put("failed", failed);
return result;
}
def tests = [
[
"name": "fill_missing_key",
"map1": ["a": 1],
"map2": ["b": 2],
"expect": ["a": 1, "b": 2]
],
[
"name": "no_overwrite_non_empty_scalar",
"map1": ["a": 1],
"map2": ["a": 2],
"expect": ["a": 1]
],
[
"name": "overwrite_null_empty_string_empty_map",
"map1": ["n": null, "s": "", "m": [:], "keep": "x"],
"map2": ["n": 5, "s": "hi", "m": ["k": 1], "keep": "y"],
"expect": ["n": 5, "s": "hi", "m": ["k": 1], "keep": "x"]
],
[
"name": "deep_merge_nested_maps",
"map1": ["o": ["x": 1, "y": ""]],
"map2": ["o": ["x": 2, "y": "filled", "z": 3]],
"expect": ["o": ["x": 1, "y": "filled", "z": 3]]
],
[
"name": "list_merge_empty_list_and_dedupe",
"map1": ["l": [], "l2": [1, 2]],
"map2": ["l": 7, "l2": [2, 3, 1]],
"expect": ["l": [7], "l2": [1, 2, 3]]
],
[
"name": "list_merge_does_not_add_null_scalar",
"map1": ["l": [1]],
"map2": ["l": null],
"expect": ["l": [1]]
]
];
runTests(tests);
PAINLESS
)
jq -n --arg src "$painless" '{"script":{"source":$src}}' |
curl -sSk \
-u "${KIBANA_USER}:${KIBANA_PASSWORD}" \
-XPOST "${KIBANA_URL}/api/console/proxy?path=_scripts%2Fpainless%2F_execute&method=POST" \
-H 'kbn-xsrf: true' \
-H 'Content-Type: application/json' \
-d @- |
jq .
There was a problem hiding this comment.
Okay. A pipeline test like below covers all those cases and is processed okay, but it fails because the fields aren't defined. I think trying to jam those cases into existing field names would get too confusing, so I'll just put a script in the commit description.
{
"events": [
{
"event": {
"original": "{\"newkey\":2,\"scalar\":\"conflicting\",\"null\":\"non-null\",\"empty_string\":\"non-null\",\"empty_map\":\"non-null\",\"map\":{\"additional\":\"val\",\"nested\":{\"additional_nested\":\"val\"}},\"array\":[2,null,3],\"empty_array\":1}"
},
"scalar": 1,
"null": null,
"empty_string": "",
"empty_map": {},
"empty_array": [],
"array": [
1,
2
],
"map": {
"existing": "value",
"nested": {
"existing_nested": "value"
}
}
}
]
}
💚 Build Succeeded
History
|
Proposed commit message
Checklist
changelog.ymlfile.How to test this PR locally
There are Painless tests that can be manually copied out of the YAML into Kibana's Painless Lab to verify the merge logic.
Related issues