lockfile-lint-api
v5.10.0
Published
Lint an npm or yarn lockfile to analyze and detect issues
Readme
About
Lints an npm or yarn lockfile to analyze and detect issues
Install
npm install --save lockfile-lint-apiUsage
lockfile-lint-api exposes a set of validator APIs that can be used for programmatic use-cases, such as being employed by other tools and programs if needed.
Validators
ValidateIntegrity.validate({integrityStrict: true}) requires a complete
base64-encoded SHA-512 digest for dependencies in npm v1-v3 and Yarn Classic
lockfiles. The default validation still only checks the hash type when present.
For example:
const {ParseLockfile, ValidateIntegrity} = require('lockfile-lint-api')
const {object: packages, format} = new ParseLockfile({lockfilePath: 'package-lock.json'}).parseSync()
const result = new ValidateIntegrity({packages, format}).validate({integrityStrict: true})Strict mode exempts Git dependencies, local directories, workspace links and
bundled dependencies. The parser resolves bundle ancestry before flattening and
records verified bundle provenance for validation. Local .tgz/.tar.gz files
and HTTP(S) tarballs still require integrity.
An SRI list is accepted if it contains a complete SHA-512 digest. Package
exclusions use integrityExclude as in the default mode. You can also pass
{integrityStrict: true} as the second argument to validateSingle(packageName).
This checks metadata without fetching package contents, and does not support
Yarn Berry's different checksum format.
For npm v2/v3, bundled entries require a verified bundler ancestor. The parser
walks up the package path, skipping ancestors marked inBundle/bundled, to the
nearest non-bundled ancestor. That ancestor must exist and declare
bundleDependencies as a non-empty array or true. It must also have a complete
SHA-512 integrity value or qualify independently as a commit-pinned Git source,
local directory or workspace link. Transitive bundled dependencies are covered
even when their names are absent from the declaration.
For npm v1, the nearest enclosing non-bundled ancestor must meet the same
integrity/source requirement. The v1 dependency tree does not record the parent's
bundleDependencies, so the parser cannot confirm the declaration itself.
Missing or unverified ancestors leave children subject to the integrity check;
excluding a parent from validation does not verify its bundle.
Raw link, bundled or inBundle flags do not exempt HTTP(S) sources or local
.tgz/.tar.gz files; the Git source exceptions below still apply.
Git-protocol URLs and Git-host shorthands require a 7-40-character hexadecimal
commit fragment to qualify for an exemption. Branches, tags, semver ranges and
missing refs require complete SHA-512 integrity. Link/bundle flags cannot bypass
this pin requirement. Local file URLs are classified using their decoded path:
percent-encoded .tgz/.tar.gz extensions still require integrity, and malformed
URL escapes do not qualify as local directories.
Yarn Classic GitHub sources are also exempt when the URL is exactly
https://codeload.github.com/<owner>/<repo>/tar.gz/<40-hex-commit-sha>,
without a query string or fragment. Codeload URLs using tags, branches or short
SHAs, and archive URLs that do not match this shape, still require integrity.
HTTPS GitHub, GitLab and Bitbucket repository URLs of the form
https://<host>/<owner>/<repo>#<commit> are exempt when the commit is 7-40
hexadecimal characters and there is no query string. This separate Git-remote
exception accepts abbreviated commits; archive/download paths remain subject
to the tarball rules above.
For Yarn Berry, strict validate() returns one unsupported-format error without
a package field:
{
"type": "error",
"errors": [
{
"message": "--validate-integrity-strict does not support Yarn Berry lockfiles (which use \"checksum\" instead of \"integrity\").",
"unsupportedFormat": true
}
]
}Consumers can inspect unsupportedFormat without matching message text. Strict
validateSingle() throws an Error with the same message and
unsupportedFormat: true; for supported formats it returns a boolean.
The CLI exits non-zero with an unsupported-format summary. It prints
"security issues detected!" only if other validators report security findings.
API consumers should pass the parser result's format alongside packages to
ValidateIntegrity so unsupported Yarn Berry input is identified. Pass the
parsed package objects directly to preserve the parser's internal bundle
provenance; raw bundle flags or JSON-serialized copies alone do not establish
verified ancestry.
The following lockfile validators are supported
| Validator API | description | implemented | |----------------------|---------------------------------------------------------------------------------| ----------- | | ValidateHttps | validates the use of HTTPS as protocol schema for all resources | ✅ | | ValidateHost | validates a whitelist of allowed hosts to be used for resources in the lockfile | ✅ | | ValidatePackageNames | validates that the resolved URL matches the package name | ✅ | | ValidateScheme | validates a whitelist of allowed URI schemes to be used for hosts | ✅ | | ValidateIntegrity | validates that the integrity hash type is sha512 | ✅ |
NOTE: package entries without a resolved field (for example, those installed from the local filesystem) will automatically pass all url-based validators.
Success and failures
When validators encounter errors they will throw an exception, and on either success or failure in validating data they will always return a descriptive object for the validation task.
Successful validation
When validation is successful the following object will be returned from the validating function:
{
"type": "success",
"errors": []
}Failed validation
When validation has failed the following object will be returned from the validating function:
{
"type": "error",
"errors": [
{
"package": "@babel/cli",
"message": "detected invalid origin for package: @babel/cli"
}
]
}Notes about the returned object:
- An errors object will always return an array of errors metadata, even if there's only one error associated with the validation being performed
- All errors should always have a message
- The availability of the
packageproperty and other metadata depends on the specific validators being used
Example
const validator = new ValidateHost({packages: lockfile.object})
let result
try {
result = validator.validate(['npm'])
} catch (error) {
// something bad happened during validation and the validation
// process couldn't take place
}
console.log(result)
/* prints
{
"type": "error",
"errors": [
{
"message": "detected invalid origin for package: meow",
"package": "meow"
}
]
}
*/Example
const {ValidateHost, ParseLockfile} = require('lockfile-lint-api')
// path to the lockfile
const yarnLockfilePath = '/path/to/my/yarn.lock'
const options = {
lockfilePath: yarnLockfilePath
}
// instantiate a new parser with options object
const parser = new ParseLockfile(options)
// read the file synchronously and parses it
// providing back an object that is compatible
// with the @yarn/lockfile library which has
// all the packages listed in `lockfile.object`
const lockfile = parser.parseSync()
// now instantiate a validator object with those
// list of packages
const validator = new ValidateHost({packages: lockfile.object})
let result
try {
// validation is synchronous and is being called
// with 'npm' as a shortcut for the npm registry
// host to validate all lockfile resources are
// whitelisted to the npm host
result = validator.validate(['npm'])
} catch (error) {
// couldn't process the validation
}
if (result.type === 'success') {
// validation succeeded
}Contributing
Please consult CONTRIBUTING for guidelines on contributing to this project.
Author
lockfile-lint-api © Liran Tal, Released under the Apache-2.0 License.
