go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/cli/printer/printer_test.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package printer 5 6 import ( 7 "strings" 8 "testing" 9 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 "go.mondoo.com/cnquery/llx" 13 "go.mondoo.com/cnquery/logger" 14 "go.mondoo.com/cnquery/providers-sdk/v1/testutils" 15 "go.mondoo.com/cnquery/utils/sortx" 16 ) 17 18 var x = testutils.InitTester(testutils.LinuxMock()) 19 20 func init() { 21 logger.InitTestEnv() 22 } 23 24 func testQuery(t *testing.T, query string) (*llx.CodeBundle, map[string]*llx.RawResult) { 25 codeBundle, err := x.Compile(query) 26 require.NoError(t, err) 27 28 results, err := x.ExecuteCode(codeBundle, nil) 29 require.NoError(t, err) 30 31 return codeBundle, results 32 } 33 34 type simpleTest struct { 35 code string 36 expected string 37 results []string 38 } 39 40 func runSimpleTests(t *testing.T, tests []simpleTest) { 41 for i := range tests { 42 cur := tests[i] 43 t.Run(cur.code, func(t *testing.T) { 44 bundle, results := testQuery(t, cur.code) 45 46 s := DefaultPrinter.CodeBundle(bundle) 47 if cur.expected != "" { 48 assert.Equal(t, cur.expected, s) 49 } 50 51 length := len(results) 52 53 assert.Equal(t, length, len(cur.results), "make sure the right number of results are returned") 54 55 keys := sortx.Keys(results) 56 for idx, id := range keys { 57 result := results[id] 58 s = DefaultPrinter.Result(result, bundle) 59 assert.Equal(t, cur.results[idx], s) 60 } 61 }) 62 } 63 } 64 65 type assessmentTest struct { 66 code string 67 result string 68 } 69 70 func runAssessmentTests(t *testing.T, tests []assessmentTest) { 71 for i := range tests { 72 cur := tests[i] 73 t.Run(cur.code, func(t *testing.T) { 74 bundle, resultsMap := testQuery(t, cur.code) 75 76 raw := DefaultPrinter.Results(bundle, resultsMap) 77 assert.Equal(t, cur.result, raw) 78 }) 79 } 80 } 81 82 func TestPrinter(t *testing.T) { 83 runSimpleTests(t, []simpleTest{ 84 { 85 "if ( mondoo.version != null ) { mondoo.build }", 86 "", // ignore 87 []string{ 88 "mondoo.version: \"unstable\"", 89 "if: {\n" + 90 " mondoo.build: \"development\"\n" + 91 "}", 92 }, 93 }, 94 { 95 "file('zzz') { content }", 96 "", 97 []string{ 98 "error: 1 error occurred:\n" + 99 "\t* file 'zzz' not found\n" + 100 "file: {\n content: error: file 'zzz' not found\n}", 101 }, 102 }, 103 { 104 "[]", 105 "", // ignore 106 []string{ 107 "[]", 108 }, 109 }, 110 { 111 "{}", 112 "", // ignore 113 []string{ 114 "{}", 115 }, 116 }, 117 { 118 "['1-2'] { _.split('-') }", 119 "", // ignore 120 []string{ 121 "[\n" + 122 " 0: {\n" + 123 " split: [\n" + 124 " 0: \"1\"\n" + 125 " 1: \"2\"\n" + 126 " ]\n" + 127 " }\n" + 128 "]", 129 }, 130 }, 131 { 132 "mondoo { version }", 133 "-> block 1\n entrypoints: [<1,2>]\n 1: mondoo \n 2: {} bind: <1,1> type:block (=> <2,0>)\n-> block 2\n entrypoints: [<2,2>]\n 1: mondoo id = context\n 2: version bind: <2,1> type:string\n", 134 []string{ 135 "mondoo: {\n version: \"unstable\"\n}", 136 }, 137 }, 138 { 139 "mondoo { _.version }", 140 "-> block 1\n entrypoints: [<1,2>]\n 1: mondoo \n 2: {} bind: <1,1> type:block (=> <2,0>)\n-> block 2\n entrypoints: [<2,2>]\n 1: mondoo id = context\n 2: version bind: <2,1> type:string\n", 141 []string{ 142 "mondoo: {\n version: \"unstable\"\n}", 143 }, 144 }, 145 { 146 "[1].where( _ > 0 )", 147 "-> block 1\n entrypoints: [<1,2>]\n 1: [\n 0: 1\n ]\n 2: where bind: <1,1> type:[]int (ref<1,1>, => <2,0>)\n-> block 2\n entrypoints: [<2,2>]\n 1: _\n 2: >\005 bind: <2,1> type:bool (0)\n", 148 []string{ 149 "where: [\n 0: 1\n]", 150 }, 151 }, 152 { 153 "a = 3\n if(true) {\n a == 3 \n}", 154 "-> block 1\n entrypoints: [<1,2>]\n 1: 3\n 2: if bind: <0,0> type:block (true, => <2,0>, [\n 0: ref<1,1>\n ])\n-> block 2\n entrypoints: [<2,2>]\n 1: ref<1,1>\n 2: ==\x05 bind: <2,1> type:bool (3)\n", 155 []string{"if: {\n a == 3: true\n}"}, 156 }, 157 { 158 "mondoo", 159 "", // ignore 160 []string{ 161 "mondoo: mondoo version=\"unstable\"", 162 }, 163 }, 164 { 165 "users", 166 "", // ignore 167 []string{ 168 "users.list: [\n" + 169 " 0: user name=\"root\" uid=0 gid=0\n" + 170 " 1: user name=\"bin\" uid=1 gid=1\n" + 171 " 2: user name=\"chris\" uid=1000 gid=1000\n" + 172 " 3: user name=\"christopher\" uid=1001 gid=1000\n" + 173 "]", 174 }, 175 }, 176 }) 177 } 178 179 func TestPrinter_Assessment(t *testing.T) { 180 runAssessmentTests(t, []assessmentTest{ 181 { 182 // mixed use: assertion and erroneous data field 183 "mondoo.build == 1; user(name: 'notthere').authorizedkeys.file", 184 strings.Join([]string{ 185 "[failed] mondoo.build == 1; user(name: 'notthere').authorizedkeys.file", 186 " [failed] mondoo.build == 1", 187 " expected: == 1", 188 " actual: \"development\"", 189 " [failed] user.authorizedkeys.file", 190 " error: cannot find user with name 'notthere'", 191 "", 192 }, "\n"), 193 }, 194 { 195 // mixed use: assertion and working data field 196 "mondoo.build == 1; mondoo.version", 197 strings.Join([]string{ 198 "[failed] mondoo.build == 1; mondoo.version", 199 " [failed] mondoo.build == 1", 200 " expected: == 1", 201 " actual: \"development\"", 202 " [ok] value: \"unstable\"", 203 "", 204 }, "\n"), 205 }, 206 { 207 "[1,2,3].\n" + 208 "# @msg Found ${length} numbers\n" + 209 "none( _ > 1 )", 210 strings.Join([]string{ 211 "[failed] Found 2 numbers", 212 "", 213 }, "\n"), 214 }, 215 { 216 "# @msg Expected ${$expected.length} users but got ${length}\n" + 217 "users.none( uid == 0 )", 218 strings.Join([]string{ 219 "[failed] Expected 4 users but got 1", 220 "", 221 }, "\n"), 222 }, 223 { 224 "mondoo.build == 1", 225 strings.Join([]string{ 226 "[failed] mondoo.build == 1", 227 " expected: == 1", 228 " actual: \"development\"", 229 "", 230 }, "\n"), 231 }, 232 { 233 "sshd.config { params['test'] }", 234 strings.Join([]string{ 235 "sshd.config: {", 236 " params[test]: null", 237 "}", 238 }, "\n"), 239 }, 240 { 241 "mondoo.build == 1;mondoo.version =='unstable';", 242 strings.Join([]string{ 243 "[failed] mondoo.build == 1;mondoo.version =='unstable';", 244 " [failed] mondoo.build == 1", 245 " expected: == 1", 246 " actual: \"development\"", 247 " [ok] value: \"unstable\"", 248 "", 249 }, "\n"), 250 }, 251 { 252 "if(true) {\n" + 253 " # @msg Expected ${$expected.length} users but got ${length}\n" + 254 " users.none( uid == 0 )\n" + 255 "}", 256 strings.Join([]string{ 257 "if: {", 258 " [failed] Expected 4 users but got 1", 259 " users.where.list: [", 260 " 0: user name=\"root\" uid=0 gid=0", 261 " ]", 262 "}", 263 }, "\n"), 264 }, 265 { 266 "users.list.duplicates(gid).none()\n", 267 strings.Join([]string{ 268 "[failed] [].none()", 269 " actual: [", 270 " 0: user {", 271 " name: \"christopher\"", 272 " gid: 1000", 273 " uid: 1001", 274 " }", 275 " 1: user {", 276 " name: \"chris\"", 277 " gid: 1000", 278 " uid: 1000", 279 " }", 280 " ]", 281 "", 282 }, "\n"), 283 }, 284 { 285 "users.all( uid < 1000 )\n", 286 strings.Join([]string{ 287 "[failed] users.all()", 288 " actual: [", 289 " 0: user {", 290 " uid: 1000", 291 " gid: 1000", 292 " name: \"chris\"", 293 " }", 294 " 1: user {", 295 " uid: 1001", 296 " gid: 1000", 297 " name: \"christopher\"", 298 " }", 299 " ]", 300 "", 301 }, "\n"), 302 }, 303 { 304 "users.all( 1000 > uid )\n", 305 strings.Join([]string{ 306 "[failed] users.all()", 307 " actual: [", 308 " 0: user {", 309 " name: \"chris\"", 310 " uid: 1000", 311 " gid: 1000", 312 " }", 313 " 1: user {", 314 " name: \"christopher\"", 315 " uid: 1001", 316 " gid: 1000", 317 " }", 318 " ]", 319 "", 320 }, "\n"), 321 }, 322 { 323 "users.all( uid == 0 && enabled == true )\n", 324 strings.Join([]string{ 325 "[failed] users.all()", 326 " actual: [", 327 " 0: user {", 328 " gid: 0", 329 " name: \"root\"", 330 " uid: 0", 331 " enabled: false", 332 " }", 333 " 1: user {", 334 " gid: 1", 335 " name: \"bin\"", 336 " uid: 1", 337 " enabled: false", 338 " }", 339 " 2: user {", 340 " gid: 1000", 341 " name: \"chris\"", 342 " uid: 1000", 343 " enabled: false", 344 " }", 345 " 3: user {", 346 " gid: 1000", 347 " name: \"christopher\"", 348 " uid: 1001", 349 " enabled: false", 350 " }", 351 " ]", 352 "", 353 }, "\n"), 354 }, 355 { 356 "users.none( '/root' == home ); users.all( name != 'root' )\n", 357 strings.Join([]string{ 358 "[failed] users.none( '/root' == home ); users.all( name != 'root' )", 359 "", 360 " [failed] users.none()", 361 " actual: [", 362 " 0: user {", 363 " gid: 0", 364 " home: \"/root\"", 365 " name: \"root\"", 366 " uid: 0", 367 " }", 368 " ]", 369 " [failed] users.all()", 370 " actual: [", 371 " 0: user {", 372 " name: \"root\"", 373 " uid: 0", 374 " gid: 0", 375 " }", 376 " ]", 377 "", 378 }, "\n"), 379 }, 380 // FIXME: these tests aren't working right in the current iteration. 381 // There is also something else a bit weird, namely it uses `groups` 382 // which is not a child field of the `user` resource. I'd love to restore 383 // these. 384 // { 385 // "users.all(groups.none(gid==0))\n", 386 // `[failed] users.all() 387 // actual: [ 388 // 0: user { 389 // uid: 0 390 // groups.list: [ 391 // 0: user group id = group/0/root 392 // 1: user group id = group/1/bin 393 // 2: user group id = group/1000/chris 394 // ] 395 // gid: 0 396 // groups: groups 397 // name: "root" 398 // } 399 // 1: user { 400 // uid: 1 401 // groups.list: [ 402 // 0: user group id = group/0/root 403 // 1: user group id = group/1/bin 404 // 2: user group id = group/1000/chris 405 // ] 406 // gid: 1 407 // groups: groups 408 // name: "bin" 409 // } 410 // 2: user { 411 // uid: 1000 412 // groups.list: [ 413 // 0: user group id = group/0/root 414 // 1: user group id = group/1/bin 415 // 2: user group id = group/1000/chris 416 // ] 417 // gid: 1000 418 // groups: groups 419 // name: "chris" 420 // } 421 // 3: user { 422 // uid: 1001 423 // groups.list: [ 424 // 0: user group id = group/0/root 425 // 1: user group id = group/1/bin 426 // 2: user group id = group/1000/chris 427 // ] 428 // gid: 1000 429 // groups: groups 430 // name: "christopher" 431 // } 432 // ] 433 // `, 434 // }, 435 // { 436 // "users.all(groups.all(name == 'root'))\n", 437 // `[failed] users.all() 438 // actual: [ 439 // 0: user { 440 // uid: 0 441 // groups.list: [ 442 // 0: user group id = group/0/root 443 // 1: user group id = group/1/bin 444 // 2: user group id = group/1000/chris 445 // ] 446 // groups: groups 447 // gid: 0 448 // name: "root" 449 // } 450 // 1: user { 451 // uid: 1 452 // groups.list: [ 453 // 0: user group id = group/0/root 454 // 1: user group id = group/1/bin 455 // 2: user group id = group/1000/chris 456 // ] 457 // groups: groups 458 // gid: 1 459 // name: "bin" 460 // } 461 // 2: user { 462 // uid: 1000 463 // groups.list: [ 464 // 0: user group id = group/0/root 465 // 1: user group id = group/1/bin 466 // 2: user group id = group/1000/chris 467 // ] 468 // groups: groups 469 // gid: 1000 470 // name: "chris" 471 // } 472 // 3: user { 473 // uid: 1001 474 // groups.list: [ 475 // 0: user group id = group/0/root 476 // 1: user group id = group/1/bin 477 // 2: user group id = group/1000/chris 478 // ] 479 // groups: groups 480 // gid: 1000 481 // name: "christopher" 482 // } 483 // ] 484 // `, 485 // }, 486 { 487 "users.all(sshkeys.length > 2)\n", 488 strings.Join([]string{ 489 "[failed] users.all()", 490 " actual: [", 491 " 0: user {", 492 " name: \"root\"", 493 " gid: 0", 494 " sshkeys: []", 495 " sshkeys.length: 0", 496 " uid: 0", 497 " }", 498 " 1: user {", 499 " name: \"bin\"", 500 " gid: 1", 501 " sshkeys: []", 502 " sshkeys.length: 0", 503 " uid: 1", 504 " }", 505 " 2: user {", 506 " name: \"chris\"", 507 " gid: 1000", 508 " sshkeys: []", 509 " sshkeys.length: 0", 510 " uid: 1000", 511 " }", 512 " 3: user {", 513 " name: \"christopher\"", 514 " gid: 1000", 515 " sshkeys: []", 516 " sshkeys.length: 0", 517 " uid: 1001", 518 " }", 519 " ]", 520 "", 521 }, "\n"), 522 }, 523 }) 524 } 525 526 func TestPrinter_Blocks(t *testing.T) { 527 runSimpleTests(t, []simpleTest{ 528 { 529 "['a', 'b'] { x=_ \n x }", 530 "", // ignore 531 []string{ 532 strings.Join([]string{ 533 "[", 534 " 0: {", 535 " x: \"a\"", 536 " }", 537 " 1: {", 538 " x: \"b\"", 539 " }", 540 "]", 541 }, "\n"), 542 }, 543 }, 544 { 545 "['a', 'b'] { x=_ \n x == 'a' }", 546 "", // ignore 547 []string{ 548 strings.Join([]string{ 549 "[", 550 " 0: {", 551 " x == \"a\": true", 552 " }", 553 " 1: {", 554 " x == \"a\": false", 555 " }", 556 "]", 557 }, "\n"), 558 }, 559 }, 560 }) 561 } 562 563 func TestPrinter_Buggy(t *testing.T) { 564 runSimpleTests(t, []simpleTest{ 565 { 566 "mondoo", 567 "", // ignore 568 []string{ 569 "mondoo: mondoo version=\"unstable\"", 570 }, 571 }, 572 }) 573 }