Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
66 changes: 52 additions & 14 deletions agent_controller/agent_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -793,33 +793,71 @@ push_error (GPtrArray **errors, const gchar *msg)
static void
parse_errors_json_into_array (const gchar *body, GPtrArray **errors)
{
cJSON *root;
const cJSON *validation_node;
gboolean any_added = FALSE;

if (!errors)
return;

/* cJSON requires NUL-terminated input; make a safe copy. */
cJSON *root = cJSON_Parse (body);
if (!body || *body == '\0')
{
push_error (errors, "Request rejected (400): empty response body.");
return;
}

root = cJSON_Parse (body);
if (!root)
{
push_error (errors, "Request rejected (400): invalid JSON payload.");
return;
}

const cJSON *errors_node = cJSON_GetObjectItemCaseSensitive (root, "errors");
gboolean any_added = FALSE;

if (cJSON_IsArray (errors_node))
validation_node = cJSON_GetObjectItemCaseSensitive (root, "validation");
if (cJSON_IsArray (validation_node))
{
int n = cJSON_GetArraySize (errors_node);
for (int i = 0; i < n; ++i)
const cJSON *validation_item;

cJSON_ArrayForEach (validation_item, validation_node)
{
const cJSON *agent_id_node;
const cJSON *errors_node;
const cJSON *error_item;
const gchar *agent_id = NULL;

if (!cJSON_IsObject (validation_item))
continue;

agent_id_node =
cJSON_GetObjectItemCaseSensitive (validation_item, "agent_id");
if (cJSON_IsString (agent_id_node) && agent_id_node->valuestring)
agent_id = agent_id_node->valuestring;

errors_node =
cJSON_GetObjectItemCaseSensitive (validation_item, "errors");
if (!cJSON_IsArray (errors_node))
continue;

cJSON_ArrayForEach (error_item, errors_node)
{
const cJSON *it = cJSON_GetArrayItem (errors_node, i);
if (cJSON_IsString (it) && it->valuestring && *it->valuestring)
{
push_error (errors, it->valuestring);
any_added = TRUE;
}
gchar *message;

if (!cJSON_IsString (error_item) || !error_item->valuestring
|| *error_item->valuestring == '\0')
continue;

if (agent_id && *agent_id)
message =
g_strdup_printf ("%s: %s", agent_id, error_item->valuestring);
else
message = g_strdup (error_item->valuestring);

push_error (errors, message);
g_free (message);

any_added = TRUE;
}
}
}

if (!any_added)
Expand Down
153 changes: 125 additions & 28 deletions agent_controller/agent_controller_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -1576,8 +1576,18 @@ Ensure (agent_controller, update_agents_fails_on_http_error_status)
Ensure (agent_controller, update_agents_400_populates_errors_from_json)
{
mock_http_status = 400;
mock_response_data =
g_strdup ("{ \"errors\": [\"e1\", \"e2\"], \"warnings\": null }");
mock_response_data = g_strdup (
"{"
" \"validation\": ["
" {"
" \"agent_id\": \"GAT-29::2d61a736\","
" \"errors\": ["
" \"agent_control.retry.attempts must be >= 0\","
" \"agent_script_executor.scheduler_cron_time[0] is invalid\""
" ]"
" }"
" ]"
"}");

agent_controller_connector_t conn = make_conn ();

Expand All @@ -1592,10 +1602,17 @@ Ensure (agent_controller, update_agents_400_populates_errors_from_json)
assert_that (rc, is_equal_to (-1));
assert_that (errs, is_not_null);
assert_that ((int) errs->len, is_equal_to (2));
assert_that ((const gchar *) g_ptr_array_index (errs, 0),
is_equal_to_string ("e1"));

assert_that (
(const gchar *) g_ptr_array_index (errs, 0),
is_equal_to_string ("GAT-29::2d61a736: "
"agent_control.retry.attempts must be >= 0"));

assert_that ((const gchar *) g_ptr_array_index (errs, 1),
is_equal_to_string ("e2"));
is_equal_to_string (
"GAT-29::2d61a736: "
"agent_script_executor.scheduler_cron_time[0] is invalid"));

assert_that (last_sent_url, contains_string ("/api/v1/admin/agents"));

g_ptr_array_free (errs, TRUE);
Expand All @@ -1606,8 +1623,18 @@ Ensure (agent_controller, update_agents_400_populates_errors_from_json)
Ensure (agent_controller, update_agents_422_populates_errors_from_json)
{
mock_http_status = 422;
mock_response_data =
g_strdup ("{ \"errors\": [\"e1\", \"e2\"], \"warnings\": null }");
mock_response_data = g_strdup (
"{"
" \"validation\": ["
" {"
" \"agent_id\": \"GAT-29::2d61a736\","
" \"errors\": ["
" \"agent_control.retry.attempts must be >= 0\","
" \"agent_script_executor.scheduler_cron_time[0] is invalid\""
" ]"
" }"
" ]"
"}");

agent_controller_connector_t conn = make_conn ();

Expand All @@ -1622,10 +1649,16 @@ Ensure (agent_controller, update_agents_422_populates_errors_from_json)
assert_that (rc, is_equal_to (-1));
assert_that (errs, is_not_null);
assert_that ((int) errs->len, is_equal_to (2));
assert_that ((const gchar *) g_ptr_array_index (errs, 0),
is_equal_to_string ("e1"));

assert_that (
(const gchar *) g_ptr_array_index (errs, 0),
is_equal_to_string ("GAT-29::2d61a736: "
"agent_control.retry.attempts must be >= 0"));

assert_that ((const gchar *) g_ptr_array_index (errs, 1),
is_equal_to_string ("e2"));
is_equal_to_string (
"GAT-29::2d61a736: "
"agent_script_executor.scheduler_cron_time[0] is invalid"));

g_ptr_array_free (errs, TRUE);
agent_controller_agent_update_list_free (updates);
Expand Down Expand Up @@ -1987,8 +2020,18 @@ Ensure (agent_controller,
update_scan_agent_config_400_populates_errors_from_json)
{
mock_http_status = 400;
mock_response_data =
g_strdup ("{ \"errors\": [\"e1\", \"e2\"], \"warnings\": null }");
mock_response_data = g_strdup (
"{"
" \"validation\": ["
" {"
" \"agent_id\": \"GAT-29::2d61a736\","
" \"errors\": ["
" \"agent_control.retry.attempts must be >= 0\","
" \"agent_script_executor.scheduler_cron_time[0] is invalid\""
" ]"
" }"
" ]"
"}");

agent_controller_connector_t conn = make_conn ();
agent_controller_scan_agent_config_t cfg = make_scan_agent_config ();
Expand All @@ -1999,10 +2042,16 @@ Ensure (agent_controller,
assert_that (rc, is_equal_to (-1));
assert_that (errs, is_not_null);
assert_that ((int) errs->len, is_equal_to (2));
assert_that ((const gchar *) g_ptr_array_index (errs, 0),
is_equal_to_string ("e1"));

assert_that (
(const gchar *) g_ptr_array_index (errs, 0),
is_equal_to_string ("GAT-29::2d61a736: "
"agent_control.retry.attempts must be >= 0"));

assert_that ((const gchar *) g_ptr_array_index (errs, 1),
is_equal_to_string ("e2"));
is_equal_to_string (
"GAT-29::2d61a736: "
"agent_script_executor.scheduler_cron_time[0] is invalid"));

g_ptr_array_free (errs, TRUE);
agent_controller_scan_agent_config_free (cfg);
Expand All @@ -2013,8 +2062,18 @@ Ensure (agent_controller,
update_scan_agent_config_422_populates_errors_from_json)
{
mock_http_status = 422;
mock_response_data =
g_strdup ("{ \"errors\": [\"e1\", \"e2\"], \"warnings\": null }");
mock_response_data = g_strdup (
"{"
" \"validation\": ["
" {"
" \"agent_id\": \"GAT-29::2d61a736\","
" \"errors\": ["
" \"agent_control.retry.attempts must be >= 0\","
" \"agent_script_executor.scheduler_cron_time[0] is invalid\""
" ]"
" }"
" ]"
"}");

agent_controller_connector_t conn = make_conn ();
agent_controller_scan_agent_config_t cfg = make_scan_agent_config ();
Expand All @@ -2025,10 +2084,16 @@ Ensure (agent_controller,
assert_that (rc, is_equal_to (-1));
assert_that (errs, is_not_null);
assert_that ((int) errs->len, is_equal_to (2));
assert_that ((const gchar *) g_ptr_array_index (errs, 0),
is_equal_to_string ("e1"));

assert_that (
(const gchar *) g_ptr_array_index (errs, 0),
is_equal_to_string ("GAT-29::2d61a736: "
"agent_control.retry.attempts must be >= 0"));

assert_that ((const gchar *) g_ptr_array_index (errs, 1),
is_equal_to_string ("e2"));
is_equal_to_string (
"GAT-29::2d61a736: "
"agent_script_executor.scheduler_cron_time[0] is invalid"));

g_ptr_array_free (errs, TRUE);
agent_controller_scan_agent_config_free (cfg);
Expand Down Expand Up @@ -2467,20 +2532,52 @@ Ensure (agent_controller, push_error_does_not_change_existing_on_null_or_empty)

Ensure (agent_controller, parse_errors_collects_messages_from_array)
{
const char *json = "{"
" \"errors\":[\"e1\",\"e2\"],"
" \"warnings\":null"
"}";
const char *json =
"{"
" \"validation\": ["
" {"
" \"agent_id\": \"GAT-29::2d61a736\","
" \"errors\": ["
" \"agent_control.retry.attempts must be >= 0\","
" \"agent_script_executor.scheduler_cron_time[0] is invalid\""
" ]"
" },"
" {"
" \"agent_id\": \"GAT-29::7f91bc22\","
" \"errors\": ["
" \"agent_control.retry.delay_seconds must be >= 0\","
" \"agent_script_executor.scheduler_cron_time[1] is invalid\""
" ]"
" }"
" ]"
"}";

GPtrArray *errs = NULL;

parse_errors_json_into_array (json, &errs);

assert_that (errs, is_not_null);
assert_that ((int) errs->len, is_equal_to (2));
assert_that ((const gchar *) g_ptr_array_index (errs, 0),
is_equal_to_string ("e1"));
assert_that ((int) errs->len, is_equal_to (4));

assert_that (
(const gchar *) g_ptr_array_index (errs, 0),
is_equal_to_string ("GAT-29::2d61a736: "
"agent_control.retry.attempts must be >= 0"));

assert_that ((const gchar *) g_ptr_array_index (errs, 1),
is_equal_to_string ("e2"));
is_equal_to_string (
"GAT-29::2d61a736: "
"agent_script_executor.scheduler_cron_time[0] is invalid"));

assert_that (
(const gchar *) g_ptr_array_index (errs, 2),
is_equal_to_string ("GAT-29::7f91bc22: "
"agent_control.retry.delay_seconds must be >= 0"));

assert_that ((const gchar *) g_ptr_array_index (errs, 3),
is_equal_to_string (
"GAT-29::7f91bc22: "
"agent_script_executor.scheduler_cron_time[1] is invalid"));

g_ptr_array_free (errs, TRUE);
}
Expand Down
Loading