Add ability to optionally ignore dev dependencies in Yarn projects
Release Notes
Problem to solve
When running Dependency Scanning on Yarn projects, Gemnasium scans all dependencies, including devDependencies
. Gemnasium should utilize the DS_INCLUDE_DEV_DEPENDENCIES
variable when determining if devDependencies
should be included during the scan.
For instance, in a project having the following package.json
dependency file, my_test_framework
and another_dev_dep
and their dependencies should not be scanned.
{
"dependencies": {
"my_dep": "^1.0.0",
"another_dep": "~2.2.0"
},
"devDependencies" : {
"my_test_framework": "^3.1.0".
"another_dev_dep": "1.0.0 - 1.2.0"
}
}
Intended users
- Sasha (Software Developer)
- Devon (DevOps Engineer)
- Sam (Security Analyst)
- Alex (Security Operations Engineer)
Proposal
When DS_INCLUDE_DEV_DEPENDENCIES
is "false"
, the Dependency Scanning job should ignore development dependencies when scanning Yarn projects. To do so, the Yarn project will require a package.json
since it is the only file that references devDependencies
. The package.json
file only lists direct dependencies, and as a result, graph traversal will be needed to see if a dependency is reachable from a package listed in the dependencies
section of the package.json
. The approach might look like the following pseudocode:
- Create an index that maps a package name to a list of its dependencies and another that identifies if it's been visited.
dependencyIndex := make(map[string][]string) // Add yarn.lock packages to dependencyIndex visited := make(map[string]bool)
- Parse the packages listed in the
package.json
dependencies section and add them to a queue. - Pop a package name from the queue and iterate through all of its dependencies. a. If the package name has not been visited, add it to the queue. b. If a package has been visited, do not add it to the queue. i.e. skip to next package in list.
- After iterating through all dependencies, set the package as visited.
visited["pkgName"] = true
- Repeat until queue is empty.
If the yarn project does not have a package.json
file, then it should revert DS_INCLUDE_DEV_DEPENDENCIES
to true
and log a warning message of the reverted option.
Documentation
Document Yarn support for DS_INCLUDE_DEV_DEPENDENCIES
in Configuring specific analyzers used by dependency scanning.
Testing
A new Yarn integration test is added to gemnasium
, to check that devDependencies
are ignored when DS_INCLUDE_DEV_DEPENDENCIES
is "false"
.
Also, the unit tests of the Yarn parser are updated.
Workaround
You can run the following script to generate an SBOM that populates the dependency list only with the production dependencies.
#!/bin/sh
set -eu
yarn dlx -q @cyclonedx/yarn-plugin-cyclonedx --production --output-file gl-sbom-node-yarn.cdx.json
find . -path '*.cdx.json' -print0 >sboms.txt
while IFS= read -r -d '' FILE; do
DIR="$(dirname "$FILE")"
SCRIPT=$(
cat <<EOF
.metadata.properties = [
{
"name": "gitlab:dependency_scanning:input_file:path",
"value": "$DIR/yarn.lock"
},
{
"name": "gitlab:dependency_scanning:package_manager:name",
"value": "yarn"
},
{
"name": "gitlab:dependency_scanning:language:name",
"value": "node"
},
{
"name": "gitlab:meta:schema_version",
"value": "1"
}
]
EOF
)
jq "$SCRIPT" "$FILE" > "$FILE.tmp"
mv "$FILE.tmp" "$FILE"
done < sboms.txt
rm -f sboms.txt
You can run this in pipeline with a configuration like so:
dependency-scanning:
image: node:22-alpine
stage: test
before_script:
- apk add --no-cache jq
script:
- ./generate-sbom.sh
artifacts:
untracked: false
when: on_success
access: developer
paths:
- "**/*.cdx.json"
reports:
cyclonedx: "**/*.cdx.json"