Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ GuardDog's behavior can be customized using environment variables:
|---------------------|-------------|---------------|
| `GUARDDOG_PARALLELISM` | Number of threads to use for parallel processing | Number of CPUs available |
| `GUARDDOG_VERIFY_EXHAUSTIVE_DEPENDENCIES` | Analyze all possible versions of dependencies (`true`/`false`) | `false` |
| `GUARDDOG_NPM_INCLUDE_DEV_DEPENDENCIES` | Include `devDependencies` when scanning npm `package.json` files (`true`/`false`) | `false` |
| `GUARDDOG_TOP_PACKAGES_CACHE_LOCATION` | Location of the top packages cache directory | `guarddog/analyzer/metadata/resources` |
| `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` |

Expand Down
20 changes: 13 additions & 7 deletions guarddog/scanners/npm_project_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@

from guarddog.scanners.npm_package_scanner import NPMPackageScanner
from guarddog.scanners.scanner import Dependency, DependencyVersion, ProjectScanner
from guarddog.utils.config import VERIFY_EXHAUSTIVE_DEPENDENCIES
from guarddog.utils.config import (
NPM_INCLUDE_DEV_DEPENDENCIES,
VERIFY_EXHAUSTIVE_DEPENDENCIES,
)

log = logging.getLogger("guarddog")

Expand Down Expand Up @@ -86,12 +89,15 @@ def find_all_versions(package_name: str) -> set[str]:
return versions

merged = {} # type: dict[str, set[str]]
for package, selector in list(dependencies_attr.items()) + list(
dev_dependencies_attr.items()
):
if package not in merged:
merged[package] = set()
merged[package].add(selector)
dependency_groups = [dependencies_attr.items()]
if NPM_INCLUDE_DEV_DEPENDENCIES:
dependency_groups.append(dev_dependencies_attr.items())

for dependency_group in dependency_groups:
for package, selector in dependency_group:
if package not in merged:
merged[package] = set()
merged[package].add(selector)

dependencies: List[Dependency] = []
for package, all_selectors in merged.items():
Expand Down
10 changes: 10 additions & 0 deletions guarddog/utils/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@
os.environ.get("GUARDDOG_VERIFY_EXHAUSTIVE_DEPENDENCIES", "false").lower() == "true"
)

"""
This flag specifies if npm devDependencies should be included in project scans
- True: dependencies and devDependencies are analyzed
- False [default]: Only dependencies are analyzed
"""
NPM_INCLUDE_DEV_DEPENDENCIES: bool = (
os.environ.get("GUARDDOG_NPM_INCLUDE_DEV_DEPENDENCIES", "false").lower()
== "true"
)

"""
This parameter specifies the location of the top packages cache
- Default: guarddog/analyzer/metadata/resources
Expand Down
43 changes: 43 additions & 0 deletions tests/core/test_npm_requirements_scanner.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import pathlib

import guarddog.scanners.npm_project_scanner as npm_project_scanner
from guarddog.scanners.npm_project_scanner import NPMRequirementsScanner


Expand Down Expand Up @@ -55,3 +56,45 @@ def test_npm_requirements_scanner_github():
)
assert lookup is not None
assert "https://github.com/expressjs/cors.git" in lookup.versions


def test_npm_requirements_scanner_excludes_dev_dependencies_by_default(monkeypatch):
monkeypatch.setattr(
npm_project_scanner, "NPM_INCLUDE_DEV_DEPENDENCIES", False
)
scanner = NPMRequirementsScanner()
result = scanner.parse_requirements("""
{
"dependencies": {
"express": "4.x"
},
"devDependencies": {
"joi": "17.6"
}
}
""")

dependency_names = {dependency.name for dependency in result}
assert "express" in dependency_names
assert "joi" not in dependency_names


def test_npm_requirements_scanner_includes_dev_dependencies_when_enabled(monkeypatch):
monkeypatch.setattr(
npm_project_scanner, "NPM_INCLUDE_DEV_DEPENDENCIES", True
)
scanner = NPMRequirementsScanner()
result = scanner.parse_requirements("""
{
"dependencies": {
"express": "4.x"
},
"devDependencies": {
"joi": "17.6"
}
}
""")

dependency_names = {dependency.name for dependency in result}
assert "express" in dependency_names
assert "joi" in dependency_names