diff --git a/__tests__/result-service.test.ts b/__tests__/result-service.test.ts index 3dc4dd8..115be9f 100644 --- a/__tests__/result-service.test.ts +++ b/__tests__/result-service.test.ts @@ -66,13 +66,9 @@ describe('Test components service', () => { it(`test c`, () => { const scannerResults = JSON.parse(t.content) as ScannerResults; const components = getComponents(scannerResults); - const util = require('util'); - // console.log(util.inspect(compoments, {showHidden: false, depth: null, colors: true})) const componentsWithCopyleft = components.filter(component => component.licenses.some(license => !!license.copyleft) ); - - console.log(util.inspect(componentsWithCopyleft, { showHidden: false, depth: null, colors: true })); }); }); diff --git a/__tests__/scan_files/format_utils.c b/__tests__/scan_files/format_utils.c new file mode 100644 index 0000000..1f4ed9d --- /dev/null +++ b/__tests__/scan_files/format_utils.c @@ -0,0 +1,319 @@ +#include "../inc/format_utils.h" +#include "json.h" +#include +#include +#include "json.h" +#include "log.h" + +#include +#include + +#include +#include "cyclonedx.h" +#include "spdx.h" + + +/* Add comments */ +component_item component_list[CRC_LIST_LEN]; + +/* Check if a crc is found in the list (add it if not) */ +bool add_CRC(uint32_t *list, uint32_t crc) +{ + for (int i = 0; i < CRC_LIST_LEN; i++) + { + if (list[i] == 0) + { + list[i] = crc; + return false; + } + if (list[i] == crc) + return true; + } + return false; +} + +/* Check if a component is found in component_list (add it if not) */ +bool add_component(match_data *match) +{ + /* Init component list */ + for (int i = 0; i < CRC_LIST_LEN; i++) + { + if (!strcmp(component_list[i].purl, match->purl)) + { + log_debug("Component %s exist", match->purl); + return true; + } + if (!*component_list[i].purl) + { + strcpy(component_list[i].license, match->license); + strcpy(component_list[i].vendor, match->vendor); + strcpy(component_list[i].component, match->component); + strcpy(component_list[i].version, match->version); + strcpy(component_list[i].latest_version, match->version); + strcpy(component_list[i].purl, match->purl); + log_debug("Component %s added", match->purl); + return false; + } + } + return false; +} + +f_contents *scan_parse_read_file(char *filename) +{ + FILE *fp; + struct stat filestatus; + + if (stat(filename, &filestatus) != 0) + { + return NULL; + } + f_contents *contents = calloc(1, sizeof(f_contents)); + contents->size = filestatus.st_size; + contents->contents = (char *)malloc(filestatus.st_size); + if (contents->contents == NULL) + { + free_f_contents(contents); + return NULL; + } + + fp = fopen(filename, "rt"); + if (fp == NULL) + { + fclose(fp); + free_f_contents(contents); + return NULL; + } + if (fread(contents->contents, contents->size, 1, fp) != 1) + { + fprintf(stderr, "Unable to read content of %s\n", filename); + fclose(fp); + free_f_contents(contents); + return NULL; + } + fclose(fp); + + return contents; +} + + + + +int scan_parse_v2(char *filename) +{ + json_char *json; + json_value *value; + f_contents *contents = scan_parse_read_file(filename); + if (!contents) + { + log_error("There was a problem reading file: %s", filename); + return 1; + } + json = (json_char *)contents->contents; + value = json_parse(json, contents->size); + + if (value == NULL) + { + log_error("Unable to parse data"); + free_f_contents(contents); + return 1; + } + + process_scan_result(value); + + json_value_free(value); + free_f_contents(contents); + return 0; +} + +void free_f_contents(f_contents *c) +{ + if (c->contents) + free(c->contents); + free(c); +} +/* Returns a string with a hex representation of md5 */ +char *md5_hex(uint8_t *md5) +{ + char *out = calloc(2 * MD5_LEN + 1, 1); + for (int i = 0; i < MD5_LEN; i++) + sprintf(out + strlen(out), "%02x", md5[i]); + return out; +} + +void process_scan_result(json_value *result) +{ + if (result == NULL) + { + return; + } + if (result->type != json_object) + { + return; + } + + for (int i = 0; i < result->u.object.length; i++) + { + process_match(result->u.object.values[i]); + log_trace("process %u/%u",i, result->u.object.length); + } +} + +void match_list_free(match_data_list *list) +{ + + for (int i = 0; i < list->count; i++) + { + + free(list->match_list[i]); + } + + free(list->match_list); + + free(list); +} + +void process_match(json_object_entry value) +{ + int array_length = value.value->u.array.length; + //match_data_list *list = calloc(1, sizeof(match_data)); + //list->match_list = calloc(1, sizeof(match_data)); + //list->count = array_length; + + for (int i = 0; i < array_length; i++) + { + match_data *match = calloc(1, sizeof(match_data)); + json_object_entry *match_value = value.value->u.array.values[i]->u.object.values; + int match_obj_len = value.value->u.array.values[i]->u.object.length; + + // list->match_list[i] = calloc(1, sizeof(match_data)); //we dont need a match list for the moment + match_data * new_item = calloc(1, sizeof(match_data)); + for (int j = 0; j < match_obj_len; j++) + { + if (!strcmp(match_value[j].name, "id")) + { + if (strstr(match_value[j].value->u.string.ptr, "none")) + break; + strcpy(match->idtype, match_value[j].value->u.string.ptr); + } + if (!strcmp(match_value[j].name, "vendor")) + { + strcpy(new_item->vendor, match_value[j].value->u.string.ptr); + } + if (!strcmp(match_value[j].name, "component")) + { + strcpy(new_item->component, match_value[j].value->u.string.ptr); + } + if (!strcmp(match_value[j].name, "version")) + { + strcpy(new_item->version, match_value[j].value->u.string.ptr); + } + if (!strcmp(match_value[j].name, "latest")) + { + strcpy(new_item->latest_version, match_value[j].value->u.string.ptr); + } + if (!strcmp(match_value[j].name, "url")) + { + strcpy(new_item->url, match_value[j].value->u.string.ptr); + } + if (!strcmp(match_value[j].name, "release_date")) + { + strcpy(new_item->release_date, match_value[j].value->u.string.ptr); + } + if (!strcmp(match_value[j].name, "file")) + { + strcpy(new_item->filename, match_value[j].value->u.string.ptr); + } + if (!strcmp(match_value[j].name, "purl")) + { + strcpy(new_item->purl, match_value[j].value->u.array.values[0]->u.string.ptr); + } + if (!strcmp(match_value[j].name, "licenses")) + { + if (match_value[j].value->u.array.length > 0) + { + strcpy(new_item->license, match_value[j].value->u.array.values[0]->u.object.values->value->u.string.ptr); + } + } + /*if (!strcmp(match_value[j].name, "lines")) + { + strcpy(match->lines, match_value[j].value->u.string.ptr); + }*/ + /*if (!strcmp(match_value[j].name, "oss_lines")) + { + strcpy(match->oss_lines, match_value[j].value->u.string.ptr); + }*/ //<---- was commented due to a bug on mac. + if (!strcmp(match_value[j].name, "matched")) + { + strcpy(match->matched, match_value[j].value->u.string.ptr); + } + if (!strcmp(match_value[j].name, "size")) + { + strcpy(match->size, match_value[j].value->u.string.ptr); + } + if (!strcmp(match_value[j].name, "url_hash")) + { + strcpy(match->md5_comp, match_value[j].value->u.string.ptr); + } + if (!strcmp(match_value[j].name, "file")) + { + strcpy(match->filename, match_value[j].value->u.string.ptr); + } + if (!strcmp(match_value[j].name, "licenses")) + { + if (match_value[j].value->u.array.length > 0) + { + strcpy(match->license, match_value[j].value->u.array.values[0]->u.object.values->value->u.string.ptr); + } + } + } + add_component(new_item); + free(match); + free(new_item); + //list->match_list[i] = new_item; + } + // match_list_free(list); +} + +/* Output contents of component_list in the requested format */ +void print_matches(FILE * output, char * format) +{ + bool cyclonedx = false; + + if (strstr(format,SCANNER_FORMAT_CYCLONEDX)) + cyclonedx = true; + + if (cyclonedx) + cyclonedx_open(output); + else + spdx_open(output); + + for (int i = 0; i < CRC_LIST_LEN && *component_list[i].purl; i++) + { + if (i) + fprintf(output," ,\n"); + + if (cyclonedx) + print_json_match_cyclonedx(output, &component_list[i]); + else + print_json_match_spdx(output, &component_list[i]); + } + + if (cyclonedx) + cyclonedx_close(output); + else + spdx_close(output); + +} + + +/* Returns the current date stamp */ +char *datestamp(void) +{ + time_t timestamp; + struct tm *times; + time(×tamp); + times = localtime(×tamp); + char *stamp = malloc(MAX_ARGLN); + strftime(stamp, MAX_ARGLN, "%FT%T%z", times); + return stamp; +} diff --git a/__tests__/scan_files/json.h b/__tests__/scan_files/json.h new file mode 100644 index 0000000..66ac7d3 --- /dev/null +++ b/__tests__/scan_files/json.h @@ -0,0 +1,291 @@ + +/* vim: set et ts=3 sw=3 sts=3 ft=c: + * + * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. + * https://github.com/udp/json-parser + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + + + + + + + +#ifndef _JSON_H +#define _JSON_H + +#ifndef json_char +#define json_char char +#endif + +#ifndef json_int_t +#ifndef _MSC_VER +#include +#define json_int_t int64_t +#else +#define json_int_t __int64 +#endif +#endif + + + +#include + +#ifdef __cplusplus + +#include + +extern "C" +{ + +#endif + + typedef struct + { + unsigned long max_memory; + int settings; + + /* Custom allocator support (leave null to use malloc/free) + */ + + void *(*mem_alloc)(size_t, int zero, void *user_data); + void (*mem_free)(void *, void *user_data); + + void *user_data; /* will be passed to mem_alloc and mem_free */ + + size_t value_extra; /* how much extra space to allocate for values? */ + + } json_settings; + + +#define json_enable_comments 0x01 + + typedef enum + { + json_none, + json_object, + json_array, + json_integer, + json_double, + json_string, + json_boolean, + json_null + + } json_type; + + extern const struct _json_value json_value_none; + + typedef struct _json_object_entry + { + json_char *name; + unsigned int name_length; + + struct _json_value *value; + + } json_object_entry; + + typedef struct _json_value + { + struct _json_value *parent; + + json_type type; + + union + { + int boolean; + json_int_t integer; + double dbl; + + struct + { + unsigned int length; + json_char *ptr; /* null terminated */ + + } string; + + struct + { + unsigned int length; + + json_object_entry *values; + +#if defined(__cplusplus) && __cplusplus >= 201103L + decltype(values) begin() const + { + return values; + } + decltype(values) end() const + { + return values + length; + } +#endif + + } object; + + struct + { + unsigned int length; + struct _json_value **values; + +#if defined(__cplusplus) && __cplusplus >= 201103L + decltype(values) begin() const + { + return values; + } + decltype(values) end() const + { + return values + length; + } +#endif + + } array; + + } u; + + union + { + struct _json_value *next_alloc; + void *object_mem; + + } _reserved; + +#ifdef JSON_TRACK_SOURCE + + /* Location of the value in the source JSON + */ + unsigned int line, col; + +#endif + + /* Some C++ operator sugar */ + +#ifdef __cplusplus + + public: + inline _json_value() + { + memset(this, 0, sizeof(_json_value)); + } + + inline const struct _json_value &operator[](int index) const + { + if (type != json_array || index < 0 || ((unsigned int)index) >= u.array.length) + { + return json_value_none; + } + + return *u.array.values[index]; + } + + inline const struct _json_value &operator[](const char *index) const + { + if (type != json_object) + return json_value_none; + + for (unsigned int i = 0; i < u.object.length; ++i) + if (!strcmp(u.object.values[i].name, index)) + return *u.object.values[i].value; + + return json_value_none; + } + + inline operator const char *() const + { + switch (type) + { + case json_string: + return u.string.ptr; + + default: + return ""; + }; + } + + inline operator json_int_t() const + { + switch (type) + { + case json_integer: + return u.integer; + + case json_double: + return (json_int_t)u.dbl; + + default: + return 0; + }; + } + + inline operator bool() const + { + if (type != json_boolean) + return false; + + return u.boolean != 0; + } + + inline operator double() const + { + switch (type) + { + case json_integer: + return (double)u.integer; + + case json_double: + return u.dbl; + + default: + return 0; + }; + } + +#endif + + } json_value; + + json_value *json_parse(const json_char *json, + size_t length); + +#define json_error_max 128 + json_value *json_parse_ex(json_settings *settings, + const json_char *json, + size_t length, + char *error); + + void json_value_free(json_value *); + + /* Not usually necessary, unless you used a custom mem_alloc and now want to + * use a custom mem_free. + */ + void json_value_free_ex(json_settings *settings, + json_value *); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/dist/index.js b/dist/index.js index 64a2560..d29915f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -125850,7 +125850,7 @@ exports.CopyleftPolicyCheck = void 0; const app_config_1 = __nccwpck_require__(29014); const policy_check_1 = __nccwpck_require__(63702); const result_service_1 = __nccwpck_require__(32414); -const markdown_util_1 = __nccwpck_require__(88623); +const markdown_utils_1 = __nccwpck_require__(96011); class CopyleftPolicyCheck extends policy_check_1.PolicyCheck { constructor() { super(`${app_config_1.CHECK_NAME}: Copyleft Policy`); @@ -125871,8 +125871,8 @@ class CopyleftPolicyCheck extends policy_check_1.PolicyCheck { } getSummary(components) { return components.length === 0 - ? '### :white_check_mark: Policy Pass \n ' + '#### ' + 'Not copyleft components were found' - : '### :x: Policy Fail \n' + '#### ' + components.length + ' component(s) with copyleft licenses were found'; + ? '### :white_check_mark: Policy Pass \n #### Not copyleft components were found' + : `### :x: Policy Fail \n #### ' + components.length + ' component(s) with copyleft licenses were found`; } getDetails(components) { if (components.length === 0) @@ -125885,7 +125885,7 @@ class CopyleftPolicyCheck extends policy_check_1.PolicyCheck { rows.push([component.purl, component.version, license.spdxid, `${license.url || ''}`, copyleftIcon]); }); }); - return (0, markdown_util_1.generateTable)(headers, rows); + return (0, markdown_utils_1.generateTable)(headers, rows); } } exports.CopyleftPolicyCheck = CopyleftPolicyCheck; @@ -126477,7 +126477,7 @@ exports.createCommentOnPR = createCommentOnPR; /***/ }), -/***/ 88623: +/***/ 96011: /***/ ((__unused_webpack_module, exports) => { "use strict"; diff --git a/src/policies/copyleft-policy-check.ts b/src/policies/copyleft-policy-check.ts index a1094a9..607b0a7 100644 --- a/src/policies/copyleft-policy-check.ts +++ b/src/policies/copyleft-policy-check.ts @@ -2,7 +2,7 @@ import { ScannerResults } from '../services/result.interfaces'; import { CHECK_NAME } from '../app.config'; import { PolicyCheck } from './policy-check'; import { Component, getComponents, getLicenses } from '../services/result.service'; -import { generateTable } from 'src/utils/markdown.util'; +import { generateTable } from '../utils/markdown.utils'; export class CopyleftPolicyCheck extends PolicyCheck { constructor() { @@ -30,8 +30,8 @@ export class CopyleftPolicyCheck extends PolicyCheck { private getSummary(components: Component[]): string { return components.length === 0 - ? '### :white_check_mark: Policy Pass \n ' + '#### ' + 'Not copyleft components were found' - : '### :x: Policy Fail \n' + '#### ' + components.length + ' component(s) with copyleft licenses were found'; + ? '### :white_check_mark: Policy Pass \n #### Not copyleft components were found' + : `### :x: Policy Fail \n #### ' + components.length + ' component(s) with copyleft licenses were found`; } private getDetails(components: Component[]): string { diff --git a/src/utils/markdown.util.ts b/src/utils/markdown.utils.ts similarity index 100% rename from src/utils/markdown.util.ts rename to src/utils/markdown.utils.ts