Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change: Use JSON streaming parser for EPSS #2293

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 118 additions & 63 deletions src/manage_sql_secinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#include <gvm/base/gvm_sentry.h>
#include <bsd/unistd.h>
#include <gvm/util/fileutils.h>
#include <gvm/util/jsonpull.h>
#include <gvm/util/xmlutils.h>

#undef G_LOG_DOMAIN
Expand Down Expand Up @@ -2859,121 +2860,175 @@
static int
update_epss_scores ()
{
GError *error = NULL;
GStatBuf state;
gchar *current_json_path;
gchar *file_contents = NULL;
cJSON *parsed, *epss_scores_list, *list_item;
gchar *error_message = NULL;

Check warning on line 2865 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2865

Added line #L2865 was not covered by tests
FILE *epss_scores_file;
cJSON *epss_entry;
gvm_json_pull_event_t event;
gvm_json_pull_parser_t parser;
gvm_json_path_elem_t *path_tail = NULL;

Check warning on line 2870 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2870

Added line #L2870 was not covered by tests
inserts_t inserts;

current_json_path = g_build_filename (GVM_SCAP_DATA_DIR,
"epss-scores-current.json",
NULL);

if (! g_file_get_contents (current_json_path, &file_contents, NULL, &error))
if (g_stat (current_json_path, &state))
{
int ret;
if (error->code == G_FILE_ERROR_NOENT)
if (errno == ENOENT)
{
g_info ("%s: EPSS scores file '%s' not found",
__func__, current_json_path);
ret = 0;
}
else
{
g_warning ("%s: Error loading EPSS scores file: %s",
__func__, error->message);
g_warning ("%s: Failed to stat EPSS scores file: %s",

Check warning on line 2887 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2887

Added line #L2887 was not covered by tests
__func__, strerror (errno));
ret = -1;
}
g_error_free (error);
g_free (current_json_path);
return ret;
}

epss_scores_file = fopen (current_json_path, "r");

Check warning on line 2895 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2895

Added line #L2895 was not covered by tests
Fixed Show fixed Hide fixed
if (epss_scores_file == NULL)
{
g_warning ("%s: Failed to open EPSS scores file: %s",

Check warning on line 2898 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2898

Added line #L2898 was not covered by tests
__func__,
strerror (errno));
g_free (current_json_path);
return -1;

Check warning on line 2902 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2901-L2902

Added lines #L2901 - L2902 were not covered by tests
}

g_info ("Updating EPSS scores from %s", current_json_path);
g_free (current_json_path);

parsed = cJSON_Parse (file_contents);
g_free (file_contents);
gvm_json_pull_event_init (&event);
gvm_json_pull_parser_init (&parser, epss_scores_file);

Check warning on line 2909 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2908-L2909

Added lines #L2908 - L2909 were not covered by tests

if (parsed == NULL)
{
g_warning ("%s: EPSS scores file is not valid JSON", __func__);
return -1;
}

if (! cJSON_IsObject (parsed))
{
g_warning ("%s: EPSS scores file is not a JSON object", __func__);
cJSON_Delete (parsed);
return -1;
}
gvm_json_pull_parser_next (&parser, &event);

Check warning on line 2911 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2911

Added line #L2911 was not covered by tests

epss_scores_list = cJSON_GetObjectItem (parsed, "epss_scores");
if (epss_scores_list == NULL)
if (event.type == GVM_JSON_PULL_EVENT_OBJECT_START)
{
g_warning ("%s: Missing epss_scores field",
__func__);
cJSON_Delete (parsed);
return -1;
}
gboolean epss_scores_found = FALSE;

Check warning on line 2915 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2915

Added line #L2915 was not covered by tests
while (!epss_scores_found)
{
gvm_json_pull_parser_next (&parser, &event);
path_tail = g_queue_peek_tail (event.path);

Check warning on line 2919 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2918-L2919

Added lines #L2918 - L2919 were not covered by tests
if (event.type == GVM_JSON_PULL_EVENT_ARRAY_START
&& path_tail && strcmp (path_tail->key, "epss_scores") == 0)

Check warning on line 2921 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2921

Added line #L2921 was not covered by tests
{
epss_scores_found = TRUE;

Check warning on line 2923 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2923

Added line #L2923 was not covered by tests
}
else if (event.type == GVM_JSON_PULL_EVENT_ERROR)

Check warning on line 2925 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2925

Added line #L2925 was not covered by tests
{
g_warning ("%s: Parser error: %s", __func__, event.error_message);
gvm_json_pull_event_cleanup (&event);
gvm_json_pull_parser_cleanup (&parser);
fclose (epss_scores_file);
return -1;

Check warning on line 2931 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2927-L2931

Added lines #L2927 - L2931 were not covered by tests
}
else if (event.type == GVM_JSON_PULL_EVENT_OBJECT_END
&& g_queue_is_empty (event.path))

Check warning on line 2934 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2933-L2934

Added lines #L2933 - L2934 were not covered by tests
{
g_warning ("%s: Unexpected json object end. Missing epss_scores field", __func__);
gvm_json_pull_event_cleanup (&event);
gvm_json_pull_parser_cleanup (&parser);
fclose (epss_scores_file);
return -1;

Check warning on line 2940 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2936-L2940

Added lines #L2936 - L2940 were not covered by tests
}
}

sql_begin_immediate ();
inserts_init (&inserts,
sql_begin_immediate ();
inserts_init (&inserts,

Check warning on line 2945 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2944-L2945

Added lines #L2944 - L2945 were not covered by tests
EPSS_MAX_CHUNK_SIZE,
setting_secinfo_sql_buffer_threshold_bytes (),
"INSERT INTO scap2.epss_scores"
" (cve, epss, percentile)"
" VALUES ",
" ON CONFLICT (cve) DO NOTHING");

cJSON_ArrayForEach (list_item, epss_scores_list)
{
cJSON *cve_json, *epss_json, *percentile_json;

EPSS_JSON_FAIL_IF (! cJSON_IsObject (list_item),
"Unexpected non-object item in EPSS scores file")
gvm_json_pull_parser_next (&parser, &event);

Check warning on line 2953 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2953

Added line #L2953 was not covered by tests
while (event.type == GVM_JSON_PULL_EVENT_OBJECT_START)
{
cJSON *cve_json, *epss_json, *percentile_json;

cve_json = cJSON_GetObjectItem (list_item, "cve");
epss_json = cJSON_GetObjectItem (list_item, "epss");
percentile_json = cJSON_GetObjectItem (list_item, "percentile");
epss_entry = gvm_json_pull_expand_container (&parser, &error_message);

Check warning on line 2958 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2958

Added line #L2958 was not covered by tests

EPSS_JSON_FAIL_IF (cve_json == NULL,
"Item missing mandatory 'cve' field");
if (error_message)
{
g_warning ("%s: Error expanding EPSS item: %s", __func__, error_message);
g_free (error_message);
goto fail_insert;

Check warning on line 2964 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2962-L2964

Added lines #L2962 - L2964 were not covered by tests
}

EPSS_JSON_FAIL_IF (epss_json == NULL,
"Item missing mandatory 'epss' field");

EPSS_JSON_FAIL_IF (percentile_json == NULL,
"Item missing mandatory 'percentile' field");
cve_json = cJSON_GetObjectItemCaseSensitive (epss_entry, "cve");
epss_json = cJSON_GetObjectItemCaseSensitive (epss_entry, "epss");
percentile_json = cJSON_GetObjectItemCaseSensitive (epss_entry, "percentile");

Check warning on line 2969 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2967-L2969

Added lines #L2967 - L2969 were not covered by tests

EPSS_JSON_FAIL_IF (! cJSON_IsString (cve_json),
"Field 'cve' in item is not a string");
EPSS_JSON_FAIL_IF (cve_json == NULL,

Check warning on line 2971 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2971

Added line #L2971 was not covered by tests
"Item missing mandatory 'cve' field");

EPSS_JSON_FAIL_IF (! cJSON_IsNumber(epss_json),
"Field 'epss' in item is not a number");

EPSS_JSON_FAIL_IF (! cJSON_IsNumber(percentile_json),
"Field 'percentile' in item is not a number");
EPSS_JSON_FAIL_IF (epss_json == NULL,

Check warning on line 2974 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2974

Added line #L2974 was not covered by tests
"Item missing mandatory 'epss' field");

EPSS_JSON_FAIL_IF (percentile_json == NULL,

Check warning on line 2977 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2977

Added line #L2977 was not covered by tests
"Item missing mandatory 'percentile' field");

EPSS_JSON_FAIL_IF (! cJSON_IsString (cve_json),

Check warning on line 2980 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2980

Added line #L2980 was not covered by tests
"Field 'cve' in item is not a string");

EPSS_JSON_FAIL_IF (! cJSON_IsNumber(epss_json),

Check warning on line 2983 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2983

Added line #L2983 was not covered by tests
"Field 'epss' in item is not a number");

insert_epss_score_entry (&inserts,
cve_json->valuestring,
epss_json->valuedouble,
percentile_json->valuedouble);
EPSS_JSON_FAIL_IF (! cJSON_IsNumber(percentile_json),

Check warning on line 2986 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2986

Added line #L2986 was not covered by tests
"Field 'percentile' in item is not a number");

insert_epss_score_entry (&inserts,
cve_json->valuestring,

Check warning on line 2990 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2989-L2990

Added lines #L2989 - L2990 were not covered by tests
epss_json->valuedouble,
percentile_json->valuedouble);

gvm_json_pull_parser_next (&parser, &event);
cJSON_Delete (epss_entry);

Check warning on line 2995 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2994-L2995

Added lines #L2994 - L2995 were not covered by tests
}
}
else if (event.type == GVM_JSON_PULL_EVENT_ERROR)

Check warning on line 2998 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L2998

Added line #L2998 was not covered by tests
{
g_warning ("%s: Parser error: %s", __func__, event.error_message);
gvm_json_pull_event_cleanup (&event);
gvm_json_pull_parser_cleanup (&parser);
fclose (epss_scores_file);
return -1;

Check warning on line 3004 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L3000-L3004

Added lines #L3000 - L3004 were not covered by tests
}
else
{
g_warning ("%s: EPSS scores file is not a JSON object.", __func__);
gvm_json_pull_event_cleanup (&event);
gvm_json_pull_parser_cleanup (&parser);
fclose (epss_scores_file);
return -1;

Check warning on line 3012 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L3008-L3012

Added lines #L3008 - L3012 were not covered by tests
}

inserts_run (&inserts, TRUE);
sql_commit ();
cJSON_Delete (parsed);

gvm_json_pull_event_cleanup (&event);
gvm_json_pull_parser_cleanup (&parser);
fclose (epss_scores_file);

Check warning on line 3019 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L3017-L3019

Added lines #L3017 - L3019 were not covered by tests
return 0;

fail_insert:
inserts_free (&inserts);
sql_rollback ();
char *printed_item = cJSON_Print (list_item);
char *printed_item = cJSON_Print (epss_entry);

Check warning on line 3025 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L3025

Added line #L3025 was not covered by tests
g_message ("%s: invalid item: %s", __func__, printed_item);
cJSON_Delete (epss_entry);

Check warning on line 3027 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L3027

Added line #L3027 was not covered by tests
free (printed_item);
cJSON_Delete (parsed);
gvm_json_pull_event_cleanup (&event);
gvm_json_pull_parser_cleanup (&parser);
fclose (epss_scores_file);

Check warning on line 3031 in src/manage_sql_secinfo.c

View check run for this annotation

Codecov / codecov/patch

src/manage_sql_secinfo.c#L3029-L3031

Added lines #L3029 - L3031 were not covered by tests
return -1;
}

Expand Down
Loading