diff --git a/.gitignore b/.gitignore index b759384..c00197a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/openscap-1.3.3.tar.gz +SOURCES/openscap-1.3.4.tar.gz diff --git a/.openscap.metadata b/.openscap.metadata index 36498f3..e3596ca 100644 --- a/.openscap.metadata +++ b/.openscap.metadata @@ -1 +1 @@ -6988d1ea7b86669d410ab5defc1be394cba5b017 SOURCES/openscap-1.3.3.tar.gz +3e303f06aa00e5c2616db606b980389ee0b73883 SOURCES/openscap-1.3.4.tar.gz diff --git a/SOURCES/openscap-1.3.4-add_compression_support-PR_1557.patch b/SOURCES/openscap-1.3.4-add_compression_support-PR_1557.patch deleted file mode 100644 index a80fe11..0000000 --- a/SOURCES/openscap-1.3.4-add_compression_support-PR_1557.patch +++ /dev/null @@ -1,70 +0,0 @@ -From d8518b70b912aa55fc47400173bf6229e40b71d0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?=C5=A0imon=20Luka=C5=A1=C3=ADk?= -Date: Wed, 8 Jul 2020 15:17:31 +0200 -Subject: [PATCH] Make a use of HTTP header content-encoding: gzip if available - -When fetching remote resources, some servers/CDNs may be able to serve us -compressed http response even in cases when the original file is not compressed -XML. libcurl is able to process encoded html for us with no added maintenance -costs. - -Attached please find a CURL log of fetching plain XML file from Red Hat CDN: - -Downloading: https://www.redhat.com/security/data/oval/com.redhat.rhsa-RHEL7.xml -... -* Trying 104.90.105.254:443... -* Connected to www.redhat.com (104.90.105.254) port 443 (#0) -* ALPN, offering h2 -* ALPN, offering http/1.1 -* successfully set certificate verify locations: -* CAfile: /etc/pki/tls/certs/ca-bundle.crt - CApath: none -* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 -* ALPN, server accepted to use h2 -* Server certificate: -* subject: businessCategory=Private Organization; jurisdictionC=US; jurisdictionST=Delaware; serialNumber=2945436; C=US; ST=North Carolina; L=Raleigh; O=Red Hat, Inc.; CN=www.redhat.com -* start date: Feb 24 00:00:00 2020 GMT -* expire date: May 24 12:00:00 2022 GMT -* subjectAltName: host "www.redhat.com" matched cert's "www.redhat.com" -* issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=DigiCert SHA2 Extended Validation Server CA -* SSL certificate verify ok. -* Using HTTP2, server supports multi-use -* Connection state changed (HTTP/2 confirmed) -* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 -* Using Stream ID: 1 (easy handle 0x776c3b0) -> GET /security/data/oval/com.redhat.rhsa-RHEL7.xml HTTP/2 -Host: www.redhat.com -accept: */* -accept-encoding: gzip - -* old SSL session ID is stale, removing -* Connection state changed (MAX_CONCURRENT_STREAMS == 100)! -< HTTP/2 200 -< server: Apache -< last-modified: Wed, 08 Jul 2020 12:41:28 GMT -< etag: "7f694279-fca5e0-5a9ed6d376a08" -< accept-ranges: bytes -< content-type: text/xml -< content-encoding: gzip -< content-length: 1766376 -< date: Wed, 08 Jul 2020 13:15:29 GMT -< vary: Accept-Encoding -< strict-transport-security: max-age=31536000 -< -* Connection #0 to host www.redhat.com left intact ---- - src/common/oscap_acquire.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/common/oscap_acquire.c b/src/common/oscap_acquire.c -index 60ab62c05..551da43f0 100644 ---- a/src/common/oscap_acquire.c -+++ b/src/common/oscap_acquire.c -@@ -302,6 +302,7 @@ char* oscap_acquire_url_download(const char *url, size_t* memory_size) - curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_memory_callback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer); -+ curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); - - CURLcode res = curl_easy_perform(curl); diff --git a/SOURCES/openscap-1.3.4-add_compression_test-PR_1564.patch b/SOURCES/openscap-1.3.4-add_compression_test-PR_1564.patch deleted file mode 100644 index e35e0f3..0000000 --- a/SOURCES/openscap-1.3.4-add_compression_test-PR_1564.patch +++ /dev/null @@ -1,168 +0,0 @@ -From 12ccadd9f9cd30143b3af6feced58f8da636e9d2 Mon Sep 17 00:00:00 2001 -From: Evgeny Kolesnikov -Date: Mon, 20 Jul 2020 07:45:05 +0200 -Subject: [PATCH] Add test for cURL "Accept-Encoding" header - ---- - tests/CMakeLists.txt | 1 + - tests/curl/CMakeLists.txt | 1 + - tests/curl/ds.xml | 99 ++++++++++++++++++++++++++++++++ - tests/curl/test_curl_encoding.sh | 23 ++++++++ - 4 files changed, 124 insertions(+) - create mode 100644 tests/curl/CMakeLists.txt - create mode 100644 tests/curl/ds.xml - create mode 100755 tests/curl/test_curl_encoding.sh - -diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt -index b7ca6cd79..6948cd260 100644 ---- a/tests/CMakeLists.txt -+++ b/tests/CMakeLists.txt -@@ -26,6 +26,7 @@ add_subdirectory("API") - add_subdirectory("bindings") - add_subdirectory("bz2") - add_subdirectory("codestyle") -+add_subdirectory("curl") - add_subdirectory("CPE") - add_subdirectory("DS") - add_subdirectory("mitre") -diff --git a/tests/curl/CMakeLists.txt b/tests/curl/CMakeLists.txt -new file mode 100644 -index 000000000..9c3d90d74 ---- /dev/null -+++ b/tests/curl/CMakeLists.txt -@@ -0,0 +1 @@ -+add_oscap_test("test_curl_encoding.sh") -diff --git a/tests/curl/ds.xml b/tests/curl/ds.xml -new file mode 100644 -index 000000000..f33cb475d ---- /dev/null -+++ b/tests/curl/ds.xml -@@ -0,0 +1,99 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ 5.11 -+ 2009-01-12T10:41:00-05:00 -+ -+ -+ -+ -+ -+ PASS -+ pass -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ oval:x:var:1 -+ -+ -+ -+ -+ -+ 100 -+ -+ -+ -+ -+ -+ -+ -+ -+ accepted -+ 1.0 -+ -+ -+ xccdf_test_profile -+ This profile is for testing. -+ -+ -+ -+ -+ test value -+ foo -+ 50 -+ 100 -+ -+ -+ This rule always pass -+ -+ -+ -+ -+ -+ This rule checks remote resource -+ -+ -+ -+ -+ -+ This rule always pass -+ -+ -+ -+ -+ -+ -+ -diff --git a/tests/curl/test_curl_encoding.sh b/tests/curl/test_curl_encoding.sh -new file mode 100755 -index 000000000..6d82f9569 ---- /dev/null -+++ b/tests/curl/test_curl_encoding.sh -@@ -0,0 +1,23 @@ -+#!/bin/bash -+ -+set -e -o pipefail -+ -+. $builddir/tests/test_common.sh -+ -+function curl_accept_encoding { -+ local DF="${srcdir}/ds.xml" -+ local RF="results.xml" -+ local LOG="verbose.log" -+ -+ $OSCAP xccdf --verbose=DEVEL eval --fetch-remote-resources --results $RF $DF 2>$LOG || echo "OK" -+ -+ grep -P "Accept-Encoding.*gzip" $LOG -+ -+ return 0 -+} -+ -+test_init -+ -+test_run "cURL: Accept-Encoding" curl_accept_encoding -+ -+test_exit diff --git a/SOURCES/openscap-1.3.4-add_compression_tracing-PR_1561.patch b/SOURCES/openscap-1.3.4-add_compression_tracing-PR_1561.patch deleted file mode 100644 index af4b663..0000000 --- a/SOURCES/openscap-1.3.4-add_compression_tracing-PR_1561.patch +++ /dev/null @@ -1,76 +0,0 @@ -From aab536acdd4b08e2e8c3d4ac43981dfcaf1cc9f8 Mon Sep 17 00:00:00 2001 -From: Evgeny Kolesnikov -Date: Mon, 13 Jul 2020 14:09:52 +0200 -Subject: [PATCH] Add CURLOPT_TRANSFER_ENCODING, enable CURLOPT_VERBOSE with - CURLOPT_DEBUGFUNCTION - -Adds a request for compressed Transfer Encoding in the outgoing -HTTP request. If the server supports this and so desires, it can -respond with the HTTP response sent using a compressed -Transfer-Encoding that will be automatically uncompressed by -libcurl on reception. - -The CURLOPT_DEBUGFUNCTION callback is used for printing headers and -connection information on VERBOSE level (dD). ---- - src/common/oscap_acquire.c | 32 ++++++++++++++++++++++++++++++++ - 1 file changed, 32 insertions(+) - -diff --git a/src/common/oscap_acquire.c b/src/common/oscap_acquire.c -index 551da43f0..666f4f5c9 100644 ---- a/src/common/oscap_acquire.c -+++ b/src/common/oscap_acquire.c -@@ -49,6 +49,7 @@ - #include "common/_error.h" - #include "oscap_string.h" - #include "oscap_helpers.h" -+#include "debug_priv.h" - - #ifndef OSCAP_TEMP_DIR - #define OSCAP_TEMP_DIR "/tmp" -@@ -288,6 +289,34 @@ oscap_acquire_url_to_filename(const char *url) - return filename; - } - -+static int _curl_trace(CURL *handle, curl_infotype type, char *data, size_t size, void *userp) -+{ -+ const char *title; -+ -+ switch (type) { -+ case CURLINFO_TEXT: -+ title = "== cURL info"; -+ break; -+ case CURLINFO_HEADER_OUT: -+ title = "=> cURL header (out)"; -+ break; -+ case CURLINFO_HEADER_IN: -+ title = "<= cURL header (in)"; -+ break; -+ case CURLINFO_DATA_OUT: -+ case CURLINFO_SSL_DATA_OUT: -+ case CURLINFO_DATA_IN: -+ case CURLINFO_SSL_DATA_IN: -+ default: -+ return 0; -+ break; -+ } -+ -+ dD("%s: %s", title, data); -+ -+ return 0; -+} -+ - char* oscap_acquire_url_download(const char *url, size_t* memory_size) - { - CURL *curl; -@@ -303,7 +332,10 @@ char* oscap_acquire_url_download(const char *url, size_t* memory_size) - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_memory_callback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer); - curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); -+ curl_easy_setopt(curl, CURLOPT_TRANSFER_ENCODING, true); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); -+ curl_easy_setopt(curl, CURLOPT_VERBOSE, true); -+ curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, _curl_trace); - - CURLcode res = curl_easy_perform(curl); - curl_easy_cleanup(curl); diff --git a/SOURCES/openscap-1.3.4-bump-yamlfilter-fix-warnings-PR_1530.patch b/SOURCES/openscap-1.3.4-bump-yamlfilter-fix-warnings-PR_1530.patch deleted file mode 100644 index 1645dd2..0000000 --- a/SOURCES/openscap-1.3.4-bump-yamlfilter-fix-warnings-PR_1530.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 31f2aa5729f9d6e9c1d8c06e3b979e89ff4e8e9e Mon Sep 17 00:00:00 2001 -From: Evgeny Kolesnikov -Date: Tue, 19 May 2020 07:26:25 +0200 -Subject: [PATCH 1/3] Update yaml-filter to the latest version (fixes minor - warnings) - -yaml-path.c:342:61: warning: comparison of integer expressions of different signedness: 'int' and 'size_t' {aka 'long unsigned int'} [-Wsign-compare] -yaml-path.c:251:27: warning: unused variable 'sec' [-Wunused-variable] ---- - CMakeLists.txt | 4 ++-- - yaml-filter | 2 +- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 65d674140..8752d66c8 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -545,7 +545,7 @@ include_directories( - "src/XCCDF/public/" - "src/XCCDF_POLICY/" - "src/XCCDF_POLICY/public/" -- "yaml-filter" -+ "yaml-filter/src/" - ${CMAKE_BINARY_DIR} # config.h is generated to build directory - ${LIBXML2_INCLUDE_DIR} - ${PCRE_INCLUDE_DIRS} -@@ -570,7 +570,7 @@ function(set_oscap_generic_properties TARGET_OBJECT) - endfunction() - - if(OPENSCAP_PROBE_INDEPENDENT_YAMLFILECONTENT) -- add_library(yamlfilter_object OBJECT yaml-filter/yaml-path.c yaml-filter/yaml-path.h) -+ add_library(yamlfilter_object OBJECT yaml-filter/src/yaml-path.c yaml-filter/src/yaml-path.h) - set_oscap_generic_properties(yamlfilter_object) - endif() - - -From 69111f40e24a44241609f485034420bac666e756 Mon Sep 17 00:00:00 2001 -From: Evgeny Kolesnikov -Date: Tue, 19 May 2020 07:28:53 +0200 -Subject: [PATCH 2/3] probes/yamlfilecontent: Properly destroy yaml_path before - bailing out - -yamlfilecontent_probe.c:163: leaked_storage: Variable "yaml_path" going out of scope leaks the storage it points to. ---- - src/OVAL/probes/independent/yamlfilecontent_probe.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c -index 8fc4b32b2..b8a379313 100644 ---- a/src/OVAL/probes/independent/yamlfilecontent_probe.c -+++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c -@@ -159,6 +159,7 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str - probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); - SEXP_free(msg); - probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); -+ yaml_path_destroy(yaml_path); - fclose(yaml_file); - return -1; - }; diff --git a/SOURCES/openscap-1.3.4-bump-yamlfilter-upgrade-probe-schemas-PR_1552.patch b/SOURCES/openscap-1.3.4-bump-yamlfilter-upgrade-probe-schemas-PR_1552.patch deleted file mode 100644 index a80bb00..0000000 --- a/SOURCES/openscap-1.3.4-bump-yamlfilter-upgrade-probe-schemas-PR_1552.patch +++ /dev/null @@ -1,1611 +0,0 @@ -From b8dcde269fb97a021b44b2c54a823a50f3d8982c Mon Sep 17 00:00:00 2001 -From: Evgeny Kolesnikov -Date: Wed, 15 Jul 2020 14:46:06 +0200 -Subject: [PATCH 1/8] OVAL: Fix evaluation of field entries in records - -Add proper evaluation implementation for operation, var_check -and var_ref attributes in the field entry of a record. ---- - src/OVAL/results/oval_cmp.c | 6 ---- - src/OVAL/results/oval_cmp_impl.h | 10 ------- - src/OVAL/results/oval_resultTest.c | 44 +++++++++++++++++++----------- - 3 files changed, 28 insertions(+), 32 deletions(-) - -diff --git a/src/OVAL/results/oval_cmp.c b/src/OVAL/results/oval_cmp.c -index 39e1f59e5..585332223 100644 ---- a/src/OVAL/results/oval_cmp.c -+++ b/src/OVAL/results/oval_cmp.c -@@ -161,9 +161,3 @@ oval_result_t oval_str_cmp_str(char *state_data, oval_datatype_t state_data_type - oscap_seterr(OSCAP_EFAMILY_OVAL, "Invalid OVAL data type: %d.", state_data_type); - return OVAL_RESULT_ERROR; - } -- --oval_result_t oval_ent_cmp_str(char *state_data, oval_datatype_t state_data_type, struct oval_sysent *sysent, oval_operation_t operation) --{ -- const char *sys_data = oval_sysent_get_value(sysent); -- return oval_str_cmp_str(state_data, state_data_type, sys_data, operation); --} -diff --git a/src/OVAL/results/oval_cmp_impl.h b/src/OVAL/results/oval_cmp_impl.h -index 4e38810f5..01014763b 100644 ---- a/src/OVAL/results/oval_cmp_impl.h -+++ b/src/OVAL/results/oval_cmp_impl.h -@@ -29,16 +29,6 @@ - #include "oval_system_characteristics.h" - - --/** -- * Compare state entity (or variable/value) to sysent object collected from system. -- * This function does not support @datatype="record". -- * @param state_value Value defined within state/entity/value or variable/value -- * @param sysent Value collected from system -- * @operation Comparison type operation -- * @returns OVAL Result of comparison -- */ --oval_result_t oval_ent_cmp_str(char *state_data, oval_datatype_t state_data_type, struct oval_sysent *sysent, oval_operation_t operation); -- - /** - * Compare state entity (or variable/value) to data collected from system. - * This function does not support @datatype="record". -diff --git a/src/OVAL/results/oval_resultTest.c b/src/OVAL/results/oval_resultTest.c -index b52b845ac..38477cb3b 100644 ---- a/src/OVAL/results/oval_resultTest.c -+++ b/src/OVAL/results/oval_resultTest.c -@@ -381,17 +381,11 @@ oval_result_t ores_get_result_byopr(struct oresults *ores, oval_operator_t op) - return result; - } - --static inline oval_result_t _evaluate_sysent_with_variable(struct oval_syschar_model *syschar_model, struct oval_entity *state_entity, struct oval_sysent *item_entity, oval_operation_t state_entity_operation, struct oval_state_content *content) -+static inline oval_result_t _evaluate_sysent_with_variable(struct oval_syschar_model *syschar_model, struct oval_variable *state_entity_var, const char *sys_data, oval_operation_t state_entity_operation, oval_check_t var_check) - { - oval_syschar_collection_flag_t flag; - oval_result_t ent_val_res; - -- struct oval_variable *state_entity_var; -- if ((state_entity_var = oval_entity_get_variable(state_entity)) == NULL) { -- oscap_seterr(OSCAP_EFAMILY_OVAL, "OVAL internal error: found NULL variable"); -- return -1; -- } -- - if (0 != oval_syschar_model_compute_variable(syschar_model, state_entity_var)) { - return -1; - } -@@ -420,16 +414,15 @@ static inline oval_result_t _evaluate_sysent_with_variable(struct oval_syschar_m - } - oval_datatype_t state_entity_val_datatype = oval_value_get_datatype(var_val); - -- var_val_res = oval_ent_cmp_str(state_entity_val_text, state_entity_val_datatype, item_entity, state_entity_operation); -+ var_val_res = oval_str_cmp_str(state_entity_val_text, state_entity_val_datatype, sys_data, state_entity_operation); - if (var_val_res == OVAL_RESULT_ERROR) { - dE("Error occured when comparing a variable '%s' value '%s' with collected item entity = '%s'", -- oval_variable_get_id(state_entity_var), state_entity_val_text, oval_sysent_get_value(item_entity)); -+ oval_variable_get_id(state_entity_var), state_entity_val_text, sys_data); - } - ores_add_res(&var_ores, var_val_res); - } - oval_value_iterator_free(val_itr); - -- oval_check_t var_check = oval_state_content_get_var_check(content); - ent_val_res = ores_get_result_bychk(&var_ores, var_check); - } break; - case SYSCHAR_FLAG_ERROR: -@@ -450,6 +443,9 @@ struct record_field_instance { - char *value; - oval_datatype_t data_type; - oval_check_t ent_check; -+ oval_operation_t operation; -+ struct oval_variable *var; -+ oval_check_t var_check; - }; - - static struct record_field_instance _oval_record_field_iterator_next_instance(struct oval_record_field_iterator *iterator) -@@ -461,11 +457,14 @@ static struct record_field_instance _oval_record_field_iterator_next_instance(st - instance.data_type = oval_record_field_get_datatype(rf); - if (oval_record_field_get_type(rf) == OVAL_RECORD_FIELD_STATE) { - instance.ent_check = oval_record_field_get_ent_check(rf); -+ instance.operation = oval_record_field_get_operation(rf); - } -+ instance.var = oval_record_field_get_variable(rf); -+ instance.var_check = oval_record_field_get_var_check(rf); - return instance; - } - --static oval_result_t _evaluate_sysent_record(struct oval_state_content *state_content, struct oval_sysent *item_entity) -+static oval_result_t _evaluate_sysent_record(struct oval_syschar_model *syschar_model, struct oval_state_content *state_content, struct oval_sysent *item_entity) - { - struct oresults record_ores; - ores_clear(&record_ores); -@@ -485,7 +484,12 @@ static oval_result_t _evaluate_sysent_record(struct oval_state_content *state_co - struct record_field_instance item_rf = _oval_record_field_iterator_next_instance(item_it); - if (strcmp(state_rf.name, item_rf.name) == 0) { - field_found = true; -- oval_result_t fields_comparison_result = oval_str_cmp_str(state_rf.value, state_rf.data_type, item_rf.value, OVAL_OPERATION_EQUALS); -+ oval_result_t fields_comparison_result; -+ if (state_rf.var != NULL) { -+ fields_comparison_result = _evaluate_sysent_with_variable(syschar_model, state_rf.var, item_rf.value, state_rf.operation, state_rf.var_check); -+ } else { -+ fields_comparison_result = oval_str_cmp_str(state_rf.value, state_rf.data_type, item_rf.value, state_rf.operation); -+ } - ores_add_res(&field_ores, fields_comparison_result); - } - } -@@ -510,10 +514,17 @@ static inline oval_result_t _evaluate_sysent(struct oval_syschar_model *syschar_ - if (oval_sysent_get_status(item_entity) == SYSCHAR_STATUS_DOES_NOT_EXIST) { - return OVAL_RESULT_FALSE; - } else if (oval_entity_get_varref_type(state_entity) == OVAL_ENTITY_VARREF_ATTRIBUTE) { -+ struct oval_variable *state_entity_var; -+ if ((state_entity_var = oval_entity_get_variable(state_entity)) == NULL) { -+ oscap_seterr(OSCAP_EFAMILY_OVAL, "OVAL internal error: found NULL variable"); -+ return -1; -+ } -+ const char *sys_data = oval_sysent_get_value(item_entity); -+ oval_check_t var_check = oval_state_content_get_var_check(content); - - return _evaluate_sysent_with_variable(syschar_model, -- state_entity, item_entity, -- state_entity_operation, content); -+ state_entity_var, sys_data, -+ state_entity_operation, var_check); - } else { - struct oval_value *state_entity_val; - char *state_entity_val_text; -@@ -525,7 +536,7 @@ static inline oval_result_t _evaluate_sysent(struct oval_syschar_model *syschar_ - dE("The only allowed operation for comparing record types is 'equals'."); - return OVAL_RESULT_ERROR; - } -- return _evaluate_sysent_record(content, item_entity); -+ return _evaluate_sysent_record(syschar_model, content, item_entity); - } else { - if ((state_entity_val = oval_entity_get_value(state_entity)) == NULL) { - oscap_seterr(OSCAP_EFAMILY_OVAL, "OVAL internal error: found NULL entity value"); -@@ -537,7 +548,8 @@ static inline oval_result_t _evaluate_sysent(struct oval_syschar_model *syschar_ - } - state_entity_val_datatype = oval_value_get_datatype(state_entity_val); - -- return oval_ent_cmp_str(state_entity_val_text, state_entity_val_datatype, item_entity, state_entity_operation); -+ const char *sys_data = oval_sysent_get_value(item_entity); -+ return oval_str_cmp_str(state_entity_val_text, state_entity_val_datatype, sys_data, state_entity_operation); - } - } - } - -From 21d52f1eb56951be976674f318ecfd5359f282c6 Mon Sep 17 00:00:00 2001 -From: Evgeny Kolesnikov -Date: Thu, 25 Jun 2020 23:31:11 +0200 -Subject: [PATCH 2/8] probes/yamlfilecontent: Bump yaml-filter, extend the - schema and probe to be able to work with a set of values in maps - -This introduces YAML Path selection ($.blah['key1','key2']) syntax and -enriches yamlfilecontent test and schema with EntityStateRecordType and -EntityItemRecordType result elements for collecting and checking -complex objects in YAML/JSON documents. - -This change also depend on removal of the 'only lower case' restriction -from the name attribute of the field element (EntityXxxFieldType). ---- - .../5.11.3/independent-definitions-schema.xsd | 19 ++- - ...ependent-system-characteristics-schema.xsd | 13 +- - .../oval/5.11.3/oval-definitions-schema.xsd | 14 +- - .../oval-system-characteristics-schema.xsd | 7 +- - .../independent/yamlfilecontent_probe.c | 155 ++++++++++++------ - .../yamlfilecontent/openshift-logging.yaml | 28 ++++ - .../test_probes_yamlfilecontent_array.xml | 8 +- - .../test_probes_yamlfilecontent_key.sh | 2 +- - .../test_probes_yamlfilecontent_key.xml | 70 +++++++- - ...st_probes_yamlfilecontent_offline_mode.xml | 12 +- - .../test_probes_yamlfilecontent_types.sh | 40 ++--- - yaml-filter | 2 +- - 12 files changed, 261 insertions(+), 109 deletions(-) - -diff --git a/schemas/oval/5.11.3/independent-definitions-schema.xsd b/schemas/oval/5.11.3/independent-definitions-schema.xsd -index 53e67e187..0f202abf6 100644 ---- a/schemas/oval/5.11.3/independent-definitions-schema.xsd -+++ b/schemas/oval/5.11.3/independent-definitions-schema.xsd -@@ -2115,7 +2115,7 @@ - - - -- Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list of zero or more scalar values which will be accessible in OVAL via instances of the value_of entity. Any results from evaluating the YAML Path expression other than a list of scalar values (e.g., a hash or list of lists) is considered an error. The intention is that the scalar values be drawn from instances of a single, uniquely named element. However, an OVAL interpreter is not required to verify this, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. -+ Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list or a map (part of a map) of zero or more scalar values which will be accessible in OVAL via instances of the result entity. Any results from evaluating the YAML Path expression other than a list of scalar values (or a map with scalar values) at the bottom level (e.g. list of lists, list of maps, map with maps or lists) is considered an error, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. - - - -@@ -2158,13 +2158,24 @@ - - - -- Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list of zero or more text values which will be accessible in OVAL via instances of the value_of entity. Any results from evaluating the YAML Path expression other than a list of text strings (e.g., a nodes set) is considered an error. The intention is that the text values be drawn from instances of a single, uniquely named element or attribute. However, an OVAL interpreter is not required to verify this, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. -+ Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list or a map (part of a map) of zero or more scalar values which will be accessible in OVAL via instances of the result entity. Any results from evaluating the YAML Path expression other than a list of scalar values (or a map with scalar values) at the bottom level (e.g. list of lists, list of maps, map with maps or lists) is considered an error, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. - - -- -+ - -- The value_of element checks the value(s) of the text node(s) or attribute(s) found. -+ The value entity specifies how to test objects in the value set of the specified YAML Path. To define tests for a signle scalar value or a list of scalar values, set name attribute of the field child element to an empty string (''). The check is entirely controlled by operator attributes of the field element. -+ -+ -+ -+ - datatype attribute for the value entity of a yamlfile_state must be 'record' -+ -+ -+ - -+ -+ -+ -+ - - - -diff --git a/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd b/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd -index 19c6a240e..b2934d4c6 100644 ---- a/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd -+++ b/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd -@@ -606,12 +606,19 @@ - - - -- Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list of zero or more scalar values which will be accessible in OVAL via instances of the value_of entity. Any results from evaluating the YAML Path expression other than a list of scalar values (e.g., a hash or list of lists) is considered an error. The intention is that the scalar values be drawn from instances of a single, uniquely named element. However, an OVAL interpreter is not required to verify this, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. -+ Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list or a map (part of a map) of zero or more scalar values which will be accessible in OVAL via instances of the result entity. Any results from evaluating the YAML Path expression other than a list of scalar values (or a map with scalar values) at the bottom level (e.g. list of lists, list of maps, map with maps or lists) is considered an error, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. - - -- -+ - -- The value_of element checks the value(s) of the text node(s) or attribute(s) found. How this is used is entirely controlled by operator attributes. -+ The value entity holds the target(s) of the specified YAML Path. If YAML Path target is a signle scalar value or a list of scalar values, the field child element's name would be empty (''). The check is entirely controlled by operator attributes of the field element. -+ -+ -+ -+ - datatype attribute for the value entity of a yamlfile_item must be 'record' -+ -+ -+ - - - -diff --git a/schemas/oval/5.11.3/oval-definitions-schema.xsd b/schemas/oval/5.11.3/oval-definitions-schema.xsd -index f43abd318..a57b889cf 100644 ---- a/schemas/oval/5.11.3/oval-definitions-schema.xsd -+++ b/schemas/oval/5.11.3/oval-definitions-schema.xsd -@@ -1553,13 +1553,8 @@ - - - -- A string restricted to disallow upper case characters. -+ A string. - -- -- -- -- -- - - - -@@ -1824,13 +1819,8 @@ - - - -- A string restricted to disallow upper case characters. -+ A string. - -- -- -- -- -- - - - -diff --git a/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd b/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd -index 30962f330..543b2db71 100644 ---- a/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd -+++ b/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd -@@ -574,13 +574,8 @@ - - - -- A string restricted to disallow upper case characters. -+ A string. - -- -- -- -- -- - - - -diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c -index 66d08ad22..f7c7d08cb 100644 ---- a/src/OVAL/probes/independent/yamlfilecontent_probe.c -+++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c -@@ -73,7 +73,7 @@ static SEXP_t *yaml_scalar_event_to_sexp(yaml_event_t *event) - char *tag = (char *) event->data.scalar.tag; - char *value = (char *) event->data.scalar.value; - -- /* nodes lacking an explicit tag are given a non-specific tag: -+ /* Nodes lacking an explicit tag are given a non-specific tag: - * “!” for non-plain scalars, and “?” for all other nodes - */ - if (tag == NULL) { -@@ -139,30 +139,30 @@ static SEXP_t *yaml_scalar_event_to_sexp(yaml_event_t *event) - return SEXP_string_new(value, strlen(value)); - } - -+#define result_error(fmt, args...) \ -+do { \ -+ SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, fmt, args); \ -+ probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); \ -+ SEXP_free(msg); \ -+ probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); \ -+ ret = -1; \ -+} while (0) -+ - static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, struct oscap_list *values, probe_ctx *ctx) - { - int ret = 0; - FILE *yaml_file = fopen(filepath, "r"); - if (yaml_file == NULL) { -- SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, -- "Unable to open file '%s': %s", filepath, strerror(errno)); -- probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); -- SEXP_free(msg); -- probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); -- return -1; -+ result_error("Unable to open file '%s': %s", filepath, strerror(errno)); -+ return ret; - } - - yaml_path_t *yaml_path = yaml_path_create(); - if (yaml_path_parse(yaml_path, (char *) yaml_path_cstr)) { -- SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, -- "Invalid YAML path '%s' (%s)\n", yaml_path_cstr, -- yaml_path_error_get(yaml_path)->message); -- probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); -- SEXP_free(msg); -- probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); -+ result_error("Invalid YAML path '%s': %s", yaml_path_cstr, yaml_path_error_get(yaml_path)->message); - yaml_path_destroy(yaml_path); - fclose(yaml_file); -- return -1; -+ return ret; - }; - - yaml_parser_t parser; -@@ -172,71 +172,94 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str - yaml_event_t event; - yaml_event_type_t event_type; - bool sequence = false; -+ bool mapping = false; -+ int index = 0; -+ char *key = strdup(""); -+ -+ struct oscap_htable *record = NULL; - - do { - if (!yaml_parser_parse(&parser, &event)) { -- SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, -- "YAML parser error: yaml_parse_parse returned 0: %s", -- parser.problem); -- probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); -- SEXP_free(msg); -- probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); -- ret = -1; -+ result_error("YAML parser error: %s", parser.problem); - goto cleanup; - } -- -- event_type = event.type; - if (!yaml_path_filter_event(yaml_path, &parser, &event, - YAML_PATH_FILTER_RETURN_ALL)) { - goto next; - } -+ -+ event_type = event.type; -+ - if (sequence) { - if (event_type == YAML_SEQUENCE_END_EVENT) { - sequence = false; -- } else if (event_type != YAML_SCALAR_EVENT) { -- SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, -- "YAML path '%s' contains non-scalar in a sequence.", -- yaml_path_cstr); -- probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); -- SEXP_free(msg); -- probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); -- ret = -1; -+ } else if (event_type == YAML_SEQUENCE_START_EVENT) { -+ result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); - goto cleanup; - } - } else { - if (event_type == YAML_SEQUENCE_START_EVENT) { - sequence = true; - } -- if (event_type == YAML_MAPPING_START_EVENT) { -- SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, -- "YAML path '%s' matches a mapping.", -- yaml_path_cstr); -- probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); -- SEXP_free(msg); -- probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); -- ret = -1; -+ } -+ -+ if (mapping) { -+ if (event_type == YAML_MAPPING_END_EVENT) { -+ mapping = false; -+ oscap_list_add(values, record); -+ record = NULL; -+ } else if (event_type == YAML_MAPPING_START_EVENT) { -+ result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); - goto cleanup; - } -+ } else { -+ if (event_type == YAML_MAPPING_START_EVENT) { -+ if (record) { -+ result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); -+ goto cleanup; -+ } -+ mapping = true; -+ sequence = false; -+ index = 0; -+ record = oscap_htable_new(); -+ } - } -+ - if (event_type == YAML_SCALAR_EVENT) { -+ if (mapping) { -+ if (!sequence) { -+ if (index++ % 2 == 0) { -+ free(key); -+ key = strdup((const char *) event.data.scalar.value); -+ goto next; -+ } -+ } -+ } -+ - SEXP_t *sexp = yaml_scalar_event_to_sexp(&event); - if (sexp == NULL) { -- SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, -- "Can't convert '%s %s' to SEXP", event.data.scalar.tag, -- event.data.scalar.value); -- probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); -- SEXP_free(msg); -- probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); -- ret = -1; -+ result_error("Can't convert '%s %s' to SEXP", event.data.scalar.tag, event.data.scalar.value); - goto cleanup; - } -- oscap_list_add(values, sexp); -+ -+ if (!record) -+ record = oscap_htable_new(); -+ struct oscap_list *field = oscap_htable_get(record, key); -+ if (!field) { -+ field = oscap_list_new(); -+ oscap_htable_add(record, key, field); -+ } -+ -+ oscap_list_add(field, sexp); - } - next: - yaml_event_delete(&event); - } while (event_type != YAML_STREAM_END_EVENT); - - cleanup: -+ if (record) -+ oscap_list_add(values, record); -+ free(key); - yaml_parser_delete(&parser); - yaml_path_destroy(yaml_path); - fclose(yaml_file); -@@ -244,6 +267,16 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str - return ret; - } - -+static void record_free(struct oscap_list *items) -+{ -+ oscap_list_free(items, (oscap_destruct_func) SEXP_free); -+} -+ -+static void values_free(struct oscap_htable *record) -+{ -+ oscap_htable_free(record, (oscap_destruct_func) record_free); -+} -+ - static int process_yaml_file(const char *prefix, const char *path, const char *filename, const char *yamlpath, probe_ctx *ctx) - { - int ret = 0; -@@ -265,21 +298,37 @@ static int process_yaml_file(const char *prefix, const char *path, const char *f - "path", OVAL_DATATYPE_STRING, path, - "filename", OVAL_DATATYPE_STRING, filename, - "yamlpath", OVAL_DATATYPE_STRING, yamlpath, -- /* -- "windows_view", -- */ -+ // TODO: Implement "windows_view", - NULL - ); - while (oscap_iterator_has_more(values_it)) { -- SEXP_t *value_sexp = oscap_iterator_next(values_it); -- probe_item_ent_add(item, "value_of", NULL, value_sexp); -+ SEXP_t *result_ent = probe_ent_creat1("value", NULL, NULL); -+ probe_ent_setdatatype(result_ent, OVAL_DATATYPE_RECORD); -+ struct oscap_htable *record = oscap_iterator_next(values_it); -+ struct oscap_htable_iterator *record_it = oscap_htable_iterator_new(record); -+ while(oscap_htable_iterator_has_more(record_it)) { -+ const struct oscap_htable_item *record_item = oscap_htable_iterator_next(record_it); -+ struct oscap_iterator *item_value_it = oscap_iterator_new(record_item->value); -+ SEXP_t se_tmp_mem; -+ SEXP_t *key = SEXP_string_new_r(&se_tmp_mem, record_item->key, strlen(record_item->key)); -+ while(oscap_iterator_has_more(item_value_it)) { -+ SEXP_t *value_sexp = oscap_iterator_next(item_value_it); -+ SEXP_t *field = probe_ent_creat1("field", NULL, value_sexp); -+ probe_item_attr_add(field, "name", key); -+ SEXP_list_add(result_ent, field); -+ } -+ oscap_iterator_free(item_value_it); -+ SEXP_free_r(&se_tmp_mem); -+ } -+ oscap_htable_iterator_free(record_it); -+ SEXP_list_add(item, result_ent); - } - probe_item_collect(ctx, item); - } - oscap_iterator_free(values_it); - - cleanup: -- oscap_list_free(values, (oscap_destruct_func) SEXP_free); -+ oscap_list_free(values, (oscap_destruct_func) values_free); - free(filepath_with_prefix); - free(filepath); - return ret; -diff --git a/tests/probes/yamlfilecontent/openshift-logging.yaml b/tests/probes/yamlfilecontent/openshift-logging.yaml -index a89e70942..fb6a9d8b6 100644 ---- a/tests/probes/yamlfilecontent/openshift-logging.yaml -+++ b/tests/probes/yamlfilecontent/openshift-logging.yaml -@@ -38,3 +38,31 @@ spec: - inputSource: logs.audit - outputRefs: - - secureforward-offcluster -+status: -+ conditions: -+ - lastTransitionTime: "2020-06-08T04:54:58Z" -+ reason: AsExpected -+ status: "False" -+ type: Degraded -+ - lastTransitionTime: "2020-06-08T06:34:00Z" -+ reason: AsExpected -+ status: "False" -+ type: Progressing -+ - lastTransitionTime: "2020-06-08T04:51:08Z" -+ reason: AsExpected -+ status: "True" -+ type: Available -+ - lastTransitionTime: "2020-06-08T04:45:45Z" -+ reason: AsExpected -+ status: "True" -+ type: Upgradeable -+ extension: null -+ relatedObjects: -+ - group: operator.openshift.io -+ name: cluster -+ resource: openshiftapiservers -+ versions: -+ - name: operator -+ version: 4.5.0-0.nightly-2020-06-04-214605 -+ - name: openshift-apiserver -+ version: 4.5.0-0.nightly-2020-06-04-214605 -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml -index 768b0b4a3..9a4227fb8 100644 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml -@@ -76,11 +76,15 @@ - - - -- secureforward-offcluster -+ -+ secureforward-offcluster -+ - - - -- -+ -+ -+ - - - -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh -index 300c1b496..b25ad99f9 100755 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh -@@ -19,7 +19,7 @@ function test_probes_yamlfilecontent_key { - $OSCAP oval eval --results $RF $DF - - if [ -f $RF ]; then -- verify_results "def" $DF $RF 3 && verify_results "tst" $DF $RF 4 -+ verify_results "def" $DF $RF 5 && verify_results "tst" $DF $RF 6 - ret_val=$? - else - ret_val=1 -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml -index f055bb648..fc3ee939e 100644 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml -@@ -21,7 +21,7 @@ - - - -- -+ - - - -@@ -41,6 +41,26 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - -@@ -55,7 +75,7 @@ - - - -- -+ - - - -@@ -63,6 +83,16 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - -@@ -91,16 +121,48 @@ - .doesnt.exist - - -+ -+ /tmp -+ openshift-logging.yaml -+ .status.conditions[:]['status','type'] -+ -+ -+ -+ /tmp -+ openshift-logging.yaml -+ .status.conditions[:] -+ -+ - - - - - -- LogForwarding -+ -+ LogForwarding -+ - - - -- openshift-logging -+ -+ openshift-logging -+ -+ -+ -+ -+ -+ True -+ Upgradeable -+ -+ -+ -+ -+ -+ True -+ AsExpected -+ Upgradeable -+ ^\d+-\d+-.*Z$ -+ - - - -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml -index 675f528e8..5c7cf5b28 100644 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml -@@ -85,15 +85,21 @@ - - - -- instance -+ -+ instance -+ - - - -- outstance -+ -+ outstance -+ - - - -- instance -+ -+ instance -+ - - - -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh -index 97bb33dfd..8b0614fc6 100755 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh -@@ -24,49 +24,49 @@ function test_probes_yamlfilecontent_types { - - sd='/oval_results/results/system/oval_system_characteristics/system_data' - -- assert_exists 8 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="boolean"]' -- assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="boolean" and text()="true"]' -- assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="boolean" and text()="false"]' -+ assert_exists 8 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="boolean"]' -+ assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="boolean" and text()="true"]' -+ assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="boolean" and text()="false"]' - -- assert_exists 5 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="int"]' -+ assert_exists 5 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int"]' - # int_10: 42 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="int" and text()="42"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="42"]' - # int_10_neg: -17 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="int" and text()="-17"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="-17"]' - # int_8: 0o33 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="int" and text()="27"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="27"]' - # int_16: 0xFF -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="int" and text()="255"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="255"]' - # int_cast: !!int "369" -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="int" and text()="369"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="369"]' - -- assert_exists 7 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float"]' -+ assert_exists 7 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float"]' - # float: 7.4 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="7.400000"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="7.400000"]' - # float_neg: -0.3 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="-0.300000"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="-0.300000"]' - # float_exp: +12e03 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="12000.000000"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="12000.000000"]' - # float_exp_neg: -43e-4 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="-0.004300"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="-0.004300"]' - # float: .inf -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="inf"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="inf"]' - # float: .NAN -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="nan"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="nan"]' - # float_cast: !!float "978.65" -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float" and text()="978.650000"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="978.650000"]' - - # string_true -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype!="boolean" and text()="true"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype!="boolean" and text()="true"]' - # string_number -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype!="int" and text()="81"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype!="int" and text()="81"]' - - # bool_error_cast, int_error_cast, float_error_cast - co='/oval_results/results/system/oval_system_characteristics/collected_objects' - assert_exists 3 $co'/object[@flag="error"]' - assert_exists 3 $co'/object[@flag="error"]/message' - -- rm -f $result -+ #rm -f $result - rm -f $YAML_FILE - - } - -From 4f129b7142360ff4adb06aa49ee050ccf335fa8e Mon Sep 17 00:00:00 2001 -From: Evgeny Kolesnikov -Date: Fri, 31 Jul 2020 08:37:25 +0200 -Subject: [PATCH 3/8] OVAL: Fix record field evaluation - ---- - src/OVAL/oval_recordField.c | 20 ++++++++++---------- - src/OVAL/results/oval_resultTest.c | 4 ++-- - 2 files changed, 12 insertions(+), 12 deletions(-) - -diff --git a/src/OVAL/oval_recordField.c b/src/OVAL/oval_recordField.c -index a0c8a6a54..dd765097d 100644 ---- a/src/OVAL/oval_recordField.c -+++ b/src/OVAL/oval_recordField.c -@@ -208,7 +208,7 @@ void oval_record_field_set_mask(struct oval_record_field *rf, int mask) - void oval_record_field_set_operation(struct oval_record_field *rf, oval_operation_t operation) - { - if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { -- dE("Wrong record field type: %d.", rf->record_field_type); -+ dE("Wrong record field type (set operation): %d.", rf->record_field_type); - return; - } - -@@ -218,7 +218,7 @@ void oval_record_field_set_operation(struct oval_record_field *rf, oval_operatio - void oval_record_field_set_variable(struct oval_record_field *rf, struct oval_variable *var) - { - if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { -- dE("Wrong record field type: %d.", rf->record_field_type); -+ dE("Wrong record field type (set variable): %d.", rf->record_field_type); - return; - } - -@@ -228,7 +228,7 @@ void oval_record_field_set_variable(struct oval_record_field *rf, struct oval_va - void oval_record_field_set_var_check(struct oval_record_field *rf, oval_check_t var_check) - { - if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { -- dE("Wrong record field type: %d.", rf->record_field_type); -+ dE("Wrong record field type (set var_check): %d.", rf->record_field_type); - return; - } - -@@ -238,7 +238,7 @@ void oval_record_field_set_var_check(struct oval_record_field *rf, oval_check_t - void oval_record_field_set_ent_check(struct oval_record_field *rf, oval_check_t ent_check) - { - if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { -- dE("Wrong record field type: %d.", rf->record_field_type); -+ dE("Wrong record field type (set ent_check): %d.", rf->record_field_type); - return; - } - -@@ -248,7 +248,7 @@ void oval_record_field_set_ent_check(struct oval_record_field *rf, oval_check_t - void oval_record_field_set_status(struct oval_record_field *rf, oval_syschar_status_t status) - { - if (rf->record_field_type != OVAL_RECORD_FIELD_ITEM) { -- dE("Wrong record field type: %d.", rf->record_field_type); -+ dE("Wrong record field type (set status): %d.", rf->record_field_type); - return; - } - -@@ -283,7 +283,7 @@ int oval_record_field_get_mask(struct oval_record_field *rf) - oval_operation_t oval_record_field_get_operation(struct oval_record_field *rf) - { - if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { -- dE("Wrong record field type: %d.", rf->record_field_type); -+ dE("Wrong record field type (get operation): %d.", rf->record_field_type); - return OVAL_OPERATION_UNKNOWN; - } - -@@ -293,7 +293,7 @@ oval_operation_t oval_record_field_get_operation(struct oval_record_field *rf) - struct oval_variable *oval_record_field_get_variable(struct oval_record_field *rf) - { - if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { -- dE("Wrong record field type: %d.", rf->record_field_type); -+ dE("Wrong record field type (get variable): %d.", rf->record_field_type); - return NULL; - } - -@@ -303,7 +303,7 @@ struct oval_variable *oval_record_field_get_variable(struct oval_record_field *r - oval_check_t oval_record_field_get_var_check(struct oval_record_field *rf) - { - if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { -- dE("Wrong record field type: %d.", rf->record_field_type); -+ dE("Wrong record field type (get var_check): %d.", rf->record_field_type); - return OVAL_CHECK_UNKNOWN; - } - -@@ -313,7 +313,7 @@ oval_check_t oval_record_field_get_var_check(struct oval_record_field *rf) - oval_check_t oval_record_field_get_ent_check(struct oval_record_field *rf) - { - if (rf->record_field_type != OVAL_RECORD_FIELD_STATE) { -- dE("Wrong record field type: %d.", rf->record_field_type); -+ dE("Wrong record field type (get ent_check): %d.", rf->record_field_type); - return OVAL_CHECK_UNKNOWN; - } - -@@ -323,7 +323,7 @@ oval_check_t oval_record_field_get_ent_check(struct oval_record_field *rf) - oval_syschar_status_t oval_record_field_get_status(struct oval_record_field *rf) - { - if (rf->record_field_type != OVAL_RECORD_FIELD_ITEM) { -- dE("Wrong record field type: %d.", rf->record_field_type); -+ dE("Wrong record field type (get status): %d.", rf->record_field_type); - return SYSCHAR_STATUS_UNKNOWN; - } - -diff --git a/src/OVAL/results/oval_resultTest.c b/src/OVAL/results/oval_resultTest.c -index 38477cb3b..00e161481 100644 ---- a/src/OVAL/results/oval_resultTest.c -+++ b/src/OVAL/results/oval_resultTest.c -@@ -458,9 +458,9 @@ static struct record_field_instance _oval_record_field_iterator_next_instance(st - if (oval_record_field_get_type(rf) == OVAL_RECORD_FIELD_STATE) { - instance.ent_check = oval_record_field_get_ent_check(rf); - instance.operation = oval_record_field_get_operation(rf); -+ instance.var = oval_record_field_get_variable(rf); -+ instance.var_check = oval_record_field_get_var_check(rf); - } -- instance.var = oval_record_field_get_variable(rf); -- instance.var_check = oval_record_field_get_var_check(rf); - return instance; - } - - -From 277548a18c4d7312df4e19da5cff38dfff56fd45 Mon Sep 17 00:00:00 2001 -From: Evgeny Kolesnikov -Date: Fri, 31 Jul 2020 08:38:10 +0200 -Subject: [PATCH 4/8] probes/yamlfilecontent: Avoid collecting empty records - ---- - .../independent/yamlfilecontent_probe.c | 7 ++++++- - .../test_probes_yamlfilecontent_key.sh | 2 +- - .../test_probes_yamlfilecontent_key.xml | 20 +++++++++++++++++++ - .../test_probes_yamlfilecontent_types.sh | 2 -- - 4 files changed, 27 insertions(+), 4 deletions(-) - -diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c -index f7c7d08cb..8e276dc3c 100644 ---- a/src/OVAL/probes/independent/yamlfilecontent_probe.c -+++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c -@@ -206,7 +206,12 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str - if (mapping) { - if (event_type == YAML_MAPPING_END_EVENT) { - mapping = false; -- oscap_list_add(values, record); -+ if (record->itemcount > 0) { -+ oscap_list_add(values, record); -+ } else { -+ // Do not collect empty records -+ oscap_htable_free0(record); -+ } - record = NULL; - } else if (event_type == YAML_MAPPING_START_EVENT) { - result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh -index b25ad99f9..fc1e0ae7e 100755 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh -@@ -19,7 +19,7 @@ function test_probes_yamlfilecontent_key { - $OSCAP oval eval --results $RF $DF - - if [ -f $RF ]; then -- verify_results "def" $DF $RF 5 && verify_results "tst" $DF $RF 6 -+ verify_results "def" $DF $RF 6 && verify_results "tst" $DF $RF 7 - ret_val=$? - else - ret_val=1 -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml -index fc3ee939e..bb40d89be 100644 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml -@@ -61,6 +61,16 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - -@@ -93,6 +103,10 @@ - - - -+ -+ -+ -+ - - - -@@ -133,6 +147,12 @@ - .status.conditions[:] - - -+ -+ /tmp -+ openshift-logging.yaml -+ .status.conditions[:]['nonexistent','dummy'] -+ -+ - - - -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh -index 8b0614fc6..83910ed38 100755 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh -@@ -66,9 +66,7 @@ function test_probes_yamlfilecontent_types { - assert_exists 3 $co'/object[@flag="error"]' - assert_exists 3 $co'/object[@flag="error"]/message' - -- #rm -f $result - rm -f $YAML_FILE -- - } - - test_probes_yamlfilecontent_types - -From 8d64db6203c02d3326c9e3336464bb2333d8f9f4 Mon Sep 17 00:00:00 2001 -From: Evgeny Kolesnikov -Date: Wed, 23 Sep 2020 13:34:59 +0200 -Subject: [PATCH 5/8] Revert changes in base OVAL schema - -And adjust probe implementation and tests for the workaround (lowercase -and escape capital letters in field names with ^, use # instead -of empty field names for scalars). ---- - .../5.11.3/independent-definitions-schema.xsd | 8 ++-- - ...ependent-system-characteristics-schema.xsd | 4 +- - .../oval/5.11.3/oval-definitions-schema.xsd | 14 +++++- - .../oval-system-characteristics-schema.xsd | 7 ++- - .../independent/yamlfilecontent_probe.c | 43 ++++++++++++++++--- - .../test_probes_yamlfilecontent_array.xml | 4 +- - .../test_probes_yamlfilecontent_key.xml | 23 ++++++++-- - ...st_probes_yamlfilecontent_offline_mode.xml | 6 +-- - .../test_probes_yamlfilecontent_types.sh | 38 ++++++++-------- - 9 files changed, 106 insertions(+), 41 deletions(-) - -diff --git a/schemas/oval/5.11.3/independent-definitions-schema.xsd b/schemas/oval/5.11.3/independent-definitions-schema.xsd -index 0f202abf6..4168b45bf 100644 ---- a/schemas/oval/5.11.3/independent-definitions-schema.xsd -+++ b/schemas/oval/5.11.3/independent-definitions-schema.xsd -@@ -2115,7 +2115,7 @@ - - - -- Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list or a map (part of a map) of zero or more scalar values which will be accessible in OVAL via instances of the result entity. Any results from evaluating the YAML Path expression other than a list of scalar values (or a map with scalar values) at the bottom level (e.g. list of lists, list of maps, map with maps or lists) is considered an error, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. -+ Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a sequence or a map (part of a map) of scalar values which will be accessible in OVAL via instances of the value entity. Any results from evaluating the YAML Path expression other than a sequence (or a map) of scalar values (e.g. sequence of sequences, sequence of maps, map of maps etc.) are considered as incorrect, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. - - - -@@ -2158,12 +2158,12 @@ - - - -- Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list or a map (part of a map) of zero or more scalar values which will be accessible in OVAL via instances of the result entity. Any results from evaluating the YAML Path expression other than a list of scalar values (or a map with scalar values) at the bottom level (e.g. list of lists, list of maps, map with maps or lists) is considered an error, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. -+ Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. Note that "equals" is the only valid operator for the yamlpath entity. - - - - -- The value entity specifies how to test objects in the value set of the specified YAML Path. To define tests for a signle scalar value or a list of scalar values, set name attribute of the field child element to an empty string (''). The check is entirely controlled by operator attributes of the field element. -+ The value entity specifies how to test objects in the value set of the specified YAML Path. To define tests for a signle scalar value or a list of scalar values (where there is no key to associate), set the name attribute of the field element to '#'. Due to the limitation of the record type field names could not contain uppercase letters, they will be converted to the lowercase and escaped using the '^' symbol (the '^' symbol would be escaped as well). For example 'myCamelCase^Key' would be collected as 'my^camel^case^^^key'. The check is entirely controlled by operator attributes of the field element. - - - -@@ -2172,7 +2172,7 @@ - - - -- -+ - - - -diff --git a/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd b/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd -index b2934d4c6..9c108297b 100644 ---- a/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd -+++ b/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd -@@ -606,12 +606,12 @@ - - - -- Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. This YAML Path expression must evaluate to a list or a map (part of a map) of zero or more scalar values which will be accessible in OVAL via instances of the result entity. Any results from evaluating the YAML Path expression other than a list of scalar values (or a map with scalar values) at the bottom level (e.g. list of lists, list of maps, map with maps or lists) is considered an error, so the author should define the YAML Path expression carefully. Note that "equals" is the only valid operator for the yamlpath entity. -+ Specifies an YAML Path expression to evaluate against the YAML file specified by the filename entity. Note that "equals" is the only valid operator for the yamlpath entity. - - - - -- The value entity holds the target(s) of the specified YAML Path. If YAML Path target is a signle scalar value or a list of scalar values, the field child element's name would be empty (''). The check is entirely controlled by operator attributes of the field element. -+ The value entity holds the target(s) of the specified YAML Path. To define tests for a signle scalar value or a list of scalar values (where there is no key to associate), set the name attribute of the field element to '#'. Due to the limitation of the record type field names could not contain uppercase letters, they will be converted to the lowercase and escaped using the '^' symbol (the '^' symbol would be escaped as well). For example 'myCamelCase^Key' would be collected as 'my^camel^case^^^key'. The check is entirely controlled by operator attributes of the field element. - - - -diff --git a/schemas/oval/5.11.3/oval-definitions-schema.xsd b/schemas/oval/5.11.3/oval-definitions-schema.xsd -index a57b889cf..f43abd318 100644 ---- a/schemas/oval/5.11.3/oval-definitions-schema.xsd -+++ b/schemas/oval/5.11.3/oval-definitions-schema.xsd -@@ -1553,8 +1553,13 @@ - - - -- A string. -+ A string restricted to disallow upper case characters. - -+ -+ -+ -+ -+ - - - -@@ -1819,8 +1824,13 @@ - - - -- A string. -+ A string restricted to disallow upper case characters. - -+ -+ -+ -+ -+ - - - -diff --git a/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd b/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd -index 543b2db71..30962f330 100644 ---- a/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd -+++ b/schemas/oval/5.11.3/oval-system-characteristics-schema.xsd -@@ -574,8 +574,13 @@ - - - -- A string. -+ A string restricted to disallow upper case characters. - -+ -+ -+ -+ -+ - - - -diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c -index 8e276dc3c..641709bb9 100644 ---- a/src/OVAL/probes/independent/yamlfilecontent_probe.c -+++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c -@@ -148,6 +148,39 @@ do { \ - ret = -1; \ - } while (0) - -+static char *escape_key(char *key) -+{ -+ if (key == NULL) -+ return NULL; -+ -+ size_t cap_letters = 0; -+ size_t key_len = strlen(key); -+ for (size_t i = 0; i < key_len; i++) -+ if ((key[i] >= 'A' && key[i] <= 'Z') || key[i] == '^') -+ cap_letters++; -+ -+ if (cap_letters == 0) -+ return key; -+ -+ char *new_key = realloc(key, key_len + 1 + cap_letters); -+ if (new_key == NULL) -+ return key; -+ new_key[key_len + cap_letters] = '\0'; -+ -+ for (ssize_t i = key_len; i >= 0; i--) { -+ if ((new_key[i] >= 'A' && new_key[i] <= 'Z') || new_key[i] == '^') { -+ if (new_key[i] != '^') -+ new_key[i] += 32; -+ memmove(new_key + i + cap_letters, new_key + i, key_len - i); -+ new_key[i + cap_letters - 1] = '^'; -+ cap_letters--; -+ key_len = i; -+ } -+ } -+ -+ return new_key; -+} -+ - static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, struct oscap_list *values, probe_ctx *ctx) - { - int ret = 0; -@@ -174,7 +207,7 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str - bool sequence = false; - bool mapping = false; - int index = 0; -- char *key = strdup(""); -+ char *key = strdup("#"); - - struct oscap_htable *record = NULL; - -@@ -194,7 +227,7 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str - if (event_type == YAML_SEQUENCE_END_EVENT) { - sequence = false; - } else if (event_type == YAML_SEQUENCE_START_EVENT) { -- result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); -+ result_error("YAML path '%s' points to a multi-dimensional structure (sequence containing another sequence)", yaml_path_cstr); - goto cleanup; - } - } else { -@@ -214,13 +247,13 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str - } - record = NULL; - } else if (event_type == YAML_MAPPING_START_EVENT) { -- result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); -+ result_error("YAML path '%s' points to a multi-dimensional structure (map containing another map)", yaml_path_cstr); - goto cleanup; - } - } else { - if (event_type == YAML_MAPPING_START_EVENT) { - if (record) { -- result_error("YAML path '%s' points to a multi-dimensional structure", yaml_path_cstr); -+ result_error("YAML path '%s' points to an invalid structure (map containing another map)", yaml_path_cstr); - goto cleanup; - } - mapping = true; -@@ -235,7 +268,7 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str - if (!sequence) { - if (index++ % 2 == 0) { - free(key); -- key = strdup((const char *) event.data.scalar.value); -+ key = escape_key(strdup((const char *) event.data.scalar.value)); - goto next; - } - } -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml -index 9a4227fb8..9fd92492e 100644 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml -@@ -77,13 +77,13 @@ - - - -- secureforward-offcluster -+ secureforward-offcluster - - - - - -- -+ - - - -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml -index bb40d89be..05757d0c8 100644 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml -@@ -71,6 +71,15 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - -@@ -107,6 +116,9 @@ - - - -+ -+ -+ - - - -@@ -153,19 +165,24 @@ - .status.conditions[:]['nonexistent','dummy'] - - -+ -+ /tmp -+ openshift-logging.yaml -+ .spec.outputs -+ - - - - - - -- LogForwarding -+ LogForwarding - - - - - -- openshift-logging -+ openshift-logging - - - -@@ -181,7 +198,7 @@ - True - AsExpected - Upgradeable -- ^\d+-\d+-.*Z$ -+ ^\d+-\d+-.*Z$ - - - -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml -index 5c7cf5b28..35a646688 100644 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_offline_mode.xml -@@ -86,19 +86,19 @@ - - - -- instance -+ instance - - - - - -- outstance -+ outstance - - - - - -- instance -+ instance - - - -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh -index 83910ed38..4f110f6eb 100755 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_types.sh -@@ -24,42 +24,42 @@ function test_probes_yamlfilecontent_types { - - sd='/oval_results/results/system/oval_system_characteristics/system_data' - -- assert_exists 8 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="boolean"]' -- assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="boolean" and text()="true"]' -- assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="boolean" and text()="false"]' -+ assert_exists 8 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="boolean"]' -+ assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="boolean" and text()="true"]' -+ assert_exists 4 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="boolean" and text()="false"]' - -- assert_exists 5 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int"]' -+ assert_exists 5 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="int"]' - # int_10: 42 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="42"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="int" and text()="42"]' - # int_10_neg: -17 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="-17"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="int" and text()="-17"]' - # int_8: 0o33 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="27"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="int" and text()="27"]' - # int_16: 0xFF -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="255"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="int" and text()="255"]' - # int_cast: !!int "369" -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="int" and text()="369"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="int" and text()="369"]' - -- assert_exists 7 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float"]' -+ assert_exists 7 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float"]' - # float: 7.4 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="7.400000"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="7.400000"]' - # float_neg: -0.3 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="-0.300000"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="-0.300000"]' - # float_exp: +12e03 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="12000.000000"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="12000.000000"]' - # float_exp_neg: -43e-4 -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="-0.004300"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="-0.004300"]' - # float: .inf -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="inf"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="inf"]' - # float: .NAN -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="nan"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="nan"]' - # float_cast: !!float "978.65" -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype="float" and text()="978.650000"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype="float" and text()="978.650000"]' - - # string_true -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype!="boolean" and text()="true"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype!="boolean" and text()="true"]' - # string_number -- assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="" and @datatype!="int" and text()="81"]' -+ assert_exists 1 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value/field[@name="#" and @datatype!="int" and text()="81"]' - - # bool_error_cast, int_error_cast, float_error_cast - co='/oval_results/results/system/oval_system_characteristics/collected_objects' - -From 5f9b9b6686e9d1b05094cdda8d5d1339ed4e8547 Mon Sep 17 00:00:00 2001 -From: Evgeny Kolesnikov -Date: Thu, 24 Sep 2020 11:21:02 +0200 -Subject: [PATCH 6/8] Bump yaml-filter - ---- - src/OVAL/probes/independent/yamlfilecontent_probe.c | 3 +-- - .../yamlfilecontent/test_probes_yamlfilecontent_array.xml | 2 +- - yaml-filter | 2 +- - 3 files changed, 3 insertions(+), 4 deletions(-) - -diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c -index 641709bb9..b57956765 100644 ---- a/src/OVAL/probes/independent/yamlfilecontent_probe.c -+++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c -@@ -216,8 +216,7 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str - result_error("YAML parser error: %s", parser.problem); - goto cleanup; - } -- if (!yaml_path_filter_event(yaml_path, &parser, &event, -- YAML_PATH_FILTER_RETURN_ALL)) { -+ if (yaml_path_filter_event(yaml_path, &parser, &event) == YAML_PATH_FILTER_RESULT_OUT) { - goto next; - } - -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml -index 9fd92492e..c05c5fbb9 100644 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml -@@ -62,7 +62,7 @@ - - /tmp - openshift-logging.yaml -- .spec.outputs[0:2].name -+ .spec.outputs[:].name - - - - -From 183e3517365890d0e704460fdb6e99672c469d22 Mon Sep 17 00:00:00 2001 -From: Evgeny Kolesnikov -Date: Tue, 29 Sep 2020 10:42:22 +0200 -Subject: [PATCH 7/8] Update schemas - ---- - .../5.11.3/independent-definitions-schema.xsd | 2 +- - ...dependent-system-characteristics-schema.xsd | 2 +- - .../probes/independent/yamlfilecontent_probe.c | 18 +++++++++--------- - 3 files changed, 11 insertions(+), 11 deletions(-) - -diff --git a/schemas/oval/5.11.3/independent-definitions-schema.xsd b/schemas/oval/5.11.3/independent-definitions-schema.xsd -index 4168b45bf..d9a891d23 100644 ---- a/schemas/oval/5.11.3/independent-definitions-schema.xsd -+++ b/schemas/oval/5.11.3/independent-definitions-schema.xsd -@@ -2163,7 +2163,7 @@ - - - -- The value entity specifies how to test objects in the value set of the specified YAML Path. To define tests for a signle scalar value or a list of scalar values (where there is no key to associate), set the name attribute of the field element to '#'. Due to the limitation of the record type field names could not contain uppercase letters, they will be converted to the lowercase and escaped using the '^' symbol (the '^' symbol would be escaped as well). For example 'myCamelCase^Key' would be collected as 'my^camel^case^^^key'. The check is entirely controlled by operator attributes of the field element. -+ The value entity specifies how to test objects in the value set of the specified YAML Path. To define tests for a single scalar value or a list of scalar values (where there is no key to associate), set the name attribute of the field element to '#'. Due to the limitation of the record type field names could not contain uppercase letters, they should be converted to the lowercase and escaped using the '^' symbol (the '^' symbol should be escaped as well). For example, to check a value associated with 'myCamelCase^Key' set the name attribute of the field to 'my^camel^case^^^key'. The check is entirely controlled by operator attributes of the field element. - - - -diff --git a/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd b/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd -index 9c108297b..c2a2aab50 100644 ---- a/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd -+++ b/schemas/oval/5.11.3/independent-system-characteristics-schema.xsd -@@ -611,7 +611,7 @@ - - - -- The value entity holds the target(s) of the specified YAML Path. To define tests for a signle scalar value or a list of scalar values (where there is no key to associate), set the name attribute of the field element to '#'. Due to the limitation of the record type field names could not contain uppercase letters, they will be converted to the lowercase and escaped using the '^' symbol (the '^' symbol would be escaped as well). For example 'myCamelCase^Key' would be collected as 'my^camel^case^^^key'. The check is entirely controlled by operator attributes of the field element. -+ The value entity holds the target(s) of the specified YAML Path. A single scalar value or a list of scalar values (where there is no key to associate) would have the name attribute of the field element set to '#'. Due to the limitation of the record type field names could not contain uppercase letters, they will be converted to the lowercase and escaped using the '^' symbol (the '^' symbol would be escaped as well). For example 'myCamelCase^Key' would be collected as 'my^camel^case^^^key'. - - - -diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c -index b57956765..72e5638ae 100644 ---- a/src/OVAL/probes/independent/yamlfilecontent_probe.c -+++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c -@@ -139,15 +139,6 @@ static SEXP_t *yaml_scalar_event_to_sexp(yaml_event_t *event) - return SEXP_string_new(value, strlen(value)); - } - --#define result_error(fmt, args...) \ --do { \ -- SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, fmt, args); \ -- probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); \ -- SEXP_free(msg); \ -- probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); \ -- ret = -1; \ --} while (0) -- - static char *escape_key(char *key) - { - if (key == NULL) -@@ -181,6 +172,15 @@ static char *escape_key(char *key) - return new_key; - } - -+#define result_error(fmt, args...) \ -+do { \ -+ SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR, fmt, args); \ -+ probe_cobj_add_msg(probe_ctx_getresult(ctx), msg); \ -+ SEXP_free(msg); \ -+ probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR); \ -+ ret = -1; \ -+} while (0) -+ - static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, struct oscap_list *values, probe_ctx *ctx) - { - int ret = 0; - -From 227cce0560574d3f2efd75e884152f1fb1a7c619 Mon Sep 17 00:00:00 2001 -From: Evgeny Kolesnikov -Date: Tue, 29 Sep 2020 15:31:41 +0200 -Subject: [PATCH 8/8] probes/yamlfilecontent: Add missed SEXP_free - ---- - src/OVAL/probes/independent/yamlfilecontent_probe.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c -index 72e5638ae..6f18abf83 100644 ---- a/src/OVAL/probes/independent/yamlfilecontent_probe.c -+++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c -@@ -359,6 +359,7 @@ static int process_yaml_file(const char *prefix, const char *path, const char *f - } - oscap_htable_iterator_free(record_it); - SEXP_list_add(item, result_ent); -+ SEXP_free(result_ent); - } - probe_item_collect(ctx, item); - } diff --git a/SOURCES/openscap-1.3.4-bump-yamlfilter-upgrade-probe-schemas-submodule-PR_1552.patch b/SOURCES/openscap-1.3.4-bump-yamlfilter-upgrade-probe-schemas-submodule-PR_1552.patch deleted file mode 100644 index 7712c0b..0000000 --- a/SOURCES/openscap-1.3.4-bump-yamlfilter-upgrade-probe-schemas-submodule-PR_1552.patch +++ /dev/null @@ -1,2641 +0,0 @@ -diff --git a/.travis.yml b/.travis.yml -index 7e776c3..7382736 100644 ---- a/.travis.yml -+++ b/.travis.yml -@@ -1,15 +1,29 @@ - language: c --dist: bionic -+ -+os: -+ - linux - - before_script: -- - mkdir -p build -- - cd build -- - sudo apt-get install -y libyaml-0-2 -+ - mkdir -p build -+ - cd build -+ - sudo apt-get install -y libyaml-0-2 - - script: -- - cmake -DENABLE_COVERAGE=yes .. -- - make && ctest -V -- - make gcov -+ - cmake -DENABLE_COVERAGE=yes .. -+ - build-wrapper-linux-x86-64 --out-dir bw-output make clean all || true # Allowed to fail in builds from forks -+ - make && ctest -V -+ - make gcov -+ - sonar-scanner -Dproject.settings=../sonar-project.properties || true # Allowed to fail in builds from forks - - after_success: -- - curl -s https://codecov.io/bash > cov.sh && bash cov.sh -x "$GCOV" -+ - curl -s https://codecov.io/bash > cov.sh && bash cov.sh -x "$GCOV" -+ -+addons: -+ sonarcloud: -+ organization: "openscap" -+ token: -+ secure: "BoPCYdulv5+7sNQtShKE0tYVelHSL3sWNhjz5QFZCDefK7az2+Lze9Zp/sas02gmBLoc0vuuFjFgtKLSPt9mEL4YabwAysCF445jwE+wu8KJf/Bz36tMz1gE9383+Ic9LcR2bdPBY/0gBWZpmKK33mNs+P5xuI23XsK2Whkjev9tg/kjjXAd3Q79WqlDW2SKT5Ugg5SxE6RgFS/pBsxWsqp3Vfx38t3hIhloECf51/aVrBabpYmwYe8l8gq/+A2PO/gpw6SBdCu2Y9x+zlAhWkY7cri7C8LSUSMS0pUM5haij4oO/7UVUbRjWmTDpg3sSLtJka2BIIl32XINMdvBCzbhIpuNCTZlWz3KCyBWRvV8r95n+p2IahbV7ZU/Jc8QvBNC0IsjCjHORtuJzXOa3BCZ2PXggboX1uaHkLe+xECC/3gjLDXAcUvM6QJN2Ytbnzfd2jTlhCt1a3ttCPUvSqN9CIJWIKnbpHPWwAk7YuMH7GXbCle9mInDvPOe16KTQ39RMsWRE1HgyTHErfT5pyaCwv2lq4oThuCrUyAGmMYgC6OZalW9DciQwp/kzKECnrwfjCCy8uJu/BlXWGMeJWjRaLFpOpZLIPaVVvKlODb8zZUZeVV1sqyyQ6+I4Opfmi0ikVW4eOqyXRy1G1O9OxXeHC2SHFuK4E5cks05EA4=" -+ -+cache: -+ directories: -+ - '$HOME/.sonar/cache' -\ No newline at end of file -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 796709d..9c14766 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -1,4 +1,5 @@ - cmake_minimum_required(VERSION 2.8) -+project(yaml-path C) - - list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") - -@@ -6,35 +7,35 @@ include(FindPkgConfig) - pkg_check_modules(YAML yaml-0.1) - find_package(codecov) - --include_directories(${YAML_INCLUDE_DIRS}) -+include_directories(${YAML_INCLUDE_DIRS} src) - --add_library(yaml-path yaml-path.c) -+add_library(yaml-path src/yaml-path.c) - target_link_libraries(yaml-path ${YAML_LIBRARIES}) -+add_coverage(yaml-path) - --add_executable(ya yaml.c) --target_link_libraries(ya yaml-path) --add_coverage(ya) -- --add_executable(yamlp yamlp.c) -+add_executable(yamlp src/yamlp.c) - target_link_libraries(yamlp yaml-path) - add_coverage(yamlp) - --add_coverage(yaml-path) -- --install(TARGETS ya RUNTIME DESTINATION bin) - install(TARGETS yamlp RUNTIME DESTINATION bin) - --add_executable(test-path-segments test-path-segments.c yaml-path.c) --add_coverage(test-path-segments) -+if(${CMAKE_C_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_C_COMPILER_ID} STREQUAL "Clang") -+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pipe -std=c99 -W -Wall -Wnonnull -Wshadow -Wformat -Wundef -Wno-unused-parameter -Wmissing-prototypes -Wno-unknown-pragmas -D_GNU_SOURCE -D_POSIX_C_SOURCE=200112L") -+endif() -+if(${CMAKE_SYSTEM_NAME} EQUAL "Solaris") -+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__EXTENSIONS__") -+endif() -+if(WIN32) -+ # Expose new WinAPI function appearing on Windows 7 (e.g. inet_pton) -+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_WIN32_WINNT=0x0600") -+endif() -+if(APPLE) -+ # Full Single Unix Standard v3 (SUSv3) conformance (the Unix API) -+ add_definitions(-D_DARWIN_C_SOURCE) -+endif() - --add_executable(test-paths test-paths.c) --target_link_libraries(test-paths yaml-path) --add_coverage(test-paths) --list(APPEND LCOV_REMOVE_PATTERNS "'${CMAKE_SOURCE_DIR}/test-*'") -+enable_testing() -+add_subdirectory("tests") - - coverage_evaluate() - --enable_testing() --add_test(NAME "test-path-segments" COMMAND ${CMAKE_BINARY_DIR}/test-path-segments) --add_test(NAME "test-paths" COMMAND ${CMAKE_BINARY_DIR}/test-paths) --add_test(NAME "test-yamlp" COMMAND ${CMAKE_SOURCE_DIR}/test-yamlp.sh) -diff --git a/README.md b/README.md -index 9f66685..26ecd44 100644 ---- a/README.md -+++ b/README.md -@@ -1,3 +1,9 @@ --# YAML Path filter -+[![Build Status](https://travis-ci.org/OpenSCAP/yaml-filter.svg?branch=master)](https://travis-ci.org/OpenSCAP/yaml-filter) [![Total alerts](https://img.shields.io/lgtm/alerts/g/OpenSCAP/yaml-filter.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/OpenSCAP/yaml-filter/alerts/) - --YAML document filtering for libyaml -+# YAML filter -+ -+YAML documnets filtering library (based on [libyaml](https://github.com/yaml/libyaml)). -+ -+[How to build and test it](docs/developer.md). -+ -+[YAML Path definition (v1)](docs/yaml_path_v1.md). -\ No newline at end of file -diff --git a/docs/developer.md b/docs/developer.md -new file mode 100644 -index 0000000..1d396af ---- /dev/null -+++ b/docs/developer.md -@@ -0,0 +1,86 @@ -+# Developer's Guide -+ -+## Building on Linux -+ -+If you want to build the `libyaml-path` library and `yamlp` filtering utility follow the these instructions: -+ -+ -+### 1. Get the source code -+ -+```sh -+$ git clone https://github.com/OpenSCAP/yaml-filter.git -+$ cd yaml-filter -+``` -+ -+ -+### 2. *Get the build dependencies* -+ -+To build the library you will also need to install the build dependencies. -+ -+The project relies on CMake (`cmake`) build system and C99 compiler (for example `gcc`). -+ -+The only mandatroy dependency of `libyaml-path` is the YAML document parser/emitter library `libyaml`. You can also use `lcov` for coverage reports, but it is optional. -+ -+```sh -+# Ubuntu -+$ sudo apt-get install -y libyaml-0-2 -+``` -+ -+```sh -+# Fedora -+$ sudo dnf install -y libyaml lcov -+``` -+ -+When you have all the build dependencies installed you can build the library. -+ -+ -+### 3. *Build the project* -+ -+Run the following commands to build the library and filtering utility: -+ -+```sh -+$ mkdir -p build -+$ cd build/ -+$ cmake .. -+$ make -+``` -+ -+ -+### 3. *Run the tests* -+ -+Now you can execute the following command to run library self-checks: -+ -+```sh -+$ ctest -+``` -+ -+ -+### 4. *Install* -+ -+Run the installation procedure by executing the following command: -+ -+```sh -+$ make install -+``` -+ -+You can also configure CMake to install everything into the $HOME/.local directory: -+ -+```sh -+$ cd build -+$ rm -rf * -+$ cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local .. -+$ make -+$ make install -+``` -+ -+ -+### 5. *Generate code coverage report* -+ -+You can use `lcov` for code coverage report generation. It is integrated into the project's build configuration: -+ -+```sh -+$ cd build -+$ cmake -DENABLE_COVERAGE=yes .. -+$ make && ctest -V -+$ make gcov -+``` -\ No newline at end of file -diff --git a/docs/yaml_path_v1.md b/docs/yaml_path_v1.md -new file mode 100644 -index 0000000..e84dbb3 ---- /dev/null -+++ b/docs/yaml_path_v1.md -@@ -0,0 +1,119 @@ -+### v1.0.0 2020-09-28 -+ -+## Overview -+This implementation is a subset of the intersection between [JSONPath](https://goessner.net/articles/JsonPath) and [YAML Path](https://pypi.org/project/yamlpath), and it focuses on addressing elements inside YAML files (node descriptors). There are no *query*-like capabilities. -+ -+Example YAML structure: -+```yaml -+foo: -+ - bar: &bar True -+ first: First Bar -+ second: 2 -+ arr: [1, 2, 3] -+ - baz: False -+ other_bar: *bar -+ first: First Baz -+ some.el/here: Delimiters... -+ "bar's": 0 -+``` -+ -+Example JSON structure: -+```json -+{ -+ "foo": [ -+ { -+ "bar": true, -+ "first": "First Bar", -+ "second": 2, -+ "arr": [1, 2, 3] -+ }, -+ { -+ "baz": false, -+ "other_bar": true, -+ "first": "First Baz", -+ "some.el/here": "Delimiters...", -+ "bar's": 0, -+ } -+ ] -+} -+``` -+ -+## Delimiters -+Dot-notation (`.`) is the only supported notation to define *map key* path segments. Both *map key* and *sequence index* path segments could also be defined using square brackets (`[`, `]`). For *map key* and *map keys selection* segments both single (`'`) and double (`"`) quotes are supported, `['key']` is the same as `["key"]` and `['key',"other's key"]` is a valid path segment. -+ -+For example: `$.foo[0].bar` or `.foo[0]['bar']` or `['foo'][0].bar` or `foo[1]["bar's"]`. -+ -+## Special symbols -+A path might be prefixed by a dollar sign and a dot (`$`, `.`), but this prefix is retained for compatibility with *JSONPath* and not mandatory. Implicit *document root* is assumed unless the path explicitly starts with an *anchor* (`&...`) segment (see below for details). -+ -+If the first segment is a *map key* segment (and explicit *document root* is omitted) the initial dot (`.`) is also not mandatory. -+ -+For example, these paths are equal: `$.el`, `.el`, `el`, `['el']`. And they all address the value stored in the "el" key of the top-most map of the document. -+ -+An asterisk (`*`) as a key name has a special meaning, and treated as an all-inclusive *keys selection* section (see below). That's it, `$.*` expression would include all keys of the map in the document root. The `[*]` syntax is also valid. One should use the `[:]` notation to acheive same effect for sequences (include all indices). -+ -+## Path Segment Types -+ -+#### Document Root -+`$` -+ -+Optional explicit document root. Only allowed to appear at the beginning of the path. -+ -+```python -+$.foo[0].bar = .foo[0].bar = foo[0].bar -+== true -+``` -+ -+ -+#### Map Key -+`.map.key` or `.map['key']` -+ -+```python -+$.foo[0].second = ['foo'][0]['second'] -+== 2 -+``` -+ -+ -+#### Map Keys Selection -+`.map['key1','key2',...'keyN']` -+ -+Special syntax for the all-inclusive key selection: `.*`. Also, there is the `[*]` variant of this syntax. -+ -+```python -+$.foo[0]['first','second'] = ['foo'][0]['first','second'] -+== {"first": "First Bar", "second": 2} -+ -+foo[0]['first','second','bar','arr'] = foo[0].* -+== {"bar": true, "first": "First Bar", "second": 2, "arr": [1, 2, 3]} -+``` -+ -+ -+#### Sequence Index -+`.array[]` -+ -+```python -+$.foo[0] -+== {"bar": True, "first": "First Bar", "second": 2} -+``` -+ -+ -+#### Sequence Indices Set -+`.array[,,...]` -+ -+Special syntax for the all-inclusive indices set: `[:]`. -+ -+```python -+$.foo[0].arr[0,1,2] = foo[0].arr[:] -+== [1, 2, 3] -+``` -+ -+ -+#### Anchor -+`&anchor` -+ -+Matches elements starting from the given anchor instead of the document root. This segment is only sensible in paths for YAML documents as there is no anchors/aliases concept in the JSON specification. -+ -+```python -+$.foo[0].bar = &bar -+== True -+``` -\ No newline at end of file -diff --git a/openshift-logging.yaml b/res/openshift-logging.yaml -similarity index 100% -rename from openshift-logging.yaml -rename to res/openshift-logging.yaml -diff --git a/res/openshift-upgradeable.yaml b/res/openshift-upgradeable.yaml -new file mode 100644 -index 0000000..e962fdd ---- /dev/null -+++ b/res/openshift-upgradeable.yaml -@@ -0,0 +1,39 @@ -+apiVersion: config.openshift.io/v1 -+kind: ClusterOperator -+metadata: -+ annotations: -+ exclude.release.openshift.io/internal-openshift-hosted: "true" -+ creationTimestamp: "2020-06-08T04:36:36Z" -+ generation: 1 -+ name: openshift-apiserver -+ resourceVersion: "53861" -+ selfLink: /apis/config.openshift.io/v1/clusteroperators/openshift-apiserver -+spec: {} -+status: -+ conditions: -+ - lastTransitionTime: "2020-06-08T04:54:58Z" -+ reason: AsExpected -+ status: "False" -+ type: Degraded -+ - lastTransitionTime: "2020-06-08T06:34:00Z" -+ reason: AsExpected -+ status: "False" -+ type: Progressing -+ - lastTransitionTime: "2020-06-08T04:51:08Z" -+ reason: AsExpected -+ status: "True" -+ type: Available -+ - lastTransitionTime: "2020-06-08T04:45:45Z" -+ reason: AsExpected -+ status: "True" -+ type: Upgradeable -+ extension: null -+ relatedObjects: -+ - group: operator.openshift.io -+ name: cluster -+ resource: openshiftapiservers -+ versions: -+ - name: operator -+ version: 4.5.0-0.nightly-2020-06-04-214605 -+ - name: openshift-apiserver -+ version: 4.5.0-0.nightly-2020-06-04-214605 -\ No newline at end of file -diff --git a/sonar-project.properties b/sonar-project.properties -new file mode 100644 -index 0000000..8983591 ---- /dev/null -+++ b/sonar-project.properties -@@ -0,0 +1,8 @@ -+sonar.organization=openscap -+ -+sonar.projectKey=OpenSCAP_yaml-filter -+sonar.projectName=yaml-filter -+ -+sonar.sources=. -+ -+sonar.cfamily.build-wrapper-output=bw-output -diff --git a/src/yaml-path.c b/src/yaml-path.c -new file mode 100644 -index 0000000..004c61d ---- /dev/null -+++ b/src/yaml-path.c -@@ -0,0 +1,829 @@ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "yaml-path.h" -+ -+ -+#define YAML_PATH_MAX_SECTION_ITEMS 256 -+ -+#define _STR(x) #x -+#define STR(x) _STR(x) -+ -+ -+typedef enum yaml_path_section_type { -+ YAML_PATH_SECTION_ROOT, -+ YAML_PATH_SECTION_ANCHOR, -+ YAML_PATH_SECTION_INDEX, -+ YAML_PATH_SECTION_SET, -+ YAML_PATH_SECTION_KEY, -+ YAML_PATH_SECTION_SELECTION, -+} yaml_path_section_type_t; -+ -+typedef struct yaml_path_selection_key_raw { -+ const char *start; -+ size_t len; -+} yaml_path_selection_key_raw_t; -+ -+ -+typedef struct yaml_path_key { -+ const char *key; -+ TAILQ_ENTRY(yaml_path_key) entries; -+} yaml_path_key_t; -+ -+typedef TAILQ_HEAD(path_key_list, yaml_path_key) path_key_list_t; -+ -+ -+typedef struct yaml_path_section { -+ yaml_path_section_type_t type; -+ size_t level; -+ union { -+ const char *anchor; -+ size_t index; -+ size_t *set; -+ const char *key; -+ path_key_list_t selection; -+ } data; -+ TAILQ_ENTRY(yaml_path_section) entries; -+ -+ yaml_node_type_t node_type; -+ size_t counter; -+ bool valid; -+ bool next_valid; -+} yaml_path_section_t; -+ -+typedef TAILQ_HEAD(path_section_list, yaml_path_section) path_section_list_t; -+ -+ -+struct yaml_path { -+ path_section_list_t sections_list; -+ size_t sections_count; -+ size_t current_level; -+ size_t start_level; -+ -+ yaml_path_error_t error; -+}; -+ -+ -+static size_t -+yaml_path_set_snprint (const size_t *set, char *s, size_t max_len) -+{ -+ assert(set != NULL); -+ if (s == NULL) -+ return -1; -+ size_t len = 0; -+ if (set[0] == 0) { -+ len += snprintf(s, max_len, "[:]"); -+ } else { -+ for (size_t i = 1; i <= set[0]; i++) -+ len += snprintf(s + (len < max_len ? len : max_len), max_len - (len < max_len ? len : max_len), "%s%zu", (len ? "," : "["), set[i]); -+ len += snprintf(s + (len < max_len ? len : max_len), max_len - (len < max_len ? len : max_len), "]"); -+ } -+ return len; -+} -+ -+static size_t -+yaml_path_selection_snprint (const path_key_list_t *selection, char *s, size_t max_len) -+{ -+ assert(selection != NULL); -+ if (s == NULL) -+ return -1; -+ size_t len = 0; -+ yaml_path_key_t *el; -+ if TAILQ_EMPTY(selection) { -+ len += snprintf(s, max_len, ".*"); -+ } else { -+ TAILQ_FOREACH(el, selection, entries) { -+ char quote = strchr(el->key, '\'') ? '"' : '\''; -+ len += snprintf(s + (len < max_len ? len : max_len), max_len - (len < max_len ? len : max_len), "%s%c%s%c", (len ? "," : "["), quote, el->key, quote); -+ } -+ len += snprintf(s + (len < max_len ? len : max_len), max_len - (len < max_len ? len : max_len), "]"); -+ } -+ return len; -+} -+ -+static bool -+yaml_path_set_is_empty (const size_t *set) -+{ -+ assert(set != NULL); -+ return set[0] == 0; -+} -+ -+static bool -+yaml_path_set_has_index (const size_t *set, size_t idx) -+{ -+ assert(set != NULL); -+ for (size_t i = 1; i <= set[0]; i++) -+ if (set[i] == idx) -+ return true; -+ return false; -+} -+ -+static bool -+yaml_path_selection_is_empty (path_key_list_t *selection) -+{ -+ assert(selection != NULL); -+ return TAILQ_EMPTY(selection) ? true : false; -+} -+ -+static const char* -+yaml_path_selection_key_get (path_key_list_t *selection, const char *key) -+{ -+ assert(selection != NULL); -+ yaml_path_key_t *el; -+ TAILQ_FOREACH(el, selection, entries) { -+ if (!strcmp(el->key, key)) -+ return el->key; -+ } -+ return NULL; -+} -+ -+static size_t -+yaml_path_selection_keys_add (path_key_list_t *selection, yaml_path_selection_key_raw_t *raw_keys, size_t count) -+{ -+ assert(selection != NULL); -+ assert(raw_keys != NULL); -+ for (size_t i = 0; i < count; i++) { -+ yaml_path_key_t *el = malloc(sizeof(*el)); -+ if (el == NULL) -+ return i; -+ TAILQ_INSERT_TAIL(selection, el, entries); -+ el->key = strndup(raw_keys[i].start, raw_keys[i].len); -+ if (el->key == NULL) -+ return i; -+ } -+ return count; -+} -+ -+static void -+yaml_path_selection_keys_remove (path_key_list_t *selection) -+{ -+ assert(selection != NULL); -+ while (!TAILQ_EMPTY(selection)) { -+ yaml_path_key_t *el = TAILQ_FIRST(selection); -+ TAILQ_REMOVE(selection, el, entries); -+ free((void *)el->key); -+ free(el); -+ } -+} -+ -+static void -+yaml_path_sections_remove (yaml_path_t *path) -+{ -+ assert(path != NULL); -+ while (!TAILQ_EMPTY(&path->sections_list)) { -+ yaml_path_section_t *el = TAILQ_FIRST(&path->sections_list); -+ TAILQ_REMOVE(&path->sections_list, el, entries); -+ path->sections_count--; -+ switch (el->type) { -+ case YAML_PATH_SECTION_KEY: -+ free((void *)el->data.key); -+ break; -+ case YAML_PATH_SECTION_ANCHOR: -+ free((void *)el->data.anchor); -+ break; -+ case YAML_PATH_SECTION_SET: -+ free((void *)el->data.set); -+ break; -+ case YAML_PATH_SECTION_SELECTION: -+ yaml_path_selection_keys_remove(&el->data.selection); -+ break; -+ default: -+ break; -+ } -+ free(el); -+ } -+} -+ -+static yaml_path_section_t* -+yaml_path_section_create (yaml_path_t *path, yaml_path_section_type_t section_type) -+{ -+ yaml_path_section_t *el = malloc(sizeof(*el)); -+ if (el != NULL) { -+ memset(el, 0, sizeof(*el)); -+ path->sections_count++; -+ el->level = path->sections_count; -+ el->type = section_type; -+ el->node_type = YAML_NO_NODE; -+ TAILQ_INSERT_TAIL(&path->sections_list, el, entries); -+ if (el->type == YAML_PATH_SECTION_SELECTION) { -+ TAILQ_INIT(&el->data.selection); -+ } -+ } -+ return el; -+} -+ -+static size_t -+yaml_path_section_snprint (yaml_path_section_t *section, char *s, size_t max_len) -+{ -+ assert(section != NULL); -+ if (s == NULL) -+ return -1; -+ size_t len; -+ switch (section->type) { -+ case YAML_PATH_SECTION_ROOT: -+ len = snprintf(s, max_len, "$"); -+ break; -+ case YAML_PATH_SECTION_KEY: { -+ char quote = '\0'; -+ if (strpbrk(section->data.key, "[]().$&*")) -+ quote = strchr(section->data.key, '\'') ? '"' : '\''; -+ if (quote) { -+ len = snprintf(s, max_len, "[%c%s%c]", quote, section->data.key, quote); -+ } else { -+ len = snprintf(s, max_len, ".%s", section->data.key); -+ } -+ } -+ break; -+ case YAML_PATH_SECTION_ANCHOR: -+ len = snprintf(s, max_len, "&%s", section->data.anchor); -+ break; -+ case YAML_PATH_SECTION_INDEX: -+ len = snprintf(s, max_len, "[%zu]", section->data.index); -+ break; -+ case YAML_PATH_SECTION_SET: -+ len = yaml_path_set_snprint(section->data.set, s, max_len); -+ break; -+ case YAML_PATH_SECTION_SELECTION: -+ len = yaml_path_selection_snprint(§ion->data.selection, s, max_len); -+ break; -+ default: -+ len = snprintf(s, max_len, ""); -+ break; -+ } -+ return len; -+} -+ -+static void -+yaml_path_error_set (yaml_path_t *path, yaml_path_error_type_t error_type, const char *message, size_t pos) -+{ -+ assert(path != NULL); -+ path->error.type = error_type; -+ path->error.message = message; -+ path->error.pos = pos; -+} -+ -+static void -+yaml_path_error_clear (yaml_path_t *path) -+{ -+ yaml_path_error_set(path, YAML_PATH_ERROR_NONE, NULL, 0); -+} -+ -+#define return_with_error(error_type, error_text, error_pos) \ -+do { \ -+ yaml_path_error_set(path, error_type, (error_text), (error_pos)); \ -+ goto error; \ -+} while (0) -+ -+static void -+yaml_path_parse_impl (yaml_path_t *path, char *s_path) { -+ char *sp = s_path; -+ char *spe = NULL; -+ -+ assert(path != NULL); -+ -+ if (s_path == NULL || !s_path[0]) { -+ yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Path string is NULL or empty", 0); -+ return; -+ } -+ -+ while (*sp != '\0') { -+ switch (*sp) { -+ case '.': -+ case '[': -+ if (path->sections_count == 0) { -+ yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_ROOT); -+ if (sec == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (section)", sp - s_path); -+ } -+ if (*sp == '.') { -+ // Key or Selection -+ spe = sp + 1; -+ if (*spe == '*') { -+ // Empty key selection section means that all keys were selected -+ yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_SELECTION); -+ if (sec == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (section)", sp - s_path); -+ while (*spe != '.' && *spe != '[' && *spe != '\0') -+ spe++; -+ } else { -+ while (*spe != '.' && *spe != '[' && *spe != '\0') -+ spe++; -+ if (spe == sp+1) -+ return_with_error(YAML_PATH_ERROR_PARSE, "Segment key is missing", sp - s_path); -+ yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_KEY); -+ if (sec == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (section)", sp - s_path); -+ sec->data.key = strndup(sp + 1, spe-sp - 1); -+ if (sec->data.key == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (key)", sp - s_path); -+ } -+ sp = spe-1; -+ } else if (*sp == '[') { -+ spe = sp + 1; -+ if (*spe == '*' && *(spe+1) == ']') { -+ // Empty key selection section means that all keys were selected -+ yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_SELECTION); -+ if (sec == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (section)", sp - s_path); -+ sp = spe+1; -+ } else if (*spe == '\'' || *spe == '"') { -+ // Key(s) -+ size_t keys_count = 0; -+ yaml_path_selection_key_raw_t raw_keys[YAML_PATH_MAX_SECTION_ITEMS] = {{NULL, 0}}; -+ sp = spe; -+ while (*spe != ']' && *spe != '\0') { -+ if (keys_count >= YAML_PATH_MAX_SECTION_ITEMS) -+ return_with_error(YAML_PATH_ERROR_SECTION, "Segment keys selection has reached the limit of keys: "STR(YAML_PATH_MAX_SECTION_ITEMS), sp - s_path); -+ char quote = *spe; -+ spe++; -+ while (*spe != quote && *spe != '\0') -+ spe++; -+ if (*spe == '\0') -+ return_with_error(YAML_PATH_ERROR_PARSE, "Segment key is invalid (unexpected end of string, missing closing quotation mark)", sp - s_path); -+ if (spe == sp+1) -+ return_with_error(YAML_PATH_ERROR_PARSE, "Segment key is missing", sp - s_path); -+ spe++; -+ if (*spe == '\0') -+ return_with_error(YAML_PATH_ERROR_PARSE, "Segment key is invalid (unexpected end of string, missing ']')", sp - s_path); -+ if (*spe == ']') { -+ raw_keys[keys_count].start = sp + 1; -+ raw_keys[keys_count].len = spe-sp - 2; -+ keys_count++; -+ } else if (*spe == ',') { -+ spe++; -+ if (*spe != '\'' && *spe != '"') -+ return_with_error(YAML_PATH_ERROR_PARSE, "Segment keys selection is invalid (invalid character)", spe - s_path); -+ raw_keys[keys_count].start = sp + 1; -+ raw_keys[keys_count].len = spe-sp - 3; -+ keys_count++; -+ sp = spe; -+ } else { -+ return_with_error(YAML_PATH_ERROR_PARSE, "Segment key is invalid (invalid character)", spe - s_path); -+ } -+ } -+ if (keys_count == 1) { -+ yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_KEY); -+ if (sec == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (section)", sp - s_path); -+ sec->data.key = strndup(raw_keys[0].start, raw_keys[0].len); -+ if (sec->data.key == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (key)", sp - s_path); -+ } else if (keys_count > 1) { -+ yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_SELECTION); -+ if (sec == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (section)", sp - s_path); -+ if (yaml_path_selection_keys_add(&sec->data.selection, raw_keys, keys_count) != keys_count) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (keys selection)", sp - s_path); -+ } -+ sp = spe; -+ } else { -+ // Indices -+ if (*spe == ':' && *(spe+1) == ']') { -+ // Set (all-inclusive) -+ yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_SET); -+ if (sec == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (section)", sp - s_path); -+ sec->data.set = malloc(sizeof(size_t) * 1); -+ if (sec->data.set == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (set)", sp - s_path); -+ sec->data.set[0] = 0; -+ sp = spe+1; -+ } else { -+ while (*spe == ' ' || *spe == '\t') -+ spe++; -+ if (*spe == '-') -+ return_with_error(YAML_PATH_ERROR_PARSE, "Segment index is invalid (negative number)", spe - s_path); -+ size_t idx = strtoul(spe, &spe, 10); -+ if (*spe == ']') { -+ // Index -+ yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_INDEX); -+ if (sec == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (section)", sp - s_path); -+ sec->data.index = idx; -+ sp = spe; -+ } else if (*spe == ',') { -+ // Set -+ size_t indices[YAML_PATH_MAX_SECTION_ITEMS+1] = {0}; -+ while (*spe == ',' && spe > sp+1) { -+ if (indices[0] >= YAML_PATH_MAX_SECTION_ITEMS) -+ return_with_error(YAML_PATH_ERROR_SECTION, "Segment indices set has reached the limit of indices: "STR(YAML_PATH_MAX_SECTION_ITEMS), sp - s_path); -+ sp = spe++; -+ indices[0]++; -+ indices[indices[0]] = idx; -+ while (*spe == ' ' || *spe == '\t') -+ spe++; -+ if (*spe == '-') -+ return_with_error(YAML_PATH_ERROR_PARSE, "Segment set index is invalid (negative number)", spe - s_path); -+ idx = strtoul(spe, &spe, 10); -+ } -+ if (*spe == ']' && spe > sp+1) { -+ indices[0]++; -+ indices[indices[0]] = idx; -+ yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_SET); -+ if (sec == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (section)", sp - s_path); -+ sec->data.set = malloc(sizeof(*indices) * (indices[0] + 1)); -+ if (sec->data.set == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (set)", sp - s_path); -+ memcpy(sec->data.set, indices, sizeof(*indices) * (indices[0] + 1)); -+ sp = spe; -+ } else { -+ return_with_error(YAML_PATH_ERROR_PARSE, "Segment set is invalid (invalid character)", spe - s_path); -+ } -+ } else if (*spe == '\0') { -+ return_with_error(YAML_PATH_ERROR_PARSE, "Segment index is invalid (unexpected end of string, missing ']')", spe - s_path); -+ } else { -+ return_with_error(YAML_PATH_ERROR_PARSE, "Segment index is invalid (invalid character)", spe - s_path); -+ } -+ } -+ } -+ } -+ break; -+ case '&': -+ if (path->sections_count == 0) { -+ spe = sp + 1; -+ while (*spe != '.' && *spe != '[' && *spe != '\0') -+ spe++; -+ if (spe - sp > 1) { -+ yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_ANCHOR); -+ if (sec == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (section)", sp - s_path); -+ sec->data.anchor = strndup(sp+1, spe-sp-1); -+ if (sec->data.anchor == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (anchor)", sp - s_path); -+ } else { -+ return_with_error(YAML_PATH_ERROR_PARSE, "Segment anchor is invalid (empty)", spe - s_path); -+ } -+ } else { -+ return_with_error(YAML_PATH_ERROR_SECTION, "Anchor segment is only allowed at the beginning of the path", sp - s_path); -+ } -+ sp = spe - 1; -+ break; -+ case '$': -+ if (path->sections_count == 0) { -+ yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_ROOT); -+ if (sec == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (section)", sp - s_path); -+ } else { -+ return_with_error(YAML_PATH_ERROR_SECTION, "Root segment is only allowed at the beginning of the path", sp - s_path); -+ } -+ break; -+ default: -+ if (path->sections_count == 0) { -+ spe = sp + 1; -+ // Special beginning of the path (implicit key) -+ while (*spe != '.' && *spe != '[' && *spe != '\0') -+ spe++; -+ yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_ROOT); -+ if (sec == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (section)", sp - s_path); -+ sec = yaml_path_section_create(path, YAML_PATH_SECTION_KEY); -+ if (sec == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (section)", sp - s_path); -+ sec->data.key = strndup(sp, spe-sp); -+ if (sec->data.key == NULL) -+ return_with_error(YAML_PATH_ERROR_NOMEM, "Unable to allocate memory (key)", sp - s_path); -+ sp = spe-1; -+ } -+ break; -+ } -+ sp++; -+ } -+ -+ if (path->sections_count == 0) -+ return_with_error(YAML_PATH_ERROR_SECTION, "Invalid, empty or meaningless path", 0); -+ -+ return; // OK -+ -+error: -+ yaml_path_sections_remove(path); -+ if (path->error.type == YAML_PATH_ERROR_NONE) -+ yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Unable to parse the path string", 0); -+} -+ -+static yaml_path_section_t* -+yaml_path_section_get_at_level (yaml_path_t *path, size_t level) -+{ -+ assert(path != NULL); -+ yaml_path_section_t *el; -+ TAILQ_FOREACH(el, &path->sections_list, entries) { -+ if (el->level == level) -+ return el; -+ } -+ return NULL; -+} -+ -+static yaml_path_section_t* -+yaml_path_section_get_first (yaml_path_t *path) -+{ -+ return yaml_path_section_get_at_level(path, 1); -+} -+ -+static yaml_path_section_t* -+yaml_path_section_get_current (yaml_path_t *path) -+{ -+ assert(path != NULL); -+ if (!path->start_level) -+ return NULL; -+ return yaml_path_section_get_at_level(path, path->current_level - path->start_level + 1); -+} -+ -+static bool -+yaml_path_section_current_is_last (yaml_path_t *path) -+{ -+ assert(path != NULL); -+ yaml_path_section_t *sec = yaml_path_section_get_current(path); -+ if (sec == NULL) -+ return false; -+ return sec->level == path->sections_count; -+} -+ -+static bool -+yaml_path_sections_prev_are_valid (yaml_path_t *path) -+{ -+ assert(path != NULL); -+ int valid = true; -+ yaml_path_section_t *el; -+ TAILQ_FOREACH(el, &path->sections_list, entries) { -+ if (el->level < path->current_level - path->start_level + 1) -+ valid = el->valid && valid; -+ } -+ return valid; -+} -+ -+static bool -+yaml_path_section_is_mandatory_container (yaml_path_section_t *sec) -+{ -+ assert(sec != NULL); -+ bool res = false; -+ if ((sec->type == YAML_PATH_SECTION_SELECTION && sec->node_type == YAML_MAPPING_NODE) -+ || -+ (sec->type == YAML_PATH_SECTION_SET && sec->node_type == YAML_SEQUENCE_NODE)) -+ res = true; -+ return res; -+} -+ -+static const char * -+yaml_path_filter_event_get_anchor (const yaml_event_t *event) -+{ -+ assert(event != NULL); -+ switch(event->type) { -+ case YAML_MAPPING_START_EVENT: -+ return (const char *)event->data.mapping_start.anchor; -+ case YAML_SEQUENCE_START_EVENT: -+ return (const char *)event->data.sequence_start.anchor; -+ case YAML_SCALAR_EVENT: -+ return (const char *)event->data.scalar.anchor; -+ default: -+ break; -+ } -+ return NULL; -+} -+ -+static bool -+yaml_path_is_valid (yaml_path_t *path) -+{ -+ assert(path != NULL); -+ bool valid = true; -+ yaml_path_section_t *el; -+ TAILQ_FOREACH(el, &path->sections_list, entries) { -+ valid = el->valid && valid; -+ } -+ return valid; -+} -+ -+ -+/* Public API -------------------------------------------------------------- */ -+ -+yaml_path_t* -+yaml_path_create (void) -+{ -+ yaml_path_t *ypath = malloc(sizeof(*ypath)); -+ if (ypath != NULL) { -+ memset (ypath, 0, sizeof(*ypath)); -+ TAILQ_INIT(&ypath->sections_list); -+ } -+ return ypath; -+} -+ -+int -+yaml_path_parse (yaml_path_t *path, char *s_path) -+{ -+ if (path == NULL) -+ return -1; -+ -+ yaml_path_sections_remove(path); -+ yaml_path_error_clear(path); -+ -+ yaml_path_parse_impl(path, s_path); -+ if (path->error.type != YAML_PATH_ERROR_NONE) -+ return -2; -+ -+ return 0; -+} -+ -+void -+yaml_path_destroy (yaml_path_t *path) -+{ -+ if (path == NULL) -+ return; -+ yaml_path_sections_remove(path); -+ free(path); -+} -+ -+const yaml_path_error_t* -+yaml_path_error_get (yaml_path_t *path) -+{ -+ if (path == NULL) -+ return NULL; -+ return &path->error; -+} -+ -+size_t -+yaml_path_snprint (yaml_path_t *path, char *s, size_t max_len) -+{ -+ if (s == NULL) -+ return -1; -+ if (path == NULL) -+ return 0; -+ -+ size_t len = 0; -+ yaml_path_section_t *el; -+ TAILQ_FOREACH(el, &path->sections_list, entries) { -+ len += yaml_path_section_snprint(el, s + (len < max_len ? len : max_len), max_len - (len < max_len ? len : max_len)); -+ } -+ return len; -+} -+ -+yaml_path_filter_result_t -+yaml_path_filter_event (yaml_path_t *path, yaml_parser_t *parser, yaml_event_t *event) -+{ -+ if (path == NULL || parser == NULL || event == NULL || path->sections_count == 0) -+ return YAML_PATH_FILTER_RESULT_OUT; -+ -+ int res = YAML_PATH_FILTER_RESULT_OUT; -+ -+ const char *anchor = yaml_path_filter_event_get_anchor(event); -+ -+ if (!path->start_level) { -+ switch (yaml_path_section_get_first(path)->type) { -+ case YAML_PATH_SECTION_ROOT: -+ if (event->type == YAML_DOCUMENT_START_EVENT) { -+ path->start_level = 1; -+ yaml_path_section_get_first(path)->valid = true; -+ } -+ break; -+ case YAML_PATH_SECTION_ANCHOR: -+ if (anchor != NULL && !strcmp(yaml_path_section_get_first(path)->data.anchor, anchor)) { -+ path->start_level = path->current_level; -+ } -+ break; -+ default: -+ break; -+ } -+ } -+ -+ yaml_path_section_t *current_section = yaml_path_section_get_current(path); -+ if (current_section) { -+ switch (event->type) { -+ case YAML_DOCUMENT_START_EVENT: -+ case YAML_MAPPING_START_EVENT: -+ case YAML_SEQUENCE_START_EVENT: -+ case YAML_ALIAS_EVENT: -+ case YAML_SCALAR_EVENT: -+ switch (current_section->node_type) { -+ case YAML_NO_NODE: -+ if (current_section->type == YAML_PATH_SECTION_ANCHOR) { -+ current_section->valid = false; -+ if (anchor != NULL && !strcmp(current_section->data.anchor, anchor)) -+ current_section->valid = true; -+ } -+ break; -+ case YAML_MAPPING_NODE: -+ if (current_section->type == YAML_PATH_SECTION_KEY) { -+ if (current_section->counter % 2) { -+ current_section->valid = current_section->next_valid; -+ current_section->next_valid = false; -+ } else { -+ current_section->next_valid = !strcmp(current_section->data.key, (const char *)event->data.scalar.value); -+ current_section->valid = false; -+ } -+ } else if (current_section->type == YAML_PATH_SECTION_SELECTION) { -+ if (current_section->counter % 2) { -+ current_section->valid = current_section->next_valid; -+ current_section->next_valid = false; -+ } else { -+ current_section->next_valid = yaml_path_selection_is_empty(¤t_section->data.selection) -+ || yaml_path_selection_key_get(¤t_section->data.selection, (const char *)event->data.scalar.value) != NULL; -+ current_section->valid = current_section->next_valid; -+ } -+ } else { -+ current_section->valid = false; -+ } -+ break; -+ case YAML_SEQUENCE_NODE: -+ if (current_section->type == YAML_PATH_SECTION_INDEX) { -+ current_section->valid = current_section->data.index == current_section->counter; -+ } else if (current_section->type == YAML_PATH_SECTION_SET) { -+ current_section->valid = yaml_path_set_is_empty(current_section->data.set) -+ || yaml_path_set_has_index(current_section->data.set, current_section->counter); -+ } else { -+ current_section->valid = false; -+ } -+ break; -+ default: -+ break; -+ } -+ current_section->counter++; -+ default: -+ break; -+ } -+ } -+ -+ switch (event->type) { -+ case YAML_STREAM_START_EVENT: -+ case YAML_STREAM_END_EVENT: -+ case YAML_NO_EVENT: -+ res = YAML_PATH_FILTER_RESULT_IN; -+ break; -+ case YAML_DOCUMENT_START_EVENT: -+ if (path->start_level == 1) -+ path->current_level++; -+ res = YAML_PATH_FILTER_RESULT_IN; -+ break; -+ case YAML_DOCUMENT_END_EVENT: -+ if (path->start_level == 1) -+ path->current_level--; -+ res = YAML_PATH_FILTER_RESULT_IN; -+ break; -+ case YAML_MAPPING_START_EVENT: -+ case YAML_SEQUENCE_START_EVENT: -+ if (current_section) { -+ if (yaml_path_section_current_is_last(path)) -+ if (yaml_path_is_valid(path)) -+ res = YAML_PATH_FILTER_RESULT_IN; -+ } else { -+ if (path->current_level > path->start_level) { -+ if (yaml_path_is_valid(path)) -+ res = YAML_PATH_FILTER_RESULT_IN; -+ } -+ } -+ path->current_level++; -+ current_section = yaml_path_section_get_current(path); -+ if (current_section) { -+ current_section->node_type = event->type == YAML_MAPPING_START_EVENT ? YAML_MAPPING_NODE : YAML_SEQUENCE_NODE; -+ current_section->counter = 0; -+ } -+ if (current_section) { -+ if (yaml_path_section_is_mandatory_container(current_section) && yaml_path_sections_prev_are_valid(path)) -+ res = YAML_PATH_FILTER_RESULT_IN; -+ } -+ break; -+ case YAML_MAPPING_END_EVENT: -+ case YAML_SEQUENCE_END_EVENT: -+ if (current_section) { -+ if (yaml_path_section_is_mandatory_container(current_section) && yaml_path_sections_prev_are_valid(path)) -+ res = YAML_PATH_FILTER_RESULT_IN; -+ -+ } -+ path->current_level--; -+ current_section = yaml_path_section_get_current(path); -+ if (current_section) { -+ if (yaml_path_section_current_is_last(path)) -+ if (yaml_path_is_valid(path)) -+ res = YAML_PATH_FILTER_RESULT_IN; -+ } else { -+ if (path->current_level > path->start_level) { -+ if (yaml_path_is_valid(path)) -+ res = YAML_PATH_FILTER_RESULT_IN; -+ } -+ } -+ break; -+ case YAML_ALIAS_EVENT: -+ case YAML_SCALAR_EVENT: -+ if (!current_section) { -+ if (path->current_level >= path->start_level) -+ if (yaml_path_is_valid(path)) -+ res = YAML_PATH_FILTER_RESULT_IN; -+ } else { -+ if (yaml_path_section_current_is_last(path) && yaml_path_is_valid(path)) -+ res = YAML_PATH_FILTER_RESULT_IN; -+ if (current_section->valid -+ && current_section->node_type == YAML_MAPPING_NODE -+ && current_section->counter % 2) { -+ if (yaml_path_section_is_mandatory_container(current_section) && yaml_path_sections_prev_are_valid(path)) -+ res = YAML_PATH_FILTER_RESULT_IN_DANGLING_KEY; -+ } -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return res; -+} -diff --git a/yaml-path.h b/src/yaml-path.h -similarity index 72% -rename from yaml-path.h -rename to src/yaml-path.h -index eb9e9dc..66e0298 100644 ---- a/yaml-path.h -+++ b/src/yaml-path.h -@@ -8,20 +8,22 @@ typedef struct yaml_path yaml_path_t; - - typedef enum yaml_path_error_type { - YAML_PATH_ERROR_NONE, -+ YAML_PATH_ERROR_NOMEM, - YAML_PATH_ERROR_PARSE, -+ YAML_PATH_ERROR_SECTION, - } yaml_path_error_type_t; - - typedef struct yaml_path_error { - yaml_path_error_type_t type; - const char *message; -- const char *context; - size_t pos; - } yaml_path_error_t; - --typedef enum yaml_path_filter_mode { -- YAML_PATH_FILTER_RETURN_ALL, -- YAML_PATH_FILTER_RETURN_SHALLOW, --} yaml_path_filter_mode_t; -+typedef enum yaml_path_filter_result { -+ YAML_PATH_FILTER_RESULT_OUT, -+ YAML_PATH_FILTER_RESULT_IN, -+ YAML_PATH_FILTER_RESULT_IN_DANGLING_KEY, -+} yaml_path_filter_result_t; - - - yaml_path_t* -@@ -36,8 +38,8 @@ yaml_path_destroy (yaml_path_t *path); - const yaml_path_error_t* - yaml_path_error_get (yaml_path_t *path); - --int --yaml_path_filter_event (yaml_path_t *path, yaml_parser_t *parser, yaml_event_t *event, yaml_path_filter_mode_t mode); -+yaml_path_filter_result_t -+yaml_path_filter_event (yaml_path_t *path, yaml_parser_t *parser, yaml_event_t *event); - - size_t - yaml_path_snprint (yaml_path_t *path, char *s, size_t max_len); -diff --git a/yamlp.c b/src/yamlp.c -similarity index 80% -rename from yamlp.c -rename to src/yamlp.c -index 334c626..f4d44d2 100644 ---- a/yamlp.c -+++ b/src/yamlp.c -@@ -9,13 +9,14 @@ - #include "yaml-path.h" - - --int parse_and_emit (yaml_parser_t *parser, yaml_emitter_t *emitter, yaml_path_t *path, yaml_path_filter_mode_t mode, int use_flow_style) -+static int -+parse_and_emit (yaml_parser_t *parser, yaml_emitter_t *emitter, yaml_path_t *path, int use_flow_style) - { - yaml_event_t event; -- yaml_event_type_t prev_event_type, event_type; -+ yaml_event_type_t event_type, prev_event_type = YAML_NO_EVENT; -+ yaml_path_filter_result_t result, prev_result = YAML_PATH_FILTER_RESULT_OUT; - - do { -- - if (!yaml_parser_parse(parser, &event)) { - switch (parser->error) { - case YAML_MEMORY_ERROR: -@@ -53,7 +54,8 @@ int parse_and_emit (yaml_parser_t *parser, yaml_emitter_t *emitter, yaml_path_t - return 1; - } else { - event_type = event.type; -- if (!yaml_path_filter_event(path, parser, &event, mode)) { -+ result = yaml_path_filter_event(path, parser, &event); -+ if (result == YAML_PATH_FILTER_RESULT_OUT) { - yaml_event_delete(&event); - } else { - if (use_flow_style) { -@@ -68,11 +70,16 @@ int parse_and_emit (yaml_parser_t *parser, yaml_emitter_t *emitter, yaml_path_t - break; - } - } -- if (prev_event_type == YAML_DOCUMENT_START_EVENT && event_type == YAML_DOCUMENT_END_EVENT) { -+ if ((prev_event_type == YAML_DOCUMENT_START_EVENT && event_type == YAML_DOCUMENT_END_EVENT) -+ || (prev_result == YAML_PATH_FILTER_RESULT_IN_DANGLING_KEY -+ && (event_type == YAML_MAPPING_END_EVENT -+ || event_type == YAML_SEQUENCE_END_EVENT -+ || result == YAML_PATH_FILTER_RESULT_IN_DANGLING_KEY))) { - yaml_event_t null_event= {0}; - yaml_scalar_event_initialize(&null_event, NULL, (yaml_char_t *)"!!null", (yaml_char_t *)"null", 4, 1, 0, YAML_ANY_SCALAR_STYLE); - yaml_emitter_emit(emitter, &null_event); - } -+ prev_result = result; - prev_event_type = event_type; - if (!yaml_emitter_emit(emitter, &event)) { - switch (emitter->error) -@@ -100,11 +107,12 @@ int parse_and_emit (yaml_parser_t *parser, yaml_emitter_t *emitter, yaml_path_t - } - - --void help (void) -+static void -+help (void) - { - printf("yamlp - filtering utility for YAML documents\n"); - printf("\n"); -- printf("Usage: yamlp [-F] [-S] [-W ] [-f ] \n"); -+ printf("Usage: yamlp [-F] [-W ] [-f ] \n"); - printf(" yamlp -h\n"); - printf("\n"); - printf("The tool will take the input YAML document from or a (-f option),\n"); -@@ -118,8 +126,6 @@ void help (void) - printf("\n"); - printf(" -h help;\n"); - printf("\n"); -- printf(" -S 'shallow' filter mode;\n"); -- printf("\n"); - printf(" -W line wrap width, no wrapping if omitted.\n"); - printf("\n"); - } -@@ -129,8 +135,7 @@ int main(int argc, char *argv[]) - int flow = 0; - char *file_name = NULL; - char *path_string = NULL; -- int wrap = -1; -- yaml_path_filter_mode_t mode = YAML_PATH_FILTER_RETURN_ALL; -+ long wrap = -1; - - int opt; - while ((opt = getopt(argc, argv, ":f:W:vhSF")) != -1) { -@@ -138,13 +143,9 @@ int main(int argc, char *argv[]) - case 'h': - help(); - return 0; -- break; - case 'F': - flow = 1; - break; -- case 'S': -- mode = YAML_PATH_FILTER_RETURN_SHALLOW; -- break; - case 'W': - wrap = strtol(optarg, NULL, 10); - if (!wrap) { -@@ -158,11 +159,12 @@ int main(int argc, char *argv[]) - case ':': - fprintf(stderr, "Option needs a value\n"); - return 1; -- break; - case '?': - fprintf(stderr, "Unknown option '%c'\n", optopt); - return 1; -- break; -+ default: -+ fprintf(stderr, "Unhandled option '%c'\n", opt); -+ return 1; - } - } - -@@ -186,9 +188,10 @@ int main(int argc, char *argv[]) - - yaml_path_t *path = yaml_path_create(); - if (yaml_path_parse(path, path_string)) { -- fprintf(stderr, "Invalid path '%s' (%s)\n", path_string, yaml_path_error_get(path)->message); -+ fprintf(stderr, "Invalid path: '%s'\n", path_string); -+ fprintf(stderr, " %*s^ %s [at position %zu]\n", (int)yaml_path_error_get(path)->pos, " ", yaml_path_error_get(path)->message, yaml_path_error_get(path)->pos); - return 3; -- }; -+ } - - yaml_parser_t parser; - yaml_emitter_t emitter; -@@ -198,9 +201,9 @@ int main(int argc, char *argv[]) - - yaml_emitter_initialize(&emitter); - yaml_emitter_set_output_file(&emitter, stdout); -- yaml_emitter_set_width(&emitter, wrap); -+ yaml_emitter_set_width(&emitter, (int) wrap); - -- if (parse_and_emit(&parser, &emitter, path, mode, flow)) { -+ if (parse_and_emit(&parser, &emitter, path, flow)) { - return 4; - } - -@@ -208,7 +211,8 @@ int main(int argc, char *argv[]) - yaml_emitter_delete(&emitter); - - yaml_path_destroy(path); -- fclose(file); -+ if (file != NULL) -+ fclose(file); - - return 0; - } -diff --git a/test-yamlp.sh b/test-yamlp.sh -deleted file mode 100755 -index 8c2b413..0000000 ---- a/test-yamlp.sh -+++ /dev/null -@@ -1,19 +0,0 @@ --#!/bin/bash -- --yamlp_test() --{ -- echo -n "$1 ($2) " -- out=$(./yamlp -F -f "$1" "$2") || return 1 -- echo -n "-> $out" -- if [ "$out" != "$3" ]; then -- echo ": FAILED, expected result: $3" -- return 2 -- else -- echo ": OK" -- fi --} -- --yamlp_test "../openshift-logging.yaml" ".spec.pipelines[:].inputSource" "[logs.app, logs.infra, logs.audit]" --res=$((res+$?)) -- --exit $res -diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt -new file mode 100644 -index 0000000..bc01b4b ---- /dev/null -+++ b/tests/CMakeLists.txt -@@ -0,0 +1,28 @@ -+function(_add_test TEST_NAME TEST_COMMAND) -+ add_test(NAME ${TEST_NAME} COMMAND ${TEST_COMMAND}) -+ set_tests_properties(${TEST_NAME} PROPERTIES -+ SKIP_RETURN_CODE 255 -+ ENVIRONMENT "CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR};SOURCE_DIR=${CMAKE_SOURCE_DIR};BINARY_DIR=${CMAKE_BINARY_DIR}" -+ ) -+endfunction() -+ -+function(add_test_executable EXECUTABLE_NAME SOURCE_FILE) -+ set(TEST_EXECUTABLE_LIBRARIES yaml-path) -+ add_executable(${EXECUTABLE_NAME} ${SOURCE_FILE} ${ARGN}) -+ target_link_libraries(${EXECUTABLE_NAME} ${TEST_EXECUTABLE_LIBRARIES}) -+ target_include_directories(${EXECUTABLE_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") -+ add_coverage(${EXECUTABLE_NAME}) -+ string(REPLACE "${CMAKE_SOURCE_DIR}/tests/" "" TEST_NAME "${CMAKE_CURRENT_SOURCE_DIR}/${EXECUTABLE_NAME}") -+ _add_test(${TEST_NAME} "${CMAKE_BINARY_DIR}/tests/${EXECUTABLE_NAME}") -+endfunction() -+ -+function(add_test_script TEST_SCRIPT) -+ string(REPLACE "${CMAKE_SOURCE_DIR}/tests/" "" TEST_NAME "${CMAKE_CURRENT_SOURCE_DIR}/${TEST_SCRIPT}") -+ _add_test(${TEST_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/${TEST_SCRIPT}") -+endfunction() -+ -+add_test_executable(test-path-segments test-path-segments.c) -+add_test_executable(test-paths test-paths.c) -+add_test_script(test-yamlp.sh) -+ -+list(APPEND LCOV_REMOVE_PATTERNS "'${CMAKE_SOURCE_DIR}/tests/*'") -diff --git a/test-path-segments.c b/tests/test-path-segments.c -similarity index 54% -rename from test-path-segments.c -rename to tests/test-path-segments.c -index 2340937..0889004 100644 ---- a/test-path-segments.c -+++ b/tests/test-path-segments.c -@@ -1,6 +1,7 @@ -+// SPDX-License-Identifier: MIT -+// Copyright (c) 2020 Red Hat Inc., Durham, North Carolina. -+ - #include --#include --#include - - #include "yaml-path.h" - -@@ -17,7 +18,7 @@ yp_s[PATH_STRING_LEN] = {0}; - #define ASCII_ERR "\033[0;33m" - #define ASCII_RST "\033[0;0m" - --void -+static void - yp_test (char *p, int expected_failure) - { - yaml_path_t *yp = yaml_path_create(); -@@ -35,7 +36,7 @@ yp_test (char *p, int expected_failure) - printf(ASCII_ERR); - test_result++; - } -- printf(" -X %s (at pos: %zu): %s\n", ype->message, ype->pos, !expected_failure ? ASCII_RST"FAILED" : "OK"); -+ printf(" -- %s (at pos: %zu): %s\n", ype->message, ype->pos, !expected_failure ? ASCII_RST"FAILED" : "OK"); - } - yaml_path_destroy(yp); - } -@@ -46,7 +47,9 @@ yp_test (char *p, int expected_failure) - - int main (int argc, char *argv[]) - { -- yp_test_good(".first"); -+ (void) argc; (void) argv; // Yep, we don't need them -+ -+ yp_test_good(".first"); - yp_test_good(".first[0]"); - yp_test_good(".first.second[0].third"); - yp_test_good(".first.0"); -@@ -58,31 +61,62 @@ int main (int argc, char *argv[]) - yp_test_good("!"); - yp_test_good("$"); - -- yp_test_good("[0:0]"); -- yp_test_good("[0:0:1]"); -- yp_test_good("[100:]"); -- yp_test_good("[100::]"); -- yp_test_good("[:100]"); -- yp_test_good("[:100:]"); - yp_test_good("[:]"); -- yp_test_good("[::]"); -- yp_test_good("[-03:-200:+500]"); -+ yp_test_good("[':']['*'][:]"); -+ yp_test_good(".:.*[:]"); -+ yp_test_good("[0,2,3,4,5,20,180]"); - - yp_test_good("&anc"); - yp_test_good("&anc[0]"); - yp_test_good("&anc[0].zzz"); - - yp_test_good("el['key']"); -- yp_test_good("el['key'].other[0]['key']"); -+ yp_test_good("el[\"key\"]"); -+ yp_test_good("el[\"k[]ey\"]"); -+ yp_test_good("el[\"k'ey\"]"); -+ yp_test_good("el['k\"ey']"); -+ yp_test_good("el.k\"ey"); -+ yp_test_good("el.k$ey"); -+ yp_test_good("el.k'&'ey"); -+ yp_test_good("el['key'].other[0]['key'][0,2]"); -+ -+ yp_test_good("el['first','other']"); -+ yp_test_good("el[\"first\",\"other\"]"); -+ yp_test_good("el[\"first\",'other']"); -+ yp_test_good("el['key','valid']['now','allowed']"); -+ yp_test_good("el.*"); -+ yp_test_good("el[*]"); -+ yp_test_good("el['*']"); -+ -+ yp_test_invalid("$$"); -+ yp_test_invalid("$&"); -+ -+ yp_test_invalid("&"); - - yp_test_invalid("$."); - yp_test_invalid(""); - yp_test_invalid("."); - yp_test_invalid("element["); - -+ yp_test_invalid("[-5]"); -+ yp_test_invalid("[1,-5]"); -+ -+ yp_test_invalid("[0:0]"); -+ yp_test_invalid("[0:0:1]"); -+ yp_test_invalid("[100:]"); -+ yp_test_invalid("[100::]"); -+ yp_test_invalid("[:100]"); -+ yp_test_invalid("[:100:]"); -+ yp_test_invalid("[::]"); -+ yp_test_invalid("[-03:-200:+500]"); -+ - yp_test_invalid("[0:0:0]"); - yp_test_invalid("[::-1]"); - yp_test_invalid("[0.key[0]"); -+ yp_test_invalid("[1,]"); -+ yp_test_invalid("[,]"); -+ yp_test_invalid("[1,:]"); -+ yp_test_invalid("[1,2:]"); - - yp_test_invalid("el[&]"); - yp_test_invalid("el[&"); -@@ -93,9 +127,18 @@ int main (int argc, char *argv[]) - yp_test_invalid("el[&anchor][100]"); - - yp_test_invalid("el[']"); -+ yp_test_invalid("[*'"); - yp_test_invalid("el['key].wrong"); - yp_test_invalid("el['key.wrong"); - yp_test_invalid("el['key'"); -+ yp_test_invalid("el['key\"]"); -+ yp_test_invalid("el[\"key']"); -+ yp_test_invalid("el['k'ey']"); -+ -+ yp_test_invalid("el['key';'wrong']"); -+ yp_test_invalid("el['key',]"); -+ yp_test_invalid("el['key',invalid]"); -+ yp_test_invalid("el['first',]"); - - return test_result; - } -diff --git a/test-paths.c b/tests/test-paths.c -similarity index 65% -rename from test-paths.c -rename to tests/test-paths.c -index 58cfdad..fa722e8 100644 ---- a/test-paths.c -+++ b/tests/test-paths.c -@@ -1,6 +1,8 @@ -+// SPDX-License-Identifier: MIT -+// Copyright (c) 2020 Red Hat Inc., Durham, North Carolina. -+ - #include - #include --#include - #include - - #include "yaml-path.h" -@@ -59,14 +61,11 @@ yaml_out[YAML_STRING_LEN] = {0}; - static size_t - yaml_out_len = 0; - --static yaml_path_filter_mode_t --mode = YAML_PATH_FILTER_RETURN_ALL; -- - static int - test_result = 0; - - --int -+static int - yp_run (char *path) - { - yaml_parser_t parser; -@@ -74,11 +73,15 @@ yp_run (char *path) - int res = 0; - - yaml_path_t *yp = yaml_path_create(); -- yaml_path_parse(yp, path); -+ if (yaml_path_parse(yp, path)) { -+ printf("Path error: %s\n", yaml_path_error_get(yp)->message); -+ yaml_path_destroy(yp); -+ return 1; -+ } - -- char spath[YAML_STRING_LEN] = {0}; -- yaml_path_snprint(yp, spath, YAML_STRING_LEN); -- printf("(%s) ", spath); -+ //char spath[YAML_STRING_LEN] = {0}; -+ //yaml_path_snprint(yp, spath, YAML_STRING_LEN); -+ //printf("(%s) ", spath); - - yaml_emitter_initialize(&emitter); - yaml_parser_initialize(&parser); -@@ -89,7 +92,8 @@ yp_run (char *path) - yaml_emitter_set_width(&emitter, -1); - - yaml_event_t event; -- yaml_event_type_t prev_event_type, event_type; -+ yaml_event_type_t event_type, prev_event_type = YAML_NO_EVENT; -+ yaml_path_filter_result_t result, prev_result = 0; - - do { - if (!yaml_parser_parse(&parser, &event)) { -@@ -126,30 +130,35 @@ yp_run (char *path) - goto error; - } else { - event_type = event.type; -- if (!yaml_path_filter_event(yp, &parser, &event, mode)) { -+ result = yaml_path_filter_event(yp, &parser, &event); -+ if (result == YAML_PATH_FILTER_RESULT_OUT) { - yaml_event_delete(&event); - } else { -- if (prev_event_type == YAML_DOCUMENT_START_EVENT && event_type == YAML_DOCUMENT_END_EVENT) { -+ if ((prev_event_type == YAML_DOCUMENT_START_EVENT && event_type == YAML_DOCUMENT_END_EVENT) -+ || (prev_result == YAML_PATH_FILTER_RESULT_IN_DANGLING_KEY -+ && (event_type == YAML_MAPPING_END_EVENT || event_type == YAML_SEQUENCE_END_EVENT || result == YAML_PATH_FILTER_RESULT_IN_DANGLING_KEY))) { - yaml_event_t null_event= {0}; - yaml_scalar_event_initialize(&null_event, NULL, (yaml_char_t *)"!!null", (yaml_char_t *)"null", 4, 1, 0, YAML_ANY_SCALAR_STYLE); - yaml_emitter_emit(&emitter, &null_event); - } -+ prev_result = result; - prev_event_type = event_type; - if (!yaml_emitter_emit(&emitter, &event)) { -- printf("Error after '%s'\n", yp_event_name(event.type)); -+ yaml_emitter_flush(&emitter); -+ printf("%s --> Error after '%s': ", yaml_out, yp_event_name(event.type)); - switch (emitter.error) - { - case YAML_MEMORY_ERROR: -- printf("Memory error: Not enough memory for emitting\n"); -+ printf("Memory error (Not enough memory for emitting)"); - break; - case YAML_WRITER_ERROR: -- printf("Writer error: %s\n", emitter.problem); -+ printf("Writer error (%s)", emitter.problem); - break; - case YAML_EMITTER_ERROR: -- printf("Emitter error: %s\n", emitter.problem); -+ printf("Emitter error (%s)", emitter.problem); - break; - default: -- printf("Internal error\n"); -+ printf("Internal error"); - break; - } - res = 2; -@@ -171,17 +180,19 @@ yp_run (char *path) - #define ASCII_ERR "\033[0;33m" - #define ASCII_RST "\033[0;0m" - --void -+static void - yp_test (char *path, char *yaml_exp) - { -- printf("%s ", path); -+ printf("%s "ASCII_ERR, path); - if (!yp_run(path)) { - rstrip(yaml_out); - if (!strcmp(yaml_exp, yaml_out)) { -- printf("(%s): OK\n", yaml_exp); -+ printf(ASCII_RST"(%s): OK\n", yaml_exp); - return; - } -- printf(ASCII_ERR"(%s != %s)"ASCII_RST": FAILED\n", yaml_exp, yaml_out); -+ printf("(%s != %s)"ASCII_RST": FAILED\n", yaml_exp, yaml_out); -+ } else { -+ printf(ASCII_RST": ERROR\n"); - } - test_result++; - } -@@ -189,6 +200,8 @@ yp_test (char *path, char *yaml_exp) - - int main (int argc, char *argv[]) - { -+ (void) argc; (void) argv; // Yep, we don't need them -+ - yaml = - "{" - "first: {" -@@ -204,14 +217,18 @@ int main (int argc, char *argv[]) - "]" - "}," - "second: [" -- "{'abc': &anc [1, 2], 'abcdef': 2, 'z': *anc}," -- "{'abc': [3, 4], 'abcdef': 4, 'z': 'zzz'}" -+ "{'abc': &anc [1, 2], 'def': [11, 22], 'abcdef': 2, 'z': *anc, 'q': 'Q'}," -+ "{'abc': [3, 4], 'def': {'z': '!'}, 'abcdef': 4, 'z': 'zzz'}" -+ "]," -+ "3rd: [" -+ "{'a': {'A': [0, 1], 'AA': [2, 3]}, 'b': {'A': [10, 11], 'BB': [9, 8]}}," -+ "{'z': {'A': [0, 1], 'BB': [22, 33]}}," -+ "&x {'q': [1, 2]}," - "]" - "}"; - - // Path Expected filtered YAML result - -- mode = YAML_PATH_FILTER_RETURN_ALL; - yp_test("$.first.Map", "{1: '1'}"); - yp_test(".first", "{'Map': {1: '1'}, 'Nop': 0, 'Yep': '1', 'Arr': [[11, 12], 2, ['31', '32'], [4, 5, 6, 7, 8, 9], {'k': 'val', 0: 0}]}"); - yp_test(".first.Nop", "0"); -@@ -219,24 +236,27 @@ int main (int argc, char *argv[]) - yp_test(".first.Arr[0]", "[11, 12]"); - yp_test(".first.Arr[1]", "2"); - yp_test(".first.Arr[2][0]", "'31'"); -- yp_test(".first.Arr[:2][0]", "[11]"); - yp_test(".first.Arr[3][:]", "[4, 5, 6, 7, 8, 9]"); -+ yp_test(".first.Arr[:][:]", "[[11, 12], ['31', '32'], [4, 5, 6, 7, 8, 9]]"); - yp_test(".first.Arr[4].k", "'val'"); - yp_test(".first.Arr[:][0]", "[11, '31', 4]"); - yp_test(".first.Arr[:].k", "['val']"); - yp_test(".first.Arr[:][2]", "[6]"); -- yp_test(".first.Arr[3][1::2]", "[5, 7, 9]"); -- yp_test(".first.Arr[3][::2]", "[4, 6, 8]"); -- yp_test(".first.Arr[3][:4:2]", "[4, 6]"); -+ yp_test(".first.Arr[:][0,1]", "[[11, 12], ['31', '32'], [4, 5]]"); -+ yp_test(".first.Arr[:][1]", "[12, '32', 5]"); - yp_test(".second[2].abc", "null"); -- yp_test(".second[0:2].abc", "[&anc [1, 2], [3, 4]]"); - yp_test(".second[0].z", "*anc"); -+ yp_test("&anc", "&anc [1, 2]"); - yp_test("&anc[0]", "1"); -- -- mode = YAML_PATH_FILTER_RETURN_SHALLOW; -- yp_test(".first", "{}"); -- yp_test(".first.Nop", "0"); -- yp_test(".first.Map", "{}"); -+ yp_test(".first['Nop','Yep']", "{'Nop': 0, 'Yep': '1'}"); -+ yp_test(".second[0]['abc','def'][0]","{'abc': 1, 'def': 11}"); -+ yp_test(".second[:]['abc','def'][0]","[{'abc': 1, 'def': 11}, {'abc': 3, 'def': null}]"); -+ yp_test(".second[:]['abc','def'].z", "[{'abc': null, 'def': null}, {'abc': null, 'def': '!'}]"); -+ yp_test(".second[:][*].z", "[{'abc': null, 'def': null, 'abcdef': null, 'z': null, 'q': null}, {'abc': null, 'def': '!', 'abcdef': null, 'z': null}]"); -+ yp_test(".second[:]['abc','q']", "[{'abc': &anc [1, 2], 'q': 'Q'}, {'abc': [3, 4]}]"); -+ yp_test(".second[:]['abc','def'][:]","[{'abc': &anc [1, 2], 'def': [11, 22]}, {'abc': [3, 4], 'def': null}]"); -+ yp_test(".second[0]['abc','def']", "{'abc': &anc [1, 2], 'def': [11, 22]}"); -+ yp_test(".3rd[:].*.*[:]", "[{'a': {'A': [0, 1], 'AA': [2, 3]}, 'b': {'A': [10, 11], 'BB': [9, 8]}}, {'z': {'A': [0, 1], 'BB': [22, 33]}}, &x {'q': null}]"); - - return test_result; - } -diff --git a/tests/test-yamlp.sh b/tests/test-yamlp.sh -new file mode 100755 -index 0000000..d009659 ---- /dev/null -+++ b/tests/test-yamlp.sh -@@ -0,0 +1,27 @@ -+#!/bin/bash -+ -+# SPDX-License-Identifier: MIT -+# Copyright (c) 2020 Red Hat Inc., Durham, North Carolina. -+ -+yamlp_test() -+{ -+ echo "$1:" -+ echo -n " ($2) " -+ out=$("${BINARY_DIR:-../build}/yamlp" -F -f "$1" "$2") || return 1 -+ echo -n "-> $out" -+ if [ "$out" != "$3" ]; then -+ echo ": FAILED, expected result: $3" -+ return 2 -+ else -+ echo ": OK" -+ fi -+} -+ -+yamlp_test "${SOURCE_DIR:-..}/res/openshift-logging.yaml" ".spec.pipelines[:].inputSource" "[logs.app, logs.infra, logs.audit]" -+res=$((res+$?)) -+ -+yamlp_test "${SOURCE_DIR:-..}/res/openshift-upgradeable.yaml" ".status.conditions[:]['status','type']" \ -+ '[{status: "False", type: Degraded}, {status: "False", type: Progressing}, {status: "True", type: Available}, {status: "True", type: Upgradeable}]' -+res=$((res+$?)) -+ -+exit $res -diff --git a/yaml-path.c b/yaml-path.c -deleted file mode 100644 -index 00611ca..0000000 ---- a/yaml-path.c -+++ /dev/null -@@ -1,588 +0,0 @@ --#include --#include --#include --#include --#include -- --#include -- --#include "yaml-path.h" -- -- --#define YAML_PATH_MAX_SECTION_LEN 1024 --#define YAML_PATH_MAX_SECTIONS 255 --#define YAML_PATH_MAX_LEN YAML_PATH_MAX_SECTION_LEN * YAML_PATH_MAX_SECTIONS -- -- --typedef enum yaml_path_section_type { -- YAML_PATH_SECTION_ROOT, -- YAML_PATH_SECTION_ANCHOR, -- YAML_PATH_SECTION_KEY, -- YAML_PATH_SECTION_INDEX, -- YAML_PATH_SECTION_SLICE, --} yaml_path_section_type_t; -- --typedef struct yaml_path_section { -- yaml_path_section_type_t type; -- int level; -- union { -- const char *key; -- const char *anchor; -- int index; -- struct {int start, end, stride;} slice; -- } data; -- TAILQ_ENTRY(yaml_path_section) entries; -- -- yaml_node_type_t node_type; -- int counter; -- bool valid; -- bool next_valid; --} yaml_path_section_t; -- --typedef TAILQ_HEAD(path_section_list, yaml_path_section) path_section_list_t; -- --typedef struct yaml_path { -- path_section_list_t sections_list; -- size_t sections_count; -- size_t sequence_level; -- -- size_t current_level; -- size_t start_level; -- -- yaml_path_error_t error; --} yaml_path_t; -- -- --static void --yaml_path_error_set (yaml_path_t *path, yaml_path_error_type_t error_type, const char *message, size_t pos) --{ -- assert(path != NULL); -- path->error.type = error_type; -- path->error.message = message; -- path->error.pos = pos; --} -- --static void --yaml_path_sections_remove (yaml_path_t *path) --{ -- assert(path != NULL); -- while (!TAILQ_EMPTY(&path->sections_list)) { -- yaml_path_section_t *el = TAILQ_FIRST(&path->sections_list); -- TAILQ_REMOVE(&path->sections_list, el, entries); -- path->sections_count--; -- switch (el->type) { -- case YAML_PATH_SECTION_KEY: -- free((void *)el->data.key); -- break; -- case YAML_PATH_SECTION_ANCHOR: -- free((void *)el->data.anchor); -- break; -- case YAML_PATH_SECTION_SLICE: -- if (path->sequence_level == el->level) -- path->sequence_level = 0; -- break; -- default: -- break; -- } -- free(el); -- } --} -- --static yaml_path_section_t* --yaml_path_section_create (yaml_path_t *path, yaml_path_section_type_t section_type) --{ -- yaml_path_section_t *el = malloc(sizeof(*el)); -- assert(el != NULL); -- memset(el, 0, sizeof(*el)); -- path->sections_count++; -- el->level = path->sections_count; -- el->type = section_type; -- el->node_type = YAML_SCALAR_NODE; -- TAILQ_INSERT_TAIL(&path->sections_list, el, entries); -- if (el->type == YAML_PATH_SECTION_SLICE && !path->sequence_level) { -- path->sequence_level = el->level; -- } -- return el; --} -- --static size_t --yaml_path_section_snprint (yaml_path_section_t *section, char *s, size_t max_len) --{ -- assert(section != NULL); -- if (s == NULL) -- return -1; -- size_t len = 0; -- switch (section->type) { -- case YAML_PATH_SECTION_ROOT: -- len = snprintf(s, max_len, "$"); -- break; -- case YAML_PATH_SECTION_KEY: -- len = snprintf(s, max_len, ".%s", section->data.key); -- break; -- case YAML_PATH_SECTION_ANCHOR: -- len = snprintf(s, max_len, "&%s", section->data.anchor); -- break; -- case YAML_PATH_SECTION_INDEX: -- len = snprintf(s, max_len, "[%d]", section->data.index); -- break; -- case YAML_PATH_SECTION_SLICE: -- len = snprintf(s, max_len, "[%d:%d:%d]", section->data.slice.start, section->data.slice.end, section->data.slice.stride); -- break; -- default: -- len = snprintf(s, max_len, ""); -- break; -- } -- return len; --} -- --static void --_parse (yaml_path_t *path, char *s_path) { -- char *sp = s_path; -- char *spe = NULL; -- -- assert(path != NULL); -- -- if (s_path == NULL || !s_path[0]) { -- yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Path is empty", 0); -- return; -- } -- -- while (*sp != '\0') { -- switch (*sp) { -- case '.': -- case '[': -- if (path->sections_count == 0) { -- yaml_path_section_create(path, YAML_PATH_SECTION_ROOT); -- } -- if (*sp == '.') { -- // Key -- spe = sp + 1; -- while (*spe != '.' && *spe != '[' && *spe != '\0') -- spe++; -- if (spe == sp+1) { -- yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment key is missing", sp - s_path); -- goto error; -- } -- yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_KEY); -- sec->data.key = strndup(sp + 1, spe-sp - 1); -- sp = spe-1; -- } else if (*sp == '[') { -- spe = sp+1; -- if (*spe == '\'') { -- // Key -- sp = spe; -- spe++; -- while (*spe != '\'' && *spe != '\0') -- spe++; -- if (spe == sp+1) { -- yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment key is missing", sp - s_path); -- goto error; -- } -- if (*spe == '\0') { -- yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment key is invalid (unxepected end of string, missing ''')", sp - s_path); -- goto error; -- } -- spe++; -- if (*spe == '\0') { -- yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment key is invalid (unxepected end of string, missing ']')", sp - s_path); -- goto error; -- } -- if (*spe != ']') { -- yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment key is invalid (invalid character)", spe - s_path); -- goto error; -- } -- yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_KEY); -- sec->data.key = strndup(sp + 1, spe-sp - 2); -- sp = spe; -- } else { -- // Index or Slice -- int idx = strtol(spe, &spe, 10); -- if (*spe == ']') { -- // Index -- yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_INDEX); -- sec->data.index = idx; -- sp = spe; -- } else if (*spe == ':') { -- // Slice -- int idx_start = idx; -- sp = spe++; -- idx = strtol(spe, &spe, 10); -- if (*spe == ':') { -- int idx_end = (spe == sp+1 ? __INT_MAX__ : idx); -- sp = spe++; -- idx = strtol(spe, &spe, 10); -- if (*spe == ']' && (idx > 0 || spe == sp+1)) { -- yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_SLICE); -- sec->data.slice.start = idx_start; -- sec->data.slice.end = idx_end; -- sec->data.slice.stride = idx > 0 ? idx : 1; -- sp = spe; -- } else if (*spe == ']' && idx <= 0) { -- yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment slice stride can not be less than 1", spe - s_path - 1); -- goto error; -- } else { -- yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment slice stride is invalid (invalid character)", spe - s_path); -- goto error; -- } -- } else if (*spe == ']') { -- yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_SLICE); -- sec->data.slice.start = idx_start; -- sec->data.slice.end = (spe == sp+1 ? __INT_MAX__ : idx); -- sec->data.slice.stride = 1; -- sp = spe; -- } else { -- yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment slice end index is invalid (invalid character)", spe - s_path); -- goto error; -- } -- } else if (*spe == '\0') { -- yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment index is invalid (unxepected end of string, missing ']')", spe - s_path); -- goto error; -- } else { -- yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment index is invalid (invalid character)", spe - s_path); -- goto error; -- } -- } -- } -- break; -- default: -- if (path->sections_count == 0) { -- spe = sp + 1; -- if (*sp == '$' && (*spe == '.' || *spe == '[' || *spe == '\0')) { -- yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_ROOT); -- } else if (*sp == '&') { -- // Anchor -- sp++; -- while (*spe != '.' && *spe != '[' && *spe != '\0') -- spe++; -- yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_ANCHOR); -- sec->data.anchor = strndup(sp, spe-sp); -- } else { -- // Key -- while (*spe != '.' && *spe != '[' && *spe != '\0') -- spe++; -- yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_ROOT); -- sec = yaml_path_section_create(path, YAML_PATH_SECTION_KEY); -- sec->data.key = strndup(sp, spe-sp); -- } -- sp = spe-1; -- } -- break; -- } -- sp++; -- } -- -- if (path->sections_count == 0) { -- yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Invalid path segments", 0); -- } -- -- return; -- --error: -- yaml_path_sections_remove(path); --} -- --static yaml_path_section_t* --yaml_path_section_get_at_level (yaml_path_t *path, size_t level) --{ -- assert(path != NULL); -- yaml_path_section_t *el; -- TAILQ_FOREACH(el, &path->sections_list, entries) { -- if (el->level == level) -- return el; -- } -- return NULL; --} -- --static yaml_path_section_t* --yaml_path_section_get_first (yaml_path_t *path) --{ -- assert(path != NULL); -- return yaml_path_section_get_at_level(path, 1); --} -- --static yaml_path_section_t* --yaml_path_section_get_current (yaml_path_t *path) --{ -- assert(path != NULL); -- if (!path->start_level) -- return NULL; -- return yaml_path_section_get_at_level(path, path->current_level - path->start_level + 1); --} -- --static bool --yaml_path_sections_prev_are_valid (yaml_path_t *path) --{ -- assert(path != NULL); -- int valid = true; -- yaml_path_section_t *el; -- TAILQ_FOREACH(el, &path->sections_list, entries) { -- if (el->level < path->current_level - path->start_level + 1) -- valid = el->valid && valid; -- } -- return valid; --} -- --static bool --yaml_path_section_current_is_last (yaml_path_t *path) --{ -- assert(path != NULL); -- yaml_path_section_t *sec = yaml_path_section_get_current(path); -- if (sec == NULL) -- return false; -- return sec->level == path->sections_count; --} -- --static bool --yaml_path_section_current_is_mandatory_sequence (yaml_path_t *path) --{ -- assert(path != NULL); -- yaml_path_section_t *sec = yaml_path_section_get_current(path); -- if (sec == NULL) -- return false; -- return (sec->type == YAML_PATH_SECTION_SLICE && sec->level == path->sequence_level); --} -- --static bool --yaml_path_is_valid (yaml_path_t *path) --{ -- assert(path != NULL); -- bool valid = true; -- yaml_path_section_t *el; -- TAILQ_FOREACH(el, &path->sections_list, entries) { -- valid = el->valid && valid; -- } -- return valid; --} -- -- --/* Public */ -- --yaml_path_t* --yaml_path_create (void) --{ -- yaml_path_t *ypath = malloc(sizeof(*ypath)); -- -- assert(ypath != NULL); -- memset (ypath, 0, sizeof(*ypath)); -- TAILQ_INIT(&ypath->sections_list); -- -- return ypath; --} -- --int --yaml_path_parse (yaml_path_t *path, char *s_path) --{ -- if (path == NULL) -- return -1; -- -- yaml_path_sections_remove(path); -- memset(&path->error, 0, sizeof(path->error)); -- -- _parse(path, s_path); -- -- if (path->sections_count == 0) -- return -2; -- -- return 0; --} -- --void --yaml_path_destroy (yaml_path_t *path) --{ -- if (path == NULL) -- return; -- yaml_path_sections_remove(path); -- free(path); --} -- --/* API */ -- --const yaml_path_error_t* --yaml_path_error_get (yaml_path_t *path) --{ -- if (path == NULL) -- return NULL; -- return &path->error; --} -- --size_t --yaml_path_snprint (yaml_path_t *path, char *s, size_t max_len) --{ -- if (s == NULL) -- return -1; -- if (path == NULL) -- return 0; -- -- size_t len = 0; -- yaml_path_section_t *el; -- TAILQ_FOREACH(el, &path->sections_list, entries) { -- len += yaml_path_section_snprint(el, s + (len < max_len ? len : max_len), max_len - (len < max_len ? len : max_len)); -- } -- return len; --} -- --int --yaml_path_filter_event (yaml_path_t *path, yaml_parser_t *parser, yaml_event_t *event, yaml_path_filter_mode_t mode) --{ -- int res = 0; -- const char *anchor = NULL; -- -- if (path == NULL || parser == NULL || event == NULL) -- goto exit; -- -- switch(event->type) { -- case YAML_MAPPING_START_EVENT: -- anchor = (const char *)event->data.mapping_start.anchor; -- break; -- case YAML_SEQUENCE_START_EVENT: -- anchor = (const char *)event->data.sequence_start.anchor; -- break; -- case YAML_SCALAR_EVENT: -- anchor = (const char *)event->data.scalar.anchor; -- break; -- default: -- break; -- } -- -- if (!path->start_level) { -- switch (yaml_path_section_get_first(path)->type) { -- case YAML_PATH_SECTION_ROOT: -- if (event->type == YAML_DOCUMENT_START_EVENT) { -- path->start_level = 1; -- yaml_path_section_get_first(path)->valid = true; -- } -- break; -- case YAML_PATH_SECTION_ANCHOR: -- if (anchor != NULL) { -- if (!strcmp(yaml_path_section_get_first(path)->data.anchor, anchor)) { -- path->start_level = path->current_level; -- if (yaml_path_section_get_current(path)) -- yaml_path_section_get_current(path)->node_type = YAML_SCALAR_NODE; -- } -- } -- break; -- default: -- //TODO: This path is invalid -- break; -- } -- } else { -- //TODO: ? -- } -- -- yaml_path_section_t *current_section = yaml_path_section_get_current(path); -- if (!current_section) { -- } else { -- switch (event->type) { -- case YAML_DOCUMENT_START_EVENT: -- case YAML_MAPPING_START_EVENT: -- case YAML_SEQUENCE_START_EVENT: -- case YAML_ALIAS_EVENT: -- case YAML_SCALAR_EVENT: -- switch (current_section->node_type) { -- case YAML_SCALAR_NODE: -- current_section->valid = true; -- break; -- case YAML_MAPPING_NODE: -- if (current_section->type == YAML_PATH_SECTION_KEY) { -- if (current_section->counter % 2) { -- current_section->valid = current_section->next_valid; -- current_section->next_valid = false; -- } else { -- current_section->next_valid = !strcmp(current_section->data.key, (const char *)event->data.scalar.value); -- current_section->valid = false; -- } -- } else { -- current_section->valid = false; -- } -- break; -- case YAML_SEQUENCE_NODE: -- if (current_section->type == YAML_PATH_SECTION_INDEX) { -- current_section->valid = current_section->data.index == current_section->counter; -- } else if (current_section->type == YAML_PATH_SECTION_SLICE) { -- current_section->valid = current_section->data.slice.start <= current_section->counter && -- current_section->data.slice.end > current_section->counter && -- (current_section->data.slice.start + current_section->counter) % current_section->data.slice.stride == 0; -- } else { -- current_section->valid = false; -- } -- break; -- default: -- break; -- } -- current_section->counter++; -- default: -- break; -- } -- } -- -- switch (event->type) { -- case YAML_STREAM_START_EVENT: -- case YAML_STREAM_END_EVENT: -- case YAML_NO_EVENT: -- res = 1; -- break; -- case YAML_DOCUMENT_START_EVENT: -- if (path->start_level == 1) -- path->current_level++; -- res = 1; -- break; -- case YAML_DOCUMENT_END_EVENT: -- if (path->start_level == 1) -- path->current_level--; -- res = 1; -- break; -- case YAML_MAPPING_START_EVENT: -- case YAML_SEQUENCE_START_EVENT: -- if (current_section) { -- if (yaml_path_section_current_is_last(path)) -- res = yaml_path_is_valid(path); -- } else { -- if (path->current_level > path->start_level) { -- if (mode == YAML_PATH_FILTER_RETURN_ALL) -- res = yaml_path_is_valid(path); -- } -- } -- path->current_level++; -- current_section = yaml_path_section_get_current(path); -- if (current_section && yaml_path_section_current_is_mandatory_sequence(path)) { -- res = yaml_path_sections_prev_are_valid(path); -- } -- if (current_section) { -- current_section->node_type = event->type == YAML_MAPPING_START_EVENT ? YAML_MAPPING_NODE : YAML_SEQUENCE_NODE; -- current_section->counter = 0; -- } -- break; -- case YAML_MAPPING_END_EVENT: -- case YAML_SEQUENCE_END_EVENT: -- if (current_section) { -- if (yaml_path_section_current_is_mandatory_sequence(path)) -- res = yaml_path_sections_prev_are_valid(path); -- } -- path->current_level--; -- current_section = yaml_path_section_get_current(path); -- if (current_section) { -- if (yaml_path_section_current_is_last(path)) -- res = yaml_path_is_valid(path); -- } else { -- if (path->current_level > path->start_level) { -- if (mode == YAML_PATH_FILTER_RETURN_ALL) -- res = yaml_path_is_valid(path); -- } -- } -- break; -- case YAML_ALIAS_EVENT: -- case YAML_SCALAR_EVENT: -- if (!current_section) { -- if ((mode == YAML_PATH_FILTER_RETURN_ALL && path->current_level > path->start_level) || path->current_level == path->start_level) -- res = yaml_path_is_valid(path); -- } else { -- res = yaml_path_is_valid(path) && yaml_path_section_current_is_last(path); -- } -- break; -- default: -- break; -- } -- --exit: -- return res; --} -diff --git a/yaml.c b/yaml.c -deleted file mode 100644 -index e2d9007..0000000 ---- a/yaml.c -+++ /dev/null -@@ -1,172 +0,0 @@ --#include --#include --#include --#include -- --#include "yaml-path.h" -- --#define INDENT " " --#define STRVAL(x) ((x) ? (char*)(x) : "") -- --void indent(int level) --{ -- int i; -- for (i = 0; i < level; i++) { -- printf("%s", INDENT); -- } --} -- --void print_event(yaml_event_t *event) --{ -- static int level = 0; -- -- switch (event->type) { -- case YAML_NO_EVENT: -- indent(level); -- printf("no-event\n"); -- break; -- case YAML_STREAM_START_EVENT: -- indent(level++); -- printf("stream-start-event\n"); -- break; -- case YAML_STREAM_END_EVENT: -- indent(--level); -- printf("stream-end-event\n"); -- break; -- case YAML_DOCUMENT_START_EVENT: -- indent(level++); -- printf("document-start-event\n"); -- break; -- case YAML_DOCUMENT_END_EVENT: -- indent(--level); -- printf("document-end-event\n"); -- break; -- case YAML_ALIAS_EVENT: -- indent(level); -- printf("alias-event * (anc=\"%s\")\n", STRVAL(event->data.scalar.anchor)); -- break; -- case YAML_SCALAR_EVENT: -- indent(level); -- printf("= scalar-event (anc=\"%s\" val=\"%s\", l=%d, t=%s, pl_impl=%d, q_impl=%d, st=%d)\n", -- STRVAL(event->data.scalar.anchor), -- STRVAL(event->data.scalar.value), -- (int)event->data.scalar.length, -- event->data.scalar.tag, -- event->data.scalar.plain_implicit, event->data.scalar.quoted_implicit, event->data.scalar.style); -- break; -- case YAML_SEQUENCE_START_EVENT: -- indent(level++); -- printf("[ sequence-start-event (anc=\"%s\", t=%s)\n", -- STRVAL(event->data.sequence_start.anchor), -- event->data.sequence_start.tag); -- break; -- case YAML_SEQUENCE_END_EVENT: -- indent(--level); -- printf("] sequence-end-event\n"); -- break; -- case YAML_MAPPING_START_EVENT: -- indent(level++); -- printf("{ mapping-start-event\n"); -- break; -- case YAML_MAPPING_END_EVENT: -- indent(--level); -- printf("} mapping-end-event\n"); -- break; -- } -- if (level < 0) { -- fprintf(stderr, "indentation underflow!\n"); -- level = 0; -- } --} -- --int yaml_parser_parse_and_filter (yaml_parser_t *parser, yaml_event_t *event, yaml_path_t *path) --{ -- int valid_event = 0; -- int res; -- do { -- res = yaml_parser_parse(parser, event); -- if (res) { -- printf("=====> "); -- print_event(event); -- if (!yaml_path_filter_event(path, parser, event, YAML_PATH_FILTER_RETURN_ALL)) { -- yaml_event_delete(event); -- } else { -- printf("+------------------------------------------------------------------------------------> "); -- print_event(event); -- valid_event = 1; -- } -- } else { -- break; -- } -- } while (!valid_event && res); -- -- return res; --} -- --int main(int argc, char *argv[]) --{ -- yaml_parser_t parser; -- yaml_event_t event; -- yaml_event_type_t event_type; -- -- yaml_path_t *yp = yaml_path_create(); -- //yaml_path_parse(yp, ".fruit.Oop[1]"); -- //yaml_path_parse(yp, ".first.Arr[:2][0]"); //.Arr[2][0] -- //yaml_path_parse(yp, ".first.Arr[3][:]"); -- //yaml_path_parse(yp, ".first.Map"); -- //yaml_path_parse(yp, ".first.Arr[:].k"); -- //yaml_path_parse(yp, ".first.Arr[:][2]"); -- //yaml_path_parse(yp, ".metadata.name"); -- //yaml_path_parse(yp, ".spec.outputs[0:2].name"); -- //yaml_path_parse(yp, ".second[0].abc"); -- //yaml_path_parse(yp, "&anc[0]"); -- yaml_path_parse(yp, ".first.Map"); -- -- //const char *yaml = "2"; -- //const char *yaml = "{'el': {'Z': &anc [{'key': 0}, {'item': 1}]}, first: {'Map': &anc {1: '1'}, 'Nop': 'b', 'Yep': '2', 'Arr': [[11,12],2,[31,32],[4, 5, 6],{'k': 1, 0: 0}]}}"; -- const char *yaml = -- "{" -- "first: {" -- "'Map': {1: '1'}," -- "'Nop': 0," -- "'Yep': '1'," -- "'Arr': [" -- "[11, 12]," -- "2," -- "['31', '32']," -- "[4, 5, 6, 7, 8, 9]," -- "{'k': 'val', 0: 0}" -- "]" -- "}," -- "second: [" -- "{'abc': &anc [1, 2], 'abcdef': 2, 'z': *anc}," -- "{'abc': [3, 4], 'abcdef': 4, 'z': 'zzz'}" -- "]" -- "}"; -- -- char ypath[255] = {0}; -- yaml_path_snprint (yp, ypath, 255); -- printf("%s\n", yaml); -- printf("%s\n\n", ypath); -- -- yaml_parser_initialize(&parser); -- //yaml_parser_set_input_file(&parser, fopen("../openshift-logging-1.yaml", "r")); -- yaml_parser_set_input_string(&parser, (const unsigned char*)yaml, strlen(yaml)); -- -- do { -- if (!yaml_parser_parse_and_filter(&parser, &event, yp)) -- goto error; -- event_type = event.type; -- yaml_event_delete(&event); -- } while (event_type != YAML_STREAM_END_EVENT); -- -- yaml_path_destroy(yp); -- yaml_parser_delete(&parser); -- return 0; -- --error: -- yaml_path_destroy(yp); -- fprintf(stderr, "Failed to parse: %s\n", parser.problem); -- yaml_parser_delete(&parser); -- return 1; --} diff --git a/SOURCES/openscap-1.3.4-detect_remote_file_systems-PR_1573.patch b/SOURCES/openscap-1.3.4-detect_remote_file_systems-PR_1573.patch deleted file mode 100644 index 77d8b01..0000000 --- a/SOURCES/openscap-1.3.4-detect_remote_file_systems-PR_1573.patch +++ /dev/null @@ -1,94 +0,0 @@ -diff --git a/src/OVAL/probes/fsdev.c b/src/OVAL/probes/fsdev.c -index 82356d5e0..983675098 100644 ---- a/src/OVAL/probes/fsdev.c -+++ b/src/OVAL/probes/fsdev.c -@@ -62,6 +62,7 @@ - #endif - - #include "fsdev.h" -+#include "common/util.h" - - /** - * Compare two dev_t variables. -@@ -79,10 +80,6 @@ static int fsdev_cmp(const void *a, const void *b) - #if defined(OS_LINUX) - static int is_local_fs(struct mntent *ment) - { --// todo: would it be usefull to provide the choice during build-time? --#if 1 -- char *s; -- - /* - * When type of the filesystem is autofs, it means the mtab entry - * describes the autofs configuration, which means ment->mnt_fsname -@@ -97,37 +94,42 @@ static int is_local_fs(struct mntent *ment) - return 0; - } - -- if (ment->mnt_fsname == NULL) { -- return 0; -- } -- -- s = ment->mnt_fsname; -- /* If the fsname begins with "//", it is probably CIFS. */ -- if (s[0] == '/' && s[1] == '/') -- return 0; -- -- /* If there's a ':' in the fsname and it occurs before any -- * '/', then this is probably NFS and the file system is -- * considered "remote". -+ /* -+ * The following code is inspired by systemd, function fstype_is_network: -+ * https://github.com/systemd/systemd/blob/21fd6bc263f49b57867d90d2e1f9f255e5509134/src/basic/mountpoint-util.c#L290 - */ -- s = strpbrk(s, "/:"); -- if (s && *s == ':') -- return 0; - -+ const char *fstype = ment->mnt_type; -+ if (oscap_str_startswith(fstype, "fuse.")) { -+ fstype += strlen("fuse."); -+ } -+ const char *network_fs[] = { -+ "afs", -+ "ceph", -+ "cifs", -+ "smb3", -+ "smbfs", -+ "sshfs", -+ "ncpfs", -+ "ncp", -+ "nfs", -+ "nfs4", -+ "gfs", -+ "gfs2", -+ "glusterfs", -+ "gpfs", -+ "pvfs2", /* OrangeFS */ -+ "ocfs2", -+ "lustre", -+ "davfs", -+ NULL -+ }; -+ for (int i = 0; network_fs[i]; i++) { -+ if (!strcmp(network_fs[i], fstype)) { -+ return 0; -+ } -+ } - return 1; --#else -- struct stat st; -- -- /* If the file system is not backed-up by a real file, it is -- considered remote. A notable exception is "tmpfs" to allow -- traversal of /tmp et al. */ -- if (strcmp(ment->mnt_fsname, "tmpfs") != 0 -- && (stat(ment->mnt_fsname, &st) != 0 -- || !(S_ISBLK(st.st_mode)))) -- return 0; -- else -- return 1; --#endif - } - - #elif defined(OS_AIX) diff --git a/SOURCES/openscap-1.3.4-export-profile-platform-PR_1609.patch b/SOURCES/openscap-1.3.4-export-profile-platform-PR_1609.patch deleted file mode 100644 index b25f114..0000000 --- a/SOURCES/openscap-1.3.4-export-profile-platform-PR_1609.patch +++ /dev/null @@ -1,107 +0,0 @@ -From cca0af9f2260a34aa4c2e57a7a418ce2b4732e16 Mon Sep 17 00:00:00 2001 -From: Watson Sato -Date: Mon, 28 Sep 2020 12:40:16 +0200 -Subject: [PATCH 1/2] Test resolving a Profile with platform - ---- - tests/API/XCCDF/unittests/CMakeLists.txt | 1 + - .../test_xccdf_resolve_profile_platform.sh | 31 +++++++++++++++++++ - ...t_xccdf_resolve_profile_platform.xccdf.xml | 13 ++++++++ - 3 files changed, 45 insertions(+) - create mode 100755 tests/API/XCCDF/unittests/test_xccdf_resolve_profile_platform.sh - create mode 100644 tests/API/XCCDF/unittests/test_xccdf_resolve_profile_platform.xccdf.xml - -diff --git a/tests/API/XCCDF/unittests/CMakeLists.txt b/tests/API/XCCDF/unittests/CMakeLists.txt -index 05ddea219..153a1c321 100644 ---- a/tests/API/XCCDF/unittests/CMakeLists.txt -+++ b/tests/API/XCCDF/unittests/CMakeLists.txt -@@ -62,6 +62,7 @@ add_oscap_test("test_default_selector.sh") - add_oscap_test("test_inherit_selector.sh") - add_oscap_test("test_xccdf_refine_value_bad.sh") - add_oscap_test("test_xccdf_resolve.sh") -+add_oscap_test("test_xccdf_resolve_profile_platform.sh") - add_oscap_test("test_xccdf_results_arf_no_oval.sh") - add_oscap_test("test_xccdf_sub_title.sh") - add_oscap_test("test_xccdf_test_system.sh") -diff --git a/tests/API/XCCDF/unittests/test_xccdf_resolve_profile_platform.sh b/tests/API/XCCDF/unittests/test_xccdf_resolve_profile_platform.sh -new file mode 100755 -index 000000000..95f8ce4b4 ---- /dev/null -+++ b/tests/API/XCCDF/unittests/test_xccdf_resolve_profile_platform.sh -@@ -0,0 +1,31 @@ -+#!/usr/bin/env bash -+. $builddir/tests/test_common.sh -+ -+######################################################################## -+### Test "oscap xccdf resolve" command on a Profile with platform -+######################################################################## -+ -+set -e -+set -o pipefail -+ -+name=$(basename $0 .sh) -+ -+result=$(mktemp -t ${name}.res.XXXXXX) -+stderr=$(mktemp -t ${name}.out.XXXXXX) -+stdout=$(mktemp -t ${name}.out.XXXXXX) -+ -+ -+echo "Stderr file = $stderr" -+echo "Result file = $result" -+ -+$OSCAP xccdf resolve --output $result $srcdir/${name}.xccdf.xml > $stdout -+$OSCAP xccdf validate $result >> $stdout -+ -+assert_exists 1 '//Benchmark[@resolved="1"]' -+ -+# Resolve Profile Platform -+assert_exists 2 '//Profile[@id="xccdf_resolve_profile_platform"]/select' -+assert_exists 1 '//Profile[@id="xccdf_resolve_profile_platform"]/platform[@idref="cpe:/a:open-scap:oscap"]' -+ -+[ -f $stderr ]; [ ! -s $stderr ]; rm $stderr -+rm $result -diff --git a/tests/API/XCCDF/unittests/test_xccdf_resolve_profile_platform.xccdf.xml b/tests/API/XCCDF/unittests/test_xccdf_resolve_profile_platform.xccdf.xml -new file mode 100644 -index 000000000..f4773bef7 ---- /dev/null -+++ b/tests/API/XCCDF/unittests/test_xccdf_resolve_profile_platform.xccdf.xml -@@ -0,0 +1,13 @@ -+ -+ -+ incomplete -+ 1.0 -+ -+ -+ Profile with platform -+ -+ -+ -+ -+ - -From 46b78146db6ba1fa57926068c4400d876423126b Mon Sep 17 00:00:00 2001 -From: Watson Sato -Date: Mon, 28 Sep 2020 13:03:46 +0200 -Subject: [PATCH 2/2] Fix export of platform profile to DOM - -The xccdf:platform should reference the ID of a CPE name or a CPE -applicability language expression. ---- - src/XCCDF/profile.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/XCCDF/profile.c b/src/XCCDF/profile.c -index 776ef616a..b8a3f4749 100644 ---- a/src/XCCDF/profile.c -+++ b/src/XCCDF/profile.c -@@ -319,7 +319,8 @@ void xccdf_profile_to_dom(struct xccdf_profile *profile, xmlNode *profile_node, - struct oscap_string_iterator *platforms = xccdf_profile_get_platforms(profile); - while (oscap_string_iterator_has_more(platforms)) { - const char *platform = oscap_string_iterator_next(platforms); -- xmlNewTextChild(profile_node, ns_xccdf, BAD_CAST "platform", BAD_CAST platform); -+ xmlNode *platform_node = xmlNewTextChild(profile_node, ns_xccdf, BAD_CAST "platform", NULL); -+ xmlNewProp(platform_node, BAD_CAST "idref", BAD_CAST platform); - } - oscap_string_iterator_free(platforms); - diff --git a/SOURCES/openscap-1.3.4-fix-environmentvariable58-regression.patch b/SOURCES/openscap-1.3.4-fix-environmentvariable58-regression.patch deleted file mode 100644 index 2c1b2db..0000000 --- a/SOURCES/openscap-1.3.4-fix-environmentvariable58-regression.patch +++ /dev/null @@ -1,59 +0,0 @@ -diff --git a/src/OVAL/probes/independent/environmentvariable58_probe.c b/src/OVAL/probes/independent/environmentvariable58_probe.c -index 552ce6700..77233aeeb 100644 ---- a/src/OVAL/probes/independent/environmentvariable58_probe.c -+++ b/src/OVAL/probes/independent/environmentvariable58_probe.c -@@ -96,32 +96,32 @@ static int read_environment(SEXP_t *pid_ent, SEXP_t *name_ent, probe_ctx *ctx) - ssize_t buffer_used; - size_t buffer_size; - -+ const char *extra_vars = getenv("OSCAP_CONTAINER_VARS"); -+ if (extra_vars && *extra_vars) { -+ char *vars = strdup(extra_vars); -+ char *tok, *eq_chr, *str, *strp; -+ -+ for (str = vars; ; str = NULL) { -+ tok = strtok_r(str, "\n", &strp); -+ if (tok == NULL) -+ break; -+ eq_chr = strchr(tok, '='); -+ if (eq_chr == NULL) -+ continue; -+ PROBE_ENT_I32VAL(pid_ent, pid, pid = -1;, pid = 0;); -+ collect_variable(tok, eq_chr - tok, pid, name_ent, ctx); -+ } -+ -+ free(vars); -+ return 0; -+ } -+ - const char *prefix = getenv("OSCAP_PROBE_ROOT"); - snprintf(path, PATH_MAX, "%s/proc", prefix ? prefix : ""); - d = opendir(path); - if (d == NULL) { -- const char *extra_vars = getenv("OSCAP_CONTAINER_VARS"); -- if (!extra_vars) { -- dE("Can't read %s/proc: errno=%d, %s.", prefix ? prefix : "", errno, strerror(errno)); -- return PROBE_EACCESS; -- } else { -- char *vars = strdup(extra_vars); -- char *tok, *eq_chr, *str, *strp; -- -- for (str = vars; ; str = NULL) { -- tok = strtok_r(str, "\n", &strp); -- if (tok == NULL) -- break; -- eq_chr = strchr(tok, '='); -- if (eq_chr == NULL) -- continue; -- PROBE_ENT_I32VAL(pid_ent, pid, pid = -1;, pid = 0;); -- collect_variable(tok, eq_chr - tok, pid, name_ent, ctx); -- } -- -- free(vars); -- return 0; -- } -+ dE("Can't read %s/proc: errno=%d, %s.", prefix ? prefix : "", errno, strerror(errno)); -+ return PROBE_EACCESS; - } - - if ((buffer = realloc(NULL, BUFFER_SIZE)) == NULL) { diff --git a/SOURCES/openscap-1.3.4-fix-no-more-recursion.patch b/SOURCES/openscap-1.3.4-fix-no-more-recursion.patch deleted file mode 100644 index ebc20ca..0000000 --- a/SOURCES/openscap-1.3.4-fix-no-more-recursion.patch +++ /dev/null @@ -1,177 +0,0 @@ -From c8fc880a672afbfdbd384dc6afa4b7fbdd666b73 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= -Date: Wed, 27 May 2020 10:38:56 +0200 -Subject: [PATCH 1/3] Add a regression test for RHBZ#1686370 - -There is a non-optimal behavior of file probe. It happens when file path -is specified using a variable with 2 values with `operation="equals"` -and `var_check="all"`. The probe recurses into a file system tree even -if it's obvious that it won't find any match. If one of values is a big -tree (for example `/`) it eventually runs out of memory and crashes. The -OVAL doesn't make sense because it's impossible that a single file would -have 2 different paths. But despite that it's a valid OVAL document. -The test is expected to fail because the bug hasn't been fixed. ---- - tests/probes/file/CMakeLists.txt | 1 + - .../test_probes_file_multiple_file_paths.sh | 39 +++++++++++++++++ - .../test_probes_file_multiple_file_paths.xml | 42 +++++++++++++++++++ - 3 files changed, 82 insertions(+) - create mode 100755 tests/probes/file/test_probes_file_multiple_file_paths.sh - create mode 100644 tests/probes/file/test_probes_file_multiple_file_paths.xml - -diff --git a/tests/probes/file/CMakeLists.txt b/tests/probes/file/CMakeLists.txt -index 12718603f..35b4c1169 100644 ---- a/tests/probes/file/CMakeLists.txt -+++ b/tests/probes/file/CMakeLists.txt -@@ -1,3 +1,4 @@ - if(ENABLE_PROBES_UNIX) - add_oscap_test("test_probes_file.sh") -+ add_oscap_test("test_probes_file_multiple_file_paths.sh") - endif() -diff --git a/tests/probes/file/test_probes_file_multiple_file_paths.sh b/tests/probes/file/test_probes_file_multiple_file_paths.sh -new file mode 100755 -index 000000000..1cececbb0 ---- /dev/null -+++ b/tests/probes/file/test_probes_file_multiple_file_paths.sh -@@ -0,0 +1,39 @@ -+#!/bin/bash -+ -+set -e -o pipefail -+ -+. $builddir/tests/test_common.sh -+ -+probecheck "file" || exit 255 -+which strace || exit 255 -+ -+function check_strace_output { -+ strace_log="$1" -+ grep -q "/tmp/numbers/1" $strace_log && return 1 -+ grep -q "/tmp/numbers/1/2" $strace_log && return 1 -+ grep -q "/tmp/numbers/1/2/3" $strace_log && return 1 -+ grep -q "/tmp/numbers/1/2/3/4" $strace_log && return 1 -+ grep -q "/tmp/numbers/1/2/3/4/5" $strace_log && return 1 -+ grep -q "/tmp/numbers/1/2/3/4/5/6" $strace_log && return 1 -+ grep -q "/tmp/letters/a" $strace_log && return 1 -+ grep -q "/tmp/letters/a/b" $strace_log && return 1 -+ grep -q "/tmp/letters/a/b/c" $strace_log && return 1 -+ grep -q "/tmp/letters/a/b/c/d" $strace_log && return 1 -+ grep -q "/tmp/letters/a/b/c/d/e" $strace_log && return 1 -+ grep -q "/tmp/letters/a/b/c/d/e/f" $strace_log && return 1 -+ return 0 -+} -+ -+rm -rf /tmp/numbers -+mkdir -p /tmp/numbers/1/2/3/4/5/6 -+rm -rf /tmp/letters -+mkdir -p /tmp/letters/a/b/c/d/e/f -+strace_log=$(mktemp) -+strace -f -e openat -o $strace_log $OSCAP oval eval --results results.xml "$srcdir/test_probes_file_multiple_file_paths.xml" -+ret=0 -+check_strace_output $strace_log || ret=$? -+rm -f $strace_log -+rm -f results.xml -+rm -rf /tmp/numbers -+rm -rf /tmp/letters -+exit $ret -diff --git a/tests/probes/file/test_probes_file_multiple_file_paths.xml b/tests/probes/file/test_probes_file_multiple_file_paths.xml -new file mode 100644 -index 000000000..893a3fe97 ---- /dev/null -+++ b/tests/probes/file/test_probes_file_multiple_file_paths.xml -@@ -0,0 +1,42 @@ -+ -+ -+ -+ 5.10 -+ 0001-01-01T00:00:00+00:00 -+ -+ -+ -+ -+ -+ Specify a file path using variable with two values -+ x -+ -+ multi_platform_all -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ /tmp/numbers -+ /tmp/letters -+ -+ -+ - -From 569e0013ca83adef233ddecc78a052db9b3ccc5c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= -Date: Tue, 2 Jun 2020 15:11:37 +0200 -Subject: [PATCH 2/3] Add strace to the list of test dependencies - ---- - docs/developer/developer.adoc | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/docs/developer/developer.adoc b/docs/developer/developer.adoc -index 823a1504e..0f01ace74 100644 ---- a/docs/developer/developer.adoc -+++ b/docs/developer/developer.adoc -@@ -152,7 +152,7 @@ After building the library you might want to run library self-checks. To do - that you need to have these additional packages installed: - - ---- --wget lua which procps-ng initscripts chkconfig sendmail bzip2 rpm-build -+wget lua which procps-ng initscripts chkconfig sendmail bzip2 rpm-build strace - ---- - - On Ubuntu 18.04, also install: - -From a47604bf30c6574e570abde4fd01488ba120f82d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= -Date: Wed, 17 Jun 2020 11:00:02 +0200 -Subject: [PATCH 3/3] Terminate matching to prevent recursion - -Fixes: RHBZ#1686370 ---- - src/OVAL/probes/oval_fts.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/src/OVAL/probes/oval_fts.c b/src/OVAL/probes/oval_fts.c -index 696997942..2b7314c38 100644 ---- a/src/OVAL/probes/oval_fts.c -+++ b/src/OVAL/probes/oval_fts.c -@@ -1029,6 +1029,15 @@ static FTSENT *oval_fts_read_match_path(OVAL_FTS *ofts) - - if (ores == OVAL_RESULT_TRUE) - break; -+ if (ofts->ofts_path_op == OVAL_OPERATION_EQUALS) { -+ /* At this point the comparison result isn't OVAL_RESULT_TRUE. Since -+ we passed the exact path (from filepath or path elements) to -+ fts_open() we surely know that we can't find other items that would -+ be equal. Therefore we can terminate the matching. This can happen -+ if the filepath or path element references a variable that has -+ multiple different values. */ -+ return NULL; -+ } - } /* for (;;) */ - - /* diff --git a/SOURCES/openscap-1.3.4-rpmverifyfile_leak-PR_1565.patch b/SOURCES/openscap-1.3.4-rpmverifyfile_leak-PR_1565.patch deleted file mode 100644 index 1cb6e65..0000000 --- a/SOURCES/openscap-1.3.4-rpmverifyfile_leak-PR_1565.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 4ef60df7edfdd7a49a565494142f86d93f9268b3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= -Date: Fri, 31 Jul 2020 10:38:17 +0200 -Subject: [PATCH] Plug a memory leak - -==12029== at 0x483A809: malloc (vg_replace_malloc.c:307) -==12029== by 0x51F1386: realpath@@GLIBC_2.3 (in /usr/lib64/libc-2.31.so) -==12029== by 0x489F8CA: oscap_realpath (util.c:251) -==12029== by 0x495E6EF: rpmverify_collect (rpmverifyfile_probe.c:248) -==12029== by 0x495F461: rpmverifyfile_probe_main (rpmverifyfile_probe.c:543) -==12029== by 0x4935598: probe_worker (worker.c:1090) -==12029== by 0x4932F10: probe_worker_runfn (worker.c:81) -==12029== by 0x4CDA431: start_thread (in /usr/lib64/libpthread-2.31.so) -==12029== by 0x52A8912: clone (in /usr/lib64/libc-2.31.so) - -==12029== at 0x483CCE8: realloc (vg_replace_malloc.c:834) -==12029== by 0x4D9DCD8: rrealloc (in /usr/lib64/librpmio.so.9.0.1) -==12029== by 0x4D25B88: headerFormat (in /usr/lib64/librpm.so.9.0.1) -==12029== by 0x495E467: rpmverify_collect (rpmverifyfile_probe.c:230) -==12029== by 0x495F461: rpmverifyfile_probe_main -(rpmverifyfile_probe.c:543) -==12029== by 0x4935598: probe_worker (worker.c:1090) -==12029== by 0x4932F10: probe_worker_runfn (worker.c:81) -==12029== by 0x4CDA431: start_thread (in -/usr/lib64/libpthread-2.31.so) -==12029== by 0x52A8912: clone (in /usr/lib64/libc-2.31.so) - -Resolves: RHBZ#1861301 ---- - .../probes/unix/linux/rpmverifyfile_probe.c | 24 ++++++++++++++----- - 1 file changed, 18 insertions(+), 6 deletions(-) - -diff --git a/src/OVAL/probes/unix/linux/rpmverifyfile_probe.c b/src/OVAL/probes/unix/linux/rpmverifyfile_probe.c -index c86818e72..57d69f552 100644 ---- a/src/OVAL/probes/unix/linux/rpmverifyfile_probe.c -+++ b/src/OVAL/probes/unix/linux/rpmverifyfile_probe.c -@@ -61,10 +61,10 @@ - - struct rpmverify_res { - char *name; /**< package name */ -- const char *epoch; -- const char *version; -- const char *release; -- const char *arch; -+ char *epoch; -+ char *version; -+ char *release; -+ char *arch; - char *file; /**< filepath */ - char extended_name[1024]; - rpmVerifyAttrs vflags; /**< rpm verify flags */ -@@ -272,14 +272,14 @@ static int rpmverify_collect(probe_ctx *ctx, - free(current_file_realpath); - continue; - } -- res.file = current_file_realpath ? current_file_realpath : strdup(current_file); -+ res.file = current_file_realpath ? oscap_strdup(current_file_realpath) : oscap_strdup(current_file); - break; - case OVAL_OPERATION_PATTERN_MATCH: - ret = pcre_exec(re, NULL, current_file, strlen(current_file), 0, 0, NULL, 0); - - switch(ret) { - case 0: /* match */ -- res.file = strdup(current_file); -+ res.file = oscap_strdup(current_file); - break; - case -1: - /* mismatch */ -@@ -299,12 +299,18 @@ static int rpmverify_collect(probe_ctx *ctx, - free(current_file_realpath); - goto ret; - } -+ free(current_file_realpath); - - if (rpmVerifyFile(g_rpm->rpmts, fi, &res.vflags, omit) != 0) - res.vflags = RPMVERIFY_FAILURES; - - if (callback(ctx, &res) != 0) { - ret = 0; -+ free(res.name); -+ free(res.epoch); -+ free(res.version); -+ free(res.release); -+ free(res.arch); - free(res.file); - goto ret; - } -@@ -313,6 +319,12 @@ static int rpmverify_collect(probe_ctx *ctx, - - rpmfiFree(fi); - } -+ -+ free(res.name); -+ free(res.epoch); -+ free(res.version); -+ free(res.release); -+ free(res.arch); - } - - match = rpmdbFreeIterator (match); --- -2.26.2 - diff --git a/SOURCES/openscap-1.3.5-bump-yamlfilter-covscan-fix-PR_1620.patch b/SOURCES/openscap-1.3.5-bump-yamlfilter-covscan-fix-PR_1620.patch deleted file mode 100644 index 961d583..0000000 --- a/SOURCES/openscap-1.3.5-bump-yamlfilter-covscan-fix-PR_1620.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c -index 6f18abf83..e7e6cb3f5 100644 ---- a/src/OVAL/probes/independent/yamlfilecontent_probe.c -+++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c -@@ -216,12 +216,13 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str - result_error("YAML parser error: %s", parser.problem); - goto cleanup; - } -+ -+ event_type = event.type; -+ - if (yaml_path_filter_event(yaml_path, &parser, &event) == YAML_PATH_FILTER_RESULT_OUT) { - goto next; - } - -- event_type = event.type; -- - if (sequence) { - if (event_type == YAML_SEQUENCE_END_EVENT) { - sequence = false; diff --git a/SOURCES/openscap-1.3.5-bump-yamlfilter-fix-field-names-PR_1619.patch b/SOURCES/openscap-1.3.5-bump-yamlfilter-fix-field-names-PR_1619.patch deleted file mode 100644 index 618a71d..0000000 --- a/SOURCES/openscap-1.3.5-bump-yamlfilter-fix-field-names-PR_1619.patch +++ /dev/null @@ -1,315 +0,0 @@ -From 81ab472c579072229a61df32969cc027b0fa4b7f Mon Sep 17 00:00:00 2001 -From: Evgeny Kolesnikov -Date: Tue, 20 Oct 2020 08:55:32 +0200 -Subject: [PATCH] probes/yamfilecontent: Fix field names for cases where key - selection section is followed by a set section - -$.foo[:].bar[:], $.foo[:][:] and alike. ---- - .../independent/yamlfilecontent_probe.c | 31 ++++++++-- - .../yamlfilecontent/openshift-logging.yaml | 12 ++++ - .../test_probes_yamlfilecontent_array.sh | 2 +- - .../test_probes_yamlfilecontent_array.xml | 45 ++++++++++++++ - .../test_probes_yamlfilecontent_key.sh | 2 +- - .../test_probes_yamlfilecontent_key.xml | 59 ++++++++++++++++++- - 6 files changed, 143 insertions(+), 8 deletions(-) - -diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c -index 6f18abf83..17741a240 100644 ---- a/src/OVAL/probes/independent/yamlfilecontent_probe.c -+++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c -@@ -206,6 +206,7 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str - yaml_event_type_t event_type; - bool sequence = false; - bool mapping = false; -+ bool fake_mapping = false; - int index = 0; - char *key = strdup("#"); - -@@ -224,21 +225,39 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str - - if (sequence) { - if (event_type == YAML_SEQUENCE_END_EVENT) { -- sequence = false; -+ if (fake_mapping) { -+ fake_mapping = false; -+ if (record && record->itemcount > 0) { -+ oscap_list_add(values, record); -+ } else { -+ // Do not collect empty records -+ oscap_htable_free0(record); -+ } -+ record = NULL; -+ } else { -+ sequence = false; -+ } - } else if (event_type == YAML_SEQUENCE_START_EVENT) { -- result_error("YAML path '%s' points to a multi-dimensional structure (sequence containing another sequence)", yaml_path_cstr); -- goto cleanup; -+ if (mapping || fake_mapping) { -+ result_error("YAML path '%s' points to a multi-dimensional structure (a map or a sequence containing other sequences)", yaml_path_cstr); -+ goto cleanup; -+ } else { -+ fake_mapping = true; -+ record = oscap_htable_new(); -+ } - } - } else { - if (event_type == YAML_SEQUENCE_START_EVENT) { - sequence = true; -+ if (mapping) -+ index++; - } - } - - if (mapping) { - if (event_type == YAML_MAPPING_END_EVENT) { - mapping = false; -- if (record->itemcount > 0) { -+ if (record && record->itemcount > 0) { - oscap_list_add(values, record); - } else { - // Do not collect empty records -@@ -255,6 +274,10 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str - result_error("YAML path '%s' points to an invalid structure (map containing another map)", yaml_path_cstr); - goto cleanup; - } -+ if (fake_mapping) { -+ result_error("YAML path '%s' points to a multi-dimensional structure (two-dimensional sequence containing a map)", yaml_path_cstr); -+ goto cleanup; -+ } - mapping = true; - sequence = false; - index = 0; -diff --git a/tests/probes/yamlfilecontent/openshift-logging.yaml b/tests/probes/yamlfilecontent/openshift-logging.yaml -index fb6a9d8b6..581a700a3 100644 ---- a/tests/probes/yamlfilecontent/openshift-logging.yaml -+++ b/tests/probes/yamlfilecontent/openshift-logging.yaml -@@ -3,6 +3,18 @@ kind: "LogForwarding" - metadata: - name: instance - namespace: openshift-logging -+arrs: -+- [1, 2, 3] -+- [4, 5, 6] -+items: -+- allowHostDirVolumePlugin: false -+ defaultAddCapabilities: null -+ requiredDropCapabilities: ['KILL', 'ALL'] -+ name: ['Name', 'Oth'] -+- allowHostDirVolumePlugin: false -+ defaultAddCapabilities: null -+ requiredDropCapabilities: ['OPS', 'KILL', 'ALL'] -+ name: ['2 Name', '2 Oth'] - spec: - disableDefaultForwarding: true - outputs: -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.sh b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.sh -index fd5e47538..695a247b3 100755 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.sh -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.sh -@@ -19,7 +19,7 @@ function test_probes_yamlfilecontent_array { - $OSCAP oval eval --results $RF $DF - - if [ -f $RF ]; then -- verify_results "def" $DF $RF 2 && verify_results "tst" $DF $RF 3 -+ verify_results "def" $DF $RF 3 && verify_results "tst" $DF $RF 5 - ret_val=$? - else - ret_val=1 -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml -index c05c5fbb9..77f57cd47 100644 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_array.xml -@@ -31,6 +31,17 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - -@@ -49,6 +60,16 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - -@@ -71,6 +92,18 @@ - .spec.outputs[0] - - -+ -+ /tmp -+ openshift-logging.yaml -+ .arrs[:][:] -+ -+ -+ -+ /tmp -+ openshift-logging.yaml -+ .arrs -+ -+ - - - -@@ -87,6 +120,12 @@ - - - -+ -+ -+ -+ -+ -+ - - - -@@ -99,5 +138,11 @@ - - - -+ -+ -+ 1|2|3|4|5|6 -+ -+ -+ - - -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh -index fc1e0ae7e..a942552e9 100755 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.sh -@@ -19,7 +19,7 @@ function test_probes_yamlfilecontent_key { - $OSCAP oval eval --results $RF $DF - - if [ -f $RF ]; then -- verify_results "def" $DF $RF 6 && verify_results "tst" $DF $RF 7 -+ verify_results "def" $DF $RF 9 && verify_results "tst" $DF $RF 10 - ret_val=$? - else - ret_val=1 -diff --git a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml -index 05757d0c8..1697b54fd 100644 ---- a/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml -+++ b/tests/probes/yamlfilecontent/test_probes_yamlfilecontent_key.xml -@@ -71,7 +71,7 @@ - - - -- -+ - - - -@@ -80,6 +80,26 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - -@@ -116,9 +136,19 @@ - - - -- -+ - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - -@@ -170,6 +200,18 @@ - openshift-logging.yaml - .spec.outputs - -+ -+ -+ /tmp -+ openshift-logging.yaml -+ .items[:]['requiredDropCapabilities','name','q','z'][:] -+ -+ -+ -+ /tmp -+ openshift-logging.yaml -+ .items[:].requiredDropCapabilities[:] -+ - - - -@@ -202,6 +244,19 @@ - - - -+ -+ -+ ^KILL$ -+ Name -+ -+ -+ -+ -+ -+ ^KILL$ -+ -+ -+ - - - diff --git a/SOURCES/openscap-1.3.5-coverity1-PR_1617.patch b/SOURCES/openscap-1.3.5-coverity1-PR_1617.patch new file mode 100644 index 0000000..ea7edcb --- /dev/null +++ b/SOURCES/openscap-1.3.5-coverity1-PR_1617.patch @@ -0,0 +1,162 @@ +From 0311ac9d8368acd5baac8b7fc6f753bd895ea3fc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= +Date: Tue, 6 Oct 2020 13:32:19 +0200 +Subject: [PATCH 1/2] Fix Coverity warnings + +Addressing multiple Coverity defects similar to this one: +Defect type: CHECKED_RETURN +check_return: Calling "curl_easy_setopt(curl, _curl_opt, _curl_trace)" +without checking return value. This library function may fail and return +an error code. +--- + src/common/oscap_acquire.c | 65 +++++++++++++++++++++++++++++++------- + 1 file changed, 53 insertions(+), 12 deletions(-) + +diff --git a/src/common/oscap_acquire.c b/src/common/oscap_acquire.c +index 666f4f5c9..34a92fa19 100644 +--- a/src/common/oscap_acquire.c ++++ b/src/common/oscap_acquire.c +@@ -326,18 +326,59 @@ char* oscap_acquire_url_download(const char *url, size_t* memory_size) + return NULL; + } + +- struct oscap_buffer* buffer = oscap_buffer_new(); +- +- curl_easy_setopt(curl, CURLOPT_URL, url); +- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_memory_callback); +- curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer); +- curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); +- curl_easy_setopt(curl, CURLOPT_TRANSFER_ENCODING, true); +- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); +- curl_easy_setopt(curl, CURLOPT_VERBOSE, true); +- curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, _curl_trace); +- +- CURLcode res = curl_easy_perform(curl); ++ CURLcode res; ++ ++ res = curl_easy_setopt(curl, CURLOPT_URL, url); ++ if (res != 0) { ++ oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_URL to '%s': %s", url, curl_easy_strerror(res)); ++ return NULL; ++ } ++ ++ res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_memory_callback); ++ if (res != 0) { ++ oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_WRITEFUNCTION to write_to_memory_callback: %s", curl_easy_strerror(res)); ++ return NULL; ++ } ++ ++ res = curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); ++ if (res != 0) { ++ oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_ACCEPT_ENCODING to an empty string: %s", curl_easy_strerror(res)); ++ return NULL; ++ } ++ ++ res = curl_easy_setopt(curl, CURLOPT_TRANSFER_ENCODING, true); ++ if (res != 0) { ++ oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_TRANSFER_ENCODING to true: %s", curl_easy_strerror(res)); ++ return NULL; ++ } ++ ++ res = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); ++ if (res != 0) { ++ oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_FOLLOWLOCATION to true: %s", curl_easy_strerror(res)); ++ return NULL; ++ } ++ ++ res = curl_easy_setopt(curl, CURLOPT_VERBOSE, true); ++ if (res != 0) { ++ oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_VERBOSE to true: %s", curl_easy_strerror(res)); ++ return NULL; ++ } ++ ++ res = curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, _curl_trace); ++ if (res != 0) { ++ oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_DEBUGFUNCTION to _curl_trace: %s", curl_easy_strerror(res)); ++ return NULL; ++ } ++ ++ struct oscap_buffer *buffer = oscap_buffer_new(); ++ res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer); ++ if (res != 0) { ++ oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_WRITEDATA as buffer: %s", curl_easy_strerror(res)); ++ oscap_buffer_free(buffer); ++ return NULL; ++ } ++ ++ res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + + if (res != 0) { + +From 34af1348b6ff6e4710aeb6e383b1a50c4751c16e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= +Date: Mon, 26 Oct 2020 11:12:04 +0100 +Subject: [PATCH 2/2] Add curl_easy_cleanup everywhere + +--- + src/common/oscap_acquire.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/common/oscap_acquire.c b/src/common/oscap_acquire.c +index 34a92fa19..cd9bfc36f 100644 +--- a/src/common/oscap_acquire.c ++++ b/src/common/oscap_acquire.c +@@ -330,42 +330,49 @@ char* oscap_acquire_url_download(const char *url, size_t* memory_size) + + res = curl_easy_setopt(curl, CURLOPT_URL, url); + if (res != 0) { ++ curl_easy_cleanup(curl); + oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_URL to '%s': %s", url, curl_easy_strerror(res)); + return NULL; + } + + res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_memory_callback); + if (res != 0) { ++ curl_easy_cleanup(curl); + oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_WRITEFUNCTION to write_to_memory_callback: %s", curl_easy_strerror(res)); + return NULL; + } + + res = curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); + if (res != 0) { ++ curl_easy_cleanup(curl); + oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_ACCEPT_ENCODING to an empty string: %s", curl_easy_strerror(res)); + return NULL; + } + + res = curl_easy_setopt(curl, CURLOPT_TRANSFER_ENCODING, true); + if (res != 0) { ++ curl_easy_cleanup(curl); + oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_TRANSFER_ENCODING to true: %s", curl_easy_strerror(res)); + return NULL; + } + + res = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); + if (res != 0) { ++ curl_easy_cleanup(curl); + oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_FOLLOWLOCATION to true: %s", curl_easy_strerror(res)); + return NULL; + } + + res = curl_easy_setopt(curl, CURLOPT_VERBOSE, true); + if (res != 0) { ++ curl_easy_cleanup(curl); + oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_VERBOSE to true: %s", curl_easy_strerror(res)); + return NULL; + } + + res = curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, _curl_trace); + if (res != 0) { ++ curl_easy_cleanup(curl); + oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_DEBUGFUNCTION to _curl_trace: %s", curl_easy_strerror(res)); + return NULL; + } +@@ -373,6 +380,7 @@ char* oscap_acquire_url_download(const char *url, size_t* memory_size) + struct oscap_buffer *buffer = oscap_buffer_new(); + res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer); + if (res != 0) { ++ curl_easy_cleanup(curl); + oscap_seterr(OSCAP_EFAMILY_NET, "Failed to set CURLOPT_WRITEDATA as buffer: %s", curl_easy_strerror(res)); + oscap_buffer_free(buffer); + return NULL; diff --git a/SOURCES/openscap-1.3.5-coverity2-PR_1620.patch b/SOURCES/openscap-1.3.5-coverity2-PR_1620.patch new file mode 100644 index 0000000..404ff9c --- /dev/null +++ b/SOURCES/openscap-1.3.5-coverity2-PR_1620.patch @@ -0,0 +1,147 @@ +From 538c70780b49a36a4d2420ef93b87b78817dc14c Mon Sep 17 00:00:00 2001 +From: Evgeny Kolesnikov +Date: Mon, 26 Oct 2020 08:31:53 +0100 +Subject: [PATCH] Covscan fixes + +--- + src/OVAL/probes/fsdev.c | 2 +- + src/OVAL/probes/independent/yamlfilecontent_probe.c | 5 +++-- + src/OVAL/probes/unix/fileextendedattribute_probe.c | 2 +- + src/OVAL/probes/unix/linux/partition_probe.c | 2 +- + src/OVAL/probes/unix/xinetd_probe.c | 7 ++++++- + src/XCCDF/xccdf_session.c | 4 ++-- + utils/oscap-tool.c | 6 +++++- + utils/oscap-xccdf.c | 3 +-- + 8 files changed, 20 insertions(+), 11 deletions(-) + +diff --git a/src/OVAL/probes/fsdev.c b/src/OVAL/probes/fsdev.c +index b2b984441..c82ab620b 100644 +--- a/src/OVAL/probes/fsdev.c ++++ b/src/OVAL/probes/fsdev.c +@@ -219,7 +219,7 @@ static fsdev_t *__fsdev_init(fsdev_t *lfs) + endmntent(fp); + + void *new_ids = realloc(lfs->ids, sizeof(dev_t) * i); +- if (new_ids == NULL) { ++ if (new_ids == NULL && i > 0) { + e = errno; + free(lfs->ids); + free(lfs); +diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c +index 6f18abf83..e7e6cb3f5 100644 +--- a/src/OVAL/probes/independent/yamlfilecontent_probe.c ++++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c +@@ -216,12 +216,13 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str + result_error("YAML parser error: %s", parser.problem); + goto cleanup; + } ++ ++ event_type = event.type; ++ + if (yaml_path_filter_event(yaml_path, &parser, &event) == YAML_PATH_FILTER_RESULT_OUT) { + goto next; + } + +- event_type = event.type; +- + if (sequence) { + if (event_type == YAML_SEQUENCE_END_EVENT) { + sequence = false; +diff --git a/src/OVAL/probes/unix/fileextendedattribute_probe.c b/src/OVAL/probes/unix/fileextendedattribute_probe.c +index b442ea540..ee853886a 100644 +--- a/src/OVAL/probes/unix/fileextendedattribute_probe.c ++++ b/src/OVAL/probes/unix/fileextendedattribute_probe.c +@@ -298,7 +298,7 @@ static int file_cb(const char *prefix, const char *p, const char *f, void *ptr, + + // Allocate buffer, '+1' is for trailing '\0' + void *new_xattr_val = realloc(xattr_val, sizeof(char) * (xattr_vallen + 1)); +- if (xattr_val == NULL) { ++ if (new_xattr_val == NULL) { + dE("Failed to allocate memory for xattr_val"); + free(xattr_val); + goto exit; +diff --git a/src/OVAL/probes/unix/linux/partition_probe.c b/src/OVAL/probes/unix/linux/partition_probe.c +index a74c0323a..adb244b04 100644 +--- a/src/OVAL/probes/unix/linux/partition_probe.c ++++ b/src/OVAL/probes/unix/linux/partition_probe.c +@@ -207,7 +207,7 @@ static int collect_item(probe_ctx *ctx, oval_schema_version_t over, struct mnten + mnt_ocnt = add_mnt_opt(&mnt_opts, mnt_ocnt, "move"); + } + +- dD("mnt_ocnt = %d, mnt_opts[mnt_ocnt]=%p", mnt_ocnt, mnt_opts[mnt_ocnt]); ++ dD("mnt_ocnt = %d, mnt_opts[mnt_ocnt]=%p", mnt_ocnt, mnt_opts == NULL ? NULL : mnt_opts[mnt_ocnt]); + + /* + * "Correct" the type (this won't be (hopefully) needed in a later version +diff --git a/src/OVAL/probes/unix/xinetd_probe.c b/src/OVAL/probes/unix/xinetd_probe.c +index 75b12f95b..d61c7d547 100644 +--- a/src/OVAL/probes/unix/xinetd_probe.c ++++ b/src/OVAL/probes/unix/xinetd_probe.c +@@ -566,7 +566,12 @@ static int xiconf_add_cfile(xiconf_t *xiconf, const char *path, int depth) + } + + xifile->depth = depth; +- xiconf->cfile = realloc(xiconf->cfile, sizeof(xiconf_file_t *) * ++xiconf->count); ++ void *cfile = realloc(xiconf->cfile, sizeof(xiconf_file_t *) * ++xiconf->count); ++ if (cfile == NULL) { ++ dE("Failed re-allocate memory for cfile"); ++ return (-1); ++ } ++ xiconf->cfile = cfile; + xiconf->cfile[xiconf->count - 1] = xifile; + + dD("Added new file to the cfile queue: %s; fi=%zu", path, xiconf->count - 1); +diff --git a/src/XCCDF/xccdf_session.c b/src/XCCDF/xccdf_session.c +index 8bd394e2f..f1b837959 100644 +--- a/src/XCCDF/xccdf_session.c ++++ b/src/XCCDF/xccdf_session.c +@@ -286,9 +286,9 @@ static struct oscap_source *xccdf_session_extract_arf_source(struct xccdf_sessio + } + struct tm *tm_mtime = malloc(sizeof(struct tm)); + #ifdef OS_WINDOWS +- tm_mtime = localtime_s(tm_mtime, &file_stat.st_mtime); ++ localtime_s(tm_mtime, &file_stat.st_mtime); + #else +- tm_mtime = localtime_r(&file_stat.st_mtime, tm_mtime); ++ localtime_r(&file_stat.st_mtime, tm_mtime); + #endif + strftime(tailoring_doc_timestamp, max_timestamp_len, + "%Y-%m-%dT%H:%M:%S", tm_mtime); +diff --git a/utils/oscap-tool.c b/utils/oscap-tool.c +index 9bfe52697..660a19047 100644 +--- a/utils/oscap-tool.c ++++ b/utils/oscap-tool.c +@@ -315,7 +315,10 @@ static void getopt_parse_env(struct oscap_module *module, int *argc, char ***arg + opt = oscap_strtok_r(opts, delim, &state); + while (opt != NULL) { + eargc++; +- eargv = realloc(eargv, eargc * sizeof(char *)); ++ void *new_eargv = realloc(eargv, eargc * sizeof(char *)); ++ if (new_eargv == NULL) ++ goto exit; ++ eargv = new_eargv; + eargv[eargc - 1] = strdup(opt); + opt = oscap_strtok_r(NULL, delim, &state); + } +@@ -334,6 +337,7 @@ static void getopt_parse_env(struct oscap_module *module, int *argc, char ***arg + + *argc = nargc; + *argv = nargv; ++exit: + free(opts); + free(eargv); + } +diff --git a/utils/oscap-xccdf.c b/utils/oscap-xccdf.c +index af337b844..0a9ae5270 100644 +--- a/utils/oscap-xccdf.c ++++ b/utils/oscap-xccdf.c +@@ -610,8 +610,7 @@ int app_evaluate_xccdf(const struct oscap_action *action) + + /* syslog message */ + #if defined(HAVE_SYSLOG_H) +- syslog(priority, "Evaluation finished. Return code: %d, Base score %f.", evaluation_result, +- session == NULL ? 0 : xccdf_session_get_base_score(session)); ++ syslog(priority, "Evaluation finished. Return code: %d, Base score %f.", evaluation_result, xccdf_session_get_base_score(session)); + #endif + + xccdf_session_set_xccdf_export(session, action->f_results); diff --git a/SOURCES/openscap-1.3.5-memory-PR_1627.patch b/SOURCES/openscap-1.3.5-memory-PR_1627.patch new file mode 100644 index 0000000..1b60ca6 --- /dev/null +++ b/SOURCES/openscap-1.3.5-memory-PR_1627.patch @@ -0,0 +1,84 @@ +From 5eea79eaf426ac3e51a09d3f3fe72c2b385abc89 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= +Date: Tue, 10 Nov 2020 11:16:00 +0100 +Subject: [PATCH] Fix memory allocation + +We can't assume that size of a structure is a sum of sizes of its +members because padding and alignment can be involved. In fact, +we need to allocate more bytes for the structure than the +sum of sizes of its members. + +The wrong assumption caused invalid writes and invalid reads +which can be discovered by valgrind. Moreover, when run with +MALLOC_CHECK_ environment variable set to non-zero value, the +program aborted. + +The memory issue happened only when NDEBUG is defined, eg. when cmake +-DCMAKE_BUILD_TYPE=RelWithDebInfo or Release, it doesn't happen if cmake +-DCMAKE_BUILD_TYPE=Debug which we usually use in Jenkins CI. This is +most likely because in debug mode the struct SEXP contains 2 additional +members which are the magic canaries and therefore is bigger. + +This commit wants to fix the problem by 2 step allocation in which +first the size of the struct SEXP_val_lblk is used and then the +array of SEXPs is allocated separately. + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1891770 +--- + src/OVAL/probes/SEAP/_sexp-value.h | 2 +- + src/OVAL/probes/SEAP/sexp-value.c | 12 ++++++------ + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/OVAL/probes/SEAP/_sexp-value.h b/src/OVAL/probes/SEAP/_sexp-value.h +index 426cd2c3d..e66777ef9 100644 +--- a/src/OVAL/probes/SEAP/_sexp-value.h ++++ b/src/OVAL/probes/SEAP/_sexp-value.h +@@ -94,7 +94,7 @@ struct SEXP_val_lblk { + uintptr_t nxsz; + uint16_t real; + uint16_t refs; +- SEXP_t memb[]; ++ SEXP_t *memb; + }; + + size_t SEXP_rawval_list_length (struct SEXP_val_list *list); +diff --git a/src/OVAL/probes/SEAP/sexp-value.c b/src/OVAL/probes/SEAP/sexp-value.c +index a11cbc70c..b8b3ed609 100644 +--- a/src/OVAL/probes/SEAP/sexp-value.c ++++ b/src/OVAL/probes/SEAP/sexp-value.c +@@ -106,10 +106,8 @@ uintptr_t SEXP_rawval_lblk_new (uint8_t sz) + { + _A(sz < 16); + +- struct SEXP_val_lblk *lblk = oscap_aligned_malloc( +- sizeof(uintptr_t) + (2 * sizeof(uint16_t)) + (sizeof(SEXP_t) * (1 << sz)), +- SEXP_LBLK_ALIGN +- ); ++ struct SEXP_val_lblk *lblk = malloc(sizeof(struct SEXP_val_lblk)); ++ lblk->memb = malloc(sizeof(SEXP_t) * (1 << sz)); + + lblk->nxsz = ((uintptr_t)(NULL) & SEXP_LBLKP_MASK) | ((uintptr_t)sz & SEXP_LBLKS_MASK); + lblk->refs = 1; +@@ -519,7 +517,8 @@ void SEXP_rawval_lblk_free (uintptr_t lblkp, void (*func) (SEXP_t *)) + func (lblk->memb + lblk->real); + } + +- oscap_aligned_free(lblk); ++ free(lblk->memb); ++ free(lblk); + + if (next != NULL) + SEXP_rawval_lblk_free ((uintptr_t)next, func); +@@ -540,7 +539,8 @@ void SEXP_rawval_lblk_free1 (uintptr_t lblkp, void (*func) (SEXP_t *)) + func (lblk->memb + lblk->real); + } + +- oscap_aligned_free(lblk); ++ free(lblk->memb); ++ free(lblk); + } + + return; +-- +2.26.2 + diff --git a/SOURCES/openscap-1.3.5-plug-memory-leak-PR_1616.patch b/SOURCES/openscap-1.3.5-plug-memory-leak-PR_1616.patch new file mode 100644 index 0000000..8c8f4cf --- /dev/null +++ b/SOURCES/openscap-1.3.5-plug-memory-leak-PR_1616.patch @@ -0,0 +1,71 @@ +From d5518f3f4c32ac19fcf3427602d5b2978b7ef1b4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= +Date: Mon, 5 Oct 2020 16:02:29 +0200 +Subject: [PATCH] Plug a memory leak + +Addressing: + +8 bytes in 1 blocks are indirectly lost in loss record 7 of 235 + at 0x483A809: malloc (vg_replace_malloc.c:307) + by 0x48F15CA: oval_collection_new (oval_collection.c:64) + by 0x48F4FCC: oval_result_criteria_node_new (oval_resultCriteriaNode.c:106) + by 0x48F5580: make_result_criteria_node_from_oval_criteria_node (oval_resultCriteriaNode.c:249) + by 0x48F6B51: make_result_definition_from_oval_definition (oval_resultDefinition.c:130) + by 0x48F7F41: oval_result_system_get_new_definition_with_check (oval_resultSystem.c:217) + by 0x48F5686: make_result_criteria_node_from_oval_criteria_node (oval_resultCriteriaNode.c:279) + by 0x48F55BD: make_result_criteria_node_from_oval_criteria_node (oval_resultCriteriaNode.c:260) + by 0x48F6B51: make_result_definition_from_oval_definition (oval_resultDefinition.c:130) + by 0x48F8794: oval_result_system_prepare_definition (oval_resultSystem.c:395) + by 0x48F86A6: oval_result_system_eval_definition (oval_resultSystem.c:369) + by 0x48C23FD: oval_agent_eval_definition (oval_agent.c:181) + +8 bytes in 1 blocks are definitely lost in loss record 8 of 235 + at 0x483A809: malloc (vg_replace_malloc.c:307) + by 0x48F1799: oval_collection_iterator (oval_collection.c:120) + by 0x48CCE4C: oval_criteria_node_get_subnodes (oval_criteriaNode.c:161) + by 0x48F5590: make_result_criteria_node_from_oval_criteria_node (oval_resultCriteriaNode.c:255) + by 0x48F6B51: make_result_definition_from_oval_definition (oval_resultDefinition.c:130) + by 0x48F7F41: oval_result_system_get_new_definition_with_check (oval_resultSystem.c:217) + by 0x48F5686: make_result_criteria_node_from_oval_criteria_node (oval_resultCriteriaNode.c:279) + by 0x48F55BD: make_result_criteria_node_from_oval_criteria_node (oval_resultCriteriaNode.c:260) + by 0x48F6B51: make_result_definition_from_oval_definition (oval_resultDefinition.c:130) + by 0x48F8794: oval_result_system_prepare_definition (oval_resultSystem.c:395) + by 0x48F86A6: oval_result_system_eval_definition (oval_resultSystem.c:369) + by 0x48C23FD: oval_agent_eval_definition (oval_agent.c:181) + +48 (40 direct, 8 indirect) bytes in 1 blocks are definitely lost in loss record 125 of 235 + at 0x483A809: malloc (vg_replace_malloc.c:307) + by 0x48F4F50: oval_result_criteria_node_new (oval_resultCriteriaNode.c:98) + by 0x48F5580: make_result_criteria_node_from_oval_criteria_node (oval_resultCriteriaNode.c:249) + by 0x48F6B51: make_result_definition_from_oval_definition (oval_resultDefinition.c:130) + by 0x48F7F41: oval_result_system_get_new_definition_with_check (oval_resultSystem.c:217) + by 0x48F5686: make_result_criteria_node_from_oval_criteria_node (oval_resultCriteriaNode.c:279) + by 0x48F55BD: make_result_criteria_node_from_oval_criteria_node (oval_resultCriteriaNode.c:260) + by 0x48F6B51: make_result_definition_from_oval_definition (oval_resultDefinition.c:130) + by 0x48F8794: oval_result_system_prepare_definition (oval_resultSystem.c:395) + by 0x48F86A6: oval_result_system_eval_definition (oval_resultSystem.c:369) + by 0x48C23FD: oval_agent_eval_definition (oval_agent.c:181) + by 0x48C2671: oval_agent_eval_system (oval_agent.c:286) + +This leak has been created by #1610. +--- + src/OVAL/results/oval_resultCriteriaNode.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/OVAL/results/oval_resultCriteriaNode.c b/src/OVAL/results/oval_resultCriteriaNode.c +index 807283206..f6e980861 100644 +--- a/src/OVAL/results/oval_resultCriteriaNode.c ++++ b/src/OVAL/results/oval_resultCriteriaNode.c +@@ -258,8 +258,11 @@ struct oval_result_criteria_node *make_result_criteria_node_from_oval_criteria_n + = oval_criteria_node_iterator_next(oval_subnodes); + struct oval_result_criteria_node *rslt_subnode + = make_result_criteria_node_from_oval_criteria_node(sys, oval_subnode, visited_definitions, variable_instance); +- if (rslt_subnode == NULL) ++ if (rslt_subnode == NULL) { ++ oval_criteria_node_iterator_free(oval_subnodes); ++ oval_result_criteria_node_free(rslt_node); + return NULL; ++ } + oval_result_criteria_node_add_subnode(rslt_node, rslt_subnode); + } + oval_criteria_node_iterator_free(oval_subnodes); diff --git a/SOURCES/openscap-1.3.5-test-non-local-gpfs-PR_1653.patch b/SOURCES/openscap-1.3.5-test-non-local-gpfs-PR_1653.patch new file mode 100644 index 0000000..7b2a2c2 --- /dev/null +++ b/SOURCES/openscap-1.3.5-test-non-local-gpfs-PR_1653.patch @@ -0,0 +1,9 @@ +diff --git a/tests/API/probes/fake_mtab b/tests/API/probes/fake_mtab +index 94b1fe295..32c516b7d 100644 +--- a/tests/API/probes/fake_mtab ++++ b/tests/API/probes/fake_mtab +@@ -5,3 +5,4 @@ tmpfs /tmp tmpfs rw,seclabel,nosuid,nodev 0 0 + /dev/mapper/fedora-home /home ext4 rw,seclabel,relatime 0 0 + proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0 + //192.168.0.5/storage /media/movies cifs guest,uid=myuser,iocharset=utf8,file_mode=0777,dir_mode=0777,noperm 0 0 ++/dev/gpfsdev /gpfs gpfs rw,relatime 0 0 diff --git a/SOURCES/openscap-1.3.5-use-MALLOC_CHECK-in-tests-PR_1635.patch b/SOURCES/openscap-1.3.5-use-MALLOC_CHECK-in-tests-PR_1635.patch new file mode 100644 index 0000000..687812a --- /dev/null +++ b/SOURCES/openscap-1.3.5-use-MALLOC_CHECK-in-tests-PR_1635.patch @@ -0,0 +1,13 @@ +diff --git a/tests/test_common.sh.in b/tests/test_common.sh.in +index 6b54ad015..5b6126dbf 100755 +--- a/tests/test_common.sh.in ++++ b/tests/test_common.sh.in +@@ -17,6 +17,9 @@ PREFERRED_PYTHON=@PREFERRED_PYTHON_PATH@ + LC_ALL=C + export LC_ALL + ++MALLOC_CHECK_=3 ++export MALLOC_CHECK_ ++ + OSCAP_FULL_VALIDATION=1 + export OSCAP_FULL_VALIDATION diff --git a/SOURCES/openscap-1.3.5-yamlfilecontent-fix-field-names-PR_1619.patch b/SOURCES/openscap-1.3.5-yamlfilecontent-fix-field-names-PR_1619.patch new file mode 100644 index 0000000..7d39e31 --- /dev/null +++ b/SOURCES/openscap-1.3.5-yamlfilecontent-fix-field-names-PR_1619.patch @@ -0,0 +1,67 @@ +diff --git a/src/OVAL/probes/independent/yamlfilecontent_probe.c b/src/OVAL/probes/independent/yamlfilecontent_probe.c +index 6f18abf83..17741a240 100644 +--- a/src/OVAL/probes/independent/yamlfilecontent_probe.c ++++ b/src/OVAL/probes/independent/yamlfilecontent_probe.c +@@ -206,6 +206,7 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str + yaml_event_type_t event_type; + bool sequence = false; + bool mapping = false; ++ bool fake_mapping = false; + int index = 0; + char *key = strdup("#"); + +@@ -224,21 +225,39 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str + + if (sequence) { + if (event_type == YAML_SEQUENCE_END_EVENT) { +- sequence = false; ++ if (fake_mapping) { ++ fake_mapping = false; ++ if (record && record->itemcount > 0) { ++ oscap_list_add(values, record); ++ } else { ++ // Do not collect empty records ++ oscap_htable_free0(record); ++ } ++ record = NULL; ++ } else { ++ sequence = false; ++ } + } else if (event_type == YAML_SEQUENCE_START_EVENT) { +- result_error("YAML path '%s' points to a multi-dimensional structure (sequence containing another sequence)", yaml_path_cstr); +- goto cleanup; ++ if (mapping || fake_mapping) { ++ result_error("YAML path '%s' points to a multi-dimensional structure (a map or a sequence containing other sequences)", yaml_path_cstr); ++ goto cleanup; ++ } else { ++ fake_mapping = true; ++ record = oscap_htable_new(); ++ } + } + } else { + if (event_type == YAML_SEQUENCE_START_EVENT) { + sequence = true; ++ if (mapping) ++ index++; + } + } + + if (mapping) { + if (event_type == YAML_MAPPING_END_EVENT) { + mapping = false; +- if (record->itemcount > 0) { ++ if (record && record->itemcount > 0) { + oscap_list_add(values, record); + } else { + // Do not collect empty records +@@ -255,6 +274,10 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str + result_error("YAML path '%s' points to an invalid structure (map containing another map)", yaml_path_cstr); + goto cleanup; + } ++ if (fake_mapping) { ++ result_error("YAML path '%s' points to a multi-dimensional structure (two-dimensional sequence containing a map)", yaml_path_cstr); ++ goto cleanup; ++ } + mapping = true; + sequence = false; + index = 0; diff --git a/SPECS/openscap.spec b/SPECS/openscap.spec index 1410370..479007b 100644 --- a/SPECS/openscap.spec +++ b/SPECS/openscap.spec @@ -1,25 +1,18 @@ Name: openscap -Version: 1.3.3 -Release: 6%{?dist} +Version: 1.3.4 +Release: 5%{?dist} Summary: Set of open source libraries enabling integration of the SCAP line of standards Group: System Environment/Libraries License: LGPLv2+ URL: http://www.open-scap.org/ Source0: https://github.com/OpenSCAP/%{name}/releases/download/%{version}/%{name}-%{version}.tar.gz -Patch1: openscap-1.3.4-fix-environmentvariable58-regression.patch -Patch2: openscap-1.3.4-fix-no-more-recursion.patch -Patch3: openscap-1.3.4-add_compression_support-PR_1557.patch -Patch4: openscap-1.3.4-add_compression_test-PR_1564.patch -Patch5: openscap-1.3.4-add_compression_tracing-PR_1561.patch -Patch6: openscap-1.3.4-rpmverifyfile_leak-PR_1565.patch -Patch7: openscap-1.3.4-detect_remote_file_systems-PR_1573.patch -Patch8: openscap-1.3.4-export-profile-platform-PR_1609.patch -Patch9: openscap-1.3.4-bump-yamlfilter-fix-warnings-PR_1530.patch -Patch10: openscap-1.3.4-bump-yamlfilter-upgrade-probe-schemas-PR_1552.patch -Patch11: openscap-1.3.4-bump-yamlfilter-upgrade-probe-schemas-submodule-PR_1552.patch -Patch12: openscap-1.3.5-bump-yamlfilter-covscan-fix-PR_1620.patch -Patch13: openscap-1.3.5-bump-yamlfilter-fix-field-names-PR_1619.patch - +Patch1: openscap-1.3.5-plug-memory-leak-PR_1616.patch +Patch2: openscap-1.3.5-coverity1-PR_1617.patch +Patch3: openscap-1.3.5-coverity2-PR_1620.patch +Patch4: openscap-1.3.5-yamlfilecontent-fix-field-names-PR_1619.patch +Patch5: openscap-1.3.5-memory-PR_1627.patch +Patch6: openscap-1.3.5-use-MALLOC_CHECK-in-tests-PR_1635.patch +Patch7: openscap-1.3.5-test-non-local-gpfs-PR_1653.patch BuildRequires: cmake >= 2.6 BuildRequires: swig libxml2-devel libxslt-devel perl-generators perl-XML-Parser BuildRequires: rpm-devel @@ -138,20 +131,7 @@ The %{name}-engine-sce-devel package contains libraries and header files for developing applications that use %{name}-engine-sce. %prep -%setup -q -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 -d yaml-filter -%patch12 -p1 -%patch13 -p1 +%autosetup -p1 mkdir build %build @@ -239,9 +219,24 @@ rm -rf $RPM_BUILD_ROOT %{_bindir}/oscap-run-sce-script %changelog -* Thu Oct 29 2020 Evgeny Kolesnikov - 1.3.3-6 -- Enable profile composition with a specific platform (RHBZ#1896676) -- Enable YAML probe to work with sets of values (RHBZ#1895715) +* Wed Nov 25 2020 Evgenii Kolesnikov - 1.3.4-5 +- Add check for non-local GPFS file system into Test Suite (RHBZ#1840578) + +* Fri Nov 13 2020 Evgenii Kolesnikov - 1.3.4-4 +- Use MALLOC_CHECK_=3 while executing Test Suite (RHBZ#1891770) + +* Tue Nov 10 2020 Jan Černý - 1.3.4-3 +- Fix memory allocation (RHBZ#1891770) + +* Mon Oct 26 2020 Evgenii Kolesnikov - 1.3.4-2 +- Fix problems uncovered by the Coverity Scan (RHBZ#1887794) + +* Wed Oct 14 2020 Evgenii Kolesnikov - 1.3.4-1 +- Upgrade to the latest upstream release (RHBZ#1887794) +- Treat GPFS as a remote file system (RHBZ#1840578, RHBZ#1840579) +- Fixed the most problematic memory issues that were causing OOM situations + for systems with large amount of files (RHBZ#1824152) +- Proper handling of OVALs with circular dependencies between definitions (RHBZ#1812476) * Wed Aug 19 2020 Jan Černý - 1.3.3-5 - Detect remote file systems correctly (RHBZ#1870087)