Skip to content

Commit bf81cd0

Browse files
committed
Added optional parameter strict
Changelog: Added an optional parameter strict for validjson and validdata policy functions. This makes the functions evaluate to false on json primitives. Ticket: CFE-4163 Signed-off-by: Victor Moene <victor.moene@northern.tech>
1 parent 824bd0c commit bf81cd0

File tree

4 files changed

+104
-6
lines changed

4 files changed

+104
-6
lines changed

examples/validdata.cf

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,24 @@ bundle agent main
33
{
44
vars:
55
"json_string" string => '{"test": [1, 2, 3]}';
6-
6+
"primitive" string => "\"hello\"";
7+
78
reports:
89
"This JSON string is valid!"
910
if => validdata("$(json_string)", "JSON");
1011
"This JSON string is not valid."
1112
unless => validdata("$(json_string)", "JSON");
13+
14+
"This JSON string is valid! (strict)"
15+
if => validdata("$(primitive)", "JSON", "true");
16+
"This JSON string is not valid. (strict)"
17+
unless => validdata("$(primitive)", "JSON", "true");
1218
}
1319
#+end_src
1420
###############################################################################
1521
#+begin_src example_output
1622
#@ ```
1723
#@ R: This JSON string is valid!
24+
#@ R: This JSON string is not valid. (strict)
1825
#@ ```
1926
#+end_src

examples/validjson.cf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,25 @@ bundle agent main
33
{
44
vars:
55
"json_string" string => '{"test": [1, 2, 3]}';
6+
"primitive" string => "\"hello\"";
67

78
reports:
89
"This JSON string is valid!"
910
if => validjson("$(json_string)");
1011
"This JSON string is not valid."
1112
unless => validjson("$(json_string)");
13+
14+
"This JSON string is valid! (strict)"
15+
if => validjson("$(primitive)", "true");
16+
"This JSON string is not valid. (strict)"
17+
unless => validjson("$(primitive)", "true");
1218
}
19+
1320
#+end_src
1421
###############################################################################
1522
#+begin_src example_output
1623
#@ ```
1724
#@ R: This JSON string is valid!
25+
#@ R: This JSON string is not valid. (strict)
1826
#@ ```
1927
#+end_src

libpromises/evalfunction.c

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7208,7 +7208,8 @@ static FnCallResult FnCallReadJson(ARG_UNUSED EvalContext *ctx,
72087208

72097209
static FnCallResult ValidateDataGeneric(const char *const fname,
72107210
const char *data,
7211-
const DataFileType requested_mode)
7211+
const DataFileType requested_mode,
7212+
bool strict)
72127213
{
72137214
assert(data != NULL);
72147215
if (requested_mode != DATAFILETYPE_JSON)
@@ -7226,7 +7227,13 @@ static FnCallResult ValidateDataGeneric(const char *const fname,
72267227
Log(LOG_LEVEL_VERBOSE, "%s: %s", fname, JsonParseErrorToString(err));
72277228
}
72287229

7229-
FnCallResult ret = FnReturnContext(json != NULL);
7230+
bool isvalid = json != NULL;
7231+
if (strict)
7232+
{
7233+
isvalid = isvalid && JsonGetElementType(json) != JSON_ELEMENT_TYPE_PRIMITIVE;
7234+
}
7235+
7236+
FnCallResult ret = FnReturnContext(isvalid);
72307237
JsonDestroy(json);
72317238
return ret;
72327239
}
@@ -7242,12 +7249,17 @@ static FnCallResult FnCallValidData(ARG_UNUSED EvalContext *ctx,
72427249
Log(LOG_LEVEL_ERR, "Function '%s' requires two arguments", fp->name);
72437250
return FnFailure();
72447251
}
7252+
bool strict = false;
7253+
if (args->next != NULL)
7254+
{
7255+
strict = BooleanFromString(RlistScalarValue(args->next));
7256+
}
72457257

72467258
const char *data = RlistScalarValue(args);
72477259
const char *const mode_string = RlistScalarValue(args->next);
72487260
DataFileType requested_mode = GetDataFileTypeFromString(mode_string);
72497261

7250-
return ValidateDataGeneric(fp->name, data, requested_mode);
7262+
return ValidateDataGeneric(fp->name, data, requested_mode, strict);
72517263
}
72527264

72537265
static FnCallResult FnCallValidJson(ARG_UNUSED EvalContext *ctx,
@@ -7261,9 +7273,14 @@ static FnCallResult FnCallValidJson(ARG_UNUSED EvalContext *ctx,
72617273
Log(LOG_LEVEL_ERR, "Function '%s' requires one argument", fp->name);
72627274
return FnFailure();
72637275
}
7276+
bool strict = false;
7277+
if (args->next != NULL)
7278+
{
7279+
strict = BooleanFromString(RlistScalarValue(args->next));
7280+
}
72647281

72657282
const char *data = RlistScalarValue(args);
7266-
return ValidateDataGeneric(fp->name, data, DATAFILETYPE_JSON);
7283+
return ValidateDataGeneric(fp->name, data, DATAFILETYPE_JSON, strict);
72677284
}
72687285

72697286
static FnCallResult FnCallReadModuleProtocol(
@@ -9885,6 +9902,7 @@ static const FnCallArg READFILE_ARGS[] =
98859902
static const FnCallArg VALIDDATATYPE_ARGS[] =
98869903
{
98879904
{CF_ANYSTRING, CF_DATA_TYPE_STRING, "String to validate as JSON"},
9905+
{CF_BOOL, CF_DATA_TYPE_OPTION, "Enable more strict validation, requiring the result to be a valid data container, matching the requirements of parsejson()."},
98889906
{NULL, CF_DATA_TYPE_NONE, NULL}
98899907
};
98909908

@@ -9941,6 +9959,7 @@ static const FnCallArg VALIDDATA_ARGS[] =
99419959
{
99429960
{CF_ANYSTRING, CF_DATA_TYPE_STRING, "String to validate as JSON"},
99439961
{"JSON", CF_DATA_TYPE_OPTION, "Type of data to validate"},
9962+
{CF_BOOL, CF_DATA_TYPE_OPTION, "Enable more strict validation, requiring the result to be a valid data container, matching the requirements of parsejson()."},
99449963
{NULL, CF_DATA_TYPE_NONE, NULL}
99459964
};
99469965

@@ -10691,7 +10710,7 @@ const FnCallType CF_FNCALL_TYPES[] =
1069110710
FnCallTypeNew("userexists", CF_DATA_TYPE_CONTEXT, USEREXISTS_ARGS, &FnCallUserExists, "True if user name or numerical id exists on this host",
1069210711
FNCALL_OPTION_NONE, FNCALL_CATEGORY_SYSTEM, SYNTAX_STATUS_NORMAL),
1069310712
FnCallTypeNew("validdata", CF_DATA_TYPE_CONTEXT, VALIDDATA_ARGS, &FnCallValidData, "Check for errors in JSON or YAML data",
10694-
FNCALL_OPTION_NONE, FNCALL_CATEGORY_DATA, SYNTAX_STATUS_NORMAL),
10713+
FNCALL_OPTION_VARARG, FNCALL_CATEGORY_DATA, SYNTAX_STATUS_NORMAL),
1069510714
FnCallTypeNew("validjson", CF_DATA_TYPE_CONTEXT, VALIDDATATYPE_ARGS, &FnCallValidJson, "Check for errors in JSON data",
1069610715
FNCALL_OPTION_VARARG, FNCALL_CATEGORY_DATA, SYNTAX_STATUS_NORMAL),
1069710716
FnCallTypeNew("variablesmatching", CF_DATA_TYPE_STRING_LIST, CLASSMATCH_ARGS, &FnCallVariablesMatching, "List the variables matching regex arg1 and tag regexes arg2,arg3,...",
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
body common control
2+
{
3+
inputs => { "../../default.cf.sub" };
4+
bundlesequence => { test, check };
5+
version => "1.0";
6+
}
7+
8+
bundle agent test
9+
{
10+
meta:
11+
"description" -> { "CFE-4163" }
12+
string => "Test policy strict parameter of validjson and validdata";
13+
}
14+
15+
bundle agent check
16+
{
17+
vars:
18+
"json" string => readfile("$(this.promise_dirname)/validdata.cf.json", inf);
19+
"invjson" string => readfile("$(this.promise_dirname)/validdata.cf.inv.json", inf);
20+
"mystring" string => "\"foo\"";
21+
"mynumber" string => "3.14";
22+
"mybool" string => "true";
23+
"mynull" string => "null";
24+
25+
classes:
26+
"isvalid_json"
27+
expression => validjson("$(json)", "false");
28+
"isinvalid_json"
29+
expression => not(validjson("$(invjson)", "false"));
30+
"isvalid_string_primitive"
31+
expression => validjson("$(mystring)", "false");
32+
"isvalid_number_primitive_strict"
33+
expression => validjson("$(mynumber)", "false");
34+
"isvalid_bool_primitive"
35+
expression => validjson("$(mybool)", "false");
36+
"isvalid_null_primitive"
37+
expression => validjson("$(mynull)", "false");
38+
39+
"invalid_json_strict"
40+
expression => validjson("$(json)", "true");
41+
"isinvalid_json_strict"
42+
expression => not(validjson("$(invjson)", "true"));
43+
"isinvalid_string_primitive_strict"
44+
expression => not(validjson("$(mystring)", "true"));
45+
"isinvalid_number_primitive_strict"
46+
expression => not(validjson("$(mynumber)", "true"));
47+
"isinvalid_bool_primitive_strict"
48+
expression => not(validjson("$(mybool)", "true"));
49+
"isinvalid_null_primitive_strict"
50+
expression => not(validjson("$(mynull)", "true"));
51+
52+
"ok"
53+
and => { "isvalid_json", "isvalid_string_primitive", "isvalid_number_primitive_strict", "isvalid_bool_primitive",
54+
"isvalid_null_primitive", "invalid_json_strict", "isinvalid_string_primitive_strict",
55+
"isinvalid_number_primitive_strict", "isinvalid_bool_primitive_strict", "isinvalid_null_primitive_strict",
56+
"isinvalid_json", "isinvalid_json_strict" };
57+
58+
59+
reports:
60+
ok::
61+
"$(this.promise_filename) Pass";
62+
!ok::
63+
"$(this.promise_filename) FAIL";
64+
}

0 commit comments

Comments
 (0)