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 format = "setuptools";
51 pname = "semgrep";
52 inherit (common) version;
53 src = fetchFromGitHub {
54 owner = "semgrep";
55 repo = "semgrep";
56 rev = "v${version}";
57 hash = common.srcHash;
58 };
59
60 # prepare a subset of the submodules as we only need a handful
61 # and there are many many submodules total
62 postPatch =
63 (lib.concatStringsSep "\n" (
64 lib.mapAttrsToList (path: submodule: ''
65 # substitute ${path}
66 # remove git submodule placeholder
67 rm -r ${path}
68 # link submodule
69 ln -s ${submodule}/ ${path}
70 '') passthru.submodulesSubset
71 ))
72 + ''
73 cd cli
74 '';
75
76 # tell cli/setup.py to not copy semgrep-core into the result
77 # this means we can share a copy of semgrep-core and avoid an issue where it
78 # copies the binary but doesn't retain the executable bit
79 SEMGREP_SKIP_BIN = true;
80
81 pythonRelaxDeps = [
82 "boltons"
83 "glom"
84 ];
85
86 dependencies = [
87 attrs
88 boltons
89 colorama
90 click
91 click-option-group
92 glom
93 requests
94 rich
95 ruamel-yaml
96 tqdm
97 packaging
98 jsonschema
99 wcmatch
100 peewee
101 defusedxml
102 urllib3
103 typing-extensions
104 python-lsp-jsonrpc
105 tomli
106 opentelemetry-api
107 opentelemetry-sdk
108 opentelemetry-exporter-otlp-proto-http
109 opentelemetry-instrumentation-requests
110 ];
111
112 doCheck = true;
113
114 nativeCheckInputs = [
115 git
116 pytestCheckHook
117 flaky
118 pytest-snapshot
119 pytest-mock
120 pytest-freezegun
121 types-freezegun
122 ];
123
124 disabledTestPaths = [
125 "tests/default/e2e"
126 "tests/default/e2e-pysemgrep"
127 "tests/default/e2e-other"
128 ];
129
130 disabledTests = [
131 # requires networking
132 "test_send"
133 # requires networking
134 "test_parse_exclude_rules_auto"
135 # many child tests require networking to download files
136 "TestConfigLoaderForProducts"
137 # doesn't start flaky plugin correctly
138 "test_debug_performance"
139 # requires .git directory
140 "clean_project_url"
141 ];
142
143 preCheck = ''
144 # tests need a home directory
145 export HOME="$(mktemp -d)"
146
147 # tests need access to `semgrep-core`
148 export OLD_PATH="$PATH"
149 export PATH="$PATH:${semgrepBinPath}"
150 '';
151
152 postCheck = ''
153 export PATH="$OLD_PATH"
154 unset OLD_PATH
155 '';
156
157 # since we stop cli/setup.py from finding semgrep-core and copying it into
158 # the result we need to provide it on the PATH
159 preFixup = ''
160 makeWrapperArgs+=(--prefix PATH : ${semgrepBinPath})
161 '';
162
163 postInstall = ''
164 chmod +x $out/bin/{,py}semgrep
165 '';
166
167 passthru = {
168 inherit common semgrep-core;
169 submodulesSubset = lib.mapAttrs (k: args: fetchFromGitHub args) common.submodules;
170 updateScript = ./update.sh;
171 };
172
173 meta = common.meta // {
174 description = common.meta.description + " - cli";
175 inherit (semgrep-core.meta) platforms;
176 };
177}