guarddog 2.7.1__py3-none-any.whl → 2.8.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. guarddog/analyzer/metadata/__init__.py +3 -0
  2. guarddog/analyzer/metadata/pypi/repository_integrity_mismatch.py +53 -164
  3. guarddog/analyzer/metadata/repository_integrity_mismatch.py +202 -2
  4. guarddog/analyzer/metadata/resources/top_rubygems_packages.json +976 -0
  5. guarddog/analyzer/metadata/rubygems/__init__.py +26 -0
  6. guarddog/analyzer/metadata/rubygems/bundled_binary.py +13 -0
  7. guarddog/analyzer/metadata/rubygems/empty_information.py +24 -0
  8. guarddog/analyzer/metadata/rubygems/release_zero.py +22 -0
  9. guarddog/analyzer/metadata/rubygems/repository_integrity_mismatch.py +49 -0
  10. guarddog/analyzer/metadata/rubygems/typosquatting.py +140 -0
  11. guarddog/analyzer/metadata/utils.py +23 -0
  12. guarddog/analyzer/sourcecode/__init__.py +2 -0
  13. guarddog/analyzer/sourcecode/api-obfuscation.yml +35 -40
  14. guarddog/analyzer/sourcecode/code-execution.yml +20 -0
  15. guarddog/analyzer/sourcecode/exec-base64.yml +19 -0
  16. guarddog/analyzer/sourcecode/exfiltrate-sensitive-data.yml +31 -5
  17. guarddog/analyzer/sourcecode/npm-api-obfuscation.yml +51 -0
  18. guarddog/analyzer/sourcecode/rubygems-code-execution.yml +67 -0
  19. guarddog/analyzer/sourcecode/rubygems-exec-base64.yml +26 -0
  20. guarddog/analyzer/sourcecode/rubygems-exfiltrate-sensitive-data.yml +70 -0
  21. guarddog/analyzer/sourcecode/rubygems-install-hook.yml +45 -0
  22. guarddog/analyzer/sourcecode/rubygems-network-on-require.yml +78 -0
  23. guarddog/analyzer/sourcecode/rubygems-serialize-environment.yml +38 -0
  24. guarddog/ecosystems.py +3 -0
  25. guarddog/scanners/__init__.py +6 -0
  26. guarddog/scanners/rubygems_package_scanner.py +112 -0
  27. guarddog/scanners/rubygems_project_scanner.py +75 -0
  28. guarddog/scanners/scanner.py +34 -8
  29. guarddog-2.8.4.dist-info/METADATA +471 -0
  30. {guarddog-2.7.1.dist-info → guarddog-2.8.4.dist-info}/RECORD +35 -19
  31. {guarddog-2.7.1.dist-info → guarddog-2.8.4.dist-info}/WHEEL +1 -1
  32. guarddog-2.7.1.dist-info/METADATA +0 -40
  33. {guarddog-2.7.1.dist-info → guarddog-2.8.4.dist-info}/entry_points.txt +0 -0
  34. {guarddog-2.7.1.dist-info → guarddog-2.8.4.dist-info}/licenses/LICENSE +0 -0
  35. {guarddog-2.7.1.dist-info → guarddog-2.8.4.dist-info}/licenses/LICENSE-3rdparty.csv +0 -0
  36. {guarddog-2.7.1.dist-info → guarddog-2.8.4.dist-info}/licenses/NOTICE +0 -0
@@ -0,0 +1,471 @@
1
+ Metadata-Version: 2.4
2
+ Name: guarddog
3
+ Version: 2.8.4
4
+ Summary: GuardDog is a CLI tool for identifying malicious open source packages
5
+ License: Apache-2.0
6
+ License-File: LICENSE
7
+ License-File: LICENSE-3rdparty.csv
8
+ License-File: NOTICE
9
+ Author: Ellen Wang
10
+ Requires-Python: >=3.10,<4
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Requires-Dist: click (>=8.1.3,<9.0.0)
19
+ Requires-Dist: configparser (>=5.3,<8.0)
20
+ Requires-Dist: disposable-email-domains (>=0.0.103,<0.0.121)
21
+ Requires-Dist: prettytable (>=3.6.0,<4.0.0)
22
+ Requires-Dist: pygit2 (>=1.11,<1.19)
23
+ Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
24
+ Requires-Dist: python-whois (>=0.8,<0.10)
25
+ Requires-Dist: pyyaml (>=6.0,<7.0)
26
+ Requires-Dist: requests (>=2.29.0,<3.0.0)
27
+ Requires-Dist: semantic-version (>=2.10.0,<3.0.0)
28
+ Requires-Dist: semgrep (>=1.147.0,<2.0.0)
29
+ Requires-Dist: tarsafe (>=0.0.5,<0.0.6)
30
+ Requires-Dist: termcolor (>=2.1.0,<3.0.0)
31
+ Requires-Dist: urllib3 (>=2.5.0,<3.0.0)
32
+ Requires-Dist: yara-python (>=4.5.1,<5.0.0)
33
+ Project-URL: Repository, https://github.com/DataDog/guarddog
34
+ Description-Content-Type: text/markdown
35
+
36
+ # GuardDog
37
+
38
+ [![Test](https://github.com/DataDog/guarddog/actions/workflows/checks.yml/badge.svg)](https://github.com/DataDog/guarddog/actions/workflows/checks.yml)
39
+
40
+ <p align="center">
41
+ <img src="https://github.com/DataDog/guarddog/blob/main/docs/images/logo.png?raw=true" alt="GuardDog" width="300" />
42
+ </p>
43
+
44
+ GuardDog is a CLI tool that allows to identify malicious PyPI and npm packages, Go modules, RubyGems, GitHub actions, or VSCode extensions. It runs a set of heuristics on the package source code (through Semgrep rules) and on the package metadata.
45
+
46
+ GuardDog can be used to scan local or remote PyPI and npm packages, Go modules, RubyGems, GitHub actions, or VSCode extensions using any of the available [heuristics](#heuristics).
47
+
48
+ It downloads and scans code from:
49
+
50
+ * NPM: Packages hosted in [npmjs.org](https://www.npmjs.com/)
51
+ * PyPI: Source files (tar.gz) packages hosted in [PyPI.org](https://pypi.org/)
52
+ * Go: GoLang source files of repositories hosted in [GitHub.com](https://github.com)
53
+ * RubyGems: Gem packages hosted in [rubygems.org](https://rubygems.org/)
54
+ * GitHub Actions: Javascript source files of repositories hosted in [GitHub.com](https://github.com)
55
+ * VSCode Extensions: Extensions (.vsix) packages hosted in [marketplace.visualstudio.com](https://marketplace.visualstudio.com/)
56
+
57
+ ![GuardDog demo usage](https://github.com/DataDog/guarddog/blob/main/docs/images/demo.png?raw=true)
58
+
59
+ ## Getting started
60
+
61
+ ### Installation
62
+
63
+ ```sh
64
+ pip install guarddog
65
+ ```
66
+
67
+ Or use the Docker image:
68
+
69
+ ```sh
70
+ docker pull ghcr.io/datadog/guarddog
71
+ alias guarddog='docker run --rm ghcr.io/datadog/guarddog'
72
+ ```
73
+
74
+ *Note: On Windows, the only supported installation method is Docker.*
75
+
76
+ ### Sample usage
77
+
78
+ ```sh
79
+ # Scan the most recent version of the 'requests' package
80
+ guarddog pypi scan requests
81
+
82
+ # Scan a specific version of the 'requests' package
83
+ guarddog pypi scan requests --version 2.28.1
84
+
85
+ # Scan the 'request' package using 2 specific heuristics
86
+ guarddog pypi scan requests --rules exec-base64 --rules code-execution
87
+
88
+ # Scan the 'requests' package using all rules but one
89
+ guarddog pypi scan requests --exclude-rules exec-base64
90
+
91
+ # Scan a local package archive
92
+ guarddog pypi scan /tmp/triage.tar.gz
93
+
94
+ # Scan a local package directory
95
+ guarddog pypi scan /tmp/triage/
96
+
97
+ # Scan every package referenced in a requirements.txt file of a local folder
98
+ guarddog pypi verify workspace/guarddog/requirements.txt
99
+
100
+ # Scan every package referenced in a requirements.txt file and output a sarif file - works only for verify
101
+ guarddog pypi verify --output-format=sarif workspace/guarddog/requirements.txt
102
+
103
+ # Output JSON to standard output - works for every command
104
+ guarddog pypi scan requests --output-format=json
105
+
106
+ # All the commands also work on npm, go, rubygems
107
+ guarddog npm scan express
108
+
109
+ guarddog go scan github.com/DataDog/dd-trace-go
110
+
111
+ guarddog go verify /tmp/repo/go.mod
112
+
113
+ # Scan RubyGems packages
114
+ guarddog rubygems scan rails
115
+
116
+ guarddog rubygems verify /tmp/repo/Gemfile.lock
117
+
118
+ # Additionally can support scanning GitHub actions that are implemented in JavaScript
119
+ guarddog github_action scan DataDog/synthetics-ci-github-action
120
+
121
+ guarddog github_action verify /tmp/repo/.github/workflows/main.yml
122
+
123
+ # Scan VSCode extensions from the marketplace
124
+ guarddog extension scan ms-python.python
125
+
126
+ # Scan a specific version of a VSCode extension
127
+ guarddog extension scan ms-python.python --version 2023.20.0
128
+
129
+ # Scan a local VSCode extension directory or VSIX archive
130
+ guarddog extension scan /tmp/my-extension/
131
+
132
+ # Run in debug mode
133
+ guarddog --log-level debug npm scan express
134
+ ```
135
+
136
+
137
+ ## Heuristics
138
+
139
+ GuardDog comes with 2 types of heuristics:
140
+
141
+ * [**Source code heuristics**](https://github.com/DataDog/guarddog/tree/main/guarddog/analyzer/sourcecode): Semgrep rules running against the package source code.
142
+
143
+ * [**Package metadata heuristics**](https://github.com/DataDog/guarddog/tree/main/guarddog/analyzer/metadata): Python or Javascript heuristics running against the package metadata on PyPI or npm.
144
+
145
+ <!-- BEGIN_RULE_LIST -->
146
+ ### PyPI
147
+
148
+ Source code heuristics:
149
+
150
+ | **Heuristic** | **Description** |
151
+ |:-------------:|:---------------:|
152
+ | api-obfuscation | Identify obfuscated API calls using alternative Python syntax patterns |
153
+ | shady-links | Identify when a package contains an URL to a domain with a suspicious extension |
154
+ | obfuscation | Identify when a package uses a common obfuscation method often used by malware |
155
+ | clipboard-access | Identify when a package reads or write data from the clipboard |
156
+ | exfiltrate-sensitive-data | Identify when a package reads and exfiltrates sensitive data from the local system |
157
+ | download-executable | Identify when a package downloads and makes executable a remote binary |
158
+ | exec-base64 | Identify when a package dynamically executes base64-encoded code |
159
+ | silent-process-execution | Identify when a package silently executes an executable |
160
+ | dll-hijacking | Identifies when a malicious package manipulates a trusted application into loading a malicious DLL |
161
+ | steganography | Identify when a package retrieves hidden data from an image and executes it |
162
+ | code-execution | Identify when an OS command is executed in the setup.py file |
163
+ | unicode | Identify suspicious unicode characters |
164
+ | cmd-overwrite | Identify when the 'install' command is overwritten in setup.py, indicating a piece of code automatically running when the package is installed |
165
+ | suspicious_passwd_access_linux | Detects suspicious read access to /etc/passwd file, which is often targeted by malware for credential harvesting |
166
+
167
+ Metadata heuristics:
168
+
169
+ | **Heuristic** | **Description** |
170
+ |:-------------:|:---------------:|
171
+ | empty_information | Identify packages with an empty description field |
172
+ | release_zero | Identify packages with an release version that's 0.0 or 0.0.0 |
173
+ | typosquatting | Identify packages that are named closely to an highly popular package |
174
+ | potentially_compromised_email_domain | Identify when a package maintainer e-mail domain (and therefore package manager account) might have been compromised |
175
+ | unclaimed_maintainer_email_domain | Identify when a package maintainer e-mail domain (and therefore npm account) is unclaimed and can be registered by an attacker |
176
+ | repository_integrity_mismatch | Identify packages with a linked GitHub repository where the package has extra unexpected files |
177
+ | single_python_file | Identify packages that have only a single Python file |
178
+ | bundled_binary | Identify packages bundling binaries |
179
+ | deceptive_author | This heuristic detects when an author is using a disposable email |
180
+
181
+
182
+ ### npm
183
+
184
+ Source code heuristics:
185
+
186
+ | **Heuristic** | **Description** |
187
+ |:-------------:|:---------------:|
188
+ | npm-serialize-environment | Identify when a package serializes 'process.env' to exfiltrate environment variables |
189
+ | npm-obfuscation | Identify when a package uses a common obfuscation method often used by malware |
190
+ | npm-silent-process-execution | Identify when a package silently executes an executable |
191
+ | shady-links | Identify when a package contains an URL to a domain with a suspicious extension |
192
+ | npm-exec-base64 | Identify when a package dynamically executes code through 'eval' |
193
+ | npm-install-script | Identify when a package has a pre or post-install script automatically running commands |
194
+ | npm-steganography | Identify when a package retrieves hidden data from an image and executes it |
195
+ | npm-dll-hijacking | Identifies when a malicious package manipulates a trusted application into loading a malicious DLL |
196
+ | npm-exfiltrate-sensitive-data | Identify when a package reads and exfiltrates sensitive data from the local system |
197
+ | suspicious_passwd_access_linux | Detects suspicious read access to /etc/passwd file, which is often targeted by malware for credential harvesting |
198
+
199
+ Metadata heuristics:
200
+
201
+ | **Heuristic** | **Description** |
202
+ |:-------------:|:---------------:|
203
+ | empty_information | Identify packages with an empty description field |
204
+ | release_zero | Identify packages with an release version that's 0.0 or 0.0.0 |
205
+ | potentially_compromised_email_domain | Identify when a package maintainer e-mail domain (and therefore package manager account) might have been compromised; note that NPM's API may not provide accurate information regarding the maintainer's email, so this detector may cause false positives for NPM packages. see https://www.theregister.com/2022/05/10/security_npm_email/ |
206
+ | unclaimed_maintainer_email_domain | Identify when a package maintainer e-mail domain (and therefore npm account) is unclaimed and can be registered by an attacker; note that NPM's API may not provide accurate information regarding the maintainer's email, so this detector may cause false positives for NPM packages. see https://www.theregister.com/2022/05/10/security_npm_email/ |
207
+ | typosquatting | Identify packages that are named closely to an highly popular package |
208
+ | direct_url_dependency | Identify packages with direct URL dependencies. Dependencies fetched this way are not immutable and can be used to inject untrusted code or reduce the likelihood of a reproducible install. |
209
+ | npm_metadata_mismatch | Identify packages which have mismatches between the npm package manifest and the package info for some critical fields |
210
+ | bundled_binary | Identify packages bundling binaries |
211
+ | deceptive_author | This heuristic detects when an author is using a disposable email |
212
+
213
+
214
+ ### go
215
+
216
+ Source code heuristics:
217
+
218
+ | **Heuristic** | **Description** |
219
+ |:-------------:|:---------------:|
220
+ | shady-links | Identify when a package contains an URL to a domain with a suspicious extension |
221
+ | go-exec-base64 | Identify Base64-decoded content being passed to execution functions in Go |
222
+ | go-exfiltrate-sensitive-data | This rule identifies when a package reads and exfiltrates sensitive data from the local system. |
223
+ | go-exec-download | This rule downloads and executes a remote binary after setting executable permissions. |
224
+ | suspicious_passwd_access_linux | Detects suspicious read access to /etc/passwd file, which is often targeted by malware for credential harvesting |
225
+
226
+ Metadata heuristics:
227
+
228
+ | **Heuristic** | **Description** |
229
+ |:-------------:|:---------------:|
230
+ | typosquatting | Identify packages that are named closely to an highly popular package |
231
+
232
+
233
+ ### GitHub Action
234
+
235
+ Source code heuristics:
236
+
237
+ | **Heuristic** | **Description** |
238
+ |:-------------:|:---------------:|
239
+ | npm-serialize-environment | Identify when a package serializes 'process.env' to exfiltrate environment variables |
240
+ | npm-obfuscation | Identify when a package uses a common obfuscation method often used by malware |
241
+ | npm-silent-process-execution | Identify when a package silently executes an executable |
242
+ | shady-links | Identify when a package contains an URL to a domain with a suspicious extension |
243
+ | npm-exec-base64 | Identify when a package dynamically executes code through 'eval' |
244
+ | npm-install-script | Identify when a package has a pre or post-install script automatically running commands |
245
+ | npm-steganography | Identify when a package retrieves hidden data from an image and executes it |
246
+ | npm-dll-hijacking | Identifies when a malicious package manipulates a trusted application into loading a malicious DLL |
247
+ | npm-exfiltrate-sensitive-data | Identify when a package reads and exfiltrates sensitive data from the local system |
248
+ | suspicious_passwd_access_linux | Detects suspicious read access to /etc/passwd file, which is often targeted by malware for credential harvesting |
249
+ ### Extension
250
+
251
+ Source code heuristics:
252
+
253
+ | **Heuristic** | **Description** |
254
+ |:-------------:|:---------------:|
255
+ | npm-serialize-environment | Identify when a package serializes 'process.env' to exfiltrate environment variables |
256
+ | npm-obfuscation | Identify when a package uses a common obfuscation method often used by malware |
257
+ | npm-silent-process-execution | Identify when a package silently executes an executable |
258
+ | shady-links | Identify when a package contains an URL to a domain with a suspicious extension |
259
+ | npm-exec-base64 | Identify when a package dynamically executes code through 'eval' |
260
+ | npm-install-script | Identify when a package has a pre or post-install script automatically running commands |
261
+ | npm-steganography | Identify when a package retrieves hidden data from an image and executes it |
262
+ | npm-dll-hijacking | Identifies when a malicious package manipulates a trusted application into loading a malicious DLL |
263
+ | npm-exfiltrate-sensitive-data | Identify when a package reads and exfiltrates sensitive data from the local system |
264
+ | suspicious_passwd_access_linux | Detects suspicious read access to /etc/passwd file, which is often targeted by malware for credential harvesting |
265
+ ### RubyGems
266
+
267
+ Source code heuristics:
268
+
269
+ | **Heuristic** | **Description** |
270
+ |:-------------:|:---------------:|
271
+ | rubygems-code-execution | Identify when a gem executes OS commands |
272
+ | rubygems-exfiltrate-sensitive-data | Identify when a package reads and exfiltrates sensitive data from the local system |
273
+ | rubygems-serialize-environment | Identify when a package serializes ENV to exfiltrate environment variables |
274
+ | rubygems-network-on-require | Identify when a gem makes network requests when required |
275
+ | rubygems-install-hook | Identify when a gem registers installation hooks |
276
+ | rubygems-exec-base64 | Identify when a package dynamically executes base64-encoded code |
277
+ | suspicious_passwd_access_linux | Detects suspicious read access to /etc/passwd file, which is often targeted by malware for credential harvesting |
278
+
279
+ Metadata heuristics:
280
+
281
+ | **Heuristic** | **Description** |
282
+ |:-------------:|:---------------:|
283
+ | typosquatting | Identify packages that are named closely to an highly popular package |
284
+ | empty_information | Identify packages with an empty description field |
285
+ | release_zero | Identify packages with an release version that's 0.0 or 0.0.0 |
286
+ | bundled_binary | Identify packages bundling binaries |
287
+ | repository_integrity_mismatch | Identify packages with a linked GitHub repository where the package has extra unexpected files |
288
+
289
+
290
+ <!-- END_RULE_LIST -->
291
+
292
+ ## Custom Rules
293
+
294
+ Guarddog allows to implement custom sourcecode rules.
295
+ Sourcecode rules live under the [guarddog/analyzer/sourcecode](guarddog/analyzer/sourcecode) directory, and supported formats are [Semgrep](https://github.com/semgrep/semgrep) or [Yara](https://github.com/VirusTotal/yara).
296
+
297
+ * Semgrep rules are language-dependent, and Guarddog will import all `.yml` rules where the language matches the ecosystem selected by the user in CLI.
298
+ * Yara rules on the other hand are language agnostic, therefore all matching `.yar` rules present will be imported.
299
+
300
+ Is possible then to write your own rule and drop it into that directory, Guarddog will allow you to select it or exclude it as any built-in rule as well as appending the findings to its output.
301
+
302
+ For example, you can create the following semgrep rule:
303
+ ```yaml
304
+ rules:
305
+ - id: sample-rule
306
+ languages:
307
+ - python
308
+ message: Output message when rule matches
309
+ metadata:
310
+ description: Description used in the CLI help
311
+ patterns:
312
+ YOUR RULE HEURISTICS GO HERE
313
+ severity: WARNING
314
+ ```
315
+
316
+ Then you'll need to save it as `sample-rule.yml` and note that the id must match the filename
317
+
318
+ In the case of Yara, you can create the following rule:
319
+ ```
320
+ rule sample-rule
321
+ {
322
+ meta:
323
+ description = "Description used in the output message"
324
+ target_entity = "file"
325
+ strings:
326
+ $exec = "exec"
327
+ condition:
328
+ 1 of them
329
+ }
330
+ ```
331
+ Then you'll need to save it as `sample-rule.yar`.
332
+
333
+ Note that in both cases, the rule id must match the filename
334
+
335
+ ## Running GuardDog in a GitHub Action
336
+
337
+ The easiest way to integrate GuardDog in your CI pipeline is to leverage the SARIF output format, and upload it to GitHub's [code scanning](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning) feature.
338
+
339
+ Using this, you get:
340
+ * Automated comments to your pull requests based on the GuardDog scan output
341
+ * Built-in false positive management directly in the GitHub UI
342
+
343
+
344
+ Sample GitHub Action using GuardDog:
345
+
346
+ ```yaml
347
+ name: GuardDog
348
+
349
+ on:
350
+ push:
351
+ branches:
352
+ - main
353
+ pull_request:
354
+ branches:
355
+ - main
356
+
357
+ permissions:
358
+ contents: read
359
+
360
+ jobs:
361
+ guarddog:
362
+ permissions:
363
+ contents: read # for actions/checkout to fetch code
364
+ security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
365
+ name: Scan dependencies
366
+ runs-on: ubuntu-latest
367
+
368
+ steps:
369
+ - uses: actions/checkout@v4
370
+
371
+ - name: Set up Python
372
+ uses: actions/setup-python@v5
373
+ with:
374
+ python-version: "3.10"
375
+
376
+ - name: Install GuardDog
377
+ run: pip install guarddog
378
+
379
+ - run: guarddog pypi verify requirements.txt --output-format sarif --exclude-rules repository_integrity_mismatch > guarddog.sarif
380
+
381
+ - name: Upload SARIF file to GitHub
382
+ uses: github/codeql-action/upload-sarif@v3
383
+ with:
384
+ category: guarddog-builtin
385
+ sarif_file: guarddog.sarif
386
+ ```
387
+
388
+
389
+ ## Development
390
+
391
+ ### Running a local version of GuardDog
392
+
393
+ * Ensure poetry has an env with `python >=3.10` `poetry env use 3.10.0`
394
+ * Install dependencies `poetry install`
395
+ * Run guarddog `poetry run guarddog` or `poetry shell` then run `guarddog`
396
+
397
+ ### Unit tests
398
+
399
+ Running all unit tests: `make test`
400
+
401
+ Running unit tests against Semgrep rules: `make test-semgrep-rules` (tests are [here](https://github.com/DataDog/guarddog/tree/main/tests/analyzer/sourcecode)). These use the standard methodology for [testing Semgrep rules](https://semgrep.dev/docs/writing-rules/testing-rules/).
402
+
403
+ Running unit tests against package metadata heuristics: `make test-metadata-rules` (tests are [here](https://github.com/DataDog/guarddog/tree/main/tests/analyzer/metadata)).
404
+
405
+ ### Benchmarking
406
+
407
+ You can run GuardDog on legitimate and malicious packages to determine false positives and false negatives. See [./tests/samples](./tests/samples)
408
+
409
+ ### Code quality checks
410
+
411
+ Run the type checker with
412
+ ```shell
413
+ mypy --install-types --non-interactive guarddog
414
+ ```
415
+ and the linter with
416
+ ```shell
417
+ flake8 guarddog --count --select=E9,F63,F7,F82 --show-source --statistics --exclude tests/analyzer/sourcecode,tests/analyzer/metadata/resources,evaluator/data
418
+ flake8 guarddog --count --max-line-length=120 --statistics --exclude tests/analyzer/sourcecode,tests/analyzer/metadata/resources,evaluator/data --ignore=E203,W503
419
+ ```
420
+
421
+ ### Configuration via Environment Variables
422
+
423
+ GuardDog's behavior can be customized using environment variables:
424
+
425
+ #### General Configuration
426
+
427
+ | Environment Variable | Description | Default Value |
428
+ |---------------------|-------------|---------------|
429
+ | `GUARDDOG_PARALLELISM` | Number of threads to use for parallel processing | Number of CPUs available |
430
+ | `GUARDDOG_VERIFY_EXHAUSTIVE_DEPENDENCIES` | Analyze all possible versions of dependencies (`true`/`false`) | `false` |
431
+ | `GUARDDOG_TOP_PACKAGES_CACHE_LOCATION` | Location of the top packages cache directory | `guarddog/analyzer/metadata/resources` |
432
+ | `GUARDDOG_YARA_EXT_EXCLUDE` | Comma-separated list of file extensions to exclude from YARA scanning | `ini,md,rst,txt,lock,json,yaml,yml,toml,xml,html,csv,sql,pdf,doc,docx,ppt,pptx,xls,xlsx,odt,changelog,readme,makefile,dockerfile,pkg-info,d.ts` |
433
+
434
+ #### Semgrep Configuration
435
+
436
+ GuardDog uses `Semgrep`, a powerful static analysis tool that scans code for patterns.
437
+
438
+ | Environment Variable | Description | Default Value |
439
+ |---------------------|-------------|---------------|
440
+ | `GUARDDOG_SEMGREP_MAX_TARGET_BYTES` | Maximum size of a file that Semgrep will analyze (files exceeding this will be skipped) | 10MB (10485760 bytes) |
441
+ | `GUARDDOG_SEMGREP_TIMEOUT` | Maximum time in seconds that Semgrep will spend running a rule on a single file | 10 seconds |
442
+
443
+ #### Archive Extraction Security Limits
444
+
445
+ GuardDog implements multiple security checks when extracting package archives to protect against compression bombs and file descriptor exhaustion attacks:
446
+
447
+ | Environment Variable | Description | Default Value |
448
+ |---------------------|-------------|---------------|
449
+ | `GUARDDOG_MAX_UNCOMPRESSED_SIZE` | Maximum allowed uncompressed size in bytes (prevents disk space exhaustion) | 2147483648 (2 GB) |
450
+ | `GUARDDOG_MAX_COMPRESSION_RATIO` | Maximum allowed compression ratio (detects suspicious compression patterns) | 100 (100:1) |
451
+ | `GUARDDOG_MAX_FILE_COUNT` | Maximum number of files allowed in an archive (prevents file descriptor/inode exhaustion) | 100000 |
452
+
453
+ ## Maintainers
454
+
455
+ * [Sebastian Obregoso](https://www.linkedin.com/in/sebastianobregoso/)
456
+ * [Ian Kretz](https://github.com/ikretz)
457
+ * [Tesnim Hamdouni](https://github.com/tesnim5hamdouni)
458
+
459
+ ## Authors
460
+ * [Ellen Wang](https://www.linkedin.com/in/ellen-wang-4bb5961a0/)
461
+ * [Christophe Tafani-Dereeper](https://github.com/christophetd)
462
+
463
+ ## Acknowledgments
464
+
465
+ Inspiration:
466
+ * [Backstabber’s Knife Collection: A Review of Open Source Software Supply Chain Attacks](https://arxiv.org/pdf/2005.09535)
467
+ * [What are Weak Links in the npm Supply Chain?](https://arxiv.org/pdf/2112.10165.pdf)
468
+ * [A Survey on Common Threats in npm and PyPi Registries](https://arxiv.org/pdf/2108.09576.pdf)
469
+ * [A Benchmark Comparison of Python Malware Detection Approaches](https://arxiv.org/pdf/2209.13288.pdf)
470
+ * [Towards Measuring Supply Chain Attacks on Package Managers for Interpreted Languages](https://arxiv.org/pdf/2002.01139)
471
+
@@ -2,7 +2,7 @@ guarddog/__init__.py,sha256=reb53KZG9b1nFmsDxj2fropaOceOCyM9bVMUdmZ2wS8,227
2
2
  guarddog/__main__.py,sha256=GEdfW6I6g2c3H7bS0G43E4C-g7kXGUswzDCPFSwPgHY,246
3
3
  guarddog/analyzer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  guarddog/analyzer/analyzer.py,sha256=eeWbazqGWFJBeT_OHHmEndH3hG_6PMxUajof6T9jutM,15413
5
- guarddog/analyzer/metadata/__init__.py,sha256=tQTwWanifLsxfCdXIytPCO3chEIiTZ583uqKiQXQOog,855
5
+ guarddog/analyzer/metadata/__init__.py,sha256=4EOtQoMW1T_OX55qapNA2zzwvROO2zOiN4mjvloAW2U,1003
6
6
  guarddog/analyzer/metadata/bundled_binary.py,sha256=Tfgbc-exhbfvYjpgFH_Aa5KtT4ugJhrTV9SavZw1pHs,2594
7
7
  guarddog/analyzer/metadata/deceptive_author.py,sha256=CLwntpSNBO4Bji3IEw2lctvNCMLiOxz0pG7KSEzIynM,2811
8
8
  guarddog/analyzer/metadata/detector.py,sha256=dFhmoPVtxoed-Lz3Bd8GXZhorOVajvo5sIl9Iw8oCOM,641
@@ -28,32 +28,40 @@ guarddog/analyzer/metadata/pypi/deceptive_author.py,sha256=KRbi7xfGYnEiq0p5HFazj
28
28
  guarddog/analyzer/metadata/pypi/empty_information.py,sha256=Ppaa_aEIlFJ5VpRtcm2ozlBoRHrTs6CWpPyh82sTM7g,814
29
29
  guarddog/analyzer/metadata/pypi/potentially_compromised_email_domain.py,sha256=8zncGNsyfhWe04HRDF54rfP8y--_6l9ze-F-gH97pWo,1774
30
30
  guarddog/analyzer/metadata/pypi/release_zero.py,sha256=UNUAFeB34B88N0LRe-tnmoZ3Y4x4AVZbe7m0i9Q3W7U,789
31
- guarddog/analyzer/metadata/pypi/repository_integrity_mismatch.py,sha256=RB-Wf5Cbuh8KswkcCCHk7BVWvmOJccdHyb4mBjxiLhk,11903
31
+ guarddog/analyzer/metadata/pypi/repository_integrity_mismatch.py,sha256=yW7TPpA-g5XNAhiDtijYiBFhOo6ilBLseuJdwvIMRHI,7670
32
32
  guarddog/analyzer/metadata/pypi/single_python_file.py,sha256=L-YlmlP1TYA9XBeTHBPfECWgVIPTenUWRRnqwCMyh-o,1402
33
33
  guarddog/analyzer/metadata/pypi/typosquatting.py,sha256=Bzx_vjIiuugeRdyR-ABg7S-6J7Udm7stM8CUU8WUafg,6042
34
34
  guarddog/analyzer/metadata/pypi/unclaimed_maintainer_email_domain.py,sha256=zfT0qTyN83O-7Yevc6tYIjmCAgh8Y_dhE6oZlKdNmm0,421
35
35
  guarddog/analyzer/metadata/pypi/utils.py,sha256=UtG2JVep8bSOMz5LkrhXqS5Oy7Na19nHVct4IQMsQik,177
36
36
  guarddog/analyzer/metadata/release_zero.py,sha256=F0I8coYivya7zns0XI1xNY4LLtTDQXoBUmze1wjwW4g,439
37
- guarddog/analyzer/metadata/repository_integrity_mismatch.py,sha256=WGvck9JV2iCB8xaOc6X5cEGiu59juSWFfwbf6uEah3E,792
37
+ guarddog/analyzer/metadata/repository_integrity_mismatch.py,sha256=R77YB2ANTALGfS8jbe7KhLJ3a3U_uPQV6VqgzFELEwM,7586
38
38
  guarddog/analyzer/metadata/resources/placeholder_email_domains.txt,sha256=o3mm9u6vuaVeN4wRgDTidR5oL6ufLTCrE9ISVYbOGUc,11
39
39
  guarddog/analyzer/metadata/resources/top_go_packages.json,sha256=HHOTcuWTGqlpXDOUgF7ejgmr8sGF_T5l7NQYdXmHcKQ,104044
40
40
  guarddog/analyzer/metadata/resources/top_npm_packages.json,sha256=eeqVkFNW8ltYcGbjAJBzZrdxBEKezxa6AVVYoEpFazs,192960
41
41
  guarddog/analyzer/metadata/resources/top_pypi_packages.json,sha256=hDQZUuG6BS4h7yNTAQ191l8_N6jaqezO9n2vdsZPKhA,1474298
42
+ guarddog/analyzer/metadata/resources/top_rubygems_packages.json,sha256=75GrX0mB_nnH-0reUQYdOvTsduELrb63yX6xvHwoSmM,20152
43
+ guarddog/analyzer/metadata/rubygems/__init__.py,sha256=DHLvlpbRdynWCIHG2caDEa3f7q0I8WsfbmrlTe-fmwM,947
44
+ guarddog/analyzer/metadata/rubygems/bundled_binary.py,sha256=eOeZXDAoDuwhUfB9W5CesnMWyVpR6BePPzNkGRKZqkc,397
45
+ guarddog/analyzer/metadata/rubygems/empty_information.py,sha256=8Dxa0Y8tbcv7lV3d3LUj_QO97lpUq2kTTY2JhQE2kw8,700
46
+ guarddog/analyzer/metadata/rubygems/release_zero.py,sha256=7rk1vxp6OxJkBTOD9kOYEEPLE7YgbApFbOVhjECnIgw,671
47
+ guarddog/analyzer/metadata/rubygems/repository_integrity_mismatch.py,sha256=pFNMdT0VpiHL6kEkj_2eOH0BwLCbQT2XLqyWJY67tr4,1582
48
+ guarddog/analyzer/metadata/rubygems/typosquatting.py,sha256=k9xu8mdAiyNFEGmWFgSql-E-fjch6rS6CXSObQ3G4-c,4745
42
49
  guarddog/analyzer/metadata/typosquatting.py,sha256=6xmqsB0oKwrsXfTJ9DE1z8-nUW8ukgk1ZSS32iJmapk,4587
43
50
  guarddog/analyzer/metadata/unclaimed_maintainer_email_domain.py,sha256=e-K9mSdph3y33fP_W7LNOlC7AnUVk28a1VfQJtG9vxo,2375
44
- guarddog/analyzer/metadata/utils.py,sha256=li7AGB8c_G4ytX0MvvyzVTFNPneK78uMp1h-pT__2qE,1772
45
- guarddog/analyzer/sourcecode/__init__.py,sha256=031VVi-DqTHxeYiI2mf2AuI76GaNUUyra_t0pRVqo5k,4631
46
- guarddog/analyzer/sourcecode/api-obfuscation.yml,sha256=y_m6PSh8CfF6nxMulj2Yx4XYxS1T5OO0Eos9WJiDR74,2137
51
+ guarddog/analyzer/metadata/utils.py,sha256=lMzwC41_-XuUa4d6E5AMyX8XZgXqrQD_gmpQCHrIzXI,2458
52
+ guarddog/analyzer/sourcecode/__init__.py,sha256=_xt-xn2lfpu-iQhe853eTbbTSN8ULxTutyYiBQ97NtM,4723
53
+ guarddog/analyzer/sourcecode/api-obfuscation.yml,sha256=bDfoX5UQ1a7Za-W2WEzrIQTL22_9mi2Sea4BU4NFABk,1813
47
54
  guarddog/analyzer/sourcecode/clipboard-access.yml,sha256=B36E7xKtAVgwZ29UWtvZa1AJcyfrhvehbLo6tlJqffk,524
48
55
  guarddog/analyzer/sourcecode/cmd-overwrite.yml,sha256=l-tE3_G-LqCuCZnHab6v0PpCdMpoHPutBYcijeMZEA0,682
49
- guarddog/analyzer/sourcecode/code-execution.yml,sha256=YyWBMhcXGzrM6JbXzRTBBFCs7bnoNGPFJJ_FIV2OYtc,5028
56
+ guarddog/analyzer/sourcecode/code-execution.yml,sha256=YGsPOxR51OkEU1xjeAg-vTXu5CyGmFefpbsBBhjAfro,5942
50
57
  guarddog/analyzer/sourcecode/dll-hijacking.yml,sha256=_lkYp0P4545aiGazC5lRBeCcMHhGWzaK-95zu5MfRLY,3721
51
58
  guarddog/analyzer/sourcecode/download-executable.yml,sha256=VuSNkpVh3DxHG7wfep3eAErGsOY9EL_268sNULYbfW4,3361
52
- guarddog/analyzer/sourcecode/exec-base64.yml,sha256=Wg1jI_ff9I58Xq8gt8wXOQMrwHcPnzkAPyAURxnKHgw,2371
53
- guarddog/analyzer/sourcecode/exfiltrate-sensitive-data.yml,sha256=hUxQEsJ4qF_25oMF8pdzAFOzq59m6k28WKz280uyaMg,2264
59
+ guarddog/analyzer/sourcecode/exec-base64.yml,sha256=ohXfoEjjVK0mlPIht82qOWoBi1U9vHL0RD0zguiaM7s,3369
60
+ guarddog/analyzer/sourcecode/exfiltrate-sensitive-data.yml,sha256=Z5pcADXvLtrHsDvhoH0AjHEnYkLVu0UU6UBvJID99RY,3383
54
61
  guarddog/analyzer/sourcecode/go-exec-base64.yml,sha256=Y5TUfLrmU1e5FTYW2zRKwn8yluBARHSXPr6Mr5vMVOY,1554
55
62
  guarddog/analyzer/sourcecode/go-exec-download.yml,sha256=ZaZOvn3Xojsd2m8MQGLW1H7p28bPdpEbmDd37q2ZiX4,2931
56
63
  guarddog/analyzer/sourcecode/go-exfiltrate-sensitive-data.yml,sha256=sb5GI-523zgE1nxNCrnRVjBSeOp7IfPy7qTQPBJMkco,3697
64
+ guarddog/analyzer/sourcecode/npm-api-obfuscation.yml,sha256=-0HwYCO8HHaEwuUeGw9q7BAxvXrCKgz8Fs40mJ_6G4M,3641
57
65
  guarddog/analyzer/sourcecode/npm-dll-hijacking.yml,sha256=1TvI6UtCGCOMy4Ii-kM_oICYbMRGeOYdgXrG7-zmJ_Y,3460
58
66
  guarddog/analyzer/sourcecode/npm-exec-base64.yml,sha256=zc5w2FTlHoZ7ot1flzlmYBkQu1I8eG1E63S5Aki7Goc,814
59
67
  guarddog/analyzer/sourcecode/npm-exfiltrate-sensitive-data.yml,sha256=UYWXdkAab-dg_6UwVjiauHmy-9nlKiF86qcyxAwUoXg,3488
@@ -63,19 +71,25 @@ guarddog/analyzer/sourcecode/npm-serialize-environment.yml,sha256=gFpr58INp44Zwx
63
71
  guarddog/analyzer/sourcecode/npm-silent-process-execution.yml,sha256=qnJHGesNPNpxGa8n2kQMpttLGck-6vZjI_SsweDyk7M,3513
64
72
  guarddog/analyzer/sourcecode/npm-steganography.yml,sha256=XH0udcriAQq_6WOHAG4TpIedw8GgKyWx9gsG_Q_Fki8,915
65
73
  guarddog/analyzer/sourcecode/obfuscation.yml,sha256=dp0BeCYShcTS8QiijSa9U53r6jkCjrFBW5jjNVoXdUU,1224
74
+ guarddog/analyzer/sourcecode/rubygems-code-execution.yml,sha256=DDNk2qtomXlm3oGPZkrYxSM8cz5bz4vFqCGLEQNCo8s,2123
75
+ guarddog/analyzer/sourcecode/rubygems-exec-base64.yml,sha256=GVOD_UrTkCnyxLjb42hzUy8p8XTbIiIVKqH32ySLeZU,891
76
+ guarddog/analyzer/sourcecode/rubygems-exfiltrate-sensitive-data.yml,sha256=Tup4P4H4wIrvZoM84_Ew8lsQmSqjewep_OYWKwPtUF4,2293
77
+ guarddog/analyzer/sourcecode/rubygems-install-hook.yml,sha256=sjv3YXeERrZDaTu0pS28rl_B8z5BAMjohntzVLE6Fm8,1636
78
+ guarddog/analyzer/sourcecode/rubygems-network-on-require.yml,sha256=kmuzYXcuPvarKSl5V5k5CBoPSeuvsLdFaf2_-GHYYmo,2095
79
+ guarddog/analyzer/sourcecode/rubygems-serialize-environment.yml,sha256=qnZaV-aj9-eSZJeeF6XCi5JrnKkXNqj9xSqGjqP6AAY,1329
66
80
  guarddog/analyzer/sourcecode/shady-links.yml,sha256=H-QdBfK30PK9JRWJXk2SlFFiSSkMkuKZF0mWoCjwQ5w,3222
67
81
  guarddog/analyzer/sourcecode/silent-process-execution.yml,sha256=b6RjenMv7si7lXGak3uMmD7PMtQRuKPeJFggPW6UDNI,418
68
82
  guarddog/analyzer/sourcecode/steganography.yml,sha256=3ceO6SJhu4XpZEjfwelLdOxeZ4Ho1OgUjbcacwtOhR0,606
69
83
  guarddog/analyzer/sourcecode/suspicious_passwd_access_linux.yar,sha256=kplidsJ-ctg6W58VlYtLq10saZbcD1pm5_Xh4sqmHwk,422
70
84
  guarddog/analyzer/sourcecode/unicode.yml,sha256=7fAygEtYwJ1iNKsyCjmLAEu15CLMWApfWXx_t_W3sOA,5596
71
85
  guarddog/cli.py,sha256=Pk4WUD5a_TlPRpq2G4v_6FDGWu8IriXQPQ_ft8RXm5o,10692
72
- guarddog/ecosystems.py,sha256=I1XPAhPuv7OnfZT3z0xcgEecUY1tFJdrklV07sMYffg,582
86
+ guarddog/ecosystems.py,sha256=AMbuD6gJSRda0_bSuvqXoaAQ6Vp_MlOwX4wpLgMUKzs,671
73
87
  guarddog/reporters/__init__.py,sha256=lHNa5ZDsaIpjzS7SmheD5_GGAimGitXU-DNk-Wn97bI,749
74
88
  guarddog/reporters/human_readable.py,sha256=WEyjOPdBE8adxC-tdFgwxcyDijsppLk4gIiZOUO69O0,4548
75
89
  guarddog/reporters/json.py,sha256=gpbucxGoXBA6s7fNRzhQwZ4P6gWyz7BowsmQrnm4x6U,802
76
90
  guarddog/reporters/reporter_factory.py,sha256=JUagC2UFkN2TZGpZIkI1MwMHEbwT9Ja1goQP95-k9SM,1465
77
91
  guarddog/reporters/sarif.py,sha256=diOHJcN3CkSBxBDDg6l9DiZ3ebtUNCw0Rwd7QxCpM9k,7691
78
- guarddog/scanners/__init__.py,sha256=dyBzyKANxTQvyd-oTjgm43gPwRMqB80eOzZ6UFNOuO8,2157
92
+ guarddog/scanners/__init__.py,sha256=ygbe0GAmvxbJNA8Wa1rlN1VHOOLcJa4TnBK8pVQ4ZMo,2443
79
93
  guarddog/scanners/extension_scanner.py,sha256=YdZ7Ai4U-MC83RJcnoo63m_aylAf3VnylwgvhGK3ktU,4915
80
94
  guarddog/scanners/github_action_project_scanner.py,sha256=ISoBqUurwN0lMBtXwcNoalo3ghlbOJkZs9vSNZOT0kk,4216
81
95
  guarddog/scanners/github_action_scanner.py,sha256=6lriTel3U7vNmCWBf0SWti9sLCv88RPlP8SVoAgpKJs,1781
@@ -85,16 +99,18 @@ guarddog/scanners/npm_package_scanner.py,sha256=ciOvpRViMIQvNFupe5-hdXv65QLU5Obm
85
99
  guarddog/scanners/npm_project_scanner.py,sha256=liz5Fyscab53IiSPg0T21Z0vT5eotcHPc_W5Xam4A88,4957
86
100
  guarddog/scanners/pypi_package_scanner.py,sha256=ZkuRRbNejnpfFpIHJJ42GH34khiG8CUKWEPvVh_M_uk,2449
87
101
  guarddog/scanners/pypi_project_scanner.py,sha256=O91c1UP2iZju84_N7cSE7pWGrY6rKapeUqXEVyKld3A,6435
88
- guarddog/scanners/scanner.py,sha256=F7FhN-BQWtcTvh_gdhvj-rXYLMslzeTNxPbJsw1he2s,13695
102
+ guarddog/scanners/rubygems_package_scanner.py,sha256=NqqkKj3aeVKj32a6dxz87ZjEu6lNDXR5BX_Zgoc3Ow4,4162
103
+ guarddog/scanners/rubygems_project_scanner.py,sha256=v6cjkngdfChLDdW8XYqm9na48jSzeYQMsVKmo2UrniA,2277
104
+ guarddog/scanners/scanner.py,sha256=a8Hgt5_xtQFrB2LokNOSvwqI_JzESsWQ_ZnLn3kJCAQ,14746
89
105
  guarddog/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
106
  guarddog/utils/archives.py,sha256=s1AXn6r8kD8hy5JxEOTzdHTgDpgSTImj_mFHfAI34IM,7417
91
107
  guarddog/utils/config.py,sha256=LfXghBsSeB_UH333C3zvh46UpG0doOW6MaZ7GG7_0Z8,2047
92
108
  guarddog/utils/exceptions.py,sha256=23Kzl3exqYK6X-bcGUeb8wPmSglWNX3GIDPkJ6lQzo4,54
93
109
  guarddog/utils/package_info.py,sha256=6fHJPeLn6-tHhKHw0Soedfv2ruPd8zhW2kbhlc3Aem0,975
94
- guarddog-2.7.1.dist-info/METADATA,sha256=rxvp3useQx0sBa_HFyCeg9cBFhnjimNEplUvC2yJics,1446
95
- guarddog-2.7.1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
96
- guarddog-2.7.1.dist-info/entry_points.txt,sha256=vX2fvhnNdkbEL4pDzrH2NqjWVxeOaEYi0sJYmNgS2-s,45
97
- guarddog-2.7.1.dist-info/licenses/LICENSE,sha256=w1aNZxHyoyOPJ4fSdiyrr06tCJZbTjCsH9K1uqeDVyU,11377
98
- guarddog-2.7.1.dist-info/licenses/LICENSE-3rdparty.csv,sha256=cS61ONZL_xlXaTMvQXyBEi3J3es-40Gg6G-6idoa5Qk,314
99
- guarddog-2.7.1.dist-info/licenses/NOTICE,sha256=nlyNt2IjG8IBoQkb7n6jszwAvmREpKAx0POzFO1s2JM,140
100
- guarddog-2.7.1.dist-info/RECORD,,
110
+ guarddog-2.8.4.dist-info/METADATA,sha256=SgaZvtbCAfOnr2PagJwdp4E-a4rXRKRG2aNO8mubQgM,22762
111
+ guarddog-2.8.4.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
112
+ guarddog-2.8.4.dist-info/entry_points.txt,sha256=vX2fvhnNdkbEL4pDzrH2NqjWVxeOaEYi0sJYmNgS2-s,45
113
+ guarddog-2.8.4.dist-info/licenses/LICENSE,sha256=w1aNZxHyoyOPJ4fSdiyrr06tCJZbTjCsH9K1uqeDVyU,11377
114
+ guarddog-2.8.4.dist-info/licenses/LICENSE-3rdparty.csv,sha256=cS61ONZL_xlXaTMvQXyBEi3J3es-40Gg6G-6idoa5Qk,314
115
+ guarddog-2.8.4.dist-info/licenses/NOTICE,sha256=nlyNt2IjG8IBoQkb7n6jszwAvmREpKAx0POzFO1s2JM,140
116
+ guarddog-2.8.4.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.2.1
2
+ Generator: poetry-core 2.3.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,40 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: guarddog
3
- Version: 2.7.1
4
- Summary: GuardDog is a CLI tool for identifying malicious open source packages
5
- License: Apache-2.0
6
- License-File: LICENSE
7
- License-File: LICENSE-3rdparty.csv
8
- License-File: NOTICE
9
- Author: Ellen Wang
10
- Requires-Python: >=3.10,<4
11
- Classifier: License :: OSI Approved :: Apache Software License
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.10
14
- Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Programming Language :: Python :: 3.12
16
- Classifier: Programming Language :: Python :: 3.13
17
- Classifier: Programming Language :: Python :: 3.14
18
- Requires-Dist: click (>=8.1.3,<9.0.0)
19
- Requires-Dist: configparser (>=5.3,<8.0)
20
- Requires-Dist: disposable-email-domains (>=0.0.103,<0.0.121)
21
- Requires-Dist: prettytable (>=3.6.0,<4.0.0)
22
- Requires-Dist: pygit2 (>=1.11,<1.19)
23
- Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
24
- Requires-Dist: python-whois (>=0.8,<0.10)
25
- Requires-Dist: pyyaml (>=6.0,<7.0)
26
- Requires-Dist: requests (>=2.29.0,<3.0.0)
27
- Requires-Dist: semantic-version (>=2.10.0,<3.0.0)
28
- Requires-Dist: semgrep (>=1.147.0,<2.0.0)
29
- Requires-Dist: tarsafe (>=0.0.5,<0.0.6)
30
- Requires-Dist: termcolor (>=2.1.0,<3.0.0)
31
- Requires-Dist: urllib3 (>=2.5.0,<3.0.0)
32
- Requires-Dist: yara-python (>=4.5.1,<5.0.0)
33
- Project-URL: Repository, https://github.com/DataDog/guarddog
34
- Description-Content-Type: text/x-rst
35
-
36
- GuardDog
37
- ========
38
-
39
- See https://github.com/datadog/guarddog
40
-