1{
2 lib,
3 callPackage,
4 fetchFromGitHub,
5 semgrep-core,
6 buildPythonPackage,
7
8 pytestCheckHook,
9 git,
10
11 # python packages
12 attrs,
13 boltons,
14 click,
15 click-option-group,
16 colorama,
17 defusedxml,
18 flaky,
19 glom,
20 jsonschema,
21 opentelemetry-api,
22 opentelemetry-exporter-otlp-proto-http,
23 opentelemetry-instrumentation-requests,
24 opentelemetry-sdk,
25 packaging,
26 peewee,
27 pytest-freezegun,
28 pytest-mock,
29 pytest-snapshot,
30 python-lsp-jsonrpc,
31 requests,
32 rich,
33 ruamel-yaml,
34 tomli,
35 tqdm,
36 types-freezegun,
37 typing-extensions,
38 urllib3,
39 wcmatch,
40}:
41
42# testing locally post build:
43# ./result/bin/semgrep scan --metrics=off --config 'r/generic.unicode.security.bidi.contains-bidirectional-characters'
44
45let
46 common = import ./common.nix { inherit lib; };
47 semgrepBinPath = lib.makeBinPath [ semgrep-core ];
48in
49buildPythonPackage rec {
50 pname = "semgrep";
51 inherit (common) version;
52 src = fetchFromGitHub {
53 owner = "semgrep";
54 repo = "semgrep";
55 rev = "v${version}";
56 hash = common.srcHash;
57 };
58
59 # prepare a subset of the submodules as we only need a handful
60 # and there are many many submodules total
61 postPatch =
62 (lib.concatStringsSep "\n" (
63 lib.mapAttrsToList (path: submodule: ''
64 # substitute ${path}
65 # remove git submodule placeholder
66 rm -r ${path}
67 # link submodule
68 ln -s ${submodule}/ ${path}
69 '') passthru.submodulesSubset
70 ))
71 + ''
72 cd cli
73 '';
74
75 # tell cli/setup.py to not copy semgrep-core into the result
76 # this means we can share a copy of semgrep-core and avoid an issue where it
77 # copies the binary but doesn't retain the executable bit
78 SEMGREP_SKIP_BIN = true;
79
80 pythonRelaxDeps = [
81 "boltons"
82 "glom"
83 ];
84
85 dependencies = [
86 attrs
87 boltons
88 colorama
89 click
90 click-option-group
91 glom
92 requests
93 rich
94 ruamel-yaml
95 tqdm
96 packaging
97 jsonschema
98 wcmatch
99 peewee
100 defusedxml
101 urllib3
102 typing-extensions
103 python-lsp-jsonrpc
104 tomli
105 opentelemetry-api
106 opentelemetry-sdk
107 opentelemetry-exporter-otlp-proto-http
108 opentelemetry-instrumentation-requests
109 ];
110
111 doCheck = true;
112
113 nativeCheckInputs = [
114 git
115 pytestCheckHook
116 flaky
117 pytest-snapshot
118 pytest-mock
119 pytest-freezegun
120 types-freezegun
121 ];
122
123 disabledTestPaths = [
124 "tests/default/e2e"
125 "tests/default/e2e-pysemgrep"
126 "tests/default/e2e-other"
127 ];
128
129 disabledTests = [
130 # requires networking
131 "test_send"
132 # requires networking
133 "test_parse_exclude_rules_auto"
134 # many child tests require networking to download files
135 "TestConfigLoaderForProducts"
136 # doesn't start flaky plugin correctly
137 "test_debug_performance"
138 # requires .git directory
139 "clean_project_url"
140 ];
141
142 preCheck = ''
143 # tests need a home directory
144 export HOME="$(mktemp -d)"
145
146 # tests need access to `semgrep-core`
147 export OLD_PATH="$PATH"
148 export PATH="$PATH:${semgrepBinPath}"
149 '';
150
151 postCheck = ''
152 export PATH="$OLD_PATH"
153 unset OLD_PATH
154 '';
155
156 # since we stop cli/setup.py from finding semgrep-core and copying it into
157 # the result we need to provide it on the PATH
158 preFixup = ''
159 makeWrapperArgs+=(--prefix PATH : ${semgrepBinPath})
160 '';
161
162 postInstall = ''
163 chmod +x $out/bin/{,py}semgrep
164 '';
165
166 passthru = {
167 inherit common semgrep-core;
168 submodulesSubset = lib.mapAttrs (k: args: fetchFromGitHub args) common.submodules;
169 updateScript = ./update.sh;
170 };
171
172 meta = common.meta // {
173 description = common.meta.description + " - cli";
174 inherit (semgrep-core.meta) platforms;
175 };
176}