diff --git a/src/csgrep.cc b/src/csgrep.cc index 0c0831a9..01d7c9f2 100644 --- a/src/csgrep.cc +++ b/src/csgrep.cc @@ -388,6 +388,54 @@ class DropScanProps: public GenericAbstractFilter { const TScanProps emp_; }; +class ScanPropSetter: public GenericAbstractFilter { + public: + ScanPropSetter(AbstractWriter *agent, const TStringList &propList); + + /// override specified scan properties + void setScanProps(const TScanProps &origProps) override; + + private: + // key/val pairs are stored in a vector + using TItem = std::pair; + using TList = std::vector; + TList itemList_; +}; + +ScanPropSetter::ScanPropSetter( + AbstractWriter *agent, + const TStringList &propList): + GenericAbstractFilter(agent) +{ + // iterate over the given NAME:VALUE strings + for (const std::string &str : propList) { + // split the string by the first occurrence of ':' + size_t ddAt = str.find(':'); + if (std::string::npos == ddAt) { + const auto msg = "missing ':' in " + str; + throw std::runtime_error(msg); + } + + // store the key/val pair into the vector + itemList_.emplace_back( + /* key */ str.substr(0, ddAt), + /* val */ str.substr(ddAt + 1)); + } +} + +void ScanPropSetter::setScanProps(const TScanProps &origProps) +{ + // we need to copy the given map + TScanProps props = origProps; + + // apply specified changes + for (const auto &item : itemList_) + props[item./* key */first] = item./* val */second; + + // forward the result + agent_->setScanProps(props); +} + class DuplicateFilter: public AbstractFilter { public: DuplicateFilter(AbstractWriter *agent): @@ -632,6 +680,7 @@ int main(int argc, char *argv[]) ("embed-context,U", po::value(), "embed a number of lines of context from the source file for the key event") ("prune-events", po::value(), "event is preserved if its verbosity level is below the given number") ("remove-duplicates,u", "remove defects that are not unique by their key event") + ("set-scan-prop", po::value(), "NAME:VALUE pair to override the specified scan property") ("strip-path-prefix", po::value(), "string prefix to strip from path (applied after all filters)") ("ignore-case,i", "ignore case when matching regular expressions") @@ -712,6 +761,11 @@ int main(int argc, char *argv[]) "strip-path-prefix")) return 1; + // insert ScanPropSetter into the chain if requested + if (!chainDecoratorGeneric(&eng, vm, + "set-scan-prop")) + return 1; + // chain all filters if (!chainFilters(&eng, vm)) // an error message already printed out diff --git a/tests/csgrep/97-sarif-set-tool-args.txt b/tests/csgrep/97-sarif-set-tool-args.txt new file mode 100644 index 00000000..9df6ddeb --- /dev/null +++ b/tests/csgrep/97-sarif-set-tool-args.txt @@ -0,0 +1 @@ +--mode=sarif --set-scan-prop=tool:shellcheck --set-scan-prop=tool-version:2.1 --set-scan-prop=tool-url:https://www.shellcheck.net/ diff --git a/tests/csgrep/97-sarif-set-tool-stdin.txt b/tests/csgrep/97-sarif-set-tool-stdin.txt new file mode 100644 index 00000000..10e96374 --- /dev/null +++ b/tests/csgrep/97-sarif-set-tool-stdin.txt @@ -0,0 +1,2 @@ +./contrib/guide/get_started/00-cleanup.sh:6:1: warning: Use 'cd ... || exit' or 'cd ... || return' in case cd fails. [SC2164] +./contrib/guide/get_started/12-datadir-create.sh:4:7: warning: When used with -p, -m only applies to the deepest directory. [SC2174] diff --git a/tests/csgrep/97-sarif-set-tool-stdout.txt b/tests/csgrep/97-sarif-set-tool-stdout.txt new file mode 100644 index 00000000..12c90685 --- /dev/null +++ b/tests/csgrep/97-sarif-set-tool-stdout.txt @@ -0,0 +1,130 @@ +{ + "$schema": "https://json.schemastore.org/sarif-2.1.0.json", + "version": "", + "inlineExternalProperties": [ + { + "externalizedProperties": { + "tool": "shellcheck", + "tool-url": "https://www.shellcheck.net/", + "tool-version": "2.1" + } + } + ], + "runs": [ + { + "tool": { + "driver": { + "name": "shellcheck", + "version": "", + "informationUri": "https://www.shellcheck.net/" + } + }, + "results": [ + { + "ruleId": "SHELLCHECK_WARNING: warning[SC2164]", + "level": "warning", + "locations": [ + { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "./contrib/guide/get_started/00-cleanup.sh" + }, + "region": { + "startLine": 6, + "startColumn": 1 + } + } + } + ], + "message": { + "text": "Use 'cd ... || exit' or 'cd ... || return' in case cd fails." + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "./contrib/guide/get_started/00-cleanup.sh" + }, + "region": { + "startLine": 6, + "startColumn": 1 + } + }, + "message": { + "text": "Use 'cd ... || exit' or 'cd ... || return' in case cd fails." + } + }, + "nestingLevel": 0, + "kinds": [ + "warning[SC2164]" + ] + } + ] + } + ] + } + ] + }, + { + "ruleId": "SHELLCHECK_WARNING: warning[SC2174]", + "level": "warning", + "locations": [ + { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "./contrib/guide/get_started/12-datadir-create.sh" + }, + "region": { + "startLine": 4, + "startColumn": 7 + } + } + } + ], + "message": { + "text": "When used with -p, -m only applies to the deepest directory." + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "id": 0, + "physicalLocation": { + "artifactLocation": { + "uri": "./contrib/guide/get_started/12-datadir-create.sh" + }, + "region": { + "startLine": 4, + "startColumn": 7 + } + }, + "message": { + "text": "When used with -p, -m only applies to the deepest directory." + } + }, + "nestingLevel": 0, + "kinds": [ + "warning[SC2174]" + ] + } + ] + } + ] + } + ] + } + ] + } + ] +} diff --git a/tests/csgrep/CMakeLists.txt b/tests/csgrep/CMakeLists.txt index 404041ca..a1e8d9b2 100644 --- a/tests/csgrep/CMakeLists.txt +++ b/tests/csgrep/CMakeLists.txt @@ -140,3 +140,4 @@ test_csgrep("93-csgrep-tool-predicate" ) test_csgrep("94-gcc-json" ) test_csgrep("95-gcc-sarif" ) test_csgrep("96-sarif-levels" ) +test_csgrep("97-sarif-set-tool" )